Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  ssl_keyupdate_unittest.cc   Sprache: 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

Messung V0.5
C=73 H=97 G=85

¤ Dauer der Verarbeitung: 0.18 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge