xref: /freebsd/crypto/openssl/providers/implementations/keymgmt/ecx_kmgmt.c (revision fe75646a0234a261c0013bf1840fdac4acaf0cec)
1 /*
2  * Copyright 2020-2023 The OpenSSL Project Authors. All Rights Reserved.
3  *
4  * Licensed under the Apache License 2.0 (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 <assert.h>
11 #include <string.h>
12 #include <openssl/core_dispatch.h>
13 #include <openssl/core_names.h>
14 #include <openssl/params.h>
15 #include <openssl/err.h>
16 #include <openssl/proverr.h>
17 #include <openssl/evp.h>
18 #include <openssl/rand.h>
19 #include "internal/param_build_set.h"
20 #include <openssl/param_build.h>
21 #include "crypto/ecx.h"
22 #include "prov/implementations.h"
23 #include "prov/providercommon.h"
24 #include "prov/provider_ctx.h"
25 #ifdef S390X_EC_ASM
26 # include "s390x_arch.h"
27 # include <openssl/sha.h>   /* For SHA512_DIGEST_LENGTH */
28 #endif
29 
30 static OSSL_FUNC_keymgmt_new_fn x25519_new_key;
31 static OSSL_FUNC_keymgmt_new_fn x448_new_key;
32 static OSSL_FUNC_keymgmt_new_fn ed25519_new_key;
33 static OSSL_FUNC_keymgmt_new_fn ed448_new_key;
34 static OSSL_FUNC_keymgmt_gen_init_fn x25519_gen_init;
35 static OSSL_FUNC_keymgmt_gen_init_fn x448_gen_init;
36 static OSSL_FUNC_keymgmt_gen_init_fn ed25519_gen_init;
37 static OSSL_FUNC_keymgmt_gen_init_fn ed448_gen_init;
38 static OSSL_FUNC_keymgmt_gen_fn x25519_gen;
39 static OSSL_FUNC_keymgmt_gen_fn x448_gen;
40 static OSSL_FUNC_keymgmt_gen_fn ed25519_gen;
41 static OSSL_FUNC_keymgmt_gen_fn ed448_gen;
42 static OSSL_FUNC_keymgmt_gen_cleanup_fn ecx_gen_cleanup;
43 static OSSL_FUNC_keymgmt_gen_set_params_fn ecx_gen_set_params;
44 static OSSL_FUNC_keymgmt_gen_settable_params_fn ecx_gen_settable_params;
45 static OSSL_FUNC_keymgmt_load_fn ecx_load;
46 static OSSL_FUNC_keymgmt_get_params_fn x25519_get_params;
47 static OSSL_FUNC_keymgmt_get_params_fn x448_get_params;
48 static OSSL_FUNC_keymgmt_get_params_fn ed25519_get_params;
49 static OSSL_FUNC_keymgmt_get_params_fn ed448_get_params;
50 static OSSL_FUNC_keymgmt_gettable_params_fn x25519_gettable_params;
51 static OSSL_FUNC_keymgmt_gettable_params_fn x448_gettable_params;
52 static OSSL_FUNC_keymgmt_gettable_params_fn ed25519_gettable_params;
53 static OSSL_FUNC_keymgmt_gettable_params_fn ed448_gettable_params;
54 static OSSL_FUNC_keymgmt_set_params_fn x25519_set_params;
55 static OSSL_FUNC_keymgmt_set_params_fn x448_set_params;
56 static OSSL_FUNC_keymgmt_set_params_fn ed25519_set_params;
57 static OSSL_FUNC_keymgmt_set_params_fn ed448_set_params;
58 static OSSL_FUNC_keymgmt_settable_params_fn x25519_settable_params;
59 static OSSL_FUNC_keymgmt_settable_params_fn x448_settable_params;
60 static OSSL_FUNC_keymgmt_settable_params_fn ed25519_settable_params;
61 static OSSL_FUNC_keymgmt_settable_params_fn ed448_settable_params;
62 static OSSL_FUNC_keymgmt_has_fn ecx_has;
63 static OSSL_FUNC_keymgmt_match_fn ecx_match;
64 static OSSL_FUNC_keymgmt_validate_fn x25519_validate;
65 static OSSL_FUNC_keymgmt_validate_fn x448_validate;
66 static OSSL_FUNC_keymgmt_validate_fn ed25519_validate;
67 static OSSL_FUNC_keymgmt_validate_fn ed448_validate;
68 static OSSL_FUNC_keymgmt_import_fn ecx_import;
69 static OSSL_FUNC_keymgmt_import_types_fn ecx_imexport_types;
70 static OSSL_FUNC_keymgmt_export_fn ecx_export;
71 static OSSL_FUNC_keymgmt_export_types_fn ecx_imexport_types;
72 static OSSL_FUNC_keymgmt_dup_fn ecx_dup;
73 
74 #define ECX_POSSIBLE_SELECTIONS (OSSL_KEYMGMT_SELECT_KEYPAIR)
75 
76 struct ecx_gen_ctx {
77     OSSL_LIB_CTX *libctx;
78     char *propq;
79     ECX_KEY_TYPE type;
80     int selection;
81 };
82 
83 #ifdef S390X_EC_ASM
84 static void *s390x_ecx_keygen25519(struct ecx_gen_ctx *gctx);
85 static void *s390x_ecx_keygen448(struct ecx_gen_ctx *gctx);
86 static void *s390x_ecd_keygen25519(struct ecx_gen_ctx *gctx);
87 static void *s390x_ecd_keygen448(struct ecx_gen_ctx *gctx);
88 #endif
89 
90 static void *x25519_new_key(void *provctx)
91 {
92     if (!ossl_prov_is_running())
93         return 0;
94     return ossl_ecx_key_new(PROV_LIBCTX_OF(provctx), ECX_KEY_TYPE_X25519, 0,
95                             NULL);
96 }
97 
98 static void *x448_new_key(void *provctx)
99 {
100     if (!ossl_prov_is_running())
101         return 0;
102     return ossl_ecx_key_new(PROV_LIBCTX_OF(provctx), ECX_KEY_TYPE_X448, 0,
103                             NULL);
104 }
105 
106 static void *ed25519_new_key(void *provctx)
107 {
108     if (!ossl_prov_is_running())
109         return 0;
110     return ossl_ecx_key_new(PROV_LIBCTX_OF(provctx), ECX_KEY_TYPE_ED25519, 0,
111                             NULL);
112 }
113 
114 static void *ed448_new_key(void *provctx)
115 {
116     if (!ossl_prov_is_running())
117         return 0;
118     return ossl_ecx_key_new(PROV_LIBCTX_OF(provctx), ECX_KEY_TYPE_ED448, 0,
119                             NULL);
120 }
121 
122 static int ecx_has(const void *keydata, int selection)
123 {
124     const ECX_KEY *key = keydata;
125     int ok = 0;
126 
127     if (ossl_prov_is_running() && key != NULL) {
128         /*
129          * ECX keys always have all the parameters they need (i.e. none).
130          * Therefore we always return with 1, if asked about parameters.
131          */
132         ok = 1;
133 
134         if ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0)
135             ok = ok && key->haspubkey;
136 
137         if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0)
138             ok = ok && key->privkey != NULL;
139     }
140     return ok;
141 }
142 
143 static int ecx_match(const void *keydata1, const void *keydata2, int selection)
144 {
145     const ECX_KEY *key1 = keydata1;
146     const ECX_KEY *key2 = keydata2;
147     int ok = 1;
148 
149     if (!ossl_prov_is_running())
150         return 0;
151 
152     if ((selection & OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS) != 0)
153         ok = ok && key1->type == key2->type;
154     if ((selection & OSSL_KEYMGMT_SELECT_KEYPAIR) != 0) {
155         int key_checked = 0;
156 
157         if ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0) {
158             const unsigned char *pa = key1->haspubkey ? key1->pubkey : NULL;
159             const unsigned char *pb = key2->haspubkey ? key2->pubkey : NULL;
160             size_t pal = key1->keylen;
161             size_t pbl = key2->keylen;
162 
163             if (pa != NULL && pb != NULL) {
164                 ok = ok
165                     && key1->type == key2->type
166                     && pal == pbl
167                     && CRYPTO_memcmp(pa, pb, pal) == 0;
168                 key_checked = 1;
169             }
170         }
171         if (!key_checked
172             && (selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0) {
173             const unsigned char *pa = key1->privkey;
174             const unsigned char *pb = key2->privkey;
175             size_t pal = key1->keylen;
176             size_t pbl = key2->keylen;
177 
178             if (pa != NULL && pb != NULL) {
179                 ok = ok
180                     && key1->type == key2->type
181                     && pal == pbl
182                     && CRYPTO_memcmp(pa, pb, pal) == 0;
183                 key_checked = 1;
184             }
185         }
186         ok = ok && key_checked;
187     }
188     return ok;
189 }
190 
191 static int ecx_import(void *keydata, int selection, const OSSL_PARAM params[])
192 {
193     ECX_KEY *key = keydata;
194     int ok = 1;
195     int include_private;
196 
197     if (!ossl_prov_is_running() || key == NULL)
198         return 0;
199 
200     if ((selection & OSSL_KEYMGMT_SELECT_KEYPAIR) == 0)
201         return 0;
202 
203     include_private = selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY ? 1 : 0;
204     ok = ok && ossl_ecx_key_fromdata(key, params, include_private);
205 
206     return ok;
207 }
208 
209 static int key_to_params(ECX_KEY *key, OSSL_PARAM_BLD *tmpl,
210                          OSSL_PARAM params[], int include_private)
211 {
212     if (key == NULL)
213         return 0;
214 
215     if (!ossl_param_build_set_octet_string(tmpl, params,
216                                            OSSL_PKEY_PARAM_PUB_KEY,
217                                            key->pubkey, key->keylen))
218         return 0;
219 
220     if (include_private
221         && key->privkey != NULL
222         && !ossl_param_build_set_octet_string(tmpl, params,
223                                               OSSL_PKEY_PARAM_PRIV_KEY,
224                                               key->privkey, key->keylen))
225         return 0;
226 
227     return 1;
228 }
229 
230 static int ecx_export(void *keydata, int selection, OSSL_CALLBACK *param_cb,
231                       void *cbarg)
232 {
233     ECX_KEY *key = keydata;
234     OSSL_PARAM_BLD *tmpl;
235     OSSL_PARAM *params = NULL;
236     int ret = 0;
237 
238     if (!ossl_prov_is_running() || key == NULL)
239         return 0;
240 
241     if ((selection & OSSL_KEYMGMT_SELECT_KEYPAIR) == 0)
242         return 0;
243 
244     tmpl = OSSL_PARAM_BLD_new();
245     if (tmpl == NULL)
246         return 0;
247 
248     if ((selection & OSSL_KEYMGMT_SELECT_KEYPAIR) != 0) {
249         int include_private = ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0);
250 
251         if (!key_to_params(key, tmpl, NULL, include_private))
252             goto err;
253     }
254 
255     params = OSSL_PARAM_BLD_to_param(tmpl);
256     if (params == NULL)
257         goto err;
258 
259     ret = param_cb(params, cbarg);
260     OSSL_PARAM_free(params);
261 err:
262     OSSL_PARAM_BLD_free(tmpl);
263     return ret;
264 }
265 
266 #define ECX_KEY_TYPES()                                                        \
267 OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_PUB_KEY, NULL, 0),                     \
268 OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_PRIV_KEY, NULL, 0)
269 
270 static const OSSL_PARAM ecx_key_types[] = {
271     ECX_KEY_TYPES(),
272     OSSL_PARAM_END
273 };
274 static const OSSL_PARAM *ecx_imexport_types(int selection)
275 {
276     if ((selection & OSSL_KEYMGMT_SELECT_KEYPAIR) != 0)
277         return ecx_key_types;
278     return NULL;
279 }
280 
281 static int ecx_get_params(void *key, OSSL_PARAM params[], int bits, int secbits,
282                           int size)
283 {
284     ECX_KEY *ecx = key;
285     OSSL_PARAM *p;
286 
287     if ((p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_BITS)) != NULL
288         && !OSSL_PARAM_set_int(p, bits))
289         return 0;
290     if ((p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_SECURITY_BITS)) != NULL
291         && !OSSL_PARAM_set_int(p, secbits))
292         return 0;
293     if ((p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_MAX_SIZE)) != NULL
294         && !OSSL_PARAM_set_int(p, size))
295         return 0;
296     if ((p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY)) != NULL
297             && (ecx->type == ECX_KEY_TYPE_X25519
298                 || ecx->type == ECX_KEY_TYPE_X448)) {
299         if (!OSSL_PARAM_set_octet_string(p, ecx->pubkey, ecx->keylen))
300             return 0;
301     }
302 
303     return key_to_params(ecx, NULL, params, 1);
304 }
305 
306 static int ed_get_params(void *key, OSSL_PARAM params[])
307 {
308     OSSL_PARAM *p;
309 
310     if ((p = OSSL_PARAM_locate(params,
311                                OSSL_PKEY_PARAM_MANDATORY_DIGEST)) != NULL
312         && !OSSL_PARAM_set_utf8_string(p, ""))
313         return 0;
314     return 1;
315 }
316 
317 static int x25519_get_params(void *key, OSSL_PARAM params[])
318 {
319     return ecx_get_params(key, params, X25519_BITS, X25519_SECURITY_BITS,
320                           X25519_KEYLEN);
321 }
322 
323 static int x448_get_params(void *key, OSSL_PARAM params[])
324 {
325     return ecx_get_params(key, params, X448_BITS, X448_SECURITY_BITS,
326                           X448_KEYLEN);
327 }
328 
329 static int ed25519_get_params(void *key, OSSL_PARAM params[])
330 {
331     return ecx_get_params(key, params, ED25519_BITS, ED25519_SECURITY_BITS,
332                           ED25519_SIGSIZE)
333         && ed_get_params(key, params);
334 }
335 
336 static int ed448_get_params(void *key, OSSL_PARAM params[])
337 {
338     return ecx_get_params(key, params, ED448_BITS, ED448_SECURITY_BITS,
339                           ED448_SIGSIZE)
340         && ed_get_params(key, params);
341 }
342 
343 static const OSSL_PARAM ecx_gettable_params[] = {
344     OSSL_PARAM_int(OSSL_PKEY_PARAM_BITS, NULL),
345     OSSL_PARAM_int(OSSL_PKEY_PARAM_SECURITY_BITS, NULL),
346     OSSL_PARAM_int(OSSL_PKEY_PARAM_MAX_SIZE, NULL),
347     OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_MANDATORY_DIGEST, NULL, 0),
348     OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY, NULL, 0),
349     ECX_KEY_TYPES(),
350     OSSL_PARAM_END
351 };
352 
353 static const OSSL_PARAM ed_gettable_params[] = {
354     OSSL_PARAM_int(OSSL_PKEY_PARAM_BITS, NULL),
355     OSSL_PARAM_int(OSSL_PKEY_PARAM_SECURITY_BITS, NULL),
356     OSSL_PARAM_int(OSSL_PKEY_PARAM_MAX_SIZE, NULL),
357     ECX_KEY_TYPES(),
358     OSSL_PARAM_END
359 };
360 
361 static const OSSL_PARAM *x25519_gettable_params(void *provctx)
362 {
363     return ecx_gettable_params;
364 }
365 
366 static const OSSL_PARAM *x448_gettable_params(void *provctx)
367 {
368     return ecx_gettable_params;
369 }
370 
371 static const OSSL_PARAM *ed25519_gettable_params(void *provctx)
372 {
373     return ed_gettable_params;
374 }
375 
376 static const OSSL_PARAM *ed448_gettable_params(void *provctx)
377 {
378     return ed_gettable_params;
379 }
380 
381 static int set_property_query(ECX_KEY *ecxkey, const char *propq)
382 {
383     OPENSSL_free(ecxkey->propq);
384     ecxkey->propq = NULL;
385     if (propq != NULL) {
386         ecxkey->propq = OPENSSL_strdup(propq);
387         if (ecxkey->propq == NULL) {
388             ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE);
389             return 0;
390         }
391     }
392     return 1;
393 }
394 
395 static int ecx_set_params(void *key, const OSSL_PARAM params[])
396 {
397     ECX_KEY *ecxkey = key;
398     const OSSL_PARAM *p;
399 
400     if (params == NULL)
401         return 1;
402 
403     p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY);
404     if (p != NULL) {
405         void *buf = ecxkey->pubkey;
406 
407         if (p->data_size != ecxkey->keylen
408                 || !OSSL_PARAM_get_octet_string(p, &buf, sizeof(ecxkey->pubkey),
409                                                 NULL))
410             return 0;
411         OPENSSL_clear_free(ecxkey->privkey, ecxkey->keylen);
412         ecxkey->privkey = NULL;
413         ecxkey->haspubkey = 1;
414     }
415     p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_PROPERTIES);
416     if (p != NULL) {
417         if (p->data_type != OSSL_PARAM_UTF8_STRING
418             || !set_property_query(ecxkey, p->data))
419             return 0;
420     }
421 
422     return 1;
423 }
424 
425 static int x25519_set_params(void *key, const OSSL_PARAM params[])
426 {
427     return ecx_set_params(key, params);
428 }
429 
430 static int x448_set_params(void *key, const OSSL_PARAM params[])
431 {
432     return ecx_set_params(key, params);
433 }
434 
435 static int ed25519_set_params(void *key, const OSSL_PARAM params[])
436 {
437     return 1;
438 }
439 
440 static int ed448_set_params(void *key, const OSSL_PARAM params[])
441 {
442     return 1;
443 }
444 
445 static const OSSL_PARAM ecx_settable_params[] = {
446     OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY, NULL, 0),
447     OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_PROPERTIES, NULL, 0),
448     OSSL_PARAM_END
449 };
450 
451 static const OSSL_PARAM ed_settable_params[] = {
452     OSSL_PARAM_END
453 };
454 
455 static const OSSL_PARAM *x25519_settable_params(void *provctx)
456 {
457     return ecx_settable_params;
458 }
459 
460 static const OSSL_PARAM *x448_settable_params(void *provctx)
461 {
462     return ecx_settable_params;
463 }
464 
465 static const OSSL_PARAM *ed25519_settable_params(void *provctx)
466 {
467     return ed_settable_params;
468 }
469 
470 static const OSSL_PARAM *ed448_settable_params(void *provctx)
471 {
472     return ed_settable_params;
473 }
474 
475 static void *ecx_gen_init(void *provctx, int selection,
476                           const OSSL_PARAM params[], ECX_KEY_TYPE type)
477 {
478     OSSL_LIB_CTX *libctx = PROV_LIBCTX_OF(provctx);
479     struct ecx_gen_ctx *gctx = NULL;
480 
481     if (!ossl_prov_is_running())
482         return NULL;
483 
484     if ((gctx = OPENSSL_zalloc(sizeof(*gctx))) != NULL) {
485         gctx->libctx = libctx;
486         gctx->type = type;
487         gctx->selection = selection;
488     }
489     if (!ecx_gen_set_params(gctx, params)) {
490         OPENSSL_free(gctx);
491         gctx = NULL;
492     }
493     return gctx;
494 }
495 
496 static void *x25519_gen_init(void *provctx, int selection,
497                              const OSSL_PARAM params[])
498 {
499     return ecx_gen_init(provctx, selection, params, ECX_KEY_TYPE_X25519);
500 }
501 
502 static void *x448_gen_init(void *provctx, int selection,
503                            const OSSL_PARAM params[])
504 {
505     return ecx_gen_init(provctx, selection, params, ECX_KEY_TYPE_X448);
506 }
507 
508 static void *ed25519_gen_init(void *provctx, int selection,
509                               const OSSL_PARAM params[])
510 {
511     return ecx_gen_init(provctx, selection, params, ECX_KEY_TYPE_ED25519);
512 }
513 
514 static void *ed448_gen_init(void *provctx, int selection,
515                             const OSSL_PARAM params[])
516 {
517     return ecx_gen_init(provctx, selection, params, ECX_KEY_TYPE_ED448);
518 }
519 
520 static int ecx_gen_set_params(void *genctx, const OSSL_PARAM params[])
521 {
522     struct ecx_gen_ctx *gctx = genctx;
523     const OSSL_PARAM *p;
524 
525     if (gctx == NULL)
526         return 0;
527 
528     p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_GROUP_NAME);
529     if (p != NULL) {
530         const char *groupname = NULL;
531 
532         /*
533          * We optionally allow setting a group name - but each algorithm only
534          * support one such name, so all we do is verify that it is the one we
535          * expected.
536          */
537         switch (gctx->type) {
538             case ECX_KEY_TYPE_X25519:
539                 groupname = "x25519";
540                 break;
541             case ECX_KEY_TYPE_X448:
542                 groupname = "x448";
543                 break;
544             default:
545                 /* We only support this for key exchange at the moment */
546                 break;
547         }
548         if (p->data_type != OSSL_PARAM_UTF8_STRING
549                 || groupname == NULL
550                 || OPENSSL_strcasecmp(p->data, groupname) != 0) {
551             ERR_raise(ERR_LIB_PROV, ERR_R_PASSED_INVALID_ARGUMENT);
552             return 0;
553         }
554     }
555     p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_PROPERTIES);
556     if (p != NULL) {
557         if (p->data_type != OSSL_PARAM_UTF8_STRING)
558             return 0;
559         OPENSSL_free(gctx->propq);
560         gctx->propq = OPENSSL_strdup(p->data);
561         if (gctx->propq == NULL)
562             return 0;
563     }
564 
565     return 1;
566 }
567 
568 static const OSSL_PARAM *ecx_gen_settable_params(ossl_unused void *genctx,
569                                                  ossl_unused void *provctx)
570 {
571     static OSSL_PARAM settable[] = {
572         OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_GROUP_NAME, NULL, 0),
573         OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_PROPERTIES, NULL, 0),
574         OSSL_PARAM_END
575     };
576     return settable;
577 }
578 
579 static void *ecx_gen(struct ecx_gen_ctx *gctx)
580 {
581     ECX_KEY *key;
582     unsigned char *privkey;
583 
584     if (gctx == NULL)
585         return NULL;
586     if ((key = ossl_ecx_key_new(gctx->libctx, gctx->type, 0,
587                                 gctx->propq)) == NULL) {
588         ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE);
589         return NULL;
590     }
591 
592     /* If we're doing parameter generation then we just return a blank key */
593     if ((gctx->selection & OSSL_KEYMGMT_SELECT_KEYPAIR) == 0)
594         return key;
595 
596     if ((privkey = ossl_ecx_key_allocate_privkey(key)) == NULL) {
597         ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE);
598         goto err;
599     }
600     if (RAND_priv_bytes_ex(gctx->libctx, privkey, key->keylen, 0) <= 0)
601         goto err;
602     switch (gctx->type) {
603     case ECX_KEY_TYPE_X25519:
604         privkey[0] &= 248;
605         privkey[X25519_KEYLEN - 1] &= 127;
606         privkey[X25519_KEYLEN - 1] |= 64;
607         ossl_x25519_public_from_private(key->pubkey, privkey);
608         break;
609     case ECX_KEY_TYPE_X448:
610         privkey[0] &= 252;
611         privkey[X448_KEYLEN - 1] |= 128;
612         ossl_x448_public_from_private(key->pubkey, privkey);
613         break;
614     case ECX_KEY_TYPE_ED25519:
615         if (!ossl_ed25519_public_from_private(gctx->libctx, key->pubkey, privkey,
616                                               gctx->propq))
617             goto err;
618         break;
619     case ECX_KEY_TYPE_ED448:
620         if (!ossl_ed448_public_from_private(gctx->libctx, key->pubkey, privkey,
621                                             gctx->propq))
622             goto err;
623         break;
624     }
625     key->haspubkey = 1;
626     return key;
627 err:
628     ossl_ecx_key_free(key);
629     return NULL;
630 }
631 
632 static void *x25519_gen(void *genctx, OSSL_CALLBACK *osslcb, void *cbarg)
633 {
634     struct ecx_gen_ctx *gctx = genctx;
635 
636     if (!ossl_prov_is_running())
637         return 0;
638 
639 #ifdef S390X_EC_ASM
640     if (OPENSSL_s390xcap_P.pcc[1] & S390X_CAPBIT(S390X_SCALAR_MULTIPLY_X25519))
641         return s390x_ecx_keygen25519(gctx);
642 #endif
643     return ecx_gen(gctx);
644 }
645 
646 static void *x448_gen(void *genctx, OSSL_CALLBACK *osslcb, void *cbarg)
647 {
648     struct ecx_gen_ctx *gctx = genctx;
649 
650     if (!ossl_prov_is_running())
651         return 0;
652 
653 #ifdef S390X_EC_ASM
654     if (OPENSSL_s390xcap_P.pcc[1] & S390X_CAPBIT(S390X_SCALAR_MULTIPLY_X448))
655         return s390x_ecx_keygen448(gctx);
656 #endif
657     return ecx_gen(gctx);
658 }
659 
660 static void *ed25519_gen(void *genctx, OSSL_CALLBACK *osslcb, void *cbarg)
661 {
662     struct ecx_gen_ctx *gctx = genctx;
663 
664     if (!ossl_prov_is_running())
665         return 0;
666 
667 #ifdef S390X_EC_ASM
668     if (OPENSSL_s390xcap_P.pcc[1] & S390X_CAPBIT(S390X_SCALAR_MULTIPLY_ED25519)
669         && OPENSSL_s390xcap_P.kdsa[0] & S390X_CAPBIT(S390X_EDDSA_SIGN_ED25519)
670         && OPENSSL_s390xcap_P.kdsa[0]
671             & S390X_CAPBIT(S390X_EDDSA_VERIFY_ED25519))
672         return s390x_ecd_keygen25519(gctx);
673 #endif
674     return ecx_gen(gctx);
675 }
676 
677 static void *ed448_gen(void *genctx, OSSL_CALLBACK *osslcb, void *cbarg)
678 {
679     struct ecx_gen_ctx *gctx = genctx;
680 
681     if (!ossl_prov_is_running())
682         return 0;
683 
684 #ifdef S390X_EC_ASM
685     if (OPENSSL_s390xcap_P.pcc[1] & S390X_CAPBIT(S390X_SCALAR_MULTIPLY_ED448)
686         && OPENSSL_s390xcap_P.kdsa[0] & S390X_CAPBIT(S390X_EDDSA_SIGN_ED448)
687         && OPENSSL_s390xcap_P.kdsa[0] & S390X_CAPBIT(S390X_EDDSA_VERIFY_ED448))
688         return s390x_ecd_keygen448(gctx);
689 #endif
690     return ecx_gen(gctx);
691 }
692 
693 static void ecx_gen_cleanup(void *genctx)
694 {
695     struct ecx_gen_ctx *gctx = genctx;
696 
697     OPENSSL_free(gctx->propq);
698     OPENSSL_free(gctx);
699 }
700 
701 void *ecx_load(const void *reference, size_t reference_sz)
702 {
703     ECX_KEY *key = NULL;
704 
705     if (ossl_prov_is_running() && reference_sz == sizeof(key)) {
706         /* The contents of the reference is the address to our object */
707         key = *(ECX_KEY **)reference;
708         /* We grabbed, so we detach it */
709         *(ECX_KEY **)reference = NULL;
710         return key;
711     }
712     return NULL;
713 }
714 
715 static void *ecx_dup(const void *keydata_from, int selection)
716 {
717     if (ossl_prov_is_running())
718         return ossl_ecx_key_dup(keydata_from, selection);
719     return NULL;
720 }
721 
722 static int ecx_key_pairwise_check(const ECX_KEY *ecx, int type)
723 {
724     uint8_t pub[64];
725 
726     switch (type) {
727     case ECX_KEY_TYPE_X25519:
728         ossl_x25519_public_from_private(pub, ecx->privkey);
729         break;
730     case ECX_KEY_TYPE_X448:
731         ossl_x448_public_from_private(pub, ecx->privkey);
732         break;
733     case ECX_KEY_TYPE_ED25519:
734         if (!ossl_ed25519_public_from_private(ecx->libctx, pub, ecx->privkey,
735                                               ecx->propq))
736             return 0;
737         break;
738     case ECX_KEY_TYPE_ED448:
739         if (!ossl_ed448_public_from_private(ecx->libctx, pub, ecx->privkey,
740                                             ecx->propq))
741             return 0;
742         break;
743     default:
744         return 0;
745     }
746     return CRYPTO_memcmp(ecx->pubkey, pub, ecx->keylen) == 0;
747 }
748 
749 static int ecx_validate(const void *keydata, int selection, int type, size_t keylen)
750 {
751     const ECX_KEY *ecx = keydata;
752     int ok = keylen == ecx->keylen;
753 
754     if (!ossl_prov_is_running())
755         return 0;
756 
757     if ((selection & ECX_POSSIBLE_SELECTIONS) == 0)
758         return 1; /* nothing to validate */
759 
760     if (!ok) {
761         ERR_raise(ERR_LIB_PROV, PROV_R_ALGORITHM_MISMATCH);
762         return 0;
763     }
764 
765     if ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0)
766         ok = ok && ecx->haspubkey;
767 
768     if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0)
769         ok = ok && ecx->privkey != NULL;
770 
771     if ((selection & OSSL_KEYMGMT_SELECT_KEYPAIR) == OSSL_KEYMGMT_SELECT_KEYPAIR)
772         ok = ok && ecx_key_pairwise_check(ecx, type);
773 
774     return ok;
775 }
776 
777 static int x25519_validate(const void *keydata, int selection, int checktype)
778 {
779     return ecx_validate(keydata, selection, ECX_KEY_TYPE_X25519, X25519_KEYLEN);
780 }
781 
782 static int x448_validate(const void *keydata, int selection, int checktype)
783 {
784     return ecx_validate(keydata, selection, ECX_KEY_TYPE_X448, X448_KEYLEN);
785 }
786 
787 static int ed25519_validate(const void *keydata, int selection, int checktype)
788 {
789     return ecx_validate(keydata, selection, ECX_KEY_TYPE_ED25519, ED25519_KEYLEN);
790 }
791 
792 static int ed448_validate(const void *keydata, int selection, int checktype)
793 {
794     return ecx_validate(keydata, selection, ECX_KEY_TYPE_ED448, ED448_KEYLEN);
795 }
796 
797 #define MAKE_KEYMGMT_FUNCTIONS(alg) \
798     const OSSL_DISPATCH ossl_##alg##_keymgmt_functions[] = { \
799         { OSSL_FUNC_KEYMGMT_NEW, (void (*)(void))alg##_new_key }, \
800         { OSSL_FUNC_KEYMGMT_FREE, (void (*)(void))ossl_ecx_key_free }, \
801         { OSSL_FUNC_KEYMGMT_GET_PARAMS, (void (*) (void))alg##_get_params }, \
802         { OSSL_FUNC_KEYMGMT_GETTABLE_PARAMS, (void (*) (void))alg##_gettable_params }, \
803         { OSSL_FUNC_KEYMGMT_SET_PARAMS, (void (*) (void))alg##_set_params }, \
804         { OSSL_FUNC_KEYMGMT_SETTABLE_PARAMS, (void (*) (void))alg##_settable_params }, \
805         { OSSL_FUNC_KEYMGMT_HAS, (void (*)(void))ecx_has }, \
806         { OSSL_FUNC_KEYMGMT_MATCH, (void (*)(void))ecx_match }, \
807         { OSSL_FUNC_KEYMGMT_VALIDATE, (void (*)(void))alg##_validate }, \
808         { OSSL_FUNC_KEYMGMT_IMPORT, (void (*)(void))ecx_import }, \
809         { OSSL_FUNC_KEYMGMT_IMPORT_TYPES, (void (*)(void))ecx_imexport_types }, \
810         { OSSL_FUNC_KEYMGMT_EXPORT, (void (*)(void))ecx_export }, \
811         { OSSL_FUNC_KEYMGMT_EXPORT_TYPES, (void (*)(void))ecx_imexport_types }, \
812         { OSSL_FUNC_KEYMGMT_GEN_INIT, (void (*)(void))alg##_gen_init }, \
813         { OSSL_FUNC_KEYMGMT_GEN_SET_PARAMS, (void (*)(void))ecx_gen_set_params }, \
814         { OSSL_FUNC_KEYMGMT_GEN_SETTABLE_PARAMS, \
815           (void (*)(void))ecx_gen_settable_params }, \
816         { OSSL_FUNC_KEYMGMT_GEN, (void (*)(void))alg##_gen }, \
817         { OSSL_FUNC_KEYMGMT_GEN_CLEANUP, (void (*)(void))ecx_gen_cleanup }, \
818         { OSSL_FUNC_KEYMGMT_LOAD, (void (*)(void))ecx_load }, \
819         { OSSL_FUNC_KEYMGMT_DUP, (void (*)(void))ecx_dup }, \
820         { 0, NULL } \
821     };
822 
823 MAKE_KEYMGMT_FUNCTIONS(x25519)
824 MAKE_KEYMGMT_FUNCTIONS(x448)
825 MAKE_KEYMGMT_FUNCTIONS(ed25519)
826 MAKE_KEYMGMT_FUNCTIONS(ed448)
827 
828 #ifdef S390X_EC_ASM
829 # include "s390x_arch.h"
830 
831 static void *s390x_ecx_keygen25519(struct ecx_gen_ctx *gctx)
832 {
833     static const unsigned char generator[] = {
834         0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
835         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
836         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
837     };
838     ECX_KEY *key = ossl_ecx_key_new(gctx->libctx, ECX_KEY_TYPE_X25519, 1,
839                                     gctx->propq);
840     unsigned char *privkey = NULL, *pubkey;
841 
842     if (key == NULL) {
843         ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE);
844         goto err;
845     }
846 
847     /* If we're doing parameter generation then we just return a blank key */
848     if ((gctx->selection & OSSL_KEYMGMT_SELECT_KEYPAIR) == 0)
849         return key;
850 
851     pubkey = key->pubkey;
852 
853     privkey = ossl_ecx_key_allocate_privkey(key);
854     if (privkey == NULL) {
855         ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE);
856         goto err;
857     }
858 
859     if (RAND_priv_bytes_ex(gctx->libctx, privkey, X25519_KEYLEN, 0) <= 0)
860         goto err;
861 
862     privkey[0] &= 248;
863     privkey[31] &= 127;
864     privkey[31] |= 64;
865 
866     if (s390x_x25519_mul(pubkey, generator, privkey) != 1)
867         goto err;
868     key->haspubkey = 1;
869     return key;
870  err:
871     ossl_ecx_key_free(key);
872     return NULL;
873 }
874 
875 static void *s390x_ecx_keygen448(struct ecx_gen_ctx *gctx)
876 {
877     static const unsigned char generator[] = {
878         0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
879         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
880         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
881         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
882         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
883     };
884     ECX_KEY *key = ossl_ecx_key_new(gctx->libctx, ECX_KEY_TYPE_X448, 1,
885                                     gctx->propq);
886     unsigned char *privkey = NULL, *pubkey;
887 
888     if (key == NULL) {
889         ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE);
890         goto err;
891     }
892 
893     /* If we're doing parameter generation then we just return a blank key */
894     if ((gctx->selection & OSSL_KEYMGMT_SELECT_KEYPAIR) == 0)
895         return key;
896 
897     pubkey = key->pubkey;
898 
899     privkey = ossl_ecx_key_allocate_privkey(key);
900     if (privkey == NULL) {
901         ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE);
902         goto err;
903     }
904 
905     if (RAND_priv_bytes_ex(gctx->libctx, privkey, X448_KEYLEN, 0) <= 0)
906         goto err;
907 
908     privkey[0] &= 252;
909     privkey[55] |= 128;
910 
911     if (s390x_x448_mul(pubkey, generator, privkey) != 1)
912         goto err;
913     key->haspubkey = 1;
914     return key;
915  err:
916     ossl_ecx_key_free(key);
917     return NULL;
918 }
919 
920 static void *s390x_ecd_keygen25519(struct ecx_gen_ctx *gctx)
921 {
922     static const unsigned char generator_x[] = {
923         0x1a, 0xd5, 0x25, 0x8f, 0x60, 0x2d, 0x56, 0xc9, 0xb2, 0xa7, 0x25, 0x95,
924         0x60, 0xc7, 0x2c, 0x69, 0x5c, 0xdc, 0xd6, 0xfd, 0x31, 0xe2, 0xa4, 0xc0,
925         0xfe, 0x53, 0x6e, 0xcd, 0xd3, 0x36, 0x69, 0x21
926     };
927     static const unsigned char generator_y[] = {
928         0x58, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
929         0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
930         0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
931     };
932     unsigned char x_dst[32], buff[SHA512_DIGEST_LENGTH];
933     ECX_KEY *key = ossl_ecx_key_new(gctx->libctx, ECX_KEY_TYPE_ED25519, 1,
934                                     gctx->propq);
935     unsigned char *privkey = NULL, *pubkey;
936     unsigned int sz;
937     EVP_MD *sha = NULL;
938     int j;
939 
940     if (key == NULL) {
941         ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE);
942         goto err;
943     }
944 
945     /* If we're doing parameter generation then we just return a blank key */
946     if ((gctx->selection & OSSL_KEYMGMT_SELECT_KEYPAIR) == 0)
947         return key;
948 
949     pubkey = key->pubkey;
950 
951     privkey = ossl_ecx_key_allocate_privkey(key);
952     if (privkey == NULL) {
953         ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE);
954         goto err;
955     }
956 
957     if (RAND_priv_bytes_ex(gctx->libctx, privkey, ED25519_KEYLEN, 0) <= 0)
958         goto err;
959 
960     sha = EVP_MD_fetch(gctx->libctx, "SHA512", gctx->propq);
961     if (sha == NULL)
962         goto err;
963     j = EVP_Digest(privkey, 32, buff, &sz, sha, NULL);
964     EVP_MD_free(sha);
965     if (!j)
966         goto err;
967 
968     buff[0] &= 248;
969     buff[31] &= 63;
970     buff[31] |= 64;
971 
972     if (s390x_ed25519_mul(x_dst, pubkey,
973                           generator_x, generator_y, buff) != 1)
974         goto err;
975 
976     pubkey[31] |= ((x_dst[0] & 0x01) << 7);
977     key->haspubkey = 1;
978     return key;
979  err:
980     ossl_ecx_key_free(key);
981     return NULL;
982 }
983 
984 static void *s390x_ecd_keygen448(struct ecx_gen_ctx *gctx)
985 {
986     static const unsigned char generator_x[] = {
987         0x5e, 0xc0, 0x0c, 0xc7, 0x2b, 0xa8, 0x26, 0x26, 0x8e, 0x93, 0x00, 0x8b,
988         0xe1, 0x80, 0x3b, 0x43, 0x11, 0x65, 0xb6, 0x2a, 0xf7, 0x1a, 0xae, 0x12,
989         0x64, 0xa4, 0xd3, 0xa3, 0x24, 0xe3, 0x6d, 0xea, 0x67, 0x17, 0x0f, 0x47,
990         0x70, 0x65, 0x14, 0x9e, 0xda, 0x36, 0xbf, 0x22, 0xa6, 0x15, 0x1d, 0x22,
991         0xed, 0x0d, 0xed, 0x6b, 0xc6, 0x70, 0x19, 0x4f, 0x00
992     };
993     static const unsigned char generator_y[] = {
994         0x14, 0xfa, 0x30, 0xf2, 0x5b, 0x79, 0x08, 0x98, 0xad, 0xc8, 0xd7, 0x4e,
995         0x2c, 0x13, 0xbd, 0xfd, 0xc4, 0x39, 0x7c, 0xe6, 0x1c, 0xff, 0xd3, 0x3a,
996         0xd7, 0xc2, 0xa0, 0x05, 0x1e, 0x9c, 0x78, 0x87, 0x40, 0x98, 0xa3, 0x6c,
997         0x73, 0x73, 0xea, 0x4b, 0x62, 0xc7, 0xc9, 0x56, 0x37, 0x20, 0x76, 0x88,
998         0x24, 0xbc, 0xb6, 0x6e, 0x71, 0x46, 0x3f, 0x69, 0x00
999     };
1000     unsigned char x_dst[57], buff[114];
1001     ECX_KEY *key = ossl_ecx_key_new(gctx->libctx, ECX_KEY_TYPE_ED448, 1,
1002                                     gctx->propq);
1003     unsigned char *privkey = NULL, *pubkey;
1004     EVP_MD_CTX *hashctx = NULL;
1005     EVP_MD *shake = NULL;
1006 
1007     if (key == NULL) {
1008         ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE);
1009         goto err;
1010     }
1011 
1012     /* If we're doing parameter generation then we just return a blank key */
1013     if ((gctx->selection & OSSL_KEYMGMT_SELECT_KEYPAIR) == 0)
1014         return key;
1015 
1016     pubkey = key->pubkey;
1017 
1018     privkey = ossl_ecx_key_allocate_privkey(key);
1019     if (privkey == NULL) {
1020         ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE);
1021         goto err;
1022     }
1023 
1024     shake = EVP_MD_fetch(gctx->libctx, "SHAKE256", gctx->propq);
1025     if (shake == NULL)
1026         goto err;
1027     if (RAND_priv_bytes_ex(gctx->libctx, privkey, ED448_KEYLEN, 0) <= 0)
1028         goto err;
1029 
1030     hashctx = EVP_MD_CTX_new();
1031     if (hashctx == NULL)
1032         goto err;
1033     if (EVP_DigestInit_ex(hashctx, shake, NULL) != 1)
1034         goto err;
1035     if (EVP_DigestUpdate(hashctx, privkey, 57) != 1)
1036         goto err;
1037     if (EVP_DigestFinalXOF(hashctx, buff, sizeof(buff)) != 1)
1038         goto err;
1039 
1040     buff[0] &= -4;
1041     buff[55] |= 0x80;
1042     buff[56] = 0;
1043 
1044     if (s390x_ed448_mul(x_dst, pubkey,
1045                         generator_x, generator_y, buff) != 1)
1046         goto err;
1047 
1048     pubkey[56] |= ((x_dst[0] & 0x01) << 7);
1049     EVP_MD_CTX_free(hashctx);
1050     EVP_MD_free(shake);
1051     key->haspubkey = 1;
1052     return key;
1053  err:
1054     ossl_ecx_key_free(key);
1055     EVP_MD_CTX_free(hashctx);
1056     EVP_MD_free(shake);
1057     return NULL;
1058 }
1059 #endif
1060