提交 11c67eea 编写于 作者: M Matt Caswell

HelloRetryRequest updates for draft-19

Draft-19 changes the HRR transcript hash so that the initial ClientHello
is replaced in the transcript with a special synthetic message_hash message
that just contains a hash of ClientHello1 as its message body.
Reviewed-by: NRich Salz <rsalz@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/2895)
上级 9e0ac6a2
......@@ -2135,6 +2135,7 @@ int ERR_load_SSL_strings(void);
# define SSL_F_ADD_KEY_SHARE 512
# define SSL_F_BYTES_TO_CIPHER_LIST 519
# define SSL_F_CHECK_SUITEB_CIPHER_LIST 331
# define SSL_F_CREATE_SYNTHETIC_MESSAGE_HASH 539
# define SSL_F_CT_MOVE_SCTS 345
# define SSL_F_CT_STRICT 349
# define SSL_F_D2I_SSL_SESSION 103
......@@ -2175,6 +2176,7 @@ int ERR_load_SSL_strings(void);
# define SSL_F_OSSL_STATEM_SERVER_READ_TRANSITION 418
# define SSL_F_PROCESS_KEY_SHARE_EXT 439
# define SSL_F_READ_STATE_MACHINE 352
# define SSL_F_SET_CLIENT_CIPHERSUITE 540
# define SSL_F_SSL3_CHANGE_CIPHER_STATE 129
# define SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM 130
# define SSL_F_SSL3_CTRL 213
......@@ -2464,6 +2466,7 @@ int ERR_load_SSL_strings(void);
# define SSL_R_AT_LEAST_TLS_1_0_NEEDED_IN_FIPS_MODE 143
# define SSL_R_AT_LEAST_TLS_1_2_NEEDED_IN_SUITEB_MODE 158
# define SSL_R_BAD_CHANGE_CIPHER_SPEC 103
# define SSL_R_BAD_CIPHER 186
# define SSL_R_BAD_DATA 390
# define SSL_R_BAD_DATA_RETURNED_BY_CALLBACK 106
# define SSL_R_BAD_DECOMPRESSION 107
......
......@@ -295,6 +295,7 @@ extern "C" {
# ifndef OPENSSL_NO_NEXTPROTONEG
# define SSL3_MT_NEXT_PROTO 67
# endif
# define SSL3_MT_MESSAGE_HASH 254
# define DTLS1_MT_HELLO_VERIFY_REQUEST 3
/* Dummy message type for handling CCS like a normal handshake message */
......
......@@ -23,6 +23,8 @@ static ERR_STRING_DATA SSL_str_functs[] = {
{ERR_FUNC(SSL_F_ADD_KEY_SHARE), "add_key_share"},
{ERR_FUNC(SSL_F_BYTES_TO_CIPHER_LIST), "bytes_to_cipher_list"},
{ERR_FUNC(SSL_F_CHECK_SUITEB_CIPHER_LIST), "check_suiteb_cipher_list"},
{ERR_FUNC(SSL_F_CREATE_SYNTHETIC_MESSAGE_HASH),
"create_synthetic_message_hash"},
{ERR_FUNC(SSL_F_CT_MOVE_SCTS), "ct_move_scts"},
{ERR_FUNC(SSL_F_CT_STRICT), "ct_strict"},
{ERR_FUNC(SSL_F_D2I_SSL_SESSION), "d2i_SSL_SESSION"},
......@@ -74,6 +76,7 @@ static ERR_STRING_DATA SSL_str_functs[] = {
"ossl_statem_server_read_transition"},
{ERR_FUNC(SSL_F_PROCESS_KEY_SHARE_EXT), "process_key_share_ext"},
{ERR_FUNC(SSL_F_READ_STATE_MACHINE), "read_state_machine"},
{ERR_FUNC(SSL_F_SET_CLIENT_CIPHERSUITE), "set_client_ciphersuite"},
{ERR_FUNC(SSL_F_SSL3_CHANGE_CIPHER_STATE), "ssl3_change_cipher_state"},
{ERR_FUNC(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM),
"ssl3_check_cert_and_algorithm"},
......@@ -481,6 +484,7 @@ static ERR_STRING_DATA SSL_str_reasons[] = {
{ERR_REASON(SSL_R_AT_LEAST_TLS_1_2_NEEDED_IN_SUITEB_MODE),
"at least (D)TLS 1.2 needed in Suite B mode"},
{ERR_REASON(SSL_R_BAD_CHANGE_CIPHER_SPEC), "bad change cipher spec"},
{ERR_REASON(SSL_R_BAD_CIPHER), "bad cipher"},
{ERR_REASON(SSL_R_BAD_DATA), "bad data"},
{ERR_REASON(SSL_R_BAD_DATA_RETURNED_BY_CALLBACK),
"bad data returned by callback"},
......
......@@ -1243,14 +1243,65 @@ MSG_PROCESS_RETURN dtls_process_hello_verify(SSL *s, PACKET *pkt)
return MSG_PROCESS_ERROR;
}
MSG_PROCESS_RETURN tls_process_server_hello(SSL *s, PACKET *pkt)
static int set_client_ciphersuite(SSL *s, const unsigned char *cipherchars)
{
STACK_OF(SSL_CIPHER) *sk;
const SSL_CIPHER *c;
int i;
c = ssl_get_cipher_by_char(s, cipherchars, 0);
if (c == NULL) {
/* unknown cipher */
SSLerr(SSL_F_SET_CLIENT_CIPHERSUITE, SSL_R_UNKNOWN_CIPHER_RETURNED);
return 0;
}
/*
* If it is a disabled cipher we either didn't send it in client hello,
* or it's not allowed for the selected protocol. So we return an error.
*/
if (ssl_cipher_disabled(s, c, SSL_SECOP_CIPHER_CHECK)) {
SSLerr(SSL_F_SET_CLIENT_CIPHERSUITE, SSL_R_WRONG_CIPHER_RETURNED);
return 0;
}
sk = ssl_get_ciphers_by_id(s);
i = sk_SSL_CIPHER_find(sk, c);
if (i < 0) {
/* we did not say we would use this cipher */
SSLerr(SSL_F_SET_CLIENT_CIPHERSUITE, SSL_R_WRONG_CIPHER_RETURNED);
return 0;
}
if (SSL_IS_TLS13(s) && s->s3->tmp.new_cipher != NULL
&& s->s3->tmp.new_cipher->id != c->id) {
/* ServerHello selected a different ciphersuite to that in the HRR */
SSLerr(SSL_F_SET_CLIENT_CIPHERSUITE, SSL_R_WRONG_CIPHER_RETURNED);
return 0;
}
/*
* Depending on the session caching (internal/external), the cipher
* and/or cipher_id values may not be set. Make sure that cipher_id is
* set and use it for comparison.
*/
if (s->session->cipher != NULL)
s->session->cipher_id = s->session->cipher->id;
if (s->hit && (s->session->cipher_id != c->id)) {
SSLerr(SSL_F_SET_CLIENT_CIPHERSUITE,
SSL_R_OLD_SESSION_CIPHER_NOT_RETURNED);
return 0;
}
s->s3->tmp.new_cipher = c;
return 1;
}
MSG_PROCESS_RETURN tls_process_server_hello(SSL *s, PACKET *pkt)
{
PACKET session_id, extpkt;
size_t session_id_len;
const unsigned char *cipherchars;
int i, al = SSL_AD_INTERNAL_ERROR;
int al = SSL_AD_INTERNAL_ERROR;
unsigned int compression;
unsigned int sversion;
unsigned int context;
......@@ -1437,53 +1488,17 @@ MSG_PROCESS_RETURN tls_process_server_hello(SSL *s, PACKET *pkt)
SSL_R_SSL_SESSION_VERSION_MISMATCH);
goto f_err;
}
c = ssl_get_cipher_by_char(s, cipherchars, 0);
if (c == NULL) {
/* unknown cipher */
al = SSL_AD_ILLEGAL_PARAMETER;
SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, SSL_R_UNKNOWN_CIPHER_RETURNED);
goto f_err;
}
/*
* Now that we know the version, update the check to see if it's an allowed
* version.
*/
s->s3->tmp.min_ver = s->version;
s->s3->tmp.max_ver = s->version;
/*
* If it is a disabled cipher we either didn't send it in client hello,
* or it's not allowed for the selected protocol. So we return an error.
*/
if (ssl_cipher_disabled(s, c, SSL_SECOP_CIPHER_CHECK)) {
al = SSL_AD_ILLEGAL_PARAMETER;
SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, SSL_R_WRONG_CIPHER_RETURNED);
goto f_err;
}
sk = ssl_get_ciphers_by_id(s);
i = sk_SSL_CIPHER_find(sk, c);
if (i < 0) {
/* we did not say we would use this cipher */
if (!set_client_ciphersuite(s, cipherchars)) {
al = SSL_AD_ILLEGAL_PARAMETER;
SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, SSL_R_WRONG_CIPHER_RETURNED);
goto f_err;
}
/*
* Depending on the session caching (internal/external), the cipher
* and/or cipher_id values may not be set. Make sure that cipher_id is
* set and use it for comparison.
*/
if (s->session->cipher)
s->session->cipher_id = s->session->cipher->id;
if (s->hit && (s->session->cipher_id != c->id)) {
al = SSL_AD_ILLEGAL_PARAMETER;
SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO,
SSL_R_OLD_SESSION_CIPHER_NOT_RETURNED);
goto f_err;
}
s->s3->tmp.new_cipher = c;
#ifdef OPENSSL_NO_COMP
if (compression != 0) {
......@@ -1580,6 +1595,7 @@ static MSG_PROCESS_RETURN tls_process_hello_retry_request(SSL *s, PACKET *pkt)
{
unsigned int sversion;
int errorcode;
const unsigned char *cipherchars;
RAW_EXTENSION *extensions = NULL;
int al;
PACKET extpkt;
......@@ -1600,6 +1616,17 @@ static MSG_PROCESS_RETURN tls_process_hello_retry_request(SSL *s, PACKET *pkt)
goto f_err;
}
if (!PACKET_get_bytes(pkt, &cipherchars, TLS_CIPHER_LEN)) {
SSLerr(SSL_F_TLS_PROCESS_HELLO_RETRY_REQUEST, SSL_R_LENGTH_MISMATCH);
al = SSL_AD_DECODE_ERROR;
goto f_err;
}
if (!set_client_ciphersuite(s, cipherchars)) {
al = SSL_AD_ILLEGAL_PARAMETER;
goto f_err;
}
if (!PACKET_as_length_prefixed_2(pkt, &extpkt)) {
al = SSL_AD_DECODE_ERROR;
SSLerr(SSL_F_TLS_PROCESS_HELLO_RETRY_REQUEST, SSL_R_BAD_LENGTH);
......@@ -1614,6 +1641,28 @@ static MSG_PROCESS_RETURN tls_process_hello_retry_request(SSL *s, PACKET *pkt)
OPENSSL_free(extensions);
/*
* 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)) {
al = SSL_AD_INTERNAL_ERROR;
goto f_err;
}
/*
* Add this message to the Transcript Hash. Normally this is done
* automatically prior to the message processing stage. However due to the
* need to create the synthetic message hash, we defer that step until now
* for HRR messages.
*/
if (!ssl3_finish_mac(s, (unsigned char *)s->init_buf->data,
s->init_num + SSL3_HM_HEADER_LENGTH)) {
al = SSL_AD_INTERNAL_ERROR;
SSLerr(SSL_F_TLS_PROCESS_HELLO_RETRY_REQUEST, ERR_R_INTERNAL_ERROR);
goto f_err;
}
return MSG_PROCESS_FINISHED_READING;
f_err:
ssl3_send_alert(s, SSL3_AL_FATAL, al);
......
......@@ -1149,7 +1149,12 @@ int tls_get_message_body(SSL *s, size_t *len)
s->msg_callback(0, SSL2_VERSION, 0, s->init_buf->data,
(size_t)s->init_num, s, s->msg_callback_arg);
} else {
if (!ssl3_finish_mac(s, (unsigned char *)s->init_buf->data,
/*
* We defer feeding in the HRR until later. We'll do it as part of
* processing the message
*/
if (s->s3->tmp.message_type != SSL3_MT_HELLO_RETRY_REQUEST
&& !ssl3_finish_mac(s, (unsigned char *)s->init_buf->data,
s->init_num + SSL3_HM_HEADER_LENGTH)) {
SSLerr(SSL_F_TLS_GET_MESSAGE_BODY, ERR_R_EVP_LIB);
ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
......@@ -1870,3 +1875,37 @@ int check_in_list(SSL *s, unsigned int group_id, const unsigned char *groups,
return i < num_groups;
}
#endif
/* Replace ClientHello1 in the transcript hash with a synthetic message */
int create_synthetic_message_hash(SSL *s)
{
unsigned char hashval[EVP_MAX_MD_SIZE];
size_t hashlen = 0;
unsigned char msghdr[SSL3_HM_HEADER_LENGTH] = {
SSL3_MT_MESSAGE_HASH,
0,
0,
0
};
/* Get the hash of the initial ClientHello */
if (!ssl3_digest_cached_records(s, 0)
|| !ssl_handshake_hash(s, hashval, sizeof(hashval), &hashlen)) {
SSLerr(SSL_F_CREATE_SYNTHETIC_MESSAGE_HASH, ERR_R_INTERNAL_ERROR);
return 0;
}
/* Reinitialise the transcript hash */
if (!ssl3_init_finished_mac(s))
return 0;
/* Inject the synthetic message_hash message */
msghdr[SSL3_HM_HEADER_LENGTH - 1] = hashlen;
if (!ssl3_finish_mac(s, msghdr, SSL3_HM_HEADER_LENGTH)
|| !ssl3_finish_mac(s, hashval, hashlen)) {
SSLerr(SSL_F_CREATE_SYNTHETIC_MESSAGE_HASH, ERR_R_INTERNAL_ERROR);
return 0;
}
return 1;
}
......@@ -79,7 +79,7 @@ typedef int (*confunc_f) (SSL *s, WPACKET *pkt);
int check_in_list(SSL *s, unsigned int group_id, const unsigned char *groups,
size_t num_groups, int checkallow);
int create_synthetic_message_hash(SSL *s);
/*
* TLS/DTLS client state machine functions
*/
......
......@@ -1975,6 +1975,16 @@ WORK_STATE tls_post_process_client_hello(SSL *s, WORK_STATE wst)
SSL_R_NO_SHARED_CIPHER);
goto f_err;
}
if (SSL_IS_TLS13(s) && s->s3->tmp.new_cipher != NULL
&& s->s3->tmp.new_cipher->id != cipher->id) {
/*
* A previous HRR picked a different ciphersuite to the one we
* just selected. Something must have changed.
*/
al = SSL_AD_ILLEGAL_PARAMETER;
SSLerr(SSL_F_TLS_POST_PROCESS_CLIENT_HELLO, SSL_R_BAD_CIPHER);
goto f_err;
}
s->s3->tmp.new_cipher = cipher;
if (!tls_choose_sigalg(s, &al))
goto f_err;
......@@ -3662,17 +3672,18 @@ static int tls_construct_encrypted_extensions(SSL *s, WPACKET *pkt)
static int tls_construct_hello_retry_request(SSL *s, WPACKET *pkt)
{
int al = SSL_AD_INTERNAL_ERROR;
size_t len = 0;
/*
* TODO(TLS1.3): Remove the DRAFT version before release
* (should be s->version)
*/
if (!WPACKET_put_bytes_u16(pkt, TLS1_3_VERSION_DRAFT)
|| !s->method->put_cipher_by_char(s->s3->tmp.new_cipher, pkt, &len)
|| !tls_construct_extensions(s, pkt, EXT_TLS1_3_HELLO_RETRY_REQUEST,
NULL, 0, &al)) {
SSLerr(SSL_F_TLS_CONSTRUCT_HELLO_RETRY_REQUEST, ERR_R_INTERNAL_ERROR);
ssl3_send_alert(s, SSL3_AL_FATAL, al);
return 0;
goto err;
}
/* Ditch the session. We'll create a new one next time around */
......@@ -3680,7 +3691,17 @@ static int tls_construct_hello_retry_request(SSL *s, WPACKET *pkt)
s->session = NULL;
s->hit = 0;
/*
* 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))
goto err;
return 1;
err:
ssl3_send_alert(s, SSL3_AL_FATAL, al);
return 0;
}
MSG_PROCESS_RETURN tls_process_end_of_early_data(SSL *s, PACKET *pkt)
......
......@@ -992,6 +992,29 @@ static int ssl_print_server_hello(BIO *bio, int indent,
return 1;
}
static int ssl_print_hello_retry_request(BIO *bio, int indent,
const unsigned char *msg,
size_t msglen)
{
unsigned int cs;
if (!ssl_print_version(bio, indent, "server_version", &msg, &msglen, NULL))
return 0;
cs = (msg[0] << 8) | msg[1];
BIO_indent(bio, indent, 80);
BIO_printf(bio, "cipher_suite {0x%02X, 0x%02X} %s\n",
msg[0], msg[1], ssl_trace_str(cs, ssl_ciphers_tbl));
msg += 2;
msglen -= 2;
if (!ssl_print_extensions(bio, indent, 1, SSL3_MT_HELLO_RETRY_REQUEST, &msg,
&msglen))
return 0;
return 1;
}
static int ssl_get_keyex(const char **pname, SSL *ssl)
{
unsigned long alg_k = ssl->s3->tmp.new_cipher->algorithm_mkey;
......@@ -1422,11 +1445,7 @@ static int ssl_print_handshake(BIO *bio, SSL *ssl, int server,
break;
case SSL3_MT_HELLO_RETRY_REQUEST:
if (!ssl_print_version(bio, indent + 2, "server_version", &msg, &msglen,
NULL)
|| !ssl_print_extensions(bio, indent + 2, 1,
SSL3_MT_HELLO_RETRY_REQUEST, &msg,
&msglen))
if (!ssl_print_hello_retry_request(bio, indent + 2, msg, msglen))
return 0;
break;
......
......@@ -47,6 +47,9 @@ sub parse
$server_version = TLSProxy::Record::VERS_TLS_1_3;
}
my $ciphersuite = unpack('n', substr($self->data, $ptr));
$ptr += 2;
my $extensions_len = unpack('n', substr($self->data, $ptr));
if (!defined $extensions_len) {
$extensions_len = 0;
......@@ -75,6 +78,7 @@ sub parse
}
$self->server_version($server_version);
$self->ciphersuite($ciphersuite);
$self->extension_data(\%extensions);
print " Extensions Len:".$extensions_len."\n";
......@@ -100,6 +104,7 @@ sub set_message_contents
}
$data = pack('n', $self->server_version);
$data .= pack('n', $self->ciphersuite);
$data .= pack('n', length($extensions));
$data .= $extensions;
$self->data($data);
......@@ -114,6 +119,14 @@ sub server_version
}
return $self->{server_version};
}
sub ciphersuite
{
my $self = shift;
if (@_) {
$self->{ciphersuite} = shift;
}
return $self->{ciphersuite};
}
sub extension_data
{
my $self = shift;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册