nss_cert_database_chromeos_unittest.cc 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367
  1. // Copyright 2013 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "net/cert/nss_cert_database_chromeos.h"
  5. #include <memory>
  6. #include "base/bind.h"
  7. #include "base/callback.h"
  8. #include "base/run_loop.h"
  9. #include "crypto/nss_util_internal.h"
  10. #include "crypto/scoped_test_nss_chromeos_user.h"
  11. #include "crypto/scoped_test_nss_db.h"
  12. #include "net/cert/cert_database.h"
  13. #include "net/cert/x509_util_nss.h"
  14. #include "net/test/cert_test_util.h"
  15. #include "net/test/test_data_directory.h"
  16. #include "net/test/test_with_task_environment.h"
  17. #include "testing/gtest/include/gtest/gtest.h"
  18. namespace net {
  19. namespace {
  20. bool IsCertInCertificateList(const X509Certificate* cert,
  21. const ScopedCERTCertificateList& cert_list) {
  22. for (const auto& other : cert_list) {
  23. if (x509_util::IsSameCertificate(other.get(), cert))
  24. return true;
  25. }
  26. return false;
  27. }
  28. bool IsCertInCertificateList(CERTCertificate* cert,
  29. const ScopedCERTCertificateList& cert_list) {
  30. for (const auto& other : cert_list) {
  31. if (x509_util::IsSameCertificate(other.get(), cert))
  32. return true;
  33. }
  34. return false;
  35. }
  36. void SwapCertLists(ScopedCERTCertificateList* destination,
  37. ScopedCERTCertificateList source) {
  38. ASSERT_TRUE(destination);
  39. destination->swap(source);
  40. }
  41. } // namespace
  42. class NSSCertDatabaseChromeOSTest : public TestWithTaskEnvironment,
  43. public CertDatabase::Observer {
  44. public:
  45. NSSCertDatabaseChromeOSTest() : user_1_("user1"), user_2_("user2") {}
  46. void SetUp() override {
  47. // Initialize nss_util slots.
  48. ASSERT_TRUE(user_1_.constructed_successfully());
  49. ASSERT_TRUE(user_2_.constructed_successfully());
  50. user_1_.FinishInit();
  51. user_2_.FinishInit();
  52. // Create NSSCertDatabaseChromeOS for each user.
  53. db_1_ = std::make_unique<NSSCertDatabaseChromeOS>(
  54. crypto::GetPublicSlotForChromeOSUser(user_1_.username_hash()),
  55. crypto::GetPrivateSlotForChromeOSUser(
  56. user_1_.username_hash(),
  57. base::OnceCallback<void(crypto::ScopedPK11Slot)>()));
  58. db_1_->SetSystemSlot(
  59. crypto::ScopedPK11Slot(PK11_ReferenceSlot(system_db_.slot())));
  60. db_2_ = std::make_unique<NSSCertDatabaseChromeOS>(
  61. crypto::GetPublicSlotForChromeOSUser(user_2_.username_hash()),
  62. crypto::GetPrivateSlotForChromeOSUser(
  63. user_2_.username_hash(),
  64. base::OnceCallback<void(crypto::ScopedPK11Slot)>()));
  65. // Add observer to CertDatabase for checking that notifications from
  66. // NSSCertDatabaseChromeOS are proxied to the CertDatabase.
  67. CertDatabase::GetInstance()->AddObserver(this);
  68. observer_added_ = true;
  69. }
  70. void TearDown() override {
  71. if (observer_added_)
  72. CertDatabase::GetInstance()->RemoveObserver(this);
  73. }
  74. // CertDatabase::Observer:
  75. void OnCertDBChanged() override { db_changed_count_++; }
  76. protected:
  77. bool observer_added_ = false;
  78. int db_changed_count_ = 0;
  79. crypto::ScopedTestNSSChromeOSUser user_1_;
  80. crypto::ScopedTestNSSChromeOSUser user_2_;
  81. crypto::ScopedTestNSSDB system_db_;
  82. std::unique_ptr<NSSCertDatabaseChromeOS> db_1_;
  83. std::unique_ptr<NSSCertDatabaseChromeOS> db_2_;
  84. };
  85. // Test that ListModules() on each user includes that user's NSS software slot,
  86. // and does not include the software slot of the other user. (Does not check the
  87. // private slot, since it is the same as the public slot in tests.)
  88. TEST_F(NSSCertDatabaseChromeOSTest, ListModules) {
  89. std::vector<crypto::ScopedPK11Slot> modules_1;
  90. std::vector<crypto::ScopedPK11Slot> modules_2;
  91. db_1_->ListModules(&modules_1, false /* need_rw */);
  92. db_2_->ListModules(&modules_2, false /* need_rw */);
  93. bool found_1 = false;
  94. for (std::vector<crypto::ScopedPK11Slot>::iterator it = modules_1.begin();
  95. it != modules_1.end(); ++it) {
  96. EXPECT_NE(db_2_->GetPublicSlot().get(), (*it).get());
  97. if ((*it).get() == db_1_->GetPublicSlot().get())
  98. found_1 = true;
  99. }
  100. EXPECT_TRUE(found_1);
  101. bool found_2 = false;
  102. for (std::vector<crypto::ScopedPK11Slot>::iterator it = modules_2.begin();
  103. it != modules_2.end(); ++it) {
  104. EXPECT_NE(db_1_->GetPublicSlot().get(), (*it).get());
  105. if ((*it).get() == db_2_->GetPublicSlot().get())
  106. found_2 = true;
  107. }
  108. EXPECT_TRUE(found_2);
  109. }
  110. // Test that ImportCACerts imports the cert to the correct slot, and that
  111. // ListCerts includes the added cert for the correct user, and does not include
  112. // it for the other user.
  113. TEST_F(NSSCertDatabaseChromeOSTest, ImportCACerts) {
  114. // Load test certs from disk.
  115. ScopedCERTCertificateList certs_1 = CreateCERTCertificateListFromFile(
  116. GetTestCertsDirectory(), "root_ca_cert.pem",
  117. X509Certificate::FORMAT_AUTO);
  118. ASSERT_EQ(1U, certs_1.size());
  119. ScopedCERTCertificateList certs_2 = CreateCERTCertificateListFromFile(
  120. GetTestCertsDirectory(), "2048-rsa-root.pem",
  121. X509Certificate::FORMAT_AUTO);
  122. ASSERT_EQ(1U, certs_2.size());
  123. // Import one cert for each user.
  124. NSSCertDatabase::ImportCertFailureList failed;
  125. EXPECT_TRUE(
  126. db_1_->ImportCACerts(certs_1, NSSCertDatabase::TRUSTED_SSL, &failed));
  127. EXPECT_EQ(0U, failed.size());
  128. failed.clear();
  129. EXPECT_TRUE(
  130. db_2_->ImportCACerts(certs_2, NSSCertDatabase::TRUSTED_SSL, &failed));
  131. EXPECT_EQ(0U, failed.size());
  132. // Get cert list for each user.
  133. ScopedCERTCertificateList user_1_certlist;
  134. ScopedCERTCertificateList user_2_certlist;
  135. db_1_->ListCerts(
  136. base::BindOnce(&SwapCertLists, base::Unretained(&user_1_certlist)));
  137. db_2_->ListCerts(
  138. base::BindOnce(&SwapCertLists, base::Unretained(&user_2_certlist)));
  139. // Run the message loop so the observer notifications get processed and
  140. // lookups are completed.
  141. RunUntilIdle();
  142. // Should have gotten two OnCertDBChanged notifications.
  143. ASSERT_EQ(2, db_changed_count_);
  144. EXPECT_TRUE(IsCertInCertificateList(certs_1[0].get(), user_1_certlist));
  145. EXPECT_FALSE(IsCertInCertificateList(certs_1[0].get(), user_2_certlist));
  146. EXPECT_TRUE(IsCertInCertificateList(certs_2[0].get(), user_2_certlist));
  147. EXPECT_FALSE(IsCertInCertificateList(certs_2[0].get(), user_1_certlist));
  148. }
  149. // Test that ImportServerCerts imports the cert to the correct slot, and that
  150. // ListCerts includes the added cert for the correct user, and does not include
  151. // it for the other user.
  152. TEST_F(NSSCertDatabaseChromeOSTest, ImportServerCert) {
  153. // Load test certs from disk.
  154. ScopedCERTCertificateList certs_1 = CreateCERTCertificateListFromFile(
  155. GetTestCertsDirectory(), "ok_cert.pem", X509Certificate::FORMAT_AUTO);
  156. ASSERT_EQ(1U, certs_1.size());
  157. ScopedCERTCertificateList certs_2 = CreateCERTCertificateListFromFile(
  158. GetTestCertsDirectory(), "2048-rsa-ee-by-2048-rsa-intermediate.pem",
  159. X509Certificate::FORMAT_AUTO);
  160. ASSERT_EQ(1U, certs_2.size());
  161. // Import one cert for each user.
  162. NSSCertDatabase::ImportCertFailureList failed;
  163. EXPECT_TRUE(
  164. db_1_->ImportServerCert(certs_1, NSSCertDatabase::TRUSTED_SSL, &failed));
  165. EXPECT_EQ(0U, failed.size());
  166. failed.clear();
  167. EXPECT_TRUE(
  168. db_2_->ImportServerCert(certs_2, NSSCertDatabase::TRUSTED_SSL, &failed));
  169. EXPECT_EQ(0U, failed.size());
  170. // Get cert list for each user.
  171. ScopedCERTCertificateList user_1_certlist;
  172. ScopedCERTCertificateList user_2_certlist;
  173. db_1_->ListCerts(
  174. base::BindOnce(&SwapCertLists, base::Unretained(&user_1_certlist)));
  175. db_2_->ListCerts(
  176. base::BindOnce(&SwapCertLists, base::Unretained(&user_2_certlist)));
  177. // Run the message loop so the observer notifications get processed and
  178. // lookups are completed.
  179. RunUntilIdle();
  180. // TODO(mattm): ImportServerCert doesn't actually cause any observers to
  181. // fire. Is that correct?
  182. EXPECT_EQ(0, db_changed_count_);
  183. EXPECT_TRUE(IsCertInCertificateList(certs_1[0].get(), user_1_certlist));
  184. EXPECT_FALSE(IsCertInCertificateList(certs_1[0].get(), user_2_certlist));
  185. EXPECT_TRUE(IsCertInCertificateList(certs_2[0].get(), user_2_certlist));
  186. EXPECT_FALSE(IsCertInCertificateList(certs_2[0].get(), user_1_certlist));
  187. }
  188. // Tests that There is no crash if the database is deleted while ListCerts
  189. // is being processed on the worker pool.
  190. TEST_F(NSSCertDatabaseChromeOSTest, NoCrashIfShutdownBeforeDoneOnWorkerPool) {
  191. ScopedCERTCertificateList certlist;
  192. db_1_->ListCerts(base::BindOnce(&SwapCertLists, base::Unretained(&certlist)));
  193. EXPECT_EQ(0U, certlist.size());
  194. db_1_.reset();
  195. RunUntilIdle();
  196. EXPECT_LT(0U, certlist.size());
  197. }
  198. TEST_F(NSSCertDatabaseChromeOSTest, ListCertsReadsSystemSlot) {
  199. scoped_refptr<X509Certificate> cert_1(
  200. ImportClientCertAndKeyFromFile(GetTestCertsDirectory(),
  201. "client_1.pem",
  202. "client_1.pk8",
  203. db_1_->GetPublicSlot().get()));
  204. scoped_refptr<X509Certificate> cert_2(
  205. ImportClientCertAndKeyFromFile(GetTestCertsDirectory(),
  206. "client_2.pem",
  207. "client_2.pk8",
  208. db_1_->GetSystemSlot().get()));
  209. ScopedCERTCertificateList certs;
  210. db_1_->ListCerts(base::BindOnce(&SwapCertLists, base::Unretained(&certs)));
  211. RunUntilIdle();
  212. EXPECT_TRUE(IsCertInCertificateList(cert_1.get(), certs));
  213. EXPECT_TRUE(IsCertInCertificateList(cert_2.get(), certs));
  214. }
  215. TEST_F(NSSCertDatabaseChromeOSTest, ListCertsDoesNotCrossReadSystemSlot) {
  216. scoped_refptr<X509Certificate> cert_1(
  217. ImportClientCertAndKeyFromFile(GetTestCertsDirectory(),
  218. "client_1.pem",
  219. "client_1.pk8",
  220. db_2_->GetPublicSlot().get()));
  221. scoped_refptr<X509Certificate> cert_2(
  222. ImportClientCertAndKeyFromFile(GetTestCertsDirectory(),
  223. "client_2.pem",
  224. "client_2.pk8",
  225. system_db_.slot()));
  226. ScopedCERTCertificateList certs;
  227. db_2_->ListCerts(base::BindOnce(&SwapCertLists, base::Unretained(&certs)));
  228. RunUntilIdle();
  229. EXPECT_TRUE(IsCertInCertificateList(cert_1.get(), certs));
  230. EXPECT_FALSE(IsCertInCertificateList(cert_2.get(), certs));
  231. }
  232. TEST_F(NSSCertDatabaseChromeOSTest, SetCertTrustCertIsAlreadyOnPublicSlot) {
  233. // Import a certificate onto the public slot (and safety check that it ended
  234. // up there).
  235. ScopedCERTCertificateList certs = CreateCERTCertificateListFromFile(
  236. GetTestCertsDirectory(), "root_ca_cert.pem",
  237. X509Certificate::FORMAT_AUTO);
  238. ASSERT_EQ(1U, certs.size());
  239. NSSCertDatabase::ImportCertFailureList failed;
  240. EXPECT_TRUE(
  241. db_1_->ImportCACerts(certs, NSSCertDatabase::TRUST_DEFAULT, &failed));
  242. EXPECT_EQ(0U, failed.size());
  243. ASSERT_TRUE(NSSCertDatabase::IsCertificateOnSlot(
  244. certs[0].get(), db_1_->GetPublicSlot().get()));
  245. // Check that trust settings modification works.
  246. EXPECT_EQ(NSSCertDatabase::TRUST_DEFAULT,
  247. db_1_->GetCertTrust(certs[0].get(), CA_CERT));
  248. EXPECT_TRUE(db_1_->SetCertTrust(certs[0].get(), CA_CERT,
  249. NSSCertDatabase::TRUSTED_SSL));
  250. EXPECT_EQ(NSSCertDatabase::TRUSTED_SSL,
  251. db_1_->GetCertTrust(certs[0].get(), CA_CERT));
  252. }
  253. TEST_F(NSSCertDatabaseChromeOSTest, SetCertTrustCertIsOnlyOnOtherSlot) {
  254. crypto::ScopedTestNSSDB other_slot;
  255. // Import a certificate onto a slot known by NSS which is not the
  256. // NSSCertDatabase's public slot.
  257. ScopedCERTCertificateList certs = CreateCERTCertificateListFromFile(
  258. GetTestCertsDirectory(), "root_ca_cert.pem",
  259. X509Certificate::FORMAT_AUTO);
  260. ASSERT_EQ(1U, certs.size());
  261. ASSERT_EQ(SECSuccess, PK11_ImportCert(other_slot.slot(), certs[0].get(),
  262. CK_INVALID_HANDLE, "cert0",
  263. PR_FALSE /* includeTrust (unused) */));
  264. ASSERT_FALSE(NSSCertDatabase::IsCertificateOnSlot(
  265. certs[0].get(), db_1_->GetPublicSlot().get()));
  266. // Check that trust settings modification works.
  267. EXPECT_EQ(NSSCertDatabase::TRUST_DEFAULT,
  268. db_1_->GetCertTrust(certs[0].get(), CA_CERT));
  269. EXPECT_TRUE(db_1_->SetCertTrust(certs[0].get(), CA_CERT,
  270. NSSCertDatabase::TRUSTED_SSL));
  271. EXPECT_EQ(NSSCertDatabase::TRUSTED_SSL,
  272. db_1_->GetCertTrust(certs[0].get(), CA_CERT));
  273. // Check that the certificate has been put onto the public slot as a side
  274. // effect of changing trust.
  275. EXPECT_TRUE(NSSCertDatabase::IsCertificateOnSlot(
  276. certs[0].get(), db_1_->GetPublicSlot().get()));
  277. }
  278. TEST_F(NSSCertDatabaseChromeOSTest, SetCertTrustPublicSlotIsSystemSlot) {
  279. // Create a NSSCertDatabase with |public_slot|==|system_slot|.
  280. NSSCertDatabaseChromeOS test_db_for_system_slot(
  281. /*public_slot=*/crypto::ScopedPK11Slot(
  282. PK11_ReferenceSlot(system_db_.slot())),
  283. /*private_slot=*/{});
  284. test_db_for_system_slot.SetSystemSlot(
  285. crypto::ScopedPK11Slot(PK11_ReferenceSlot(system_db_.slot())));
  286. // Import a certificate onto a slot known by NSS which is not the
  287. // NSSCertDatabase's public slot.
  288. crypto::ScopedTestNSSDB other_slot;
  289. ScopedCERTCertificateList certs = CreateCERTCertificateListFromFile(
  290. GetTestCertsDirectory(), "root_ca_cert.pem",
  291. X509Certificate::FORMAT_AUTO);
  292. ASSERT_EQ(1U, certs.size());
  293. ASSERT_EQ(SECSuccess, PK11_ImportCert(other_slot.slot(), certs[0].get(),
  294. CK_INVALID_HANDLE, "cert0",
  295. PR_FALSE /* includeTrust (unused) */));
  296. ASSERT_FALSE(NSSCertDatabase::IsCertificateOnSlot(
  297. certs[0].get(), test_db_for_system_slot.GetPublicSlot().get()));
  298. // Changing trust through |test_db_for_system_slot| should fail and not do
  299. // anything, because the database is not allowed to put the certificate onto
  300. // its public slot (because it is also the system slot).
  301. EXPECT_FALSE(test_db_for_system_slot.SetCertTrust(
  302. certs[0].get(), CA_CERT, NSSCertDatabase::TRUSTED_SSL));
  303. EXPECT_FALSE(NSSCertDatabase::IsCertificateOnSlot(
  304. certs[0].get(), test_db_for_system_slot.GetPublicSlot().get()));
  305. }
  306. } // namespace net