Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Bug 1599514 - Update DTLS 1.3 support to draft-30 r=mt
This patch updates the DTLS 1.3 implementation to draft version 30, including unified header format and sequence number encryption.

Also added are new `SSL_CreateMask` experimental functions.

Differential Revision: https://phabricator.services.mozilla.com/D51014

--HG--
rename : gtests/ssl_gtest/ssl_primitive_unittest.cc => gtests/ssl_gtest/ssl_aead_unittest.cc
extra : moz-landing-system : lando
  • Loading branch information
Kevin Jacobs committed Jan 6, 2020
1 parent c2f253f commit 7755a62
Show file tree
Hide file tree
Showing 32 changed files with 1,252 additions and 260 deletions.
1 change: 1 addition & 0 deletions cpputil/databuffer.h
Expand Up @@ -23,6 +23,7 @@ class DataBuffer {
DataBuffer(const DataBuffer& other) : data_(nullptr), len_(0) {
Assign(other);
}
explicit DataBuffer(size_t l) : data_(nullptr), len_(0) { Allocate(l); }
~DataBuffer() { delete[] data_; }

DataBuffer& operator=(const DataBuffer& other) {
Expand Down
2 changes: 2 additions & 0 deletions cpputil/scoped_ptrs_ssl.h
Expand Up @@ -12,6 +12,7 @@

struct ScopedDeleteSSL {
void operator()(SSLAeadContext* ctx) { SSL_DestroyAead(ctx); }
void operator()(SSLMaskingContext* ctx) { SSL_DestroyMaskingContext(ctx); }
void operator()(SSLAntiReplayContext* ctx) {
SSL_ReleaseAntiReplayContext(ctx);
}
Expand All @@ -34,6 +35,7 @@ struct ScopedMaybeDeleteSSL {

SCOPED(SSLAeadContext);
SCOPED(SSLAntiReplayContext);
SCOPED(SSLMaskingContext);
SCOPED(SSLResumptionTokenInfo);

#undef SCOPED
Expand Down
5 changes: 5 additions & 0 deletions cpputil/tls_parser.h
Expand Up @@ -74,6 +74,11 @@ const uint8_t kTlsFakeChangeCipherSpec[] = {
0x01 // Value
};

const uint8_t kCtDtlsCiphertext = 0x20;
const uint8_t kCtDtlsCiphertextMask = 0xE0;
const uint8_t kCtDtlsCiphertext16bSeqno = 0x08;
const uint8_t kCtDtlsCiphertextLengthPresent = 0x04;

static const uint8_t kTls13PskKe = 0;
static const uint8_t kTls13PskDhKe = 1;
static const uint8_t kTls13PskAuth = 0;
Expand Down
3 changes: 2 additions & 1 deletion gtests/ssl_gtest/manifest.mn
Expand Up @@ -14,6 +14,7 @@ CSRCS = \
CPPSRCS = \
bloomfilter_unittest.cc \
ssl_0rtt_unittest.cc \
ssl_aead_unittest.cc \
ssl_agent_unittest.cc \
ssl_auth_unittest.cc \
ssl_cert_ext_unittest.cc \
Expand All @@ -35,8 +36,8 @@ CPPSRCS = \
ssl_hrr_unittest.cc \
ssl_keyupdate_unittest.cc \
ssl_loopback_unittest.cc \
ssl_masking_unittest.cc \
ssl_misc_unittest.cc \
ssl_primitive_unittest.cc \
ssl_record_unittest.cc \
ssl_recordsep_unittest.cc \
ssl_recordsize_unittest.cc \
Expand Down
Expand Up @@ -54,7 +54,7 @@ class AeadTest : public ::testing::Test {
ASSERT_GE(kMaxSize, ciphertext_len);
ASSERT_LT(0U, ciphertext_len);

uint8_t output[kMaxSize];
uint8_t output[kMaxSize] = {0};
unsigned int output_len = 0;
EXPECT_EQ(SECSuccess, SSL_AeadEncrypt(ctx.get(), 0, kAad, sizeof(kAad),
kPlaintext, sizeof(kPlaintext),
Expand Down Expand Up @@ -181,7 +181,7 @@ TEST_F(AeadTest, AeadNoPointer) {
}

TEST_F(AeadTest, AeadAes128Gcm) {
SSLAeadContext *ctxInit;
SSLAeadContext *ctxInit = nullptr;
ASSERT_EQ(SECSuccess,
SSL_MakeAead(SSL_LIBRARY_VERSION_TLS_1_3, TLS_AES_128_GCM_SHA256,
secret_.get(), kLabel, strlen(kLabel), &ctxInit));
Expand All @@ -203,7 +203,7 @@ TEST_F(AeadTest, AeadAes256Gcm) {
}

TEST_F(AeadTest, AeadChaCha20Poly1305) {
SSLAeadContext *ctxInit;
SSLAeadContext *ctxInit = nullptr;
ASSERT_EQ(
SECSuccess,
SSL_MakeAead(SSL_LIBRARY_VERSION_TLS_1_3, TLS_CHACHA20_POLY1305_SHA256,
Expand Down
27 changes: 25 additions & 2 deletions gtests/ssl_gtest/ssl_ciphersuite_unittest.cc
Expand Up @@ -263,6 +263,7 @@ TEST_P(TlsCipherSuiteTest, ResumeCipherSuite) {
TEST_P(TlsCipherSuiteTest, ReadLimit) {
SetupCertificate();
EnableSingleCipher();
TlsSendCipherSpecCapturer capturer(client_);
ConnectAndCheckCipherSuite();
if (version_ < SSL_LIBRARY_VERSION_TLS_1_3) {
uint64_t last = last_safe_write();
Expand Down Expand Up @@ -295,9 +296,31 @@ TEST_P(TlsCipherSuiteTest, ReadLimit) {
} else {
epoch = 0;
}

uint64_t seqno = (epoch << 48) | record_limit();

// DTLS 1.3 masks the sequence number
if (variant_ == ssl_variant_datagram &&
version_ >= SSL_LIBRARY_VERSION_TLS_1_3) {
auto spec = capturer.spec(1);
ASSERT_NE(nullptr, spec.get());
ASSERT_EQ(3, spec->epoch());

DataBuffer pt, ct;
uint8_t dtls13_ctype = kCtDtlsCiphertext | kCtDtlsCiphertext16bSeqno |
kCtDtlsCiphertextLengthPresent;
TlsRecordHeader hdr(variant_, version_, dtls13_ctype, seqno);
pt.Assign(payload, sizeof(payload));
TlsRecordHeader out_hdr;
spec->Protect(hdr, pt, &ct, &out_hdr);

auto rv = out_hdr.Write(&record, 0, ct);
EXPECT_EQ(out_hdr.header_length() + ct.len(), rv);
} else {
TlsAgentTestBase::MakeRecord(variant_, ssl_ct_application_data, version_,
payload, sizeof(payload), &record,
(epoch << 48) | record_limit());
payload, sizeof(payload), &record, seqno);
}

client_->SendDirect(record);
server_->ExpectReadWriteError();
server_->ReadBytes();
Expand Down
69 changes: 13 additions & 56 deletions gtests/ssl_gtest/ssl_drop_unittest.cc
Expand Up @@ -619,55 +619,6 @@ TEST_P(TlsDropDatagram13, ReorderServerEE) {

// The client sends an out of order non-handshake message
// but with the handshake key.
class TlsSendCipherSpecCapturer {
public:
TlsSendCipherSpecCapturer(const std::shared_ptr<TlsAgent>& agent)
: agent_(agent), send_cipher_specs_() {
EXPECT_EQ(SECSuccess,
SSL_SecretCallback(agent_->ssl_fd(), SecretCallback, this));
}

std::shared_ptr<TlsCipherSpec> spec(size_t i) {
if (i >= send_cipher_specs_.size()) {
return nullptr;
}
return send_cipher_specs_[i];
}

private:
static void SecretCallback(PRFileDesc* fd, PRUint16 epoch,
SSLSecretDirection dir, PK11SymKey* secret,
void* arg) {
auto self = static_cast<TlsSendCipherSpecCapturer*>(arg);
std::cerr << self->agent_->role_str() << ": capture " << dir
<< " secret for epoch " << epoch << std::endl;

if (dir == ssl_secret_read) {
return;
}

SSLPreliminaryChannelInfo preinfo;
EXPECT_EQ(SECSuccess,
SSL_GetPreliminaryChannelInfo(self->agent_->ssl_fd(), &preinfo,
sizeof(preinfo)));
EXPECT_EQ(sizeof(preinfo), preinfo.length);
EXPECT_TRUE(preinfo.valuesSet & ssl_preinfo_cipher_suite);

SSLCipherSuiteInfo cipherinfo;
EXPECT_EQ(SECSuccess,
SSL_GetCipherSuiteInfo(preinfo.cipherSuite, &cipherinfo,
sizeof(cipherinfo)));
EXPECT_EQ(sizeof(cipherinfo), cipherinfo.length);

auto spec = std::make_shared<TlsCipherSpec>(true, epoch);
EXPECT_TRUE(spec->SetKeys(&cipherinfo, secret));
self->send_cipher_specs_.push_back(spec);
}

std::shared_ptr<TlsAgent> agent_;
std::vector<std::shared_ptr<TlsCipherSpec>> send_cipher_specs_;
};

TEST_F(TlsConnectDatagram13, SendOutOfOrderAppWithHandshakeKey) {
StartConnect();
// Capturing secrets means that we can't use decrypting filters on the client.
Expand All @@ -684,8 +635,10 @@ TEST_F(TlsConnectDatagram13, SendOutOfOrderAppWithHandshakeKey) {
auto spec = capturer.spec(0);
ASSERT_NE(nullptr, spec.get());
ASSERT_EQ(2, spec->epoch());
ASSERT_TRUE(client_->SendEncryptedRecord(spec, 0x0002000000000002,
ssl_ct_application_data,

uint8_t dtls13_ct = kCtDtlsCiphertext | kCtDtlsCiphertext16bSeqno |
kCtDtlsCiphertextLengthPresent;
ASSERT_TRUE(client_->SendEncryptedRecord(spec, 0x0002000000000002, dtls13_ct,
DataBuffer(buf, sizeof(buf))));

// Now have the server consume the bogus message.
Expand Down Expand Up @@ -844,7 +797,7 @@ static void GetCipherAndLimit(uint16_t version, uint16_t* cipher,
// a reasonable amount of time.
*cipher = TLS_CHACHA20_POLY1305_SHA256;
// Assume that we are starting with an expected sequence number of 0.
*limit = (1ULL << 29) - 1;
*limit = (1ULL << 15) - 1;
}
}

Expand All @@ -866,14 +819,14 @@ TEST_P(TlsConnectDatagram, MissLotsOfPackets) {
SendReceive();
}

// Send a sequence number of 0xfffffffd and it should be interpreted as that
// Send a sequence number of 0xfffd and it should be interpreted as that
// (and not -3 or UINT64_MAX - 2).
TEST_F(TlsConnectDatagram13, UnderflowSequenceNumber) {
Connect();
// This is only valid if short headers are disabled.
client_->SetOption(SSL_ENABLE_DTLS_SHORT_HEADER, PR_FALSE);
EXPECT_EQ(SECSuccess,
SSLInt_AdvanceWriteSeqNum(client_->ssl_fd(), (1ULL << 30) - 3));
SSLInt_AdvanceWriteSeqNum(client_->ssl_fd(), (1ULL << 16) - 3));
SendReceive();
}

Expand Down Expand Up @@ -918,8 +871,12 @@ class TlsReplaceFirstRecordWithJunk : public TlsRecordFilter {
return KEEP;
}
replaced_ = true;
TlsRecordHeader out_header(header.variant(), header.version(),
ssl_ct_application_data,

uint8_t dtls13_ct = kCtDtlsCiphertext | kCtDtlsCiphertext16bSeqno |
kCtDtlsCiphertextLengthPresent;
TlsRecordHeader out_header(
header.variant(), header.version(),
is_dtls13() ? dtls13_ct : ssl_ct_application_data,
header.sequence_number());

static const uint8_t junk[] = {1, 2, 3, 4};
Expand Down
3 changes: 2 additions & 1 deletion gtests/ssl_gtest/ssl_gtest.gyp
Expand Up @@ -15,6 +15,7 @@
'libssl_internals.c',
'selfencrypt_unittest.cc',
'ssl_0rtt_unittest.cc',
'ssl_aead_unittest.cc',
'ssl_agent_unittest.cc',
'ssl_auth_unittest.cc',
'ssl_cert_ext_unittest.cc',
Expand All @@ -36,8 +37,8 @@
'ssl_hrr_unittest.cc',
'ssl_keyupdate_unittest.cc',
'ssl_loopback_unittest.cc',
'ssl_masking_unittest.cc',
'ssl_misc_unittest.cc',
'ssl_primitive_unittest.cc',
'ssl_record_unittest.cc',
'ssl_recordsep_unittest.cc',
'ssl_recordsize_unittest.cc',
Expand Down

0 comments on commit 7755a62

Please sign in to comment.