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