gtests/ssl_gtest/ssl_keylog_unittest.cc
author Martin Thomson <martin.thomson@gmail.com>
Wed, 03 Jan 2018 15:36:18 +1100
changeset 14254 74e4cd34e49fa72806ed7405926591d90f4a2d2a
parent 14182 6d56dc87ea96c2d0cc5fbe3ca9ca24b2365659f0
child 14979 3e26ed39924175d8dd7e4fc3904907cae8c0689b
permissions -rw-r--r--
Bug 1427675 - Add TlsAgent argument to TlsRecordFilter, r=ekr This is a fairly disruptive change, but mostly just mechanical. There are a few extra changes: - I have renamed the TlsInspector* filters for consistency. This was purely mechanical. - I renamed the SetPacketFilter function to just SetFilter. Also mechanical. - TlsRecordFilter maintains a weak pointer reference to the TlsAgent now rather than using a bare pointer. This meant that I had to change TlsAgentTestBase to use shared_ptr rather than unique_ptr to support of use of filters with those tests. - I removed the helper function that enables decryption. Enabling decryption is now more explicit. - I ran a newer clang-format version and it fixed a few extra things, like the comments on the end of namespace {} blocks, some of which were wrong. - I discovered a bug in some of the drop tests: in the 0-RTT tests, the filters were being installed on the client and server right at the start, which meant that they were capturing the first handshake and not the second one. This was clearly against intent, but the tests were mostly right still, it was only the expected ACKs that were wrong. We were expecting just one record to be ACKed by a server (Finished), but the record with EndOfEarlyData should have been acknowledged as well. - In TlsSkipTest and Tls13SkipTest, I had to override SetUp() so that client_ and server_ are initialized prior to constructing filters. In doing so, I noticed that we weren't being consistent about overriding SetUp properly, so I fixed the small number of instances of that by adding an override label to each and marking the base method virtual. - The stateless HRR test for TLS 1.3 compat mode was replacing the server, but expecting to retain the same filters. That wasn't a problem in that case, but I didn't want to have any places where the filter was set on a different agent from the one that was passed to it.

/* -*- 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/. */

#ifdef NSS_ALLOW_SSLKEYLOGFILE

#include <cstdlib>
#include <fstream>
#include <sstream>

#include "gtest_utils.h"
#include "tls_connect.h"

namespace nss_test {

static const std::string keylog_file_path = "keylog.txt";
static const std::string keylog_env = "SSLKEYLOGFILE=" + keylog_file_path;

class KeyLogFileTest : public TlsConnectGeneric {
 public:
  void SetUp() override {
    TlsConnectGeneric::SetUp();
    // Remove previous results (if any).
    (void)remove(keylog_file_path.c_str());
    PR_SetEnv(keylog_env.c_str());
  }

  void CheckKeyLog() {
    std::ifstream f(keylog_file_path);
    std::map<std::string, size_t> labels;
    std::set<std::string> client_randoms;
    for (std::string line; std::getline(f, line);) {
      if (line[0] == '#') {
        continue;
      }

      std::istringstream iss(line);
      std::string label, client_random, secret;
      iss >> label >> client_random >> secret;

      ASSERT_EQ(64U, client_random.size());
      client_randoms.insert(client_random);
      labels[label]++;
    }

    if (version_ < SSL_LIBRARY_VERSION_TLS_1_3) {
      ASSERT_EQ(1U, client_randoms.size());
    } else {
      /* two handshakes for 0-RTT */
      ASSERT_EQ(2U, client_randoms.size());
    }

    // Every entry occurs twice (one log from server, one from client).
    if (version_ < SSL_LIBRARY_VERSION_TLS_1_3) {
      ASSERT_EQ(2U, labels["CLIENT_RANDOM"]);
    } else {
      ASSERT_EQ(2U, labels["CLIENT_EARLY_TRAFFIC_SECRET"]);
      ASSERT_EQ(2U, labels["EARLY_EXPORTER_SECRET"]);
      ASSERT_EQ(4U, labels["CLIENT_HANDSHAKE_TRAFFIC_SECRET"]);
      ASSERT_EQ(4U, labels["SERVER_HANDSHAKE_TRAFFIC_SECRET"]);
      ASSERT_EQ(4U, labels["CLIENT_TRAFFIC_SECRET_0"]);
      ASSERT_EQ(4U, labels["SERVER_TRAFFIC_SECRET_0"]);
      ASSERT_EQ(4U, labels["EXPORTER_SECRET"]);
    }
  }

  void ConnectAndCheck() {
    // This is a child process, ensure that error messages immediately
    // propagate or else it will not be visible.
    ::testing::GTEST_FLAG(throw_on_failure) = true;

    if (version_ == SSL_LIBRARY_VERSION_TLS_1_3) {
      SetupForZeroRtt();
      client_->Set0RttEnabled(true);
      server_->Set0RttEnabled(true);
      ExpectResumption(RESUME_TICKET);
      ZeroRttSendReceive(true, true);
      Handshake();
      ExpectEarlyDataAccepted(true);
      CheckConnected();
      SendReceive();
    } else {
      Connect();
    }
    CheckKeyLog();
    _exit(0);
  }
};

// Tests are run in a separate process to ensure that NSS is not initialized yet
// and can process the SSLKEYLOGFILE environment variable.

TEST_P(KeyLogFileTest, KeyLogFile) {
  testing::GTEST_FLAG(death_test_style) = "threadsafe";

  ASSERT_EXIT(ConnectAndCheck(), ::testing::ExitedWithCode(0), "");
}

INSTANTIATE_TEST_CASE_P(
    KeyLogFileDTLS12, KeyLogFileTest,
    ::testing::Combine(TlsConnectTestBase::kTlsVariantsDatagram,
                       TlsConnectTestBase::kTlsV11V12));
INSTANTIATE_TEST_CASE_P(
    KeyLogFileTLS12, KeyLogFileTest,
    ::testing::Combine(TlsConnectTestBase::kTlsVariantsStream,
                       TlsConnectTestBase::kTlsV10ToV12));
#ifndef NSS_DISABLE_TLS_1_3
INSTANTIATE_TEST_CASE_P(
    KeyLogFileTLS13, KeyLogFileTest,
    ::testing::Combine(TlsConnectTestBase::kTlsVariantsStream,
                       TlsConnectTestBase::kTlsV13));
#endif

}  // namespace nss_test

#endif  // NSS_ALLOW_SSLKEYLOGFILE