/src/libressl/crypto/ec/ecx_methods.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* $OpenBSD: ecx_methods.c,v 1.14 2024/08/28 07:15:04 tb Exp $ */ |
2 | | /* |
3 | | * Copyright (c) 2022 Joel Sing <jsing@openbsd.org> |
4 | | * |
5 | | * Permission to use, copy, modify, and distribute this software for any |
6 | | * purpose with or without fee is hereby granted, provided that the above |
7 | | * copyright notice and this permission notice appear in all copies. |
8 | | * |
9 | | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
10 | | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
11 | | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
12 | | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
13 | | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
14 | | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
15 | | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
16 | | */ |
17 | | |
18 | | #include <string.h> |
19 | | |
20 | | #include <openssl/cms.h> |
21 | | #include <openssl/curve25519.h> |
22 | | #include <openssl/ec.h> |
23 | | #include <openssl/err.h> |
24 | | #include <openssl/evp.h> |
25 | | #include <openssl/x509.h> |
26 | | |
27 | | #include "asn1_local.h" |
28 | | #include "bytestring.h" |
29 | | #include "curve25519_internal.h" |
30 | | #include "evp_local.h" |
31 | | #include "x509_local.h" |
32 | | |
33 | | /* |
34 | | * EVP PKEY and PKEY ASN.1 methods Ed25519 and X25519. |
35 | | * |
36 | | * RFC 7748 - Elliptic Curves for Security. |
37 | | * RFC 8032 - Edwards-Curve Digital Signature Algorithm (EdDSA). |
38 | | */ |
39 | | |
40 | 0 | #define ED25519_BITS 253 |
41 | 0 | #define ED25519_SECURITY_BITS 128 |
42 | 0 | #define ED25519_SIG_SIZE 64 |
43 | | |
44 | 0 | #define X25519_BITS 253 |
45 | 0 | #define X25519_SECURITY_BITS 128 |
46 | | |
47 | | static int |
48 | | ecx_key_len(int nid) |
49 | 14 | { |
50 | 14 | switch (nid) { |
51 | 5 | case NID_ED25519: |
52 | 5 | return ED25519_KEYLEN; |
53 | 9 | case NID_X25519: |
54 | 9 | return X25519_KEYLEN; |
55 | 14 | } |
56 | | |
57 | 0 | return 0; |
58 | 14 | } |
59 | | |
60 | | static struct ecx_key_st * |
61 | | ecx_key_new(int nid) |
62 | 4 | { |
63 | 4 | struct ecx_key_st *ecx_key; |
64 | 4 | int key_len; |
65 | | |
66 | 4 | if ((key_len = ecx_key_len(nid)) == 0) |
67 | 0 | return NULL; |
68 | | |
69 | 4 | if ((ecx_key = calloc(1, sizeof(*ecx_key))) == NULL) |
70 | 0 | return NULL; |
71 | | |
72 | 4 | ecx_key->nid = nid; |
73 | 4 | ecx_key->key_len = key_len; |
74 | | |
75 | 4 | return ecx_key; |
76 | 4 | } |
77 | | |
78 | | static void |
79 | | ecx_key_clear(struct ecx_key_st *ecx_key) |
80 | 8 | { |
81 | 8 | freezero(ecx_key->priv_key, ecx_key->priv_key_len); |
82 | 8 | ecx_key->priv_key = NULL; |
83 | 8 | ecx_key->priv_key_len = 0; |
84 | | |
85 | 8 | freezero(ecx_key->pub_key, ecx_key->pub_key_len); |
86 | 8 | ecx_key->pub_key = NULL; |
87 | 8 | ecx_key->pub_key_len = 0; |
88 | 8 | } |
89 | | |
90 | | static void |
91 | | ecx_key_free(struct ecx_key_st *ecx_key) |
92 | 56 | { |
93 | 56 | if (ecx_key == NULL) |
94 | 52 | return; |
95 | | |
96 | 4 | ecx_key_clear(ecx_key); |
97 | | |
98 | 4 | freezero(ecx_key, sizeof(*ecx_key)); |
99 | 4 | } |
100 | | |
101 | | static int |
102 | | ecx_key_generate(struct ecx_key_st *ecx_key) |
103 | 0 | { |
104 | 0 | uint8_t *pub_key = NULL, *priv_key = NULL; |
105 | 0 | int ret = 0; |
106 | |
|
107 | 0 | ecx_key_clear(ecx_key); |
108 | |
|
109 | 0 | if ((pub_key = calloc(1, ecx_key->key_len)) == NULL) |
110 | 0 | goto err; |
111 | 0 | if ((priv_key = calloc(1, ecx_key->key_len)) == NULL) |
112 | 0 | goto err; |
113 | | |
114 | 0 | switch (ecx_key->nid) { |
115 | 0 | case NID_ED25519: |
116 | 0 | ED25519_keypair(pub_key, priv_key); |
117 | 0 | break; |
118 | 0 | case NID_X25519: |
119 | 0 | X25519_keypair(pub_key, priv_key); |
120 | 0 | break; |
121 | 0 | default: |
122 | 0 | goto err; |
123 | 0 | } |
124 | | |
125 | 0 | ecx_key->priv_key = priv_key; |
126 | 0 | ecx_key->priv_key_len = ecx_key->key_len; |
127 | 0 | priv_key = NULL; |
128 | |
|
129 | 0 | ecx_key->pub_key = pub_key; |
130 | 0 | ecx_key->pub_key_len = ecx_key->key_len; |
131 | 0 | pub_key = NULL; |
132 | |
|
133 | 0 | ret = 1; |
134 | |
|
135 | 0 | err: |
136 | 0 | freezero(pub_key, ecx_key->key_len); |
137 | 0 | freezero(priv_key, ecx_key->key_len); |
138 | |
|
139 | 0 | return ret; |
140 | 0 | } |
141 | | |
142 | | static int |
143 | | ecx_key_set_priv(struct ecx_key_st *ecx_key, const uint8_t *priv_key, |
144 | | size_t priv_key_len) |
145 | 2 | { |
146 | 2 | uint8_t *pub_key = NULL; |
147 | 2 | CBS cbs; |
148 | | |
149 | 2 | ecx_key_clear(ecx_key); |
150 | | |
151 | 2 | if (priv_key_len != ecx_key->key_len) |
152 | 0 | goto err; |
153 | | |
154 | 2 | if ((pub_key = calloc(1, ecx_key->key_len)) == NULL) |
155 | 0 | goto err; |
156 | | |
157 | 2 | switch (ecx_key->nid) { |
158 | 1 | case NID_ED25519: |
159 | 1 | ED25519_public_from_private(pub_key, priv_key); |
160 | 1 | break; |
161 | 1 | case NID_X25519: |
162 | 1 | X25519_public_from_private(pub_key, priv_key); |
163 | 1 | break; |
164 | 0 | default: |
165 | 0 | goto err; |
166 | 2 | } |
167 | | |
168 | 2 | CBS_init(&cbs, priv_key, priv_key_len); |
169 | 2 | if (!CBS_stow(&cbs, &ecx_key->priv_key, &ecx_key->priv_key_len)) |
170 | 0 | goto err; |
171 | | |
172 | 2 | ecx_key->pub_key = pub_key; |
173 | 2 | ecx_key->pub_key_len = ecx_key->key_len; |
174 | 2 | pub_key = NULL; |
175 | | |
176 | 2 | err: |
177 | 2 | freezero(pub_key, ecx_key->key_len); |
178 | | |
179 | 2 | return 1; |
180 | 2 | } |
181 | | |
182 | | static int |
183 | | ecx_key_set_pub(struct ecx_key_st *ecx_key, const uint8_t *pub_key, |
184 | | size_t pub_key_len) |
185 | 2 | { |
186 | 2 | CBS cbs; |
187 | | |
188 | 2 | ecx_key_clear(ecx_key); |
189 | | |
190 | 2 | if (pub_key_len != ecx_key->key_len) |
191 | 0 | return 0; |
192 | | |
193 | 2 | CBS_init(&cbs, pub_key, pub_key_len); |
194 | 2 | if (!CBS_stow(&cbs, &ecx_key->pub_key, &ecx_key->pub_key_len)) |
195 | 0 | return 0; |
196 | | |
197 | 2 | return 1; |
198 | 2 | } |
199 | | |
200 | | static int |
201 | | ecx_pub_decode(EVP_PKEY *pkey, X509_PUBKEY *xpubkey) |
202 | 16 | { |
203 | 16 | struct ecx_key_st *ecx_key = NULL; |
204 | 16 | X509_ALGOR *algor; |
205 | 16 | int algor_type; |
206 | 16 | const uint8_t *param; |
207 | 16 | int param_len; |
208 | 16 | int ret = 0; |
209 | | |
210 | 16 | if (!X509_PUBKEY_get0_param(NULL, ¶m, ¶m_len, &algor, xpubkey)) |
211 | 0 | goto err; |
212 | | |
213 | | /* Ensure that parameters have not been specified in the encoding. */ |
214 | 16 | if (algor != NULL) { |
215 | 16 | X509_ALGOR_get0(NULL, &algor_type, NULL, algor); |
216 | 16 | if (algor_type != V_ASN1_UNDEF) { |
217 | 9 | ECerror(EC_R_INVALID_ENCODING); |
218 | 9 | goto err; |
219 | 9 | } |
220 | 16 | } |
221 | | |
222 | 7 | if (param == NULL || param_len != ecx_key_len(pkey->ameth->pkey_id)) { |
223 | 5 | ECerror(EC_R_INVALID_ENCODING); |
224 | 5 | goto err; |
225 | 5 | } |
226 | | |
227 | 2 | if ((ecx_key = ecx_key_new(pkey->ameth->pkey_id)) == NULL) |
228 | 0 | goto err; |
229 | 2 | if (!ecx_key_set_pub(ecx_key, param, param_len)) |
230 | 0 | goto err; |
231 | 2 | if (!EVP_PKEY_assign(pkey, pkey->ameth->pkey_id, ecx_key)) |
232 | 0 | goto err; |
233 | 2 | ecx_key = NULL; |
234 | | |
235 | 2 | ret = 1; |
236 | | |
237 | 16 | err: |
238 | 16 | ecx_key_free(ecx_key); |
239 | | |
240 | 16 | return ret; |
241 | 2 | } |
242 | | |
243 | | static int |
244 | | ecx_pub_encode(X509_PUBKEY *xpubkey, const EVP_PKEY *pkey) |
245 | 0 | { |
246 | 0 | const struct ecx_key_st *ecx_key = pkey->pkey.ecx; |
247 | 0 | uint8_t *pub_key = NULL; |
248 | 0 | size_t pub_key_len = 0; |
249 | 0 | ASN1_OBJECT *aobj; |
250 | 0 | CBS cbs; |
251 | 0 | int ret = 0; |
252 | |
|
253 | 0 | if (ecx_key == NULL) { |
254 | 0 | ECerror(EC_R_INVALID_KEY); |
255 | 0 | goto err; |
256 | 0 | } |
257 | | |
258 | 0 | if (ecx_key->pub_key_len != ecx_key->key_len) |
259 | 0 | goto err; |
260 | | |
261 | 0 | if ((aobj = OBJ_nid2obj(pkey->ameth->pkey_id)) == NULL) |
262 | 0 | goto err; |
263 | | |
264 | 0 | CBS_init(&cbs, ecx_key->pub_key, ecx_key->pub_key_len); |
265 | 0 | if (!CBS_stow(&cbs, &pub_key, &pub_key_len)) |
266 | 0 | goto err; |
267 | | |
268 | 0 | if (!X509_PUBKEY_set0_param(xpubkey, aobj, V_ASN1_UNDEF, NULL, |
269 | 0 | pub_key, pub_key_len)) |
270 | 0 | goto err; |
271 | | |
272 | 0 | pub_key = NULL; |
273 | 0 | pub_key_len = 0; |
274 | |
|
275 | 0 | ret = 1; |
276 | |
|
277 | 0 | err: |
278 | 0 | free(pub_key); |
279 | |
|
280 | 0 | return ret; |
281 | 0 | } |
282 | | |
283 | | static int |
284 | | ecx_pub_cmp(const EVP_PKEY *pkey1, const EVP_PKEY *pkey2) |
285 | 0 | { |
286 | 0 | if (pkey1->pkey.ecx == NULL || pkey1->pkey.ecx->pub_key == NULL) |
287 | 0 | return -2; |
288 | 0 | if (pkey2->pkey.ecx == NULL || pkey2->pkey.ecx->pub_key == NULL) |
289 | 0 | return -2; |
290 | 0 | if (pkey1->pkey.ecx->pub_key_len != pkey2->pkey.ecx->pub_key_len) |
291 | 0 | return -2; |
292 | | |
293 | 0 | return timingsafe_memcmp(pkey1->pkey.ecx->pub_key, pkey2->pkey.ecx->pub_key, |
294 | 0 | pkey1->pkey.ecx->pub_key_len) == 0; |
295 | 0 | } |
296 | | |
297 | | /* Reimplementation of ASN1_buf_print() that adds a secondary indent of 4. */ |
298 | | static int |
299 | | ecx_buf_print(BIO *bio, const uint8_t *buf, size_t buf_len, int indent) |
300 | 6 | { |
301 | 6 | uint8_t u8; |
302 | 6 | size_t octets = 0; |
303 | 6 | const char *sep = ":", *nl = ""; |
304 | 6 | CBS cbs; |
305 | | |
306 | 6 | if (indent > 60) |
307 | 0 | indent = 60; |
308 | 6 | indent += 4; |
309 | 6 | if (indent < 0) |
310 | 0 | indent = 0; |
311 | | |
312 | 6 | CBS_init(&cbs, buf, buf_len); |
313 | 198 | while (CBS_len(&cbs) > 0) { |
314 | 192 | if (!CBS_get_u8(&cbs, &u8)) |
315 | 0 | return 0; |
316 | 192 | if (octets++ % 15 == 0) { |
317 | 18 | if (BIO_printf(bio, "%s%*s", nl, indent, "") < 0) |
318 | 0 | return 0; |
319 | 18 | nl = "\n"; |
320 | 18 | } |
321 | 192 | if (CBS_len(&cbs) == 0) |
322 | 6 | sep = ""; |
323 | 192 | if (BIO_printf(bio, "%02x%s", u8, sep) <= 0) |
324 | 0 | return 0; |
325 | 192 | } |
326 | | |
327 | 6 | if (BIO_printf(bio, "\n") <= 0) |
328 | 0 | return 0; |
329 | | |
330 | 6 | return 1; |
331 | 6 | } |
332 | | |
333 | | static int |
334 | | ecx_pub_print(BIO *bio, const EVP_PKEY *pkey, int indent, ASN1_PCTX *ctx) |
335 | 2 | { |
336 | 2 | struct ecx_key_st *ecx_key = pkey->pkey.ecx; |
337 | 2 | const char *name; |
338 | | |
339 | 2 | if ((name = OBJ_nid2ln(pkey->ameth->pkey_id)) == NULL) |
340 | 0 | return 0; |
341 | | |
342 | 2 | if (ecx_key == NULL || ecx_key->pub_key == NULL) |
343 | 0 | return BIO_printf(bio, "%*s<INVALID PUBLIC KEY>\n", |
344 | 0 | indent, "") > 0; |
345 | | |
346 | 2 | if (BIO_printf(bio, "%*s%s Public-Key:\n", indent, "", name) <= 0) |
347 | 0 | return 0; |
348 | 2 | if (BIO_printf(bio, "%*spub:\n", indent, "") <= 0) |
349 | 0 | return 0; |
350 | 2 | if (!ecx_buf_print(bio, ecx_key->pub_key, ecx_key->pub_key_len, indent)) |
351 | 0 | return 0; |
352 | | |
353 | 2 | return 1; |
354 | 2 | } |
355 | | |
356 | | static int |
357 | | ecx_priv_decode(EVP_PKEY *pkey, const PKCS8_PRIV_KEY_INFO *p8pki) |
358 | 10 | { |
359 | 10 | struct ecx_key_st *ecx_key = NULL; |
360 | 10 | ASN1_OCTET_STRING *aos = NULL; |
361 | 10 | const X509_ALGOR *algor; |
362 | 10 | int algor_type; |
363 | 10 | const uint8_t *param; |
364 | 10 | int param_len; |
365 | 10 | int ret = 0; |
366 | | |
367 | 10 | if (!PKCS8_pkey_get0(NULL, ¶m, ¶m_len, &algor, p8pki)) |
368 | 0 | goto err; |
369 | 10 | if ((aos = d2i_ASN1_OCTET_STRING(NULL, ¶m, param_len)) == NULL) |
370 | 2 | goto err; |
371 | | |
372 | | /* Ensure that parameters have not been specified in the encoding. */ |
373 | 8 | if (algor != NULL) { |
374 | 8 | X509_ALGOR_get0(NULL, &algor_type, NULL, algor); |
375 | 8 | if (algor_type != V_ASN1_UNDEF) { |
376 | 1 | ECerror(EC_R_INVALID_ENCODING); |
377 | 1 | goto err; |
378 | 1 | } |
379 | 8 | } |
380 | | |
381 | 7 | if (ASN1_STRING_get0_data(aos) == NULL || |
382 | 7 | ASN1_STRING_length(aos) != ecx_key_len(pkey->ameth->pkey_id)) { |
383 | 5 | ECerror(EC_R_INVALID_ENCODING); |
384 | 5 | goto err; |
385 | 5 | } |
386 | | |
387 | 2 | if ((ecx_key = ecx_key_new(pkey->ameth->pkey_id)) == NULL) |
388 | 0 | goto err; |
389 | 2 | if (!ecx_key_set_priv(ecx_key, ASN1_STRING_get0_data(aos), |
390 | 2 | ASN1_STRING_length(aos))) |
391 | 0 | goto err; |
392 | 2 | if (!EVP_PKEY_assign(pkey, pkey->ameth->pkey_id, ecx_key)) |
393 | 0 | goto err; |
394 | 2 | ecx_key = NULL; |
395 | | |
396 | 2 | ret = 1; |
397 | | |
398 | 10 | err: |
399 | 10 | ASN1_OCTET_STRING_free(aos); |
400 | 10 | ecx_key_free(ecx_key); |
401 | | |
402 | 10 | return ret; |
403 | 2 | } |
404 | | |
405 | | static int |
406 | | ecx_priv_encode(PKCS8_PRIV_KEY_INFO *p8pki, const EVP_PKEY *pkey) |
407 | 2 | { |
408 | 2 | struct ecx_key_st *ecx_key = pkey->pkey.ecx; |
409 | 2 | ASN1_OCTET_STRING *aos = NULL; |
410 | 2 | ASN1_OBJECT *aobj; |
411 | 2 | uint8_t *der = NULL; |
412 | 2 | int der_len = 0; |
413 | 2 | int ret = 0; |
414 | | |
415 | 2 | if (ecx_key == NULL || ecx_key->priv_key == NULL) { |
416 | 0 | ECerror(EC_R_INVALID_PRIVATE_KEY); |
417 | 0 | goto err; |
418 | 0 | } |
419 | | |
420 | 2 | if ((aobj = OBJ_nid2obj(pkey->ameth->pkey_id)) == NULL) |
421 | 0 | goto err; |
422 | | |
423 | 2 | if ((aos = ASN1_OCTET_STRING_new()) == NULL) |
424 | 0 | goto err; |
425 | 2 | if (!ASN1_OCTET_STRING_set(aos, ecx_key->priv_key, |
426 | 2 | ecx_key->priv_key_len)) |
427 | 0 | goto err; |
428 | 2 | if ((der_len = i2d_ASN1_OCTET_STRING(aos, &der)) < 0) |
429 | 0 | goto err; |
430 | 2 | if (!PKCS8_pkey_set0(p8pki, aobj, 0, V_ASN1_UNDEF, NULL, der, der_len)) |
431 | 0 | goto err; |
432 | | |
433 | 2 | der = NULL; |
434 | 2 | der_len = 0; |
435 | | |
436 | 2 | ret = 1; |
437 | | |
438 | 2 | err: |
439 | 2 | freezero(der, der_len); |
440 | 2 | ASN1_OCTET_STRING_free(aos); |
441 | | |
442 | 2 | return ret; |
443 | 2 | } |
444 | | |
445 | | static int |
446 | | ecx_priv_print(BIO *bio, const EVP_PKEY *pkey, int indent, ASN1_PCTX *ctx) |
447 | 2 | { |
448 | 2 | struct ecx_key_st *ecx_key = pkey->pkey.ecx; |
449 | 2 | const char *name; |
450 | | |
451 | 2 | if ((name = OBJ_nid2ln(pkey->ameth->pkey_id)) == NULL) |
452 | 0 | return 0; |
453 | | |
454 | 2 | if (ecx_key == NULL || ecx_key->priv_key == NULL) |
455 | 0 | return BIO_printf(bio, "%*s<INVALID PRIVATE KEY>\n", |
456 | 0 | indent, "") > 0; |
457 | | |
458 | 2 | if (BIO_printf(bio, "%*s%s Private-Key:\n", indent, "", name) <= 0) |
459 | 0 | return 0; |
460 | 2 | if (BIO_printf(bio, "%*spriv:\n", indent, "") <= 0) |
461 | 0 | return 0; |
462 | 2 | if (!ecx_buf_print(bio, ecx_key->priv_key, ecx_key->priv_key_len, indent)) |
463 | 0 | return 0; |
464 | 2 | if (BIO_printf(bio, "%*spub:\n", indent, "") <= 0) |
465 | 0 | return 0; |
466 | 2 | if (!ecx_buf_print(bio, ecx_key->pub_key, ecx_key->pub_key_len, indent)) |
467 | 0 | return 0; |
468 | | |
469 | 2 | return 1; |
470 | 2 | } |
471 | | |
472 | | static int |
473 | | ecx_size(const EVP_PKEY *pkey) |
474 | 0 | { |
475 | 0 | return ecx_key_len(pkey->ameth->pkey_id); |
476 | 0 | } |
477 | | |
478 | | static int |
479 | | ecx_sig_size(const EVP_PKEY *pkey) |
480 | 0 | { |
481 | 0 | switch (pkey->ameth->pkey_id) { |
482 | 0 | case EVP_PKEY_ED25519: |
483 | 0 | return ED25519_SIG_SIZE; |
484 | 0 | } |
485 | 0 | return 0; |
486 | 0 | } |
487 | | |
488 | | static int |
489 | | ecx_bits(const EVP_PKEY *pkey) |
490 | 0 | { |
491 | 0 | switch (pkey->ameth->pkey_id) { |
492 | 0 | case EVP_PKEY_ED25519: |
493 | 0 | return ED25519_BITS; |
494 | 0 | case EVP_PKEY_X25519: |
495 | 0 | return X25519_BITS; |
496 | 0 | } |
497 | 0 | return 0; |
498 | 0 | } |
499 | | |
500 | | static int |
501 | | ecx_security_bits(const EVP_PKEY *pkey) |
502 | 0 | { |
503 | 0 | switch (pkey->ameth->pkey_id) { |
504 | 0 | case EVP_PKEY_ED25519: |
505 | 0 | return ED25519_SECURITY_BITS; |
506 | 0 | case EVP_PKEY_X25519: |
507 | 0 | return X25519_SECURITY_BITS; |
508 | 0 | } |
509 | 0 | return 0; |
510 | 0 | } |
511 | | |
512 | | static int |
513 | | ecx_signature_info(const X509_ALGOR *algor, int *md_nid, int *pkey_nid, |
514 | | int *security_bits, uint32_t *flags) |
515 | 0 | { |
516 | 0 | const ASN1_OBJECT *aobj; |
517 | |
|
518 | 0 | X509_ALGOR_get0(&aobj, NULL, NULL, algor); |
519 | 0 | if (OBJ_obj2nid(aobj) != EVP_PKEY_ED25519) |
520 | 0 | return 0; |
521 | | |
522 | 0 | *md_nid = NID_undef; |
523 | 0 | *pkey_nid = NID_ED25519; |
524 | 0 | *security_bits = ED25519_SECURITY_BITS; |
525 | 0 | *flags = X509_SIG_INFO_TLS | X509_SIG_INFO_VALID; |
526 | |
|
527 | 0 | return 1; |
528 | 0 | } |
529 | | |
530 | | static int |
531 | | ecx_param_cmp(const EVP_PKEY *pkey1, const EVP_PKEY *pkey2) |
532 | 0 | { |
533 | | /* No parameters, so always equivalent. */ |
534 | 0 | return 1; |
535 | 0 | } |
536 | | |
537 | | static void |
538 | | ecx_free(EVP_PKEY *pkey) |
539 | 30 | { |
540 | 30 | struct ecx_key_st *ecx_key = pkey->pkey.ecx; |
541 | | |
542 | 30 | ecx_key_free(ecx_key); |
543 | 30 | } |
544 | | |
545 | | static int |
546 | | ecx_ctrl(EVP_PKEY *pkey, int op, long arg1, void *arg2) |
547 | 0 | { |
548 | | /* Not supported. */ |
549 | 0 | return -2; |
550 | 0 | } |
551 | | |
552 | | #ifndef OPENSSL_NO_CMS |
553 | | static int |
554 | | ecx_cms_sign_or_verify(EVP_PKEY *pkey, long verify, CMS_SignerInfo *si) |
555 | 0 | { |
556 | 0 | X509_ALGOR *digestAlgorithm, *signatureAlgorithm; |
557 | |
|
558 | 0 | if (verify != 0 && verify != 1) |
559 | 0 | return -1; |
560 | | |
561 | | /* Check that we have an Ed25519 public key. */ |
562 | 0 | if (EVP_PKEY_id(pkey) != NID_ED25519) |
563 | 0 | return -1; |
564 | | |
565 | 0 | CMS_SignerInfo_get0_algs(si, NULL, NULL, &digestAlgorithm, |
566 | 0 | &signatureAlgorithm); |
567 | | |
568 | | /* RFC 8419, section 2.3: digestAlgorithm MUST be SHA-512. */ |
569 | 0 | if (digestAlgorithm == NULL) |
570 | 0 | return -1; |
571 | 0 | if (OBJ_obj2nid(digestAlgorithm->algorithm) != NID_sha512) |
572 | 0 | return -1; |
573 | | |
574 | | /* |
575 | | * RFC 8419, section 2.4: signatureAlgorithm MUST be Ed25519, and the |
576 | | * parameters MUST be absent. For verification check that this is the |
577 | | * case, for signing set the signatureAlgorithm accordingly. |
578 | | */ |
579 | 0 | if (verify) { |
580 | 0 | const ASN1_OBJECT *obj; |
581 | 0 | int param_type; |
582 | |
|
583 | 0 | if (signatureAlgorithm == NULL) |
584 | 0 | return -1; |
585 | | |
586 | 0 | X509_ALGOR_get0(&obj, ¶m_type, NULL, signatureAlgorithm); |
587 | 0 | if (OBJ_obj2nid(obj) != NID_ED25519) |
588 | 0 | return -1; |
589 | 0 | if (param_type != V_ASN1_UNDEF) |
590 | 0 | return -1; |
591 | | |
592 | 0 | return 1; |
593 | 0 | } |
594 | | |
595 | 0 | if (!X509_ALGOR_set0_by_nid(signatureAlgorithm, NID_ED25519, |
596 | 0 | V_ASN1_UNDEF, NULL)) |
597 | 0 | return -1; |
598 | | |
599 | 0 | return 1; |
600 | 0 | } |
601 | | #endif |
602 | | |
603 | | static int |
604 | | ecx_sign_ctrl(EVP_PKEY *pkey, int op, long arg1, void *arg2) |
605 | 0 | { |
606 | 0 | switch (op) { |
607 | 0 | #ifndef OPENSSL_NO_CMS |
608 | 0 | case ASN1_PKEY_CTRL_CMS_SIGN: |
609 | 0 | return ecx_cms_sign_or_verify(pkey, arg1, arg2); |
610 | 0 | #endif |
611 | 0 | case ASN1_PKEY_CTRL_DEFAULT_MD_NID: |
612 | | /* PureEdDSA does its own hashing. */ |
613 | 0 | *(int *)arg2 = NID_undef; |
614 | 0 | return 2; |
615 | 0 | } |
616 | 0 | return -2; |
617 | 0 | } |
618 | | |
619 | | static int |
620 | | ecx_set_priv_key(EVP_PKEY *pkey, const uint8_t *priv, size_t len) |
621 | 0 | { |
622 | 0 | struct ecx_key_st *ecx_key = NULL; |
623 | 0 | int ret = 0; |
624 | |
|
625 | 0 | if (priv == NULL || len != ecx_key_len(pkey->ameth->pkey_id)) { |
626 | 0 | ECerror(EC_R_INVALID_ENCODING); |
627 | 0 | goto err; |
628 | 0 | } |
629 | | |
630 | 0 | if ((ecx_key = ecx_key_new(pkey->ameth->pkey_id)) == NULL) |
631 | 0 | goto err; |
632 | 0 | if (!ecx_key_set_priv(ecx_key, priv, len)) |
633 | 0 | goto err; |
634 | 0 | if (!EVP_PKEY_assign(pkey, pkey->ameth->pkey_id, ecx_key)) |
635 | 0 | goto err; |
636 | 0 | ecx_key = NULL; |
637 | |
|
638 | 0 | ret = 1; |
639 | |
|
640 | 0 | err: |
641 | 0 | ecx_key_free(ecx_key); |
642 | |
|
643 | 0 | return ret; |
644 | 0 | } |
645 | | |
646 | | static int |
647 | | ecx_set_pub_key(EVP_PKEY *pkey, const uint8_t *pub, size_t len) |
648 | 0 | { |
649 | 0 | struct ecx_key_st *ecx_key = NULL; |
650 | 0 | int ret = 0; |
651 | |
|
652 | 0 | if (pub == NULL || len != ecx_key_len(pkey->ameth->pkey_id)) { |
653 | 0 | ECerror(EC_R_INVALID_ENCODING); |
654 | 0 | goto err; |
655 | 0 | } |
656 | | |
657 | 0 | if ((ecx_key = ecx_key_new(pkey->ameth->pkey_id)) == NULL) |
658 | 0 | goto err; |
659 | 0 | if (!ecx_key_set_pub(ecx_key, pub, len)) |
660 | 0 | goto err; |
661 | 0 | if (!EVP_PKEY_assign(pkey, pkey->ameth->pkey_id, ecx_key)) |
662 | 0 | goto err; |
663 | 0 | ecx_key = NULL; |
664 | |
|
665 | 0 | ret = 1; |
666 | |
|
667 | 0 | err: |
668 | 0 | ecx_key_free(ecx_key); |
669 | |
|
670 | 0 | return ret; |
671 | 0 | } |
672 | | |
673 | | static int |
674 | | ecx_get_priv_key(const EVP_PKEY *pkey, unsigned char *out_priv, size_t *out_len) |
675 | 0 | { |
676 | 0 | struct ecx_key_st *ecx_key = pkey->pkey.ecx; |
677 | 0 | CBS cbs; |
678 | |
|
679 | 0 | if (out_priv == NULL) { |
680 | 0 | *out_len = ecx_key_len(pkey->ameth->pkey_id); |
681 | 0 | return 1; |
682 | 0 | } |
683 | | |
684 | 0 | if (ecx_key == NULL || ecx_key->priv_key == NULL) |
685 | 0 | return 0; |
686 | | |
687 | 0 | CBS_init(&cbs, ecx_key->priv_key, ecx_key->priv_key_len); |
688 | 0 | if (!CBS_write_bytes(&cbs, out_priv, *out_len, out_len)) |
689 | 0 | return 0; |
690 | | |
691 | 0 | return 1; |
692 | 0 | } |
693 | | |
694 | | static int |
695 | | ecx_get_pub_key(const EVP_PKEY *pkey, unsigned char *out_pub, size_t *out_len) |
696 | 0 | { |
697 | 0 | struct ecx_key_st *ecx_key = pkey->pkey.ecx; |
698 | 0 | CBS cbs; |
699 | |
|
700 | 0 | if (out_pub == NULL) { |
701 | 0 | *out_len = ecx_key_len(pkey->ameth->pkey_id); |
702 | 0 | return 1; |
703 | 0 | } |
704 | | |
705 | 0 | if (ecx_key == NULL || ecx_key->pub_key == NULL) |
706 | 0 | return 0; |
707 | | |
708 | 0 | CBS_init(&cbs, ecx_key->pub_key, ecx_key->pub_key_len); |
709 | 0 | if (!CBS_write_bytes(&cbs, out_pub, *out_len, out_len)) |
710 | 0 | return 0; |
711 | | |
712 | 0 | return 1; |
713 | 0 | } |
714 | | |
715 | | static int |
716 | | pkey_ecx_keygen(EVP_PKEY_CTX *pkey_ctx, EVP_PKEY *pkey) |
717 | 0 | { |
718 | 0 | struct ecx_key_st *ecx_key = NULL; |
719 | 0 | int ret = 0; |
720 | |
|
721 | 0 | if ((ecx_key = ecx_key_new(pkey_ctx->pmeth->pkey_id)) == NULL) |
722 | 0 | goto err; |
723 | 0 | if (!ecx_key_generate(ecx_key)) |
724 | 0 | goto err; |
725 | 0 | if (!EVP_PKEY_assign(pkey, pkey_ctx->pmeth->pkey_id, ecx_key)) |
726 | 0 | goto err; |
727 | 0 | ecx_key = NULL; |
728 | |
|
729 | 0 | ret = 1; |
730 | |
|
731 | 0 | err: |
732 | 0 | ecx_key_free(ecx_key); |
733 | |
|
734 | 0 | return ret; |
735 | 0 | } |
736 | | |
737 | | static int |
738 | | pkey_ecx_derive(EVP_PKEY_CTX *pkey_ctx, unsigned char *out_key, |
739 | | size_t *out_key_len) |
740 | 0 | { |
741 | 0 | struct ecx_key_st *ecx_key, *ecx_peer_key; |
742 | |
|
743 | 0 | if (pkey_ctx->pkey == NULL || pkey_ctx->peerkey == NULL) { |
744 | 0 | ECerror(EC_R_KEYS_NOT_SET); |
745 | 0 | return 0; |
746 | 0 | } |
747 | | |
748 | 0 | if ((ecx_key = pkey_ctx->pkey->pkey.ecx) == NULL) { |
749 | 0 | ECerror(EC_R_INVALID_PRIVATE_KEY); |
750 | 0 | return 0; |
751 | 0 | } |
752 | 0 | if (ecx_key->priv_key == NULL) { |
753 | 0 | ECerror(EC_R_INVALID_PRIVATE_KEY); |
754 | 0 | return 0; |
755 | 0 | } |
756 | | |
757 | 0 | if ((ecx_peer_key = pkey_ctx->peerkey->pkey.ecx) == NULL) { |
758 | 0 | ECerror(EC_R_INVALID_PEER_KEY); |
759 | 0 | return 0; |
760 | 0 | } |
761 | | |
762 | 0 | if (out_key != NULL) { |
763 | 0 | if (!X25519(out_key, ecx_key->priv_key, ecx_peer_key->pub_key)) |
764 | 0 | return 0; |
765 | 0 | } |
766 | | |
767 | 0 | *out_key_len = X25519_KEYLEN; |
768 | |
|
769 | 0 | return 1; |
770 | 0 | } |
771 | | |
772 | | static int |
773 | | pkey_ecx_ctrl(EVP_PKEY_CTX *pkey_ctx, int op, int arg1, void *arg2) |
774 | 0 | { |
775 | 0 | if (op == EVP_PKEY_CTRL_PEER_KEY) |
776 | 0 | return 1; |
777 | | |
778 | 0 | return -2; |
779 | 0 | } |
780 | | |
781 | | static int |
782 | | ecx_item_verify(EVP_MD_CTX *md_ctx, const ASN1_ITEM *it, void *asn, |
783 | | X509_ALGOR *algor, ASN1_BIT_STRING *abs, EVP_PKEY *pkey) |
784 | 0 | { |
785 | 0 | const ASN1_OBJECT *aobj; |
786 | 0 | int nid, param_type; |
787 | |
|
788 | 0 | X509_ALGOR_get0(&aobj, ¶m_type, NULL, algor); |
789 | |
|
790 | 0 | nid = OBJ_obj2nid(aobj); |
791 | |
|
792 | 0 | if (nid != NID_ED25519 || param_type != V_ASN1_UNDEF) { |
793 | 0 | ECerror(EC_R_INVALID_ENCODING); |
794 | 0 | return -1; |
795 | 0 | } |
796 | | |
797 | 0 | if (!EVP_DigestVerifyInit(md_ctx, NULL, NULL, NULL, pkey)) |
798 | 0 | return -1; |
799 | | |
800 | 0 | return 2; |
801 | 0 | } |
802 | | |
803 | | static int |
804 | | ecx_item_sign(EVP_MD_CTX *md_ctx, const ASN1_ITEM *it, void *asn, |
805 | | X509_ALGOR *algor1, X509_ALGOR *algor2, ASN1_BIT_STRING *abs) |
806 | 0 | { |
807 | 0 | if (!X509_ALGOR_set0_by_nid(algor1, NID_ED25519, V_ASN1_UNDEF, NULL)) |
808 | 0 | return 0; |
809 | | |
810 | 0 | if (algor2 != NULL) { |
811 | 0 | if (!X509_ALGOR_set0_by_nid(algor2, NID_ED25519, V_ASN1_UNDEF, |
812 | 0 | NULL)) |
813 | 0 | return 0; |
814 | 0 | } |
815 | | |
816 | | /* Tell ASN1_item_sign_ctx() that identifiers are set and it needs to sign. */ |
817 | 0 | return 3; |
818 | 0 | } |
819 | | |
820 | | static int |
821 | | pkey_ecx_digestsign(EVP_MD_CTX *md_ctx, unsigned char *out_sig, |
822 | | size_t *out_sig_len, const unsigned char *message, size_t message_len) |
823 | 0 | { |
824 | 0 | struct ecx_key_st *ecx_key; |
825 | 0 | EVP_PKEY_CTX *pkey_ctx; |
826 | |
|
827 | 0 | pkey_ctx = EVP_MD_CTX_pkey_ctx(md_ctx); |
828 | 0 | ecx_key = pkey_ctx->pkey->pkey.ecx; |
829 | |
|
830 | 0 | if (out_sig == NULL) { |
831 | 0 | *out_sig_len = ecx_sig_size(pkey_ctx->pkey); |
832 | 0 | return 1; |
833 | 0 | } |
834 | 0 | if (*out_sig_len < ecx_sig_size(pkey_ctx->pkey)) { |
835 | 0 | ECerror(EC_R_BUFFER_TOO_SMALL); |
836 | 0 | return 0; |
837 | 0 | } |
838 | | |
839 | 0 | if (ecx_key == NULL) |
840 | 0 | return 0; |
841 | 0 | if (ecx_key->priv_key == NULL || ecx_key->pub_key == NULL) |
842 | 0 | return 0; |
843 | | |
844 | 0 | if (!ED25519_sign(out_sig, message, message_len, ecx_key->pub_key, |
845 | 0 | ecx_key->priv_key)) |
846 | 0 | return 0; |
847 | | |
848 | 0 | *out_sig_len = ecx_sig_size(pkey_ctx->pkey); |
849 | |
|
850 | 0 | return 1; |
851 | 0 | } |
852 | | |
853 | | static int |
854 | | pkey_ecx_digestverify(EVP_MD_CTX *md_ctx, const unsigned char *sig, |
855 | | size_t sig_len, const unsigned char *message, size_t message_len) |
856 | 0 | { |
857 | 0 | struct ecx_key_st *ecx_key; |
858 | 0 | EVP_PKEY_CTX *pkey_ctx; |
859 | |
|
860 | 0 | pkey_ctx = EVP_MD_CTX_pkey_ctx(md_ctx); |
861 | 0 | ecx_key = pkey_ctx->pkey->pkey.ecx; |
862 | |
|
863 | 0 | if (ecx_key == NULL || ecx_key->pub_key == NULL) |
864 | 0 | return -1; |
865 | 0 | if (sig_len != ecx_sig_size(pkey_ctx->pkey)) |
866 | 0 | return -1; |
867 | | |
868 | 0 | return ED25519_verify(message, message_len, sig, ecx_key->pub_key); |
869 | 0 | } |
870 | | |
871 | | static int |
872 | | pkey_ecx_ed_ctrl(EVP_PKEY_CTX *pkey_ctx, int op, int arg1, void *arg2) |
873 | 0 | { |
874 | 0 | switch (op) { |
875 | 0 | case EVP_PKEY_CTRL_MD: |
876 | | /* PureEdDSA does its own hashing. */ |
877 | 0 | if (arg2 != NULL && (const EVP_MD *)arg2 != EVP_md_null()) { |
878 | 0 | ECerror(EC_R_INVALID_DIGEST_TYPE); |
879 | 0 | return 0; |
880 | 0 | } |
881 | 0 | return 1; |
882 | | |
883 | 0 | #ifndef OPENSSL_NO_CMS |
884 | 0 | case EVP_PKEY_CTRL_CMS_SIGN: |
885 | 0 | #endif |
886 | 0 | case EVP_PKEY_CTRL_DIGESTINIT: |
887 | 0 | return 1; |
888 | 0 | } |
889 | 0 | return -2; |
890 | 0 | } |
891 | | |
892 | | const EVP_PKEY_ASN1_METHOD x25519_asn1_meth = { |
893 | | .base_method = &x25519_asn1_meth, |
894 | | .pkey_id = EVP_PKEY_X25519, |
895 | | .pkey_flags = 0, |
896 | | .pem_str = "X25519", |
897 | | .info = "OpenSSL X25519 algorithm", |
898 | | |
899 | | .pub_decode = ecx_pub_decode, |
900 | | .pub_encode = ecx_pub_encode, |
901 | | .pub_cmp = ecx_pub_cmp, |
902 | | .pub_print = ecx_pub_print, |
903 | | |
904 | | .priv_decode = ecx_priv_decode, |
905 | | .priv_encode = ecx_priv_encode, |
906 | | .priv_print = ecx_priv_print, |
907 | | |
908 | | .pkey_size = ecx_size, |
909 | | .pkey_bits = ecx_bits, |
910 | | .pkey_security_bits = ecx_security_bits, |
911 | | |
912 | | .param_cmp = ecx_param_cmp, |
913 | | |
914 | | .pkey_free = ecx_free, |
915 | | .pkey_ctrl = ecx_ctrl, |
916 | | |
917 | | .set_priv_key = ecx_set_priv_key, |
918 | | .set_pub_key = ecx_set_pub_key, |
919 | | .get_priv_key = ecx_get_priv_key, |
920 | | .get_pub_key = ecx_get_pub_key, |
921 | | }; |
922 | | |
923 | | const EVP_PKEY_METHOD x25519_pkey_meth = { |
924 | | .pkey_id = EVP_PKEY_X25519, |
925 | | .keygen = pkey_ecx_keygen, |
926 | | .derive = pkey_ecx_derive, |
927 | | .ctrl = pkey_ecx_ctrl, |
928 | | }; |
929 | | |
930 | | const EVP_PKEY_ASN1_METHOD ed25519_asn1_meth = { |
931 | | .base_method = &ed25519_asn1_meth, |
932 | | .pkey_id = EVP_PKEY_ED25519, |
933 | | .pkey_flags = 0, |
934 | | .pem_str = "ED25519", |
935 | | .info = "OpenSSL ED25519 algorithm", |
936 | | |
937 | | .pub_decode = ecx_pub_decode, |
938 | | .pub_encode = ecx_pub_encode, |
939 | | .pub_cmp = ecx_pub_cmp, |
940 | | .pub_print = ecx_pub_print, |
941 | | |
942 | | .priv_decode = ecx_priv_decode, |
943 | | .priv_encode = ecx_priv_encode, |
944 | | .priv_print = ecx_priv_print, |
945 | | |
946 | | .pkey_size = ecx_sig_size, |
947 | | .pkey_bits = ecx_bits, |
948 | | .pkey_security_bits = ecx_security_bits, |
949 | | |
950 | | .signature_info = ecx_signature_info, |
951 | | |
952 | | .param_cmp = ecx_param_cmp, |
953 | | |
954 | | .pkey_free = ecx_free, |
955 | | .pkey_ctrl = ecx_sign_ctrl, |
956 | | |
957 | | .item_verify = ecx_item_verify, |
958 | | .item_sign = ecx_item_sign, |
959 | | |
960 | | .set_priv_key = ecx_set_priv_key, |
961 | | .set_pub_key = ecx_set_pub_key, |
962 | | .get_priv_key = ecx_get_priv_key, |
963 | | .get_pub_key = ecx_get_pub_key, |
964 | | }; |
965 | | |
966 | | const EVP_PKEY_METHOD ed25519_pkey_meth = { |
967 | | .pkey_id = EVP_PKEY_ED25519, |
968 | | .flags = EVP_PKEY_FLAG_SIGCTX_CUSTOM, |
969 | | .keygen = pkey_ecx_keygen, |
970 | | .ctrl = pkey_ecx_ed_ctrl, |
971 | | .digestsign = pkey_ecx_digestsign, |
972 | | .digestverify = pkey_ecx_digestverify, |
973 | | }; |