-
Notifications
You must be signed in to change notification settings - Fork 136
/
pki.go
182 lines (160 loc) · 4.29 KB
/
pki.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
package pki
import (
"crypto/x509/pkix"
"encoding/asn1"
"encoding/pem"
"errors"
"strings"
"github.com/cloudflare/circl/sign"
"github.com/cloudflare/circl/sign/schemes"
)
var (
allSchemesByOID map[string]sign.Scheme
allSchemesByTLS map[uint]sign.Scheme
)
type pkixPrivKey struct {
Version int
Algorithm pkix.AlgorithmIdentifier
PrivateKey []byte
}
func init() {
allSchemesByOID = make(map[string]sign.Scheme)
allSchemesByTLS = make(map[uint]sign.Scheme)
for _, scheme := range schemes.All() {
if cert, ok := scheme.(CertificateScheme); ok {
allSchemesByOID[cert.Oid().String()] = scheme
}
if tlsScheme, ok := scheme.(TLSScheme); ok {
allSchemesByTLS[tlsScheme.TLSIdentifier()] = scheme
}
}
}
func SchemeByOid(oid asn1.ObjectIdentifier) sign.Scheme { return allSchemesByOID[oid.String()] }
func SchemeByTLSID(id uint) sign.Scheme { return allSchemesByTLS[id] }
// Additional methods when the signature scheme is supported in X509.
type CertificateScheme interface {
// Return the appropriate OIDs for this instance. It is implicitly
// assumed that the encoding is simple: e.g. uses the same OID for
// signature and public key like Ed25519.
Oid() asn1.ObjectIdentifier
}
// Additional methods when the signature scheme is supported in TLS.
type TLSScheme interface {
TLSIdentifier() uint
}
func UnmarshalPEMPublicKey(data []byte) (sign.PublicKey, error) {
block, rest := pem.Decode(data)
if len(rest) != 0 {
return nil, errors.New("trailing data")
}
if !strings.HasSuffix(block.Type, "PUBLIC KEY") {
return nil, errors.New("pem block type is not public key")
}
return UnmarshalPKIXPublicKey(block.Bytes)
}
func UnmarshalPKIXPublicKey(data []byte) (sign.PublicKey, error) {
var pkix struct {
Raw asn1.RawContent
Algorithm pkix.AlgorithmIdentifier
PublicKey asn1.BitString
}
if rest, err := asn1.Unmarshal(data, &pkix); err != nil {
return nil, err
} else if len(rest) != 0 {
return nil, errors.New("trailing data")
}
scheme := SchemeByOid(pkix.Algorithm.Algorithm)
if scheme == nil {
return nil, errors.New("unsupported public key algorithm")
}
return scheme.UnmarshalBinaryPublicKey(pkix.PublicKey.RightAlign())
}
func UnmarshalPEMPrivateKey(data []byte) (sign.PrivateKey, error) {
block, rest := pem.Decode(data)
if len(rest) != 0 {
return nil, errors.New("trailing")
}
if !strings.HasSuffix(block.Type, "PRIVATE KEY") {
return nil, errors.New("pem block type is not private key")
}
return UnmarshalPKIXPrivateKey(block.Bytes)
}
func UnmarshalPKIXPrivateKey(data []byte) (sign.PrivateKey, error) {
var pkix pkixPrivKey
if rest, err := asn1.Unmarshal(data, &pkix); err != nil {
return nil, err
} else if len(rest) != 0 {
return nil, errors.New("trailing data")
}
scheme := SchemeByOid(pkix.Algorithm.Algorithm)
if scheme == nil {
return nil, errors.New("unsupported public key algorithm")
}
var sk []byte
if rest, err := asn1.Unmarshal(pkix.PrivateKey, &sk); err != nil {
return nil, err
} else if len(rest) > 0 {
return nil, errors.New("trailing data")
}
return scheme.UnmarshalBinaryPrivateKey(sk)
}
func MarshalPEMPublicKey(pk sign.PublicKey) ([]byte, error) {
data, err := MarshalPKIXPublicKey(pk)
if err != nil {
return nil, err
}
str := pem.EncodeToMemory(&pem.Block{
Type: "PUBLIC KEY",
Bytes: data,
})
return str, nil
}
func MarshalPKIXPublicKey(pk sign.PublicKey) ([]byte, error) {
data, err := pk.MarshalBinary()
if err != nil {
return nil, err
}
scheme := pk.Scheme()
return asn1.Marshal(struct {
pkix.AlgorithmIdentifier
asn1.BitString
}{
pkix.AlgorithmIdentifier{
Algorithm: scheme.(CertificateScheme).Oid(),
},
asn1.BitString{
Bytes: data,
BitLength: len(data) * 8,
},
})
}
func MarshalPEMPrivateKey(sk sign.PrivateKey) ([]byte, error) {
data, err := MarshalPKIXPrivateKey(sk)
if err != nil {
return nil, err
}
str := pem.EncodeToMemory(&pem.Block{
Type: sk.Scheme().Name() + " PRIVATE KEY",
Bytes: data,
},
)
return str, nil
}
func MarshalPKIXPrivateKey(sk sign.PrivateKey) ([]byte, error) {
data, err := sk.MarshalBinary()
if err != nil {
return nil, err
}
data, err = asn1.Marshal(data)
if err != nil {
return nil, err
}
scheme := sk.Scheme()
return asn1.Marshal(pkixPrivKey{
0,
pkix.AlgorithmIdentifier{
Algorithm: scheme.(CertificateScheme).Oid(),
},
data,
})
}