forked from zboya/gomitmproxy
-
Notifications
You must be signed in to change notification settings - Fork 0
/
genKey.go
309 lines (275 loc) · 9.06 KB
/
genKey.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
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
// Package keyman provides convenience APIs around Go's built-in crypto APIs.
package main
import (
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"crypto/x509/pkix"
"encoding/pem"
"fmt"
"io/ioutil"
"math/big"
"net"
"os"
"time"
)
const (
PEM_HEADER_PRIVATE_KEY = "RSA PRIVATE KEY"
PEM_HEADER_PUBLIC_KEY = "RSA PRIVATE KEY"
PEM_HEADER_CERTIFICATE = "CERTIFICATE"
)
var (
tenYearsFromToday = time.Now().AddDate(10, 0, 0)
)
// PrivateKey is a convenience wrapper for rsa.PrivateKey
type PrivateKey struct {
rsaKey *rsa.PrivateKey
}
// Certificate is a convenience wrapper for x509.Certificate
type Certificate struct {
cert *x509.Certificate
derBytes []byte
}
/*******************************************************************************
* Private Key Functions
******************************************************************************/
// GeneratePK generates a PrivateKey with a specified size in bits.
func GeneratePK(bits int) (key *PrivateKey, err error) {
var rsaKey *rsa.PrivateKey
rsaKey, err = rsa.GenerateKey(rand.Reader, bits)
if err == nil {
key = &PrivateKey{rsaKey: rsaKey}
}
return
}
// LoadPKFromFile loads a PEM-encoded PrivateKey from a file
func LoadPKFromFile(filename string) (key *PrivateKey, err error) {
privateKeyData, err := ioutil.ReadFile(filename)
if err != nil {
if os.IsNotExist(err) {
return nil, err
}
return nil, fmt.Errorf("Unable to read private key file from file %s: %s", filename, err)
}
block, _ := pem.Decode(privateKeyData)
if block == nil {
return nil, fmt.Errorf("Unable to decode PEM encoded private key data: %s", err)
}
rsaKey, err := x509.ParsePKCS1PrivateKey(block.Bytes)
if err != nil {
return nil, fmt.Errorf("Unable to decode X509 private key data: %s", err)
}
return &PrivateKey{rsaKey: rsaKey}, nil
}
// PEMEncoded encodes the PrivateKey in PEM
func (key *PrivateKey) PEMEncoded() (pemBytes []byte) {
return pem.EncodeToMemory(key.pemBlock())
}
// WriteToFile writes the PEM-encoded PrivateKey to the given file
func (key *PrivateKey) WriteToFile(filename string) (err error) {
keyOut, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
if err != nil {
return fmt.Errorf("Failed to open %s for writing: %s", filename, err)
}
if err := pem.Encode(keyOut, key.pemBlock()); err != nil {
return fmt.Errorf("Unable to PEM encode private key: %s", err)
}
if err := keyOut.Close(); err != nil {
logger.Printf("Unable to close file: %v", err)
}
return
}
func (key *PrivateKey) pemBlock() *pem.Block {
return &pem.Block{Type: PEM_HEADER_PRIVATE_KEY, Bytes: x509.MarshalPKCS1PrivateKey(key.rsaKey)}
}
/*******************************************************************************
* Certificate Functions
******************************************************************************/
/*
Certificate() generates a certificate for the Public Key of the given PrivateKey
based on the given template and signed by the given issuer. If issuer is nil,
the generated certificate is self-signed.
*/
func (key *PrivateKey) Certificate(template *x509.Certificate, issuer *Certificate) (*Certificate, error) {
return key.CertificateForKey(template, issuer, &key.rsaKey.PublicKey)
}
/*
CertificateForKey() generates a certificate for the given Public Key based on
the given template and signed by the given issuer. If issuer is nil, the
generated certificate is self-signed.
*/
func (key *PrivateKey) CertificateForKey(template *x509.Certificate, issuer *Certificate, publicKey interface{}) (*Certificate, error) {
var issuerCert *x509.Certificate
if issuer == nil {
// Note - for self-signed certificates, we include the host's external IP address
issuerCert = template
} else {
issuerCert = issuer.cert
}
derBytes, err := x509.CreateCertificate(
rand.Reader, // secure entropy
template, // the template for the new cert
issuerCert, // cert that's signing this cert
publicKey, // public key
key.rsaKey, // private key
)
if err != nil {
return nil, err
}
return bytesToCert(derBytes)
}
// TLSCertificateFor generates a certificate useful for TLS use based on the
// given parameters. These certs are usable for key encipherment and digital
// signatures.
//
// organization: the org name for the cert.
// name: used as the common name for the cert. If name is an IP
// address, it is also added as an IP SAN.
// validUntil: time at which certificate expires
// isCA: whether or not this cert is a CA
// issuer: the certificate which is issuing the new cert. If nil, the
// new cert will be a self-signed CA certificate.
//
func (key *PrivateKey) TLSCertificateFor(
organization string,
name string,
validUntil time.Time,
isCA bool,
issuer *Certificate) (cert *Certificate, err error) {
template := &x509.Certificate{
SerialNumber: new(big.Int).SetInt64(int64(time.Now().UnixNano())),
Subject: pkix.Name{
Organization: []string{organization},
CommonName: name,
},
NotBefore: time.Now().AddDate(0, -1, 0),
NotAfter: validUntil,
BasicConstraintsValid: true,
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
}
// If name is an ip address, add it as an IP SAN
ip := net.ParseIP(name)
if ip != nil {
template.IPAddresses = []net.IP{ip}
}
isSelfSigned := issuer == nil
if isSelfSigned {
template.ExtKeyUsage = []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth}
}
// If it's a CA, add certificate signing
if isCA {
template.KeyUsage = template.KeyUsage | x509.KeyUsageCertSign
template.IsCA = true
}
cert, err = key.Certificate(template, issuer)
return
}
// LoadCertificateFromFile loads a Certificate from a PEM-encoded file
func LoadCertificateFromFile(filename string) (*Certificate, error) {
certificateData, err := ioutil.ReadFile(filename)
if err != nil {
if os.IsNotExist(err) {
return nil, err
}
return nil, fmt.Errorf("Unable to read certificate file from disk: %s", err)
}
return LoadCertificateFromPEMBytes(certificateData)
}
// LoadCertificateFromPEMBytes loads a Certificate from a byte array in PEM
// format
func LoadCertificateFromPEMBytes(pemBytes []byte) (*Certificate, error) {
block, _ := pem.Decode(pemBytes)
if block == nil {
return nil, fmt.Errorf("Unable to decode PEM encoded certificate")
}
return bytesToCert(block.Bytes)
}
// LoadCertificateFromX509 loads a Certificate from an x509.Certificate
func LoadCertificateFromX509(cert *x509.Certificate) (*Certificate, error) {
pemBytes := pem.EncodeToMemory(&pem.Block{
Type: "CERTIFICATE",
Headers: nil,
Bytes: cert.Raw,
})
return LoadCertificateFromPEMBytes(pemBytes)
}
// X509 returns the x509 certificate underlying this Certificate
func (cert *Certificate) X509() *x509.Certificate {
return cert.cert
}
// PEMEncoded encodes the Certificate in PEM
func (cert *Certificate) PEMEncoded() (pemBytes []byte) {
return pem.EncodeToMemory(cert.pemBlock())
}
// WriteToFile writes the PEM-encoded Certificate to a file.
func (cert *Certificate) WriteToFile(filename string) (err error) {
certOut, err := os.Create(filename)
if err != nil {
return fmt.Errorf("Failed to open %s for writing: %s", filename, err)
}
defer func() {
if err := certOut.Close(); err != nil {
logger.Printf("Unable to close file: %v", err)
}
}()
return pem.Encode(certOut, cert.pemBlock())
}
func (cert *Certificate) WriteToTempFile() (name string, err error) {
// Create a temp file containing the certificate
tempFile, err := ioutil.TempFile("", "tempCert")
if err != nil {
return "", fmt.Errorf("Unable to create temp file: %s", err)
}
name = tempFile.Name()
err = cert.WriteToFile(name)
if err != nil {
return "", fmt.Errorf("Unable to save certificate to temp file: %s", err)
}
return
}
// WriteToDERFile writes the DER-encoded Certificate to a file.
func (cert *Certificate) WriteToDERFile(filename string) (err error) {
certOut, err := os.Create(filename)
if err != nil {
return fmt.Errorf("Failed to open %s for writing: %s", filename, err)
}
defer func() {
if err := certOut.Close(); err != nil {
logger.Printf("Unable to close file: %v", err)
}
}()
_, err = certOut.Write(cert.derBytes)
return err
}
// PoolContainingCert creates a pool containing this cert.
func (cert *Certificate) PoolContainingCert() *x509.CertPool {
pool := x509.NewCertPool()
pool.AddCert(cert.cert)
return pool
}
// PoolContainingCerts constructs a CertPool containing all of the given certs
// (PEM encoded).
func PoolContainingCerts(certs ...string) (*x509.CertPool, error) {
pool := x509.NewCertPool()
for _, cert := range certs {
c, err := LoadCertificateFromPEMBytes([]byte(cert))
if err != nil {
return nil, err
}
pool.AddCert(c.cert)
}
return pool, nil
}
func (cert *Certificate) ExpiresBefore(time time.Time) bool {
return cert.cert.NotAfter.Before(time)
}
func bytesToCert(derBytes []byte) (*Certificate, error) {
cert, err := x509.ParseCertificate(derBytes)
if err != nil {
return nil, err
}
return &Certificate{cert, derBytes}, nil
}
func (cert *Certificate) pemBlock() *pem.Block {
return &pem.Block{Type: PEM_HEADER_CERTIFICATE, Bytes: cert.derBytes}
}