Only have one ClientHello parser, not three.
Between TLS 1.2, TLS 1.3, and the early callback, we've got a lot of ClientHello parsers. Unify everything on the early callback's parser. As a side effect, this means we can parse a ClientHello fairly succinctly from any function which will let us split up ClientHello states where appropriate. Change-Id: I2359b75f80926cc7d827570cf33f93029b39e525 Reviewed-on: https://boringssl-review.googlesource.com/10184 Reviewed-by: Adam Langley <agl@google.com> Commit-Queue: Adam Langley <agl@google.com> CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
This commit is contained in:
parent
e4a432687e
commit
e14ff06694
@ -2919,6 +2919,9 @@ struct ssl_early_callback_ctx {
|
|||||||
SSL *ssl;
|
SSL *ssl;
|
||||||
const uint8_t *client_hello;
|
const uint8_t *client_hello;
|
||||||
size_t client_hello_len;
|
size_t client_hello_len;
|
||||||
|
uint16_t version;
|
||||||
|
const uint8_t *random;
|
||||||
|
size_t random_len;
|
||||||
const uint8_t *session_id;
|
const uint8_t *session_id;
|
||||||
size_t session_id_len;
|
size_t session_id_len;
|
||||||
const uint8_t *cipher_suites;
|
const uint8_t *cipher_suites;
|
||||||
|
@ -534,18 +534,10 @@ static int ssl3_get_client_hello(SSL *ssl) {
|
|||||||
int al = SSL_AD_INTERNAL_ERROR, ret = -1;
|
int al = SSL_AD_INTERNAL_ERROR, ret = -1;
|
||||||
const SSL_CIPHER *c;
|
const SSL_CIPHER *c;
|
||||||
STACK_OF(SSL_CIPHER) *ciphers = NULL;
|
STACK_OF(SSL_CIPHER) *ciphers = NULL;
|
||||||
struct ssl_early_callback_ctx early_ctx;
|
|
||||||
CBS client_hello;
|
|
||||||
uint16_t client_wire_version;
|
|
||||||
CBS client_random, session_id, cipher_suites, compression_methods;
|
|
||||||
SSL_SESSION *session = NULL;
|
SSL_SESSION *session = NULL;
|
||||||
|
|
||||||
/* We do this so that we will respond with our native type. If we are TLSv1
|
if (ssl->state == SSL3_ST_SR_CLNT_HELLO_A) {
|
||||||
* and we get SSLv3, we will respond with TLSv1, This down switching should
|
/* The first time around, read the ClientHello. */
|
||||||
* be handled by a different method. If we are SSLv3, we will respond with
|
|
||||||
* SSLv3, even if prompted with TLSv1. */
|
|
||||||
switch (ssl->state) {
|
|
||||||
case SSL3_ST_SR_CLNT_HELLO_A: {
|
|
||||||
int msg_ret = ssl->method->ssl_get_message(ssl, SSL3_MT_CLIENT_HELLO,
|
int msg_ret = ssl->method->ssl_get_message(ssl, SSL3_MT_CLIENT_HELLO,
|
||||||
ssl_hash_message);
|
ssl_hash_message);
|
||||||
if (msg_ret <= 0) {
|
if (msg_ret <= 0) {
|
||||||
@ -554,20 +546,23 @@ static int ssl3_get_client_hello(SSL *ssl) {
|
|||||||
|
|
||||||
ssl->state = SSL3_ST_SR_CLNT_HELLO_B;
|
ssl->state = SSL3_ST_SR_CLNT_HELLO_B;
|
||||||
}
|
}
|
||||||
/* fallthrough */
|
|
||||||
case SSL3_ST_SR_CLNT_HELLO_B:
|
struct ssl_early_callback_ctx client_hello;
|
||||||
case SSL3_ST_SR_CLNT_HELLO_C:
|
if (!ssl_early_callback_init(ssl, &client_hello, ssl->init_msg,
|
||||||
if (!ssl_early_callback_init(ssl, &early_ctx, ssl->init_msg,
|
|
||||||
ssl->init_num)) {
|
ssl->init_num)) {
|
||||||
al = SSL_AD_DECODE_ERROR;
|
al = SSL_AD_DECODE_ERROR;
|
||||||
OPENSSL_PUT_ERROR(SSL, SSL_R_CLIENTHELLO_PARSE_FAILED);
|
OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
|
||||||
goto f_err;
|
goto f_err;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ssl->state == SSL3_ST_SR_CLNT_HELLO_B &&
|
if (ssl->state == SSL3_ST_SR_CLNT_HELLO_B) {
|
||||||
ssl->ctx->select_certificate_cb != NULL) {
|
/* Unlike other callbacks, the early callback is not run a second time if
|
||||||
|
* paused. */
|
||||||
ssl->state = SSL3_ST_SR_CLNT_HELLO_C;
|
ssl->state = SSL3_ST_SR_CLNT_HELLO_C;
|
||||||
switch (ssl->ctx->select_certificate_cb(&early_ctx)) {
|
|
||||||
|
/* Run the early callback. */
|
||||||
|
if (ssl->ctx->select_certificate_cb != NULL) {
|
||||||
|
switch (ssl->ctx->select_certificate_cb(&client_hello)) {
|
||||||
case 0:
|
case 0:
|
||||||
ssl->rwstate = SSL_CERTIFICATE_SELECTION_PENDING;
|
ssl->rwstate = SSL_CERTIFICATE_SELECTION_PENDING;
|
||||||
goto err;
|
goto err;
|
||||||
@ -582,26 +577,11 @@ static int ssl3_get_client_hello(SSL *ssl) {
|
|||||||
/* fallthrough */;
|
/* fallthrough */;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ssl->state = SSL3_ST_SR_CLNT_HELLO_C;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_STATE);
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CBS_init(&client_hello, ssl->init_msg, ssl->init_num);
|
uint16_t client_version =
|
||||||
if (!CBS_get_u16(&client_hello, &client_wire_version)) {
|
ssl->method->version_from_wire(client_hello.version);
|
||||||
al = SSL_AD_DECODE_ERROR;
|
ssl->client_version = client_hello.version;
|
||||||
OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
|
|
||||||
goto f_err;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t client_version = ssl->method->version_from_wire(client_wire_version);
|
|
||||||
|
|
||||||
/* use version from inside client hello, not from record header (may differ:
|
|
||||||
* see RFC 2246, Appendix E, second paragraph) */
|
|
||||||
ssl->client_version = client_wire_version;
|
|
||||||
|
|
||||||
uint16_t min_version, max_version;
|
uint16_t min_version, max_version;
|
||||||
if (!ssl_get_version_range(ssl, &min_version, &max_version)) {
|
if (!ssl_get_version_range(ssl, &min_version, &max_version)) {
|
||||||
@ -642,30 +622,16 @@ static int ssl3_get_client_hello(SSL *ssl) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!CBS_get_bytes(&client_hello, &client_random, SSL3_RANDOM_SIZE) ||
|
|
||||||
!CBS_get_u8_length_prefixed(&client_hello, &session_id) ||
|
|
||||||
CBS_len(&session_id) > SSL_MAX_SSL_SESSION_ID_LENGTH) {
|
|
||||||
al = SSL_AD_DECODE_ERROR;
|
|
||||||
OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
|
|
||||||
goto f_err;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Load the client random. */
|
/* Load the client random. */
|
||||||
memcpy(ssl->s3->client_random, CBS_data(&client_random), SSL3_RANDOM_SIZE);
|
if (client_hello.random_len != SSL3_RANDOM_SIZE) {
|
||||||
|
OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
|
||||||
if (SSL_is_dtls(ssl)) {
|
return -1;
|
||||||
CBS cookie;
|
|
||||||
|
|
||||||
if (!CBS_get_u8_length_prefixed(&client_hello, &cookie) ||
|
|
||||||
CBS_len(&cookie) > DTLS1_COOKIE_LENGTH) {
|
|
||||||
al = SSL_AD_DECODE_ERROR;
|
|
||||||
OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
|
|
||||||
goto f_err;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
memcpy(ssl->s3->client_random, client_hello.random, client_hello.random_len);
|
||||||
|
|
||||||
int send_new_ticket = 0;
|
int send_new_ticket = 0;
|
||||||
switch (ssl_get_prev_session(ssl, &session, &send_new_ticket, &early_ctx)) {
|
switch (
|
||||||
|
ssl_get_prev_session(ssl, &session, &send_new_ticket, &client_hello)) {
|
||||||
case ssl_session_success:
|
case ssl_session_success:
|
||||||
break;
|
break;
|
||||||
case ssl_session_error:
|
case ssl_session_error:
|
||||||
@ -683,7 +649,7 @@ static int ssl3_get_client_hello(SSL *ssl) {
|
|||||||
CBS ems;
|
CBS ems;
|
||||||
int have_extended_master_secret =
|
int have_extended_master_secret =
|
||||||
ssl->version != SSL3_VERSION &&
|
ssl->version != SSL3_VERSION &&
|
||||||
ssl_early_callback_get_extension(&early_ctx, &ems,
|
ssl_early_callback_get_extension(&client_hello, &ems,
|
||||||
TLSEXT_TYPE_extended_master_secret) &&
|
TLSEXT_TYPE_extended_master_secret) &&
|
||||||
CBS_len(&ems) == 0;
|
CBS_len(&ems) == 0;
|
||||||
|
|
||||||
@ -725,24 +691,14 @@ static int ssl3_get_client_hello(SSL *ssl) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (ssl->ctx->dos_protection_cb != NULL &&
|
if (ssl->ctx->dos_protection_cb != NULL &&
|
||||||
ssl->ctx->dos_protection_cb(&early_ctx) == 0) {
|
ssl->ctx->dos_protection_cb(&client_hello) == 0) {
|
||||||
/* Connection rejected for DOS reasons. */
|
/* Connection rejected for DOS reasons. */
|
||||||
al = SSL_AD_ACCESS_DENIED;
|
al = SSL_AD_ACCESS_DENIED;
|
||||||
OPENSSL_PUT_ERROR(SSL, SSL_R_CONNECTION_REJECTED);
|
OPENSSL_PUT_ERROR(SSL, SSL_R_CONNECTION_REJECTED);
|
||||||
goto f_err;
|
goto f_err;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!CBS_get_u16_length_prefixed(&client_hello, &cipher_suites) ||
|
ciphers = ssl_parse_client_cipher_list(ssl, &client_hello, max_version);
|
||||||
CBS_len(&cipher_suites) == 0 ||
|
|
||||||
CBS_len(&cipher_suites) % 2 != 0 ||
|
|
||||||
!CBS_get_u8_length_prefixed(&client_hello, &compression_methods) ||
|
|
||||||
CBS_len(&compression_methods) == 0) {
|
|
||||||
al = SSL_AD_DECODE_ERROR;
|
|
||||||
OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
|
|
||||||
goto f_err;
|
|
||||||
}
|
|
||||||
|
|
||||||
ciphers = ssl_bytes_to_cipher_list(ssl, &cipher_suites, max_version);
|
|
||||||
if (ciphers == NULL) {
|
if (ciphers == NULL) {
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
@ -771,28 +727,19 @@ static int ssl3_get_client_hello(SSL *ssl) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Only null compression is supported. */
|
/* Only null compression is supported. */
|
||||||
if (memchr(CBS_data(&compression_methods), 0,
|
if (memchr(client_hello.compression_methods, 0,
|
||||||
CBS_len(&compression_methods)) == NULL) {
|
client_hello.compression_methods_len) == NULL) {
|
||||||
al = SSL_AD_ILLEGAL_PARAMETER;
|
al = SSL_AD_ILLEGAL_PARAMETER;
|
||||||
OPENSSL_PUT_ERROR(SSL, SSL_R_NO_COMPRESSION_SPECIFIED);
|
OPENSSL_PUT_ERROR(SSL, SSL_R_NO_COMPRESSION_SPECIFIED);
|
||||||
goto f_err;
|
goto f_err;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TLS extensions. */
|
/* TLS extensions. */
|
||||||
if (ssl->version >= SSL3_VERSION &&
|
if (!ssl_parse_clienthello_tlsext(ssl, &client_hello)) {
|
||||||
!ssl_parse_clienthello_tlsext(ssl, &client_hello)) {
|
|
||||||
OPENSSL_PUT_ERROR(SSL, SSL_R_PARSE_TLSEXT);
|
OPENSSL_PUT_ERROR(SSL, SSL_R_PARSE_TLSEXT);
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* There should be nothing left over in the record. */
|
|
||||||
if (CBS_len(&client_hello) != 0) {
|
|
||||||
/* wrong packet length */
|
|
||||||
al = SSL_AD_DECODE_ERROR;
|
|
||||||
OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_PACKET_LENGTH);
|
|
||||||
goto f_err;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (have_extended_master_secret != ssl->s3->tmp.extended_master_secret) {
|
if (have_extended_master_secret != ssl->s3->tmp.extended_master_secret) {
|
||||||
al = SSL_AD_INTERNAL_ERROR;
|
al = SSL_AD_INTERNAL_ERROR;
|
||||||
OPENSSL_PUT_ERROR(SSL, SSL_R_EMS_STATE_INCONSISTENT);
|
OPENSSL_PUT_ERROR(SSL, SSL_R_EMS_STATE_INCONSISTENT);
|
||||||
|
@ -958,6 +958,20 @@ int ssl_log_secret(const SSL *ssl, const char *label, const uint8_t *secret,
|
|||||||
size_t secret_len);
|
size_t secret_len);
|
||||||
|
|
||||||
|
|
||||||
|
/* ClientHello functions. */
|
||||||
|
|
||||||
|
int ssl_early_callback_init(SSL *ssl, struct ssl_early_callback_ctx *ctx,
|
||||||
|
const uint8_t *in, size_t in_len);
|
||||||
|
|
||||||
|
int ssl_early_callback_get_extension(const struct ssl_early_callback_ctx *ctx,
|
||||||
|
CBS *out, uint16_t extension_type);
|
||||||
|
|
||||||
|
STACK_OF(SSL_CIPHER) *
|
||||||
|
ssl_parse_client_cipher_list(SSL *ssl,
|
||||||
|
const struct ssl_early_callback_ctx *ctx,
|
||||||
|
uint16_t max_version);
|
||||||
|
|
||||||
|
|
||||||
/* Underdocumented functions.
|
/* Underdocumented functions.
|
||||||
*
|
*
|
||||||
* Functions below here haven't been touched up and may be underdocumented. */
|
* Functions below here haven't been touched up and may be underdocumented. */
|
||||||
@ -1239,8 +1253,6 @@ enum ssl_session_result_t ssl_get_prev_session(
|
|||||||
OPENSSL_EXPORT SSL_SESSION *SSL_SESSION_dup(SSL_SESSION *session,
|
OPENSSL_EXPORT SSL_SESSION *SSL_SESSION_dup(SSL_SESSION *session,
|
||||||
int include_ticket);
|
int include_ticket);
|
||||||
|
|
||||||
STACK_OF(SSL_CIPHER) *
|
|
||||||
ssl_bytes_to_cipher_list(SSL *ssl, const CBS *cbs, uint16_t max_version);
|
|
||||||
void ssl_cipher_preference_list_free(
|
void ssl_cipher_preference_list_free(
|
||||||
struct ssl_cipher_preference_list_st *cipher_list);
|
struct ssl_cipher_preference_list_st *cipher_list);
|
||||||
struct ssl_cipher_preference_list_st *ssl_get_cipher_preferences(SSL *ssl);
|
struct ssl_cipher_preference_list_st *ssl_get_cipher_preferences(SSL *ssl);
|
||||||
@ -1370,12 +1382,6 @@ int tls1_handshake_digest(SSL *ssl, uint8_t *out, size_t out_len);
|
|||||||
int tls1_generate_master_secret(SSL *ssl, uint8_t *out, const uint8_t *premaster,
|
int tls1_generate_master_secret(SSL *ssl, uint8_t *out, const uint8_t *premaster,
|
||||||
size_t premaster_len);
|
size_t premaster_len);
|
||||||
|
|
||||||
int ssl_early_callback_init(SSL *ssl, struct ssl_early_callback_ctx *ctx,
|
|
||||||
const uint8_t *in, size_t in_len);
|
|
||||||
|
|
||||||
int ssl_early_callback_get_extension(const struct ssl_early_callback_ctx *ctx,
|
|
||||||
CBS *out, uint16_t extension_type);
|
|
||||||
|
|
||||||
/* tls1_get_grouplist sets |*out_group_ids| and |*out_group_ids_len| to the
|
/* tls1_get_grouplist sets |*out_group_ids| and |*out_group_ids_len| to the
|
||||||
* list of allowed group IDs. If |get_peer_groups| is non-zero, return the
|
* list of allowed group IDs. If |get_peer_groups| is non-zero, return the
|
||||||
* peer's group list. Otherwise, return the preferred list. */
|
* peer's group list. Otherwise, return the preferred list. */
|
||||||
@ -1412,7 +1418,8 @@ int tls1_check_ec_cert(SSL *ssl, X509 *x);
|
|||||||
int ssl_add_clienthello_tlsext(SSL *ssl, CBB *out, size_t header_len);
|
int ssl_add_clienthello_tlsext(SSL *ssl, CBB *out, size_t header_len);
|
||||||
|
|
||||||
int ssl_add_serverhello_tlsext(SSL *ssl, CBB *out);
|
int ssl_add_serverhello_tlsext(SSL *ssl, CBB *out);
|
||||||
int ssl_parse_clienthello_tlsext(SSL *ssl, CBS *cbs);
|
int ssl_parse_clienthello_tlsext(
|
||||||
|
SSL *ssl, const struct ssl_early_callback_ctx *client_hello);
|
||||||
int ssl_parse_serverhello_tlsext(SSL *ssl, CBS *cbs);
|
int ssl_parse_serverhello_tlsext(SSL *ssl, CBS *cbs);
|
||||||
|
|
||||||
#define tlsext_tick_md EVP_sha256
|
#define tlsext_tick_md EVP_sha256
|
||||||
|
@ -1630,21 +1630,15 @@ int SSL_set_cipher_list(SSL *ssl, const char *str) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
STACK_OF(SSL_CIPHER) *
|
STACK_OF(SSL_CIPHER) *
|
||||||
ssl_bytes_to_cipher_list(SSL *ssl, const CBS *cbs, uint16_t max_version) {
|
ssl_parse_client_cipher_list(SSL *ssl,
|
||||||
CBS cipher_suites = *cbs;
|
const struct ssl_early_callback_ctx *ctx,
|
||||||
const SSL_CIPHER *c;
|
uint16_t max_version) {
|
||||||
STACK_OF(SSL_CIPHER) *sk;
|
CBS cipher_suites;
|
||||||
|
CBS_init(&cipher_suites, ctx->cipher_suites, ctx->cipher_suites_len);
|
||||||
|
|
||||||
if (ssl->s3) {
|
|
||||||
ssl->s3->send_connection_binding = 0;
|
ssl->s3->send_connection_binding = 0;
|
||||||
}
|
|
||||||
|
|
||||||
if (CBS_len(&cipher_suites) % 2 != 0) {
|
STACK_OF(SSL_CIPHER) *sk = sk_SSL_CIPHER_new_null();
|
||||||
OPENSSL_PUT_ERROR(SSL, SSL_R_ERROR_IN_RECEIVED_CIPHER_LIST);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
sk = sk_SSL_CIPHER_new_null();
|
|
||||||
if (sk == NULL) {
|
if (sk == NULL) {
|
||||||
OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
|
OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
|
||||||
goto err;
|
goto err;
|
||||||
@ -1654,7 +1648,7 @@ STACK_OF(SSL_CIPHER) *
|
|||||||
uint16_t cipher_suite;
|
uint16_t cipher_suite;
|
||||||
|
|
||||||
if (!CBS_get_u16(&cipher_suites, &cipher_suite)) {
|
if (!CBS_get_u16(&cipher_suites, &cipher_suite)) {
|
||||||
OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
|
OPENSSL_PUT_ERROR(SSL, SSL_R_ERROR_IN_RECEIVED_CIPHER_LIST);
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1680,7 +1674,7 @@ STACK_OF(SSL_CIPHER) *
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
c = SSL_get_cipher_by_value(cipher_suite);
|
const SSL_CIPHER *c = SSL_get_cipher_by_value(cipher_suite);
|
||||||
if (c != NULL && !sk_SSL_CIPHER_push(sk, c)) {
|
if (c != NULL && !sk_SSL_CIPHER_push(sk, c)) {
|
||||||
OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
|
OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
|
||||||
goto err;
|
goto err;
|
||||||
|
56
ssl/t1_lib.c
56
ssl/t1_lib.c
@ -209,43 +209,39 @@ int ssl_early_callback_init(SSL *ssl, struct ssl_early_callback_ctx *ctx,
|
|||||||
ctx->client_hello = in;
|
ctx->client_hello = in;
|
||||||
ctx->client_hello_len = in_len;
|
ctx->client_hello_len = in_len;
|
||||||
|
|
||||||
CBS client_hello, session_id, cipher_suites, compression_methods, extensions;
|
CBS client_hello, random, session_id;
|
||||||
CBS_init(&client_hello, ctx->client_hello, ctx->client_hello_len);
|
CBS_init(&client_hello, ctx->client_hello, ctx->client_hello_len);
|
||||||
|
if (!CBS_get_u16(&client_hello, &ctx->version) ||
|
||||||
if (/* Skip client version. */
|
!CBS_get_bytes(&client_hello, &random, SSL3_RANDOM_SIZE) ||
|
||||||
!CBS_skip(&client_hello, 2) ||
|
!CBS_get_u8_length_prefixed(&client_hello, &session_id) ||
|
||||||
/* Skip client nonce. */
|
CBS_len(&session_id) > SSL_MAX_SSL_SESSION_ID_LENGTH) {
|
||||||
!CBS_skip(&client_hello, 32) ||
|
|
||||||
/* Extract session_id. */
|
|
||||||
!CBS_get_u8_length_prefixed(&client_hello, &session_id)) {
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ctx->random = CBS_data(&random);
|
||||||
|
ctx->random_len = CBS_len(&random);
|
||||||
ctx->session_id = CBS_data(&session_id);
|
ctx->session_id = CBS_data(&session_id);
|
||||||
ctx->session_id_len = CBS_len(&session_id);
|
ctx->session_id_len = CBS_len(&session_id);
|
||||||
|
|
||||||
/* Skip past DTLS cookie */
|
/* Skip past DTLS cookie */
|
||||||
if (SSL_is_dtls(ctx->ssl)) {
|
if (SSL_is_dtls(ctx->ssl)) {
|
||||||
CBS cookie;
|
CBS cookie;
|
||||||
|
if (!CBS_get_u8_length_prefixed(&client_hello, &cookie) ||
|
||||||
if (!CBS_get_u8_length_prefixed(&client_hello, &cookie)) {
|
CBS_len(&cookie) > DTLS1_COOKIE_LENGTH) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Extract cipher_suites. */
|
CBS cipher_suites, compression_methods;
|
||||||
if (!CBS_get_u16_length_prefixed(&client_hello, &cipher_suites) ||
|
if (!CBS_get_u16_length_prefixed(&client_hello, &cipher_suites) ||
|
||||||
CBS_len(&cipher_suites) < 2 || (CBS_len(&cipher_suites) & 1) != 0) {
|
CBS_len(&cipher_suites) < 2 || (CBS_len(&cipher_suites) & 1) != 0 ||
|
||||||
return 0;
|
!CBS_get_u8_length_prefixed(&client_hello, &compression_methods) ||
|
||||||
}
|
|
||||||
ctx->cipher_suites = CBS_data(&cipher_suites);
|
|
||||||
ctx->cipher_suites_len = CBS_len(&cipher_suites);
|
|
||||||
|
|
||||||
/* Extract compression_methods. */
|
|
||||||
if (!CBS_get_u8_length_prefixed(&client_hello, &compression_methods) ||
|
|
||||||
CBS_len(&compression_methods) < 1) {
|
CBS_len(&compression_methods) < 1) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ctx->cipher_suites = CBS_data(&cipher_suites);
|
||||||
|
ctx->cipher_suites_len = CBS_len(&cipher_suites);
|
||||||
ctx->compression_methods = CBS_data(&compression_methods);
|
ctx->compression_methods = CBS_data(&compression_methods);
|
||||||
ctx->compression_methods_len = CBS_len(&compression_methods);
|
ctx->compression_methods_len = CBS_len(&compression_methods);
|
||||||
|
|
||||||
@ -258,11 +254,13 @@ int ssl_early_callback_init(SSL *ssl, struct ssl_early_callback_ctx *ctx,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Extract extensions and check it is valid. */
|
/* Extract extensions and check it is valid. */
|
||||||
|
CBS extensions;
|
||||||
if (!CBS_get_u16_length_prefixed(&client_hello, &extensions) ||
|
if (!CBS_get_u16_length_prefixed(&client_hello, &extensions) ||
|
||||||
!tls1_check_duplicate_extensions(&extensions) ||
|
!tls1_check_duplicate_extensions(&extensions) ||
|
||||||
CBS_len(&client_hello) != 0) {
|
CBS_len(&client_hello) != 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx->extensions = CBS_data(&extensions);
|
ctx->extensions = CBS_data(&extensions);
|
||||||
ctx->extensions_len = CBS_len(&extensions);
|
ctx->extensions_len = CBS_len(&extensions);
|
||||||
|
|
||||||
@ -2512,7 +2510,9 @@ err:
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ssl_scan_clienthello_tlsext(SSL *ssl, CBS *cbs, int *out_alert) {
|
static int ssl_scan_clienthello_tlsext(
|
||||||
|
SSL *ssl, const struct ssl_early_callback_ctx *client_hello,
|
||||||
|
int *out_alert) {
|
||||||
size_t i;
|
size_t i;
|
||||||
for (i = 0; i < kNumExtensions; i++) {
|
for (i = 0; i < kNumExtensions; i++) {
|
||||||
if (kExtensions[i].init != NULL) {
|
if (kExtensions[i].init != NULL) {
|
||||||
@ -2527,16 +2527,8 @@ static int ssl_scan_clienthello_tlsext(SSL *ssl, CBS *cbs, int *out_alert) {
|
|||||||
* sent as an SCSV. */
|
* sent as an SCSV. */
|
||||||
assert(kExtensions[0].value == TLSEXT_TYPE_renegotiate);
|
assert(kExtensions[0].value == TLSEXT_TYPE_renegotiate);
|
||||||
|
|
||||||
/* There may be no extensions. */
|
|
||||||
if (CBS_len(cbs) != 0) {
|
|
||||||
/* Decode the extensions block and check it is valid. */
|
|
||||||
CBS extensions;
|
CBS extensions;
|
||||||
if (!CBS_get_u16_length_prefixed(cbs, &extensions) ||
|
CBS_init(&extensions, client_hello->extensions, client_hello->extensions_len);
|
||||||
!tls1_check_duplicate_extensions(&extensions)) {
|
|
||||||
*out_alert = SSL_AD_DECODE_ERROR;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (CBS_len(&extensions) != 0) {
|
while (CBS_len(&extensions) != 0) {
|
||||||
uint16_t type;
|
uint16_t type;
|
||||||
CBS extension;
|
CBS extension;
|
||||||
@ -2575,7 +2567,6 @@ static int ssl_scan_clienthello_tlsext(SSL *ssl, CBS *cbs, int *out_alert) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < kNumExtensions; i++) {
|
for (i = 0; i < kNumExtensions; i++) {
|
||||||
if (!(ssl->s3->tmp.extensions.received & (1u << i))) {
|
if (!(ssl->s3->tmp.extensions.received & (1u << i))) {
|
||||||
@ -2594,9 +2585,10 @@ static int ssl_scan_clienthello_tlsext(SSL *ssl, CBS *cbs, int *out_alert) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ssl_parse_clienthello_tlsext(SSL *ssl, CBS *cbs) {
|
int ssl_parse_clienthello_tlsext(
|
||||||
|
SSL *ssl, const struct ssl_early_callback_ctx *client_hello) {
|
||||||
int alert = -1;
|
int alert = -1;
|
||||||
if (ssl_scan_clienthello_tlsext(ssl, cbs, &alert) <= 0) {
|
if (ssl_scan_clienthello_tlsext(ssl, client_hello, &alert) <= 0) {
|
||||||
ssl3_send_alert(ssl, SSL3_AL_FATAL, alert);
|
ssl3_send_alert(ssl, SSL3_AL_FATAL, alert);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -105,36 +105,22 @@ static enum ssl_hs_wait_t do_process_client_hello(SSL *ssl, SSL_HANDSHAKE *hs) {
|
|||||||
return ssl_hs_error;
|
return ssl_hs_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ssl_early_callback_ctx early_ctx;
|
struct ssl_early_callback_ctx client_hello;
|
||||||
if (!ssl_early_callback_init(ssl, &early_ctx, ssl->init_msg,
|
if (!ssl_early_callback_init(ssl, &client_hello, ssl->init_msg,
|
||||||
ssl->init_num)) {
|
ssl->init_num)) {
|
||||||
OPENSSL_PUT_ERROR(SSL, SSL_R_CLIENTHELLO_PARSE_FAILED);
|
OPENSSL_PUT_ERROR(SSL, SSL_R_CLIENTHELLO_PARSE_FAILED);
|
||||||
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
|
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
|
||||||
return ssl_hs_error;
|
return ssl_hs_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
CBS cbs, client_random, session_id, cipher_suites, compression_methods;
|
|
||||||
uint16_t client_wire_version;
|
|
||||||
CBS_init(&cbs, ssl->init_msg, ssl->init_num);
|
|
||||||
if (!CBS_get_u16(&cbs, &client_wire_version) ||
|
|
||||||
!CBS_get_bytes(&cbs, &client_random, SSL3_RANDOM_SIZE) ||
|
|
||||||
!CBS_get_u8_length_prefixed(&cbs, &session_id) ||
|
|
||||||
CBS_len(&session_id) > SSL_MAX_SSL_SESSION_ID_LENGTH) {
|
|
||||||
OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
|
|
||||||
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
|
|
||||||
return ssl_hs_error;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t min_version, max_version;
|
|
||||||
if (!ssl_get_version_range(ssl, &min_version, &max_version)) {
|
|
||||||
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
|
|
||||||
return ssl_hs_error;
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(ssl->s3->have_version);
|
assert(ssl->s3->have_version);
|
||||||
|
|
||||||
/* Load the client random. */
|
/* Load the client random. */
|
||||||
memcpy(ssl->s3->client_random, CBS_data(&client_random), SSL3_RANDOM_SIZE);
|
if (client_hello.random_len != SSL3_RANDOM_SIZE) {
|
||||||
|
OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
memcpy(ssl->s3->client_random, client_hello.random, client_hello.random_len);
|
||||||
|
|
||||||
SSL_set_session(ssl, NULL);
|
SSL_set_session(ssl, NULL);
|
||||||
if (!ssl_get_new_session(ssl, 1 /* server */)) {
|
if (!ssl_get_new_session(ssl, 1 /* server */)) {
|
||||||
@ -143,44 +129,27 @@ static enum ssl_hs_wait_t do_process_client_hello(SSL *ssl, SSL_HANDSHAKE *hs) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (ssl->ctx->dos_protection_cb != NULL &&
|
if (ssl->ctx->dos_protection_cb != NULL &&
|
||||||
ssl->ctx->dos_protection_cb(&early_ctx) == 0) {
|
ssl->ctx->dos_protection_cb(&client_hello) == 0) {
|
||||||
/* Connection rejected for DOS reasons. */
|
/* Connection rejected for DOS reasons. */
|
||||||
OPENSSL_PUT_ERROR(SSL, SSL_R_CONNECTION_REJECTED);
|
OPENSSL_PUT_ERROR(SSL, SSL_R_CONNECTION_REJECTED);
|
||||||
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ACCESS_DENIED);
|
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ACCESS_DENIED);
|
||||||
return ssl_hs_error;
|
return ssl_hs_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!CBS_get_u16_length_prefixed(&cbs, &cipher_suites) ||
|
|
||||||
CBS_len(&cipher_suites) == 0 ||
|
|
||||||
CBS_len(&cipher_suites) % 2 != 0 ||
|
|
||||||
!CBS_get_u8_length_prefixed(&cbs, &compression_methods) ||
|
|
||||||
CBS_len(&compression_methods) == 0) {
|
|
||||||
OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
|
|
||||||
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
|
|
||||||
return ssl_hs_error;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* TLS 1.3 requires the peer only advertise the null compression. */
|
/* TLS 1.3 requires the peer only advertise the null compression. */
|
||||||
if (CBS_len(&compression_methods) != 1 ||
|
if (client_hello.compression_methods_len != 1 ||
|
||||||
CBS_data(&compression_methods)[0] != 0) {
|
client_hello.compression_methods[0] != 0) {
|
||||||
OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_COMPRESSION_LIST);
|
OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_COMPRESSION_LIST);
|
||||||
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
|
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
|
||||||
return ssl_hs_error;
|
return ssl_hs_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TLS extensions. */
|
/* TLS extensions. */
|
||||||
if (!ssl_parse_clienthello_tlsext(ssl, &cbs)) {
|
if (!ssl_parse_clienthello_tlsext(ssl, &client_hello)) {
|
||||||
OPENSSL_PUT_ERROR(SSL, SSL_R_PARSE_TLSEXT);
|
OPENSSL_PUT_ERROR(SSL, SSL_R_PARSE_TLSEXT);
|
||||||
return ssl_hs_error;
|
return ssl_hs_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* There should be nothing left over in the message. */
|
|
||||||
if (CBS_len(&cbs) != 0) {
|
|
||||||
OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_PACKET_LENGTH);
|
|
||||||
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
|
|
||||||
return ssl_hs_error;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Let cert callback update server certificates if required.
|
/* Let cert callback update server certificates if required.
|
||||||
*
|
*
|
||||||
* TODO(davidben): Can this get run earlier? */
|
* TODO(davidben): Can this get run earlier? */
|
||||||
@ -197,8 +166,14 @@ static enum ssl_hs_wait_t do_process_client_hello(SSL *ssl, SSL_HANDSHAKE *hs) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint16_t min_version, max_version;
|
||||||
|
if (!ssl_get_version_range(ssl, &min_version, &max_version)) {
|
||||||
|
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
|
||||||
|
return ssl_hs_error;
|
||||||
|
}
|
||||||
|
|
||||||
STACK_OF(SSL_CIPHER) *ciphers =
|
STACK_OF(SSL_CIPHER) *ciphers =
|
||||||
ssl_bytes_to_cipher_list(ssl, &cipher_suites, max_version);
|
ssl_parse_client_cipher_list(ssl, &client_hello, max_version);
|
||||||
if (ciphers == NULL) {
|
if (ciphers == NULL) {
|
||||||
return ssl_hs_error;
|
return ssl_hs_error;
|
||||||
}
|
}
|
||||||
@ -232,7 +207,7 @@ static enum ssl_hs_wait_t do_process_client_hello(SSL *ssl, SSL_HANDSHAKE *hs) {
|
|||||||
|
|
||||||
/* Resolve ECDHE and incorporate it into the secret. */
|
/* Resolve ECDHE and incorporate it into the secret. */
|
||||||
int need_retry;
|
int need_retry;
|
||||||
if (!resolve_ecdhe_secret(ssl, &need_retry, &early_ctx)) {
|
if (!resolve_ecdhe_secret(ssl, &need_retry, &client_hello)) {
|
||||||
if (need_retry) {
|
if (need_retry) {
|
||||||
hs->state = state_send_hello_retry_request;
|
hs->state = state_send_hello_retry_request;
|
||||||
return ssl_hs_ok;
|
return ssl_hs_ok;
|
||||||
@ -276,8 +251,8 @@ static enum ssl_hs_wait_t do_process_second_client_hello(SSL *ssl,
|
|||||||
return ssl_hs_error;
|
return ssl_hs_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ssl_early_callback_ctx early_ctx;
|
struct ssl_early_callback_ctx client_hello;
|
||||||
if (!ssl_early_callback_init(ssl, &early_ctx, ssl->init_msg,
|
if (!ssl_early_callback_init(ssl, &client_hello, ssl->init_msg,
|
||||||
ssl->init_num)) {
|
ssl->init_num)) {
|
||||||
OPENSSL_PUT_ERROR(SSL, SSL_R_CLIENTHELLO_PARSE_FAILED);
|
OPENSSL_PUT_ERROR(SSL, SSL_R_CLIENTHELLO_PARSE_FAILED);
|
||||||
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
|
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
|
||||||
@ -285,7 +260,7 @@ static enum ssl_hs_wait_t do_process_second_client_hello(SSL *ssl,
|
|||||||
}
|
}
|
||||||
|
|
||||||
int need_retry;
|
int need_retry;
|
||||||
if (!resolve_ecdhe_secret(ssl, &need_retry, &early_ctx)) {
|
if (!resolve_ecdhe_secret(ssl, &need_retry, &client_hello)) {
|
||||||
if (need_retry) {
|
if (need_retry) {
|
||||||
/* Only send one HelloRetryRequest. */
|
/* Only send one HelloRetryRequest. */
|
||||||
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
|
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
|
||||||
|
Loading…
Reference in New Issue
Block a user