summaryrefslogtreecommitdiffstats
path: root/security/nss/gtests/ssl_gtest/ssl_cipherorder_unittest.cc
diff options
context:
space:
mode:
Diffstat (limited to 'security/nss/gtests/ssl_gtest/ssl_cipherorder_unittest.cc')
-rw-r--r--security/nss/gtests/ssl_gtest/ssl_cipherorder_unittest.cc241
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 0000000000..1e4f817e95
--- /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(),
+ &current_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(),
+ &current_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(),
+ &current_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(),
+ &current_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(),
+ &current_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(),
+ &current_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