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;