The branch master has been updated
       via  4350a6bd427f52d38f32b19f1c4b38a3afe62941 (commit)
       via  19985ac42cab57bf55acb626aebfdc1194771b76 (commit)
       via  b5bcc053024ce5adeb714d0a48dce71188cbd13c (commit)
       via  d8171446a274ab57e7d55d8d9f6ca8a0a7144d13 (commit)
       via  c1e48c5171affd99111fd08e7a0a7e1a76121138 (commit)
       via  43cd37014ef4433ae8e82ba64bddc42cf0bd618a (commit)
       via  1ee1e551148d963b566a69c2e6e9a583646112fc (commit)
      from  8a5cb59601fa9892e22e26337917cf513d57c473 (commit)


- Log -----------------------------------------------------------------
commit 4350a6bd427f52d38f32b19f1c4b38a3afe62941
Author: Pauli <[email protected]>
Date:   Thu Apr 16 10:17:07 2020 +1000

    doc: note that the FIPS provider contains some non-approved algorithms.
    
    Also note how to select them.
    
    Reviewed-by: Matt Caswell <[email protected]>
    (Merged from https://github.com/openssl/openssl/pull/11371)

commit 19985ac42cab57bf55acb626aebfdc1194771b76
Author: Pauli <[email protected]>
Date:   Thu Apr 16 07:55:17 2020 +1000

    news: note the addition of ECX and SHAKE256 to the FIPS provider as 
non-approved algorithms
    
    Reviewed-by: Matt Caswell <[email protected]>
    (Merged from https://github.com/openssl/openssl/pull/11371)

commit b5bcc053024ce5adeb714d0a48dce71188cbd13c
Author: Pauli <[email protected]>
Date:   Wed Apr 15 12:32:01 2020 +1000

    pkey: free key manager on error path
    
    Reviewed-by: Matt Caswell <[email protected]>
    (Merged from https://github.com/openssl/openssl/pull/11371)

commit d8171446a274ab57e7d55d8d9f6ca8a0a7144d13
Author: Pauli <[email protected]>
Date:   Wed Apr 15 10:06:20 2020 +1000

    ecx: check for errors creating public keys from private ones.
    
    Reviewed-by: Matt Caswell <[email protected]>
    (Merged from https://github.com/openssl/openssl/pull/11371)

commit c1e48c5171affd99111fd08e7a0a7e1a76121138
Author: Pauli <[email protected]>
Date:   Thu Apr 2 14:37:26 2020 +1000

    s390: ECX key generation fixes.
    
    Reviewed-by: Matt Caswell <[email protected]>
    (Merged from https://github.com/openssl/openssl/pull/11371)

commit 43cd37014ef4433ae8e82ba64bddc42cf0bd618a
Author: Pauli <[email protected]>
Date:   Wed Mar 18 09:25:33 2020 +1000

    ecx: add key generation support.
    
    Specifically for x25519, x448, ed25519 and ed448.
    
    Reviewed-by: Matt Caswell <[email protected]>
    (Merged from https://github.com/openssl/openssl/pull/11371)

commit 1ee1e551148d963b566a69c2e6e9a583646112fc
Author: Pauli <[email protected]>
Date:   Fri Mar 20 12:58:37 2020 +1000

    Add ECX to FIPS provider as non-FIPS algorithms
    
    Reviewed-by: Matt Caswell <[email protected]>
    (Merged from https://github.com/openssl/openssl/pull/11371)

-----------------------------------------------------------------------

Summary of changes:
 NEWS.md                                       |   3 +
 crypto/ec/build.info                          |   5 +-
 crypto/ec/curve25519.c                        |  17 +-
 crypto/ec/curve448/curve448_local.h           |   3 -
 crypto/ec/ec_err.c                            |   4 +-
 crypto/ec/ec_local.h                          |   2 -
 crypto/ec/ecx_meth.c                          | 209 +-------------
 crypto/ec/ecx_s390x.c                         | 217 +++++++++++++++
 crypto/err/openssl.txt                        |   3 +-
 crypto/evp/pmeth_lib.c                        |   1 +
 crypto/s390x_arch.h                           |  17 ++
 doc/man7/provider.pod                         |   5 +-
 include/crypto/ecx.h                          |  12 +-
 include/openssl/ecerr.h                       |   3 +-
 providers/fips/fipsprov.c                     |  10 +
 providers/implementations/keymgmt/build.info  |  12 +
 providers/implementations/keymgmt/ecx_kmgmt.c | 379 +++++++++++++++++++++++++-
 17 files changed, 678 insertions(+), 224 deletions(-)
 create mode 100644 crypto/ec/ecx_s390x.c

diff --git a/NEWS.md b/NEWS.md
index 9f29a59323..9f18f416f8 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -21,6 +21,9 @@ OpenSSL 3.0
 
 ### Major changes between OpenSSL 1.1.1 and OpenSSL 3.0 [under development] ###
 
+  * The X25519, X448, Ed25519, Ed448 and SHAKE256 algorithms are included in
+    the FIPS provider.  None have the "fips=yes" property set and, as such,
+    will not be accidentially used.
   * The algorithm specific public key command line applications have
     been deprecated.  These include dhparam, gendsa and others.  The pkey
     alternatives should be used intead: pkey, pkeyparam and genpkey.
diff --git a/crypto/ec/build.info b/crypto/ec/build.info
index a802beaa68..8e4a6a9f4b 100644
--- a/crypto/ec/build.info
+++ b/crypto/ec/build.info
@@ -18,7 +18,7 @@ IF[{- !$disabled{asm} -}]
   $ECASM_mips32=
   $ECASM_mips64=
 
-  $ECASM_s390x=ecp_s390x_nistp.c
+  $ECASM_s390x=ecp_s390x_nistp.c ecx_s390x.c
   $ECDEF_s390x=S390X_EC_ASM
 
   $ECASM_armv4=ecp_nistz256.c ecp_nistz256-armv4.S
@@ -44,7 +44,7 @@ IF[{- !$disabled{asm} -}]
 ENDIF
 
 $COMMON=ec_lib.c ecp_smpl.c ecp_mont.c ecp_nist.c ec_cvt.c ec_mult.c \
-        ec_curve.c ec_check.c ec_print.c ec_key.c ec_asn1.c \
+        ec_curve.c ec_check.c ec_print.c ec_key.c ecx_key.c ec_asn1.c \
         ec2_smpl.c \
         ecp_oct.c ec2_oct.c ec_oct.c ec_kmeth.c ecdh_ossl.c \
         ecdsa_ossl.c ecdsa_sign.c ecdsa_vrf.c curve25519.c \
@@ -76,6 +76,7 @@ GENERATE[ecp_nistz256-sparcv9.S]=asm/ecp_nistz256-sparcv9.pl
 INCLUDE[ecp_nistz256-sparcv9.o]=..
 
 INCLUDE[ecp_s390x_nistp.o]=..
+INCLUDE[ecx_s390x.o]=..
 INCLUDE[ecx_meth.o]=..
 
 GENERATE[ecp_nistz256-armv4.S]=asm/ecp_nistz256-armv4.pl
diff --git a/crypto/ec/curve25519.c b/crypto/ec/curve25519.c
index 8db6cdb16d..b8e998a0f4 100644
--- a/crypto/ec/curve25519.c
+++ b/crypto/ec/curve25519.c
@@ -5577,13 +5577,23 @@ err:
     return res;
 }
 
-void ED25519_public_from_private(uint8_t out_public_key[32],
-                                 const uint8_t private_key[32])
+int ED25519_public_from_private(OPENSSL_CTX *ctx, uint8_t out_public_key[32],
+                                const uint8_t private_key[32])
 {
     uint8_t az[SHA512_DIGEST_LENGTH];
     ge_p3 A;
+    int r;
+    EVP_MD *sha512 = NULL;
 
-    SHA512(private_key, 32, az);
+    sha512 = EVP_MD_fetch(ctx, SN_sha512, NULL);
+    if (sha512 == NULL)
+        return 0;
+    r = EVP_Digest(private_key, 32, az, NULL, sha512, NULL);
+    EVP_MD_free(sha512);
+    if (!r) {
+        OPENSSL_cleanse(az, sizeof(az));
+        return 0;
+    }
 
     az[0] &= 248;
     az[31] &= 63;
@@ -5593,6 +5603,7 @@ void ED25519_public_from_private(uint8_t 
out_public_key[32],
     ge_p3_tobytes(out_public_key, &A);
 
     OPENSSL_cleanse(az, sizeof(az));
+    return 1;
 }
 
 int X25519(uint8_t out_shared_key[32], const uint8_t private_key[32],
diff --git a/crypto/ec/curve448/curve448_local.h 
b/crypto/ec/curve448/curve448_local.h
index b70a1b5406..5b3b71ff62 100644
--- a/crypto/ec/curve448/curve448_local.h
+++ b/crypto/ec/curve448/curve448_local.h
@@ -18,7 +18,4 @@ int ED448ph_verify(OPENSSL_CTX *ctx, const uint8_t hash[64],
                    const uint8_t signature[114], const uint8_t public_key[57],
                    const uint8_t *context, size_t context_len);
 
-int ED448_public_from_private(OPENSSL_CTX *ctx, uint8_t out_public_key[57],
-                              const uint8_t private_key[57]);
-
 #endif              /* OSSL_CRYPTO_EC_CURVE448_LOCAL_H */
diff --git a/crypto/ec/ec_err.c b/crypto/ec/ec_err.c
index 66d9c4b16e..d775ced93a 100644
--- a/crypto/ec/ec_err.c
+++ b/crypto/ec/ec_err.c
@@ -1,6 +1,6 @@
 /*
  * Generated by util/mkerr.pl DO NOT EDIT
- * Copyright 1995-2019 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 1995-2020 The OpenSSL Project Authors. All Rights Reserved.
  *
  * Licensed under the Apache License 2.0 (the "License").  You may not use
  * this file except in compliance with the License.  You can obtain a copy
@@ -34,6 +34,8 @@ static const ERR_STRING_DATA EC_str_reasons[] = {
     "discriminant is zero"},
     {ERR_PACK(ERR_LIB_EC, 0, EC_R_EC_GROUP_NEW_BY_NAME_FAILURE),
     "ec group new by name failure"},
+    {ERR_PACK(ERR_LIB_EC, 0, EC_R_FAILED_MAKING_PUBLIC_KEY),
+    "failed making public key"},
     {ERR_PACK(ERR_LIB_EC, 0, EC_R_FIELD_TOO_LARGE), "field too large"},
     {ERR_PACK(ERR_LIB_EC, 0, EC_R_GF2M_NOT_SUPPORTED), "gf2m not supported"},
     {ERR_PACK(ERR_LIB_EC, 0, EC_R_GROUP2PKPARAMETERS_FAILURE),
diff --git a/crypto/ec/ec_local.h b/crypto/ec/ec_local.h
index b5963a7e5f..d10de2fc98 100644
--- a/crypto/ec/ec_local.h
+++ b/crypto/ec/ec_local.h
@@ -679,8 +679,6 @@ ECDSA_SIG *ecdsa_simple_sign_sig(const unsigned char *dgst, 
int dgst_len,
 int ecdsa_simple_verify_sig(const unsigned char *dgst, int dgst_len,
                             const ECDSA_SIG *sig, EC_KEY *eckey);
 
-void ED25519_public_from_private(uint8_t out_public_key[32],
-                                 const uint8_t private_key[32]);
 
 /*-
  * This functions computes a single point multiplication over the EC group,
diff --git a/crypto/ec/ecx_meth.c b/crypto/ec/ecx_meth.c
index 62a73f9b08..ba037ffb8b 100644
--- a/crypto/ec/ecx_meth.c
+++ b/crypto/ec/ecx_meth.c
@@ -93,13 +93,19 @@ static int ecx_key_op(EVP_PKEY *pkey, int id, const 
X509_ALGOR *palg,
             X25519_public_from_private(pubkey, privkey);
             break;
         case EVP_PKEY_ED25519:
-            ED25519_public_from_private(pubkey, privkey);
+            if (!ED25519_public_from_private(libctx, pubkey, privkey)) {
+                ECerr(EC_F_ECX_KEY_OP, EC_R_FAILED_MAKING_PUBLIC_KEY);
+                return 0;
+            }
             break;
         case EVP_PKEY_X448:
             X448_public_from_private(pubkey, privkey);
             break;
         case EVP_PKEY_ED448:
-            ED448_public_from_private(libctx, pubkey, privkey);
+            if (!ED448_public_from_private(libctx, pubkey, privkey)) {
+                ECerr(EC_F_ECX_KEY_OP, EC_R_FAILED_MAKING_PUBLIC_KEY);
+                return 0;
+            }
             break;
         }
     }
@@ -948,205 +954,6 @@ static const EVP_PKEY_METHOD ed448_pkey_meth = {
 
 #ifdef S390X_EC_ASM
 # include "s390x_arch.h"
-# include "internal/constant_time.h"
-
-static void s390x_x25519_mod_p(unsigned char u[32])
-{
-    unsigned char u_red[32];
-    unsigned int c = 0;
-    int i;
-
-    memcpy(u_red, u, sizeof(u_red));
-
-    c += (unsigned int)u_red[31] + 19;
-    u_red[31] = (unsigned char)c;
-    c >>= 8;
-
-    for (i = 30; i >= 0; i--) {
-        c += (unsigned int)u_red[i];
-        u_red[i] = (unsigned char)c;
-        c >>= 8;
-    }
-
-    c = (u_red[0] & 0x80) >> 7;
-    u_red[0] &= 0x7f;
-    constant_time_cond_swap_buff(0 - (unsigned char)c,
-                                 u, u_red, sizeof(u_red));
-}
-
-static void s390x_x448_mod_p(unsigned char u[56])
-{
-    unsigned char u_red[56];
-    unsigned int c = 0;
-    int i;
-
-    memcpy(u_red, u, sizeof(u_red));
-
-    c += (unsigned int)u_red[55] + 1;
-    u_red[55] = (unsigned char)c;
-    c >>= 8;
-
-    for (i = 54; i >= 28; i--) {
-        c += (unsigned int)u_red[i];
-        u_red[i] = (unsigned char)c;
-        c >>= 8;
-    }
-
-    c += (unsigned int)u_red[27] + 1;
-    u_red[27] = (unsigned char)c;
-    c >>= 8;
-
-    for (i = 26; i >= 0; i--) {
-        c += (unsigned int)u_red[i];
-        u_red[i] = (unsigned char)c;
-        c >>= 8;
-    }
-
-    constant_time_cond_swap_buff(0 - (unsigned char)c,
-                                 u, u_red, sizeof(u_red));
-}
-
-int s390x_x25519_mul(unsigned char u_dst[32],
-                     const unsigned char u_src[32],
-                     const unsigned char d_src[32])
-{
-    union {
-        struct {
-            unsigned char u_dst[32];
-            unsigned char u_src[32];
-            unsigned char d_src[32];
-        } x25519;
-        unsigned long long buff[512];
-    } param;
-    int rc;
-
-    memset(&param, 0, sizeof(param));
-
-    s390x_flip_endian32(param.x25519.u_src, u_src);
-    param.x25519.u_src[0] &= 0x7f;
-    s390x_x25519_mod_p(param.x25519.u_src);
-
-    s390x_flip_endian32(param.x25519.d_src, d_src);
-    param.x25519.d_src[31] &= 248;
-    param.x25519.d_src[0] &= 127;
-    param.x25519.d_src[0] |= 64;
-
-    rc = s390x_pcc(S390X_SCALAR_MULTIPLY_X25519, &param.x25519) ? 0 : 1;
-    if (rc == 1)
-        s390x_flip_endian32(u_dst, param.x25519.u_dst);
-
-    OPENSSL_cleanse(param.x25519.d_src, sizeof(param.x25519.d_src));
-    return rc;
-}
-
-int s390x_x448_mul(unsigned char u_dst[56],
-                   const unsigned char u_src[56],
-                   const unsigned char d_src[56])
-{
-    union {
-        struct {
-            unsigned char u_dst[64];
-            unsigned char u_src[64];
-            unsigned char d_src[64];
-        } x448;
-        unsigned long long buff[512];
-    } param;
-    int rc;
-
-    memset(&param, 0, sizeof(param));
-
-    memcpy(param.x448.u_src, u_src, 56);
-    memcpy(param.x448.d_src, d_src, 56);
-
-    s390x_flip_endian64(param.x448.u_src, param.x448.u_src);
-    s390x_x448_mod_p(param.x448.u_src + 8);
-
-    s390x_flip_endian64(param.x448.d_src, param.x448.d_src);
-    param.x448.d_src[63] &= 252;
-    param.x448.d_src[8] |= 128;
-
-    rc = s390x_pcc(S390X_SCALAR_MULTIPLY_X448, &param.x448) ? 0 : 1;
-    if (rc == 1) {
-        s390x_flip_endian64(param.x448.u_dst, param.x448.u_dst);
-        memcpy(u_dst, param.x448.u_dst, 56);
-    }
-
-    OPENSSL_cleanse(param.x448.d_src, sizeof(param.x448.d_src));
-    return rc;
-}
-
-static int s390x_ed25519_mul(unsigned char x_dst[32],
-                             unsigned char y_dst[32],
-                             const unsigned char x_src[32],
-                             const unsigned char y_src[32],
-                             const unsigned char d_src[32])
-{
-    union {
-        struct {
-            unsigned char x_dst[32];
-            unsigned char y_dst[32];
-            unsigned char x_src[32];
-            unsigned char y_src[32];
-            unsigned char d_src[32];
-        } ed25519;
-        unsigned long long buff[512];
-    } param;
-    int rc;
-
-    memset(&param, 0, sizeof(param));
-
-    s390x_flip_endian32(param.ed25519.x_src, x_src);
-    s390x_flip_endian32(param.ed25519.y_src, y_src);
-    s390x_flip_endian32(param.ed25519.d_src, d_src);
-
-    rc = s390x_pcc(S390X_SCALAR_MULTIPLY_ED25519, &param.ed25519) ? 0 : 1;
-    if (rc == 1) {
-        s390x_flip_endian32(x_dst, param.ed25519.x_dst);
-        s390x_flip_endian32(y_dst, param.ed25519.y_dst);
-    }
-
-    OPENSSL_cleanse(param.ed25519.d_src, sizeof(param.ed25519.d_src));
-    return rc;
-}
-
-static int s390x_ed448_mul(unsigned char x_dst[57],
-                           unsigned char y_dst[57],
-                           const unsigned char x_src[57],
-                           const unsigned char y_src[57],
-                           const unsigned char d_src[57])
-{
-    union {
-        struct {
-            unsigned char x_dst[64];
-            unsigned char y_dst[64];
-            unsigned char x_src[64];
-            unsigned char y_src[64];
-            unsigned char d_src[64];
-        } ed448;
-        unsigned long long buff[512];
-    } param;
-    int rc;
-
-    memset(&param, 0, sizeof(param));
-
-    memcpy(param.ed448.x_src, x_src, 57);
-    memcpy(param.ed448.y_src, y_src, 57);
-    memcpy(param.ed448.d_src, d_src, 57);
-    s390x_flip_endian64(param.ed448.x_src, param.ed448.x_src);
-    s390x_flip_endian64(param.ed448.y_src, param.ed448.y_src);
-    s390x_flip_endian64(param.ed448.d_src, param.ed448.d_src);
-
-    rc = s390x_pcc(S390X_SCALAR_MULTIPLY_ED448, &param.ed448) ? 0 : 1;
-    if (rc == 1) {
-        s390x_flip_endian64(param.ed448.x_dst, param.ed448.x_dst);
-        s390x_flip_endian64(param.ed448.y_dst, param.ed448.y_dst);
-        memcpy(x_dst, param.ed448.x_dst, 57);
-        memcpy(y_dst, param.ed448.y_dst, 57);
-    }
-
-    OPENSSL_cleanse(param.ed448.d_src, sizeof(param.ed448.d_src));
-    return rc;
-}
 
 static int s390x_pkey_ecx_keygen25519(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey)
 {
diff --git a/crypto/ec/ecx_s390x.c b/crypto/ec/ecx_s390x.c
new file mode 100644
index 0000000000..1e6f65011b
--- /dev/null
+++ b/crypto/ec/ecx_s390x.c
@@ -0,0 +1,217 @@
+/*
+ * Copyright 2006-2018 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License 2.0 (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include <stdio.h>
+#include "internal/cryptlib.h"
+#include <openssl/ec.h>
+#include <openssl/rand.h>
+#include "crypto/ecx.h"
+#include "ec_local.h"
+#include "curve448/curve448_local.h"
+#include "ecx_backend.h"
+#include "s390x_arch.h"
+#include "internal/constant_time.h"
+
+static void s390x_x25519_mod_p(unsigned char u[32])
+{
+    unsigned char u_red[32];
+    unsigned int c = 0;
+    int i;
+
+    memcpy(u_red, u, sizeof(u_red));
+
+    c += (unsigned int)u_red[31] + 19;
+    u_red[31] = (unsigned char)c;
+    c >>= 8;
+
+    for (i = 30; i >= 0; i--) {
+        c += (unsigned int)u_red[i];
+        u_red[i] = (unsigned char)c;
+        c >>= 8;
+    }
+
+    c = (u_red[0] & 0x80) >> 7;
+    u_red[0] &= 0x7f;
+    constant_time_cond_swap_buff(0 - (unsigned char)c,
+                                 u, u_red, sizeof(u_red));
+}
+
+static void s390x_x448_mod_p(unsigned char u[56])
+{
+    unsigned char u_red[56];
+    unsigned int c = 0;
+    int i;
+
+    memcpy(u_red, u, sizeof(u_red));
+
+    c += (unsigned int)u_red[55] + 1;
+    u_red[55] = (unsigned char)c;
+    c >>= 8;
+
+    for (i = 54; i >= 28; i--) {
+        c += (unsigned int)u_red[i];
+        u_red[i] = (unsigned char)c;
+        c >>= 8;
+    }
+
+    c += (unsigned int)u_red[27] + 1;
+    u_red[27] = (unsigned char)c;
+    c >>= 8;
+
+    for (i = 26; i >= 0; i--) {
+        c += (unsigned int)u_red[i];
+        u_red[i] = (unsigned char)c;
+        c >>= 8;
+    }
+
+    constant_time_cond_swap_buff(0 - (unsigned char)c,
+                                 u, u_red, sizeof(u_red));
+}
+
+int s390x_x25519_mul(unsigned char u_dst[32],
+                     const unsigned char u_src[32],
+                     const unsigned char d_src[32])
+{
+    union {
+        struct {
+            unsigned char u_dst[32];
+            unsigned char u_src[32];
+            unsigned char d_src[32];
+        } x25519;
+        unsigned long long buff[512];
+    } param;
+    int rc;
+
+    memset(&param, 0, sizeof(param));
+
+    s390x_flip_endian32(param.x25519.u_src, u_src);
+    param.x25519.u_src[0] &= 0x7f;
+    s390x_x25519_mod_p(param.x25519.u_src);
+
+    s390x_flip_endian32(param.x25519.d_src, d_src);
+    param.x25519.d_src[31] &= 248;
+    param.x25519.d_src[0] &= 127;
+    param.x25519.d_src[0] |= 64;
+
+    rc = s390x_pcc(S390X_SCALAR_MULTIPLY_X25519, &param.x25519) ? 0 : 1;
+    if (rc == 1)
+        s390x_flip_endian32(u_dst, param.x25519.u_dst);
+
+    OPENSSL_cleanse(param.x25519.d_src, sizeof(param.x25519.d_src));
+    return rc;
+}
+
+int s390x_x448_mul(unsigned char u_dst[56],
+                   const unsigned char u_src[56],
+                   const unsigned char d_src[56])
+{
+    union {
+        struct {
+            unsigned char u_dst[64];
+            unsigned char u_src[64];
+            unsigned char d_src[64];
+        } x448;
+        unsigned long long buff[512];
+    } param;
+    int rc;
+
+    memset(&param, 0, sizeof(param));
+
+    memcpy(param.x448.u_src, u_src, 56);
+    memcpy(param.x448.d_src, d_src, 56);
+
+    s390x_flip_endian64(param.x448.u_src, param.x448.u_src);
+    s390x_x448_mod_p(param.x448.u_src + 8);
+
+    s390x_flip_endian64(param.x448.d_src, param.x448.d_src);
+    param.x448.d_src[63] &= 252;
+    param.x448.d_src[8] |= 128;
+
+    rc = s390x_pcc(S390X_SCALAR_MULTIPLY_X448, &param.x448) ? 0 : 1;
+    if (rc == 1) {
+        s390x_flip_endian64(param.x448.u_dst, param.x448.u_dst);
+        memcpy(u_dst, param.x448.u_dst, 56);
+    }
+
+    OPENSSL_cleanse(param.x448.d_src, sizeof(param.x448.d_src));
+    return rc;
+}
+
+int s390x_ed25519_mul(unsigned char x_dst[32],
+                      unsigned char y_dst[32],
+                      const unsigned char x_src[32],
+                      const unsigned char y_src[32],
+                      const unsigned char d_src[32])
+{
+    union {
+        struct {
+            unsigned char x_dst[32];
+            unsigned char y_dst[32];
+            unsigned char x_src[32];
+            unsigned char y_src[32];
+            unsigned char d_src[32];
+        } ed25519;
+        unsigned long long buff[512];
+    } param;
+    int rc;
+
+    memset(&param, 0, sizeof(param));
+
+    s390x_flip_endian32(param.ed25519.x_src, x_src);
+    s390x_flip_endian32(param.ed25519.y_src, y_src);
+    s390x_flip_endian32(param.ed25519.d_src, d_src);
+
+    rc = s390x_pcc(S390X_SCALAR_MULTIPLY_ED25519, &param.ed25519) ? 0 : 1;
+    if (rc == 1) {
+        s390x_flip_endian32(x_dst, param.ed25519.x_dst);
+        s390x_flip_endian32(y_dst, param.ed25519.y_dst);
+    }
+
+    OPENSSL_cleanse(param.ed25519.d_src, sizeof(param.ed25519.d_src));
+    return rc;
+}
+
+int s390x_ed448_mul(unsigned char x_dst[57],
+                    unsigned char y_dst[57],
+                    const unsigned char x_src[57],
+                    const unsigned char y_src[57],
+                    const unsigned char d_src[57])
+{
+    union {
+        struct {
+            unsigned char x_dst[64];
+            unsigned char y_dst[64];
+            unsigned char x_src[64];
+            unsigned char y_src[64];
+            unsigned char d_src[64];
+        } ed448;
+        unsigned long long buff[512];
+    } param;
+    int rc;
+
+    memset(&param, 0, sizeof(param));
+
+    memcpy(param.ed448.x_src, x_src, 57);
+    memcpy(param.ed448.y_src, y_src, 57);
+    memcpy(param.ed448.d_src, d_src, 57);
+    s390x_flip_endian64(param.ed448.x_src, param.ed448.x_src);
+    s390x_flip_endian64(param.ed448.y_src, param.ed448.y_src);
+    s390x_flip_endian64(param.ed448.d_src, param.ed448.d_src);
+
+    rc = s390x_pcc(S390X_SCALAR_MULTIPLY_ED448, &param.ed448) ? 0 : 1;
+    if (rc == 1) {
+        s390x_flip_endian64(param.ed448.x_dst, param.ed448.x_dst);
+        s390x_flip_endian64(param.ed448.y_dst, param.ed448.y_dst);
+        memcpy(x_dst, param.ed448.x_dst, 57);
+        memcpy(y_dst, param.ed448.y_dst, 57);
+    }
+
+    OPENSSL_cleanse(param.ed448.d_src, sizeof(param.ed448.d_src));
+    return rc;
+}
diff --git a/crypto/err/openssl.txt b/crypto/err/openssl.txt
index 12826beb0b..793473684c 100644
--- a/crypto/err/openssl.txt
+++ b/crypto/err/openssl.txt
@@ -2402,6 +2402,7 @@ EC_R_D2I_ECPKPARAMETERS_FAILURE:117:d2i ecpkparameters 
failure
 EC_R_DECODE_ERROR:142:decode error
 EC_R_DISCRIMINANT_IS_ZERO:118:discriminant is zero
 EC_R_EC_GROUP_NEW_BY_NAME_FAILURE:119:ec group new by name failure
+EC_R_FAILED_MAKING_PUBLIC_KEY:166:failed making public key
 EC_R_FIELD_TOO_LARGE:143:field too large
 EC_R_GF2M_NOT_SUPPORTED:147:gf2m not supported
 EC_R_GROUP2PKPARAMETERS_FAILURE:120:group2pkparameters failure
@@ -3013,6 +3014,7 @@ SM2_R_INVALID_ENCODING:104:invalid encoding
 SM2_R_INVALID_FIELD:105:invalid field
 SM2_R_NO_PARAMETERS_SET:109:no parameters set
 SM2_R_USER_ID_TOO_LARGE:106:user id too large
+SSL_R_ALGORITHM_FETCH_FAILED:295:algorithm fetch failed
 SSL_R_APPLICATION_DATA_AFTER_CLOSE_NOTIFY:291:\
        application data after close notify
 SSL_R_APP_DATA_IN_HANDSHAKE:100:app data in handshake
@@ -3119,7 +3121,6 @@ SSL_R_EXTENSION_NOT_RECEIVED:279:extension not received
 SSL_R_EXTRA_DATA_IN_MESSAGE:153:extra data in message
 SSL_R_EXT_LENGTH_MISMATCH:163:ext length mismatch
 SSL_R_FAILED_TO_INIT_ASYNC:405:failed to init async
-SSL_R_ALGORITHM_FETCH_FAILED:295:algorithm fetch failed
 SSL_R_FRAGMENTED_CLIENT_HELLO:401:fragmented client hello
 SSL_R_GOT_A_FIN_BEFORE_A_CCS:154:got a fin before a ccs
 SSL_R_HTTPS_PROXY_REQUEST:155:https proxy request
diff --git a/crypto/evp/pmeth_lib.c b/crypto/evp/pmeth_lib.c
index b6617492da..e816265bc7 100644
--- a/crypto/evp/pmeth_lib.c
+++ b/crypto/evp/pmeth_lib.c
@@ -236,6 +236,7 @@ static EVP_PKEY_CTX *int_ctx_new(OPENSSL_CTX *libctx,
 
     ret = OPENSSL_zalloc(sizeof(*ret));
     if (ret == NULL) {
+        EVP_KEYMGMT_free(keymgmt);
 #if !defined(OPENSSL_NO_ENGINE) && !defined(FIPS_MODE)
         ENGINE_finish(e);
 #endif
diff --git a/crypto/s390x_arch.h b/crypto/s390x_arch.h
index 0123de9477..c20fc342f6 100644
--- a/crypto/s390x_arch.h
+++ b/crypto/s390x_arch.h
@@ -33,6 +33,23 @@ int s390x_kdsa(unsigned int fc, void *param, const unsigned 
char *in,
 void s390x_flip_endian32(unsigned char dst[32], const unsigned char src[32]);
 void s390x_flip_endian64(unsigned char dst[64], const unsigned char src[64]);
 
+int s390x_x25519_mul(unsigned char u_dst[32],
+                     const unsigned char u_src[32],
+                     const unsigned char d_src[32]);
+int s390x_x448_mul(unsigned char u_dst[56],
+                   const unsigned char u_src[56],
+                   const unsigned char d_src[56]);
+int s390x_ed25519_mul(unsigned char x_dst[32],
+                      unsigned char y_dst[32],
+                      const unsigned char x_src[32],
+                      const unsigned char y_src[32],
+                      const unsigned char d_src[32]);
+int s390x_ed448_mul(unsigned char x_dst[57],
+                    unsigned char y_dst[57],
+                    const unsigned char x_src[57],
+                    const unsigned char y_src[57],
+                    const unsigned char d_src[57]);
+
 /*
  * The field elements of OPENSSL_s390xcap_P are the 64-bit words returned by
  * the STFLE instruction followed by the 64-bit word pairs returned by
diff --git a/doc/man7/provider.pod b/doc/man7/provider.pod
index de8e2499d9..fcb9fa1122 100644
--- a/doc/man7/provider.pod
+++ b/doc/man7/provider.pod
@@ -274,9 +274,10 @@ be loaded explicitly, either in code or through OpenSSL 
configuration
 (see L<config(5)>).
 Should it be needed (if other providers are loaded and offer
 implementations of the same algorithms), the property "provider=fips" can
-be used as a search criterion for these implementations. All algorithm
+be used as a search criterion for these implementations. All approved algorithm
 implementations in the FIPS provider can also be selected with the property
-"fips=yes".
+"fips=yes". The FIPS provider also contains a number of non-approved algorithm
+implementations and these can be selected with the property "fips=no".
 
 =head2 Legacy provider
 
diff --git a/include/crypto/ecx.h b/include/crypto/ecx.h
index 0c6655ca79..5ee6b8ce7e 100644
--- a/include/crypto/ecx.h
+++ b/include/crypto/ecx.h
@@ -72,6 +72,7 @@ struct ecx_key_st {
 
 typedef struct ecx_key_st ECX_KEY;
 
+size_t ecx_key_length(ECX_KEY_TYPE type);
 ECX_KEY *ecx_key_new(ECX_KEY_TYPE type, int haspubkey);
 unsigned char *ecx_key_allocate_privkey(ECX_KEY *key);
 void ecx_key_free(ECX_KEY *key);
@@ -82,6 +83,8 @@ int X25519(uint8_t out_shared_key[32], const uint8_t 
private_key[32],
 void X25519_public_from_private(uint8_t out_public_value[32],
                                 const uint8_t private_key[32]);
 
+int ED25519_public_from_private(OPENSSL_CTX *ctx, uint8_t out_public_key[32],
+                                const uint8_t private_key[32]);
 int ED25519_sign(uint8_t *out_sig, const uint8_t *message, size_t message_len,
                  const uint8_t public_key[32], const uint8_t private_key[32],
                  OPENSSL_CTX *libctx, const char *propq);
@@ -89,6 +92,8 @@ int ED25519_verify(const uint8_t *message, size_t message_len,
                    const uint8_t signature[64], const uint8_t public_key[32],
                    OPENSSL_CTX *libctx, const char *propq);
 
+int ED448_public_from_private(OPENSSL_CTX *ctx, uint8_t out_public_key[57],
+                              const uint8_t private_key[57]);
 int ED448_sign(OPENSSL_CTX *ctx, uint8_t *out_sig, const uint8_t *message,
                size_t message_len, const uint8_t public_key[57],
                const uint8_t private_key[57], const uint8_t *context,
@@ -103,13 +108,6 @@ int X448(uint8_t out_shared_key[56], const uint8_t 
private_key[56],
 void X448_public_from_private(uint8_t out_public_value[56],
                               const uint8_t private_key[56]);
 
-int s390x_x25519_mul(unsigned char u_dst[32],
-                     const unsigned char u_src[32],
-                     const unsigned char d_src[32]);
-int s390x_x448_mul(unsigned char u_dst[56],
-                   const unsigned char u_src[56],
-                   const unsigned char d_src[56]);
-
 /* Backend support */
 int ecx_key_fromdata(ECX_KEY *ecx, const OSSL_PARAM params[],
                      int include_private);
diff --git a/include/openssl/ecerr.h b/include/openssl/ecerr.h
index 41d592b085..cf845fbb1a 100644
--- a/include/openssl/ecerr.h
+++ b/include/openssl/ecerr.h
@@ -1,6 +1,6 @@
 /*
  * Generated by util/mkerr.pl DO NOT EDIT
- * Copyright 1995-2019 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 1995-2020 The OpenSSL Project Authors. All Rights Reserved.
  *
  * Licensed under the Apache License 2.0 (the "License").  You may not use
  * this file except in compliance with the License.  You can obtain a copy
@@ -237,6 +237,7 @@ int ERR_load_EC_strings(void);
 #  define EC_R_DECODE_ERROR                                142
 #  define EC_R_DISCRIMINANT_IS_ZERO                        118
 #  define EC_R_EC_GROUP_NEW_BY_NAME_FAILURE                119
+#  define EC_R_FAILED_MAKING_PUBLIC_KEY                    166
 #  define EC_R_FIELD_TOO_LARGE                             143
 #  define EC_R_GF2M_NOT_SUPPORTED                          147
 #  define EC_R_GROUP2PKPARAMETERS_FAILURE                  120
diff --git a/providers/fips/fipsprov.c b/providers/fips/fipsprov.c
index c107d690b7..4fe14c2ba3 100644
--- a/providers/fips/fipsprov.c
+++ b/providers/fips/fipsprov.c
@@ -374,6 +374,8 @@ static const OSSL_ALGORITHM fips_digests[] = {
     { "KECCAK-KMAC-128:KECCAK-KMAC128", "provider=fips,fips=yes", 
keccak_kmac_128_functions },
     { "KECCAK-KMAC-256:KECCAK-KMAC256", "provider=fips,fips=yes", 
keccak_kmac_256_functions },
 
+    /* Non-FIPS algorithm to support oneshot_hash in the Ed448 code */
+    { "SHAKE-256:SHAKE256", "provider=fips,fips=no", shake_256_functions },
     { NULL, NULL, NULL }
 };
 
@@ -447,6 +449,8 @@ static const OSSL_ALGORITHM fips_keyexch[] = {
 #endif
 #ifndef OPENSSL_NO_EC
     { "ECDH", "provider=fips,fips=yes", ecdh_keyexch_functions },
+    { "X25519", "provider=fips,fips=no", x25519_keyexch_functions },
+    { "X448", "provider=fips,fips=no", x448_keyexch_functions },
 #endif
     { NULL, NULL, NULL }
 };
@@ -457,6 +461,8 @@ static const OSSL_ALGORITHM fips_signature[] = {
 #endif
     { "RSA:rsaEncryption", "provider=fips,fips=yes", rsa_signature_functions },
 #ifndef OPENSSL_NO_EC
+    { "ED25519", "provider=fips,fips=no", ed25519_signature_functions },
+    { "ED448", "provider=fips,fips=no", ed448_signature_functions },
     { "ECDSA", "provider=fips,fips=yes", ecdsa_signature_functions },
 #endif
     { NULL, NULL, NULL }
@@ -477,6 +483,10 @@ static const OSSL_ALGORITHM fips_keymgmt[] = {
     { "RSA:rsaEncryption", "provider=fips,fips=yes", rsa_keymgmt_functions },
 #ifndef OPENSSL_NO_EC
     { "EC:id-ecPublicKey", "provider=fips,fips=yes", ec_keymgmt_functions },
+    { "X25519", "provider=fips,fips=no", x25519_keymgmt_functions },
+    { "X448", "provider=fips,fips=no", x448_keymgmt_functions },
+    { "ED25519", "provider=fips,fips=no", ed25519_keymgmt_functions },
+    { "ED448", "provider=fips,fips=no", ed448_keymgmt_functions },
 #endif
     { NULL, NULL, NULL }
 };
diff --git a/providers/implementations/keymgmt/build.info 
b/providers/implementations/keymgmt/build.info
index 92cac52e11..73597c7cea 100644
--- a/providers/implementations/keymgmt/build.info
+++ b/providers/implementations/keymgmt/build.info
@@ -15,8 +15,20 @@ ENDIF
 IF[{- !$disabled{ec} -}]
   SOURCE[$EC_GOAL]=ec_kmgmt.c
 ENDIF
+
+IF[{- !$disabled{asm} -}]
+  $ECDEF_s390x=S390X_EC_ASM
+
+  # Now that we have defined all the arch specific variables, use the
+  # appropriate one, and define the appropriate macros
+  IF[$ECASM_{- $target{asm_arch} -}]
+    $ECDEF=$ECDEF_{- $target{asm_arch} -}
+  ENDIF
+ENDIF
+
 IF[{- !$disabled{ec} -}]
   SOURCE[$ECX_GOAL]=ecx_kmgmt.c
+  DEFINE[$ECX_GOAL]=$ECDEF
 ENDIF
 
 SOURCE[../../libfips.a]=rsa_kmgmt.c
diff --git a/providers/implementations/keymgmt/ecx_kmgmt.c 
b/providers/implementations/keymgmt/ecx_kmgmt.c
index ca53a93f5e..c9105f777d 100644
--- a/providers/implementations/keymgmt/ecx_kmgmt.c
+++ b/providers/implementations/keymgmt/ecx_kmgmt.c
@@ -10,15 +10,34 @@
 #include <assert.h>
 #include <openssl/core_numbers.h>
 #include <openssl/core_names.h>
+#include <openssl/params.h>
+#include <openssl/err.h>
+#include <openssl/evp.h>
+#include <openssl/rand.h>
+#include "internal/param_build_set.h"
+#include "openssl/param_build.h"
 #include "crypto/ecx.h"
 #include "prov/implementations.h"
 #include "prov/providercommon.h"
-#include "internal/param_build_set.h"
+#include "prov/provider_ctx.h"
+#ifdef S390X_EC_ASM
+# include "s390x_arch.h"
+# include <openssl/sha.h>   /* For SHA512_DIGEST_LENGTH */
+#endif
 
 static OSSL_OP_keymgmt_new_fn x25519_new_key;
 static OSSL_OP_keymgmt_new_fn x448_new_key;
 static OSSL_OP_keymgmt_new_fn ed25519_new_key;
 static OSSL_OP_keymgmt_new_fn ed448_new_key;
+static OSSL_OP_keymgmt_gen_init_fn x25519_gen_init;
+static OSSL_OP_keymgmt_gen_init_fn x448_gen_init;
+static OSSL_OP_keymgmt_gen_init_fn ed25519_gen_init;
+static OSSL_OP_keymgmt_gen_init_fn ed448_gen_init;
+static OSSL_OP_keymgmt_gen_fn x25519_gen;
+static OSSL_OP_keymgmt_gen_fn x448_gen;
+static OSSL_OP_keymgmt_gen_fn ed25519_gen;
+static OSSL_OP_keymgmt_gen_fn ed448_gen;
+static OSSL_OP_keymgmt_gen_cleanup_fn ecx_gen_cleanup;
 static OSSL_OP_keymgmt_get_params_fn x25519_get_params;
 static OSSL_OP_keymgmt_get_params_fn x448_get_params;
 static OSSL_OP_keymgmt_get_params_fn ed25519_get_params;
@@ -32,6 +51,18 @@ static OSSL_OP_keymgmt_export_types_fn ecx_imexport_types;
 
 #define ECX_POSSIBLE_SELECTIONS (OSSL_KEYMGMT_SELECT_KEYPAIR)
 
+struct ecx_gen_ctx {
+    OPENSSL_CTX *libctx;
+    ECX_KEY_TYPE type;
+};
+
+#ifdef S390X_EC_ASM
+static void *s390x_ecx_keygen25519(struct ecx_gen_ctx *gctx);
+static void *s390x_ecx_keygen448(struct ecx_gen_ctx *gctx);
+static void *s390x_ecd_keygen25519(struct ecx_gen_ctx *gctx);
+static void *s390x_ecd_keygen448(struct ecx_gen_ctx *gctx);
+#endif
+
 static void *x25519_new_key(void *provctx)
 {
     return ecx_key_new(ECX_KEY_TYPE_X25519, 0);
@@ -213,6 +244,140 @@ static const OSSL_PARAM *ecx_gettable_params(void)
     return ecx_params;
 }
 
+static void *ecx_gen_init(void *provctx, int selection, ECX_KEY_TYPE type)
+{
+    OPENSSL_CTX *libctx = PROV_LIBRARY_CONTEXT_OF(provctx);
+    struct ecx_gen_ctx *gctx = NULL;
+
+    if ((selection & OSSL_KEYMGMT_SELECT_KEYPAIR) == 0)
+        return NULL;
+
+    if ((gctx = OPENSSL_malloc(sizeof(*gctx))) != NULL) {
+        gctx->libctx = libctx;
+        gctx->type = type;
+    }
+    return gctx;
+}
+
+static void *x25519_gen_init(void *provctx, int selection)
+{
+    return ecx_gen_init(provctx, selection, ECX_KEY_TYPE_X25519);
+}
+
+static void *x448_gen_init(void *provctx, int selection)
+{
+    return ecx_gen_init(provctx, selection, ECX_KEY_TYPE_X448);
+}
+
+static void *ed25519_gen_init(void *provctx, int selection)
+{
+    return ecx_gen_init(provctx, selection, ECX_KEY_TYPE_ED25519);
+}
+
+static void *ed448_gen_init(void *provctx, int selection)
+{
+    return ecx_gen_init(provctx, selection, ECX_KEY_TYPE_ED448);
+}
+
+static void *ecx_gen(struct ecx_gen_ctx *gctx)
+{
+    ECX_KEY *key;
+    unsigned char *privkey;
+
+    if (gctx == NULL)
+        return NULL;
+    if ((key = ecx_key_new(gctx->type, 0)) == NULL) {
+        ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE);
+        return NULL;
+    }
+    if ((privkey = ecx_key_allocate_privkey(key)) == NULL) {
+        ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE);
+        goto err;
+    }
+    if (RAND_priv_bytes_ex(gctx->libctx, privkey, key->keylen) <= 0)
+        goto err;
+    switch (gctx->type) {
+    case ECX_KEY_TYPE_X25519:
+        privkey[0] &= 248;
+        privkey[X25519_KEYLEN - 1] &= 127;
+        privkey[X25519_KEYLEN - 1] |= 64;
+        X25519_public_from_private(key->pubkey, privkey);
+        break;
+    case ECX_KEY_TYPE_X448:
+        privkey[0] &= 252;
+        privkey[X448_KEYLEN - 1] |= 128;
+        X448_public_from_private(key->pubkey, privkey);
+        break;
+    case ECX_KEY_TYPE_ED25519:
+        if (!ED25519_public_from_private(gctx->libctx, key->pubkey, privkey))
+            goto err;
+        break;
+    case ECX_KEY_TYPE_ED448:
+        if (!ED448_public_from_private(gctx->libctx, key->pubkey, privkey))
+            goto err;
+        break;
+    }
+    return key;
+err:
+    ecx_key_free(key);
+    return NULL;
+}
+
+static void *x25519_gen(void *genctx, OSSL_CALLBACK *osslcb, void *cbarg)
+{
+    struct ecx_gen_ctx *gctx = genctx;
+
+#ifdef S390X_EC_ASM
+    if (OPENSSL_s390xcap_P.pcc[1] & S390X_CAPBIT(S390X_SCALAR_MULTIPLY_X25519))
+        return s390x_ecx_keygen25519(gctx);
+#endif
+    return ecx_gen(gctx);
+}
+
+static void *x448_gen(void *genctx, OSSL_CALLBACK *osslcb, void *cbarg)
+{
+    struct ecx_gen_ctx *gctx = genctx;
+
+#ifdef S390X_EC_ASM
+    if (OPENSSL_s390xcap_P.pcc[1] & S390X_CAPBIT(S390X_SCALAR_MULTIPLY_X448))
+        return s390x_ecx_keygen448(gctx);
+#endif
+    return ecx_gen(gctx);
+}
+
+static void *ed25519_gen(void *genctx, OSSL_CALLBACK *osslcb, void *cbarg)
+{
+    struct ecx_gen_ctx *gctx = genctx;
+#ifdef S390X_EC_ASM
+    if (OPENSSL_s390xcap_P.pcc[1] & S390X_CAPBIT(S390X_SCALAR_MULTIPLY_ED25519)
+        && OPENSSL_s390xcap_P.kdsa[0] & S390X_CAPBIT(S390X_EDDSA_SIGN_ED25519)
+        && OPENSSL_s390xcap_P.kdsa[0]
+            & S390X_CAPBIT(S390X_EDDSA_VERIFY_ED25519))
+        return s390x_ecd_keygen25519(gctx);
+#endif
+    return ecx_gen(gctx);
+}
+
+static void *ed448_gen(void *genctx, OSSL_CALLBACK *osslcb, void *cbarg)
+{
+    struct ecx_gen_ctx *gctx = genctx;
+
+#ifdef S390X_EC_ASM
+    if (OPENSSL_s390xcap_P.pcc[1] & S390X_CAPBIT(S390X_SCALAR_MULTIPLY_ED448)
+        && OPENSSL_s390xcap_P.kdsa[0] & S390X_CAPBIT(S390X_EDDSA_SIGN_ED448)
+        && OPENSSL_s390xcap_P.kdsa[0] & S390X_CAPBIT(S390X_EDDSA_VERIFY_ED448))
+        return s390x_ecd_keygen448(gctx);
+#endif
+    return ecx_gen(gctx);
+}
+
+static void ecx_gen_cleanup(void *genctx)
+{
+    struct ecx_gen_ctx *gctx = genctx;
+
+    OPENSSL_free(gctx);
+}
+
 #define MAKE_KEYMGMT_FUNCTIONS(alg) \
     const OSSL_DISPATCH alg##_keymgmt_functions[] = { \
         { OSSL_FUNC_KEYMGMT_NEW, (void (*)(void))alg##_new_key }, \
@@ -224,6 +389,9 @@ static const OSSL_PARAM *ecx_gettable_params(void)
         { OSSL_FUNC_KEYMGMT_IMPORT_TYPES, (void (*)(void))ecx_imexport_types 
}, \
         { OSSL_FUNC_KEYMGMT_EXPORT, (void (*)(void))ecx_export }, \
         { OSSL_FUNC_KEYMGMT_EXPORT_TYPES, (void (*)(void))ecx_imexport_types 
}, \
+        { OSSL_FUNC_KEYMGMT_GEN_INIT, (void (*)(void))alg##_gen_init }, \
+        { OSSL_FUNC_KEYMGMT_GEN, (void (*)(void))alg##_gen }, \
+        { OSSL_FUNC_KEYMGMT_GEN_CLEANUP, (void (*)(void))ecx_gen_cleanup }, \
         { 0, NULL } \
     };
 
@@ -231,3 +399,212 @@ MAKE_KEYMGMT_FUNCTIONS(x25519)
 MAKE_KEYMGMT_FUNCTIONS(x448)
 MAKE_KEYMGMT_FUNCTIONS(ed25519)
 MAKE_KEYMGMT_FUNCTIONS(ed448)
+
+#ifdef S390X_EC_ASM
+# include "s390x_arch.h"
+
+static void *s390x_ecx_keygen25519(struct ecx_gen_ctx *gctx)
+{
+    static const unsigned char generator[] = {
+        0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+    };
+    ECX_KEY *key = ecx_key_new(ECX_KEY_TYPE_X25519, 1);
+    unsigned char *privkey = NULL, *pubkey;
+
+    if (key == NULL) {
+        ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE);
+        goto err;
+    }
+
+    pubkey = key->pubkey;
+
+    privkey = ecx_key_allocate_privkey(key);
+    if (privkey == NULL) {
+        ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE);
+        goto err;
+    }
+
+    if (RAND_priv_bytes_ex(gctx->libctx, privkey, X25519_KEYLEN) <= 0)
+        goto err;
+
+    privkey[0] &= 248;
+    privkey[31] &= 127;
+    privkey[31] |= 64;
+
+    if (s390x_x25519_mul(pubkey, generator, privkey) != 1)
+        goto err;
+    return key;
+ err:
+    ecx_key_free(key);
+    return NULL;
+}
+
+static void *s390x_ecx_keygen448(struct ecx_gen_ctx *gctx)
+{
+    static const unsigned char generator[] = {
+        0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+    };
+    ECX_KEY *key = ecx_key_new(ECX_KEY_TYPE_X448, 1);
+    unsigned char *privkey = NULL, *pubkey;
+
+    if (key == NULL) {
+        ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE);
+        goto err;
+    }
+
+    pubkey = key->pubkey;
+
+    privkey = ecx_key_allocate_privkey(key);
+    if (privkey == NULL) {
+        ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE);
+        goto err;
+    }
+
+    if (RAND_priv_bytes_ex(gctx->libctx, privkey, X448_KEYLEN) <= 0)
+        goto err;
+
+    privkey[0] &= 252;
+    privkey[55] |= 128;
+
+    if (s390x_x448_mul(pubkey, generator, privkey) != 1)
+        goto err;
+    return key;
+ err:
+    ecx_key_free(key);
+    return NULL;
+}
+
+static void *s390x_ecd_keygen25519(struct ecx_gen_ctx *gctx)
+{
+    static const unsigned char generator_x[] = {
+        0x1a, 0xd5, 0x25, 0x8f, 0x60, 0x2d, 0x56, 0xc9, 0xb2, 0xa7, 0x25, 0x95,
+        0x60, 0xc7, 0x2c, 0x69, 0x5c, 0xdc, 0xd6, 0xfd, 0x31, 0xe2, 0xa4, 0xc0,
+        0xfe, 0x53, 0x6e, 0xcd, 0xd3, 0x36, 0x69, 0x21
+    };
+    static const unsigned char generator_y[] = {
+        0x58, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
+        0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
+        0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
+    };
+    unsigned char x_dst[32], buff[SHA512_DIGEST_LENGTH];
+    ECX_KEY *key = ecx_key_new(ECX_KEY_TYPE_ED25519, 1);
+    unsigned char *privkey = NULL, *pubkey;
+    unsigned int sz;
+    EVP_MD *sha = NULL;
+    int j;
+
+    if (key == NULL) {
+        ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE);
+        goto err;
+    }
+
+    pubkey = key->pubkey;
+
+    privkey = ecx_key_allocate_privkey(key);
+    if (privkey == NULL) {
+        ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE);
+        goto err;
+    }
+
+    if (RAND_priv_bytes_ex(gctx->libctx, privkey, ED25519_KEYLEN) <= 0)
+        goto err;
+
+    sha = EVP_MD_fetch(gctx->libctx, "SHA512", NULL);
+    if (sha == NULL)
+        goto err;
+    j = EVP_Digest(privkey, 32, buff, &sz, sha, NULL);
+    EVP_MD_free(sha);
+    if (!j)
+        goto err;
+
+    buff[0] &= 248;
+    buff[31] &= 63;
+    buff[31] |= 64;
+
+    if (s390x_ed25519_mul(x_dst, pubkey,
+                          generator_x, generator_y, buff) != 1)
+        goto err;
+
+    pubkey[31] |= ((x_dst[0] & 0x01) << 7);
+    return key;
+ err:
+    ecx_key_free(key);
+    return NULL;
+}
+
+static void *s390x_ecd_keygen448(struct ecx_gen_ctx *gctx)
+{
+    static const unsigned char generator_x[] = {
+        0x5e, 0xc0, 0x0c, 0xc7, 0x2b, 0xa8, 0x26, 0x26, 0x8e, 0x93, 0x00, 0x8b,
+        0xe1, 0x80, 0x3b, 0x43, 0x11, 0x65, 0xb6, 0x2a, 0xf7, 0x1a, 0xae, 0x12,
+        0x64, 0xa4, 0xd3, 0xa3, 0x24, 0xe3, 0x6d, 0xea, 0x67, 0x17, 0x0f, 0x47,
+        0x70, 0x65, 0x14, 0x9e, 0xda, 0x36, 0xbf, 0x22, 0xa6, 0x15, 0x1d, 0x22,
+        0xed, 0x0d, 0xed, 0x6b, 0xc6, 0x70, 0x19, 0x4f, 0x00
+    };
+    static const unsigned char generator_y[] = {
+        0x14, 0xfa, 0x30, 0xf2, 0x5b, 0x79, 0x08, 0x98, 0xad, 0xc8, 0xd7, 0x4e,
+        0x2c, 0x13, 0xbd, 0xfd, 0xc4, 0x39, 0x7c, 0xe6, 0x1c, 0xff, 0xd3, 0x3a,
+        0xd7, 0xc2, 0xa0, 0x05, 0x1e, 0x9c, 0x78, 0x87, 0x40, 0x98, 0xa3, 0x6c,
+        0x73, 0x73, 0xea, 0x4b, 0x62, 0xc7, 0xc9, 0x56, 0x37, 0x20, 0x76, 0x88,
+        0x24, 0xbc, 0xb6, 0x6e, 0x71, 0x46, 0x3f, 0x69, 0x00
+    };
+    unsigned char x_dst[57], buff[114];
+    ECX_KEY *key = ecx_key_new(ECX_KEY_TYPE_ED448, 1);
+    unsigned char *privkey = NULL, *pubkey;
+    EVP_MD_CTX *hashctx = NULL;
+    EVP_MD *shake = NULL;
+
+    if (key == NULL) {
+        ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE);
+        goto err;
+    }
+
+    pubkey = key->pubkey;
+
+    privkey = ecx_key_allocate_privkey(key);
+    if (privkey == NULL) {
+        ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE);
+        goto err;
+    }
+
+    shake = EVP_MD_fetch(gctx->libctx, "SHAKE256", NULL);
+    if (shake == NULL)
+        goto err;
+    if (RAND_priv_bytes_ex(gctx->libctx, privkey, ED448_KEYLEN) <= 0)
+        goto err;
+
+    hashctx = EVP_MD_CTX_new();
+    if (hashctx == NULL)
+        goto err;
+    if (EVP_DigestInit_ex(hashctx, shake, NULL) != 1)
+        goto err;
+    if (EVP_DigestUpdate(hashctx, privkey, 57) != 1)
+        goto err;
+    if (EVP_DigestFinalXOF(hashctx, buff, sizeof(buff)) != 1)
+        goto err;
+
+    buff[0] &= -4;
+    buff[55] |= 0x80;
+    buff[56] = 0;
+
+    if (s390x_ed448_mul(x_dst, pubkey,
+                        generator_x, generator_y, buff) != 1)
+        goto err;
+
+    pubkey[56] |= ((x_dst[0] & 0x01) << 7);
+    EVP_MD_CTX_free(hashctx);
+    EVP_MD_free(shake);
+    return key;
+ err:
+    ecx_key_free(key);
+    EVP_MD_CTX_free(hashctx);
+    EVP_MD_free(shake);
+    return NULL;
+}
+#endif

Reply via email to