Add TLS 1.3 1-RTT.
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>
This commit is contained in:
parent
4ee027fd05
commit
143e8b3fd9
@ -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)) {
|
||||
|
138
ssl/internal.h
138
ssl/internal.h
@ -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) {
|
||||
|
340
ssl/t1_lib.c
340
ssl/t1_lib.c
@ -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) {
|
||||
uint32_t received = 0;
|
||||
/* 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;
|
||||
}
|
||||
|
||||
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 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;
|
||||
|
||||
/* 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 (!(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 (ext == NULL) {
|
||||
if (!custom_ext_parse_serverhello(ssl, out_alert, type, &extension)) {
|
||||
return 0;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
received |= (1u << ext_index);
|
||||
|
||||
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);
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -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;
|
||||
|
437
ssl/tls13_both.c
Normal file
437
ssl/tls13_both.c
Normal file
@ -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;
|
||||
}
|
462
ssl/tls13_client.c
Normal file
462
ssl/tls13_client.c
Normal file
@ -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;
|
||||
}
|
344
ssl/tls13_enc.c
Normal file
344
ssl/tls13_enc.c
Normal file
@ -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);
|
||||
}
|
483
ssl/tls13_server.c
Normal file
483
ssl/tls13_server.c
Normal file
@ -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));
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user