From f637004037a11bc04682f54571e3ff11d48d8e36 Mon Sep 17 00:00:00 2001 From: Matt Caswell Date: Fri, 24 Feb 2017 12:45:37 +0000 Subject: [PATCH] Only accept early_data if the negotiated ALPN is the same Reviewed-by: Rich Salz (Merged from https://github.com/openssl/openssl/pull/2737) --- ssl/ssl_asn1.c | 24 ++++++++++++++++++++---- ssl/ssl_locl.h | 3 +++ ssl/ssl_sess.c | 1 + ssl/statem/extensions.c | 6 +++++- ssl/statem/statem_srvr.c | 21 +++++++++++++++++---- 5 files changed, 46 insertions(+), 9 deletions(-) diff --git a/ssl/ssl_asn1.c b/ssl/ssl_asn1.c index 705db16470..856db205ef 100644 --- a/ssl/ssl_asn1.c +++ b/ssl/ssl_asn1.c @@ -66,6 +66,7 @@ typedef struct { #endif long flags; uint32_t max_early_data; + ASN1_OCTET_STRING *alpn_selected; } SSL_SESSION_ASN1; ASN1_SEQUENCE(SSL_SESSION_ASN1) = { @@ -93,7 +94,8 @@ ASN1_SEQUENCE(SSL_SESSION_ASN1) = { #endif ASN1_EXP_OPT(SSL_SESSION_ASN1, flags, ZLONG, 13), ASN1_EXP_OPT(SSL_SESSION_ASN1, tlsext_tick_age_add, ZLONG, 14), - ASN1_EXP_OPT(SSL_SESSION_ASN1, max_early_data, ZLONG, 15) + ASN1_EXP_OPT(SSL_SESSION_ASN1, max_early_data, ZLONG, 15), + ASN1_EXP_OPT(SSL_SESSION_ASN1, alpn_selected, ASN1_OCTET_STRING, 16) } static_ASN1_SEQUENCE_END(SSL_SESSION_ASN1) IMPLEMENT_STATIC_ASN1_ENCODE_FUNCTIONS(SSL_SESSION_ASN1) @@ -134,16 +136,14 @@ int i2d_SSL_SESSION(SSL_SESSION *in, unsigned char **pp) ASN1_OCTET_STRING comp_id; unsigned char comp_id_data; #endif - ASN1_OCTET_STRING tlsext_hostname, tlsext_tick; - #ifndef OPENSSL_NO_SRP ASN1_OCTET_STRING srp_username; #endif - #ifndef OPENSSL_NO_PSK ASN1_OCTET_STRING psk_identity, psk_identity_hint; #endif + ASN1_OCTET_STRING alpn_selected; long l; @@ -207,6 +207,12 @@ int i2d_SSL_SESSION(SSL_SESSION *in, unsigned char **pp) as.flags = in->flags; as.max_early_data = in->ext.max_early_data; + if (in->ext.alpn_selected == NULL) + as.alpn_selected = NULL; + else + ssl_session_oinit(&as.alpn_selected, &alpn_selected, + in->ext.alpn_selected, in->ext.alpn_selected_len); + return i2d_SSL_SESSION_ASN1(&as, pp); } @@ -362,6 +368,16 @@ SSL_SESSION *d2i_SSL_SESSION(SSL_SESSION **a, const unsigned char **pp, ret->flags = as->flags; ret->ext.max_early_data = as->max_early_data; + if (as->alpn_selected != NULL) { + if (!ssl_session_strndup((char **)&ret->ext.alpn_selected, + as->alpn_selected)) + goto err; + ret->ext.alpn_selected_len = as->alpn_selected->length; + } else { + ret->ext.alpn_selected = NULL; + ret->ext.alpn_selected_len = 0; + } + M_ASN1_free_of(as, SSL_SESSION_ASN1); if ((a != NULL) && (*a == NULL)) diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h index 9e71768903..d8d16eb944 100644 --- a/ssl/ssl_locl.h +++ b/ssl/ssl_locl.h @@ -580,6 +580,9 @@ struct ssl_session_st { int tick_identity; /* Max number of bytes that can be sent as early data */ uint32_t max_early_data; + /* The ALPN protocol selected for this session */ + unsigned char *alpn_selected; + size_t alpn_selected_len; } ext; # ifndef OPENSSL_NO_SRP char *srp_username; diff --git a/ssl/ssl_sess.c b/ssl/ssl_sess.c index be3c4c3526..cc9eeadc12 100644 --- a/ssl/ssl_sess.c +++ b/ssl/ssl_sess.c @@ -791,6 +791,7 @@ void SSL_SESSION_free(SSL_SESSION *ss) #ifndef OPENSSL_NO_SRP OPENSSL_free(ss->srp_username); #endif + OPENSSL_free(ss->ext.alpn_selected); CRYPTO_THREAD_lock_free(ss->lock); OPENSSL_clear_free(ss, sizeof(*ss)); } diff --git a/ssl/statem/extensions.c b/ssl/statem/extensions.c index fa6221f6e2..edcfe718c4 100644 --- a/ssl/statem/extensions.c +++ b/ssl/statem/extensions.c @@ -7,6 +7,7 @@ * https://www.openssl.org/source/license.html */ +#include #include "../ssl_locl.h" #include "statem_locl.h" @@ -1242,7 +1243,10 @@ static int final_early_data(SSL *s, unsigned int context, int sent, int *al) || s->session->ext.tick_identity != 0 || s->early_data_state != SSL_EARLY_DATA_ACCEPTING || !s->ext.early_data_ok - || s->hello_retry_request) { + || s->hello_retry_request + || s->s3->alpn_selected_len != s->session->ext.alpn_selected_len + || memcmp(s->s3->alpn_selected, s->session->ext.alpn_selected, + s->s3->alpn_selected_len) != 0){ s->ext.early_data = SSL_EARLY_DATA_REJECTED; } else { s->ext.early_data = SSL_EARLY_DATA_ACCEPTED; diff --git a/ssl/statem/statem_srvr.c b/ssl/statem/statem_srvr.c index 56db987ee4..571425d7b6 100644 --- a/ssl/statem/statem_srvr.c +++ b/ssl/statem/statem_srvr.c @@ -3401,6 +3401,18 @@ int tls_construct_new_session_ticket(SSL *s, WPACKET *pkt) goto err; s->session->ext.tick_age_add = age_add_u.age_add; s->session->time = (long)time(NULL); + if (s->s3->alpn_selected != NULL) { + OPENSSL_free(s->session->ext.alpn_selected); + s->session->ext.alpn_selected = + OPENSSL_memdup(s->s3->alpn_selected, s->s3->alpn_selected_len); + if (s->session->ext.alpn_selected == NULL) { + SSLerr(SSL_F_TLS_CONSTRUCT_NEW_SESSION_TICKET, + ERR_R_MALLOC_FAILURE); + goto err; + } + s->session->ext.alpn_selected_len = s->s3->alpn_selected_len; + } + s->session->ext.max_early_data = s->max_early_data; } /* get session encoding length */ @@ -3410,13 +3422,13 @@ int tls_construct_new_session_ticket(SSL *s, WPACKET *pkt) * long */ if (slen_full == 0 || slen_full > 0xFF00) { - ossl_statem_set_error(s); - return 0; + SSLerr(SSL_F_TLS_CONSTRUCT_NEW_SESSION_TICKET, ERR_R_INTERNAL_ERROR); + goto err; } senc = OPENSSL_malloc(slen_full); if (senc == NULL) { - ossl_statem_set_error(s); - return 0; + SSLerr(SSL_F_TLS_CONSTRUCT_NEW_SESSION_TICKET, ERR_R_MALLOC_FAILURE); + goto err; } ctx = EVP_CIPHER_CTX_new(); @@ -3545,6 +3557,7 @@ int tls_construct_new_session_ticket(SSL *s, WPACKET *pkt) return 1; err: + ossl_statem_set_error(s); OPENSSL_free(senc); EVP_CIPHER_CTX_free(ctx); HMAC_CTX_free(hctx); -- 2.25.1