1 package pki
2
3 import (
4 "crypto/x509/pkix"
5 "encoding/asn1"
6 "encoding/pem"
7 "errors"
8 "strings"
9
10 "github.com/cloudflare/circl/sign"
11 "github.com/cloudflare/circl/sign/schemes"
12 )
13
14 var (
15 allSchemesByOID map[string]sign.Scheme
16 allSchemesByTLS map[uint]sign.Scheme
17 )
18
19 type pkixPrivKey struct {
20 Version int
21 Algorithm pkix.AlgorithmIdentifier
22 PrivateKey []byte
23 }
24
25 func init() {
26 allSchemesByOID = make(map[string]sign.Scheme)
27 allSchemesByTLS = make(map[uint]sign.Scheme)
28 for _, scheme := range schemes.All() {
29 if cert, ok := scheme.(CertificateScheme); ok {
30 allSchemesByOID[cert.Oid().String()] = scheme
31 }
32 if tlsScheme, ok := scheme.(TLSScheme); ok {
33 allSchemesByTLS[tlsScheme.TLSIdentifier()] = scheme
34 }
35 }
36 }
37
38 func SchemeByOid(oid asn1.ObjectIdentifier) sign.Scheme { return allSchemesByOID[oid.String()] }
39
40 func SchemeByTLSID(id uint) sign.Scheme { return allSchemesByTLS[id] }
41
42
43 type CertificateScheme interface {
44
45
46
47 Oid() asn1.ObjectIdentifier
48 }
49
50
51 type TLSScheme interface {
52 TLSIdentifier() uint
53 }
54
55 func UnmarshalPEMPublicKey(data []byte) (sign.PublicKey, error) {
56 block, rest := pem.Decode(data)
57 if len(rest) != 0 {
58 return nil, errors.New("trailing data")
59 }
60 if !strings.HasSuffix(block.Type, "PUBLIC KEY") {
61 return nil, errors.New("pem block type is not public key")
62 }
63
64 return UnmarshalPKIXPublicKey(block.Bytes)
65 }
66
67 func UnmarshalPKIXPublicKey(data []byte) (sign.PublicKey, error) {
68 var pkix struct {
69 Raw asn1.RawContent
70 Algorithm pkix.AlgorithmIdentifier
71 PublicKey asn1.BitString
72 }
73 if rest, err := asn1.Unmarshal(data, &pkix); err != nil {
74 return nil, err
75 } else if len(rest) != 0 {
76 return nil, errors.New("trailing data")
77 }
78 scheme := SchemeByOid(pkix.Algorithm.Algorithm)
79 if scheme == nil {
80 return nil, errors.New("unsupported public key algorithm")
81 }
82 return scheme.UnmarshalBinaryPublicKey(pkix.PublicKey.RightAlign())
83 }
84
85 func UnmarshalPEMPrivateKey(data []byte) (sign.PrivateKey, error) {
86 block, rest := pem.Decode(data)
87 if len(rest) != 0 {
88 return nil, errors.New("trailing")
89 }
90 if !strings.HasSuffix(block.Type, "PRIVATE KEY") {
91 return nil, errors.New("pem block type is not private key")
92 }
93
94 return UnmarshalPKIXPrivateKey(block.Bytes)
95 }
96
97 func UnmarshalPKIXPrivateKey(data []byte) (sign.PrivateKey, error) {
98 var pkix pkixPrivKey
99 if rest, err := asn1.Unmarshal(data, &pkix); err != nil {
100 return nil, err
101 } else if len(rest) != 0 {
102 return nil, errors.New("trailing data")
103 }
104 scheme := SchemeByOid(pkix.Algorithm.Algorithm)
105 if scheme == nil {
106 return nil, errors.New("unsupported public key algorithm")
107 }
108 var sk []byte
109 if rest, err := asn1.Unmarshal(pkix.PrivateKey, &sk); err != nil {
110 return nil, err
111 } else if len(rest) > 0 {
112 return nil, errors.New("trailing data")
113 }
114 return scheme.UnmarshalBinaryPrivateKey(sk)
115 }
116
117 func MarshalPEMPublicKey(pk sign.PublicKey) ([]byte, error) {
118 data, err := MarshalPKIXPublicKey(pk)
119 if err != nil {
120 return nil, err
121 }
122 str := pem.EncodeToMemory(&pem.Block{
123 Type: "PUBLIC KEY",
124 Bytes: data,
125 })
126 return str, nil
127 }
128
129 func MarshalPKIXPublicKey(pk sign.PublicKey) ([]byte, error) {
130 data, err := pk.MarshalBinary()
131 if err != nil {
132 return nil, err
133 }
134
135 scheme := pk.Scheme()
136 return asn1.Marshal(struct {
137 pkix.AlgorithmIdentifier
138 asn1.BitString
139 }{
140 pkix.AlgorithmIdentifier{
141 Algorithm: scheme.(CertificateScheme).Oid(),
142 },
143 asn1.BitString{
144 Bytes: data,
145 BitLength: len(data) * 8,
146 },
147 })
148 }
149
150 func MarshalPEMPrivateKey(sk sign.PrivateKey) ([]byte, error) {
151 data, err := MarshalPKIXPrivateKey(sk)
152 if err != nil {
153 return nil, err
154 }
155 str := pem.EncodeToMemory(&pem.Block{
156 Type: sk.Scheme().Name() + " PRIVATE KEY",
157 Bytes: data,
158 },
159 )
160 return str, nil
161 }
162
163 func MarshalPKIXPrivateKey(sk sign.PrivateKey) ([]byte, error) {
164 data, err := sk.MarshalBinary()
165 if err != nil {
166 return nil, err
167 }
168
169 data, err = asn1.Marshal(data)
170 if err != nil {
171 return nil, err
172 }
173
174 scheme := sk.Scheme()
175 return asn1.Marshal(pkixPrivKey{
176 0,
177 pkix.AlgorithmIdentifier{
178 Algorithm: scheme.(CertificateScheme).Oid(),
179 },
180 data,
181 })
182 }
183
View as plain text