aboutsummaryrefslogtreecommitdiff
path: root/certificate.go
diff options
context:
space:
mode:
authorGibheer <gibheer@gmail.com>2015-03-16 17:11:28 +0100
committerGibheer <gibheer@gmail.com>2015-03-16 17:11:28 +0100
commit2c43111aecbf3f808e03c628ebf587994ce6b384 (patch)
tree4030ee781235af1e270c733af3184ea4807d05d6 /certificate.go
parentb7f4f3ae2123301b6957498ef92d580f4b8ed105 (diff)
parent2b74dbb334192eb25ebd9de2d1273692797ec558 (diff)
Merge branch 'certificate'
This adds the API to generate certificates in the same way certificate sign requests were built. It works but still lacks some features and fields.
Diffstat (limited to 'certificate.go')
-rw-r--r--certificate.go126
1 files changed, 126 insertions, 0 deletions
diff --git a/certificate.go b/certificate.go
new file mode 100644
index 0000000..b6fa252
--- /dev/null
+++ b/certificate.go
@@ -0,0 +1,126 @@
+package pki
+
+import (
+ "crypto/rand"
+ "crypto/x509"
+ "crypto/x509/pkix"
+ "encoding/pem"
+ "fmt"
+ "math/big"
+ "net"
+ "time"
+)
+
+const (
+ PemLabelCertificateRequest = "CERTIFICATE REQUEST"
+ PemLabelCertificate = "CERTIFICATE"
+)
+
+type (
+ CertificateData struct {
+ Subject pkix.Name
+
+ DNSNames []string
+ EmailAddresses []string
+ 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 {
+ return &CertificateData{Subject: pkix.Name{}}
+}
+
+// Create a certificate sign request from the input data and the private key of
+// the request creator.
+func (c *CertificateData) ToCertificateRequest(private_key PrivateKey) (*CertificateRequest, error) {
+ csr := &x509.CertificateRequest{}
+
+ csr.Subject = c.Subject
+ csr.DNSNames = c.DNSNames
+ csr.IPAddresses = c.IPAddresses
+ csr.EmailAddresses = c.EmailAddresses
+
+ csr_asn1, err := x509.CreateCertificateRequest(rand.Reader, csr, private_key.PrivateKey())
+ if err != nil { return nil, err }
+ return LoadCertificateSignRequest(csr_asn1)
+}
+
+// Load a certificate sign request from its asn1 representation.
+func LoadCertificateSignRequest(raw []byte) (*CertificateRequest, error) {
+ csr, err := x509.ParseCertificateRequest(raw)
+ if err != nil { return nil, err }
+ return (*CertificateRequest)(csr), nil
+}
+
+// Return the certificate sign request as a pem block.
+func (c *CertificateRequest) MarshalPem() (marshalledPemBlock, error) {
+ block := &pem.Block{Type: PemLabelCertificateRequest, Bytes: c.Raw}
+ return pem.EncodeToMemory(block), nil
+}
+
+// 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,
+ 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.PrivateKey())
+ } else {
+ 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)
+}
+
+// Load a certificate from its asn1 representation.
+func LoadCertificate(raw []byte) (*Certificate, error) {
+ cert, err := x509.ParseCertificate(raw)
+ if err != nil { return nil, err }
+ return (*Certificate)(cert), nil
+}
+
+// marshal the certificate to a pem block
+func (c *Certificate) MarshalPem() (marshalledPemBlock, error) {
+ block := &pem.Block{Type: PemLabelCertificate, Bytes: c.Raw}
+ return pem.EncodeToMemory(block), nil
+}
+
+func (co *CertificateOptions) Valid() error {
+ if co.SerialNumber == nil { return fmt.Errorf("No serial number set!") }
+ return nil
+}