OLD | NEW |
(Empty) | |
| 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 <string.h> |
| 8 #ifdef XP_UNIX |
| 9 #include <sys/resource.h> |
| 10 #endif |
| 11 |
| 12 #include <memory> // for unique_ptr |
| 13 |
| 14 #include "prthread.h" |
| 15 |
| 16 #include "gtest_utils.h" |
| 17 #include "keyhi.h" |
| 18 #include "scoped_ptrs.h" |
| 19 #include "ssl.h" |
| 20 #include "sslerr.h" |
| 21 #include "sslimpl.h" |
| 22 #include "test_io.h" |
| 23 |
| 24 namespace nss_test { |
| 25 |
| 26 // This can't be defined in scoped_ptrs.h because that's shared with |
| 27 // other tests that aren't set up to include sslimpl.h to get the |
| 28 // ssl3* internal declarations. |
| 29 struct ScopedMaybeDeleteKeyPair { |
| 30 void operator()(ssl3KeyPair* ptr) { |
| 31 if (ptr) { |
| 32 ssl3_FreeKeyPair(ptr); |
| 33 } |
| 34 } |
| 35 }; |
| 36 typedef std::unique_ptr<ssl3KeyPair, ScopedMaybeDeleteKeyPair> ScopedKeyPair; |
| 37 |
| 38 // DEBUG_ASSERT_DEATH, for operations that should crash on debug |
| 39 // builds and do something expected on non-debug builds. |
| 40 // TODO(jld@mozilla.com), bug 1243238: move this into a common location. |
| 41 #ifdef DEBUG |
| 42 #ifdef XP_UNIX |
| 43 // Unix + debug: check that assertion crashes as expected; suppress |
| 44 // core dumps, which the test harness would treat as a failure. |
| 45 class SuppressCoreDump { |
| 46 public: |
| 47 SuppressCoreDump() { |
| 48 if (getrlimit(RLIMIT_CORE, &saved_limit_) != 0) { |
| 49 saved_limit_.rlim_cur = saved_limit_.rlim_max = RLIM_INFINITY; |
| 50 } |
| 51 struct ::rlimit new_limit = saved_limit_; |
| 52 new_limit.rlim_cur = 0; |
| 53 setrlimit(RLIMIT_CORE, &new_limit); |
| 54 } |
| 55 |
| 56 ~SuppressCoreDump() { |
| 57 setrlimit(RLIMIT_CORE, &saved_limit_); |
| 58 } |
| 59 |
| 60 private: |
| 61 struct ::rlimit saved_limit_; |
| 62 }; |
| 63 |
| 64 #define DEBUG_ASSERT_DEATH(stmt, regex) ASSERT_DEATH_IF_SUPPORTED({ \ |
| 65 SuppressCoreDump _coreDumpGuard; \ |
| 66 stmt; \ |
| 67 }, regex) |
| 68 #else |
| 69 // Not-Unix + debug: check that assertion crashes; core dumps not an issue. |
| 70 #define DEBUG_ASSERT_DEATH(stmt, regex) ASSERT_DEATH_IF_SUPPORTED(stmt, regex) |
| 71 #endif |
| 72 #else |
| 73 // Non-debug: check that the bad thing *doesn't* crash by doing it. |
| 74 #define DEBUG_ASSERT_DEATH(stmt, regex) stmt |
| 75 #endif |
| 76 |
| 77 class InternalSocketTest : public ::testing::Test { |
| 78 public: |
| 79 InternalSocketTest() : fd_(nullptr), ss_(nullptr) { } |
| 80 ~InternalSocketTest() { } |
| 81 |
| 82 void SetUp() { |
| 83 fd_.reset(DummyPrSocket::CreateFD("fake", STREAM)); |
| 84 ASSERT_NE(nullptr, fd_); |
| 85 ASSERT_EQ(fd_.get(), SSL_ImportFD(nullptr, fd_.get())); |
| 86 ss_ = ssl_FindSocket(fd_.get()); |
| 87 ASSERT_NE(nullptr, ss_); |
| 88 } |
| 89 |
| 90 protected: |
| 91 ScopedPRFileDesc fd_; |
| 92 sslSocket *ss_; // The sslSocket is owned by the PRFileDesc. |
| 93 }; |
| 94 |
| 95 class InternalKeyPairTest : public ::testing::Test { |
| 96 public: |
| 97 InternalKeyPairTest() : keys_(nullptr) { } |
| 98 ~InternalKeyPairTest() { } |
| 99 |
| 100 void SetUp() { |
| 101 static const ECName curve = ec_secp256r1; |
| 102 ScopedSECItem ecParams(SECITEM_AllocItem(nullptr, // no arena |
| 103 nullptr, // not reallocating |
| 104 0)); // length |
| 105 ASSERT_TRUE(ecParams); |
| 106 ASSERT_EQ(SECSuccess, |
| 107 ssl3_ECName2Params(nullptr, // no arena |
| 108 curve, ecParams.get())); |
| 109 EXPECT_NE(nullptr, ecParams->data); |
| 110 EXPECT_NE(0U, ecParams->len); |
| 111 |
| 112 |
| 113 SECKEYPublicKey *tmpPubKey; |
| 114 ScopedSECKEYPrivateKey |
| 115 privKey(SECKEY_CreateECPrivateKey(ecParams.get(), |
| 116 &tmpPubKey, |
| 117 nullptr)); // no UI context |
| 118 ScopedSECKEYPublicKey pubKey(tmpPubKey); |
| 119 |
| 120 ASSERT_TRUE(privKey); |
| 121 ASSERT_TRUE(pubKey); |
| 122 |
| 123 keys_.reset(ssl3_NewKeyPair(privKey.release(), pubKey.release())); |
| 124 ASSERT_TRUE(keys_); |
| 125 } |
| 126 |
| 127 protected: |
| 128 ScopedKeyPair keys_; |
| 129 }; |
| 130 |
| 131 template<class F> |
| 132 static void |
| 133 ThreadFunctionalMain(void *vp) { |
| 134 (*static_cast<const F*>(vp))(); |
| 135 } |
| 136 |
| 137 template<class F> |
| 138 static void |
| 139 RunOnThreads(size_t numThreads, const F& func) |
| 140 { |
| 141 void* vp = const_cast<void*>(static_cast<const void*>(&func)); |
| 142 std::unique_ptr<PRThread*[]> threads(new PRThread*[numThreads]); |
| 143 |
| 144 for (size_t i = 0; i < numThreads; ++i) { |
| 145 threads[i] = PR_CreateThread(PR_SYSTEM_THREAD, |
| 146 ThreadFunctionalMain<F>, |
| 147 vp, |
| 148 PR_PRIORITY_NORMAL, |
| 149 PR_GLOBAL_THREAD, |
| 150 PR_JOINABLE_THREAD, |
| 151 0); // use default stack size |
| 152 ASSERT_NE(nullptr, threads[i]); |
| 153 } |
| 154 for (size_t i = 0; i < numThreads; ++i) { |
| 155 EXPECT_EQ(PR_SUCCESS, PR_JoinThread(threads[i])); |
| 156 } |
| 157 } |
| 158 |
| 159 TEST(SSL3Random, SmokeTest) { |
| 160 // Check that two successive random numbers aren't equal. This is |
| 161 // wrong with probability 2**-256 per test run, which is negligible. |
| 162 SSL3Random r0; |
| 163 ASSERT_EQ(SECSuccess, ssl3_GetNewRandom(&r0)); |
| 164 SSL3Random r1; |
| 165 ASSERT_EQ(SECSuccess, ssl3_GetNewRandom(&r1)); |
| 166 EXPECT_NE(0, memcmp(&r0, &r1, SSL3_RANDOM_LENGTH)); |
| 167 |
| 168 // ssl3_GetNewRandom uses the "rand" field, but other code memcpy()s |
| 169 // the first SSL3_RANDOM_LENGTH bytes, so make sure that does what's |
| 170 // expected: |
| 171 ASSERT_LE(static_cast<size_t>(SSL3_RANDOM_LENGTH), sizeof(SSL3Random)); |
| 172 ASSERT_EQ(static_cast<void*>(&r0), static_cast<void*>(r0.rand)); |
| 173 } |
| 174 |
| 175 typedef InternalSocketTest InternalSocketDeathTest; |
| 176 |
| 177 TEST_F(InternalSocketDeathTest, DoubleUnlockReader) { |
| 178 // On non-debug builds, an excess unlock is ignored. There isn't a |
| 179 // clean way to verify that directly, but the second loop iteration |
| 180 // will at least show that further lock operations don't crash. |
| 181 for (int i = 0; i < 2; ++i) { |
| 182 SSL_LOCK_READER(ss_); |
| 183 SSL_UNLOCK_READER(ss_); |
| 184 DEBUG_ASSERT_DEATH(SSL_UNLOCK_READER(ss_), "Assertion failure:"); |
| 185 } |
| 186 } |
| 187 |
| 188 TEST_F(InternalSocketDeathTest, DoubleUnlock1stHandshake) { |
| 189 // Similarly to the above test, except that this lock supports an |
| 190 // "is this held" operation, so on non-debug builds the second loop |
| 191 // iteration will better verify that the extra unlock is ignored as |
| 192 // expected. |
| 193 for (int i = 0; i < 2; ++i) { |
| 194 EXPECT_FALSE(ssl_Have1stHandshakeLock(ss_)); |
| 195 ssl_Get1stHandshakeLock(ss_); |
| 196 EXPECT_TRUE(ssl_Have1stHandshakeLock(ss_)); |
| 197 ssl_Release1stHandshakeLock(ss_); |
| 198 EXPECT_FALSE(ssl_Have1stHandshakeLock(ss_)); |
| 199 DEBUG_ASSERT_DEATH(ssl_Release1stHandshakeLock(ss_), "Assertion failure:"); |
| 200 } |
| 201 } |
| 202 |
| 203 TEST_F(InternalKeyPairTest, RefCountSimple) { |
| 204 EXPECT_EQ(1, keys_->refCount); |
| 205 EXPECT_EQ(keys_.get(), ssl3_GetKeyPairRef(keys_.get())); |
| 206 EXPECT_EQ(2, keys_->refCount); |
| 207 ssl3_FreeKeyPair(keys_.get()); |
| 208 EXPECT_EQ(1, keys_->refCount); |
| 209 } |
| 210 |
| 211 TEST_F(InternalKeyPairTest, RefCountThreaded) { |
| 212 static const size_t numThreads = 5; |
| 213 static const size_t iterations = 1000000; |
| 214 ssl3KeyPair *const keys = keys_.get(); |
| 215 |
| 216 RunOnThreads(numThreads, [=]{ |
| 217 for (size_t i = 0; i < iterations; ++i) { |
| 218 ssl3_GetKeyPairRef(keys); |
| 219 } |
| 220 }); |
| 221 |
| 222 ASSERT_EQ(1 + numThreads * iterations, static_cast<size_t>(keys->refCount)); |
| 223 |
| 224 RunOnThreads(numThreads, [=]{ |
| 225 for (size_t i = 0; i < iterations; ++i) { |
| 226 ssl3_FreeKeyPair(keys); |
| 227 } |
| 228 }); |
| 229 |
| 230 EXPECT_EQ(1, keys->refCount); |
| 231 } |
| 232 |
| 233 } // namespace nss_test |
OLD | NEW |