0
0
Fork 0

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:
Gibheer 2015-03-16 16:48:42 +01:00
parent d4d2d4c09b
commit 362fe8ff38
2 changed files with 85 additions and 7 deletions

View File

@ -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
}

46
certificate_test.go Normal file
View File

@ -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
}