This adds the machinery for doing TLS 1.3 1RTT. Change-Id: I736921ffe9dc6f6e64a08a836df6bb166d20f504 Reviewed-on: https://boringssl-review.googlesource.com/8720 Reviewed-by: David Benjamin <davidben@google.com> Commit-Queue: David Benjamin <davidben@google.com> CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>kris/onging/CECPQ3_patch15
@@ -44,6 +44,7 @@ SSL,141,DH_P_TOO_LONG | |||
SSL,142,DIGEST_CHECK_FAILED | |||
SSL,254,DOWNGRADE_DETECTED | |||
SSL,143,DTLS_MESSAGE_TOO_BIG | |||
SSL,257,DUPLICATE_EXTENSION | |||
SSL,144,ECC_CERT_NOT_FOR_SIGNING | |||
SSL,145,EMS_STATE_INCONSISTENT | |||
SSL,146,ENCRYPTED_LENGTH_TOO_LONG | |||
@@ -59,6 +60,7 @@ SSL,155,HTTPS_PROXY_REQUEST | |||
SSL,156,HTTP_REQUEST | |||
SSL,157,INAPPROPRIATE_FALLBACK | |||
SSL,158,INVALID_COMMAND | |||
SSL,256,INVALID_COMPRESSION_LIST | |||
SSL,159,INVALID_MESSAGE | |||
SSL,251,INVALID_OUTER_RECORD_TYPE | |||
SSL,160,INVALID_SSL_SESSION | |||
@@ -66,6 +68,7 @@ SSL,161,INVALID_TICKET_KEYS_LENGTH | |||
SSL,162,LENGTH_MISMATCH | |||
SSL,163,LIBRARY_HAS_NO_CIPHERS | |||
SSL,164,MISSING_EXTENSION | |||
SSL,258,MISSING_KEY_SHARE | |||
SSL,165,MISSING_RSA_CERTIFICATE | |||
SSL,166,MISSING_TMP_DH_KEY | |||
SSL,167,MISSING_TMP_ECDH_KEY | |||
@@ -548,6 +548,8 @@ OPENSSL_EXPORT int DTLSv1_handle_timeout(SSL *ssl); | |||
#define DTLS1_VERSION 0xfeff | |||
#define DTLS1_2_VERSION 0xfefd | |||
#define TLS1_3_DRAFT_VERSION 13 | |||
/* SSL_CTX_set_min_version sets the minimum protocol version for |ctx| to | |||
* |version|. */ | |||
OPENSSL_EXPORT void SSL_CTX_set_min_version(SSL_CTX *ctx, uint16_t version); | |||
@@ -2655,6 +2657,7 @@ OPENSSL_EXPORT const char *SSL_get_psk_identity(const SSL *ssl); | |||
#define SSL_AD_INTERNAL_ERROR TLS1_AD_INTERNAL_ERROR | |||
#define SSL_AD_USER_CANCELLED TLS1_AD_USER_CANCELLED | |||
#define SSL_AD_NO_RENEGOTIATION TLS1_AD_NO_RENEGOTIATION | |||
#define SSL_AD_MISSING_EXTENSION TLS1_AD_MISSING_EXTENSION | |||
#define SSL_AD_UNSUPPORTED_EXTENSION TLS1_AD_UNSUPPORTED_EXTENSION | |||
#define SSL_AD_CERTIFICATE_UNOBTAINABLE TLS1_AD_CERTIFICATE_UNOBTAINABLE | |||
#define SSL_AD_UNRECOGNIZED_NAME TLS1_AD_UNRECOGNIZED_NAME | |||
@@ -2919,6 +2922,7 @@ OPENSSL_EXPORT void SSL_CTX_set_dos_protection_cb( | |||
#define SSL_ST_INIT (SSL_ST_CONNECT | SSL_ST_ACCEPT) | |||
#define SSL_ST_OK 0x03 | |||
#define SSL_ST_RENEGOTIATE (0x04 | SSL_ST_INIT) | |||
#define SSL_ST_TLS13 (0x05 | SSL_ST_INIT) | |||
/* SSL_CB_* are possible values for the |type| parameter in the info | |||
* callback and the bitmasks that make them up. */ | |||
@@ -3538,6 +3542,7 @@ OPENSSL_EXPORT int SSL_set_private_key_digest_prefs(SSL *ssl, | |||
typedef struct ssl_protocol_method_st SSL_PROTOCOL_METHOD; | |||
typedef struct ssl3_enc_method SSL3_ENC_METHOD; | |||
typedef struct ssl_aead_ctx_st SSL_AEAD_CTX; | |||
typedef struct ssl_handshake_st SSL_HANDSHAKE; | |||
struct ssl_cipher_st { | |||
/* name is the OpenSSL name for the cipher. */ | |||
@@ -3578,6 +3583,8 @@ struct ssl_session_st { | |||
* A zero indicates that the value is unknown. */ | |||
uint32_t key_exchange_info; | |||
/* master_key, in TLS 1.2 and below, is the master secret associated with the | |||
* session. In TLS 1.3 and up, it is the resumption secret. */ | |||
int master_key_length; | |||
uint8_t master_key[SSL_MAX_MASTER_KEY_LENGTH]; | |||
@@ -4234,11 +4241,21 @@ typedef struct ssl3_state_st { | |||
uint8_t *pending_message; | |||
uint32_t pending_message_len; | |||
/* hs is the handshake state for the current handshake or NULL if there isn't | |||
* one. */ | |||
SSL_HANDSHAKE *hs; | |||
uint8_t write_traffic_secret[EVP_MAX_MD_SIZE]; | |||
uint8_t write_traffic_secret_len; | |||
uint8_t read_traffic_secret[EVP_MAX_MD_SIZE]; | |||
uint8_t read_traffic_secret_len; | |||
uint8_t exporter_secret[EVP_MAX_MD_SIZE]; | |||
uint8_t exporter_secret_len; | |||
/* State pertaining to the pending handshake. | |||
* | |||
* TODO(davidben): State is current spread all over the place. Move | |||
* pending handshake state here so it can be managed separately from | |||
* established connection state in case of renegotiations. */ | |||
* TODO(davidben): Move everything not needed after the handshake completes to | |||
* |hs| and remove this. */ | |||
struct { | |||
uint8_t finish_md[EVP_MAX_MD_SIZE]; | |||
uint8_t finish_md_len; | |||
@@ -4715,6 +4732,9 @@ OPENSSL_EXPORT int SSL_set_ssl_method(SSL *s, const SSL_METHOD *method); | |||
#define SSL_R_NO_COMMON_SIGNATURE_ALGORITHMS 253 | |||
#define SSL_R_DOWNGRADE_DETECTED 254 | |||
#define SSL_R_BUFFERED_MESSAGES_ON_CIPHER_CHANGE 255 | |||
#define SSL_R_INVALID_COMPRESSION_LIST 256 | |||
#define SSL_R_DUPLICATE_EXTENSION 257 | |||
#define SSL_R_MISSING_KEY_SHARE 258 | |||
#define SSL_R_SSLV3_ALERT_CLOSE_NOTIFY 1000 | |||
#define SSL_R_SSLV3_ALERT_UNEXPECTED_MESSAGE 1010 | |||
#define SSL_R_SSLV3_ALERT_BAD_RECORD_MAC 1020 | |||
@@ -392,6 +392,8 @@ OPENSSL_COMPILE_ASSERT( | |||
#define SSL3_MT_CLIENT_HELLO 1 | |||
#define SSL3_MT_SERVER_HELLO 2 | |||
#define SSL3_MT_NEW_SESSION_TICKET 4 | |||
#define SSL3_MT_HELLO_RETRY_REQUEST 6 | |||
#define SSL3_MT_ENCRYPTED_EXTENSIONS 8 | |||
#define SSL3_MT_CERTIFICATE 11 | |||
#define SSL3_MT_SERVER_KEY_EXCHANGE 12 | |||
#define SSL3_MT_CERTIFICATE_REQUEST 13 | |||
@@ -401,6 +403,7 @@ OPENSSL_COMPILE_ASSERT( | |||
#define SSL3_MT_FINISHED 20 | |||
#define SSL3_MT_CERTIFICATE_STATUS 22 | |||
#define SSL3_MT_SUPPLEMENTAL_DATA 23 | |||
#define SSL3_MT_KEY_UPDATE 24 | |||
#define SSL3_MT_NEXT_PROTO 67 | |||
#define SSL3_MT_CHANNEL_ID 203 | |||
#define DTLS1_MT_HELLO_VERIFY_REQUEST 3 | |||
@@ -211,6 +211,14 @@ extern "C" { | |||
#define TLSEXT_TYPE_early_data 42 | |||
#define TLSEXT_TYPE_cookie 44 | |||
/* TLSEXT_TYPE_draft_version is the extension used to advertise the TLS 1.3 | |||
* draft implemented. | |||
* | |||
* See | |||
* https://github.com/tlswg/tls13-spec/wiki/Implementations#version-negotiation | |||
*/ | |||
#define TLSEXT_TYPE_draft_version 0xff02 | |||
/* ExtensionType value from RFC5746 */ | |||
#define TLSEXT_TYPE_renegotiate 0xff01 | |||
@@ -31,6 +31,10 @@ add_library( | |||
t1_lib.c | |||
tls_method.c | |||
tls_record.c | |||
tls13_both.c | |||
tls13_client.c | |||
tls13_enc.c | |||
tls13_server.c | |||
) | |||
target_link_libraries(ssl crypto) | |||
@@ -200,7 +200,9 @@ int ssl3_connect(SSL *ssl) { | |||
case SSL_ST_CONNECT: | |||
ssl_do_info_callback(ssl, SSL_CB_HANDSHAKE_START, 1); | |||
if (!ssl->method->begin_handshake(ssl)) { | |||
ssl->s3->hs = ssl_handshake_new(tls13_client_handshake); | |||
if (ssl->s3->hs == NULL || | |||
!ssl->method->begin_handshake(ssl)) { | |||
ret = -1; | |||
goto end; | |||
} | |||
@@ -244,6 +246,9 @@ int ssl3_connect(SSL *ssl) { | |||
case SSL3_ST_CR_SRVR_HELLO_A: | |||
ret = ssl3_get_server_hello(ssl); | |||
if (ssl->state == SSL_ST_TLS13) { | |||
break; | |||
} | |||
if (ret <= 0) { | |||
goto end; | |||
} | |||
@@ -490,6 +495,14 @@ int ssl3_connect(SSL *ssl) { | |||
} | |||
break; | |||
case SSL_ST_TLS13: | |||
ret = tls13_handshake(ssl); | |||
if (ret <= 0) { | |||
goto end; | |||
} | |||
ssl->state = SSL_ST_OK; | |||
break; | |||
case SSL_ST_OK: | |||
/* clean a few things up */ | |||
ssl3_cleanup_key_block(ssl); | |||
@@ -499,6 +512,9 @@ int ssl3_connect(SSL *ssl) { | |||
/* Remove write buffering now. */ | |||
ssl_free_wbio_buffer(ssl); | |||
ssl_handshake_free(ssl->s3->hs); | |||
ssl->s3->hs = NULL; | |||
const int is_initial_handshake = !ssl->s3->initial_handshake_complete; | |||
ssl->s3->tmp.in_false_start = 0; | |||
@@ -730,8 +746,7 @@ static int ssl3_get_server_hello(SSL *ssl) { | |||
uint16_t server_wire_version, server_version, cipher_suite; | |||
uint8_t compression_method; | |||
int ret = | |||
ssl->method->ssl_get_message(ssl, SSL3_MT_SERVER_HELLO, ssl_hash_message); | |||
int ret = ssl->method->ssl_get_message(ssl, -1, ssl_hash_message); | |||
if (ret <= 0) { | |||
uint32_t err = ERR_peek_error(); | |||
if (ERR_GET_LIB(err) == ERR_LIB_SSL && | |||
@@ -747,14 +762,16 @@ static int ssl3_get_server_hello(SSL *ssl) { | |||
return ret; | |||
} | |||
if (ssl->s3->tmp.message_type != SSL3_MT_SERVER_HELLO && | |||
ssl->s3->tmp.message_type != SSL3_MT_HELLO_RETRY_REQUEST) { | |||
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE); | |||
OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_MESSAGE); | |||
return -1; | |||
} | |||
CBS_init(&server_hello, ssl->init_msg, ssl->init_num); | |||
if (!CBS_get_u16(&server_hello, &server_wire_version) || | |||
!CBS_get_bytes(&server_hello, &server_random, SSL3_RANDOM_SIZE) || | |||
!CBS_get_u8_length_prefixed(&server_hello, &session_id) || | |||
CBS_len(&session_id) > SSL3_SESSION_ID_SIZE || | |||
!CBS_get_u16(&server_hello, &cipher_suite) || | |||
!CBS_get_u8(&server_hello, &compression_method)) { | |||
if (!CBS_get_u16(&server_hello, &server_wire_version)) { | |||
al = SSL_AD_DECODE_ERROR; | |||
OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); | |||
goto f_err; | |||
@@ -784,6 +801,27 @@ static int ssl3_get_server_hello(SSL *ssl) { | |||
goto f_err; | |||
} | |||
if (ssl3_protocol_version(ssl) >= TLS1_3_VERSION) { | |||
ssl->state = SSL_ST_TLS13; | |||
return 1; | |||
} | |||
if (ssl->s3->tmp.message_type != SSL3_MT_SERVER_HELLO) { | |||
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE); | |||
OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_MESSAGE); | |||
return -1; | |||
} | |||
if (!CBS_get_bytes(&server_hello, &server_random, SSL3_RANDOM_SIZE) || | |||
!CBS_get_u8_length_prefixed(&server_hello, &session_id) || | |||
CBS_len(&session_id) > SSL3_SESSION_ID_SIZE || | |||
!CBS_get_u16(&server_hello, &cipher_suite) || | |||
!CBS_get_u8(&server_hello, &compression_method)) { | |||
al = SSL_AD_DECODE_ERROR; | |||
OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); | |||
goto f_err; | |||
} | |||
/* Copy over the server random. */ | |||
memcpy(ssl->s3->server_random, CBS_data(&server_random), SSL3_RANDOM_SIZE); | |||
@@ -201,7 +201,9 @@ int ssl3_accept(SSL *ssl) { | |||
case SSL_ST_ACCEPT: | |||
ssl_do_info_callback(ssl, SSL_CB_HANDSHAKE_START, 1); | |||
if (!ssl->method->begin_handshake(ssl)) { | |||
ssl->s3->hs = ssl_handshake_new(tls13_server_handshake); | |||
if (ssl->s3->hs == NULL || | |||
!ssl->method->begin_handshake(ssl)) { | |||
ret = -1; | |||
goto end; | |||
} | |||
@@ -226,6 +228,9 @@ int ssl3_accept(SSL *ssl) { | |||
case SSL3_ST_SR_CLNT_HELLO_B: | |||
case SSL3_ST_SR_CLNT_HELLO_C: | |||
ret = ssl3_get_client_hello(ssl); | |||
if (ssl->state == SSL_ST_TLS13) { | |||
break; | |||
} | |||
if (ret <= 0) { | |||
goto end; | |||
} | |||
@@ -458,6 +463,14 @@ int ssl3_accept(SSL *ssl) { | |||
} | |||
break; | |||
case SSL_ST_TLS13: | |||
ret = tls13_handshake(ssl); | |||
if (ret <= 0) { | |||
goto end; | |||
} | |||
ssl->state = SSL_ST_OK; | |||
break; | |||
case SSL_ST_OK: | |||
/* clean a few things up */ | |||
ssl3_cleanup_key_block(ssl); | |||
@@ -467,6 +480,9 @@ int ssl3_accept(SSL *ssl) { | |||
/* remove buffering on output */ | |||
ssl_free_wbio_buffer(ssl); | |||
ssl_handshake_free(ssl->s3->hs); | |||
ssl->s3->hs = NULL; | |||
/* If we aren't retaining peer certificates then we can discard it | |||
* now. */ | |||
if (ssl->ctx->retain_only_sha256_of_client_certs) { | |||
@@ -569,10 +585,7 @@ static int ssl3_get_client_hello(SSL *ssl) { | |||
} | |||
CBS_init(&client_hello, ssl->init_msg, ssl->init_num); | |||
if (!CBS_get_u16(&client_hello, &client_wire_version) || | |||
!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) { | |||
if (!CBS_get_u16(&client_hello, &client_wire_version)) { | |||
al = SSL_AD_DECODE_ERROR; | |||
OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); | |||
goto f_err; | |||
@@ -584,20 +597,6 @@ static int ssl3_get_client_hello(SSL *ssl) { | |||
* see RFC 2246, Appendix E, second paragraph) */ | |||
ssl->client_version = client_wire_version; | |||
/* Load the client random. */ | |||
memcpy(ssl->s3->client_random, CBS_data(&client_random), SSL3_RANDOM_SIZE); | |||
if (SSL_IS_DTLS(ssl)) { | |||
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; | |||
} | |||
} | |||
uint16_t min_version, max_version; | |||
if (!ssl_get_version_range(ssl, &min_version, &max_version)) { | |||
al = SSL_AD_PROTOCOL_VERSION; | |||
@@ -632,6 +631,33 @@ static int ssl3_get_client_hello(SSL *ssl) { | |||
goto f_err; | |||
} | |||
if (ssl3_protocol_version(ssl) >= TLS1_3_VERSION) { | |||
ssl->state = SSL_ST_TLS13; | |||
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. */ | |||
memcpy(ssl->s3->client_random, CBS_data(&client_random), SSL3_RANDOM_SIZE); | |||
if (SSL_IS_DTLS(ssl)) { | |||
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; | |||
} | |||
} | |||
ssl->hit = 0; | |||
int send_new_ticket = 0; | |||
switch (ssl_get_prev_session(ssl, &session, &send_new_ticket, &early_ctx)) { | |||
@@ -615,6 +615,9 @@ void SSL_ECDH_CTX_init_for_cecpq1(SSL_ECDH_CTX *ctx); | |||
* call it in the zero state. */ | |||
void SSL_ECDH_CTX_cleanup(SSL_ECDH_CTX *ctx); | |||
/* SSL_ECDH_CTX_get_id returns the group ID for |ctx|. */ | |||
uint16_t SSL_ECDH_CTX_get_id(const SSL_ECDH_CTX *ctx); | |||
/* SSL_ECDH_CTX_get_key calls the |get_key| method of |SSL_ECDH_METHOD|. */ | |||
int SSL_ECDH_CTX_get_key(SSL_ECDH_CTX *ctx, CBS *cbs, CBS *out); | |||
@@ -772,6 +775,141 @@ int ssl_add_client_CA_list(SSL *ssl, CBB *cbb); | |||
int ssl_check_leaf_certificate(SSL *ssl, X509 *leaf); | |||
/* TLS 1.3 key derivation. */ | |||
/* tls13_init_key_schedule initializes the handshake hash and key derivation | |||
* state with the given resumption context. The cipher suite and PRF hash must | |||
* have been selected at this point. It returns one on success and zero on | |||
* error. */ | |||
int tls13_init_key_schedule(SSL *ssl, const uint8_t *resumption_ctx, | |||
size_t resumption_ctx_len); | |||
/* tls13_advance_key_schedule incorporates |in| into the key schedule with | |||
* HKDF-Extract. It returns one on success and zero on error. */ | |||
int tls13_advance_key_schedule(SSL *ssl, const uint8_t *in, size_t len); | |||
/* tls13_get_context_hashes writes Hash(Handshake Context) + | |||
* Hash(resumption_context) to |out| which much have room for at least 2 * | |||
* |EVP_MAX_MD_SIZE| bytes. On success, it returns one and sets |*out_len| to | |||
* the number of bytes written. Otherwise, it returns zero. */ | |||
int tls13_get_context_hashes(SSL *ssl, uint8_t *out, size_t *out_len); | |||
enum tls_record_type_t { | |||
type_early_handshake, | |||
type_early_data, | |||
type_handshake, | |||
type_data, | |||
}; | |||
/* tls13_set_traffic_key sets the read or write traffic keys to |traffic_secret| | |||
* for the given traffic phase |type|. It returns one on success and zero on | |||
* error. */ | |||
int tls13_set_traffic_key(SSL *ssl, enum tls_record_type_t type, | |||
enum evp_aead_direction_t direction, | |||
const uint8_t *traffic_secret, | |||
size_t traffic_secret_len); | |||
/* tls13_set_handshake_traffic derives the handshake traffic secret and | |||
* switches both read and write traffic to it. It returns one on success and | |||
* zero on error. */ | |||
int tls13_set_handshake_traffic(SSL *ssl); | |||
/* tls13_derive_traffic_secret_0 derives the initial application data traffic | |||
* secret based on the handshake transcripts and |master_secret|. It returns one | |||
* on success and zero on error. */ | |||
int tls13_derive_traffic_secret_0(SSL *ssl); | |||
/* tls13_finalize_keys derives the |exporter_secret| and |resumption_secret|. */ | |||
int tls13_finalize_keys(SSL *ssl); | |||
/* tls13_export_keying_material provides and exporter interface to use the | |||
* |exporter_secret|. */ | |||
int tls13_export_keying_material(SSL *ssl, uint8_t *out, size_t out_len, | |||
const char *label, size_t label_len, | |||
const uint8_t *context, size_t context_len, | |||
int use_context); | |||
/* tls13_finished_mac calculates the MAC of the handshake transcript to verify | |||
* the integrity of the Finished message, and stores the result in |out| and | |||
* length in |out_len|. |is_server| is 1 if this is for the Server Finished and | |||
* 0 for the Client Finished. */ | |||
int tls13_finished_mac(SSL *ssl, uint8_t *out, size_t *out_len, int is_server); | |||
/* Handshake functions. */ | |||
enum ssl_hs_wait_t { | |||
ssl_hs_error, | |||
ssl_hs_ok, | |||
ssl_hs_read_message, | |||
ssl_hs_write_message, | |||
ssl_hs_flush, | |||
ssl_hs_x509_lookup, | |||
ssl_hs_private_key_operation, | |||
}; | |||
struct ssl_handshake_st { | |||
/* wait contains the operation |do_handshake| is currently blocking on or | |||
* |ssl_hs_ok| if none. */ | |||
enum ssl_hs_wait_t wait; | |||
/* do_handshake runs the handshake. On completion, it returns |ssl_hs_ok|. | |||
* Otherwise, it returns a value corresponding to what operation is needed to | |||
* progress. */ | |||
enum ssl_hs_wait_t (*do_handshake)(SSL *ssl); | |||
int state; | |||
size_t hash_len; | |||
uint8_t resumption_hash[EVP_MAX_MD_SIZE]; | |||
uint8_t secret[EVP_MAX_MD_SIZE]; | |||
uint8_t traffic_secret_0[EVP_MAX_MD_SIZE]; | |||
SSL_ECDH_CTX *groups; | |||
size_t groups_len; | |||
uint8_t *public_key; | |||
size_t public_key_len; | |||
uint8_t *cert_context; | |||
size_t cert_context_len; | |||
} /* SSL_HANDSHAKE */; | |||
SSL_HANDSHAKE *ssl_handshake_new(enum ssl_hs_wait_t (*do_handshake)(SSL *ssl)); | |||
/* ssl_handshake_free releases all memory associated with |hs|. */ | |||
void ssl_handshake_free(SSL_HANDSHAKE *hs); | |||
/* tls13_handshake runs the TLS 1.3 handshake. It returns one on success and <= | |||
* 0 on error. */ | |||
int tls13_handshake(SSL *ssl); | |||
/* The following are implementations of |do_handshake| for the client and | |||
* server. */ | |||
enum ssl_hs_wait_t tls13_client_handshake(SSL *ssl); | |||
enum ssl_hs_wait_t tls13_server_handshake(SSL *ssl); | |||
/* tls13_check_message_type checks if the current message has type |type|. If so | |||
* it returns one. Otherwise, it sends an alert and returns zero. */ | |||
int tls13_check_message_type(SSL *ssl, int type); | |||
int tls13_process_certificate(SSL *ssl); | |||
int tls13_process_certificate_verify(SSL *ssl); | |||
int tls13_process_finished(SSL *ssl); | |||
int tls13_prepare_certificate(SSL *ssl); | |||
enum ssl_private_key_result_t tls13_prepare_certificate_verify( | |||
SSL *ssl, int is_first_run); | |||
int tls13_prepare_finished(SSL *ssl); | |||
int ext_key_share_parse_serverhello(SSL *ssl, uint8_t **out_secret, | |||
size_t *out_secret_len, uint8_t *out_alert, | |||
CBS *contents); | |||
int ext_key_share_parse_clienthello(SSL *ssl, uint8_t **out_secret, | |||
size_t *out_secret_len, uint8_t *out_alert, | |||
CBS *contents); | |||
int ext_key_share_add_serverhello(SSL *ssl, CBB *out); | |||
/* Underdocumented functions. | |||
* | |||
* Functions below here haven't been touched up and may be underdocumented. */ | |||
@@ -213,6 +213,7 @@ void ssl3_free(SSL *ssl) { | |||
OPENSSL_free(ssl->s3->tmp.peer_psk_identity_hint); | |||
ssl3_free_handshake_buffer(ssl); | |||
ssl3_free_handshake_hash(ssl); | |||
ssl_handshake_free(ssl->s3->hs); | |||
OPENSSL_free(ssl->s3->next_proto_negotiated); | |||
OPENSSL_free(ssl->s3->alpn_selected); | |||
SSL_AEAD_CTX_free(ssl->s3->aead_read_ctx); | |||
@@ -443,6 +443,13 @@ start: | |||
/* Process unexpected records. */ | |||
if (type == SSL3_RT_APPLICATION_DATA && rr->type == SSL3_RT_HANDSHAKE) { | |||
if (ssl3_protocol_version(ssl) >= TLS1_3_VERSION) { | |||
/* TODO(svaldez): Handle TLS 1.3 post-handshake messages. For now, | |||
* silently drop all handshake records. */ | |||
rr->length = 0; | |||
goto start; | |||
} | |||
/* If peer renegotiations are disabled, all out-of-order handshake records | |||
* are fatal. Renegotiations as a server are never supported. */ | |||
if (ssl->server || !ssl3_can_renegotiate(ssl)) { | |||
@@ -567,6 +567,19 @@ void SSL_ECDH_CTX_init_for_cecpq1(SSL_ECDH_CTX *ctx) { | |||
ctx->method = &kCECPQ1Method; | |||
} | |||
void SSL_ECDH_CTX_cleanup(SSL_ECDH_CTX *ctx) { | |||
if (ctx->method == NULL) { | |||
return; | |||
} | |||
ctx->method->cleanup(ctx); | |||
ctx->method = NULL; | |||
ctx->data = NULL; | |||
} | |||
uint16_t SSL_ECDH_CTX_get_id(const SSL_ECDH_CTX *ctx) { | |||
return ctx->method->group_id; | |||
} | |||
int SSL_ECDH_CTX_get_key(SSL_ECDH_CTX *ctx, CBS *cbs, CBS *out) { | |||
if (ctx->method == NULL) { | |||
return 0; | |||
@@ -581,15 +594,6 @@ int SSL_ECDH_CTX_add_key(SSL_ECDH_CTX *ctx, CBB *cbb, CBB *out_contents) { | |||
return ctx->method->add_key(cbb, out_contents); | |||
} | |||
void SSL_ECDH_CTX_cleanup(SSL_ECDH_CTX *ctx) { | |||
if (ctx->method == NULL) { | |||
return; | |||
} | |||
ctx->method->cleanup(ctx); | |||
ctx->method = NULL; | |||
ctx->data = NULL; | |||
} | |||
int SSL_ECDH_CTX_offer(SSL_ECDH_CTX *ctx, CBB *out_public_key) { | |||
return ctx->method->offer(ctx, out_public_key); | |||
} | |||
@@ -1122,7 +1122,8 @@ int SSL_get_verify_depth(const SSL *ssl) { | |||
} | |||
int SSL_get_extms_support(const SSL *ssl) { | |||
return ssl->s3->tmp.extended_master_secret == 1; | |||
return ssl3_protocol_version(ssl) >= TLS1_3_VERSION || | |||
ssl->s3->tmp.extended_master_secret == 1; | |||
} | |||
int (*SSL_get_verify_callback(const SSL *ssl))(int, X509_STORE_CTX *) { | |||
@@ -501,6 +501,11 @@ int SSL_export_keying_material(SSL *ssl, uint8_t *out, size_t out_len, | |||
return 0; | |||
} | |||
if (ssl3_protocol_version(ssl) >= TLS1_3_VERSION) { | |||
return tls13_export_keying_material(ssl, out, out_len, label, label_len, | |||
context, context_len, use_context); | |||
} | |||
size_t seed_len = 2 * SSL3_RANDOM_SIZE; | |||
if (use_context) { | |||
if (context_len >= 1u << 16) { | |||
@@ -808,6 +808,10 @@ static int ext_ri_add_clienthello(SSL *ssl, CBB *out) { | |||
static int ext_ri_parse_serverhello(SSL *ssl, uint8_t *out_alert, | |||
CBS *contents) { | |||
if (contents != NULL && ssl3_protocol_version(ssl) >= TLS1_3_VERSION) { | |||
return 0; | |||
} | |||
/* Servers may not switch between omitting the extension and supporting it. | |||
* See RFC 5746, sections 3.5 and 4.2. */ | |||
if (ssl->s3->initial_handshake_complete && | |||
@@ -877,6 +881,10 @@ static int ext_ri_parse_clienthello(SSL *ssl, uint8_t *out_alert, | |||
* called after the initial handshake. */ | |||
assert(!ssl->s3->initial_handshake_complete); | |||
if (ssl3_protocol_version(ssl) >= TLS1_3_VERSION) { | |||
return 1; | |||
} | |||
CBS fake_contents; | |||
static const uint8_t kFakeExtension[] = {0}; | |||
@@ -917,6 +925,10 @@ static int ext_ri_parse_clienthello(SSL *ssl, uint8_t *out_alert, | |||
} | |||
static int ext_ri_add_serverhello(SSL *ssl, CBB *out) { | |||
if (ssl3_protocol_version(ssl) >= TLS1_3_VERSION) { | |||
return 1; | |||
} | |||
CBB contents, prev_finished; | |||
if (!CBB_add_u16(out, TLSEXT_TYPE_renegotiate) || | |||
!CBB_add_u16_length_prefixed(out, &contents) || | |||
@@ -960,7 +972,12 @@ static int ext_ems_parse_serverhello(SSL *ssl, uint8_t *out_alert, | |||
return 1; | |||
} | |||
if (ssl->version == SSL3_VERSION || CBS_len(contents) != 0) { | |||
if (ssl3_protocol_version(ssl) >= TLS1_3_VERSION || | |||
ssl->version == SSL3_VERSION) { | |||
return 0; | |||
} | |||
if (CBS_len(contents) != 0) { | |||
return 0; | |||
} | |||
@@ -970,7 +987,12 @@ static int ext_ems_parse_serverhello(SSL *ssl, uint8_t *out_alert, | |||
static int ext_ems_parse_clienthello(SSL *ssl, uint8_t *out_alert, | |||
CBS *contents) { | |||
if (ssl->version == SSL3_VERSION || contents == NULL) { | |||
if (ssl3_protocol_version(ssl) >= TLS1_3_VERSION || | |||
ssl->version == SSL3_VERSION) { | |||
return 1; | |||
} | |||
if (contents == NULL) { | |||
return 1; | |||
} | |||
@@ -1038,6 +1060,10 @@ static int ext_ticket_parse_serverhello(SSL *ssl, uint8_t *out_alert, | |||
return 1; | |||
} | |||
if (ssl3_protocol_version(ssl) >= TLS1_3_VERSION) { | |||
return 0; | |||
} | |||
/* If |SSL_OP_NO_TICKET| is set then no extension will have been sent and | |||
* this function should never be called, even if the server tries to send the | |||
* extension. */ | |||
@@ -1185,6 +1211,10 @@ static int ext_ocsp_parse_clienthello(SSL *ssl, uint8_t *out_alert, | |||
} | |||
static int ext_ocsp_add_serverhello(SSL *ssl, CBB *out) { | |||
if (ssl3_protocol_version(ssl) >= TLS1_3_VERSION) { | |||
return 1; | |||
} | |||
/* The extension shouldn't be sent when resuming sessions. */ | |||
if (ssl->hit || | |||
!ssl->s3->tmp.ocsp_stapling_requested || | |||
@@ -1229,6 +1259,10 @@ static int ext_npn_parse_serverhello(SSL *ssl, uint8_t *out_alert, | |||
return 1; | |||
} | |||
if (ssl3_protocol_version(ssl) >= TLS1_3_VERSION) { | |||
return 0; | |||
} | |||
/* If any of these are false then we should never have sent the NPN | |||
* extension in the ClientHello and thus this function should never have been | |||
* called. */ | |||
@@ -1279,6 +1313,10 @@ static int ext_npn_parse_serverhello(SSL *ssl, uint8_t *out_alert, | |||
static int ext_npn_parse_clienthello(SSL *ssl, uint8_t *out_alert, | |||
CBS *contents) { | |||
if (ssl3_protocol_version(ssl) >= TLS1_3_VERSION) { | |||
return 1; | |||
} | |||
if (contents != NULL && CBS_len(contents) != 0) { | |||
return 0; | |||
} | |||
@@ -1555,6 +1593,10 @@ static int ext_channel_id_parse_serverhello(SSL *ssl, uint8_t *out_alert, | |||
return 1; | |||
} | |||
if (ssl3_protocol_version(ssl) >= TLS1_3_VERSION) { | |||
return 0; | |||
} | |||
assert(!SSL_IS_DTLS(ssl)); | |||
assert(ssl->tlsext_channel_id_enabled); | |||
@@ -1583,6 +1625,10 @@ static int ext_channel_id_parse_clienthello(SSL *ssl, uint8_t *out_alert, | |||
} | |||
static int ext_channel_id_add_serverhello(SSL *ssl, CBB *out) { | |||
if (ssl3_protocol_version(ssl) >= TLS1_3_VERSION) { | |||
return 1; | |||
} | |||
if (!ssl->s3->tlsext_channel_id_valid) { | |||
return 1; | |||
} | |||
@@ -1801,6 +1847,10 @@ static int ext_ec_point_parse_serverhello(SSL *ssl, uint8_t *out_alert, | |||
return 1; | |||
} | |||
if (ssl3_protocol_version(ssl) >= TLS1_3_VERSION) { | |||
return 0; | |||
} | |||
CBS ec_point_format_list; | |||
if (!CBS_get_u8_length_prefixed(contents, &ec_point_format_list) || | |||
CBS_len(contents) != 0) { | |||
@@ -1820,10 +1870,18 @@ static int ext_ec_point_parse_serverhello(SSL *ssl, uint8_t *out_alert, | |||
static int ext_ec_point_parse_clienthello(SSL *ssl, uint8_t *out_alert, | |||
CBS *contents) { | |||
if (ssl3_protocol_version(ssl) >= TLS1_3_VERSION) { | |||
return 1; | |||
} | |||
return ext_ec_point_parse_serverhello(ssl, out_alert, contents); | |||
} | |||
static int ext_ec_point_add_serverhello(SSL *ssl, CBB *out) { | |||
if (ssl3_protocol_version(ssl) >= TLS1_3_VERSION) { | |||
return 1; | |||
} | |||
const uint32_t alg_k = ssl->s3->tmp.new_cipher->algorithm_mkey; | |||
const uint32_t alg_a = ssl->s3->tmp.new_cipher->algorithm_auth; | |||
const int using_ecc = (alg_k & SSL_kECDHE) || (alg_a & SSL_aECDSA); | |||
@@ -1836,6 +1894,182 @@ static int ext_ec_point_add_serverhello(SSL *ssl, CBB *out) { | |||
} | |||
/* Draft Version Extension */ | |||
static int ext_draft_version_add_clienthello(SSL *ssl, CBB *out) { | |||
uint16_t min_version, max_version; | |||
if (!ssl_get_version_range(ssl, &min_version, &max_version) || | |||
max_version >= TLS1_3_VERSION) { | |||
return 1; | |||
} | |||
CBB contents; | |||
if (!CBB_add_u16(out, TLSEXT_TYPE_draft_version) || | |||
!CBB_add_u16_length_prefixed(out, &contents) || | |||
!CBB_add_u16(&contents, TLS1_3_DRAFT_VERSION)) { | |||
return 0; | |||
} | |||
return CBB_flush(out); | |||
} | |||
/* Key Share | |||
* | |||
* https://tools.ietf.org/html/draft-ietf-tls-tls13-12 */ | |||
static int ext_key_share_add_clienthello(SSL *ssl, CBB *out) { | |||
uint16_t min_version, max_version; | |||
if (!ssl_get_version_range(ssl, &min_version, &max_version)) { | |||
return 0; | |||
} | |||
if (max_version < TLS1_3_VERSION || !ssl_any_ec_cipher_suites_enabled(ssl)) { | |||
return 1; | |||
} | |||
CBB contents, kse_bytes; | |||
if (!CBB_add_u16(out, TLSEXT_TYPE_key_share) || | |||
!CBB_add_u16_length_prefixed(out, &contents) || | |||
!CBB_add_u16_length_prefixed(&contents, &kse_bytes)) { | |||
return 0; | |||
} | |||
const uint16_t *groups; | |||
size_t groups_len; | |||
tls1_get_grouplist(ssl, 0 /* local groups */, &groups, &groups_len); | |||
ssl->s3->hs->groups = OPENSSL_malloc(groups_len * sizeof(SSL_ECDH_CTX)); | |||
if (ssl->s3->hs->groups == NULL) { | |||
return 0; | |||
} | |||
memset(ssl->s3->hs->groups, 0, groups_len * sizeof(SSL_ECDH_CTX)); | |||
ssl->s3->hs->groups_len = groups_len; | |||
for (size_t i = 0; i < groups_len; i++) { | |||
if (!CBB_add_u16(&kse_bytes, groups[i])) { | |||
return 0; | |||
} | |||
CBB key_exchange; | |||
if (!CBB_add_u16_length_prefixed(&kse_bytes, &key_exchange) || | |||
!SSL_ECDH_CTX_init(&ssl->s3->hs->groups[i], groups[i]) || | |||
!SSL_ECDH_CTX_offer(&ssl->s3->hs->groups[i], &key_exchange) || | |||
!CBB_flush(&kse_bytes)) { | |||
return 0; | |||
} | |||
} | |||
return CBB_flush(out); | |||
} | |||
int ext_key_share_parse_serverhello(SSL *ssl, uint8_t **out_secret, | |||
size_t *out_secret_len, uint8_t *out_alert, | |||
CBS *contents) { | |||
CBS peer_key; | |||
uint16_t group; | |||
if (!CBS_get_u16(contents, &group) || | |||
!CBS_get_u16_length_prefixed(contents, &peer_key)) { | |||
*out_alert = SSL_AD_DECODE_ERROR; | |||
return 0; | |||
} | |||
SSL_ECDH_CTX *group_ctx = NULL; | |||
for (size_t i = 0; i < ssl->s3->hs->groups_len; i++) { | |||
if (SSL_ECDH_CTX_get_id(&ssl->s3->hs->groups[i]) == group) { | |||
group_ctx = &ssl->s3->hs->groups[i]; | |||
break; | |||
} | |||
} | |||
if (group_ctx == NULL) { | |||
*out_alert = SSL_AD_ILLEGAL_PARAMETER; | |||
OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_CURVE); | |||
return 0; | |||
} | |||
if (!SSL_ECDH_CTX_finish(group_ctx, out_secret, out_secret_len, out_alert, | |||
CBS_data(&peer_key), CBS_len(&peer_key))) { | |||
*out_alert = SSL_AD_INTERNAL_ERROR; | |||
return 0; | |||
} | |||
for (size_t i = 0; i < ssl->s3->hs->groups_len; i++) { | |||
SSL_ECDH_CTX_cleanup(&ssl->s3->hs->groups[i]); | |||
} | |||
OPENSSL_free(ssl->s3->hs->groups); | |||
ssl->s3->hs->groups = NULL; | |||
return 1; | |||
} | |||
int ext_key_share_parse_clienthello(SSL *ssl, uint8_t **out_secret, | |||
size_t *out_secret_len, uint8_t *out_alert, | |||
CBS *contents) { | |||
uint16_t group_id; | |||
CBS key_shares; | |||
if (!tls1_get_shared_group(ssl, &group_id) || | |||
!CBS_get_u16_length_prefixed(contents, &key_shares)) { | |||
return 0; | |||
} | |||
int found = 0; | |||
while (CBS_len(&key_shares) > 0) { | |||
uint16_t id; | |||
CBS peer_key; | |||
if (!CBS_get_u16(&key_shares, &id) || | |||
!CBS_get_u16_length_prefixed(&key_shares, &peer_key)) { | |||
return 0; | |||
} | |||
if (id != group_id || found) { | |||
continue; | |||
} | |||
SSL_ECDH_CTX group; | |||
memset(&group, 0, sizeof(SSL_ECDH_CTX)); | |||
CBB public_key; | |||
if (!CBB_init(&public_key, 0) || | |||
!SSL_ECDH_CTX_init(&group, group_id) || | |||
!SSL_ECDH_CTX_accept(&group, &public_key, out_secret, out_secret_len, | |||
out_alert, CBS_data(&peer_key), | |||
CBS_len(&peer_key)) || | |||
!CBB_finish(&public_key, &ssl->s3->hs->public_key, | |||
&ssl->s3->hs->public_key_len)) { | |||
SSL_ECDH_CTX_cleanup(&group); | |||
CBB_cleanup(&public_key); | |||
return 0; | |||
} | |||
SSL_ECDH_CTX_cleanup(&group); | |||
found = 1; | |||
} | |||
return found; | |||
} | |||
int ext_key_share_add_serverhello(SSL *ssl, CBB *out) { | |||
if (ssl->s3->tmp.new_cipher->algorithm_mkey != SSL_kECDHE) { | |||
return 1; | |||
} | |||
uint16_t group_id; | |||
CBB kse_bytes, public_key; | |||
if (!tls1_get_shared_group(ssl, &group_id) || | |||
!CBB_add_u16(out, TLSEXT_TYPE_key_share) || | |||
!CBB_add_u16_length_prefixed(out, &kse_bytes) || | |||
!CBB_add_u16(&kse_bytes, group_id) || | |||
!CBB_add_u16_length_prefixed(&kse_bytes, &public_key) || | |||
!CBB_add_bytes(&public_key, ssl->s3->hs->public_key, | |||
ssl->s3->hs->public_key_len) || | |||
!CBB_flush(out)) { | |||
return 0; | |||
} | |||
return 1; | |||
} | |||
/* Negotiated Groups | |||
* | |||
* https://tools.ietf.org/html/rfc4492#section-5.1.2 | |||
@@ -2029,6 +2263,22 @@ static const struct tls_extension kExtensions[] = { | |||
ext_ec_point_parse_clienthello, | |||
ext_ec_point_add_serverhello, | |||
}, | |||
{ | |||
TLSEXT_TYPE_draft_version, | |||
NULL, | |||
ext_draft_version_add_clienthello, | |||
forbid_parse_serverhello, | |||
ignore_parse_clienthello, | |||
dont_add_serverhello, | |||
}, | |||
{ | |||
TLSEXT_TYPE_key_share, | |||
NULL, | |||
ext_key_share_add_clienthello, | |||
forbid_parse_serverhello, | |||
ignore_parse_clienthello, | |||
dont_add_serverhello, | |||
}, | |||
/* The final extension must be non-empty. WebSphere Application Server 7.0 is | |||
* intolerant to the last extension being zero-length. See | |||
* https://crbug.com/363583. */ | |||
@@ -2175,8 +2425,9 @@ int ssl_add_serverhello_tlsext(SSL *ssl, CBB *out) { | |||
goto err; | |||
} | |||
/* Discard empty extensions blocks. */ | |||
if (CBB_len(&extensions) == 0) { | |||
/* Discard empty extensions blocks before TLS 1.3. */ | |||
if (ssl3_protocol_version(ssl) < TLS1_3_VERSION && | |||
CBB_len(&extensions) == 0) { | |||
CBB_discard_child(out); | |||
} | |||
@@ -2287,57 +2538,58 @@ int ssl_parse_clienthello_tlsext(SSL *ssl, CBS *cbs) { | |||
OPENSSL_COMPILE_ASSERT(kNumExtensions <= sizeof(uint32_t) * 8, too_many_bits); | |||
static int ssl_scan_serverhello_tlsext(SSL *ssl, CBS *cbs, int *out_alert) { | |||
/* Before TLS 1.3, ServerHello extensions blocks may be omitted if empty. */ | |||
if (CBS_len(cbs) == 0 && ssl3_protocol_version(ssl) < TLS1_3_VERSION) { | |||
return 1; | |||
} | |||
/* Decode the extensions block and check it is valid. */ | |||
CBS extensions; | |||
if (!CBS_get_u16_length_prefixed(cbs, &extensions) || | |||
!tls1_check_duplicate_extensions(&extensions)) { | |||
*out_alert = SSL_AD_DECODE_ERROR; | |||
return 0; | |||
} | |||
uint32_t received = 0; | |||
while (CBS_len(&extensions) != 0) { | |||
uint16_t type; | |||
CBS extension; | |||
if (CBS_len(cbs) != 0) { | |||
/* Decode the extensions block and check it is valid. */ | |||
CBS extensions; | |||
if (!CBS_get_u16_length_prefixed(cbs, &extensions) || | |||
!tls1_check_duplicate_extensions(&extensions)) { | |||
/* Decode the next extension. */ | |||
if (!CBS_get_u16(&extensions, &type) || | |||
!CBS_get_u16_length_prefixed(&extensions, &extension)) { | |||
*out_alert = SSL_AD_DECODE_ERROR; | |||
return 0; | |||
} | |||
unsigned ext_index; | |||
const struct tls_extension *const ext = | |||
tls_extension_find(&ext_index, type); | |||
while (CBS_len(&extensions) != 0) { | |||
uint16_t type; | |||
CBS extension; | |||
/* Decode the next extension. */ | |||
if (!CBS_get_u16(&extensions, &type) || | |||
!CBS_get_u16_length_prefixed(&extensions, &extension)) { | |||
*out_alert = SSL_AD_DECODE_ERROR; | |||
if (ext == NULL) { | |||
if (!custom_ext_parse_serverhello(ssl, out_alert, type, &extension)) { | |||
return 0; | |||
} | |||
continue; | |||
} | |||
unsigned ext_index; | |||
const struct tls_extension *const ext = | |||
tls_extension_find(&ext_index, type); | |||
if (ext == NULL) { | |||
if (!custom_ext_parse_serverhello(ssl, out_alert, type, &extension)) { | |||
return 0; | |||
} | |||
continue; | |||
} | |||
if (!(ssl->s3->tmp.extensions.sent & (1u << ext_index))) { | |||
/* If the extension was never sent then it is illegal. */ | |||
OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_EXTENSION); | |||
ERR_add_error_dataf("extension :%u", (unsigned)type); | |||
*out_alert = SSL_AD_DECODE_ERROR; | |||
return 0; | |||
} | |||
if (!(ssl->s3->tmp.extensions.sent & (1u << ext_index))) { | |||
/* If the extension was never sent then it is illegal. */ | |||
OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_EXTENSION); | |||
ERR_add_error_dataf("extension :%u", (unsigned)type); | |||
*out_alert = SSL_AD_DECODE_ERROR; | |||
return 0; | |||
} | |||
received |= (1u << ext_index); | |||
received |= (1u << ext_index); | |||
uint8_t alert = SSL_AD_DECODE_ERROR; | |||
if (!ext->parse_serverhello(ssl, &alert, &extension)) { | |||
OPENSSL_PUT_ERROR(SSL, SSL_R_ERROR_PARSING_EXTENSION); | |||
ERR_add_error_dataf("extension: %u", (unsigned)type); | |||
*out_alert = alert; | |||
return 0; | |||
} | |||
uint8_t alert = SSL_AD_DECODE_ERROR; | |||
if (!ext->parse_serverhello(ssl, &alert, &extension)) { | |||
OPENSSL_PUT_ERROR(SSL, SSL_R_ERROR_PARSING_EXTENSION); | |||
ERR_add_error_dataf("extension: %u", (unsigned)type); | |||
*out_alert = alert; | |||
return 0; | |||
} | |||
} | |||
@@ -1045,7 +1045,9 @@ static bool CheckHandshakeProperties(SSL *ssl, bool is_resume) { | |||
if (expect_handshake_done && !config->is_server) { | |||
bool expect_new_session = | |||
!config->expect_no_session && | |||
(!SSL_session_reused(ssl) || config->expect_ticket_renewal); | |||
(!SSL_session_reused(ssl) || config->expect_ticket_renewal) && | |||
/* TODO(svaldez): Implement Session Resumption. */ | |||
SSL_version(ssl) != TLS1_3_VERSION; | |||
if (expect_new_session != GetTestState(ssl)->got_new_session) { | |||
fprintf(stderr, | |||
"new session was%s cached, but we expected the opposite\n", | |||
@@ -1264,7 +1266,8 @@ static bool DoExchange(ScopedSSL_SESSION *out_session, SSL_CTX *ssl_ctx, | |||
if (config->no_ssl3) { | |||
SSL_set_options(ssl.get(), SSL_OP_NO_SSLv3); | |||
} | |||
if (!config->expected_channel_id.empty()) { | |||
if (!config->expected_channel_id.empty() || | |||
config->enable_channel_id) { | |||
SSL_enable_tls_channel_id(ssl.get()); | |||
} | |||
if (!config->send_channel_id.empty()) { | |||
@@ -18,8 +18,7 @@ import ( | |||
"time" | |||
) | |||
// TODO(davidben): Flip this to true when the C code lands. | |||
const enableTLS13Handshake = false | |||
const enableTLS13Handshake = true | |||
const ( | |||
VersionSSL30 = 0x0300 | |||
@@ -919,6 +918,43 @@ type ProtocolBugs struct { | |||
// IgnoreSignatureVersionChecks, if true, causes all signature | |||
// algorithms to be enabled at all TLS versions. | |||
IgnoreSignatureVersionChecks bool | |||
// NegotiateRenegotiationInfoAtAllVersions, if true, causes | |||
// Renegotiation Info to be negotiated at all versions. | |||
NegotiateRenegotiationInfoAtAllVersions bool | |||
// NegotiateChannelIDAtAllVersions, if true, causes Channel ID to be | |||
// negotiated at all versions. | |||
NegotiateChannelIDAtAllVersions bool | |||
// NegotiateNPNAtAllVersions, if true, causes NPN to be negotiated at | |||
// all versions. | |||
NegotiateNPNAtAllVersions bool | |||
// NegotiateEMSAtAllVersions, if true, causes EMS to be negotiated at | |||
// all versions. | |||
NegotiateEMSAtAllVersions bool | |||
// AdvertiseTicketExtension, if true, causes the ticket extension to be | |||
// advertised in server extensions | |||
AdvertiseTicketExtension bool | |||
// MissingKeyShare, if true, causes the TLS 1.3 implementation to skip | |||
// sending a key_share extension and use the zero ECDHE secret | |||
// instead. | |||
MissingKeyShare bool | |||
// DuplicateKeyShares, if true, causes the TLS 1.3 client to send two | |||
// copies of each KeyShareEntry. | |||
DuplicateKeyShares bool | |||
// EmptyEncryptedExtensions, if true, causes the TLS 1.3 server to | |||
// emit an empty EncryptedExtensions block. | |||
EmptyEncryptedExtensions bool | |||
// EncryptedExtensionsWithKeyShare, if true, causes the TLS 1.3 server to | |||
// include the KeyShare extension in the EncryptedExtensions block. | |||
EncryptedExtensionsWithKeyShare bool | |||
} | |||
func (c *Config) serverInit() { | |||
@@ -133,6 +133,14 @@ func (c *Conn) clientHandshake() error { | |||
keyExchange: publicKey, | |||
}) | |||
keyShares[curveID] = curve | |||
if c.config.Bugs.DuplicateKeyShares { | |||
hello.keyShares = append(hello.keyShares, hello.keyShares[len(hello.keyShares)-1]) | |||
} | |||
} | |||
if c.config.Bugs.MissingKeyShare { | |||
hello.keyShares = nil | |||
} | |||
} | |||
@@ -477,7 +485,7 @@ func (hs *clientHandshakeState) doTLS13Handshake() error { | |||
// Resolve ECDHE and compute the handshake secret. | |||
var ecdheSecret []byte | |||
if hs.suite.flags&suiteECDHE != 0 { | |||
if hs.suite.flags&suiteECDHE != 0 && !c.config.Bugs.MissingKeyShare { | |||
if !hs.serverHello.hasKeyShare { | |||
c.sendAlert(alertMissingExtension) | |||
return errors.New("tls: server omitted the key share extension") | |||
@@ -1014,6 +1022,10 @@ func (hs *clientHandshakeState) processServerExtensions(serverExtensions *server | |||
return errors.New("tls: server advertised extended master secret over TLS 1.3") | |||
} | |||
if serverExtensions.ticketSupported && c.vers >= VersionTLS13 && enableTLS13Handshake { | |||
return errors.New("tls: server advertised ticket extension over TLS 1.3") | |||
} | |||
if serverExtensions.srtpProtectionProfile != 0 { | |||
if serverExtensions.srtpMasterKeyIdentifier != "" { | |||
return errors.New("tls: server selected SRTP MKI value") | |||
@@ -847,6 +847,7 @@ func (m *serverHelloMsg) unmarshal(data []byte) bool { | |||
type encryptedExtensionsMsg struct { | |||
raw []byte | |||
extensions serverExtensions | |||
empty bool | |||
} | |||
func (m *encryptedExtensionsMsg) marshal() []byte { | |||
@@ -857,8 +858,10 @@ func (m *encryptedExtensionsMsg) marshal() []byte { | |||
encryptedExtensionsMsg := newByteBuilder() | |||
encryptedExtensionsMsg.addU8(typeEncryptedExtensions) | |||
encryptedExtensions := encryptedExtensionsMsg.addU24LengthPrefixed() | |||
extensions := encryptedExtensions.addU16LengthPrefixed() | |||
m.extensions.marshal(extensions, VersionTLS13) | |||
if !m.empty { | |||
extensions := encryptedExtensions.addU16LengthPrefixed() | |||
m.extensions.marshal(extensions, VersionTLS13) | |||
} | |||
m.raw = encryptedExtensionsMsg.finish() | |||
return m.raw | |||
@@ -902,6 +905,8 @@ type serverExtensions struct { | |||
sctList []byte | |||
customExtension string | |||
npnLast bool | |||
hasKeyShare bool | |||
keyShare keyShareEntry | |||
} | |||
func (m *serverExtensions) marshal(extensions *byteBuilder, version uint16) { | |||
@@ -999,6 +1004,13 @@ func (m *serverExtensions) marshal(extensions *byteBuilder, version uint16) { | |||
npn.addBytes([]byte(v)) | |||
} | |||
} | |||
if m.hasKeyShare { | |||
extensions.addU16(extensionKeyShare) | |||
keyShare := extensions.addU16LengthPrefixed() | |||
keyShare.addU16(uint16(m.keyShare.group)) | |||
keyExchange := keyShare.addU16LengthPrefixed() | |||
keyExchange.addBytes(m.keyShare.keyExchange) | |||
} | |||
} | |||
func (m *serverExtensions) unmarshal(data []byte, version uint16) bool { | |||
@@ -279,6 +279,7 @@ func (hs *serverHandshakeState) doTLS13Handshake() error { | |||
// Prepare an EncryptedExtensions message, but do not send it yet. | |||
encryptedExtensions := new(encryptedExtensionsMsg) | |||
encryptedExtensions.empty = config.Bugs.EmptyEncryptedExtensions | |||
if err := hs.processClientExtensions(&encryptedExtensions.extensions); err != nil { | |||
return err | |||
} | |||
@@ -341,7 +342,7 @@ Curves: | |||
// Resolve ECDHE and compute the handshake secret. | |||
var ecdheSecret []byte | |||
if hs.suite.flags&suiteECDHE != 0 { | |||
if hs.suite.flags&suiteECDHE != 0 && !config.Bugs.MissingKeyShare { | |||
// Look for the key share corresponding to our selected curve. | |||
var selectedKeyShare *keyShareEntry | |||
for i := range hs.clientHello.keyShares { | |||
@@ -384,6 +385,14 @@ Curves: | |||
group: curveID, | |||
keyExchange: publicKey, | |||
} | |||
if config.Bugs.EncryptedExtensionsWithKeyShare { | |||
encryptedExtensions.extensions.hasKeyShare = true | |||
encryptedExtensions.extensions.keyShare = keyShareEntry{ | |||
group: curveID, | |||
keyExchange: publicKey, | |||
} | |||
} | |||
} else { | |||
ecdheSecret = hs.finishedHash.zeroSecret() | |||
} | |||
@@ -700,7 +709,7 @@ func (hs *serverHandshakeState) processClientExtensions(serverExtensions *server | |||
config := hs.c.config | |||
c := hs.c | |||
if c.vers < VersionTLS13 || !enableTLS13Handshake { | |||
if c.vers < VersionTLS13 || config.Bugs.NegotiateRenegotiationInfoAtAllVersions || !enableTLS13Handshake { | |||
if !bytes.Equal(c.clientVerify, hs.clientHello.secureRenegotiation) { | |||
c.sendAlert(alertHandshakeFailure) | |||
return errors.New("tls: renegotiation mismatch") | |||
@@ -751,7 +760,7 @@ func (hs *serverHandshakeState) processClientExtensions(serverExtensions *server | |||
} | |||
} | |||
if c.vers < VersionTLS13 || !enableTLS13Handshake { | |||
if c.vers < VersionTLS13 || config.Bugs.NegotiateNPNAtAllVersions || !enableTLS13Handshake { | |||
if len(hs.clientHello.alpnProtocols) == 0 || c.config.Bugs.NegotiateALPNAndNPN { | |||
// Although sending an empty NPN extension is reasonable, Firefox has | |||
// had a bug around this. Best to send nothing at all if | |||
@@ -763,9 +772,13 @@ func (hs *serverHandshakeState) processClientExtensions(serverExtensions *server | |||
serverExtensions.npnLast = config.Bugs.SwapNPNAndALPN | |||
} | |||
} | |||
} | |||
if c.vers < VersionTLS13 || config.Bugs.NegotiateEMSAtAllVersions || !enableTLS13Handshake { | |||
serverExtensions.extendedMasterSecret = c.vers >= VersionTLS10 && hs.clientHello.extendedMasterSecret && !c.config.Bugs.NoExtendedMasterSecret | |||
} | |||
if c.vers < VersionTLS13 || config.Bugs.NegotiateChannelIDAtAllVersions || !enableTLS13Handshake { | |||
if hs.clientHello.channelIDSupported && config.RequestChannelID { | |||
serverExtensions.channelIDRequested = true | |||
} | |||
@@ -795,6 +808,10 @@ func (hs *serverHandshakeState) processClientExtensions(serverExtensions *server | |||
} | |||
serverExtensions.customExtension = config.Bugs.CustomExtension | |||
if c.config.Bugs.AdvertiseTicketExtension { | |||
serverExtensions.ticketSupported = true | |||
} | |||
return nil | |||
} | |||
@@ -61,6 +61,7 @@ const Flag<bool> kBoolFlags[] = { | |||
{ "-no-tls11", &TestConfig::no_tls11 }, | |||
{ "-no-tls1", &TestConfig::no_tls1 }, | |||
{ "-no-ssl3", &TestConfig::no_ssl3 }, | |||
{ "-enable-channel-id", &TestConfig::enable_channel_id }, | |||
{ "-shim-writes-first", &TestConfig::shim_writes_first }, | |||
{ "-expect-session-miss", &TestConfig::expect_session_miss }, | |||
{ "-decline-alpn", &TestConfig::decline_alpn }, | |||
@@ -46,6 +46,7 @@ struct TestConfig { | |||
bool no_tls1 = false; | |||
bool no_ssl3 = false; | |||
std::string expected_channel_id; | |||
bool enable_channel_id = false; | |||
std::string send_channel_id; | |||
bool shim_writes_first = false; | |||
std::string host_name; | |||
@@ -0,0 +1,437 @@ | |||
/* Copyright (c) 2016, Google Inc. | |||
* | |||
* Permission to use, copy, modify, and/or distribute this software for any | |||
* purpose with or without fee is hereby granted, provided that the above | |||
* copyright notice and this permission notice appear in all copies. | |||
* | |||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY | |||
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION | |||
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | |||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ | |||
#include <openssl/ssl.h> | |||
#include <assert.h> | |||
#include <string.h> | |||
#include <openssl/bytestring.h> | |||
#include <openssl/err.h> | |||
#include <openssl/hkdf.h> | |||
#include <openssl/mem.h> | |||
#include <openssl/stack.h> | |||
#include <openssl/x509.h> | |||
#include <openssl/x509v3.h> | |||
#include "internal.h" | |||
SSL_HANDSHAKE *ssl_handshake_new(enum ssl_hs_wait_t (*do_handshake)(SSL *ssl)) { | |||
SSL_HANDSHAKE *hs = OPENSSL_malloc(sizeof(SSL_HANDSHAKE)); | |||
if (hs == NULL) { | |||
OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); | |||
return NULL; | |||
} | |||
memset(hs, 0, sizeof(SSL_HANDSHAKE)); | |||
hs->do_handshake = do_handshake; | |||
hs->wait = ssl_hs_ok; | |||
return hs; | |||
} | |||
void ssl_handshake_free(SSL_HANDSHAKE *hs) { | |||
if (hs == NULL) { | |||
return; | |||
} | |||
OPENSSL_cleanse(hs->secret, sizeof(hs->secret)); | |||
OPENSSL_cleanse(hs->traffic_secret_0, sizeof(hs->traffic_secret_0)); | |||
if (hs->groups != NULL) { | |||
for (size_t i = 0; i < hs->groups_len; i++) { | |||
SSL_ECDH_CTX_cleanup(&hs->groups[i]); | |||
} | |||
OPENSSL_free(hs->groups); | |||
} | |||
OPENSSL_free(hs->public_key); | |||
OPENSSL_free(hs->cert_context); | |||
OPENSSL_free(hs); | |||
} | |||
int tls13_handshake(SSL *ssl) { | |||
SSL_HANDSHAKE *hs = ssl->s3->hs; | |||
for (;;) { | |||
/* Resolve the operation the handshake was waiting on. */ | |||
switch (hs->wait) { | |||
case ssl_hs_error: | |||
OPENSSL_PUT_ERROR(SSL, SSL_R_SSL_HANDSHAKE_FAILURE); | |||
return -1; | |||
case ssl_hs_read_message: { | |||
int ret = ssl->method->ssl_get_message(ssl, -1, ssl_dont_hash_message); | |||
if (ret <= 0) { | |||
return ret; | |||
} | |||
break; | |||
} | |||
case ssl_hs_write_message: { | |||
int ret = ssl->method->write_message(ssl); | |||
if (ret <= 0) { | |||
return ret; | |||
} | |||
break; | |||
} | |||
case ssl_hs_flush: { | |||
int ret = BIO_flush(ssl->wbio); | |||
if (ret <= 0) { | |||
ssl->rwstate = SSL_WRITING; | |||
return ret; | |||
} | |||
break; | |||
} | |||
case ssl_hs_x509_lookup: | |||
ssl->rwstate = SSL_X509_LOOKUP; | |||
hs->wait = ssl_hs_ok; | |||
return -1; | |||
case ssl_hs_private_key_operation: | |||
ssl->rwstate = SSL_PRIVATE_KEY_OPERATION; | |||
hs->wait = ssl_hs_ok; | |||
return -1; | |||
case ssl_hs_ok: | |||
break; | |||
} | |||
/* Run the state machine again. */ | |||
hs->wait = hs->do_handshake(ssl); | |||
if (hs->wait == ssl_hs_error) { | |||
/* Don't loop around to avoid a stray |SSL_R_SSL_HANDSHAKE_FAILURE| the | |||
* first time around. */ | |||
return -1; | |||
} | |||
if (hs->wait == ssl_hs_ok) { | |||
/* The handshake has completed. */ | |||
return 1; | |||
} | |||
/* Otherwise, loop to the beginning and resolve what was blocking the | |||
* handshake. */ | |||
} | |||
} | |||
static int tls13_get_cert_verify_signature_input(SSL *ssl, uint8_t **out, | |||
size_t *out_len, int server) { | |||
CBB cbb; | |||
if (!CBB_init(&cbb, 64 + 33 + 1 + 2 * EVP_MAX_MD_SIZE)) { | |||
goto err; | |||
} | |||
for (size_t i = 0; i < 64; i++) { | |||
if (!CBB_add_u8(&cbb, 0x20)) { | |||
goto err; | |||
} | |||
} | |||
if (server) { | |||
/* Include the NUL byte. */ | |||
static const char kContext[] = "TLS 1.3, server CertificateVerify"; | |||
if (!CBB_add_bytes(&cbb, (const uint8_t *)kContext, sizeof(kContext))) { | |||
goto err; | |||
} | |||
} else { | |||
static const char kContext[] = "TLS 1.3, client CertificateVerify"; | |||
if (!CBB_add_bytes(&cbb, (const uint8_t *)kContext, sizeof(kContext))) { | |||
goto err; | |||
} | |||
} | |||
uint8_t context_hashes[2 * EVP_MAX_MD_SIZE]; | |||
size_t context_hashes_len; | |||
if (!tls13_get_context_hashes(ssl, context_hashes, &context_hashes_len) || | |||
!CBB_add_bytes(&cbb, context_hashes, context_hashes_len) || | |||
!CBB_finish(&cbb, out, out_len)) { | |||
goto err; | |||
} | |||
return 1; | |||
err: | |||
OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); | |||
CBB_cleanup(&cbb); | |||
return 0; | |||
} | |||
int tls13_process_certificate(SSL *ssl) { | |||
CBS cbs, context; | |||
CBS_init(&cbs, ssl->init_msg, ssl->init_num); | |||
if (!CBS_get_u8_length_prefixed(&cbs, &context) || | |||
CBS_len(&context) != 0) { | |||
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); | |||
OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); | |||
return 0; | |||
} | |||
int ret = 0; | |||
uint8_t alert; | |||
STACK_OF(X509) *chain = ssl_parse_cert_chain( | |||
ssl, &alert, | |||
ssl->ctx->retain_only_sha256_of_client_certs ? ssl->session->peer_sha256 | |||
: NULL, | |||
&cbs); | |||
if (chain == NULL) { | |||
ssl3_send_alert(ssl, SSL3_AL_FATAL, alert); | |||
goto err; | |||
} | |||
if (CBS_len(&cbs) != 0) { | |||
OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); | |||
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); | |||
goto err; | |||
} | |||
if (sk_X509_num(chain) == 0) { | |||
/* Clients must receive a certificate from the server. */ | |||
if (!ssl->server) { | |||
OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); | |||
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); | |||
goto err; | |||
} | |||
/* Servers may be configured to accept anonymous clients. */ | |||
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); | |||
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE); | |||
goto err; | |||
} | |||
/* No certificate, so nothing more to do. */ | |||
ret = 1; | |||
goto err; | |||
} | |||
if (ssl->server && ssl->ctx->retain_only_sha256_of_client_certs) { | |||
/* The hash was filled in by |ssl_parse_cert_chain|. */ | |||
ssl->session->peer_sha256_valid = 1; | |||
} | |||
X509 *leaf = sk_X509_value(chain, 0); | |||
if (!ssl->server && !ssl_check_leaf_certificate(ssl, leaf)) { | |||
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER); | |||
goto err; | |||
} | |||
int verify_ret = ssl_verify_cert_chain(ssl, chain); | |||
/* If |SSL_VERIFY_NONE|, the error is non-fatal, but we keep the result. */ | |||
if (ssl->verify_mode != SSL_VERIFY_NONE && verify_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); | |||
goto err; | |||
} | |||
ERR_clear_error(); | |||
ssl->session->verify_result = ssl->verify_result; | |||
X509_free(ssl->session->peer); | |||
/* For historical reasons, the client and server differ on whether the chain | |||
* includes the leaf. */ | |||
if (ssl->server) { | |||
ssl->session->peer = sk_X509_shift(chain); | |||
} else { | |||
ssl->session->peer = X509_up_ref(leaf); | |||
} | |||
sk_X509_pop_free(ssl->session->cert_chain, X509_free); | |||
ssl->session->cert_chain = chain; | |||
chain = NULL; | |||
ret = 1; | |||
err: | |||
sk_X509_pop_free(chain, X509_free); | |||
return ret; | |||
} | |||
int tls13_process_certificate_verify(SSL *ssl) { | |||
int ret = 0; | |||
X509 *peer = ssl->session->peer; | |||
EVP_PKEY *pkey = NULL; | |||
uint8_t *msg = NULL; | |||
size_t msg_len; | |||
/* Filter out unsupported certificate types. */ | |||
pkey = X509_get_pubkey(peer); | |||
if (pkey == NULL) { | |||
goto err; | |||
} | |||
CBS cbs, signature; | |||
uint16_t signature_algorithm; | |||
CBS_init(&cbs, ssl->init_msg, ssl->init_num); | |||
if (!CBS_get_u16(&cbs, &signature_algorithm) || | |||
!CBS_get_u16_length_prefixed(&cbs, &signature) || | |||
CBS_len(&cbs) != 0) { | |||
OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); | |||
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); | |||
goto err; | |||
} | |||
int al; | |||
if (!tls12_check_peer_sigalg(ssl, &al, signature_algorithm)) { | |||
ssl3_send_alert(ssl, SSL3_AL_FATAL, al); | |||
goto err; | |||
} | |||
ssl->s3->tmp.peer_signature_algorithm = signature_algorithm; | |||
if (!tls13_get_cert_verify_signature_input(ssl, &msg, &msg_len, | |||
!ssl->server)) { | |||
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR); | |||
goto err; | |||
} | |||
int sig_ok = | |||
ssl_public_key_verify(ssl, CBS_data(&signature), CBS_len(&signature), | |||
signature_algorithm, pkey, msg, msg_len); | |||
if (!sig_ok) { | |||
OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_SIGNATURE); | |||
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECRYPT_ERROR); | |||
goto err; | |||
} | |||
ret = 1; | |||
err: | |||
EVP_PKEY_free(pkey); | |||
OPENSSL_free(msg); | |||
return ret; | |||
} | |||
int tls13_check_message_type(SSL *ssl, int type) { | |||
if (ssl->s3->tmp.message_type != type) { | |||
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE); | |||
OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_MESSAGE); | |||
return 0; | |||
} | |||
return 1; | |||
} | |||
int tls13_process_finished(SSL *ssl) { | |||
uint8_t verify_data[EVP_MAX_MD_SIZE]; | |||
size_t verify_data_len; | |||
if (!tls13_finished_mac(ssl, verify_data, &verify_data_len, !ssl->server)) { | |||
return 0; | |||
} | |||
if (ssl->init_num != verify_data_len || | |||
CRYPTO_memcmp(verify_data, ssl->init_msg, verify_data_len) != 0) { | |||
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECRYPT_ERROR); | |||
OPENSSL_PUT_ERROR(SSL, SSL_R_DIGEST_CHECK_FAILED); | |||
return 0; | |||
} | |||
return 1; | |||
} | |||
int tls13_prepare_certificate(SSL *ssl) { | |||
CBB cbb, body, context; | |||
if (!ssl->method->init_message(ssl, &cbb, &body, SSL3_MT_CERTIFICATE) || | |||
!CBB_add_u8_length_prefixed(&body, &context) || | |||
!CBB_add_bytes(&context, ssl->s3->hs->cert_context, | |||
ssl->s3->hs->cert_context_len) || | |||
!ssl_add_cert_chain(ssl, &body) || | |||
!ssl->method->finish_message(ssl, &cbb)) { | |||
CBB_cleanup(&cbb); | |||
return 0; | |||
} | |||
return 1; | |||
} | |||
enum ssl_private_key_result_t tls13_prepare_certificate_verify( | |||
SSL *ssl, int is_first_run) { | |||
enum ssl_private_key_result_t ret = ssl_private_key_failure; | |||
uint8_t *msg = NULL; | |||
size_t msg_len; | |||
CBB cbb, body; | |||
CBB_zero(&cbb); | |||
uint16_t signature_algorithm; | |||
if (!tls1_choose_signature_algorithm(ssl, &signature_algorithm)) { | |||
goto err; | |||
} | |||
if (!ssl->method->init_message(ssl, &cbb, &body, | |||
SSL3_MT_CERTIFICATE_VERIFY) || | |||
!CBB_add_u16(&body, signature_algorithm)) { | |||
OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); | |||
goto err; | |||
} | |||
/* Sign the digest. */ | |||
CBB child; | |||
const size_t max_sig_len = ssl_private_key_max_signature_len(ssl); | |||
uint8_t *sig; | |||
size_t sig_len; | |||
if (!CBB_add_u16_length_prefixed(&body, &child) || | |||
!CBB_reserve(&child, &sig, max_sig_len)) { | |||
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR); | |||
goto err; | |||
} | |||
enum ssl_private_key_result_t sign_result; | |||
if (is_first_run) { | |||
if (!tls13_get_cert_verify_signature_input(ssl, &msg, &msg_len, | |||
ssl->server)) { | |||
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR); | |||
goto err; | |||
} | |||
sign_result = ssl_private_key_sign(ssl, sig, &sig_len, max_sig_len, | |||
signature_algorithm, msg, msg_len); | |||
} else { | |||
sign_result = ssl_private_key_complete(ssl, sig, &sig_len, max_sig_len); | |||
} | |||
if (sign_result != ssl_private_key_success) { | |||
ret = sign_result; | |||
goto err; | |||
} | |||
if (!CBB_did_write(&child, sig_len) || | |||
!ssl->method->finish_message(ssl, &cbb)) { | |||
goto err; | |||
} | |||
ret = ssl_private_key_success; | |||
err: | |||
CBB_cleanup(&cbb); | |||
OPENSSL_free(msg); | |||
return ret; | |||
} | |||
int tls13_prepare_finished(SSL *ssl) { | |||
size_t verify_data_len; | |||
uint8_t verify_data[EVP_MAX_MD_SIZE]; | |||
if (!tls13_finished_mac(ssl, verify_data, &verify_data_len, ssl->server)) { | |||
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR); | |||
OPENSSL_PUT_ERROR(SSL, SSL_R_DIGEST_CHECK_FAILED); | |||
return 0; | |||
} | |||
CBB cbb, body; | |||
if (!ssl->method->init_message(ssl, &cbb, &body, SSL3_MT_FINISHED) || | |||
!CBB_add_bytes(&body, verify_data, verify_data_len) || | |||
!ssl->method->finish_message(ssl, &cbb)) { | |||
CBB_cleanup(&cbb); | |||
return 0; | |||
} | |||
return 1; | |||
} |
@@ -0,0 +1,462 @@ | |||
/* Copyright (c) 2016, Google Inc. | |||
* | |||
* Permission to use, copy, modify, and/or distribute this software for any | |||
* purpose with or without fee is hereby granted, provided that the above | |||
* copyright notice and this permission notice appear in all copies. | |||
* | |||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY | |||
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION | |||
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | |||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ | |||
#include <openssl/ssl.h> | |||
#include <assert.h> | |||
#include <string.h> | |||
#include <openssl/bytestring.h> | |||
#include <openssl/digest.h> | |||
#include <openssl/err.h> | |||
#include <openssl/mem.h> | |||
#include <openssl/stack.h> | |||
#include <openssl/x509.h> | |||
#include "internal.h" | |||
enum client_hs_state_t { | |||
state_process_server_hello = 0, | |||
state_process_encrypted_extensions, | |||
state_process_certificate_request, | |||
state_process_server_certificate, | |||
state_process_server_certificate_verify, | |||
state_process_server_finished, | |||
state_certificate_callback, | |||
state_send_client_certificate, | |||
state_send_client_certificate_verify, | |||
state_complete_client_certificate_verify, | |||
state_send_client_finished, | |||
state_flush, | |||
state_done, | |||
}; | |||
static enum ssl_hs_wait_t do_process_server_hello(SSL *ssl, SSL_HANDSHAKE *hs) { | |||
if (!tls13_check_message_type(ssl, SSL3_MT_SERVER_HELLO)) { | |||
return ssl_hs_error; | |||
} | |||
CBS cbs, server_random, extensions; | |||
uint16_t server_wire_version; | |||
uint16_t cipher_suite; | |||
CBS_init(&cbs, ssl->init_msg, ssl->init_num); | |||
if (!CBS_get_u16(&cbs, &server_wire_version) || | |||
!CBS_get_bytes(&cbs, &server_random, SSL3_RANDOM_SIZE) || | |||
!CBS_get_u16(&cbs, &cipher_suite) || | |||
!CBS_get_u16_length_prefixed(&cbs, &extensions) || | |||
CBS_len(&cbs) != 0) { | |||
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); | |||
return ssl_hs_error; | |||
} | |||
/* Parse out the extensions. */ | |||
int have_key_share = 0; | |||
CBS key_share; | |||
while (CBS_len(&extensions) != 0) { | |||
uint16_t type; | |||
CBS extension; | |||
if (!CBS_get_u16(&extensions, &type) || | |||
!CBS_get_u16_length_prefixed(&extensions, &extension)) { | |||
OPENSSL_PUT_ERROR(SSL, SSL_R_PARSE_TLSEXT); | |||
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); | |||
return ssl_hs_error; | |||
} | |||
switch (type) { | |||
case TLSEXT_TYPE_key_share: | |||
if (have_key_share) { | |||
OPENSSL_PUT_ERROR(SSL, SSL_R_DUPLICATE_EXTENSION); | |||
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); | |||
return ssl_hs_error; | |||
} | |||
key_share = extension; | |||
have_key_share = 1; | |||
break; | |||
default: | |||
OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_EXTENSION); | |||
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNSUPPORTED_EXTENSION); | |||
return ssl_hs_error; | |||
} | |||
} | |||
assert(ssl->s3->have_version); | |||
memcpy(ssl->s3->server_random, CBS_data(&server_random), SSL3_RANDOM_SIZE); | |||
ssl->hit = 0; | |||
if (!ssl_get_new_session(ssl, 0)) { | |||
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR); | |||
return ssl_hs_error; | |||
} | |||
const SSL_CIPHER *cipher = SSL_get_cipher_by_value(cipher_suite); | |||
if (cipher == NULL) { | |||
OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_CIPHER_RETURNED); | |||
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER); | |||
return ssl_hs_error; | |||
} | |||
/* Check if the cipher is disabled. */ | |||
if ((cipher->algorithm_mkey & ssl->cert->mask_k) || | |||
(cipher->algorithm_auth & ssl->cert->mask_a) || | |||
SSL_CIPHER_get_min_version(cipher) > ssl3_protocol_version(ssl) || | |||
SSL_CIPHER_get_max_version(cipher) < ssl3_protocol_version(ssl) || | |||
!sk_SSL_CIPHER_find(ssl_get_ciphers_by_id(ssl), NULL, cipher)) { | |||
OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_CIPHER_RETURNED); | |||
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER); | |||
return ssl_hs_error; | |||
} | |||
ssl->session->cipher = cipher; | |||
ssl->s3->tmp.new_cipher = cipher; | |||
/* The PRF hash is now known. Set up the key schedule. */ | |||
static const uint8_t kZeroes[EVP_MAX_MD_SIZE] = {0}; | |||
size_t hash_len = | |||
EVP_MD_size(ssl_get_handshake_digest(ssl_get_algorithm_prf(ssl))); | |||
if (!tls13_init_key_schedule(ssl, kZeroes, hash_len)) { | |||
return ssl_hs_error; | |||
} | |||
/* Resolve PSK and incorporate it into the secret. */ | |||
if (cipher->algorithm_auth == SSL_aPSK) { | |||
/* TODO(davidben): Support PSK. */ | |||
OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); | |||
return ssl_hs_error; | |||
} else if (!tls13_advance_key_schedule(ssl, kZeroes, hash_len)) { | |||
return ssl_hs_error; | |||
} | |||
/* Resolve ECDHE and incorporate it into the secret. */ | |||
if (cipher->algorithm_mkey == SSL_kECDHE) { | |||
if (!have_key_share) { | |||
OPENSSL_PUT_ERROR(SSL, SSL_R_MISSING_KEY_SHARE); | |||
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_MISSING_EXTENSION); | |||
return ssl_hs_error; | |||
} | |||
uint8_t *dhe_secret; | |||
size_t dhe_secret_len; | |||
uint8_t alert = SSL_AD_DECODE_ERROR; | |||
if (!ext_key_share_parse_serverhello(ssl, &dhe_secret, &dhe_secret_len, | |||
&alert, &key_share)) { | |||
ssl3_send_alert(ssl, SSL3_AL_FATAL, alert); | |||
return ssl_hs_error; | |||
} | |||
int ok = tls13_advance_key_schedule(ssl, dhe_secret, dhe_secret_len); | |||
OPENSSL_free(dhe_secret); | |||
if (!ok) { | |||
return ssl_hs_error; | |||
} | |||
} else { | |||
if (have_key_share) { | |||
OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_EXTENSION); | |||
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNSUPPORTED_EXTENSION); | |||
return ssl_hs_error; | |||
} | |||
if (!tls13_advance_key_schedule(ssl, kZeroes, hash_len)) { | |||
return ssl_hs_error; | |||
} | |||
return ssl_hs_error; | |||
} | |||
if (!tls13_set_handshake_traffic(ssl)) { | |||
return ssl_hs_error; | |||
} | |||
hs->state = state_process_encrypted_extensions; | |||
return ssl_hs_read_message; | |||
} | |||
static enum ssl_hs_wait_t do_process_encrypted_extensions(SSL *ssl, | |||
SSL_HANDSHAKE *hs) { | |||
if (!tls13_check_message_type(ssl, SSL3_MT_ENCRYPTED_EXTENSIONS)) { | |||
return ssl_hs_error; | |||
} | |||
CBS cbs; | |||
CBS_init(&cbs, ssl->init_msg, ssl->init_num); | |||
if (!ssl_parse_serverhello_tlsext(ssl, &cbs)) { | |||
OPENSSL_PUT_ERROR(SSL, SSL_R_PARSE_TLSEXT); | |||
return ssl_hs_error; | |||
} | |||
if (CBS_len(&cbs) != 0) { | |||
OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); | |||
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); | |||
return ssl_hs_error; | |||
} | |||
if (!ssl->method->hash_current_message(ssl)) { | |||
return ssl_hs_error; | |||
} | |||
hs->state = state_process_certificate_request; | |||
return ssl_hs_read_message; | |||
} | |||
static enum ssl_hs_wait_t do_process_certificate_request(SSL *ssl, | |||
SSL_HANDSHAKE *hs) { | |||
ssl->s3->tmp.cert_request = 0; | |||
/* CertificateRequest may only be sent in certificate-based ciphers. */ | |||
if (!ssl_cipher_uses_certificate_auth(ssl->s3->tmp.new_cipher)) { | |||
hs->state = state_process_server_finished; | |||
return ssl_hs_ok; | |||
} | |||
/* CertificateRequest is optional. */ | |||
if (ssl->s3->tmp.message_type != SSL3_MT_CERTIFICATE_REQUEST) { | |||
hs->state = state_process_server_certificate; | |||
return ssl_hs_ok; | |||
} | |||
CBS cbs, context, supported_signature_algorithms; | |||
CBS_init(&cbs, ssl->init_msg, ssl->init_num); | |||
if (!CBS_get_u8_length_prefixed(&cbs, &context) || | |||
!CBS_stow(&context, &ssl->s3->hs->cert_context, | |||
&ssl->s3->hs->cert_context_len) || | |||
!CBS_get_u16_length_prefixed(&cbs, &supported_signature_algorithms) || | |||
!tls1_parse_peer_sigalgs(ssl, &supported_signature_algorithms)) { | |||
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); | |||
OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); | |||
return ssl_hs_error; | |||
} | |||
uint8_t alert; | |||
STACK_OF(X509_NAME) *ca_sk = ssl_parse_client_CA_list(ssl, &alert, &cbs); | |||
if (ca_sk == NULL) { | |||
ssl3_send_alert(ssl, SSL3_AL_FATAL, alert); | |||
return ssl_hs_error; | |||
} | |||
/* Ignore extensions. */ | |||
CBS extensions; | |||
if (!CBS_get_u16_length_prefixed(&cbs, &extensions) || | |||
CBS_len(&cbs) != 0) { | |||
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); | |||
OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); | |||
return ssl_hs_error; | |||
} | |||
ssl->s3->tmp.cert_request = 1; | |||
sk_X509_NAME_pop_free(ssl->s3->tmp.ca_names, X509_NAME_free); | |||
ssl->s3->tmp.ca_names = ca_sk; | |||
if (!ssl->method->hash_current_message(ssl)) { | |||
return ssl_hs_error; | |||
} | |||
hs->state = state_process_server_certificate; | |||
return ssl_hs_read_message; | |||
} | |||
static enum ssl_hs_wait_t do_process_server_certificate(SSL *ssl, | |||
SSL_HANDSHAKE *hs) { | |||
if (!tls13_check_message_type(ssl, SSL3_MT_CERTIFICATE) || | |||
!tls13_process_certificate(ssl) || | |||
!ssl->method->hash_current_message(ssl)) { | |||
return ssl_hs_error; | |||
} | |||
hs->state = state_process_server_certificate_verify; | |||
return ssl_hs_read_message; | |||
} | |||
static enum ssl_hs_wait_t do_process_server_certificate_verify( | |||
SSL *ssl, SSL_HANDSHAKE *hs) { | |||
if (!tls13_check_message_type(ssl, SSL3_MT_CERTIFICATE_VERIFY) || | |||
!tls13_process_certificate_verify(ssl) || | |||
!ssl->method->hash_current_message(ssl)) { | |||
return 0; | |||
} | |||
hs->state = state_process_server_finished; | |||
return ssl_hs_read_message; | |||
} | |||
static enum ssl_hs_wait_t do_process_server_finished(SSL *ssl, | |||
SSL_HANDSHAKE *hs) { | |||
static const uint8_t kZeroes[EVP_MAX_MD_SIZE] = {0}; | |||
if (!tls13_check_message_type(ssl, SSL3_MT_FINISHED) || | |||
!tls13_process_finished(ssl) || | |||
!ssl->method->hash_current_message(ssl) || | |||
/* Update the secret to the master secret and derive traffic keys. */ | |||
!tls13_advance_key_schedule(ssl, kZeroes, hs->hash_len) || | |||
!tls13_derive_traffic_secret_0(ssl)) { | |||
return ssl_hs_error; | |||
} | |||
hs->state = state_certificate_callback; | |||
return ssl_hs_ok; | |||
} | |||
static enum ssl_hs_wait_t do_certificate_callback(SSL *ssl, SSL_HANDSHAKE *hs) { | |||
/* The peer didn't request a certificate. */ | |||
if (!ssl->s3->tmp.cert_request) { | |||
hs->state = state_send_client_finished; | |||
return ssl_hs_ok; | |||
} | |||
/* Call cert_cb to update the certificate. */ | |||
if (ssl->cert->cert_cb != NULL) { | |||
int rv = ssl->cert->cert_cb(ssl, ssl->cert->cert_cb_arg); | |||
if (rv == 0) { | |||
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR); | |||
OPENSSL_PUT_ERROR(SSL, SSL_R_CERT_CB_ERROR); | |||
return ssl_hs_error; | |||
} | |||
if (rv < 0) { | |||
hs->state = state_certificate_callback; | |||
return ssl_hs_x509_lookup; | |||
} | |||
} | |||
hs->state = state_send_client_certificate; | |||
return ssl_hs_ok; | |||
} | |||
static enum ssl_hs_wait_t do_send_client_certificate(SSL *ssl, | |||
SSL_HANDSHAKE *hs) { | |||
if (!ssl_has_certificate(ssl) && ssl->ctx->client_cert_cb != NULL) { | |||
X509 *x509 = NULL; | |||
EVP_PKEY *pkey = NULL; | |||
int rv = ssl->ctx->client_cert_cb(ssl, &x509, &pkey); | |||
if (rv < 0) { | |||
hs->state = state_send_client_certificate; | |||
return ssl_hs_x509_lookup; | |||
} | |||
int setup_error = rv == 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 ssl_hs_error; | |||
} | |||
} | |||
if (!tls13_prepare_certificate(ssl)) { | |||
return ssl_hs_error; | |||
} | |||
hs->state = state_send_client_certificate_verify; | |||
return ssl_hs_write_message; | |||
} | |||
static enum ssl_hs_wait_t do_send_client_certificate_verify(SSL *ssl, | |||
SSL_HANDSHAKE *hs, | |||
int is_first_run) { | |||
/* Don't send CertificateVerify if there is no certificate. */ | |||
if (!ssl_has_certificate(ssl)) { | |||
hs->state = state_send_client_finished; | |||
return ssl_hs_ok; | |||
} | |||
switch (tls13_prepare_certificate_verify(ssl, is_first_run)) { | |||
case ssl_private_key_success: | |||
hs->state = state_send_client_finished; | |||
return ssl_hs_write_message; | |||
case ssl_private_key_retry: | |||
hs->state = state_complete_client_certificate_verify; | |||
return ssl_hs_private_key_operation; | |||
case ssl_private_key_failure: | |||
return ssl_hs_error; | |||
} | |||
assert(0); | |||
return ssl_hs_error; | |||
} | |||
static enum ssl_hs_wait_t do_send_client_finished(SSL *ssl, SSL_HANDSHAKE *hs) { | |||
if (!tls13_prepare_finished(ssl)) { | |||
return ssl_hs_error; | |||
} | |||
hs->state = state_flush; | |||
return ssl_hs_write_message; | |||
} | |||
static enum ssl_hs_wait_t do_flush(SSL *ssl, SSL_HANDSHAKE *hs) { | |||
if (!tls13_set_traffic_key(ssl, type_data, evp_aead_open, | |||
hs->traffic_secret_0, hs->hash_len) || | |||
!tls13_set_traffic_key(ssl, type_data, evp_aead_seal, | |||
hs->traffic_secret_0, hs->hash_len) || | |||
!tls13_finalize_keys(ssl)) { | |||
return ssl_hs_error; | |||
} | |||
hs->state = state_done; | |||
return ssl_hs_flush; | |||
} | |||
enum ssl_hs_wait_t tls13_client_handshake(SSL *ssl) { | |||
SSL_HANDSHAKE *hs = ssl->s3->hs; | |||
while (hs->state != state_done) { | |||
enum ssl_hs_wait_t ret = ssl_hs_error; | |||
enum client_hs_state_t state = hs->state; | |||
switch (state) { | |||
case state_process_server_hello: | |||
ret = do_process_server_hello(ssl, hs); | |||
break; | |||
case state_process_encrypted_extensions: | |||
ret = do_process_encrypted_extensions(ssl, hs); | |||
break; | |||
case state_process_certificate_request: | |||
ret = do_process_certificate_request(ssl, hs); | |||
break; | |||
case state_process_server_certificate: | |||
ret = do_process_server_certificate(ssl, hs); | |||
break; | |||
case state_process_server_certificate_verify: | |||
ret = do_process_server_certificate_verify(ssl, hs); | |||
break; | |||
case state_process_server_finished: | |||
ret = do_process_server_finished(ssl, hs); | |||
break; | |||
case state_certificate_callback: | |||
ret = do_certificate_callback(ssl, hs); | |||
break; | |||
case state_send_client_certificate: | |||
ret = do_send_client_certificate(ssl, hs); | |||
break; | |||
case state_send_client_certificate_verify: | |||
ret = do_send_client_certificate_verify(ssl, hs, 1 /* first run */); | |||
break; | |||
case state_complete_client_certificate_verify: | |||
ret = do_send_client_certificate_verify(ssl, hs, 0 /* complete */); | |||
break; | |||
case state_send_client_finished: | |||
ret = do_send_client_finished(ssl, hs); | |||
break; | |||
case state_flush: | |||
ret = do_flush(ssl, hs); | |||
break; | |||
case state_done: | |||
ret = ssl_hs_ok; | |||
break; | |||
} | |||
if (ret != ssl_hs_ok) { | |||
return ret; | |||
} | |||
} | |||
return ssl_hs_ok; | |||
} |
@@ -0,0 +1,344 @@ | |||
/* Copyright (c) 2016, Google Inc. | |||
* | |||
* Permission to use, copy, modify, and/or distribute this software for any | |||
* purpose with or without fee is hereby granted, provided that the above | |||
* copyright notice and this permission notice appear in all copies. | |||
* | |||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY | |||
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION | |||
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | |||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ | |||
#include <openssl/ssl.h> | |||
#include <assert.h> | |||
#include <string.h> | |||
#include <openssl/aead.h> | |||
#include <openssl/bytestring.h> | |||
#include <openssl/digest.h> | |||
#include <openssl/hmac.h> | |||
#include <openssl/hkdf.h> | |||
#include <openssl/mem.h> | |||
#include "internal.h" | |||
int tls13_init_key_schedule(SSL *ssl, const uint8_t *resumption_ctx, | |||
size_t resumption_ctx_len) { | |||
SSL_HANDSHAKE *hs = ssl->s3->hs; | |||
const EVP_MD *digest = ssl_get_handshake_digest(ssl_get_algorithm_prf(ssl)); | |||
hs->hash_len = EVP_MD_size(digest); | |||
/* Save the hash of the resumption context. */ | |||
unsigned resumption_hash_len; | |||
if (!EVP_Digest(resumption_ctx, resumption_ctx_len, hs->resumption_hash, | |||
&resumption_hash_len, digest, NULL)) { | |||
return 0; | |||
} | |||
/* Initialize the secret to the zero key. */ | |||
memset(hs->secret, 0, hs->hash_len); | |||
/* Initialize the rolling hashes and release the handshake buffer. */ | |||
if (!ssl3_init_handshake_hash(ssl)) { | |||
return 0; | |||
} | |||
ssl3_free_handshake_buffer(ssl); | |||
return 1; | |||
} | |||
int tls13_advance_key_schedule(SSL *ssl, const uint8_t *in, size_t len) { | |||
SSL_HANDSHAKE *hs = ssl->s3->hs; | |||
const EVP_MD *digest = ssl_get_handshake_digest(ssl_get_algorithm_prf(ssl)); | |||
return HKDF_extract(hs->secret, &hs->hash_len, digest, in, len, hs->secret, | |||
hs->hash_len); | |||
} | |||
static int hkdf_expand_label(uint8_t *out, const EVP_MD *digest, | |||
const uint8_t *secret, size_t secret_len, | |||
const uint8_t *label, size_t label_len, | |||
const uint8_t *hash, size_t hash_len, size_t len) { | |||
static const char kTLS13LabelVersion[] = "TLS 1.3, "; | |||
CBB cbb, child; | |||
uint8_t *hkdf_label; | |||
size_t hkdf_label_len; | |||
if (!CBB_init(&cbb, 2 + 1 + strlen(kTLS13LabelVersion) + label_len + 1 + | |||
hash_len) || | |||
!CBB_add_u16(&cbb, len) || | |||
!CBB_add_u8_length_prefixed(&cbb, &child) || | |||
!CBB_add_bytes(&child, (const uint8_t *)kTLS13LabelVersion, | |||
strlen(kTLS13LabelVersion)) || | |||
!CBB_add_bytes(&child, label, label_len) || | |||
!CBB_add_u8_length_prefixed(&cbb, &child) || | |||
!CBB_add_bytes(&child, hash, hash_len) || | |||
!CBB_finish(&cbb, &hkdf_label, &hkdf_label_len)) { | |||
CBB_cleanup(&cbb); | |||
return 0; | |||
} | |||
int ret = HKDF_expand(out, len, digest, secret, secret_len, hkdf_label, | |||
hkdf_label_len); | |||
OPENSSL_free(hkdf_label); | |||
return ret; | |||
} | |||
int tls13_get_context_hashes(SSL *ssl, uint8_t *out, size_t *out_len) { | |||
SSL_HANDSHAKE *hs = ssl->s3->hs; | |||
EVP_MD_CTX ctx; | |||
EVP_MD_CTX_init(&ctx); | |||
unsigned handshake_len = 0; | |||
int ok = EVP_MD_CTX_copy_ex(&ctx, &ssl->s3->handshake_hash) && | |||
EVP_DigestFinal_ex(&ctx, out, &handshake_len); | |||
EVP_MD_CTX_cleanup(&ctx); | |||
if (!ok) { | |||
return 0; | |||
} | |||
memcpy(out + handshake_len, hs->resumption_hash, hs->hash_len); | |||
*out_len = handshake_len + hs->hash_len; | |||
return 1; | |||
} | |||
/* derive_secret derives a secret of length |len| and writes the result in |out| | |||
* with the given label and the current base secret and most recently-saved | |||
* handshake context. It returns one on success and zero on error. */ | |||
static int derive_secret(SSL *ssl, uint8_t *out, size_t len, | |||
const uint8_t *label, size_t label_len) { | |||
SSL_HANDSHAKE *hs = ssl->s3->hs; | |||
const EVP_MD *digest = ssl_get_handshake_digest(ssl_get_algorithm_prf(ssl)); | |||
uint8_t context_hashes[2 * EVP_MAX_MD_SIZE]; | |||
size_t context_hashes_len; | |||
if (!tls13_get_context_hashes(ssl, context_hashes, &context_hashes_len)) { | |||
return 0; | |||
} | |||
return hkdf_expand_label(out, digest, hs->secret, hs->hash_len, label, | |||
label_len, context_hashes, context_hashes_len, len); | |||
} | |||
int tls13_set_traffic_key(SSL *ssl, enum tls_record_type_t type, | |||
enum evp_aead_direction_t direction, | |||
const uint8_t *traffic_secret, | |||
size_t traffic_secret_len) { | |||
if (traffic_secret_len > 0xff) { | |||
OPENSSL_PUT_ERROR(SSL, ERR_R_OVERFLOW); | |||
return 0; | |||
} | |||
const char *phase; | |||
switch (type) { | |||
case type_early_handshake: | |||
phase = "early handshake key expansion, "; | |||
break; | |||
case type_early_data: | |||
phase = "early application data key expansion, "; | |||
break; | |||
case type_handshake: | |||
phase = "handshake key expansion, "; | |||
break; | |||
case type_data: | |||
phase = "application data key expansion, "; | |||
break; | |||
default: | |||
return 0; | |||
} | |||
size_t phase_len = strlen(phase); | |||
const char *purpose = "client write key"; | |||
if ((ssl->server && direction == evp_aead_seal) || | |||
(!ssl->server && direction == evp_aead_open)) { | |||
purpose = "server write key"; | |||
} | |||
size_t purpose_len = strlen(purpose); | |||
/* The longest label has length 38 (type_early_data) + 16 (either purpose | |||
* value). */ | |||
uint8_t label[38 + 16]; | |||
size_t label_len = phase_len + purpose_len; | |||
if (label_len > sizeof(label)) { | |||
assert(0); | |||
return 0; | |||
} | |||
memcpy(label, phase, phase_len); | |||
memcpy(label + phase_len, purpose, purpose_len); | |||
/* Look up cipher suite properties. */ | |||
const EVP_AEAD *aead; | |||
const EVP_MD *digest = ssl_get_handshake_digest(ssl_get_algorithm_prf(ssl)); | |||
size_t mac_secret_len, fixed_iv_len; | |||
if (!ssl_cipher_get_evp_aead(&aead, &mac_secret_len, &fixed_iv_len, | |||
ssl->session->cipher, | |||
ssl3_protocol_version(ssl))) { | |||
return 0; | |||
} | |||
/* Derive the key. */ | |||
size_t key_len = EVP_AEAD_key_length(aead); | |||
uint8_t key[EVP_AEAD_MAX_KEY_LENGTH]; | |||
if (!hkdf_expand_label(key, digest, traffic_secret, traffic_secret_len, label, | |||
label_len, NULL, 0, key_len)) { | |||
return 0; | |||
} | |||
/* The IV's label ends in "iv" instead of "key". */ | |||
if (label_len < 3) { | |||
assert(0); | |||
return 0; | |||
} | |||
label_len--; | |||
label[label_len - 2] = 'i'; | |||
label[label_len - 1] = 'v'; | |||
/* Derive the IV. */ | |||
size_t iv_len = EVP_AEAD_nonce_length(aead); | |||
uint8_t iv[EVP_AEAD_MAX_NONCE_LENGTH]; | |||
if (!hkdf_expand_label(iv, digest, traffic_secret, traffic_secret_len, label, | |||
label_len, NULL, 0, iv_len)) { | |||
return 0; | |||
} | |||
SSL_AEAD_CTX *traffic_aead = SSL_AEAD_CTX_new(direction, | |||
ssl3_protocol_version(ssl), | |||
ssl->session->cipher, | |||
key, key_len, NULL, 0, | |||
iv, iv_len); | |||
if (traffic_aead == NULL) { | |||
return 0; | |||
} | |||
if (direction == evp_aead_open) { | |||
if (!ssl->method->set_read_state(ssl, traffic_aead)) { | |||
return 0; | |||
} | |||
} else { | |||
if (!ssl->method->set_write_state(ssl, traffic_aead)) { | |||
return 0; | |||
} | |||
} | |||
/* Save the traffic secret. */ | |||
if (direction == evp_aead_open) { | |||
memcpy(ssl->s3->read_traffic_secret, traffic_secret, traffic_secret_len); | |||
ssl->s3->read_traffic_secret_len = traffic_secret_len; | |||
} else { | |||
memcpy(ssl->s3->write_traffic_secret, traffic_secret, traffic_secret_len); | |||
ssl->s3->write_traffic_secret_len = traffic_secret_len; | |||
} | |||
return 1; | |||
} | |||
static const char kTLS13LabelHandshakeTraffic[] = "handshake traffic secret"; | |||
static const char kTLS13LabelApplicationTraffic[] = | |||
"application traffic secret"; | |||
int tls13_set_handshake_traffic(SSL *ssl) { | |||
SSL_HANDSHAKE *hs = ssl->s3->hs; | |||
uint8_t traffic_secret[EVP_MAX_MD_SIZE]; | |||
if (!derive_secret(ssl, traffic_secret, hs->hash_len, | |||
(const uint8_t *)kTLS13LabelHandshakeTraffic, | |||
strlen(kTLS13LabelHandshakeTraffic)) || | |||
!tls13_set_traffic_key(ssl, type_handshake, evp_aead_open, traffic_secret, | |||
hs->hash_len) || | |||
!tls13_set_traffic_key(ssl, type_handshake, evp_aead_seal, traffic_secret, | |||
hs->hash_len)) { | |||
return 0; | |||
} | |||
return 1; | |||
} | |||
int tls13_derive_traffic_secret_0(SSL *ssl) { | |||
SSL_HANDSHAKE *hs = ssl->s3->hs; | |||
return derive_secret(ssl, hs->traffic_secret_0, hs->hash_len, | |||
(const uint8_t *)kTLS13LabelApplicationTraffic, | |||
strlen(kTLS13LabelApplicationTraffic)); | |||
} | |||
static const char kTLS13LabelExporter[] = "exporter master secret"; | |||
static const char kTLS13LabelResumption[] = "resumption master secret"; | |||
int tls13_finalize_keys(SSL *ssl) { | |||
SSL_HANDSHAKE *hs = ssl->s3->hs; | |||
ssl->s3->exporter_secret_len = hs->hash_len; | |||
ssl->session->master_key_length = hs->hash_len; | |||
if (!derive_secret( | |||
ssl, ssl->s3->exporter_secret, ssl->s3->exporter_secret_len, | |||
(const uint8_t *)kTLS13LabelExporter, strlen(kTLS13LabelExporter)) || | |||
!derive_secret(ssl, ssl->session->master_key, | |||
ssl->session->master_key_length, | |||
(const uint8_t *)kTLS13LabelResumption, | |||
strlen(kTLS13LabelResumption))) { | |||
return 0; | |||
} | |||
return 1; | |||
} | |||
int tls13_finished_mac(SSL *ssl, uint8_t *out, size_t *out_len, int is_server) { | |||
SSL_HANDSHAKE *hs = ssl->s3->hs; | |||
const EVP_MD *digest = ssl_get_handshake_digest(ssl_get_algorithm_prf(ssl)); | |||
uint8_t key[EVP_MAX_MD_SIZE]; | |||
size_t key_len = EVP_MD_size(digest); | |||
uint8_t *traffic_secret; | |||
const char *label; | |||
if (is_server) { | |||
label = "server finished"; | |||
if (ssl->server) { | |||
traffic_secret = ssl->s3->write_traffic_secret; | |||
} else { | |||
traffic_secret = ssl->s3->read_traffic_secret; | |||
} | |||
} else { | |||
label = "client finished"; | |||
if (!ssl->server) { | |||
traffic_secret = ssl->s3->write_traffic_secret; | |||
} else { | |||
traffic_secret = ssl->s3->read_traffic_secret; | |||
} | |||
} | |||
uint8_t context_hashes[2 * EVP_MAX_MD_SIZE]; | |||
size_t context_hashes_len; | |||
unsigned len; | |||
if (!hkdf_expand_label(key, digest, traffic_secret, hs->hash_len, | |||
(const uint8_t *)label, strlen(label), NULL, 0, | |||
hs->hash_len) || | |||
!tls13_get_context_hashes(ssl, context_hashes, &context_hashes_len) || | |||
HMAC(digest, key, key_len, context_hashes, context_hashes_len, out, | |||
&len) == NULL) { | |||
return 0; | |||
} | |||
*out_len = len; | |||
return 1; | |||
} | |||
int tls13_export_keying_material(SSL *ssl, uint8_t *out, size_t out_len, | |||
const char *label, size_t label_len, | |||
const uint8_t *context, size_t context_len, | |||
int use_context) { | |||
const EVP_MD *digest = ssl_get_handshake_digest(ssl_get_algorithm_prf(ssl)); | |||
const uint8_t *hash = NULL; | |||
size_t hash_len = 0; | |||
if (use_context) { | |||
hash = context; | |||
hash_len = context_len; | |||
} | |||
return hkdf_expand_label(out, digest, ssl->s3->exporter_secret, | |||
ssl->s3->exporter_secret_len, (const uint8_t *)label, | |||
label_len, hash, hash_len, out_len); | |||
} |
@@ -0,0 +1,483 @@ | |||
/* Copyright (c) 2016, Google Inc. | |||
* | |||
* Permission to use, copy, modify, and/or distribute this software for any | |||
* purpose with or without fee is hereby granted, provided that the above | |||
* copyright notice and this permission notice appear in all copies. | |||
* | |||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY | |||
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION | |||
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | |||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ | |||
#include <openssl/ssl.h> | |||
#include <assert.h> | |||
#include <string.h> | |||
#include <openssl/bytestring.h> | |||
#include <openssl/digest.h> | |||
#include <openssl/err.h> | |||
#include <openssl/mem.h> | |||
#include <openssl/rand.h> | |||
#include <openssl/stack.h> | |||
#include "internal.h" | |||
enum server_hs_state_t { | |||
state_process_client_hello = 0, | |||
state_send_server_hello, | |||
state_send_encrypted_extensions, | |||
state_send_certificate_request, | |||
state_send_server_certificate, | |||
state_send_server_certificate_verify, | |||
state_complete_server_certificate_verify, | |||
state_send_server_finished, | |||
state_flush, | |||
state_read_client_second_flight, | |||
state_process_client_certificate, | |||
state_process_client_certificate_verify, | |||
state_process_client_finished, | |||
state_done, | |||
}; | |||
static enum ssl_hs_wait_t do_process_client_hello(SSL *ssl, SSL_HANDSHAKE *hs) { | |||
if (!tls13_check_message_type(ssl, SSL3_MT_CLIENT_HELLO)) { | |||
return ssl_hs_error; | |||
} | |||
struct ssl_early_callback_ctx early_ctx; | |||
uint16_t client_wire_version; | |||
CBS client_random, session_id, cipher_suites, compression_methods; | |||
memset(&early_ctx, 0, sizeof(early_ctx)); | |||
early_ctx.ssl = ssl; | |||
early_ctx.client_hello = ssl->init_msg; | |||
early_ctx.client_hello_len = ssl->init_num; | |||
if (!ssl_early_callback_init(&early_ctx)) { | |||
OPENSSL_PUT_ERROR(SSL, SSL_R_CLIENTHELLO_PARSE_FAILED); | |||
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); | |||
return ssl_hs_error; | |||
} | |||
CBS cbs; | |||
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); | |||
/* Load the client random. */ | |||
memcpy(ssl->s3->client_random, CBS_data(&client_random), SSL3_RANDOM_SIZE); | |||
ssl->hit = 0; | |||
if (!ssl_get_new_session(ssl, 1 /* server */)) { | |||
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR); | |||
return ssl_hs_error; | |||
} | |||
if (ssl->ctx->dos_protection_cb != NULL && | |||
ssl->ctx->dos_protection_cb(&early_ctx) == 0) { | |||
/* Connection rejected for DOS reasons. */ | |||
OPENSSL_PUT_ERROR(SSL, SSL_R_CONNECTION_REJECTED); | |||
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ACCESS_DENIED); | |||
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. */ | |||
if (CBS_len(&compression_methods) != 1 || | |||
CBS_data(&compression_methods)[0] != 0) { | |||
OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_COMPRESSION_LIST); | |||
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER); | |||
return ssl_hs_error; | |||
} | |||
/* TLS extensions. */ | |||
if (!ssl_parse_clienthello_tlsext(ssl, &cbs)) { | |||
OPENSSL_PUT_ERROR(SSL, SSL_R_PARSE_TLSEXT); | |||
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. | |||
* | |||
* TODO(davidben): Can this get run earlier? */ | |||
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 ssl_hs_error; | |||
} | |||
if (rv < 0) { | |||
hs->state = state_process_client_hello; | |||
return ssl_hs_x509_lookup; | |||
} | |||
} | |||
STACK_OF(SSL_CIPHER) *ciphers = | |||
ssl_bytes_to_cipher_list(ssl, &cipher_suites, max_version); | |||
if (ciphers == NULL) { | |||
return ssl_hs_error; | |||
} | |||
const SSL_CIPHER *cipher = | |||
ssl3_choose_cipher(ssl, ciphers, ssl_get_cipher_preferences(ssl)); | |||
sk_SSL_CIPHER_free(ciphers); | |||
if (cipher == NULL) { | |||
OPENSSL_PUT_ERROR(SSL, SSL_R_NO_SHARED_CIPHER); | |||
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE); | |||
return ssl_hs_error; | |||
} | |||
ssl->session->cipher = cipher; | |||
ssl->s3->tmp.new_cipher = cipher; | |||
/* The PRF hash is now known. Set up the key schedule and hash the | |||
* ClientHello. */ | |||
static const uint8_t kZeroes[EVP_MAX_MD_SIZE] = {0}; | |||
size_t hash_len = | |||
EVP_MD_size(ssl_get_handshake_digest(ssl_get_algorithm_prf(ssl))); | |||
if (!tls13_init_key_schedule(ssl, kZeroes, hash_len)) { | |||
return ssl_hs_error; | |||
} | |||
/* Resolve PSK and incorporate it into the secret. */ | |||
if (cipher->algorithm_auth == SSL_aPSK) { | |||
/* TODO(davidben): Support PSK. */ | |||
OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); | |||
return ssl_hs_error; | |||
} else if (!tls13_advance_key_schedule(ssl, kZeroes, hash_len)) { | |||
return ssl_hs_error; | |||
} | |||
/* Resolve ECDHE and incorporate it into the secret. */ | |||
if (cipher->algorithm_mkey == SSL_kECDHE) { | |||
const uint8_t *key_share_buf = NULL; | |||
size_t key_share_len = 0; | |||
CBS key_share; | |||
if (!SSL_early_callback_ctx_extension_get(&early_ctx, TLSEXT_TYPE_key_share, | |||
&key_share_buf, &key_share_len)) { | |||
OPENSSL_PUT_ERROR(SSL, SSL_R_MISSING_KEY_SHARE); | |||
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_MISSING_EXTENSION); | |||
return ssl_hs_error; | |||
} | |||
CBS_init(&key_share, key_share_buf, key_share_len); | |||
uint8_t *dhe_secret; | |||
size_t dhe_secret_len; | |||
uint8_t alert; | |||
if (!ext_key_share_parse_clienthello(ssl, &dhe_secret, &dhe_secret_len, | |||
&alert, &key_share)) { | |||
ssl3_send_alert(ssl, SSL3_AL_FATAL, alert); | |||
return ssl_hs_error; | |||
} | |||
int ok = tls13_advance_key_schedule(ssl, dhe_secret, dhe_secret_len); | |||
OPENSSL_free(dhe_secret); | |||
if (!ok) { | |||
return ssl_hs_error; | |||
} | |||
} else if (!tls13_advance_key_schedule(ssl, kZeroes, hash_len)) { | |||
return ssl_hs_error; | |||
} | |||
hs->state = state_send_server_hello; | |||
return ssl_hs_ok; | |||
} | |||
static enum ssl_hs_wait_t do_send_server_hello(SSL *ssl, SSL_HANDSHAKE *hs) { | |||
CBB cbb, body, extensions; | |||
if (!ssl->method->init_message(ssl, &cbb, &body, SSL3_MT_SERVER_HELLO) || | |||
!CBB_add_u16(&body, ssl->version) || | |||
!RAND_bytes(ssl->s3->server_random, sizeof(ssl->s3->server_random)) || | |||
!CBB_add_bytes(&body, ssl->s3->server_random, SSL3_RANDOM_SIZE) || | |||
!CBB_add_u16(&body, ssl_cipher_get_value(ssl->s3->tmp.new_cipher)) || | |||
!CBB_add_u16_length_prefixed(&body, &extensions) || | |||
!ext_key_share_add_serverhello(ssl, &extensions) || | |||
!ssl->method->finish_message(ssl, &cbb)) { | |||
CBB_cleanup(&cbb); | |||
return ssl_hs_error; | |||
} | |||
hs->state = state_send_encrypted_extensions; | |||
return ssl_hs_write_message; | |||
} | |||
static enum ssl_hs_wait_t do_send_encrypted_extensions(SSL *ssl, | |||
SSL_HANDSHAKE *hs) { | |||
if (!tls13_set_handshake_traffic(ssl)) { | |||
return ssl_hs_error; | |||
} | |||
CBB cbb, body; | |||
if (!ssl->method->init_message(ssl, &cbb, &body, | |||
SSL3_MT_ENCRYPTED_EXTENSIONS) || | |||
!ssl_add_serverhello_tlsext(ssl, &body) || | |||
!ssl->method->finish_message(ssl, &cbb)) { | |||
CBB_cleanup(&cbb); | |||
return ssl_hs_error; | |||
} | |||
hs->state = state_send_certificate_request; | |||
return ssl_hs_write_message; | |||
} | |||
static enum ssl_hs_wait_t do_send_certificate_request(SSL *ssl, | |||
SSL_HANDSHAKE *hs) { | |||
/* Determine whether to request a client certificate. */ | |||
ssl->s3->tmp.cert_request = !!(ssl->verify_mode & SSL_VERIFY_PEER); | |||
/* CertificateRequest may only be sent in certificate-based ciphers. */ | |||
if (!ssl_cipher_uses_certificate_auth(ssl->s3->tmp.new_cipher)) { | |||
ssl->s3->tmp.cert_request = 0; | |||
} | |||
if (!ssl->s3->tmp.cert_request) { | |||
/* Skip this state. */ | |||
hs->state = state_send_server_certificate; | |||
return ssl_hs_ok; | |||
} | |||
CBB cbb, body, sigalgs_cbb; | |||
if (!ssl->method->init_message(ssl, &cbb, &body, | |||
SSL3_MT_CERTIFICATE_REQUEST) || | |||
!CBB_add_u8(&body, 0 /* no certificate_request_context. */)) { | |||
goto err; | |||
} | |||
const uint16_t *sigalgs; | |||
size_t sigalgs_len = tls12_get_psigalgs(ssl, &sigalgs); | |||
if (!CBB_add_u16_length_prefixed(&body, &sigalgs_cbb)) { | |||
goto err; | |||
} | |||
for (size_t i = 0; i < sigalgs_len; i++) { | |||
if (!CBB_add_u16(&sigalgs_cbb, sigalgs[i])) { | |||
goto err; | |||
} | |||
} | |||
if (!ssl_add_client_CA_list(ssl, &body) || | |||
!CBB_add_u16(&body, 0 /* empty certificate_extensions. */) || | |||
!ssl->method->finish_message(ssl, &cbb)) { | |||
goto err; | |||
} | |||
hs->state = state_send_server_certificate; | |||
return ssl_hs_write_message; | |||
err: | |||
CBB_cleanup(&cbb); | |||
return ssl_hs_error; | |||
} | |||
static enum ssl_hs_wait_t do_send_server_certificate(SSL *ssl, | |||
SSL_HANDSHAKE *hs) { | |||
if (!ssl_cipher_uses_certificate_auth(ssl->s3->tmp.new_cipher)) { | |||
hs->state = state_send_server_finished; | |||
return ssl_hs_ok; | |||
} | |||
if (!ssl_has_certificate(ssl)) { | |||
OPENSSL_PUT_ERROR(SSL, SSL_R_NO_CERTIFICATE_SET); | |||
return ssl_hs_error; | |||
} | |||
if (!tls13_prepare_certificate(ssl)) { | |||
return ssl_hs_error; | |||
} | |||
hs->state = state_send_server_certificate_verify; | |||
return ssl_hs_write_message; | |||
} | |||
static enum ssl_hs_wait_t do_send_server_certificate_verify(SSL *ssl, | |||
SSL_HANDSHAKE *hs, | |||
int is_first_run) { | |||
switch (tls13_prepare_certificate_verify(ssl, is_first_run)) { | |||
case ssl_private_key_success: | |||
hs->state = state_send_server_finished; | |||
return ssl_hs_write_message; | |||
case ssl_private_key_retry: | |||
hs->state = state_complete_server_certificate_verify; | |||
return ssl_hs_private_key_operation; | |||
case ssl_private_key_failure: | |||
return ssl_hs_error; | |||
} | |||
assert(0); | |||
return ssl_hs_error; | |||
} | |||
static enum ssl_hs_wait_t do_send_server_finished(SSL *ssl, SSL_HANDSHAKE *hs) { | |||
if (!tls13_prepare_finished(ssl)) { | |||
return ssl_hs_error; | |||
} | |||
hs->state = state_flush; | |||
return ssl_hs_write_message; | |||
} | |||
static enum ssl_hs_wait_t do_flush(SSL *ssl, SSL_HANDSHAKE *hs) { | |||
hs->state = state_read_client_second_flight; | |||
return ssl_hs_flush; | |||
} | |||
static enum ssl_hs_wait_t do_read_client_second_flight(SSL *ssl, | |||
SSL_HANDSHAKE *hs) { | |||
/* Update the secret to the master secret and derive traffic keys. */ | |||
static const uint8_t kZeroes[EVP_MAX_MD_SIZE] = {0}; | |||
if (!tls13_advance_key_schedule(ssl, kZeroes, hs->hash_len) || | |||
!tls13_derive_traffic_secret_0(ssl) || | |||
!tls13_set_traffic_key(ssl, type_data, evp_aead_seal, | |||
hs->traffic_secret_0, hs->hash_len)) { | |||
return ssl_hs_error; | |||
} | |||
hs->state = state_process_client_certificate; | |||
return ssl_hs_read_message; | |||
} | |||
static enum ssl_hs_wait_t do_process_client_certificate(SSL *ssl, | |||
SSL_HANDSHAKE *hs) { | |||
if (!ssl->s3->tmp.cert_request) { | |||
/* Skip this state. */ | |||
hs->state = state_process_client_certificate_verify; | |||
return ssl_hs_ok; | |||
} | |||
if (!tls13_check_message_type(ssl, SSL3_MT_CERTIFICATE) || | |||
!tls13_process_certificate(ssl) || | |||
!ssl->method->hash_current_message(ssl)) { | |||
return ssl_hs_error; | |||
} | |||
hs->state = state_process_client_certificate_verify; | |||
return ssl_hs_read_message; | |||
} | |||
static enum ssl_hs_wait_t do_process_client_certificate_verify( | |||
SSL *ssl, SSL_HANDSHAKE *hs) { | |||
if (ssl->session->peer == NULL) { | |||
/* Skip this state. */ | |||
hs->state = state_process_client_finished; | |||
return ssl_hs_ok; | |||
} | |||
if (!tls13_check_message_type(ssl, SSL3_MT_CERTIFICATE_VERIFY) || | |||
!tls13_process_certificate_verify(ssl) || | |||
!ssl->method->hash_current_message(ssl)) { | |||
return 0; | |||
} | |||
hs->state = state_process_client_finished; | |||
return ssl_hs_read_message; | |||
} | |||
static enum ssl_hs_wait_t do_process_client_finished(SSL *ssl, | |||
SSL_HANDSHAKE *hs) { | |||
if (!tls13_check_message_type(ssl, SSL3_MT_FINISHED) || | |||
!tls13_process_finished(ssl) || | |||
!ssl->method->hash_current_message(ssl) || | |||
/* evp_aead_seal keys have already been switched. */ | |||
!tls13_set_traffic_key(ssl, type_data, evp_aead_open, | |||
hs->traffic_secret_0, hs->hash_len) || | |||
!tls13_finalize_keys(ssl)) { | |||
return ssl_hs_error; | |||
} | |||
hs->state = state_done; | |||
return ssl_hs_ok; | |||
} | |||
enum ssl_hs_wait_t tls13_server_handshake(SSL *ssl) { | |||
SSL_HANDSHAKE *hs = ssl->s3->hs; | |||
while (hs->state != state_done) { | |||
enum ssl_hs_wait_t ret = ssl_hs_error; | |||
enum server_hs_state_t state = hs->state; | |||
switch (state) { | |||
case state_process_client_hello: | |||
ret = do_process_client_hello(ssl, hs); | |||
break; | |||
case state_send_server_hello: | |||
ret = do_send_server_hello(ssl, hs); | |||
break; | |||
case state_send_encrypted_extensions: | |||
ret = do_send_encrypted_extensions(ssl, hs); | |||
break; | |||
case state_send_certificate_request: | |||
ret = do_send_certificate_request(ssl, hs); | |||
break; | |||
case state_send_server_certificate: | |||
ret = do_send_server_certificate(ssl, hs); | |||
break; | |||
case state_send_server_certificate_verify: | |||
ret = do_send_server_certificate_verify(ssl, hs, 1 /* first run */); | |||
break; | |||
case state_complete_server_certificate_verify: | |||
ret = do_send_server_certificate_verify(ssl, hs, 0 /* complete */); | |||
break; | |||
case state_send_server_finished: | |||
ret = do_send_server_finished(ssl, hs); | |||
break; | |||
case state_flush: | |||
ret = do_flush(ssl, hs); | |||
break; | |||
case state_read_client_second_flight: | |||
ret = do_read_client_second_flight(ssl, hs); | |||
break; | |||
case state_process_client_certificate: | |||
ret = do_process_client_certificate(ssl, hs); | |||
break; | |||
case state_process_client_certificate_verify: | |||
ret = do_process_client_certificate_verify(ssl, hs); | |||
break; | |||
case state_process_client_finished: | |||
ret = do_process_client_finished(ssl, hs); | |||
break; | |||
case state_done: | |||
ret = ssl_hs_ok; | |||
break; | |||
} | |||
if (ret != ssl_hs_ok) { | |||
return ret; | |||
} | |||
} | |||
return ssl_hs_ok; | |||
} |
@@ -56,7 +56,6 @@ | |||
#include <openssl/ssl.h> | |||
#include <assert.h> | |||
#include <string.h> | |||
#include <openssl/buf.h> | |||
@@ -93,9 +92,13 @@ static void ssl3_finish_handshake(SSL *ssl) { | |||
} | |||
static int ssl3_set_read_state(SSL *ssl, SSL_AEAD_CTX *aead_ctx) { | |||
/* TODO(davidben): In TLS 1.3, cipher changes are not always preceeded by a | |||
* ChangeCipherSpec, so this must become a runtime check. */ | |||
assert(ssl->s3->rrec.length == 0); | |||
if (ssl->s3->rrec.length != 0) { | |||
/* There may not be unprocessed record data at a cipher change. */ | |||
OPENSSL_PUT_ERROR(SSL, SSL_R_BUFFERED_MESSAGES_ON_CIPHER_CHANGE); | |||
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE); | |||
SSL_AEAD_CTX_free(aead_ctx); | |||
return 0; | |||
} | |||
memset(ssl->s3->read_sequence, 0, sizeof(ssl->s3->read_sequence)); | |||