1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
|
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.
IsCA bool
// how many sub ca are allowed between this ca and the end/final certificate
// if it is -1, then no limit will be set
CALength int
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.IsCA = cert_opts.IsCA
if cert_opts.IsCA {
template.BasicConstraintsValid = true
}
if cert_opts.CALength >= 0 {
template.MaxPathLen = cert_opts.CALength
template.MaxPathLenZero = true
template.BasicConstraintsValid = true
}
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
}
|