stream-based transport protocols (e.g. QUIC) may not validate the source
address. In this case a TLSv1.3 application would be susceptible to this attack.
-As a counter measure to this issue TLSv1.3 and DTLS include a stateless cookie
+As a countermeasure to this issue TLSv1.3 and DTLS include a stateless cookie
mechanism. The idea is that when a client attempts to connect to a server it
sends a ClientHello message. The server responds with a HelloRetryRequest (in
TLSv1.3) or a HelloVerifyRequest (in DTLS) which contains a unique cookie. The
},
#endif
{
+ /* Must be after key_share */
TLSEXT_TYPE_cookie,
SSL_EXT_CLIENT_HELLO | SSL_EXT_TLS1_3_HELLO_RETRY_REQUEST
| SSL_EXT_TLS_IMPLEMENTATION_ONLY | SSL_EXT_TLS1_3_ONLY,
/*
* Message header + 2 bytes for protocol version + number of random bytes +
- * + number of bytes in legacy session id + 2 bytes for ciphersuite
- * + 1 byte for legacy compression + 2 bytes for extension block length
- * + 6 bytes for key_share extension + 4 bytes for cookie extension header
- * + the number of bytes in the cookie
+ * + 1 byte for legacy session id length + number of bytes in legacy session id
+ * + 2 bytes for ciphersuite + 1 byte for legacy compression
+ * + 2 bytes for extension block length + 6 bytes for key_share extension
+ * + 4 bytes for cookie extension header + the number of bytes in the cookie
*/
-#define MAX_HRR_SIZE (SSL3_HM_HEADER_LENGTH + 2 + SSL3_RANDOM_SIZE \
+#define MAX_HRR_SIZE (SSL3_HM_HEADER_LENGTH + 2 + SSL3_RANDOM_SIZE + 1 \
+ SSL_MAX_SSL_SESSION_ID_LENGTH + 2 + 1 + 2 + 6 + 4 \
+ MAX_COOKIE_SIZE)
return 0;
}
- hmaclen = sizeof(s->session_ctx->ext.cookie_hmac_key);
+ hmaclen = SHA256_DIGEST_LENGTH;
if (EVP_DigestSignInit(hctx, NULL, EVP_sha256(), NULL, pkey) <= 0
- || EVP_DigestSignUpdate(hctx, data,
- rawlen - SHA256_DIGEST_LENGTH) <= 0
- || EVP_DigestSignFinal(hctx, hmac, &hmaclen) <= 0
+ || EVP_DigestSign(hctx, hmac, &hmaclen, data,
+ rawlen - SHA256_DIGEST_LENGTH) <= 0
|| hmaclen != SHA256_DIGEST_LENGTH) {
EVP_MD_CTX_free(hctx);
EVP_PKEY_free(pkey);
* Not suitable as a real cookie generation function but good enough for
* testing!
*/
- memcpy(cookie, cookie_magic_value, sizeof(cookie_magic_value));
- *cookie_len = sizeof(cookie_magic_value);
+ memcpy(cookie, cookie_magic_value, sizeof(cookie_magic_value) - 1);
+ *cookie_len = sizeof(cookie_magic_value) - 1;
return 1;
}
static int verify_cookie_callback(SSL *ssl, const unsigned char *cookie,
unsigned int cookie_len)
{
- if (cookie_len == sizeof(cookie_magic_value)
+ if (cookie_len == sizeof(cookie_magic_value) - 1
&& memcmp(cookie, cookie_magic_value, cookie_len) == 0)
return 1;
|| !TEST_false(create_ssl_connection(serverssl, clientssl,
SSL_ERROR_WANT_READ))
/* This should fail because there is no cookie */
- || !TEST_int_le(SSL_stateless(serverssl), 0))
+ || !TEST_false(SSL_stateless(serverssl)))
goto end;
/* Abandon the connection from this client */
|| !TEST_false(create_ssl_connection(serverssl, clientssl,
SSL_ERROR_WANT_READ))
/* This should fail because there is no cookie */
- || !TEST_int_le(SSL_stateless(serverssl), 0)
+ || !TEST_false(SSL_stateless(serverssl))
/* Send the second ClientHello */
|| !TEST_false(create_ssl_connection(serverssl, clientssl,
SSL_ERROR_WANT_READ))
/* This should succeed because a cookie is now present */
- || !TEST_int_gt(SSL_stateless(serverssl), 0)
+ || !TEST_true(SSL_stateless(serverssl))
/* Complete the connection */
|| !TEST_true(create_ssl_connection(serverssl, clientssl,
SSL_ERROR_NONE)))