tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

ssl_timers_unittest.cc (9647B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
      5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #include "secerr.h"
      8 #include "ssl.h"
      9 #include "sslerr.h"
     10 #include "sslproto.h"
     11 
     12 extern "C" {
     13 // This is not something that should make you happy.
     14 #include "libssl_internals.h"
     15 }
     16 
     17 #include "gtest_utils.h"
     18 #include "nss_scoped_ptrs.h"
     19 #include "tls_connect.h"
     20 #include "tls_filter.h"
     21 #include "tls_parser.h"
     22 
     23 namespace nss_test {
     24 
     25 // Reproducing https://bugzilla.mozilla.org/show_bug.cgi?id=1978603
     26 // The test causes assertion failure: timer->cb == NULL, at
     27 // lib/ssl/dtlscon.c:922
     28 
     29 // The general problem in the bug was that each post-handshake message
     30 // was starting a new retransmit timer.
     31 // We've decided to change the timer logic such that a retransmit timer
     32 // will be restarted when a new request for a timer arrives.
     33 
     34 // This test ensures that if two different post-handshake messages are queued
     35 // for retransmission, the timer behaves correctly. When the second message is
     36 // queued, we reset the timer. This means a message never waits longer than the
     37 // minimum timer delay. The first message queued will be retransmitted a bit
     38 // more aggressively than it would otherwise, but this is unlikely to be a
     39 // problem.
     40 
     41 // We're currently supporting NewSessionTicker and KeyUpdate post-handshake
     42 // messages.
     43 
     44 // The filter will be dropping Key Update and New Session Ticket until disabled
     45 // When it's disabled, it will keep track of the New Session Ticket messages
     46 // sent by the server, and when it founds one - it will record the sequence
     47 // number This sequence number will then be provided to the second filter that
     48 // will be checking the list of ACKs seaching for this message
     49 class TLSSessionTicketAndKUDropper : public TlsRecordFilter {
     50 public:
     51  TLSSessionTicketAndKUDropper(const std::shared_ptr<TlsAgent>& a)
     52      : TlsRecordFilter(a), enabled_(true), sequenceNumberNST(0) {}
     53 
     54  void disable() { enabled_ = false; }
     55 
     56  uint64_t getSentSessionTicketSeqNum() { return sequenceNumberNST; }
     57 
     58 protected:
     59  PacketFilter::Action FilterRecord(const TlsRecordHeader& header,
     60                                    const DataBuffer& record, size_t* offset,
     61                                    DataBuffer* output) override {
     62    if (!header.is_protected()) {
     63      return KEEP;
     64    }
     65 
     66    uint16_t protection_epoch;
     67    uint8_t inner_content_type;
     68    DataBuffer plaintext;
     69    TlsRecordHeader out_header;
     70 
     71    if (!Unprotect(header, record, &protection_epoch, &inner_content_type,
     72                   &plaintext, &out_header)) {
     73      return KEEP;
     74    }
     75 
     76    if (plaintext.data()[0] == ssl_hs_new_session_ticket) {
     77      if (enabled_) {
     78        return DROP;
     79      } else {
     80        sequenceNumberNST = out_header.sequence_number();
     81      }
     82    }
     83 
     84    if (plaintext.data()[0] == ssl_hs_key_update && enabled_) {
     85      return DROP;
     86    }
     87 
     88    return KEEP;
     89  }
     90 
     91 private:
     92  bool enabled_;
     93  uint64_t sequenceNumberNST;
     94 };
     95 
     96 class TLSACKRecorder : public TlsRecordFilter {
     97 public:
     98  TLSACKRecorder(const std::shared_ptr<TlsAgent>& a)
     99      : TlsRecordFilter(a),
    100        enabled_(false),
    101        isSeqNumFound(false),
    102        sequenceNumberToFindACKed(0) {}
    103 
    104  void EnableTLSACKCatcherWithSeqNum(uint64_t seqNum) {
    105    enabled_ = true;
    106    sequenceNumberToFindACKed = seqNum;
    107  }
    108 
    109  bool isNSTACKFound() { return isSeqNumFound; }
    110 
    111 protected:
    112  PacketFilter::Action FilterRecord(const TlsRecordHeader& header,
    113                                    const DataBuffer& record, size_t* offset,
    114                                    DataBuffer* output) override {
    115    if (!enabled_) {
    116      return KEEP;
    117    }
    118 
    119    if (!header.is_protected()) {
    120      return KEEP;
    121    }
    122 
    123    uint16_t protection_epoch;
    124    uint8_t inner_content_type;
    125    DataBuffer plaintext;
    126    TlsRecordHeader out_header;
    127 
    128    if (!Unprotect(header, record, &protection_epoch, &inner_content_type,
    129                   &plaintext, &out_header)) {
    130      return KEEP;
    131    }
    132 
    133    if (plaintext.data() == NULL || plaintext.len() == 0) {
    134      return KEEP;
    135    }
    136 
    137    if (decrypting() && inner_content_type != ssl_ct_ack) {
    138      return KEEP;
    139    }
    140 
    141    uint8_t ack_message_header_len = 2;
    142 
    143    uint8_t ack_message_len_one_ACK = 16;
    144    size_t acks = plaintext.len() - ack_message_header_len;
    145    EXPECT_EQ((uint64_t)0, acks % ack_message_len_one_ACK);
    146    acks = acks / ack_message_len_one_ACK;
    147 
    148    // struct {
    149    //   uint64 epoch;
    150    //   uint64 sequence_number;
    151    // } RecordNumber;
    152 
    153    // sequenceNumberToFindACKed has 16 bits for epoch and 48 for seqNum
    154    uint64_t epoch = sequenceNumberToFindACKed >> 48;
    155    uint64_t seqNum = sequenceNumberToFindACKed & 0xFFFFFFFFFFFF;
    156 
    157    uint64_t lastByteEpoch = 0;
    158    uint64_t leastByteSequence = 0;
    159 
    160    for (size_t i = 0; i < acks; i++) {
    161      // Here we check that the last byte of the epoch and the last byte of the
    162      // sequence Because we just sent a couple of messages, so the values will
    163      // be less than 256.
    164      lastByteEpoch = plaintext.data()[2 + i * ack_message_len_one_ACK + 7];
    165      leastByteSequence =
    166          plaintext.data()[2 + i * ack_message_len_one_ACK + 15];
    167 
    168      if ((epoch % 256 == lastByteEpoch) &&
    169          (seqNum % 256) == leastByteSequence) {
    170        isSeqNumFound = true;
    171        return KEEP;
    172      }
    173    }
    174    return KEEP;
    175  }
    176 
    177 private:
    178  bool enabled_;
    179  bool isSeqNumFound;
    180  uint64_t sequenceNumberToFindACKed;
    181 };
    182 
    183 TEST_F(TlsConnectDatagram13, SendTicketThenKeyUpdate) {
    184  ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
    185  Connect();
    186 
    187  SendReceive();  // Need to read so that we absorb the session tickets.
    188  CheckKeys();
    189 
    190  // Resume the connection.
    191  Reset();
    192  ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
    193  ExpectResumption(RESUME_TICKET);
    194 
    195  auto filter = MakeTlsFilter<TLSSessionTicketAndKUDropper>(server_);
    196  filter->EnableDecryption();
    197 
    198  auto ackRecorderFilter = MakeTlsFilter<TLSACKRecorder>(client_);
    199  ackRecorderFilter->EnableDecryption();
    200 
    201  // This should cause sending a NewSessionTicket (thus, starting the timer)
    202  // Sending the NewSessionTicket will be blocked by the filter
    203  Connect();
    204 
    205  // Server sends Key Update
    206  // The first Key Update will also be dropped by the server
    207  EXPECT_EQ(SECSuccess, SSL_KeyUpdate(server_->ssl_fd(), false));
    208 
    209  client_->ReadBytes();
    210  // Check that the client indeed has not received the KU.
    211  SSLInt_SendImmediateACK(client_->ssl_fd());
    212  server_->ReadBytes();
    213  CheckEpochs(3, 3);
    214 
    215  // Disabling dropping the message, the effective retransmit will start
    216  filter->disable();
    217 
    218  // So, we don't have to wait until the next retransmit happens
    219  ShiftDtlsTimers();
    220  server_->ReadBytes();
    221  // We get the Sequence number of the NewSessionTicket that the server has sent
    222  uint64_t sequenceNumberNST = filter->getSentSessionTicketSeqNum();
    223  // And we check that the client has received (thus acked) the newly
    224  // retransmitted NewSessionTicket
    225  ackRecorderFilter->EnableTLSACKCatcherWithSeqNum(sequenceNumberNST);
    226 
    227  // Client Received NewSessionTicker and KU
    228  client_->ReadBytes();
    229  SSLInt_SendImmediateACK(client_->ssl_fd());
    230  server_->ReadBytes();
    231 
    232  // Client and Server both received and processed KU
    233  CheckEpochs(3, 4);
    234 
    235  // Client has successfully received and sent an ACK for NST message
    236  EXPECT_EQ(true, ackRecorderFilter->isNSTACKFound());
    237 
    238  SendReceive(50);
    239 }
    240 
    241 class TLSIthMessageSeqNumDropper : public TlsRecordFilter {
    242 public:
    243  TLSIthMessageSeqNumDropper(const std::shared_ptr<TlsAgent>& a,
    244                             uint8_t messageSeqNumToDrop)
    245      : TlsRecordFilter(a),
    246        enabled_(true),
    247        messageSeqNumToDrop_(messageSeqNumToDrop),
    248        currentMessageSeqNum_(0) {}
    249 
    250  void disable() { enabled_ = false; }
    251 
    252 protected:
    253  PacketFilter::Action FilterRecord(const TlsRecordHeader& header,
    254                                    const DataBuffer& record, size_t* offset,
    255                                    DataBuffer* output) override {
    256    if (enabled_ && currentMessageSeqNum_ == messageSeqNumToDrop_) {
    257      enabled_ = false;
    258 
    259      uint16_t protection_epoch;
    260      uint8_t inner_content_type;
    261      DataBuffer plaintext;
    262      TlsRecordHeader out_header;
    263 
    264      if (!Unprotect(header, record, &protection_epoch, &inner_content_type,
    265                     &plaintext, &out_header)) {
    266        return KEEP;
    267      }
    268 
    269      if (inner_content_type == ssl_ct_ack ||
    270          inner_content_type == ssl_ct_application_data) {
    271        return KEEP;
    272      }
    273 
    274      return DROP;
    275    }
    276 
    277    currentMessageSeqNum_ += 1;
    278    return KEEP;
    279  }
    280 
    281 private:
    282  bool enabled_;
    283  uint8_t messageSeqNumToDrop_;
    284  uint8_t currentMessageSeqNum_;
    285 };
    286 
    287 TEST_F(TlsConnectDatagram13, HandshakeDropIthMessageServer) {
    288  uint8_t maxServerMessageSeq = 10;
    289 
    290  for (uint8_t currMesSeqNum = 0; currMesSeqNum < maxServerMessageSeq;
    291       currMesSeqNum++) {
    292    EnsureTlsSetup();
    293    auto filter =
    294        MakeTlsFilter<TLSIthMessageSeqNumDropper>(server_, currMesSeqNum);
    295    filter->EnableDecryption();
    296 
    297    Connect();
    298    SendReceive();
    299    Reset();
    300  }
    301 }
    302 
    303 TEST_F(TlsConnectDatagram13, HandshakeDropIthMessageClient) {
    304  uint8_t maxClientMessageSeq = 10;
    305 
    306  for (uint8_t currMesSeqNum = 0; currMesSeqNum < maxClientMessageSeq;
    307       currMesSeqNum++) {
    308    EnsureTlsSetup();
    309    auto filter =
    310        MakeTlsFilter<TLSIthMessageSeqNumDropper>(client_, currMesSeqNum);
    311    filter->EnableDecryption();
    312 
    313    Connect();
    314    SendReceive();
    315    Reset();
    316  }
    317 }
    318 
    319 }  // namespace nss_test