]>
Commit | Line | Data |
---|---|---|
756b198d | 1 | /* |
b0edda11 | 2 | * Copyright 2006-2018 The OpenSSL Project Authors. All Rights Reserved. |
756b198d | 3 | * |
a7f182b7 | 4 | * Licensed under the Apache License 2.0 (the "License"). You may not use |
756b198d DSH |
5 | * this file except in compliance with the License. You can obtain a copy |
6 | * in the file LICENSE in the source distribution or at | |
7 | * https://www.openssl.org/source/license.html | |
8 | */ | |
9 | ||
10 | #include <stdio.h> | |
11 | #include "internal/cryptlib.h" | |
12 | #include <openssl/x509.h> | |
13 | #include <openssl/ec.h> | |
14 | #include <openssl/rand.h> | |
15 | #include "internal/asn1_int.h" | |
16 | #include "internal/evp_int.h" | |
17 | #include "ec_lcl.h" | |
18 | ||
756b198d DSH |
19 | #define X25519_BITS 253 |
20 | #define X25519_SECURITY_BITS 128 | |
21 | ||
8ecade8b DSH |
22 | #define ED25519_SIGSIZE 64 |
23 | ||
13735cfe MC |
24 | #define X448_BITS 448 |
25 | #define ED448_BITS 456 | |
26 | #define X448_SECURITY_BITS 224 | |
27 | ||
28 | #define ED448_SIGSIZE 114 | |
29 | ||
30 | #define ISX448(id) ((id) == EVP_PKEY_X448) | |
31 | #define IS25519(id) ((id) == EVP_PKEY_X25519 || (id) == EVP_PKEY_ED25519) | |
32 | #define KEYLENID(id) (IS25519(id) ? X25519_KEYLEN \ | |
33 | : ((id) == EVP_PKEY_X448 ? X448_KEYLEN \ | |
34 | : ED448_KEYLEN)) | |
35 | #define KEYLEN(p) KEYLENID((p)->ameth->pkey_id) | |
36 | ||
756b198d DSH |
37 | |
38 | typedef enum { | |
13735cfe MC |
39 | KEY_OP_PUBLIC, |
40 | KEY_OP_PRIVATE, | |
41 | KEY_OP_KEYGEN | |
756b198d DSH |
42 | } ecx_key_op_t; |
43 | ||
44 | /* Setup EVP_PKEY using public, private or generation */ | |
42a3008a | 45 | static int ecx_key_op(EVP_PKEY *pkey, int id, const X509_ALGOR *palg, |
756b198d DSH |
46 | const unsigned char *p, int plen, ecx_key_op_t op) |
47 | { | |
13735cfe MC |
48 | ECX_KEY *key = NULL; |
49 | unsigned char *privkey, *pubkey; | |
756b198d | 50 | |
13735cfe | 51 | if (op != KEY_OP_KEYGEN) { |
5d6aaf8a DSH |
52 | if (palg != NULL) { |
53 | int ptype; | |
54 | ||
55 | /* Algorithm parameters must be absent */ | |
56 | X509_ALGOR_get0(NULL, &ptype, NULL, palg); | |
57 | if (ptype != V_ASN1_UNDEF) { | |
58 | ECerr(EC_F_ECX_KEY_OP, EC_R_INVALID_ENCODING); | |
59 | return 0; | |
60 | } | |
756b198d DSH |
61 | } |
62 | ||
13735cfe | 63 | if (p == NULL || plen != KEYLENID(id)) { |
756b198d DSH |
64 | ECerr(EC_F_ECX_KEY_OP, EC_R_INVALID_ENCODING); |
65 | return 0; | |
66 | } | |
67 | } | |
68 | ||
13735cfe MC |
69 | key = OPENSSL_zalloc(sizeof(*key)); |
70 | if (key == NULL) { | |
756b198d DSH |
71 | ECerr(EC_F_ECX_KEY_OP, ERR_R_MALLOC_FAILURE); |
72 | return 0; | |
73 | } | |
13735cfe | 74 | pubkey = key->pubkey; |
756b198d | 75 | |
13735cfe MC |
76 | if (op == KEY_OP_PUBLIC) { |
77 | memcpy(pubkey, p, plen); | |
756b198d | 78 | } else { |
13735cfe MC |
79 | privkey = key->privkey = OPENSSL_secure_malloc(KEYLENID(id)); |
80 | if (privkey == NULL) { | |
756b198d | 81 | ECerr(EC_F_ECX_KEY_OP, ERR_R_MALLOC_FAILURE); |
13735cfe | 82 | goto err; |
756b198d | 83 | } |
13735cfe MC |
84 | if (op == KEY_OP_KEYGEN) { |
85 | if (RAND_priv_bytes(privkey, KEYLENID(id)) <= 0) { | |
86 | OPENSSL_secure_free(privkey); | |
87 | key->privkey = NULL; | |
88 | goto err; | |
756b198d | 89 | } |
d2916a5b | 90 | if (id == EVP_PKEY_X25519) { |
13735cfe MC |
91 | privkey[0] &= 248; |
92 | privkey[X25519_KEYLEN - 1] &= 127; | |
93 | privkey[X25519_KEYLEN - 1] |= 64; | |
94 | } else if (id == EVP_PKEY_X448) { | |
95 | privkey[0] &= 252; | |
96 | privkey[X448_KEYLEN - 1] |= 128; | |
8ecade8b | 97 | } |
756b198d | 98 | } else { |
13735cfe MC |
99 | memcpy(privkey, p, KEYLENID(id)); |
100 | } | |
101 | switch (id) { | |
102 | case EVP_PKEY_X25519: | |
103 | X25519_public_from_private(pubkey, privkey); | |
104 | break; | |
105 | case EVP_PKEY_ED25519: | |
106 | ED25519_public_from_private(pubkey, privkey); | |
107 | break; | |
108 | case EVP_PKEY_X448: | |
109 | X448_public_from_private(pubkey, privkey); | |
110 | break; | |
111 | case EVP_PKEY_ED448: | |
112 | ED448_public_from_private(pubkey, privkey); | |
113 | break; | |
756b198d | 114 | } |
756b198d DSH |
115 | } |
116 | ||
13735cfe | 117 | EVP_PKEY_assign(pkey, id, key); |
756b198d | 118 | return 1; |
13735cfe MC |
119 | err: |
120 | OPENSSL_free(key); | |
121 | return 0; | |
756b198d DSH |
122 | } |
123 | ||
124 | static int ecx_pub_encode(X509_PUBKEY *pk, const EVP_PKEY *pkey) | |
125 | { | |
13735cfe | 126 | const ECX_KEY *ecxkey = pkey->pkey.ecx; |
756b198d DSH |
127 | unsigned char *penc; |
128 | ||
13735cfe | 129 | if (ecxkey == NULL) { |
756b198d DSH |
130 | ECerr(EC_F_ECX_PUB_ENCODE, EC_R_INVALID_KEY); |
131 | return 0; | |
132 | } | |
133 | ||
13735cfe | 134 | penc = OPENSSL_memdup(ecxkey->pubkey, KEYLEN(pkey)); |
756b198d DSH |
135 | if (penc == NULL) { |
136 | ECerr(EC_F_ECX_PUB_ENCODE, ERR_R_MALLOC_FAILURE); | |
137 | return 0; | |
138 | } | |
139 | ||
8ecade8b | 140 | if (!X509_PUBKEY_set0_param(pk, OBJ_nid2obj(pkey->ameth->pkey_id), |
13735cfe | 141 | V_ASN1_UNDEF, NULL, penc, KEYLEN(pkey))) { |
756b198d DSH |
142 | OPENSSL_free(penc); |
143 | ECerr(EC_F_ECX_PUB_ENCODE, ERR_R_MALLOC_FAILURE); | |
144 | return 0; | |
145 | } | |
146 | return 1; | |
147 | } | |
148 | ||
149 | static int ecx_pub_decode(EVP_PKEY *pkey, X509_PUBKEY *pubkey) | |
150 | { | |
151 | const unsigned char *p; | |
152 | int pklen; | |
153 | X509_ALGOR *palg; | |
154 | ||
155 | if (!X509_PUBKEY_get0_param(NULL, &p, &pklen, &palg, pubkey)) | |
156 | return 0; | |
42a3008a | 157 | return ecx_key_op(pkey, pkey->ameth->pkey_id, palg, p, pklen, |
13735cfe | 158 | KEY_OP_PUBLIC); |
756b198d DSH |
159 | } |
160 | ||
161 | static int ecx_pub_cmp(const EVP_PKEY *a, const EVP_PKEY *b) | |
162 | { | |
13735cfe MC |
163 | const ECX_KEY *akey = a->pkey.ecx; |
164 | const ECX_KEY *bkey = b->pkey.ecx; | |
756b198d DSH |
165 | |
166 | if (akey == NULL || bkey == NULL) | |
167 | return -2; | |
13735cfe MC |
168 | |
169 | return CRYPTO_memcmp(akey->pubkey, bkey->pubkey, KEYLEN(a)) == 0; | |
756b198d DSH |
170 | } |
171 | ||
245c6bc3 | 172 | static int ecx_priv_decode(EVP_PKEY *pkey, const PKCS8_PRIV_KEY_INFO *p8) |
756b198d DSH |
173 | { |
174 | const unsigned char *p; | |
175 | int plen; | |
176 | ASN1_OCTET_STRING *oct = NULL; | |
245c6bc3 | 177 | const X509_ALGOR *palg; |
756b198d DSH |
178 | int rv; |
179 | ||
180 | if (!PKCS8_pkey_get0(NULL, &p, &plen, &palg, p8)) | |
181 | return 0; | |
182 | ||
183 | oct = d2i_ASN1_OCTET_STRING(NULL, &p, plen); | |
184 | if (oct == NULL) { | |
185 | p = NULL; | |
186 | plen = 0; | |
187 | } else { | |
17ebf85a | 188 | p = ASN1_STRING_get0_data(oct); |
756b198d DSH |
189 | plen = ASN1_STRING_length(oct); |
190 | } | |
191 | ||
13735cfe | 192 | rv = ecx_key_op(pkey, pkey->ameth->pkey_id, palg, p, plen, KEY_OP_PRIVATE); |
756b198d DSH |
193 | ASN1_OCTET_STRING_free(oct); |
194 | return rv; | |
195 | } | |
196 | ||
197 | static int ecx_priv_encode(PKCS8_PRIV_KEY_INFO *p8, const EVP_PKEY *pkey) | |
198 | { | |
13735cfe | 199 | const ECX_KEY *ecxkey = pkey->pkey.ecx; |
756b198d DSH |
200 | ASN1_OCTET_STRING oct; |
201 | unsigned char *penc = NULL; | |
202 | int penclen; | |
203 | ||
13735cfe | 204 | if (ecxkey == NULL || ecxkey->privkey == NULL) { |
756b198d DSH |
205 | ECerr(EC_F_ECX_PRIV_ENCODE, EC_R_INVALID_PRIVATE_KEY); |
206 | return 0; | |
207 | } | |
208 | ||
13735cfe MC |
209 | oct.data = ecxkey->privkey; |
210 | oct.length = KEYLEN(pkey); | |
756b198d DSH |
211 | oct.flags = 0; |
212 | ||
213 | penclen = i2d_ASN1_OCTET_STRING(&oct, &penc); | |
214 | if (penclen < 0) { | |
215 | ECerr(EC_F_ECX_PRIV_ENCODE, ERR_R_MALLOC_FAILURE); | |
216 | return 0; | |
217 | } | |
218 | ||
8ecade8b | 219 | if (!PKCS8_pkey_set0(p8, OBJ_nid2obj(pkey->ameth->pkey_id), 0, |
756b198d DSH |
220 | V_ASN1_UNDEF, NULL, penc, penclen)) { |
221 | OPENSSL_clear_free(penc, penclen); | |
222 | ECerr(EC_F_ECX_PRIV_ENCODE, ERR_R_MALLOC_FAILURE); | |
223 | return 0; | |
224 | } | |
225 | ||
226 | return 1; | |
227 | } | |
228 | ||
229 | static int ecx_size(const EVP_PKEY *pkey) | |
230 | { | |
13735cfe | 231 | return KEYLEN(pkey); |
756b198d DSH |
232 | } |
233 | ||
234 | static int ecx_bits(const EVP_PKEY *pkey) | |
235 | { | |
13735cfe MC |
236 | if (IS25519(pkey->ameth->pkey_id)) { |
237 | return X25519_BITS; | |
238 | } else if(ISX448(pkey->ameth->pkey_id)) { | |
239 | return X448_BITS; | |
240 | } else { | |
241 | return ED448_BITS; | |
242 | } | |
756b198d DSH |
243 | } |
244 | ||
245 | static int ecx_security_bits(const EVP_PKEY *pkey) | |
246 | { | |
13735cfe MC |
247 | if (IS25519(pkey->ameth->pkey_id)) { |
248 | return X25519_SECURITY_BITS; | |
249 | } else { | |
250 | return X448_SECURITY_BITS; | |
251 | } | |
756b198d DSH |
252 | } |
253 | ||
254 | static void ecx_free(EVP_PKEY *pkey) | |
255 | { | |
13735cfe MC |
256 | if (pkey->pkey.ecx != NULL) |
257 | OPENSSL_secure_clear_free(pkey->pkey.ecx->privkey, KEYLEN(pkey)); | |
258 | OPENSSL_free(pkey->pkey.ecx); | |
756b198d DSH |
259 | } |
260 | ||
261 | /* "parameters" are always equal */ | |
262 | static int ecx_cmp_parameters(const EVP_PKEY *a, const EVP_PKEY *b) | |
263 | { | |
264 | return 1; | |
265 | } | |
266 | ||
267 | static int ecx_key_print(BIO *bp, const EVP_PKEY *pkey, int indent, | |
268 | ASN1_PCTX *ctx, ecx_key_op_t op) | |
269 | { | |
13735cfe | 270 | const ECX_KEY *ecxkey = pkey->pkey.ecx; |
8ecade8b DSH |
271 | const char *nm = OBJ_nid2ln(pkey->ameth->pkey_id); |
272 | ||
13735cfe MC |
273 | if (op == KEY_OP_PRIVATE) { |
274 | if (ecxkey == NULL || ecxkey->privkey == NULL) { | |
756b198d DSH |
275 | if (BIO_printf(bp, "%*s<INVALID PRIVATE KEY>\n", indent, "") <= 0) |
276 | return 0; | |
277 | return 1; | |
278 | } | |
8ecade8b | 279 | if (BIO_printf(bp, "%*s%s Private-Key:\n", indent, "", nm) <= 0) |
756b198d DSH |
280 | return 0; |
281 | if (BIO_printf(bp, "%*spriv:\n", indent, "") <= 0) | |
282 | return 0; | |
13735cfe MC |
283 | if (ASN1_buf_print(bp, ecxkey->privkey, KEYLEN(pkey), |
284 | indent + 4) == 0) | |
756b198d DSH |
285 | return 0; |
286 | } else { | |
13735cfe | 287 | if (ecxkey == NULL) { |
756b198d DSH |
288 | if (BIO_printf(bp, "%*s<INVALID PUBLIC KEY>\n", indent, "") <= 0) |
289 | return 0; | |
290 | return 1; | |
291 | } | |
8ecade8b | 292 | if (BIO_printf(bp, "%*s%s Public-Key:\n", indent, "", nm) <= 0) |
756b198d DSH |
293 | return 0; |
294 | } | |
295 | if (BIO_printf(bp, "%*spub:\n", indent, "") <= 0) | |
296 | return 0; | |
13735cfe MC |
297 | |
298 | if (ASN1_buf_print(bp, ecxkey->pubkey, KEYLEN(pkey), | |
299 | indent + 4) == 0) | |
756b198d DSH |
300 | return 0; |
301 | return 1; | |
302 | } | |
303 | ||
304 | static int ecx_priv_print(BIO *bp, const EVP_PKEY *pkey, int indent, | |
305 | ASN1_PCTX *ctx) | |
306 | { | |
13735cfe | 307 | return ecx_key_print(bp, pkey, indent, ctx, KEY_OP_PRIVATE); |
756b198d DSH |
308 | } |
309 | ||
310 | static int ecx_pub_print(BIO *bp, const EVP_PKEY *pkey, int indent, | |
311 | ASN1_PCTX *ctx) | |
312 | { | |
13735cfe | 313 | return ecx_key_print(bp, pkey, indent, ctx, KEY_OP_PUBLIC); |
756b198d DSH |
314 | } |
315 | ||
316 | static int ecx_ctrl(EVP_PKEY *pkey, int op, long arg1, void *arg2) | |
317 | { | |
5d6aaf8a DSH |
318 | switch (op) { |
319 | ||
320 | case ASN1_PKEY_CTRL_SET1_TLS_ENCPT: | |
13735cfe MC |
321 | return ecx_key_op(pkey, pkey->ameth->pkey_id, NULL, arg2, arg1, |
322 | KEY_OP_PUBLIC); | |
5d6aaf8a DSH |
323 | |
324 | case ASN1_PKEY_CTRL_GET1_TLS_ENCPT: | |
13735cfe | 325 | if (pkey->pkey.ecx != NULL) { |
5d6aaf8a | 326 | unsigned char **ppt = arg2; |
13735cfe MC |
327 | |
328 | *ppt = OPENSSL_memdup(pkey->pkey.ecx->pubkey, KEYLEN(pkey)); | |
5d6aaf8a | 329 | if (*ppt != NULL) |
13735cfe | 330 | return KEYLEN(pkey); |
5d6aaf8a DSH |
331 | } |
332 | return 0; | |
333 | ||
aabbc24e MC |
334 | default: |
335 | return -2; | |
336 | ||
337 | } | |
338 | } | |
339 | ||
340 | static int ecd_ctrl(EVP_PKEY *pkey, int op, long arg1, void *arg2) | |
341 | { | |
342 | switch (op) { | |
5d6aaf8a | 343 | case ASN1_PKEY_CTRL_DEFAULT_MD_NID: |
aabbc24e MC |
344 | /* We currently only support Pure EdDSA which takes no digest */ |
345 | *(int *)arg2 = NID_undef; | |
5d6aaf8a DSH |
346 | return 2; |
347 | ||
348 | default: | |
349 | return -2; | |
350 | ||
351 | } | |
756b198d DSH |
352 | } |
353 | ||
cc8b15c7 MC |
354 | static int ecx_set_priv_key(EVP_PKEY *pkey, const unsigned char *priv, |
355 | size_t len) | |
356 | { | |
357 | return ecx_key_op(pkey, pkey->ameth->pkey_id, NULL, priv, len, | |
358 | KEY_OP_PRIVATE); | |
359 | } | |
360 | ||
361 | static int ecx_set_pub_key(EVP_PKEY *pkey, const unsigned char *pub, size_t len) | |
362 | { | |
363 | return ecx_key_op(pkey, pkey->ameth->pkey_id, NULL, pub, len, | |
364 | KEY_OP_PUBLIC); | |
365 | } | |
366 | ||
0d124b0a MC |
367 | static int ecx_get_priv_key(const EVP_PKEY *pkey, unsigned char *priv, |
368 | size_t *len) | |
369 | { | |
370 | const ECX_KEY *key = pkey->pkey.ecx; | |
371 | ||
372 | if (priv == NULL) { | |
373 | *len = KEYLENID(pkey->ameth->pkey_id); | |
374 | return 1; | |
375 | } | |
376 | ||
377 | if (key == NULL | |
378 | || key->privkey == NULL | |
379 | || *len < (size_t)KEYLENID(pkey->ameth->pkey_id)) | |
380 | return 0; | |
381 | ||
382 | *len = KEYLENID(pkey->ameth->pkey_id); | |
383 | memcpy(priv, key->privkey, *len); | |
384 | ||
385 | return 1; | |
386 | } | |
387 | ||
388 | static int ecx_get_pub_key(const EVP_PKEY *pkey, unsigned char *pub, | |
389 | size_t *len) | |
390 | { | |
391 | const ECX_KEY *key = pkey->pkey.ecx; | |
392 | ||
393 | if (pub == NULL) { | |
394 | *len = KEYLENID(pkey->ameth->pkey_id); | |
395 | return 1; | |
396 | } | |
397 | ||
398 | if (key == NULL | |
399 | || *len < (size_t)KEYLENID(pkey->ameth->pkey_id)) | |
400 | return 0; | |
401 | ||
402 | *len = KEYLENID(pkey->ameth->pkey_id); | |
403 | memcpy(pub, key->pubkey, *len); | |
404 | ||
405 | return 1; | |
406 | } | |
407 | ||
756b198d | 408 | const EVP_PKEY_ASN1_METHOD ecx25519_asn1_meth = { |
d2916a5b DSH |
409 | EVP_PKEY_X25519, |
410 | EVP_PKEY_X25519, | |
756b198d DSH |
411 | 0, |
412 | "X25519", | |
413 | "OpenSSL X25519 algorithm", | |
414 | ||
415 | ecx_pub_decode, | |
416 | ecx_pub_encode, | |
417 | ecx_pub_cmp, | |
418 | ecx_pub_print, | |
419 | ||
420 | ecx_priv_decode, | |
421 | ecx_priv_encode, | |
422 | ecx_priv_print, | |
423 | ||
424 | ecx_size, | |
425 | ecx_bits, | |
426 | ecx_security_bits, | |
427 | ||
428 | 0, 0, 0, 0, | |
429 | ecx_cmp_parameters, | |
430 | 0, 0, | |
431 | ||
432 | ecx_free, | |
433 | ecx_ctrl, | |
434 | NULL, | |
cc8b15c7 MC |
435 | NULL, |
436 | ||
437 | NULL, | |
438 | NULL, | |
439 | NULL, | |
440 | ||
441 | NULL, | |
442 | NULL, | |
443 | NULL, | |
444 | ||
445 | ecx_set_priv_key, | |
446 | ecx_set_pub_key, | |
0d124b0a MC |
447 | ecx_get_priv_key, |
448 | ecx_get_pub_key, | |
756b198d DSH |
449 | }; |
450 | ||
13735cfe MC |
451 | const EVP_PKEY_ASN1_METHOD ecx448_asn1_meth = { |
452 | EVP_PKEY_X448, | |
453 | EVP_PKEY_X448, | |
454 | 0, | |
455 | "X448", | |
456 | "OpenSSL X448 algorithm", | |
457 | ||
458 | ecx_pub_decode, | |
459 | ecx_pub_encode, | |
460 | ecx_pub_cmp, | |
461 | ecx_pub_print, | |
462 | ||
463 | ecx_priv_decode, | |
464 | ecx_priv_encode, | |
465 | ecx_priv_print, | |
466 | ||
467 | ecx_size, | |
468 | ecx_bits, | |
469 | ecx_security_bits, | |
470 | ||
471 | 0, 0, 0, 0, | |
472 | ecx_cmp_parameters, | |
473 | 0, 0, | |
474 | ||
475 | ecx_free, | |
476 | ecx_ctrl, | |
477 | NULL, | |
cc8b15c7 MC |
478 | NULL, |
479 | ||
480 | NULL, | |
481 | NULL, | |
482 | NULL, | |
483 | ||
484 | NULL, | |
485 | NULL, | |
486 | NULL, | |
487 | ||
488 | ecx_set_priv_key, | |
489 | ecx_set_pub_key, | |
0d124b0a MC |
490 | ecx_get_priv_key, |
491 | ecx_get_pub_key, | |
13735cfe MC |
492 | }; |
493 | ||
494 | static int ecd_size25519(const EVP_PKEY *pkey) | |
8ecade8b DSH |
495 | { |
496 | return ED25519_SIGSIZE; | |
497 | } | |
498 | ||
13735cfe MC |
499 | static int ecd_size448(const EVP_PKEY *pkey) |
500 | { | |
501 | return ED448_SIGSIZE; | |
502 | } | |
503 | ||
9f98fbad DSH |
504 | static int ecd_item_verify(EVP_MD_CTX *ctx, const ASN1_ITEM *it, void *asn, |
505 | X509_ALGOR *sigalg, ASN1_BIT_STRING *str, | |
506 | EVP_PKEY *pkey) | |
507 | { | |
508 | const ASN1_OBJECT *obj; | |
509 | int ptype; | |
13735cfe | 510 | int nid; |
9f98fbad | 511 | |
13735cfe | 512 | /* Sanity check: make sure it is ED25519/ED448 with absent parameters */ |
9f98fbad | 513 | X509_ALGOR_get0(&obj, &ptype, NULL, sigalg); |
13735cfe MC |
514 | nid = OBJ_obj2nid(obj); |
515 | if ((nid != NID_ED25519 && nid != NID_ED448) || ptype != V_ASN1_UNDEF) { | |
9f98fbad DSH |
516 | ECerr(EC_F_ECD_ITEM_VERIFY, EC_R_INVALID_ENCODING); |
517 | return 0; | |
518 | } | |
519 | ||
520 | if (!EVP_DigestVerifyInit(ctx, NULL, NULL, NULL, pkey)) | |
521 | return 0; | |
522 | ||
523 | return 2; | |
524 | } | |
525 | ||
13735cfe MC |
526 | static int ecd_item_sign25519(EVP_MD_CTX *ctx, const ASN1_ITEM *it, void *asn, |
527 | X509_ALGOR *alg1, X509_ALGOR *alg2, | |
528 | ASN1_BIT_STRING *str) | |
9f98fbad DSH |
529 | { |
530 | /* Set algorithms identifiers */ | |
531 | X509_ALGOR_set0(alg1, OBJ_nid2obj(NID_ED25519), V_ASN1_UNDEF, NULL); | |
532 | if (alg2) | |
533 | X509_ALGOR_set0(alg2, OBJ_nid2obj(NID_ED25519), V_ASN1_UNDEF, NULL); | |
534 | /* Algorithm idetifiers set: carry on as normal */ | |
535 | return 3; | |
536 | } | |
537 | ||
13735cfe MC |
538 | static int ecd_sig_info_set25519(X509_SIG_INFO *siginf, const X509_ALGOR *alg, |
539 | const ASN1_STRING *sig) | |
684c41c8 DSH |
540 | { |
541 | X509_SIG_INFO_set(siginf, NID_undef, NID_ED25519, X25519_SECURITY_BITS, | |
542 | X509_SIG_INFO_TLS); | |
543 | return 1; | |
544 | } | |
545 | ||
13735cfe MC |
546 | static int ecd_item_sign448(EVP_MD_CTX *ctx, const ASN1_ITEM *it, void *asn, |
547 | X509_ALGOR *alg1, X509_ALGOR *alg2, | |
548 | ASN1_BIT_STRING *str) | |
549 | { | |
550 | /* Set algorithm identifier */ | |
551 | X509_ALGOR_set0(alg1, OBJ_nid2obj(NID_ED448), V_ASN1_UNDEF, NULL); | |
552 | if (alg2 != NULL) | |
553 | X509_ALGOR_set0(alg2, OBJ_nid2obj(NID_ED448), V_ASN1_UNDEF, NULL); | |
554 | /* Algorithm identifier set: carry on as normal */ | |
555 | return 3; | |
556 | } | |
557 | ||
558 | static int ecd_sig_info_set448(X509_SIG_INFO *siginf, const X509_ALGOR *alg, | |
559 | const ASN1_STRING *sig) | |
560 | { | |
561 | X509_SIG_INFO_set(siginf, NID_undef, NID_ED448, X448_SECURITY_BITS, | |
562 | X509_SIG_INFO_TLS); | |
563 | return 1; | |
564 | } | |
565 | ||
566 | ||
8ecade8b | 567 | const EVP_PKEY_ASN1_METHOD ed25519_asn1_meth = { |
d2916a5b DSH |
568 | EVP_PKEY_ED25519, |
569 | EVP_PKEY_ED25519, | |
8ecade8b DSH |
570 | 0, |
571 | "ED25519", | |
572 | "OpenSSL ED25519 algorithm", | |
573 | ||
574 | ecx_pub_decode, | |
575 | ecx_pub_encode, | |
576 | ecx_pub_cmp, | |
577 | ecx_pub_print, | |
578 | ||
579 | ecx_priv_decode, | |
580 | ecx_priv_encode, | |
581 | ecx_priv_print, | |
582 | ||
13735cfe MC |
583 | ecd_size25519, |
584 | ecx_bits, | |
585 | ecx_security_bits, | |
586 | ||
587 | 0, 0, 0, 0, | |
588 | ecx_cmp_parameters, | |
589 | 0, 0, | |
590 | ||
591 | ecx_free, | |
aabbc24e | 592 | ecd_ctrl, |
13735cfe MC |
593 | NULL, |
594 | NULL, | |
595 | ecd_item_verify, | |
596 | ecd_item_sign25519, | |
cc8b15c7 MC |
597 | ecd_sig_info_set25519, |
598 | ||
599 | NULL, | |
600 | NULL, | |
601 | NULL, | |
602 | ||
603 | ecx_set_priv_key, | |
604 | ecx_set_pub_key, | |
0d124b0a MC |
605 | ecx_get_priv_key, |
606 | ecx_get_pub_key, | |
13735cfe MC |
607 | }; |
608 | ||
609 | const EVP_PKEY_ASN1_METHOD ed448_asn1_meth = { | |
610 | EVP_PKEY_ED448, | |
611 | EVP_PKEY_ED448, | |
612 | 0, | |
613 | "ED448", | |
614 | "OpenSSL ED448 algorithm", | |
615 | ||
616 | ecx_pub_decode, | |
617 | ecx_pub_encode, | |
618 | ecx_pub_cmp, | |
619 | ecx_pub_print, | |
620 | ||
621 | ecx_priv_decode, | |
622 | ecx_priv_encode, | |
623 | ecx_priv_print, | |
624 | ||
625 | ecd_size448, | |
8ecade8b DSH |
626 | ecx_bits, |
627 | ecx_security_bits, | |
628 | ||
629 | 0, 0, 0, 0, | |
630 | ecx_cmp_parameters, | |
631 | 0, 0, | |
632 | ||
633 | ecx_free, | |
aabbc24e | 634 | ecd_ctrl, |
8ecade8b | 635 | NULL, |
9f98fbad DSH |
636 | NULL, |
637 | ecd_item_verify, | |
13735cfe | 638 | ecd_item_sign448, |
cc8b15c7 MC |
639 | ecd_sig_info_set448, |
640 | ||
641 | NULL, | |
642 | NULL, | |
643 | NULL, | |
644 | ||
645 | ecx_set_priv_key, | |
646 | ecx_set_pub_key, | |
0d124b0a MC |
647 | ecx_get_priv_key, |
648 | ecx_get_pub_key, | |
8ecade8b DSH |
649 | }; |
650 | ||
756b198d DSH |
651 | static int pkey_ecx_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey) |
652 | { | |
13735cfe | 653 | return ecx_key_op(pkey, ctx->pmeth->pkey_id, NULL, NULL, 0, KEY_OP_KEYGEN); |
756b198d DSH |
654 | } |
655 | ||
13735cfe MC |
656 | static int validate_ecx_derive(EVP_PKEY_CTX *ctx, unsigned char *key, |
657 | size_t *keylen, | |
658 | const unsigned char **privkey, | |
659 | const unsigned char **pubkey) | |
756b198d | 660 | { |
13735cfe | 661 | const ECX_KEY *ecxkey, *peerkey; |
756b198d DSH |
662 | |
663 | if (ctx->pkey == NULL || ctx->peerkey == NULL) { | |
13735cfe | 664 | ECerr(EC_F_VALIDATE_ECX_DERIVE, EC_R_KEYS_NOT_SET); |
756b198d DSH |
665 | return 0; |
666 | } | |
13735cfe MC |
667 | ecxkey = ctx->pkey->pkey.ecx; |
668 | peerkey = ctx->peerkey->pkey.ecx; | |
669 | if (ecxkey == NULL || ecxkey->privkey == NULL) { | |
670 | ECerr(EC_F_VALIDATE_ECX_DERIVE, EC_R_INVALID_PRIVATE_KEY); | |
756b198d DSH |
671 | return 0; |
672 | } | |
673 | if (peerkey == NULL) { | |
13735cfe | 674 | ECerr(EC_F_VALIDATE_ECX_DERIVE, EC_R_INVALID_PEER_KEY); |
756b198d DSH |
675 | return 0; |
676 | } | |
13735cfe MC |
677 | *privkey = ecxkey->privkey; |
678 | *pubkey = peerkey->pubkey; | |
679 | ||
680 | return 1; | |
681 | } | |
682 | ||
683 | static int pkey_ecx_derive25519(EVP_PKEY_CTX *ctx, unsigned char *key, | |
684 | size_t *keylen) | |
685 | { | |
686 | const unsigned char *privkey, *pubkey; | |
687 | ||
688 | if (!validate_ecx_derive(ctx, key, keylen, &privkey, &pubkey) | |
689 | || (key != NULL | |
690 | && X25519(key, privkey, pubkey) == 0)) | |
691 | return 0; | |
756b198d | 692 | *keylen = X25519_KEYLEN; |
13735cfe MC |
693 | return 1; |
694 | } | |
695 | ||
696 | static int pkey_ecx_derive448(EVP_PKEY_CTX *ctx, unsigned char *key, | |
697 | size_t *keylen) | |
698 | { | |
699 | const unsigned char *privkey, *pubkey; | |
700 | ||
701 | if (!validate_ecx_derive(ctx, key, keylen, &privkey, &pubkey) | |
702 | || (key != NULL | |
703 | && X448(key, privkey, pubkey) == 0)) | |
756b198d | 704 | return 0; |
13735cfe | 705 | *keylen = X448_KEYLEN; |
756b198d DSH |
706 | return 1; |
707 | } | |
708 | ||
709 | static int pkey_ecx_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2) | |
710 | { | |
711 | /* Only need to handle peer key for derivation */ | |
712 | if (type == EVP_PKEY_CTRL_PEER_KEY) | |
713 | return 1; | |
714 | return -2; | |
715 | } | |
716 | ||
717 | const EVP_PKEY_METHOD ecx25519_pkey_meth = { | |
d2916a5b | 718 | EVP_PKEY_X25519, |
756b198d DSH |
719 | 0, 0, 0, 0, 0, 0, 0, |
720 | pkey_ecx_keygen, | |
721 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
13735cfe | 722 | pkey_ecx_derive25519, |
756b198d DSH |
723 | pkey_ecx_ctrl, |
724 | 0 | |
725 | }; | |
42a3008a | 726 | |
13735cfe MC |
727 | const EVP_PKEY_METHOD ecx448_pkey_meth = { |
728 | EVP_PKEY_X448, | |
729 | 0, 0, 0, 0, 0, 0, 0, | |
730 | pkey_ecx_keygen, | |
731 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
732 | pkey_ecx_derive448, | |
733 | pkey_ecx_ctrl, | |
734 | 0 | |
735 | }; | |
736 | ||
07824f30 MC |
737 | static int pkey_ecd_digestsign25519(EVP_MD_CTX *ctx, unsigned char *sig, |
738 | size_t *siglen, const unsigned char *tbs, | |
739 | size_t tbslen) | |
42a3008a | 740 | { |
07824f30 | 741 | const ECX_KEY *edkey = EVP_MD_CTX_pkey_ctx(ctx)->pkey->pkey.ecx; |
42a3008a DSH |
742 | |
743 | if (sig == NULL) { | |
744 | *siglen = ED25519_SIGSIZE; | |
745 | return 1; | |
746 | } | |
747 | if (*siglen < ED25519_SIGSIZE) { | |
07824f30 | 748 | ECerr(EC_F_PKEY_ECD_DIGESTSIGN25519, EC_R_BUFFER_TOO_SMALL); |
42a3008a DSH |
749 | return 0; |
750 | } | |
751 | ||
752 | if (ED25519_sign(sig, tbs, tbslen, edkey->pubkey, edkey->privkey) == 0) | |
753 | return 0; | |
754 | *siglen = ED25519_SIGSIZE; | |
755 | return 1; | |
756 | } | |
757 | ||
07824f30 MC |
758 | static int pkey_ecd_digestsign448(EVP_MD_CTX *ctx, unsigned char *sig, |
759 | size_t *siglen, const unsigned char *tbs, | |
760 | size_t tbslen) | |
13735cfe | 761 | { |
07824f30 | 762 | const ECX_KEY *edkey = EVP_MD_CTX_pkey_ctx(ctx)->pkey->pkey.ecx; |
13735cfe MC |
763 | |
764 | if (sig == NULL) { | |
765 | *siglen = ED448_SIGSIZE; | |
766 | return 1; | |
767 | } | |
768 | if (*siglen < ED448_SIGSIZE) { | |
07824f30 | 769 | ECerr(EC_F_PKEY_ECD_DIGESTSIGN448, EC_R_BUFFER_TOO_SMALL); |
13735cfe MC |
770 | return 0; |
771 | } | |
772 | ||
773 | if (ED448_sign(sig, tbs, tbslen, edkey->pubkey, edkey->privkey, NULL, | |
774 | 0) == 0) | |
775 | return 0; | |
776 | *siglen = ED448_SIGSIZE; | |
777 | return 1; | |
778 | } | |
779 | ||
07824f30 MC |
780 | static int pkey_ecd_digestverify25519(EVP_MD_CTX *ctx, const unsigned char *sig, |
781 | size_t siglen, const unsigned char *tbs, | |
782 | size_t tbslen) | |
42a3008a | 783 | { |
07824f30 | 784 | const ECX_KEY *edkey = EVP_MD_CTX_pkey_ctx(ctx)->pkey->pkey.ecx; |
42a3008a DSH |
785 | |
786 | if (siglen != ED25519_SIGSIZE) | |
787 | return 0; | |
788 | ||
789 | return ED25519_verify(tbs, tbslen, sig, edkey->pubkey); | |
790 | } | |
791 | ||
07824f30 MC |
792 | static int pkey_ecd_digestverify448(EVP_MD_CTX *ctx, const unsigned char *sig, |
793 | size_t siglen, const unsigned char *tbs, | |
794 | size_t tbslen) | |
13735cfe | 795 | { |
07824f30 | 796 | const ECX_KEY *edkey = EVP_MD_CTX_pkey_ctx(ctx)->pkey->pkey.ecx; |
13735cfe MC |
797 | |
798 | if (siglen != ED448_SIGSIZE) | |
799 | return 0; | |
800 | ||
801 | return ED448_verify(tbs, tbslen, sig, edkey->pubkey, NULL, 0); | |
802 | } | |
803 | ||
42a3008a DSH |
804 | static int pkey_ecd_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2) |
805 | { | |
806 | switch (type) { | |
807 | case EVP_PKEY_CTRL_MD: | |
808 | /* Only NULL allowed as digest */ | |
f3021aca | 809 | if (p2 == NULL || (const EVP_MD *)p2 == EVP_md_null()) |
42a3008a DSH |
810 | return 1; |
811 | ECerr(EC_F_PKEY_ECD_CTRL, EC_R_INVALID_DIGEST_TYPE); | |
812 | return 0; | |
813 | ||
814 | case EVP_PKEY_CTRL_DIGESTINIT: | |
815 | return 1; | |
816 | } | |
817 | return -2; | |
818 | } | |
819 | ||
820 | const EVP_PKEY_METHOD ed25519_pkey_meth = { | |
d2916a5b | 821 | EVP_PKEY_ED25519, EVP_PKEY_FLAG_SIGCTX_CUSTOM, |
42a3008a DSH |
822 | 0, 0, 0, 0, 0, 0, |
823 | pkey_ecx_keygen, | |
07824f30 | 824 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
42a3008a DSH |
825 | pkey_ecd_ctrl, |
826 | 0, | |
13735cfe MC |
827 | pkey_ecd_digestsign25519, |
828 | pkey_ecd_digestverify25519 | |
829 | }; | |
830 | ||
831 | const EVP_PKEY_METHOD ed448_pkey_meth = { | |
832 | EVP_PKEY_ED448, EVP_PKEY_FLAG_SIGCTX_CUSTOM, | |
833 | 0, 0, 0, 0, 0, 0, | |
834 | pkey_ecx_keygen, | |
07824f30 | 835 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
13735cfe MC |
836 | pkey_ecd_ctrl, |
837 | 0, | |
838 | pkey_ecd_digestsign448, | |
839 | pkey_ecd_digestverify448 | |
42a3008a | 840 | }; |