[openssl-commits] [openssl] master update

Dr. Stephen Henson steve at openssl.org
Wed Dec 16 14:22:34 UTC 2015


The branch master has been updated
       via  91b0d2c114d843ca775fafa12a74a33e974f4a4f (commit)
       via  61dd9f7a2260b846f07481e0392a941703cf2be5 (commit)
       via  880d9d8609506e27e2031cc1a96663380ab70da5 (commit)
       via  3f3504bdaf4f43971a1e584b566d7a5281a33c43 (commit)
       via  44d4f8f2d761d919fd6267cce112dad36590879f (commit)
       via  2c61a5eccad5085cab916c0959cb4c2fec16f9e5 (commit)
       via  c66ce5eb23f7611bd2822650d6ffeacbe0671072 (commit)
       via  57be4444c645247d15428217e289ae36e5c3e6a8 (commit)
       via  cae4136431e7298760cae50732226c64e438d8dd (commit)
       via  981bd8a2f28c17f774ecb8b60233858fe52db502 (commit)
      from  19a86b03010c111d4e05ce252247e30f0e940dad (commit)


- Log -----------------------------------------------------------------
commit 91b0d2c114d843ca775fafa12a74a33e974f4a4f
Author: Dr. Stephen Henson <steve at openssl.org>
Date:   Wed Dec 16 13:21:52 2015 +0000

    make update
    
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit 61dd9f7a2260b846f07481e0392a941703cf2be5
Author: Dr. Stephen Henson <steve at openssl.org>
Date:   Mon Dec 14 00:33:33 2015 +0000

    Use EVP_PKEY for client side EC.
    
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit 880d9d8609506e27e2031cc1a96663380ab70da5
Author: Dr. Stephen Henson <steve at openssl.org>
Date:   Sun Dec 13 13:41:32 2015 +0000

    Use EVP_PKEY for server EC.
    
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit 3f3504bdaf4f43971a1e584b566d7a5281a33c43
Author: Dr. Stephen Henson <steve at openssl.org>
Date:   Tue Dec 15 18:15:16 2015 +0000

    Add ECDH/DH utility functions.
    
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit 44d4f8f2d761d919fd6267cce112dad36590879f
Author: Dr. Stephen Henson <steve at openssl.org>
Date:   Sun Dec 13 00:18:31 2015 +0000

    remove unnecessary key copy
    
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit 2c61a5eccad5085cab916c0959cb4c2fec16f9e5
Author: Dr. Stephen Henson <steve at openssl.org>
Date:   Sun Dec 13 00:11:42 2015 +0000

    Constify EC_KEY in ECDH_compute_key.
    
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit c66ce5eb23f7611bd2822650d6ffeacbe0671072
Author: Dr. Stephen Henson <steve at openssl.org>
Date:   Sat Dec 12 17:41:18 2015 +0000

    Remove ECDH client auth code.
    
    Remove incomplete non-functional ECDH client authentication code.
    
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit 57be4444c645247d15428217e289ae36e5c3e6a8
Author: Dr. Stephen Henson <steve at openssl.org>
Date:   Sat Dec 12 14:00:01 2015 +0000

    Remove SSL_OP_SINGLE_ECDH_USE code.
    
    Since auto ecdh is now always used SSL_OP_SINGLE_ECDH_USE is
    redundant. Simplify associated code.
    
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit cae4136431e7298760cae50732226c64e438d8dd
Author: Dr. Stephen Henson <steve at openssl.org>
Date:   Sat Dec 12 01:13:42 2015 +0000

    Use EC_KEY_key2buf and EC_oct2key in libssl.
    
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit 981bd8a2f28c17f774ecb8b60233858fe52db502
Author: Dr. Stephen Henson <steve at openssl.org>
Date:   Sat Dec 12 01:04:25 2015 +0000

    New EC functions.
    
    New functions EC_POINT_point2buf and EC_KEY_key2buf which encode
    a point and allocate a buffer in one call.
    
    New function EC_KEY_oct2key() which sets public key in an EC_KEY
    structure from an encoded point.
    
    Reviewed-by: Richard Levitte <levitte at openssl.org>

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

Summary of changes:
 crypto/ec/ec_asn1.c      |  10 +-
 crypto/ec/ec_key.c       |  20 ++++
 crypto/ec/ec_kmeth.c     |   6 +-
 crypto/ec/ec_lcl.h       |   4 +-
 crypto/ec/ec_oct.c       |  21 +++++
 crypto/ec/ec_print.c     |  24 +----
 crypto/ec/ecdh_ossl.c    |   2 +-
 include/openssl/ec.h     |  46 ++++++++-
 include/openssl/ssl.h    |   4 +-
 ssl/s3_lib.c             | 102 ++++++++++++++++----
 ssl/ssl_locl.h           |   6 +-
 ssl/statem/statem_clnt.c | 237 ++++++++++-------------------------------------
 ssl/statem/statem_srvr.c | 215 +++++++++---------------------------------
 util/libeay.num          |   3 +
 14 files changed, 284 insertions(+), 416 deletions(-)

diff --git a/crypto/ec/ec_asn1.c b/crypto/ec/ec_asn1.c
index 4206d77..05cdfbf 100644
--- a/crypto/ec/ec_asn1.c
+++ b/crypto/ec/ec_asn1.c
@@ -578,19 +578,11 @@ static ECPARAMETERS *ec_asn1_group2parameters(const EC_GROUP *group,
 
     form = EC_GROUP_get_point_conversion_form(group);
 
-    len = EC_POINT_point2oct(group, point, form, NULL, len, NULL);
+    len = EC_POINT_point2buf(group, point, form, &buffer, NULL);
     if (len == 0) {
         ECerr(EC_F_EC_ASN1_GROUP2PARAMETERS, ERR_R_EC_LIB);
         goto err;
     }
-    if ((buffer = OPENSSL_malloc(len)) == NULL) {
-        ECerr(EC_F_EC_ASN1_GROUP2PARAMETERS, ERR_R_MALLOC_FAILURE);
-        goto err;
-    }
-    if (!EC_POINT_point2oct(group, point, form, buffer, len, NULL)) {
-        ECerr(EC_F_EC_ASN1_GROUP2PARAMETERS, ERR_R_EC_LIB);
-        goto err;
-    }
     if (ret->base == NULL && (ret->base = ASN1_OCTET_STRING_new()) == NULL) {
         ECerr(EC_F_EC_ASN1_GROUP2PARAMETERS, ERR_R_MALLOC_FAILURE);
         goto err;
diff --git a/crypto/ec/ec_key.c b/crypto/ec/ec_key.c
index ac661ed..e2ca142 100644
--- a/crypto/ec/ec_key.c
+++ b/crypto/ec/ec_key.c
@@ -575,3 +575,23 @@ void EC_KEY_clear_flags(EC_KEY *key, int flags)
 {
     key->flags &= ~flags;
 }
+
+size_t EC_KEY_key2buf(const EC_KEY *key, point_conversion_form_t form,
+                        unsigned char **pbuf, BN_CTX *ctx)
+{
+    if (key == NULL || key->pub_key == NULL || key->group == NULL)
+        return 0;
+    return EC_POINT_point2buf(key->group, key->pub_key, form, pbuf, ctx);
+}
+
+int EC_KEY_oct2key(EC_KEY *key, const unsigned char *buf, size_t len,
+                   BN_CTX *ctx)
+{
+    if (key == NULL || key->group == NULL)
+        return 0;
+    if (key->pub_key == NULL)
+        key->pub_key = EC_POINT_new(key->group);
+    if (key->pub_key == NULL)
+        return 0;
+    return EC_POINT_oct2point(key->group, key->pub_key, buf, len, ctx);
+}
diff --git a/crypto/ec/ec_kmeth.c b/crypto/ec/ec_kmeth.c
index e754179..d6c2811 100644
--- a/crypto/ec/ec_kmeth.c
+++ b/crypto/ec/ec_kmeth.c
@@ -134,7 +134,7 @@ EC_KEY *EC_KEY_new_method(ENGINE *engine)
 }
 
 int ECDH_compute_key(void *out, size_t outlen, const EC_POINT *pub_key,
-                     EC_KEY *eckey,
+                     const EC_KEY *eckey,
                      void *(*KDF) (const void *in, size_t inlen, void *out,
                                    size_t *outlen))
 {
@@ -190,7 +190,7 @@ void EC_KEY_METHOD_set_compute_key(EC_KEY_METHOD *meth,
                                    int (*ckey)(void *out,
                                                size_t outlen,
                                                const EC_POINT *pub_key,
-                                               EC_KEY *ecdh,
+                                               const EC_KEY *ecdh,
                                                void *(*KDF) (const void *in,
                                                              size_t inlen,
                                                              void *out,
@@ -268,7 +268,7 @@ void EC_KEY_METHOD_get_compute_key(EC_KEY_METHOD *meth,
                                    int (**pck)(void *out,
                                                size_t outlen,
                                                const EC_POINT *pub_key,
-                                               EC_KEY *ecdh,
+                                               const EC_KEY *ecdh,
                                                void *(*KDF) (const void *in,
                                                              size_t inlen,
                                                              void *out,
diff --git a/crypto/ec/ec_lcl.h b/crypto/ec/ec_lcl.h
index 3cd2345..ebfaae3 100644
--- a/crypto/ec/ec_lcl.h
+++ b/crypto/ec/ec_lcl.h
@@ -568,7 +568,7 @@ struct ec_key_method_st {
     int (*set_public)(EC_KEY *key, const EC_POINT *pub_key);
     int (*keygen)(EC_KEY *key);
     int (*compute_key)(void *out, size_t outlen, const EC_POINT *pub_key,
-                       EC_KEY *ecdh,
+                       const EC_KEY *ecdh,
                        void *(*KDF) (const void *in, size_t inlen,
                                      void *out, size_t *outlen));
 
@@ -591,7 +591,7 @@ struct ec_key_method_st {
 
 int ossl_ec_key_gen(EC_KEY *eckey);
 int ossl_ecdh_compute_key(void *out, size_t outlen, const EC_POINT *pub_key,
-                          EC_KEY *ecdh,
+                          const EC_KEY *ecdh,
                           void *(*KDF) (const void *in, size_t inlen,
                                         void *out, size_t *outlen));
 
diff --git a/crypto/ec/ec_oct.c b/crypto/ec/ec_oct.c
index 040c414..fca50dc 100644
--- a/crypto/ec/ec_oct.c
+++ b/crypto/ec/ec_oct.c
@@ -190,3 +190,24 @@ int EC_POINT_oct2point(const EC_GROUP *group, EC_POINT *point,
     }
     return group->meth->oct2point(group, point, buf, len, ctx);
 }
+
+size_t EC_POINT_point2buf(const EC_GROUP *group, const EC_POINT *point,
+                          point_conversion_form_t form,
+                          unsigned char **pbuf, BN_CTX *ctx)
+{
+    size_t len;
+    unsigned char *buf;
+    len = EC_POINT_point2oct(group, point, form, NULL, 0, NULL);
+    if (len == 0)
+        return 0;
+    buf = OPENSSL_malloc(len);
+    if (buf == NULL)
+        return 0;
+    len = EC_POINT_point2oct(group, point, form, buf, len, ctx);
+    if (len == 0) {
+        OPENSSL_free(buf);
+        return 0;
+    }
+    *pbuf = buf;
+    return len;
+}
diff --git a/crypto/ec/ec_print.c b/crypto/ec/ec_print.c
index 5ae85cc..7bc0760 100644
--- a/crypto/ec/ec_print.c
+++ b/crypto/ec/ec_print.c
@@ -64,17 +64,10 @@ BIGNUM *EC_POINT_point2bn(const EC_GROUP *group,
     size_t buf_len = 0;
     unsigned char *buf;
 
-    buf_len = EC_POINT_point2oct(group, point, form, NULL, 0, ctx);
-    if (buf_len == 0)
-        return NULL;
-
-    if ((buf = OPENSSL_malloc(buf_len)) == NULL)
-        return NULL;
+    buf_len = EC_POINT_point2buf(group, point, form, &buf, ctx);
 
-    if (!EC_POINT_point2oct(group, point, form, buf, buf_len, ctx)) {
-        OPENSSL_free(buf);
+    if (buf_len == 0)
         return NULL;
-    }
 
     ret = BN_bin2bn(buf, buf_len, ret);
 
@@ -129,19 +122,12 @@ char *EC_POINT_point2hex(const EC_GROUP *group,
 {
     char *ret, *p;
     size_t buf_len = 0, i;
-    unsigned char *buf, *pbuf;
+    unsigned char *buf = NULL, *pbuf;
 
-    buf_len = EC_POINT_point2oct(group, point, form, NULL, 0, ctx);
-    if (buf_len == 0)
-        return NULL;
-
-    if ((buf = OPENSSL_malloc(buf_len)) == NULL)
-        return NULL;
+    buf_len = EC_POINT_point2buf(group, point, form, &buf, ctx);
 
-    if (!EC_POINT_point2oct(group, point, form, buf, buf_len, ctx)) {
-        OPENSSL_free(buf);
+    if (buf_len == 0)
         return NULL;
-    }
 
     ret = OPENSSL_malloc(buf_len * 2 + 2);
     if (ret == NULL) {
diff --git a/crypto/ec/ecdh_ossl.c b/crypto/ec/ecdh_ossl.c
index 94339e4..b7f09eb 100644
--- a/crypto/ec/ecdh_ossl.c
+++ b/crypto/ec/ecdh_ossl.c
@@ -85,7 +85,7 @@
  * Finally an optional KDF is applied.
  */
 int ossl_ecdh_compute_key(void *out, size_t outlen, const EC_POINT *pub_key,
-                          EC_KEY *ecdh,
+                          const EC_KEY *ecdh,
                           void *(*KDF) (const void *in, size_t inlen,
                                         void *out, size_t *outlen))
 {
diff --git a/include/openssl/ec.h b/include/openssl/ec.h
index a7793b8..1dc2db1 100644
--- a/include/openssl/ec.h
+++ b/include/openssl/ec.h
@@ -589,6 +589,20 @@ size_t EC_POINT_point2oct(const EC_GROUP *group, const EC_POINT *p,
 int EC_POINT_oct2point(const EC_GROUP *group, EC_POINT *p,
                        const unsigned char *buf, size_t len, BN_CTX *ctx);
 
+/** Encodes an EC_POINT object to an allocated octet string
+ *  \param  group  underlying EC_GROUP object
+ *  \param  point  EC_POINT object
+ *  \param  form   point conversion form
+ *  \param  pbuf   returns pointer to allocated buffer
+ *  \param  len    length of the memory buffer
+ *  \param  ctx    BN_CTX object (optional)
+ *  \return the length of the encoded octet string or 0 if an error occurred
+ */
+
+size_t EC_POINT_point2buf(const EC_GROUP *group, const EC_POINT *point,
+                          point_conversion_form_t form,
+                          unsigned char **pbuf, BN_CTX *ctx);
+
 /* other interfaces to point2oct/oct2point: */
 BIGNUM *EC_POINT_point2bn(const EC_GROUP *, const EC_POINT *,
                           point_conversion_form_t form, BIGNUM *, BN_CTX *);
@@ -887,6 +901,29 @@ int EC_KEY_check_key(const EC_KEY *key);
 int EC_KEY_set_public_key_affine_coordinates(EC_KEY *key, BIGNUM *x,
                                              BIGNUM *y);
 
+/** Encodes an EC_KEY public key to an allocated octet string
+ *  \param  key    key to encode
+ *  \param  form   point conversion form
+ *  \param  pbuf   returns pointer to allocated buffer
+ *  \param  len    length of the memory buffer
+ *  \param  ctx    BN_CTX object (optional)
+ *  \return the length of the encoded octet string or 0 if an error occurred
+ */
+
+size_t EC_KEY_key2buf(const EC_KEY *key, point_conversion_form_t form,
+                      unsigned char **pbuf, BN_CTX *ctx);
+
+/** Decodes a EC_KEY public key from a octet string
+ *  \param  key    key to decode
+ *  \param  buf    memory buffer with the encoded ec point
+ *  \param  len    length of the encoded ec point
+ *  \param  ctx    BN_CTX object (optional)
+ *  \return 1 on success and 0 if an error occurred
+ */
+
+int EC_KEY_oct2key(EC_KEY *key, const unsigned char *buf, size_t len,
+                   BN_CTX *ctx);
+
 /********************************************************************/
 /*        de- and encoding functions for SEC1 ECPrivateKey          */
 /********************************************************************/
@@ -994,8 +1031,9 @@ int ECDH_KDF_X9_62(unsigned char *out, size_t outlen,
                    const EVP_MD *md);
 
 int ECDH_compute_key(void *out, size_t outlen, const EC_POINT *pub_key,
-                     EC_KEY *ecdh, void *(*KDF) (const void *in, size_t inlen,
-                                                 void *out, size_t *outlen));
+                     const EC_KEY *ecdh,
+                     void *(*KDF) (const void *in, size_t inlen,
+                                   void *out, size_t *outlen));
 
 typedef struct ECDSA_SIG_st ECDSA_SIG;
 
@@ -1151,7 +1189,7 @@ void EC_KEY_METHOD_set_compute_key(EC_KEY_METHOD *meth,
                                    int (*ckey)(void *out,
                                                size_t outlen,
                                                const EC_POINT *pub_key,
-                                               EC_KEY *ecdh,
+                                               const EC_KEY *ecdh,
                                                void *(*KDF) (const void *in,
                                                              size_t inlen,
                                                              void *out,
@@ -1199,7 +1237,7 @@ void EC_KEY_METHOD_get_compute_key(EC_KEY_METHOD *meth,
                                    int (**pck)(void *out,
                                                size_t outlen,
                                                const EC_POINT *pub_key,
-                                               EC_KEY *ecdh,
+                                               const EC_KEY *ecdh,
                                                void *(*KDF) (const void *in,
                                                              size_t inlen,
                                                              void *out,
diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h
index 04ce444..d6d05ae 100644
--- a/include/openssl/ssl.h
+++ b/include/openssl/ssl.h
@@ -409,8 +409,8 @@ typedef int (*custom_ext_parse_cb) (SSL *s, unsigned int ext_type,
 # define SSL_OP_NO_COMPRESSION                           0x00020000U
 /* Permit unsafe legacy renegotiation */
 # define SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION        0x00040000U
-/* If set, always create a new key when using tmp_ecdh parameters */
-# define SSL_OP_SINGLE_ECDH_USE                          0x00080000U
+/* Does nothing: retained for compatibility */
+# define SSL_OP_SINGLE_ECDH_USE                          0x0
 /* If set, always create a new key when using tmp_dh parameters */
 # define SSL_OP_SINGLE_DH_USE                            0x00100000U
 /* Does nothing: retained for compatibiity */
diff --git a/ssl/s3_lib.c b/ssl/s3_lib.c
index c08065f..465ed1e 100644
--- a/ssl/s3_lib.c
+++ b/ssl/s3_lib.c
@@ -3760,8 +3760,10 @@ void ssl3_free(SSL *s)
     DH_free(s->s3->peer_dh_tmp);
 #endif
 #ifndef OPENSSL_NO_EC
-    EC_KEY_free(s->s3->tmp.ecdh);
-    EC_KEY_free(s->s3->peer_ecdh_tmp);
+    EVP_PKEY_free(s->s3->tmp.pkey);
+    s->s3->tmp.pkey = NULL;
+    EVP_PKEY_free(s->s3->peer_tmp);
+    s->s3->peer_tmp = NULL;
 #endif
 
     sk_X509_NAME_pop_free(s->s3->tmp.ca_names, X509_NAME_free);
@@ -3798,10 +3800,10 @@ void ssl3_clear(SSL *s)
     s->s3->peer_dh_tmp = NULL;
 #endif
 #ifndef OPENSSL_NO_EC
-    EC_KEY_free(s->s3->tmp.ecdh);
-    s->s3->tmp.ecdh = NULL;
-    EC_KEY_free(s->s3->peer_ecdh_tmp);
-    s->s3->peer_ecdh_tmp = NULL;
+    EVP_PKEY_free(s->s3->tmp.pkey);
+    s->s3->tmp.pkey = NULL;
+    EVP_PKEY_free(s->s3->peer_tmp);
+    s->s3->peer_tmp = NULL;
     s->s3->is_probably_safari = 0;
 #endif                         /* !OPENSSL_NO_EC */
 
@@ -4154,19 +4156,20 @@ long ssl3_ctrl(SSL *s, int cmd, long larg, void *parg)
             EVP_PKEY *ptmp;
             int rv = 0;
 #if !defined(OPENSSL_NO_DH) && !defined(OPENSSL_NO_EC)
-            if (!s->s3->peer_dh_tmp && !s->s3->peer_ecdh_tmp)
+            if (s->s3->peer_dh_tmp == NULL && s->s3->peer_tmp == NULL)
                 return 0;
 #endif
             ptmp = EVP_PKEY_new();
             if (ptmp == NULL)
                 return 0;
 #ifndef OPENSSL_NO_DH
-            else if (s->s3->peer_dh_tmp)
+            else if (s->s3->peer_dh_tmp != NULL)
                 rv = EVP_PKEY_set1_DH(ptmp, s->s3->peer_dh_tmp);
 #endif
 #ifndef OPENSSL_NO_EC
-            else if (s->s3->peer_ecdh_tmp)
-                rv = EVP_PKEY_set1_EC_KEY(ptmp, s->s3->peer_ecdh_tmp);
+            else if (s->s3->peer_tmp != NULL)
+                rv = EVP_PKEY_set1_EC_KEY(ptmp,
+                                          EVP_PKEY_get0_EC_KEY(s->s3->peer_tmp));
 #endif
             if (rv) {
                 *(EVP_PKEY **)parg = ptmp;
@@ -4722,14 +4725,8 @@ int ssl3_get_req_cert_type(SSL *s, unsigned char *p)
         p[ret++] = SSL3_CT_DSS_SIGN;
 #endif
 #ifndef OPENSSL_NO_EC
-    if ((alg_k & (SSL_kECDHr | SSL_kECDHe)) && (s->version >= TLS1_VERSION)) {
-        if (nostrict || !(alg_a & SSL_aRSA))
-            p[ret++] = TLS_CT_RSA_FIXED_ECDH;
-        if (nostrict || !(alg_a & SSL_aECDSA))
-            p[ret++] = TLS_CT_ECDSA_FIXED_ECDH;
-    }
     /*
-     * ECDSA certs can be used with RSA cipher suites as well so we don't
+     * ECDSA certs can be used with RSA cipher suites too so we don't
      * need to check for SSL_kECDH or SSL_kECDHE
      */
     if (s->version >= TLS1_VERSION) {
@@ -4991,3 +4988,74 @@ int ssl_generate_master_secret(SSL *s, unsigned char *pms, size_t pmslen,
         s->s3->tmp.pms = NULL;
     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)
+{
+    EVP_PKEY_CTX *pctx = NULL;
+    EVP_PKEY *pkey = NULL;
+    if (pm != NULL) {
+        pctx = EVP_PKEY_CTX_new(pm, NULL);
+    } else {
+        /* Generate a new key for this curve */
+        pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL);
+    }
+    if (pctx == NULL)
+        goto err;
+    if (EVP_PKEY_keygen_init(pctx) <= 0)
+        goto err;
+    if (pm == NULL && EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, nid) <= 0)
+        goto err;
+
+    if (EVP_PKEY_keygen(pctx, &pkey) <= 0) {
+        EVP_PKEY_free(pkey);
+        pkey = NULL;
+    }
+
+    err:
+    EVP_PKEY_CTX_free(pctx);
+    return pkey;
+}
+/* Derive premaster or master secret for ECDH/DH */
+int ssl_derive(SSL *s, EVP_PKEY *privkey, EVP_PKEY *pubkey)
+{
+    int rv = 0;
+    unsigned char *pms = NULL;
+    size_t pmslen = 0;
+    EVP_PKEY_CTX *pctx;
+
+    if (privkey == NULL || pubkey == NULL)
+        return 0;
+
+    pctx = EVP_PKEY_CTX_new(privkey, NULL);
+
+    if (EVP_PKEY_derive_init(pctx) <= 0
+        || EVP_PKEY_derive_set_peer(pctx, pubkey) <= 0
+        || EVP_PKEY_derive(pctx, NULL, &pmslen) <= 0) {
+        goto err;
+    }
+
+    pms = OPENSSL_malloc(pmslen);
+    if (pms == NULL)
+        goto err;
+
+    if (EVP_PKEY_derive(pctx, pms, &pmslen) <= 0)
+        goto err;
+
+    if (s->server) {
+        /* For server generate master secret and discard premaster */
+        rv = ssl_generate_master_secret(s, pms, pmslen, 1);
+        pms = NULL;
+    } else {
+        /* For client just save premaster secret */
+        s->s3->tmp.pms = pms;
+        s->s3->tmp.pmslen = pmslen;
+        pms = NULL;
+        rv = 1;
+    }
+
+    err:
+    OPENSSL_clear_free(pms, pmslen);
+    EVP_PKEY_CTX_free(pctx);
+    return rv;
+}
diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h
index b161387..7a16f00 100644
--- a/ssl/ssl_locl.h
+++ b/ssl/ssl_locl.h
@@ -1241,7 +1241,7 @@ typedef struct ssl3_state_st {
         DH *dh;
 #  endif
 #  ifndef OPENSSL_NO_EC
-        EC_KEY *ecdh;           /* holds short lived ECDH key */
+        EVP_PKEY *pkey;            /* holds short lived ECDH key */
 #  endif
         /* used for certificate requests */
         int cert_req;
@@ -1341,7 +1341,7 @@ typedef struct ssl3_state_st {
     DH *peer_dh_tmp;
 # endif
 # ifndef OPENSSL_NO_EC
-    EC_KEY *peer_ecdh_tmp;
+    EVP_PKEY *peer_tmp;
 # endif
 
 } SSL3_STATE;
@@ -1870,6 +1870,8 @@ void ssl_load_ciphers(void);
 __owur int ssl_fill_hello_random(SSL *s, int server, unsigned char *field, int len);
 __owur int ssl_generate_master_secret(SSL *s, unsigned char *pms, size_t pmslen,
                                       int free_pms);
+__owur EVP_PKEY *ssl_generate_pkey(EVP_PKEY *pm, int nid);
+__owur int ssl_derive(SSL *s, EVP_PKEY *privkey, EVP_PKEY *pubkey);
 
 __owur const SSL_CIPHER *ssl3_get_cipher_by_char(const unsigned char *p);
 __owur int ssl3_put_cipher_by_char(const SSL_CIPHER *c, unsigned char *p);
diff --git a/ssl/statem/statem_clnt.c b/ssl/statem/statem_clnt.c
index 633e677..2c2a521 100644
--- a/ssl/statem/statem_clnt.c
+++ b/ssl/statem/statem_clnt.c
@@ -1585,10 +1585,7 @@ MSG_PROCESS_RETURN tls_process_key_exchange(SSL *s, PACKET *pkt)
     DH *dh = NULL;
 #endif
 #ifndef OPENSSL_NO_EC
-    EC_KEY *ecdh = NULL;
-    BN_CTX *bn_ctx = NULL;
-    EC_POINT *srvr_ecpoint = NULL;
-    int curve_nid = 0;
+    EVP_PKEY_CTX *pctx = NULL;
 #endif
     PACKET save_param_start, signature;
 
@@ -1608,8 +1605,8 @@ MSG_PROCESS_RETURN tls_process_key_exchange(SSL *s, PACKET *pkt)
     s->s3->peer_dh_tmp = NULL;
 #endif
 #ifndef OPENSSL_NO_EC
-    EC_KEY_free(s->s3->peer_ecdh_tmp);
-    s->s3->peer_ecdh_tmp = NULL;
+    EVP_PKEY_free(s->s3->peer_tmp);
+    s->s3->peer_tmp = NULL;
 #endif
 
     alg_a = s->s3->tmp.new_cipher->algorithm_auth;
@@ -1742,15 +1739,9 @@ MSG_PROCESS_RETURN tls_process_key_exchange(SSL *s, PACKET *pkt)
 
 #ifndef OPENSSL_NO_EC
     else if (alg_k & (SSL_kECDHE | SSL_kECDHEPSK)) {
-        EC_GROUP *ngroup;
-        const EC_GROUP *group;
         PACKET encoded_pt;
         unsigned char *ecparams;
-
-        if ((ecdh = EC_KEY_new()) == NULL) {
-            SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, ERR_R_MALLOC_FAILURE);
-            goto err;
-        }
+        int curve_nid;
 
         /*
          * Extract elliptic curve parameters and the server's ephemeral ECDH
@@ -1770,40 +1761,35 @@ MSG_PROCESS_RETURN tls_process_key_exchange(SSL *s, PACKET *pkt)
             goto f_err;
         }
 
-        if ((curve_nid = tls1_ec_curve_id2nid(*(ecparams + 2))) == 0) {
+        curve_nid = tls1_ec_curve_id2nid(*(ecparams + 2));
+        if (curve_nid  == 0) {
             al = SSL_AD_INTERNAL_ERROR;
             SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE,
                    SSL_R_UNABLE_TO_FIND_ECDH_PARAMETERS);
             goto f_err;
         }
 
-        ngroup = EC_GROUP_new_by_curve_name(curve_nid);
-        if (ngroup == NULL) {
-            SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, ERR_R_EC_LIB);
-            goto err;
-        }
-        if (EC_KEY_set_group(ecdh, ngroup) == 0) {
-            SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, ERR_R_EC_LIB);
-            goto err;
-        }
-        EC_GROUP_free(ngroup);
-
-        group = EC_KEY_get0_group(ecdh);
-
-        /* Next, get the encoded ECPoint */
-        if (((srvr_ecpoint = EC_POINT_new(group)) == NULL) ||
-            ((bn_ctx = BN_CTX_new()) == NULL)) {
-            SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, ERR_R_MALLOC_FAILURE);
-            goto err;
+        /* 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_KEY_EXCHANGE, ERR_R_EVP_LIB);
+            goto f_err;
         }
+        EVP_PKEY_CTX_free(pctx);
+        pctx = NULL;
 
         if (!PACKET_get_length_prefixed_1(pkt, &encoded_pt)) {
             SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, SSL_R_LENGTH_MISMATCH);
             goto f_err;
         }
 
-        if (EC_POINT_oct2point(group, srvr_ecpoint, PACKET_data(&encoded_pt),
-                               PACKET_remaining(&encoded_pt), bn_ctx) == 0) {
+        if (EC_KEY_oct2key(EVP_PKEY_get0_EC_KEY(s->s3->peer_tmp),
+                           PACKET_data(&encoded_pt),
+                           PACKET_remaining(&encoded_pt), NULL) == 0) {
             SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, SSL_R_BAD_ECPOINT);
             goto f_err;
         }
@@ -1823,13 +1809,6 @@ MSG_PROCESS_RETURN tls_process_key_exchange(SSL *s, PACKET *pkt)
             pkey = X509_get_pubkey(s->session->peer);
 # endif
         /* else anonymous ECDH, so no certificate or pkey. */
-        EC_KEY_set_public_key(ecdh, srvr_ecpoint);
-        s->s3->peer_ecdh_tmp = ecdh;
-        ecdh = NULL;
-        BN_CTX_free(bn_ctx);
-        bn_ctx = NULL;
-        EC_POINT_free(srvr_ecpoint);
-        srvr_ecpoint = NULL;
     } else if (alg_k) {
         al = SSL_AD_UNEXPECTED_MESSAGE;
         SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, SSL_R_UNEXPECTED_MESSAGE);
@@ -1940,9 +1919,7 @@ MSG_PROCESS_RETURN tls_process_key_exchange(SSL *s, PACKET *pkt)
     DH_free(dh);
 #endif
 #ifndef OPENSSL_NO_EC
-    BN_CTX_free(bn_ctx);
-    EC_POINT_free(srvr_ecpoint);
-    EC_KEY_free(ecdh);
+    EVP_PKEY_CTX_free(pctx);
 #endif
     EVP_MD_CTX_free(md_ctx);
     ossl_statem_set_error(s);
@@ -2267,12 +2244,9 @@ int tls_construct_client_key_exchange(SSL *s)
     EVP_PKEY *pkey = NULL;
 #endif
 #ifndef OPENSSL_NO_EC
-    EC_KEY *clnt_ecdh = NULL;
-    const EC_POINT *srvr_ecpoint = NULL;
-    EVP_PKEY *srvr_pub_pkey = NULL;
+    EVP_PKEY *ckey = NULL, *skey = NULL;
     unsigned char *encodedPoint = NULL;
     int encoded_pt_len = 0;
-    BN_CTX *bn_ctx = NULL;
 #endif
     unsigned char *pms = NULL;
     size_t pmslen = 0;
@@ -2498,162 +2472,53 @@ psk_err:
 
 #ifndef OPENSSL_NO_EC
     else if (alg_k & (SSL_kECDHE | SSL_kECDHr | SSL_kECDHe | SSL_kECDHEPSK)) {
-        const EC_GROUP *srvr_group = NULL;
-        EC_KEY *tkey;
-        int ecdh_clnt_cert = 0;
-        int field_size = 0;
-        /*
-         * Did we send out the client's ECDH share for use in premaster
-         * computation as part of client certificate? If so, set
-         * ecdh_clnt_cert to 1.
-         */
-        if ((alg_k & (SSL_kECDHr | SSL_kECDHe)) && (s->cert != NULL)) {
-            /*-
-             * XXX: For now, we do not support client
-             * authentication using ECDH certificates.
-             * To add such support, one needs to add
-             * code that checks for appropriate
-             * conditions and sets ecdh_clnt_cert to 1.
-             * For example, the cert have an ECC
-             * key on the same curve as the server's
-             * and the key should be authorized for
-             * key agreement.
-             *
-             * One also needs to add code in ssl3_connect
-             * to skip sending the certificate verify
-             * message.
-             *
-             * if ((s->cert->key->privatekey != NULL) &&
-             *     (s->cert->key->privatekey->type ==
-             *      EVP_PKEY_EC) && ...)
-             * ecdh_clnt_cert = 1;
-             */
-        }
 
-        if (s->s3->peer_ecdh_tmp != NULL) {
-            tkey = s->s3->peer_ecdh_tmp;
+        if (s->s3->peer_tmp != NULL) {
+            skey = s->s3->peer_tmp;
         } else {
             /* Get the Server Public Key from Cert */
-            srvr_pub_pkey = X509_get_pubkey(s->session->peer);
-            if ((srvr_pub_pkey == NULL)
-                || (srvr_pub_pkey->type != EVP_PKEY_EC)
-                || (srvr_pub_pkey->pkey.ec == NULL)) {
+            skey = X509_get0_pubkey(s->session->peer);
+            if ((skey == NULL)
+                || (skey->type != EVP_PKEY_EC)
+                || (skey->pkey.ec == NULL)) {
                 SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE,
                        ERR_R_INTERNAL_ERROR);
                 goto err;
             }
-
-            tkey = srvr_pub_pkey->pkey.ec;
         }
 
-        srvr_group = EC_KEY_get0_group(tkey);
-        srvr_ecpoint = EC_KEY_get0_public_key(tkey);
+        ckey = ssl_generate_pkey(skey, NID_undef);
 
-        if ((srvr_group == NULL) || (srvr_ecpoint == NULL)) {
-            SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE,
-                   ERR_R_INTERNAL_ERROR);
+        if (ssl_derive(s, ckey, skey) == 0) {
+            SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE, ERR_R_EVP_LIB);
             goto err;
         }
 
-        if ((clnt_ecdh = EC_KEY_new()) == NULL) {
-            SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE,
-                   ERR_R_MALLOC_FAILURE);
-            goto err;
-        }
+        /* Generate encoding of client key */
+        encoded_pt_len = EC_KEY_key2buf(EVP_PKEY_get0_EC_KEY(ckey),
+                                        POINT_CONVERSION_UNCOMPRESSED,
+                                        &encodedPoint, NULL);
 
-        if (!EC_KEY_set_group(clnt_ecdh, srvr_group)) {
+        if (encoded_pt_len == 0) {
             SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE, ERR_R_EC_LIB);
             goto err;
         }
-        if (ecdh_clnt_cert) {
-            /*
-             * Reuse key info from our certificate We only need our
-             * private key to perform the ECDH computation.
-             */
-            const BIGNUM *priv_key;
-            tkey = s->cert->key->privatekey->pkey.ec;
-            priv_key = EC_KEY_get0_private_key(tkey);
-            if (priv_key == NULL) {
-                SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE,
-                       ERR_R_MALLOC_FAILURE);
-                goto err;
-            }
-            if (!EC_KEY_set_private_key(clnt_ecdh, priv_key)) {
-                SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE, ERR_R_EC_LIB);
-                goto err;
-            }
-        } else {
-            /* Generate a new ECDH key pair */
-            if (!(EC_KEY_generate_key(clnt_ecdh))) {
-                SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE,
-                       ERR_R_ECDH_LIB);
-                goto err;
-            }
-        }
-
-        /*
-         * use the 'p' output buffer for the ECDH key, but make sure to
-         * clear it out afterwards
-         */
-
-        field_size = EC_GROUP_get_degree(srvr_group);
-        if (field_size <= 0) {
-            SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE, ERR_R_ECDH_LIB);
-            goto err;
-        }
-        pmslen = (field_size + 7) / 8;
-        pms = OPENSSL_malloc(pmslen);
-        if (pms == NULL)
-            goto memerr;
-        n = ECDH_compute_key(pms, pmslen, srvr_ecpoint, clnt_ecdh, NULL);
-        if (n <= 0 || pmslen != (size_t)n) {
-            SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE, ERR_R_ECDH_LIB);
-            goto err;
-        }
 
-        if (ecdh_clnt_cert) {
-            /* Send empty client key exch message */
-            n = 0;
-        } else {
-            /*
-             * First check the size of encoding and allocate memory
-             * accordingly.
-             */
-            encoded_pt_len =
-                EC_POINT_point2oct(srvr_group,
-                                   EC_KEY_get0_public_key(clnt_ecdh),
-                                   POINT_CONVERSION_UNCOMPRESSED,
-                                   NULL, 0, NULL);
-
-            encodedPoint = (unsigned char *)
-                OPENSSL_malloc(encoded_pt_len * sizeof(unsigned char));
-            bn_ctx = BN_CTX_new();
-            if ((encodedPoint == NULL) || (bn_ctx == NULL)) {
-                SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE,
-                       ERR_R_MALLOC_FAILURE);
-                goto err;
-            }
+        EVP_PKEY_free(ckey);
+        ckey = NULL;
 
-            /* Encode the public key */
-            n = EC_POINT_point2oct(srvr_group,
-                                   EC_KEY_get0_public_key(clnt_ecdh),
-                                   POINT_CONVERSION_UNCOMPRESSED,
-                                   encodedPoint, encoded_pt_len, bn_ctx);
+        n = encoded_pt_len;
 
-            *p = n;         /* length of encoded point */
-            /* Encoded point will be copied here */
-            p += 1;
-            /* copy the point */
-            memcpy(p, encodedPoint, n);
-            /* increment n to account for length field */
-            n += 1;
-        }
+        *p = n;         /* length of encoded point */
+        /* Encoded point will be copied here */
+        p += 1;
+        /* copy the point */
+        memcpy(p, encodedPoint, n);
+        /* increment n to account for length field */
+        n += 1;
 
         /* Free allocated memory */
-        BN_CTX_free(bn_ctx);
         OPENSSL_free(encodedPoint);
-        EC_KEY_free(clnt_ecdh);
-        EVP_PKEY_free(srvr_pub_pkey);
     }
 #endif                          /* !OPENSSL_NO_EC */
 #ifndef OPENSSL_NO_GOST
@@ -2817,8 +2682,10 @@ psk_err:
         goto err;
     }
 
-    s->s3->tmp.pms = pms;
-    s->s3->tmp.pmslen = pmslen;
+    if (pms != NULL) {
+        s->s3->tmp.pms = pms;
+        s->s3->tmp.pmslen = pmslen;
+    }
 
     return 1;
  memerr:
@@ -2828,10 +2695,8 @@ psk_err:
     OPENSSL_clear_free(pms, pmslen);
     s->s3->tmp.pms = NULL;
 #ifndef OPENSSL_NO_EC
-    BN_CTX_free(bn_ctx);
     OPENSSL_free(encodedPoint);
-    EC_KEY_free(clnt_ecdh);
-    EVP_PKEY_free(srvr_pub_pkey);
+    EVP_PKEY_free(ckey);
 #endif
 #ifndef OPENSSL_NO_PSK
     OPENSSL_clear_free(s->s3->tmp.psk, s->s3->tmp.psklen);
diff --git a/ssl/statem/statem_srvr.c b/ssl/statem/statem_srvr.c
index 1307816..f4c5e8c 100644
--- a/ssl/statem/statem_srvr.c
+++ b/ssl/statem/statem_srvr.c
@@ -1721,7 +1721,6 @@ int tls_construct_server_key_exchange(SSL *s)
     unsigned char *encodedPoint = NULL;
     int encodedlen = 0;
     int curve_id = 0;
-    BN_CTX *bn_ctx = NULL;
 #endif
     EVP_PKEY *pkey;
     const EVP_MD *md = NULL;
@@ -1824,93 +1823,44 @@ int tls_construct_server_key_exchange(SSL *s)
 #endif
 #ifndef OPENSSL_NO_EC
     if (type & (SSL_kECDHE | SSL_kECDHEPSK)) {
-        const EC_GROUP *group;
-        EC_KEY *ecdh = NULL;
+        int nid;
 
-        /* Get NID of appropriate shared curve */
-        int nid = tls1_shared_curve(s, -2);
-        if (nid != NID_undef)
-            ecdh = EC_KEY_new_by_curve_name(nid);
-        if (ecdh == NULL) {
-            al = SSL_AD_HANDSHAKE_FAILURE;
-            SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE,
-                   SSL_R_MISSING_TMP_ECDH_KEY);
-            goto f_err;
-        }
-
-        if (s->s3->tmp.ecdh != NULL) {
+        if (s->s3->tmp.pkey != NULL) {
             SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE,
                    ERR_R_INTERNAL_ERROR);
             goto err;
         }
 
-        s->s3->tmp.ecdh = ecdh;
-        if ((EC_KEY_get0_public_key(ecdh) == NULL) ||
-            (EC_KEY_get0_private_key(ecdh) == NULL) ||
-            (s->options & SSL_OP_SINGLE_ECDH_USE)) {
-            if (!EC_KEY_generate_key(ecdh)) {
-                SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE,
-                       ERR_R_ECDH_LIB);
-                goto err;
-            }
-        }
-
-        if (((group = EC_KEY_get0_group(ecdh)) == NULL) ||
-            (EC_KEY_get0_public_key(ecdh) == NULL) ||
-            (EC_KEY_get0_private_key(ecdh) == NULL)) {
-            SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE, ERR_R_ECDH_LIB);
-            goto err;
-        }
-
-        /*
-         * XXX: For now, we only support ephemeral ECDH keys over named
-         * (not generic) curves. For supported named curves, curve_id is
-         * non-zero.
-         */
-        if ((curve_id =
-             tls1_ec_nid2curve_id(EC_GROUP_get_curve_name(group)))
-            == 0) {
+        /* Get NID of appropriate shared curve */
+        nid = tls1_shared_curve(s, -2);
+        curve_id = tls1_ec_nid2curve_id(nid);
+        if (curve_id == 0) {
             SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE,
                    SSL_R_UNSUPPORTED_ELLIPTIC_CURVE);
             goto err;
         }
-
-        /*
-         * Encode the public key. First check the size of encoding and
-         * allocate memory accordingly.
-         */
-        encodedlen = EC_POINT_point2oct(group,
-                                        EC_KEY_get0_public_key(ecdh),
-                                        POINT_CONVERSION_UNCOMPRESSED,
-                                        NULL, 0, NULL);
-
-        encodedPoint = (unsigned char *)
-            OPENSSL_malloc(encodedlen * sizeof(unsigned char));
-        bn_ctx = BN_CTX_new();
-        if ((encodedPoint == NULL) || (bn_ctx == NULL)) {
-            SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE,
-                   ERR_R_MALLOC_FAILURE);
-            goto err;
+        s->s3->tmp.pkey = ssl_generate_pkey(NULL, nid);
+        /* Generate a new key for this curve */
+        if (s->s3->tmp.pkey == NULL) {
+            al = SSL_AD_INTERNAL_ERROR;
+            SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE, ERR_R_EVP_LIB);
+            goto f_err;
         }
 
-        encodedlen = EC_POINT_point2oct(group,
-                                        EC_KEY_get0_public_key(ecdh),
-                                        POINT_CONVERSION_UNCOMPRESSED,
-                                        encodedPoint, encodedlen, bn_ctx);
+        /* Encode the public key. */
+        encodedlen = EC_KEY_key2buf(EVP_PKEY_get0_EC_KEY(s->s3->tmp.pkey),
+                                    POINT_CONVERSION_UNCOMPRESSED,
+                                    &encodedPoint, NULL);
 
         if (encodedlen == 0) {
-            SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE, ERR_R_ECDH_LIB);
+            SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE, ERR_R_EC_LIB);
             goto err;
         }
 
-        BN_CTX_free(bn_ctx);
-        bn_ctx = NULL;
-
         /*
-         * XXX: For now, we only support named (not generic) curves in
-         * ECDH ephemeral key exchanges. In this situation, we need four
-         * additional bytes to encode the entire ServerECDHParams
-         * structure.
+         * We only support named (not generic) curves in ECDH ephemeral key
+         * exchanges. In this situation, we need four additional bytes to
+         * encode the entire ServerECDHParams structure.
          */
         n += 4 + encodedlen;
 
@@ -2082,7 +2032,6 @@ int tls_construct_server_key_exchange(SSL *s)
  err:
 #ifndef OPENSSL_NO_EC
     OPENSSL_free(encodedPoint);
-    BN_CTX_free(bn_ctx);
 #endif
     EVP_MD_CTX_free(md_ctx);
     ossl_statem_set_error(s);
@@ -2175,10 +2124,8 @@ MSG_PROCESS_RETURN tls_process_client_key_exchange(SSL *s, PACKET *pkt)
     DH *dh_srvr, *dh_clnt = NULL;
 #endif
 #ifndef OPENSSL_NO_EC
-    EC_KEY *srvr_ecdh = NULL;
-    EVP_PKEY *clnt_pub_pkey = NULL;
-    EC_POINT *clnt_ecpoint = NULL;
-    BN_CTX *bn_ctx = NULL;
+    EVP_PKEY *ckey = NULL;
+    EVP_PKEY_CTX *pctx = NULL;
 #endif
     PACKET enc_premaster;
     unsigned char *data, *rsa_decrypt = NULL;
@@ -2505,87 +2452,31 @@ MSG_PROCESS_RETURN tls_process_client_key_exchange(SSL *s, PACKET *pkt)
 
 #ifndef OPENSSL_NO_EC
     if (alg_k & (SSL_kECDHE | SSL_kECDHr | SSL_kECDHe | SSL_kECDHEPSK)) {
-        int field_size = 0;
-        const EC_KEY *tkey;
-        const EC_GROUP *group;
-        const BIGNUM *priv_key;
-        unsigned char *shared;
-
-        /* initialize structures for server's ECDH key pair */
-        if ((srvr_ecdh = EC_KEY_new()) == NULL) {
-            SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE, ERR_R_MALLOC_FAILURE);
-            goto err;
-        }
+        EVP_PKEY *skey = NULL;
 
         /* Let's get server private key and group information */
         if (alg_k & (SSL_kECDHr | SSL_kECDHe)) {
             /* use the certificate */
-            tkey = s->cert->pkeys[SSL_PKEY_ECC].privatekey->pkey.ec;
+            skey = s->cert->pkeys[SSL_PKEY_ECC].privatekey;
         } else {
             /*
              * use the ephermeral values we saved when generating the
              * ServerKeyExchange msg.
              */
-            tkey = s->s3->tmp.ecdh;
-        }
-
-        group = EC_KEY_get0_group(tkey);
-        priv_key = EC_KEY_get0_private_key(tkey);
-
-        if (!EC_KEY_set_group(srvr_ecdh, group) ||
-            !EC_KEY_set_private_key(srvr_ecdh, priv_key)) {
-            SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE, ERR_R_EC_LIB);
-            goto err;
-        }
-
-        /* Let's get client's public key */
-        if ((clnt_ecpoint = EC_POINT_new(group)) == NULL) {
-            SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE, ERR_R_MALLOC_FAILURE);
-            goto err;
+            skey = s->s3->tmp.pkey;
         }
 
         if (PACKET_remaining(pkt) == 0L) {
-            /* Client Publickey was in Client Certificate */
-
-            if (alg_k & (SSL_kECDHE | SSL_kECDHEPSK)) {
-                al = SSL_AD_HANDSHAKE_FAILURE;
-                SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE,
-                       SSL_R_MISSING_TMP_ECDH_KEY);
-                goto f_err;
-            }
-            if (((clnt_pub_pkey = X509_get_pubkey(s->session->peer))
-                 == NULL) || (clnt_pub_pkey->type != EVP_PKEY_EC)) {
-                /*
-                 * XXX: For now, we do not support client authentication
-                 * using ECDH certificates so this branch (n == 0L) of the
-                 * code is never executed. When that support is added, we
-                 * ought to ensure the key received in the certificate is
-                 * authorized for key agreement. ECDH_compute_key implicitly
-                 * checks that the two ECDH shares are for the same group.
-                 */
-                al = SSL_AD_HANDSHAKE_FAILURE;
-                SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE,
-                       SSL_R_UNABLE_TO_DECODE_ECDH_CERTS);
-                goto f_err;
-            }
-
-            if (EC_POINT_copy(clnt_ecpoint,
-                              EC_KEY_get0_public_key(clnt_pub_pkey->
-                                                     pkey.ec)) == 0) {
-                SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE, ERR_R_EC_LIB);
-                goto err;
-            }
-            s->statem.no_cert_verify = 1;
+            /* We don't support ECDH client auth */
+            al = SSL_AD_HANDSHAKE_FAILURE;
+            SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE,
+                   SSL_R_MISSING_TMP_ECDH_KEY);
+            goto f_err;
         } else {
             /*
              * Get client's public key from encoded point in the
              * ClientKeyExchange message.
              */
-            if ((bn_ctx = BN_CTX_new()) == NULL) {
-                SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE,
-                       ERR_R_MALLOC_FAILURE);
-                goto err;
-            }
 
             /* Get encoded point length */
             if (!PACKET_get_1(pkt, &i)) {
@@ -2599,43 +2490,27 @@ MSG_PROCESS_RETURN tls_process_client_key_exchange(SSL *s, PACKET *pkt)
                 SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE, ERR_R_EC_LIB);
                 goto err;
             }
-            if (EC_POINT_oct2point(group, clnt_ecpoint, data, i, bn_ctx) == 0) {
+            ckey = EVP_PKEY_new();
+            if (ckey == NULL || EVP_PKEY_copy_parameters(ckey, skey) <= 0) {
+                SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE, ERR_R_EVP_LIB);
+                goto err;
+            }
+            if (EC_KEY_oct2key(EVP_PKEY_get0_EC_KEY(ckey), data, i,
+                               NULL) == 0) {
                 SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE, ERR_R_EC_LIB);
                 goto err;
             }
         }
 
-        /* Compute the shared pre-master secret */
-        field_size = EC_GROUP_get_degree(group);
-        if (field_size <= 0) {
-            SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE, ERR_R_ECDH_LIB);
-            goto err;
-        }
-        shared = OPENSSL_malloc((field_size + 7) / 8);
-        if (shared == NULL) {
-            SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE, ERR_R_MALLOC_FAILURE);
-            goto err;
-        }
-        i = ECDH_compute_key(shared, (field_size + 7) / 8, clnt_ecpoint,
-                             srvr_ecdh, NULL);
-        if (i <= 0) {
-            SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE, ERR_R_ECDH_LIB);
-            OPENSSL_free(shared);
-            goto err;
-        }
-
-        EVP_PKEY_free(clnt_pub_pkey);
-        EC_POINT_free(clnt_ecpoint);
-        EC_KEY_free(srvr_ecdh);
-        BN_CTX_free(bn_ctx);
-        EC_KEY_free(s->s3->tmp.ecdh);
-        s->s3->tmp.ecdh = NULL;
-
-        if (!ssl_generate_master_secret(s, shared, i, 1)) {
+        if (ssl_derive(s, skey, ckey) == 0) {
             al = SSL_AD_INTERNAL_ERROR;
             SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
             goto f_err;
         }
+
+        EVP_PKEY_free(ckey);
+        ckey = NULL;
+
         return MSG_PROCESS_CONTINUE_PROCESSING;
     } else
 #endif
@@ -2780,10 +2655,8 @@ MSG_PROCESS_RETURN tls_process_client_key_exchange(SSL *s, PACKET *pkt)
  err:
 #endif
 #ifndef OPENSSL_NO_EC
-    EVP_PKEY_free(clnt_pub_pkey);
-    EC_POINT_free(clnt_ecpoint);
-    EC_KEY_free(srvr_ecdh);
-    BN_CTX_free(bn_ctx);
+    EVP_PKEY_free(ckey);
+    EVP_PKEY_CTX_free(pctx);
     OPENSSL_free(rsa_decrypt);
 #endif
 #ifndef OPENSSL_NO_PSK
diff --git a/util/libeay.num b/util/libeay.num
index efa4953..98e0ca8 100755
--- a/util/libeay.num
+++ b/util/libeay.num
@@ -4739,3 +4739,6 @@ EVP_PKEY_get0_DH                        5101	1_1_0	EXIST::FUNCTION:DH
 X509_get0_pubkey                        5102	1_1_0	EXIST::FUNCTION:
 X509_PUBKEY_get0                        5103	1_1_0	EXIST::FUNCTION:
 EVP_PKEY_get0_RSA                       5104	1_1_0	EXIST::FUNCTION:RSA
+EC_POINT_point2buf                      5105	1_1_0	EXIST::FUNCTION:EC
+EC_KEY_key2buf                          5106	1_1_0	EXIST::FUNCTION:EC
+EC_KEY_oct2key                          5107	1_1_0	EXIST::FUNCTION:EC


More information about the openssl-commits mailing list