Skip to content

Commit

Permalink
Bug 1310991 - Fuzzing mode: Disable session ticket encryption and MAC…
Browse files Browse the repository at this point in the history
… checks r=franziskus

Differential Revision: https://nss-review.dev.mozaws.net/D254
  • Loading branch information
Tim Taubert committed Mar 16, 2017
1 parent 878c48c commit 6f334b7
Show file tree
Hide file tree
Showing 6 changed files with 130 additions and 3 deletions.
2 changes: 2 additions & 0 deletions coreconf/config.gypi
Expand Up @@ -363,10 +363,12 @@
[ 'fuzz_tls==1', {
'cflags': [
'-Wno-unused-function',
'-Wno-unused-variable',
],
'xcode_settings': {
'OTHER_CFLAGS': [
'-Wno-unused-function',
'-Wno-unused-variable',
],
},
}],
Expand Down
97 changes: 97 additions & 0 deletions gtests/ssl_gtest/ssl_fuzz_unittest.cc
Expand Up @@ -226,4 +226,101 @@ FUZZ_P(TlsConnectGeneric, BogusClientAuthSignature) {
std::make_shared<TlsSignatureDamager>(kTlsHandshakeCertificateVerify));
Connect();
}

// Check that session ticket resumption works.
FUZZ_P(TlsConnectGeneric, SessionTicketResumption) {
ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
Connect();
SendReceive();

Reset();
ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
ExpectResumption(RESUME_TICKET);
Connect();
SendReceive();
}

class TlsSessionTicketMacDamager : public TlsExtensionFilter {
public:
TlsSessionTicketMacDamager() {}
virtual PacketFilter::Action FilterExtension(uint16_t extension_type,
const DataBuffer& input,
DataBuffer* output) {
if (extension_type != ssl_session_ticket_xtn &&
extension_type != ssl_tls13_pre_shared_key_xtn) {
return KEEP;
}

*output = input;

// Handle everything before TLS 1.3.
if (extension_type == ssl_session_ticket_xtn) {
// Modify the last byte of the MAC.
output->data()[output->len() - 1] ^= 0xff;
}

// Handle TLS 1.3.
if (extension_type == ssl_tls13_pre_shared_key_xtn) {
TlsParser parser(input);

uint32_t ids_len;
EXPECT_TRUE(parser.Read(&ids_len, 2) && ids_len > 0);

uint32_t ticket_len;
EXPECT_TRUE(parser.Read(&ticket_len, 2) && ticket_len > 0);

// Modify the last byte of the MAC.
output->data()[2 + 2 + ticket_len - 1] ^= 0xff;
}

return CHANGE;
}
};

// Check that session ticket resumption works with a bad MAC.
FUZZ_P(TlsConnectGeneric, SessionTicketResumptionBadMac) {
ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
Connect();
SendReceive();

Reset();
ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
ExpectResumption(RESUME_TICKET);

client_->SetPacketFilter(std::make_shared<TlsSessionTicketMacDamager>());
Connect();
SendReceive();
}

// Check that session tickets are not encrypted.
FUZZ_P(TlsConnectGeneric, UnencryptedSessionTickets) {
ConfigureSessionCache(RESUME_TICKET, RESUME_TICKET);

auto i1 = std::make_shared<TlsInspectorRecordHandshakeMessage>(
kTlsHandshakeNewSessionTicket);
server_->SetPacketFilter(i1);
Connect();

size_t offset = 4; /* lifetime */
if (version_ == SSL_LIBRARY_VERSION_TLS_1_3) {
offset += 1 + 1 + /* ke_modes */
1 + 1; /* auth_modes */
}

offset += 2 + /* ticket length */
16 + /* SESS_TICKET_KEY_NAME_LEN */
16 + /* AES-128 IV */
2 + /* ciphertext length */
2; /* TLS_EX_SESS_TICKET_VERSION */

// Check the protocol version number.
uint32_t tls_version;
EXPECT_TRUE(i1->buffer().Read(offset, sizeof(version_), &tls_version));
EXPECT_EQ(version_, static_cast<decltype(version_)>(tls_version));

// Check the cipher suite.
uint32_t suite;
EXPECT_TRUE(i1->buffer().Read(offset + sizeof(version_), 2, &suite));
client_->CheckCipherSuite(static_cast<uint16_t>(suite));
}
}
4 changes: 4 additions & 0 deletions gtests/ssl_gtest/tls_agent.cc
Expand Up @@ -241,6 +241,10 @@ bool TlsAgent::GetPeerChainLength(size_t* count) {
return true;
}

void TlsAgent::CheckCipherSuite(uint16_t cipher_suite) {
EXPECT_EQ(csinfo_.cipherSuite, cipher_suite);
}

void TlsAgent::RequestClientAuth(bool requireAuth) {
EXPECT_TRUE(EnsureTlsSetup());
ASSERT_EQ(SERVER, role_);
Expand Down
1 change: 1 addition & 0 deletions gtests/ssl_gtest/tls_agent.h
Expand Up @@ -163,6 +163,7 @@ class TlsAgent : public PollTarget {
void ConfigNamedGroups(const std::vector<SSLNamedGroup>& groups);
void DisableECDHEServerKeyReuse();
bool GetPeerChainLength(size_t* count);
void CheckCipherSuite(uint16_t cipher_suite);

const std::string& name() const { return name_; }

Expand Down
1 change: 1 addition & 0 deletions gtests/ssl_gtest/tls_parser.h
Expand Up @@ -26,6 +26,7 @@ const uint8_t kTlsApplicationDataType = 23;

const uint8_t kTlsHandshakeClientHello = 1;
const uint8_t kTlsHandshakeServerHello = 2;
const uint8_t kTlsHandshakeNewSessionTicket = 4;
const uint8_t kTlsHandshakeHelloRetryRequest = 6;
const uint8_t kTlsHandshakeEncryptedExtensions = 8;
const uint8_t kTlsHandshakeCertificate = 11;
Expand Down
28 changes: 25 additions & 3 deletions lib/ssl/ssl3exthandle.c
Expand Up @@ -1004,9 +1004,13 @@ ssl3_EncodeSessionTicket(sslSocket *ss,
+ sizeof(ticket->ticket_lifetime_hint) /* ticket lifetime hint */
+ sizeof(ticket->flags) /* ticket flags */
+ 1 + alpnSelection.len; /* npn value + length field. */
#ifdef UNSAFE_FUZZER_MODE
padding_length = 0;
#else
padding_length = AES_BLOCK_SIZE -
(ciphertext_length %
AES_BLOCK_SIZE);
#endif
ciphertext_length += padding_length;

if (SECITEM_AllocItem(NULL, &plaintext_item, ciphertext_length) == NULL)
Expand Down Expand Up @@ -1159,6 +1163,10 @@ ssl3_EncodeSessionTicket(sslSocket *ss,

/* Generate encrypted portion of ticket. */
PORT_Assert(aes_key);
#ifdef UNSAFE_FUZZER_MODE
ciphertext.len = plaintext_item.len;
PORT_Memcpy(ciphertext.data, plaintext_item.data, plaintext_item.len);
#else
aes_ctx = PK11_CreateContextBySymKey(cipherMech, CKA_ENCRYPT, aes_key, &ivItem);
if (!aes_ctx)
goto loser;
Expand All @@ -1170,10 +1178,10 @@ ssl3_EncodeSessionTicket(sslSocket *ss,
PK11_DestroyContext(aes_ctx, PR_TRUE);
if (rv != SECSuccess)
goto loser;
#endif

/* Convert ciphertext length to network order. */
length_buf[0] = (ciphertext.len >> 8) & 0xff;
length_buf[1] = (ciphertext.len) & 0xff;
(void)ssl_EncodeUintX(ciphertext.len, 2, length_buf);

/* Compute MAC. */
PORT_Assert(mac_key);
Expand Down Expand Up @@ -1337,9 +1345,11 @@ ssl3_ProcessSessionTicketCommon(sslSocket *ss, SECItem *data)
*/
if (PORT_Memcmp(enc_session_ticket.key_name, key_name,
SESS_TICKET_KEY_NAME_LEN) != 0) {
#ifndef UNSAFE_FUZZER_MODE
SSL_DBG(("%d: SSL[%d]: Session ticket key_name sent mismatch.",
SSL_GETPID(), ss->fd));
goto no_ticket;
#endif
}

/* Verify the MAC on the ticket. MAC verification may also
Expand Down Expand Up @@ -1376,9 +1386,11 @@ ssl3_ProcessSessionTicketCommon(sslSocket *ss, SECItem *data)
if (NSS_SecureMemcmp(computed_mac, enc_session_ticket.mac,
computed_mac_length) !=
0) {
#ifndef UNSAFE_FUZZER_MODE
SSL_DBG(("%d: SSL[%d]: Session ticket MAC mismatch.",
SSL_GETPID(), ss->fd));
goto no_ticket;
#endif
}

/* We ignore key_name for now.
Expand All @@ -1392,6 +1404,12 @@ ssl3_ProcessSessionTicketCommon(sslSocket *ss, SECItem *data)
enc_session_ticket.encrypted_state.len);

PORT_Assert(aes_key);
#ifdef UNSAFE_FUZZER_MODE
decrypted_state->len = enc_session_ticket.encrypted_state.len;
PORT_Memcpy(decrypted_state->data,
enc_session_ticket.encrypted_state.data,
enc_session_ticket.encrypted_state.len);
#else
ivItem.data = enc_session_ticket.iv;
ivItem.len = AES_BLOCK_SIZE;
aes_ctx = PK11_CreateContextBySymKey(cipherMech, CKA_DECRYPT,
Expand Down Expand Up @@ -1422,6 +1440,7 @@ ssl3_ProcessSessionTicketCommon(sslSocket *ss, SECItem *data)
if (padding_length != (PRUint32)*padding)
goto no_ticket;
}
#endif

/* Deserialize session state. */
buffer = decrypted_state->data;
Expand Down Expand Up @@ -1589,9 +1608,12 @@ ssl3_ProcessSessionTicketCommon(sslSocket *ss, SECItem *data)
goto no_ticket;
}

#ifndef UNSAFE_FUZZER_MODE
/* Done parsing. Check that all bytes have been consumed. */
if (buffer_len != padding_length)
if (buffer_len != padding_length) {
goto no_ticket;
}
#endif

/* Use the ticket if it has not expired, otherwise free the allocated
* memory since the ticket is of no use.
Expand Down

0 comments on commit 6f334b7

Please sign in to comment.