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