From ff74aeb1fa43d616c06cc519df7baae5916f1cba Mon Sep 17 00:00:00 2001 From: Matt Caswell Date: Fri, 8 Jul 2016 15:26:13 +0100 Subject: [PATCH] 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 --- ssl/statem/statem_clnt.c | 162 +++++++++++++++++++++------------------ 1 file changed, 86 insertions(+), 76 deletions(-) diff --git a/ssl/statem/statem_clnt.c b/ssl/statem/statem_clnt.c index 6d937a4c6b..d5c6e87158 100644 --- a/ssl/statem/statem_clnt.c +++ b/ssl/statem/statem_clnt.c @@ -1489,6 +1489,89 @@ static int tls_process_ske_dhe(SSL *s, PACKET *pkt, EVP_PKEY **pkey, int *al) #endif } +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; + + /* + * 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_KEY_EXCHANGE, 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_KEY_EXCHANGE, SSL_R_WRONG_CURVE); + return 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); + 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_KEY_EXCHANGE, ERR_R_EVP_LIB); + EVP_PKEY_CTX_free(pctx); + return 0; + } + EVP_PKEY_CTX_free(pctx); + pctx = NULL; + + if (!PACKET_get_length_prefixed_1(pkt, &encoded_pt)) { + *al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, SSL_R_LENGTH_MISMATCH); + 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) { + *al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, SSL_R_BAD_ECPOINT); + return 0; + } + + /* + * 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. */ + + return 1; +#else + SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR); + *al = SSL_AD_INTERNAL_ERROR; + return 0; +#endif +} + MSG_PROCESS_RETURN tls_process_key_exchange(SSL *s, PACKET *pkt) { EVP_MD_CTX *md_ctx; @@ -1528,87 +1611,14 @@ MSG_PROCESS_RETURN tls_process_key_exchange(SSL *s, PACKET *pkt) } else if (alg_k & (SSL_kDHE | SSL_kDHEPSK)) { if (!tls_process_ske_dhe(s, pkt, &pkey, &al)) goto err; - } -#ifndef OPENSSL_NO_EC - else if (alg_k & (SSL_kECDHE | SSL_kECDHEPSK)) { - PACKET encoded_pt; - const unsigned char *ecparams; - int curve_nid; - EVP_PKEY_CTX *pctx = NULL; - - /* - * 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; - } - - 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; - } - - /* 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); - EVP_PKEY_CTX_free(pctx); - 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(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; - } - - /* - * 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. */ + } 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; } -#endif /* !OPENSSL_NO_EC */ /* if it was signed, check the signature */ if (pkey != NULL) { -- GitLab