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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
|
package pki
import (
"crypto/rand"
"crypto/x509"
"crypto/x509/pkix"
"encoding/pem"
"fmt"
"math/big"
"net"
"time"
)
// labels used in the pem file format to mark certificate sign requests and certificates
const (
PemLabelCertificateRequest = "CERTIFICATE REQUEST"
PemLabelCertificate = "CERTIFICATE"
)
type (
// Use CertificateData to fill in the minimum data you need to create a certificate
// sign request.
CertificateData struct {
Subject pkix.Name
DNSNames []string
EmailAddresses []string
IPAddresses []net.IP
}
// Certificate is an alias on the x509.Certificate to add some methods.
Certificate x509.Certificate
// CertificateRequest is an alias on the x509.CertificateRequest to add some methods.
CertificateRequest x509.CertificateRequest
// CertificateOptions is used to provide the necessary information to create
// a certificate from a certificate sign request.
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 // for what can the certificate be used
KeyExtendedUsage []x509.ExtKeyUsage // extended usage for the certificate
}
)
// Create a new set of certificate data.
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.ExtKeyUsage = cert_opts.KeyExtendedUsage
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
}
// Check if the certificate options have the required fields set.
func (co *CertificateOptions) Valid() error {
if co.SerialNumber == nil {
return fmt.Errorf("No serial number set!")
}
return nil
}
|