[openssl-commits] [openssl] master update

Matt Caswell matt at openssl.org
Tue Jul 19 11:20:53 UTC 2016


The branch master has been updated
       via  4fa88861eed81915f45c48d4ebd7b5bf3a51963b (commit)
       via  e1e588acae078f05159683876540235d8a70a648 (commit)
       via  ff74aeb1fa43d616c06cc519df7baae5916f1cba (commit)
       via  e01a610db8dc7b86422fd08447de25756ddc21e9 (commit)
       via  25c6c10cd7facdbf96a43a6031aad5a8a2e3b7e7 (commit)
       via  7dc1c64774d712629388f89373a494f992f441dd (commit)
       via  02a74590bb9e22d0f4131e8bd6b391402f7d3752 (commit)
       via  be8dba2c924b81a28053588f171b91b72e7e3ebc (commit)
      from  eaa776da07bffbcea4ec32bdc5bf65fefb610fc5 (commit)


- Log -----------------------------------------------------------------
commit 4fa88861eed81915f45c48d4ebd7b5bf3a51963b
Author: Matt Caswell <matt at openssl.org>
Date:   Fri Jul 8 15:48:26 2016 +0100

    Update error codes following tls_process_key_exchange() refactor
    
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit e1e588acae078f05159683876540235d8a70a648
Author: Matt Caswell <matt at openssl.org>
Date:   Fri Jul 8 15:41:36 2016 +0100

    Tidy up tls_process_key_exchange()
    
    After the refactor of tls_process_key_exchange(), this commit tidies up
    some loose ends.
    
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit ff74aeb1fa43d616c06cc519df7baae5916f1cba
Author: Matt Caswell <matt at openssl.org>
Date:   Fri Jul 8 15:26:13 2016 +0100

    Split out ECDHE from tls_process_key_exchange()
    
    Continuing from the previous commit. Refactor tls_process_key_exchange() to
    split out into a separate function the ECDHE aspects.
    
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit e01a610db8dc7b86422fd08447de25756ddc21e9
Author: Matt Caswell <matt at openssl.org>
Date:   Fri Jul 8 15:08:50 2016 +0100

    Split out DHE from tls_process_key_exchange()
    
    Continuing from the previous commit. Refactor tls_process_key_exchange() to
    split out into a separate function the DHE aspects.
    
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit 25c6c10cd7facdbf96a43a6031aad5a8a2e3b7e7
Author: Matt Caswell <matt at openssl.org>
Date:   Fri Jul 8 14:55:56 2016 +0100

    Split out SRP from tls_process_key_exchange()
    
    Continuing from the previous commit. Refactor tls_process_key_exchange() to
    split out into a separate function the SRP aspects.
    
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit 7dc1c64774d712629388f89373a494f992f441dd
Author: Matt Caswell <matt at openssl.org>
Date:   Fri Jul 8 12:44:53 2016 +0100

    Split out the PSK preamble from tls_process_key_exchange()
    
    The tls_process_key_exchange() function is too long. This commit starts
    the process of splitting it up by moving the PSK preamble code to a
    separate function.
    
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit 02a74590bb9e22d0f4131e8bd6b391402f7d3752
Author: Matt Caswell <matt at openssl.org>
Date:   Fri Jul 8 12:20:42 2016 +0100

    Move the PSK preamble for tls_process_key_exchange()
    
    The function tls_process_key_exchange() is too long. This commit moves
    the PSK preamble processing out to a separate function.
    
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit be8dba2c924b81a28053588f171b91b72e7e3ebc
Author: Matt Caswell <matt at openssl.org>
Date:   Fri Jul 8 12:18:18 2016 +0100

    Narrow scope of locals vars in tls_process_key_exchange()
    
    Narrow the scope of the local vars in preparation for split up this
    function.
    
    Reviewed-by: Richard Levitte <levitte at openssl.org>

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

Summary of changes:
 include/openssl/ssl.h    |   4 +
 ssl/ssl_err.c            |   5 +
 ssl/statem/statem_clnt.c | 566 +++++++++++++++++++++++++----------------------
 3 files changed, 316 insertions(+), 259 deletions(-)

diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h
index 7cf8e51..3a6cd4c 100644
--- a/include/openssl/ssl.h
+++ b/include/openssl/ssl.h
@@ -2246,6 +2246,10 @@ void ERR_load_SSL_strings(void);
 # define SSL_F_TLS_PROCESS_SERVER_CERTIFICATE             367
 # define SSL_F_TLS_PROCESS_SERVER_DONE                    368
 # define SSL_F_TLS_PROCESS_SERVER_HELLO                   369
+# define SSL_F_TLS_PROCESS_SKE_DHE                        419
+# define SSL_F_TLS_PROCESS_SKE_ECDHE                      420
+# define SSL_F_TLS_PROCESS_SKE_PSK_PREAMBLE               421
+# define SSL_F_TLS_PROCESS_SKE_SRP                        422
 # define SSL_F_USE_CERTIFICATE_CHAIN_FILE                 220
 
 /* Reason codes. */
diff --git a/ssl/ssl_err.c b/ssl/ssl_err.c
index 34da5f2..aed91e3 100644
--- a/ssl/ssl_err.c
+++ b/ssl/ssl_err.c
@@ -295,6 +295,11 @@ static ERR_STRING_DATA SSL_str_functs[] = {
      "tls_process_server_certificate"},
     {ERR_FUNC(SSL_F_TLS_PROCESS_SERVER_DONE), "tls_process_server_done"},
     {ERR_FUNC(SSL_F_TLS_PROCESS_SERVER_HELLO), "tls_process_server_hello"},
+    {ERR_FUNC(SSL_F_TLS_PROCESS_SKE_DHE), "tls_process_ske_dhe"},
+    {ERR_FUNC(SSL_F_TLS_PROCESS_SKE_ECDHE), "tls_process_ske_ecdhe"},
+    {ERR_FUNC(SSL_F_TLS_PROCESS_SKE_PSK_PREAMBLE),
+     "tls_process_ske_psk_preamble"},
+    {ERR_FUNC(SSL_F_TLS_PROCESS_SKE_SRP), "tls_process_ske_srp"},
     {ERR_FUNC(SSL_F_USE_CERTIFICATE_CHAIN_FILE),
      "use_certificate_chain_file"},
     {0, NULL}
diff --git a/ssl/statem/statem_clnt.c b/ssl/statem/statem_clnt.c
index 4bd5a29..b0f508c 100644
--- a/ssl/statem/statem_clnt.c
+++ b/ssl/statem/statem_clnt.c
@@ -1302,287 +1302,319 @@ MSG_PROCESS_RETURN tls_process_server_certificate(SSL *s, PACKET *pkt)
     return ret;
 }
 
-MSG_PROCESS_RETURN tls_process_key_exchange(SSL *s, PACKET *pkt)
+static int tls_process_ske_psk_preamble(SSL *s, PACKET *pkt, int *al)
 {
-    EVP_MD_CTX *md_ctx;
-    int al, j;
-    long alg_k, alg_a;
-    EVP_PKEY *pkey = NULL;
-    const EVP_MD *md = NULL;
-#ifndef OPENSSL_NO_RSA
-    RSA *rsa = NULL;
-#endif
-#ifndef OPENSSL_NO_EC
-    EVP_PKEY_CTX *pctx = NULL;
+#ifndef OPENSSL_NO_PSK
+    PACKET psk_identity_hint;
+
+    /* PSK ciphersuites are preceded by an identity hint */
+
+    if (!PACKET_get_length_prefixed_2(pkt, &psk_identity_hint)) {
+        *al = SSL_AD_DECODE_ERROR;
+        SSLerr(SSL_F_TLS_PROCESS_SKE_PSK_PREAMBLE, SSL_R_LENGTH_MISMATCH);
+        return 0;
+    }
+
+    /*
+     * Store PSK identity hint for later use, hint is used in
+     * tls_construct_client_key_exchange.  Assume that the maximum length of
+     * a PSK identity hint can be as long as the maximum length of a PSK
+     * identity.
+     */
+    if (PACKET_remaining(&psk_identity_hint) > PSK_MAX_IDENTITY_LEN) {
+        *al = SSL_AD_HANDSHAKE_FAILURE;
+        SSLerr(SSL_F_TLS_PROCESS_SKE_PSK_PREAMBLE, SSL_R_DATA_LENGTH_TOO_LONG);
+        return 0;
+    }
+
+    if (PACKET_remaining(&psk_identity_hint) == 0) {
+        OPENSSL_free(s->session->psk_identity_hint);
+        s->session->psk_identity_hint = NULL;
+    } else if (!PACKET_strndup(&psk_identity_hint,
+                        &s->session->psk_identity_hint)) {
+        *al = SSL_AD_INTERNAL_ERROR;
+        return 0;
+    }
+
+    return 1;
+#else
+    SSLerr(SSL_F_TLS_PROCESS_SKE_PSK_PREAMBLE, ERR_R_INTERNAL_ERROR);
+    *al = SSL_AD_INTERNAL_ERROR;
+    return 0;
 #endif
-    PACKET save_param_start, signature;
+}
 
-    md_ctx = EVP_MD_CTX_new();
-    if (md_ctx == NULL) {
-        al = SSL_AD_INTERNAL_ERROR;
-        SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, ERR_R_MALLOC_FAILURE);
-        goto f_err;
+static int tls_process_ske_srp(SSL *s, PACKET *pkt, EVP_PKEY **pkey, int *al)
+{
+#ifndef OPENSSL_NO_SRP
+    PACKET prime, generator, salt, server_pub;
+
+    if (!PACKET_get_length_prefixed_2(pkt, &prime)
+        || !PACKET_get_length_prefixed_2(pkt, &generator)
+        || !PACKET_get_length_prefixed_1(pkt, &salt)
+        || !PACKET_get_length_prefixed_2(pkt, &server_pub)) {
+        *al = SSL_AD_DECODE_ERROR;
+        SSLerr(SSL_F_TLS_PROCESS_SKE_SRP, SSL_R_LENGTH_MISMATCH);
+        return 0;
     }
 
-    alg_k = s->s3->tmp.new_cipher->algorithm_mkey;
+    if ((s->srp_ctx.N =
+         BN_bin2bn(PACKET_data(&prime),
+                   PACKET_remaining(&prime), NULL)) == NULL
+        || (s->srp_ctx.g =
+            BN_bin2bn(PACKET_data(&generator),
+                      PACKET_remaining(&generator), NULL)) == NULL
+        || (s->srp_ctx.s =
+            BN_bin2bn(PACKET_data(&salt),
+                      PACKET_remaining(&salt), NULL)) == NULL
+        || (s->srp_ctx.B =
+            BN_bin2bn(PACKET_data(&server_pub),
+                      PACKET_remaining(&server_pub), NULL)) == NULL) {
+        *al = SSL_AD_INTERNAL_ERROR;
+        SSLerr(SSL_F_TLS_PROCESS_SKE_SRP, ERR_R_BN_LIB);
+        return 0;
+    }
 
-    save_param_start = *pkt;
+    if (!srp_verify_server_param(s, al)) {
+        *al = SSL_AD_DECODE_ERROR;
+        SSLerr(SSL_F_TLS_PROCESS_SKE_SRP, SSL_R_BAD_SRP_PARAMETERS);
+        return 0;
+    }
 
-#if !defined(OPENSSL_NO_EC) || !defined(OPENSSL_NO_DH)
-    EVP_PKEY_free(s->s3->peer_tmp);
-    s->s3->peer_tmp = NULL;
+    /* We must check if there is a certificate */
+    if (s->s3->tmp.new_cipher->algorithm_auth & (SSL_aRSA|SSL_aDSS))
+        *pkey = X509_get0_pubkey(s->session->peer);
+
+    return 1;
+#else
+    SSLerr(SSL_F_TLS_PROCESS_SKE_SRP, ERR_R_INTERNAL_ERROR);
+    *al = SSL_AD_INTERNAL_ERROR;
+    return 0;
 #endif
+}
 
-    alg_a = s->s3->tmp.new_cipher->algorithm_auth;
+static int tls_process_ske_dhe(SSL *s, PACKET *pkt, EVP_PKEY **pkey, int *al)
+{
+#ifndef OPENSSL_NO_DH
+    PACKET prime, generator, pub_key;
+    EVP_PKEY *peer_tmp = NULL;
 
-    al = SSL_AD_DECODE_ERROR;
+    DH *dh = NULL;
+    BIGNUM *p = NULL, *g = NULL, *bnpub_key = NULL;
 
-#ifndef OPENSSL_NO_PSK
-    /* PSK ciphersuites are preceded by an identity hint */
-    if (alg_k & SSL_PSK) {
-        PACKET psk_identity_hint;
-        if (!PACKET_get_length_prefixed_2(pkt, &psk_identity_hint)) {
-            SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, SSL_R_LENGTH_MISMATCH);
-            goto f_err;
-        }
+    if (!PACKET_get_length_prefixed_2(pkt, &prime)
+        || !PACKET_get_length_prefixed_2(pkt, &generator)
+        || !PACKET_get_length_prefixed_2(pkt, &pub_key)) {
+        *al = SSL_AD_DECODE_ERROR;
+        SSLerr(SSL_F_TLS_PROCESS_SKE_DHE, SSL_R_LENGTH_MISMATCH);
+        return 0;
+    }
 
-        /*
-         * Store PSK identity hint for later use, hint is used in
-         * ssl3_send_client_key_exchange.  Assume that the maximum length of
-         * a PSK identity hint can be as long as the maximum length of a PSK
-         * identity.
-         */
-        if (PACKET_remaining(&psk_identity_hint) > PSK_MAX_IDENTITY_LEN) {
-            al = SSL_AD_HANDSHAKE_FAILURE;
-            SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, SSL_R_DATA_LENGTH_TOO_LONG);
-            goto f_err;
-        }
+    peer_tmp = EVP_PKEY_new();
+    dh = DH_new();
 
-        if (PACKET_remaining(&psk_identity_hint) == 0) {
-            OPENSSL_free(s->session->psk_identity_hint);
-            s->session->psk_identity_hint = NULL;
-        } else if (!PACKET_strndup(&psk_identity_hint,
-                            &s->session->psk_identity_hint)) {
-            al = SSL_AD_INTERNAL_ERROR;
-            goto f_err;
-        }
+    if (peer_tmp == NULL || dh == NULL) {
+        *al = SSL_AD_INTERNAL_ERROR;
+        SSLerr(SSL_F_TLS_PROCESS_SKE_DHE, ERR_R_MALLOC_FAILURE);
+        goto err;
     }
 
-    /* Nothing else to do for plain PSK or RSAPSK */
-    if (alg_k & (SSL_kPSK | SSL_kRSAPSK)) {
-    } else
-#endif                          /* !OPENSSL_NO_PSK */
-    /*
-     * Dummy "if" to ensure sane C code in the event of various OPENSSL_NO_*
-     * options
-     */
-    if (0) {
+    p = BN_bin2bn(PACKET_data(&prime), PACKET_remaining(&prime), NULL);
+    g = BN_bin2bn(PACKET_data(&generator), PACKET_remaining(&generator),
+                  NULL);
+    bnpub_key = BN_bin2bn(PACKET_data(&pub_key), PACKET_remaining(&pub_key),
+                          NULL);
+    if (p == NULL || g == NULL || bnpub_key == NULL) {
+        *al = SSL_AD_INTERNAL_ERROR;
+        SSLerr(SSL_F_TLS_PROCESS_SKE_DHE, ERR_R_BN_LIB);
+        goto err;
     }
-#ifndef OPENSSL_NO_SRP
-    else if (alg_k & SSL_kSRP) {
-        PACKET prime, generator, salt, server_pub;
-        if (!PACKET_get_length_prefixed_2(pkt, &prime)
-            || !PACKET_get_length_prefixed_2(pkt, &generator)
-            || !PACKET_get_length_prefixed_1(pkt, &salt)
-            || !PACKET_get_length_prefixed_2(pkt, &server_pub)) {
-            SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, SSL_R_LENGTH_MISMATCH);
-            goto f_err;
-        }
 
-        if ((s->srp_ctx.N =
-             BN_bin2bn(PACKET_data(&prime),
-                       PACKET_remaining(&prime), NULL)) == NULL
-            || (s->srp_ctx.g =
-                BN_bin2bn(PACKET_data(&generator),
-                          PACKET_remaining(&generator), NULL)) == NULL
-            || (s->srp_ctx.s =
-                BN_bin2bn(PACKET_data(&salt),
-                          PACKET_remaining(&salt), NULL)) == NULL
-            || (s->srp_ctx.B =
-                BN_bin2bn(PACKET_data(&server_pub),
-                          PACKET_remaining(&server_pub), NULL)) == NULL) {
-            SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, ERR_R_BN_LIB);
-            goto err;
-        }
+    if (BN_is_zero(p) || BN_is_zero(g) || BN_is_zero(bnpub_key)) {
+        *al = SSL_AD_DECODE_ERROR;
+        SSLerr(SSL_F_TLS_PROCESS_SKE_DHE, SSL_R_BAD_DH_VALUE);
+        goto err;
+    }
 
-        if (!srp_verify_server_param(s, &al)) {
-            SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, SSL_R_BAD_SRP_PARAMETERS);
-            goto f_err;
-        }
+    if (!DH_set0_pqg(dh, p, NULL, g)) {
+        *al = SSL_AD_INTERNAL_ERROR;
+        SSLerr(SSL_F_TLS_PROCESS_SKE_DHE, ERR_R_BN_LIB);
+        goto err;
+    }
+    p = g = NULL;
 
-/* We must check if there is a certificate */
-        if (alg_a & (SSL_aRSA|SSL_aDSS))
-            pkey = X509_get0_pubkey(s->session->peer);
+    if (!DH_set0_key(dh, bnpub_key, NULL)) {
+        *al = SSL_AD_INTERNAL_ERROR;
+        SSLerr(SSL_F_TLS_PROCESS_SKE_DHE, ERR_R_BN_LIB);
+        goto err;
     }
-#endif                          /* !OPENSSL_NO_SRP */
-#ifndef OPENSSL_NO_DH
-    else if (alg_k & (SSL_kDHE | SSL_kDHEPSK)) {
-        PACKET prime, generator, pub_key;
-        EVP_PKEY *peer_tmp = NULL;
+    bnpub_key = NULL;
 
-        DH *dh = NULL;
-        BIGNUM *p = NULL, *g = NULL, *bnpub_key = NULL;
+    if (!ssl_security(s, SSL_SECOP_TMP_DH, DH_security_bits(dh), 0, dh)) {
+        *al = SSL_AD_HANDSHAKE_FAILURE;
+        SSLerr(SSL_F_TLS_PROCESS_SKE_DHE, SSL_R_DH_KEY_TOO_SMALL);
+        goto err;
+    }
 
-        if (!PACKET_get_length_prefixed_2(pkt, &prime)
-            || !PACKET_get_length_prefixed_2(pkt, &generator)
-            || !PACKET_get_length_prefixed_2(pkt, &pub_key)) {
-            SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, SSL_R_LENGTH_MISMATCH);
-            goto f_err;
-        }
+    if (EVP_PKEY_assign_DH(peer_tmp, dh) == 0) {
+        *al = SSL_AD_INTERNAL_ERROR;
+        SSLerr(SSL_F_TLS_PROCESS_SKE_DHE, ERR_R_EVP_LIB);
+        goto err;
+    }
 
-        peer_tmp = EVP_PKEY_new();
-        dh = DH_new();
+    s->s3->peer_tmp = peer_tmp;
 
-        if (peer_tmp == NULL || dh == NULL) {
-            al = SSL_AD_INTERNAL_ERROR;
-            SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, ERR_R_MALLOC_FAILURE);
-            goto dherr;
-        }
+    /*
+     * FIXME: This makes assumptions about which ciphersuites come with
+     * public keys. We should have a less ad-hoc way of doing this
+     */
+    if (s->s3->tmp.new_cipher->algorithm_auth & (SSL_aRSA|SSL_aDSS))
+        *pkey = X509_get0_pubkey(s->session->peer);
+    /* else anonymous DH, so no certificate or pkey. */
 
-        p = BN_bin2bn(PACKET_data(&prime), PACKET_remaining(&prime), NULL);
-        g = BN_bin2bn(PACKET_data(&generator), PACKET_remaining(&generator),
-                      NULL);
-        bnpub_key = BN_bin2bn(PACKET_data(&pub_key), PACKET_remaining(&pub_key),
-                              NULL);
-        if (p == NULL || g == NULL || bnpub_key == NULL) {
-            SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, ERR_R_BN_LIB);
-            goto dherr;
-        }
+    return 1;
 
-        if (BN_is_zero(p) || BN_is_zero(g) || BN_is_zero(bnpub_key)) {
-            SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, SSL_R_BAD_DH_VALUE);
-            goto dherr;
-        }
+ err:
+    BN_free(p);
+    BN_free(g);
+    BN_free(bnpub_key);
+    DH_free(dh);
+    EVP_PKEY_free(peer_tmp);
 
-        if (!DH_set0_pqg(dh, p, NULL, g)) {
-            al = SSL_AD_INTERNAL_ERROR;
-            SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, ERR_R_BN_LIB);
-            goto dherr;
-        }
-        p = g = NULL;
+    return 0;
+#else
+    SSLerr(SSL_F_TLS_PROCESS_SKE_DHE, ERR_R_INTERNAL_ERROR);
+    *al = SSL_AD_INTERNAL_ERROR;
+    return 0;
+#endif
+}
 
-        if (!DH_set0_key(dh, bnpub_key, NULL)) {
-            al = SSL_AD_INTERNAL_ERROR;
-            SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, ERR_R_BN_LIB);
-            goto dherr;
-        }
-        bnpub_key = NULL;
+static int tls_process_ske_ecdhe(SSL *s, PACKET *pkt, EVP_PKEY **pkey, int *al)
+{
+#ifndef OPENSSL_NO_EC
+    PACKET encoded_pt;
+    const unsigned char *ecparams;
+    int curve_nid;
+    EVP_PKEY_CTX *pctx = NULL;
 
-        if (!ssl_security(s, SSL_SECOP_TMP_DH, DH_security_bits(dh), 0, dh)) {
-            al = SSL_AD_HANDSHAKE_FAILURE;
-            SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, SSL_R_DH_KEY_TOO_SMALL);
-            goto dherr;
-        }
+    /*
+     * Extract elliptic curve parameters and the server's ephemeral ECDH
+     * public key. For now we only support named (not generic) curves and
+     * ECParameters in this case is just three bytes.
+     */
+    if (!PACKET_get_bytes(pkt, &ecparams, 3)) {
+        *al = SSL_AD_DECODE_ERROR;
+        SSLerr(SSL_F_TLS_PROCESS_SKE_ECDHE, SSL_R_LENGTH_TOO_SHORT);
+        return 0;
+    }
+    /*
+     * Check curve is one of our preferences, if not server has sent an
+     * invalid curve. ECParameters is 3 bytes.
+     */
+    if (!tls1_check_curve(s, ecparams, 3)) {
+        *al = SSL_AD_DECODE_ERROR;
+        SSLerr(SSL_F_TLS_PROCESS_SKE_ECDHE, SSL_R_WRONG_CURVE);
+        return 0;
+    }
 
-        if (EVP_PKEY_assign_DH(peer_tmp, dh) == 0) {
-            al = SSL_AD_INTERNAL_ERROR;
-            SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, ERR_R_EVP_LIB);
-            goto dherr;
-        }
+    curve_nid = tls1_ec_curve_id2nid(*(ecparams + 2));
+    if (curve_nid  == 0) {
+        *al = SSL_AD_INTERNAL_ERROR;
+        SSLerr(SSL_F_TLS_PROCESS_SKE_ECDHE,
+               SSL_R_UNABLE_TO_FIND_ECDH_PARAMETERS);
+        return 0;
+    }
 
-        s->s3->peer_tmp = peer_tmp;
+    /* 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);
+    pctx = NULL;
 
-        goto dhend;
- dherr:
-        BN_free(p);
-        BN_free(g);
-        BN_free(bnpub_key);
-        DH_free(dh);
-        EVP_PKEY_free(peer_tmp);
-        goto f_err;
- dhend:
-        /*
-         * FIXME: This makes assumptions about which ciphersuites come with
-         * public keys. We should have a less ad-hoc way of doing this
-         */
-        if (alg_a & (SSL_aRSA|SSL_aDSS))
-            pkey = X509_get0_pubkey(s->session->peer);
-        /* else anonymous DH, so no certificate or pkey. */
+    if (!PACKET_get_length_prefixed_1(pkt, &encoded_pt)) {
+        *al = SSL_AD_DECODE_ERROR;
+        SSLerr(SSL_F_TLS_PROCESS_SKE_ECDHE, SSL_R_LENGTH_MISMATCH);
+        return 0;
     }
-#endif                          /* !OPENSSL_NO_DH */
 
-#ifndef OPENSSL_NO_EC
-    else if (alg_k & (SSL_kECDHE | SSL_kECDHEPSK)) {
-        PACKET encoded_pt;
-        const unsigned char *ecparams;
-        int curve_nid;
+    if (EC_KEY_oct2key(EVP_PKEY_get0_EC_KEY(s->s3->peer_tmp),
+                       PACKET_data(&encoded_pt),
+                       PACKET_remaining(&encoded_pt), NULL) == 0) {
+        *al = SSL_AD_DECODE_ERROR;
+        SSLerr(SSL_F_TLS_PROCESS_SKE_ECDHE, SSL_R_BAD_ECPOINT);
+        return 0;
+    }
 
-        /*
-         * Extract elliptic curve parameters and the server's ephemeral ECDH
-         * public key. For now we only support named (not generic) curves and
-         * ECParameters in this case is just three bytes.
-         */
-        if (!PACKET_get_bytes(pkt, &ecparams, 3)) {
-            SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, SSL_R_LENGTH_TOO_SHORT);
-            goto f_err;
-        }
-        /*
-         * Check curve is one of our preferences, if not server has sent an
-         * invalid curve. ECParameters is 3 bytes.
-         */
-        if (!tls1_check_curve(s, ecparams, 3)) {
-            SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, SSL_R_WRONG_CURVE);
-            goto f_err;
-        }
+    /*
+     * The ECC/TLS specification does not mention the use of DSA to sign
+     * ECParameters in the server key exchange message. We do support RSA
+     * and ECDSA.
+     */
+    if (s->s3->tmp.new_cipher->algorithm_auth & SSL_aECDSA)
+        *pkey = X509_get0_pubkey(s->session->peer);
+    else if (s->s3->tmp.new_cipher->algorithm_auth & SSL_aRSA)
+        *pkey = X509_get0_pubkey(s->session->peer);
+    /* else anonymous ECDH, so no certificate or pkey. */
 
-        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;
-        }
+    return 1;
+#else
+    SSLerr(SSL_F_TLS_PROCESS_SKE_ECDHE, ERR_R_INTERNAL_ERROR);
+    *al = SSL_AD_INTERNAL_ERROR;
+    return 0;
+#endif
+}
 
-        /* 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;
+MSG_PROCESS_RETURN tls_process_key_exchange(SSL *s, PACKET *pkt)
+{
+    int al = -1;
+    long alg_k;
+    EVP_PKEY *pkey = NULL;
+    PACKET save_param_start, signature;
 
-        if (!PACKET_get_length_prefixed_1(pkt, &encoded_pt)) {
-            SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, SSL_R_LENGTH_MISMATCH);
-            goto f_err;
-        }
+    alg_k = s->s3->tmp.new_cipher->algorithm_mkey;
 
-        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;
-        }
+    save_param_start = *pkt;
 
-        /*
-         * The ECC/TLS specification does not mention the use of DSA to sign
-         * ECParameters in the server key exchange message. We do support RSA
-         * and ECDSA.
-         */
-        if (0) ;
-# ifndef OPENSSL_NO_RSA
-        else if (alg_a & SSL_aRSA)
-            pkey = X509_get0_pubkey(s->session->peer);
-# endif
-# ifndef OPENSSL_NO_EC
-        else if (alg_a & SSL_aECDSA)
-            pkey = X509_get0_pubkey(s->session->peer);
-# endif
-        /* else anonymous ECDH, so no certificate or pkey. */
+    EVP_PKEY_free(s->s3->peer_tmp);
+    s->s3->peer_tmp = NULL;
+
+    if (alg_k & SSL_PSK) {
+        if (!tls_process_ske_psk_preamble(s, pkt, &al))
+            goto err;
+    }
+
+    /* Nothing else to do for plain PSK or RSAPSK */
+    if (alg_k & (SSL_kPSK | SSL_kRSAPSK)) {
+    } else if (alg_k & SSL_kSRP) {
+        if (!tls_process_ske_srp(s, pkt, &pkey, &al))
+            goto err;
+    } else if (alg_k & (SSL_kDHE | SSL_kDHEPSK)) {
+        if (!tls_process_ske_dhe(s, pkt, &pkey, &al))
+            goto err;
+    } else if (alg_k & (SSL_kECDHE | SSL_kECDHEPSK)) {
+        if (!tls_process_ske_ecdhe(s, pkt, &pkey, &al))
+            goto err;
     } else if (alg_k) {
         al = SSL_AD_UNEXPECTED_MESSAGE;
         SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, SSL_R_UNEXPECTED_MESSAGE);
-        goto f_err;
+        goto err;
     }
-#endif                          /* !OPENSSL_NO_EC */
 
     /* if it was signed, check the signature */
     if (pkey != NULL) {
         PACKET params;
+        int maxsig;
+        const EVP_MD *md = NULL;
+        EVP_MD_CTX *md_ctx;
+
         /*
          * |pkt| now points to the beginning of the signature, so the difference
          * equals the length of the parameters.
@@ -1592,21 +1624,24 @@ MSG_PROCESS_RETURN tls_process_key_exchange(SSL *s, PACKET *pkt)
                                    PACKET_remaining(pkt))) {
             al = SSL_AD_INTERNAL_ERROR;
             SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
-            goto f_err;
+            goto err;
         }
 
         if (SSL_USE_SIGALGS(s)) {
             const unsigned char *sigalgs;
             int rv;
             if (!PACKET_get_bytes(pkt, &sigalgs, 2)) {
+                al = SSL_AD_DECODE_ERROR;
                 SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, SSL_R_LENGTH_TOO_SHORT);
-                goto f_err;
+                goto err;
             }
             rv = tls12_check_peer_sigalg(&md, s, sigalgs, pkey);
-            if (rv == -1)
+            if (rv == -1) {
+                al = SSL_AD_INTERNAL_ERROR;
+                goto err;
+            } else if (rv == 0) {
+                al = SSL_AD_DECODE_ERROR;
                 goto err;
-            else if (rv == 0) {
-                goto f_err;
             }
 #ifdef SSL_DEBUG
             fprintf(stderr, "USING TLSv1.2 HASH %s\n", EVP_MD_name(md));
@@ -1619,23 +1654,34 @@ MSG_PROCESS_RETURN tls_process_key_exchange(SSL *s, PACKET *pkt)
 
         if (!PACKET_get_length_prefixed_2(pkt, &signature)
             || PACKET_remaining(pkt) != 0) {
+            al = SSL_AD_DECODE_ERROR;
             SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, SSL_R_LENGTH_MISMATCH);
-            goto f_err;
+            goto err;
         }
-        j = EVP_PKEY_size(pkey);
-        if (j < 0) {
+        maxsig = EVP_PKEY_size(pkey);
+        if (maxsig < 0) {
+            al = SSL_AD_INTERNAL_ERROR;
             SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
-            goto f_err;
+            goto err;
         }
 
         /*
          * Check signature length
          */
-        if (PACKET_remaining(&signature) > (size_t)j) {
+        if (PACKET_remaining(&signature) > (size_t)maxsig) {
             /* wrong packet length */
+            al = SSL_AD_DECODE_ERROR;
             SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, SSL_R_WRONG_SIGNATURE_LENGTH);
-            goto f_err;
+            goto err;
+        }
+
+        md_ctx = EVP_MD_CTX_new();
+        if (md_ctx == NULL) {
+            al = SSL_AD_INTERNAL_ERROR;
+            SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, ERR_R_MALLOC_FAILURE);
+            goto err;
         }
+
         if (EVP_VerifyInit_ex(md_ctx, md, NULL) <= 0
                 || EVP_VerifyUpdate(md_ctx, &(s->s3->client_random[0]),
                                     SSL3_RANDOM_SIZE) <= 0
@@ -1643,44 +1689,46 @@ MSG_PROCESS_RETURN tls_process_key_exchange(SSL *s, PACKET *pkt)
                                     SSL3_RANDOM_SIZE) <= 0
                 || EVP_VerifyUpdate(md_ctx, PACKET_data(&params),
                                     PACKET_remaining(&params)) <= 0) {
+            EVP_MD_CTX_free(md_ctx);
             al = SSL_AD_INTERNAL_ERROR;
             SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, ERR_R_EVP_LIB);
-            goto f_err;
+            goto err;
         }
         if (EVP_VerifyFinal(md_ctx, PACKET_data(&signature),
                             PACKET_remaining(&signature), pkey) <= 0) {
             /* bad signature */
+            EVP_MD_CTX_free(md_ctx);
             al = SSL_AD_DECRYPT_ERROR;
             SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, SSL_R_BAD_SIGNATURE);
-            goto f_err;
+            goto err;
         }
+        EVP_MD_CTX_free(md_ctx);
     } else {
         /* aNULL, aSRP or PSK do not need public keys */
-        if (!(alg_a & (SSL_aNULL | SSL_aSRP)) && !(alg_k & SSL_PSK)) {
+        if (!(s->s3->tmp.new_cipher->algorithm_auth & (SSL_aNULL | SSL_aSRP))
+                && !(alg_k & SSL_PSK)) {
             /* Might be wrong key type, check it */
-            if (ssl3_check_cert_and_algorithm(s))
+            if (ssl3_check_cert_and_algorithm(s)) {
                 /* Otherwise this shouldn't happen */
+                al = SSL_AD_INTERNAL_ERROR;
                 SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
+            } else {
+                al = SSL_AD_DECODE_ERROR;
+            }
             goto err;
         }
         /* still data left over */
         if (PACKET_remaining(pkt) != 0) {
+            al = SSL_AD_DECODE_ERROR;
             SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, SSL_R_EXTRA_DATA_IN_MESSAGE);
-            goto f_err;
+            goto err;
         }
     }
-    EVP_MD_CTX_free(md_ctx);
+
     return MSG_PROCESS_CONTINUE_READING;
- f_err:
-    ssl3_send_alert(s, SSL3_AL_FATAL, al);
  err:
-#ifndef OPENSSL_NO_RSA
-    RSA_free(rsa);
-#endif
-#ifndef OPENSSL_NO_EC
-    EVP_PKEY_CTX_free(pctx);
-#endif
-    EVP_MD_CTX_free(md_ctx);
+    if (al != -1)
+        ssl3_send_alert(s, SSL3_AL_FATAL, al);
     ossl_statem_set_error(s);
     return MSG_PROCESS_ERROR;
 }


More information about the openssl-commits mailing list