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


Quelle  ssl_drop_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 "sslexp.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_P(TlsConnectDatagramPre13, DropClientFirstFlightOnce) {
  client_->SetFilter(std::make_shared<SelectiveDropFilter>(0x1));
  Connect();
  SendReceive();
}

TEST_P(TlsConnectDatagramPre13, DropServerFirstFlightOnce) {
  server_->SetFilter(std::make_shared<SelectiveDropFilter>(0x1));
  Connect();
  SendReceive();
}

// This drops the first transmission from both the client and server of all
// flights that they send.  Note: In DTLS 1.3, the shorter handshake means that
// this will also drop some application data, so we can't call SendReceive().
TEST_P(TlsConnectDatagramPre13, DropAllFirstTransmissions) {
  client_->SetFilter(std::make_shared<SelectiveDropFilter>(0x15));
  server_->SetFilter(std::make_shared<SelectiveDropFilter>(0x5));
  Connect();
}

// This drops the server's first flight three times.
TEST_P(TlsConnectDatagramPre13, DropServerFirstFlightThrice) {
  server_->SetFilter(std::make_shared<SelectiveDropFilter>(0x7));
  Connect();
}

// This drops the client's second flight once
TEST_P(TlsConnectDatagramPre13, DropClientSecondFlightOnce) {
  client_->SetFilter(std::make_shared<SelectiveDropFilter>(0x2));
  Connect();
}

// This drops the client's second flight three times.
TEST_P(TlsConnectDatagramPre13, DropClientSecondFlightThrice) {
  client_->SetFilter(std::make_shared<SelectiveDropFilter>(0xe));
  Connect();
}

// This drops the server's second flight three times.
TEST_P(TlsConnectDatagramPre13, DropServerSecondFlightThrice) {
  server_->SetFilter(std::make_shared<SelectiveDropFilter>(0xe));
  Connect();
}

static void CheckAcks(const std::shared_ptr<TlsRecordRecorder>& acks,
                      size_t index, std::vector<uint64_t> expected) {
  ASSERT_LT(index, acks->count());
  const DataBuffer& buf = acks->record(index).buffer;
  size_t offset = 2;
  uint64_t len;
  // RFC 9147 -  7. ACK Message.
  // 16 bytes correspond to the length of the epoch and the length of the seqNum
  EXPECT_EQ(2 + expected.size() * 16, buf.len());
  ASSERT_TRUE(buf.Read(0, 2, &len));
  ASSERT_EQ(static_cast<size_t>(len + 2), buf.len());
  if ((2 + expected.size() * 16) != buf.len()) {
    while (offset < buf.len()) {
      uint64_t ack;
      ASSERT_TRUE(buf.Read(offset, 8, &ack));
      offset += 8;
      std::cerr << "Ack=0x" << std::hex << ack << std::dec << std::endl;
    }
    return;
  }

  for (size_t i = 0; i < expected.size(); ++i) {
    uint64_t a = expected[i];
    uint64_t ackEpoch;
    uint64_t ackSeq;
    ASSERT_TRUE(buf.Read(offset, 8, &ackEpoch));
    offset += 8;
    ASSERT_TRUE(buf.Read(offset, 8, &ackSeq));
    offset += 8;
    uint64_t ack = (ackEpoch << 48) | ackSeq;
    if (a != ack) {
      ADD_FAILURE() << "Wrong ack " << i << " expected=0x" << std::hex << a
                    << " got=0x" << ack << std::dec;
    }
  }
}

class TlsDropDatagram13 : public TlsConnectDatagram13,
                          public ::testing::WithParamInterface<bool> {
 public:
  TlsDropDatagram13()
      : client_filters_(),
        server_filters_(),
        expected_client_acks_(0),
        expected_server_acks_(1) {}

  void SetUp() override {
    TlsConnectDatagram13::SetUp();
    ConfigureSessionCache(RESUME_NONE, RESUME_NONE);
    int short_header = GetParam() ? PR_TRUE : PR_FALSE;
    client_->SetOption(SSL_ENABLE_DTLS_SHORT_HEADER, short_header);
    server_->SetOption(SSL_ENABLE_DTLS_SHORT_HEADER, short_header);
    SetFilters();
  }

  void SetFilters() {
    EnsureTlsSetup();
    client_filters_.Init(client_);
    server_filters_.Init(server_);
  }

  void HandshakeAndAck(const std::shared_ptr<TlsAgent>& agent) {
    agent->Handshake();  // Read flight.
    ShiftDtlsTimers();
    agent->Handshake();  // Generate ACK.
  }

  void ShrinkPostServerHelloMtu() {
    // Abuse the custom extension mechanism to modify the MTU so that the
    // Certificate message is split into two pieces.
    ASSERT_EQ(
        SECSuccess,
        SSL_InstallExtensionHooks(
            server_->ssl_fd(), 1,
            [](PRFileDesc* fd, SSLHandshakeType message, PRUint8* data,
               unsigned int* len, unsigned int maxLen, void* arg) -> PRBool {
              SSLInt_SetMTU(fd, 500);  // Splits the certificate.
              return PR_FALSE;
            },
            nullptr,
            [](PRFileDesc* fd, SSLHandshakeType message, const PRUint8* data,
               unsigned int len, SSLAlertDescription* alert,
               void* arg) -> SECStatus { return SECSuccess; },
            nullptr));
  }

 protected:
  class DropAckChain {
   public:
    DropAckChain()
        : records_(nullptr), ack_(nullptr), drop_(nullptr), chain_(nullptr) {}

    void Init(const std::shared_ptr<TlsAgent>& agent) {
      records_ = std::make_shared<TlsRecordRecorder>(agent);
      ack_ = std::make_shared<TlsRecordRecorder>(agent, ssl_ct_ack);
      ack_->EnableDecryption();
      drop_ = std::make_shared<SelectiveRecordDropFilter>(agent, 0, false);
      chain_ = std::make_shared<ChainedPacketFilter>(
          ChainedPacketFilterInit({records_, ack_, drop_}));
      agent->SetFilter(chain_);
    }

    const TlsRecord& record(size_t i) const { return records_->record(i); }

    std::shared_ptr<TlsRecordRecorder> records_;
    std::shared_ptr<TlsRecordRecorder> ack_;
    std::shared_ptr<SelectiveRecordDropFilter> drop_;
    std::shared_ptr<PacketFilter> chain_;
  };

  void CheckedHandshakeSendReceive() {
    Handshake();
    CheckPostHandshake();
  }

  void CheckPostHandshake() {
    CheckConnected();
    SendReceive();
    EXPECT_EQ(expected_client_acks_, client_filters_.ack_->count());
    EXPECT_EQ(expected_server_acks_, server_filters_.ack_->count());
  }

 protected:
  DropAckChain client_filters_;
  DropAckChain server_filters_;
  size_t expected_client_acks_;
  size_t expected_server_acks_;
};

// All of these tests produce a minimum one ACK, from the server
// to the client upon receiving the client Finished.
// Dropping complete first and second flights does not produce
// ACKs
TEST_P(TlsDropDatagram13, DropClientFirstFlightOnce) {
  client_filters_.drop_->Reset({0});
  StartConnect();
  client_->Handshake();
  server_->Handshake();
  CheckedHandshakeSendReceive();
  CheckAcks(server_filters_.ack_, 0, {0x0002000000000000ULL});
}

TEST_P(TlsDropDatagram13, DropServerFirstFlightOnce) {
  server_filters_.drop_->Reset(0xff);
  StartConnect();
  client_->Handshake();
  // Send the first flight, all dropped.
  server_->Handshake();
  server_filters_.drop_->Disable();
  CheckedHandshakeSendReceive();
  CheckAcks(server_filters_.ack_, 0, {0x0002000000000000ULL});
}

// Dropping the server's first record also does not produce
// an ACK because the next record is ignored.
// TODO(ekr@rtfm.com): We should generate an empty ACK.
TEST_P(TlsDropDatagram13, DropServerFirstRecordOnce) {
  server_filters_.drop_->Reset({0});
  StartConnect();
  client_->Handshake();
  server_->Handshake();
  Handshake();
  CheckedHandshakeSendReceive();
  CheckAcks(server_filters_.ack_, 0, {0x0002000000000000ULL});
}

// Dropping the second packet of the server's flight should
// produce an ACK.
TEST_P(TlsDropDatagram13, DropServerSecondRecordOnce) {
  server_filters_.drop_->Reset({1});
  StartConnect();
  client_->Handshake();
  server_->Handshake();
  HandshakeAndAck(client_);
  expected_client_acks_ = 1;
  CheckedHandshakeSendReceive();
  CheckAcks(client_filters_.ack_, 0, {0});  // ServerHello
  CheckAcks(server_filters_.ack_, 0, {0x0002000000000000ULL});
}

// Drop the server ACK and verify that the client retransmits
// the ClientHello.
TEST_P(TlsDropDatagram13, DropServerAckOnce) {
  StartConnect();
  client_->Handshake();
  server_->Handshake();
  // At this point the server has sent it's first flight,
  // so make it drop the ACK.
  server_filters_.drop_->Reset({0});
  client_->Handshake();  // Send the client Finished.
  server_->Handshake();  // Receive the Finished and send the ACK.
  EXPECT_EQ(TlsAgent::STATE_CONNECTED, client_->state());
  EXPECT_EQ(TlsAgent::STATE_CONNECTED, server_->state());
  // Wait for the DTLS timeout to make sure we retransmit the
  // Finished.
  ShiftDtlsTimers();
  client_->Handshake();  // Retransmit the Finished.
  server_->Handshake();  // Read the Finished and send an ACK.
  uint8_t buf[1];
  PRInt32 rv = PR_Read(client_->ssl_fd(), buf, sizeof(buf));
  expected_server_acks_ = 2;
  EXPECT_GT(0, rv);
  EXPECT_EQ(PR_WOULD_BLOCK_ERROR, PORT_GetError());
  CheckPostHandshake();
  // There should be two copies of the finished ACK
  CheckAcks(server_filters_.ack_, 0, {0x0002000000000000ULL});
  CheckAcks(server_filters_.ack_, 1, {0x0002000000000000ULL});
}

// Drop the client certificate verify.
TEST_P(TlsDropDatagram13, DropClientCertVerify) {
  StartConnect();
  client_->SetupClientAuth();
  server_->RequestClientAuth(true);
  client_->Handshake();
  server_->Handshake();
  // Have the client drop Cert Verify
  client_filters_.drop_->Reset({1});
  expected_server_acks_ = 2;
  CheckedHandshakeSendReceive();
  // Ack of the Cert.
  CheckAcks(server_filters_.ack_, 0, {0x0002000000000000ULL});
  // Ack of the whole client handshake.
  CheckAcks(
      server_filters_.ack_, 1,
      {0x0002000000000000ULL,    // CH (we drop everything after this on client)
       0x0002000000000003ULL,    // CT (2)
       0x0002000000000004ULL});  // FIN (2)
}

// Shrink the MTU down so that certs get split and drop the first piece.
TEST_P(TlsDropDatagram13, DropFirstHalfOfServerCertificate) {
  server_filters_.drop_->Reset({2});
  StartConnect();
  ShrinkPostServerHelloMtu();
  client_->Handshake();
  server_->Handshake();
  // Check that things got split.
  EXPECT_EQ(6UL,
            server_filters_.records_->count());  // SH, EE, CT1, CT2, CV, FIN
  size_t ct1_size = server_filters_.record(2).buffer.len();
  server_filters_.records_->Clear();
  expected_client_acks_ = 1;
  HandshakeAndAck(client_);
  server_->Handshake();                               // Retransmit
  EXPECT_EQ(3UL, server_filters_.records_->count());  // CT2, CV, FIN
  // Check that the first record is CT1 (which is identical to the same
  // as the previous CT1).
  EXPECT_EQ(ct1_size, server_filters_.record(0).buffer.len());
  CheckedHandshakeSendReceive();
  CheckAcks(client_filters_.ack_, 0,
            {0,                        // SH
             0x0002000000000000ULL,    // EE
             0x0002000000000002ULL});  // CT2
  CheckAcks(server_filters_.ack_, 0, {0x0002000000000000ULL});
}

// Shrink the MTU down so that certs get split and drop the second piece.
TEST_P(TlsDropDatagram13, DropSecondHalfOfServerCertificate) {
  server_filters_.drop_->Reset({3});
  StartConnect();
  ShrinkPostServerHelloMtu();
  client_->Handshake();
  server_->Handshake();
  // Check that things got split.
  EXPECT_EQ(6UL,
            server_filters_.records_->count());  // SH, EE, CT1, CT2, CV, FIN
  size_t ct1_size = server_filters_.record(3).buffer.len();
  server_filters_.records_->Clear();
  expected_client_acks_ = 1;
  HandshakeAndAck(client_);
  server_->Handshake();                               // Retransmit
  EXPECT_EQ(3UL, server_filters_.records_->count());  // CT1, CV, FIN
  // Check that the first record is CT1
  EXPECT_EQ(ct1_size, server_filters_.record(0).buffer.len());
  CheckedHandshakeSendReceive();
  CheckAcks(client_filters_.ack_, 0,
            {
                0,                      // SH
                0x0002000000000000ULL,  // EE
                0x0002000000000001ULL,  // CT1
            });
  CheckAcks(server_filters_.ack_, 0, {0x0002000000000000ULL});
}

// In this test, the Certificate message is sent four times, we drop all or part
// of the first three attempts:
// 1. Without fragmentation so that we can see how big it is - we drop that.
// 2. In two pieces - we drop half AND the resulting ACK.
// 3. In three pieces - we drop the middle piece.
//
// After that we let all the ACKs through and allow the handshake to complete
// without further interference.
//
// This allows us to test that ranges of handshake messages are sent correctly
// even when there are overlapping acknowledgments; that ACKs with duplicate or
// overlapping message ranges are handled properly; and that extra
// retransmissions are handled properly.
class TlsFragmentationAndRecoveryTest : public TlsDropDatagram13 {
 public:
  TlsFragmentationAndRecoveryTest() : cert_len_(0) {}

 protected:
  void RunTest(size_t dropped_half) {
    FirstFlightDropCertificate();

    SecondAttemptDropHalf(dropped_half);
    size_t dropped_half_size = server_record_len(dropped_half);
    size_t second_flight_count = server_filters_.records_->count();

    ThirdAttemptDropMiddle();
    size_t repaired_third_size = server_record_len((dropped_half == 0) ? 0 : 2);
    size_t third_flight_count = server_filters_.records_->count();

    AckAndCompleteRetransmission();
    size_t final_server_flight_count = server_filters_.records_->count();
    EXPECT_LE(3U, final_server_flight_count);  // CT(sixth), CV, Fin
    CheckSizeOfSixth(dropped_half_size, repaired_third_size);

    SendDelayedAck();
    // Same number of messages as the last flight.
    EXPECT_EQ(final_server_flight_count, server_filters_.records_->count());
    // Double check that the Certificate size is still correct.
    CheckSizeOfSixth(dropped_half_size, repaired_third_size);

    CompleteHandshake(final_server_flight_count);

    // This is the ACK for the first attempt to send a whole certificate.
    std::vector<uint64_t> client_acks = {
        0,                     // SH
        0x0002000000000000ULL  // EE
    };
    CheckAcks(client_filters_.ack_, 0, client_acks);
    // And from the second attempt for the half was kept (we delayed this ACK).
    client_acks.push_back(0x0002000000000000ULL + second_flight_count +
                          ~dropped_half % 2);
    CheckAcks(client_filters_.ack_, 1, client_acks);
    // And the third attempt where the first and last thirds got through.
    client_acks.push_back(0x0002000000000000ULL + second_flight_count +
                          third_flight_count - 1);
    client_acks.push_back(0x0002000000000000ULL + second_flight_count +
                          third_flight_count + 1);
    CheckAcks(client_filters_.ack_, 2, client_acks);
    CheckAcks(server_filters_.ack_, 0, {0x0002000000000000ULL});
  }

 private:
  void FirstFlightDropCertificate() {
    StartConnect();
    client_->Handshake();

    // Note: 1 << N is the Nth packet, starting from zero.
    server_filters_.drop_->Reset(1 << 2);  // Drop Cert0.
    server_->Handshake();
    EXPECT_EQ(5U, server_filters_.records_->count());  // SH, EE, CT, CV, Fin
    cert_len_ = server_filters_.records_->record(2).buffer.len();

    HandshakeAndAck(client_);
    EXPECT_EQ(2U, client_filters_.records_->count());
  }

  // Lower the MTU so that the server has to split the certificate in two
  // pieces.  The server resends Certificate (in two), plus CV and Fin.
  void SecondAttemptDropHalf(size_t dropped_half) {
    ASSERT_LE(0U, dropped_half);
    ASSERT_GT(2U, dropped_half);
    server_filters_.records_->Clear();
    server_filters_.drop_->Reset({dropped_half});  // Drop Cert1[half]
    SplitServerMtu(2);
    server_->Handshake();
    EXPECT_LE(4U, server_filters_.records_->count());  // CT x2, CV, Fin

    // Generate and capture the ACK from the client.
    client_filters_.drop_->Reset({0});
    HandshakeAndAck(client_);
    EXPECT_EQ(3U, client_filters_.records_->count());
  }

  // Lower the MTU again so that the server sends Certificate cut into three
  // pieces.  Drop the middle piece.
  void ThirdAttemptDropMiddle() {
    server_filters_.records_->Clear();
    server_filters_.drop_->Reset({1});  // Drop Cert2[1] (of 3)
    SplitServerMtu(3);
    // Because we dropped the client ACK, the server retransmits on a timer.
    ShiftDtlsTimers();
    server_->Handshake();
    EXPECT_LE(5U, server_filters_.records_->count());  // CT x3, CV, Fin
  }

  void AckAndCompleteRetransmission() {
    // Generate ACKs.
    HandshakeAndAck(client_);
    // The server should send the final sixth of the certificate: the client has
    // acknowledged the first half and the last third.  Also send CV and Fin.
    server_filters_.records_->Clear();
    server_->Handshake();
  }

  void CheckSizeOfSixth(size_t size_of_half, size_t size_of_third) {
    // Work out if the final sixth is the right size.  We get the records with
    // overheads added, which obscures the length of the payload.  We want to
    // ensure that the server only sent the missing sixth of the Certificate.
    //
    // We captured |size_of_half + overhead| and |size_of_third + overhead| and
    // want to calculate |size_of_third - size_of_third + overhead|.  We can't
    // calculate |overhead|, but it is is (currently) always a handshake message
    // header, a content type, and an authentication tag:
    static const size_t record_overhead = 12 + 1 + 16;
    EXPECT_EQ(size_of_half - size_of_third + record_overhead,
              server_filters_.records_->record(0).buffer.len());
  }

  void SendDelayedAck() {
    // Send the ACK we held back.  The reordered ACK doesn't add new
    // information,
    // but triggers an extra retransmission of the missing records again (even
    // though the client has all that it needs).
    client_->SendRecordDirect(client_filters_.records_->record(2));
    server_filters_.records_->Clear();
    server_->Handshake();
  }

  void CompleteHandshake(size_t extra_retransmissions) {
    // All this messing around shouldn't cause a failure...
    Handshake();
    // ...but it leaves a mess.  Add an extra few calls to Handshake() for the
    // client so that it absorbs the extra retransmissions.
    for (size_t i = 0; i < extra_retransmissions; ++i) {
      client_->Handshake();
    }
    CheckConnected();
  }

  // Split the server MTU so that the Certificate is split into |count| pieces.
  // The calculation doesn't need to be perfect as long as the Certificate
  // message is split into the right number of pieces.
  void SplitServerMtu(size_t count) {
    // Set the MTU based on the formula:
    // bare_size = cert_len_ - actual_overhead
    // MTU = ceil(bare_size / count) + pessimistic_overhead
    //
    // actual_overhead is the amount of actual overhead on the record we
    // captured, which is (note that our length doesn't include the header):
    static const size_t actual_overhead = 12 +  // handshake message header
                                          1 +   // content type
                                          16;   // authentication tag
    size_t bare_size = cert_len_ - actual_overhead;

    // pessimistic_overhead is the amount of expansion that NSS assumes will be
    // added to each handshake record.  Right now, that is DTLS_MIN_FRAGMENT:
    static const size_t pessimistic_overhead =
        12 +  // handshake message header
        1 +   // content type
        13 +  // record header length
        64;   // maximum record expansion: IV, MAC and block cipher expansion

    size_t mtu = (bare_size + count - 1) / count + pessimistic_overhead;
    if (g_ssl_gtest_verbose) {
      std::cerr << "server: set MTU to " << mtu << std::endl;
    }
    EXPECT_EQ(SECSuccess, SSLInt_SetMTU(server_->ssl_fd(), mtu));
  }

  size_t server_record_len(size_t index) const {
    return server_filters_.records_->record(index).buffer.len();
  }

  size_t cert_len_;
};

TEST_P(TlsFragmentationAndRecoveryTest, DropFirstHalf) { RunTest(0); }

TEST_P(TlsFragmentationAndRecoveryTest, DropSecondHalf) { RunTest(1); }

TEST_P(TlsDropDatagram13, NoDropsDuringZeroRtt) {
  SetupForZeroRtt();
  SetFilters();
  std::cerr << "Starting second handshake" << std::endl;
  client_->Set0RttEnabled(true);
  server_->Set0RttEnabled(true);
  ExpectResumption(RESUME_TICKET);
  ZeroRttSendReceive(truetrue);
  Handshake();
  ExpectEarlyDataAccepted(true);
  CheckConnected();
  SendReceive();
  EXPECT_EQ(0U, client_filters_.ack_->count());
  CheckAcks(server_filters_.ack_, 0,
            {0x0001000000000001ULL,    // EOED
             0x0002000000000000ULL});  // Finished
}

TEST_P(TlsDropDatagram13, DropEEDuringZeroRtt) {
  SetupForZeroRtt();
  SetFilters();
  std::cerr << "Starting second handshake" << std::endl;
  client_->Set0RttEnabled(true);
  server_->Set0RttEnabled(true);
  ExpectResumption(RESUME_TICKET);
  server_filters_.drop_->Reset({1});
  ZeroRttSendReceive(truetrue);
  HandshakeAndAck(client_);
  Handshake();
  ExpectEarlyDataAccepted(true);
  CheckConnected();
  SendReceive();
  CheckAcks(client_filters_.ack_, 0, {0});
  CheckAcks(server_filters_.ack_, 0,
            {0x0001000000000002ULL,    // EOED
             0x0002000000000000ULL});  // Finished
}

class TlsReorderDatagram13 : public TlsDropDatagram13 {
 public:
  TlsReorderDatagram13() {}

  // Send records from the records buffer in the given order.
  void ReSend(TlsAgent::Role side, std::vector<size_t> indices) {
    std::shared_ptr<TlsAgent> agent;
    std::shared_ptr<TlsRecordRecorder> records;

    if (side == TlsAgent::CLIENT) {
      agent = client_;
      records = client_filters_.records_;
    } else {
      agent = server_;
      records = server_filters_.records_;
    }

    for (auto i : indices) {
      agent->SendRecordDirect(records->record(i));
    }
  }
};

// Reorder the server records so that EE comes at the end
// of the flight and will still produce an ACK.
TEST_P(TlsDropDatagram13, ReorderServerEE) {
  server_filters_.drop_->Reset({1});
  StartConnect();
  client_->Handshake();
  server_->Handshake();
  // We dropped EE, now reinject.
  server_->SendRecordDirect(server_filters_.record(1));
  expected_client_acks_ = 1;
  HandshakeAndAck(client_);
  CheckedHandshakeSendReceive();
  CheckAcks(client_filters_.ack_, 0,
            {
                0,                   // SH
                0x0002000000000000,  // EE
            });
  CheckAcks(server_filters_.ack_, 0, {0x0002000000000000ULL});
}

// The client sends an out of order non-handshake message
// but with the handshake key.
TEST_F(TlsConnectDatagram13, SendOutOfOrderAppWithHandshakeKey) {
  StartConnect();
  // Capturing secrets means that we can't use decrypting filters on the client.
  TlsSendCipherSpecCapturer capturer(client_);
  client_->Handshake();
  server_->Handshake();
  client_->Handshake();
  EXPECT_EQ(TlsAgent::STATE_CONNECTED, client_->state());
  server_->Handshake();
  EXPECT_EQ(TlsAgent::STATE_CONNECTED, server_->state());
  // After the client sends Finished, inject an app data record
  // with the handshake key. This should produce an alert.
  uint8_t buf[] = {'a''b''c'};
  auto spec = capturer.spec(0);
  ASSERT_NE(nullptr, spec.get());
  ASSERT_EQ(2, spec->epoch());

  uint8_t dtls13_ct = kCtDtlsCiphertext | kCtDtlsCiphertext16bSeqno |
                      kCtDtlsCiphertextLengthPresent;
  ASSERT_TRUE(client_->SendEncryptedRecord(spec, 0x0002000000000002, dtls13_ct,
                                           DataBuffer(buf, sizeof(buf))));

  // Now have the server consume the bogus message.
  server_->ExpectSendAlert(illegal_parameter, kTlsAlertFatal);
  server_->Handshake();
  EXPECT_EQ(TlsAgent::STATE_ERROR, server_->state());
  EXPECT_EQ(SSL_ERROR_RX_UNKNOWN_RECORD_TYPE, PORT_GetError());
}

TEST_F(TlsConnectDatagram13, SendOutOfOrderHsNonsenseWithHandshakeKey) {
  StartConnect();
  TlsSendCipherSpecCapturer capturer(client_);
  auto acks = MakeTlsFilter<TlsRecordRecorder>(server_, ssl_ct_ack);
  acks->EnableDecryption();

  client_->Handshake();
  server_->Handshake();
  client_->Handshake();
  EXPECT_EQ(TlsAgent::STATE_CONNECTED, client_->state());
  server_->Handshake();
  EXPECT_EQ(TlsAgent::STATE_CONNECTED, server_->state());
  // Inject a new bogus handshake record, which the server responds
  // to by just ACKing the original one (we ignore the contents).
  uint8_t buf[] = {'a''b''c'};
  auto spec = capturer.spec(0);
  ASSERT_NE(nullptr, spec.get());
  ASSERT_EQ(2, spec->epoch());
  ASSERT_TRUE(client_->SendEncryptedRecord(spec, 0x0002000000000002,
                                           ssl_ct_handshake,
                                           DataBuffer(buf, sizeof(buf))));
  server_->Handshake();
  EXPECT_EQ(2UL, acks->count());
  // The server acknowledges client Finished twice.
  CheckAcks(acks, 0, {0x0002000000000000ULL});
  CheckAcks(acks, 1, {0x0002000000000000ULL});
}

// Shrink the MTU down so that certs get split and then swap the first and
// second pieces of the server certificate.
TEST_P(TlsReorderDatagram13, ReorderServerCertificate) {
  StartConnect();
  ShrinkPostServerHelloMtu();
  client_->Handshake();
  // Drop the entire handshake flight so we can reorder.
  server_filters_.drop_->Reset(0xff);
  server_->Handshake();
  // Check that things got split.
  EXPECT_EQ(6UL,
            server_filters_.records_->count());  // CH, EE, CT1, CT2, CV, FIN
  // Now re-send things in a different order.
  ReSend(TlsAgent::SERVER, std::vector<size_t>{0, 1, 3, 2, 4, 5});
  // Clear.
  server_filters_.drop_->Disable();
  server_filters_.records_->Clear();
  // Wait for client to send ACK.
  ShiftDtlsTimers();
  CheckedHandshakeSendReceive();
  EXPECT_EQ(2UL, server_filters_.records_->count());  // ACK + Data
  CheckAcks(server_filters_.ack_, 0, {0x0002000000000000ULL});
}

TEST_P(TlsReorderDatagram13, DataAfterEOEDDuringZeroRtt) {
  SetupForZeroRtt();
  SetFilters();
  std::cerr << "Starting second handshake" << std::endl;
  client_->Set0RttEnabled(true);
  server_->Set0RttEnabled(true);
  ExpectResumption(RESUME_TICKET);
  // Send the client's first flight of zero RTT data.
  ZeroRttSendReceive(truetrue);
  // Now send another client application data record but
  // capture it.
  client_filters_.records_->Clear();
  client_filters_.drop_->Reset(0xff);
  const char* k0RttData = "123456";
  const PRInt32 k0RttDataLen = static_cast<PRInt32>(strlen(k0RttData));
  PRInt32 rv =
      PR_Write(client_->ssl_fd(), k0RttData, k0RttDataLen);  // 0-RTT write.
  EXPECT_EQ(k0RttDataLen, rv);
  EXPECT_EQ(1UL, client_filters_.records_->count());  // data
  server_->Handshake();
  client_->Handshake();
  ExpectEarlyDataAccepted(true);
  // The server still hasn't received anything at this point.
  EXPECT_EQ(3UL, client_filters_.records_->count());  // data, EOED, FIN
  EXPECT_EQ(TlsAgent::STATE_CONNECTED, client_->state());
  EXPECT_EQ(TlsAgent::STATE_CONNECTING, server_->state());
  // Now re-send the client's messages: EOED, data, FIN
  ReSend(TlsAgent::CLIENT, std::vector<size_t>({1, 0, 2}));
  server_->Handshake();
  CheckConnected();
  EXPECT_EQ(0U, client_filters_.ack_->count());
  // Acknowledgements for EOED and Finished.
  CheckAcks(server_filters_.ack_, 0,
            {0x0001000000000002ULL, 0x0002000000000000ULL});
  uint8_t buf[8];
  rv = PR_Read(server_->ssl_fd(), buf, sizeof(buf));
  EXPECT_EQ(-1, rv);
  EXPECT_EQ(PR_WOULD_BLOCK_ERROR, PORT_GetError());
}

TEST_P(TlsReorderDatagram13, DataAfterFinDuringZeroRtt) {
  SetupForZeroRtt();
  SetFilters();
  std::cerr << "Starting second handshake" << std::endl;
  client_->Set0RttEnabled(true);
  server_->Set0RttEnabled(true);
  ExpectResumption(RESUME_TICKET);
  // Send the client's first flight of zero RTT data.
  ZeroRttSendReceive(truetrue);
  // Now send another client application data record but
  // capture it.
  client_filters_.records_->Clear();
  client_filters_.drop_->Reset(0xff);
  const char* k0RttData = "123456";
  const PRInt32 k0RttDataLen = static_cast<PRInt32>(strlen(k0RttData));
  PRInt32 rv =
      PR_Write(client_->ssl_fd(), k0RttData, k0RttDataLen);  // 0-RTT write.
  EXPECT_EQ(k0RttDataLen, rv);
  EXPECT_EQ(1UL, client_filters_.records_->count());  // data
  server_->Handshake();
  client_->Handshake();
  ExpectEarlyDataAccepted(true);
  // The server still hasn't received anything at this point.
  EXPECT_EQ(3UL, client_filters_.records_->count());  // EOED, FIN, Data
  EXPECT_EQ(TlsAgent::STATE_CONNECTED, client_->state());
  EXPECT_EQ(TlsAgent::STATE_CONNECTING, server_->state());
  // Now re-send the client's messages: EOED, FIN, Data
  ReSend(TlsAgent::CLIENT, std::vector<size_t>({1, 2, 0}));
  server_->Handshake();
  CheckConnected();
  EXPECT_EQ(0U, client_filters_.ack_->count());
  // Acknowledgements for EOED and Finished.
  CheckAcks(server_filters_.ack_, 0,
            {0x0001000000000002ULL, 0x0002000000000000ULL});
  uint8_t buf[8];
  rv = PR_Read(server_->ssl_fd(), buf, sizeof(buf));
  EXPECT_EQ(-1, rv);
  EXPECT_EQ(PR_WOULD_BLOCK_ERROR, PORT_GetError());
}

static void GetCipherAndLimit(uint16_t version, uint16_t* cipher,
                              uint64_t* limit = nullptr) {
  uint64_t l;
  if (!limit) limit = &l;

  if (version < SSL_LIBRARY_VERSION_TLS_1_2) {
    *cipher = TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA;
    *limit = 0x5aULL << 28;
  } else if (version == SSL_LIBRARY_VERSION_TLS_1_2) {
    *cipher = TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256;
    *limit = (1ULL << 48) - 1;
  } else {
    // This test probably isn't especially useful for TLS 1.3, which has a much
    // shorter sequence number encoding.  That space can probably be searched in
    // a reasonable amount of time.
    *cipher = TLS_CHACHA20_POLY1305_SHA256;
    // Assume that we are starting with an expected sequence number of 0.
    *limit = (1ULL << 15) - 1;
  }
}

// This simulates a huge number of drops on one side.
// See Bug 12965514 where a large gap was handled very inefficiently.
TEST_P(TlsConnectDatagram, MissLotsOfPackets) {
  uint16_t cipher;
  uint64_t limit;

  GetCipherAndLimit(version_, &cipher, &limit);

  EnsureTlsSetup();
  server_->EnableSingleCipher(cipher);
  Connect();

  // Note that the limit for ChaCha is 2^48-1.
  EXPECT_EQ(SECSuccess,
            SSLInt_AdvanceWriteSeqNum(client_->ssl_fd(), limit - 10));
  SendReceive();
}

// Send a sequence number of 0xfffd and it should be interpreted as that
// (and not -3 or UINT64_MAX - 2).
TEST_F(TlsConnectDatagram13, UnderflowSequenceNumber) {
  Connect();
  // This is only valid if short headers are disabled.
  client_->SetOption(SSL_ENABLE_DTLS_SHORT_HEADER, PR_FALSE);
  EXPECT_EQ(SECSuccess,
            SSLInt_AdvanceWriteSeqNum(client_->ssl_fd(), (1ULL << 16) - 3));
  SendReceive();
}

class TlsConnectDatagram12Plus : public TlsConnectDatagram {
 public:
  TlsConnectDatagram12Plus() : TlsConnectDatagram() {}
};

// This simulates missing a window's worth of packets.
TEST_P(TlsConnectDatagram12Plus, MissAWindow) {
  EnsureTlsSetup();
  uint16_t cipher;
  GetCipherAndLimit(version_, &cipher);
  server_->EnableSingleCipher(cipher);
  Connect();
  EXPECT_EQ(SECSuccess, SSLInt_AdvanceWriteSeqByAWindow(client_->ssl_fd(), 0));
  SendReceive();
}

TEST_P(TlsConnectDatagram12Plus, MissAWindowAndOne) {
  EnsureTlsSetup();
  uint16_t cipher;
  GetCipherAndLimit(version_, &cipher);
  server_->EnableSingleCipher(cipher);
  Connect();

  EXPECT_EQ(SECSuccess, SSLInt_AdvanceWriteSeqByAWindow(client_->ssl_fd(), 1));
  SendReceive();
}

// This filter replaces the first record it sees with junk application data.
class TlsReplaceFirstRecordWithJunk : public TlsRecordFilter {
 public:
  TlsReplaceFirstRecordWithJunk(const std::shared_ptr<TlsAgent>& a)
      : TlsRecordFilter(a), replaced_(false) {}

 protected:
  PacketFilter::Action FilterRecord(const TlsRecordHeader& header,
                                    const DataBuffer& record, size_t* offset,
                                    DataBuffer* output) override {
    if (replaced_) {
      return KEEP;
    }
    replaced_ = true;

    uint8_t dtls13_ct = kCtDtlsCiphertext | kCtDtlsCiphertext16bSeqno |
                        kCtDtlsCiphertextLengthPresent;
    TlsRecordHeader out_header(
        header.variant(), header.version(),
        is_dtls13() ? dtls13_ct : ssl_ct_application_data,
        header.sequence_number());

    static const uint8_t junk[] = {1, 2, 3, 4};
    *offset = out_header.Write(output, *offset, DataBuffer(junk, sizeof(junk)));
    return CHANGE;
  }

 private:
  bool replaced_;
};

// DTLS needs to discard application_data that it receives prior to handshake
// completion, not generate an error.
TEST_P(TlsConnectDatagram, ReplaceFirstServerRecordWithApplicationData) {
  MakeTlsFilter<TlsReplaceFirstRecordWithJunk>(server_);
  Connect();
}

TEST_P(TlsConnectDatagram, ReplaceFirstClientRecordWithApplicationData) {
  MakeTlsFilter<TlsReplaceFirstRecordWithJunk>(client_);
  Connect();
}

INSTANTIATE_TEST_SUITE_P(Datagram12Plus, TlsConnectDatagram12Plus,
                         TlsConnectTestBase::kTlsV12Plus);
INSTANTIATE_TEST_SUITE_P(DatagramPre13, TlsConnectDatagramPre13,
                         TlsConnectTestBase::kTlsV11V12);
INSTANTIATE_TEST_SUITE_P(DatagramDrop13, TlsDropDatagram13,
                         ::testing::Values(truefalse));
INSTANTIATE_TEST_SUITE_P(DatagramReorder13, TlsReorderDatagram13,
                         ::testing::Values(truefalse));
INSTANTIATE_TEST_SUITE_P(DatagramFragment13, TlsFragmentationAndRecoveryTest,
                         ::testing::Values(truefalse));

class FirstDropThenKeepHandshakeFilter : public TlsHandshakeFilter {
 public:
  FirstDropThenKeepHandshakeFilter(const std::shared_ptr<TlsAgent>& a)
      : TlsHandshakeFilter(a) {}

  virtual PacketFilter::Action FilterHandshake(
      const TlsHandshakeFilter::HandshakeHeader& header,
      const DataBuffer& input, DataBuffer* output) {
    if (enabled) {
      return KEEP;
    } else {
      enabled = true;
      return DROP;
    }
  }

 private:
  bool enabled = false;
};

// This test is responsible for checking that when DTLS fragments the message,
// the hanshake will be successfully reconstructed, but if one of handshakes
// was dropped, they are not going to be glued all together.

// See: https://bugzilla.mozilla.org/show_bug.cgi?id=1874451
TEST_F(TlsConnectDatagram13, PreviousHandshakeRemovedWhenDropped) {
  EnsureTlsSetup();
  static const std::vector<SSLNamedGroup> client_groups = {
      ssl_grp_ec_secp384r1, ssl_grp_ec_secp521r1, ssl_grp_ec_curve25519};
  client_->ConfigNamedGroups(client_groups);
  // Ensure that the message is indeed longer than the MTU we install.
  EXPECT_EQ(SECSuccess, SSL_SendAdditionalKeyShares(client_->ssl_fd(), 2));

  SSLInt_SetMTU(client_->ssl_fd(), 150);
  auto filter = MakeTlsFilter<FirstDropThenKeepHandshakeFilter>(client_);
  Connect();
}

}  // namespace nss_test

Messung V0.5
C=79 H=96 G=87

¤ Dauer der Verarbeitung: 0.14 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