finalize creation of a certificate
With the options it is now finished. The only stuff left to do is to add all options provided by the go API. But this should be sufficient.
This commit is contained in:
parent
d4d2d4c09b
commit
362fe8ff38
|
@ -5,7 +5,10 @@ import (
|
|||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/pem"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"net"
|
||||
"time"
|
||||
)
|
||||
|
||||
const PemLabelCertificateRequest = "CERTIFICATE REQUEST"
|
||||
|
@ -14,13 +17,20 @@ type (
|
|||
CertificateData struct {
|
||||
Subject pkix.Name
|
||||
|
||||
DnsNames []string
|
||||
DNSNames []string
|
||||
EmailAddresses []string
|
||||
IpAddresses []net.IP
|
||||
IPAddresses []net.IP
|
||||
}
|
||||
|
||||
Certificate x509.Certificate
|
||||
CertificateRequest x509.CertificateRequest
|
||||
|
||||
CertificateOptions struct {
|
||||
SerialNumber *big.Int
|
||||
NotBefore time.Time
|
||||
NotAfter time.Time // Validity bounds.
|
||||
KeyUsage x509.KeyUsage
|
||||
}
|
||||
)
|
||||
|
||||
func NewCertificateData() *CertificateData {
|
||||
|
@ -33,8 +43,8 @@ func (c *CertificateData) ToCertificateRequest(private_key PrivateKey) (*Certifi
|
|||
csr := &x509.CertificateRequest{}
|
||||
|
||||
csr.Subject = c.Subject
|
||||
csr.DNSNames = c.DnsNames
|
||||
csr.IPAddresses = c.IpAddresses
|
||||
csr.DNSNames = c.DNSNames
|
||||
csr.IPAddresses = c.IPAddresses
|
||||
csr.EmailAddresses = c.EmailAddresses
|
||||
|
||||
csr_asn1, err := x509.CreateCertificateRequest(rand.Reader, csr, private_key.PrivateKey())
|
||||
|
@ -58,20 +68,37 @@ func (c *CertificateRequest) MarshalPem() (marshalledPemBlock, error) {
|
|||
// Convert the certificate sign request to a certificate using the private key
|
||||
// of the signer and the certificate of the signer.
|
||||
// If the certificate is null, the sign request will be used to sign itself.
|
||||
// Please also see the certificate options struct for information on mandatory fields.
|
||||
// For more information, please read http://golang.org/pkg/crypto/x509/#CreateCertificate
|
||||
func (c *CertificateRequest) ToCertificate(private_key PrivateKey, ca *Certificate) (*Certificate, error) {
|
||||
func (c *CertificateRequest) ToCertificate(private_key PrivateKey,
|
||||
cert_opts CertificateOptions, ca *Certificate) (*Certificate, error) {
|
||||
|
||||
if err := cert_opts.Valid(); err != nil { return nil, err }
|
||||
|
||||
template := &x509.Certificate{}
|
||||
template.Subject = c.Subject
|
||||
template.DNSNames = c.DNSNames
|
||||
template.IPAddresses = c.IPAddresses
|
||||
template.EmailAddresses = c.EmailAddresses
|
||||
|
||||
// if no ca is given, we have to set IsCA to self sign
|
||||
if ca == nil {
|
||||
template.IsCA = true
|
||||
}
|
||||
|
||||
template.NotBefore = cert_opts.NotBefore
|
||||
template.NotAfter = cert_opts.NotAfter
|
||||
template.KeyUsage = cert_opts.KeyUsage
|
||||
template.SerialNumber = cert_opts.SerialNumber
|
||||
|
||||
var cert_asn1 []byte
|
||||
var err error
|
||||
// if we have no ca which can sign the cert, a self signed cert is wanted
|
||||
// (or isn't it? Maybe we should split creation of the template? But that would be ugly)
|
||||
if ca == nil {
|
||||
cert_asn1, err = x509.CreateCertificate(rand.Reader, template, template, c.PublicKey, private_key)
|
||||
cert_asn1, err = x509.CreateCertificate(rand.Reader, template, template, c.PublicKey, private_key.PrivateKey())
|
||||
} else {
|
||||
cert_asn1, err = x509.CreateCertificate(rand.Reader, template, (*x509.Certificate)(ca), c.PublicKey, private_key)
|
||||
cert_asn1, err = x509.CreateCertificate(rand.Reader, template, (*x509.Certificate)(ca), c.PublicKey, private_key.PrivateKey())
|
||||
}
|
||||
if err != nil { return nil, err }
|
||||
return LoadCertificate(cert_asn1)
|
||||
|
@ -83,3 +110,8 @@ func LoadCertificate(raw []byte) (*Certificate, error) {
|
|||
if err != nil { return nil, err }
|
||||
return (*Certificate)(cert), nil
|
||||
}
|
||||
|
||||
func (co *CertificateOptions) Valid() error {
|
||||
if co.SerialNumber == nil { return fmt.Errorf("No serial number set!") }
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
package pki
|
||||
|
||||
import (
|
||||
"crypto/elliptic"
|
||||
// "crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"math/big"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var (
|
||||
TestCertificateData = CertificateData{
|
||||
Subject: pkix.Name{CommonName: "foobar"},
|
||||
DNSNames: []string{"foo.bar", "example.com"},
|
||||
}
|
||||
)
|
||||
|
||||
func TestCertificateCreation(t *testing.T) {
|
||||
pk, err := NewPrivateKeyEcdsa(elliptic.P224())
|
||||
if err != nil { t.Errorf("cert: creating private key failed: %s", err) }
|
||||
|
||||
csr, err := TestCertificateData.ToCertificateRequest(pk)
|
||||
if err != nil { t.Errorf("cert: creating csr failed: %s", err) }
|
||||
|
||||
cert_opts := CertificateOptions{
|
||||
// KeyUsage: x509.KeyUsageEncipherOnly | x509.KeyUsageKeyEncipherment | x509.KeyUsageCertSign,
|
||||
SerialNumber: big.NewInt(1),
|
||||
}
|
||||
|
||||
cert, err := csr.ToCertificate(pk, cert_opts, nil)
|
||||
if err != nil { t.Errorf("cert: creating cert failed: %s", err) }
|
||||
|
||||
if !fieldsAreSame(TestCertificateData, cert) {
|
||||
t.Errorf("cert: Fields are not the same")
|
||||
}
|
||||
}
|
||||
|
||||
func fieldsAreSame(data CertificateData, cert *Certificate) bool {
|
||||
if data.Subject.CommonName != cert.Subject.CommonName { return false }
|
||||
if !reflect.DeepEqual(data.Subject.Country, cert.Subject.Country) { return false }
|
||||
if !reflect.DeepEqual(data.DNSNames, cert.DNSNames) { return false }
|
||||
if !reflect.DeepEqual(data.IPAddresses, cert.IPAddresses) { return false }
|
||||
if !reflect.DeepEqual(data.EmailAddresses, cert.EmailAddresses) { return false }
|
||||
return true
|
||||
}
|
Loading…
Reference in New Issue