Split TLS 1.2 ClientHello processing into separate functions.

This ABCD thing with multiple ways to enter the same function is
confusing. ClientHello processing is the most egregious of these, so
split it up ahead of time as an intermediate step.

States remain named as-is due to them being exposed as public API. We
should have a story for which subset of states we need to promise as
public API and to intentionally break all other cases (map to some
generic value) before we go too far there.

BUG=128

Change-Id: Id9d28c6de14bd53c3294552691cebe705748f489
Reviewed-on: https://boringssl-review.googlesource.com/13563
Reviewed-by: Adam Langley <agl@google.com>
This commit is contained in:
David Benjamin 2017-02-02 23:51:22 -05:00 committed by Adam Langley
parent 7dccc71e08
commit 59bae5aa3a

View File

@ -171,7 +171,9 @@
#include "../crypto/internal.h" #include "../crypto/internal.h"
static int ssl3_get_client_hello(SSL_HANDSHAKE *hs); static int ssl3_process_client_hello(SSL_HANDSHAKE *hs);
static int ssl3_select_certificate(SSL_HANDSHAKE *hs);
static int ssl3_select_parameters(SSL_HANDSHAKE *hs);
static int ssl3_send_server_hello(SSL_HANDSHAKE *hs); static int ssl3_send_server_hello(SSL_HANDSHAKE *hs);
static int ssl3_send_server_certificate(SSL_HANDSHAKE *hs); static int ssl3_send_server_certificate(SSL_HANDSHAKE *hs);
static int ssl3_send_certificate_status(SSL_HANDSHAKE *hs); static int ssl3_send_certificate_status(SSL_HANDSHAKE *hs);
@ -227,13 +229,33 @@ int ssl3_accept(SSL_HANDSHAKE *hs) {
break; break;
case SSL3_ST_SR_CLNT_HELLO_A: case SSL3_ST_SR_CLNT_HELLO_A:
case SSL3_ST_SR_CLNT_HELLO_B: ret = ssl->method->ssl_get_message(ssl);
case SSL3_ST_SR_CLNT_HELLO_C: if (ret <= 0) {
case SSL3_ST_SR_CLNT_HELLO_D: goto end;
ret = ssl3_get_client_hello(hs);
if (hs->state == SSL_ST_TLS13) {
break;
} }
hs->state = SSL3_ST_SR_CLNT_HELLO_B;
break;
case SSL3_ST_SR_CLNT_HELLO_B:
ret = ssl3_process_client_hello(hs);
if (ret <= 0) {
goto end;
}
hs->state = SSL3_ST_SR_CLNT_HELLO_C;
break;
case SSL3_ST_SR_CLNT_HELLO_C:
ret = ssl3_select_certificate(hs);
if (ret <= 0) {
goto end;
}
if (hs->state != SSL_ST_TLS13) {
hs->state = SSL3_ST_SR_CLNT_HELLO_D;
}
break;
case SSL3_ST_SR_CLNT_HELLO_D:
ret = ssl3_select_parameters(hs);
if (ret <= 0) { if (ret <= 0) {
goto end; goto end;
} }
@ -807,125 +829,129 @@ static const SSL_CIPHER *ssl3_choose_cipher(
return ret; return ret;
} }
static int ssl3_get_client_hello(SSL_HANDSHAKE *hs) { static int ssl3_process_client_hello(SSL_HANDSHAKE *hs) {
SSL *const ssl = hs->ssl; SSL *const ssl = hs->ssl;
uint8_t al = SSL_AD_INTERNAL_ERROR; if (!ssl_check_message_type(ssl, SSL3_MT_CLIENT_HELLO)) {
int ret = -1; return -1;
SSL_SESSION *session = NULL;
if (hs->state == SSL3_ST_SR_CLNT_HELLO_A) {
/* The first time around, read the ClientHello. */
int msg_ret = ssl->method->ssl_get_message(ssl);
if (msg_ret <= 0) {
return msg_ret;
}
if (!ssl_check_message_type(ssl, SSL3_MT_CLIENT_HELLO)) {
return -1;
}
hs->state = SSL3_ST_SR_CLNT_HELLO_B;
} }
SSL_CLIENT_HELLO client_hello; SSL_CLIENT_HELLO client_hello;
if (!ssl_client_hello_init(ssl, &client_hello, ssl->init_msg, if (!ssl_client_hello_init(ssl, &client_hello, ssl->init_msg,
ssl->init_num)) { ssl->init_num)) {
al = SSL_AD_DECODE_ERROR;
OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
goto f_err; ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
return -1;
} }
if (hs->state == SSL3_ST_SR_CLNT_HELLO_B) { /* Run the early callback. */
/* Run the early callback. */ if (ssl->ctx->select_certificate_cb != NULL) {
if (ssl->ctx->select_certificate_cb != NULL) { switch (ssl->ctx->select_certificate_cb(&client_hello)) {
switch (ssl->ctx->select_certificate_cb(&client_hello)) { case 0:
case 0: ssl->rwstate = SSL_CERTIFICATE_SELECTION_PENDING;
ssl->rwstate = SSL_CERTIFICATE_SELECTION_PENDING; return -1;
goto err;
case -1: case -1:
/* Connection rejected. */ /* Connection rejected. */
al = SSL_AD_HANDSHAKE_FAILURE; 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_HANDSHAKE_FAILURE);
goto f_err; return -1;
default: default:
/* fallthrough */; /* fallthrough */;
}
} }
}
if (!negotiate_version(hs, &al, &client_hello)) { uint8_t alert;
goto f_err; if (!negotiate_version(hs, &alert, &client_hello)) {
} ssl3_send_alert(ssl, SSL3_AL_FATAL, alert);
return -1;
}
/* Load the client random. */ /* Load the client random. */
if (client_hello.random_len != SSL3_RANDOM_SIZE) { if (client_hello.random_len != SSL3_RANDOM_SIZE) {
OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
return -1;
}
OPENSSL_memcpy(ssl->s3->client_random, client_hello.random,
client_hello.random_len);
/* Only null compression is supported. TLS 1.3 further requires the peer
* advertise no other compression. */
if (OPENSSL_memchr(client_hello.compression_methods, 0,
client_hello.compression_methods_len) == NULL ||
(ssl3_protocol_version(ssl) >= TLS1_3_VERSION &&
client_hello.compression_methods_len != 1)) {
OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_COMPRESSION_LIST);
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
return -1;
}
/* TLS extensions. */
if (!ssl_parse_clienthello_tlsext(hs, &client_hello)) {
OPENSSL_PUT_ERROR(SSL, SSL_R_PARSE_TLSEXT);
return -1;
}
return 1;
}
static int ssl3_select_certificate(SSL_HANDSHAKE *hs) {
SSL *const ssl = hs->ssl;
/* Call |cert_cb| to update server certificates if required. */
if (ssl->cert->cert_cb != NULL) {
int rv = ssl->cert->cert_cb(ssl, ssl->cert->cert_cb_arg);
if (rv == 0) {
OPENSSL_PUT_ERROR(SSL, SSL_R_CERT_CB_ERROR);
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
return -1; return -1;
} }
OPENSSL_memcpy(ssl->s3->client_random, client_hello.random, if (rv < 0) {
client_hello.random_len); ssl->rwstate = SSL_X509_LOOKUP;
return -1;
/* Only null compression is supported. TLS 1.3 further requires the peer
* advertise no other compression. */
if (OPENSSL_memchr(client_hello.compression_methods, 0,
client_hello.compression_methods_len) == NULL ||
(ssl3_protocol_version(ssl) >= TLS1_3_VERSION &&
client_hello.compression_methods_len != 1)) {
al = SSL_AD_ILLEGAL_PARAMETER;
OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_COMPRESSION_LIST);
goto f_err;
} }
/* TLS extensions. */
if (!ssl_parse_clienthello_tlsext(hs, &client_hello)) {
OPENSSL_PUT_ERROR(SSL, SSL_R_PARSE_TLSEXT);
goto err;
}
hs->state = SSL3_ST_SR_CLNT_HELLO_C;
} }
if (hs->state == SSL3_ST_SR_CLNT_HELLO_C) { if (!ssl_auto_chain_if_needed(ssl)) {
/* Call |cert_cb| to update server certificates if required. */ return -1;
if (ssl->cert->cert_cb != NULL) {
int rv = ssl->cert->cert_cb(ssl, ssl->cert->cert_cb_arg);
if (rv == 0) {
al = SSL_AD_INTERNAL_ERROR;
OPENSSL_PUT_ERROR(SSL, SSL_R_CERT_CB_ERROR);
goto f_err;
}
if (rv < 0) {
ssl->rwstate = SSL_X509_LOOKUP;
goto err;
}
}
if (!ssl_auto_chain_if_needed(ssl)) {
goto err;
}
if (ssl3_protocol_version(ssl) >= TLS1_3_VERSION) {
/* Jump to the TLS 1.3 state machine. */
hs->state = SSL_ST_TLS13;
hs->do_tls13_handshake = tls13_server_handshake;
return 1;
}
/* Negotiate the cipher suite. This must be done after |cert_cb| so the
* certificate is finalized. */
ssl->s3->tmp.new_cipher =
ssl3_choose_cipher(hs, &client_hello, ssl_get_cipher_preferences(ssl));
if (ssl->s3->tmp.new_cipher == NULL) {
al = SSL_AD_HANDSHAKE_FAILURE;
OPENSSL_PUT_ERROR(SSL, SSL_R_NO_SHARED_CIPHER);
goto f_err;
}
hs->state = SSL3_ST_SR_CLNT_HELLO_D;
} }
assert(hs->state == SSL3_ST_SR_CLNT_HELLO_D); if (ssl3_protocol_version(ssl) >= TLS1_3_VERSION) {
/* Jump to the TLS 1.3 state machine. */
hs->state = SSL_ST_TLS13;
hs->do_tls13_handshake = tls13_server_handshake;
return 1;
}
SSL_CLIENT_HELLO client_hello;
if (!ssl_client_hello_init(ssl, &client_hello, ssl->init_msg,
ssl->init_num)) {
return -1;
}
/* Negotiate the cipher suite. This must be done after |cert_cb| so the
* certificate is finalized. */
ssl->s3->tmp.new_cipher =
ssl3_choose_cipher(hs, &client_hello, ssl_get_cipher_preferences(ssl));
if (ssl->s3->tmp.new_cipher == NULL) {
OPENSSL_PUT_ERROR(SSL, SSL_R_NO_SHARED_CIPHER);
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE);
return -1;
}
return 1;
}
static int ssl3_select_parameters(SSL_HANDSHAKE *hs) {
SSL *const ssl = hs->ssl;
uint8_t al = SSL_AD_INTERNAL_ERROR;
int ret = -1;
SSL_SESSION *session = NULL;
SSL_CLIENT_HELLO client_hello;
if (!ssl_client_hello_init(ssl, &client_hello, ssl->init_msg,
ssl->init_num)) {
return -1;
}
/* Determine whether we are doing session resumption. */ /* Determine whether we are doing session resumption. */
int tickets_supported = 0, renew_ticket = 0; int tickets_supported = 0, renew_ticket = 0;