tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

ssl_cipherorder_unittest.cc (9416B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
      5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #include "ssl.h"
      8 #include "sslerr.h"
      9 #include "sslproto.h"
     10 
     11 #include <memory>
     12 
     13 #include "tls_connect.h"
     14 #include "tls_filter.h"
     15 
     16 namespace nss_test {
     17 
     18 class TlsCipherOrderTest : public TlsConnectTestBase {
     19 protected:
     20  virtual void ConfigureTLS() {
     21    EnsureTlsSetup();
     22    ConfigureVersion(SSL_LIBRARY_VERSION_TLS_1_3);
     23  }
     24 
     25  virtual SECStatus BuildTestLists(std::vector<uint16_t> &cs_initial_list,
     26                                   std::vector<uint16_t> &cs_new_list) {
     27    // This is the current CipherSuites order of enabled CipherSuites as defined
     28    // in ssl3con.c
     29    const PRUint16 *kCipherSuites = SSL_GetImplementedCiphers();
     30 
     31    for (unsigned int i = 0; i < kNumImplementedCiphers; i++) {
     32      PRBool pref = PR_FALSE, policy = PR_FALSE;
     33      SECStatus rv;
     34      rv = SSL_CipherPolicyGet(kCipherSuites[i], &policy);
     35      if (rv != SECSuccess) {
     36        return SECFailure;
     37      }
     38      rv = SSL_CipherPrefGetDefault(kCipherSuites[i], &pref);
     39      if (rv != SECSuccess) {
     40        return SECFailure;
     41      }
     42      if (pref && policy) {
     43        cs_initial_list.push_back(kCipherSuites[i]);
     44      }
     45    }
     46 
     47    // We will test set function with the first 15 enabled ciphers.
     48    const PRUint16 kNumCiphersToSet = 15;
     49    for (unsigned int i = 0; i < kNumCiphersToSet; i++) {
     50      cs_new_list.push_back(cs_initial_list[i]);
     51    }
     52    cs_new_list[0] = cs_initial_list[1];
     53    cs_new_list[1] = cs_initial_list[0];
     54    return SECSuccess;
     55  }
     56 
     57 public:
     58  TlsCipherOrderTest() : TlsConnectTestBase(ssl_variant_stream, 0) {}
     59  const unsigned int kNumImplementedCiphers = SSL_GetNumImplementedCiphers();
     60 };
     61 
     62 const PRUint16 kCSUnsupported[] = {20196, 10101};
     63 const PRUint16 kNumCSUnsupported = PR_ARRAY_SIZE(kCSUnsupported);
     64 const PRUint16 kCSEmpty[] = {0};
     65 
     66 // Get the active CipherSuites odered as they were compiled
     67 TEST_F(TlsCipherOrderTest, CipherOrderGet) {
     68  std::vector<uint16_t> initial_cs_order;
     69  std::vector<uint16_t> new_cs_order;
     70  SECStatus result = BuildTestLists(initial_cs_order, new_cs_order);
     71  ASSERT_EQ(result, SECSuccess);
     72  ConfigureTLS();
     73 
     74  std::vector<uint16_t> current_cs_order(SSL_GetNumImplementedCiphers() + 1);
     75  unsigned int current_num_active_cs = 0;
     76  result = SSL_CipherSuiteOrderGet(client_->ssl_fd(), current_cs_order.data(),
     77                                   &current_num_active_cs);
     78  ASSERT_EQ(result, SECSuccess);
     79  ASSERT_EQ(current_num_active_cs, initial_cs_order.size());
     80  for (unsigned int i = 0; i < initial_cs_order.size(); i++) {
     81    EXPECT_EQ(initial_cs_order[i], current_cs_order[i]);
     82  }
     83  // Get the chosen CipherSuite during the Handshake without any modification.
     84  Connect();
     85  SSLChannelInfo channel;
     86  result = SSL_GetChannelInfo(client_->ssl_fd(), &channel, sizeof channel);
     87  ASSERT_EQ(result, SECSuccess);
     88  EXPECT_EQ(channel.cipherSuite, initial_cs_order[0]);
     89 }
     90 
     91 // The "server" used for gtests honor only its ciphersuites order.
     92 // So, we apply the new set for the server instead of client.
     93 // This is enough to test the effect of SSL_CipherSuiteOrderSet function.
     94 TEST_F(TlsCipherOrderTest, CipherOrderSet) {
     95  std::vector<uint16_t> initial_cs_order;
     96  std::vector<uint16_t> new_cs_order;
     97  SECStatus result = BuildTestLists(initial_cs_order, new_cs_order);
     98  ASSERT_EQ(result, SECSuccess);
     99  ConfigureTLS();
    100 
    101  // change the server_ ciphersuites order.
    102  result = SSL_CipherSuiteOrderSet(server_->ssl_fd(), new_cs_order.data(),
    103                                   new_cs_order.size());
    104  ASSERT_EQ(result, SECSuccess);
    105 
    106  // The function expect an array. We are using vector for VStudio
    107  // compatibility.
    108  std::vector<uint16_t> current_cs_order(SSL_GetNumImplementedCiphers() + 1);
    109  unsigned int current_num_active_cs = 0;
    110  result = SSL_CipherSuiteOrderGet(server_->ssl_fd(), current_cs_order.data(),
    111                                   &current_num_active_cs);
    112  ASSERT_EQ(result, SECSuccess);
    113  ASSERT_EQ(current_num_active_cs, new_cs_order.size());
    114  for (unsigned int i = 0; i < new_cs_order.size(); i++) {
    115    ASSERT_EQ(new_cs_order[i], current_cs_order[i]);
    116  }
    117 
    118  Connect();
    119  SSLChannelInfo channel;
    120  // changes in server_ order reflect in client chosen ciphersuite.
    121  result = SSL_GetChannelInfo(client_->ssl_fd(), &channel, sizeof channel);
    122  ASSERT_EQ(result, SECSuccess);
    123  EXPECT_EQ(channel.cipherSuite, new_cs_order[0]);
    124 }
    125 
    126 // Duplicate socket configuration from a model.
    127 TEST_F(TlsCipherOrderTest, CipherOrderCopySocket) {
    128  std::vector<uint16_t> initial_cs_order;
    129  std::vector<uint16_t> new_cs_order;
    130  SECStatus result = BuildTestLists(initial_cs_order, new_cs_order);
    131  ASSERT_EQ(result, SECSuccess);
    132  ConfigureTLS();
    133 
    134  // Use the existing sockets for this test.
    135  result = SSL_CipherSuiteOrderSet(client_->ssl_fd(), new_cs_order.data(),
    136                                   new_cs_order.size());
    137  ASSERT_EQ(result, SECSuccess);
    138 
    139  std::vector<uint16_t> current_cs_order(SSL_GetNumImplementedCiphers() + 1);
    140  unsigned int current_num_active_cs = 0;
    141  result = SSL_CipherSuiteOrderGet(server_->ssl_fd(), current_cs_order.data(),
    142                                   &current_num_active_cs);
    143  ASSERT_EQ(result, SECSuccess);
    144  ASSERT_EQ(current_num_active_cs, initial_cs_order.size());
    145  for (unsigned int i = 0; i < current_num_active_cs; i++) {
    146    ASSERT_EQ(initial_cs_order[i], current_cs_order[i]);
    147  }
    148 
    149  // Import/Duplicate configurations from client_ to server_
    150  PRFileDesc *rv = SSL_ImportFD(client_->ssl_fd(), server_->ssl_fd());
    151  EXPECT_NE(nullptr, rv);
    152 
    153  result = SSL_CipherSuiteOrderGet(server_->ssl_fd(), current_cs_order.data(),
    154                                   &current_num_active_cs);
    155  ASSERT_EQ(result, SECSuccess);
    156  ASSERT_EQ(current_num_active_cs, new_cs_order.size());
    157  for (unsigned int i = 0; i < new_cs_order.size(); i++) {
    158    EXPECT_EQ(new_cs_order.data()[i], current_cs_order[i]);
    159  }
    160 }
    161 
    162 // If the infomed num of elements is lower than the actual list size, only the
    163 // first "informed num" elements will be considered. The rest is ignored.
    164 TEST_F(TlsCipherOrderTest, CipherOrderSetLower) {
    165  std::vector<uint16_t> initial_cs_order;
    166  std::vector<uint16_t> new_cs_order;
    167  SECStatus result = BuildTestLists(initial_cs_order, new_cs_order);
    168  ASSERT_EQ(result, SECSuccess);
    169  ConfigureTLS();
    170 
    171  result = SSL_CipherSuiteOrderSet(client_->ssl_fd(), new_cs_order.data(),
    172                                   new_cs_order.size() - 1);
    173  ASSERT_EQ(result, SECSuccess);
    174 
    175  std::vector<uint16_t> current_cs_order(SSL_GetNumImplementedCiphers() + 1);
    176  unsigned int current_num_active_cs = 0;
    177  result = SSL_CipherSuiteOrderGet(client_->ssl_fd(), current_cs_order.data(),
    178                                   &current_num_active_cs);
    179  ASSERT_EQ(result, SECSuccess);
    180  ASSERT_EQ(current_num_active_cs, new_cs_order.size() - 1);
    181  for (unsigned int i = 0; i < new_cs_order.size() - 1; i++) {
    182    ASSERT_EQ(new_cs_order.data()[i], current_cs_order[i]);
    183  }
    184 }
    185 
    186 // Testing Errors Controls
    187 TEST_F(TlsCipherOrderTest, CipherOrderSetControls) {
    188  std::vector<uint16_t> initial_cs_order;
    189  std::vector<uint16_t> new_cs_order;
    190  SECStatus result = BuildTestLists(initial_cs_order, new_cs_order);
    191  ASSERT_EQ(result, SECSuccess);
    192  ConfigureTLS();
    193 
    194  // Create a new vector with diplicated entries
    195  std::vector<uint16_t> repeated_cs_order(SSL_GetNumImplementedCiphers() + 1);
    196  std::copy(initial_cs_order.begin(), initial_cs_order.end(),
    197            repeated_cs_order.begin());
    198  repeated_cs_order[0] = repeated_cs_order[1];
    199 
    200  // Repeated ciphersuites in the list
    201  result = SSL_CipherSuiteOrderSet(client_->ssl_fd(), repeated_cs_order.data(),
    202                                   initial_cs_order.size());
    203  EXPECT_EQ(result, SECFailure);
    204 
    205  // Zero size for the sent list
    206  result = SSL_CipherSuiteOrderSet(client_->ssl_fd(), new_cs_order.data(), 0);
    207  EXPECT_EQ(result, SECFailure);
    208 
    209  // Wrong size, greater than actual
    210  result = SSL_CipherSuiteOrderSet(client_->ssl_fd(), new_cs_order.data(),
    211                                   SSL_GetNumImplementedCiphers() + 1);
    212  EXPECT_EQ(result, SECFailure);
    213 
    214  // Wrong ciphersuites, not implemented
    215  result = SSL_CipherSuiteOrderSet(client_->ssl_fd(), kCSUnsupported,
    216                                   kNumCSUnsupported);
    217  EXPECT_EQ(result, SECFailure);
    218 
    219  // Null list
    220  result =
    221      SSL_CipherSuiteOrderSet(client_->ssl_fd(), nullptr, new_cs_order.size());
    222  EXPECT_EQ(result, SECFailure);
    223 
    224  // Empty list
    225  result =
    226      SSL_CipherSuiteOrderSet(client_->ssl_fd(), kCSEmpty, new_cs_order.size());
    227  EXPECT_EQ(result, SECFailure);
    228 
    229  // Confirm that the controls are working, as the current ciphersuites
    230  // remained untouched
    231  std::vector<uint16_t> current_cs_order(SSL_GetNumImplementedCiphers() + 1);
    232  unsigned int current_num_active_cs = 0;
    233  result = SSL_CipherSuiteOrderGet(client_->ssl_fd(), current_cs_order.data(),
    234                                   &current_num_active_cs);
    235  ASSERT_EQ(result, SECSuccess);
    236  ASSERT_EQ(current_num_active_cs, initial_cs_order.size());
    237  for (unsigned int i = 0; i < initial_cs_order.size(); i++) {
    238    ASSERT_EQ(initial_cs_order[i], current_cs_order[i]);
    239  }
    240 }
    241 }  // namespace nss_test