[openssl-commits] [openssl] master update

Dr. Stephen Henson steve at openssl.org
Sat Aug 13 13:13:42 UTC 2016


The branch master has been updated
       via  3d9a51f7edc48ebf4252c6585943c635261aa28f (commit)
       via  c082201a36303850e67300e0e8e3e2c67ed914dc (commit)
       via  23143e4da6b6545bc8e3e2d6dd4b1be4e4b3f539 (commit)
       via  bc7bfb83b7189c052bf2898bd6b82f8e4b4fd3f6 (commit)
       via  ec24630ae2b714d6e22fbfa4695aa8f8adef1828 (commit)
       via  3bca6c27317958f30f8bbfe67814a7ab9a07f4a3 (commit)
       via  c06f2aaa08dec00cda6a3c3c063de7827b379797 (commit)
       via  5d6aaf8a9d0c5ad71a4cb5e4bfc3c2fc29f782ba (commit)
       via  10f8d0eaa54707eeff6b4d08b4ec3f0124edea33 (commit)
       via  262bd85fdead8808240f92eaea899615912001f7 (commit)
       via  873feeb9cfd026b5cadc50ab026f4839ea9e3c08 (commit)
       via  59bf0f031fdbf8cb2f5371e6f32478e1bb05bd78 (commit)
       via  756b198d247d0040b7e2abed9b9b12bc6634a3ad (commit)
       via  a4cb54d2576995f6eed25d11ae421d915f60f3a5 (commit)
       via  4950f8885c8384b945a7a801f47319b9e29344e6 (commit)
      from  e92813234318635639dba0168c7ef5568757449b (commit)


- Log -----------------------------------------------------------------
commit 3d9a51f7edc48ebf4252c6585943c635261aa28f
Author: Dr. Stephen Henson <steve at openssl.org>
Date:   Sat Aug 13 13:49:17 2016 +0100

    update CHANGES
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>

commit c082201a36303850e67300e0e8e3e2c67ed914dc
Author: Dr. Stephen Henson <steve at openssl.org>
Date:   Fri Aug 12 17:27:11 2016 +0100

    add documentation
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>

commit 23143e4da6b6545bc8e3e2d6dd4b1be4e4b3f539
Author: Dr. Stephen Henson <steve at openssl.org>
Date:   Thu Aug 11 16:37:00 2016 +0100

    Print out names of other temp key algorithms.
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>

commit bc7bfb83b7189c052bf2898bd6b82f8e4b4fd3f6
Author: Dr. Stephen Henson <steve at openssl.org>
Date:   Thu Aug 11 15:49:07 2016 +0100

    Remove old EC based X25519 code.
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>

commit ec24630ae2b714d6e22fbfa4695aa8f8adef1828
Author: Dr. Stephen Henson <steve at openssl.org>
Date:   Thu Aug 11 15:41:49 2016 +0100

    Modify TLS support for new X25519 API.
    
    When handling ECDH check to see if the curve is "custom" (X25519 is
    currently the only curve of this type) and instead of setting a curve
    NID just allocate a key of appropriate type.
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>

commit 3bca6c27317958f30f8bbfe67814a7ab9a07f4a3
Author: Dr. Stephen Henson <steve at openssl.org>
Date:   Thu Aug 11 15:38:37 2016 +0100

    Add encoded points to other EC curves too.
    
    Add encoded point ctrl support for other curves: this makes it possible
    to handle X25519 and other EC curve point encoding in a similar way
    for TLS.
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>

commit c06f2aaa08dec00cda6a3c3c063de7827b379797
Author: Dr. Stephen Henson <steve at openssl.org>
Date:   Thu Aug 11 15:49:57 2016 +0100

    make update
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>

commit 5d6aaf8a9d0c5ad71a4cb5e4bfc3c2fc29f782ba
Author: Dr. Stephen Henson <steve at openssl.org>
Date:   Wed Aug 10 22:30:43 2016 +0100

    Add point ctrls to X25519
    
    Add ctrl operations to set or retrieve encoded point in
    EVP_PKEY structures containing X25519 keys.
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>

commit 10f8d0eaa54707eeff6b4d08b4ec3f0124edea33
Author: Dr. Stephen Henson <steve at openssl.org>
Date:   Wed Aug 10 16:04:51 2016 +0100

    Update X25519 key format in evptests.txt
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>

commit 262bd85fdead8808240f92eaea899615912001f7
Author: Dr. Stephen Henson <steve at openssl.org>
Date:   Tue Aug 9 21:58:55 2016 +0100

    Add X25519 methods to internal tables
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>

commit 873feeb9cfd026b5cadc50ab026f4839ea9e3c08
Author: Dr. Stephen Henson <steve at openssl.org>
Date:   Tue Aug 9 20:25:12 2016 +0100

    add to build.info
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>

commit 59bf0f031fdbf8cb2f5371e6f32478e1bb05bd78
Author: Dr. Stephen Henson <steve at openssl.org>
Date:   Wed Aug 10 16:27:22 2016 +0100

    make errors
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>

commit 756b198d247d0040b7e2abed9b9b12bc6634a3ad
Author: Dr. Stephen Henson <steve at openssl.org>
Date:   Tue Aug 9 20:23:04 2016 +0100

    X25519 public key methods
    
    Add X25519 methods to match current key format defined in
    draft-ietf-curdle-pkix-02
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>

commit a4cb54d2576995f6eed25d11ae421d915f60f3a5
Author: Dr. Stephen Henson <steve at openssl.org>
Date:   Tue Aug 9 20:53:37 2016 +0100

    Fix type of ptr field.
    
    Since "ptr" is used to handle arbitrary other types it should be
    void *.
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>

commit 4950f8885c8384b945a7a801f47319b9e29344e6
Author: Dr. Stephen Henson <steve at openssl.org>
Date:   Tue Aug 9 11:40:48 2016 +0100

    Use OIDs from draft-ietf-curdle-pkix-02
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>

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

Summary of changes:
 CHANGES                            |  18 +-
 apps/s_cb.c                        |   4 +
 crypto/asn1/ameth_lib.c            |   5 +-
 crypto/ec/build.info               |   2 +-
 crypto/ec/ec_25519.c               | 328 --------------------------------
 crypto/ec/ec_ameth.c               |   7 +
 crypto/ec/ec_curve.c               |   1 -
 crypto/ec/ec_err.c                 |   6 +
 crypto/ec/ec_lcl.h                 |  13 --
 crypto/ec/ecx_meth.c               | 373 +++++++++++++++++++++++++++++++++++++
 crypto/evp/p_lib.c                 |  32 +++-
 crypto/evp/pmeth_lib.c             |   3 +
 crypto/include/internal/asn1_int.h |   1 +
 crypto/include/internal/evp_int.h  |   3 +-
 crypto/objects/obj_dat.h           |  34 ++--
 crypto/objects/objects.txt         |   7 +-
 doc/apps/genpkey.pod               |   7 +
 doc/apps/pkeyutl.pod               |   5 +
 include/openssl/ec.h               |   6 +
 include/openssl/evp.h              |   7 +
 include/openssl/obj_mac.h          |   4 +-
 ssl/s3_lib.c                       |  21 ++-
 ssl/ssl_locl.h                     |   8 +-
 ssl/statem/statem_clnt.c           |  50 +++--
 ssl/statem/statem_srvr.c           |  11 +-
 ssl/t1_lib.c                       |  19 +-
 test/evptests.txt                  |  24 +--
 util/libcrypto.num                 |   2 +
 28 files changed, 554 insertions(+), 447 deletions(-)
 delete mode 100644 crypto/ec/ec_25519.c
 create mode 100644 crypto/ec/ecx_meth.c

diff --git a/CHANGES b/CHANGES
index d3c04a9..32a7c7b 100644
--- a/CHANGES
+++ b/CHANGES
@@ -200,19 +200,13 @@
      [Emilia Käsper]
 
   *) Add X25519 support.
-     Integrate support for X25519 into EC library. This includes support
+     Add ASN.1 and EVP_PKEY methods for X25519. This includes support
      for public and private key encoding using the format documented in
-     draft-josefsson-pkix-newcurves-01: specifically X25519 uses the
-     OID from that draft, encodes public keys using little endian
-     format in the ECPoint structure and private keys using
-     little endian form in the privateKey field of the ECPrivateKey
-     structure. TLS support complies with draft-ietf-tls-rfc4492bis-06
-     and uses X25519(29).
-
-     Note: the current version supports key generation, public and
-     private key encoding and ECDH key agreement using the EC API.
-     Low level point operations such as EC_POINT_add(), EC_POINT_mul()
-     are NOT supported.
+     draft-ietf-curdle-pkix-02. The coresponding EVP_PKEY method supports
+     key generation and key derivation.
+
+     TLS support complies with draft-ietf-tls-rfc4492bis-08 and uses
+     X25519(29).
      [Steve Henson]
 
   *) Deprecate SRP_VBASE_get_by_user.
diff --git a/apps/s_cb.c b/apps/s_cb.c
index 330dedb..e960b94 100644
--- a/apps/s_cb.c
+++ b/apps/s_cb.c
@@ -383,7 +383,11 @@ int ssl_print_tmp_key(BIO *out, SSL *s)
                 cname = OBJ_nid2sn(nid);
             BIO_printf(out, "ECDH, %s, %d bits\n", cname, EVP_PKEY_bits(key));
         }
+    break;
 #endif
+    default:
+        BIO_printf(out, "%s, %d bits\n", OBJ_nid2sn(EVP_PKEY_id(key)),
+                   EVP_PKEY_bits(key));
     }
     EVP_PKEY_free(key);
     return 1;
diff --git a/crypto/asn1/ameth_lib.c b/crypto/asn1/ameth_lib.c
index 577e205..d5a0247 100644
--- a/crypto/asn1/ameth_lib.c
+++ b/crypto/asn1/ameth_lib.c
@@ -39,7 +39,10 @@ static const EVP_PKEY_ASN1_METHOD *standard_methods[] = {
     &cmac_asn1_meth,
 #endif
 #ifndef OPENSSL_NO_DH
-    &dhx_asn1_meth
+    &dhx_asn1_meth,
+#endif
+#ifndef OPENSSL_NO_EC
+    &ecx25519_asn1_meth
 #endif
 };
 
diff --git a/crypto/ec/build.info b/crypto/ec/build.info
index 935f8b0..970c292 100644
--- a/crypto/ec/build.info
+++ b/crypto/ec/build.info
@@ -5,7 +5,7 @@ SOURCE[../../libcrypto]=\
         ec2_smpl.c ec2_mult.c ec_ameth.c ec_pmeth.c eck_prn.c \
         ecp_nistp224.c ecp_nistp256.c ecp_nistp521.c ecp_nistputil.c \
         ecp_oct.c ec2_oct.c ec_oct.c ec_kmeth.c ecdh_ossl.c ecdh_kdf.c \
-        ecdsa_ossl.c ecdsa_sign.c ecdsa_vrf.c ec_25519.c curve25519.c \
+        ecdsa_ossl.c ecdsa_sign.c ecdsa_vrf.c curve25519.c ecx_meth.c \
         {- $target{ec_asm_src} -}
 
 GENERATE[ecp_nistz256-x86.s]=asm/ecp_nistz256-x86.pl $(PERLASM_SCHEME) $(CFLAGS) $(LIB_CFLAGS) $(PROCESSOR)
diff --git a/crypto/ec/ec_25519.c b/crypto/ec/ec_25519.c
deleted file mode 100644
index df0ad8a..0000000
--- a/crypto/ec/ec_25519.c
+++ /dev/null
@@ -1,328 +0,0 @@
-/*
- * Copyright 2016 The OpenSSL Project Authors. All Rights Reserved.
- *
- * Licensed under the OpenSSL license (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 <string.h>
-#include <openssl/err.h>
-#include <openssl/rand.h>
-#include "ec_lcl.h"
-
-/* Length of Curve 25519 keys */
-#define EC_X25519_KEYLEN    32
-/* Group degree and order bits */
-#define EC_X25519_BITS      253
-
-/* Copy Curve25519 public key buffer, allocating is necessary */
-static int x25519_init_public(EC_POINT *pub, const void *src)
-{
-    if (pub->custom_data == NULL) {
-        pub->custom_data = OPENSSL_malloc(EC_X25519_KEYLEN);
-        if (pub->custom_data == NULL)
-            return 0;
-    }
-    if (src != NULL)
-        memcpy(pub->custom_data, src, EC_X25519_KEYLEN);
-    return 1;
-}
-
-/* Copy Curve25519 private key buffer, allocating is necessary */
-static int x25519_init_private(EC_KEY *dst, const void *src)
-{
-    if (dst->custom_data == NULL) {
-        dst->custom_data = OPENSSL_secure_malloc(EC_X25519_KEYLEN);
-        if (dst->custom_data == NULL)
-            return 0;
-    }
-    if (src != NULL)
-        memcpy(dst->custom_data, src, EC_X25519_KEYLEN);
-    return 1;
-}
-
-static int x25519_group_init(EC_GROUP *grp)
-{
-    return 1;
-}
-
-static int x25519_group_copy(EC_GROUP *dst, const EC_GROUP *src)
-{
-    return 1;
-}
-
-static int x25519_group_get_degree(const EC_GROUP *src)
-{
-    return EC_X25519_BITS;
-}
-
-static int x25519_group_order_bits(const EC_GROUP *src)
-{
-    return EC_X25519_BITS;
-}
-
-static int x25519_set_private(EC_KEY *eckey, const BIGNUM *priv_key)
-{
-    if (BN_num_bytes(priv_key) > EC_X25519_KEYLEN)
-        return 0;
-    if (x25519_init_private(eckey, NULL))
-        return 0;
-    /* Convert BIGNUM form private key to internal format */
-    if (BN_bn2lebinpad(priv_key, eckey->custom_data, EC_X25519_KEYLEN)
-        != EC_X25519_KEYLEN)
-        return 0;
-    return 1;
-}
-
-static int x25519_keycheck(const EC_KEY *eckey)
-{
-    const char *pubkey;
-    if (eckey->pub_key == NULL)
-        return 0;
-    pubkey = eckey->pub_key->custom_data;
-    if (pubkey == NULL)
-        return 0;
-    if (eckey->custom_data != NULL) {
-        uint8_t tmp[EC_X25519_KEYLEN];
-        /* Check eckey->priv_key exists and matches eckey->custom_data */
-        if (eckey->priv_key == NULL)
-            return 0;
-        if (BN_bn2lebinpad(eckey->priv_key, tmp, EC_X25519_KEYLEN)
-            != EC_X25519_KEYLEN
-            || CRYPTO_memcmp(tmp, eckey->custom_data,
-                             EC_X25519_KEYLEN) != 0) {
-            OPENSSL_cleanse(tmp, EC_X25519_KEYLEN);
-            return 0;
-        }
-        X25519_public_from_private(tmp, eckey->custom_data);
-        if (CRYPTO_memcmp(pubkey, tmp, EC_X25519_KEYLEN) == 0)
-            return 1;
-        return 0;
-    } else {
-        return 1;
-    }
-}
-
-static int x25519_keygenpub(EC_KEY *eckey)
-{
-    X25519_public_from_private(eckey->pub_key->custom_data,
-                               eckey->custom_data);
-    return 1;
-}
-
-static int x25519_keygen(EC_KEY *eckey)
-{
-    unsigned char *key;
-    if (x25519_init_private(eckey, NULL) == 0)
-        return 0;
-    key = eckey->custom_data;
-    if (RAND_bytes(key, EC_X25519_KEYLEN) <= 0)
-        return 0;
-    key[0] &= 248;
-    key[31] &= 127;
-    key[31] |= 64;
-    /*
-     * Although the private key is kept as an array in eckey->custom_data
-     * Set eckey->priv_key too so existing code which uses
-     * EC_KEY_get0_private_key() still works.
-     */
-    if (eckey->priv_key == NULL)
-        eckey->priv_key = BN_secure_new();
-    if (eckey->priv_key == NULL)
-        return 0;
-    if (BN_lebin2bn(eckey->custom_data, EC_X25519_KEYLEN, eckey->priv_key) ==
-        NULL)
-        return 0;
-    if (eckey->pub_key == NULL)
-        eckey->pub_key = EC_POINT_new(eckey->group);
-    if (eckey->pub_key == NULL)
-        return 0;
-    return x25519_keygenpub(eckey);
-}
-
-static void x25519_keyfinish(EC_KEY *eckey)
-{
-    OPENSSL_secure_free(eckey->custom_data);
-    eckey->custom_data = NULL;
-}
-
-static int x25519_keycopy(EC_KEY *dest, const EC_KEY *src)
-{
-    if (src->custom_data == NULL)
-        return 0;
-    return x25519_init_private(dest, src->custom_data);
-}
-
-static int x25519_oct2priv(EC_KEY *eckey, const unsigned char *buf, size_t len)
-{
-    if (len != EC_X25519_KEYLEN)
-        return 0;
-    if (x25519_init_private(eckey, buf) == 0)
-        return 0;
-    /*
-     * Although the private key is kept as an array in eckey->custom_data
-     * Set eckey->priv_key too so existing code which uses
-     * EC_KEY_get0_private_key() still works.
-     */
-    if (eckey->priv_key == NULL)
-        eckey->priv_key = BN_secure_new();
-    if (eckey->priv_key == NULL)
-        return 0;
-    if (BN_lebin2bn(buf, EC_X25519_KEYLEN, eckey->priv_key) == NULL)
-        return 0;
-    return 1;
-}
-
-static size_t x25519_priv2oct(const EC_KEY *eckey,
-                              unsigned char *buf, size_t len)
-{
-    size_t keylen = EC_X25519_KEYLEN;
-    if (eckey->custom_data == NULL)
-        return 0;
-    if (buf != NULL) {
-        if (len < keylen)
-            return 0;
-        memcpy(buf, eckey->custom_data, keylen);
-    }
-    return keylen;
-}
-
-static int x25519_point_init(EC_POINT *pt)
-{
-    return x25519_init_public(pt, NULL);
-}
-
-static void x25519_point_finish(EC_POINT *pt)
-{
-    OPENSSL_free(pt->custom_data);
-    pt->custom_data = NULL;
-}
-
-static void x25519_point_clear_finish(EC_POINT *pt)
-{
-    OPENSSL_clear_free(pt->custom_data, EC_X25519_KEYLEN);
-    pt->custom_data = NULL;
-}
-
-static int x25519_point_copy(EC_POINT *dst, const EC_POINT *src)
-{
-    memcpy(dst->custom_data, src->custom_data, EC_X25519_KEYLEN);
-    return 1;
-}
-
-static size_t x25519_point2oct(const EC_GROUP *grp, const EC_POINT *pt,
-                               point_conversion_form_t form,
-                               unsigned char *buf, size_t len, BN_CTX *ctx)
-{
-    if (buf != NULL) {
-        if (len < EC_X25519_KEYLEN)
-            return 0;
-        memcpy(buf, pt->custom_data, EC_X25519_KEYLEN);
-    }
-    return EC_X25519_KEYLEN;
-}
-
-static int x25519_oct2point(const EC_GROUP *grp, EC_POINT *pt,
-                            const unsigned char *buf, size_t len, BN_CTX *ctx)
-{
-    unsigned char *pubkey = pt->custom_data;
-    if (len != EC_X25519_KEYLEN)
-        return 0;
-    memcpy(pubkey, buf, EC_X25519_KEYLEN);
-    /* Mask off MSB */
-    pubkey[EC_X25519_KEYLEN - 1] &= 0x7F;
-    return 1;
-}
-
-static int x25519_point_cmp(const EC_GROUP *group, const EC_POINT *a,
-                            const EC_POINT *b, BN_CTX *ctx)
-{
-    /* Shouldn't happen as initialised to non-zero */
-    if (a->custom_data == NULL || b->custom_data == NULL)
-        return -1;
-
-    if (CRYPTO_memcmp(a->custom_data, b->custom_data, EC_X25519_KEYLEN) == 0)
-        return 0;
-
-    return 1;
-}
-
-static int x25519_compute_key(unsigned char **psec, size_t *pseclen,
-                              const EC_POINT *pub_key, const EC_KEY *ecdh)
-{
-    unsigned char *key;
-    int ret = 0;
-    if (ecdh->custom_data == NULL)
-        return 0;
-    key = OPENSSL_malloc(EC_X25519_KEYLEN);
-    if (key == NULL)
-        return 0;
-    if (X25519(key, ecdh->custom_data, pub_key->custom_data) == 0)
-        goto err;
-    *psec = key;
-    *pseclen = EC_X25519_KEYLEN;
-    return 1;
-
- err:
-    OPENSSL_clear_free(key, EC_X25519_KEYLEN);
-    return ret;
-}
-
-const EC_METHOD *ec_x25519_meth(void)
-{
-    static const EC_METHOD ret = {
-        EC_FLAGS_CUSTOM_CURVE | EC_FLAGS_NO_SIGN,
-        NID_undef,
-        x25519_group_init,      /* group_init */
-        0,                      /* group_finish */
-        0,                      /* group_clear_finish */
-        x25519_group_copy,      /* group_copy */
-        0,                      /* group_set_curve */
-        0,                      /* group_get_curve */
-        x25519_group_get_degree,
-        x25519_group_order_bits,
-        0,                      /* group_check_discriminant */
-        x25519_point_init,
-        x25519_point_finish,
-        x25519_point_clear_finish,
-        x25519_point_copy,
-        0,                      /* point_set_to_infinity */
-        0,                      /* set_Jprojective_coordinates_GFp */
-        0,                      /* get_Jprojective_coordinates_GFp */
-        0,                      /* point_set_affine_coordinates */
-        0,                      /* point_get_affine_coordinates */
-        0,                      /* point_set_compressed_coordinates */
-        x25519_point2oct,
-        x25519_oct2point,
-        0,                      /* simple_add */
-        0,                      /* simple_dbl */
-        0,                      /* simple_invert */
-        0,                      /* simple_is_at_infinity */
-        0,                      /* simple_is_on_curve */
-        x25519_point_cmp,
-        0,                      /* simple_make_affine */
-        0,                      /* simple_points_make_affine */
-        0,                      /* points_mul */
-        0,                      /* precompute_mult */
-        0,                      /* have_precompute_mult */
-        0,                      /* field_mul */
-        0,                      /* field_sqr */
-        0,                      /* field_div */
-        0,                      /* field_encode */
-        0,                      /* field_decode */
-        0,                      /* field_set_to_one */
-        x25519_priv2oct,
-        x25519_oct2priv,
-        x25519_set_private,
-        x25519_keygen,
-        x25519_keycheck,
-        x25519_keygenpub,
-        x25519_keycopy,
-        x25519_keyfinish,
-        x25519_compute_key
-    };
-
-    return &ret;
-}
diff --git a/crypto/ec/ec_ameth.c b/crypto/ec/ec_ameth.c
index b1dc011..f6a3f5c 100644
--- a/crypto/ec/ec_ameth.c
+++ b/crypto/ec/ec_ameth.c
@@ -496,6 +496,13 @@ static int ec_pkey_ctrl(EVP_PKEY *pkey, int op, long arg1, void *arg2)
         *(int *)arg2 = NID_sha256;
         return 2;
 
+    case ASN1_PKEY_CTRL_SET1_TLS_ENCPT:
+        return EC_KEY_oct2key(EVP_PKEY_get0_EC_KEY(pkey), arg2, arg1, NULL);
+
+    case ASN1_PKEY_CTRL_GET1_TLS_ENCPT:
+        return EC_KEY_key2buf(EVP_PKEY_get0_EC_KEY(pkey),
+                              POINT_CONVERSION_UNCOMPRESSED, arg2, NULL);
+
     default:
         return -2;
 
diff --git a/crypto/ec/ec_curve.c b/crypto/ec/ec_curve.c
index 6e125f4..f8a3846 100644
--- a/crypto/ec/ec_curve.c
+++ b/crypto/ec/ec_curve.c
@@ -2973,7 +2973,6 @@ static const ec_list_element curve_list[] = {
      "RFC 5639 curve over a 512 bit prime field"},
     {NID_brainpoolP512t1, &_EC_brainpoolP512t1.h, 0,
      "RFC 5639 curve over a 512 bit prime field"},
-    {NID_X25519, NULL, ec_x25519_meth, "X25519"},
 };
 
 #define curve_list_length OSSL_NELEM(curve_list)
diff --git a/crypto/ec/ec_err.c b/crypto/ec/ec_err.c
index 39e8343..e4c2c1c 100644
--- a/crypto/ec/ec_err.c
+++ b/crypto/ec/ec_err.c
@@ -51,6 +51,9 @@ static ERR_STRING_DATA EC_str_functs[] = {
     {ERR_FUNC(EC_F_ECP_NISTZ256_POINTS_MUL), "ecp_nistz256_points_mul"},
     {ERR_FUNC(EC_F_ECP_NISTZ256_PRE_COMP_NEW), "ecp_nistz256_pre_comp_new"},
     {ERR_FUNC(EC_F_ECP_NISTZ256_WINDOWED_MUL), "ecp_nistz256_windowed_mul"},
+    {ERR_FUNC(EC_F_ECX_KEY_OP), "ecx_key_op"},
+    {ERR_FUNC(EC_F_ECX_PRIV_ENCODE), "ecx_priv_encode"},
+    {ERR_FUNC(EC_F_ECX_PUB_ENCODE), "ecx_pub_encode"},
     {ERR_FUNC(EC_F_EC_ASN1_GROUP2CURVE), "ec_asn1_group2curve"},
     {ERR_FUNC(EC_F_EC_ASN1_GROUP2FIELDID), "ec_asn1_group2fieldid"},
     {ERR_FUNC(EC_F_EC_GF2M_MONTGOMERY_POINT_MULTIPLY),
@@ -191,6 +194,7 @@ static ERR_STRING_DATA EC_str_functs[] = {
     {ERR_FUNC(EC_F_OSSL_ECDH_COMPUTE_KEY), "ossl_ecdh_compute_key"},
     {ERR_FUNC(EC_F_OSSL_ECDSA_SIGN_SIG), "ossl_ecdsa_sign_sig"},
     {ERR_FUNC(EC_F_OSSL_ECDSA_VERIFY_SIG), "ossl_ecdsa_verify_sig"},
+    {ERR_FUNC(EC_F_PKEY_ECX_DERIVE), "pkey_ecx_derive"},
     {ERR_FUNC(EC_F_PKEY_EC_CTRL), "pkey_ec_ctrl"},
     {ERR_FUNC(EC_F_PKEY_EC_CTRL_STR), "pkey_ec_ctrl_str"},
     {ERR_FUNC(EC_F_PKEY_EC_DERIVE), "pkey_ec_derive"},
@@ -233,7 +237,9 @@ static ERR_STRING_DATA EC_str_reasons[] = {
     {ERR_REASON(EC_R_INVALID_FIELD), "invalid field"},
     {ERR_REASON(EC_R_INVALID_FORM), "invalid form"},
     {ERR_REASON(EC_R_INVALID_GROUP_ORDER), "invalid group order"},
+    {ERR_REASON(EC_R_INVALID_KEY), "invalid key"},
     {ERR_REASON(EC_R_INVALID_OUTPUT_LENGTH), "invalid output length"},
+    {ERR_REASON(EC_R_INVALID_PEER_KEY), "invalid peer key"},
     {ERR_REASON(EC_R_INVALID_PENTANOMIAL_BASIS), "invalid pentanomial basis"},
     {ERR_REASON(EC_R_INVALID_PRIVATE_KEY), "invalid private key"},
     {ERR_REASON(EC_R_INVALID_TRINOMIAL_BASIS), "invalid trinomial basis"},
diff --git a/crypto/ec/ec_lcl.h b/crypto/ec/ec_lcl.h
index 5b79340..c67efef 100644
--- a/crypto/ec/ec_lcl.h
+++ b/crypto/ec/ec_lcl.h
@@ -254,12 +254,6 @@ struct ec_key_st {
     EC_GROUP *group;
     EC_POINT *pub_key;
     BIGNUM *priv_key;
-    /*
-     * Arbitrary extra data.
-     * For example in X25519 this contains the raw private key in a 32 byte
-     * buffer.
-     */
-    void *custom_data;
     unsigned int enc_flag;
     point_conversion_form_t conv_form;
     int references;
@@ -280,11 +274,6 @@ struct ec_point_st {
                                  * Z) represents (X/Z^2, Y/Z^3) if Z != 0 */
     int Z_is_one;               /* enable optimized point arithmetics for
                                  * special case */
-    /*
-     * Arbitrary extra data.
-     * For example in X25519 this contains the public key in a 32 byte buffer.
-     */
-    void *custom_data;
 } /* EC_POINT */ ;
 
 NISTP224_PRE_COMP *EC_nistp224_pre_comp_dup(NISTP224_PRE_COMP *);
@@ -613,8 +602,6 @@ int ossl_ecdsa_verify(int type, const unsigned char *dgst, int dgst_len,
 int ossl_ecdsa_verify_sig(const unsigned char *dgst, int dgst_len,
                           const ECDSA_SIG *sig, EC_KEY *eckey);
 
-const EC_METHOD *ec_x25519_meth(void);
-
 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],
diff --git a/crypto/ec/ecx_meth.c b/crypto/ec/ecx_meth.c
new file mode 100644
index 0000000..354d387
--- /dev/null
+++ b/crypto/ec/ecx_meth.c
@@ -0,0 +1,373 @@
+/*
+ * Copyright 2006-2016 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the OpenSSL license (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/x509.h>
+#include <openssl/ec.h>
+#include <openssl/rand.h>
+#include "internal/asn1_int.h"
+#include "internal/evp_int.h"
+#include "ec_lcl.h"
+
+#define X25519_KEYLEN        32
+#define X25519_BITS          253
+#define X25519_SECURITY_BITS 128
+
+typedef struct {
+    unsigned char pubkey[X25519_KEYLEN];
+    unsigned char *privkey;
+} X25519_KEY;
+
+typedef enum {
+    X25519_PUBLIC,
+    X25519_PRIVATE,
+    X25519_KEYGEN
+} ecx_key_op_t;
+
+/* Setup EVP_PKEY using public, private or generation */
+static int ecx_key_op(EVP_PKEY *pkey, X509_ALGOR *palg,
+                      const unsigned char *p, int plen, ecx_key_op_t op)
+{
+    X25519_KEY *xkey;
+
+    if (op != X25519_KEYGEN) {
+        if (palg != NULL) {
+            int ptype;
+
+            /* Algorithm parameters must be absent */
+            X509_ALGOR_get0(NULL, &ptype, NULL, palg);
+            if (ptype != V_ASN1_UNDEF) {
+                ECerr(EC_F_ECX_KEY_OP, EC_R_INVALID_ENCODING);
+                return 0;
+            }
+        }
+
+        if (p == NULL || plen != X25519_KEYLEN) {
+            ECerr(EC_F_ECX_KEY_OP, EC_R_INVALID_ENCODING);
+            return 0;
+        }
+    }
+
+    xkey = OPENSSL_zalloc(sizeof(*xkey));
+    if (xkey == NULL) {
+        ECerr(EC_F_ECX_KEY_OP, ERR_R_MALLOC_FAILURE);
+        return 0;
+    }
+
+    if (op == X25519_PUBLIC) {
+        memcpy(xkey->pubkey, p, plen);
+    } else {
+        xkey->privkey = OPENSSL_secure_malloc(X25519_KEYLEN);
+        if (xkey->privkey == NULL) {
+            ECerr(EC_F_ECX_KEY_OP, ERR_R_MALLOC_FAILURE);
+            OPENSSL_free(xkey);
+            return 0;
+        }
+        if (op == X25519_KEYGEN) {
+            if (RAND_bytes(xkey->privkey, X25519_KEYLEN) <= 0) {
+                OPENSSL_secure_free(xkey->privkey);
+                OPENSSL_free(xkey);
+                return 0;
+            }
+            xkey->privkey[0] &= 248;
+            xkey->privkey[31] &= 127;
+            xkey->privkey[31] |= 64;
+        } else {
+            memcpy(xkey->privkey, p, X25519_KEYLEN);
+        }
+        X25519_public_from_private(xkey->pubkey, xkey->privkey);
+    }
+
+    EVP_PKEY_assign(pkey, NID_X25519, xkey);
+    return 1;
+}
+
+static int ecx_pub_encode(X509_PUBKEY *pk, const EVP_PKEY *pkey)
+{
+    const X25519_KEY *xkey = pkey->pkey.ptr;
+    unsigned char *penc;
+
+    if (xkey == NULL) {
+        ECerr(EC_F_ECX_PUB_ENCODE, EC_R_INVALID_KEY);
+        return 0;
+    }
+
+    penc = OPENSSL_memdup(xkey->pubkey, X25519_KEYLEN);
+    if (penc == NULL) {
+        ECerr(EC_F_ECX_PUB_ENCODE, ERR_R_MALLOC_FAILURE);
+        return 0;
+    }
+
+    if (!X509_PUBKEY_set0_param(pk, OBJ_nid2obj(NID_X25519), V_ASN1_UNDEF,
+                                NULL, penc, X25519_KEYLEN)) {
+        OPENSSL_free(penc);
+        ECerr(EC_F_ECX_PUB_ENCODE, ERR_R_MALLOC_FAILURE);
+        return 0;
+    }
+    return 1;
+}
+
+static int ecx_pub_decode(EVP_PKEY *pkey, X509_PUBKEY *pubkey)
+{
+    const unsigned char *p;
+    int pklen;
+    X509_ALGOR *palg;
+
+    if (!X509_PUBKEY_get0_param(NULL, &p, &pklen, &palg, pubkey))
+        return 0;
+    return ecx_key_op(pkey, palg, p, pklen, X25519_PUBLIC);
+}
+
+static int ecx_pub_cmp(const EVP_PKEY *a, const EVP_PKEY *b)
+{
+    const X25519_KEY *akey = a->pkey.ptr;
+    const X25519_KEY *bkey = b->pkey.ptr;
+
+    if (akey == NULL || bkey == NULL)
+        return -2;
+    return !CRYPTO_memcmp(akey->pubkey, bkey->pubkey, X25519_KEYLEN);
+}
+
+static int ecx_priv_decode(EVP_PKEY *pkey, PKCS8_PRIV_KEY_INFO *p8)
+{
+    const unsigned char *p;
+    int plen;
+    ASN1_OCTET_STRING *oct = NULL;
+    X509_ALGOR *palg;
+    int rv;
+
+    if (!PKCS8_pkey_get0(NULL, &p, &plen, &palg, p8))
+        return 0;
+
+    oct = d2i_ASN1_OCTET_STRING(NULL, &p, plen);
+    if (oct == NULL) {
+        p = NULL;
+        plen = 0;
+    } else {
+        p = ASN1_STRING_data(oct);
+        plen = ASN1_STRING_length(oct);
+    }
+
+    rv = ecx_key_op(pkey, palg, p, plen, X25519_PRIVATE);
+    ASN1_OCTET_STRING_free(oct);
+    return rv;
+}
+
+static int ecx_priv_encode(PKCS8_PRIV_KEY_INFO *p8, const EVP_PKEY *pkey)
+{
+    const X25519_KEY *xkey = pkey->pkey.ptr;
+    ASN1_OCTET_STRING oct;
+    unsigned char *penc = NULL;
+    int penclen;
+
+    if (xkey == NULL || xkey->privkey == NULL) {
+        ECerr(EC_F_ECX_PRIV_ENCODE, EC_R_INVALID_PRIVATE_KEY);
+        return 0;
+    }
+
+    oct.data = xkey->privkey;
+    oct.length = X25519_KEYLEN;
+    oct.flags = 0;
+
+    penclen = i2d_ASN1_OCTET_STRING(&oct, &penc);
+    if (penclen < 0) {
+        ECerr(EC_F_ECX_PRIV_ENCODE, ERR_R_MALLOC_FAILURE);
+        return 0;
+    }
+
+    if (!PKCS8_pkey_set0(p8, OBJ_nid2obj(NID_X25519), 0,
+                         V_ASN1_UNDEF, NULL, penc, penclen)) {
+        OPENSSL_clear_free(penc, penclen);
+        ECerr(EC_F_ECX_PRIV_ENCODE, ERR_R_MALLOC_FAILURE);
+        return 0;
+    }
+
+    return 1;
+}
+
+static int ecx_size(const EVP_PKEY *pkey)
+{
+    return X25519_KEYLEN;
+}
+
+static int ecx_bits(const EVP_PKEY *pkey)
+{
+    return X25519_BITS;
+}
+
+static int ecx_security_bits(const EVP_PKEY *pkey)
+{
+    return X25519_SECURITY_BITS;
+}
+
+static void ecx_free(EVP_PKEY *pkey)
+{
+    X25519_KEY *xkey = pkey->pkey.ptr;
+
+    if (xkey)
+        OPENSSL_secure_free(xkey->privkey);
+    OPENSSL_free(xkey);
+}
+
+/* "parameters" are always equal */
+static int ecx_cmp_parameters(const EVP_PKEY *a, const EVP_PKEY *b)
+{
+    return 1;
+}
+
+static int ecx_key_print(BIO *bp, const EVP_PKEY *pkey, int indent,
+                         ASN1_PCTX *ctx, ecx_key_op_t op)
+{
+    const X25519_KEY *xkey = pkey->pkey.ptr;
+
+    if (op == X25519_PRIVATE) {
+        if (xkey == NULL || xkey->privkey == NULL) {
+            if (BIO_printf(bp, "%*s<INVALID PRIVATE KEY>\n", indent, "") <= 0)
+                return 0;
+            return 1;
+        }
+        if (BIO_printf(bp, "%*sX25519 Private-Key:\n", indent, "") <= 0)
+            return 0;
+        if (BIO_printf(bp, "%*spriv:\n", indent, "") <= 0)
+            return 0;
+        if (ASN1_buf_print(bp, xkey->privkey, X25519_KEYLEN, indent + 4) == 0)
+            return 0;
+    } else {
+        if (xkey == NULL) {
+            if (BIO_printf(bp, "%*s<INVALID PUBLIC KEY>\n", indent, "") <= 0)
+                return 0;
+            return 1;
+        }
+        if (BIO_printf(bp, "%*sX25519 Public-Key:\n", indent, "") <= 0)
+            return 0;
+    }
+    if (BIO_printf(bp, "%*spub:\n", indent, "") <= 0)
+        return 0;
+    if (ASN1_buf_print(bp, xkey->pubkey, X25519_KEYLEN, indent + 4) == 0)
+        return 0;
+    return 1;
+}
+
+static int ecx_priv_print(BIO *bp, const EVP_PKEY *pkey, int indent,
+                          ASN1_PCTX *ctx)
+{
+    return ecx_key_print(bp, pkey, indent, ctx, X25519_PRIVATE);
+}
+
+static int ecx_pub_print(BIO *bp, const EVP_PKEY *pkey, int indent,
+                         ASN1_PCTX *ctx)
+{
+    return ecx_key_print(bp, pkey, indent, ctx, X25519_PUBLIC);
+}
+
+static int ecx_ctrl(EVP_PKEY *pkey, int op, long arg1, void *arg2)
+{
+    switch (op) {
+
+    case ASN1_PKEY_CTRL_SET1_TLS_ENCPT:
+        return ecx_key_op(pkey, NULL, arg2, arg1, X25519_PUBLIC);
+
+    case ASN1_PKEY_CTRL_GET1_TLS_ENCPT:
+        if (pkey->pkey.ptr != NULL) {
+            const X25519_KEY *xkey = pkey->pkey.ptr;
+            unsigned char **ppt = arg2;
+            *ppt = OPENSSL_memdup(xkey->pubkey, X25519_KEYLEN);
+            if (*ppt != NULL)
+                return X25519_KEYLEN;
+        }
+        return 0;
+
+    case ASN1_PKEY_CTRL_DEFAULT_MD_NID:
+        *(int *)arg2 = NID_sha256;
+        return 2;
+
+    default:
+        return -2;
+
+    }
+}
+
+const EVP_PKEY_ASN1_METHOD ecx25519_asn1_meth = {
+    NID_X25519,
+    NID_X25519,
+    0,
+    "X25519",
+    "OpenSSL X25519 algorithm",
+
+    ecx_pub_decode,
+    ecx_pub_encode,
+    ecx_pub_cmp,
+    ecx_pub_print,
+
+    ecx_priv_decode,
+    ecx_priv_encode,
+    ecx_priv_print,
+
+    ecx_size,
+    ecx_bits,
+    ecx_security_bits,
+
+    0, 0, 0, 0,
+    ecx_cmp_parameters,
+    0, 0,
+
+    ecx_free,
+    ecx_ctrl,
+    NULL,
+    NULL
+};
+
+static int pkey_ecx_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey)
+{
+    return ecx_key_op(pkey, NULL, NULL, 0, X25519_KEYGEN);
+}
+
+static int pkey_ecx_derive(EVP_PKEY_CTX *ctx, unsigned char *key,
+                           size_t *keylen)
+{
+    const X25519_KEY *pkey, *peerkey;
+
+    if (ctx->pkey == NULL || ctx->peerkey == NULL) {
+        ECerr(EC_F_PKEY_ECX_DERIVE, EC_R_KEYS_NOT_SET);
+        return 0;
+    }
+    pkey = ctx->pkey->pkey.ptr;
+    peerkey = ctx->peerkey->pkey.ptr;
+    if (pkey == NULL || pkey->privkey == NULL) {
+        ECerr(EC_F_PKEY_ECX_DERIVE, EC_R_INVALID_PRIVATE_KEY);
+        return 0;
+    }
+    if (peerkey == NULL) {
+        ECerr(EC_F_PKEY_ECX_DERIVE, EC_R_INVALID_PEER_KEY);
+        return 0;
+    }
+    *keylen = X25519_KEYLEN;
+    if (key != NULL && X25519(key, pkey->privkey, peerkey->pubkey) == 0)
+        return 0;
+    return 1;
+}
+
+static int pkey_ecx_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2)
+{
+    /* Only need to handle peer key for derivation */
+    if (type == EVP_PKEY_CTRL_PEER_KEY)
+        return 1;
+    return -2;
+}
+
+const EVP_PKEY_METHOD ecx25519_pkey_meth = {
+    NID_X25519,
+    0, 0, 0, 0, 0, 0, 0,
+    pkey_ecx_keygen,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    pkey_ecx_derive,
+    pkey_ecx_ctrl,
+    0
+};
diff --git a/crypto/evp/p_lib.c b/crypto/evp/p_lib.c
index 802f6dd..5b776ff 100644
--- a/crypto/evp/p_lib.c
+++ b/crypto/evp/p_lib.c
@@ -451,10 +451,34 @@ int EVP_PKEY_print_params(BIO *out, const EVP_PKEY *pkey,
     return unsup_alg(out, pkey, indent, "Parameters");
 }
 
-int EVP_PKEY_get_default_digest_nid(EVP_PKEY *pkey, int *pnid)
+static int evp_pkey_asn1_ctrl(EVP_PKEY *pkey, int op, int arg1, void *arg2)
 {
-    if (!pkey->ameth || !pkey->ameth->pkey_ctrl)
+    if (pkey->ameth == NULL || pkey->ameth->pkey_ctrl == NULL)
         return -2;
-    return pkey->ameth->pkey_ctrl(pkey, ASN1_PKEY_CTRL_DEFAULT_MD_NID,
-                                  0, pnid);
+    return pkey->ameth->pkey_ctrl(pkey, op, arg1, arg2);
+}
+
+int EVP_PKEY_get_default_digest_nid(EVP_PKEY *pkey, int *pnid)
+{
+    return evp_pkey_asn1_ctrl(pkey, ASN1_PKEY_CTRL_DEFAULT_MD_NID, 0, pnid);
+}
+
+int EVP_PKEY_set1_tls_encodedpoint(EVP_PKEY *pkey,
+                               const unsigned char *pt, size_t ptlen)
+{
+    if (ptlen > INT_MAX)
+        return 0;
+    if (evp_pkey_asn1_ctrl(pkey, ASN1_PKEY_CTRL_SET1_TLS_ENCPT, ptlen,
+                           (void *)pt) <= 0)
+        return 0;
+    return 1;
+}
+
+size_t EVP_PKEY_get1_tls_encodedpoint(EVP_PKEY *pkey, unsigned char **ppt)
+{
+    int rv;
+    rv = evp_pkey_asn1_ctrl(pkey, ASN1_PKEY_CTRL_GET1_TLS_ENCPT, 0, ppt);
+    if (rv <= 0)
+        return 0;
+    return rv;
 }
diff --git a/crypto/evp/pmeth_lib.c b/crypto/evp/pmeth_lib.c
index 2e5e932..169639b 100644
--- a/crypto/evp/pmeth_lib.c
+++ b/crypto/evp/pmeth_lib.c
@@ -42,6 +42,9 @@ static const EVP_PKEY_METHOD *standard_methods[] = {
     &dhx_pkey_meth,
 #endif
     &tls1_prf_pkey_meth,
+#ifndef OPENSSL_NO_EC
+    &ecx25519_pkey_meth,
+#endif
     &hkdf_pkey_meth
 };
 
diff --git a/crypto/include/internal/asn1_int.h b/crypto/include/internal/asn1_int.h
index aad047e..f4c71fc 100644
--- a/crypto/include/internal/asn1_int.h
+++ b/crypto/include/internal/asn1_int.h
@@ -61,6 +61,7 @@ extern const EVP_PKEY_ASN1_METHOD dh_asn1_meth;
 extern const EVP_PKEY_ASN1_METHOD dhx_asn1_meth;
 extern const EVP_PKEY_ASN1_METHOD dsa_asn1_meths[5];
 extern const EVP_PKEY_ASN1_METHOD eckey_asn1_meth;
+extern const EVP_PKEY_ASN1_METHOD ecx25519_asn1_meth;
 extern const EVP_PKEY_ASN1_METHOD hmac_asn1_meth;
 extern const EVP_PKEY_ASN1_METHOD rsa_asn1_meths[2];
 
diff --git a/crypto/include/internal/evp_int.h b/crypto/include/internal/evp_int.h
index 2e4ca02..d1e607e 100644
--- a/crypto/include/internal/evp_int.h
+++ b/crypto/include/internal/evp_int.h
@@ -79,6 +79,7 @@ extern const EVP_PKEY_METHOD dh_pkey_meth;
 extern const EVP_PKEY_METHOD dhx_pkey_meth;
 extern const EVP_PKEY_METHOD dsa_pkey_meth;
 extern const EVP_PKEY_METHOD ec_pkey_meth;
+extern const EVP_PKEY_METHOD ecx25519_pkey_meth;
 extern const EVP_PKEY_METHOD hmac_pkey_meth;
 extern const EVP_PKEY_METHOD rsa_pkey_meth;
 extern const EVP_PKEY_METHOD tls1_prf_pkey_meth;
@@ -356,7 +357,7 @@ struct evp_pkey_st {
     const EVP_PKEY_ASN1_METHOD *ameth;
     ENGINE *engine;
     union {
-        char *ptr;
+        void *ptr;
 # ifndef OPENSSL_NO_RSA
         struct rsa_st *rsa;     /* RSA */
 # endif
diff --git a/crypto/objects/obj_dat.h b/crypto/objects/obj_dat.h
index 03c69a9..e1fc64f 100644
--- a/crypto/objects/obj_dat.h
+++ b/crypto/objects/obj_dat.h
@@ -10,7 +10,7 @@
  */
 
 /* Serialized OID's */
-static const unsigned char so[6777] = {
+static const unsigned char so[6765] = {
     0x2A,0x86,0x48,0x86,0xF7,0x0D,                 /* [    0] OBJ_rsadsi */
     0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,            /* [    6] OBJ_pkcs */
     0x2A,0x86,0x48,0x86,0xF7,0x0D,0x02,0x02,       /* [   13] OBJ_md2 */
@@ -954,13 +954,13 @@ static const unsigned char so[6777] = {
     0x2B,0x06,0x01,0x05,0x02,0x03,                 /* [ 6683] OBJ_id_pkinit */
     0x2B,0x06,0x01,0x05,0x02,0x03,0x04,            /* [ 6689] OBJ_pkInitClientAuth */
     0x2B,0x06,0x01,0x05,0x02,0x03,0x05,            /* [ 6696] OBJ_pkInitKDC */
-    0x2B,0x06,0x01,0x04,0x01,0xDA,0x47,0x0F,0x01,  /* [ 6703] OBJ_X25519 */
-    0x2B,0x06,0x01,0x04,0x01,0xDA,0x47,0x0F,0x02,  /* [ 6712] OBJ_X448 */
-    0x2B,0x06,0x01,0x04,0x01,0x8D,0x3A,0x0C,0x02,0x01,0x10,  /* [ 6721] OBJ_blake2b512 */
-    0x2B,0x06,0x01,0x04,0x01,0x8D,0x3A,0x0C,0x02,0x02,0x08,  /* [ 6732] OBJ_blake2s256 */
-    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x01,0x13,  /* [ 6743] OBJ_id_smime_ct_contentCollection */
-    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x01,0x17,  /* [ 6754] OBJ_id_smime_ct_authEnvelopedData */
-    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x01,0x1C,  /* [ 6765] OBJ_id_ct_xml */
+    0x2B,0x65,0x6E,                                /* [ 6703] OBJ_X25519 */
+    0x2B,0x65,0x6F,                                /* [ 6706] OBJ_X448 */
+    0x2B,0x06,0x01,0x04,0x01,0x8D,0x3A,0x0C,0x02,0x01,0x10,  /* [ 6709] OBJ_blake2b512 */
+    0x2B,0x06,0x01,0x04,0x01,0x8D,0x3A,0x0C,0x02,0x02,0x08,  /* [ 6720] OBJ_blake2s256 */
+    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x01,0x13,  /* [ 6731] OBJ_id_smime_ct_contentCollection */
+    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x01,0x17,  /* [ 6742] OBJ_id_smime_ct_authEnvelopedData */
+    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x01,0x1C,  /* [ 6753] OBJ_id_ct_xml */
 };
 
 #define NUM_NID 1061
@@ -1999,8 +1999,8 @@ static const ASN1_OBJECT nid_objs[NUM_NID] = {
     {"id-pkinit", "id-pkinit", NID_id_pkinit, 6, &so[6683]},
     {"pkInitClientAuth", "PKINIT Client Auth", NID_pkInitClientAuth, 7, &so[6689]},
     {"pkInitKDC", "Signing KDC Response", NID_pkInitKDC, 7, &so[6696]},
-    {"X25519", "X25519", NID_X25519, 9, &so[6703]},
-    {"X448", "X448", NID_X448, 9, &so[6712]},
+    {"X25519", "X25519", NID_X25519, 3, &so[6703]},
+    {"X448", "X448", NID_X448, 3, &so[6706]},
     {"HKDF", "hkdf", NID_hkdf},
     {"KxRSA", "kx-rsa", NID_kx_rsa},
     {"KxECDHE", "kx-ecdhe", NID_kx_ecdhe},
@@ -2021,11 +2021,11 @@ static const ASN1_OBJECT nid_objs[NUM_NID] = {
     {"AuthNULL", "auth-null", NID_auth_null},
     { NULL, NULL, NID_undef },
     { NULL, NULL, NID_undef },
-    {"BLAKE2b512", "blake2b512", NID_blake2b512, 11, &so[6721]},
-    {"BLAKE2s256", "blake2s256", NID_blake2s256, 11, &so[6732]},
-    {"id-smime-ct-contentCollection", "id-smime-ct-contentCollection", NID_id_smime_ct_contentCollection, 11, &so[6743]},
-    {"id-smime-ct-authEnvelopedData", "id-smime-ct-authEnvelopedData", NID_id_smime_ct_authEnvelopedData, 11, &so[6754]},
-    {"id-ct-xml", "id-ct-xml", NID_id_ct_xml, 11, &so[6765]},
+    {"BLAKE2b512", "blake2b512", NID_blake2b512, 11, &so[6709]},
+    {"BLAKE2s256", "blake2s256", NID_blake2s256, 11, &so[6720]},
+    {"id-smime-ct-contentCollection", "id-smime-ct-contentCollection", NID_id_smime_ct_contentCollection, 11, &so[6731]},
+    {"id-smime-ct-authEnvelopedData", "id-smime-ct-authEnvelopedData", NID_id_smime_ct_authEnvelopedData, 11, &so[6742]},
+    {"id-ct-xml", "id-ct-xml", NID_id_ct_xml, 11, &so[6753]},
 };
 
 #define NUM_SN 1052
@@ -4163,6 +4163,8 @@ static const unsigned int obj_objs[NUM_OBJ] = {
      435,    /* OBJ_pss                          0 9 2342 */
      183,    /* OBJ_ISO_US                       1 2 840 */
      381,    /* OBJ_iana                         1 3 6 1 */
+    1034,    /* OBJ_X25519                       1 3 101 110 */
+    1035,    /* OBJ_X448                         1 3 101 111 */
      677,    /* OBJ_certicom_arc                 1 3 132 */
      394,    /* OBJ_selected_attribute_types     2 5 1 5 */
       13,    /* OBJ_commonName                   2 5 4 3 */
@@ -4843,8 +4845,6 @@ static const unsigned int obj_objs[NUM_OBJ] = {
      390,    /* OBJ_dcObject                     1 3 6 1 4 1 1466 344 */
       91,    /* OBJ_bf_cbc                       1 3 6 1 4 1 3029 1 2 */
      973,    /* OBJ_id_scrypt                    1 3 6 1 4 1 11591 4 11 */
-    1034,    /* OBJ_X25519                       1 3 6 1 4 1 11591 15 1 */
-    1035,    /* OBJ_X448                         1 3 6 1 4 1 11591 15 2 */
      315,    /* OBJ_id_regCtrl_regToken          1 3 6 1 5 5 7 5 1 1 */
      316,    /* OBJ_id_regCtrl_authenticator     1 3 6 1 5 5 7 5 1 2 */
      317,    /* OBJ_id_regCtrl_pkiPublicationInfo 1 3 6 1 5 5 7 5 1 3 */
diff --git a/crypto/objects/objects.txt b/crypto/objects/objects.txt
index bf4d3d2..fc0781d 100644
--- a/crypto/objects/objects.txt
+++ b/crypto/objects/objects.txt
@@ -1458,10 +1458,9 @@ secg-scheme 14 3 : dhSinglePass-cofactorDH-sha512kdf-scheme
 id-pkinit 4                     : pkInitClientAuth      : PKINIT Client Auth
 id-pkinit 5                     : pkInitKDC             : Signing KDC Response
 
-# New curves from draft-josefsson-pkix-newcurves
-
-1 3 6 1 4 1 11591 15 1      : X25519
-1 3 6 1 4 1 11591 15 2      : X448
+# New curves from draft-ietf-curdle-pkix-00
+1 3 101 110 : X25519
+1 3 101 111 : X448
 
 # NIDs for cipher key exchange
                             : KxRSA        : kx-rsa
diff --git a/doc/apps/genpkey.pod b/doc/apps/genpkey.pod
index 8a78946..e77fc7e 100644
--- a/doc/apps/genpkey.pod
+++ b/doc/apps/genpkey.pod
@@ -192,6 +192,9 @@ numeric OID. Following parameter sets are supported:
 
 =back
 
+=head1 X25519 KEY GENERATION OPTIONS
+
+The X25519 algorithm does not currently support any key generation options.
 
 
 =head1 NOTES
@@ -253,6 +256,10 @@ Generate EC key directly:
         -pkeyopt ec_paramgen_curve:P-384 \
         -pkeyopt ec_param_enc:named_curve
 
+Generate an X25519 private key:
+
+ openssl genpkey -algorithm X25519 -out xkey.pem
+
 =head1 HISTORY
 
 The ability to use NIST curve names, and to generate an EC key directly,
diff --git a/doc/apps/pkeyutl.pod b/doc/apps/pkeyutl.pod
index 91eeda5..8a455b8 100644
--- a/doc/apps/pkeyutl.pod
+++ b/doc/apps/pkeyutl.pod
@@ -240,6 +240,11 @@ verify operations use ECDSA and derive uses ECDH. Currently there are no
 additional options other than B<digest>. Only the SHA1 digest can be used and
 this digest is assumed by default.
 
+=head1 X25519 ALGORITHM
+
+The X25519 algorithm supports key derivation only. Currently there are no
+additional options.
+
 =head1 EXAMPLES
 
 Sign some data using a private key:
diff --git a/include/openssl/ec.h b/include/openssl/ec.h
index 9db2397..4a8b832 100644
--- a/include/openssl/ec.h
+++ b/include/openssl/ec.h
@@ -1396,6 +1396,9 @@ int ERR_load_EC_strings(void);
 # define EC_F_ECP_NISTZ256_POINTS_MUL                     241
 # define EC_F_ECP_NISTZ256_PRE_COMP_NEW                   244
 # define EC_F_ECP_NISTZ256_WINDOWED_MUL                   242
+# define EC_F_ECX_KEY_OP                                  266
+# define EC_F_ECX_PRIV_ENCODE                             267
+# define EC_F_ECX_PUB_ENCODE                              268
 # define EC_F_EC_ASN1_GROUP2CURVE                         153
 # define EC_F_EC_ASN1_GROUP2FIELDID                       154
 # define EC_F_EC_GF2M_MONTGOMERY_POINT_MULTIPLY           208
@@ -1500,6 +1503,7 @@ int ERR_load_EC_strings(void);
 # define EC_F_OSSL_ECDH_COMPUTE_KEY                       247
 # define EC_F_OSSL_ECDSA_SIGN_SIG                         249
 # define EC_F_OSSL_ECDSA_VERIFY_SIG                       250
+# define EC_F_PKEY_ECX_DERIVE                             269
 # define EC_F_PKEY_EC_CTRL                                197
 # define EC_F_PKEY_EC_CTRL_STR                            198
 # define EC_F_PKEY_EC_DERIVE                              217
@@ -1534,7 +1538,9 @@ int ERR_load_EC_strings(void);
 # define EC_R_INVALID_FIELD                               103
 # define EC_R_INVALID_FORM                                104
 # define EC_R_INVALID_GROUP_ORDER                         122
+# define EC_R_INVALID_KEY                                 116
 # define EC_R_INVALID_OUTPUT_LENGTH                       161
+# define EC_R_INVALID_PEER_KEY                            133
 # define EC_R_INVALID_PENTANOMIAL_BASIS                   132
 # define EC_R_INVALID_PRIVATE_KEY                         123
 # define EC_R_INVALID_TRINOMIAL_BASIS                     137
diff --git a/include/openssl/evp.h b/include/openssl/evp.h
index 84df8a0..46a2e26 100644
--- a/include/openssl/evp.h
+++ b/include/openssl/evp.h
@@ -959,6 +959,10 @@ int EVP_PKEY_print_params(BIO *out, const EVP_PKEY *pkey,
 
 int EVP_PKEY_get_default_digest_nid(EVP_PKEY *pkey, int *pnid);
 
+int EVP_PKEY_set1_tls_encodedpoint(EVP_PKEY *pkey,
+                                   const unsigned char *pt, size_t ptlen);
+size_t EVP_PKEY_get1_tls_encodedpoint(EVP_PKEY *pkey, unsigned char **ppt);
+
 int EVP_CIPHER_type(const EVP_CIPHER *ctx);
 
 /* calls methods */
@@ -1028,6 +1032,9 @@ int EVP_PBE_get(int *ptype, int *ppbe_nid, size_t num);
 # define ASN1_PKEY_CTRL_CMS_ENVELOPE     0x7
 # define ASN1_PKEY_CTRL_CMS_RI_TYPE      0x8
 
+# define ASN1_PKEY_CTRL_SET1_TLS_ENCPT   0x9
+# define ASN1_PKEY_CTRL_GET1_TLS_ENCPT   0xa
+
 int EVP_PKEY_asn1_get_count(void);
 const EVP_PKEY_ASN1_METHOD *EVP_PKEY_asn1_get0(int idx);
 const EVP_PKEY_ASN1_METHOD *EVP_PKEY_asn1_find(ENGINE **pe, int type);
diff --git a/include/openssl/obj_mac.h b/include/openssl/obj_mac.h
index ca296e6..f97f3ea 100644
--- a/include/openssl/obj_mac.h
+++ b/include/openssl/obj_mac.h
@@ -4502,11 +4502,11 @@
 
 #define SN_X25519               "X25519"
 #define NID_X25519              1034
-#define OBJ_X25519              1L,3L,6L,1L,4L,1L,11591L,15L,1L
+#define OBJ_X25519              1L,3L,101L,110L
 
 #define SN_X448         "X448"
 #define NID_X448                1035
-#define OBJ_X448                1L,3L,6L,1L,4L,1L,11591L,15L,2L
+#define OBJ_X448                1L,3L,101L,111L
 
 #define SN_kx_rsa               "KxRSA"
 #define LN_kx_rsa               "kx-rsa"
diff --git a/ssl/s3_lib.c b/ssl/s3_lib.c
index e14b448..f1363ca 100644
--- a/ssl/s3_lib.c
+++ b/ssl/s3_lib.c
@@ -3090,7 +3090,7 @@ long ssl3_ctrl(SSL *s, int cmd, long larg, void *parg)
                 unsigned int cid, nid;
                 for (i = 0; i < clistlen; i++) {
                     n2s(clist, cid);
-                    nid = tls1_ec_curve_id2nid(cid);
+                    nid = tls1_ec_curve_id2nid(cid, NULL);
                     if (nid != 0)
                         cptr[i] = nid;
                     else
@@ -3982,27 +3982,38 @@ int ssl_generate_master_secret(SSL *s, unsigned char *pms, size_t pmslen,
     return s->session->master_key_length >= 0;
 }
 
-/* Generate a private key from parameters or a curve NID */
-EVP_PKEY *ssl_generate_pkey(EVP_PKEY *pm, int nid)
+/* Generate a private key from parameters or a curve ID */
+EVP_PKEY *ssl_generate_pkey(EVP_PKEY *pm, int id)
 {
     EVP_PKEY_CTX *pctx = NULL;
     EVP_PKEY *pkey = NULL;
+    int nid;
     if (pm != NULL) {
         pctx = EVP_PKEY_CTX_new(pm, NULL);
+        nid = 0;
     } else {
+        unsigned int curve_flags;
+        nid = tls1_ec_curve_id2nid(id, &curve_flags);
+        if (nid == 0)
+            goto err;
         /*
          * Generate a new key for this curve.
          * Should not be called if EC is disabled: if it is it will
          * fail with an unknown algorithm error.
          */
-        pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL);
+        if ((curve_flags & TLS_CURVE_TYPE) == TLS_CURVE_CUSTOM) {
+            pctx = EVP_PKEY_CTX_new_id(nid, NULL);
+            nid = 0;
+        } else {
+            pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL);
+        }
     }
     if (pctx == NULL)
         goto err;
     if (EVP_PKEY_keygen_init(pctx) <= 0)
         goto err;
 #ifndef OPENSSL_NO_EC
-    if (pm == NULL && EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, nid) <= 0)
+    if (nid != 0 && EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, nid) <= 0)
         goto err;
 #endif
 
diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h
index f502cad..3c230d1 100644
--- a/ssl/ssl_locl.h
+++ b/ssl/ssl_locl.h
@@ -1987,7 +1987,13 @@ __owur int ssl_check_srvr_ecc_cert_and_alg(X509 *x, SSL *s);
 SSL_COMP *ssl3_comp_find(STACK_OF(SSL_COMP) *sk, int n);
 
 #  ifndef OPENSSL_NO_EC
-__owur int tls1_ec_curve_id2nid(int curve_id);
+/* Flags values from tls1_ec_curve_id2nid() */
+/* Mask for curve type */
+# define TLS_CURVE_TYPE          0x3
+# define TLS_CURVE_PRIME         0x0
+# define TLS_CURVE_CHAR2         0x1
+# define TLS_CURVE_CUSTOM        0x2
+__owur int tls1_ec_curve_id2nid(int curve_id, unsigned int *pflags);
 __owur int tls1_ec_nid2curve_id(int nid);
 __owur int tls1_check_curve(SSL *s, const unsigned char *p, size_t len);
 __owur int tls1_shared_curve(SSL *s, int nmatch);
diff --git a/ssl/statem/statem_clnt.c b/ssl/statem/statem_clnt.c
index df19211..6f4c8ff 100644
--- a/ssl/statem/statem_clnt.c
+++ b/ssl/statem/statem_clnt.c
@@ -1497,6 +1497,7 @@ static int tls_process_ske_ecdhe(SSL *s, PACKET *pkt, EVP_PKEY **pkey, int *al)
     PACKET encoded_pt;
     const unsigned char *ecparams;
     int curve_nid;
+    unsigned int curve_flags;
     EVP_PKEY_CTX *pctx = NULL;
 
     /*
@@ -1519,7 +1520,8 @@ static int tls_process_ske_ecdhe(SSL *s, PACKET *pkt, EVP_PKEY **pkey, int *al)
         return 0;
     }
 
-    curve_nid = tls1_ec_curve_id2nid(*(ecparams + 2));
+    curve_nid = tls1_ec_curve_id2nid(*(ecparams + 2), &curve_flags);
+
     if (curve_nid  == 0) {
         *al = SSL_AD_INTERNAL_ERROR;
         SSLerr(SSL_F_TLS_PROCESS_SKE_ECDHE,
@@ -1527,19 +1529,31 @@ static int tls_process_ske_ecdhe(SSL *s, PACKET *pkt, EVP_PKEY **pkey, int *al)
         return 0;
     }
 
-    /* Set up EVP_PKEY with named curve as parameters */
-    pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL);
-    if (pctx == NULL
-        || EVP_PKEY_paramgen_init(pctx) <= 0
-        || EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, curve_nid) <= 0
-        || EVP_PKEY_paramgen(pctx, &s->s3->peer_tmp) <= 0) {
-        *al = SSL_AD_INTERNAL_ERROR;
-        SSLerr(SSL_F_TLS_PROCESS_SKE_ECDHE, ERR_R_EVP_LIB);
+    if ((curve_flags & TLS_CURVE_TYPE) == TLS_CURVE_CUSTOM) {
+        EVP_PKEY *key = EVP_PKEY_new();
+
+        if (key == NULL || !EVP_PKEY_set_type(key, curve_nid)) {
+            *al = SSL_AD_INTERNAL_ERROR;
+            SSLerr(SSL_F_TLS_PROCESS_SKE_ECDHE, ERR_R_EVP_LIB);
+            EVP_PKEY_free(key);
+            return 0;
+        }
+        s->s3->peer_tmp = key;
+    } else {
+        /* Set up EVP_PKEY with named curve as parameters */
+        pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL);
+        if (pctx == NULL
+            || EVP_PKEY_paramgen_init(pctx) <= 0
+            || EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, curve_nid) <= 0
+            || EVP_PKEY_paramgen(pctx, &s->s3->peer_tmp) <= 0) {
+            *al = SSL_AD_INTERNAL_ERROR;
+            SSLerr(SSL_F_TLS_PROCESS_SKE_ECDHE, ERR_R_EVP_LIB);
+            EVP_PKEY_CTX_free(pctx);
+            return 0;
+        }
         EVP_PKEY_CTX_free(pctx);
-        return 0;
+        pctx = NULL;
     }
-    EVP_PKEY_CTX_free(pctx);
-    pctx = NULL;
 
     if (!PACKET_get_length_prefixed_1(pkt, &encoded_pt)) {
         *al = SSL_AD_DECODE_ERROR;
@@ -1547,9 +1561,9 @@ static int tls_process_ske_ecdhe(SSL *s, PACKET *pkt, EVP_PKEY **pkey, int *al)
         return 0;
     }
 
-    if (EC_KEY_oct2key(EVP_PKEY_get0_EC_KEY(s->s3->peer_tmp),
-                       PACKET_data(&encoded_pt),
-                       PACKET_remaining(&encoded_pt), NULL) == 0) {
+    if (!EVP_PKEY_set1_tls_encodedpoint(s->s3->peer_tmp,
+                                        PACKET_data(&encoded_pt),
+                                        PACKET_remaining(&encoded_pt))) {
         *al = SSL_AD_DECODE_ERROR;
         SSLerr(SSL_F_TLS_PROCESS_SKE_ECDHE, SSL_R_BAD_ECPOINT);
         return 0;
@@ -2269,7 +2283,7 @@ static int tls_construct_cke_ecdhe(SSL *s, unsigned char **p, int *len, int *al)
     EVP_PKEY *ckey = NULL, *skey = NULL;
 
     skey = s->s3->peer_tmp;
-    if ((skey == NULL) || EVP_PKEY_get0_EC_KEY(skey) == NULL) {
+    if (skey == NULL) {
         SSLerr(SSL_F_TLS_CONSTRUCT_CKE_ECDHE, ERR_R_INTERNAL_ERROR);
         return 0;
     }
@@ -2282,9 +2296,7 @@ static int tls_construct_cke_ecdhe(SSL *s, unsigned char **p, int *len, int *al)
     }
 
     /* Generate encoding of client key */
-    encoded_pt_len = EC_KEY_key2buf(EVP_PKEY_get0_EC_KEY(ckey),
-                                    POINT_CONVERSION_UNCOMPRESSED,
-                                    &encodedPoint, NULL);
+    encoded_pt_len = EVP_PKEY_get1_tls_encodedpoint(ckey, &encodedPoint);
 
     if (encoded_pt_len == 0) {
         SSLerr(SSL_F_TLS_CONSTRUCT_CKE_ECDHE, ERR_R_EC_LIB);
diff --git a/ssl/statem/statem_srvr.c b/ssl/statem/statem_srvr.c
index 602336a..a5fe752 100644
--- a/ssl/statem/statem_srvr.c
+++ b/ssl/statem/statem_srvr.c
@@ -1737,7 +1737,7 @@ int tls_construct_server_key_exchange(SSL *s)
                    SSL_R_UNSUPPORTED_ELLIPTIC_CURVE);
             goto err;
         }
-        s->s3->tmp.pkey = ssl_generate_pkey(NULL, nid);
+        s->s3->tmp.pkey = ssl_generate_pkey(NULL, curve_id);
         /* Generate a new key for this curve */
         if (s->s3->tmp.pkey == NULL) {
             al = SSL_AD_INTERNAL_ERROR;
@@ -1746,10 +1746,8 @@ int tls_construct_server_key_exchange(SSL *s)
         }
 
         /* Encode the public key. */
-        encodedlen = EC_KEY_key2buf(EVP_PKEY_get0_EC_KEY(s->s3->tmp.pkey),
-                                    POINT_CONVERSION_UNCOMPRESSED,
-                                    &encodedPoint, NULL);
-
+        encodedlen = EVP_PKEY_get1_tls_encodedpoint(s->s3->tmp.pkey,
+                                                    &encodedPoint);
         if (encodedlen == 0) {
             SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE, ERR_R_EC_LIB);
             goto err;
@@ -2386,8 +2384,7 @@ static int tls_process_cke_ecdhe(SSL *s, PACKET *pkt, int *al)
             SSLerr(SSL_F_TLS_PROCESS_CKE_ECDHE, ERR_R_EVP_LIB);
             goto err;
         }
-        if (EC_KEY_oct2key(EVP_PKEY_get0_EC_KEY(ckey), data, i,
-                           NULL) == 0) {
+        if (EVP_PKEY_set1_tls_encodedpoint(ckey, data, i) == 0) {
             *al = SSL_AD_HANDSHAKE_FAILURE;
             SSLerr(SSL_F_TLS_PROCESS_CKE_ECDHE, ERR_R_EC_LIB);
             goto err;
diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c
index 2418c65..ca4e7d6 100644
--- a/ssl/t1_lib.c
+++ b/ssl/t1_lib.c
@@ -121,12 +121,6 @@ typedef struct {
     unsigned int flags;         /* Flags: currently just field type */
 } tls_curve_info;
 
-/* Mask for curve type */
-# define TLS_CURVE_TYPE          0x3
-# define TLS_CURVE_PRIME         0x0
-# define TLS_CURVE_CHAR2         0x1
-# define TLS_CURVE_CUSTOM        0x2
-
 /*
  * Table of curve information.
  * Do not delete entries or reorder this array! It is used as a lookup
@@ -161,8 +155,7 @@ static const tls_curve_info nid_list[] = {
     {NID_brainpoolP256r1, 128, TLS_CURVE_PRIME}, /* brainpoolP256r1 (26) */
     {NID_brainpoolP384r1, 192, TLS_CURVE_PRIME}, /* brainpoolP384r1 (27) */
     {NID_brainpoolP512r1, 256, TLS_CURVE_PRIME}, /* brainpool512r1 (28) */
-    /* X25519 (29) */
-    {NID_X25519, 128, TLS_CURVE_CUSTOM},
+    {NID_X25519, 128, TLS_CURVE_CUSTOM}, /* X25519 (29) */
 };
 
 static const unsigned char ecformats_default[] = {
@@ -222,12 +215,16 @@ static const unsigned char suiteb_curves[] = {
     0, TLSEXT_curve_P_384
 };
 
-int tls1_ec_curve_id2nid(int curve_id)
+int tls1_ec_curve_id2nid(int curve_id, unsigned int *pflags)
 {
+    const tls_curve_info *cinfo;
     /* ECC curves from RFC 4492 and RFC 7027 */
     if ((curve_id < 1) || ((unsigned int)curve_id > OSSL_NELEM(nid_list)))
         return 0;
-    return nid_list[curve_id - 1].nid;
+    cinfo = nid_list + curve_id - 1;
+    if (pflags)
+        *pflags = cinfo->flags;
+    return cinfo->nid;
 }
 
 int tls1_ec_nid2curve_id(int nid)
@@ -413,7 +410,7 @@ int tls1_shared_curve(SSL *s, int nmatch)
                     continue;
                 if (nmatch == k) {
                     int id = (pref[0] << 8) | pref[1];
-                    return tls1_ec_curve_id2nid(id);
+                    return tls1_ec_curve_id2nid(id, NULL);
                 }
                 k++;
             }
diff --git a/test/evptests.txt b/test/evptests.txt
index a66a152..147c8a4 100644
--- a/test/evptests.txt
+++ b/test/evptests.txt
@@ -3307,23 +3307,19 @@ SharedSecret=E3CC07DFBDDE76A1139811DB9FF5FAF9D17EF39944F1E77D1F6A208524BF7B1B
 # X25519 test vectors from RFC7748 6.1
 PrivateKey=Alice-25519
 -----BEGIN PRIVATE KEY-----
-MEICAQAwFAYHKoZIzj0CAQYJKwYBBAHaRw8BBCcwJQIBAQQgdwdtCnMYpX08FsFy
-UbJmRd9ML4frwJkqsXf7pR25LCo=
+MC4CAQAwBQYDK2VuBCIEIHcHbQpzGKV9PBbBclGyZkXfTC+H68CZKrF3+6UduSwq
 -----END PRIVATE KEY-----
 PublicKey=Alice-25519-PUBLIC
 -----BEGIN PUBLIC KEY-----
-MDkwFAYHKoZIzj0CAQYJKwYBBAHaRw8BAyEAhSDwCYkwp1R0i33ctD73Wg2/Og0m
-OBr066SpjqqbTmo=
+MCowBQYDK2VuAyEAhSDwCYkwp1R0i33ctD73Wg2/Og0mOBr066SpjqqbTmo=
 -----END PUBLIC KEY-----
 PrivateKey=Bob-25519
 -----BEGIN PRIVATE KEY-----
-MEICAQAwFAYHKoZIzj0CAQYJKwYBBAHaRw8BBCcwJQIBAQQgXasIfmJKikt54X+L
-g4AO5m87sSkmGLb9HC+LJ/+I4Os=
+MC4CAQAwBQYDK2VuBCIEIF2rCH5iSopLeeF/i4OADuZvO7EpJhi2/Rwviyf/iODr
 -----END PRIVATE KEY-----
 PublicKey=Bob-25519-PUBLIC
 -----BEGIN PUBLIC KEY-----
-MDkwFAYHKoZIzj0CAQYJKwYBBAHaRw8BAyEA3p7bfXt9wbTTW2HC7OQ1Nz+DQ8hb
-eGdNrfx+FG+IK08=
+MCowBQYDK2VuAyEA3p7bfXt9wbTTW2HC7OQ1Nz+DQ8hbeGdNrfx+FG+IK08=
 -----END PUBLIC KEY-----
 
 Derive=Alice-25519
@@ -3333,15 +3329,3 @@ SharedSecret=4A5D9D5BA4CE2DE1728E3BF480350F25E07E21C947D19E3376F09B3C1E161742
 Derive=Bob-25519
 PeerKey=Alice-25519-PUBLIC
 SharedSecret=4A5D9D5BA4CE2DE1728E3BF480350F25E07E21C947D19E3376F09B3C1E161742
-# Try to sign/verify using X25519 keys: both return errors.
-Sign = Alice-25519
-Ctrl = digest:SHA256
-Input = "0123456789ABCDEF1234"
-Output = 30
-Result = KEYOP_ERROR
-
-Verify = Alice-25519-PUBLIC
-Ctrl = digest:SHA256
-Input = "0123456789ABCDEF1234"
-Output = 30
-Result = VERIFY_ERROR
diff --git a/util/libcrypto.num b/util/libcrypto.num
index a02cc8d..cffb46a 100644
--- a/util/libcrypto.num
+++ b/util/libcrypto.num
@@ -4188,3 +4188,5 @@ X509_STORE_lock                         4134	1_1_0	EXIST::FUNCTION:
 X509_set_proxy_pathlen                  4135	1_1_0	EXIST::FUNCTION:
 X509_get_proxy_pathlen                  4136	1_1_0	EXIST::FUNCTION:
 DSA_bits                                4137	1_1_0	EXIST::FUNCTION:DSA
+EVP_PKEY_set1_tls_encodedpoint          4138	1_1_0	EXIST::FUNCTION:
+EVP_PKEY_get1_tls_encodedpoint          4139	1_1_0	EXIST::FUNCTION:


More information about the openssl-commits mailing list