From ffc5bbaaee2bfaba8d420e912c4d77b4090b896f Mon Sep 17 00:00:00 2001 From: Matt Caswell Date: Fri, 21 Jul 2017 11:41:05 +0100 Subject: [PATCH] Complain if we are writing early data but SNI or ALPN is incorrect SNI and ALPN must be set to be consistent with the PSK. Otherwise this is an error. Reviewed-by: Ben Kaduk (Merged from https://github.com/openssl/openssl/pull/3926) --- crypto/err/openssl.txt | 2 ++ include/openssl/sslerr.h | 2 ++ ssl/ssl_err.c | 4 +++ ssl/statem/extensions_clnt.c | 52 +++++++++++++++++++++++++++++++++--- 4 files changed, 56 insertions(+), 4 deletions(-) diff --git a/crypto/err/openssl.txt b/crypto/err/openssl.txt index 517c9f4803..4b3c55b010 100644 --- a/crypto/err/openssl.txt +++ b/crypto/err/openssl.txt @@ -2320,6 +2320,8 @@ SSL_R_ILLEGAL_POINT_COMPRESSION:162:illegal point compression SSL_R_ILLEGAL_SUITEB_DIGEST:380:illegal Suite B digest SSL_R_INAPPROPRIATE_FALLBACK:373:inappropriate fallback SSL_R_INCONSISTENT_COMPRESSION:340:inconsistent compression +SSL_R_INCONSISTENT_EARLY_DATA_ALPN:222:inconsistent early data alpn +SSL_R_INCONSISTENT_EARLY_DATA_SNI:231:inconsistent early data sni SSL_R_INCONSISTENT_EXTMS:104:inconsistent extms SSL_R_INVALID_ALERT:205:invalid alert SSL_R_INVALID_COMMAND:280:invalid command diff --git a/include/openssl/sslerr.h b/include/openssl/sslerr.h index bc4c17e4d1..91f6d21fb4 100644 --- a/include/openssl/sslerr.h +++ b/include/openssl/sslerr.h @@ -458,6 +458,8 @@ int ERR_load_SSL_strings(void); # define SSL_R_ILLEGAL_SUITEB_DIGEST 380 # define SSL_R_INAPPROPRIATE_FALLBACK 373 # define SSL_R_INCONSISTENT_COMPRESSION 340 +# define SSL_R_INCONSISTENT_EARLY_DATA_ALPN 222 +# define SSL_R_INCONSISTENT_EARLY_DATA_SNI 231 # define SSL_R_INCONSISTENT_EXTMS 104 # define SSL_R_INVALID_ALERT 205 # define SSL_R_INVALID_COMMAND 280 diff --git a/ssl/ssl_err.c b/ssl/ssl_err.c index dc1d439b1b..0ce7f271f3 100644 --- a/ssl/ssl_err.c +++ b/ssl/ssl_err.c @@ -724,6 +724,10 @@ static const ERR_STRING_DATA SSL_str_reasons[] = { "inappropriate fallback"}, {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INCONSISTENT_COMPRESSION), "inconsistent compression"}, + {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INCONSISTENT_EARLY_DATA_ALPN), + "inconsistent early data alpn"}, + {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INCONSISTENT_EARLY_DATA_SNI), + "inconsistent early data sni"}, {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INCONSISTENT_EXTMS), "inconsistent extms"}, {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INVALID_ALERT), "invalid alert"}, {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INVALID_COMMAND), "invalid command"}, diff --git a/ssl/statem/extensions_clnt.c b/ssl/statem/extensions_clnt.c index 86a1cab9ae..3a198f421c 100644 --- a/ssl/statem/extensions_clnt.c +++ b/ssl/statem/extensions_clnt.c @@ -682,13 +682,17 @@ EXT_RETURN tls_construct_ctos_early_data(SSL *s, WPACKET *pkt, const unsigned char *id; size_t idlen; SSL_SESSION *psksess = NULL; + SSL_SESSION *edsess = NULL; const EVP_MD *handmd = NULL; if (s->hello_retry_request) handmd = ssl_handshake_md(s); if (s->psk_use_session_cb != NULL - && !s->psk_use_session_cb(s, handmd, &id, &idlen, &psksess)) { + && (!s->psk_use_session_cb(s, handmd, &id, &idlen, &psksess) + || (psksess != NULL + && psksess->ssl_version != TLS1_3_VERSION))) { + SSL_SESSION_free(psksess); SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_EARLY_DATA, SSL_R_BAD_PSK); return EXT_RETURN_FAIL; } @@ -711,9 +715,49 @@ EXT_RETURN tls_construct_ctos_early_data(SSL *s, WPACKET *pkt, s->max_early_data = 0; return EXT_RETURN_NOT_SENT; } - s->max_early_data = s->session->ext.max_early_data != 0 ? - s->session->ext.max_early_data - : psksess->ext.max_early_data; + edsess = s->session->ext.max_early_data != 0 ? s->session : psksess; + s->max_early_data = edsess->ext.max_early_data; + + if ((s->ext.hostname == NULL && edsess->ext.hostname != NULL) + || (s->ext.hostname != NULL + && (edsess->ext.hostname == NULL + || strcmp(s->ext.hostname, edsess->ext.hostname) != 0))) { + SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_EARLY_DATA, + SSL_R_INCONSISTENT_EARLY_DATA_SNI); + return EXT_RETURN_FAIL; + } + + if ((s->ext.alpn == NULL && edsess->ext.alpn_selected != NULL)) { + SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_EARLY_DATA, + SSL_R_INCONSISTENT_EARLY_DATA_ALPN); + return EXT_RETURN_FAIL; + } + + /* + * Verify that we are offering an ALPN protocol consistent with the early + * data. + */ + if (edsess->ext.alpn_selected != NULL) { + PACKET prots, alpnpkt; + int found = 0; + + if (!PACKET_buf_init(&prots, s->ext.alpn, s->ext.alpn_len)) { + SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_EARLY_DATA, ERR_R_INTERNAL_ERROR); + return EXT_RETURN_FAIL; + } + while (PACKET_get_length_prefixed_1(&prots, &alpnpkt)) { + if (PACKET_equal(&alpnpkt, edsess->ext.alpn_selected, + edsess->ext.alpn_selected_len)) { + found = 1; + break; + } + } + if (!found) { + SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_EARLY_DATA, + SSL_R_INCONSISTENT_EARLY_DATA_ALPN); + return EXT_RETURN_FAIL; + } + } if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_early_data) || !WPACKET_start_sub_packet_u16(pkt) -- GitLab