-
Notifications
You must be signed in to change notification settings - Fork 7
/
x509.go
158 lines (131 loc) · 4.45 KB
/
x509.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
// Package utiltest provides testing helpers, for generating valid mock data like
// X509 certificates etc.
package utiltest
import (
"bytes"
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"crypto/x509/pkix"
"encoding/pem"
"fmt"
"math/big"
"testing"
"time"
)
const (
// certValidityDuration is how long certificate is valid from the moment of generation.
certValidityDuration = 1 * time.Hour
)
// PKI struct holds X509 certificate and belonging RSA private key in PEM format.
type PKI struct {
Certificate string
PrivateKey string
}
// GenerateX509Certificate generates random X.509 certificate and
// returns it as string in PEM format.
func GenerateX509Certificate(t *testing.T) string {
return GeneratePKI(t).Certificate
}
// GenerateRSAPrivateKey generates RSA private key and returns it
// as string in PEM format.
func GenerateRSAPrivateKey(t *testing.T) string {
return GeneratePKI(t).PrivateKey
}
// GeneratePKCS1PrivateKey generates RSA private key in PKCS1 format,
// PEM encoded.
func GeneratePKCS1PrivateKey(t *testing.T) string {
priv, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
t.Fatalf("Failed to generate RSA key: %v", err)
}
privBytes := x509.MarshalPKCS1PrivateKey(priv)
var key bytes.Buffer
if err := pem.Encode(&key, &pem.Block{Type: "RSA PRIVATE KEY", Bytes: privBytes}); err != nil {
t.Fatalf("Failed to write data to key.pem: %s", err)
}
return key.String()
}
// GenerateECPrivateKey generates EC private key, PEM encoded.
func GenerateECPrivateKey(t *testing.T) string {
priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
if err != nil {
t.Fatalf("Failed generating ECDSA key: %v", err)
}
privBytes, err := x509.MarshalECPrivateKey(priv)
if err != nil {
t.Fatalf("Failed serializing EC private key: %v", err)
}
var key bytes.Buffer
if err := pem.Encode(&key, &pem.Block{Type: "EC PRIVATE KEY", Bytes: privBytes}); err != nil {
t.Fatalf("Failed to write data to key.pem: %s", err)
}
return key.String()
}
// GeneratePKI generates PKI struct.
func GeneratePKI(t *testing.T) *PKI {
p, err := GeneratePKIErr()
if err != nil {
t.Fatalf("failed generating fake PKI: %v", err)
}
return p
}
// generateX509Certificate generates X.509 certificate in DER format using given RSA private key.
func generateX509Certificate(priv *rsa.PrivateKey) ([]byte, error) {
// Generate serial number for X.509 certificate.
serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
if err != nil {
return nil, fmt.Errorf("failed to generate serial number: %w", err)
}
template := x509.Certificate{
SerialNumber: serialNumber,
Subject: pkix.Name{
Organization: []string{"example"},
},
NotBefore: time.Now(),
NotAfter: time.Now().Add(certValidityDuration),
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
BasicConstraintsValid: true,
}
// Create X.509 certificate in DER format.
return x509.CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv)
}
// encodePKI converts RSA private key and X.509 certificate in DER format into PKI struct.
func encodePKI(priv *rsa.PrivateKey, pub []byte) (*PKI, error) {
// Encode private certificate into PEM format.
var cert bytes.Buffer
if err := pem.Encode(&cert, &pem.Block{Type: "CERTIFICATE", Bytes: pub}); err != nil {
return nil, fmt.Errorf("failed to write data to cert.pem: %w", err)
}
// Convert RSA private key into PKCS8 DER format.
privBytes, err := x509.MarshalPKCS8PrivateKey(priv)
if err != nil {
return nil, fmt.Errorf("unable to marshal private key: %w", err)
}
// Convert private key from PKCS8 DER format to PEM format.
var key bytes.Buffer
if err := pem.Encode(&key, &pem.Block{Type: "PRIVATE KEY", Bytes: privBytes}); err != nil {
return nil, fmt.Errorf("failed to write data to key.pem: %w", err)
}
return &PKI{
Certificate: cert.String(),
PrivateKey: key.String(),
}, nil
}
// GeneratePKIErr generates fake PKI X.509 key pair sutiable for tests.
func GeneratePKIErr() (*PKI, error) {
// Generate RSA private key.
priv, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
return nil, fmt.Errorf("failed to generate RSA key: %w", err)
}
derBytes, err := generateX509Certificate(priv)
if err != nil {
return nil, fmt.Errorf("failed to create X.509 certificate: %w", err)
}
return encodePKI(priv, derBytes)
}