/src/boringssl/crypto/evp/p_ed25519.cc
Line | Count | Source |
1 | | // Copyright 2017 The BoringSSL Authors |
2 | | // |
3 | | // Licensed under the Apache License, Version 2.0 (the "License"); |
4 | | // you may not use this file except in compliance with the License. |
5 | | // You may obtain a copy of the License at |
6 | | // |
7 | | // https://www.apache.org/licenses/LICENSE-2.0 |
8 | | // |
9 | | // Unless required by applicable law or agreed to in writing, software |
10 | | // distributed under the License is distributed on an "AS IS" BASIS, |
11 | | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 | | // See the License for the specific language governing permissions and |
13 | | // limitations under the License. |
14 | | |
15 | | #include <openssl/evp.h> |
16 | | |
17 | | #include <openssl/bytestring.h> |
18 | | #include <openssl/curve25519.h> |
19 | | #include <openssl/err.h> |
20 | | #include <openssl/mem.h> |
21 | | |
22 | | #include "../internal.h" |
23 | | #include "internal.h" |
24 | | |
25 | | namespace { |
26 | | |
27 | | struct ED25519_KEY { |
28 | | // key is the concatenation of the private seed and public key. It is stored |
29 | | // as a single 64-bit array to allow passing to |ED25519_sign|. If |
30 | | // |has_private| is false, the first 32 bytes are uninitialized and the public |
31 | | // key is in the last 32 bytes. |
32 | | uint8_t key[64]; |
33 | | bool has_private; |
34 | | }; |
35 | | |
36 | | extern const EVP_PKEY_ASN1_METHOD ed25519_asn1_meth; |
37 | | |
38 | 266 | #define ED25519_PUBLIC_KEY_OFFSET 32 |
39 | | |
40 | 286 | static void ed25519_free(EVP_PKEY *pkey) { |
41 | 286 | OPENSSL_free(pkey->pkey); |
42 | 286 | pkey->pkey = nullptr; |
43 | 286 | } |
44 | | |
45 | 80 | static int ed25519_set_priv_raw(EVP_PKEY *pkey, const uint8_t *in, size_t len) { |
46 | 80 | if (len != 32) { |
47 | 51 | OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR); |
48 | 51 | return 0; |
49 | 51 | } |
50 | | |
51 | 29 | ED25519_KEY *key = |
52 | 29 | reinterpret_cast<ED25519_KEY *>(OPENSSL_malloc(sizeof(ED25519_KEY))); |
53 | 29 | if (key == nullptr) { |
54 | 0 | return 0; |
55 | 0 | } |
56 | | |
57 | | // The RFC 8032 encoding stores only the 32-byte seed, so we must recover the |
58 | | // full representation which we use from it. |
59 | 29 | uint8_t pubkey_unused[32]; |
60 | 29 | ED25519_keypair_from_seed(pubkey_unused, key->key, in); |
61 | 29 | key->has_private = true; |
62 | 29 | evp_pkey_set0(pkey, &ed25519_asn1_meth, key); |
63 | 29 | return 1; |
64 | 29 | } |
65 | | |
66 | 314 | static int ed25519_set_pub_raw(EVP_PKEY *pkey, const uint8_t *in, size_t len) { |
67 | 314 | if (len != 32) { |
68 | 57 | OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR); |
69 | 57 | return 0; |
70 | 57 | } |
71 | | |
72 | 257 | ED25519_KEY *key = |
73 | 257 | reinterpret_cast<ED25519_KEY *>(OPENSSL_malloc(sizeof(ED25519_KEY))); |
74 | 257 | if (key == nullptr) { |
75 | 0 | return 0; |
76 | 0 | } |
77 | | |
78 | 257 | OPENSSL_memcpy(key->key + ED25519_PUBLIC_KEY_OFFSET, in, 32); |
79 | 257 | key->has_private = false; |
80 | 257 | evp_pkey_set0(pkey, &ed25519_asn1_meth, key); |
81 | 257 | return 1; |
82 | 257 | } |
83 | | |
84 | | static int ed25519_get_priv_raw(const EVP_PKEY *pkey, uint8_t *out, |
85 | 0 | size_t *out_len) { |
86 | 0 | const ED25519_KEY *key = reinterpret_cast<const ED25519_KEY *>(pkey->pkey); |
87 | 0 | if (!key->has_private) { |
88 | 0 | OPENSSL_PUT_ERROR(EVP, EVP_R_NOT_A_PRIVATE_KEY); |
89 | 0 | return 0; |
90 | 0 | } |
91 | | |
92 | 0 | if (out == nullptr) { |
93 | 0 | *out_len = 32; |
94 | 0 | return 1; |
95 | 0 | } |
96 | | |
97 | 0 | if (*out_len < 32) { |
98 | 0 | OPENSSL_PUT_ERROR(EVP, EVP_R_BUFFER_TOO_SMALL); |
99 | 0 | return 0; |
100 | 0 | } |
101 | | |
102 | | // The raw private key format is the first 32 bytes of the private key. |
103 | 0 | OPENSSL_memcpy(out, key->key, 32); |
104 | 0 | *out_len = 32; |
105 | 0 | return 1; |
106 | 0 | } |
107 | | |
108 | | static int ed25519_get_pub_raw(const EVP_PKEY *pkey, uint8_t *out, |
109 | 0 | size_t *out_len) { |
110 | 0 | const ED25519_KEY *key = reinterpret_cast<const ED25519_KEY *>(pkey->pkey); |
111 | 0 | if (out == nullptr) { |
112 | 0 | *out_len = 32; |
113 | 0 | return 1; |
114 | 0 | } |
115 | | |
116 | 0 | if (*out_len < 32) { |
117 | 0 | OPENSSL_PUT_ERROR(EVP, EVP_R_BUFFER_TOO_SMALL); |
118 | 0 | return 0; |
119 | 0 | } |
120 | | |
121 | 0 | OPENSSL_memcpy(out, key->key + ED25519_PUBLIC_KEY_OFFSET, 32); |
122 | 0 | *out_len = 32; |
123 | 0 | return 1; |
124 | 0 | } |
125 | | |
126 | | static evp_decode_result_t ed25519_pub_decode(const EVP_PKEY_ALG *alg, |
127 | | EVP_PKEY *out, CBS *params, |
128 | 356 | CBS *key) { |
129 | | // See RFC 8410, section 4. |
130 | | |
131 | | // The parameters must be omitted. Public keys have length 32. |
132 | 356 | if (CBS_len(params) != 0) { |
133 | 42 | OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR); |
134 | 42 | return evp_decode_error; |
135 | 42 | } |
136 | | |
137 | 314 | return ed25519_set_pub_raw(out, CBS_data(key), CBS_len(key)) |
138 | 314 | ? evp_decode_ok |
139 | 314 | : evp_decode_error; |
140 | 356 | } |
141 | | |
142 | 9 | static int ed25519_pub_encode(CBB *out, const EVP_PKEY *pkey) { |
143 | 9 | const ED25519_KEY *key = reinterpret_cast<const ED25519_KEY *>(pkey->pkey); |
144 | | |
145 | | // See RFC 8410, section 4. |
146 | 9 | CBB spki, algorithm, key_bitstring; |
147 | 9 | if (!CBB_add_asn1(out, &spki, CBS_ASN1_SEQUENCE) || |
148 | 9 | !CBB_add_asn1(&spki, &algorithm, CBS_ASN1_SEQUENCE) || |
149 | 9 | !CBB_add_asn1_element(&algorithm, CBS_ASN1_OBJECT, ed25519_asn1_meth.oid, |
150 | 9 | ed25519_asn1_meth.oid_len) || |
151 | 9 | !CBB_add_asn1(&spki, &key_bitstring, CBS_ASN1_BITSTRING) || |
152 | 9 | !CBB_add_u8(&key_bitstring, 0 /* padding */) || |
153 | 9 | !CBB_add_bytes(&key_bitstring, key->key + ED25519_PUBLIC_KEY_OFFSET, |
154 | 9 | 32) || |
155 | 9 | !CBB_flush(out)) { |
156 | 0 | OPENSSL_PUT_ERROR(EVP, EVP_R_ENCODE_ERROR); |
157 | 0 | return 0; |
158 | 0 | } |
159 | | |
160 | 9 | return 1; |
161 | 9 | } |
162 | | |
163 | 0 | static int ed25519_pub_cmp(const EVP_PKEY *a, const EVP_PKEY *b) { |
164 | 0 | const ED25519_KEY *a_key = reinterpret_cast<const ED25519_KEY *>(a->pkey); |
165 | 0 | const ED25519_KEY *b_key = reinterpret_cast<const ED25519_KEY *>(b->pkey); |
166 | 0 | return OPENSSL_memcmp(a_key->key + ED25519_PUBLIC_KEY_OFFSET, |
167 | 0 | b_key->key + ED25519_PUBLIC_KEY_OFFSET, 32) == 0; |
168 | 0 | } |
169 | | |
170 | | static evp_decode_result_t ed25519_priv_decode(const EVP_PKEY_ALG *alg, |
171 | | EVP_PKEY *out, CBS *params, |
172 | 123 | CBS *key) { |
173 | | // See RFC 8410, section 7. |
174 | | |
175 | | // Parameters must be empty. The key is a 32-byte value wrapped in an extra |
176 | | // OCTET STRING layer. |
177 | 123 | CBS inner; |
178 | 123 | if (CBS_len(params) != 0 || |
179 | 114 | !CBS_get_asn1(key, &inner, CBS_ASN1_OCTETSTRING) || CBS_len(key) != 0) { |
180 | 43 | OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR); |
181 | 43 | return evp_decode_error; |
182 | 43 | } |
183 | | |
184 | 80 | return ed25519_set_priv_raw(out, CBS_data(&inner), CBS_len(&inner)) |
185 | 80 | ? evp_decode_ok |
186 | 80 | : evp_decode_error; |
187 | 123 | } |
188 | | |
189 | 23 | static int ed25519_priv_encode(CBB *out, const EVP_PKEY *pkey) { |
190 | 23 | const ED25519_KEY *key = reinterpret_cast<const ED25519_KEY *>(pkey->pkey); |
191 | 23 | if (!key->has_private) { |
192 | 0 | OPENSSL_PUT_ERROR(EVP, EVP_R_NOT_A_PRIVATE_KEY); |
193 | 0 | return 0; |
194 | 0 | } |
195 | | |
196 | | // See RFC 8410, section 7. |
197 | 23 | CBB pkcs8, algorithm, private_key, inner; |
198 | 23 | if (!CBB_add_asn1(out, &pkcs8, CBS_ASN1_SEQUENCE) || |
199 | 23 | !CBB_add_asn1_uint64(&pkcs8, 0 /* version */) || |
200 | 23 | !CBB_add_asn1(&pkcs8, &algorithm, CBS_ASN1_SEQUENCE) || |
201 | 23 | !CBB_add_asn1_element(&algorithm, CBS_ASN1_OBJECT, ed25519_asn1_meth.oid, |
202 | 23 | ed25519_asn1_meth.oid_len) || |
203 | 23 | !CBB_add_asn1(&pkcs8, &private_key, CBS_ASN1_OCTETSTRING) || |
204 | 23 | !CBB_add_asn1(&private_key, &inner, CBS_ASN1_OCTETSTRING) || |
205 | | // The PKCS#8 encoding stores only the 32-byte seed which is the first 32 |
206 | | // bytes of the private key. |
207 | 23 | !CBB_add_bytes(&inner, key->key, 32) || // |
208 | 23 | !CBB_flush(out)) { |
209 | 0 | OPENSSL_PUT_ERROR(EVP, EVP_R_ENCODE_ERROR); |
210 | 0 | return 0; |
211 | 0 | } |
212 | | |
213 | 23 | return 1; |
214 | 23 | } |
215 | | |
216 | 0 | static int ed25519_size(const EVP_PKEY *pkey) { return 64; } |
217 | | |
218 | 0 | static int ed25519_bits(const EVP_PKEY *pkey) { return 253; } |
219 | | |
220 | | const EVP_PKEY_ASN1_METHOD ed25519_asn1_meth = { |
221 | | EVP_PKEY_ED25519, |
222 | | {0x2b, 0x65, 0x70}, |
223 | | 3, |
224 | | &ed25519_pkey_meth, |
225 | | ed25519_pub_decode, |
226 | | ed25519_pub_encode, |
227 | | ed25519_pub_cmp, |
228 | | ed25519_priv_decode, |
229 | | ed25519_priv_encode, |
230 | | ed25519_set_priv_raw, |
231 | | /*set_priv_seed=*/nullptr, |
232 | | ed25519_set_pub_raw, |
233 | | ed25519_get_priv_raw, |
234 | | /*get_priv_seed=*/nullptr, |
235 | | ed25519_get_pub_raw, |
236 | | /*set1_tls_encodedpoint=*/nullptr, |
237 | | /*get1_tls_encodedpoint=*/nullptr, |
238 | | /*pkey_opaque=*/nullptr, |
239 | | ed25519_size, |
240 | | ed25519_bits, |
241 | | /*param_missing=*/nullptr, |
242 | | /*param_copy=*/nullptr, |
243 | | /*param_cmp=*/nullptr, |
244 | | ed25519_free, |
245 | | }; |
246 | | |
247 | | // Ed25519 has no parameters to copy. |
248 | 0 | static int pkey_ed25519_copy(EVP_PKEY_CTX *dst, EVP_PKEY_CTX *src) { return 1; } |
249 | | |
250 | 0 | static int pkey_ed25519_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey) { |
251 | 0 | ED25519_KEY *key = |
252 | 0 | reinterpret_cast<ED25519_KEY *>(OPENSSL_malloc(sizeof(ED25519_KEY))); |
253 | 0 | if (key == nullptr) { |
254 | 0 | return 0; |
255 | 0 | } |
256 | | |
257 | 0 | uint8_t pubkey_unused[32]; |
258 | 0 | ED25519_keypair(pubkey_unused, key->key); |
259 | 0 | key->has_private = true; |
260 | |
|
261 | 0 | evp_pkey_set0(pkey, &ed25519_asn1_meth, key); |
262 | 0 | return 1; |
263 | 0 | } |
264 | | |
265 | | static int pkey_ed25519_sign_message(EVP_PKEY_CTX *ctx, uint8_t *sig, |
266 | | size_t *siglen, const uint8_t *tbs, |
267 | 0 | size_t tbslen) { |
268 | 0 | const ED25519_KEY *key = |
269 | 0 | reinterpret_cast<const ED25519_KEY *>(ctx->pkey->pkey); |
270 | 0 | if (!key->has_private) { |
271 | 0 | OPENSSL_PUT_ERROR(EVP, EVP_R_NOT_A_PRIVATE_KEY); |
272 | 0 | return 0; |
273 | 0 | } |
274 | | |
275 | 0 | if (sig == nullptr) { |
276 | 0 | *siglen = 64; |
277 | 0 | return 1; |
278 | 0 | } |
279 | | |
280 | 0 | if (*siglen < 64) { |
281 | 0 | OPENSSL_PUT_ERROR(EVP, EVP_R_BUFFER_TOO_SMALL); |
282 | 0 | return 0; |
283 | 0 | } |
284 | | |
285 | 0 | if (!ED25519_sign(sig, tbs, tbslen, key->key)) { |
286 | 0 | return 0; |
287 | 0 | } |
288 | | |
289 | 0 | *siglen = 64; |
290 | 0 | return 1; |
291 | 0 | } |
292 | | |
293 | | static int pkey_ed25519_verify_message(EVP_PKEY_CTX *ctx, const uint8_t *sig, |
294 | | size_t siglen, const uint8_t *tbs, |
295 | 0 | size_t tbslen) { |
296 | 0 | const ED25519_KEY *key = |
297 | 0 | reinterpret_cast<const ED25519_KEY *>(ctx->pkey->pkey); |
298 | 0 | if (siglen != 64 || |
299 | 0 | !ED25519_verify(tbs, tbslen, sig, key->key + ED25519_PUBLIC_KEY_OFFSET)) { |
300 | 0 | OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_SIGNATURE); |
301 | 0 | return 0; |
302 | 0 | } |
303 | | |
304 | 0 | return 1; |
305 | 0 | } |
306 | | |
307 | | } // namespace |
308 | | |
309 | | const EVP_PKEY_CTX_METHOD ed25519_pkey_meth = { |
310 | | /*pkey_id=*/EVP_PKEY_ED25519, |
311 | | /*init=*/nullptr, |
312 | | /*copy=*/pkey_ed25519_copy, |
313 | | /*cleanup=*/nullptr, |
314 | | /*keygen=*/pkey_ed25519_keygen, |
315 | | /*sign=*/nullptr, |
316 | | /*sign_message=*/pkey_ed25519_sign_message, |
317 | | /*verify=*/nullptr, |
318 | | /*verify_message=*/pkey_ed25519_verify_message, |
319 | | /*verify_recover=*/nullptr, |
320 | | /*encrypt=*/nullptr, |
321 | | /*decrypt=*/nullptr, |
322 | | /*derive=*/nullptr, |
323 | | /*paramgen=*/nullptr, |
324 | | /*ctrl=*/nullptr, |
325 | | }; |
326 | | |
327 | 291k | const EVP_PKEY_ALG *EVP_pkey_ed25519(void) { |
328 | 291k | static const EVP_PKEY_ALG kAlg = {&ed25519_asn1_meth}; |
329 | 291k | return &kAlg; |
330 | 291k | } |