Use EVP_PKEY for client side EC.
authorDr. Stephen Henson <steve@openssl.org>
Mon, 14 Dec 2015 00:33:33 +0000 (00:33 +0000)
committerDr. Stephen Henson <steve@openssl.org>
Wed, 16 Dec 2015 14:17:53 +0000 (14:17 +0000)
Reviewed-by: Richard Levitte <levitte@openssl.org>
ssl/s3_lib.c
ssl/ssl_locl.h
ssl/statem/statem_clnt.c

index ddb7ed4204276c03473ee18850b74e9f2f192e5e..465ed1ef653a61a2a125b76855bfe55cb5b2ede4 100644 (file)
@@ -3762,7 +3762,8 @@ void ssl3_free(SSL *s)
 #ifndef OPENSSL_NO_EC
     EVP_PKEY_free(s->s3->tmp.pkey);
     s->s3->tmp.pkey = NULL;
-    EC_KEY_free(s->s3->peer_ecdh_tmp);
+    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);
@@ -3801,8 +3802,8 @@ void ssl3_clear(SSL *s)
 #ifndef OPENSSL_NO_EC
     EVP_PKEY_free(s->s3->tmp.pkey);
     s->s3->tmp.pkey = NULL;
-    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;
     s->s3->is_probably_safari = 0;
 #endif                         /* !OPENSSL_NO_EC */
 
@@ -4155,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;
index 24265b288d582aaf2de5eb55a6a0e4f2954f2cf8..7a16f004d6806c02a0ad31a7eceac0b8dfae7b2b 100644 (file)
@@ -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;
index 69a9763d823a50ac908516a15193e930db1ba896..2c2a5215cc0d57666961e1efc6a50a4acf93474b 100644 (file)
@@ -1585,8 +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;
-    int curve_nid = 0;
+    EVP_PKEY_CTX *pctx = NULL;
 #endif
     PACKET save_param_start, signature;
 
@@ -1606,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,6 +1741,7 @@ MSG_PROCESS_RETURN tls_process_key_exchange(SSL *s, PACKET *pkt)
     else if (alg_k & (SSL_kECDHE | SSL_kECDHEPSK)) {
         PACKET encoded_pt;
         unsigned char *ecparams;
+        int curve_nid;
 
         /*
          * Extract elliptic curve parameters and the server's ephemeral ECDH
@@ -1761,26 +1761,34 @@ 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;
         }
 
-        ecdh = EC_KEY_new_by_curve_name(curve_nid);
-
-        if (ecdh == NULL) {
-            SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, ERR_R_EC_LIB);
-            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_KEY_oct2key(ecdh, PACKET_data(&encoded_pt),
+        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;
@@ -1801,8 +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. */
-        s->s3->peer_ecdh_tmp = ecdh;
-        ecdh = NULL;
     } else if (alg_k) {
         al = SSL_AD_UNEXPECTED_MESSAGE;
         SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, SSL_R_UNEXPECTED_MESSAGE);
@@ -1913,7 +1919,7 @@ MSG_PROCESS_RETURN tls_process_key_exchange(SSL *s, PACKET *pkt)
     DH_free(dh);
 #endif
 #ifndef OPENSSL_NO_EC
-    EC_KEY_free(ecdh);
+    EVP_PKEY_CTX_free(pctx);
 #endif
     EVP_MD_CTX_free(md_ctx);
     ossl_statem_set_error(s);
@@ -2238,9 +2244,7 @@ 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;
 #endif
@@ -2468,84 +2472,41 @@ 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 field_size = 0;
 
-        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);
-
-        if ((srvr_group == NULL) || (srvr_ecpoint == NULL)) {
-            SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE,
-                   ERR_R_INTERNAL_ERROR);
-            goto err;
-        }
+        ckey = ssl_generate_pkey(skey, NID_undef);
 
-        if ((clnt_ecdh = EC_KEY_new()) == NULL) {
-            SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE,
-                   ERR_R_MALLOC_FAILURE);
+        if (ssl_derive(s, ckey, skey) == 0) {
+            SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE, ERR_R_EVP_LIB);
             goto err;
         }
 
-        if (!EC_KEY_set_group(clnt_ecdh, srvr_group)) {
-            SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE, ERR_R_EC_LIB);
-            goto err;
-        }
-        /* 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;
-        }
-
-        /*
-         * First check the size of encoding and allocate memory
-         * accordingly.
-         */
-        encoded_pt_len =
-            EC_KEY_key2buf(clnt_ecdh, POINT_CONVERSION_UNCOMPRESSED,
-                               &encodedPoint, NULL);
+        /* Generate encoding of client key */
+        encoded_pt_len = EC_KEY_key2buf(EVP_PKEY_get0_EC_KEY(ckey),
+                                        POINT_CONVERSION_UNCOMPRESSED,
+                                        &encodedPoint, NULL);
 
         if (encoded_pt_len == 0) {
             SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE, ERR_R_EC_LIB);
             goto err;
         }
 
+        EVP_PKEY_free(ckey);
+        ckey = NULL;
+
         n = encoded_pt_len;
 
         *p = n;         /* length of encoded point */
@@ -2558,8 +2519,6 @@ psk_err:
 
         /* Free allocated memory */
         OPENSSL_free(encodedPoint);
-        EC_KEY_free(clnt_ecdh);
-        EVP_PKEY_free(srvr_pub_pkey);
     }
 #endif                          /* !OPENSSL_NO_EC */
 #ifndef OPENSSL_NO_GOST
@@ -2723,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:
@@ -2735,8 +2696,7 @@ psk_err:
     s->s3->tmp.pms = NULL;
 #ifndef OPENSSL_NO_EC
     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);