-
Notifications
You must be signed in to change notification settings - Fork 0
/
issuer.go
180 lines (160 loc) · 4.81 KB
/
issuer.go
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
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
package issuer
import (
"crypto/rand"
"crypto/rsa"
"crypto/tls"
"crypto/x509"
"crypto/x509/pkix"
"encoding/pem"
"io"
"math/big"
"net"
"sync"
"time"
)
// Issuer defines interface for on-flight certificate generator
type Issuer interface {
Issue(cn string, dnsnames []string, ipaddresses []net.IP) (*tls.Certificate, error)
}
// SelfSignedCA defines an Issuer. Zero value is a valid instance.
type SelfSignedCA struct {
// Cert is a cert chain used to sign newly issued certs. The cert's primary usage must be x509.KeyUsageCertSign
//
// If nil, a self-signed cert will be generated.
Cert *tls.Certificate
// BitSize defines bit size for issued certificate keys generation.
//
// If 0, DefaultIssuerBitSize will be used.
BitSize int
// RootBitSize defines bit size for self-signed root certificate key generation.
//
// If 0, DefaultIssuerRootBitSize will be used.
RootBitSize int
// Tmpl is a template for issued certificates.
//
// If nil, DefaultIssuerTmpl will be used.
Tmpl *x509.Certificate
// RootTmpl is a template for self-signed root certificate.
//
// If nil, DefaultIssuerRootTmpl will be used.
RootTmpl *x509.Certificate
// Rand is a source of randomness for generated certs.
//
// If nil, crypto/rand.Reader will be used.
Rand io.Reader
once sync.Once
}
// Issue implements Issuer interface
func (ca *SelfSignedCA) Issue(cn string, dnsnames []string, ipaddresses []net.IP) (*tls.Certificate, error) {
ca.once.Do(ca.init)
tmpl := *ca.Tmpl
tmpl.Subject.CommonName = cn
tmpl.NotBefore = time.Now()
tmpl.NotAfter = time.Now().AddDate(10, 0, 0)
tmpl.KeyUsage = x509.KeyUsageDigitalSignature
tmpl.ExtKeyUsage = []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth}
tmpl.DNSNames = dnsnames
tmpl.IPAddresses = ipaddresses
key, err := rsa.GenerateKey(ca.Rand, 1024)
if err != nil {
return nil, err
}
der, err := x509.CreateCertificate(ca.Rand, &tmpl, ca.Cert.Leaf, &key.PublicKey, ca.Cert.PrivateKey)
if err != nil {
return nil, err
}
cert, err := tls.X509KeyPair(
pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: der}),
pem.EncodeToMemory(&pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(key)}),
)
if err != nil {
return nil, err
}
cert.Leaf, err = x509.ParseCertificate(cert.Certificate[0])
if err != nil {
return nil, err
}
return &cert, nil
}
func (ca *SelfSignedCA) init() {
if ca.Rand == nil {
ca.Rand = rand.Reader
}
if ca.Tmpl == nil {
ca.Tmpl = &DefaultIssuerTmpl
}
if ca.RootTmpl == nil {
ca.RootTmpl = &DefaultIssuerRootTmpl
}
if ca.BitSize == 0 {
ca.BitSize = DefaultIssuerBitSize
}
if ca.RootBitSize == 0 {
ca.RootBitSize = DefaultIssuerRootBitSize
}
if ca.Cert == nil {
ca.initRootCert()
}
if ca.Cert.Leaf == nil {
// pre-parse leaf certificate, ignore potential error, it will inevitably pop up on the first use any way
ca.Cert.Leaf, _ = x509.ParseCertificate(ca.Cert.Certificate[0])
}
}
func (ca *SelfSignedCA) initRootCert() {
key, err := rsa.GenerateKey(ca.Rand, ca.RootBitSize)
if err != nil {
panic(err)
}
cert, err := x509.CreateCertificate(ca.Rand, ca.RootTmpl, ca.RootTmpl, &key.PublicKey, key)
if err != nil {
panic(err)
}
pair, err := tls.X509KeyPair(
pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: cert}),
pem.EncodeToMemory(&pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(key)}),
)
if err != nil {
panic(err)
}
pair.Leaf, err = x509.ParseCertificate(pair.Certificate[0])
if err != nil {
panic(err)
}
ca.Cert = &pair
}
// DefaultIssuerRootBitSize defines default bit size for a self-signed root cert.
const DefaultIssuerRootBitSize = 2048
// DefaultIssuerBitSize defines default bit size for issued certs.
const DefaultIssuerBitSize = 1024
var (
// DefaultIssuerRootTmpl is the default template for self-signed root CA certificate.
DefaultIssuerRootTmpl = x509.Certificate{
SerialNumber: big.NewInt(1),
Issuer: pkix.Name{
CommonName: "issuer.example.org",
Organization: []string{"Multiproxy Issuer Org"},
},
Subject: pkix.Name{
CommonName: "root.example.org",
Organization: []string{"Multiproxy Root Org"},
},
NotBefore: time.Now(),
NotAfter: time.Now().Add(time.Hour * 24 * 365 * 2),
IsCA: true,
BasicConstraintsValid: true,
OCSPServer: []string{"ocsp.example.org"},
DNSNames: []string{"root.example.org"},
SignatureAlgorithm: x509.SHA1WithRSA,
KeyUsage: x509.KeyUsageCertSign,
}
// DefaultIssuerTmpl is the default template for issued certificates.
DefaultIssuerTmpl = x509.Certificate{
SerialNumber: big.NewInt(1),
Subject: pkix.Name{
Country: []string{"AQ"},
Organization: []string{"Multiproxy"},
},
KeyUsage: x509.KeyUsageDigitalSignature,
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
}
)