Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/boringssl.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crypto/err/ssl.errordata3
-rw-r--r--include/openssl/ssl.h26
-rw-r--r--include/openssl/ssl3.h3
-rw-r--r--include/openssl/tls1.h8
-rw-r--r--ssl/CMakeLists.txt4
-rw-r--r--ssl/handshake_client.c56
-rw-r--r--ssl/handshake_server.c64
-rw-r--r--ssl/internal.h138
-rw-r--r--ssl/s3_lib.c1
-rw-r--r--ssl/s3_pkt.c7
-rw-r--r--ssl/ssl_ecdh.c22
-rw-r--r--ssl/ssl_lib.c3
-rw-r--r--ssl/t1_enc.c5
-rw-r--r--ssl/t1_lib.c338
-rw-r--r--ssl/test/bssl_shim.cc7
-rw-r--r--ssl/test/runner/common.go40
-rw-r--r--ssl/test/runner/handshake_client.go14
-rw-r--r--ssl/test/runner/handshake_messages.go16
-rw-r--r--ssl/test/runner/handshake_server.go23
-rw-r--r--ssl/test/runner/runner.go912
-rw-r--r--ssl/test/test_config.cc1
-rw-r--r--ssl/test/test_config.h1
-rw-r--r--ssl/tls13_both.c437
-rw-r--r--ssl/tls13_client.c462
-rw-r--r--ssl/tls13_enc.c344
-rw-r--r--ssl/tls13_server.c483
-rw-r--r--ssl/tls_method.c11
27 files changed, 3249 insertions, 180 deletions
diff --git a/crypto/err/ssl.errordata b/crypto/err/ssl.errordata
index f9d557e6..5800d41d 100644
--- a/crypto/err/ssl.errordata
+++ b/crypto/err/ssl.errordata
@@ -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
diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h
index 44026aa5..d84ca305 100644
--- a/include/openssl/ssl.h
+++ b/include/openssl/ssl.h
@@ -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
diff --git a/include/openssl/ssl3.h b/include/openssl/ssl3.h
index b71c1de5..beab5722 100644
--- a/include/openssl/ssl3.h
+++ b/include/openssl/ssl3.h
@@ -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
diff --git a/include/openssl/tls1.h b/include/openssl/tls1.h
index ae1ab7cc..3c97d26a 100644
--- a/include/openssl/tls1.h
+++ b/include/openssl/tls1.h
@@ -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
diff --git a/ssl/CMakeLists.txt b/ssl/CMakeLists.txt
index d5cb8703..9287a63b 100644
--- a/ssl/CMakeLists.txt
+++ b/ssl/CMakeLists.txt
@@ -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)
diff --git a/ssl/handshake_client.c b/ssl/handshake_client.c
index ee2de2b7..4a82c497 100644
--- a/ssl/handshake_client.c
+++ b/ssl/handshake_client.c
@@ -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);
diff --git a/ssl/handshake_server.c b/ssl/handshake_server.c
index 52b681cf..8427a298 100644
--- a/ssl/handshake_server.c
+++ b/ssl/handshake_server.c
@@ -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)) {
diff --git a/ssl/internal.h b/ssl/internal.h
index 5620c53b..a70400b1 100644
--- a/ssl/internal.h
+++ b/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. */
diff --git a/ssl/s3_lib.c b/ssl/s3_lib.c
index 3827f155..c93722ae 100644
--- a/ssl/s3_lib.c
+++ b/ssl/s3_lib.c
@@ -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);
diff --git a/ssl/s3_pkt.c b/ssl/s3_pkt.c
index dec82882..060ef691 100644
--- a/ssl/s3_pkt.c
+++ b/ssl/s3_pkt.c
@@ -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)) {
diff --git a/ssl/ssl_ecdh.c b/ssl/ssl_ecdh.c
index bc363e95..dd70bdb2 100644
--- a/ssl/ssl_ecdh.c
+++ b/ssl/ssl_ecdh.c
@@ -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);
}
diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c
index 9842d961..66ce84de 100644
--- a/ssl/ssl_lib.c
+++ b/ssl/ssl_lib.c
@@ -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 *) {
diff --git a/ssl/t1_enc.c b/ssl/t1_enc.c
index 053196dc..74c5d41b 100644
--- a/ssl/t1_enc.c
+++ b/ssl/t1_enc.c
@@ -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) {
diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c
index 9761dc92..9143ba85 100644
--- a/ssl/t1_lib.c
+++ b/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) {
+ /* Before TLS 1.3, ServerHello extensions blocks may be omitted if empty. */
+ if (CBS_len(cbs) == 0 && ssl3_protocol_version(ssl) < TLS1_3_VERSION) {
+ return 1;
+ }
+
+ /* Decode the extensions block and check it is valid. */
+ CBS extensions;
+ if (!CBS_get_u16_length_prefixed(cbs, &extensions) ||
+ !tls1_check_duplicate_extensions(&extensions)) {
+ *out_alert = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+
uint32_t received = 0;
+ while (CBS_len(&extensions) != 0) {
+ uint16_t type;
+ CBS extension;
- if (CBS_len(cbs) != 0) {
- /* Decode the extensions block and check it is valid. */
- CBS extensions;
- if (!CBS_get_u16_length_prefixed(cbs, &extensions) ||
- !tls1_check_duplicate_extensions(&extensions)) {
+ /* Decode the next extension. */
+ if (!CBS_get_u16(&extensions, &type) ||
+ !CBS_get_u16_length_prefixed(&extensions, &extension)) {
*out_alert = SSL_AD_DECODE_ERROR;
return 0;
}
+ unsigned ext_index;
+ const struct tls_extension *const ext =
+ tls_extension_find(&ext_index, type);
- while (CBS_len(&extensions) != 0) {
- uint16_t type;
- CBS extension;
-
- /* Decode the next extension. */
- if (!CBS_get_u16(&extensions, &type) ||
- !CBS_get_u16_length_prefixed(&extensions, &extension)) {
- *out_alert = SSL_AD_DECODE_ERROR;
+ if (ext == NULL) {
+ if (!custom_ext_parse_serverhello(ssl, out_alert, type, &extension)) {
return 0;
}
+ continue;
+ }
- unsigned ext_index;
- const struct tls_extension *const ext =
- tls_extension_find(&ext_index, type);
-
- if (ext == NULL) {
- if (!custom_ext_parse_serverhello(ssl, out_alert, type, &extension)) {
- return 0;
- }
- continue;
- }
-
- if (!(ssl->s3->tmp.extensions.sent & (1u << ext_index))) {
- /* If the extension was never sent then it is illegal. */
- OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_EXTENSION);
- ERR_add_error_dataf("extension :%u", (unsigned)type);
- *out_alert = SSL_AD_DECODE_ERROR;
- return 0;
- }
+ if (!(ssl->s3->tmp.extensions.sent & (1u << ext_index))) {
+ /* If the extension was never sent then it is illegal. */
+ OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_EXTENSION);
+ ERR_add_error_dataf("extension :%u", (unsigned)type);
+ *out_alert = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
- received |= (1u << ext_index);
+ received |= (1u << ext_index);
- uint8_t alert = SSL_AD_DECODE_ERROR;
- if (!ext->parse_serverhello(ssl, &alert, &extension)) {
- OPENSSL_PUT_ERROR(SSL, SSL_R_ERROR_PARSING_EXTENSION);
- ERR_add_error_dataf("extension: %u", (unsigned)type);
- *out_alert = alert;
- return 0;
- }
+ uint8_t alert = SSL_AD_DECODE_ERROR;
+ if (!ext->parse_serverhello(ssl, &alert, &extension)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_ERROR_PARSING_EXTENSION);
+ ERR_add_error_dataf("extension: %u", (unsigned)type);
+ *out_alert = alert;
+ return 0;
}
}
diff --git a/ssl/test/bssl_shim.cc b/ssl/test/bssl_shim.cc
index 0bdfc942..d1aadb87 100644
--- a/ssl/test/bssl_shim.cc
+++ b/ssl/test/bssl_shim.cc
@@ -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()) {
diff --git a/ssl/test/runner/common.go b/ssl/test/runner/common.go
index 5fd3436f..0ae360ac 100644
--- a/ssl/test/runner/common.go
+++ b/ssl/test/runner/common.go
@@ -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() {
diff --git a/ssl/test/runner/handshake_client.go b/ssl/test/runner/handshake_client.go
index a2ea50e6..3d9fa5ad 100644
--- a/ssl/test/runner/handshake_client.go
+++ b/ssl/test/runner/handshake_client.go
@@ -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")
diff --git a/ssl/test/runner/handshake_messages.go b/ssl/test/runner/handshake_messages.go
index 6d0f9205..376d88cb 100644
--- a/ssl/test/runner/handshake_messages.go
+++ b/ssl/test/runner/handshake_messages.go
@@ -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 {
diff --git a/ssl/test/runner/handshake_server.go b/ssl/test/runner/handshake_server.go
index d4dba75a..24d64254 100644
--- a/ssl/test/runner/handshake_server.go
+++ b/ssl/test/runner/handshake_server.go
@@ -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
}
diff --git a/ssl/test/runner/runner.go b/ssl/test/runner/runner.go
index a0edf77b..e5faae52 100644
--- a/ssl/test/runner/runner.go
+++ b/ssl/test/runner/runner.go
@@ -941,8 +941,7 @@ var tlsVersions = []struct {
{"TLS1", VersionTLS10, "-no-tls1", true},
{"TLS11", VersionTLS11, "-no-tls11", false},
{"TLS12", VersionTLS12, "-no-tls12", true},
- // TODO(nharper): Once we have a real implementation of TLS 1.3, update the name here.
- {"FakeTLS13", VersionTLS13, "-no-tls13", false},
+ {"TLS13", VersionTLS13, "-no-tls13", false},
}
var testCipherSuites = []struct {
@@ -1340,7 +1339,6 @@ func addBasicTests() {
{
name: "CertMismatchRSA",
config: Config{
- // TODO(davidben): Add a TLS 1.3 version of this test.
MaxVersion: VersionTLS12,
CipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256},
Certificates: []Certificate{ecdsaP256Certificate},
@@ -1352,9 +1350,21 @@ func addBasicTests() {
expectedError: ":WRONG_CERTIFICATE_TYPE:",
},
{
+ name: "CertMismatchRSA-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ CipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256},
+ Certificates: []Certificate{ecdsaP256Certificate},
+ Bugs: ProtocolBugs{
+ SendCipherSuite: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":WRONG_CERTIFICATE_TYPE:",
+ },
+ {
name: "CertMismatchECDSA",
config: Config{
- // TODO(davidben): Add a TLS 1.3 version of this test.
MaxVersion: VersionTLS12,
CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
Certificates: []Certificate{rsaCertificate},
@@ -1366,9 +1376,21 @@ func addBasicTests() {
expectedError: ":WRONG_CERTIFICATE_TYPE:",
},
{
+ name: "CertMismatchECDSA-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
+ Certificates: []Certificate{rsaCertificate},
+ Bugs: ProtocolBugs{
+ SendCipherSuite: TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":WRONG_CERTIFICATE_TYPE:",
+ },
+ {
name: "EmptyCertificateList",
config: Config{
- // TODO(davidben): Add a TLS 1.3 version of this test.
MaxVersion: VersionTLS12,
CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
Bugs: ProtocolBugs{
@@ -1694,7 +1716,6 @@ func addBasicTests() {
{
name: "BadFinished-Client",
config: Config{
- // TODO(davidben): Add a TLS 1.3 version of this.
MaxVersion: VersionTLS12,
Bugs: ProtocolBugs{
BadFinished: true,
@@ -1704,10 +1725,20 @@ func addBasicTests() {
expectedError: ":DIGEST_CHECK_FAILED:",
},
{
+ name: "BadFinished-Client-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ BadFinished: true,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":DIGEST_CHECK_FAILED:",
+ },
+ {
testType: serverTest,
name: "BadFinished-Server",
config: Config{
- // TODO(davidben): Add a TLS 1.3 version of this.
MaxVersion: VersionTLS12,
Bugs: ProtocolBugs{
BadFinished: true,
@@ -1717,6 +1748,18 @@ func addBasicTests() {
expectedError: ":DIGEST_CHECK_FAILED:",
},
{
+ testType: serverTest,
+ name: "BadFinished-Server-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ BadFinished: true,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":DIGEST_CHECK_FAILED:",
+ },
+ {
name: "FalseStart-BadFinished",
config: Config{
MaxVersion: VersionTLS12,
@@ -2182,7 +2225,6 @@ func addCipherSuiteTests() {
testCases = append(testCases, testCase{
name: "NoSharedCipher",
config: Config{
- // TODO(davidben): Add a TLS 1.3 version of this test.
MaxVersion: VersionTLS12,
CipherSuites: []uint16{},
},
@@ -2191,6 +2233,16 @@ func addCipherSuiteTests() {
})
testCases = append(testCases, testCase{
+ name: "NoSharedCipher-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ CipherSuites: []uint16{},
+ },
+ shouldFail: true,
+ expectedError: ":HANDSHAKE_FAILURE_ON_CLIENT_HELLO:",
+ })
+
+ testCases = append(testCases, testCase{
name: "UnsupportedCipherSuite",
config: Config{
MaxVersion: VersionTLS12,
@@ -2509,9 +2561,6 @@ func addClientAuthTests() {
}
}
- // TODO(davidben): These tests will need TLS 1.3 versions when the
- // handshake is separate.
-
testCases = append(testCases, testCase{
name: "NoClientCertificate",
config: Config{
@@ -2523,6 +2572,16 @@ func addClientAuthTests() {
})
testCases = append(testCases, testCase{
+ name: "NoClientCertificate-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ ClientAuth: RequireAnyClientCert,
+ },
+ shouldFail: true,
+ expectedLocalError: "client didn't provide a certificate",
+ })
+
+ testCases = append(testCases, testCase{
testType: serverTest,
name: "RequireAnyClientCertificate",
config: Config{
@@ -2535,6 +2594,17 @@ func addClientAuthTests() {
testCases = append(testCases, testCase{
testType: serverTest,
+ name: "RequireAnyClientCertificate-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ },
+ flags: []string{"-require-any-client-certificate"},
+ shouldFail: true,
+ expectedError: ":PEER_DID_NOT_RETURN_A_CERTIFICATE:",
+ })
+
+ testCases = append(testCases, testCase{
+ testType: serverTest,
name: "RequireAnyClientCertificate-SSL3",
config: Config{
MaxVersion: VersionSSL30,
@@ -2559,6 +2629,21 @@ func addClientAuthTests() {
expectedError: ":UNEXPECTED_MESSAGE:",
})
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "SkipClientCertificate-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ SkipClientCertificate: true,
+ },
+ },
+ // Setting SSL_VERIFY_PEER allows anonymous clients.
+ flags: []string{"-verify-peer"},
+ shouldFail: true,
+ expectedError: ":UNEXPECTED_MESSAGE:",
+ })
+
// Client auth is only legal in certificate-based ciphers.
testCases = append(testCases, testCase{
testType: clientTest,
@@ -2616,10 +2701,8 @@ func addExtendedMasterSecretTests() {
for _, with := range []bool{false, true} {
prefix := "No"
- var flags []string
if with {
prefix = ""
- flags = []string{expectEMSFlag}
}
for _, isClient := range []bool{false, true} {
@@ -2630,10 +2713,14 @@ func addExtendedMasterSecretTests() {
testType = clientTest
}
- // TODO(davidben): Once the new TLS 1.3 handshake is in,
- // test that the extension is irrelevant, but the API
- // acts as if it is enabled.
for _, ver := range tlsVersions {
+ // In TLS 1.3, the extension is irrelevant and
+ // always reports as enabled.
+ var flags []string
+ if with || ver.version >= VersionTLS13 {
+ flags = []string{expectEMSFlag}
+ }
+
test := testCase{
testType: testType,
name: prefix + "ExtendedMasterSecret-" + ver.name + suffix,
@@ -2784,9 +2871,6 @@ func addStateMachineCoverageTests(config stateMachineTestConfig) {
// Basic handshake, with resumption. Client and server,
// session ID and session ticket.
- //
- // TODO(davidben): Add TLS 1.3 tests for all of its different handshake
- // shapes.
tests = append(tests, testCase{
name: "Basic-Client",
config: Config{
@@ -2862,9 +2946,22 @@ func addStateMachineCoverageTests(config stateMachineTestConfig) {
resumeSession: true,
})
+ // TLS 1.3 basic handshake shapes.
+ tests = append(tests, testCase{
+ name: "TLS13-1RTT-Client",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ },
+ })
+ tests = append(tests, testCase{
+ testType: serverTest,
+ name: "TLS13-1RTT-Server",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ },
+ })
+
// TLS client auth.
- //
- // TODO(davidben): Add TLS 1.3 client auth tests.
tests = append(tests, testCase{
testType: clientTest,
name: "ClientAuth-NoCertificate-Client",
@@ -2900,6 +2997,23 @@ func addStateMachineCoverageTests(config stateMachineTestConfig) {
// Setting SSL_VERIFY_PEER allows anonymous clients.
flags: []string{"-verify-peer"},
})
+ tests = append(tests, testCase{
+ testType: clientTest,
+ name: "ClientAuth-NoCertificate-Client-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ ClientAuth: RequestClientCert,
+ },
+ })
+ tests = append(tests, testCase{
+ testType: serverTest,
+ name: "ClientAuth-NoCertificate-Server-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ },
+ // Setting SSL_VERIFY_PEER allows anonymous clients.
+ flags: []string{"-verify-peer"},
+ })
}
tests = append(tests, testCase{
testType: clientTest,
@@ -2915,6 +3029,18 @@ func addStateMachineCoverageTests(config stateMachineTestConfig) {
})
tests = append(tests, testCase{
testType: clientTest,
+ name: "ClientAuth-RSA-Client-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ ClientAuth: RequireAnyClientCert,
+ },
+ flags: []string{
+ "-cert-file", path.Join(*resourceDir, rsaCertificateFile),
+ "-key-file", path.Join(*resourceDir, rsaKeyFile),
+ },
+ })
+ tests = append(tests, testCase{
+ testType: clientTest,
name: "ClientAuth-ECDSA-Client",
config: Config{
MaxVersion: VersionTLS12,
@@ -2927,6 +3053,18 @@ func addStateMachineCoverageTests(config stateMachineTestConfig) {
})
tests = append(tests, testCase{
testType: clientTest,
+ name: "ClientAuth-ECDSA-Client-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ ClientAuth: RequireAnyClientCert,
+ },
+ flags: []string{
+ "-cert-file", path.Join(*resourceDir, ecdsaP256CertificateFile),
+ "-key-file", path.Join(*resourceDir, ecdsaP256KeyFile),
+ },
+ })
+ tests = append(tests, testCase{
+ testType: clientTest,
name: "ClientAuth-NoCertificate-OldCallback",
config: Config{
MaxVersion: VersionTLS12,
@@ -2936,6 +3074,15 @@ func addStateMachineCoverageTests(config stateMachineTestConfig) {
})
tests = append(tests, testCase{
testType: clientTest,
+ name: "ClientAuth-NoCertificate-OldCallback-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ ClientAuth: RequestClientCert,
+ },
+ flags: []string{"-use-old-client-cert-callback"},
+ })
+ tests = append(tests, testCase{
+ testType: clientTest,
name: "ClientAuth-OldCallback",
config: Config{
MaxVersion: VersionTLS12,
@@ -2948,6 +3095,19 @@ func addStateMachineCoverageTests(config stateMachineTestConfig) {
},
})
tests = append(tests, testCase{
+ testType: clientTest,
+ name: "ClientAuth-OldCallback-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ ClientAuth: RequireAnyClientCert,
+ },
+ flags: []string{
+ "-cert-file", path.Join(*resourceDir, rsaCertificateFile),
+ "-key-file", path.Join(*resourceDir, rsaKeyFile),
+ "-use-old-client-cert-callback",
+ },
+ })
+ tests = append(tests, testCase{
testType: serverTest,
name: "ClientAuth-Server",
config: Config{
@@ -2956,10 +3116,17 @@ func addStateMachineCoverageTests(config stateMachineTestConfig) {
},
flags: []string{"-require-any-client-certificate"},
})
+ tests = append(tests, testCase{
+ testType: serverTest,
+ name: "ClientAuth-Server-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Certificates: []Certificate{rsaCertificate},
+ },
+ flags: []string{"-require-any-client-certificate"},
+ })
// Test each key exchange on the server side for async keys.
- //
- // TODO(davidben): Add TLS 1.3 versions of these.
tests = append(tests, testCase{
testType: serverTest,
name: "Basic-Server-RSA",
@@ -3068,42 +3235,45 @@ func addStateMachineCoverageTests(config stateMachineTestConfig) {
})
// Certificate verification tests.
- //
- // TODO(davidben): Test the TLS 1.3 version.
- tests = append(tests, testCase{
- testType: clientTest,
- name: "CertificateVerificationSucceed",
- config: Config{
- MaxVersion: VersionTLS12,
- },
- flags: []string{
- "-verify-peer",
- },
- })
- tests = append(tests, testCase{
- testType: clientTest,
- name: "CertificateVerificationFail",
- config: Config{
- MaxVersion: VersionTLS12,
- },
- flags: []string{
- "-verify-fail",
- "-verify-peer",
- },
- shouldFail: true,
- expectedError: ":CERTIFICATE_VERIFY_FAILED:",
- })
- tests = append(tests, testCase{
- testType: clientTest,
- name: "CertificateVerificationSoftFail",
- config: Config{
- MaxVersion: VersionTLS12,
- },
- flags: []string{
- "-verify-fail",
- "-expect-verify-result",
- },
- })
+ for _, vers := range tlsVersions {
+ if config.protocol == dtls && !vers.hasDTLS {
+ continue
+ }
+ tests = append(tests, testCase{
+ testType: clientTest,
+ name: "CertificateVerificationSucceed-" + vers.name,
+ config: Config{
+ MaxVersion: vers.version,
+ },
+ flags: []string{
+ "-verify-peer",
+ },
+ })
+ tests = append(tests, testCase{
+ testType: clientTest,
+ name: "CertificateVerificationFail-" + vers.name,
+ config: Config{
+ MaxVersion: vers.version,
+ },
+ flags: []string{
+ "-verify-fail",
+ "-verify-peer",
+ },
+ shouldFail: true,
+ expectedError: ":CERTIFICATE_VERIFY_FAILED:",
+ })
+ tests = append(tests, testCase{
+ testType: clientTest,
+ name: "CertificateVerificationSoftFail-" + vers.name,
+ config: Config{
+ MaxVersion: vers.version,
+ },
+ flags: []string{
+ "-verify-fail",
+ "-expect-verify-result",
+ },
+ })
+ }
if config.protocol == tls {
tests = append(tests, testCase{
@@ -3391,15 +3561,13 @@ func addStateMachineCoverageTests(config stateMachineTestConfig) {
func addDDoSCallbackTests() {
// DDoS callback.
-
+ // TODO(davidben): Implement DDoS resumption tests for TLS 1.3.
for _, resume := range []bool{false, true} {
suffix := "Resume"
if resume {
suffix = "No" + suffix
}
- // TODO(davidben): Test TLS 1.3's version of the DDoS callback.
-
testCases = append(testCases, testCase{
testType: serverTest,
name: "Server-DDoS-OK-" + suffix,
@@ -3409,6 +3577,17 @@ func addDDoSCallbackTests() {
flags: []string{"-install-ddos-callback"},
resumeSession: resume,
})
+ if !resume {
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "Server-DDoS-OK-" + suffix + "-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ },
+ flags: []string{"-install-ddos-callback"},
+ resumeSession: resume,
+ })
+ }
failFlag := "-fail-ddos-callback"
if resume {
@@ -3425,6 +3604,19 @@ func addDDoSCallbackTests() {
shouldFail: true,
expectedError: ":CONNECTION_REJECTED:",
})
+ if !resume {
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "Server-DDoS-Reject-" + suffix + "-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ },
+ flags: []string{"-install-ddos-callback", failFlag},
+ resumeSession: resume,
+ shouldFail: true,
+ expectedError: ":CONNECTION_REJECTED:",
+ })
+ }
}
}
@@ -4228,6 +4420,95 @@ func addExtensionTests() {
},
},
})
+
+ // Test that illegal extensions in TLS 1.3 are rejected by the client if
+ // in ServerHello.
+ testCases = append(testCases, testCase{
+ name: "NPN-Forbidden-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ NextProtos: []string{"foo"},
+ Bugs: ProtocolBugs{
+ NegotiateNPNAtAllVersions: true,
+ },
+ },
+ flags: []string{"-select-next-proto", "foo"},
+ shouldFail: true,
+ expectedError: ":ERROR_PARSING_EXTENSION:",
+ })
+ testCases = append(testCases, testCase{
+ name: "EMS-Forbidden-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ NegotiateEMSAtAllVersions: true,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":ERROR_PARSING_EXTENSION:",
+ })
+ testCases = append(testCases, testCase{
+ name: "RenegotiationInfo-Forbidden-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ NegotiateRenegotiationInfoAtAllVersions: true,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":ERROR_PARSING_EXTENSION:",
+ })
+ testCases = append(testCases, testCase{
+ name: "ChannelID-Forbidden-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ RequestChannelID: true,
+ Bugs: ProtocolBugs{
+ NegotiateChannelIDAtAllVersions: true,
+ },
+ },
+ flags: []string{"-send-channel-id", path.Join(*resourceDir, channelIDKeyFile)},
+ shouldFail: true,
+ expectedError: ":ERROR_PARSING_EXTENSION:",
+ })
+ testCases = append(testCases, testCase{
+ name: "Ticket-Forbidden-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ },
+ resumeConfig: &Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ AdvertiseTicketExtension: true,
+ },
+ },
+ resumeSession: true,
+ shouldFail: true,
+ expectedError: ":ERROR_PARSING_EXTENSION:",
+ })
+
+ // Test that illegal extensions in TLS 1.3 are declined by the server if
+ // offered in ClientHello. The runner's server will fail if this occurs,
+ // so we exercise the offering path. (EMS and Renegotiation Info are
+ // implicit in every test.)
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "ChannelID-Declined-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ ChannelID: channelIDKey,
+ },
+ flags: []string{"-enable-channel-id"},
+ })
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "NPN-Server",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ NextProtos: []string{"bar"},
+ },
+ flags: []string{"-advertise-npn", "\x03foo\x03bar\x03baz"},
+ })
}
func addResumptionVersionTests() {
@@ -4636,17 +4917,21 @@ func addRenegotiationTests() {
})
// Renegotiation is forbidden in TLS 1.3.
+ //
+ // TODO(davidben): This test current asserts that we ignore
+ // HelloRequests, but we actually should hard reject them. Fix this
+ // test once we actually parse post-handshake messages.
testCases = append(testCases, testCase{
name: "Renegotiate-Client-TLS13",
config: Config{
MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ SendHelloRequestBeforeEveryAppDataRecord: true,
+ },
},
- renegotiate: 1,
flags: []string{
"-renegotiate-freely",
},
- shouldFail: true,
- expectedError: ":NO_RENEGOTIATION:",
})
// Stray HelloRequests during the handshake are forbidden in TLS 1.3.
@@ -4948,8 +5233,6 @@ func addSignatureAlgorithmTests() {
}
// Test that algorithm selection takes the key type into account.
- //
- // TODO(davidben): Test this in TLS 1.3.
testCases = append(testCases, testCase{
name: "ClientAuth-SignatureType",
config: Config{
@@ -4969,6 +5252,25 @@ func addSignatureAlgorithmTests() {
})
testCases = append(testCases, testCase{
+ name: "ClientAuth-SignatureType-TLS13",
+ config: Config{
+ ClientAuth: RequireAnyClientCert,
+ MaxVersion: VersionTLS13,
+ VerifySignatureAlgorithms: []signatureAlgorithm{
+ signatureECDSAWithP521AndSHA512,
+ signatureRSAPKCS1WithSHA384,
+ signatureRSAPSSWithSHA384,
+ signatureECDSAWithSHA1,
+ },
+ },
+ flags: []string{
+ "-cert-file", path.Join(*resourceDir, rsaCertificateFile),
+ "-key-file", path.Join(*resourceDir, rsaKeyFile),
+ },
+ expectedPeerSignatureAlgorithm: signatureRSAPSSWithSHA384,
+ })
+
+ testCases = append(testCases, testCase{
testType: serverTest,
name: "ServerAuth-SignatureType",
config: Config{
@@ -4983,9 +5285,23 @@ func addSignatureAlgorithmTests() {
expectedPeerSignatureAlgorithm: signatureRSAPKCS1WithSHA384,
})
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "ServerAuth-SignatureType-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
+ VerifySignatureAlgorithms: []signatureAlgorithm{
+ signatureECDSAWithP521AndSHA512,
+ signatureRSAPKCS1WithSHA384,
+ signatureRSAPSSWithSHA384,
+ signatureECDSAWithSHA1,
+ },
+ },
+ expectedPeerSignatureAlgorithm: signatureRSAPSSWithSHA384,
+ })
+
// Test that signature verification takes the key type into account.
- //
- // TODO(davidben): Test this in TLS 1.3.
testCases = append(testCases, testCase{
testType: serverTest,
name: "Verify-ClientAuth-SignatureType",
@@ -5007,6 +5323,26 @@ func addSignatureAlgorithmTests() {
})
testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "Verify-ClientAuth-SignatureType-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Certificates: []Certificate{rsaCertificate},
+ SignSignatureAlgorithms: []signatureAlgorithm{
+ signatureRSAPSSWithSHA256,
+ },
+ Bugs: ProtocolBugs{
+ SendSignatureAlgorithm: signatureECDSAWithP256AndSHA256,
+ },
+ },
+ flags: []string{
+ "-require-any-client-certificate",
+ },
+ shouldFail: true,
+ expectedError: ":WRONG_SIGNATURE_TYPE:",
+ })
+
+ testCases = append(testCases, testCase{
name: "Verify-ServerAuth-SignatureType",
config: Config{
MaxVersion: VersionTLS12,
@@ -5022,6 +5358,22 @@ func addSignatureAlgorithmTests() {
expectedError: ":WRONG_SIGNATURE_TYPE:",
})
+ testCases = append(testCases, testCase{
+ name: "Verify-ServerAuth-SignatureType-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
+ SignSignatureAlgorithms: []signatureAlgorithm{
+ signatureRSAPSSWithSHA256,
+ },
+ Bugs: ProtocolBugs{
+ SendSignatureAlgorithm: signatureECDSAWithP256AndSHA256,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":WRONG_SIGNATURE_TYPE:",
+ })
+
// Test that, if the list is missing, the peer falls back to SHA-1 in
// TLS 1.2, but not TLS 1.3.
testCases = append(testCases, testCase{
@@ -5137,8 +5489,6 @@ func addSignatureAlgorithmTests() {
// Test that the agreed upon digest respects the client preferences and
// the server digests.
- //
- // TODO(davidben): Add TLS 1.3 versions of these.
testCases = append(testCases, testCase{
name: "NoCommonAlgorithms-Digests",
config: Config{
@@ -5421,7 +5771,7 @@ func addDTLSRetransmitTests() {
// shim must send flight N again, testing that the shim implements DTLS
// retransmit on a timeout.
- // TODO(davidben): Add TLS 1.3 versions of these tests. There will
+ // TODO(davidben): Add DTLS 1.3 versions of these tests. There will
// likely be more epochs to cross and the final message's retransmit may
// be more complex.
@@ -5658,7 +6008,6 @@ func addCustomExtensionTests() {
expectedContents := "custom extension"
emptyString := ""
- // TODO(davidben): Add TLS 1.3 versions of these tests.
for _, isClient := range []bool{false, true} {
suffix := "Server"
flag := "-enable-server-custom-extension"
@@ -5681,6 +6030,18 @@ func addCustomExtensionTests() {
},
flags: []string{flag},
})
+ testCases = append(testCases, testCase{
+ testType: testType,
+ name: "CustomExtensions-" + suffix + "-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ CustomExtension: expectedContents,
+ ExpectedCustomExtension: &expectedContents,
+ },
+ },
+ flags: []string{flag},
+ })
// If the parse callback fails, the handshake should also fail.
testCases = append(testCases, testCase{
@@ -5697,6 +6058,20 @@ func addCustomExtensionTests() {
shouldFail: true,
expectedError: ":CUSTOM_EXTENSION_ERROR:",
})
+ testCases = append(testCases, testCase{
+ testType: testType,
+ name: "CustomExtensions-ParseError-" + suffix + "-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ CustomExtension: expectedContents + "foo",
+ ExpectedCustomExtension: &expectedContents,
+ },
+ },
+ flags: []string{flag},
+ shouldFail: true,
+ expectedError: ":CUSTOM_EXTENSION_ERROR:",
+ })
// If the add callback fails, the handshake should also fail.
testCases = append(testCases, testCase{
@@ -5713,6 +6088,20 @@ func addCustomExtensionTests() {
shouldFail: true,
expectedError: ":CUSTOM_EXTENSION_ERROR:",
})
+ testCases = append(testCases, testCase{
+ testType: testType,
+ name: "CustomExtensions-FailAdd-" + suffix + "-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ CustomExtension: expectedContents,
+ ExpectedCustomExtension: &expectedContents,
+ },
+ },
+ flags: []string{flag, "-custom-extension-fail-add"},
+ shouldFail: true,
+ expectedError: ":CUSTOM_EXTENSION_ERROR:",
+ })
// If the add callback returns zero, no extension should be
// added.
@@ -5734,6 +6123,18 @@ func addCustomExtensionTests() {
},
flags: []string{flag, "-custom-extension-skip"},
})
+ testCases = append(testCases, testCase{
+ testType: testType,
+ name: "CustomExtensions-Skip-" + suffix + "-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ CustomExtension: skipCustomExtension,
+ ExpectedCustomExtension: &emptyString,
+ },
+ },
+ flags: []string{flag, "-custom-extension-skip"},
+ })
}
// The custom extension add callback should not be called if the client
@@ -5750,6 +6151,18 @@ func addCustomExtensionTests() {
flags: []string{"-enable-server-custom-extension", "-custom-extension-fail-add"},
})
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "CustomExtensions-NotCalled-Server-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ ExpectedCustomExtension: &emptyString,
+ },
+ },
+ flags: []string{"-enable-server-custom-extension", "-custom-extension-fail-add"},
+ })
+
// Test an unknown extension from the server.
testCases = append(testCases, testCase{
testType: clientTest,
@@ -5763,6 +6176,18 @@ func addCustomExtensionTests() {
shouldFail: true,
expectedError: ":UNEXPECTED_EXTENSION:",
})
+ testCases = append(testCases, testCase{
+ testType: clientTest,
+ name: "UnknownExtension-Client-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ CustomExtension: expectedContents,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":UNEXPECTED_EXTENSION:",
+ })
}
func addRSAClientKeyExchangeTests() {
@@ -5797,7 +6222,6 @@ var testCurves = []struct {
}
func addCurveTests() {
- // TODO(davidben): Add a TLS 1.3 versions of these tests.
for _, curve := range testCurves {
testCases = append(testCases, testCase{
name: "CurveTest-Client-" + curve.name,
@@ -5809,6 +6233,15 @@ func addCurveTests() {
flags: []string{"-enable-all-curves"},
})
testCases = append(testCases, testCase{
+ name: "CurveTest-Client-" + curve.name + "-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
+ CurvePreferences: []CurveID{curve.id},
+ },
+ flags: []string{"-enable-all-curves"},
+ })
+ testCases = append(testCases, testCase{
testType: serverTest,
name: "CurveTest-Server-" + curve.name,
config: Config{
@@ -5818,6 +6251,16 @@ func addCurveTests() {
},
flags: []string{"-enable-all-curves"},
})
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "CurveTest-Server-" + curve.name + "-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
+ CurvePreferences: []CurveID{curve.id},
+ },
+ flags: []string{"-enable-all-curves"},
+ })
}
// The server must be tolerant to bogus curves.
@@ -5837,7 +6280,6 @@ func addCurveTests() {
testType: serverTest,
name: "NoSupportedCurves",
config: Config{
- // TODO(davidben): Add a TLS 1.3 version of this.
MaxVersion: VersionTLS12,
CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
Bugs: ProtocolBugs{
@@ -5847,6 +6289,19 @@ func addCurveTests() {
shouldFail: true,
expectedError: ":NO_SHARED_CIPHER:",
})
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "NoSupportedCurves-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
+ Bugs: ProtocolBugs{
+ NoSupportedCurves: true,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":NO_SHARED_CIPHER:",
+ })
// The server must fall back to another cipher when there are no
// supported curves.
@@ -5868,7 +6323,6 @@ func addCurveTests() {
testCases = append(testCases, testCase{
name: "BadECDHECurve",
config: Config{
- // TODO(davidben): Add a TLS 1.3 version of this.
MaxVersion: VersionTLS12,
CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
Bugs: ProtocolBugs{
@@ -5878,11 +6332,23 @@ func addCurveTests() {
shouldFail: true,
expectedError: ":WRONG_CURVE:",
})
+ testCases = append(testCases, testCase{
+ name: "BadECDHECurve-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
+ Bugs: ProtocolBugs{
+ SendCurve: bogusCurve,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":WRONG_CURVE:",
+ })
testCases = append(testCases, testCase{
name: "UnsupportedCurve",
config: Config{
- // TODO(davidben): Add a TLS 1.3 version of this.
+ // TODO(davidben): Add a TLS 1.3 version of this test.
MaxVersion: VersionTLS12,
CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
CurvePreferences: []CurveID{CurveP256},
@@ -5899,7 +6365,6 @@ func addCurveTests() {
testCases = append(testCases, testCase{
name: "InvalidECDHPoint-Client",
config: Config{
- // TODO(davidben): Add a TLS 1.3 version of this test.
MaxVersion: VersionTLS12,
CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
CurvePreferences: []CurveID{CurveP256},
@@ -5911,10 +6376,22 @@ func addCurveTests() {
expectedError: ":INVALID_ENCODING:",
})
testCases = append(testCases, testCase{
+ name: "InvalidECDHPoint-Client-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
+ CurvePreferences: []CurveID{CurveP256},
+ Bugs: ProtocolBugs{
+ InvalidECDHPoint: true,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":INVALID_ENCODING:",
+ })
+ testCases = append(testCases, testCase{
testType: serverTest,
name: "InvalidECDHPoint-Server",
config: Config{
- // TODO(davidben): Add a TLS 1.3 version of this test.
MaxVersion: VersionTLS12,
CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
CurvePreferences: []CurveID{CurveP256},
@@ -5925,6 +6402,20 @@ func addCurveTests() {
shouldFail: true,
expectedError: ":INVALID_ENCODING:",
})
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "InvalidECDHPoint-Server-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
+ CurvePreferences: []CurveID{CurveP256},
+ Bugs: ProtocolBugs{
+ InvalidECDHPoint: true,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":INVALID_ENCODING:",
+ })
}
func addCECPQ1Tests() {
@@ -6016,9 +6507,6 @@ func addKeyExchangeInfoTests() {
flags: []string{"-expect-dhe-group-size", "2048"},
})
- // TODO(davidben): Add TLS 1.3 versions of these tests once the
- // handshake is separate.
-
testCases = append(testCases, testCase{
name: "KeyExchangeInfo-ECDHE-Client",
config: Config{
@@ -6242,6 +6730,32 @@ func addChangeCipherSpecTests() {
expectedError: ":BUFFERED_MESSAGES_ON_CIPHER_CHANGE:",
})
+ // Test synchronization between encryption changes and the handshake in
+ // TLS 1.3, where ChangeCipherSpec is implicit.
+ testCases = append(testCases, testCase{
+ name: "PartialEncryptedExtensionsWithServerHello",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ PartialEncryptedExtensionsWithServerHello: true,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":BUFFERED_MESSAGES_ON_CIPHER_CHANGE:",
+ })
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "PartialClientFinishedWithClientHello",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ PartialClientFinishedWithClientHello: true,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":BUFFERED_MESSAGES_ON_CIPHER_CHANGE:",
+ })
+
// Test that early ChangeCipherSpecs are handled correctly.
testCases = append(testCases, testCase{
testType: serverTest,
@@ -6589,6 +7103,238 @@ func addWrongMessageTypeTests() {
}
}
+func addTLS13WrongMessageTypeTests() {
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "WrongMessageType-TLS13-ClientHello",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ SendWrongMessageType: typeClientHello,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":UNEXPECTED_MESSAGE:",
+ expectedLocalError: "remote error: unexpected message",
+ })
+
+ testCases = append(testCases, testCase{
+ name: "WrongMessageType-TLS13-ServerHello",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ SendWrongMessageType: typeServerHello,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":UNEXPECTED_MESSAGE:",
+ // The alert comes in with the wrong encryption.
+ expectedLocalError: "local error: bad record MAC",
+ })
+
+ testCases = append(testCases, testCase{
+ name: "WrongMessageType-TLS13-EncryptedExtensions",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ SendWrongMessageType: typeEncryptedExtensions,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":UNEXPECTED_MESSAGE:",
+ expectedLocalError: "remote error: unexpected message",
+ })
+
+ testCases = append(testCases, testCase{
+ name: "WrongMessageType-TLS13-CertificateRequest",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ ClientAuth: RequireAnyClientCert,
+ Bugs: ProtocolBugs{
+ SendWrongMessageType: typeCertificateRequest,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":UNEXPECTED_MESSAGE:",
+ expectedLocalError: "remote error: unexpected message",
+ })
+
+ testCases = append(testCases, testCase{
+ name: "WrongMessageType-TLS13-ServerCertificate",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ SendWrongMessageType: typeCertificate,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":UNEXPECTED_MESSAGE:",
+ expectedLocalError: "remote error: unexpected message",
+ })
+
+ testCases = append(testCases, testCase{
+ name: "WrongMessageType-TLS13-ServerCertificateVerify",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ SendWrongMessageType: typeCertificateVerify,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":UNEXPECTED_MESSAGE:",
+ expectedLocalError: "remote error: unexpected message",
+ })
+
+ testCases = append(testCases, testCase{
+ name: "WrongMessageType-TLS13-ServerFinished",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ SendWrongMessageType: typeFinished,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":UNEXPECTED_MESSAGE:",
+ expectedLocalError: "remote error: unexpected message",
+ })
+
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "WrongMessageType-TLS13-ClientCertificate",
+ config: Config{
+ Certificates: []Certificate{rsaCertificate},
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ SendWrongMessageType: typeCertificate,
+ },
+ },
+ flags: []string{"-require-any-client-certificate"},
+ shouldFail: true,
+ expectedError: ":UNEXPECTED_MESSAGE:",
+ expectedLocalError: "remote error: unexpected message",
+ })
+
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "WrongMessageType-TLS13-ClientCertificateVerify",
+ config: Config{
+ Certificates: []Certificate{rsaCertificate},
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ SendWrongMessageType: typeCertificateVerify,
+ },
+ },
+ flags: []string{"-require-any-client-certificate"},
+ shouldFail: true,
+ expectedError: ":UNEXPECTED_MESSAGE:",
+ expectedLocalError: "remote error: unexpected message",
+ })
+
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "WrongMessageType-TLS13-ClientFinished",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ SendWrongMessageType: typeFinished,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":UNEXPECTED_MESSAGE:",
+ expectedLocalError: "remote error: unexpected message",
+ })
+}
+
+func addTLS13HandshakeTests() {
+ testCases = append(testCases, testCase{
+ testType: clientTest,
+ name: "MissingKeyShare-Client",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ MissingKeyShare: true,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":MISSING_KEY_SHARE:",
+ })
+
+ testCases = append(testCases, testCase{
+ name: "MissingKeyShare-Server",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ MissingKeyShare: true,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":MISSING_KEY_SHARE:",
+ })
+
+ testCases = append(testCases, testCase{
+ testType: clientTest,
+ name: "ClientHelloMissingKeyShare",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ MissingKeyShare: true,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":MISSING_KEY_SHARE:",
+ })
+
+ testCases = append(testCases, testCase{
+ testType: clientTest,
+ name: "MissingKeyShare",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ MissingKeyShare: true,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":MISSING_KEY_SHARE:",
+ })
+
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "DuplicateKeyShares",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ DuplicateKeyShares: true,
+ },
+ },
+ })
+
+ testCases = append(testCases, testCase{
+ testType: clientTest,
+ name: "EmptyEncryptedExtensions",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ EmptyEncryptedExtensions: true,
+ },
+ },
+ shouldFail: true,
+ expectedLocalError: "remote error: error decoding message",
+ })
+
+ testCases = append(testCases, testCase{
+ testType: clientTest,
+ name: "EncryptedExtensionsWithKeyShare",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ EncryptedExtensionsWithKeyShare: true,
+ },
+ },
+ shouldFail: true,
+ expectedLocalError: "remote error: unsupported extension",
+ })
+}
+
func worker(statusChan chan statusMsg, c chan *testCase, shimPath string, wg *sync.WaitGroup) {
defer wg.Done()
@@ -6694,6 +7440,8 @@ func main() {
addAllStateMachineCoverageTests()
addChangeCipherSpecTests()
addWrongMessageTypeTests()
+ addTLS13WrongMessageTypeTests()
+ addTLS13HandshakeTests()
var wg sync.WaitGroup
diff --git a/ssl/test/test_config.cc b/ssl/test/test_config.cc
index 24a4646a..b1a07924 100644
--- a/ssl/test/test_config.cc
+++ b/ssl/test/test_config.cc
@@ -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 },
diff --git a/ssl/test/test_config.h b/ssl/test/test_config.h
index 4ee717ee..73bdc6eb 100644
--- a/ssl/test/test_config.h
+++ b/ssl/test/test_config.h
@@ -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;
diff --git a/ssl/tls13_both.c b/ssl/tls13_both.c
new file mode 100644
index 00000000..4e9feaa5
--- /dev/null
+++ b/ssl/tls13_both.c
@@ -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;
+}
diff --git a/ssl/tls13_client.c b/ssl/tls13_client.c
new file mode 100644
index 00000000..cf8b390e
--- /dev/null
+++ b/ssl/tls13_client.c
@@ -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;
+}
diff --git a/ssl/tls13_enc.c b/ssl/tls13_enc.c
new file mode 100644
index 00000000..ea88675c
--- /dev/null
+++ b/ssl/tls13_enc.c
@@ -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);
+}
diff --git a/ssl/tls13_server.c b/ssl/tls13_server.c
new file mode 100644
index 00000000..ce65abfb
--- /dev/null
+++ b/ssl/tls13_server.c
@@ -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;
+}
diff --git a/ssl/tls_method.c b/ssl/tls_method.c
index ccf4f988..39daa5ad 100644
--- a/ssl/tls_method.c
+++ b/ssl/tls_method.c
@@ -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));