Add experiment without client CCS and fix session ID bug. Change-Id: Id6cf63caf5a00d4d4ca66a5c7530c48c2d9ed91f Reviewed-on: https://boringssl-review.googlesource.com/20164 Reviewed-by: Steven Valdez <svaldez@google.com> Commit-Queue: Steven Valdez <svaldez@google.com> CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h index c81ce6a..36f61a6 100644 --- a/include/openssl/ssl.h +++ b/include/openssl/ssl.h
@@ -591,6 +591,7 @@ #define TLS1_3_DRAFT_VERSION 0x7f12 #define TLS1_3_EXPERIMENT_VERSION 0x7e01 #define TLS1_3_EXPERIMENT2_VERSION 0x7e02 +#define TLS1_3_EXPERIMENT3_VERSION 0x7e03 #define TLS1_3_RECORD_TYPE_EXPERIMENT_VERSION 0x7a12 // SSL_CTX_set_min_proto_version sets the minimum protocol version for |ctx| to @@ -3179,6 +3180,7 @@ tls13_record_type_experiment = 2, tls13_no_session_id_experiment = 3, tls13_experiment2 = 4, + tls13_experiment3 = 5, }; // SSL_CTX_set_tls13_variant sets which variant of TLS 1.3 we negotiate. On the
diff --git a/ssl/dtls_record.cc b/ssl/dtls_record.cc index dbc8fa2..5009f04 100644 --- a/ssl/dtls_record.cc +++ b/ssl/dtls_record.cc
@@ -192,14 +192,27 @@ !CBS_get_u16(&cbs, &version) || !CBS_copy_bytes(&cbs, sequence, 8) || !CBS_get_u16_length_prefixed(&cbs, &body) || - (ssl->s3->have_version && version != ssl->version) || - (version >> 8) != DTLS1_VERSION_MAJOR || CBS_len(&body) > SSL3_RT_MAX_ENCRYPTED_LENGTH) { // The record header was incomplete or malformed. Drop the entire packet. *out_consumed = in_len; return ssl_open_record_discard; } + bool version_ok; + if (ssl->s3->aead_read_ctx->is_null_cipher()) { + // Only check the first byte. Enforcing beyond that can prevent decoding + // version negotiation failure alerts. + version_ok = (version >> 8) == DTLS1_VERSION_MAJOR; + } else { + version_ok = version == ssl->s3->aead_read_ctx->RecordVersion(); + } + + if (!version_ok) { + // The record header was incomplete or malformed. Drop the entire packet. + *out_consumed = in_len; + return ssl_open_record_discard; + } + ssl_do_msg_callback(ssl, 0 /* read */, SSL3_RT_HEADER, in, DTLS1_RT_HEADER_LENGTH); @@ -300,9 +313,9 @@ out[0] = type; - uint16_t wire_version = ssl->s3->have_version ? ssl->version : DTLS1_VERSION; - out[1] = wire_version >> 8; - out[2] = wire_version & 0xff; + uint16_t record_version = ssl->s3->aead_write_ctx->RecordVersion(); + out[1] = record_version >> 8; + out[2] = record_version & 0xff; out[3] = epoch >> 8; out[4] = epoch & 0xff; @@ -310,7 +323,7 @@ size_t ciphertext_len; if (!aead->Seal(out + DTLS1_RT_HEADER_LENGTH, &ciphertext_len, - max_out - DTLS1_RT_HEADER_LENGTH, type, wire_version, + max_out - DTLS1_RT_HEADER_LENGTH, type, record_version, &out[3] /* seq */, in, in_len) || !ssl_record_sequence_update(&seq[2], 6)) { return 0;
diff --git a/ssl/handshake_client.cc b/ssl/handshake_client.cc index 52d2e94..18dd58f 100644 --- a/ssl/handshake_client.cc +++ b/ssl/handshake_client.cc
@@ -316,7 +316,7 @@ // In TLS 1.3 experimental encodings, send a fake placeholder session ID // when we do not otherwise have one to send. if (hs->max_version >= TLS1_3_VERSION && - ssl->tls13_variant == tls13_experiment && + ssl_is_resumption_variant(ssl->tls13_variant) && !CBB_add_bytes(&child, hs->session_id, hs->session_id_len)) { return 0; } @@ -438,6 +438,12 @@ return ssl_hs_error; } + // SSL 3.0 ClientHellos should use SSL 3.0 not TLS 1.0, for the record-layer + // version. + if (hs->max_version == SSL3_VERSION) { + ssl->s3->aead_write_ctx->SetVersionIfNullCipher(SSL3_VERSION); + } + // Always advertise the ClientHello version from the original maximum version, // even on renegotiation. The static RSA key exchange uses this field, and // some servers fail when it changes across handshakes. @@ -468,7 +474,7 @@ // Initialize a random session ID for the experimental TLS 1.3 variant // requiring a session id. - if (ssl->tls13_variant == tls13_experiment) { + if (ssl_is_resumption_variant(ssl->tls13_variant)) { hs->session_id_len = sizeof(hs->session_id); if (!RAND_bytes(hs->session_id, hs->session_id_len)) { return ssl_hs_error; @@ -584,6 +590,7 @@ // At this point, the connection's version is known and ssl->version is // fixed. Begin enforcing the record-layer version. ssl->s3->have_version = true; + ssl->s3->aead_write_ctx->SetVersionIfNullCipher(ssl->version); } else if (server_version != ssl->version) { OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_SSL_VERSION); ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_PROTOCOL_VERSION);
diff --git a/ssl/handshake_server.cc b/ssl/handshake_server.cc index 10e618d..cd99ec9 100644 --- a/ssl/handshake_server.cc +++ b/ssl/handshake_server.cc
@@ -276,6 +276,7 @@ // At this point, the connection's version is known and |ssl->version| is // fixed. Begin enforcing the record-layer version. ssl->s3->have_version = true; + ssl->s3->aead_write_ctx->SetVersionIfNullCipher(ssl->version); // Handle FALLBACK_SCSV. if (ssl_client_cipher_list_contains_cipher(client_hello,
diff --git a/ssl/internal.h b/ssl/internal.h index ddc91c7..2fb3614 100644 --- a/ssl/internal.h +++ b/ssl/internal.h
@@ -286,6 +286,20 @@ // TLS 1.3 resumption experiment. bool ssl_is_resumption_experiment(uint16_t version); +// ssl_is_resumption_variant returns whether the version corresponds to a +// TLS 1.3 resumption experiment. +bool ssl_is_resumption_variant(enum tls13_variant_t variant); + +// ssl_is_resumption_client_ccs_experiment returns whether the version +// corresponds to a TLS 1.3 resumption experiment that sends a client CCS. +bool ssl_is_resumption_client_ccs_experiment(uint16_t version); + +// ssl_is_resumption_record_version_experiment returns whether the version +// corresponds to a TLS 1.3 resumption experiment that modifies the record +// version. +bool ssl_is_resumption_record_version_experiment(uint16_t version); + + // Cipher suites. // Bits for |algorithm_mkey| (key exchange algorithm). @@ -469,7 +483,7 @@ // encrypt an SSL connection. class SSLAEADContext { public: - SSLAEADContext(uint16_t version, const SSL_CIPHER *cipher); + SSLAEADContext(uint16_t version, bool is_dtls, const SSL_CIPHER *cipher); ~SSLAEADContext(); static constexpr bool kAllowUniquePtr = true; @@ -477,7 +491,7 @@ SSLAEADContext &operator=(const SSLAEADContext &&) = delete; // CreateNullCipher creates an |SSLAEADContext| for the null cipher. - static UniquePtr<SSLAEADContext> CreateNullCipher(); + static UniquePtr<SSLAEADContext> CreateNullCipher(bool is_dtls); // Create creates an |SSLAEADContext| using the supplied key material. It // returns nullptr on error. Only one of |Open| or |Seal| may be used with the @@ -489,7 +503,20 @@ const uint8_t *mac_key, size_t mac_key_len, const uint8_t *fixed_iv, size_t fixed_iv_len); - uint16_t version() const { return version_; } + // SetVersionIfNullCipher sets the version the SSLAEADContext for the null + // cipher, to make version-specific determinations in the record layer prior + // to a cipher being selected. + void SetVersionIfNullCipher(uint16_t version); + + // ProtocolVersion returns the protocol version associated with this + // SSLAEADContext. It can only be called once |version_| has been set to a + // valid value. + uint16_t ProtocolVersion() const; + + // RecordVersion returns the record version that should be used with this + // SSLAEADContext for record construction and crypto. + uint16_t RecordVersion() const; + const SSL_CIPHER *cipher() const { return cipher_; } // is_null_cipher returns true if this is the null cipher. @@ -512,7 +539,7 @@ // success, it sets |*out| to the plaintext in |in| and returns true. // Otherwise, it returns false. The output will always be |ExplicitNonceLen| // bytes ahead of |in|. - bool Open(CBS *out, uint8_t type, uint16_t wire_version, + bool Open(CBS *out, uint8_t type, uint16_t record_version, const uint8_t seqnum[8], uint8_t *in, size_t in_len); // Seal encrypts and authenticates |in_len| bytes from |in| and writes the @@ -520,7 +547,7 @@ // // If |in| and |out| alias then |out| + |ExplicitNonceLen| must be == |in|. bool Seal(uint8_t *out, size_t *out_len, size_t max_out, uint8_t type, - uint16_t wire_version, const uint8_t seqnum[8], const uint8_t *in, + uint16_t record_version, const uint8_t seqnum[8], const uint8_t *in, size_t in_len); // SealScatter encrypts and authenticates |in_len| bytes from |in| and splits @@ -539,17 +566,18 @@ // If |in| and |out| alias then |out| must be == |in|. Other arguments may not // alias anything. bool SealScatter(uint8_t *out_prefix, uint8_t *out, uint8_t *out_suffix, - uint8_t type, uint16_t wire_version, const uint8_t seqnum[8], - const uint8_t *in, size_t in_len, const uint8_t *extra_in, - size_t extra_in_len); + uint8_t type, uint16_t record_version, + const uint8_t seqnum[8], const uint8_t *in, size_t in_len, + const uint8_t *extra_in, size_t extra_in_len); bool GetIV(const uint8_t **out_iv, size_t *out_iv_len) const; private: // GetAdditionalData writes the additional data into |out| and returns the // number of bytes written. - size_t GetAdditionalData(uint8_t out[13], uint8_t type, uint16_t wire_version, - const uint8_t seqnum[8], size_t plaintext_len); + size_t GetAdditionalData(uint8_t out[13], uint8_t type, + uint16_t record_version, const uint8_t seqnum[8], + size_t plaintext_len); const SSL_CIPHER *cipher_; ScopedEVP_AEAD_CTX ctx_; @@ -557,8 +585,10 @@ // records. uint8_t fixed_nonce_[12]; uint8_t fixed_nonce_len_ = 0, variable_nonce_len_ = 0; - // version_ is the protocol version that should be used with this AEAD. + // version_ is the wire version that should be used with this AEAD. uint16_t version_; + // is_dtls_ is whether DTLS is being used with this AEAD. + bool is_dtls_; // variable_nonce_included_in_record_ is true if the variable nonce // for a record is included as a prefix before the ciphertext. bool variable_nonce_included_in_record_ : 1;
diff --git a/ssl/s3_lib.cc b/ssl/s3_lib.cc index dcf9559..3df8e1b 100644 --- a/ssl/s3_lib.cc +++ b/ssl/s3_lib.cc
@@ -165,8 +165,10 @@ namespace bssl { int ssl3_new(SSL *ssl) { - UniquePtr<SSLAEADContext> aead_read_ctx = SSLAEADContext::CreateNullCipher(); - UniquePtr<SSLAEADContext> aead_write_ctx = SSLAEADContext::CreateNullCipher(); + UniquePtr<SSLAEADContext> aead_read_ctx = + SSLAEADContext::CreateNullCipher(SSL_is_dtls(ssl)); + UniquePtr<SSLAEADContext> aead_write_ctx = + SSLAEADContext::CreateNullCipher(SSL_is_dtls(ssl)); if (!aead_read_ctx || !aead_write_ctx) { return 0; }
diff --git a/ssl/ssl_aead_ctx.cc b/ssl/ssl_aead_ctx.cc index 69129af..d03a4a0 100644 --- a/ssl/ssl_aead_ctx.cc +++ b/ssl/ssl_aead_ctx.cc
@@ -33,10 +33,11 @@ namespace bssl { -SSLAEADContext::SSLAEADContext(uint16_t version_arg, +SSLAEADContext::SSLAEADContext(uint16_t version_arg, bool is_dtls_arg, const SSL_CIPHER *cipher_arg) : cipher_(cipher_arg), version_(version_arg), + is_dtls_(is_dtls_arg), variable_nonce_included_in_record_(false), random_variable_nonce_(false), omit_length_in_ad_(false), @@ -48,8 +49,9 @@ SSLAEADContext::~SSLAEADContext() {} -UniquePtr<SSLAEADContext> SSLAEADContext::CreateNullCipher() { - return MakeUnique<SSLAEADContext>(0 /* version */, nullptr /* cipher */); +UniquePtr<SSLAEADContext> SSLAEADContext::CreateNullCipher(bool is_dtls) { + return MakeUnique<SSLAEADContext>(0 /* version */, is_dtls, + nullptr /* cipher */); } UniquePtr<SSLAEADContext> SSLAEADContext::Create( @@ -57,10 +59,13 @@ const SSL_CIPHER *cipher, const uint8_t *enc_key, size_t enc_key_len, const uint8_t *mac_key, size_t mac_key_len, const uint8_t *fixed_iv, size_t fixed_iv_len) { + const EVP_AEAD *aead; + uint16_t protocol_version; size_t expected_mac_key_len, expected_fixed_iv_len; - if (!ssl_cipher_get_evp_aead(&aead, &expected_mac_key_len, - &expected_fixed_iv_len, cipher, version, + if (!ssl_protocol_version_from_wire(&protocol_version, version) || + !ssl_cipher_get_evp_aead(&aead, &expected_mac_key_len, + &expected_fixed_iv_len, cipher, protocol_version, is_dtls) || // Ensure the caller returned correct key sizes. expected_fixed_iv_len != fixed_iv_len || @@ -87,12 +92,14 @@ } UniquePtr<SSLAEADContext> aead_ctx = - MakeUnique<SSLAEADContext>(version, cipher); + MakeUnique<SSLAEADContext>(version, is_dtls, cipher); if (!aead_ctx) { OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); return nullptr; } + assert(aead_ctx->ProtocolVersion() == protocol_version); + if (!EVP_AEAD_CTX_init_with_direction( aead_ctx->ctx_.get(), aead, enc_key, enc_key_len, EVP_AEAD_DEFAULT_TAG_LENGTH, direction)) { @@ -125,7 +132,7 @@ // The TLS 1.3 construction XORs the fixed nonce into the sequence number // and omits the additional data. - if (version >= TLS1_3_VERSION) { + if (protocol_version >= TLS1_3_VERSION) { aead_ctx->xor_fixed_nonce_ = true; aead_ctx->variable_nonce_len_ = 8; aead_ctx->variable_nonce_included_in_record_ = false; @@ -133,16 +140,47 @@ assert(fixed_iv_len >= aead_ctx->variable_nonce_len_); } } else { - assert(version < TLS1_3_VERSION); + assert(protocol_version < TLS1_3_VERSION); aead_ctx->variable_nonce_included_in_record_ = true; aead_ctx->random_variable_nonce_ = true; aead_ctx->omit_length_in_ad_ = true; - aead_ctx->omit_version_in_ad_ = (version == SSL3_VERSION); + aead_ctx->omit_version_in_ad_ = (protocol_version == SSL3_VERSION); } return aead_ctx; } +void SSLAEADContext::SetVersionIfNullCipher(uint16_t version) { + if (is_null_cipher()) { + version_ = version; + } +} + +uint16_t SSLAEADContext::ProtocolVersion() const { + uint16_t protocol_version; + if(!ssl_protocol_version_from_wire(&protocol_version, version_)) { + assert(false); + return 0; + } + return protocol_version; +} + +uint16_t SSLAEADContext::RecordVersion() const { + if (version_ == 0) { + assert(is_null_cipher()); + return is_dtls_ ? DTLS1_VERSION : TLS1_VERSION; + } + + if (ProtocolVersion() <= TLS1_2_VERSION) { + return version_; + } + + if (ssl_is_resumption_record_version_experiment(version_)) { + return TLS1_2_VERSION; + } + return TLS1_VERSION; +} + size_t SSLAEADContext::ExplicitNonceLen() const { if (!FUZZER_MODE && variable_nonce_included_in_record_) { return variable_nonce_len_; @@ -168,7 +206,7 @@ } size_t SSLAEADContext::GetAdditionalData(uint8_t out[13], uint8_t type, - uint16_t wire_version, + uint16_t record_version, const uint8_t seqnum[8], size_t plaintext_len) { if (omit_ad_) { @@ -179,8 +217,8 @@ size_t len = 8; out[len++] = type; if (!omit_version_in_ad_) { - out[len++] = static_cast<uint8_t>((wire_version >> 8)); - out[len++] = static_cast<uint8_t>(wire_version); + out[len++] = static_cast<uint8_t>((record_version >> 8)); + out[len++] = static_cast<uint8_t>(record_version); } if (!omit_length_in_ad_) { out[len++] = static_cast<uint8_t>((plaintext_len >> 8)); @@ -189,7 +227,7 @@ return len; } -bool SSLAEADContext::Open(CBS *out, uint8_t type, uint16_t wire_version, +bool SSLAEADContext::Open(CBS *out, uint8_t type, uint16_t record_version, const uint8_t seqnum[8], uint8_t *in, size_t in_len) { if (is_null_cipher() || FUZZER_MODE) { // Handle the initial NULL cipher. @@ -211,7 +249,7 @@ } uint8_t ad[13]; size_t ad_len = - GetAdditionalData(ad, type, wire_version, seqnum, plaintext_len); + GetAdditionalData(ad, type, record_version, seqnum, plaintext_len); // Assemble the nonce. uint8_t nonce[EVP_AEAD_MAX_NONCE_LENGTH]; @@ -262,9 +300,10 @@ bool SSLAEADContext::SealScatter(uint8_t *out_prefix, uint8_t *out, uint8_t *out_suffix, uint8_t type, - uint16_t wire_version, const uint8_t seqnum[8], - const uint8_t *in, size_t in_len, - const uint8_t *extra_in, size_t extra_in_len) { + uint16_t record_version, + const uint8_t seqnum[8], const uint8_t *in, + size_t in_len, const uint8_t *extra_in, + size_t extra_in_len) { const size_t prefix_len = ExplicitNonceLen(); size_t suffix_len; if (!SuffixLen(&suffix_len, in_len, extra_in_len)) { @@ -286,7 +325,7 @@ } uint8_t ad[13]; - size_t ad_len = GetAdditionalData(ad, type, wire_version, seqnum, in_len); + size_t ad_len = GetAdditionalData(ad, type, record_version, seqnum, in_len); // Assemble the nonce. uint8_t nonce[EVP_AEAD_MAX_NONCE_LENGTH]; @@ -343,7 +382,7 @@ } bool SSLAEADContext::Seal(uint8_t *out, size_t *out_len, size_t max_out_len, - uint8_t type, uint16_t wire_version, + uint8_t type, uint16_t record_version, const uint8_t seqnum[8], const uint8_t *in, size_t in_len) { const size_t prefix_len = ExplicitNonceLen(); @@ -363,7 +402,7 @@ } if (!SealScatter(out, out + prefix_len, out + prefix_len + in_len, type, - wire_version, seqnum, in, in_len, 0, 0)) { + record_version, seqnum, in, in_len, 0, 0)) { return false; } *out_len = prefix_len + in_len + suffix_len;
diff --git a/ssl/ssl_versions.cc b/ssl/ssl_versions.cc index f6dea8c..560d0cf 100644 --- a/ssl/ssl_versions.cc +++ b/ssl/ssl_versions.cc
@@ -37,6 +37,7 @@ case TLS1_3_DRAFT_VERSION: case TLS1_3_EXPERIMENT_VERSION: case TLS1_3_EXPERIMENT2_VERSION: + case TLS1_3_EXPERIMENT3_VERSION: case TLS1_3_RECORD_TYPE_EXPERIMENT_VERSION: *out = TLS1_3_VERSION; return 1; @@ -59,6 +60,7 @@ // decreasing preference. static const uint16_t kTLSVersions[] = { + TLS1_3_EXPERIMENT3_VERSION, TLS1_3_EXPERIMENT2_VERSION, TLS1_3_EXPERIMENT_VERSION, TLS1_3_RECORD_TYPE_EXPERIMENT_VERSION, @@ -106,6 +108,7 @@ if (version == TLS1_3_DRAFT_VERSION || version == TLS1_3_EXPERIMENT_VERSION || version == TLS1_3_EXPERIMENT2_VERSION || + version == TLS1_3_EXPERIMENT3_VERSION || version == TLS1_3_RECORD_TYPE_EXPERIMENT_VERSION) { OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_SSL_VERSION); return 0; @@ -233,6 +236,7 @@ case TLS1_3_DRAFT_VERSION: case TLS1_3_EXPERIMENT_VERSION: case TLS1_3_EXPERIMENT2_VERSION: + case TLS1_3_EXPERIMENT3_VERSION: case TLS1_3_RECORD_TYPE_EXPERIMENT_VERSION: return "TLSv1.3"; @@ -280,6 +284,7 @@ if (ssl->tls13_variant == tls13_default && (version == TLS1_3_EXPERIMENT_VERSION || version == TLS1_3_EXPERIMENT2_VERSION || + version == TLS1_3_EXPERIMENT3_VERSION || version == TLS1_3_RECORD_TYPE_EXPERIMENT_VERSION)) { return 0; } @@ -289,6 +294,8 @@ version == TLS1_3_EXPERIMENT_VERSION) || (ssl->tls13_variant != tls13_experiment2 && version == TLS1_3_EXPERIMENT2_VERSION) || + (ssl->tls13_variant != tls13_experiment3 && + version == TLS1_3_EXPERIMENT3_VERSION) || (ssl->tls13_variant != tls13_record_type_experiment && version == TLS1_3_RECORD_TYPE_EXPERIMENT_VERSION) || (ssl->tls13_variant != tls13_default && @@ -350,9 +357,25 @@ bool ssl_is_resumption_experiment(uint16_t version) { return version == TLS1_3_EXPERIMENT_VERSION || + version == TLS1_3_EXPERIMENT2_VERSION || + version == TLS1_3_EXPERIMENT3_VERSION; +} + +bool ssl_is_resumption_variant(enum tls13_variant_t variant) { + return variant == tls13_experiment || variant == tls13_experiment2 || + variant == tls13_experiment3; +} + +bool ssl_is_resumption_client_ccs_experiment(uint16_t version) { + return version == TLS1_3_EXPERIMENT_VERSION || version == TLS1_3_EXPERIMENT2_VERSION; } +bool ssl_is_resumption_record_version_experiment(uint16_t version) { + return version == TLS1_3_EXPERIMENT2_VERSION || + version == TLS1_3_EXPERIMENT3_VERSION; +} + } // namespace bssl using namespace bssl; @@ -379,6 +402,7 @@ if (ret == TLS1_3_DRAFT_VERSION || ret == TLS1_3_EXPERIMENT_VERSION || ret == TLS1_3_EXPERIMENT2_VERSION || + ret == TLS1_3_EXPERIMENT3_VERSION || ret == TLS1_3_RECORD_TYPE_EXPERIMENT_VERSION) { return TLS1_3_VERSION; }
diff --git a/ssl/t1_enc.cc b/ssl/t1_enc.cc index f917ed7..0283c6e 100644 --- a/ssl/t1_enc.cc +++ b/ssl/t1_enc.cc
@@ -422,7 +422,7 @@ } UniquePtr<SSLAEADContext> aead_ctx = SSLAEADContext::Create( - is_read ? evp_aead_open : evp_aead_seal, ssl3_protocol_version(ssl), + is_read ? evp_aead_open : evp_aead_seal, ssl->version, SSL_is_dtls(ssl), hs->new_cipher, key, key_len, mac_secret, mac_secret_len, iv, iv_len); if (!aead_ctx) {
diff --git a/ssl/test/runner/common.go b/ssl/test/runner/common.go index 61540bb..19edb7f 100644 --- a/ssl/test/runner/common.go +++ b/ssl/test/runner/common.go
@@ -36,6 +36,7 @@ tls13DraftVersion = 0x7f12 tls13ExperimentVersion = 0x7e01 tls13Experiment2Version = 0x7e02 + tls13Experiment3Version = 0x7e03 tls13RecordTypeExperimentVersion = 0x7a12 ) @@ -45,10 +46,12 @@ TLS13RecordTypeExperiment = 2 TLS13NoSessionIDExperiment = 3 TLS13Experiment2 = 4 + TLS13Experiment3 = 5 ) var allTLSWireVersions = []uint16{ tls13DraftVersion, + tls13Experiment3Version, tls13Experiment2Version, tls13ExperimentVersion, tls13RecordTypeExperimentVersion, @@ -279,6 +282,7 @@ sessionId []uint8 // Session ID supplied by the server. nil if the session has a ticket. sessionTicket []uint8 // Encrypted ticket used for session resumption with server vers uint16 // SSL/TLS version negotiated for the session + wireVersion uint16 // Wire SSL/TLS version negotiated for the session cipherSuite uint16 // Ciphersuite negotiated for the session masterSecret []byte // MasterSecret generated by client on a full handshake handshakeHash []byte // Handshake hash for Channel ID purposes. @@ -1559,7 +1563,7 @@ switch vers { case VersionSSL30, VersionTLS10, VersionTLS11, VersionTLS12: return vers, true - case tls13DraftVersion, tls13ExperimentVersion, tls13Experiment2Version, tls13RecordTypeExperimentVersion: + case tls13DraftVersion, tls13ExperimentVersion, tls13Experiment2Version, tls13Experiment3Version, tls13RecordTypeExperimentVersion: return VersionTLS13, true } } @@ -1568,15 +1572,24 @@ } func isResumptionExperiment(vers uint16) bool { + return vers == tls13ExperimentVersion || vers == tls13Experiment2Version || vers == tls13Experiment3Version +} + +func isResumptionClientCCSExperiment(vers uint16) bool { return vers == tls13ExperimentVersion || vers == tls13Experiment2Version } +func isResumptionRecordVersionExperiment(vers uint16) bool { + return vers == tls13Experiment2Version || vers == tls13Experiment3Version +} + // isSupportedVersion checks if the specified wire version is acceptable. If so, // it returns true and the corresponding protocol version. Otherwise, it returns // false. func (c *Config) isSupportedVersion(wireVers uint16, isDTLS bool) (uint16, bool) { if (c.TLS13Variant != TLS13Experiment && c.TLS13Variant != TLS13NoSessionIDExperiment && wireVers == tls13ExperimentVersion) || (c.TLS13Variant != TLS13Experiment2 && wireVers == tls13Experiment2Version) || + (c.TLS13Variant != TLS13Experiment3 && wireVers == tls13Experiment3Version) || (c.TLS13Variant != TLS13RecordTypeExperiment && wireVers == tls13RecordTypeExperimentVersion) || (c.TLS13Variant != TLS13Default && wireVers == tls13DraftVersion) { return 0, false
diff --git a/ssl/test/runner/conn.go b/ssl/test/runner/conn.go index 615e224..25123b1 100644 --- a/ssl/test/runner/conn.go +++ b/ssl/test/runner/conn.go
@@ -151,14 +151,15 @@ type halfConn struct { sync.Mutex - err error // first permanent error - version uint16 // protocol version - isDTLS bool - cipher interface{} // cipher algorithm - mac macFunction - seq [8]byte // 64-bit sequence number - outSeq [8]byte // Mapped sequence number - bfree *block // list of free blocks + err error // first permanent error + version uint16 // protocol version + wireVersion uint16 // wire version + isDTLS bool + cipher interface{} // cipher algorithm + mac macFunction + seq [8]byte // 64-bit sequence number + outSeq [8]byte // Mapped sequence number + bfree *block // list of free blocks nextCipher interface{} // next encryption state nextMac macFunction // next MAC algorithm @@ -188,7 +189,12 @@ // prepareCipherSpec sets the encryption and MAC states // that a subsequent changeCipherSpec will use. func (hc *halfConn) prepareCipherSpec(version uint16, cipher interface{}, mac macFunction) { - hc.version = version + hc.wireVersion = version + protocolVersion, ok := wireToVersion(version, hc.isDTLS) + if !ok { + panic("TLS: unknown version") + } + hc.version = protocolVersion hc.nextCipher = cipher hc.nextMac = mac } @@ -215,7 +221,12 @@ // useTrafficSecret sets the current cipher state for TLS 1.3. func (hc *halfConn) useTrafficSecret(version uint16, suite *cipherSuite, secret []byte, side trafficDirection) { - hc.version = version + hc.wireVersion = version + protocolVersion, ok := wireToVersion(version, hc.isDTLS) + if !ok { + panic("TLS: unknown version") + } + hc.version = protocolVersion hc.cipher = deriveTrafficAEAD(version, suite, secret, side) if hc.config.Bugs.NullAllCiphers { hc.cipher = nullCipher{} @@ -237,7 +248,7 @@ if c.isClient == isOutgoing { side = clientWrite } - hc.useTrafficSecret(hc.version, c.cipherSuite, updateTrafficSecret(c.cipherSuite.hash(), hc.trafficSecret), side) + hc.useTrafficSecret(hc.wireVersion, c.cipherSuite, updateTrafficSecret(c.cipherSuite.hash(), hc.trafficSecret), side) } // incSeq increments the sequence number. @@ -781,7 +792,7 @@ if c.vers >= VersionTLS13 { expect = VersionTLS10 } - if c.wireVersion == tls13Experiment2Version { + if isResumptionRecordVersionExperiment(c.wireVersion) { expect = VersionTLS12 } } else { @@ -1128,8 +1139,9 @@ // layer to {3, 1}. vers = VersionTLS10 } - if c.wireVersion == tls13Experiment2Version { + if isResumptionRecordVersionExperiment(c.wireVersion) || isResumptionRecordVersionExperiment(c.out.wireVersion) { vers = VersionTLS12 + } else { } if c.config.Bugs.SendRecordVersion != 0 { @@ -1465,6 +1477,7 @@ session := &ClientSessionState{ sessionTicket: newSessionTicket.ticket, vers: c.vers, + wireVersion: c.wireVersion, cipherSuite: cipherSuite.id, masterSecret: c.resumptionSecret, serverCertificates: c.peerCertificates, @@ -1888,6 +1901,10 @@ payload[0] = byte(recordTypeApplicationData) payload[1] = 3 payload[2] = 1 + if c.config.TLS13Variant == TLS13Experiment2 || c.config.TLS13Variant == TLS13Experiment3 { + payload[1] = 3 + payload[2] = 3 + } payload[3] = byte(len >> 8) payload[4] = byte(len) _, err := c.conn.Write(payload)
diff --git a/ssl/test/runner/handshake_client.go b/ssl/test/runner/handshake_client.go index 13c3a19..a04ffd0 100644 --- a/ssl/test/runner/handshake_client.go +++ b/ssl/test/runner/handshake_client.go
@@ -412,7 +412,7 @@ finishedHash.addEntropy(session.masterSecret) finishedHash.Write(helloBytes) earlyTrafficSecret := finishedHash.deriveSecret(earlyTrafficLabel) - c.out.useTrafficSecret(session.vers, pskCipherSuite, earlyTrafficSecret, clientWrite) + c.out.useTrafficSecret(session.wireVersion, pskCipherSuite, earlyTrafficSecret, clientWrite) for _, earlyData := range c.config.Bugs.SendEarlyData { if _, err := c.writeRecord(recordTypeApplicationData, earlyData); err != nil { return err @@ -755,7 +755,7 @@ // traffic key. clientHandshakeTrafficSecret := hs.finishedHash.deriveSecret(clientHandshakeTrafficLabel) serverHandshakeTrafficSecret := hs.finishedHash.deriveSecret(serverHandshakeTrafficLabel) - c.in.useTrafficSecret(c.vers, hs.suite, serverHandshakeTrafficSecret, serverWrite) + c.in.useTrafficSecret(c.wireVersion, hs.suite, serverHandshakeTrafficSecret, serverWrite) msg, err := c.readHandshake() if err != nil { @@ -889,7 +889,7 @@ // Switch to application data keys on read. In particular, any alerts // from the client certificate are read over these keys. - c.in.useTrafficSecret(c.vers, hs.suite, serverTrafficSecret, serverWrite) + c.in.useTrafficSecret(c.wireVersion, hs.suite, serverTrafficSecret, serverWrite) // If we're expecting 0.5-RTT messages from the server, read them // now. @@ -931,11 +931,11 @@ c.sendAlert(alertEndOfEarlyData) } - if isResumptionExperiment(c.wireVersion) { + if isResumptionClientCCSExperiment(c.wireVersion) { c.writeRecord(recordTypeChangeCipherSpec, []byte{1}) } - c.out.useTrafficSecret(c.vers, hs.suite, clientHandshakeTrafficSecret, clientWrite) + c.out.useTrafficSecret(c.wireVersion, hs.suite, clientHandshakeTrafficSecret, clientWrite) if certReq != nil && !c.config.Bugs.SkipClientCertificate { certMsg := &certificateMsg{ @@ -1021,7 +1021,7 @@ c.flushHandshake() // Switch to application data keys. - c.out.useTrafficSecret(c.vers, hs.suite, clientTrafficSecret, clientWrite) + c.out.useTrafficSecret(c.wireVersion, hs.suite, clientTrafficSecret, clientWrite) c.resumptionSecret = hs.finishedHash.deriveSecret(resumptionLabel) return nil @@ -1288,8 +1288,8 @@ serverCipher = hs.suite.aead(c.vers, serverKey, serverIV) } - c.in.prepareCipherSpec(c.vers, serverCipher, serverHash) - c.out.prepareCipherSpec(c.vers, clientCipher, clientHash) + c.in.prepareCipherSpec(c.wireVersion, serverCipher, serverHash) + c.out.prepareCipherSpec(c.wireVersion, clientCipher, clientHash) return nil }
diff --git a/ssl/test/runner/handshake_server.go b/ssl/test/runner/handshake_server.go index 3fbd828..0a67a80 100644 --- a/ssl/test/runner/handshake_server.go +++ b/ssl/test/runner/handshake_server.go
@@ -668,7 +668,7 @@ } if encryptedExtensions.extensions.hasEarlyData { earlyTrafficSecret := hs.finishedHash.deriveSecret(earlyTrafficLabel) - c.in.useTrafficSecret(c.vers, hs.suite, earlyTrafficSecret, clientWrite) + c.in.useTrafficSecret(c.wireVersion, hs.suite, earlyTrafficSecret, clientWrite) for _, expectedMsg := range config.Bugs.ExpectEarlyData { if err := c.readRecord(recordTypeApplicationData); err != nil { @@ -769,7 +769,7 @@ // Switch to handshake traffic keys. serverHandshakeTrafficSecret := hs.finishedHash.deriveSecret(serverHandshakeTrafficLabel) - c.out.useTrafficSecret(c.vers, hs.suite, serverHandshakeTrafficSecret, serverWrite) + c.out.useTrafficSecret(c.wireVersion, hs.suite, serverHandshakeTrafficSecret, serverWrite) // Derive handshake traffic read key, but don't switch yet. clientHandshakeTrafficSecret := hs.finishedHash.deriveSecret(clientHandshakeTrafficLabel) @@ -910,7 +910,7 @@ // Switch to application data keys on write. In particular, any alerts // from the client certificate are sent over these keys. - c.out.useTrafficSecret(c.vers, hs.suite, serverTrafficSecret, serverWrite) + c.out.useTrafficSecret(c.wireVersion, hs.suite, serverTrafficSecret, serverWrite) // Send 0.5-RTT messages. for _, halfRTTMsg := range config.Bugs.SendHalfRTTData { @@ -929,14 +929,14 @@ } } - if isResumptionExperiment(c.wireVersion) && !c.skipEarlyData { + if isResumptionClientCCSExperiment(c.wireVersion) && !c.skipEarlyData { if err := c.readRecord(recordTypeChangeCipherSpec); err != nil { return err } } // Switch input stream to handshake traffic keys. - c.in.useTrafficSecret(c.vers, hs.suite, clientHandshakeTrafficSecret, clientWrite) + c.in.useTrafficSecret(c.wireVersion, hs.suite, clientHandshakeTrafficSecret, clientWrite) // If we requested a client certificate, then the client must send a // certificate message, even if it's empty. @@ -1040,7 +1040,7 @@ hs.writeClientHash(clientFinished.marshal()) // Switch to application data keys on read. - c.in.useTrafficSecret(c.vers, hs.suite, clientTrafficSecret, clientWrite) + c.in.useTrafficSecret(c.wireVersion, hs.suite, clientTrafficSecret, clientWrite) c.cipherSuite = hs.suite c.resumptionSecret = hs.finishedHash.deriveSecret(resumptionLabel) @@ -1697,8 +1697,8 @@ serverCipher = hs.suite.aead(c.vers, serverKey, serverIV) } - c.in.prepareCipherSpec(c.vers, clientCipher, clientHash) - c.out.prepareCipherSpec(c.vers, serverCipher, serverHash) + c.in.prepareCipherSpec(c.wireVersion, clientCipher, clientHash) + c.out.prepareCipherSpec(c.wireVersion, serverCipher, serverHash) return nil }
diff --git a/ssl/test/runner/runner.go b/ssl/test/runner/runner.go index 0bd24ff..ee72c2e 100644 --- a/ssl/test/runner/runner.go +++ b/ssl/test/runner/runner.go
@@ -1310,6 +1310,13 @@ tls13Variant: TLS13Experiment2, }, { + name: "TLS13Experiment3", + version: VersionTLS13, + excludeFlag: "-no-tls13", + versionWire: tls13Experiment3Version, + tls13Variant: TLS13Experiment3, + }, + { name: "TLS13RecordTypeExperiment", version: VersionTLS13, excludeFlag: "-no-tls13", @@ -4105,85 +4112,6 @@ tests = append(tests, testCase{ testType: clientTest, - name: "TLS13-EarlyData-Client", - config: Config{ - MaxVersion: VersionTLS13, - MinVersion: VersionTLS13, - MaxEarlyDataSize: 16384, - }, - resumeConfig: &Config{ - MaxVersion: VersionTLS13, - MinVersion: VersionTLS13, - MaxEarlyDataSize: 16384, - Bugs: ProtocolBugs{ - ExpectEarlyData: [][]byte{{'h', 'e', 'l', 'l', 'o'}}, - }, - }, - resumeSession: true, - flags: []string{ - "-enable-early-data", - "-expect-early-data-info", - "-expect-accept-early-data", - "-on-resume-shim-writes-first", - }, - }) - - tests = append(tests, testCase{ - testType: clientTest, - name: "TLS13Experiment-EarlyData-Client", - config: Config{ - MaxVersion: VersionTLS13, - MinVersion: VersionTLS13, - MaxEarlyDataSize: 16384, - }, - resumeConfig: &Config{ - MaxVersion: VersionTLS13, - MinVersion: VersionTLS13, - MaxEarlyDataSize: 16384, - Bugs: ProtocolBugs{ - ExpectEarlyData: [][]byte{{'h', 'e', 'l', 'l', 'o'}}, - }, - }, - tls13Variant: TLS13Experiment, - resumeSession: true, - flags: []string{ - "-enable-early-data", - "-expect-early-data-info", - "-expect-accept-early-data", - "-on-resume-shim-writes-first", - }, - }) - - tests = append(tests, testCase{ - testType: clientTest, - name: "TLS13RecordTypeExperiment-EarlyData-Client", - config: Config{ - MaxVersion: VersionTLS13, - MinVersion: VersionTLS13, - TLS13Variant: TLS13RecordTypeExperiment, - MaxEarlyDataSize: 16384, - }, - resumeConfig: &Config{ - MaxVersion: VersionTLS13, - MinVersion: VersionTLS13, - TLS13Variant: TLS13RecordTypeExperiment, - MaxEarlyDataSize: 16384, - Bugs: ProtocolBugs{ - ExpectEarlyData: [][]byte{{'h', 'e', 'l', 'l', 'o'}}, - }, - }, - tls13Variant: TLS13RecordTypeExperiment, - resumeSession: true, - flags: []string{ - "-enable-early-data", - "-expect-early-data-info", - "-expect-accept-early-data", - "-on-resume-shim-writes-first", - }, - }) - - tests = append(tests, testCase{ - testType: clientTest, name: "TLS13-EarlyData-TooMuchData-Client", config: Config{ MaxVersion: VersionTLS13, @@ -4270,68 +4198,6 @@ tests = append(tests, testCase{ testType: serverTest, - name: "TLS13-EarlyData-Server", - config: Config{ - MaxVersion: VersionTLS13, - MinVersion: VersionTLS13, - Bugs: ProtocolBugs{ - SendEarlyData: [][]byte{{1, 2, 3, 4}}, - ExpectEarlyDataAccepted: true, - ExpectHalfRTTData: [][]byte{{254, 253, 252, 251}}, - }, - }, - messageCount: 2, - resumeSession: true, - flags: []string{ - "-enable-early-data", - "-expect-accept-early-data", - }, - }) - - tests = append(tests, testCase{ - testType: serverTest, - name: "TLS13Experiment-EarlyData-Server", - config: Config{ - MaxVersion: VersionTLS13, - MinVersion: VersionTLS13, - Bugs: ProtocolBugs{ - SendEarlyData: [][]byte{{1, 2, 3, 4}}, - ExpectEarlyDataAccepted: true, - ExpectHalfRTTData: [][]byte{{254, 253, 252, 251}}, - }, - }, - tls13Variant: TLS13Experiment, - messageCount: 2, - resumeSession: true, - flags: []string{ - "-enable-early-data", - "-expect-accept-early-data", - }, - }) - - tests = append(tests, testCase{ - testType: serverTest, - name: "TLS13RecordTypeExperiment-EarlyData-Server", - config: Config{ - MaxVersion: VersionTLS13, - MinVersion: VersionTLS13, - Bugs: ProtocolBugs{ - SendEarlyData: [][]byte{{1, 2, 3, 4}}, - ExpectEarlyDataAccepted: true, - ExpectHalfRTTData: [][]byte{{254, 253, 252, 251}}, - }, - }, - tls13Variant: TLS13RecordTypeExperiment, - messageCount: 2, - resumeSession: true, - flags: []string{ - "-enable-early-data", - "-expect-accept-early-data", - }, - }) - - tests = append(tests, testCase{ - testType: serverTest, name: "TLS13-MaxEarlyData-Server", config: Config{ MaxVersion: VersionTLS13, @@ -5189,7 +5055,7 @@ serverVers := expectedServerVersion if expectedServerVersion >= VersionTLS13 { serverVers = VersionTLS10 - if runnerVers.tls13Variant == TLS13Experiment2 { + if runnerVers.tls13Variant == TLS13Experiment2 || runnerVers.tls13Variant == TLS13Experiment3 { serverVers = VersionTLS12 } } @@ -10844,40 +10710,170 @@ expectedError: ":DUPLICATE_KEY_SHARE:", }) - testCases = append(testCases, testCase{ - testType: serverTest, - name: "SkipEarlyData", - config: Config{ - MaxVersion: VersionTLS13, - Bugs: ProtocolBugs{ - SendFakeEarlyDataLength: 4, - }, - }, - }) + for _, version := range allVersions(tls) { + if version.version != VersionTLS13 { + continue + } + name := version.name + variant := version.tls13Variant - testCases = append(testCases, testCase{ - testType: serverTest, - name: "SkipEarlyData-TLS13Experiment", - config: Config{ - MaxVersion: VersionTLS13, - Bugs: ProtocolBugs{ - SendFakeEarlyDataLength: 4, + testCases = append(testCases, testCase{ + testType: serverTest, + name: "SkipEarlyData-" + name, + config: Config{ + MaxVersion: VersionTLS13, + Bugs: ProtocolBugs{ + SendFakeEarlyDataLength: 4, + }, }, - }, - tls13Variant: TLS13Experiment, - }) + tls13Variant: variant, + }) - testCases = append(testCases, testCase{ - testType: serverTest, - name: "SkipEarlyData-TLS13RecordTypeExperiment", - config: Config{ - MaxVersion: VersionTLS13, - Bugs: ProtocolBugs{ - SendFakeEarlyDataLength: 4, + // Test that enabling a TLS 1.3 variant does not interfere with + // TLS 1.2 session ID resumption. + testCases = append(testCases, testCase{ + testType: clientTest, + name: "ResumeTLS12SessionID-" + name, + config: Config{ + MaxVersion: VersionTLS12, + SessionTicketsDisabled: true, }, - }, - tls13Variant: TLS13RecordTypeExperiment, - }) + tls13Variant: variant, + resumeSession: true, + }) + + // Test that the server correctly echoes back session IDs of + // various lengths. + testCases = append(testCases, testCase{ + testType: serverTest, + name: "EmptySessionID-" + name, + config: Config{ + MaxVersion: VersionTLS13, + Bugs: ProtocolBugs{ + SendClientHelloSessionID: []byte{}, + }, + }, + tls13Variant: variant, + }) + + testCases = append(testCases, testCase{ + testType: serverTest, + name: "ShortSessionID-" + name, + config: Config{ + MaxVersion: VersionTLS13, + Bugs: ProtocolBugs{ + SendClientHelloSessionID: make([]byte, 16), + }, + }, + tls13Variant: variant, + }) + + testCases = append(testCases, testCase{ + testType: serverTest, + name: "FullSessionID-" + name, + config: Config{ + MaxVersion: VersionTLS13, + Bugs: ProtocolBugs{ + SendClientHelloSessionID: make([]byte, 32), + }, + }, + tls13Variant: variant, + }) + + hasSessionID := false + hasEmptySessionID := false + if variant == TLS13NoSessionIDExperiment { + hasEmptySessionID = true + } else if variant != TLS13Default && variant != TLS13RecordTypeExperiment { + hasSessionID = true + } + + // Test that the client sends a fake session ID in the correct experiments. + testCases = append(testCases, testCase{ + testType: clientTest, + name: "TLS13SessionID-" + name, + config: Config{ + MaxVersion: VersionTLS13, + Bugs: ProtocolBugs{ + ExpectClientHelloSessionID: hasSessionID, + ExpectEmptyClientHelloSessionID: hasEmptySessionID, + }, + }, + tls13Variant: variant, + }) + + testCases = append(testCases, testCase{ + testType: clientTest, + name: "EarlyData-Client-" + name, + config: Config{ + MaxVersion: VersionTLS13, + MinVersion: VersionTLS13, + MaxEarlyDataSize: 16384, + }, + resumeConfig: &Config{ + MaxVersion: VersionTLS13, + MinVersion: VersionTLS13, + MaxEarlyDataSize: 16384, + Bugs: ProtocolBugs{ + ExpectEarlyData: [][]byte{{'h', 'e', 'l', 'l', 'o'}}, + }, + }, + tls13Variant: variant, + resumeSession: true, + flags: []string{ + "-enable-early-data", + "-expect-early-data-info", + "-expect-accept-early-data", + "-on-resume-shim-writes-first", + }, + }) + + testCases = append(testCases, testCase{ + testType: clientTest, + name: "EarlyData-Reject-Client-" + name, + config: Config{ + MaxVersion: VersionTLS13, + MaxEarlyDataSize: 16384, + }, + resumeConfig: &Config{ + MaxVersion: VersionTLS13, + MaxEarlyDataSize: 16384, + Bugs: ProtocolBugs{ + AlwaysRejectEarlyData: true, + }, + }, + tls13Variant: variant, + resumeSession: true, + flags: []string{ + "-enable-early-data", + "-expect-early-data-info", + "-expect-reject-early-data", + "-on-resume-shim-writes-first", + }, + }) + + testCases = append(testCases, testCase{ + testType: serverTest, + name: "EarlyData-Server-" + name, + config: Config{ + MaxVersion: VersionTLS13, + MinVersion: VersionTLS13, + Bugs: ProtocolBugs{ + SendEarlyData: [][]byte{{1, 2, 3, 4}}, + ExpectEarlyDataAccepted: true, + ExpectHalfRTTData: [][]byte{{254, 253, 252, 251}}, + }, + }, + tls13Variant: variant, + messageCount: 2, + resumeSession: true, + flags: []string{ + "-enable-early-data", + "-expect-accept-early-data", + }, + }) + + } testCases = append(testCases, testCase{ testType: serverTest, @@ -11355,165 +11351,6 @@ }, }, }) - - for _, noSessionID := range []bool{false, true} { - prefix := "TLS13Experiment" - variant := TLS13Experiment - if noSessionID { - prefix = "TLS13NoSessionIDExperiment" - variant = TLS13NoSessionIDExperiment - } - - // Test that enabling a TLS 1.3 variant does not interfere with - // TLS 1.2 session ID resumption. - testCases = append(testCases, testCase{ - testType: clientTest, - name: prefix + "-ResumeTLS12SessionID", - config: Config{ - MaxVersion: VersionTLS12, - SessionTicketsDisabled: true, - }, - resumeSession: true, - flags: []string{"-tls13-variant", strconv.Itoa(variant)}, - }) - - // Test that the server correctly echoes back session IDs of - // various lengths. - testCases = append(testCases, testCase{ - testType: serverTest, - name: prefix + "-EmptySessionID", - config: Config{ - MaxVersion: VersionTLS13, - Bugs: ProtocolBugs{ - SendClientHelloSessionID: []byte{}, - }, - }, - tls13Variant: variant, - }) - - testCases = append(testCases, testCase{ - testType: serverTest, - name: prefix + "-ShortSessionID", - config: Config{ - MaxVersion: VersionTLS13, - Bugs: ProtocolBugs{ - SendClientHelloSessionID: make([]byte, 16), - }, - }, - tls13Variant: variant, - }) - - testCases = append(testCases, testCase{ - testType: serverTest, - name: prefix + "-FullSessionID", - config: Config{ - MaxVersion: VersionTLS13, - Bugs: ProtocolBugs{ - SendClientHelloSessionID: make([]byte, 32), - }, - }, - tls13Variant: variant, - }) - } - - // Test that the client sends a fake session ID in TLS13Experiment. - testCases = append(testCases, testCase{ - testType: clientTest, - name: "TLS13Experiment-RequireSessionID", - config: Config{ - MaxVersion: VersionTLS13, - Bugs: ProtocolBugs{ - ExpectClientHelloSessionID: true, - }, - }, - tls13Variant: TLS13Experiment, - }) - - // Test that the client does not send a fake session ID in - // TLS13NoSessionIDExperiment. - testCases = append(testCases, testCase{ - testType: clientTest, - name: "TLS13NoSessionIDExperiment-RequireEmptySessionID", - config: Config{ - MaxVersion: VersionTLS13, - Bugs: ProtocolBugs{ - ExpectEmptyClientHelloSessionID: true, - }, - }, - tls13Variant: TLS13NoSessionIDExperiment, - }) - - testCases = append(testCases, testCase{ - testType: clientTest, - name: "TLS13-EarlyData-Reject-Client", - config: Config{ - MaxVersion: VersionTLS13, - MaxEarlyDataSize: 16384, - }, - resumeConfig: &Config{ - MaxVersion: VersionTLS13, - MaxEarlyDataSize: 16384, - Bugs: ProtocolBugs{ - AlwaysRejectEarlyData: true, - }, - }, - resumeSession: true, - flags: []string{ - "-enable-early-data", - "-expect-early-data-info", - "-expect-reject-early-data", - "-on-resume-shim-writes-first", - }, - }) - - testCases = append(testCases, testCase{ - testType: clientTest, - name: "TLS13Experiment-EarlyData-Reject-Client", - config: Config{ - MaxVersion: VersionTLS13, - MaxEarlyDataSize: 16384, - }, - resumeConfig: &Config{ - MaxVersion: VersionTLS13, - MaxEarlyDataSize: 16384, - Bugs: ProtocolBugs{ - AlwaysRejectEarlyData: true, - }, - }, - tls13Variant: TLS13Experiment, - resumeSession: true, - flags: []string{ - "-enable-early-data", - "-expect-early-data-info", - "-expect-reject-early-data", - "-on-resume-shim-writes-first", - }, - }) - - testCases = append(testCases, testCase{ - testType: clientTest, - name: "TLS13RecordTypeExperiment-EarlyData-Reject-Client", - config: Config{ - MaxVersion: VersionTLS13, - MaxEarlyDataSize: 16384, - }, - resumeConfig: &Config{ - MaxVersion: VersionTLS13, - MaxEarlyDataSize: 16384, - Bugs: ProtocolBugs{ - AlwaysRejectEarlyData: true, - }, - }, - tls13Variant: TLS13RecordTypeExperiment, - resumeSession: true, - flags: []string{ - "-enable-early-data", - "-expect-early-data-info", - "-expect-reject-early-data", - "-on-resume-shim-writes-first", - }, - }) - testCases = append(testCases, testCase{ testType: clientTest, name: "TLS13-EarlyData-RejectTicket-Client",
diff --git a/ssl/tls13_client.cc b/ssl/tls13_client.cc index dad7cad..f50b077 100644 --- a/ssl/tls13_client.cc +++ b/ssl/tls13_client.cc
@@ -159,10 +159,16 @@ static enum ssl_hs_wait_t do_send_second_client_hello(SSL_HANDSHAKE *hs) { SSL *const ssl = hs->ssl; // Restore the null cipher. We may have switched due to 0-RTT. - bssl::UniquePtr<SSLAEADContext> null_ctx = SSLAEADContext::CreateNullCipher(); + bssl::UniquePtr<SSLAEADContext> null_ctx = + SSLAEADContext::CreateNullCipher(SSL_is_dtls(ssl)); if (!null_ctx || - !ssl->method->set_write_state(ssl, std::move(null_ctx)) || - !ssl_write_client_hello(hs)) { + !ssl->method->set_write_state(ssl, std::move(null_ctx))) { + return ssl_hs_error; + } + + ssl->s3->aead_write_ctx->SetVersionIfNullCipher(ssl->version); + + if (!ssl_write_client_hello(hs)) { return ssl_hs_error; } @@ -367,7 +373,7 @@ if (!hs->early_data_offered) { // If not sending early data, set client traffic keys now so that alerts are // encrypted. - if ((ssl_is_resumption_experiment(ssl->version) && + if ((ssl_is_resumption_client_ccs_experiment(ssl->version) && !ssl3_add_change_cipher_spec(ssl)) || !tls13_set_traffic_key(ssl, evp_aead_seal, hs->client_handshake_secret, hs->hash_len)) { @@ -575,7 +581,7 @@ } if (hs->early_data_offered) { - if ((ssl_is_resumption_experiment(ssl->version) && + if ((ssl_is_resumption_client_ccs_experiment(ssl->version) && !ssl3_add_change_cipher_spec(ssl)) || !tls13_set_traffic_key(ssl, evp_aead_seal, hs->client_handshake_secret, hs->hash_len)) {
diff --git a/ssl/tls13_enc.cc b/ssl/tls13_enc.cc index 7bd87c5..6ff9972 100644 --- a/ssl/tls13_enc.cc +++ b/ssl/tls13_enc.cc
@@ -150,8 +150,8 @@ } UniquePtr<SSLAEADContext> traffic_aead = SSLAEADContext::Create( - direction, version, SSL_is_dtls(ssl), session->cipher, key, key_len, NULL, - 0, iv, iv_len); + direction, session->ssl_version, SSL_is_dtls(ssl), session->cipher, key, + key_len, NULL, 0, iv, iv_len); if (!traffic_aead) { return 0; }
diff --git a/ssl/tls13_server.cc b/ssl/tls13_server.cc index a0f115b..550f3b5 100644 --- a/ssl/tls13_server.cc +++ b/ssl/tls13_server.cc
@@ -706,7 +706,7 @@ if (hs->early_data_offered && !hs->ssl->early_data_accepted) { return ssl_hs_ok; } - return ssl_is_resumption_experiment(hs->ssl->version) + return ssl_is_resumption_client_ccs_experiment(hs->ssl->version) ? ssl_hs_read_change_cipher_spec : ssl_hs_ok; }
diff --git a/ssl/tls_record.cc b/ssl/tls_record.cc index 511f489..5eeff3c 100644 --- a/ssl/tls_record.cc +++ b/ssl/tls_record.cc
@@ -143,7 +143,7 @@ static int ssl_needs_record_splitting(const SSL *ssl) { #if !defined(BORINGSSL_UNSAFE_FUZZER_MODE) return !ssl->s3->aead_write_ctx->is_null_cipher() && - ssl->s3->aead_write_ctx->version() < TLS1_1_VERSION && + ssl->s3->aead_write_ctx->ProtocolVersion() < TLS1_1_VERSION && (ssl->mode & SSL_MODE_CBC_RECORD_SPLITTING) != 0 && SSL_CIPHER_is_block_cipher(ssl->s3->aead_write_ctx->cipher()); #else @@ -205,19 +205,13 @@ return ssl_open_record_partial; } - int version_ok; + bool version_ok; if (ssl->s3->aead_read_ctx->is_null_cipher()) { // Only check the first byte. Enforcing beyond that can prevent decoding // version negotiation failure alerts. version_ok = (version >> 8) == SSL3_VERSION_MAJOR; - } else if (ssl3_protocol_version(ssl) < TLS1_3_VERSION) { - // Earlier versions of TLS switch the record version. - version_ok = version == ssl->version; - } else if (ssl->version == TLS1_3_EXPERIMENT2_VERSION) { - version_ok = version == TLS1_2_VERSION; } else { - // Starting TLS 1.3, the version field is frozen at {3, 1}. - version_ok = version == TLS1_VERSION; + version_ok = version == ssl->s3->aead_read_ctx->RecordVersion(); } if (!version_ok) { @@ -276,7 +270,7 @@ // TLS 1.3 hides the record type inside the encrypted data. if (!ssl->s3->aead_read_ctx->is_null_cipher() && - ssl->s3->aead_read_ctx->version() >= TLS1_3_VERSION) { + ssl->s3->aead_read_ctx->ProtocolVersion() >= TLS1_3_VERSION) { // The outer record type is always application_data. if (type != SSL3_RT_APPLICATION_DATA) { OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_OUTER_RECORD_TYPE); @@ -352,7 +346,7 @@ uint8_t *extra_in = NULL; size_t extra_in_len = 0; if (!ssl->s3->aead_write_ctx->is_null_cipher() && - ssl->s3->aead_write_ctx->version() >= TLS1_3_VERSION) { + ssl->s3->aead_write_ctx->ProtocolVersion() >= TLS1_3_VERSION) { // TLS 1.3 hides the actual record type inside the encrypted data. extra_in = &type; extra_in_len = 1; @@ -381,30 +375,17 @@ out_prefix[0] = type; } - // The TLS record-layer version number is meaningless and, starting in - // TLS 1.3, is frozen at TLS 1.0. But for historical reasons, SSL 3.0 - // ClientHellos should use SSL 3.0 and pre-TLS-1.3 expects the version - // to change after version negotiation. - uint16_t wire_version = TLS1_VERSION; - if (ssl->s3->hs != NULL && ssl->s3->hs->max_version == SSL3_VERSION) { - wire_version = SSL3_VERSION; - } - if (ssl->s3->have_version && ssl3_protocol_version(ssl) < TLS1_3_VERSION) { - wire_version = ssl->version; - } - if (ssl->s3->have_version && ssl->version == TLS1_3_EXPERIMENT2_VERSION) { - wire_version = TLS1_2_VERSION; - } + uint16_t record_version = ssl->s3->aead_write_ctx->RecordVersion(); - out_prefix[1] = wire_version >> 8; - out_prefix[2] = wire_version & 0xff; + out_prefix[1] = record_version >> 8; + out_prefix[2] = record_version & 0xff; out_prefix[3] = ciphertext_len >> 8; out_prefix[4] = ciphertext_len & 0xff; - if (!ssl->s3->aead_write_ctx->SealScatter(out_prefix + SSL3_RT_HEADER_LENGTH, - out, out_suffix, type, wire_version, - ssl->s3->write_sequence, in, in_len, - extra_in, extra_in_len) || + if (!ssl->s3->aead_write_ctx->SealScatter( + out_prefix + SSL3_RT_HEADER_LENGTH, out, out_suffix, type, + record_version, ssl->s3->write_sequence, in, in_len, extra_in, + extra_in_len) || !ssl_record_sequence_update(ssl->s3->write_sequence, 8)) { return 0; } @@ -435,7 +416,7 @@ uint8_t type, size_t in_len) { size_t extra_in_len = 0; if (!ssl->s3->aead_write_ctx->is_null_cipher() && - ssl->s3->aead_write_ctx->version() >= TLS1_3_VERSION) { + ssl->s3->aead_write_ctx->ProtocolVersion() >= TLS1_3_VERSION) { // TLS 1.3 adds an extra byte for encrypted record type. extra_in_len = 1; } @@ -685,7 +666,7 @@ ret += ssl->s3->aead_write_ctx->MaxOverhead(); // TLS 1.3 needs an extra byte for the encrypted record type. if (!ssl->s3->aead_write_ctx->is_null_cipher() && - ssl->s3->aead_write_ctx->version() >= TLS1_3_VERSION) { + ssl->s3->aead_write_ctx->ProtocolVersion() >= TLS1_3_VERSION) { ret += 1; } if (ssl_needs_record_splitting(ssl)) {
diff --git a/tool/client.cc b/tool/client.cc index cde3397..e2da29e 100644 --- a/tool/client.cc +++ b/tool/client.cc
@@ -322,6 +322,10 @@ *out = tls13_experiment2; return true; } + if (in == "experiment3") { + *out = tls13_experiment3; + return true; + } if (in == "record-type") { *out = tls13_record_type_experiment; return true;