s390: ECX key generation fixes.
[openssl.git] / providers / implementations / keymgmt / ecx_kmgmt.c
1 /*
2  * Copyright 2020 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 <openssl/core_numbers.h>
12 #include <openssl/core_names.h>
13 #include <openssl/params.h>
14 #include <openssl/err.h>
15 #include <openssl/evp.h>
16 #include <openssl/rand.h>
17 #include "internal/param_build_set.h"
18 #include "openssl/param_build.h"
19 #include "crypto/ecx.h"
20 #include "prov/implementations.h"
21 #include "prov/providercommon.h"
22 #include "prov/provider_ctx.h"
23 #ifdef S390X_EC_ASM
24 # include "s390x_arch.h"
25 # include <openssl/sha.h>   /* For SHA512_DIGEST_LENGTH */
26 #endif
27
28 static OSSL_OP_keymgmt_new_fn x25519_new_key;
29 static OSSL_OP_keymgmt_new_fn x448_new_key;
30 static OSSL_OP_keymgmt_new_fn ed25519_new_key;
31 static OSSL_OP_keymgmt_new_fn ed448_new_key;
32 static OSSL_OP_keymgmt_gen_init_fn x25519_gen_init;
33 static OSSL_OP_keymgmt_gen_init_fn x448_gen_init;
34 static OSSL_OP_keymgmt_gen_init_fn ed25519_gen_init;
35 static OSSL_OP_keymgmt_gen_init_fn ed448_gen_init;
36 static OSSL_OP_keymgmt_gen_fn x25519_gen;
37 static OSSL_OP_keymgmt_gen_fn x448_gen;
38 static OSSL_OP_keymgmt_gen_fn ed25519_gen;
39 static OSSL_OP_keymgmt_gen_fn ed448_gen;
40 static OSSL_OP_keymgmt_gen_cleanup_fn ecx_gen_cleanup;
41 static OSSL_OP_keymgmt_get_params_fn x25519_get_params;
42 static OSSL_OP_keymgmt_get_params_fn x448_get_params;
43 static OSSL_OP_keymgmt_get_params_fn ed25519_get_params;
44 static OSSL_OP_keymgmt_get_params_fn ed448_get_params;
45 static OSSL_OP_keymgmt_gettable_params_fn ecx_gettable_params;
46 static OSSL_OP_keymgmt_has_fn ecx_has;
47 static OSSL_OP_keymgmt_import_fn ecx_import;
48 static OSSL_OP_keymgmt_import_types_fn ecx_imexport_types;
49 static OSSL_OP_keymgmt_export_fn ecx_export;
50 static OSSL_OP_keymgmt_export_types_fn ecx_imexport_types;
51
52 #define ECX_POSSIBLE_SELECTIONS (OSSL_KEYMGMT_SELECT_KEYPAIR)
53
54 struct ecx_gen_ctx {
55     OPENSSL_CTX *libctx;
56     ECX_KEY_TYPE type;
57 };
58
59 #ifdef S390X_EC_ASM
60 static void *s390x_ecx_keygen25519(struct ecx_gen_ctx *gctx);
61 static void *s390x_ecx_keygen448(struct ecx_gen_ctx *gctx);
62 static void *s390x_ecd_keygen25519(struct ecx_gen_ctx *gctx);
63 static void *s390x_ecd_keygen448(struct ecx_gen_ctx *gctx);
64 #endif
65
66 static void *x25519_new_key(void *provctx)
67 {
68     return ecx_key_new(ECX_KEY_TYPE_X25519, 0);
69 }
70
71 static void *x448_new_key(void *provctx)
72 {
73     return ecx_key_new(ECX_KEY_TYPE_X448, 0);
74 }
75
76 static void *ed25519_new_key(void *provctx)
77 {
78     return ecx_key_new(ECX_KEY_TYPE_ED25519, 0);
79 }
80
81 static void *ed448_new_key(void *provctx)
82 {
83     return ecx_key_new(ECX_KEY_TYPE_ED448, 0);
84 }
85
86 static int ecx_has(void *keydata, int selection)
87 {
88     ECX_KEY *key = keydata;
89     int ok = 0;
90
91     if (key != NULL) {
92         if ((selection & ECX_POSSIBLE_SELECTIONS) != 0)
93             ok = 1;
94
95         if ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0)
96             ok = ok && key->haspubkey;
97
98         if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0)
99             ok = ok && key->privkey != NULL;
100     }
101     return ok;
102 }
103
104 static int ecx_import(void *keydata, int selection, const OSSL_PARAM params[])
105 {
106     ECX_KEY *key = keydata;
107     int ok = 1;
108     int include_private = 0;
109
110     if (key == NULL)
111         return 0;
112
113     if ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) == 0)
114         return 0;
115
116     include_private = ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0);
117     if ((selection & OSSL_KEYMGMT_SELECT_KEYPAIR) != 0)
118         ok = ok && ecx_key_fromdata(key, params, include_private);
119
120     return ok;
121 }
122
123 static int key_to_params(ECX_KEY *key, OSSL_PARAM_BLD *tmpl,
124                          OSSL_PARAM params[])
125 {
126     if (key == NULL)
127         return 0;
128
129     if (!ossl_param_build_set_octet_string(tmpl, params,
130                                            OSSL_PKEY_PARAM_PUB_KEY,
131                                            key->pubkey, key->keylen))
132         return 0;
133
134     if (key->privkey != NULL
135         && !ossl_param_build_set_octet_string(tmpl, params,
136                                               OSSL_PKEY_PARAM_PRIV_KEY,
137                                               key->privkey, key->keylen))
138         return 0;
139
140     return 1;
141 }
142
143 static int ecx_export(void *keydata, int selection, OSSL_CALLBACK *param_cb,
144                       void *cbarg)
145 {
146     ECX_KEY *key = keydata;
147     OSSL_PARAM_BLD *tmpl;
148     OSSL_PARAM *params = NULL;
149     int ret = 0;
150
151     if (key == NULL)
152         return 0;
153
154     tmpl = OSSL_PARAM_BLD_new();
155     if (tmpl == NULL)
156         return 0;
157
158     if ((selection & OSSL_KEYMGMT_SELECT_KEYPAIR) != 0
159          && !key_to_params(key, tmpl, NULL))
160         goto err;
161
162     if ((selection & OSSL_KEYMGMT_SELECT_KEYPAIR) != 0
163          && !key_to_params(key, tmpl, NULL))
164         goto err;
165
166     params = OSSL_PARAM_BLD_to_param(tmpl);
167     if (params == NULL)
168         goto err;
169
170     ret = param_cb(params, cbarg);
171     OSSL_PARAM_BLD_free_params(params);
172 err:
173     OSSL_PARAM_BLD_free(tmpl);
174     return ret;
175 }
176
177 #define ECX_KEY_TYPES()                                                        \
178 OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_PUB_KEY, NULL, 0),                     \
179 OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_PRIV_KEY, NULL, 0)
180
181 static const OSSL_PARAM ecx_key_types[] = {
182     ECX_KEY_TYPES(),
183     OSSL_PARAM_END
184 };
185 static const OSSL_PARAM *ecx_imexport_types(int selection)
186 {
187     if ((selection & OSSL_KEYMGMT_SELECT_KEYPAIR) != 0)
188         return ecx_key_types;
189     return NULL;
190 }
191
192 static int ecx_get_params(void *key, OSSL_PARAM params[], int bits, int secbits,
193                           int size)
194 {
195     ECX_KEY *ecx = key;
196     OSSL_PARAM *p;
197
198     if ((p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_BITS)) != NULL
199         && !OSSL_PARAM_set_int(p, bits))
200         return 0;
201     if ((p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_SECURITY_BITS)) != NULL
202         && !OSSL_PARAM_set_int(p, secbits))
203         return 0;
204     if ((p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_MAX_SIZE)) != NULL
205         && !OSSL_PARAM_set_int(p, size))
206         return 0;
207     return key_to_params(ecx, NULL, params);
208 }
209
210 static int x25519_get_params(void *key, OSSL_PARAM params[])
211 {
212     return ecx_get_params(key, params, X25519_BITS, X25519_SECURITY_BITS,
213                           X25519_KEYLEN);
214 }
215
216 static int x448_get_params(void *key, OSSL_PARAM params[])
217 {
218     return ecx_get_params(key, params, X448_BITS, X448_SECURITY_BITS,
219                           X448_KEYLEN);
220 }
221
222 static int ed25519_get_params(void *key, OSSL_PARAM params[])
223 {
224     return ecx_get_params(key, params, ED25519_BITS, ED25519_SECURITY_BITS,
225                           ED25519_KEYLEN);
226 }
227
228 static int ed448_get_params(void *key, OSSL_PARAM params[])
229 {
230     return ecx_get_params(key, params, ED448_BITS, ED448_SECURITY_BITS,
231                           ED448_KEYLEN);
232 }
233
234 static const OSSL_PARAM ecx_params[] = {
235     OSSL_PARAM_int(OSSL_PKEY_PARAM_BITS, NULL),
236     OSSL_PARAM_int(OSSL_PKEY_PARAM_SECURITY_BITS, NULL),
237     OSSL_PARAM_int(OSSL_PKEY_PARAM_MAX_SIZE, NULL),
238     ECX_KEY_TYPES(),
239     OSSL_PARAM_END
240 };
241
242 static const OSSL_PARAM *ecx_gettable_params(void)
243 {
244     return ecx_params;
245 }
246
247 static void *ecx_gen_init(void *provctx, int selection, ECX_KEY_TYPE type)
248 {
249     OPENSSL_CTX *libctx = PROV_LIBRARY_CONTEXT_OF(provctx);
250     struct ecx_gen_ctx *gctx = NULL;
251
252     if ((selection & OSSL_KEYMGMT_SELECT_KEYPAIR) == 0)
253         return NULL;
254
255     if ((gctx = OPENSSL_malloc(sizeof(*gctx))) != NULL) {
256         gctx->libctx = libctx;
257         gctx->type = type;
258     }
259     return gctx;
260 }
261
262 static void *x25519_gen_init(void *provctx, int selection)
263 {
264     return ecx_gen_init(provctx, selection, ECX_KEY_TYPE_X25519);
265 }
266
267 static void *x448_gen_init(void *provctx, int selection)
268 {
269     return ecx_gen_init(provctx, selection, ECX_KEY_TYPE_X448);
270 }
271
272 static void *ed25519_gen_init(void *provctx, int selection)
273 {
274     return ecx_gen_init(provctx, selection, ECX_KEY_TYPE_ED25519);
275 }
276
277 static void *ed448_gen_init(void *provctx, int selection)
278 {
279     return ecx_gen_init(provctx, selection, ECX_KEY_TYPE_ED448);
280 }
281
282 static void *ecx_gen(struct ecx_gen_ctx *gctx)
283 {
284     ECX_KEY *key;
285     unsigned char *privkey;
286
287     if (gctx == NULL)
288         return NULL;
289     if ((key = ecx_key_new(gctx->type, 0)) == NULL) {
290         ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE);
291         return NULL;
292     }
293     if ((privkey = ecx_key_allocate_privkey(key)) == NULL) {
294         ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE);
295         goto err;
296     }
297     if (RAND_priv_bytes_ex(gctx->libctx, privkey, key->keylen) <= 0)
298         goto err;
299     switch (gctx->type) {
300     case ECX_KEY_TYPE_X25519:
301         privkey[0] &= 248;
302         privkey[X25519_KEYLEN - 1] &= 127;
303         privkey[X25519_KEYLEN - 1] |= 64;
304         X25519_public_from_private(key->pubkey, privkey);
305         break;
306     case ECX_KEY_TYPE_X448:
307         privkey[0] &= 252;
308         privkey[X448_KEYLEN - 1] |= 128;
309         X448_public_from_private(key->pubkey, privkey);
310         break;
311     case ECX_KEY_TYPE_ED25519:
312         if (!ED25519_public_from_private(gctx->libctx, key->pubkey, privkey))
313             goto err;
314         break;
315     case ECX_KEY_TYPE_ED448:
316         if (!ED448_public_from_private(gctx->libctx, key->pubkey, privkey))
317             goto err;
318         break;
319     }
320     return key;
321 err:
322     ecx_key_free(key);
323     return NULL;
324 }
325
326 static void *x25519_gen(void *genctx, OSSL_CALLBACK *osslcb, void *cbarg)
327 {
328     struct ecx_gen_ctx *gctx = genctx;
329
330 #ifdef S390X_EC_ASM
331     if (OPENSSL_s390xcap_P.pcc[1] & S390X_CAPBIT(S390X_SCALAR_MULTIPLY_X25519))
332         return s390x_ecx_keygen25519(gctx);
333 #endif
334     return ecx_gen(gctx);
335 }
336
337 static void *x448_gen(void *genctx, OSSL_CALLBACK *osslcb, void *cbarg)
338 {
339     struct ecx_gen_ctx *gctx = genctx;
340
341 #ifdef S390X_EC_ASM
342     if (OPENSSL_s390xcap_P.pcc[1] & S390X_CAPBIT(S390X_SCALAR_MULTIPLY_X448))
343         return s390x_ecx_keygen448(gctx);
344 #endif
345     return ecx_gen(gctx);
346 }
347
348 static void *ed25519_gen(void *genctx, OSSL_CALLBACK *osslcb, void *cbarg)
349 {
350     struct ecx_gen_ctx *gctx = genctx;
351 #ifdef S390X_EC_ASM
352     if (OPENSSL_s390xcap_P.pcc[1] & S390X_CAPBIT(S390X_SCALAR_MULTIPLY_ED25519)
353         && OPENSSL_s390xcap_P.kdsa[0] & S390X_CAPBIT(S390X_EDDSA_SIGN_ED25519)
354         && OPENSSL_s390xcap_P.kdsa[0]
355             & S390X_CAPBIT(S390X_EDDSA_VERIFY_ED25519))
356         return s390x_ecd_keygen25519(gctx);
357 #endif
358     return ecx_gen(gctx);
359 }
360
361 static void *ed448_gen(void *genctx, OSSL_CALLBACK *osslcb, void *cbarg)
362 {
363     struct ecx_gen_ctx *gctx = genctx;
364
365 #ifdef S390X_EC_ASM
366     if (OPENSSL_s390xcap_P.pcc[1] & S390X_CAPBIT(S390X_SCALAR_MULTIPLY_ED448)
367         && OPENSSL_s390xcap_P.kdsa[0] & S390X_CAPBIT(S390X_EDDSA_SIGN_ED448)
368         && OPENSSL_s390xcap_P.kdsa[0] & S390X_CAPBIT(S390X_EDDSA_VERIFY_ED448))
369         return s390x_ecd_keygen448(gctx);
370 #endif
371     return ecx_gen(gctx);
372 }
373
374 static void ecx_gen_cleanup(void *genctx)
375 {
376     struct ecx_gen_ctx *gctx = genctx;
377
378     OPENSSL_free(gctx);
379 }
380
381 #define MAKE_KEYMGMT_FUNCTIONS(alg) \
382     const OSSL_DISPATCH alg##_keymgmt_functions[] = { \
383         { OSSL_FUNC_KEYMGMT_NEW, (void (*)(void))alg##_new_key }, \
384         { OSSL_FUNC_KEYMGMT_FREE, (void (*)(void))ecx_key_free }, \
385         { OSSL_FUNC_KEYMGMT_GET_PARAMS, (void (*) (void))alg##_get_params }, \
386         { OSSL_FUNC_KEYMGMT_GETTABLE_PARAMS, (void (*) (void))ecx_gettable_params }, \
387         { OSSL_FUNC_KEYMGMT_HAS, (void (*)(void))ecx_has }, \
388         { OSSL_FUNC_KEYMGMT_IMPORT, (void (*)(void))ecx_import }, \
389         { OSSL_FUNC_KEYMGMT_IMPORT_TYPES, (void (*)(void))ecx_imexport_types }, \
390         { OSSL_FUNC_KEYMGMT_EXPORT, (void (*)(void))ecx_export }, \
391         { OSSL_FUNC_KEYMGMT_EXPORT_TYPES, (void (*)(void))ecx_imexport_types }, \
392         { OSSL_FUNC_KEYMGMT_GEN_INIT, (void (*)(void))alg##_gen_init }, \
393         { OSSL_FUNC_KEYMGMT_GEN, (void (*)(void))alg##_gen }, \
394         { OSSL_FUNC_KEYMGMT_GEN_CLEANUP, (void (*)(void))ecx_gen_cleanup }, \
395         { 0, NULL } \
396     };
397
398 MAKE_KEYMGMT_FUNCTIONS(x25519)
399 MAKE_KEYMGMT_FUNCTIONS(x448)
400 MAKE_KEYMGMT_FUNCTIONS(ed25519)
401 MAKE_KEYMGMT_FUNCTIONS(ed448)
402
403 #ifdef S390X_EC_ASM
404 # include "s390x_arch.h"
405
406 static void *s390x_ecx_keygen25519(struct ecx_gen_ctx *gctx)
407 {
408     static const unsigned char generator[] = {
409         0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
410         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
411         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
412     };
413     ECX_KEY *key = ecx_key_new(ECX_KEY_TYPE_X25519, 1);
414     unsigned char *privkey = NULL, *pubkey;
415
416     if (key == NULL) {
417         ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE);
418         goto err;
419     }
420
421     pubkey = key->pubkey;
422
423     privkey = ecx_key_allocate_privkey(key);
424     if (privkey == NULL) {
425         ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE);
426         goto err;
427     }
428
429     if (RAND_priv_bytes_ex(gctx->libctx, privkey, X25519_KEYLEN) <= 0)
430         goto err;
431
432     privkey[0] &= 248;
433     privkey[31] &= 127;
434     privkey[31] |= 64;
435
436     if (s390x_x25519_mul(pubkey, generator, privkey) != 1)
437         goto err;
438     return key;
439  err:
440     ecx_key_free(key);
441     return NULL;
442 }
443
444 static void *s390x_ecx_keygen448(struct ecx_gen_ctx *gctx)
445 {
446     static const unsigned char generator[] = {
447         0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
448         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
449         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
450         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
451         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
452     };
453     ECX_KEY *key = ecx_key_new(ECX_KEY_TYPE_X448, 1);
454     unsigned char *privkey = NULL, *pubkey;
455
456     if (key == NULL) {
457         ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE);
458         goto err;
459     }
460
461     pubkey = key->pubkey;
462
463     privkey = ecx_key_allocate_privkey(key);
464     if (privkey == NULL) {
465         ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE);
466         goto err;
467     }
468
469     if (RAND_priv_bytes_ex(gctx->libctx, privkey, X448_KEYLEN) <= 0)
470         goto err;
471
472     privkey[0] &= 252;
473     privkey[55] |= 128;
474
475     if (s390x_x448_mul(pubkey, generator, privkey) != 1)
476         goto err;
477     return key;
478  err:
479     ecx_key_free(key);
480     return NULL;
481 }
482
483 static void *s390x_ecd_keygen25519(struct ecx_gen_ctx *gctx)
484 {
485     static const unsigned char generator_x[] = {
486         0x1a, 0xd5, 0x25, 0x8f, 0x60, 0x2d, 0x56, 0xc9, 0xb2, 0xa7, 0x25, 0x95,
487         0x60, 0xc7, 0x2c, 0x69, 0x5c, 0xdc, 0xd6, 0xfd, 0x31, 0xe2, 0xa4, 0xc0,
488         0xfe, 0x53, 0x6e, 0xcd, 0xd3, 0x36, 0x69, 0x21
489     };
490     static const unsigned char generator_y[] = {
491         0x58, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
492         0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
493         0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
494     };
495     unsigned char x_dst[32], buff[SHA512_DIGEST_LENGTH];
496     ECX_KEY *key = ecx_key_new(ECX_KEY_TYPE_ED25519, 1);
497     unsigned char *privkey = NULL, *pubkey;
498     unsigned int sz;
499     EVP_MD *sha = NULL;
500     int j;
501
502     if (key == NULL) {
503         ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE);
504         goto err;
505     }
506
507     pubkey = key->pubkey;
508
509     privkey = ecx_key_allocate_privkey(key);
510     if (privkey == NULL) {
511         ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE);
512         goto err;
513     }
514
515     if (RAND_priv_bytes_ex(gctx->libctx, privkey, ED25519_KEYLEN) <= 0)
516         goto err;
517
518     sha = EVP_MD_fetch(gctx->libctx, "SHA512", NULL);
519     if (sha == NULL)
520         goto err;
521     j = EVP_Digest(privkey, 32, buff, &sz, sha, NULL);
522     EVP_MD_free(sha);
523     if (!j)
524         goto err;
525
526     buff[0] &= 248;
527     buff[31] &= 63;
528     buff[31] |= 64;
529
530     if (s390x_ed25519_mul(x_dst, pubkey,
531                           generator_x, generator_y, buff) != 1)
532         goto err;
533
534     pubkey[31] |= ((x_dst[0] & 0x01) << 7);
535     return key;
536  err:
537     ecx_key_free(key);
538     return NULL;
539 }
540
541 static void *s390x_ecd_keygen448(struct ecx_gen_ctx *gctx)
542 {
543     static const unsigned char generator_x[] = {
544         0x5e, 0xc0, 0x0c, 0xc7, 0x2b, 0xa8, 0x26, 0x26, 0x8e, 0x93, 0x00, 0x8b,
545         0xe1, 0x80, 0x3b, 0x43, 0x11, 0x65, 0xb6, 0x2a, 0xf7, 0x1a, 0xae, 0x12,
546         0x64, 0xa4, 0xd3, 0xa3, 0x24, 0xe3, 0x6d, 0xea, 0x67, 0x17, 0x0f, 0x47,
547         0x70, 0x65, 0x14, 0x9e, 0xda, 0x36, 0xbf, 0x22, 0xa6, 0x15, 0x1d, 0x22,
548         0xed, 0x0d, 0xed, 0x6b, 0xc6, 0x70, 0x19, 0x4f, 0x00
549     };
550     static const unsigned char generator_y[] = {
551         0x14, 0xfa, 0x30, 0xf2, 0x5b, 0x79, 0x08, 0x98, 0xad, 0xc8, 0xd7, 0x4e,
552         0x2c, 0x13, 0xbd, 0xfd, 0xc4, 0x39, 0x7c, 0xe6, 0x1c, 0xff, 0xd3, 0x3a,
553         0xd7, 0xc2, 0xa0, 0x05, 0x1e, 0x9c, 0x78, 0x87, 0x40, 0x98, 0xa3, 0x6c,
554         0x73, 0x73, 0xea, 0x4b, 0x62, 0xc7, 0xc9, 0x56, 0x37, 0x20, 0x76, 0x88,
555         0x24, 0xbc, 0xb6, 0x6e, 0x71, 0x46, 0x3f, 0x69, 0x00
556     };
557     unsigned char x_dst[57], buff[114];
558     ECX_KEY *key = ecx_key_new(ECX_KEY_TYPE_ED448, 1);
559     unsigned char *privkey = NULL, *pubkey;
560     EVP_MD_CTX *hashctx = NULL;
561     EVP_MD *shake = NULL;
562
563     if (key == NULL) {
564         ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE);
565         goto err;
566     }
567
568     pubkey = key->pubkey;
569
570     privkey = ecx_key_allocate_privkey(key);
571     if (privkey == NULL) {
572         ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE);
573         goto err;
574     }
575
576     shake = EVP_MD_fetch(gctx->libctx, "SHAKE256", NULL);
577     if (shake == NULL)
578         goto err;
579     if (RAND_priv_bytes_ex(gctx->libctx, privkey, ED448_KEYLEN) <= 0)
580         goto err;
581
582     hashctx = EVP_MD_CTX_new();
583     if (hashctx == NULL)
584         goto err;
585     if (EVP_DigestInit_ex(hashctx, shake, NULL) != 1)
586         goto err;
587     if (EVP_DigestUpdate(hashctx, privkey, 57) != 1)
588         goto err;
589     if (EVP_DigestFinalXOF(hashctx, buff, sizeof(buff)) != 1)
590         goto err;
591
592     buff[0] &= -4;
593     buff[55] |= 0x80;
594     buff[56] = 0;
595
596     if (s390x_ed448_mul(x_dst, pubkey,
597                         generator_x, generator_y, buff) != 1)
598         goto err;
599
600     pubkey[56] |= ((x_dst[0] & 0x01) << 7);
601     EVP_MD_CTX_free(hashctx);
602     EVP_MD_free(shake);
603     return key;
604  err:
605     ecx_key_free(key);
606     EVP_MD_CTX_free(hashctx);
607     EVP_MD_free(shake);
608     return NULL;
609 }
610 #endif