From b1834ad781ee445f5f580e5dcf4792b96ae08d1d Mon Sep 17 00:00:00 2001 From: Matt Caswell Date: Tue, 1 Nov 2016 10:53:32 +0000 Subject: [PATCH] Add the key_share processing to the server side At the moment the server doesn't yet do anything with this information. We still need to send the server's key_share info back to the client. That will happen in subsequent commits. Reviewed-by: Rich Salz --- include/openssl/ssl.h | 1 + ssl/ssl_err.c | 1 + ssl/statem/statem_srvr.c | 9 ++++ ssl/t1_lib.c | 102 ++++++++++++++++++++++++++++++++++++++- 4 files changed, 112 insertions(+), 1 deletion(-) diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h index b61a992e16..dab0c4ee38 100644 --- a/include/openssl/ssl.h +++ b/include/openssl/ssl.h @@ -2427,6 +2427,7 @@ int ERR_load_SSL_strings(void); # define SSL_R_NO_SHARED_CIPHER 193 # define SSL_R_NO_SHARED_SIGNATURE_ALGORITHMS 376 # define SSL_R_NO_SRTP_PROFILES 359 +# define SSL_R_NO_SUITABLE_KEY_SHARE 101 # define SSL_R_NO_VALID_SCTS 216 # define SSL_R_NO_VERIFY_COOKIE_CALLBACK 403 # define SSL_R_NULL_SSL_CTX 195 diff --git a/ssl/ssl_err.c b/ssl/ssl_err.c index 6c438fe2fe..7523f1c76f 100644 --- a/ssl/ssl_err.c +++ b/ssl/ssl_err.c @@ -488,6 +488,7 @@ static ERR_STRING_DATA SSL_str_reasons[] = { {ERR_REASON(SSL_R_NO_SHARED_SIGNATURE_ALGORITHMS), "no shared signature algorithms"}, {ERR_REASON(SSL_R_NO_SRTP_PROFILES), "no srtp profiles"}, + {ERR_REASON(SSL_R_NO_SUITABLE_KEY_SHARE), "no suitable key share"}, {ERR_REASON(SSL_R_NO_VALID_SCTS), "no valid scts"}, {ERR_REASON(SSL_R_NO_VERIFY_COOKIE_CALLBACK), "no verify cookie callback"}, diff --git a/ssl/statem/statem_srvr.c b/ssl/statem/statem_srvr.c index 142c637dc9..38a1b6931d 100644 --- a/ssl/statem/statem_srvr.c +++ b/ssl/statem/statem_srvr.c @@ -1263,6 +1263,15 @@ MSG_PROCESS_RETURN tls_process_client_hello(SSL *s, PACKET *pkt) goto err; } + /* Check we've got a key_share for TLSv1.3 */ + if (s->version == TLS1_3_VERSION && s->s3->peer_tmp == NULL) { + /* No suitable share */ + /* TODO(1.3): Send a HelloRetryRequest */ + al = SSL_AD_HANDSHAKE_FAILURE; + SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, SSL_R_NO_SUITABLE_KEY_SHARE); + goto f_err; + } + /* * Check if we want to use external pre-shared secret for this handshake * for not reused session only. We need to generate server_random before diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c index d78ea684d8..37e6841d7e 100644 --- a/ssl/t1_lib.c +++ b/ssl/t1_lib.c @@ -2201,8 +2201,108 @@ static int ssl_scan_clienthello_tlsext(SSL *s, CLIENTHELLO_MSG *hello, int *al) } #endif else if (currext->type == TLSEXT_TYPE_encrypt_then_mac - && !(s->options & SSL_OP_NO_ENCRYPT_THEN_MAC)) + && !(s->options & SSL_OP_NO_ENCRYPT_THEN_MAC)) { s->s3->flags |= TLS1_FLAGS_ENCRYPT_THEN_MAC; + } else if (currext->type == TLSEXT_TYPE_key_share + && s->version == TLS1_3_VERSION) { + unsigned int group_id; + PACKET key_share_list, encoded_pt; + const unsigned char *curves; + size_t num_curves, i; + int group_nid; + unsigned int curve_flags; + + /* Sanity check */ + if (s->s3->peer_tmp != NULL) { + *al = SSL_AD_INTERNAL_ERROR; + SSLerr(SSL_F_SSL_SCAN_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR); + return 0; + } + + if (!PACKET_as_length_prefixed_2(&currext->data, &key_share_list)) { + *al = SSL_AD_HANDSHAKE_FAILURE; + SSLerr(SSL_F_SSL_SCAN_CLIENTHELLO_TLSEXT, + SSL_R_LENGTH_MISMATCH); + return 0; + } + + while (PACKET_remaining(&key_share_list) > 0) { + if (!PACKET_get_net_2(&key_share_list, &group_id) + || !PACKET_get_length_prefixed_2(&key_share_list, + &encoded_pt)) { + *al = SSL_AD_HANDSHAKE_FAILURE; + SSLerr(SSL_F_SSL_SCAN_CLIENTHELLO_TLSEXT, + SSL_R_LENGTH_MISMATCH); + return 0; + } + + /* Find a share that we can use */ + if (!tls1_get_curvelist(s, 0, &curves, &num_curves)) { + *al = SSL_AD_INTERNAL_ERROR; + SSLerr(SSL_F_SSL_SCAN_CLIENTHELLO_TLSEXT, + ERR_R_INTERNAL_ERROR); + return 0; + } + for (i = 0; i < num_curves; i++, curves += 2) { + unsigned int share_id = (curves[0] << 8) | (curves[1]); + if (group_id == share_id + && tls_curve_allowed(s, curves, + SSL_SECOP_CURVE_CHECK)) { + break; + } + } + + if (i == num_curves) { + /* Share not suitable */ + continue; + } + + group_nid = tls1_ec_curve_id2nid(group_id, &curve_flags); + + if (group_nid == 0) { + *al = SSL_AD_INTERNAL_ERROR; + SSLerr(SSL_F_SSL_SCAN_CLIENTHELLO_TLSEXT, + SSL_R_UNABLE_TO_FIND_ECDH_PARAMETERS); + return 0; + } + + if ((curve_flags & TLS_CURVE_TYPE) == TLS_CURVE_CUSTOM) { + /* Can happen for some curves, e.g. X25519 */ + EVP_PKEY *key = EVP_PKEY_new(); + + if (key == NULL || !EVP_PKEY_set_type(key, group_nid)) { + *al = SSL_AD_INTERNAL_ERROR; + SSLerr(SSL_F_SSL_SCAN_CLIENTHELLO_TLSEXT, ERR_R_EVP_LIB); + EVP_PKEY_free(key); + return 0; + } + s->s3->peer_tmp = key; + } else { + /* Set up EVP_PKEY with named curve as parameters */ + EVP_PKEY_CTX *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, + group_nid) <= 0 + || EVP_PKEY_paramgen(pctx, &s->s3->peer_tmp) <= 0) { + *al = SSL_AD_INTERNAL_ERROR; + SSLerr(SSL_F_SSL_SCAN_CLIENTHELLO_TLSEXT, ERR_R_EVP_LIB); + EVP_PKEY_CTX_free(pctx); + return 0; + } + EVP_PKEY_CTX_free(pctx); + pctx = NULL; + } + + if (!EVP_PKEY_set1_tls_encodedpoint(s->s3->peer_tmp, + PACKET_data(&encoded_pt), + PACKET_remaining(&encoded_pt))) { + *al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_SSL_SCAN_CLIENTHELLO_TLSEXT, SSL_R_BAD_ECPOINT); + return 0; + } + } + } /* * Note: extended master secret extension handled in * tls_check_client_ems_support() -- 2.25.1