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 <rsalz@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/2839)
diff --git a/ssl/ssl_err.c b/ssl/ssl_err.c
index 0ace985..ee1ca62 100644
--- a/ssl/ssl_err.c
+++ b/ssl/ssl_err.c
@@ -304,6 +304,7 @@
{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 @@
{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 fcf4f4d..f0e8639 100644
--- a/ssl/ssl_lib.c
+++ b/ssl/ssl_lib.c
@@ -1017,6 +1017,7 @@
#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 6811b4f..f4860ea 100644
--- a/ssl/ssl_locl.h
+++ b/ssl/ssl_locl.h
@@ -1211,6 +1211,10 @@
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 @@
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 edcfe71..8c4013e 100644
--- a/ssl/statem/extensions.c
+++ b/ssl/statem/extensions.c
@@ -270,6 +270,13 @@
},
#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
* SSL_OP_CRYPTOPRO_TLSEXT_BUG is set
diff --git a/ssl/statem/extensions_clnt.c b/ssl/statem/extensions_clnt.c
index 0af4d1b..23dc8d3 100644
--- a/ssl/statem/extensions_clnt.c
+++ b/ssl/statem/extensions_clnt.c
@@ -636,6 +636,33 @@
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 @@
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 c52ce2b..68160c9 100644
--- a/ssl/statem/statem_locl.h
+++ b/ssl/statem/statem_locl.h
@@ -332,6 +332,8 @@
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 @@
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);