/* -*- 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 "ssl.h" #include "gtest_utils.h" #include "tls_connect.h" namespace nss_test { static const char* kExporterLabel = "EXPORTER-duck"; static const uint8_t kExporterContext[] = {0x12, 0x34, 0x56}; static void ExportAndCompare(std::shared_ptr& client, std::shared_ptr& server, bool context) { static const size_t exporter_len = 10; uint8_t client_value[exporter_len] = {0}; EXPECT_EQ(SECSuccess, SSL_ExportKeyingMaterial( client->ssl_fd(), kExporterLabel, strlen(kExporterLabel), context ? PR_TRUE : PR_FALSE, kExporterContext, sizeof(kExporterContext), client_value, sizeof(client_value))); uint8_t server_value[exporter_len] = {0xff}; EXPECT_EQ(SECSuccess, SSL_ExportKeyingMaterial( server->ssl_fd(), kExporterLabel, strlen(kExporterLabel), context ? PR_TRUE : PR_FALSE, kExporterContext, sizeof(kExporterContext), server_value, sizeof(server_value))); EXPECT_EQ(0, memcmp(client_value, server_value, sizeof(client_value))); } TEST_P(TlsConnectGeneric, ExporterBasic) { EnsureTlsSetup(); if (version_ >= SSL_LIBRARY_VERSION_TLS_1_3) { server_->EnableSingleCipher(TLS_AES_128_GCM_SHA256); } else { server_->EnableSingleCipher(TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA); } Connect(); CheckKeys(); ExportAndCompare(client_, server_, false); } TEST_P(TlsConnectGeneric, ExporterContext) { EnsureTlsSetup(); if (version_ >= SSL_LIBRARY_VERSION_TLS_1_3) { server_->EnableSingleCipher(TLS_AES_128_GCM_SHA256); } else { server_->EnableSingleCipher(TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA); } Connect(); CheckKeys(); ExportAndCompare(client_, server_, true); } // Bug 1312976 - SHA-384 doesn't work in 1.2 right now. TEST_P(TlsConnectTls13, ExporterSha384) { EnsureTlsSetup(); client_->EnableSingleCipher(TLS_AES_256_GCM_SHA384); Connect(); CheckKeys(); ExportAndCompare(client_, server_, false); } TEST_P(TlsConnectTls13, ExporterContextEmptyIsSameAsNone) { EnsureTlsSetup(); if (version_ >= SSL_LIBRARY_VERSION_TLS_1_3) { server_->EnableSingleCipher(TLS_AES_128_GCM_SHA256); } else { server_->EnableSingleCipher(TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA); } Connect(); CheckKeys(); ExportAndCompare(client_, server_, false); } TEST_P(TlsConnectGenericPre13, ExporterContextLengthTooLong) { static const uint8_t kExporterContextTooLong[PR_UINT16_MAX] = { 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xFF}; EnsureTlsSetup(); Connect(); CheckKeys(); static const size_t exporter_len = 10; uint8_t client_value[exporter_len] = {0}; EXPECT_EQ(SECFailure, SSL_ExportKeyingMaterial(client_->ssl_fd(), kExporterLabel, strlen(kExporterLabel), PR_TRUE, kExporterContextTooLong, sizeof(kExporterContextTooLong), client_value, sizeof(client_value))); EXPECT_EQ(PORT_GetError(), SEC_ERROR_INVALID_ARGS); uint8_t server_value[exporter_len] = {0xff}; EXPECT_EQ(SECFailure, SSL_ExportKeyingMaterial(server_->ssl_fd(), kExporterLabel, strlen(kExporterLabel), PR_TRUE, kExporterContextTooLong, sizeof(kExporterContextTooLong), server_value, sizeof(server_value))); EXPECT_EQ(PORT_GetError(), SEC_ERROR_INVALID_ARGS); } // This has a weird signature so that it can be passed to the SNI callback. int32_t RegularExporterShouldFail(TlsAgent* agent, const SECItem* srvNameArr, PRUint32 srvNameArrSize) { uint8_t val[10]; EXPECT_EQ(SECFailure, SSL_ExportKeyingMaterial( agent->ssl_fd(), kExporterLabel, strlen(kExporterLabel), PR_TRUE, kExporterContext, sizeof(kExporterContext), val, sizeof(val))) << "regular exporter should fail"; return 0; } TEST_P(TlsConnectTls13, EarlyExporter) { SetupForZeroRtt(); client_->Set0RttEnabled(true); server_->Set0RttEnabled(true); ExpectResumption(RESUME_TICKET); client_->Handshake(); // Send ClientHello. uint8_t client_value[10] = {0}; RegularExporterShouldFail(client_.get(), nullptr, 0); EXPECT_EQ(SECSuccess, SSL_ExportEarlyKeyingMaterial( client_->ssl_fd(), kExporterLabel, strlen(kExporterLabel), kExporterContext, sizeof(kExporterContext), client_value, sizeof(client_value))); server_->SetSniCallback(RegularExporterShouldFail); server_->Handshake(); // Handle ClientHello. uint8_t server_value[10] = {0}; EXPECT_EQ(SECSuccess, SSL_ExportEarlyKeyingMaterial( server_->ssl_fd(), kExporterLabel, strlen(kExporterLabel), kExporterContext, sizeof(kExporterContext), server_value, sizeof(server_value))); EXPECT_EQ(0, memcmp(client_value, server_value, sizeof(client_value))); Handshake(); ExpectEarlyDataAccepted(true); CheckConnected(); SendReceive(); } TEST_P(TlsConnectTls13, EarlyExporterExternalPsk) { RolloverAntiReplay(); ScopedPK11SlotInfo slot(PK11_GetInternalSlot()); ASSERT_TRUE(!!slot); ScopedPK11SymKey scoped_psk( PK11_KeyGen(slot.get(), CKM_HKDF_KEY_GEN, nullptr, 16, nullptr)); AddPsk(scoped_psk, std::string("foo"), ssl_hash_sha256, TLS_CHACHA20_POLY1305_SHA256); StartConnect(); client_->Set0RttEnabled(true); server_->Set0RttEnabled(true); client_->Handshake(); // Send ClientHello. uint8_t client_value[10] = {0}; RegularExporterShouldFail(client_.get(), nullptr, 0); EXPECT_EQ(SECSuccess, SSL_ExportEarlyKeyingMaterial( client_->ssl_fd(), kExporterLabel, strlen(kExporterLabel), kExporterContext, sizeof(kExporterContext), client_value, sizeof(client_value))); server_->SetSniCallback(RegularExporterShouldFail); server_->Handshake(); // Handle ClientHello. uint8_t server_value[10] = {0}; EXPECT_EQ(SECSuccess, SSL_ExportEarlyKeyingMaterial( server_->ssl_fd(), kExporterLabel, strlen(kExporterLabel), kExporterContext, sizeof(kExporterContext), server_value, sizeof(server_value))); EXPECT_EQ(0, memcmp(client_value, server_value, sizeof(client_value))); Handshake(); ExpectEarlyDataAccepted(true); CheckConnected(); SendReceive(); } } // namespace nss_test