[openssl] master update

Dr. Paul Dale pauli at openssl.org
Fri Apr 17 11:10:13 UTC 2020


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 <paul.dale at oracle.com>
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 <matt at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/11371)

commit 19985ac42cab57bf55acb626aebfdc1194771b76
Author: Pauli <paul.dale at oracle.com>
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 <matt at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/11371)

commit b5bcc053024ce5adeb714d0a48dce71188cbd13c
Author: Pauli <paul.dale at oracle.com>
Date:   Wed Apr 15 12:32:01 2020 +1000

    pkey: free key manager on error path
    
    Reviewed-by: Matt Caswell <matt at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/11371)

commit d8171446a274ab57e7d55d8d9f6ca8a0a7144d13
Author: Pauli <paul.dale at oracle.com>
Date:   Wed Apr 15 10:06:20 2020 +1000

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

commit c1e48c5171affd99111fd08e7a0a7e1a76121138
Author: Pauli <paul.dale at oracle.com>
Date:   Thu Apr 2 14:37:26 2020 +1000

    s390: ECX key generation fixes.
    
    Reviewed-by: Matt Caswell <matt at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/11371)

commit 43cd37014ef4433ae8e82ba64bddc42cf0bd618a
Author: Pauli <paul.dale at oracle.com>
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 <matt at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/11371)

commit 1ee1e551148d963b566a69c2e6e9a583646112fc
Author: Pauli <paul.dale at oracle.com>
Date:   Fri Mar 20 12:58:37 2020 +1000

    Add ECX to FIPS provider as non-FIPS algorithms
    
    Reviewed-by: Matt Caswell <matt at openssl.org>
    (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


More information about the openssl-commits mailing list