1501 lines
No EOL
50 KiB
C++
1501 lines
No EOL
50 KiB
C++
/* -*- 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,
|
|
// See bug https://bugzilla.mozilla.org/show_bug.cgi?id=1809872
|
|
// 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
|