]>
Commit | Line | Data |
---|---|---|
756b198d | 1 | /* |
b0edda11 | 2 | * Copyright 2006-2018 The OpenSSL Project Authors. All Rights Reserved. |
756b198d DSH |
3 | * |
4 | * Licensed under the OpenSSL license (the "License"). You may not use | |
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 | ||
334 | case ASN1_PKEY_CTRL_DEFAULT_MD_NID: | |
335 | *(int *)arg2 = NID_sha256; | |
336 | return 2; | |
337 | ||
338 | default: | |
339 | return -2; | |
340 | ||
341 | } | |
756b198d DSH |
342 | } |
343 | ||
cc8b15c7 MC |
344 | static int ecx_set_priv_key(EVP_PKEY *pkey, const unsigned char *priv, |
345 | size_t len) | |
346 | { | |
347 | return ecx_key_op(pkey, pkey->ameth->pkey_id, NULL, priv, len, | |
348 | KEY_OP_PRIVATE); | |
349 | } | |
350 | ||
351 | static int ecx_set_pub_key(EVP_PKEY *pkey, const unsigned char *pub, size_t len) | |
352 | { | |
353 | return ecx_key_op(pkey, pkey->ameth->pkey_id, NULL, pub, len, | |
354 | KEY_OP_PUBLIC); | |
355 | } | |
356 | ||
0d124b0a MC |
357 | static int ecx_get_priv_key(const EVP_PKEY *pkey, unsigned char *priv, |
358 | size_t *len) | |
359 | { | |
360 | const ECX_KEY *key = pkey->pkey.ecx; | |
361 | ||
362 | if (priv == NULL) { | |
363 | *len = KEYLENID(pkey->ameth->pkey_id); | |
364 | return 1; | |
365 | } | |
366 | ||
367 | if (key == NULL | |
368 | || key->privkey == NULL | |
369 | || *len < (size_t)KEYLENID(pkey->ameth->pkey_id)) | |
370 | return 0; | |
371 | ||
372 | *len = KEYLENID(pkey->ameth->pkey_id); | |
373 | memcpy(priv, key->privkey, *len); | |
374 | ||
375 | return 1; | |
376 | } | |
377 | ||
378 | static int ecx_get_pub_key(const EVP_PKEY *pkey, unsigned char *pub, | |
379 | size_t *len) | |
380 | { | |
381 | const ECX_KEY *key = pkey->pkey.ecx; | |
382 | ||
383 | if (pub == NULL) { | |
384 | *len = KEYLENID(pkey->ameth->pkey_id); | |
385 | return 1; | |
386 | } | |
387 | ||
388 | if (key == NULL | |
389 | || *len < (size_t)KEYLENID(pkey->ameth->pkey_id)) | |
390 | return 0; | |
391 | ||
392 | *len = KEYLENID(pkey->ameth->pkey_id); | |
393 | memcpy(pub, key->pubkey, *len); | |
394 | ||
395 | return 1; | |
396 | } | |
397 | ||
756b198d | 398 | const EVP_PKEY_ASN1_METHOD ecx25519_asn1_meth = { |
d2916a5b DSH |
399 | EVP_PKEY_X25519, |
400 | EVP_PKEY_X25519, | |
756b198d DSH |
401 | 0, |
402 | "X25519", | |
403 | "OpenSSL X25519 algorithm", | |
404 | ||
405 | ecx_pub_decode, | |
406 | ecx_pub_encode, | |
407 | ecx_pub_cmp, | |
408 | ecx_pub_print, | |
409 | ||
410 | ecx_priv_decode, | |
411 | ecx_priv_encode, | |
412 | ecx_priv_print, | |
413 | ||
414 | ecx_size, | |
415 | ecx_bits, | |
416 | ecx_security_bits, | |
417 | ||
418 | 0, 0, 0, 0, | |
419 | ecx_cmp_parameters, | |
420 | 0, 0, | |
421 | ||
422 | ecx_free, | |
423 | ecx_ctrl, | |
424 | NULL, | |
cc8b15c7 MC |
425 | NULL, |
426 | ||
427 | NULL, | |
428 | NULL, | |
429 | NULL, | |
430 | ||
431 | NULL, | |
432 | NULL, | |
433 | NULL, | |
434 | ||
435 | ecx_set_priv_key, | |
436 | ecx_set_pub_key, | |
0d124b0a MC |
437 | ecx_get_priv_key, |
438 | ecx_get_pub_key, | |
756b198d DSH |
439 | }; |
440 | ||
13735cfe MC |
441 | const EVP_PKEY_ASN1_METHOD ecx448_asn1_meth = { |
442 | EVP_PKEY_X448, | |
443 | EVP_PKEY_X448, | |
444 | 0, | |
445 | "X448", | |
446 | "OpenSSL X448 algorithm", | |
447 | ||
448 | ecx_pub_decode, | |
449 | ecx_pub_encode, | |
450 | ecx_pub_cmp, | |
451 | ecx_pub_print, | |
452 | ||
453 | ecx_priv_decode, | |
454 | ecx_priv_encode, | |
455 | ecx_priv_print, | |
456 | ||
457 | ecx_size, | |
458 | ecx_bits, | |
459 | ecx_security_bits, | |
460 | ||
461 | 0, 0, 0, 0, | |
462 | ecx_cmp_parameters, | |
463 | 0, 0, | |
464 | ||
465 | ecx_free, | |
466 | ecx_ctrl, | |
467 | NULL, | |
cc8b15c7 MC |
468 | NULL, |
469 | ||
470 | NULL, | |
471 | NULL, | |
472 | NULL, | |
473 | ||
474 | NULL, | |
475 | NULL, | |
476 | NULL, | |
477 | ||
478 | ecx_set_priv_key, | |
479 | ecx_set_pub_key, | |
0d124b0a MC |
480 | ecx_get_priv_key, |
481 | ecx_get_pub_key, | |
13735cfe MC |
482 | }; |
483 | ||
484 | static int ecd_size25519(const EVP_PKEY *pkey) | |
8ecade8b DSH |
485 | { |
486 | return ED25519_SIGSIZE; | |
487 | } | |
488 | ||
13735cfe MC |
489 | static int ecd_size448(const EVP_PKEY *pkey) |
490 | { | |
491 | return ED448_SIGSIZE; | |
492 | } | |
493 | ||
9f98fbad DSH |
494 | static int ecd_item_verify(EVP_MD_CTX *ctx, const ASN1_ITEM *it, void *asn, |
495 | X509_ALGOR *sigalg, ASN1_BIT_STRING *str, | |
496 | EVP_PKEY *pkey) | |
497 | { | |
498 | const ASN1_OBJECT *obj; | |
499 | int ptype; | |
13735cfe | 500 | int nid; |
9f98fbad | 501 | |
13735cfe | 502 | /* Sanity check: make sure it is ED25519/ED448 with absent parameters */ |
9f98fbad | 503 | X509_ALGOR_get0(&obj, &ptype, NULL, sigalg); |
13735cfe MC |
504 | nid = OBJ_obj2nid(obj); |
505 | if ((nid != NID_ED25519 && nid != NID_ED448) || ptype != V_ASN1_UNDEF) { | |
9f98fbad DSH |
506 | ECerr(EC_F_ECD_ITEM_VERIFY, EC_R_INVALID_ENCODING); |
507 | return 0; | |
508 | } | |
509 | ||
510 | if (!EVP_DigestVerifyInit(ctx, NULL, NULL, NULL, pkey)) | |
511 | return 0; | |
512 | ||
513 | return 2; | |
514 | } | |
515 | ||
13735cfe MC |
516 | static int ecd_item_sign25519(EVP_MD_CTX *ctx, const ASN1_ITEM *it, void *asn, |
517 | X509_ALGOR *alg1, X509_ALGOR *alg2, | |
518 | ASN1_BIT_STRING *str) | |
9f98fbad DSH |
519 | { |
520 | /* Set algorithms identifiers */ | |
521 | X509_ALGOR_set0(alg1, OBJ_nid2obj(NID_ED25519), V_ASN1_UNDEF, NULL); | |
522 | if (alg2) | |
523 | X509_ALGOR_set0(alg2, OBJ_nid2obj(NID_ED25519), V_ASN1_UNDEF, NULL); | |
524 | /* Algorithm idetifiers set: carry on as normal */ | |
525 | return 3; | |
526 | } | |
527 | ||
13735cfe MC |
528 | static int ecd_sig_info_set25519(X509_SIG_INFO *siginf, const X509_ALGOR *alg, |
529 | const ASN1_STRING *sig) | |
684c41c8 DSH |
530 | { |
531 | X509_SIG_INFO_set(siginf, NID_undef, NID_ED25519, X25519_SECURITY_BITS, | |
532 | X509_SIG_INFO_TLS); | |
533 | return 1; | |
534 | } | |
535 | ||
13735cfe MC |
536 | static int ecd_item_sign448(EVP_MD_CTX *ctx, const ASN1_ITEM *it, void *asn, |
537 | X509_ALGOR *alg1, X509_ALGOR *alg2, | |
538 | ASN1_BIT_STRING *str) | |
539 | { | |
540 | /* Set algorithm identifier */ | |
541 | X509_ALGOR_set0(alg1, OBJ_nid2obj(NID_ED448), V_ASN1_UNDEF, NULL); | |
542 | if (alg2 != NULL) | |
543 | X509_ALGOR_set0(alg2, OBJ_nid2obj(NID_ED448), V_ASN1_UNDEF, NULL); | |
544 | /* Algorithm identifier set: carry on as normal */ | |
545 | return 3; | |
546 | } | |
547 | ||
548 | static int ecd_sig_info_set448(X509_SIG_INFO *siginf, const X509_ALGOR *alg, | |
549 | const ASN1_STRING *sig) | |
550 | { | |
551 | X509_SIG_INFO_set(siginf, NID_undef, NID_ED448, X448_SECURITY_BITS, | |
552 | X509_SIG_INFO_TLS); | |
553 | return 1; | |
554 | } | |
555 | ||
556 | ||
8ecade8b | 557 | const EVP_PKEY_ASN1_METHOD ed25519_asn1_meth = { |
d2916a5b DSH |
558 | EVP_PKEY_ED25519, |
559 | EVP_PKEY_ED25519, | |
8ecade8b DSH |
560 | 0, |
561 | "ED25519", | |
562 | "OpenSSL ED25519 algorithm", | |
563 | ||
564 | ecx_pub_decode, | |
565 | ecx_pub_encode, | |
566 | ecx_pub_cmp, | |
567 | ecx_pub_print, | |
568 | ||
569 | ecx_priv_decode, | |
570 | ecx_priv_encode, | |
571 | ecx_priv_print, | |
572 | ||
13735cfe MC |
573 | ecd_size25519, |
574 | ecx_bits, | |
575 | ecx_security_bits, | |
576 | ||
577 | 0, 0, 0, 0, | |
578 | ecx_cmp_parameters, | |
579 | 0, 0, | |
580 | ||
581 | ecx_free, | |
582 | 0, | |
583 | NULL, | |
584 | NULL, | |
585 | ecd_item_verify, | |
586 | ecd_item_sign25519, | |
cc8b15c7 MC |
587 | ecd_sig_info_set25519, |
588 | ||
589 | NULL, | |
590 | NULL, | |
591 | NULL, | |
592 | ||
593 | ecx_set_priv_key, | |
594 | ecx_set_pub_key, | |
0d124b0a MC |
595 | ecx_get_priv_key, |
596 | ecx_get_pub_key, | |
13735cfe MC |
597 | }; |
598 | ||
599 | const EVP_PKEY_ASN1_METHOD ed448_asn1_meth = { | |
600 | EVP_PKEY_ED448, | |
601 | EVP_PKEY_ED448, | |
602 | 0, | |
603 | "ED448", | |
604 | "OpenSSL ED448 algorithm", | |
605 | ||
606 | ecx_pub_decode, | |
607 | ecx_pub_encode, | |
608 | ecx_pub_cmp, | |
609 | ecx_pub_print, | |
610 | ||
611 | ecx_priv_decode, | |
612 | ecx_priv_encode, | |
613 | ecx_priv_print, | |
614 | ||
615 | ecd_size448, | |
8ecade8b DSH |
616 | ecx_bits, |
617 | ecx_security_bits, | |
618 | ||
619 | 0, 0, 0, 0, | |
620 | ecx_cmp_parameters, | |
621 | 0, 0, | |
622 | ||
623 | ecx_free, | |
624 | 0, | |
625 | NULL, | |
9f98fbad DSH |
626 | NULL, |
627 | ecd_item_verify, | |
13735cfe | 628 | ecd_item_sign448, |
cc8b15c7 MC |
629 | ecd_sig_info_set448, |
630 | ||
631 | NULL, | |
632 | NULL, | |
633 | NULL, | |
634 | ||
635 | ecx_set_priv_key, | |
636 | ecx_set_pub_key, | |
0d124b0a MC |
637 | ecx_get_priv_key, |
638 | ecx_get_pub_key, | |
8ecade8b DSH |
639 | }; |
640 | ||
756b198d DSH |
641 | static int pkey_ecx_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey) |
642 | { | |
13735cfe | 643 | return ecx_key_op(pkey, ctx->pmeth->pkey_id, NULL, NULL, 0, KEY_OP_KEYGEN); |
756b198d DSH |
644 | } |
645 | ||
13735cfe MC |
646 | static int validate_ecx_derive(EVP_PKEY_CTX *ctx, unsigned char *key, |
647 | size_t *keylen, | |
648 | const unsigned char **privkey, | |
649 | const unsigned char **pubkey) | |
756b198d | 650 | { |
13735cfe | 651 | const ECX_KEY *ecxkey, *peerkey; |
756b198d DSH |
652 | |
653 | if (ctx->pkey == NULL || ctx->peerkey == NULL) { | |
13735cfe | 654 | ECerr(EC_F_VALIDATE_ECX_DERIVE, EC_R_KEYS_NOT_SET); |
756b198d DSH |
655 | return 0; |
656 | } | |
13735cfe MC |
657 | ecxkey = ctx->pkey->pkey.ecx; |
658 | peerkey = ctx->peerkey->pkey.ecx; | |
659 | if (ecxkey == NULL || ecxkey->privkey == NULL) { | |
660 | ECerr(EC_F_VALIDATE_ECX_DERIVE, EC_R_INVALID_PRIVATE_KEY); | |
756b198d DSH |
661 | return 0; |
662 | } | |
663 | if (peerkey == NULL) { | |
13735cfe | 664 | ECerr(EC_F_VALIDATE_ECX_DERIVE, EC_R_INVALID_PEER_KEY); |
756b198d DSH |
665 | return 0; |
666 | } | |
13735cfe MC |
667 | *privkey = ecxkey->privkey; |
668 | *pubkey = peerkey->pubkey; | |
669 | ||
670 | return 1; | |
671 | } | |
672 | ||
673 | static int pkey_ecx_derive25519(EVP_PKEY_CTX *ctx, unsigned char *key, | |
674 | size_t *keylen) | |
675 | { | |
676 | const unsigned char *privkey, *pubkey; | |
677 | ||
678 | if (!validate_ecx_derive(ctx, key, keylen, &privkey, &pubkey) | |
679 | || (key != NULL | |
680 | && X25519(key, privkey, pubkey) == 0)) | |
681 | return 0; | |
756b198d | 682 | *keylen = X25519_KEYLEN; |
13735cfe MC |
683 | return 1; |
684 | } | |
685 | ||
686 | static int pkey_ecx_derive448(EVP_PKEY_CTX *ctx, unsigned char *key, | |
687 | size_t *keylen) | |
688 | { | |
689 | const unsigned char *privkey, *pubkey; | |
690 | ||
691 | if (!validate_ecx_derive(ctx, key, keylen, &privkey, &pubkey) | |
692 | || (key != NULL | |
693 | && X448(key, privkey, pubkey) == 0)) | |
756b198d | 694 | return 0; |
13735cfe | 695 | *keylen = X448_KEYLEN; |
756b198d DSH |
696 | return 1; |
697 | } | |
698 | ||
699 | static int pkey_ecx_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2) | |
700 | { | |
701 | /* Only need to handle peer key for derivation */ | |
702 | if (type == EVP_PKEY_CTRL_PEER_KEY) | |
703 | return 1; | |
704 | return -2; | |
705 | } | |
706 | ||
707 | const EVP_PKEY_METHOD ecx25519_pkey_meth = { | |
d2916a5b | 708 | EVP_PKEY_X25519, |
756b198d DSH |
709 | 0, 0, 0, 0, 0, 0, 0, |
710 | pkey_ecx_keygen, | |
711 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
13735cfe | 712 | pkey_ecx_derive25519, |
756b198d DSH |
713 | pkey_ecx_ctrl, |
714 | 0 | |
715 | }; | |
42a3008a | 716 | |
13735cfe MC |
717 | const EVP_PKEY_METHOD ecx448_pkey_meth = { |
718 | EVP_PKEY_X448, | |
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, | |
722 | pkey_ecx_derive448, | |
723 | pkey_ecx_ctrl, | |
724 | 0 | |
725 | }; | |
726 | ||
07824f30 MC |
727 | static int pkey_ecd_digestsign25519(EVP_MD_CTX *ctx, unsigned char *sig, |
728 | size_t *siglen, const unsigned char *tbs, | |
729 | size_t tbslen) | |
42a3008a | 730 | { |
07824f30 | 731 | const ECX_KEY *edkey = EVP_MD_CTX_pkey_ctx(ctx)->pkey->pkey.ecx; |
42a3008a DSH |
732 | |
733 | if (sig == NULL) { | |
734 | *siglen = ED25519_SIGSIZE; | |
735 | return 1; | |
736 | } | |
737 | if (*siglen < ED25519_SIGSIZE) { | |
07824f30 | 738 | ECerr(EC_F_PKEY_ECD_DIGESTSIGN25519, EC_R_BUFFER_TOO_SMALL); |
42a3008a DSH |
739 | return 0; |
740 | } | |
741 | ||
742 | if (ED25519_sign(sig, tbs, tbslen, edkey->pubkey, edkey->privkey) == 0) | |
743 | return 0; | |
744 | *siglen = ED25519_SIGSIZE; | |
745 | return 1; | |
746 | } | |
747 | ||
07824f30 MC |
748 | static int pkey_ecd_digestsign448(EVP_MD_CTX *ctx, unsigned char *sig, |
749 | size_t *siglen, const unsigned char *tbs, | |
750 | size_t tbslen) | |
13735cfe | 751 | { |
07824f30 | 752 | const ECX_KEY *edkey = EVP_MD_CTX_pkey_ctx(ctx)->pkey->pkey.ecx; |
13735cfe MC |
753 | |
754 | if (sig == NULL) { | |
755 | *siglen = ED448_SIGSIZE; | |
756 | return 1; | |
757 | } | |
758 | if (*siglen < ED448_SIGSIZE) { | |
07824f30 | 759 | ECerr(EC_F_PKEY_ECD_DIGESTSIGN448, EC_R_BUFFER_TOO_SMALL); |
13735cfe MC |
760 | return 0; |
761 | } | |
762 | ||
763 | if (ED448_sign(sig, tbs, tbslen, edkey->pubkey, edkey->privkey, NULL, | |
764 | 0) == 0) | |
765 | return 0; | |
766 | *siglen = ED448_SIGSIZE; | |
767 | return 1; | |
768 | } | |
769 | ||
07824f30 MC |
770 | static int pkey_ecd_digestverify25519(EVP_MD_CTX *ctx, const unsigned char *sig, |
771 | size_t siglen, const unsigned char *tbs, | |
772 | size_t tbslen) | |
42a3008a | 773 | { |
07824f30 | 774 | const ECX_KEY *edkey = EVP_MD_CTX_pkey_ctx(ctx)->pkey->pkey.ecx; |
42a3008a DSH |
775 | |
776 | if (siglen != ED25519_SIGSIZE) | |
777 | return 0; | |
778 | ||
779 | return ED25519_verify(tbs, tbslen, sig, edkey->pubkey); | |
780 | } | |
781 | ||
07824f30 MC |
782 | static int pkey_ecd_digestverify448(EVP_MD_CTX *ctx, const unsigned char *sig, |
783 | size_t siglen, const unsigned char *tbs, | |
784 | size_t tbslen) | |
13735cfe | 785 | { |
07824f30 | 786 | const ECX_KEY *edkey = EVP_MD_CTX_pkey_ctx(ctx)->pkey->pkey.ecx; |
13735cfe MC |
787 | |
788 | if (siglen != ED448_SIGSIZE) | |
789 | return 0; | |
790 | ||
791 | return ED448_verify(tbs, tbslen, sig, edkey->pubkey, NULL, 0); | |
792 | } | |
793 | ||
42a3008a DSH |
794 | static int pkey_ecd_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2) |
795 | { | |
796 | switch (type) { | |
797 | case EVP_PKEY_CTRL_MD: | |
798 | /* Only NULL allowed as digest */ | |
f3021aca | 799 | if (p2 == NULL || (const EVP_MD *)p2 == EVP_md_null()) |
42a3008a DSH |
800 | return 1; |
801 | ECerr(EC_F_PKEY_ECD_CTRL, EC_R_INVALID_DIGEST_TYPE); | |
802 | return 0; | |
803 | ||
804 | case EVP_PKEY_CTRL_DIGESTINIT: | |
805 | return 1; | |
806 | } | |
807 | return -2; | |
808 | } | |
809 | ||
810 | const EVP_PKEY_METHOD ed25519_pkey_meth = { | |
d2916a5b | 811 | EVP_PKEY_ED25519, EVP_PKEY_FLAG_SIGCTX_CUSTOM, |
42a3008a DSH |
812 | 0, 0, 0, 0, 0, 0, |
813 | pkey_ecx_keygen, | |
07824f30 | 814 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
42a3008a DSH |
815 | pkey_ecd_ctrl, |
816 | 0, | |
13735cfe MC |
817 | pkey_ecd_digestsign25519, |
818 | pkey_ecd_digestverify25519 | |
819 | }; | |
820 | ||
821 | const EVP_PKEY_METHOD ed448_pkey_meth = { | |
822 | EVP_PKEY_ED448, EVP_PKEY_FLAG_SIGCTX_CUSTOM, | |
823 | 0, 0, 0, 0, 0, 0, | |
824 | pkey_ecx_keygen, | |
07824f30 | 825 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
13735cfe MC |
826 | pkey_ecd_ctrl, |
827 | 0, | |
828 | pkey_ecd_digestsign448, | |
829 | pkey_ecd_digestverify448 | |
42a3008a | 830 | }; |