Reorder states and functions by where they appear in the handshake. Remove unnecessary hooks on SSL_PROTOCOL_METHOD. Change-Id: I78dae9cf70792170abed6f38510ce870707e82ff Reviewed-on: https://boringssl-review.googlesource.com/8184 Reviewed-by: David Benjamin <davidben@google.com>kris/onging/CECPQ3_patch15
@@ -63,8 +63,6 @@ static const SSL_PROTOCOL_METHOD DTLS_protocol_method = { | |||
1 /* is_dtls */, | |||
dtls1_new, | |||
dtls1_free, | |||
ssl3_accept, | |||
ssl3_connect, | |||
dtls1_get_message, | |||
dtls1_read_app_data, | |||
dtls1_read_change_cipher_spec, | |||
@@ -806,8 +806,6 @@ struct ssl_protocol_method_st { | |||
char is_dtls; | |||
int (*ssl_new)(SSL *ssl); | |||
void (*ssl_free)(SSL *ssl); | |||
int (*ssl_accept)(SSL *ssl); | |||
int (*ssl_connect)(SSL *ssl); | |||
long (*ssl_get_message)(SSL *ssl, int msg_type, | |||
enum ssl_hash_message_t hash_message, int *ok); | |||
int (*ssl_read_app_data)(SSL *ssl, uint8_t *buf, int len, int peek); | |||
@@ -173,20 +173,18 @@ | |||
static int ssl3_send_client_hello(SSL *ssl); | |||
static int dtls1_get_hello_verify(SSL *ssl); | |||
static int ssl3_get_server_hello(SSL *ssl); | |||
static int ssl3_get_certificate_request(SSL *ssl); | |||
static int ssl3_get_new_session_ticket(SSL *ssl); | |||
static int ssl3_get_server_certificate(SSL *ssl); | |||
static int ssl3_get_cert_status(SSL *ssl); | |||
static int ssl3_verify_server_cert(SSL *ssl); | |||
static int ssl3_get_server_key_exchange(SSL *ssl); | |||
static int ssl3_get_certificate_request(SSL *ssl); | |||
static int ssl3_get_server_done(SSL *ssl); | |||
static int ssl3_send_cert_verify(SSL *ssl); | |||
static int ssl3_send_client_certificate(SSL *ssl); | |||
static int ssl_do_client_cert_cb(SSL *ssl, X509 **out_x509, | |||
EVP_PKEY **out_pkey); | |||
static int ssl3_send_client_key_exchange(SSL *ssl); | |||
static int ssl3_get_server_key_exchange(SSL *ssl); | |||
static int ssl3_get_server_certificate(SSL *ssl); | |||
static int ssl3_send_cert_verify(SSL *ssl); | |||
static int ssl3_send_next_proto(SSL *ssl); | |||
static int ssl3_send_channel_id(SSL *ssl); | |||
static int ssl3_verify_server_cert(SSL *ssl); | |||
static int ssl3_get_new_session_ticket(SSL *ssl); | |||
int ssl3_connect(SSL *ssl) { | |||
BUF_MEM *buf = NULL; | |||
@@ -287,6 +285,14 @@ int ssl3_connect(SSL *ssl) { | |||
} | |||
break; | |||
case SSL3_ST_CR_CERT_STATUS_A: | |||
ret = ssl3_get_cert_status(ssl); | |||
if (ret <= 0) { | |||
goto end; | |||
} | |||
ssl->state = SSL3_ST_VERIFY_SERVER_CERT; | |||
break; | |||
case SSL3_ST_VERIFY_SERVER_CERT: | |||
ret = ssl3_verify_server_cert(ssl); | |||
if (ret <= 0) { | |||
@@ -448,6 +454,19 @@ int ssl3_connect(SSL *ssl) { | |||
} | |||
break; | |||
case SSL3_ST_FALSE_START: | |||
/* Allow NewSessionTicket if ticket expected */ | |||
if (ssl->tlsext_ticket_expected) { | |||
ssl->state = SSL3_ST_CR_SESSION_TICKET_A; | |||
} else { | |||
ssl->state = SSL3_ST_CR_CHANGE; | |||
} | |||
ssl->s3->tmp.in_false_start = 1; | |||
ssl_free_wbio_buffer(ssl); | |||
ret = 1; | |||
goto end; | |||
case SSL3_ST_CR_SESSION_TICKET_A: | |||
ret = ssl3_get_new_session_ticket(ssl); | |||
if (ret <= 0) { | |||
@@ -456,14 +475,6 @@ int ssl3_connect(SSL *ssl) { | |||
ssl->state = SSL3_ST_CR_CHANGE; | |||
break; | |||
case SSL3_ST_CR_CERT_STATUS_A: | |||
ret = ssl3_get_cert_status(ssl); | |||
if (ret <= 0) { | |||
goto end; | |||
} | |||
ssl->state = SSL3_ST_VERIFY_SERVER_CERT; | |||
break; | |||
case SSL3_ST_CR_CHANGE: | |||
ret = ssl->method->ssl_read_change_cipher_spec(ssl); | |||
if (ret <= 0) { | |||
@@ -503,19 +514,6 @@ int ssl3_connect(SSL *ssl) { | |||
} | |||
break; | |||
case SSL3_ST_FALSE_START: | |||
/* Allow NewSessionTicket if ticket expected */ | |||
if (ssl->tlsext_ticket_expected) { | |||
ssl->state = SSL3_ST_CR_SESSION_TICKET_A; | |||
} else { | |||
ssl->state = SSL3_ST_CR_CHANGE; | |||
} | |||
ssl->s3->tmp.in_false_start = 1; | |||
ssl_free_wbio_buffer(ssl); | |||
ret = 1; | |||
goto end; | |||
case SSL_ST_OK: | |||
/* clean a few things up */ | |||
ssl3_cleanup_key_block(ssl); | |||
@@ -1083,6 +1081,63 @@ err: | |||
return ret; | |||
} | |||
static int ssl3_get_cert_status(SSL *ssl) { | |||
int ok, al; | |||
long n; | |||
CBS certificate_status, ocsp_response; | |||
uint8_t status_type; | |||
n = ssl->method->ssl_get_message(ssl, -1, ssl_hash_message, &ok); | |||
if (!ok) { | |||
return n; | |||
} | |||
if (ssl->s3->tmp.message_type != SSL3_MT_CERTIFICATE_STATUS) { | |||
/* A server may send status_request in ServerHello and then change | |||
* its mind about sending CertificateStatus. */ | |||
ssl->s3->tmp.reuse_message = 1; | |||
return 1; | |||
} | |||
CBS_init(&certificate_status, ssl->init_msg, n); | |||
if (!CBS_get_u8(&certificate_status, &status_type) || | |||
status_type != TLSEXT_STATUSTYPE_ocsp || | |||
!CBS_get_u24_length_prefixed(&certificate_status, &ocsp_response) || | |||
CBS_len(&ocsp_response) == 0 || | |||
CBS_len(&certificate_status) != 0) { | |||
al = SSL_AD_DECODE_ERROR; | |||
OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); | |||
goto f_err; | |||
} | |||
if (!CBS_stow(&ocsp_response, &ssl->session->ocsp_response, | |||
&ssl->session->ocsp_response_length)) { | |||
al = SSL_AD_INTERNAL_ERROR; | |||
OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); | |||
goto f_err; | |||
} | |||
return 1; | |||
f_err: | |||
ssl3_send_alert(ssl, SSL3_AL_FATAL, al); | |||
return -1; | |||
} | |||
static int ssl3_verify_server_cert(SSL *ssl) { | |||
int ret = ssl_verify_cert_chain(ssl, ssl->session->cert_chain); | |||
if (ssl->verify_mode != SSL_VERIFY_NONE && ret <= 0) { | |||
int al = ssl_verify_alarm_type(ssl->verify_result); | |||
ssl3_send_alert(ssl, SSL3_AL_FATAL, al); | |||
OPENSSL_PUT_ERROR(SSL, SSL_R_CERTIFICATE_VERIFY_FAILED); | |||
} else { | |||
ret = 1; | |||
ERR_clear_error(); /* but we keep ssl->verify_result */ | |||
} | |||
return ret; | |||
} | |||
static int ssl3_get_server_key_exchange(SSL *ssl) { | |||
EVP_MD_CTX md_ctx; | |||
int al, ok; | |||
@@ -1460,141 +1515,120 @@ err: | |||
return ret; | |||
} | |||
static int ssl3_get_new_session_ticket(SSL *ssl) { | |||
int ok, al; | |||
long n = ssl->method->ssl_get_message(ssl, SSL3_MT_NEW_SESSION_TICKET, | |||
ssl_hash_message, &ok); | |||
static int ssl3_get_server_done(SSL *ssl) { | |||
int ok; | |||
long n; | |||
n = ssl->method->ssl_get_message(ssl, SSL3_MT_SERVER_DONE, ssl_hash_message, | |||
&ok); | |||
if (!ok) { | |||
return n; | |||
} | |||
CBS new_session_ticket, ticket; | |||
uint32_t ticket_lifetime_hint; | |||
CBS_init(&new_session_ticket, ssl->init_msg, n); | |||
if (!CBS_get_u32(&new_session_ticket, &ticket_lifetime_hint) || | |||
!CBS_get_u16_length_prefixed(&new_session_ticket, &ticket) || | |||
CBS_len(&new_session_ticket) != 0) { | |||
al = SSL_AD_DECODE_ERROR; | |||
OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); | |||
goto f_err; | |||
} | |||
if (CBS_len(&ticket) == 0) { | |||
/* RFC 5077 allows a server to change its mind and send no ticket after | |||
* negotiating the extension. The value of |tlsext_ticket_expected| is | |||
* checked in |ssl_update_cache| so is cleared here to avoid an unnecessary | |||
* update. */ | |||
ssl->tlsext_ticket_expected = 0; | |||
return 1; | |||
if (n > 0) { | |||
/* should contain no data */ | |||
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); | |||
OPENSSL_PUT_ERROR(SSL, SSL_R_LENGTH_MISMATCH); | |||
return -1; | |||
} | |||
if (ssl->hit) { | |||
/* The server is sending a new ticket for an existing session. Sessions are | |||
* immutable once established, so duplicate all but the ticket of the | |||
* existing session. */ | |||
uint8_t *bytes; | |||
size_t bytes_len; | |||
if (!SSL_SESSION_to_bytes_for_ticket(ssl->session, &bytes, &bytes_len)) { | |||
goto err; | |||
} | |||
SSL_SESSION *new_session = SSL_SESSION_from_bytes(bytes, bytes_len); | |||
OPENSSL_free(bytes); | |||
if (new_session == NULL) { | |||
/* This should never happen. */ | |||
OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); | |||
goto err; | |||
} | |||
return 1; | |||
} | |||
SSL_SESSION_free(ssl->session); | |||
ssl->session = new_session; | |||
} | |||
/* ssl3_has_client_certificate returns true if a client certificate is | |||
* configured. */ | |||
static int ssl3_has_client_certificate(SSL *ssl) { | |||
return ssl->cert && ssl->cert->x509 && ssl_has_private_key(ssl); | |||
} | |||
if (!CBS_stow(&ticket, &ssl->session->tlsext_tick, | |||
&ssl->session->tlsext_ticklen)) { | |||
OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); | |||
goto err; | |||
static int ssl_do_client_cert_cb(SSL *ssl, X509 **out_x509, | |||
EVP_PKEY **out_pkey) { | |||
if (ssl->ctx->client_cert_cb == NULL) { | |||
return 0; | |||
} | |||
ssl->session->tlsext_tick_lifetime_hint = ticket_lifetime_hint; | |||
/* Generate a session ID for this session based on the session ticket. We use | |||
* the session ID mechanism for detecting ticket resumption. This also fits in | |||
* with assumptions elsewhere in OpenSSL.*/ | |||
if (!EVP_Digest(CBS_data(&ticket), CBS_len(&ticket), ssl->session->session_id, | |||
&ssl->session->session_id_length, EVP_sha256(), NULL)) { | |||
goto err; | |||
int ret = ssl->ctx->client_cert_cb(ssl, out_x509, out_pkey); | |||
if (ret <= 0) { | |||
return ret; | |||
} | |||
assert(*out_x509 != NULL); | |||
assert(*out_pkey != NULL); | |||
return 1; | |||
f_err: | |||
ssl3_send_alert(ssl, SSL3_AL_FATAL, al); | |||
err: | |||
return -1; | |||
} | |||
static int ssl3_get_cert_status(SSL *ssl) { | |||
int ok, al; | |||
long n; | |||
CBS certificate_status, ocsp_response; | |||
uint8_t status_type; | |||
n = ssl->method->ssl_get_message(ssl, -1, ssl_hash_message, &ok); | |||
static int ssl3_send_client_certificate(SSL *ssl) { | |||
if (ssl->state == SSL3_ST_CW_CERT_A) { | |||
/* Call cert_cb to update the certificate. */ | |||
if (ssl->cert->cert_cb) { | |||
int ret = ssl->cert->cert_cb(ssl, ssl->cert->cert_cb_arg); | |||
if (ret < 0) { | |||
ssl->rwstate = SSL_X509_LOOKUP; | |||
return -1; | |||
} | |||
if (ret == 0) { | |||
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR); | |||
return -1; | |||
} | |||
} | |||
if (!ok) { | |||
return n; | |||
if (ssl3_has_client_certificate(ssl)) { | |||
ssl->state = SSL3_ST_CW_CERT_C; | |||
} else { | |||
ssl->state = SSL3_ST_CW_CERT_B; | |||
} | |||
} | |||
if (ssl->s3->tmp.message_type != SSL3_MT_CERTIFICATE_STATUS) { | |||
/* A server may send status_request in ServerHello and then change | |||
* its mind about sending CertificateStatus. */ | |||
ssl->s3->tmp.reuse_message = 1; | |||
return 1; | |||
} | |||
if (ssl->state == SSL3_ST_CW_CERT_B) { | |||
/* Call client_cert_cb to update the certificate. */ | |||
X509 *x509 = NULL; | |||
EVP_PKEY *pkey = NULL; | |||
int ret = ssl_do_client_cert_cb(ssl, &x509, &pkey); | |||
if (ret < 0) { | |||
ssl->rwstate = SSL_X509_LOOKUP; | |||
return -1; | |||
} | |||
CBS_init(&certificate_status, ssl->init_msg, n); | |||
if (!CBS_get_u8(&certificate_status, &status_type) || | |||
status_type != TLSEXT_STATUSTYPE_ocsp || | |||
!CBS_get_u24_length_prefixed(&certificate_status, &ocsp_response) || | |||
CBS_len(&ocsp_response) == 0 || | |||
CBS_len(&certificate_status) != 0) { | |||
al = SSL_AD_DECODE_ERROR; | |||
OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); | |||
goto f_err; | |||
} | |||
int setup_error = ret == 1 && (!SSL_use_certificate(ssl, x509) || | |||
!SSL_use_PrivateKey(ssl, pkey)); | |||
X509_free(x509); | |||
EVP_PKEY_free(pkey); | |||
if (setup_error) { | |||
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR); | |||
return -1; | |||
} | |||
if (!CBS_stow(&ocsp_response, &ssl->session->ocsp_response, | |||
&ssl->session->ocsp_response_length)) { | |||
al = SSL_AD_INTERNAL_ERROR; | |||
OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); | |||
goto f_err; | |||
ssl->state = SSL3_ST_CW_CERT_C; | |||
} | |||
return 1; | |||
f_err: | |||
ssl3_send_alert(ssl, SSL3_AL_FATAL, al); | |||
return -1; | |||
} | |||
static int ssl3_get_server_done(SSL *ssl) { | |||
int ok; | |||
long n; | |||
n = ssl->method->ssl_get_message(ssl, SSL3_MT_SERVER_DONE, ssl_hash_message, | |||
&ok); | |||
if (ssl->state == SSL3_ST_CW_CERT_C) { | |||
if (!ssl3_has_client_certificate(ssl)) { | |||
/* Without a client certificate, the handshake buffer may be released. */ | |||
ssl3_free_handshake_buffer(ssl); | |||
if (!ok) { | |||
return n; | |||
} | |||
if (ssl->version == SSL3_VERSION) { | |||
/* In SSL 3.0, send no certificate by skipping both messages. */ | |||
ssl->s3->tmp.cert_req = 0; | |||
ssl3_send_alert(ssl, SSL3_AL_WARNING, SSL_AD_NO_CERTIFICATE); | |||
return 1; | |||
} | |||
if (n > 0) { | |||
/* should contain no data */ | |||
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); | |||
OPENSSL_PUT_ERROR(SSL, SSL_R_LENGTH_MISMATCH); | |||
return -1; | |||
/* In TLS, send an empty Certificate message. */ | |||
ssl->s3->tmp.cert_req = 2; | |||
uint8_t *p = ssl_handshake_start(ssl); | |||
l2n3(0, p); | |||
if (!ssl_set_handshake_header(ssl, SSL3_MT_CERTIFICATE, 3)) { | |||
return -1; | |||
} | |||
} else if (!ssl3_output_cert_chain(ssl)) { | |||
return -1; | |||
} | |||
ssl->state = SSL3_ST_CW_CERT_D; | |||
} | |||
return 1; | |||
assert(ssl->state == SSL3_ST_CW_CERT_D); | |||
return ssl_do_write(ssl); | |||
} | |||
OPENSSL_COMPILE_ASSERT(sizeof(size_t) >= sizeof(unsigned), | |||
@@ -1887,85 +1921,6 @@ err: | |||
return -1; | |||
} | |||
/* ssl3_has_client_certificate returns true if a client certificate is | |||
* configured. */ | |||
static int ssl3_has_client_certificate(SSL *ssl) { | |||
return ssl->cert && ssl->cert->x509 && ssl_has_private_key(ssl); | |||
} | |||
static int ssl3_send_client_certificate(SSL *ssl) { | |||
if (ssl->state == SSL3_ST_CW_CERT_A) { | |||
/* Call cert_cb to update the certificate. */ | |||
if (ssl->cert->cert_cb) { | |||
int ret = ssl->cert->cert_cb(ssl, ssl->cert->cert_cb_arg); | |||
if (ret < 0) { | |||
ssl->rwstate = SSL_X509_LOOKUP; | |||
return -1; | |||
} | |||
if (ret == 0) { | |||
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR); | |||
return -1; | |||
} | |||
} | |||
if (ssl3_has_client_certificate(ssl)) { | |||
ssl->state = SSL3_ST_CW_CERT_C; | |||
} else { | |||
ssl->state = SSL3_ST_CW_CERT_B; | |||
} | |||
} | |||
if (ssl->state == SSL3_ST_CW_CERT_B) { | |||
/* Call client_cert_cb to update the certificate. */ | |||
X509 *x509 = NULL; | |||
EVP_PKEY *pkey = NULL; | |||
int ret = ssl_do_client_cert_cb(ssl, &x509, &pkey); | |||
if (ret < 0) { | |||
ssl->rwstate = SSL_X509_LOOKUP; | |||
return -1; | |||
} | |||
int setup_error = ret == 1 && (!SSL_use_certificate(ssl, x509) || | |||
!SSL_use_PrivateKey(ssl, pkey)); | |||
X509_free(x509); | |||
EVP_PKEY_free(pkey); | |||
if (setup_error) { | |||
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR); | |||
return -1; | |||
} | |||
ssl->state = SSL3_ST_CW_CERT_C; | |||
} | |||
if (ssl->state == SSL3_ST_CW_CERT_C) { | |||
if (!ssl3_has_client_certificate(ssl)) { | |||
/* Without a client certificate, the handshake buffer may be released. */ | |||
ssl3_free_handshake_buffer(ssl); | |||
if (ssl->version == SSL3_VERSION) { | |||
/* In SSL 3.0, send no certificate by skipping both messages. */ | |||
ssl->s3->tmp.cert_req = 0; | |||
ssl3_send_alert(ssl, SSL3_AL_WARNING, SSL_AD_NO_CERTIFICATE); | |||
return 1; | |||
} | |||
/* In TLS, send an empty Certificate message. */ | |||
ssl->s3->tmp.cert_req = 2; | |||
uint8_t *p = ssl_handshake_start(ssl); | |||
l2n3(0, p); | |||
if (!ssl_set_handshake_header(ssl, SSL3_MT_CERTIFICATE, 3)) { | |||
return -1; | |||
} | |||
} else if (!ssl3_output_cert_chain(ssl)) { | |||
return -1; | |||
} | |||
ssl->state = SSL3_ST_CW_CERT_D; | |||
} | |||
assert(ssl->state == SSL3_ST_CW_CERT_D); | |||
return ssl_do_write(ssl); | |||
} | |||
static int ssl3_send_next_proto(SSL *ssl) { | |||
if (ssl->state == SSL3_ST_CW_NEXT_PROTO_B) { | |||
return ssl_do_write(ssl); | |||
@@ -2078,32 +2033,75 @@ err: | |||
return ret; | |||
} | |||
static int ssl_do_client_cert_cb(SSL *ssl, X509 **out_x509, | |||
EVP_PKEY **out_pkey) { | |||
if (ssl->ctx->client_cert_cb == NULL) { | |||
return 0; | |||
static int ssl3_get_new_session_ticket(SSL *ssl) { | |||
int ok, al; | |||
long n = ssl->method->ssl_get_message(ssl, SSL3_MT_NEW_SESSION_TICKET, | |||
ssl_hash_message, &ok); | |||
if (!ok) { | |||
return n; | |||
} | |||
int ret = ssl->ctx->client_cert_cb(ssl, out_x509, out_pkey); | |||
if (ret <= 0) { | |||
return ret; | |||
CBS new_session_ticket, ticket; | |||
uint32_t ticket_lifetime_hint; | |||
CBS_init(&new_session_ticket, ssl->init_msg, n); | |||
if (!CBS_get_u32(&new_session_ticket, &ticket_lifetime_hint) || | |||
!CBS_get_u16_length_prefixed(&new_session_ticket, &ticket) || | |||
CBS_len(&new_session_ticket) != 0) { | |||
al = SSL_AD_DECODE_ERROR; | |||
OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); | |||
goto f_err; | |||
} | |||
assert(*out_x509 != NULL); | |||
assert(*out_pkey != NULL); | |||
return 1; | |||
} | |||
if (CBS_len(&ticket) == 0) { | |||
/* RFC 5077 allows a server to change its mind and send no ticket after | |||
* negotiating the extension. The value of |tlsext_ticket_expected| is | |||
* checked in |ssl_update_cache| so is cleared here to avoid an unnecessary | |||
* update. */ | |||
ssl->tlsext_ticket_expected = 0; | |||
return 1; | |||
} | |||
static int ssl3_verify_server_cert(SSL *ssl) { | |||
int ret = ssl_verify_cert_chain(ssl, ssl->session->cert_chain); | |||
if (ssl->verify_mode != SSL_VERIFY_NONE && ret <= 0) { | |||
int al = ssl_verify_alarm_type(ssl->verify_result); | |||
ssl3_send_alert(ssl, SSL3_AL_FATAL, al); | |||
OPENSSL_PUT_ERROR(SSL, SSL_R_CERTIFICATE_VERIFY_FAILED); | |||
} else { | |||
ret = 1; | |||
ERR_clear_error(); /* but we keep ssl->verify_result */ | |||
if (ssl->hit) { | |||
/* The server is sending a new ticket for an existing session. Sessions are | |||
* immutable once established, so duplicate all but the ticket of the | |||
* existing session. */ | |||
uint8_t *bytes; | |||
size_t bytes_len; | |||
if (!SSL_SESSION_to_bytes_for_ticket(ssl->session, &bytes, &bytes_len)) { | |||
goto err; | |||
} | |||
SSL_SESSION *new_session = SSL_SESSION_from_bytes(bytes, bytes_len); | |||
OPENSSL_free(bytes); | |||
if (new_session == NULL) { | |||
/* This should never happen. */ | |||
OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); | |||
goto err; | |||
} | |||
SSL_SESSION_free(ssl->session); | |||
ssl->session = new_session; | |||
} | |||
return ret; | |||
if (!CBS_stow(&ticket, &ssl->session->tlsext_tick, | |||
&ssl->session->tlsext_ticklen)) { | |||
OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); | |||
goto err; | |||
} | |||
ssl->session->tlsext_tick_lifetime_hint = ticket_lifetime_hint; | |||
/* Generate a session ID for this session based on the session ticket. We use | |||
* the session ID mechanism for detecting ticket resumption. This also fits in | |||
* with assumptions elsewhere in OpenSSL.*/ | |||
if (!EVP_Digest(CBS_data(&ticket), CBS_len(&ticket), ssl->session->session_id, | |||
&ssl->session->session_id_length, EVP_sha256(), NULL)) { | |||
goto err; | |||
} | |||
return 1; | |||
f_err: | |||
ssl3_send_alert(ssl, SSL3_AL_FATAL, al); | |||
err: | |||
return -1; | |||
} |
@@ -63,8 +63,6 @@ static const SSL_PROTOCOL_METHOD TLS_protocol_method = { | |||
0 /* is_dtls */, | |||
ssl3_new, | |||
ssl3_free, | |||
ssl3_accept, | |||
ssl3_connect, | |||
ssl3_get_message, | |||
ssl3_read_app_data, | |||
ssl3_read_change_cipher_spec, | |||
@@ -177,17 +177,17 @@ static int ssl3_get_initial_bytes(SSL *ssl); | |||
static int ssl3_get_v2_client_hello(SSL *ssl); | |||
static int ssl3_get_client_hello(SSL *ssl); | |||
static int ssl3_send_server_hello(SSL *ssl); | |||
static int ssl3_send_server_certificate(SSL *ssl); | |||
static int ssl3_send_certificate_status(SSL *ssl); | |||
static int ssl3_send_server_done(SSL *ssl); | |||
static int ssl3_send_server_key_exchange(SSL *ssl); | |||
static int ssl3_send_certificate_request(SSL *ssl); | |||
static int ssl3_send_server_done(SSL *ssl); | |||
static int ssl3_get_client_certificate(SSL *ssl); | |||
static int ssl3_get_client_key_exchange(SSL *ssl); | |||
static int ssl3_get_cert_verify(SSL *ssl); | |||
static int ssl3_get_client_certificate(SSL *ssl); | |||
static int ssl3_send_server_certificate(SSL *ssl); | |||
static int ssl3_send_new_session_ticket(SSL *ssl); | |||
static int ssl3_get_next_proto(SSL *ssl); | |||
static int ssl3_get_channel_id(SSL *ssl); | |||
static int ssl3_send_new_session_ticket(SSL *ssl); | |||
int ssl3_accept(SSL *ssl) { | |||
BUF_MEM *buf = NULL; | |||
@@ -352,19 +352,6 @@ int ssl3_accept(SSL *ssl) { | |||
ssl->state = SSL3_ST_SW_FLUSH; | |||
break; | |||
case SSL3_ST_SW_FLUSH: | |||
if (BIO_flush(ssl->wbio) <= 0) { | |||
ssl->rwstate = SSL_WRITING; | |||
ret = -1; | |||
goto end; | |||
} | |||
ssl->state = ssl->s3->tmp.next_state; | |||
if (ssl->state != SSL_ST_OK) { | |||
ssl->method->expect_flight(ssl); | |||
} | |||
break; | |||
case SSL3_ST_SR_CERT_A: | |||
if (ssl->s3->tmp.cert_request) { | |||
ret = ssl3_get_client_certificate(ssl); | |||
@@ -498,6 +485,19 @@ int ssl3_accept(SSL *ssl) { | |||
} | |||
break; | |||
case SSL3_ST_SW_FLUSH: | |||
if (BIO_flush(ssl->wbio) <= 0) { | |||
ssl->rwstate = SSL_WRITING; | |||
ret = -1; | |||
goto end; | |||
} | |||
ssl->state = ssl->s3->tmp.next_state; | |||
if (ssl->state != SSL_ST_OK) { | |||
ssl->method->expect_flight(ssl); | |||
} | |||
break; | |||
case SSL_ST_OK: | |||
/* clean a few things up */ | |||
ssl3_cleanup_key_block(ssl); | |||
@@ -1121,6 +1121,18 @@ static int ssl3_send_server_hello(SSL *ssl) { | |||
return ssl_do_write(ssl); | |||
} | |||
static int ssl3_send_server_certificate(SSL *ssl) { | |||
if (ssl->state == SSL3_ST_SW_CERT_A) { | |||
if (!ssl3_output_cert_chain(ssl)) { | |||
return 0; | |||
} | |||
ssl->state = SSL3_ST_SW_CERT_B; | |||
} | |||
/* SSL3_ST_SW_CERT_B */ | |||
return ssl_do_write(ssl); | |||
} | |||
static int ssl3_send_certificate_status(SSL *ssl) { | |||
if (ssl->state == SSL3_ST_SW_CERT_STATUS_A) { | |||
CBB out, ocsp_response; | |||
@@ -1147,18 +1159,6 @@ static int ssl3_send_certificate_status(SSL *ssl) { | |||
return ssl_do_write(ssl); | |||
} | |||
static int ssl3_send_server_done(SSL *ssl) { | |||
if (ssl->state == SSL3_ST_SW_SRVR_DONE_A) { | |||
if (!ssl_set_handshake_header(ssl, SSL3_MT_SERVER_DONE, 0)) { | |||
return -1; | |||
} | |||
ssl->state = SSL3_ST_SW_SRVR_DONE_B; | |||
} | |||
/* SSL3_ST_SW_SRVR_DONE_B */ | |||
return ssl_do_write(ssl); | |||
} | |||
static int ssl3_send_server_key_exchange(SSL *ssl) { | |||
if (ssl->state == SSL3_ST_SW_KEY_EXCH_C) { | |||
return ssl_do_write(ssl); | |||
@@ -1415,6 +1415,157 @@ err: | |||
return -1; | |||
} | |||
static int ssl3_send_server_done(SSL *ssl) { | |||
if (ssl->state == SSL3_ST_SW_SRVR_DONE_A) { | |||
if (!ssl_set_handshake_header(ssl, SSL3_MT_SERVER_DONE, 0)) { | |||
return -1; | |||
} | |||
ssl->state = SSL3_ST_SW_SRVR_DONE_B; | |||
} | |||
/* SSL3_ST_SW_SRVR_DONE_B */ | |||
return ssl_do_write(ssl); | |||
} | |||
static int ssl3_get_client_certificate(SSL *ssl) { | |||
int ok, al, ret = -1; | |||
X509 *x = NULL; | |||
unsigned long n; | |||
STACK_OF(X509) *sk = NULL; | |||
SHA256_CTX sha256; | |||
CBS certificate_msg, certificate_list; | |||
int is_first_certificate = 1; | |||
assert(ssl->s3->tmp.cert_request); | |||
n = ssl->method->ssl_get_message(ssl, -1, ssl_hash_message, &ok); | |||
if (!ok) { | |||
return n; | |||
} | |||
if (ssl->s3->tmp.message_type != SSL3_MT_CERTIFICATE) { | |||
if (ssl->version == SSL3_VERSION && | |||
ssl->s3->tmp.message_type == SSL3_MT_CLIENT_KEY_EXCHANGE) { | |||
/* In SSL 3.0, the Certificate message is omitted to signal no certificate. */ | |||
if ((ssl->verify_mode & SSL_VERIFY_PEER) && | |||
(ssl->verify_mode & SSL_VERIFY_FAIL_IF_NO_PEER_CERT)) { | |||
OPENSSL_PUT_ERROR(SSL, SSL_R_PEER_DID_NOT_RETURN_A_CERTIFICATE); | |||
al = SSL_AD_HANDSHAKE_FAILURE; | |||
goto f_err; | |||
} | |||
ssl->s3->tmp.reuse_message = 1; | |||
return 1; | |||
} | |||
al = SSL_AD_UNEXPECTED_MESSAGE; | |||
OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_MESSAGE); | |||
goto f_err; | |||
} | |||
CBS_init(&certificate_msg, ssl->init_msg, n); | |||
sk = sk_X509_new_null(); | |||
if (sk == NULL) { | |||
OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); | |||
goto err; | |||
} | |||
if (!CBS_get_u24_length_prefixed(&certificate_msg, &certificate_list) || | |||
CBS_len(&certificate_msg) != 0) { | |||
al = SSL_AD_DECODE_ERROR; | |||
OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); | |||
goto f_err; | |||
} | |||
while (CBS_len(&certificate_list) > 0) { | |||
CBS certificate; | |||
const uint8_t *data; | |||
if (!CBS_get_u24_length_prefixed(&certificate_list, &certificate)) { | |||
al = SSL_AD_DECODE_ERROR; | |||
OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); | |||
goto f_err; | |||
} | |||
if (is_first_certificate && ssl->ctx->retain_only_sha256_of_client_certs) { | |||
/* If this is the first certificate, and we don't want to keep peer | |||
* certificates in memory, then we hash it right away. */ | |||
SHA256_Init(&sha256); | |||
SHA256_Update(&sha256, CBS_data(&certificate), CBS_len(&certificate)); | |||
SHA256_Final(ssl->session->peer_sha256, &sha256); | |||
ssl->session->peer_sha256_valid = 1; | |||
} | |||
is_first_certificate = 0; | |||
/* A u24 length cannot overflow a long. */ | |||
data = CBS_data(&certificate); | |||
x = d2i_X509(NULL, &data, (long)CBS_len(&certificate)); | |||
if (x == NULL) { | |||
al = SSL_AD_BAD_CERTIFICATE; | |||
OPENSSL_PUT_ERROR(SSL, ERR_R_ASN1_LIB); | |||
goto f_err; | |||
} | |||
if (data != CBS_data(&certificate) + CBS_len(&certificate)) { | |||
al = SSL_AD_DECODE_ERROR; | |||
OPENSSL_PUT_ERROR(SSL, SSL_R_CERT_LENGTH_MISMATCH); | |||
goto f_err; | |||
} | |||
if (!sk_X509_push(sk, x)) { | |||
OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); | |||
goto err; | |||
} | |||
x = NULL; | |||
} | |||
if (sk_X509_num(sk) <= 0) { | |||
/* No client certificate so the handshake buffer may be discarded. */ | |||
ssl3_free_handshake_buffer(ssl); | |||
/* TLS does not mind 0 certs returned */ | |||
if (ssl->version == SSL3_VERSION) { | |||
al = SSL_AD_HANDSHAKE_FAILURE; | |||
OPENSSL_PUT_ERROR(SSL, SSL_R_NO_CERTIFICATES_RETURNED); | |||
goto f_err; | |||
} else if ((ssl->verify_mode & SSL_VERIFY_PEER) && | |||
(ssl->verify_mode & SSL_VERIFY_FAIL_IF_NO_PEER_CERT)) { | |||
/* Fail for TLS only if we required a certificate */ | |||
OPENSSL_PUT_ERROR(SSL, SSL_R_PEER_DID_NOT_RETURN_A_CERTIFICATE); | |||
al = SSL_AD_HANDSHAKE_FAILURE; | |||
goto f_err; | |||
} | |||
} else { | |||
if (ssl_verify_cert_chain(ssl, sk) <= 0) { | |||
al = ssl_verify_alarm_type(ssl->verify_result); | |||
OPENSSL_PUT_ERROR(SSL, SSL_R_CERTIFICATE_VERIFY_FAILED); | |||
goto f_err; | |||
} | |||
} | |||
X509_free(ssl->session->peer); | |||
ssl->session->peer = sk_X509_shift(sk); | |||
ssl->session->verify_result = ssl->verify_result; | |||
sk_X509_pop_free(ssl->session->cert_chain, X509_free); | |||
ssl->session->cert_chain = sk; | |||
/* Inconsistency alert: cert_chain does *not* include the peer's own | |||
* certificate, while we do include it in s3_clnt.c */ | |||
sk = NULL; | |||
ret = 1; | |||
if (0) { | |||
f_err: | |||
ssl3_send_alert(ssl, SSL3_AL_FATAL, al); | |||
} | |||
err: | |||
X509_free(x); | |||
sk_X509_pop_free(sk, X509_free); | |||
return ret; | |||
} | |||
static int ssl3_get_client_key_exchange(SSL *ssl) { | |||
int al; | |||
CBS client_key_exchange; | |||
@@ -1790,155 +1941,155 @@ err: | |||
return ret; | |||
} | |||
static int ssl3_get_client_certificate(SSL *ssl) { | |||
int ok, al, ret = -1; | |||
X509 *x = NULL; | |||
unsigned long n; | |||
STACK_OF(X509) *sk = NULL; | |||
SHA256_CTX sha256; | |||
CBS certificate_msg, certificate_list; | |||
int is_first_certificate = 1; | |||
assert(ssl->s3->tmp.cert_request); | |||
n = ssl->method->ssl_get_message(ssl, -1, ssl_hash_message, &ok); | |||
/* ssl3_get_next_proto reads a Next Protocol Negotiation handshake message. It | |||
* sets the next_proto member in s if found */ | |||
static int ssl3_get_next_proto(SSL *ssl) { | |||
int ok; | |||
long n; | |||
CBS next_protocol, selected_protocol, padding; | |||
if (!ok) { | |||
return n; | |||
/* Clients cannot send a NextProtocol message if we didn't see the extension | |||
* in their ClientHello */ | |||
if (!ssl->s3->next_proto_neg_seen) { | |||
OPENSSL_PUT_ERROR(SSL, SSL_R_GOT_NEXT_PROTO_WITHOUT_EXTENSION); | |||
return -1; | |||
} | |||
if (ssl->s3->tmp.message_type != SSL3_MT_CERTIFICATE) { | |||
if (ssl->version == SSL3_VERSION && | |||
ssl->s3->tmp.message_type == SSL3_MT_CLIENT_KEY_EXCHANGE) { | |||
/* In SSL 3.0, the Certificate message is omitted to signal no certificate. */ | |||
if ((ssl->verify_mode & SSL_VERIFY_PEER) && | |||
(ssl->verify_mode & SSL_VERIFY_FAIL_IF_NO_PEER_CERT)) { | |||
OPENSSL_PUT_ERROR(SSL, SSL_R_PEER_DID_NOT_RETURN_A_CERTIFICATE); | |||
al = SSL_AD_HANDSHAKE_FAILURE; | |||
goto f_err; | |||
} | |||
ssl->s3->tmp.reuse_message = 1; | |||
return 1; | |||
} | |||
n = ssl->method->ssl_get_message(ssl, SSL3_MT_NEXT_PROTO, ssl_hash_message, | |||
&ok); | |||
al = SSL_AD_UNEXPECTED_MESSAGE; | |||
OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_MESSAGE); | |||
goto f_err; | |||
if (!ok) { | |||
return n; | |||
} | |||
CBS_init(&certificate_msg, ssl->init_msg, n); | |||
CBS_init(&next_protocol, ssl->init_msg, n); | |||
sk = sk_X509_new_null(); | |||
if (sk == NULL) { | |||
OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); | |||
goto err; | |||
} | |||
if (!CBS_get_u24_length_prefixed(&certificate_msg, &certificate_list) || | |||
CBS_len(&certificate_msg) != 0) { | |||
al = SSL_AD_DECODE_ERROR; | |||
OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); | |||
goto f_err; | |||
/* The payload looks like: | |||
* uint8 proto_len; | |||
* uint8 proto[proto_len]; | |||
* uint8 padding_len; | |||
* uint8 padding[padding_len]; */ | |||
if (!CBS_get_u8_length_prefixed(&next_protocol, &selected_protocol) || | |||
!CBS_get_u8_length_prefixed(&next_protocol, &padding) || | |||
CBS_len(&next_protocol) != 0 || | |||
!CBS_stow(&selected_protocol, &ssl->s3->next_proto_negotiated, | |||
&ssl->s3->next_proto_negotiated_len)) { | |||
return 0; | |||
} | |||
while (CBS_len(&certificate_list) > 0) { | |||
CBS certificate; | |||
const uint8_t *data; | |||
return 1; | |||
} | |||
if (!CBS_get_u24_length_prefixed(&certificate_list, &certificate)) { | |||
al = SSL_AD_DECODE_ERROR; | |||
OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); | |||
goto f_err; | |||
} | |||
/* ssl3_get_channel_id reads and verifies a ClientID handshake message. */ | |||
static int ssl3_get_channel_id(SSL *ssl) { | |||
int ret = -1, ok; | |||
long n; | |||
uint8_t channel_id_hash[EVP_MAX_MD_SIZE]; | |||
size_t channel_id_hash_len; | |||
const uint8_t *p; | |||
uint16_t extension_type; | |||
EC_GROUP *p256 = NULL; | |||
EC_KEY *key = NULL; | |||
EC_POINT *point = NULL; | |||
ECDSA_SIG sig; | |||
BIGNUM x, y; | |||
CBS encrypted_extensions, extension; | |||
if (is_first_certificate && ssl->ctx->retain_only_sha256_of_client_certs) { | |||
/* If this is the first certificate, and we don't want to keep peer | |||
* certificates in memory, then we hash it right away. */ | |||
SHA256_Init(&sha256); | |||
SHA256_Update(&sha256, CBS_data(&certificate), CBS_len(&certificate)); | |||
SHA256_Final(ssl->session->peer_sha256, &sha256); | |||
ssl->session->peer_sha256_valid = 1; | |||
} | |||
is_first_certificate = 0; | |||
n = ssl->method->ssl_get_message(ssl, SSL3_MT_CHANNEL_ID_ENCRYPTED_EXTENSIONS, | |||
ssl_dont_hash_message, &ok); | |||
/* A u24 length cannot overflow a long. */ | |||
data = CBS_data(&certificate); | |||
x = d2i_X509(NULL, &data, (long)CBS_len(&certificate)); | |||
if (x == NULL) { | |||
al = SSL_AD_BAD_CERTIFICATE; | |||
OPENSSL_PUT_ERROR(SSL, ERR_R_ASN1_LIB); | |||
goto f_err; | |||
} | |||
if (data != CBS_data(&certificate) + CBS_len(&certificate)) { | |||
al = SSL_AD_DECODE_ERROR; | |||
OPENSSL_PUT_ERROR(SSL, SSL_R_CERT_LENGTH_MISMATCH); | |||
goto f_err; | |||
} | |||
if (!sk_X509_push(sk, x)) { | |||
OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); | |||
goto err; | |||
} | |||
x = NULL; | |||
if (!ok) { | |||
return n; | |||
} | |||
if (sk_X509_num(sk) <= 0) { | |||
/* No client certificate so the handshake buffer may be discarded. */ | |||
ssl3_free_handshake_buffer(ssl); | |||
/* Before incorporating the EncryptedExtensions message to the handshake | |||
* hash, compute the hash that should have been signed. */ | |||
if (!tls1_channel_id_hash(ssl, channel_id_hash, &channel_id_hash_len)) { | |||
return -1; | |||
} | |||
assert(channel_id_hash_len == SHA256_DIGEST_LENGTH); | |||
/* TLS does not mind 0 certs returned */ | |||
if (ssl->version == SSL3_VERSION) { | |||
al = SSL_AD_HANDSHAKE_FAILURE; | |||
OPENSSL_PUT_ERROR(SSL, SSL_R_NO_CERTIFICATES_RETURNED); | |||
goto f_err; | |||
} else if ((ssl->verify_mode & SSL_VERIFY_PEER) && | |||
(ssl->verify_mode & SSL_VERIFY_FAIL_IF_NO_PEER_CERT)) { | |||
/* Fail for TLS only if we required a certificate */ | |||
OPENSSL_PUT_ERROR(SSL, SSL_R_PEER_DID_NOT_RETURN_A_CERTIFICATE); | |||
al = SSL_AD_HANDSHAKE_FAILURE; | |||
goto f_err; | |||
} | |||
} else { | |||
if (ssl_verify_cert_chain(ssl, sk) <= 0) { | |||
al = ssl_verify_alarm_type(ssl->verify_result); | |||
OPENSSL_PUT_ERROR(SSL, SSL_R_CERTIFICATE_VERIFY_FAILED); | |||
goto f_err; | |||
} | |||
if (!ssl3_hash_current_message(ssl)) { | |||
return -1; | |||
} | |||
X509_free(ssl->session->peer); | |||
ssl->session->peer = sk_X509_shift(sk); | |||
ssl->session->verify_result = ssl->verify_result; | |||
CBS_init(&encrypted_extensions, ssl->init_msg, n); | |||
sk_X509_pop_free(ssl->session->cert_chain, X509_free); | |||
ssl->session->cert_chain = sk; | |||
/* Inconsistency alert: cert_chain does *not* include the peer's own | |||
* certificate, while we do include it in s3_clnt.c */ | |||
/* EncryptedExtensions could include multiple extensions, but the only | |||
* extension that could be negotiated is ChannelID, so there can only be one | |||
* entry. | |||
* | |||
* The payload looks like: | |||
* uint16 extension_type | |||
* uint16 extension_len; | |||
* uint8 x[32]; | |||
* uint8 y[32]; | |||
* uint8 r[32]; | |||
* uint8 s[32]; */ | |||
sk = NULL; | |||
if (!CBS_get_u16(&encrypted_extensions, &extension_type) || | |||
!CBS_get_u16_length_prefixed(&encrypted_extensions, &extension) || | |||
CBS_len(&encrypted_extensions) != 0 || | |||
extension_type != TLSEXT_TYPE_channel_id || | |||
CBS_len(&extension) != TLSEXT_CHANNEL_ID_SIZE) { | |||
OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_MESSAGE); | |||
return -1; | |||
} | |||
ret = 1; | |||
p256 = EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1); | |||
if (!p256) { | |||
OPENSSL_PUT_ERROR(SSL, SSL_R_NO_P256_SUPPORT); | |||
return -1; | |||
} | |||
if (0) { | |||
f_err: | |||
ssl3_send_alert(ssl, SSL3_AL_FATAL, al); | |||
BN_init(&x); | |||
BN_init(&y); | |||
sig.r = BN_new(); | |||
sig.s = BN_new(); | |||
if (sig.r == NULL || sig.s == NULL) { | |||
goto err; | |||
} | |||
err: | |||
X509_free(x); | |||
sk_X509_pop_free(sk, X509_free); | |||
return ret; | |||
} | |||
p = CBS_data(&extension); | |||
if (BN_bin2bn(p + 0, 32, &x) == NULL || | |||
BN_bin2bn(p + 32, 32, &y) == NULL || | |||
BN_bin2bn(p + 64, 32, sig.r) == NULL || | |||
BN_bin2bn(p + 96, 32, sig.s) == NULL) { | |||
goto err; | |||
} | |||
static int ssl3_send_server_certificate(SSL *ssl) { | |||
if (ssl->state == SSL3_ST_SW_CERT_A) { | |||
if (!ssl3_output_cert_chain(ssl)) { | |||
return 0; | |||
} | |||
ssl->state = SSL3_ST_SW_CERT_B; | |||
point = EC_POINT_new(p256); | |||
if (!point || | |||
!EC_POINT_set_affine_coordinates_GFp(p256, point, &x, &y, NULL)) { | |||
goto err; | |||
} | |||
/* SSL3_ST_SW_CERT_B */ | |||
return ssl_do_write(ssl); | |||
key = EC_KEY_new(); | |||
if (!key || !EC_KEY_set_group(key, p256) || | |||
!EC_KEY_set_public_key(key, point)) { | |||
goto err; | |||
} | |||
/* We stored the handshake hash in |tlsext_channel_id| the first time that we | |||
* were called. */ | |||
if (!ECDSA_do_verify(channel_id_hash, channel_id_hash_len, &sig, key)) { | |||
OPENSSL_PUT_ERROR(SSL, SSL_R_CHANNEL_ID_SIGNATURE_INVALID); | |||
ssl->s3->tlsext_channel_id_valid = 0; | |||
goto err; | |||
} | |||
memcpy(ssl->s3->tlsext_channel_id, p, 64); | |||
ret = 1; | |||
err: | |||
BN_free(&x); | |||
BN_free(&y); | |||
BN_free(sig.r); | |||
BN_free(sig.s); | |||
EC_KEY_free(key); | |||
EC_POINT_free(point); | |||
EC_GROUP_free(p256); | |||
return ret; | |||
} | |||
/* send a new session ticket (not necessarily for a new session) */ | |||
@@ -2072,154 +2223,3 @@ err: | |||
HMAC_CTX_cleanup(&hctx); | |||
return ret; | |||
} | |||
/* ssl3_get_next_proto reads a Next Protocol Negotiation handshake message. It | |||
* sets the next_proto member in s if found */ | |||
static int ssl3_get_next_proto(SSL *ssl) { | |||
int ok; | |||
long n; | |||
CBS next_protocol, selected_protocol, padding; | |||
/* Clients cannot send a NextProtocol message if we didn't see the extension | |||
* in their ClientHello */ | |||
if (!ssl->s3->next_proto_neg_seen) { | |||
OPENSSL_PUT_ERROR(SSL, SSL_R_GOT_NEXT_PROTO_WITHOUT_EXTENSION); | |||
return -1; | |||
} | |||
n = ssl->method->ssl_get_message(ssl, SSL3_MT_NEXT_PROTO, ssl_hash_message, | |||
&ok); | |||
if (!ok) { | |||
return n; | |||
} | |||
CBS_init(&next_protocol, ssl->init_msg, n); | |||
/* The payload looks like: | |||
* uint8 proto_len; | |||
* uint8 proto[proto_len]; | |||
* uint8 padding_len; | |||
* uint8 padding[padding_len]; */ | |||
if (!CBS_get_u8_length_prefixed(&next_protocol, &selected_protocol) || | |||
!CBS_get_u8_length_prefixed(&next_protocol, &padding) || | |||
CBS_len(&next_protocol) != 0 || | |||
!CBS_stow(&selected_protocol, &ssl->s3->next_proto_negotiated, | |||
&ssl->s3->next_proto_negotiated_len)) { | |||
return 0; | |||
} | |||
return 1; | |||
} | |||
/* ssl3_get_channel_id reads and verifies a ClientID handshake message. */ | |||
static int ssl3_get_channel_id(SSL *ssl) { | |||
int ret = -1, ok; | |||
long n; | |||
uint8_t channel_id_hash[EVP_MAX_MD_SIZE]; | |||
size_t channel_id_hash_len; | |||
const uint8_t *p; | |||
uint16_t extension_type; | |||
EC_GROUP *p256 = NULL; | |||
EC_KEY *key = NULL; | |||
EC_POINT *point = NULL; | |||
ECDSA_SIG sig; | |||
BIGNUM x, y; | |||
CBS encrypted_extensions, extension; | |||
n = ssl->method->ssl_get_message(ssl, SSL3_MT_CHANNEL_ID_ENCRYPTED_EXTENSIONS, | |||
ssl_dont_hash_message, &ok); | |||
if (!ok) { | |||
return n; | |||
} | |||
/* Before incorporating the EncryptedExtensions message to the handshake | |||
* hash, compute the hash that should have been signed. */ | |||
if (!tls1_channel_id_hash(ssl, channel_id_hash, &channel_id_hash_len)) { | |||
return -1; | |||
} | |||
assert(channel_id_hash_len == SHA256_DIGEST_LENGTH); | |||
if (!ssl3_hash_current_message(ssl)) { | |||
return -1; | |||
} | |||
CBS_init(&encrypted_extensions, ssl->init_msg, n); | |||
/* EncryptedExtensions could include multiple extensions, but the only | |||
* extension that could be negotiated is ChannelID, so there can only be one | |||
* entry. | |||
* | |||
* The payload looks like: | |||
* uint16 extension_type | |||
* uint16 extension_len; | |||
* uint8 x[32]; | |||
* uint8 y[32]; | |||
* uint8 r[32]; | |||
* uint8 s[32]; */ | |||
if (!CBS_get_u16(&encrypted_extensions, &extension_type) || | |||
!CBS_get_u16_length_prefixed(&encrypted_extensions, &extension) || | |||
CBS_len(&encrypted_extensions) != 0 || | |||
extension_type != TLSEXT_TYPE_channel_id || | |||
CBS_len(&extension) != TLSEXT_CHANNEL_ID_SIZE) { | |||
OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_MESSAGE); | |||
return -1; | |||
} | |||
p256 = EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1); | |||
if (!p256) { | |||
OPENSSL_PUT_ERROR(SSL, SSL_R_NO_P256_SUPPORT); | |||
return -1; | |||
} | |||
BN_init(&x); | |||
BN_init(&y); | |||
sig.r = BN_new(); | |||
sig.s = BN_new(); | |||
if (sig.r == NULL || sig.s == NULL) { | |||
goto err; | |||
} | |||
p = CBS_data(&extension); | |||
if (BN_bin2bn(p + 0, 32, &x) == NULL || | |||
BN_bin2bn(p + 32, 32, &y) == NULL || | |||
BN_bin2bn(p + 64, 32, sig.r) == NULL || | |||
BN_bin2bn(p + 96, 32, sig.s) == NULL) { | |||
goto err; | |||
} | |||
point = EC_POINT_new(p256); | |||
if (!point || | |||
!EC_POINT_set_affine_coordinates_GFp(p256, point, &x, &y, NULL)) { | |||
goto err; | |||
} | |||
key = EC_KEY_new(); | |||
if (!key || !EC_KEY_set_group(key, p256) || | |||
!EC_KEY_set_public_key(key, point)) { | |||
goto err; | |||
} | |||
/* We stored the handshake hash in |tlsext_channel_id| the first time that we | |||
* were called. */ | |||
if (!ECDSA_do_verify(channel_id_hash, channel_id_hash_len, &sig, key)) { | |||
OPENSSL_PUT_ERROR(SSL, SSL_R_CHANNEL_ID_SIGNATURE_INVALID); | |||
ssl->s3->tlsext_channel_id_valid = 0; | |||
goto err; | |||
} | |||
memcpy(ssl->s3->tlsext_channel_id, p, 64); | |||
ret = 1; | |||
err: | |||
BN_free(&x); | |||
BN_free(&y); | |||
BN_free(sig.r); | |||
BN_free(sig.s); | |||
EC_KEY_free(key); | |||
EC_POINT_free(point); | |||
EC_GROUP_free(p256); | |||
return ret; | |||
} |
@@ -514,13 +514,13 @@ void SSL_free(SSL *ssl) { | |||
void SSL_set_connect_state(SSL *ssl) { | |||
ssl->server = 0; | |||
ssl->state = SSL_ST_CONNECT; | |||
ssl->handshake_func = ssl->method->ssl_connect; | |||
ssl->handshake_func = ssl3_connect; | |||
} | |||
void SSL_set_accept_state(SSL *ssl) { | |||
ssl->server = 1; | |||
ssl->state = SSL_ST_ACCEPT; | |||
ssl->handshake_func = ssl->method->ssl_accept; | |||
ssl->handshake_func = ssl3_accept; | |||
} | |||
void SSL_set_bio(SSL *ssl, BIO *rbio, BIO *wbio) { | |||
@@ -579,8 +579,6 @@ int SSL_connect(SSL *ssl) { | |||
SSL_set_connect_state(ssl); | |||
} | |||
assert(ssl->handshake_func == ssl->method->ssl_connect); | |||
return SSL_do_handshake(ssl); | |||
} | |||
@@ -590,8 +588,6 @@ int SSL_accept(SSL *ssl) { | |||
SSL_set_accept_state(ssl); | |||
} | |||
assert(ssl->handshake_func == ssl->method->ssl_accept); | |||
return SSL_do_handshake(ssl); | |||
} | |||