Source code

Revision control

Copy as Markdown

Other Tools

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "secerr.h"
#include "ssl.h"
#include "sslerr.h"
#include "sslproto.h"
extern "C" {
// This is not something that should make you happy.
#include "libssl_internals.h"
}
#include "gtest_utils.h"
#include "nss_scoped_ptrs.h"
#include "tls_connect.h"
#include "tls_filter.h"
#include "tls_parser.h"
namespace nss_test {
TEST_F(TlsConnectTest, KeyUpdateClient) {
ConfigureVersion(SSL_LIBRARY_VERSION_TLS_1_3);
Connect();
EXPECT_EQ(SECSuccess, SSL_KeyUpdate(client_->ssl_fd(), PR_FALSE));
SendReceive(50);
SendReceive(60);
CheckEpochs(4, 3);
}
TEST_F(TlsConnectStreamTls13, KeyUpdateTooEarly_Client) {
StartConnect();
auto filter = MakeTlsFilter<TlsEncryptedHandshakeMessageReplacer>(
server_, kTlsHandshakeFinished, kTlsHandshakeKeyUpdate);
filter->EnableDecryption();
client_->Handshake();
server_->Handshake();
ExpectAlert(client_, kTlsAlertUnexpectedMessage);
client_->Handshake();
client_->CheckErrorCode(SSL_ERROR_RX_UNEXPECTED_KEY_UPDATE);
server_->Handshake();
server_->CheckErrorCode(SSL_ERROR_HANDSHAKE_UNEXPECTED_ALERT);
}
TEST_F(TlsConnectStreamTls13, KeyUpdateTooEarly_Server) {
StartConnect();
auto filter = MakeTlsFilter<TlsEncryptedHandshakeMessageReplacer>(
client_, kTlsHandshakeFinished, kTlsHandshakeKeyUpdate);
filter->EnableDecryption();
client_->Handshake();
server_->Handshake();
client_->Handshake();
ExpectAlert(server_, kTlsAlertUnexpectedMessage);
server_->Handshake();
server_->CheckErrorCode(SSL_ERROR_RX_UNEXPECTED_KEY_UPDATE);
client_->Handshake();
client_->CheckErrorCode(SSL_ERROR_HANDSHAKE_UNEXPECTED_ALERT);
}
TEST_F(TlsConnectTest, KeyUpdateClientRequestUpdate) {
ConfigureVersion(SSL_LIBRARY_VERSION_TLS_1_3);
Connect();
EXPECT_EQ(SECSuccess, SSL_KeyUpdate(client_->ssl_fd(), PR_TRUE));
// SendReceive() only gives each peer one chance to read. This isn't enough
// when the read on one side generates another handshake message. A second
// read gives each peer an extra chance to consume the KeyUpdate.
SendReceive(50);
SendReceive(60); // Cumulative count.
CheckEpochs(4, 4);
}
TEST_F(TlsConnectTest, KeyUpdateServer) {
ConfigureVersion(SSL_LIBRARY_VERSION_TLS_1_3);
Connect();
EXPECT_EQ(SECSuccess, SSL_KeyUpdate(server_->ssl_fd(), PR_FALSE));
SendReceive(50);
SendReceive(60);
CheckEpochs(3, 4);
}
TEST_F(TlsConnectTest, KeyUpdateServerRequestUpdate) {
ConfigureVersion(SSL_LIBRARY_VERSION_TLS_1_3);
Connect();
EXPECT_EQ(SECSuccess, SSL_KeyUpdate(server_->ssl_fd(), PR_TRUE));
SendReceive(50);
SendReceive(60);
CheckEpochs(4, 4);
}
TEST_F(TlsConnectTest, KeyUpdateConsecutiveRequests) {
ConfigureVersion(SSL_LIBRARY_VERSION_TLS_1_3);
Connect();
EXPECT_EQ(SECSuccess, SSL_KeyUpdate(server_->ssl_fd(), PR_TRUE));
EXPECT_EQ(SECSuccess, SSL_KeyUpdate(server_->ssl_fd(), PR_TRUE));
SendReceive(50);
SendReceive(60);
// The server should have updated twice, but the client should have declined
// to respond to the second request from the server, since it doesn't send
// anything in between those two requests.
CheckEpochs(4, 5);
}
// Check that a local update can be immediately followed by a remotely triggered
// update even if there is no use of the keys.
TEST_F(TlsConnectTest, KeyUpdateLocalUpdateThenConsecutiveRequests) {
ConfigureVersion(SSL_LIBRARY_VERSION_TLS_1_3);
Connect();
// This should trigger an update on the client.
EXPECT_EQ(SECSuccess, SSL_KeyUpdate(client_->ssl_fd(), PR_FALSE));
// The client should update for the first request.
EXPECT_EQ(SECSuccess, SSL_KeyUpdate(server_->ssl_fd(), PR_TRUE));
// ...but not the second.
EXPECT_EQ(SECSuccess, SSL_KeyUpdate(server_->ssl_fd(), PR_TRUE));
SendReceive(50);
SendReceive(60);
// Both should have updated twice.
CheckEpochs(5, 5);
}
TEST_F(TlsConnectTest, KeyUpdateMultiple) {
ConfigureVersion(SSL_LIBRARY_VERSION_TLS_1_3);
Connect();
EXPECT_EQ(SECSuccess, SSL_KeyUpdate(server_->ssl_fd(), PR_FALSE));
EXPECT_EQ(SECSuccess, SSL_KeyUpdate(server_->ssl_fd(), PR_TRUE));
EXPECT_EQ(SECSuccess, SSL_KeyUpdate(server_->ssl_fd(), PR_FALSE));
EXPECT_EQ(SECSuccess, SSL_KeyUpdate(client_->ssl_fd(), PR_FALSE));
SendReceive(50);
SendReceive(60);
CheckEpochs(5, 6);
}
// Both ask the other for an update, and both should react.
TEST_F(TlsConnectTest, KeyUpdateBothRequest) {
ConfigureVersion(SSL_LIBRARY_VERSION_TLS_1_3);
Connect();
EXPECT_EQ(SECSuccess, SSL_KeyUpdate(client_->ssl_fd(), PR_TRUE));
EXPECT_EQ(SECSuccess, SSL_KeyUpdate(server_->ssl_fd(), PR_TRUE));
SendReceive(50);
SendReceive(60);
CheckEpochs(5, 5);
}
// If the sequence number exceeds the number of writes before an automatic
// update (currently 3/4 of the max records for the cipher suite), then the
// stack should send an update automatically (but not request one).
TEST_F(TlsConnectTest, KeyUpdateAutomaticOnWrite) {
ConfigureVersion(SSL_LIBRARY_VERSION_TLS_1_3);
ConnectWithCipherSuite(TLS_AES_128_GCM_SHA256);
// Set this to one below the write threshold.
uint64_t threshold = (0x5aULL << 28) * 3 / 4;
EXPECT_EQ(SECSuccess,
SSLInt_AdvanceWriteSeqNum(client_->ssl_fd(), threshold));
EXPECT_EQ(SECSuccess, SSLInt_AdvanceReadSeqNum(server_->ssl_fd(), threshold));
// This should be OK.
client_->SendData(10);
server_->ReadBytes();
// This should cause the client to update.
client_->SendData(20);
server_->ReadBytes();
SendReceive(100);
CheckEpochs(4, 3);
}
// If the sequence number exceeds a certain number of reads (currently 7/8 of
// the max records for the cipher suite), then the stack should send AND request
// an update automatically. However, the sender (client) will be above its
// automatic update threshold, so the KeyUpdate - that it sends with the old
// cipher spec - will exceed the receiver (server) automatic update threshold.
// The receiver gets a packet with a sequence number over its automatic read
// update threshold. Even though the sender has updated, the code that checks
// the sequence numbers at the receiver doesn't know this and it will request an
// update. This causes two updates: one from the sender (without requesting a
// response) and one from the receiver (which does request a response).
TEST_F(TlsConnectTest, KeyUpdateAutomaticOnRead) {
ConfigureVersion(SSL_LIBRARY_VERSION_TLS_1_3);
ConnectWithCipherSuite(TLS_AES_128_GCM_SHA256);
// Move to right at the read threshold. Unlike the write test, we can't send
// packets because that would cause the client to update, which would spoil
// the test.
uint64_t threshold = ((0x5aULL << 28) * 7 / 8) + 1;
EXPECT_EQ(SECSuccess,
SSLInt_AdvanceWriteSeqNum(client_->ssl_fd(), threshold));
EXPECT_EQ(SECSuccess, SSLInt_AdvanceReadSeqNum(server_->ssl_fd(), threshold));
// This should cause the client to update, but not early enough to prevent the
// server from updating also.
client_->SendData(10);
server_->ReadBytes();
// Need two SendReceive() calls to ensure that the update that the server
// requested is properly generated and consumed.
SendReceive(70);
SendReceive(80);
CheckEpochs(5, 4);
}
// Filter to modify KeyUpdate message. Takes as an input which byte and what
// value to install.
class TLSKeyUpdateDamager : public TlsRecordFilter {
public:
TLSKeyUpdateDamager(const std::shared_ptr<TlsAgent>& a, size_t byte,
uint8_t val)
: TlsRecordFilter(a), offset_(byte), value_(val) {}
protected:
PacketFilter::Action FilterRecord(const TlsRecordHeader& header,
const DataBuffer& record, size_t* offset,
DataBuffer* output) override {
if (!header.is_protected()) {
return KEEP;
}
uint16_t protection_epoch;
uint8_t inner_content_type;
DataBuffer plaintext;
TlsRecordHeader out_header;
if (!Unprotect(header, record, &protection_epoch, &inner_content_type,
&plaintext, &out_header)) {
return KEEP;
}
if (inner_content_type != ssl_ct_handshake) {
return KEEP;
}
if (plaintext.data()[0] != ssl_hs_key_update) {
return KEEP;
}
if (offset_ >= plaintext.len()) {
ADD_FAILURE() << "TLSKeyUpdateDamager: the input (offset_) is out "
"of the range (the expected len is equal to "
<< plaintext.len() << ")." << std::endl;
return KEEP;
}
plaintext.data()[offset_] = value_;
DataBuffer ciphertext;
bool ok = Protect(spec(protection_epoch), out_header, inner_content_type,
plaintext, &ciphertext, &out_header);
if (!ok) {
ADD_FAILURE() << "Unable to protect the plaintext using "
<< protection_epoch << "epoch. " << std::endl;
return KEEP;
}
*offset = out_header.Write(output, *offset, ciphertext);
return CHANGE;
}
protected:
size_t offset_;
uint8_t value_;
};
// The next tests check the behaviour in case of malformed KeyUpdate.
// The first test, TLSKeyUpdateWrongValueForUpdateRequested,
// modifies the 4th byte (KeyUpdate) to have the incorrect value.
// The last tests check the incorrect values of the length.
// RFC 8446: 4. Handshake Protocol
// struct {
// HandshakeType msg_type; handshake type
// uint24 length; remaining bytes in message
// select (Handshake.msg_type) {
// case key_update: KeyUpdate; (4th byte)
// };
// } Handshake;
TEST_F(TlsConnectStreamTls13, TLSKeyUpdateWrongValueForUpdateRequested) {
EnsureTlsSetup();
// This test is setting the update_requested to be equal to 2
// Whereas the allowed values are [0, 1].
auto filter = MakeTlsFilter<TLSKeyUpdateDamager>(client_, 4, 2);
filter->EnableDecryption();
filter->Disable();
Connect();
filter->Enable();
SSL_KeyUpdate(client_->ssl_fd(), PR_FALSE);
filter->Disable();
ExpectAlert(server_, kTlsAlertDecodeError);
client_->ExpectReceiveAlert(kTlsAlertDecodeError);
server_->ExpectReadWriteError();
client_->ExpectReadWriteError();
server_->ReadBytes();
client_->ReadBytes();
server_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_KEY_UPDATE);
client_->CheckErrorCode(SSL_ERROR_DECODE_ERROR_ALERT);
// Even if the client has updated his writing key,
client_->CheckEpochs(3, 4);
// the server has not.
server_->CheckEpochs(3, 3);
}
TEST_F(TlsConnectStreamTls13, TLSKeyUpdateWrongValueForLength_MessageTooLong) {
EnsureTlsSetup();
// the first byte of the length was replaced with 0xff.
// The message now is too long.
auto filter = MakeTlsFilter<TLSKeyUpdateDamager>(client_, 1, 0xff);
filter->EnableDecryption();
filter->Disable();
Connect();
filter->Enable();
SSL_KeyUpdate(client_->ssl_fd(), PR_FALSE);
filter->Disable();
ExpectAlert(server_, kTlsAlertDecodeError);
client_->ExpectReceiveAlert(kTlsAlertDecodeError);
server_->ExpectReadWriteError();
client_->ExpectReadWriteError();
server_->ReadBytes();
client_->ReadBytes();
server_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_HANDSHAKE);
client_->CheckErrorCode(SSL_ERROR_DECODE_ERROR_ALERT);
// Even if the client has updated his writing key,
client_->CheckEpochs(3, 4);
// the server has not.
server_->CheckEpochs(3, 3);
}
TEST_F(TlsConnectStreamTls13, TLSKeyUpdateWrongValueForLength_MessageTooShort) {
EnsureTlsSetup();
// Changing the value of length of the KU message to be shorter than the
// correct one.
auto filter = MakeTlsFilter<TLSKeyUpdateDamager>(client_, 0x3, 0x00);
filter->EnableDecryption();
filter->Disable();
Connect();
filter->Enable();
SSL_KeyUpdate(client_->ssl_fd(), PR_FALSE);
filter->Disable();
ExpectAlert(server_, kTlsAlertDecodeError);
client_->ExpectReceiveAlert(kTlsAlertCloseNotify);
client_->SendData(10);
server_->ReadBytes();
}
// DTLS1.3 tests
// The KeyUpdate in DTLS1.3 workflow (with the update_requested set):
// Client(P1) is asking for KeyUpdate
// Here the second parameter states whether the P1 requires update_requested
// (RFC9147, Section 8).
// EXPECT_EQ(SECSuccess, SSL_KeyUpdate(client_->ssl_fd(),
// PR_FALSE));
// The server (P2) receives the KeyUpdate request and processes it.
// server_->ReadBytes();
// P2 sends ACK.
// SSLInt_SendImmediateACK(server_->ssl_fd());
// P1 receives ACK and finished the KeyUpdate:
// client_->ReadBytes();
// This function sends and proceeds KeyUpdate explained above (assuming
// updateRequested == PR_FALSE) For the explantation of the updateRequested look
// at the test DTLSKeyUpdateClientUpdateRequestedSucceed.*/
static void SendAndProcessKU(const std::shared_ptr<TlsAgent>& sender,
const std::shared_ptr<TlsAgent>& receiver,
bool updateRequested) {
EXPECT_EQ(SECSuccess, SSL_KeyUpdate(sender->ssl_fd(), updateRequested));
receiver->ReadBytes();
// It takes some time to send an ack message, so here we send it immediately
SSLInt_SendImmediateACK(receiver->ssl_fd());
sender->ReadBytes();
if (updateRequested) {
SSLInt_SendImmediateACK(sender->ssl_fd());
receiver->ReadBytes();
}
}
// This test checks that after the execution of KeyUpdate started by the client,
// the writing client/reading server key epoch was incremented.
// RFC 9147. Section 4.
// However, this value is set [...] of the connection epoch,
// which is an [...] counter incremented on every KeyUpdate.
TEST_F(TlsConnectDatagram13, DTLSKU_ClientKUSucceed) {
Connect();
CheckEpochs(3, 3);
// Client starts KeyUpdate
// The updateRequested is not requested.
SendAndProcessKU(client_, server_, PR_FALSE);
// The KeyUpdate is finished, and the client writing spec/the server reading
// spec is incremented.
CheckEpochs(4, 3);
// Check that we can send/receive data after KeyUpdate.
SendReceive(50);
}
// This test checks that only one KeyUpdate is possible at the same time.
// RFC 9147 Section 5.8.4
// In contrast, implementations MUST NOT send KeyUpdate, NewConnectionId, or
// RequestConnectionId messages if an earlier message of the same type has not
// yet been acknowledged.
TEST_F(TlsConnectDatagram13, DTLSKU_ClientKUTwiceOnceIgnored) {
Connect();
CheckEpochs(3, 3);
// Client sends a key update message.
EXPECT_EQ(SECSuccess, SSL_KeyUpdate(client_->ssl_fd(), PR_FALSE));
// The second key update message will be ignored as there is KeyUpdate in
// progress.
EXPECT_EQ(SECSuccess, SSL_KeyUpdate(client_->ssl_fd(), PR_FALSE));
// For the workflow see ssl_KeyUpdate_unittest.cc:SendAndProcessKU.
server_->ReadBytes();
SSLInt_SendImmediateACK(server_->ssl_fd());
client_->ReadBytes();
// As only one KeyUpdate was executed, the key epoch was incremented only
// once.
CheckEpochs(4, 3);
SendReceive(50);
}
// This test checks the same as the test DTLSKeyUpdateClientKeyUpdateSucceed,
// except that the server sends KeyUpdate.
TEST_F(TlsConnectDatagram13, DTLSKU_ServerKUSucceed) {
Connect();
CheckEpochs(3, 3);
SendAndProcessKU(server_, client_, PR_FALSE);
CheckEpochs(3, 4);
SendReceive(50);
}
// This test checks the same as the test
// DTLSKeyUpdateClientKeyUpdateTwiceOnceIgnored, except that the server sends
// KeyUpdate.
TEST_F(TlsConnectDatagram13, DTLSKU_PreviousKUNotYetACKed) {
Connect();
CheckEpochs(3, 3);
EXPECT_EQ(SECSuccess, SSL_KeyUpdate(server_->ssl_fd(), PR_FALSE));
// The second key update message will be ignored
EXPECT_EQ(SECSuccess, SSL_KeyUpdate(server_->ssl_fd(), PR_FALSE));
client_->ReadBytes();
SSLInt_SendImmediateACK(client_->ssl_fd());
server_->ReadBytes();
CheckEpochs(3, 4);
// Checking that we still can send/receive data.
SendReceive(50);
}
// This test checks that if we receive two KeyUpdates, one will be ignored
TEST_F(TlsConnectDatagram13, DTLSKU_TwiceReceivedOnceIgnored) {
Connect();
CheckEpochs(3, 3);
auto filter = MakeTlsFilter<TLSRecordSaveAndDropNext>(server_);
EXPECT_EQ(SECSuccess, SSL_KeyUpdate(server_->ssl_fd(), PR_FALSE));
// Here we check that there was no KeyUpdate happened
client_->ReadBytes();
SSLInt_SendImmediateACK(client_->ssl_fd());
server_->ReadBytes();
CheckEpochs(3, 3);
DataBuffer d = filter->ReturnRecorded();
// Sending the recorded KeyUpdate
server_->SendDirect(d);
// Sending the KeyUpdate again
server_->SendDirect(d);
client_->ReadBytes();
SSLInt_SendImmediateACK(client_->ssl_fd());
server_->ReadBytes();
// We observe that only one KeyUpdate has happened
CheckEpochs(3, 4);
// Checking that we still can send/receive data.
SendReceive(50);
}
// The KeyUpdate in DTLS1.3 workflow (with the update_requested set):
// Client(P1) is asking for KeyUpdate
// EXPECT_EQ(SECSuccess, SSL_KeyUpdate(client_->ssl_fd(), PR_TRUE));
// The server (P2) receives and processes the KeyUpdate request
// At the same time, P2 sends its own KeyUpdate request (due to update_requested
// was set)
// server_->ReadBytes();
// P1 receives the ACK and finalizes the KeyUpdate.
// SSLInt_SendImmediateACK(server_->ssl_fd());
// P1 receives the KeyUpdate request and processes it.
// client_->ReadBytes();
// P2 receives the ACK and finalizes the KeyUpdate.
// SSLInt_SendImmediateACK(client_->ssl_fd());
// server_->ReadBytes();
// This test checks that after the KeyUpdate (with update requested set)
// both client w/r and server w/r key epochs were incremented.
TEST_F(TlsConnectDatagram13, DTLSKU_UpdateRequestedSucceed) {
Connect();
CheckEpochs(3, 3);
// Here the second parameter sets the update_requested to true.
SendAndProcessKU(client_, server_, PR_TRUE);
// As there were two KeyUpdates executed (one by a client, another one by a
// server) Both of the keys were modified.
CheckEpochs(4, 4);
// Checking that we still can send/receive data.
SendReceive(50);
}
// This test checks that after two KeyUpdates (with update requested set)
// the keys epochs were incremented twice.
TEST_F(TlsConnectDatagram13, DTLSKU_UpdateRequestedTwiceSucceed) {
Connect();
CheckEpochs(3, 3);
SendAndProcessKU(client_, server_, PR_TRUE);
// The KeyUpdate is finished, so both of the epochs got incremented.
CheckEpochs(4, 4);
SendAndProcessKU(client_, server_, PR_TRUE);
// The second KeyUpdate is finished, so finally the epochs were incremented
// twice.
CheckEpochs(5, 5);
// Checking that we still can send/receive data.
SendReceive(50);
}
// This test checks the same as the test DTLSKeyUpdateUpdateRequestedSucceed,
// except that the server sends KeyUpdate.
TEST_F(TlsConnectDatagram13, DTLSKU_ServerUpdateRequestedSucceed) {
Connect();
CheckEpochs(3, 3);
SendAndProcessKU(server_, client_, PR_TRUE);
CheckEpochs(4, 4);
SendReceive(50);
}
// This test checks that after two KeyUpdates (with update requested set)
// the keys epochs were incremented twice.
TEST_F(TlsConnectDatagram13, DTLSKU_ServerUpdateRequestedTwiceSucceed) {
Connect();
CheckEpochs(3, 3);
SendAndProcessKU(server_, client_, PR_TRUE);
// The KeyUpdate is finished, so both of the epochs got incremented.
CheckEpochs(4, 4);
// Server sends another KeyUpdate
SendAndProcessKU(server_, client_, PR_TRUE);
// The second KeyUpdate is finished, so finally the epochs were incremented
// twice.
CheckEpochs(5, 5);
// Checking that we still can send/receive data.
SendReceive(50);
}
// This test checks that both client and server can send the KeyUpdate in
// consequence.
TEST_F(TlsConnectDatagram13, DTLSKU_ClientServerConseqSucceed) {
Connect();
CheckEpochs(3, 3);
SendAndProcessKU(client_, server_, PR_FALSE);
// As the server initiated KeyUpdate and did not request an update_request,
// Only the server writing/client reading key epoch was incremented.
CheckEpochs(4, 3);
SendAndProcessKU(server_, client_, PR_FALSE);
// Now the client initiated KeyUpdate and did not request an update_request,
// so now both of epochs got incremented.
CheckEpochs(4, 4);
// Checking that we still can send/receive data.
SendReceive(50);
}
// This test checks that both client and server can send the KeyUpdate in
// consequence. Compared to the DTLSKeyUpdateClientServerConseqSucceed TV, this
// time both parties set update_requested to be true.
TEST_F(TlsConnectDatagram13, DTLSKU_ClientServerUpdateRequestedBothSucceed) {
Connect();
CheckEpochs(3, 3);
SendAndProcessKU(client_, server_, PR_TRUE);
SendAndProcessKU(server_, client_, PR_TRUE);
// The second KeyUpdate (update_request = True) increments again the epochs
// of both keys.
CheckEpochs(5, 5);
// Checking that we still can send/receive data.
SendReceive(50);
}
// This test checks that if there is an ongoing KeyUpdate, the one started
// durint the KU is not going to be executed.
TEST_F(TlsConnectDatagram13, DTLSKU_KUInTheMiddleIsRejected) {
Connect();
CheckEpochs(3, 3);
EXPECT_EQ(SECSuccess, SSL_KeyUpdate(server_->ssl_fd(), PR_TRUE));
client_->ReadBytes();
SSLInt_SendImmediateACK(client_->ssl_fd());
// Here a client starts KeyUpdate at the same time as the ongoing KeyUpdate
// This KeyUpdate will not execute
EXPECT_EQ(SECSuccess, SSL_KeyUpdate(client_->ssl_fd(), PR_TRUE));
server_->ReadBytes();
SSLInt_SendImmediateACK(server_->ssl_fd());
client_->ReadBytes();
// As there was only one KeyUpdate executed, both keys got incremented only
// once.
CheckEpochs(4, 4);
// Checking that we still can send/receive data.
SendReceive(50);
}
// DTLS1.3 KeyUpdate - Immediate Send Tests.
// The expected behaviour of the protocol:
// P1 starts initiates KeyUpdate
// P2 receives KeyUpdate
// And this moment, P2 will update the reading key to n
// But P2 will be accepting the keys from the previous epoch until a new message
// encrypted with the epoch n arrives.
// This test checks that when a client sent KeyUpdate, but the KeyUpdate message
// was not yet received, client can still send data.
TEST_F(TlsConnectDatagram13, DTLSKU_ClientImmediateSend) {
Connect();
// Client has initiated KeyUpdate
EXPECT_EQ(SECSuccess, SSL_KeyUpdate(client_->ssl_fd(), PR_FALSE));
// Server has not yet received it, client is trying to send some additional
// data.
CheckEpochs(3, 3);
client_->SendData(10);
// Server successfully receives it.
WAIT_(server_->received_bytes() == 10, 2000);
ASSERT_EQ((size_t)10, server_->received_bytes());
SendReceive(50);
}
// This test checks that when a client sent KeyUpdate, but the KeyUpdate message
// was not yet received, it can still receive data.
TEST_F(TlsConnectDatagram13, DTLSKU_ServerImmediateSend) {
Connect();
// Client has initiated KeyUpdate
EXPECT_EQ(SECSuccess, SSL_KeyUpdate(client_->ssl_fd(), PR_FALSE));
// The server can successfully send data.
CheckEpochs(3, 3);
server_->SendData(10);
WAIT_(client_->received_bytes() == 10, 2000);
ASSERT_EQ((size_t)10, client_->received_bytes());
SendReceive(50);
}
// This test checks that when a client sent KeyUpdate,
// the server has not yet sent an ACK and the client has not yet ACKed
// KeyUpdate, both parties can exchange data.
TEST_F(TlsConnectDatagram13, DTLSKU_ClientImmediateSendAfterServerRead) {
Connect();
// Client has initiated KeyUpdate
EXPECT_EQ(SECSuccess, SSL_KeyUpdate(client_->ssl_fd(), PR_FALSE));
// Server receives KeyUpdate
server_->ReadBytes();
// Client can send data before the server sending ACK and client receiving
// * ACK messages
// Only server keys got updated.
server_->CheckEpochs(4, 3);
client_->CheckEpochs(3, 3);
client_->SendData(10);
WAIT_(server_->received_bytes() == 10, 2000);
ASSERT_EQ((size_t)10, server_->received_bytes());
// Server can send data
server_->SendData(10);
WAIT_(client_->received_bytes() == 10, 2000);
ASSERT_EQ((size_t)10, client_->received_bytes());
SendReceive(50);
}
// This test checks that when a client sent KeyUpdate, but has not yet ACKed it,
// both parties can exchange data.
TEST_F(TlsConnectDatagram13, DTLSKU_ClientImmediateSendAfterServerReadAndACK) {
Connect();
CheckEpochs(3, 3);
// Client has initiated KeyUpdate
EXPECT_EQ(SECSuccess, SSL_KeyUpdate(client_->ssl_fd(), PR_FALSE));
// Server receives KeyUpdate
server_->ReadBytes();
// Server sends ACK
SSLInt_SendImmediateACK(server_->ssl_fd());
// Client can send data before he has received KeyUpdate
// Only server keys got updated.
server_->CheckEpochs(4, 3);
client_->CheckEpochs(3, 3);
client_->SendData(10);
WAIT_(server_->received_bytes() == 10, 2000);
ASSERT_EQ((size_t)10, server_->received_bytes());
// Server can send data
server_->SendData(10);
WAIT_(client_->received_bytes() == 10, 2000);
ASSERT_EQ((size_t)10, client_->received_bytes());
SendReceive(50);
}
// This test checks that the client writing epoch is updated only
// when the client has received the ACK.
// RFC 9147. Section 8
// As with other handshake messages with no built-in response, KeyUpdates MUST
// be acknowledged.
TEST_F(TlsConnectDatagram13, DTLSKU_ClientWritingEpochUpdatedAfterReceivedACK) {
Connect();
// Previous epoch
CheckEpochs(3, 3);
// Client sends a KeyUpdate
EXPECT_EQ(SECSuccess, SSL_KeyUpdate(client_->ssl_fd(), PR_FALSE));
// Server updates his reading key
server_->ReadBytes();
// Now the server has a reading key = 4
server_->CheckEpochs(4, 3);
// But the client has a writing key = 3
client_->CheckEpochs(3, 3);
// Client sends a data, but using the old (3) keys
client_->SendData(10);
WAIT_(server_->received_bytes() == 10, 2000);
ASSERT_EQ((size_t)10, server_->received_bytes());
server_->CheckEpochs(4, 3);
client_->CheckEpochs(3, 3);
SSLInt_SendImmediateACK(server_->ssl_fd());
client_->ReadBytes();
CheckEpochs(4, 3);
SendReceive(50);
}
// DTLS1.3 KeyUpdate - Testing the border conditions
// (i.e. the cases where we reached the highest epoch).
// This test checks that the maximum epoch will not be exceeded on KeyUpdate.
// RFC 9147. Section 8.
// In order to provide an extra margin of security,
// sending implementations MUST NOT allow the epoch to exceed 2^48-1.
// Here we use the maximum as 2^16,
// When the bug is solved, the constant is to be replaced with 2^48 as
// required by RFC.
TEST_F(TlsConnectDatagram13, DTLSKU_ClientMaxEpochReached) {
Connect();
CheckEpochs(3, 3);
PRUint64 max_epoch_type = (0x1ULL << 16) - 1;
// We assign the maximum possible epochs
EXPECT_EQ(SECSuccess,
SSLInt_AdvanceWriteEpochNum(client_->ssl_fd(), max_epoch_type));
EXPECT_EQ(SECSuccess,
SSLInt_AdvanceReadEpochNum(server_->ssl_fd(), max_epoch_type));
CheckEpochs(max_epoch_type, 3);
// Upon trying to execute KeyUpdate, we return a SECFailure.
EXPECT_EQ(SECFailure, SSL_KeyUpdate(client_->ssl_fd(), PR_FALSE));
SendReceive(50);
}
// This test checks the compliance with the RFC 9147 stating the behaviour
// reaching the max epoch: RFC 9147 Section 8. If a sending implementation
// receives a KeyUpdate with request_update set to "update_requested", it MUST
// NOT send its own KeyUpdate if that would cause it to exceed these limits and
// SHOULD instead ignore the "update_requested" flag.
TEST_F(TlsConnectDatagram13, DTLSKU_ClientMaxEpochReachedUpdateRequested) {
Connect();
CheckEpochs(3, 3);
PRUint64 max_epoch_type = (0x1ULL << 16) - 1;
// We assign the maximum possible epochs - 1.
EXPECT_EQ(SECSuccess,
SSLInt_AdvanceWriteEpochNum(client_->ssl_fd(), max_epoch_type));
EXPECT_EQ(SECSuccess,
SSLInt_AdvanceReadEpochNum(server_->ssl_fd(), max_epoch_type));
CheckEpochs(max_epoch_type, 3);
// Once we call KeyUpdate with update requested
EXPECT_EQ(SECSuccess, SSL_KeyUpdate(server_->ssl_fd(), PR_TRUE));
client_->ReadBytes();
SSLInt_SendImmediateACK(client_->ssl_fd());
server_->ReadBytes();
SSLInt_SendImmediateACK(server_->ssl_fd());
client_->ReadBytes();
// Only one key (that has not reached the maximum epoch) was updated.
CheckEpochs(max_epoch_type, 4);
SendReceive(50);
}
// DTLS1.3 KeyUpdate - Automatic update tests
// RFC 9147 Section 4.5.3.
// Implementations SHOULD NOT protect more records than allowed by the limit
// specified for the negotiated AEAD.
// Implementations SHOULD initiate a key update before reaching this limit.
// These two tests check that the KeyUpdate is automatically called upon
// reaching the reading/writing limit.
TEST_F(TlsConnectDatagram13, DTLSKU_AutomaticOnWrite) {
ConfigureVersion(SSL_LIBRARY_VERSION_TLS_1_3);
ConnectWithCipherSuite(TLS_AES_128_GCM_SHA256);
CheckEpochs(3, 3);
// Set this to one below the write threshold.
uint64_t threshold = 0x438000000;
EXPECT_EQ(SECSuccess,
SSLInt_AdvanceWriteSeqNum(client_->ssl_fd(), threshold));
EXPECT_EQ(SECSuccess, SSLInt_AdvanceReadSeqNum(server_->ssl_fd(), threshold));
// This should be OK.
client_->SendData(10);
server_->ReadBytes();
// This should cause the client to update.
client_->SendData(15);
server_->ReadBytes();
SSLInt_SendImmediateACK(server_->ssl_fd());
client_->ReadBytes();
// The client key epoch was incremented.
CheckEpochs(4, 3);
// Checking that we still can send/receive data.
SendReceive(100);
}
TEST_F(TlsConnectDatagram13, DTLSKU_AutomaticOnRead) {
ConfigureVersion(SSL_LIBRARY_VERSION_TLS_1_3);
ConnectWithCipherSuite(TLS_AES_128_GCM_SHA256);
CheckEpochs(3, 3);
// Set this to one below the read threshold.
uint64_t threshold = 0x4ec000000 - 1;
EXPECT_EQ(SECSuccess,
SSLInt_AdvanceWriteSeqNum(client_->ssl_fd(), threshold));
EXPECT_EQ(SECSuccess, SSLInt_AdvanceReadSeqNum(server_->ssl_fd(), threshold));
auto filter = MakeTlsFilter<TLSRecordSaveAndDropNext>(client_);
client_->SendData(10);
DataBuffer d = filter->ReturnRecorded();
client_->SendDirect(d);
// This message will cause the server to start KeyUpdate with updateRequested
// = 1.
server_->ReadBytes();
SSLInt_SendImmediateACK(server_->ssl_fd());
client_->ReadBytes();
SSLInt_SendImmediateACK(client_->ssl_fd());
server_->ReadBytes();
// Both keys got updated.
CheckEpochs(4, 4);
// Checking that we still can send/receive data.
SendReceive(100);
}
// The test describes the situation when there was a request
// to execute an automatic KU, but the server has not responded.
TEST_F(TlsConnectDatagram13, DTLSKU_CanSendBeforeThreshold) {
ConfigureVersion(SSL_LIBRARY_VERSION_TLS_1_3);
ConnectWithCipherSuite(TLS_AES_128_GCM_SHA256);
CheckEpochs(3, 3);
uint64_t threshold = 0x5a0000000 - 2;
EXPECT_EQ(SECSuccess,
SSLInt_AdvanceWriteSeqNum(client_->ssl_fd(), threshold));
EXPECT_EQ(SECSuccess, SSLInt_AdvanceReadSeqNum(server_->ssl_fd(), threshold));
size_t received_bytes = server_->received_bytes();
// We still can send a message
client_->SendData(15);
// We can not send a message anymore
client_->ExpectReadWriteError();
client_->SendData(105);
server_->ReadBytes();
// And it was not received.
ASSERT_EQ((size_t)received_bytes + 15, server_->received_bytes());
}
TEST_F(TlsConnectDatagram13, DTLSKU_DiscardAfterThreshold) {
ConfigureVersion(SSL_LIBRARY_VERSION_TLS_1_3);
ConnectWithCipherSuite(TLS_AES_128_GCM_SHA256);
CheckEpochs(3, 3);
uint64_t threshold = 0x5a0000000 - 3;
EXPECT_EQ(SECSuccess,
SSLInt_AdvanceWriteSeqNum(client_->ssl_fd(), threshold));
EXPECT_EQ(SECSuccess, SSLInt_AdvanceReadSeqNum(server_->ssl_fd(), threshold));
size_t received_bytes = server_->received_bytes();
auto filter = MakeTlsFilter<TLSRecordSaveAndDropNext>(client_);
client_->SendData(30);
DataBuffer d = filter->ReturnRecorded();
client_->SendDirect(d);
client_->SendDirect(d);
server_->ReadBytes();
// Only one message was received.
ASSERT_EQ((size_t)received_bytes + 30, server_->received_bytes());
}
// DTLS1.3 KeyUpdate - Managing previous epoch messages
// RFC 9147 Section 8.
// Due to the possibility of an ACK message for a KeyUpdate being lost
// and thereby preventing the sender of the KeyUpdate from updating its
// keying material, receivers MUST retain the pre-update keying material
// until receipt and successful decryption of a message using the new
// keys.
// This test checks that message encrypted with the key n-1 will be accepted
// after KeyUpdate is executed, but before the message n has arrived.
TEST_F(TlsConnectDatagram13, DTLSKU_PreviousEpochIsAcceptedBeforeNew) {
size_t len = 10;
Connect();
// Client starts KeyUpdate
EXPECT_EQ(SECSuccess, SSL_KeyUpdate(client_->ssl_fd(), PR_FALSE));
// Server receives KeyUpdate and sends ACK
server_->ReadBytes();
SSLInt_SendImmediateACK(server_->ssl_fd());
// Client has not yet received the ACK, so the writing key epoch has not
// changed
client_->CheckEpochs(3, 3);
server_->CheckEpochs(4, 3);
auto filter = MakeTlsFilter<TLSRecordSaveAndDropNext>(client_);
// Here the message previousEpochMessageBuffer contains a message
// encrypted with the client 3rd epoch key, m1 = enc(message, key_3)
client_->SendData(len);
DataBuffer d = filter->ReturnRecorded();
// Client has received the ACK
client_->ReadBytes();
// Now he updates the writing Key to 4
client_->CheckEpochs(3, 4);
server_->CheckEpochs(4, 3);
// And now we resend the message m1 and successfully receive it
client_->SendDirect(d);
WAIT_(server_->received_bytes() == len, 2000);
ASSERT_EQ(len, server_->received_bytes());
// Checking that we still can send/receive data.
SendReceive(50);
}
// This test checks that message encrypted with the key n-2 will not be accepted
// after KeyUpdate is executed, but before the message n has arrived.
TEST_F(TlsConnectDatagram13, DTLSKU_2EpochsAgoIsRejected) {
size_t len = 10;
Connect();
CheckEpochs(3, 3);
auto filter = MakeTlsFilter<TLSRecordSaveAndDropNext>(client_);
client_->SendData(len);
DataBuffer d = filter->ReturnRecorded();
client_->ResetSentBytes();
SendAndProcessKU(client_, server_, PR_FALSE);
SendAndProcessKU(client_, server_, PR_FALSE);
// Executing 2 KeyUpdates, so the client writing key is equal to 5 now
CheckEpochs(5, 3);
// And now we resend the message m1 encrypted with the key n-2 (3)
client_->SendDirect(d);
server_->ReadBytes();
// Server has still received just legal_message_len of bytes (not the
// previousEpochLen + legal_message_len)
ASSERT_EQ((size_t)0, server_->received_bytes());
// Checking that we still can send/receive data.
SendReceive(60);
}
// This test checks that that message encrypted with the key n-1 will be
// rejected after KeyUpdate is executed, and after the message n has arrived.
TEST_F(TlsConnectDatagram13, DTLSKU_PreviousEpochIsAcceptedAfterNew) {
size_t len = 30;
size_t legal_message_len = 20;
Connect();
// Client starts KeyUpdate
EXPECT_EQ(SECSuccess, SSL_KeyUpdate(client_->ssl_fd(), PR_FALSE));
// Server receives KeyUpdate and sends ACK
server_->ReadBytes();
SSLInt_SendImmediateACK(server_->ssl_fd());
// Client has not yet received the ACK, so the writing key epoch has not
// changed
client_->CheckEpochs(3, 3);
server_->CheckEpochs(4, 3);
auto filter = MakeTlsFilter<TLSRecordSaveAndDropNext>(client_);
// Here the message previousEpochMessageBuffer contains a message
// encrypted with the client 3rd epoch key, m1 = enc(message, key_3)
client_->SendData(len);
DataBuffer d = filter->ReturnRecorded();
client_->ResetSentBytes();
// Client has received the ACK
client_->ReadBytes();
client_->CheckEpochs(3, 4);
server_->CheckEpochs(4, 3);
// At this moment, a client will send a message with the new key
SendReceive(legal_message_len);
// As soon as it's received, the server will forbid the messaged from the
// previous epochs
server_->ReadBytes();
// If a message from the previous epoch arrives to the server (m1, the key_3
// was used to encrypt it)
client_->SendDirect(d);
// it will be silently dropped
server_->ReadBytes();
// Server has still received just legal_message_len of bytes (not the
// previousEpochLen + legal_message_len)
ASSERT_EQ((size_t)legal_message_len, server_->received_bytes());
// Checking that we still can send/receive data.
SendReceive(50);
}
// DTLS Epoch reconstruction test
// RFC 9147 Section 8. 4.2.2. Reconstructing the Sequence Number and Epoch
// This test checks that the epoch reconstruction is correct.
// The function under testing is dtlscon.c::dtls_ReadEpoch.
// We only consider the case when dtls_IsDtls13Ciphertext is true.
typedef struct sslKeyUpdateReadEpochTVStr {
// The current epoch
DTLSEpoch epoch;
// Only two-bit epoch here
PRUint8 header;
DTLSEpoch expected_reconstructed_epoch;
} sslKeyUpdateReadEpochTV_t;
static const sslKeyUpdateReadEpochTV_t sslKeyUpdateReadEpochTV[26] = {
{0x1, 0x1, 0x1},
{0x2, 0x1, 0x1},
{0x2, 0x2, 0x2},
{0x3, 0x3, 0x3},
{0x3, 0x2, 0x2},
{0x3, 0x1, 0x1},
{0x4, 0x0, 0x4}, // the difference (diff) between the reconstructed and
// the current epoch is equal to 0
{0x4, 0x1, 0x1}, // diff == 3
{0x4, 0x2, 0x2}, // diff == 2
{0x4, 0x3, 0x3}, // diff == 1
{0x5, 0x0, 0x4}, // diff == 1
{0x5, 0x1, 0x5}, // diff == 0
{0x5, 0x2, 0x2}, // diff == 3
{0x5, 0x3, 0x3}, // diff == 2
{0x6, 0x0, 0x4},
{0x6, 0x1, 0x5},
{0x6, 0x2, 0x6},
{0x6, 0x3, 0x3},
{0x7, 0x0, 0x4},
{0x7, 0x1, 0x5},
{0x7, 0x2, 0x6},
{0x7, 0x3, 0x7},
{0x8, 0x0, 0x8},
{0x8, 0x1, 0x5},
{0x8, 0x2, 0x6},
{0x8, 0x3, 0x7},
// Starting from here the pattern (starting from 4) repeats:
// if a current epoch is equal to n,
// the difference will behave as for n % 4 + 4.
// For example, if the current epoch is equal to 9, then
// the difference between the reconstructed epoch and the current one
// will be the same as for the 5th epoch.
};
TEST_F(TlsConnectDatagram13, DTLS_EpochReconstruction) {
PRUint8 header[5] = {0};
header[0] = 0x20;
DTLSEpoch epoch;
for (size_t i = 0; i < 26; i++) {
epoch = sslKeyUpdateReadEpochTV[i].epoch;
header[0] = (header[0] & 0xfc) | (sslKeyUpdateReadEpochTV[i].header & 0x3);
// ReadEpoch (dtlscon.c#1339) uses only spec->version and spec->epoch.
ASSERT_EQ(sslKeyUpdateReadEpochTV[i].expected_reconstructed_epoch,
dtls_ReadEpoch(SSL_LIBRARY_VERSION_TLS_1_3, epoch, header));
}
}
// RFC 9147. A.2. Handshake Protocol
// struct {
// HandshakeType msg_type; -- handshake type
// uint24 length; -- bytes in message
// uint16 message_seq; -- DTLS-required field
// uint24 fragment_offset; -- DTLS-required field
// uint24 fragment_length; -- DTLS-required field
// select (msg_type) {
// ...
// case key_update: KeyUpdate;
// } body;
// } Handshake;
//
// enum {
// update_not_requested(0), update_requested(1), (255)
// } KeyUpdateRequest;
// The next tests send malformed KeyUpdate messages.
// A remainder: TLSKeyUpdateDamager filter takes as an input an agent,
// a byte index and a value that the existing value of the byte with the byte
// index will be replaced with. The filter catchs only the KeyUpdate messages,
// keeping unchanged all the rest.
// The first test, DTLSKeyUpdateDamagerFilterTestingNoModification,
// checks the correctness of the filter itself. It replaces the value of 12th
// byte with 0: The 12th byte is used to specify KeyUpdateRequest. Thus, the
// modification done in the test will still result in the correct KeyUpdate
// request.
// The test DTLSKU_WrongValueForUpdateRequested is modifying
// KeyUpdateRequest byte to have an not-allowed value.
// The test DTLSKeyUpdateDamagedLength modifies the 3rd byte (one of the length
// bytes).
// The test DTLSKeyUpdateDamagedLengthLongMessage changes the length of the
// message as well.
// The test DTLSKeyUpdateDamagedFragmentLength modifies the 10th byte (one of
// the fragment_length bytes)
TEST_F(TlsConnectDatagram13, DTLSKU_WrongValueForUpdateRequested) {
EnsureTlsSetup();
// Filter replacing the update_requested with an unexpected value.
auto filter = MakeTlsFilter<TLSKeyUpdateDamager>(client_, 12, 2);
filter->EnableDecryption();
filter->Disable();
Connect();
filter->Enable();
SSL_KeyUpdate(client_->ssl_fd(), PR_FALSE);
filter->Disable();
ExpectAlert(server_, kTlsAlertDecodeError);
client_->ExpectReceiveAlert(kTlsAlertDecodeError);
server_->ExpectReadWriteError();
client_->ExpectReadWriteError();
server_->ReadBytes();
client_->ReadBytes();
server_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_KEY_UPDATE);
client_->CheckErrorCode(SSL_ERROR_DECODE_ERROR_ALERT);
// No KeyUpdate happened.
CheckEpochs(3, 3);
}
TEST_F(TlsConnectDatagram13, DTLSKU_DamagedLength) {
EnsureTlsSetup();
// Filter replacing the length value with 0.
auto filter = MakeTlsFilter<TLSKeyUpdateDamager>(client_, 3, 0);
filter->EnableDecryption();
filter->Disable();
Connect();
filter->Enable();
SSL_KeyUpdate(client_->ssl_fd(), PR_FALSE);
filter->Disable();
SSLInt_SendImmediateACK(server_->ssl_fd());
client_->ReadBytes();
// No KeyUpdate happened.
CheckEpochs(3, 3);
SendReceive(50);
}
TEST_F(TlsConnectDatagram13, DTLSKU_DamagedLengthTooLong) {
EnsureTlsSetup();
// Filter replacing the second byte of length with one
// The message length is increased by 2 ^ 8
auto filter = MakeTlsFilter<TLSKeyUpdateDamager>(client_, 2, 2);
filter->EnableDecryption();
filter->Disable();
Connect();
filter->Enable();
SSL_KeyUpdate(client_->ssl_fd(), PR_FALSE);
filter->Disable();
SSLInt_SendImmediateACK(server_->ssl_fd());
client_->ReadBytes();
// No KeyUpdate happened.
CheckEpochs(3, 3);
SendReceive(50);
}
TEST_F(TlsConnectDatagram13, DTLSKU_DamagedFragmentLength) {
EnsureTlsSetup();
// Filter replacing the fragment length with 1.
auto filter = MakeTlsFilter<TLSKeyUpdateDamager>(client_, 10, 1);
filter->EnableDecryption();
filter->Disable();
Connect();
filter->Enable();
SSL_KeyUpdate(client_->ssl_fd(), PR_FALSE);
filter->Disable();
SSLInt_SendImmediateACK(server_->ssl_fd());
client_->ReadBytes();
// No KeyUpdate happened.
CheckEpochs(3, 3);
SendReceive(50);
}
// This filter is used in order to modify an ACK message.
// As it's possible that one record contains several ACKs,
// we fault all of them.
class TLSACKDamager : public TlsRecordFilter {
public:
TLSACKDamager(const std::shared_ptr<TlsAgent>& a, size_t byte, uint8_t val)
: TlsRecordFilter(a), offset_(byte), value_(val) {}
protected:
PacketFilter::Action FilterRecord(const TlsRecordHeader& header,
const DataBuffer& record, size_t* offset,
DataBuffer* output) override {
if (!header.is_protected()) {
return KEEP;
}
uint16_t protection_epoch;
uint8_t inner_content_type;
DataBuffer plaintext;
TlsRecordHeader out_header;
if (!Unprotect(header, record, &protection_epoch, &inner_content_type,
&plaintext, &out_header)) {
return KEEP;
}
if (plaintext.data() == NULL || plaintext.len() == 0) {
return KEEP;
}
if (decrypting() && inner_content_type != ssl_ct_ack) {
return KEEP;
}
// We compute the number of ACKS in the message
// As we keep processing the ACK even if one message is incorrent,
// we fault all the found ACKs.
uint8_t ack_message_header_len = 2;
uint8_t ack_message_len_one_ACK = 16;
uint64_t acks = plaintext.len() - ack_message_header_len;
EXPECT_EQ((uint64_t)0, acks % ack_message_len_one_ACK);
acks = acks / ack_message_len_one_ACK;
if (plaintext.len() <= ack_message_header_len + offset_ +
(acks - 1) * ack_message_len_one_ACK) {
return KEEP;
}
for (size_t i = 0; i < acks; i++) {
// Here we replace the offset_-th byte after the header
// i.e. headerAck + ACK(0) + ACK(1) <-- the offset_-th byte
// of ACK(0), ACK(1), etc
plaintext.data()[ack_message_header_len + offset_ +
i * ack_message_len_one_ACK] = value_;
}
DataBuffer ciphertext;
bool ok = Protect(spec(protection_epoch), out_header, inner_content_type,
plaintext, &ciphertext, &out_header);
if (!ok) {
return KEEP;
}
*offset = out_header.Write(output, *offset, ciphertext);
return CHANGE;
}
protected:
size_t offset_;
uint8_t value_;
};
// The next two tests are modifying the ACK message:
// First, we call KeyUpdate on the client side. The server successfully
// processes it, and it's sending an ACK message. At this moment, the filter
// modifies the content of the ACK message by changing the seqNum or epoch and
// sends it back to the client.
//
// struct {
// uint64 epoch;
// uint64 sequence_number;
// } RecordNumber;
// struct {
// RecordNumber record_numbers<0..2^16-1>;
// } ACK;
TEST_F(TlsConnectDatagram13, DTLSKU_ModifACKEpoch) {
EnsureTlsSetup();
uint8_t byte = 3;
uint8_t v = 1;
// The filter will replace value-th byte of each ACK with one
// The epoch will be more than v * 2 ^ ((byte - 1) * 8).
// HandleACK function allows the epochs such that (epoch > RECORD_EPOCH_MAX)
// where RECORD_EPOCH_MAX == ((0x1ULL << 16) - 1)
auto filter = MakeTlsFilter<TLSACKDamager>(server_, byte, v);
filter->EnableDecryption();
filter->Disable();
Connect();
CheckEpochs(3, 3);
EXPECT_EQ(SECSuccess, SSL_KeyUpdate(client_->ssl_fd(), PR_FALSE));
server_->ReadBytes();
filter->Enable();
SSLInt_SendImmediateACK(server_->ssl_fd());
filter->Disable();
client_->ReadBytes();
server_->CheckEpochs(4, 3);
// The client has not received the ACK, so it will not update the key.
client_->CheckEpochs(3, 3);
// The communication still continues.
SendReceive(50);
}
TEST_F(TlsConnectDatagram13, DTLSKU_ModifACKSeqNum) {
EnsureTlsSetup();
uint8_t byte = 7;
uint8_t v = 1;
// The filter will replace value byte of each ACK with one
// The seqNum will be more than v * 2 ^ ((byte - 1) * 8).
// HandleACK function allows the epochs such that (seq > RECORD_SEQ_MAX)
// where RECORD_SEQ_MAX == ((0x1ULL << 48) - 1)
// here byte + 8 means that we modify not epoch, but sequenceNum
auto filter = MakeTlsFilter<TLSACKDamager>(server_, byte + 8, v);
filter->EnableDecryption();
filter->Disable();
Connect();
EXPECT_EQ(SECSuccess, SSL_KeyUpdate(client_->ssl_fd(), PR_FALSE));
server_->ReadBytes();
filter->Enable();
SSLInt_SendImmediateACK(server_->ssl_fd());
filter->Disable();
client_->ReadBytes();
client_->ReadBytes();
server_->CheckEpochs(4, 3);
// The client has not received the ACK, so it will not update the key.
client_->CheckEpochs(3, 3);
// The communication still continues.
SendReceive(50);
}
TEST_F(TlsConnectDatagram13, DTLSKU_TooEarly_ClientCannotSendKeyUpdate) {
StartConnect();
auto filter = MakeTlsFilter<TLSRecordSaveAndDropNext>(server_);
filter->EnableDecryption();
client_->Handshake();
server_->Handshake();
EXPECT_EQ(SECFailure, SSL_KeyUpdate(client_->ssl_fd(), PR_FALSE));
}
TEST_F(TlsConnectDatagram13, DTLSKeyUpdateTooEarly_ServerCannotSendKeyUpdate) {
StartConnect();
auto filter = MakeTlsFilter<TLSRecordSaveAndDropNext>(server_);
filter->EnableDecryption();
client_->Handshake();
server_->Handshake();
EXPECT_EQ(SECFailure, SSL_KeyUpdate(server_->ssl_fd(), PR_FALSE));
}
class DTlsEncryptedHandshakeHeaderReplacer : public TlsRecordFilter {
public:
DTlsEncryptedHandshakeHeaderReplacer(const std::shared_ptr<TlsAgent>& a,
uint8_t old_ct, uint8_t new_ct)
: TlsRecordFilter(a),
old_ct_(old_ct),
new_ct_(new_ct),
replaced_(false) {}
protected:
PacketFilter::Action FilterRecord(const TlsRecordHeader& header,
const DataBuffer& record, size_t* offset,
DataBuffer* output) override {
if (replaced_) return KEEP;
uint8_t inner_content_type;
DataBuffer plaintext;
uint16_t protection_epoch = 0;
TlsRecordHeader out_header(header);
if (!Unprotect(header, record, &protection_epoch, &inner_content_type,
&plaintext, &out_header)) {
return KEEP;
}
auto& protection_spec = spec(protection_epoch);
uint32_t msg_type = 256; // Not a real message
if (!plaintext.Read(0, 1, &msg_type) || msg_type == old_ct_) {
replaced_ = true;
plaintext.Write(0, new_ct_, 1);
}
uint64_t seq_num = protection_spec.next_out_seqno();
if (out_header.is_dtls()) {
seq_num |= out_header.sequence_number() & (0xffffULL << 48);
}
out_header.sequence_number(seq_num);
DataBuffer ciphertext;
bool rv = Protect(protection_spec, out_header, inner_content_type,
plaintext, &ciphertext, &out_header);
if (!rv) {
return KEEP;
}
*offset = out_header.Write(output, *offset, ciphertext);
return CHANGE;
}
private:
uint8_t old_ct_;
uint8_t new_ct_;
bool replaced_;
};
// The next tests check the behaviour of KU before the handshake is finished.
TEST_F(TlsConnectDatagram13, DTLSKU_TooEarly_Client) {
StartConnect();
// This filter takes the record and if it finds kTlsHandshakeFinished
// it replaces it with kTlsHandshakeKeyUpdate
// Then, the KeyUpdate will be started when the handshake is not yet finished
// This handshake will be cancelled.
auto filter = MakeTlsFilter<DTlsEncryptedHandshakeHeaderReplacer>(
server_, kTlsHandshakeFinished, kTlsHandshakeKeyUpdate);
filter->EnableDecryption();
client_->Handshake();
server_->Handshake();
ExpectAlert(client_, kTlsAlertUnexpectedMessage);
client_->Handshake();
client_->CheckErrorCode(SSL_ERROR_RX_UNEXPECTED_KEY_UPDATE);
server_->Handshake();
server_->CheckErrorCode(SSL_ERROR_HANDSHAKE_UNEXPECTED_ALERT);
}
TEST_F(TlsConnectDatagram13, DTLSKU_TooEarly_Server) {
StartConnect();
// This filter takes the record and if it finds kTlsHandshakeFinished
// it replaces it with kTlsHandshakeKeyUpdate
auto filter = MakeTlsFilter<DTlsEncryptedHandshakeHeaderReplacer>(
client_, kTlsHandshakeFinished, kTlsHandshakeKeyUpdate);
filter->EnableDecryption();
client_->Handshake();
server_->Handshake();
client_->Handshake();
ExpectAlert(server_, kTlsAlertUnexpectedMessage);
server_->Handshake();
server_->CheckErrorCode(SSL_ERROR_RX_UNEXPECTED_KEY_UPDATE);
client_->Handshake();
client_->CheckErrorCode(SSL_ERROR_HANDSHAKE_UNEXPECTED_ALERT);
}
} // namespace nss_test