update main-with-bazel from master branch

This commit is contained in:
BoringSSL Robot
2024-12-07 00:06:02 +00:00
13 changed files with 317 additions and 147 deletions
+1 -11
View File
@@ -672,17 +672,7 @@ OPENSSL_EXPORT int DTLSv1_handle_timeout(SSL *ssl);
#define DTLS1_VERSION 0xfeff
#define DTLS1_2_VERSION 0xfefd
// DTLS1_3_EXPERIMENTAL_VERSION gates experimental, in-progress code for DTLS
// 1.3.
//
// WARNING: Do not use this value. BoringSSL's DTLS 1.3 implementation is still
// under development. The code enabled by this value is neither stable nor
// secure. It does not correspond to any real protocol. It is also incompatible
// with other DTLS implementations, and it is not compatible with future or past
// versions of BoringSSL.
//
// When the DTLS 1.3 implementation is complete, this symbol will be replaced.
#define DTLS1_3_EXPERIMENTAL_VERSION 0xfc25
#define DTLS1_3_VERSION 0xfefc
// SSL_CTX_set_min_proto_version sets the minimum protocol version for |ctx| to
// |version|. If |version| is zero, the default minimum version is used. It
+30 -24
View File
@@ -368,9 +368,8 @@ bool dtls1_process_handshake_fragments(SSL *ssl, uint8_t *out_alert,
const size_t frag_off = msg_hdr.frag_off;
const size_t frag_len = msg_hdr.frag_len;
const size_t msg_len = msg_hdr.msg_len;
if (frag_off > msg_len || frag_len > msg_len - frag_off ||
msg_len > ssl_max_handshake_message_len(ssl)) {
OPENSSL_PUT_ERROR(SSL, SSL_R_EXCESSIVE_MESSAGE_SIZE);
if (frag_off > msg_len || frag_len > msg_len - frag_off) {
OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_HANDSHAKE_RECORD);
*out_alert = SSL_AD_ILLEGAL_PARAMETER;
return false;
}
@@ -384,19 +383,24 @@ bool dtls1_process_handshake_fragments(SSL *ssl, uint8_t *out_alert,
continue;
}
assert(record_number.epoch() == ssl->d1->read_epoch.epoch);
if (ssl->d1->next_read_epoch != nullptr) {
// Any any time, we only expect new messages in one epoch. If
// |next_read_epoch| is set, we've started a new epoch but haven't
// received records in it yet. (Once a record is received in the new
// epoch, |next_read_epoch| becomes the current read epoch.) This new
// fragment is in the old epoch, but we expect handshake messages to be in
// the next epoch, so this is an error.
if (record_number.epoch() != ssl->d1->read_epoch.epoch ||
ssl->d1->next_read_epoch != nullptr) {
// New messages can only arrive in the latest epoch. This can fail if the
// record came from |prev_read_epoch|, or if it came from |read_epoch| but
// |next_read_epoch| exists. (It cannot come from |next_read_epoch|
// because |next_read_epoch| becomes |read_epoch| once it receives a
// record.)
OPENSSL_PUT_ERROR(SSL, SSL_R_EXCESS_HANDSHAKE_DATA);
*out_alert = SSL_AD_UNEXPECTED_MESSAGE;
return false;
}
if (msg_len > ssl_max_handshake_message_len(ssl)) {
OPENSSL_PUT_ERROR(SSL, SSL_R_EXCESSIVE_MESSAGE_SIZE);
*out_alert = SSL_AD_ILLEGAL_PARAMETER;
return false;
}
if (SSL_in_init(ssl) && ssl_has_final_version(ssl) &&
ssl_protocol_version(ssl) >= TLS1_3_VERSION) {
// During the handshake, if we receive any portion of the next flight, the
@@ -482,18 +486,23 @@ ssl_open_record_t dtls1_open_handshake(SSL *ssl, size_t *out_consumed,
return ssl_open_record_discard;
case SSL3_RT_CHANGE_CIPHER_SPEC:
if (record.size() != 1u || record[0] != SSL3_MT_CCS) {
OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_CHANGE_CIPHER_SPEC);
*out_alert = SSL_AD_ILLEGAL_PARAMETER;
return ssl_open_record_error;
}
// We do not support renegotiation, so encrypted ChangeCipherSpec records
// are illegal.
if (ssl->d1->read_epoch.epoch != 0) {
if (record_number.epoch() != 0) {
OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_RECORD);
*out_alert = SSL_AD_UNEXPECTED_MESSAGE;
return ssl_open_record_error;
}
if (record.size() != 1u || record[0] != SSL3_MT_CCS) {
OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_CHANGE_CIPHER_SPEC);
*out_alert = SSL_AD_ILLEGAL_PARAMETER;
return ssl_open_record_error;
// Ignore ChangeCipherSpec from a previous epoch.
if (record_number.epoch() != ssl->d1->read_epoch.epoch) {
return ssl_open_record_discard;
}
// Flag the ChangeCipherSpec for later.
@@ -507,20 +516,17 @@ ssl_open_record_t dtls1_open_handshake(SSL *ssl, size_t *out_consumed,
return dtls1_process_ack(ssl, out_alert, record_number, record);
case SSL3_RT_HANDSHAKE:
// Break out to main processing.
break;
if (!dtls1_process_handshake_fragments(ssl, out_alert, record_number,
record)) {
return ssl_open_record_error;
}
return ssl_open_record_success;
default:
OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_RECORD);
*out_alert = SSL_AD_UNEXPECTED_MESSAGE;
return ssl_open_record_error;
}
if (!dtls1_process_handshake_fragments(ssl, out_alert, record_number,
record)) {
return ssl_open_record_error;
}
return ssl_open_record_success;
}
bool dtls1_get_message(const SSL *ssl, SSLMessage *out) {
+31 -11
View File
@@ -265,6 +265,13 @@ static bool parse_dtls13_record(SSL *ssl, CBS *in, ParsedDTLSRecord *out) {
BSSL_CHECK(CBS_get_bytes(in, &out->body, CBS_len(in)));
}
// Drop the previous read epoch if expired.
if (ssl->d1->prev_read_epoch != nullptr &&
ssl_ctx_get_current_time(ssl->ctx.get()).tv_sec >
ssl->d1->prev_read_epoch->expire) {
ssl->d1->prev_read_epoch = nullptr;
}
// Look up the corresponding epoch. This header form only matches encrypted
// DTLS 1.3 epochs.
DTLSReadEpoch *read_epoch = nullptr;
@@ -273,6 +280,9 @@ static bool parse_dtls13_record(SSL *ssl, CBS *in, ParsedDTLSRecord *out) {
} else if (ssl->d1->next_read_epoch != nullptr &&
epoch == ssl->d1->next_read_epoch->epoch) {
read_epoch = ssl->d1->next_read_epoch.get();
} else if (ssl->d1->prev_read_epoch != nullptr &&
epoch == ssl->d1->prev_read_epoch->epoch.epoch) {
read_epoch = &ssl->d1->prev_read_epoch->epoch;
}
if (read_epoch != nullptr && use_dtls13_record_header(ssl, epoch)) {
out->read_epoch = read_epoch;
@@ -434,22 +444,32 @@ enum ssl_open_record_t dtls_open_record(SSL *ssl, uint8_t *out_type,
record.read_epoch->bitmap.Record(record.number.sequence());
// Once we receive a record from the next epoch, it becomes the current epoch.
// Once we receive a record from the next epoch in DTLS 1.3, it becomes the
// current epoch. Also save the previous epoch. This allows us to handle
// packet reordering on KeyUpdate, as well as ACK retransmissions of the
// Finished flight.
if (record.read_epoch == ssl->d1->next_read_epoch.get()) {
assert(ssl_protocol_version(ssl) >= TLS1_3_VERSION);
auto prev = MakeUnique<DTLSPrevReadEpoch>();
if (prev == nullptr) {
*out_alert = SSL_AD_INTERNAL_ERROR;
return ssl_open_record_error;
}
// Release the epoch after a timeout.
prev->expire = ssl_ctx_get_current_time(ssl->ctx.get()).tv_sec;
if (prev->expire >= UINT64_MAX - DTLS_PREV_READ_EPOCH_EXPIRE_SECONDS) {
prev->expire = UINT64_MAX; // Saturate on overflow.
} else {
prev->expire += DTLS_PREV_READ_EPOCH_EXPIRE_SECONDS;
}
prev->epoch = std::move(ssl->d1->read_epoch);
ssl->d1->prev_read_epoch = std::move(prev);
ssl->d1->read_epoch = std::move(*ssl->d1->next_read_epoch);
ssl->d1->next_read_epoch = nullptr;
}
// We do not retain previous epochs, so it is guaranteed records come in at
// the "current" epoch. (But the current epoch may be one behind the
// handshake.)
//
// TODO(crbug.com/374890768): In DTLS 1.3, where rekeys may occur
// mid-connection, retaining previous epochs would make us more robust to
// packet reordering. If we do this, we'll need to take care to not
// accidentally accept data at the wrong epoch.
assert(record.number.epoch() == ssl->d1->read_epoch.epoch);
// TODO(davidben): Limit the number of empty records as in TLS? This is only
// useful if we also limit discarded packets.
+1 -1
View File
@@ -796,7 +796,7 @@ static enum ssl_hs_wait_t do_read_server_hello(SSL_HANDSHAKE *hs) {
// Enforce the TLS 1.3 anti-downgrade feature.
if (!ssl->s3->initial_handshake_complete &&
ssl_supports_version(hs, TLS1_3_VERSION)) {
hs->max_version >= TLS1_3_VERSION) {
static_assert(
sizeof(kTLS12DowngradeRandom) == sizeof(kTLS13DowngradeRandom),
"downgrade signals have different size");
+1 -1
View File
@@ -1057,7 +1057,7 @@ static enum ssl_hs_wait_t do_send_server_hello(SSL_HANDSHAKE *hs) {
}
// Implement the TLS 1.3 anti-downgrade feature.
if (ssl_supports_version(hs, TLS1_3_VERSION)) {
if (hs->max_version >= TLS1_3_VERSION) {
if (ssl_protocol_version(ssl) == TLS1_2_VERSION) {
if (hs->apply_jdk11_workaround) {
// JDK 11 implements the TLS 1.3 downgrade signal, so we cannot send it
+26 -2
View File
@@ -3540,6 +3540,27 @@ enum class QueuedKeyUpdate {
kUpdateRequested,
};
// DTLS_PREV_READ_EPOCH_EXPIRE_SECONDS is how long to retain the previous read
// epoch in DTLS 1.3. This value is set based on the following:
//
// - Section 4.2.1 of RFC 9147 recommends retaining past read epochs for the
// default TCP MSL. This accommodates packet reordering with KeyUpdate.
//
// - Section 5.8.1 of RFC 9147 requires being capable of ACKing the client's
// final flight for at least twice the default MSL. That requires retaining
// epoch 2 after the handshake.
//
// - Section 4 of RFC 9293 defines the MSL to be two minutes.
#define DTLS_PREV_READ_EPOCH_EXPIRE_SECONDS (4 * 60)
struct DTLSPrevReadEpoch {
static constexpr bool kAllowUniquePtr = true;
DTLSReadEpoch epoch;
// expire is the expiration time of the read epoch, expressed as a POSIX
// timestamp in seconds.
uint64_t expire;
};
struct DTLS1_STATE {
static constexpr bool kAllowUniquePtr = true;
@@ -3579,13 +3600,16 @@ struct DTLS1_STATE {
uint16_t handshake_write_seq = 0;
uint16_t handshake_read_seq = 0;
// read_epoch is the current DTLS read epoch.
// read_epoch is the current read epoch.
DTLSReadEpoch read_epoch;
// next_read_epoch is the next DTLS read epoch in DTLS 1.3. It will become
// next_read_epoch is the next read epoch in DTLS 1.3. It will become
// current once a record is received from it.
UniquePtr<DTLSReadEpoch> next_read_epoch;
// prev_read_epoch is the previous read epoch in DTLS 1.3.
UniquePtr<DTLSPrevReadEpoch> prev_read_epoch;
// write_epoch is the current DTLS write epoch. Non-retransmit records will
// generally use this epoch.
// TODO(crbug.com/381113363): 0-RTT will be the exception, when implemented.
+10 -15
View File
@@ -92,7 +92,7 @@ static const VersionParam kAllVersions[] = {
{TLS1_3_VERSION, VersionParam::is_tls, "TLS1_3"},
{DTLS1_VERSION, VersionParam::is_dtls, "DTLS1"},
{DTLS1_2_VERSION, VersionParam::is_dtls, "DTLS1_2"},
{DTLS1_3_EXPERIMENTAL_VERSION, VersionParam::is_dtls, "DTLS1_3"},
{DTLS1_3_VERSION, VersionParam::is_dtls, "DTLS1_3"},
};
struct ExpectedCipher {
@@ -2765,8 +2765,7 @@ class SSLVersionTest : public ::testing::TestWithParam<VersionParam> {
uint16_t version() const { return GetParam().version; }
bool is_tls13() const {
return version() == TLS1_3_VERSION ||
version() == DTLS1_3_EXPERIMENTAL_VERSION;
return version() == TLS1_3_VERSION || version() == DTLS1_3_VERSION;
}
bool is_dtls() const {
@@ -2799,7 +2798,7 @@ TEST_P(SSLVersionTest, SequenceNumber) {
uint64_t server_write_seq = SSL_get_write_sequence(server_.get());
if (is_dtls()) {
if (version() == DTLS1_3_EXPERIMENTAL_VERSION) {
if (version() == DTLS1_3_VERSION) {
// Both client and server must be at epoch 3 (application data).
EXPECT_EQ(EpochFromSequence(client_write_seq), 3);
EXPECT_EQ(EpochFromSequence(server_write_seq), 3);
@@ -2830,7 +2829,7 @@ TEST_P(SSLVersionTest, SequenceNumber) {
EXPECT_EQ(SSL_write(client_.get(), &byte, 1), 1);
EXPECT_EQ(SSL_read(server_.get(), &byte, 1), 1);
if (version() == DTLS1_3_EXPERIMENTAL_VERSION) {
if (version() == DTLS1_3_VERSION) {
// TODO(crbug.com/42290608): Write an appropriate test for incrementing both
// sequence number and epoch in the following test. The server read seq was
// in epoch 2, but after the write it's in epoch 3, so adding 1 doesn't work
@@ -3985,7 +3984,7 @@ static const char *GetVersionName(uint16_t version) {
return "DTLSv1";
case DTLS1_2_VERSION:
return "DTLSv1.2";
case DTLS1_3_EXPERIMENTAL_VERSION:
case DTLS1_3_VERSION:
return "DTLSv1.3";
default:
return "???";
@@ -4376,7 +4375,7 @@ TEST_P(SSLVersionTest, SSLWriteRetry) {
}
TEST_P(SSLVersionTest, RecordCallback) {
if (version() == DTLS1_3_EXPERIMENTAL_VERSION) {
if (version() == DTLS1_3_VERSION) {
// The DTLS 1.3 record header is vastly different than the TLS or DTLS < 1.3
// header format. Instead of checking that the record header is formatted as
// expected here, the runner implementation in dtls.go is strict about what
@@ -9749,14 +9748,10 @@ TEST(SSLTest, EarlyDataDisabledInDTLS13) {
SSL_CTX_set_early_data_enabled(server_ctx.get(), true);
SSL_CTX_set_session_cache_mode(client_ctx.get(), SSL_SESS_CACHE_BOTH);
SSL_CTX_set_session_cache_mode(server_ctx.get(), SSL_SESS_CACHE_BOTH);
ASSERT_TRUE(SSL_CTX_set_min_proto_version(client_ctx.get(),
DTLS1_3_EXPERIMENTAL_VERSION));
ASSERT_TRUE(SSL_CTX_set_max_proto_version(client_ctx.get(),
DTLS1_3_EXPERIMENTAL_VERSION));
ASSERT_TRUE(SSL_CTX_set_min_proto_version(server_ctx.get(),
DTLS1_3_EXPERIMENTAL_VERSION));
ASSERT_TRUE(SSL_CTX_set_max_proto_version(server_ctx.get(),
DTLS1_3_EXPERIMENTAL_VERSION));
ASSERT_TRUE(SSL_CTX_set_min_proto_version(client_ctx.get(), DTLS1_3_VERSION));
ASSERT_TRUE(SSL_CTX_set_max_proto_version(client_ctx.get(), DTLS1_3_VERSION));
ASSERT_TRUE(SSL_CTX_set_min_proto_version(server_ctx.get(), DTLS1_3_VERSION));
ASSERT_TRUE(SSL_CTX_set_max_proto_version(server_ctx.get(), DTLS1_3_VERSION));
bssl::UniquePtr<SSL_SESSION> session =
CreateClientSession(client_ctx.get(), server_ctx.get());
+5 -3
View File
@@ -46,7 +46,7 @@ bool ssl_protocol_version_from_wire(uint16_t *out, uint16_t version) {
*out = TLS1_2_VERSION;
return true;
case DTLS1_3_EXPERIMENTAL_VERSION:
case DTLS1_3_VERSION:
*out = TLS1_3_VERSION;
return true;
@@ -66,7 +66,7 @@ static const uint16_t kTLSVersions[] = {
};
static const uint16_t kDTLSVersions[] = {
DTLS1_3_EXPERIMENTAL_VERSION,
DTLS1_3_VERSION,
DTLS1_2_VERSION,
DTLS1_VERSION,
};
@@ -104,7 +104,7 @@ static const VersionInfo kVersionNames[] = {
{TLS1_VERSION, "TLSv1"},
{DTLS1_VERSION, "DTLSv1"},
{DTLS1_2_VERSION, "DTLSv1.2"},
{DTLS1_3_EXPERIMENTAL_VERSION, "DTLSv1.3"},
{DTLS1_3_VERSION, "DTLSv1.3"},
};
static const char *ssl_version_to_string(uint16_t version) {
@@ -156,6 +156,8 @@ static bool set_min_version(const SSL_PROTOCOL_METHOD *method, uint16_t *out,
static bool set_max_version(const SSL_PROTOCOL_METHOD *method, uint16_t *out,
uint16_t version) {
// Zero is interpreted as the default maximum version.
// TODO(crbug.com/42290594): Enable DTLS 1.3 by default, after it's
// successfully shipped in WebRTC.
if (version == 0) {
*out = method->is_dtls ? DTLS1_2_VERSION : TLS1_3_VERSION;
return true;
+6 -1
View File
@@ -414,7 +414,12 @@ class TLSFuzzer {
SSL_CTX_enable_ocsp_stapling(ctx_.get());
// Enable versions and ciphers that are off by default.
if (!SSL_CTX_set_strict_cipher_list(ctx_.get(), "ALL:3DES")) {
uint16_t min_version = protocol_ == kDTLS ? DTLS1_VERSION : TLS1_VERSION;
uint16_t max_version =
protocol_ == kDTLS ? DTLS1_3_VERSION : TLS1_3_VERSION;
if (!SSL_CTX_set_min_proto_version(ctx_.get(), min_version) ||
!SSL_CTX_set_max_proto_version(ctx_.get(), max_version) ||
!SSL_CTX_set_strict_cipher_list(ctx_.get(), "ALL:3DES")) {
return false;
}
+10 -5
View File
@@ -31,9 +31,9 @@ const (
)
const (
VersionDTLS10 = 0xfeff
VersionDTLS12 = 0xfefd
VersionDTLS125Experimental = 0xfc25
VersionDTLS10 = 0xfeff
VersionDTLS12 = 0xfefd
VersionDTLS13 = 0xfefc
)
var allTLSWireVersions = []uint16{
@@ -45,7 +45,7 @@ var allTLSWireVersions = []uint16{
}
var allDTLSWireVersions = []uint16{
VersionDTLS125Experimental,
VersionDTLS13,
VersionDTLS12,
VersionDTLS10,
}
@@ -1291,6 +1291,11 @@ type ProtocolBugs struct {
// post-handshake transaction) in DTLS. See DTLSController for details.
ACKFlightDTLS ACKFlightFunc
// SkipImplicitACKRead, if true, causes the DTLS 1.3 client to skip
// implicitly reading the ACK at the end of the handshake. This may be used
// when WriteFlightDTLS consumes the ACK itself.
SkipImplicitACKRead bool
// MockQUICTransport is the mockQUICTransport used when testing
// QUIC interfaces.
MockQUICTransport *mockQUICTransport
@@ -2121,7 +2126,7 @@ func (c *Config) echCipherSuitePreferences() []HPKECipherSuite {
func wireToVersion(vers uint16, isDTLS bool) (uint16, bool) {
if isDTLS {
switch vers {
case VersionDTLS125Experimental:
case VersionDTLS13:
return VersionTLS13, true
case VersionDTLS12:
return VersionTLS12, true
+9 -8
View File
@@ -848,7 +848,7 @@ func (hs *clientHandshakeState) createClientHello(innerHello *clientHelloMsg, ec
if session.vers < VersionTLS13 {
version = VersionTLS13
if c.isDTLS {
version = VersionDTLS125Experimental
version = VersionDTLS13
}
}
generatePSKBinders(version, c.isDTLS, hello, session, nil, nil, c.config)
@@ -1477,9 +1477,6 @@ func (hs *clientHandshakeState) doTLS13Handshake(msg any) error {
if c.config.Bugs.SendExtraFinished {
c.writeRecord(recordTypeHandshake, finished.marshal())
}
if err := c.flushHandshake(); err != nil {
return err
}
if data := c.config.Bugs.AppDataBeforeTLS13KeyChange; data != nil {
c.writeRecord(recordTypeApplicationData, data)
@@ -1488,14 +1485,18 @@ func (hs *clientHandshakeState) doTLS13Handshake(msg any) error {
// Switch to application data keys.
c.useOutTrafficSecret(uint16(encryptionApplication), c.wireVersion, hs.suite, clientTrafficSecret)
c.resumptionSecret = hs.finishedHash.deriveSecret(resumptionLabel)
for _, ticket := range deferredTickets {
if err := c.processTLS13NewSessionTicket(ticket, hs.suite); err != nil {
if err := c.flushHandshake(); err != nil {
return err
}
if c.isDTLS && len(c.expectedACK) != 0 && !c.config.Bugs.SkipImplicitACKRead {
if err := c.readRecord(recordTypeACK); err != nil {
return err
}
}
if c.isDTLS && len(c.expectedACK) != 0 {
if err := c.readRecord(recordTypeACK); err != nil {
for _, ticket := range deferredTickets {
if err := c.processTLS13NewSessionTicket(ticket, hs.suite); err != nil {
return err
}
}
+185 -64
View File
@@ -1903,7 +1903,7 @@ var tlsVersions = []tlsVersion{
excludeFlag: "-no-tls13",
hasQUIC: true,
hasDTLS: true,
versionDTLS: VersionDTLS125Experimental,
versionDTLS: VersionDTLS13,
versionWire: VersionTLS13,
},
}
@@ -3466,6 +3466,45 @@ read alert 1 0
expectedError: ":EXCESS_HANDSHAKE_DATA:",
expectedLocalError: "remote error: unexpected message",
},
{
protocol: dtls,
testType: serverTest,
name: "DTLS13-SendExtraFinished-AfterAppData",
config: Config{
MaxVersion: VersionTLS13,
Bugs: ProtocolBugs{
SkipImplicitACKRead: true,
WriteFlightDTLS: func(c *DTLSController, prev, received, next []DTLSMessage, records []DTLSRecordNumberInfo) {
if next[len(next)-1].Type != typeFinished {
c.WriteFlight(next)
return
}
// Complete the handshake.
c.WriteFlight(next)
c.ReadACK(c.InEpoch())
// Send some application data. The shim is now on epoch 3.
msg := []byte("hello")
c.WriteAppData(c.OutEpoch(), msg)
c.ReadAppData(c.InEpoch(), expectedReply(msg))
// The shim is still accepting data from epoch 2, so it can
// ACK a retransmit if needed, but it should not accept new
// messages at epoch three.
extraFinished := next[len(next)-1]
extraFinished.Sequence++
c.WriteFlight([]DTLSMessage{extraFinished})
},
},
},
shouldFail: true,
expectedError: ":EXCESS_HANDSHAKE_DATA:",
expectedLocalError: "remote error: unexpected message",
// Disable tickets on the shim to avoid NewSessionTicket
// interfering with the test callback.
flags: []string{"-no-ticket"},
},
{
testType: serverTest,
name: "V2ClientHello-EmptyRecordPrefix",
@@ -6852,8 +6891,9 @@ func addVersionNegotiationTests() {
name: "MinorVersionTolerance-DTLS",
config: Config{
Bugs: ProtocolBugs{
SendClientVersion: 0xfe00,
OmitSupportedVersions: true,
SendClientVersion: 0xfe00,
OmitSupportedVersions: true,
IgnoreTLS13DowngradeRandom: true,
},
},
expectations: connectionExpectations{
@@ -6866,8 +6906,9 @@ func addVersionNegotiationTests() {
name: "MajorVersionTolerance-DTLS",
config: Config{
Bugs: ProtocolBugs{
SendClientVersion: 0xfdff,
OmitSupportedVersions: true,
SendClientVersion: 0xfdff,
OmitSupportedVersions: true,
IgnoreTLS13DowngradeRandom: true,
},
},
expectations: connectionExpectations{
@@ -6914,49 +6955,50 @@ func addVersionNegotiationTests() {
})
// Test TLS 1.3's downgrade signal.
var downgradeTests = []struct {
name string
version uint16
clientShimError string
}{
{"TLS12", VersionTLS12, "tls: downgrade from TLS 1.3 detected"},
{"TLS11", VersionTLS11, "tls: downgrade from TLS 1.2 detected"},
// TLS 1.0 does not have a dedicated value.
{"TLS10", VersionTLS10, "tls: downgrade from TLS 1.2 detected"},
}
for _, test := range downgradeTests {
// The client should enforce the downgrade sentinel.
testCases = append(testCases, testCase{
name: "Downgrade-" + test.name + "-Client",
config: Config{
Bugs: ProtocolBugs{
NegotiateVersion: test.version,
for _, protocol := range []protocol{tls, dtls} {
for _, vers := range allVersions(protocol) {
if vers.version >= VersionTLS13 {
continue
}
clientShimError := "tls: downgrade from TLS 1.3 detected"
if vers.version < VersionTLS12 {
clientShimError = "tls: downgrade from TLS 1.2 detected"
}
// for _, test := range downgradeTests {
// The client should enforce the downgrade sentinel.
testCases = append(testCases, testCase{
protocol: protocol,
name: "Downgrade-" + vers.name + "-Client-" + protocol.String(),
config: Config{
Bugs: ProtocolBugs{
NegotiateVersion: vers.wire(protocol),
},
},
},
expectations: connectionExpectations{
version: test.version,
},
shouldFail: true,
expectedError: ":TLS13_DOWNGRADE:",
expectedLocalError: "remote error: illegal parameter",
})
// The server should emit the downgrade signal.
testCases = append(testCases, testCase{
testType: serverTest,
name: "Downgrade-" + test.name + "-Server",
config: Config{
Bugs: ProtocolBugs{
SendSupportedVersions: []uint16{test.version},
expectations: connectionExpectations{
version: vers.version,
},
},
expectations: connectionExpectations{
version: test.version,
},
shouldFail: true,
expectedLocalError: test.clientShimError,
})
shouldFail: true,
expectedError: ":TLS13_DOWNGRADE:",
expectedLocalError: "remote error: illegal parameter",
})
// The server should emit the downgrade signal.
testCases = append(testCases, testCase{
protocol: protocol,
testType: serverTest,
name: "Downgrade-" + vers.name + "-Server-" + protocol.String(),
config: Config{
Bugs: ProtocolBugs{
SendSupportedVersions: []uint16{vers.wire(protocol)},
},
},
expectations: connectionExpectations{
version: vers.version,
},
shouldFail: true,
expectedLocalError: clientShimError,
})
}
}
// SSL 3.0 support has been removed. Test that the shim does not
@@ -11548,6 +11590,10 @@ var shortTimeouts = []time.Duration{
60 * time.Second,
}
// dtlsPrevEpochExpiration is how long before the shim releases old epochs. Add
// an extra second to allow the shim to be less precise.
const dtlsPrevEpochExpiration = 4*time.Minute + 1*time.Second
func addDTLSRetransmitTests() {
for _, shortTimeout := range []bool{false, true} {
for _, vers := range allVersions(dtls) {
@@ -11899,8 +11945,9 @@ func addDTLSRetransmitTests() {
MaxHandshakeRecordLength: 512,
WriteFlightDTLS: func(c *DTLSController, prev, received, next []DTLSMessage, records []DTLSRecordNumberInfo) {
if len(received) > 0 {
ackEpoch := received[len(received)-1].Epoch
c.ExpectNextTimeout(useTimeouts[0])
c.WriteACK(c.OutEpoch(), records)
c.WriteACK(ackEpoch, records)
// After everything is ACKed, the shim should stop the timer
// and wait for the next flight.
c.ExpectNoNextTimeout()
@@ -11911,8 +11958,9 @@ func addDTLSRetransmitTests() {
c.WriteFlight(next)
},
ACKFlightDTLS: handleNewSessionTicket(func(c *DTLSController, prev, received []DTLSMessage, records []DTLSRecordNumberInfo) {
ackEpoch := received[len(received)-1].Epoch
c.ExpectNextTimeout(useTimeouts[0])
c.WriteACK(c.OutEpoch(), records)
c.WriteACK(ackEpoch, records)
// After everything is ACKed, the shim should stop the timer.
c.ExpectNoNextTimeout()
for _, t := range useTimeouts {
@@ -11948,9 +11996,10 @@ func addDTLSRetransmitTests() {
MaxPacketLength: 512,
WriteFlightDTLS: func(c *DTLSController, prev, received, next []DTLSMessage, records []DTLSRecordNumberInfo) {
if len(received) > 0 {
ackEpoch := received[len(received)-1].Epoch
for _, t := range useTimeouts[:len(useTimeouts)-1] {
if len(records) > 0 {
c.WriteACK(c.OutEpoch(), []DTLSRecordNumberInfo{records[len(records)-1]})
c.WriteACK(ackEpoch, []DTLSRecordNumberInfo{records[len(records)-1]})
}
c.AdvanceClock(t)
records = c.ReadRetransmit()
@@ -11959,9 +12008,10 @@ func addDTLSRetransmitTests() {
c.WriteFlight(next)
},
ACKFlightDTLS: handleNewSessionTicket(func(c *DTLSController, prev, received []DTLSMessage, records []DTLSRecordNumberInfo) {
ackEpoch := received[len(received)-1].Epoch
for _, t := range useTimeouts[:len(useTimeouts)-1] {
if len(records) > 0 {
c.WriteACK(c.OutEpoch(), []DTLSRecordNumberInfo{records[len(records)-1]})
c.WriteACK(ackEpoch, []DTLSRecordNumberInfo{records[len(records)-1]})
}
c.AdvanceClock(t)
records = c.ReadRetransmit()
@@ -11986,9 +12036,10 @@ func addDTLSRetransmitTests() {
MaxPacketLength: 512,
WriteFlightDTLS: func(c *DTLSController, prev, received, next []DTLSMessage, records []DTLSRecordNumberInfo) {
if len(received) > 0 {
ackEpoch := received[len(received)-1].Epoch
for _, t := range useTimeouts[:len(useTimeouts)-1] {
if len(records) > 0 {
c.WriteACK(c.OutEpoch(), []DTLSRecordNumberInfo{records[0]})
c.WriteACK(ackEpoch, []DTLSRecordNumberInfo{records[0]})
}
c.AdvanceClock(t)
records = c.ReadRetransmit()
@@ -11997,9 +12048,10 @@ func addDTLSRetransmitTests() {
c.WriteFlight(next)
},
ACKFlightDTLS: handleNewSessionTicket(func(c *DTLSController, prev, received []DTLSMessage, records []DTLSRecordNumberInfo) {
ackEpoch := received[len(received)-1].Epoch
for _, t := range useTimeouts[:len(useTimeouts)-1] {
if len(records) > 0 {
c.WriteACK(c.OutEpoch(), []DTLSRecordNumberInfo{records[0]})
c.WriteACK(ackEpoch, []DTLSRecordNumberInfo{records[0]})
}
c.AdvanceClock(t)
records = c.ReadRetransmit()
@@ -12024,13 +12076,14 @@ func addDTLSRetransmitTests() {
MaxPacketLength: 512,
WriteFlightDTLS: func(c *DTLSController, prev, received, next []DTLSMessage, records []DTLSRecordNumberInfo) {
if len(received) > 0 {
ackEpoch := received[len(received)-1].Epoch
for i, t := range useTimeouts[:len(useTimeouts)-1] {
if len(records) > 0 {
ack := make([]DTLSRecordNumberInfo, 0, (len(records)+2)/3)
for i := 0; i < len(records); i += 3 {
ack = append(ack, records[i])
}
c.WriteACK(c.OutEpoch(), ack)
c.WriteACK(ackEpoch, ack)
}
// Change the MTU every iteration, to make the fragment
// patterns more complex.
@@ -12042,9 +12095,10 @@ func addDTLSRetransmitTests() {
c.WriteFlight(next)
},
ACKFlightDTLS: handleNewSessionTicket(func(c *DTLSController, prev, received []DTLSMessage, records []DTLSRecordNumberInfo) {
ackEpoch := received[len(received)-1].Epoch
for _, t := range useTimeouts[:len(useTimeouts)-1] {
if len(records) > 0 {
c.WriteACK(c.OutEpoch(), []DTLSRecordNumberInfo{records[0]})
c.WriteACK(ackEpoch, []DTLSRecordNumberInfo{records[0]})
}
c.AdvanceClock(t)
records = c.ReadRetransmit()
@@ -12067,26 +12121,28 @@ func addDTLSRetransmitTests() {
SendHelloRetryRequestCookie: []byte("cookie"),
WriteFlightDTLS: func(c *DTLSController, prev, received, next []DTLSMessage, records []DTLSRecordNumberInfo) {
if len(received) > 0 {
ackEpoch := received[len(received)-1].Epoch
// Keep ACKing the same record over and over.
c.WriteACK(c.OutEpoch(), records[:1])
c.WriteACK(ackEpoch, records[:1])
c.AdvanceClock(useTimeouts[0])
c.ReadRetransmit()
c.WriteACK(c.OutEpoch(), records[:1])
c.WriteACK(ackEpoch, records[:1])
c.AdvanceClock(useTimeouts[1])
c.ReadRetransmit()
}
c.WriteFlight(next)
},
ACKFlightDTLS: handleNewSessionTicket(func(c *DTLSController, prev, received []DTLSMessage, records []DTLSRecordNumberInfo) {
ackEpoch := received[len(received)-1].Epoch
// Keep ACKing the same record over and over.
c.WriteACK(c.OutEpoch(), records[:1])
c.WriteACK(ackEpoch, records[:1])
c.AdvanceClock(useTimeouts[0])
c.ReadRetransmit()
c.WriteACK(c.OutEpoch(), records[:1])
c.WriteACK(ackEpoch, records[:1])
c.AdvanceClock(useTimeouts[1])
c.ReadRetransmit()
// ACK everything to clear the timer.
c.WriteACK(c.OutEpoch(), records)
c.WriteACK(ackEpoch, records)
}),
},
},
@@ -12185,10 +12241,11 @@ func addDTLSRetransmitTests() {
MaxPacketLength: 512,
WriteFlightDTLS: func(c *DTLSController, prev, received, next []DTLSMessage, records []DTLSRecordNumberInfo) {
if len(received) > 0 {
c.WriteACK(c.OutEpoch(), records[len(records)/2:])
ackEpoch := received[len(received)-1].Epoch
c.WriteACK(ackEpoch, records[len(records)/2:])
c.AdvanceClock(useTimeouts[0])
c.ReadRetransmit()
c.WriteACK(c.OutEpoch(), records[:len(records)/2])
c.WriteACK(ackEpoch, records[:len(records)/2])
// Everything should be ACKed now. The shim should not
// retransmit anything.
c.AdvanceClock(useTimeouts[1])
@@ -12295,6 +12352,59 @@ func addDTLSRetransmitTests() {
flags: flags,
})
// The server must continue to ACK the Finished flight even after
// receiving application data from the client.
testCases = append(testCases, testCase{
protocol: dtls,
testType: serverTest,
name: "DTLS-Retransmit-Server-ACKFinishedAfterAppData" + suffix,
config: Config{
MaxVersion: vers.version,
Bugs: ProtocolBugs{
// WriteFlightDTLS will handle consuming ACKs.
SkipImplicitACKRead: true,
WriteFlightDTLS: func(c *DTLSController, prev, received, next []DTLSMessage, records []DTLSRecordNumberInfo) {
if next[len(next)-1].Type != typeFinished {
c.WriteFlight(next)
return
}
// Write Finished. The shim should ACK it immediately.
c.WriteFlight(next)
c.ReadACK(c.InEpoch())
// Exchange some application data.
msg := []byte("hello")
c.WriteAppData(c.OutEpoch(), msg)
c.ReadAppData(c.InEpoch(), expectedReply(msg))
// Act as if the ACK was dropped and retransmit Finished.
// The shim should process the retransmit from epoch 2 and
// ACK, although it has already received data at epoch 3.
c.WriteFlight(next)
ackTimeout := useTimeouts[0] / 4
c.AdvanceClock(ackTimeout)
c.ReadACK(c.InEpoch())
// Partially retransmit Finished. The shim should continue
// to ACK.
c.WriteFragments([]DTLSFragment{next[0].Fragment(0, 1)})
c.WriteFragments([]DTLSFragment{next[0].Fragment(1, 1)})
c.AdvanceClock(ackTimeout)
c.ReadACK(c.InEpoch())
// Eventually, the shim assumes we have received the ACK
// and drops epoch 2. Retransmits now go unanswered.
c.AdvanceClock(dtlsPrevEpochExpiration)
c.WriteFlight(next)
},
},
},
// Disable tickets on the shim to avoid NewSessionTicket
// interfering with the test callback.
flags: slices.Concat(flags, []string{"-no-ticket"}),
})
// As a client, the shim must tolerate ACKs in response to its
// initial ClientHello, but it will not process them because the
// version is not yet known. The second ClientHello, in response
@@ -22259,9 +22369,20 @@ func addKeyUpdateTests() {
c.WriteAppData(c.OutEpoch(), msg)
c.ReadAppData(c.InEpoch(), expectedReply(msg))
// Having received something at the new epoch, the shim
// should discard the old epoch. The following writes should
// be ignored.
// The shim continues to accept application data at the old
// epoch, for a period of time.
c.WriteAppData(c.OutEpoch()-1, msg)
c.ReadAppData(c.InEpoch(), expectedReply(msg))
// It will even ACK the retransmission, though it knows the
// shim has seen the ACK.
c.WriteFlight(next)
c.AdvanceClock(ackTimeout)
c.ReadACK(c.InEpoch())
// After some time has passed, the shim will discard the old
// epoch. The following writes should be ignored.
c.AdvanceClock(dtlsPrevEpochExpiration)
f := next[0].Fragment(0, len(next[0].Data))
f.ShouldDiscard = true
c.WriteFragments([]DTLSFragment{f})
+2 -1
View File
@@ -2316,8 +2316,9 @@ bssl::UniquePtr<SSL> TestConfig::NewSSL(
!SSL_set_min_proto_version(ssl.get(), min_version)) {
return nullptr;
}
// TODO(crbug.com/42290594): Remove this once DTLS 1.3 is enabled by default.
if (is_dtls && max_version == 0 &&
!SSL_set_max_proto_version(ssl.get(), DTLS1_3_EXPERIMENTAL_VERSION)) {
!SSL_set_max_proto_version(ssl.get(), DTLS1_3_VERSION)) {
return nullptr;
}
if (max_version != 0 &&