-
Notifications
You must be signed in to change notification settings - Fork 0
/
utils.go
136 lines (125 loc) · 3.84 KB
/
utils.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
package smolcert
import (
"crypto/rand"
"time"
"golang.org/x/crypto/ed25519"
)
func ensureExtension(extensions []Extension, extp Extension) []Extension {
found := false
for _, ext := range extensions {
if ext.OID == extp.OID {
ext.Critical = extp.Critical
ext.Value = extp.Value
found = true
break
}
}
if !found {
extensions = append(extensions, extp)
}
return extensions
}
// SignCertificate takes a certificate, removes the signature and creates a new signature with the given key
func SignCertificate(cert *Certificate, priv ed25519.PrivateKey) (*Certificate, error) {
cert.Signature = nil
certBytes, err := cert.Bytes()
if err != nil {
return nil, err
}
cert.Signature = ed25519.Sign(priv, certBytes)
return cert, nil
}
// ClientCertificate is a convenience function to create a valid client certificate
func ClientCertificate(subject string, serialNumber uint64, notBefore, notAfter time.Time,
extensions []Extension, rootKey ed25519.PrivateKey, issuer string) (*Certificate, ed25519.PrivateKey, error) {
extensions = ensureExtension(extensions, Extension{
OID: OIDKeyUsage,
Critical: true,
Value: KeyUsageClientIdentification.ToBytes(),
})
return SignedCertificate(subject, serialNumber, notBefore, notAfter, extensions, rootKey, issuer)
}
// ServerCertificate is a convenience function to create a valid server certificate
func ServerCertificate(subject string, serialNumber uint64, notBefore, notAfter time.Time,
extensions []Extension, rootKey ed25519.PrivateKey, issuer string) (*Certificate, ed25519.PrivateKey, error) {
extensions = ensureExtension(extensions, Extension{
OID: OIDKeyUsage,
Critical: true,
Value: KeyUsageServerIdentification.ToBytes(),
})
return SignedCertificate(subject, serialNumber, notBefore, notAfter, extensions, rootKey, issuer)
}
// SignedCertificate creates a new certificate signed with the specified rooKey and issuer.
func SignedCertificate(subject string, serialNumber uint64, notBefore, notAfter time.Time,
extensions []Extension, rootKey ed25519.PrivateKey, issuer string) (*Certificate, ed25519.PrivateKey, error) {
validity := &Validity{}
if extensions == nil {
extensions = []Extension{}
}
if notBefore.IsZero() {
validity.NotBefore = ZeroTime
} else {
validity.NotBefore = NewTime(notBefore)
}
if notAfter.IsZero() {
validity.NotAfter = ZeroTime
} else {
validity.NotAfter = NewTime(notAfter)
}
pub, priv, err := ed25519.GenerateKey(rand.Reader)
if err != nil {
return nil, ed25519.PrivateKey{}, err
}
cert := &Certificate{
Version: smolcertVersion,
SerialNumber: serialNumber,
Issuer: issuer,
Validity: validity,
Subject: subject,
PubKey: pub,
Extensions: extensions,
Signature: nil,
}
cert, err = SignCertificate(cert, rootKey)
return cert, priv, err
}
// SelfSignedCertificate is a simple function to generate a self signed certificate
func SelfSignedCertificate(subject string,
notBefore, notAfter time.Time,
extensions []Extension) (*Certificate, ed25519.PrivateKey, error) {
validity := &Validity{}
if extensions == nil {
extensions = []Extension{}
}
extensions = ensureExtension(extensions, Extension{
OID: OIDKeyUsage,
Critical: true,
Value: KeyUsageSignCert.ToBytes(),
})
if notBefore.IsZero() {
validity.NotBefore = ZeroTime
} else {
validity.NotBefore = NewTime(notBefore)
}
if notAfter.IsZero() {
validity.NotAfter = ZeroTime
} else {
validity.NotAfter = NewTime(notAfter)
}
pub, priv, err := ed25519.GenerateKey(rand.Reader)
if err != nil {
return nil, ed25519.PrivateKey{}, err
}
cert := &Certificate{
Version: smolcertVersion,
SerialNumber: 1,
Issuer: subject,
Validity: validity,
Subject: subject,
PubKey: pub,
Extensions: extensions,
Signature: nil,
}
cert, err = SignCertificate(cert, priv)
return cert, priv, err
}