diff options
Diffstat (limited to 'security/nss/gtests/ssl_gtest/ssl_cipherorder_unittest.cc')
-rw-r--r-- | security/nss/gtests/ssl_gtest/ssl_cipherorder_unittest.cc | 241 |
1 files changed, 241 insertions, 0 deletions
diff --git a/security/nss/gtests/ssl_gtest/ssl_cipherorder_unittest.cc b/security/nss/gtests/ssl_gtest/ssl_cipherorder_unittest.cc new file mode 100644 index 000000000..1e4f817e9 --- /dev/null +++ b/security/nss/gtests/ssl_gtest/ssl_cipherorder_unittest.cc @@ -0,0 +1,241 @@ +/* -*- 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 "sslerr.h" +#include "sslproto.h" + +#include <memory> + +#include "tls_connect.h" +#include "tls_filter.h" + +namespace nss_test { + +class TlsCipherOrderTest : public TlsConnectTestBase { + protected: + virtual void ConfigureTLS() { + EnsureTlsSetup(); + ConfigureVersion(SSL_LIBRARY_VERSION_TLS_1_3); + } + + virtual SECStatus BuildTestLists(std::vector<uint16_t> &cs_initial_list, + std::vector<uint16_t> &cs_new_list) { + // This is the current CipherSuites order of enabled CipherSuites as defined + // in ssl3con.c + const PRUint16 *kCipherSuites = SSL_GetImplementedCiphers(); + + for (unsigned int i = 0; i < kNumImplementedCiphers; i++) { + PRBool pref = PR_FALSE, policy = PR_FALSE; + SECStatus rv; + rv = SSL_CipherPolicyGet(kCipherSuites[i], &policy); + if (rv != SECSuccess) { + return SECFailure; + } + rv = SSL_CipherPrefGetDefault(kCipherSuites[i], &pref); + if (rv != SECSuccess) { + return SECFailure; + } + if (pref && policy) { + cs_initial_list.push_back(kCipherSuites[i]); + } + } + + // We will test set function with the first 15 enabled ciphers. + const PRUint16 kNumCiphersToSet = 15; + for (unsigned int i = 0; i < kNumCiphersToSet; i++) { + cs_new_list.push_back(cs_initial_list[i]); + } + cs_new_list[0] = cs_initial_list[1]; + cs_new_list[1] = cs_initial_list[0]; + return SECSuccess; + } + + public: + TlsCipherOrderTest() : TlsConnectTestBase(ssl_variant_stream, 0) {} + const unsigned int kNumImplementedCiphers = SSL_GetNumImplementedCiphers(); +}; + +const PRUint16 kCSUnsupported[] = {20196, 10101}; +const PRUint16 kNumCSUnsupported = PR_ARRAY_SIZE(kCSUnsupported); +const PRUint16 kCSEmpty[] = {0}; + +// Get the active CipherSuites odered as they were compiled +TEST_F(TlsCipherOrderTest, CipherOrderGet) { + std::vector<uint16_t> initial_cs_order; + std::vector<uint16_t> new_cs_order; + SECStatus result = BuildTestLists(initial_cs_order, new_cs_order); + ASSERT_EQ(result, SECSuccess); + ConfigureTLS(); + + std::vector<uint16_t> current_cs_order(SSL_GetNumImplementedCiphers() + 1); + unsigned int current_num_active_cs = 0; + result = SSL_CipherSuiteOrderGet(client_->ssl_fd(), current_cs_order.data(), + ¤t_num_active_cs); + ASSERT_EQ(result, SECSuccess); + ASSERT_EQ(current_num_active_cs, initial_cs_order.size()); + for (unsigned int i = 0; i < initial_cs_order.size(); i++) { + EXPECT_EQ(initial_cs_order[i], current_cs_order[i]); + } + // Get the chosen CipherSuite during the Handshake without any modification. + Connect(); + SSLChannelInfo channel; + result = SSL_GetChannelInfo(client_->ssl_fd(), &channel, sizeof channel); + ASSERT_EQ(result, SECSuccess); + EXPECT_EQ(channel.cipherSuite, initial_cs_order[0]); +} + +// The "server" used for gtests honor only its ciphersuites order. +// So, we apply the new set for the server instead of client. +// This is enough to test the effect of SSL_CipherSuiteOrderSet function. +TEST_F(TlsCipherOrderTest, CipherOrderSet) { + std::vector<uint16_t> initial_cs_order; + std::vector<uint16_t> new_cs_order; + SECStatus result = BuildTestLists(initial_cs_order, new_cs_order); + ASSERT_EQ(result, SECSuccess); + ConfigureTLS(); + + // change the server_ ciphersuites order. + result = SSL_CipherSuiteOrderSet(server_->ssl_fd(), new_cs_order.data(), + new_cs_order.size()); + ASSERT_EQ(result, SECSuccess); + + // The function expect an array. We are using vector for VStudio + // compatibility. + std::vector<uint16_t> current_cs_order(SSL_GetNumImplementedCiphers() + 1); + unsigned int current_num_active_cs = 0; + result = SSL_CipherSuiteOrderGet(server_->ssl_fd(), current_cs_order.data(), + ¤t_num_active_cs); + ASSERT_EQ(result, SECSuccess); + ASSERT_EQ(current_num_active_cs, new_cs_order.size()); + for (unsigned int i = 0; i < new_cs_order.size(); i++) { + ASSERT_EQ(new_cs_order[i], current_cs_order[i]); + } + + Connect(); + SSLChannelInfo channel; + // changes in server_ order reflect in client chosen ciphersuite. + result = SSL_GetChannelInfo(client_->ssl_fd(), &channel, sizeof channel); + ASSERT_EQ(result, SECSuccess); + EXPECT_EQ(channel.cipherSuite, new_cs_order[0]); +} + +// Duplicate socket configuration from a model. +TEST_F(TlsCipherOrderTest, CipherOrderCopySocket) { + std::vector<uint16_t> initial_cs_order; + std::vector<uint16_t> new_cs_order; + SECStatus result = BuildTestLists(initial_cs_order, new_cs_order); + ASSERT_EQ(result, SECSuccess); + ConfigureTLS(); + + // Use the existing sockets for this test. + result = SSL_CipherSuiteOrderSet(client_->ssl_fd(), new_cs_order.data(), + new_cs_order.size()); + ASSERT_EQ(result, SECSuccess); + + std::vector<uint16_t> current_cs_order(SSL_GetNumImplementedCiphers() + 1); + unsigned int current_num_active_cs = 0; + result = SSL_CipherSuiteOrderGet(server_->ssl_fd(), current_cs_order.data(), + ¤t_num_active_cs); + ASSERT_EQ(result, SECSuccess); + ASSERT_EQ(current_num_active_cs, initial_cs_order.size()); + for (unsigned int i = 0; i < current_num_active_cs; i++) { + ASSERT_EQ(initial_cs_order[i], current_cs_order[i]); + } + + // Import/Duplicate configurations from client_ to server_ + PRFileDesc *rv = SSL_ImportFD(client_->ssl_fd(), server_->ssl_fd()); + EXPECT_NE(nullptr, rv); + + result = SSL_CipherSuiteOrderGet(server_->ssl_fd(), current_cs_order.data(), + ¤t_num_active_cs); + ASSERT_EQ(result, SECSuccess); + ASSERT_EQ(current_num_active_cs, new_cs_order.size()); + for (unsigned int i = 0; i < new_cs_order.size(); i++) { + EXPECT_EQ(new_cs_order.data()[i], current_cs_order[i]); + } +} + +// If the infomed num of elements is lower than the actual list size, only the +// first "informed num" elements will be considered. The rest is ignored. +TEST_F(TlsCipherOrderTest, CipherOrderSetLower) { + std::vector<uint16_t> initial_cs_order; + std::vector<uint16_t> new_cs_order; + SECStatus result = BuildTestLists(initial_cs_order, new_cs_order); + ASSERT_EQ(result, SECSuccess); + ConfigureTLS(); + + result = SSL_CipherSuiteOrderSet(client_->ssl_fd(), new_cs_order.data(), + new_cs_order.size() - 1); + ASSERT_EQ(result, SECSuccess); + + std::vector<uint16_t> current_cs_order(SSL_GetNumImplementedCiphers() + 1); + unsigned int current_num_active_cs = 0; + result = SSL_CipherSuiteOrderGet(client_->ssl_fd(), current_cs_order.data(), + ¤t_num_active_cs); + ASSERT_EQ(result, SECSuccess); + ASSERT_EQ(current_num_active_cs, new_cs_order.size() - 1); + for (unsigned int i = 0; i < new_cs_order.size() - 1; i++) { + ASSERT_EQ(new_cs_order.data()[i], current_cs_order[i]); + } +} + +// Testing Errors Controls +TEST_F(TlsCipherOrderTest, CipherOrderSetControls) { + std::vector<uint16_t> initial_cs_order; + std::vector<uint16_t> new_cs_order; + SECStatus result = BuildTestLists(initial_cs_order, new_cs_order); + ASSERT_EQ(result, SECSuccess); + ConfigureTLS(); + + // Create a new vector with diplicated entries + std::vector<uint16_t> repeated_cs_order(SSL_GetNumImplementedCiphers() + 1); + std::copy(initial_cs_order.begin(), initial_cs_order.end(), + repeated_cs_order.begin()); + repeated_cs_order[0] = repeated_cs_order[1]; + + // Repeated ciphersuites in the list + result = SSL_CipherSuiteOrderSet(client_->ssl_fd(), repeated_cs_order.data(), + initial_cs_order.size()); + EXPECT_EQ(result, SECFailure); + + // Zero size for the sent list + result = SSL_CipherSuiteOrderSet(client_->ssl_fd(), new_cs_order.data(), 0); + EXPECT_EQ(result, SECFailure); + + // Wrong size, greater than actual + result = SSL_CipherSuiteOrderSet(client_->ssl_fd(), new_cs_order.data(), + SSL_GetNumImplementedCiphers() + 1); + EXPECT_EQ(result, SECFailure); + + // Wrong ciphersuites, not implemented + result = SSL_CipherSuiteOrderSet(client_->ssl_fd(), kCSUnsupported, + kNumCSUnsupported); + EXPECT_EQ(result, SECFailure); + + // Null list + result = + SSL_CipherSuiteOrderSet(client_->ssl_fd(), nullptr, new_cs_order.size()); + EXPECT_EQ(result, SECFailure); + + // Empty list + result = + SSL_CipherSuiteOrderSet(client_->ssl_fd(), kCSEmpty, new_cs_order.size()); + EXPECT_EQ(result, SECFailure); + + // Confirm that the controls are working, as the current ciphersuites + // remained untouched + std::vector<uint16_t> current_cs_order(SSL_GetNumImplementedCiphers() + 1); + unsigned int current_num_active_cs = 0; + result = SSL_CipherSuiteOrderGet(client_->ssl_fd(), current_cs_order.data(), + ¤t_num_active_cs); + ASSERT_EQ(result, SECSuccess); + ASSERT_EQ(current_num_active_cs, initial_cs_order.size()); + for (unsigned int i = 0; i < initial_cs_order.size(); i++) { + ASSERT_EQ(initial_cs_order[i], current_cs_order[i]); + } +} +} // namespace nss_test |