From cfef5027bf27a74098588e48829f0d058b4b0aea Mon Sep 17 00:00:00 2001 From: Matt Caswell Date: Thu, 2 Mar 2017 17:37:03 +0000 Subject: [PATCH] Add basic TLSv1.3 cookie support We do not allow the generation of TLSv1.3 cookies. But if we receive one in an HRR we will echo it back in the ClientHello. Reviewed-by: Rich Salz (Merged from https://github.com/openssl/openssl/pull/2839) --- include/openssl/ssl.h | 2 ++ include/openssl/tls1.h | 1 + ssl/ssl_err.c | 2 ++ ssl/ssl_lib.c | 1 + ssl/ssl_locl.h | 5 +++++ ssl/statem/extensions.c | 7 ++++++ ssl/statem/extensions_clnt.c | 43 ++++++++++++++++++++++++++++++++++++ ssl/statem/statem_locl.h | 4 ++++ 8 files changed, 65 insertions(+) diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h index 64a312c588..c569407701 100644 --- a/include/openssl/ssl.h +++ b/include/openssl/ssl.h @@ -2348,6 +2348,7 @@ int ERR_load_SSL_strings(void); # define SSL_F_TLS_CONSTRUCT_CLIENT_VERIFY 489 # define SSL_F_TLS_CONSTRUCT_CTOS_ALPN 466 # define SSL_F_TLS_CONSTRUCT_CTOS_CERTIFICATE 355 +# define SSL_F_TLS_CONSTRUCT_CTOS_COOKIE 535 # define SSL_F_TLS_CONSTRUCT_CTOS_EARLY_DATA 530 # define SSL_F_TLS_CONSTRUCT_CTOS_EC_PT_FORMATS 467 # define SSL_F_TLS_CONSTRUCT_CTOS_EMS 468 @@ -2408,6 +2409,7 @@ int ERR_load_SSL_strings(void); # define SSL_F_TLS_PARSE_CTOS_PSK 505 # define SSL_F_TLS_PARSE_CTOS_RENEGOTIATE 464 # define SSL_F_TLS_PARSE_CTOS_USE_SRTP 465 +# define SSL_F_TLS_PARSE_STOC_COOKIE 534 # define SSL_F_TLS_PARSE_STOC_EARLY_DATA_INFO 528 # define SSL_F_TLS_PARSE_STOC_KEY_SHARE 445 # define SSL_F_TLS_PARSE_STOC_PSK 502 diff --git a/include/openssl/tls1.h b/include/openssl/tls1.h index 10544872b3..280d131c6f 100644 --- a/include/openssl/tls1.h +++ b/include/openssl/tls1.h @@ -181,6 +181,7 @@ extern "C" { # define TLSEXT_TYPE_psk 41 # define TLSEXT_TYPE_early_data 42 # define TLSEXT_TYPE_supported_versions 43 +# define TLSEXT_TYPE_cookie 44 # define TLSEXT_TYPE_psk_kex_modes 45 # define TLSEXT_TYPE_early_data_info 46 diff --git a/ssl/ssl_err.c b/ssl/ssl_err.c index 0ace985cf2..ee1ca6293c 100644 --- a/ssl/ssl_err.c +++ b/ssl/ssl_err.c @@ -304,6 +304,7 @@ static ERR_STRING_DATA SSL_str_functs[] = { {ERR_FUNC(SSL_F_TLS_CONSTRUCT_CTOS_ALPN), "tls_construct_ctos_alpn"}, {ERR_FUNC(SSL_F_TLS_CONSTRUCT_CTOS_CERTIFICATE), "TLS_CONSTRUCT_CTOS_CERTIFICATE"}, + {ERR_FUNC(SSL_F_TLS_CONSTRUCT_CTOS_COOKIE), "tls_construct_ctos_cookie"}, {ERR_FUNC(SSL_F_TLS_CONSTRUCT_CTOS_EARLY_DATA), "tls_construct_ctos_early_data"}, {ERR_FUNC(SSL_F_TLS_CONSTRUCT_CTOS_EC_PT_FORMATS), @@ -401,6 +402,7 @@ static ERR_STRING_DATA SSL_str_functs[] = { {ERR_FUNC(SSL_F_TLS_PARSE_CTOS_RENEGOTIATE), "tls_parse_ctos_renegotiate"}, {ERR_FUNC(SSL_F_TLS_PARSE_CTOS_USE_SRTP), "tls_parse_ctos_use_srtp"}, + {ERR_FUNC(SSL_F_TLS_PARSE_STOC_COOKIE), "tls_parse_stoc_cookie"}, {ERR_FUNC(SSL_F_TLS_PARSE_STOC_EARLY_DATA_INFO), "tls_parse_stoc_early_data_info"}, {ERR_FUNC(SSL_F_TLS_PARSE_STOC_KEY_SHARE), "tls_parse_stoc_key_share"}, diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c index fcf4f4d347..f0e8639d61 100644 --- a/ssl/ssl_lib.c +++ b/ssl/ssl_lib.c @@ -1017,6 +1017,7 @@ void SSL_free(SSL *s) #endif OPENSSL_free(s->ext.ocsp.resp); OPENSSL_free(s->ext.alpn); + OPENSSL_free(s->ext.tls13_cookie); OPENSSL_free(s->clienthello); sk_X509_NAME_pop_free(s->client_CA, X509_NAME_free); diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h index 6811b4f3f4..f4860ea1fd 100644 --- a/ssl/ssl_locl.h +++ b/ssl/ssl_locl.h @@ -1211,6 +1211,10 @@ struct ssl_st { int early_data; /* Is the session suitable for early data? */ int early_data_ok; + + /* May be sent by a server in HRR. Must be echoed back in ClientHello */ + unsigned char *tls13_cookie; + size_t tls13_cookie_len; } ext; /* Parsed form of the ClientHello, kept around across early_cb calls. */ @@ -1801,6 +1805,7 @@ typedef enum tlsext_index_en { TLSEXT_IDX_supported_versions, TLSEXT_IDX_psk_kex_modes, TLSEXT_IDX_key_share, + TLSEXT_IDX_cookie, TLSEXT_IDX_cryptopro_bug, TLSEXT_IDX_early_data, TLSEXT_IDX_padding, diff --git a/ssl/statem/extensions.c b/ssl/statem/extensions.c index edcfe718c4..8c4013e416 100644 --- a/ssl/statem/extensions.c +++ b/ssl/statem/extensions.c @@ -269,6 +269,13 @@ static const EXTENSION_DEFINITION ext_defs[] = { final_key_share }, #endif + { + TLSEXT_TYPE_cookie, + EXT_CLIENT_HELLO | EXT_TLS1_3_HELLO_RETRY_REQUEST + | EXT_TLS_IMPLEMENTATION_ONLY | EXT_TLS1_3_ONLY, + NULL, NULL, tls_parse_stoc_cookie, NULL, tls_construct_ctos_cookie, + NULL + }, { /* * Special unsolicited ServerHello extension only used when diff --git a/ssl/statem/extensions_clnt.c b/ssl/statem/extensions_clnt.c index 0af4d1b588..23dc8d3363 100644 --- a/ssl/statem/extensions_clnt.c +++ b/ssl/statem/extensions_clnt.c @@ -636,6 +636,33 @@ int tls_construct_ctos_key_share(SSL *s, WPACKET *pkt, unsigned int context, return 1; } +int tls_construct_ctos_cookie(SSL *s, WPACKET *pkt, unsigned int context, + X509 *x, size_t chainidx, int *al) +{ + int ret = 0; + + /* Should only be set if we've had an HRR */ + if (s->ext.tls13_cookie_len == 0) + return 1; + + if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_cookie) + /* Extension data sub-packet */ + || !WPACKET_start_sub_packet_u16(pkt) + || !WPACKET_sub_memcpy_u16(pkt, s->ext.tls13_cookie, + s->ext.tls13_cookie_len) + || !WPACKET_close(pkt)) { + SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_COOKIE, ERR_R_INTERNAL_ERROR); + goto end; + } + + ret = 1; + end: + OPENSSL_free(s->ext.tls13_cookie); + s->ext.tls13_cookie_len = 0; + + return ret; +} + int tls_construct_ctos_early_data(SSL *s, WPACKET *pkt, unsigned int context, X509 *x, size_t chainidx, int *al) { @@ -1338,6 +1365,22 @@ int tls_parse_stoc_key_share(SSL *s, PACKET *pkt, unsigned int context, X509 *x, return 1; } +int tls_parse_stoc_cookie(SSL *s, PACKET *pkt, unsigned int context, X509 *x, + size_t chainidx, int *al) +{ + PACKET cookie; + + if (!PACKET_as_length_prefixed_2(pkt, &cookie) + || !PACKET_memdup(&cookie, &s->ext.tls13_cookie, + &s->ext.tls13_cookie_len)) { + *al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_TLS_PARSE_STOC_COOKIE, SSL_R_LENGTH_MISMATCH); + return 0; + } + + return 1; +} + int tls_parse_stoc_early_data(SSL *s, PACKET *pkt, unsigned int context, X509 *x, size_t chainidx, int *al) { diff --git a/ssl/statem/statem_locl.h b/ssl/statem/statem_locl.h index c52ce2bd16..68160c9bc7 100644 --- a/ssl/statem/statem_locl.h +++ b/ssl/statem/statem_locl.h @@ -332,6 +332,8 @@ int tls_construct_ctos_key_share(SSL *s, WPACKET *pkt, unsigned int context, X509 *x, size_t chainidx, int *al); int tls_construct_ctos_psk_kex_modes(SSL *s, WPACKET *pkt, unsigned int context, X509 *x, size_t chainidx, int *al); +int tls_construct_ctos_cookie(SSL *s, WPACKET *pkt, unsigned int context, + X509 *x, size_t chainidx, int *al); int tls_construct_ctos_padding(SSL *s, WPACKET *pkt, unsigned int context, X509 *x, size_t chainidx, int *al); int tls_construct_ctos_psk(SSL *s, WPACKET *pkt, unsigned int context, X509 *x, @@ -374,5 +376,7 @@ int tls_parse_stoc_ems(SSL *s, PACKET *pkt, unsigned int context, X509 *x, size_t chainidx, int *al); int tls_parse_stoc_key_share(SSL *s, PACKET *pkt, unsigned int context, X509 *x, size_t chainidx, int *al); +int tls_parse_stoc_cookie(SSL *s, PACKET *pkt, unsigned int context, X509 *x, + size_t chainidx, int *al); int tls_parse_stoc_psk(SSL *s, PACKET *pkt, unsigned int context, X509 *x, size_t chainidx, int *al);