Add support for sending TLSv1.3 cookies
This just adds the various extension functions. More changes will be required to actually use them. Reviewed-by: Ben Kaduk <kaduk@mit.edu> (Merged from https://github.com/openssl/openssl/pull/4435)
This commit is contained in:
parent
14262ca950
commit
43054d3d73
14 changed files with 437 additions and 13 deletions
|
@ -1275,6 +1275,7 @@ SSL_F_TLS_CONSTRUCT_SERVER_HELLO:491:tls_construct_server_hello
|
|||
SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE:492:tls_construct_server_key_exchange
|
||||
SSL_F_TLS_CONSTRUCT_STOC_ALPN:451:tls_construct_stoc_alpn
|
||||
SSL_F_TLS_CONSTRUCT_STOC_CERTIFICATE:374:*
|
||||
SSL_F_TLS_CONSTRUCT_STOC_COOKIE:613:tls_construct_stoc_cookie
|
||||
SSL_F_TLS_CONSTRUCT_STOC_CRYPTOPRO_BUG:452:tls_construct_stoc_cryptopro_bug
|
||||
SSL_F_TLS_CONSTRUCT_STOC_DONE:375:*
|
||||
SSL_F_TLS_CONSTRUCT_STOC_EARLY_DATA:531:tls_construct_stoc_early_data
|
||||
|
@ -1307,6 +1308,7 @@ SSL_F_TLS_HANDLE_STATUS_REQUEST:563:tls_handle_status_request
|
|||
SSL_F_TLS_PARSE_CERTIFICATE_AUTHORITIES:566:tls_parse_certificate_authorities
|
||||
SSL_F_TLS_PARSE_CLIENTHELLO_TLSEXT:449:*
|
||||
SSL_F_TLS_PARSE_CTOS_ALPN:567:tls_parse_ctos_alpn
|
||||
SSL_F_TLS_PARSE_CTOS_COOKIE:614:tls_parse_ctos_cookie
|
||||
SSL_F_TLS_PARSE_CTOS_EARLY_DATA:568:tls_parse_ctos_early_data
|
||||
SSL_F_TLS_PARSE_CTOS_EC_PT_FORMATS:569:tls_parse_ctos_ec_pt_formats
|
||||
SSL_F_TLS_PARSE_CTOS_EMS:570:tls_parse_ctos_ems
|
||||
|
|
|
@ -26,6 +26,10 @@ extern "C" {
|
|||
# define DTLS_ANY_VERSION 0x1FFFF
|
||||
|
||||
/* lengths of messages */
|
||||
/*
|
||||
* Actually the max cookie length in DTLS is 255. But we can't change this now
|
||||
* due to compatibility concerns.
|
||||
*/
|
||||
# define DTLS1_COOKIE_LENGTH 256
|
||||
|
||||
# define DTLS1_RT_HEADER_LENGTH 13
|
||||
|
|
|
@ -546,6 +546,9 @@ typedef int (*SSL_verify_cb)(int preverify_ok, X509_STORE_CTX *x509_ctx);
|
|||
# define SSL_CONF_TYPE_DIR 0x3
|
||||
# define SSL_CONF_TYPE_NONE 0x4
|
||||
|
||||
/* Length of a TLSv1.3 cookie */
|
||||
# define SSL_COOKIE_LENGTH 255
|
||||
|
||||
/*
|
||||
* Note: SSL[_CTX]_set_{options,mode} use |= op on the previous value, they
|
||||
* cannot be used to clear bits.
|
||||
|
|
|
@ -284,6 +284,8 @@ extern "C" {
|
|||
|
||||
# define TLS1_FLAGS_ENCRYPT_THEN_MAC_WRITE 0x0400
|
||||
|
||||
# define TLS1_FLAGS_STATELESS 0x0800
|
||||
|
||||
# define SSL3_MT_HELLO_REQUEST 0
|
||||
# define SSL3_MT_CLIENT_HELLO 1
|
||||
# define SSL3_MT_SERVER_HELLO 2
|
||||
|
|
|
@ -322,6 +322,7 @@ int ERR_load_SSL_strings(void);
|
|||
# define SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE 492
|
||||
# define SSL_F_TLS_CONSTRUCT_STOC_ALPN 451
|
||||
# define SSL_F_TLS_CONSTRUCT_STOC_CERTIFICATE 374
|
||||
# define SSL_F_TLS_CONSTRUCT_STOC_COOKIE 613
|
||||
# define SSL_F_TLS_CONSTRUCT_STOC_CRYPTOPRO_BUG 452
|
||||
# define SSL_F_TLS_CONSTRUCT_STOC_DONE 375
|
||||
# define SSL_F_TLS_CONSTRUCT_STOC_EARLY_DATA 531
|
||||
|
@ -351,6 +352,7 @@ int ERR_load_SSL_strings(void);
|
|||
# define SSL_F_TLS_PARSE_CERTIFICATE_AUTHORITIES 566
|
||||
# define SSL_F_TLS_PARSE_CLIENTHELLO_TLSEXT 449
|
||||
# define SSL_F_TLS_PARSE_CTOS_ALPN 567
|
||||
# define SSL_F_TLS_PARSE_CTOS_COOKIE 614
|
||||
# define SSL_F_TLS_PARSE_CTOS_EARLY_DATA 568
|
||||
# define SSL_F_TLS_PARSE_CTOS_EC_PT_FORMATS 569
|
||||
# define SSL_F_TLS_PARSE_CTOS_EMS 570
|
||||
|
|
|
@ -492,6 +492,8 @@ static const ERR_STRING_DATA SSL_str_functs[] = {
|
|||
{ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_CONSTRUCT_STOC_ALPN, 0),
|
||||
"tls_construct_stoc_alpn"},
|
||||
{ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_CONSTRUCT_STOC_CERTIFICATE, 0), ""},
|
||||
{ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_CONSTRUCT_STOC_COOKIE, 0),
|
||||
"tls_construct_stoc_cookie"},
|
||||
{ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_CONSTRUCT_STOC_CRYPTOPRO_BUG, 0),
|
||||
"tls_construct_stoc_cryptopro_bug"},
|
||||
{ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_CONSTRUCT_STOC_DONE, 0), ""},
|
||||
|
@ -544,6 +546,8 @@ static const ERR_STRING_DATA SSL_str_functs[] = {
|
|||
{ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_PARSE_CLIENTHELLO_TLSEXT, 0), ""},
|
||||
{ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_PARSE_CTOS_ALPN, 0),
|
||||
"tls_parse_ctos_alpn"},
|
||||
{ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_PARSE_CTOS_COOKIE, 0),
|
||||
"tls_parse_ctos_cookie"},
|
||||
{ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_PARSE_CTOS_EARLY_DATA, 0),
|
||||
"tls_parse_ctos_early_data"},
|
||||
{ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_PARSE_CTOS_EC_PT_FORMATS, 0),
|
||||
|
|
|
@ -2939,6 +2939,10 @@ SSL_CTX *SSL_CTX_new(const SSL_METHOD *meth)
|
|||
sizeof(ret->ext.tick_aes_key)) <= 0))
|
||||
ret->options |= SSL_OP_NO_TICKET;
|
||||
|
||||
if (RAND_bytes(ret->ext.cookie_hmac_key,
|
||||
sizeof(ret->ext.cookie_hmac_key)) <= 0)
|
||||
goto err;
|
||||
|
||||
#ifndef OPENSSL_NO_SRP
|
||||
if (!SSL_CTX_SRP_CTX_init(ret))
|
||||
goto err;
|
||||
|
|
|
@ -972,6 +972,8 @@ struct ssl_ctx_st {
|
|||
SSL_CTX_npn_select_cb_func npn_select_cb;
|
||||
void *npn_select_cb_arg;
|
||||
# endif
|
||||
|
||||
unsigned char cookie_hmac_key[SHA256_DIGEST_LENGTH];
|
||||
} ext;
|
||||
|
||||
# ifndef OPENSSL_NO_PSK
|
||||
|
|
|
@ -323,8 +323,8 @@ static const EXTENSION_DEFINITION ext_defs[] = {
|
|||
TLSEXT_TYPE_cookie,
|
||||
SSL_EXT_CLIENT_HELLO | SSL_EXT_TLS1_3_HELLO_RETRY_REQUEST
|
||||
| SSL_EXT_TLS_IMPLEMENTATION_ONLY | SSL_EXT_TLS1_3_ONLY,
|
||||
NULL, NULL, tls_parse_stoc_cookie, NULL, tls_construct_ctos_cookie,
|
||||
NULL
|
||||
NULL, tls_parse_ctos_cookie, tls_parse_stoc_cookie,
|
||||
tls_construct_stoc_cookie, tls_construct_ctos_cookie, NULL
|
||||
},
|
||||
{
|
||||
/*
|
||||
|
|
|
@ -10,6 +10,30 @@
|
|||
#include <openssl/ocsp.h>
|
||||
#include "../ssl_locl.h"
|
||||
#include "statem_locl.h"
|
||||
#include "internal/cryptlib.h"
|
||||
|
||||
#define COOKIE_STATE_FORMAT_VERSION 0
|
||||
|
||||
/*
|
||||
* 2 bytes for packet length, 2 bytes for format version, 2 bytes for
|
||||
* protocol version, 2 bytes for group id, 2 bytes for cipher id, 1 byte for
|
||||
* key_share present flag, 2 bytes for the hashlen, EVP_MAX_MD_SIZE for
|
||||
* transcript hash, 1 byte for app cookie length, app cookie length bytes,
|
||||
* SHA256_DIGEST_LENGTH bytes for the HMAC of the whole thing.
|
||||
*/
|
||||
#define MAX_COOKIE_SIZE (2 + 2 + 2 + 2 + 2 + 1 + 2 + EVP_MAX_MD_SIZE + 1 \
|
||||
+ SSL_COOKIE_LENGTH + SHA256_DIGEST_LENGTH)
|
||||
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
#define MAX_HRR_SIZE (SSL3_HM_HEADER_LENGTH + 2 + SSL3_RANDOM_SIZE \
|
||||
+ SSL_MAX_SSL_SESSION_ID_LENGTH + 2 + 1 + 2 + 6 + 4 \
|
||||
+ MAX_COOKIE_SIZE)
|
||||
|
||||
/*
|
||||
* Parse the client's renegotiation binding and abort if it's not right
|
||||
|
@ -594,6 +618,17 @@ int tls_parse_ctos_key_share(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (s->s3->group_id != 0 && PACKET_remaining(&key_share_list) == 0) {
|
||||
/*
|
||||
* If we set a group_id already, then we must have sent an HRR
|
||||
* requesting a new key_share. If we haven't got one then that is an
|
||||
* error
|
||||
*/
|
||||
SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_F_TLS_PARSE_CTOS_KEY_SHARE,
|
||||
SSL_R_BAD_KEY_SHARE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (PACKET_remaining(&key_share_list) > 0) {
|
||||
if (!PACKET_get_net_2(&key_share_list, &group_id)
|
||||
|| !PACKET_get_length_prefixed_2(&key_share_list, &encoded_pt)
|
||||
|
@ -610,6 +645,18 @@ int tls_parse_ctos_key_share(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
|
|||
if (found)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* If we sent an HRR then the key_share sent back MUST be for the group
|
||||
* we requested, and must be the only key_share sent.
|
||||
*/
|
||||
if (s->s3->group_id != 0
|
||||
&& (group_id != s->s3->group_id
|
||||
|| PACKET_remaining(&key_share_list) != 0)) {
|
||||
SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER,
|
||||
SSL_F_TLS_PARSE_CTOS_KEY_SHARE, SSL_R_BAD_KEY_SHARE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Check if this share is in supported_groups sent from client */
|
||||
if (!check_in_list(s, group_id, clntgroups, clnt_num_groups, 0)) {
|
||||
SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER,
|
||||
|
@ -646,6 +693,211 @@ int tls_parse_ctos_key_share(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
|
|||
return 1;
|
||||
}
|
||||
|
||||
int tls_parse_ctos_cookie(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
|
||||
size_t chainidx)
|
||||
{
|
||||
unsigned int format, version, key_share;
|
||||
EVP_MD_CTX *hctx;
|
||||
EVP_PKEY *pkey;
|
||||
PACKET cookie, raw, chhash, appcookie;
|
||||
WPACKET hrrpkt;
|
||||
const unsigned char *data, *mdin, *ciphdata;
|
||||
unsigned char hmac[SHA256_DIGEST_LENGTH];
|
||||
unsigned char hrr[MAX_HRR_SIZE];
|
||||
size_t rawlen, hmaclen, hrrlen, ciphlen;
|
||||
|
||||
/* Ignore any cookie if we're not set up to verify it */
|
||||
if (s->ctx->app_verify_cookie_cb == NULL
|
||||
|| (s->s3->flags & TLS1_FLAGS_STATELESS) == 0)
|
||||
return 1;
|
||||
|
||||
if (!PACKET_as_length_prefixed_2(pkt, &cookie)) {
|
||||
SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PARSE_CTOS_COOKIE,
|
||||
SSL_R_LENGTH_MISMATCH);
|
||||
return 0;
|
||||
}
|
||||
|
||||
raw = cookie;
|
||||
data = PACKET_data(&raw);
|
||||
rawlen = PACKET_remaining(&raw);
|
||||
if (rawlen < SHA256_DIGEST_LENGTH
|
||||
|| !PACKET_forward(&raw, rawlen - SHA256_DIGEST_LENGTH)) {
|
||||
SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PARSE_CTOS_COOKIE,
|
||||
SSL_R_LENGTH_MISMATCH);
|
||||
return 0;
|
||||
}
|
||||
mdin = PACKET_data(&raw);
|
||||
|
||||
/* Verify the HMAC of the cookie */
|
||||
hctx = EVP_MD_CTX_create();
|
||||
pkey = EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, NULL,
|
||||
s->session_ctx->ext.cookie_hmac_key,
|
||||
sizeof(s->session_ctx->ext.cookie_hmac_key));
|
||||
if (hctx == NULL || pkey == NULL) {
|
||||
EVP_MD_CTX_free(hctx);
|
||||
EVP_PKEY_free(pkey);
|
||||
SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PARSE_CTOS_COOKIE,
|
||||
ERR_R_MALLOC_FAILURE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
hmaclen = sizeof(s->session_ctx->ext.cookie_hmac_key);
|
||||
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
|
||||
|| hmaclen != SHA256_DIGEST_LENGTH) {
|
||||
EVP_MD_CTX_free(hctx);
|
||||
EVP_PKEY_free(pkey);
|
||||
SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PARSE_CTOS_COOKIE,
|
||||
ERR_R_INTERNAL_ERROR);
|
||||
return 0;
|
||||
}
|
||||
|
||||
EVP_MD_CTX_free(hctx);
|
||||
EVP_PKEY_free(pkey);
|
||||
|
||||
if (CRYPTO_memcmp(hmac, mdin, SHA256_DIGEST_LENGTH) != 0) {
|
||||
SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_F_TLS_PARSE_CTOS_COOKIE,
|
||||
SSL_R_COOKIE_MISMATCH);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!PACKET_get_net_2(&cookie, &format)) {
|
||||
SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PARSE_CTOS_COOKIE,
|
||||
SSL_R_LENGTH_MISMATCH);
|
||||
return 0;
|
||||
}
|
||||
/* Check the cookie format is something we recognise. Ignore it if not */
|
||||
if (format != COOKIE_STATE_FORMAT_VERSION)
|
||||
return 1;
|
||||
|
||||
/*
|
||||
* The rest of these checks really shouldn't fail since we have verified the
|
||||
* HMAC above.
|
||||
*/
|
||||
|
||||
/* Check the version number is sane */
|
||||
if (!PACKET_get_net_2(&cookie, &version)) {
|
||||
SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PARSE_CTOS_COOKIE,
|
||||
SSL_R_LENGTH_MISMATCH);
|
||||
return 0;
|
||||
}
|
||||
if (version != TLS1_3_VERSION) {
|
||||
SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_F_TLS_PARSE_CTOS_COOKIE,
|
||||
SSL_R_BAD_PROTOCOL_VERSION_NUMBER);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!PACKET_get_net_2(&cookie, &s->s3->group_id)) {
|
||||
SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PARSE_CTOS_COOKIE,
|
||||
SSL_R_LENGTH_MISMATCH);
|
||||
return 0;
|
||||
}
|
||||
ciphdata = PACKET_data(&cookie);
|
||||
if (!PACKET_forward(&cookie, 2)) {
|
||||
SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PARSE_CTOS_COOKIE,
|
||||
SSL_R_LENGTH_MISMATCH);
|
||||
return 0;
|
||||
}
|
||||
s->s3->tmp.new_cipher = ssl_get_cipher_by_char(s, ciphdata, 0);
|
||||
if (s->s3->tmp.new_cipher == NULL) {
|
||||
SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PARSE_CTOS_COOKIE,
|
||||
ERR_R_INTERNAL_ERROR);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!PACKET_get_1(&cookie, &key_share)
|
||||
|| !PACKET_get_length_prefixed_2(&cookie, &chhash)
|
||||
|| !PACKET_get_length_prefixed_1(&cookie, &appcookie)
|
||||
|| PACKET_remaining(&cookie) != SHA256_DIGEST_LENGTH) {
|
||||
SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PARSE_CTOS_COOKIE,
|
||||
SSL_R_LENGTH_MISMATCH);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Verify the app cookie */
|
||||
if (s->ctx->app_verify_cookie_cb(s, PACKET_data(&appcookie),
|
||||
PACKET_remaining(&appcookie)) == 0) {
|
||||
SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_F_TLS_PARSE_CTOS_COOKIE,
|
||||
SSL_R_COOKIE_MISMATCH);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reconstruct the HRR that we would have sent in response to the original
|
||||
* ClientHello so we can add it to the transcript hash.
|
||||
* Note: This won't work with custom HRR extensions
|
||||
*/
|
||||
if (!WPACKET_init_static_len(&hrrpkt, hrr, sizeof(hrr), 0)) {
|
||||
SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PARSE_CTOS_COOKIE,
|
||||
ERR_R_INTERNAL_ERROR);
|
||||
return 0;
|
||||
}
|
||||
if (!WPACKET_put_bytes_u8(&hrrpkt, SSL3_MT_SERVER_HELLO)
|
||||
|| !WPACKET_start_sub_packet_u24(&hrrpkt)
|
||||
|| !WPACKET_put_bytes_u16(&hrrpkt, TLS1_2_VERSION)
|
||||
|| !WPACKET_memcpy(&hrrpkt, hrrrandom, SSL3_RANDOM_SIZE)
|
||||
|| !WPACKET_sub_memcpy_u8(&hrrpkt, s->tmp_session_id,
|
||||
s->tmp_session_id_len)
|
||||
|| !s->method->put_cipher_by_char(s->s3->tmp.new_cipher, &hrrpkt,
|
||||
&ciphlen)
|
||||
|| !WPACKET_put_bytes_u8(&hrrpkt, 0)
|
||||
|| !WPACKET_start_sub_packet_u16(&hrrpkt)) {
|
||||
WPACKET_cleanup(&hrrpkt);
|
||||
SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PARSE_CTOS_COOKIE,
|
||||
ERR_R_INTERNAL_ERROR);
|
||||
return 0;
|
||||
}
|
||||
if (!WPACKET_put_bytes_u16(&hrrpkt, TLSEXT_TYPE_supported_versions)
|
||||
|| !WPACKET_start_sub_packet_u16(&hrrpkt)
|
||||
/* TODO(TLS1.3): Fix this before release */
|
||||
|| !WPACKET_put_bytes_u16(&hrrpkt, TLS1_3_VERSION_DRAFT)
|
||||
|| !WPACKET_close(&hrrpkt)) {
|
||||
WPACKET_cleanup(&hrrpkt);
|
||||
SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PARSE_CTOS_COOKIE,
|
||||
ERR_R_INTERNAL_ERROR);
|
||||
return 0;
|
||||
}
|
||||
if (key_share) {
|
||||
if (!WPACKET_put_bytes_u16(&hrrpkt, TLSEXT_TYPE_key_share)
|
||||
|| !WPACKET_start_sub_packet_u16(&hrrpkt)
|
||||
|| !WPACKET_put_bytes_u16(&hrrpkt, s->s3->group_id)
|
||||
|| !WPACKET_close(&hrrpkt)) {
|
||||
WPACKET_cleanup(&hrrpkt);
|
||||
SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PARSE_CTOS_COOKIE,
|
||||
ERR_R_INTERNAL_ERROR);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (!WPACKET_put_bytes_u16(&hrrpkt, TLSEXT_TYPE_cookie)
|
||||
|| !WPACKET_start_sub_packet_u16(&hrrpkt)
|
||||
|| !WPACKET_sub_memcpy_u16(&hrrpkt, data, rawlen)
|
||||
|| !WPACKET_close(&hrrpkt) /* cookie extension */
|
||||
|| !WPACKET_close(&hrrpkt) /* extension block */
|
||||
|| !WPACKET_close(&hrrpkt) /* message */
|
||||
|| !WPACKET_get_total_written(&hrrpkt, &hrrlen)
|
||||
|| !WPACKET_finish(&hrrpkt)) {
|
||||
WPACKET_cleanup(&hrrpkt);
|
||||
SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PARSE_CTOS_COOKIE,
|
||||
ERR_R_INTERNAL_ERROR);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Reconstruct the transcript hash */
|
||||
if (!create_synthetic_message_hash(s, PACKET_data(&chhash),
|
||||
PACKET_remaining(&chhash), hrr,
|
||||
hrrlen)) {
|
||||
/* SSLfatal() already called */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Act as if this ClientHello came after a HelloRetryRequest */
|
||||
s->hello_retry_request = 1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifndef OPENSSL_NO_EC
|
||||
int tls_parse_ctos_supported_groups(SSL *s, PACKET *pkt, unsigned int context,
|
||||
X509 *x, size_t chainidx)
|
||||
|
@ -1313,6 +1565,129 @@ EXT_RETURN tls_construct_stoc_key_share(SSL *s, WPACKET *pkt,
|
|||
return EXT_RETURN_SENT;
|
||||
}
|
||||
|
||||
EXT_RETURN tls_construct_stoc_cookie(SSL *s, WPACKET *pkt, unsigned int context,
|
||||
X509 *x, size_t chainidx)
|
||||
{
|
||||
unsigned char *hashval1, *hashval2, *appcookie1, *appcookie2, *cookie;
|
||||
unsigned char *hmac, *hmac2;
|
||||
size_t startlen, ciphlen, totcookielen, hashlen, hmaclen;
|
||||
unsigned int appcookielen;
|
||||
EVP_MD_CTX *hctx;
|
||||
EVP_PKEY *pkey;
|
||||
int ret = EXT_RETURN_FAIL;
|
||||
|
||||
if (s->ctx->app_gen_cookie_cb == NULL
|
||||
|| (s->s3->flags & TLS1_FLAGS_STATELESS) == 0)
|
||||
return EXT_RETURN_NOT_SENT;
|
||||
|
||||
if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_cookie)
|
||||
|| !WPACKET_start_sub_packet_u16(pkt)
|
||||
|| !WPACKET_start_sub_packet_u16(pkt)
|
||||
|| !WPACKET_get_total_written(pkt, &startlen)
|
||||
|| !WPACKET_reserve_bytes(pkt, MAX_COOKIE_SIZE, &cookie)
|
||||
|| !WPACKET_put_bytes_u16(pkt, COOKIE_STATE_FORMAT_VERSION)
|
||||
|| !WPACKET_put_bytes_u16(pkt, TLS1_3_VERSION)
|
||||
|| !WPACKET_put_bytes_u16(pkt, s->s3->group_id)
|
||||
|| !s->method->put_cipher_by_char(s->s3->tmp.new_cipher, pkt,
|
||||
&ciphlen)
|
||||
/* Is there a key_share extension present in this HRR? */
|
||||
|| !WPACKET_put_bytes_u8(pkt, s->s3->peer_tmp == NULL)
|
||||
|| !WPACKET_start_sub_packet_u16(pkt)
|
||||
|| !WPACKET_reserve_bytes(pkt, EVP_MAX_MD_SIZE, &hashval1)) {
|
||||
SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_STOC_COOKIE,
|
||||
ERR_R_INTERNAL_ERROR);
|
||||
return EXT_RETURN_FAIL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the hash of the initial ClientHello. ssl_handshake_hash() operates
|
||||
* on raw buffers, so we first reserve sufficient bytes (above) and then
|
||||
* subsequently allocate them (below)
|
||||
*/
|
||||
if (!ssl3_digest_cached_records(s, 0)
|
||||
|| !ssl_handshake_hash(s, hashval1, EVP_MAX_MD_SIZE, &hashlen)) {
|
||||
/* SSLfatal() already called */
|
||||
return EXT_RETURN_FAIL;
|
||||
}
|
||||
|
||||
if (!WPACKET_allocate_bytes(pkt, hashlen, &hashval2)
|
||||
|| !ossl_assert(hashval1 == hashval2)
|
||||
|| !WPACKET_close(pkt)
|
||||
|| !WPACKET_start_sub_packet_u8(pkt)
|
||||
|| !WPACKET_reserve_bytes(pkt, SSL_COOKIE_LENGTH, &appcookie1)) {
|
||||
SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_STOC_COOKIE,
|
||||
ERR_R_INTERNAL_ERROR);
|
||||
return EXT_RETURN_FAIL;
|
||||
}
|
||||
|
||||
/* Generate the application cookie */
|
||||
if (s->ctx->app_gen_cookie_cb(s, appcookie1, &appcookielen) == 0) {
|
||||
SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_STOC_COOKIE,
|
||||
SSL_R_COOKIE_GEN_CALLBACK_FAILURE);
|
||||
return EXT_RETURN_FAIL;
|
||||
}
|
||||
|
||||
if (!WPACKET_allocate_bytes(pkt, appcookielen, &appcookie2)
|
||||
|| !ossl_assert(appcookie1 == appcookie2)
|
||||
|| !WPACKET_close(pkt)
|
||||
|| !WPACKET_get_total_written(pkt, &totcookielen)
|
||||
|| !WPACKET_reserve_bytes(pkt, SHA256_DIGEST_LENGTH, &hmac)) {
|
||||
SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_STOC_COOKIE,
|
||||
ERR_R_INTERNAL_ERROR);
|
||||
return EXT_RETURN_FAIL;
|
||||
}
|
||||
hmaclen = SHA256_DIGEST_LENGTH;
|
||||
|
||||
totcookielen -= startlen;
|
||||
if (!ossl_assert(totcookielen <= MAX_COOKIE_SIZE - SHA256_DIGEST_LENGTH)) {
|
||||
SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_STOC_COOKIE,
|
||||
ERR_R_INTERNAL_ERROR);
|
||||
return EXT_RETURN_FAIL;
|
||||
}
|
||||
|
||||
/* HMAC the cookie */
|
||||
hctx = EVP_MD_CTX_create();
|
||||
pkey = EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, NULL,
|
||||
s->session_ctx->ext.cookie_hmac_key,
|
||||
sizeof(s->session_ctx->ext.cookie_hmac_key));
|
||||
if (hctx == NULL || pkey == NULL) {
|
||||
SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_STOC_COOKIE,
|
||||
ERR_R_MALLOC_FAILURE);
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (EVP_DigestSignInit(hctx, NULL, EVP_sha256(), NULL, pkey) <= 0
|
||||
|| EVP_DigestSign(hctx, hmac, &hmaclen, cookie,
|
||||
totcookielen) <= 0) {
|
||||
SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_STOC_COOKIE,
|
||||
ERR_R_INTERNAL_ERROR);
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (!ossl_assert(totcookielen + hmaclen <= MAX_COOKIE_SIZE)) {
|
||||
SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_STOC_COOKIE,
|
||||
ERR_R_INTERNAL_ERROR);
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (!WPACKET_allocate_bytes(pkt, hmaclen, &hmac2)
|
||||
|| !ossl_assert(hmac == hmac2)
|
||||
|| !ossl_assert(cookie == hmac - totcookielen)
|
||||
|| !WPACKET_close(pkt)
|
||||
|| !WPACKET_close(pkt)) {
|
||||
SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_STOC_COOKIE,
|
||||
ERR_R_INTERNAL_ERROR);
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = EXT_RETURN_SENT;
|
||||
|
||||
err:
|
||||
EVP_MD_CTX_free(hctx);
|
||||
EVP_PKEY_free(pkey);
|
||||
return ret;
|
||||
}
|
||||
|
||||
EXT_RETURN tls_construct_stoc_cryptopro_bug(SSL *s, WPACKET *pkt,
|
||||
unsigned int context, X509 *x,
|
||||
size_t chainidx)
|
||||
|
|
|
@ -1739,7 +1739,7 @@ static MSG_PROCESS_RETURN tls_process_as_hello_retry_request(SSL *s,
|
|||
* Re-initialise the Transcript Hash. We're going to prepopulate it with
|
||||
* a synthetic message_hash in place of ClientHello1.
|
||||
*/
|
||||
if (!create_synthetic_message_hash(s)) {
|
||||
if (!create_synthetic_message_hash(s, NULL, 0, NULL, 0)) {
|
||||
/* SSLfatal() already called */
|
||||
goto err;
|
||||
}
|
||||
|
|
|
@ -2033,19 +2033,25 @@ int check_in_list(SSL *s, uint16_t group_id, const uint16_t *groups,
|
|||
#endif
|
||||
|
||||
/* Replace ClientHello1 in the transcript hash with a synthetic message */
|
||||
int create_synthetic_message_hash(SSL *s)
|
||||
int create_synthetic_message_hash(SSL *s, const unsigned char *hashval,
|
||||
size_t hashlen, const unsigned char *hrr,
|
||||
size_t hrrlen)
|
||||
{
|
||||
unsigned char hashval[EVP_MAX_MD_SIZE];
|
||||
size_t hashlen = 0;
|
||||
unsigned char hashvaltmp[EVP_MAX_MD_SIZE];
|
||||
unsigned char msghdr[SSL3_HM_HEADER_LENGTH];
|
||||
|
||||
memset(msghdr, 0, sizeof(msghdr));
|
||||
|
||||
/* Get the hash of the initial ClientHello */
|
||||
if (!ssl3_digest_cached_records(s, 0)
|
||||
|| !ssl_handshake_hash(s, hashval, sizeof(hashval), &hashlen)) {
|
||||
/* SSLfatal() already called */
|
||||
return 0;
|
||||
if (hashval == NULL) {
|
||||
hashval = hashvaltmp;
|
||||
hashlen = 0;
|
||||
/* Get the hash of the initial ClientHello */
|
||||
if (!ssl3_digest_cached_records(s, 0)
|
||||
|| !ssl_handshake_hash(s, hashvaltmp, sizeof(hashvaltmp),
|
||||
&hashlen)) {
|
||||
/* SSLfatal() already called */
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Reinitialise the transcript hash */
|
||||
|
@ -2063,6 +2069,20 @@ int create_synthetic_message_hash(SSL *s)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Now re-inject the HRR and current message if appropriate (we just deleted
|
||||
* it when we reinitialised the transcript hash above). Only necessary after
|
||||
* receiving a ClientHello2 with a cookie.
|
||||
*/
|
||||
if (hrr != NULL
|
||||
&& (!ssl3_finish_mac(s, hrr, hrrlen)
|
||||
|| !ssl3_finish_mac(s, (unsigned char *)s->init_buf->data,
|
||||
s->s3->tmp.message_size
|
||||
+ SSL3_HM_HEADER_LENGTH))) {
|
||||
/* SSLfatal() already called */
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
|
@ -56,7 +56,9 @@ typedef int (*confunc_f) (SSL *s, WPACKET *pkt);
|
|||
|
||||
int check_in_list(SSL *s, uint16_t group_id, const uint16_t *groups,
|
||||
size_t num_groups, int checkallow);
|
||||
int create_synthetic_message_hash(SSL *s);
|
||||
int create_synthetic_message_hash(SSL *s, const unsigned char *hashval,
|
||||
size_t hashlen, const unsigned char *hrr,
|
||||
size_t hrrlen);
|
||||
int parse_ca_names(SSL *s, PACKET *pkt);
|
||||
int construct_ca_names(SSL *s, WPACKET *pkt);
|
||||
size_t construct_key_exchange_tbs(SSL *s, unsigned char **ptbs,
|
||||
|
@ -223,6 +225,8 @@ int tls_parse_ctos_etm(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
|
|||
size_t chainidx);
|
||||
int tls_parse_ctos_key_share(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
|
||||
size_t chainidx);
|
||||
int tls_parse_ctos_cookie(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
|
||||
size_t chainidx);
|
||||
int tls_parse_ctos_ems(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
|
||||
size_t chainidx);
|
||||
int tls_parse_ctos_psk_kex_modes(SSL *s, PACKET *pkt, unsigned int context,
|
||||
|
@ -279,6 +283,8 @@ EXT_RETURN tls_construct_stoc_supported_versions(SSL *s, WPACKET *pkt,
|
|||
EXT_RETURN tls_construct_stoc_key_share(SSL *s, WPACKET *pkt,
|
||||
unsigned int context, X509 *x,
|
||||
size_t chainidx);
|
||||
EXT_RETURN tls_construct_stoc_cookie(SSL *s, WPACKET *pkt, unsigned int context,
|
||||
X509 *x, size_t chainidx);
|
||||
/*
|
||||
* Not in public headers as this is not an official extension. Only used when
|
||||
* SSL_OP_CRYPTOPRO_TLSEXT_BUG is set.
|
||||
|
|
|
@ -2303,7 +2303,7 @@ int tls_construct_server_hello(SSL *s, WPACKET *pkt)
|
|||
* Re-initialise the Transcript Hash. We're going to prepopulate it with
|
||||
* a synthetic message_hash in place of ClientHello1.
|
||||
*/
|
||||
if (!create_synthetic_message_hash(s)) {
|
||||
if (!create_synthetic_message_hash(s, NULL, 0, NULL, 0)) {
|
||||
/* SSLfatal() already called */
|
||||
return 0;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue