[openssl] master update

Matt Caswell matt at openssl.org
Tue Feb 11 22:40:19 UTC 2020


The branch master has been updated
       via  97b50f67f212589661c9f1edd5285822c6cc642b (commit)
       via  6f7d213533d9c7c2d810499cfedaa6d2424482c9 (commit)
       via  90d3cb57c6caafbe031e32a99051386b8c5a90c0 (commit)
       via  4de88fe6daad0b7bd65b20bc887ff1ac62ae2ce8 (commit)
      from  620c97b671a9c7bc31ca36a24b2242aa1aa80022 (commit)


- Log -----------------------------------------------------------------
commit 97b50f67f212589661c9f1edd5285822c6cc642b
Author: Matt Caswell <matt at openssl.org>
Date:   Tue Feb 4 16:41:19 2020 +0000

    Add S390 support for provider based X25519/X448
    
    Reviewed-by: Patrick Steuer <patrick.steuer at de.ibm.com>
    Reviewed-by: Shane Lontis <shane.lontis at oracle.com>
    (Merged from https://github.com/openssl/openssl/pull/10964)

commit 6f7d213533d9c7c2d810499cfedaa6d2424482c9
Author: Matt Caswell <matt at openssl.org>
Date:   Fri Jan 24 17:13:40 2020 +0000

    Add X25519/X448 Key Exchange to the default provider
    
    Reviewed-by: Patrick Steuer <patrick.steuer at de.ibm.com>
    Reviewed-by: Shane Lontis <shane.lontis at oracle.com>
    (Merged from https://github.com/openssl/openssl/pull/10964)

commit 90d3cb57c6caafbe031e32a99051386b8c5a90c0
Author: Matt Caswell <matt at openssl.org>
Date:   Mon Jan 27 16:57:03 2020 +0000

    Implement Provider side Key Management for X25519 and X448
    
    Reviewed-by: Patrick Steuer <patrick.steuer at de.ibm.com>
    Reviewed-by: Shane Lontis <shane.lontis at oracle.com>
    (Merged from https://github.com/openssl/openssl/pull/10964)

commit 4de88fe6daad0b7bd65b20bc887ff1ac62ae2ce8
Author: Matt Caswell <matt at openssl.org>
Date:   Mon Jan 27 16:50:47 2020 +0000

    Implement a stricter ECX_KEY type
    
    Add ref counting and control how we allocate storage for the private key.
    We will need this type in following commits where we move the ecx code
    to be provider aware.
    
    Reviewed-by: Patrick Steuer <patrick.steuer at de.ibm.com>
    Reviewed-by: Shane Lontis <shane.lontis at oracle.com>
    (Merged from https://github.com/openssl/openssl/pull/10964)

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

Summary of changes:
 crypto/dh/dh_ameth.c                               |   4 +-
 crypto/dsa/dsa_ameth.c                             |   4 +-
 crypto/ec/build.info                               |   4 +-
 crypto/ec/curve25519.c                             |   1 +
 crypto/ec/curve448/curve448.c                      |   1 +
 crypto/ec/curve448/curve448_local.h                |   6 -
 crypto/ec/ec_local.h                               |   5 -
 crypto/ec/ecx_key.c                                |  69 ++++++
 crypto/ec/ecx_meth.c                               | 123 ++++++-----
 crypto/err/openssl.txt                             |   3 +-
 include/crypto/ecx.h                               |  74 +++++++
 include/crypto/evp.h                               |  18 +-
 include/openssl/core_names.h                       |  10 +-
 providers/common/include/prov/providercommonerr.h  |   1 +
 providers/common/provider_err.c                    |   2 +
 providers/defltprov.c                              |   8 +
 providers/fips/fipsprov.c                          |  10 +-
 providers/implementations/exchange/build.info      |  15 ++
 providers/implementations/exchange/ecx_exch.c      | 223 ++++++++++++++++++++
 .../implementations/include/prov/implementations.h |   4 +
 providers/implementations/keymgmt/build.info       |   2 +
 providers/implementations/keymgmt/dh_kmgmt.c       |  12 +-
 providers/implementations/keymgmt/dsa_kmgmt.c      |  12 +-
 providers/implementations/keymgmt/ecx_kmgmt.c      | 231 +++++++++++++++++++++
 test/curve448_internal_test.c                      |   1 +
 test/evp_pkey_provided_test.c                      |   4 +-
 26 files changed, 734 insertions(+), 113 deletions(-)
 create mode 100644 crypto/ec/ecx_key.c
 create mode 100644 include/crypto/ecx.h
 create mode 100644 providers/implementations/exchange/ecx_exch.c
 create mode 100644 providers/implementations/keymgmt/ecx_kmgmt.c

diff --git a/crypto/dh/dh_ameth.c b/crypto/dh/dh_ameth.c
index 4f74ab6f4a..bee414abf7 100644
--- a/crypto/dh/dh_ameth.c
+++ b/crypto/dh/dh_ameth.c
@@ -505,10 +505,10 @@ static int dh_pkey_export_to(const EVP_PKEY *from, void *to_keydata,
             return 0;
     }
     /* A key must at least have a public part. */
-    if (!ossl_param_bld_push_BN(&tmpl, OSSL_PKEY_PARAM_DH_PUB_KEY, pub_key))
+    if (!ossl_param_bld_push_BN(&tmpl, OSSL_PKEY_PARAM_PUB_KEY, pub_key))
         return 0;
     if (priv_key != NULL) {
-        if (!ossl_param_bld_push_BN(&tmpl, OSSL_PKEY_PARAM_DH_PRIV_KEY,
+        if (!ossl_param_bld_push_BN(&tmpl, OSSL_PKEY_PARAM_PRIV_KEY,
                                     priv_key))
             return 0;
     }
diff --git a/crypto/dsa/dsa_ameth.c b/crypto/dsa/dsa_ameth.c
index 9d1b89717c..a68928497e 100644
--- a/crypto/dsa/dsa_ameth.c
+++ b/crypto/dsa/dsa_ameth.c
@@ -530,11 +530,11 @@ static int dsa_pkey_export_to(const EVP_PKEY *from, void *to_keydata,
         || !ossl_param_bld_push_BN(&tmpl, OSSL_PKEY_PARAM_FFC_Q, q)
         || !ossl_param_bld_push_BN(&tmpl, OSSL_PKEY_PARAM_FFC_G, g))
         return 0;
-    if (!ossl_param_bld_push_BN(&tmpl, OSSL_PKEY_PARAM_DSA_PUB_KEY,
+    if (!ossl_param_bld_push_BN(&tmpl, OSSL_PKEY_PARAM_PUB_KEY,
                                 pub_key))
         return 0;
     if (priv_key != NULL) {
-        if (!ossl_param_bld_push_BN(&tmpl, OSSL_PKEY_PARAM_DSA_PRIV_KEY,
+        if (!ossl_param_bld_push_BN(&tmpl, OSSL_PKEY_PARAM_PRIV_KEY,
                                     priv_key))
             return 0;
     }
diff --git a/crypto/ec/build.info b/crypto/ec/build.info
index ba16e088fa..a8828c5102 100644
--- a/crypto/ec/build.info
+++ b/crypto/ec/build.info
@@ -54,8 +54,8 @@ $COMMON=ec_lib.c ecp_smpl.c ecp_mont.c ecp_nist.c ec_cvt.c ec_mult.c \
         curve448/arch_32/f_impl.c curve448/f_generic.c curve448/scalar.c \
         curve448/curve448_tables.c curve448/eddsa.c curve448/curve448.c \
         $ECASM
-SOURCE[../../libcrypto]=$COMMON ec_ameth.c ec_pmeth.c ecx_meth.c ec_err.c \
-                        ecdh_kdf.c eck_prn.c
+SOURCE[../../libcrypto]=$COMMON ec_ameth.c ec_pmeth.c ecx_meth.c ecx_key.c \
+                        ec_err.c ecdh_kdf.c eck_prn.c
 SOURCE[../../providers/libfips.a]=$COMMON
 
 # Implementations are now spread across several libraries, so the defines
diff --git a/crypto/ec/curve25519.c b/crypto/ec/curve25519.c
index 6672f5d249..024f7fe169 100644
--- a/crypto/ec/curve25519.c
+++ b/crypto/ec/curve25519.c
@@ -14,6 +14,7 @@
 #include "internal/deprecated.h"
 
 #include <string.h>
+#include "crypto/ecx.h"
 #include "ec_local.h"
 #include <openssl/evp.h>
 #include <openssl/sha.h>
diff --git a/crypto/ec/curve448/curve448.c b/crypto/ec/curve448/curve448.c
index e3dffd09c9..ecc98d884c 100644
--- a/crypto/ec/curve448/curve448.c
+++ b/crypto/ec/curve448/curve448.c
@@ -15,6 +15,7 @@
 
 #include "point_448.h"
 #include "ed448.h"
+#include "crypto/ecx.h"
 #include "curve448_local.h"
 
 #define COFACTOR 4
diff --git a/crypto/ec/curve448/curve448_local.h b/crypto/ec/curve448/curve448_local.h
index 197627f6b8..36f960ec0e 100644
--- a/crypto/ec/curve448/curve448_local.h
+++ b/crypto/ec/curve448/curve448_local.h
@@ -10,12 +10,6 @@
 # define OSSL_CRYPTO_EC_CURVE448_LOCAL_H
 # include "curve448utils.h"
 
-int X448(uint8_t out_shared_key[56], const uint8_t private_key[56],
-         const uint8_t peer_public_value[56]);
-
-void X448_public_from_private(uint8_t out_public_value[56],
-                              const uint8_t private_key[56]);
-
 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,
diff --git a/crypto/ec/ec_local.h b/crypto/ec/ec_local.h
index a523ab6422..c0eacc9ce5 100644
--- a/crypto/ec/ec_local.h
+++ b/crypto/ec/ec_local.h
@@ -683,11 +683,6 @@ int ED25519_verify(const uint8_t *message, size_t message_len,
 void ED25519_public_from_private(uint8_t out_public_key[32],
                                  const uint8_t private_key[32]);
 
-int X25519(uint8_t out_shared_key[32], const uint8_t private_key[32],
-           const uint8_t peer_public_value[32]);
-void X25519_public_from_private(uint8_t out_public_value[32],
-                                const uint8_t private_key[32]);
-
 /*-
  * This functions computes a single point multiplication over the EC group,
  * using, at a high level, a Montgomery ladder with conditional swaps, with
diff --git a/crypto/ec/ecx_key.c b/crypto/ec/ecx_key.c
new file mode 100644
index 0000000000..59643cc6ad
--- /dev/null
+++ b/crypto/ec/ecx_key.c
@@ -0,0 +1,69 @@
+/*
+ * Copyright 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
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include <openssl/err.h>
+#include "crypto/ecx.h"
+
+ECX_KEY *ecx_key_new(size_t keylen, int haspubkey)
+{
+    ECX_KEY *ret = OPENSSL_zalloc(sizeof(*ret));
+
+    if (ret == NULL)
+        return NULL;
+
+    ret->haspubkey = haspubkey;
+    ret->keylen = keylen;
+    ret->references = 1;
+
+    ret->lock = CRYPTO_THREAD_lock_new();
+    if (ret->lock == NULL) {
+        ERR_raise(ERR_LIB_EC, ERR_R_MALLOC_FAILURE);
+        OPENSSL_free(ret);
+        return NULL;
+    }
+
+    return ret;
+}
+
+void ecx_key_free(ECX_KEY *key)
+{
+    int i;
+
+    if (key == NULL)
+        return;
+
+    CRYPTO_DOWN_REF(&key->references, &i, key->lock);
+    REF_PRINT_COUNT("ECX_KEY", r);
+    if (i > 0)
+        return;
+    REF_ASSERT_ISNT(i < 0);
+
+    OPENSSL_secure_clear_free(key->privkey, key->keylen);
+    CRYPTO_THREAD_lock_free(key->lock);
+    OPENSSL_free(key);
+}
+
+int ecx_key_up_ref(ECX_KEY *key)
+{
+    int i;
+
+    if (CRYPTO_UP_REF(&key->references, &i, key->lock) <= 0)
+        return 0;
+
+    REF_PRINT_COUNT("ECX_KEY", key);
+    REF_ASSERT_ISNT(i < 2);
+    return ((i > 1) ? 1 : 0);
+}
+
+unsigned char *ecx_key_allocate_privkey(ECX_KEY *key)
+{
+    key->privkey = OPENSSL_secure_zalloc(key->keylen);
+
+    return key->privkey;
+}
diff --git a/crypto/ec/ecx_meth.c b/crypto/ec/ecx_meth.c
index 525fcd343f..32817562bf 100644
--- a/crypto/ec/ecx_meth.c
+++ b/crypto/ec/ecx_meth.c
@@ -18,22 +18,14 @@
 #include <openssl/x509.h>
 #include <openssl/ec.h>
 #include <openssl/rand.h>
+#include <openssl/core_names.h>
+#include "internal/param_build.h"
 #include "crypto/asn1.h"
 #include "crypto/evp.h"
+#include "crypto/ecx.h"
 #include "ec_local.h"
 #include "curve448/curve448_local.h"
 
-#define X25519_BITS          253
-#define X25519_SECURITY_BITS 128
-
-#define ED25519_SIGSIZE      64
-
-#define X448_BITS            448
-#define ED448_BITS           456
-#define X448_SECURITY_BITS   224
-
-#define ED448_SIGSIZE        114
-
 #define ISX448(id)      ((id) == EVP_PKEY_X448)
 #define IS25519(id)     ((id) == EVP_PKEY_X25519 || (id) == EVP_PKEY_ED25519)
 #define KEYLENID(id)    (IS25519(id) ? X25519_KEYLEN \
@@ -73,7 +65,7 @@ static int ecx_key_op(EVP_PKEY *pkey, int id, const X509_ALGOR *palg,
         }
     }
 
-    key = OPENSSL_zalloc(sizeof(*key));
+    key = ecx_key_new(KEYLENID(id), 1);
     if (key == NULL) {
         ECerr(EC_F_ECX_KEY_OP, ERR_R_MALLOC_FAILURE);
         return 0;
@@ -83,17 +75,14 @@ static int ecx_key_op(EVP_PKEY *pkey, int id, const X509_ALGOR *palg,
     if (op == KEY_OP_PUBLIC) {
         memcpy(pubkey, p, plen);
     } else {
-        privkey = key->privkey = OPENSSL_secure_malloc(KEYLENID(id));
+        privkey = ecx_key_allocate_privkey(key);
         if (privkey == NULL) {
             ECerr(EC_F_ECX_KEY_OP, ERR_R_MALLOC_FAILURE);
             goto err;
         }
         if (op == KEY_OP_KEYGEN) {
-            if (RAND_priv_bytes(privkey, KEYLENID(id)) <= 0) {
-                OPENSSL_secure_free(privkey);
-                key->privkey = NULL;
+            if (RAND_priv_bytes(privkey, KEYLENID(id)) <= 0)
                 goto err;
-            }
             if (id == EVP_PKEY_X25519) {
                 privkey[0] &= 248;
                 privkey[X25519_KEYLEN - 1] &= 127;
@@ -128,7 +117,7 @@ static int ecx_key_op(EVP_PKEY *pkey, int id, const X509_ALGOR *palg,
     EVP_PKEY_assign(pkey, id, key);
     return 1;
  err:
-    OPENSSL_free(key);
+    ecx_key_free(key);
     return 0;
 }
 
@@ -264,9 +253,7 @@ static int ecx_security_bits(const EVP_PKEY *pkey)
 
 static void ecx_free(EVP_PKEY *pkey)
 {
-    if (pkey->pkey.ecx != NULL)
-        OPENSSL_secure_clear_free(pkey->pkey.ecx->privkey, KEYLEN(pkey));
-    OPENSSL_free(pkey->pkey.ecx);
+    ecx_key_free(pkey->pkey.ecx);
 }
 
 /* "parameters" are always equal */
@@ -416,6 +403,48 @@ static int ecx_get_pub_key(const EVP_PKEY *pkey, unsigned char *pub,
     return 1;
 }
 
+static size_t ecx_pkey_dirty_cnt(const EVP_PKEY *pkey)
+{
+    /*
+     * We provide no mechanism to "update" an ECX key once it has been set,
+     * therefore we do not have to maintain a dirty count.
+     */
+    return 1;
+}
+
+static int ecx_pkey_export_to(const EVP_PKEY *from, void *to_keydata,
+                              EVP_KEYMGMT *to_keymgmt)
+{
+    const ECX_KEY *key = from->pkey.ecx;
+    OSSL_PARAM_BLD tmpl;
+    OSSL_PARAM *params = NULL;
+    int rv = 0;
+
+    ossl_param_bld_init(&tmpl);
+
+    /* A key must at least have a public part */
+    if (!ossl_param_bld_push_octet_string(&tmpl, OSSL_PKEY_PARAM_PUB_KEY,
+                                          key->pubkey, key->keylen))
+        goto err;
+
+    if (key->privkey != NULL) {
+        if (!ossl_param_bld_push_octet_string(&tmpl,
+                                              OSSL_PKEY_PARAM_PRIV_KEY,
+                                              key->privkey, key->keylen))
+            goto err;
+    }
+
+    params = ossl_param_bld_to_param(&tmpl);
+
+    /* We export, the provider imports */
+    rv = evp_keymgmt_import(to_keymgmt, to_keydata, OSSL_KEYMGMT_SELECT_ALL,
+                            params);
+
+ err:
+    ossl_param_bld_free(params);
+    return rv;
+}
+
 const EVP_PKEY_ASN1_METHOD ecx25519_asn1_meth = {
     EVP_PKEY_X25519,
     EVP_PKEY_X25519,
@@ -457,6 +486,8 @@ const EVP_PKEY_ASN1_METHOD ecx25519_asn1_meth = {
     ecx_set_pub_key,
     ecx_get_priv_key,
     ecx_get_pub_key,
+    ecx_pkey_dirty_cnt,
+    ecx_pkey_export_to
 };
 
 const EVP_PKEY_ASN1_METHOD ecx448_asn1_meth = {
@@ -500,6 +531,8 @@ const EVP_PKEY_ASN1_METHOD ecx448_asn1_meth = {
     ecx_set_pub_key,
     ecx_get_priv_key,
     ecx_get_pub_key,
+    ecx_pkey_dirty_cnt,
+    ecx_pkey_export_to
 };
 
 static int ecd_size25519(const EVP_PKEY *pkey)
@@ -918,9 +951,9 @@ static void s390x_x448_mod_p(unsigned char u[56])
                                  u, u_red, sizeof(u_red));
 }
 
-static int s390x_x25519_mul(unsigned char u_dst[32],
-                            const unsigned char u_src[32],
-                            const unsigned char d_src[32])
+int s390x_x25519_mul(unsigned char u_dst[32],
+                     const unsigned char u_src[32],
+                     const unsigned char d_src[32])
 {
     union {
         struct {
@@ -951,9 +984,9 @@ static int s390x_x25519_mul(unsigned char u_dst[32],
     return rc;
 }
 
-static int s390x_x448_mul(unsigned char u_dst[56],
-                          const unsigned char u_src[56],
-                          const unsigned char d_src[56])
+int s390x_x448_mul(unsigned char u_dst[56],
+                   const unsigned char u_src[56],
+                   const unsigned char d_src[56])
 {
     union {
         struct {
@@ -1067,10 +1100,9 @@ static int s390x_pkey_ecx_keygen25519(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey)
         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 *key = ecx_key_new(X25519_KEYLEN, 1);
     unsigned char *privkey = NULL, *pubkey;
 
-    key = OPENSSL_zalloc(sizeof(*key));
     if (key == NULL) {
         ECerr(EC_F_S390X_PKEY_ECX_KEYGEN25519, ERR_R_MALLOC_FAILURE);
         goto err;
@@ -1078,7 +1110,7 @@ static int s390x_pkey_ecx_keygen25519(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey)
 
     pubkey = key->pubkey;
 
-    privkey = key->privkey = OPENSSL_secure_malloc(X25519_KEYLEN);
+    privkey = ecx_key_allocate_privkey(key);
     if (privkey == NULL) {
         ECerr(EC_F_S390X_PKEY_ECX_KEYGEN25519, ERR_R_MALLOC_FAILURE);
         goto err;
@@ -1097,9 +1129,7 @@ static int s390x_pkey_ecx_keygen25519(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey)
     EVP_PKEY_assign(pkey, ctx->pmeth->pkey_id, key);
     return 1;
  err:
-    OPENSSL_secure_clear_free(privkey, X25519_KEYLEN);
-    key->privkey = NULL;
-    OPENSSL_free(key);
+    ecx_key_free(key);
     return 0;
 }
 
@@ -1112,10 +1142,9 @@ static int s390x_pkey_ecx_keygen448(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey)
         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 *key = ecx_key_new(X448_KEYLEN, 1);
     unsigned char *privkey = NULL, *pubkey;
 
-    key = OPENSSL_zalloc(sizeof(*key));
     if (key == NULL) {
         ECerr(EC_F_S390X_PKEY_ECX_KEYGEN448, ERR_R_MALLOC_FAILURE);
         goto err;
@@ -1123,7 +1152,7 @@ static int s390x_pkey_ecx_keygen448(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey)
 
     pubkey = key->pubkey;
 
-    privkey = key->privkey = OPENSSL_secure_malloc(X448_KEYLEN);
+    privkey = ecx_key_allocate_privkey(key);
     if (privkey == NULL) {
         ECerr(EC_F_S390X_PKEY_ECX_KEYGEN448, ERR_R_MALLOC_FAILURE);
         goto err;
@@ -1141,9 +1170,7 @@ static int s390x_pkey_ecx_keygen448(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey)
     EVP_PKEY_assign(pkey, ctx->pmeth->pkey_id, key);
     return 1;
  err:
-    OPENSSL_secure_clear_free(privkey, X448_KEYLEN);
-    key->privkey = NULL;
-    OPENSSL_free(key);
+    ecx_key_free(key);
     return 0;
 }
 
@@ -1160,11 +1187,10 @@ static int s390x_pkey_ecd_keygen25519(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey)
         0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
     };
     unsigned char x_dst[32], buff[SHA512_DIGEST_LENGTH];
-    ECX_KEY *key;
+    ECX_KEY *key = ecx_key_new(ED25519_KEYLEN, 1);
     unsigned char *privkey = NULL, *pubkey;
     unsigned int sz;
 
-    key = OPENSSL_zalloc(sizeof(*key));
     if (key == NULL) {
         ECerr(EC_F_S390X_PKEY_ECD_KEYGEN25519, ERR_R_MALLOC_FAILURE);
         goto err;
@@ -1172,7 +1198,7 @@ static int s390x_pkey_ecd_keygen25519(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey)
 
     pubkey = key->pubkey;
 
-    privkey = key->privkey = OPENSSL_secure_malloc(ED25519_KEYLEN);
+    privkey = ecx_key_allocate_privkey(key);
     if (privkey == NULL) {
         ECerr(EC_F_S390X_PKEY_ECD_KEYGEN25519, ERR_R_MALLOC_FAILURE);
         goto err;
@@ -1197,9 +1223,7 @@ static int s390x_pkey_ecd_keygen25519(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey)
     EVP_PKEY_assign(pkey, ctx->pmeth->pkey_id, key);
     return 1;
  err:
-    OPENSSL_secure_clear_free(privkey, ED25519_KEYLEN);
-    key->privkey = NULL;
-    OPENSSL_free(key);
+    ecx_key_free(key);
     return 0;
 }
 
@@ -1220,11 +1244,10 @@ static int s390x_pkey_ecd_keygen448(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey)
         0x24, 0xbc, 0xb6, 0x6e, 0x71, 0x46, 0x3f, 0x69, 0x00
     };
     unsigned char x_dst[57], buff[114];
-    ECX_KEY *key;
+    ECX_KEY *key = ecx_key_new(ED448_KEYLEN, 1);
     unsigned char *privkey = NULL, *pubkey;
     EVP_MD_CTX *hashctx = NULL;
 
-    key = OPENSSL_zalloc(sizeof(*key));
     if (key == NULL) {
         ECerr(EC_F_S390X_PKEY_ECD_KEYGEN448, ERR_R_MALLOC_FAILURE);
         goto err;
@@ -1232,7 +1255,7 @@ static int s390x_pkey_ecd_keygen448(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey)
 
     pubkey = key->pubkey;
 
-    privkey = key->privkey = OPENSSL_secure_malloc(ED448_KEYLEN);
+    privkey = ecx_key_allocate_privkey(key);
     if (privkey == NULL) {
         ECerr(EC_F_S390X_PKEY_ECD_KEYGEN448, ERR_R_MALLOC_FAILURE);
         goto err;
@@ -1265,9 +1288,7 @@ static int s390x_pkey_ecd_keygen448(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey)
     EVP_MD_CTX_free(hashctx);
     return 1;
  err:
-    OPENSSL_secure_clear_free(privkey, ED448_KEYLEN);
-    key->privkey = NULL;
-    OPENSSL_free(key);
+    ecx_key_free(key);
     EVP_MD_CTX_free(hashctx);
     return 0;
 }
diff --git a/crypto/err/openssl.txt b/crypto/err/openssl.txt
index a663bd2858..8920a77390 100644
--- a/crypto/err/openssl.txt
+++ b/crypto/err/openssl.txt
@@ -1822,13 +1822,13 @@ X509V3_F_X509_PURPOSE_SET:141:X509_PURPOSE_set
 X509_F_ADD_CERT_DIR:100:add_cert_dir
 X509_F_BUILD_CHAIN:106:build_chain
 X509_F_BY_FILE_CTRL:101:by_file_ctrl
+X509_F_CACHE_OBJECTS:163:cache_objects
 X509_F_CHECK_NAME_CONSTRAINTS:149:check_name_constraints
 X509_F_CHECK_POLICY:145:check_policy
 X509_F_COMMON_VERIFY_SM2:165:common_verify_sm2
 X509_F_DANE_I2D:107:dane_i2d
 X509_F_DIR_CTRL:102:dir_ctrl
 X509_F_GET_CERT_BY_SUBJECT:103:get_cert_by_subject
-X509_F_CACHE_OBJECTS:163:cache_objects
 X509_F_I2D_X509_AUX:151:i2d_X509_AUX
 X509_F_LOOKUP_CERTS_SK:152:lookup_certs_sk
 X509_F_NETSCAPE_SPKI_B64_DECODE:129:NETSCAPE_SPKI_b64_decode
@@ -2741,6 +2741,7 @@ PROV_R_BAD_TLS_CLIENT_VERSION:161:bad tls client version
 PROV_R_BN_ERROR:160:bn error
 PROV_R_BOTH_MODE_AND_MODE_INT:127:both mode and mode int
 PROV_R_CIPHER_OPERATION_FAILED:102:cipher operation failed
+PROV_R_FAILED_DURING_DERIVATION:164:failed during derivation
 PROV_R_FAILED_TO_DECRYPT:162:failed to decrypt
 PROV_R_FAILED_TO_GENERATE_KEY:121:failed to generate key
 PROV_R_FAILED_TO_GET_PARAMETER:103:failed to get parameter
diff --git a/include/crypto/ecx.h b/include/crypto/ecx.h
new file mode 100644
index 0000000000..e179db1b53
--- /dev/null
+++ b/include/crypto/ecx.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright 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
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+/* Internal EC functions for other submodules: not for application use */
+
+#ifndef OSSL_CRYPTO_ECX_H
+# define OSSL_CRYPTO_ECX_H
+# include <openssl/opensslconf.h>
+
+# ifndef OPENSSL_NO_EC
+
+#  include <openssl/e_os2.h>
+#  include <openssl/crypto.h>
+#  include "internal/refcount.h"
+
+#  define X25519_KEYLEN        32
+#  define X448_KEYLEN          56
+#  define ED25519_KEYLEN       32
+#  define ED448_KEYLEN         57
+
+#  define MAX_KEYLEN  ED448_KEYLEN
+
+#  define X25519_BITS          253
+#  define X25519_SECURITY_BITS 128
+
+#  define ED25519_SIGSIZE      64
+
+#  define X448_BITS            448
+#  define ED448_BITS           456
+#  define X448_SECURITY_BITS   224
+
+#  define ED448_SIGSIZE        114
+
+struct ecx_key_st {
+    unsigned int haspubkey:1;
+    unsigned char pubkey[MAX_KEYLEN];
+    unsigned char *privkey;
+    size_t keylen;
+    CRYPTO_REF_COUNT references;
+    CRYPTO_RWLOCK *lock;
+};
+
+typedef struct ecx_key_st ECX_KEY;
+
+ECX_KEY *ecx_key_new(size_t keylen, int haspubkey);
+unsigned char *ecx_key_allocate_privkey(ECX_KEY *key);
+void ecx_key_free(ECX_KEY *key);
+int ecx_key_up_ref(ECX_KEY *key);
+
+int X25519(uint8_t out_shared_key[32], const uint8_t private_key[32],
+           const uint8_t peer_public_value[32]);
+void X25519_public_from_private(uint8_t out_public_value[32],
+                                const uint8_t private_key[32]);
+
+int X448(uint8_t out_shared_key[56], const uint8_t private_key[56],
+         const uint8_t peer_public_value[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]);
+
+# endif /* OPENSSL_NO_EC */
+#endif
diff --git a/include/crypto/evp.h b/include/crypto/evp.h
index 6903cc656a..65889ae812 100644
--- a/include/crypto/evp.h
+++ b/include/crypto/evp.h
@@ -10,6 +10,7 @@
 #include <openssl/evp.h>
 #include <openssl/core_numbers.h>
 #include "internal/refcount.h"
+#include "crypto/ecx.h"
 
 /*
  * Don't free up md_ctx->pctx in EVP_MD_CTX_reset, use the reserved flag
@@ -495,23 +496,6 @@ const EVP_CIPHER *EVP_##cname##_ecb(void) { return &cname##_ecb; }
                              (fl)|EVP_CIPH_FLAG_DEFAULT_ASN1, \
                              cipher##_init_key, NULL, NULL, NULL, NULL)
 
-
-# ifndef OPENSSL_NO_EC
-
-#define X25519_KEYLEN        32
-#define X448_KEYLEN          56
-#define ED25519_KEYLEN       32
-#define ED448_KEYLEN         57
-
-#define MAX_KEYLEN  ED448_KEYLEN
-
-typedef struct {
-    unsigned char pubkey[MAX_KEYLEN];
-    unsigned char *privkey;
-} ECX_KEY;
-
-#endif
-
 /*
  * Type needs to be a bit field Sub-type needs to be for variations on the
  * method, as in, can it do arbitrary encryption....
diff --git a/include/openssl/core_names.h b/include/openssl/core_names.h
index c17eee42a5..84fbcf38e3 100644
--- a/include/openssl/core_names.h
+++ b/include/openssl/core_names.h
@@ -171,20 +171,14 @@ extern "C" {
 #define OSSL_PKEY_PARAM_PROPERTIES          OSSL_ALG_PARAM_PROPERTIES
 #define OSSL_PKEY_PARAM_DEFAULT_DIGEST      "default-digest" /* utf8 string */
 #define OSSL_PKEY_PARAM_MANDATORY_DIGEST    "mandatory-digest" /* utf8 string */
+#define OSSL_PKEY_PARAM_PUB_KEY             "pub"
+#define OSSL_PKEY_PARAM_PRIV_KEY            "priv"
 
 /* Diffie-Hellman/DSA Parameters */
 #define OSSL_PKEY_PARAM_FFC_P        "p"
 #define OSSL_PKEY_PARAM_FFC_G        "g"
 #define OSSL_PKEY_PARAM_FFC_Q        "q"
 
-/* Diffie-Hellman Keys */
-#define OSSL_PKEY_PARAM_DH_PUB_KEY   "pub"
-#define OSSL_PKEY_PARAM_DH_PRIV_KEY  "priv"
-
-/* DSA Keys */
-#define OSSL_PKEY_PARAM_DSA_PUB_KEY  "pub"
-#define OSSL_PKEY_PARAM_DSA_PRIV_KEY "priv"
-
 /* RSA Keys */
 /*
  * n, e, d are the usual public and private key components
diff --git a/providers/common/include/prov/providercommonerr.h b/providers/common/include/prov/providercommonerr.h
index 21d7f54a57..6586d65626 100644
--- a/providers/common/include/prov/providercommonerr.h
+++ b/providers/common/include/prov/providercommonerr.h
@@ -57,6 +57,7 @@ int ERR_load_PROV_strings(void);
 # define PROV_R_BN_ERROR                                  160
 # define PROV_R_BOTH_MODE_AND_MODE_INT                    127
 # define PROV_R_CIPHER_OPERATION_FAILED                   102
+# define PROV_R_FAILED_DURING_DERIVATION                  164
 # define PROV_R_FAILED_TO_DECRYPT                         162
 # define PROV_R_FAILED_TO_GENERATE_KEY                    121
 # define PROV_R_FAILED_TO_GET_PARAMETER                   103
diff --git a/providers/common/provider_err.c b/providers/common/provider_err.c
index fcb0722070..792697c810 100644
--- a/providers/common/provider_err.c
+++ b/providers/common/provider_err.c
@@ -26,6 +26,8 @@ static const ERR_STRING_DATA PROV_str_reasons[] = {
     "both mode and mode int"},
     {ERR_PACK(ERR_LIB_PROV, 0, PROV_R_CIPHER_OPERATION_FAILED),
     "cipher operation failed"},
+    {ERR_PACK(ERR_LIB_PROV, 0, PROV_R_FAILED_DURING_DERIVATION),
+    "failed during derivation"},
     {ERR_PACK(ERR_LIB_PROV, 0, PROV_R_FAILED_TO_DECRYPT), "failed to decrypt"},
     {ERR_PACK(ERR_LIB_PROV, 0, PROV_R_FAILED_TO_GENERATE_KEY),
     "failed to generate key"},
diff --git a/providers/defltprov.c b/providers/defltprov.c
index 8d89322825..6740a8e58f 100644
--- a/providers/defltprov.c
+++ b/providers/defltprov.c
@@ -371,6 +371,10 @@ static const OSSL_ALGORITHM deflt_kdfs[] = {
 static const OSSL_ALGORITHM deflt_keyexch[] = {
 #ifndef OPENSSL_NO_DH
     { "DH:dhKeyAgreement", "default=yes", dh_keyexch_functions },
+#endif
+#ifndef OPENSSL_NO_EC
+    { "X25519", "default=yes", x25519_keyexch_functions },
+    { "X448", "default=yes", x448_keyexch_functions },
 #endif
     { NULL, NULL, NULL }
 };
@@ -395,6 +399,10 @@ static const OSSL_ALGORITHM deflt_keymgmt[] = {
     { "DSA:dsaEncryption", "default=yes", dsa_keymgmt_functions },
 #endif
     { "RSA:rsaEncryption", "default=yes", rsa_keymgmt_functions },
+#ifndef OPENSSL_NO_EC
+    { "X25519", "default=yes", x25519_keymgmt_functions },
+    { "X448", "default=yes", x448_keymgmt_functions },
+#endif
     { NULL, NULL, NULL }
 };
 
diff --git a/providers/fips/fipsprov.c b/providers/fips/fipsprov.c
index 0301954c30..acc7edfa0d 100644
--- a/providers/fips/fipsprov.c
+++ b/providers/fips/fipsprov.c
@@ -258,8 +258,8 @@ static int dsa_key_signature_test(OPENSSL_CTX *libctx)
     if (!ossl_param_bld_push_BN(&bld, OSSL_PKEY_PARAM_FFC_P, p)
         || !ossl_param_bld_push_BN(&bld, OSSL_PKEY_PARAM_FFC_Q, q)
         || !ossl_param_bld_push_BN(&bld, OSSL_PKEY_PARAM_FFC_G, g)
-        || !ossl_param_bld_push_BN(&bld, OSSL_PKEY_PARAM_DSA_PUB_KEY, pub)
-        || !ossl_param_bld_push_BN(&bld, OSSL_PKEY_PARAM_DSA_PRIV_KEY, priv))
+        || !ossl_param_bld_push_BN(&bld, OSSL_PKEY_PARAM_PUB_KEY, pub)
+        || !ossl_param_bld_push_BN(&bld, OSSL_PKEY_PARAM_PRIV_KEY, priv))
         goto err;
     params = ossl_param_bld_to_param(&bld);
 
@@ -407,8 +407,8 @@ static int dh_key_exchange_test(OPENSSL_CTX *libctx)
     if (!ossl_param_bld_push_BN(&bld, OSSL_PKEY_PARAM_FFC_P, p)
         || !ossl_param_bld_push_BN(&bld, OSSL_PKEY_PARAM_FFC_Q, q)
         || !ossl_param_bld_push_BN(&bld, OSSL_PKEY_PARAM_FFC_G, g)
-        || !ossl_param_bld_push_BN(&bld, OSSL_PKEY_PARAM_DH_PUB_KEY, pub)
-        || !ossl_param_bld_push_BN(&bld, OSSL_PKEY_PARAM_DH_PRIV_KEY, priv))
+        || !ossl_param_bld_push_BN(&bld, OSSL_PKEY_PARAM_PUB_KEY, pub)
+        || !ossl_param_bld_push_BN(&bld, OSSL_PKEY_PARAM_PRIV_KEY, priv))
         goto err;
     params = ossl_param_bld_to_param(&bld);
 
@@ -416,7 +416,7 @@ static int dh_key_exchange_test(OPENSSL_CTX *libctx)
     if (!ossl_param_bld_push_BN(&bld, OSSL_PKEY_PARAM_FFC_P, p)
         || !ossl_param_bld_push_BN(&bld, OSSL_PKEY_PARAM_FFC_Q, q)
         || !ossl_param_bld_push_BN(&bld, OSSL_PKEY_PARAM_FFC_G, g)
-        || !ossl_param_bld_push_BN(&bld, OSSL_PKEY_PARAM_DH_PUB_KEY, pub_peer))
+        || !ossl_param_bld_push_BN(&bld, OSSL_PKEY_PARAM_PUB_KEY, pub_peer))
         goto err;
 
     params_peer = ossl_param_bld_to_param(&bld);
diff --git a/providers/implementations/exchange/build.info b/providers/implementations/exchange/build.info
index fdedb86c03..c74e122844 100644
--- a/providers/implementations/exchange/build.info
+++ b/providers/implementations/exchange/build.info
@@ -2,7 +2,22 @@
 # switch each to the Legacy provider when needed.
 
 $DH_GOAL=../../libimplementations.a
+$ECX_GOAL=../../libimplementations.a
 
 IF[{- !$disabled{dh} -}]
   SOURCE[$DH_GOAL]=dh_exch.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
+
+
+SOURCE[$ECX_GOAL]=ecx_exch.c
+DEFINE[$ECX_GOAL]=$ECDEF
diff --git a/providers/implementations/exchange/ecx_exch.c b/providers/implementations/exchange/ecx_exch.c
new file mode 100644
index 0000000000..ea12628937
--- /dev/null
+++ b/providers/implementations/exchange/ecx_exch.c
@@ -0,0 +1,223 @@
+/*
+ * Copyright 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
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include <openssl/crypto.h>
+#include <openssl/core_numbers.h>
+#include <openssl/core_names.h>
+#include <openssl/params.h>
+#include <openssl/err.h>
+#include "internal/cryptlib.h"
+#include "crypto/ecx.h"
+#include "prov/implementations.h"
+#include "prov/providercommonerr.h"
+#ifdef S390X_EC_ASM
+# include "s390x_arch.h"
+#endif
+
+static OSSL_OP_keyexch_newctx_fn x25519_newctx;
+static OSSL_OP_keyexch_newctx_fn x448_newctx;
+static OSSL_OP_keyexch_init_fn ecx_init;
+static OSSL_OP_keyexch_set_peer_fn ecx_set_peer;
+static OSSL_OP_keyexch_derive_fn ecx_derive;
+static OSSL_OP_keyexch_freectx_fn ecx_freectx;
+static OSSL_OP_keyexch_dupctx_fn ecx_dupctx;
+
+/*
+ * What's passed as an actual key is defined by the KEYMGMT interface.
+ * We happen to know that our KEYMGMT simply passes ECX_KEY structures, so
+ * we use that here too.
+ */
+
+typedef struct {
+    size_t keylen;
+    ECX_KEY *key;
+    ECX_KEY *peerkey;
+} PROV_ECX_CTX;
+
+static void *ecx_newctx(void *provctx, size_t keylen)
+{
+    PROV_ECX_CTX *ctx = OPENSSL_zalloc(sizeof(PROV_ECX_CTX));
+
+    if (ctx == NULL) {
+        ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE);
+        return NULL;
+    }
+
+    ctx->keylen = keylen;
+
+    return ctx;
+}
+
+static void *x25519_newctx(void *provctx)
+{
+    return ecx_newctx(provctx, X25519_KEYLEN);
+}
+
+static void *x448_newctx(void *provctx)
+{
+    return ecx_newctx(provctx, X448_KEYLEN);
+}
+
+static int ecx_init(void *vecxctx, void *vkey)
+{
+    PROV_ECX_CTX *ecxctx = (PROV_ECX_CTX *)vecxctx;
+    ECX_KEY *key = vkey;
+
+    if (ecxctx == NULL
+            || key == NULL
+            || key->keylen != ecxctx->keylen
+            || !ecx_key_up_ref(key)) {
+        ERR_raise(ERR_LIB_PROV, ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    ecx_key_free(ecxctx->key);
+    ecxctx->key = key;
+
+    return 1;
+}
+
+static int ecx_set_peer(void *vecxctx, void *vkey)
+{
+    PROV_ECX_CTX *ecxctx = (PROV_ECX_CTX *)vecxctx;
+    ECX_KEY *key = vkey;
+
+    if (ecxctx == NULL
+            || key == NULL
+            || key->keylen != ecxctx->keylen
+            || !ecx_key_up_ref(key)) {
+        ERR_raise(ERR_LIB_PROV, ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+    ecx_key_free(ecxctx->peerkey);
+    ecxctx->peerkey = key;
+
+    return 1;
+}
+
+static int ecx_derive(void *vecxctx, unsigned char *secret, size_t *secretlen,
+                      size_t outlen)
+{
+    PROV_ECX_CTX *ecxctx = (PROV_ECX_CTX *)vecxctx;
+
+    if (ecxctx->key == NULL
+            || ecxctx->key->privkey == NULL
+            || ecxctx->peerkey == NULL) {
+        ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY);
+        return 0;
+    }
+
+    if (!ossl_assert(ecxctx->keylen == X25519_KEYLEN
+            || ecxctx->keylen == X448_KEYLEN)) {
+        ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY_LENGTH);
+        return 0;
+    }
+
+    if (secret == NULL) {
+        *secretlen = ecxctx->keylen;
+        return 1;
+    }
+    if (outlen < ecxctx->keylen) {
+        ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY_LENGTH);
+        return 0;
+    }
+
+    if (ecxctx->keylen == X25519_KEYLEN) {
+#ifdef S390X_EC_ASM
+        if (OPENSSL_s390xcap_P.pcc[1]
+                & S390X_CAPBIT(S390X_SCALAR_MULTIPLY_X25519)) {
+            if (s390x_x25519_mul(secret, ecxctx->peerkey->pubkey,
+                                 ecxctx->key->privkey) == 0) {
+                ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_DURING_DERIVATION);
+                return 0;
+            }
+        } else
+#endif
+        if (X25519(secret, ecxctx->key->privkey, ecxctx->peerkey->pubkey) == 0) {
+            ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_DURING_DERIVATION);
+            return 0;
+        }
+    } else {
+#ifdef S390X_EC_ASM
+        if (OPENSSL_s390xcap_P.pcc[1]
+                & S390X_CAPBIT(S390X_SCALAR_MULTIPLY_X448)) {
+            if (s390x_x448_mul(secret, ecxctx->peerkey->pubkey,
+                               ecxctx->key->privkey) == 0) {
+                ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_DURING_DERIVATION);
+                return 0;
+            }
+        } else
+#endif
+        if (X448(secret, ecxctx->key->privkey, ecxctx->peerkey->pubkey) == 0) {
+            ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_DURING_DERIVATION);
+            return 0;
+        }
+    }
+
+    *secretlen = ecxctx->keylen;
+    return 1;
+}
+
+static void ecx_freectx(void *vecxctx)
+{
+    PROV_ECX_CTX *ecxctx = (PROV_ECX_CTX *)vecxctx;
+
+    ecx_key_free(ecxctx->key);
+    ecx_key_free(ecxctx->peerkey);
+
+    OPENSSL_free(ecxctx);
+}
+
+static void *ecx_dupctx(void *vecxctx)
+{
+    PROV_ECX_CTX *srcctx = (PROV_ECX_CTX *)vecxctx;
+    PROV_ECX_CTX *dstctx;
+
+    dstctx = OPENSSL_zalloc(sizeof(*srcctx));
+    if (dstctx == NULL) {
+        ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE);
+        return NULL;
+    }
+
+    *dstctx = *srcctx;
+    if (dstctx->key != NULL && !ecx_key_up_ref(dstctx->key)) {
+        ERR_raise(ERR_LIB_PROV, ERR_R_INTERNAL_ERROR);
+        OPENSSL_free(dstctx);
+        return NULL;
+    }
+
+    if (dstctx->peerkey != NULL && !ecx_key_up_ref(dstctx->peerkey)) {
+        ERR_raise(ERR_LIB_PROV, ERR_R_INTERNAL_ERROR);
+        ecx_key_free(dstctx->key);
+        OPENSSL_free(dstctx);
+        return NULL;
+    }
+
+    return dstctx;
+}
+
+const OSSL_DISPATCH x25519_keyexch_functions[] = {
+    { OSSL_FUNC_KEYEXCH_NEWCTX, (void (*)(void))x25519_newctx },
+    { OSSL_FUNC_KEYEXCH_INIT, (void (*)(void))ecx_init },
+    { OSSL_FUNC_KEYEXCH_DERIVE, (void (*)(void))ecx_derive },
+    { OSSL_FUNC_KEYEXCH_SET_PEER, (void (*)(void))ecx_set_peer },
+    { OSSL_FUNC_KEYEXCH_FREECTX, (void (*)(void))ecx_freectx },
+    { OSSL_FUNC_KEYEXCH_DUPCTX, (void (*)(void))ecx_dupctx },
+    { 0, NULL }
+};
+
+const OSSL_DISPATCH x448_keyexch_functions[] = {
+    { OSSL_FUNC_KEYEXCH_NEWCTX, (void (*)(void))x448_newctx },
+    { OSSL_FUNC_KEYEXCH_INIT, (void (*)(void))ecx_init },
+    { OSSL_FUNC_KEYEXCH_DERIVE, (void (*)(void))ecx_derive },
+    { OSSL_FUNC_KEYEXCH_SET_PEER, (void (*)(void))ecx_set_peer },
+    { OSSL_FUNC_KEYEXCH_FREECTX, (void (*)(void))ecx_freectx },
+    { OSSL_FUNC_KEYEXCH_DUPCTX, (void (*)(void))ecx_dupctx },
+    { 0, NULL }
+};
diff --git a/providers/implementations/include/prov/implementations.h b/providers/implementations/include/prov/implementations.h
index 417f74afea..f4e0dc9b02 100644
--- a/providers/implementations/include/prov/implementations.h
+++ b/providers/implementations/include/prov/implementations.h
@@ -257,9 +257,13 @@ extern const OSSL_DISPATCH kdf_krb5kdf_functions[];
 extern const OSSL_DISPATCH dh_keymgmt_functions[];
 extern const OSSL_DISPATCH dsa_keymgmt_functions[];
 extern const OSSL_DISPATCH rsa_keymgmt_functions[];
+extern const OSSL_DISPATCH x25519_keymgmt_functions[];
+extern const OSSL_DISPATCH x448_keymgmt_functions[];
 
 /* Key Exchange */
 extern const OSSL_DISPATCH dh_keyexch_functions[];
+extern const OSSL_DISPATCH x25519_keyexch_functions[];
+extern const OSSL_DISPATCH x448_keyexch_functions[];
 
 /* Signature */
 extern const OSSL_DISPATCH dsa_signature_functions[];
diff --git a/providers/implementations/keymgmt/build.info b/providers/implementations/keymgmt/build.info
index f4a9d1a5de..2a79b39b33 100644
--- a/providers/implementations/keymgmt/build.info
+++ b/providers/implementations/keymgmt/build.info
@@ -4,6 +4,7 @@
 $DH_GOAL=../../libimplementations.a
 $DSA_GOAL=../../libimplementations.a
 $RSA_GOAL=../../libimplementations.a
+$ECX_GOAL=../../libimplementations.a
 
 IF[{- !$disabled{dh} -}]
   SOURCE[$DH_GOAL]=dh_kmgmt.c
@@ -12,3 +13,4 @@ IF[{- !$disabled{dsa} -}]
   SOURCE[$DSA_GOAL]=dsa_kmgmt.c
 ENDIF
 SOURCE[$RSA_GOAL]=rsa_kmgmt.c
+SOURCE[$ECX_GOAL]=ecx_kmgmt.c
diff --git a/providers/implementations/keymgmt/dh_kmgmt.c b/providers/implementations/keymgmt/dh_kmgmt.c
index 44791a13e4..9a1734bd57 100644
--- a/providers/implementations/keymgmt/dh_kmgmt.c
+++ b/providers/implementations/keymgmt/dh_kmgmt.c
@@ -86,9 +86,9 @@ static int params_to_key(DH *dh, const OSSL_PARAM params[])
         return 0;
 
     param_priv_key =
-        OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_DH_PRIV_KEY);
+        OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_PRIV_KEY);
     param_pub_key =
-        OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_DH_PUB_KEY);
+        OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_PUB_KEY);
 
     /*
      * DH documentation says that a public key must be present if a
@@ -126,10 +126,10 @@ static int key_to_params(DH *dh, OSSL_PARAM_BLD *tmpl)
 
     DH_get0_key(dh, &pub_key, &priv_key);
     if (priv_key != NULL
-        && !ossl_param_bld_push_BN(tmpl, OSSL_PKEY_PARAM_DH_PRIV_KEY, priv_key))
+        && !ossl_param_bld_push_BN(tmpl, OSSL_PKEY_PARAM_PRIV_KEY, priv_key))
         return 0;
     if (pub_key != NULL
-        && !ossl_param_bld_push_BN(tmpl, OSSL_PKEY_PARAM_DH_PUB_KEY, pub_key))
+        && !ossl_param_bld_push_BN(tmpl, OSSL_PKEY_PARAM_PUB_KEY, pub_key))
         return 0;
 
     return 1;
@@ -214,9 +214,9 @@ static int dh_export(void *keydata, int selection, OSSL_CALLBACK *param_cb,
     OSSL_PARAM_BN(OSSL_PKEY_PARAM_FFC_P, NULL, 0),      \
     OSSL_PARAM_BN(OSSL_PKEY_PARAM_FFC_G, NULL, 0)
 # define DH_IMEXPORTABLE_PUBLIC_KEY                     \
-    OSSL_PARAM_BN(OSSL_PKEY_PARAM_DH_PUB_KEY, NULL, 0)
+    OSSL_PARAM_BN(OSSL_PKEY_PARAM_PUB_KEY, NULL, 0)
 # define DH_IMEXPORTABLE_PRIVATE_KEY                    \
-    OSSL_PARAM_BN(OSSL_PKEY_PARAM_DH_PRIV_KEY, NULL, 0)
+    OSSL_PARAM_BN(OSSL_PKEY_PARAM_PRIV_KEY, NULL, 0)
 static const OSSL_PARAM dh_all_types[] = {
     DH_IMEXPORTABLE_PARAMETERS,
     DH_IMEXPORTABLE_PUBLIC_KEY,
diff --git a/providers/implementations/keymgmt/dsa_kmgmt.c b/providers/implementations/keymgmt/dsa_kmgmt.c
index f5bbc5260b..00fa492b22 100644
--- a/providers/implementations/keymgmt/dsa_kmgmt.c
+++ b/providers/implementations/keymgmt/dsa_kmgmt.c
@@ -94,9 +94,9 @@ static int params_to_key(DSA *dsa, const OSSL_PARAM params[])
         return 0;
 
     param_priv_key =
-        OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_DSA_PRIV_KEY);
+        OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_PRIV_KEY);
     param_pub_key =
-        OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_DSA_PUB_KEY);
+        OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_PUB_KEY);
 
     /*
      * DSA documentation says that a public key must be present if a private key
@@ -133,10 +133,10 @@ static int key_to_params(DSA *dsa, OSSL_PARAM_BLD *tmpl)
 
     DSA_get0_key(dsa, &pub_key, &priv_key);
     if (priv_key != NULL
-        && !ossl_param_bld_push_BN(tmpl, OSSL_PKEY_PARAM_DSA_PRIV_KEY, priv_key))
+        && !ossl_param_bld_push_BN(tmpl, OSSL_PKEY_PARAM_PRIV_KEY, priv_key))
         return 0;
     if (pub_key != NULL
-        && !ossl_param_bld_push_BN(tmpl, OSSL_PKEY_PARAM_DSA_PUB_KEY, pub_key))
+        && !ossl_param_bld_push_BN(tmpl, OSSL_PKEY_PARAM_PUB_KEY, pub_key))
         return 0;
 
     return 1;
@@ -222,9 +222,9 @@ static int dsa_export(void *keydata, int selection, OSSL_CALLBACK *param_cb,
     OSSL_PARAM_BN(OSSL_PKEY_PARAM_FFC_Q, NULL, 0),      \
     OSSL_PARAM_BN(OSSL_PKEY_PARAM_FFC_G, NULL, 0)
 # define DSA_IMEXPORTABLE_PUBLIC_KEY                    \
-    OSSL_PARAM_BN(OSSL_PKEY_PARAM_DSA_PUB_KEY, NULL, 0)
+    OSSL_PARAM_BN(OSSL_PKEY_PARAM_PUB_KEY, NULL, 0)
 # define DSA_IMEXPORTABLE_PRIVATE_KEY                   \
-    OSSL_PARAM_BN(OSSL_PKEY_PARAM_DSA_PRIV_KEY, NULL, 0)
+    OSSL_PARAM_BN(OSSL_PKEY_PARAM_PRIV_KEY, NULL, 0)
 static const OSSL_PARAM dsa_all_types[] = {
     DSA_IMEXPORTABLE_PARAMETERS,
     DSA_IMEXPORTABLE_PUBLIC_KEY,
diff --git a/providers/implementations/keymgmt/ecx_kmgmt.c b/providers/implementations/keymgmt/ecx_kmgmt.c
new file mode 100644
index 0000000000..cbb302efc4
--- /dev/null
+++ b/providers/implementations/keymgmt/ecx_kmgmt.c
@@ -0,0 +1,231 @@
+/*
+ * Copyright 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
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include <assert.h>
+#include <openssl/core_numbers.h>
+#include <openssl/core_names.h>
+#include <openssl/params.h>
+#include "internal/param_build.h"
+#include "crypto/ecx.h"
+#include "prov/implementations.h"
+#include "prov/providercommon.h"
+
+static OSSL_OP_keymgmt_new_fn x25519_new_key;
+static OSSL_OP_keymgmt_new_fn x448_new_key;
+static OSSL_OP_keymgmt_get_params_fn x25519_get_params;
+static OSSL_OP_keymgmt_get_params_fn x448_get_params;
+static OSSL_OP_keymgmt_gettable_params_fn ecx_gettable_params;
+static OSSL_OP_keymgmt_has_fn ecx_has;
+static OSSL_OP_keymgmt_import_fn ecx_import;
+static OSSL_OP_keymgmt_import_types_fn ecx_imexport_types;
+static OSSL_OP_keymgmt_export_fn ecx_export;
+static OSSL_OP_keymgmt_export_types_fn ecx_imexport_types;
+
+static void *x25519_new_key(void *provctx)
+{
+    return ecx_key_new(X25519_KEYLEN, 0);
+}
+
+static void *x448_new_key(void *provctx)
+{
+    return ecx_key_new(X448_KEYLEN, 0);
+}
+
+static int ecx_has(void *keydata, int selection)
+{
+    ECX_KEY *key = keydata;
+    const int ecx_selections = OSSL_KEYMGMT_SELECT_PUBLIC_KEY
+                               | OSSL_KEYMGMT_SELECT_PRIVATE_KEY;
+    int ok = 1;
+
+    if ((selection & ~ecx_selections) != 0
+            || (selection & ecx_selections) == 0)
+        return 0;
+
+    if ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0)
+        ok = ok && key->haspubkey;
+
+    if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0)
+        ok = ok && key->privkey != NULL;
+
+    return ok;
+}
+
+static int ecx_import(void *keydata, int selection, const OSSL_PARAM params[])
+{
+    ECX_KEY *key = keydata;
+    size_t privkeylen = 0, pubkeylen;
+    const OSSL_PARAM *param_priv_key = NULL, *param_pub_key;
+    unsigned char *pubkey;
+    const int ecx_selections = OSSL_KEYMGMT_SELECT_PUBLIC_KEY
+                               | OSSL_KEYMGMT_SELECT_PRIVATE_KEY;
+
+    if (key == NULL)
+        return 0;
+
+    if ((selection & ~ecx_selections) != 0
+            || (selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) == 0)
+        return 0;
+
+    if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0)
+        param_priv_key =
+            OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_PRIV_KEY);
+    param_pub_key =
+        OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_PUB_KEY);
+
+    /*
+     * If a private key is present then a public key must also be present.
+     * Alternatively we've just got a public key.
+     */
+    if (param_pub_key == NULL
+            || (param_priv_key == NULL
+                && (selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0))
+        return 0;
+
+    if (param_priv_key != NULL
+             && !OSSL_PARAM_get_octet_string(param_priv_key,
+                                            (void **)&key->privkey, key->keylen,
+                                             &privkeylen))
+        return 0;
+
+    pubkey = key->pubkey;
+    if (!OSSL_PARAM_get_octet_string(param_pub_key,
+                                     (void **)&pubkey,
+                                     sizeof(key->pubkey), &pubkeylen))
+        return 0;
+
+    if (pubkeylen != key->keylen
+            || (param_priv_key != NULL && privkeylen != key->keylen))
+        return 0;
+
+    key->haspubkey = 1;
+
+    return 1;
+}
+
+static int key_to_params(ECX_KEY *key, OSSL_PARAM_BLD *tmpl)
+{
+    if (key == NULL)
+        return 0;
+
+    if (!ossl_param_bld_push_octet_string(tmpl, OSSL_PKEY_PARAM_PUB_KEY,
+                                          key->pubkey, key->keylen))
+        return 0;
+
+    if (key->privkey != NULL
+        && !ossl_param_bld_push_octet_string(tmpl, OSSL_PKEY_PARAM_PRIV_KEY,
+                                             key->privkey, key->keylen))
+        return 0;
+
+    return 1;
+}
+
+static int ecx_export(void *keydata, int selection, OSSL_CALLBACK *param_cb,
+                      void *cbarg)
+{
+    ECX_KEY *key = keydata;
+    OSSL_PARAM_BLD tmpl;
+    OSSL_PARAM *params = NULL;
+    int ret;
+
+    if (key == NULL)
+        return 0;
+
+    if ((selection & OSSL_KEYMGMT_SELECT_KEYPAIR) != 0
+            && !key_to_params(key, &tmpl))
+        return 0;
+
+    ossl_param_bld_init(&tmpl);
+    params = ossl_param_bld_to_param(&tmpl);
+    if (params == NULL) {
+        ossl_param_bld_free(params);
+        return 0;
+    }
+
+    ret = param_cb(params, cbarg);
+    ossl_param_bld_free(params);
+    return ret;
+}
+
+static const OSSL_PARAM ecx_key_types[] = {
+    OSSL_PARAM_BN(OSSL_PKEY_PARAM_PUB_KEY, NULL, 0),
+    OSSL_PARAM_BN(OSSL_PKEY_PARAM_PRIV_KEY, NULL, 0),
+    OSSL_PARAM_END
+};
+static const OSSL_PARAM *ecx_imexport_types(int selection)
+{
+    if ((selection & OSSL_KEYMGMT_SELECT_KEYPAIR) != 0)
+        return ecx_key_types;
+    return NULL;
+}
+
+static int ecx_get_params(OSSL_PARAM params[], int bits, int secbits,
+                          int size)
+{
+    OSSL_PARAM *p;
+
+    if ((p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_BITS)) != NULL
+        && !OSSL_PARAM_set_int(p, bits))
+        return 0;
+    if ((p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_SECURITY_BITS)) != NULL
+        && !OSSL_PARAM_set_int(p, secbits))
+        return 0;
+    if ((p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_MAX_SIZE)) != NULL
+        && !OSSL_PARAM_set_int(p, size))
+        return 0;
+    return 1;
+}
+
+static int x25519_get_params(void *key, OSSL_PARAM params[])
+{
+    return ecx_get_params(params, X25519_BITS, X25519_SECURITY_BITS, X25519_KEYLEN);
+}
+
+static int x448_get_params(void *key, OSSL_PARAM params[])
+{
+    return ecx_get_params(params, X448_BITS, X448_SECURITY_BITS, X448_KEYLEN);
+}
+
+static const OSSL_PARAM ecx_params[] = {
+    OSSL_PARAM_int(OSSL_PKEY_PARAM_BITS, NULL),
+    OSSL_PARAM_int(OSSL_PKEY_PARAM_SECURITY_BITS, NULL),
+    OSSL_PARAM_int(OSSL_PKEY_PARAM_MAX_SIZE, NULL),
+    OSSL_PARAM_END
+};
+
+static const OSSL_PARAM *ecx_gettable_params(void)
+{
+    return ecx_params;
+}
+
+const OSSL_DISPATCH x25519_keymgmt_functions[] = {
+    { OSSL_FUNC_KEYMGMT_NEW, (void (*)(void))x25519_new_key },
+    { OSSL_FUNC_KEYMGMT_FREE, (void (*)(void))ecx_key_free },
+    { OSSL_FUNC_KEYMGMT_GET_PARAMS, (void (*) (void))x25519_get_params },
+    { OSSL_FUNC_KEYMGMT_GETTABLE_PARAMS, (void (*) (void))ecx_gettable_params },
+    { OSSL_FUNC_KEYMGMT_HAS, (void (*)(void))ecx_has },
+    { OSSL_FUNC_KEYMGMT_IMPORT, (void (*)(void))ecx_import },
+    { 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 },
+    { 0, NULL }
+};
+
+const OSSL_DISPATCH x448_keymgmt_functions[] = {
+    { OSSL_FUNC_KEYMGMT_NEW, (void (*)(void))x448_new_key },
+    { OSSL_FUNC_KEYMGMT_FREE, (void (*)(void))ecx_key_free },
+    { OSSL_FUNC_KEYMGMT_GET_PARAMS, (void (*) (void))x448_get_params },
+    { OSSL_FUNC_KEYMGMT_GETTABLE_PARAMS, (void (*) (void))ecx_gettable_params },
+    { OSSL_FUNC_KEYMGMT_HAS, (void (*)(void))ecx_has },
+    { OSSL_FUNC_KEYMGMT_IMPORT, (void (*)(void))ecx_import },
+    { 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 },
+    { 0, NULL }
+};
diff --git a/test/curve448_internal_test.c b/test/curve448_internal_test.c
index 054948d23b..953b56c012 100644
--- a/test/curve448_internal_test.c
+++ b/test/curve448_internal_test.c
@@ -10,6 +10,7 @@
 #include <string.h>
 #include <openssl/e_os2.h>
 #include <openssl/evp.h>
+#include "crypto/ecx.h"
 #include "curve448_local.h"
 #include "testutil.h"
 
diff --git a/test/evp_pkey_provided_test.c b/test/evp_pkey_provided_test.c
index a39fa0a724..3c1c090bde 100644
--- a/test/evp_pkey_provided_test.c
+++ b/test/evp_pkey_provided_test.c
@@ -178,8 +178,8 @@ static int test_fromdata_dh(void)
         0x2,                     /* G */
     };
     OSSL_PARAM fromdata_params[] = {
-        OSSL_PARAM_ulong(OSSL_PKEY_PARAM_DH_PRIV_KEY, &key_numbers[PRIV_KEY]),
-        OSSL_PARAM_ulong(OSSL_PKEY_PARAM_DH_PUB_KEY, &key_numbers[PUB_KEY]),
+        OSSL_PARAM_ulong(OSSL_PKEY_PARAM_PRIV_KEY, &key_numbers[PRIV_KEY]),
+        OSSL_PARAM_ulong(OSSL_PKEY_PARAM_PUB_KEY, &key_numbers[PUB_KEY]),
         OSSL_PARAM_ulong(OSSL_PKEY_PARAM_FFC_P, &key_numbers[FFC_P]),
         OSSL_PARAM_ulong(OSSL_PKEY_PARAM_FFC_G, &key_numbers[FFC_G]),
         OSSL_PARAM_END


More information about the openssl-commits mailing list