// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include <cert.h> #include <certdb.h> #include <pk11pub.h> #include <algorithm> #include "base/file_util.h" #include "base/files/file_path.h" #include "base/lazy_instance.h" #include "base/message_loop/message_loop.h" #include "base/path_service.h" #include "base/strings/string16.h" #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" #include "crypto/nss_util.h" #include "crypto/nss_util_internal.h" #include "crypto/scoped_nss_types.h" #include "net/base/crypto_module.h" #include "net/base/net_errors.h" #include "net/base/test_data_directory.h" #include "net/cert/cert_status_flags.h" #include "net/cert/cert_verify_proc_nss.h" #include "net/cert/cert_verify_result.h" #include "net/cert/nss_cert_database.h" #include "net/cert/x509_certificate.h" #include "net/test/cert_test_util.h" #include "net/third_party/mozilla_security_manager/nsNSSCertificateDB.h" #include "testing/gtest/include/gtest/gtest.h" // In NSS 3.13, CERTDB_VALID_PEER was renamed CERTDB_TERMINAL_RECORD. So we use // the new name of the macro. #if !defined(CERTDB_TERMINAL_RECORD) #define CERTDB_TERMINAL_RECORD CERTDB_VALID_PEER #endif namespace net { class CertDatabaseNSSTest : public testing::Test { public: virtual void SetUp() { ASSERT_TRUE(test_nssdb_.is_open()); cert_db_ = NSSCertDatabase::GetInstance(); slot_ = cert_db_->GetPublicModule(); // Test db should be empty at start of test. EXPECT_EQ(0U, ListCertsInSlot(slot_->os_module_handle()).size()); } virtual void TearDown() { // Don't try to cleanup if the setup failed. ASSERT_TRUE(slot_->os_module_handle()); EXPECT_TRUE(CleanupSlotContents()); // Run the message loop to process any observer callbacks (e.g. for the // ClientSocketFactory singleton) so that the scoped ref ptrs created in // NSSCertDatabase::NotifyObservers* get released. base::MessageLoop::current()->RunUntilIdle(); EXPECT_EQ(0U, ListCertsInSlot(slot_->os_module_handle()).size()); } protected: static std::string ReadTestFile(const std::string& name) { std::string result; base::FilePath cert_path = GetTestCertsDirectory().AppendASCII(name); EXPECT_TRUE(base::ReadFileToString(cert_path, &result)); return result; } static bool ReadCertIntoList(const std::string& name, CertificateList* certs) { scoped_refptr<X509Certificate> cert( ImportCertFromFile(GetTestCertsDirectory(), name)); if (!cert.get()) return false; certs->push_back(cert); return true; } static CertificateList ListCertsInSlot(PK11SlotInfo* slot) { CertificateList result; CERTCertList* cert_list = PK11_ListCertsInSlot(slot); for (CERTCertListNode* node = CERT_LIST_HEAD(cert_list); !CERT_LIST_END(node, cert_list); node = CERT_LIST_NEXT(node)) { result.push_back(X509Certificate::CreateFromHandle( node->cert, X509Certificate::OSCertHandles())); } CERT_DestroyCertList(cert_list); // Sort the result so that test comparisons can be deterministic. std::sort(result.begin(), result.end(), X509Certificate::LessThan()); return result; } scoped_refptr<CryptoModule> slot_; NSSCertDatabase* cert_db_; const CertificateList empty_cert_list_; private: bool CleanupSlotContents() { bool ok = true; CertificateList certs = ListCertsInSlot(slot_->os_module_handle()); CERTCertTrust default_trust = {0}; for (size_t i = 0; i < certs.size(); ++i) { // Reset cert trust values to defaults before deleting. Otherwise NSS // somehow seems to remember the trust which can break following tests. SECStatus srv = CERT_ChangeCertTrust( CERT_GetDefaultCertDB(), certs[i]->os_cert_handle(), &default_trust); if (srv != SECSuccess) ok = false; if (!cert_db_->DeleteCertAndKey(certs[i].get())) ok = false; } return ok; } crypto::ScopedTestNSSDB test_nssdb_; }; TEST_F(CertDatabaseNSSTest, ListCerts) { // This test isn't terribly useful, though it will at least let valgrind test // for leaks. CertificateList certs; cert_db_->ListCerts(&certs); // The test DB is empty, but let's assume there will always be something in // the other slots. EXPECT_LT(0U, certs.size()); } TEST_F(CertDatabaseNSSTest, ImportFromPKCS12WrongPassword) { std::string pkcs12_data = ReadTestFile("client.p12"); EXPECT_EQ(ERR_PKCS12_IMPORT_BAD_PASSWORD, cert_db_->ImportFromPKCS12(slot_.get(), pkcs12_data, base::string16(), true, // is_extractable NULL)); // Test db should still be empty. EXPECT_EQ(0U, ListCertsInSlot(slot_->os_module_handle()).size()); } TEST_F(CertDatabaseNSSTest, ImportFromPKCS12AsExtractableAndExportAgain) { std::string pkcs12_data = ReadTestFile("client.p12"); EXPECT_EQ(OK, cert_db_->ImportFromPKCS12(slot_.get(), pkcs12_data, ASCIIToUTF16("12345"), true, // is_extractable NULL)); CertificateList cert_list = ListCertsInSlot(slot_->os_module_handle()); ASSERT_EQ(1U, cert_list.size()); scoped_refptr<X509Certificate> cert(cert_list[0]); EXPECT_EQ("testusercert", cert->subject().common_name); // TODO(mattm): move export test to separate test case? std::string exported_data; EXPECT_EQ(1, cert_db_->ExportToPKCS12(cert_list, ASCIIToUTF16("exportpw"), &exported_data)); ASSERT_LT(0U, exported_data.size()); // TODO(mattm): further verification of exported data? } TEST_F(CertDatabaseNSSTest, ImportFromPKCS12Twice) { std::string pkcs12_data = ReadTestFile("client.p12"); EXPECT_EQ(OK, cert_db_->ImportFromPKCS12(slot_.get(), pkcs12_data, ASCIIToUTF16("12345"), true, // is_extractable NULL)); EXPECT_EQ(1U, ListCertsInSlot(slot_->os_module_handle()).size()); // NSS has a SEC_ERROR_PKCS12_DUPLICATE_DATA error, but it doesn't look like // it's ever used. This test verifies that. EXPECT_EQ(OK, cert_db_->ImportFromPKCS12(slot_.get(), pkcs12_data, ASCIIToUTF16("12345"), true, // is_extractable NULL)); EXPECT_EQ(1U, ListCertsInSlot(slot_->os_module_handle()).size()); } TEST_F(CertDatabaseNSSTest, ImportFromPKCS12AsUnextractableAndExportAgain) { std::string pkcs12_data = ReadTestFile("client.p12"); EXPECT_EQ(OK, cert_db_->ImportFromPKCS12(slot_.get(), pkcs12_data, ASCIIToUTF16("12345"), false, // is_extractable NULL)); CertificateList cert_list = ListCertsInSlot(slot_->os_module_handle()); ASSERT_EQ(1U, cert_list.size()); scoped_refptr<X509Certificate> cert(cert_list[0]); EXPECT_EQ("testusercert", cert->subject().common_name); std::string exported_data; EXPECT_EQ(0, cert_db_->ExportToPKCS12(cert_list, ASCIIToUTF16("exportpw"), &exported_data)); } // Importing a PKCS#12 file with a certificate but no corresponding // private key should not mark an existing private key as unextractable. TEST_F(CertDatabaseNSSTest, ImportFromPKCS12OnlyMarkIncludedKey) { std::string pkcs12_data = ReadTestFile("client.p12"); EXPECT_EQ(OK, cert_db_->ImportFromPKCS12(slot_.get(), pkcs12_data, ASCIIToUTF16("12345"), true, // is_extractable NULL)); CertificateList cert_list = ListCertsInSlot(slot_->os_module_handle()); ASSERT_EQ(1U, cert_list.size()); // Now import a PKCS#12 file with just a certificate but no private key. pkcs12_data = ReadTestFile("client-nokey.p12"); EXPECT_EQ(OK, cert_db_->ImportFromPKCS12(slot_.get(), pkcs12_data, ASCIIToUTF16("12345"), false, // is_extractable NULL)); cert_list = ListCertsInSlot(slot_->os_module_handle()); ASSERT_EQ(1U, cert_list.size()); // Make sure the imported private key is still extractable. std::string exported_data; EXPECT_EQ(1, cert_db_->ExportToPKCS12(cert_list, ASCIIToUTF16("exportpw"), &exported_data)); ASSERT_LT(0U, exported_data.size()); } TEST_F(CertDatabaseNSSTest, ImportFromPKCS12InvalidFile) { std::string pkcs12_data = "Foobarbaz"; EXPECT_EQ(ERR_PKCS12_IMPORT_INVALID_FILE, cert_db_->ImportFromPKCS12(slot_.get(), pkcs12_data, base::string16(), true, // is_extractable NULL)); // Test db should still be empty. EXPECT_EQ(0U, ListCertsInSlot(slot_->os_module_handle()).size()); } TEST_F(CertDatabaseNSSTest, ImportCACert_SSLTrust) { CertificateList certs = CreateCertificateListFromFile( GetTestCertsDirectory(), "root_ca_cert.pem", X509Certificate::FORMAT_AUTO); ASSERT_EQ(1U, certs.size()); EXPECT_FALSE(certs[0]->os_cert_handle()->isperm); // Import it. NSSCertDatabase::ImportCertFailureList failed; EXPECT_TRUE(cert_db_->ImportCACerts(certs, NSSCertDatabase::TRUSTED_SSL, &failed)); EXPECT_EQ(0U, failed.size()); CertificateList cert_list = ListCertsInSlot(slot_->os_module_handle()); ASSERT_EQ(1U, cert_list.size()); scoped_refptr<X509Certificate> cert(cert_list[0]); EXPECT_EQ("Test Root CA", cert->subject().common_name); EXPECT_EQ(NSSCertDatabase::TRUSTED_SSL, cert_db_->GetCertTrust(cert.get(), CA_CERT)); EXPECT_EQ(unsigned(CERTDB_VALID_CA | CERTDB_TRUSTED_CA | CERTDB_TRUSTED_CLIENT_CA), cert->os_cert_handle()->trust->sslFlags); EXPECT_EQ(unsigned(CERTDB_VALID_CA), cert->os_cert_handle()->trust->emailFlags); EXPECT_EQ(unsigned(CERTDB_VALID_CA), cert->os_cert_handle()->trust->objectSigningFlags); } TEST_F(CertDatabaseNSSTest, ImportCACert_EmailTrust) { CertificateList certs = CreateCertificateListFromFile( GetTestCertsDirectory(), "root_ca_cert.pem", X509Certificate::FORMAT_AUTO); ASSERT_EQ(1U, certs.size()); EXPECT_FALSE(certs[0]->os_cert_handle()->isperm); // Import it. NSSCertDatabase::ImportCertFailureList failed; EXPECT_TRUE(cert_db_->ImportCACerts(certs, NSSCertDatabase::TRUSTED_EMAIL, &failed)); EXPECT_EQ(0U, failed.size()); CertificateList cert_list = ListCertsInSlot(slot_->os_module_handle()); ASSERT_EQ(1U, cert_list.size()); scoped_refptr<X509Certificate> cert(cert_list[0]); EXPECT_EQ("Test Root CA", cert->subject().common_name); EXPECT_EQ(NSSCertDatabase::TRUSTED_EMAIL, cert_db_->GetCertTrust(cert.get(), CA_CERT)); EXPECT_EQ(unsigned(CERTDB_VALID_CA), cert->os_cert_handle()->trust->sslFlags); EXPECT_EQ(unsigned(CERTDB_VALID_CA | CERTDB_TRUSTED_CA | CERTDB_TRUSTED_CLIENT_CA), cert->os_cert_handle()->trust->emailFlags); EXPECT_EQ(unsigned(CERTDB_VALID_CA), cert->os_cert_handle()->trust->objectSigningFlags); } TEST_F(CertDatabaseNSSTest, ImportCACert_ObjSignTrust) { CertificateList certs = CreateCertificateListFromFile( GetTestCertsDirectory(), "root_ca_cert.pem", X509Certificate::FORMAT_AUTO); ASSERT_EQ(1U, certs.size()); EXPECT_FALSE(certs[0]->os_cert_handle()->isperm); // Import it. NSSCertDatabase::ImportCertFailureList failed; EXPECT_TRUE(cert_db_->ImportCACerts(certs, NSSCertDatabase::TRUSTED_OBJ_SIGN, &failed)); EXPECT_EQ(0U, failed.size()); CertificateList cert_list = ListCertsInSlot(slot_->os_module_handle()); ASSERT_EQ(1U, cert_list.size()); scoped_refptr<X509Certificate> cert(cert_list[0]); EXPECT_EQ("Test Root CA", cert->subject().common_name); EXPECT_EQ(NSSCertDatabase::TRUSTED_OBJ_SIGN, cert_db_->GetCertTrust(cert.get(), CA_CERT)); EXPECT_EQ(unsigned(CERTDB_VALID_CA), cert->os_cert_handle()->trust->sslFlags); EXPECT_EQ(unsigned(CERTDB_VALID_CA), cert->os_cert_handle()->trust->emailFlags); EXPECT_EQ(unsigned(CERTDB_VALID_CA | CERTDB_TRUSTED_CA | CERTDB_TRUSTED_CLIENT_CA), cert->os_cert_handle()->trust->objectSigningFlags); } TEST_F(CertDatabaseNSSTest, ImportCA_NotCACert) { CertificateList certs = CreateCertificateListFromFile( GetTestCertsDirectory(), "ok_cert.pem", X509Certificate::FORMAT_AUTO); ASSERT_EQ(1U, certs.size()); EXPECT_FALSE(certs[0]->os_cert_handle()->isperm); // Import it. NSSCertDatabase::ImportCertFailureList failed; EXPECT_TRUE(cert_db_->ImportCACerts(certs, NSSCertDatabase::TRUSTED_SSL, &failed)); ASSERT_EQ(1U, failed.size()); // Note: this compares pointers directly. It's okay in this case because // ImportCACerts returns the same pointers that were passed in. In the // general case IsSameOSCert should be used. EXPECT_EQ(certs[0], failed[0].certificate); EXPECT_EQ(ERR_IMPORT_CA_CERT_NOT_CA, failed[0].net_error); EXPECT_EQ(0U, ListCertsInSlot(slot_->os_module_handle()).size()); } TEST_F(CertDatabaseNSSTest, ImportCACertHierarchy) { CertificateList certs; ASSERT_TRUE(ReadCertIntoList("dod_root_ca_2_cert.der", &certs)); ASSERT_TRUE(ReadCertIntoList("dod_ca_17_cert.der", &certs)); ASSERT_TRUE(ReadCertIntoList("www_us_army_mil_cert.der", &certs)); // Import it. NSSCertDatabase::ImportCertFailureList failed; // Have to specify email trust for the cert verification of the child cert to // work (see // http://mxr.mozilla.org/mozilla/source/security/nss/lib/certhigh/certvfy.c#752 // "XXX This choice of trustType seems arbitrary.") EXPECT_TRUE(cert_db_->ImportCACerts( certs, NSSCertDatabase::TRUSTED_SSL | NSSCertDatabase::TRUSTED_EMAIL, &failed)); ASSERT_EQ(2U, failed.size()); EXPECT_EQ("DOD CA-17", failed[0].certificate->subject().common_name); EXPECT_EQ(ERR_FAILED, failed[0].net_error); // The certificate expired. EXPECT_EQ("www.us.army.mil", failed[1].certificate->subject().common_name); EXPECT_EQ(ERR_IMPORT_CA_CERT_NOT_CA, failed[1].net_error); CertificateList cert_list = ListCertsInSlot(slot_->os_module_handle()); ASSERT_EQ(1U, cert_list.size()); EXPECT_EQ("DoD Root CA 2", cert_list[0]->subject().common_name); } TEST_F(CertDatabaseNSSTest, ImportCACertHierarchyDupeRoot) { CertificateList certs; ASSERT_TRUE(ReadCertIntoList("dod_root_ca_2_cert.der", &certs)); // First import just the root. NSSCertDatabase::ImportCertFailureList failed; EXPECT_TRUE(cert_db_->ImportCACerts( certs, NSSCertDatabase::TRUSTED_SSL | NSSCertDatabase::TRUSTED_EMAIL, &failed)); EXPECT_EQ(0U, failed.size()); CertificateList cert_list = ListCertsInSlot(slot_->os_module_handle()); ASSERT_EQ(1U, cert_list.size()); EXPECT_EQ("DoD Root CA 2", cert_list[0]->subject().common_name); ASSERT_TRUE(ReadCertIntoList("dod_ca_17_cert.der", &certs)); ASSERT_TRUE(ReadCertIntoList("www_us_army_mil_cert.der", &certs)); // Now import with the other certs in the list too. Even though the root is // already present, we should still import the rest. failed.clear(); EXPECT_TRUE(cert_db_->ImportCACerts( certs, NSSCertDatabase::TRUSTED_SSL | NSSCertDatabase::TRUSTED_EMAIL, &failed)); ASSERT_EQ(3U, failed.size()); EXPECT_EQ("DoD Root CA 2", failed[0].certificate->subject().common_name); EXPECT_EQ(ERR_IMPORT_CERT_ALREADY_EXISTS, failed[0].net_error); EXPECT_EQ("DOD CA-17", failed[1].certificate->subject().common_name); EXPECT_EQ(ERR_FAILED, failed[1].net_error); // The certificate expired. EXPECT_EQ("www.us.army.mil", failed[2].certificate->subject().common_name); EXPECT_EQ(ERR_IMPORT_CA_CERT_NOT_CA, failed[2].net_error); cert_list = ListCertsInSlot(slot_->os_module_handle()); ASSERT_EQ(1U, cert_list.size()); EXPECT_EQ("DoD Root CA 2", cert_list[0]->subject().common_name); } TEST_F(CertDatabaseNSSTest, ImportCACertHierarchyUntrusted) { CertificateList certs; ASSERT_TRUE(ReadCertIntoList("dod_root_ca_2_cert.der", &certs)); ASSERT_TRUE(ReadCertIntoList("dod_ca_17_cert.der", &certs)); // Import it. NSSCertDatabase::ImportCertFailureList failed; EXPECT_TRUE(cert_db_->ImportCACerts(certs, NSSCertDatabase::TRUST_DEFAULT, &failed)); ASSERT_EQ(1U, failed.size()); EXPECT_EQ("DOD CA-17", failed[0].certificate->subject().common_name); // TODO(mattm): should check for net error equivalent of // SEC_ERROR_UNTRUSTED_ISSUER EXPECT_EQ(ERR_FAILED, failed[0].net_error); CertificateList cert_list = ListCertsInSlot(slot_->os_module_handle()); ASSERT_EQ(1U, cert_list.size()); EXPECT_EQ("DoD Root CA 2", cert_list[0]->subject().common_name); } TEST_F(CertDatabaseNSSTest, ImportCACertHierarchyTree) { CertificateList certs; ASSERT_TRUE(ReadCertIntoList("dod_root_ca_2_cert.der", &certs)); ASSERT_TRUE(ReadCertIntoList("dod_ca_13_cert.der", &certs)); ASSERT_TRUE(ReadCertIntoList("dod_ca_17_cert.der", &certs)); // Import it. NSSCertDatabase::ImportCertFailureList failed; EXPECT_TRUE(cert_db_->ImportCACerts( certs, NSSCertDatabase::TRUSTED_SSL | NSSCertDatabase::TRUSTED_EMAIL, &failed)); EXPECT_EQ(2U, failed.size()); EXPECT_EQ("DOD CA-13", failed[0].certificate->subject().common_name); EXPECT_EQ(ERR_FAILED, failed[0].net_error); // The certificate expired. EXPECT_EQ("DOD CA-17", failed[1].certificate->subject().common_name); EXPECT_EQ(ERR_FAILED, failed[1].net_error); // The certificate expired. CertificateList cert_list = ListCertsInSlot(slot_->os_module_handle()); ASSERT_EQ(1U, cert_list.size()); EXPECT_EQ("DoD Root CA 2", cert_list[0]->subject().common_name); } TEST_F(CertDatabaseNSSTest, ImportCACertNotHierarchy) { CertificateList certs = CreateCertificateListFromFile( GetTestCertsDirectory(), "root_ca_cert.pem", X509Certificate::FORMAT_AUTO); ASSERT_EQ(1U, certs.size()); ASSERT_TRUE(ReadCertIntoList("dod_ca_13_cert.der", &certs)); ASSERT_TRUE(ReadCertIntoList("dod_ca_17_cert.der", &certs)); // Import it. NSSCertDatabase::ImportCertFailureList failed; EXPECT_TRUE(cert_db_->ImportCACerts( certs, NSSCertDatabase::TRUSTED_SSL | NSSCertDatabase::TRUSTED_EMAIL | NSSCertDatabase::TRUSTED_OBJ_SIGN, &failed)); ASSERT_EQ(2U, failed.size()); // TODO(mattm): should check for net error equivalent of // SEC_ERROR_UNKNOWN_ISSUER EXPECT_EQ("DOD CA-13", failed[0].certificate->subject().common_name); EXPECT_EQ(ERR_FAILED, failed[0].net_error); EXPECT_EQ("DOD CA-17", failed[1].certificate->subject().common_name); EXPECT_EQ(ERR_FAILED, failed[1].net_error); CertificateList cert_list = ListCertsInSlot(slot_->os_module_handle()); ASSERT_EQ(1U, cert_list.size()); EXPECT_EQ("Test Root CA", cert_list[0]->subject().common_name); } // http://crbug.com/108009 - Disabled, as google.chain.pem is an expired // certificate. TEST_F(CertDatabaseNSSTest, DISABLED_ImportServerCert) { // Need to import intermediate cert for the verify of google cert, otherwise // it will try to fetch it automatically with cert_pi_useAIACertFetch, which // will cause OCSPCreateSession on the main thread, which is not allowed. CertificateList certs = CreateCertificateListFromFile( GetTestCertsDirectory(), "google.chain.pem", X509Certificate::FORMAT_AUTO); ASSERT_EQ(2U, certs.size()); NSSCertDatabase::ImportCertFailureList failed; EXPECT_TRUE(cert_db_->ImportServerCert(certs, NSSCertDatabase::TRUST_DEFAULT, &failed)); EXPECT_EQ(0U, failed.size()); CertificateList cert_list = ListCertsInSlot(slot_->os_module_handle()); ASSERT_EQ(2U, cert_list.size()); scoped_refptr<X509Certificate> goog_cert(cert_list[0]); scoped_refptr<X509Certificate> thawte_cert(cert_list[1]); EXPECT_EQ("www.google.com", goog_cert->subject().common_name); EXPECT_EQ("Thawte SGC CA", thawte_cert->subject().common_name); EXPECT_EQ(NSSCertDatabase::TRUST_DEFAULT, cert_db_->GetCertTrust(goog_cert.get(), SERVER_CERT)); EXPECT_EQ(0U, goog_cert->os_cert_handle()->trust->sslFlags); scoped_refptr<CertVerifyProc> verify_proc(new CertVerifyProcNSS()); int flags = 0; CertVerifyResult verify_result; int error = verify_proc->Verify(goog_cert.get(), "www.google.com", flags, NULL, empty_cert_list_, &verify_result); EXPECT_EQ(OK, error); EXPECT_EQ(0U, verify_result.cert_status); } TEST_F(CertDatabaseNSSTest, ImportServerCert_SelfSigned) { CertificateList certs; ASSERT_TRUE(ReadCertIntoList("punycodetest.der", &certs)); NSSCertDatabase::ImportCertFailureList failed; EXPECT_TRUE(cert_db_->ImportServerCert(certs, NSSCertDatabase::TRUST_DEFAULT, &failed)); EXPECT_EQ(0U, failed.size()); CertificateList cert_list = ListCertsInSlot(slot_->os_module_handle()); ASSERT_EQ(1U, cert_list.size()); scoped_refptr<X509Certificate> puny_cert(cert_list[0]); EXPECT_EQ(NSSCertDatabase::TRUST_DEFAULT, cert_db_->GetCertTrust(puny_cert.get(), SERVER_CERT)); EXPECT_EQ(0U, puny_cert->os_cert_handle()->trust->sslFlags); scoped_refptr<CertVerifyProc> verify_proc(new CertVerifyProcNSS()); int flags = 0; CertVerifyResult verify_result; int error = verify_proc->Verify(puny_cert.get(), "xn--wgv71a119e.com", flags, NULL, empty_cert_list_, &verify_result); EXPECT_EQ(ERR_CERT_AUTHORITY_INVALID, error); EXPECT_EQ(CERT_STATUS_AUTHORITY_INVALID, verify_result.cert_status); } TEST_F(CertDatabaseNSSTest, ImportServerCert_SelfSigned_Trusted) { // When using CERT_PKIXVerifyCert (which we do), server trust only works from // 3.13.4 onwards. See https://bugzilla.mozilla.org/show_bug.cgi?id=647364. if (!NSS_VersionCheck("3.13.4")) { LOG(INFO) << "test skipped on NSS < 3.13.4"; return; } CertificateList certs; ASSERT_TRUE(ReadCertIntoList("punycodetest.der", &certs)); NSSCertDatabase::ImportCertFailureList failed; EXPECT_TRUE(cert_db_->ImportServerCert(certs, NSSCertDatabase::TRUSTED_SSL, &failed)); EXPECT_EQ(0U, failed.size()); CertificateList cert_list = ListCertsInSlot(slot_->os_module_handle()); ASSERT_EQ(1U, cert_list.size()); scoped_refptr<X509Certificate> puny_cert(cert_list[0]); EXPECT_EQ(NSSCertDatabase::TRUSTED_SSL, cert_db_->GetCertTrust(puny_cert.get(), SERVER_CERT)); EXPECT_EQ(unsigned(CERTDB_TRUSTED | CERTDB_TERMINAL_RECORD), puny_cert->os_cert_handle()->trust->sslFlags); scoped_refptr<CertVerifyProc> verify_proc(new CertVerifyProcNSS()); int flags = 0; CertVerifyResult verify_result; int error = verify_proc->Verify(puny_cert.get(), "xn--wgv71a119e.com", flags, NULL, empty_cert_list_, &verify_result); EXPECT_EQ(OK, error); EXPECT_EQ(0U, verify_result.cert_status); } TEST_F(CertDatabaseNSSTest, ImportCaAndServerCert) { CertificateList ca_certs = CreateCertificateListFromFile( GetTestCertsDirectory(), "root_ca_cert.pem", X509Certificate::FORMAT_AUTO); ASSERT_EQ(1U, ca_certs.size()); // Import CA cert and trust it. NSSCertDatabase::ImportCertFailureList failed; EXPECT_TRUE(cert_db_->ImportCACerts(ca_certs, NSSCertDatabase::TRUSTED_SSL, &failed)); EXPECT_EQ(0U, failed.size()); CertificateList certs = CreateCertificateListFromFile( GetTestCertsDirectory(), "ok_cert.pem", X509Certificate::FORMAT_AUTO); ASSERT_EQ(1U, certs.size()); // Import server cert with default trust. EXPECT_TRUE(cert_db_->ImportServerCert(certs, NSSCertDatabase::TRUST_DEFAULT, &failed)); EXPECT_EQ(0U, failed.size()); // Server cert should verify. scoped_refptr<CertVerifyProc> verify_proc(new CertVerifyProcNSS()); int flags = 0; CertVerifyResult verify_result; int error = verify_proc->Verify(certs[0].get(), "127.0.0.1", flags, NULL, empty_cert_list_, &verify_result); EXPECT_EQ(OK, error); EXPECT_EQ(0U, verify_result.cert_status); } TEST_F(CertDatabaseNSSTest, ImportCaAndServerCert_DistrustServer) { // Explicit distrust only works starting in NSS 3.13. if (!NSS_VersionCheck("3.13")) { LOG(INFO) << "test skipped on NSS < 3.13"; return; } CertificateList ca_certs = CreateCertificateListFromFile( GetTestCertsDirectory(), "root_ca_cert.pem", X509Certificate::FORMAT_AUTO); ASSERT_EQ(1U, ca_certs.size()); // Import CA cert and trust it. NSSCertDatabase::ImportCertFailureList failed; EXPECT_TRUE(cert_db_->ImportCACerts(ca_certs, NSSCertDatabase::TRUSTED_SSL, &failed)); EXPECT_EQ(0U, failed.size()); CertificateList certs = CreateCertificateListFromFile( GetTestCertsDirectory(), "ok_cert.pem", X509Certificate::FORMAT_AUTO); ASSERT_EQ(1U, certs.size()); // Import server cert without inheriting trust from issuer (explicit // distrust). EXPECT_TRUE(cert_db_->ImportServerCert( certs, NSSCertDatabase::DISTRUSTED_SSL, &failed)); EXPECT_EQ(0U, failed.size()); EXPECT_EQ(NSSCertDatabase::DISTRUSTED_SSL, cert_db_->GetCertTrust(certs[0].get(), SERVER_CERT)); EXPECT_EQ(unsigned(CERTDB_TERMINAL_RECORD), certs[0]->os_cert_handle()->trust->sslFlags); // Server cert should fail to verify. scoped_refptr<CertVerifyProc> verify_proc(new CertVerifyProcNSS()); int flags = 0; CertVerifyResult verify_result; int error = verify_proc->Verify(certs[0].get(), "127.0.0.1", flags, NULL, empty_cert_list_, &verify_result); EXPECT_EQ(ERR_CERT_REVOKED, error); EXPECT_EQ(CERT_STATUS_REVOKED, verify_result.cert_status); } TEST_F(CertDatabaseNSSTest, TrustIntermediateCa) { CertificateList ca_certs = CreateCertificateListFromFile( GetTestCertsDirectory(), "2048-rsa-root.pem", X509Certificate::FORMAT_AUTO); ASSERT_EQ(1U, ca_certs.size()); // Import Root CA cert and distrust it. NSSCertDatabase::ImportCertFailureList failed; EXPECT_TRUE(cert_db_->ImportCACerts(ca_certs, NSSCertDatabase::DISTRUSTED_SSL, &failed)); EXPECT_EQ(0U, failed.size()); CertificateList intermediate_certs = CreateCertificateListFromFile( GetTestCertsDirectory(), "2048-rsa-intermediate.pem", X509Certificate::FORMAT_AUTO); ASSERT_EQ(1U, intermediate_certs.size()); // Import Intermediate CA cert and trust it. EXPECT_TRUE(cert_db_->ImportCACerts(intermediate_certs, NSSCertDatabase::TRUSTED_SSL, &failed)); EXPECT_EQ(0U, failed.size()); CertificateList certs = CreateCertificateListFromFile( GetTestCertsDirectory(), "2048-rsa-ee-by-2048-rsa-intermediate.pem", X509Certificate::FORMAT_AUTO); ASSERT_EQ(1U, certs.size()); // Import server cert with default trust. EXPECT_TRUE(cert_db_->ImportServerCert( certs, NSSCertDatabase::TRUST_DEFAULT, &failed)); EXPECT_EQ(0U, failed.size()); EXPECT_EQ(NSSCertDatabase::TRUST_DEFAULT, cert_db_->GetCertTrust(certs[0].get(), SERVER_CERT)); // Server cert should verify. scoped_refptr<CertVerifyProc> verify_proc(new CertVerifyProcNSS()); int flags = 0; CertVerifyResult verify_result; int error = verify_proc->Verify(certs[0].get(), "127.0.0.1", flags, NULL, empty_cert_list_, &verify_result); EXPECT_EQ(OK, error); EXPECT_EQ(0U, verify_result.cert_status); // Explicit distrust only works starting in NSS 3.13. if (!NSS_VersionCheck("3.13")) { LOG(INFO) << "test partially skipped on NSS < 3.13"; return; } // Trust the root cert and distrust the intermediate. EXPECT_TRUE(cert_db_->SetCertTrust( ca_certs[0].get(), CA_CERT, NSSCertDatabase::TRUSTED_SSL)); EXPECT_TRUE(cert_db_->SetCertTrust( intermediate_certs[0].get(), CA_CERT, NSSCertDatabase::DISTRUSTED_SSL)); EXPECT_EQ( unsigned(CERTDB_VALID_CA | CERTDB_TRUSTED_CA | CERTDB_TRUSTED_CLIENT_CA), ca_certs[0]->os_cert_handle()->trust->sslFlags); EXPECT_EQ(unsigned(CERTDB_VALID_CA), ca_certs[0]->os_cert_handle()->trust->emailFlags); EXPECT_EQ(unsigned(CERTDB_VALID_CA), ca_certs[0]->os_cert_handle()->trust->objectSigningFlags); EXPECT_EQ(unsigned(CERTDB_TERMINAL_RECORD), intermediate_certs[0]->os_cert_handle()->trust->sslFlags); EXPECT_EQ(unsigned(CERTDB_VALID_CA), intermediate_certs[0]->os_cert_handle()->trust->emailFlags); EXPECT_EQ( unsigned(CERTDB_VALID_CA), intermediate_certs[0]->os_cert_handle()->trust->objectSigningFlags); // Server cert should fail to verify. CertVerifyResult verify_result2; error = verify_proc->Verify(certs[0].get(), "127.0.0.1", flags, NULL, empty_cert_list_, &verify_result2); EXPECT_EQ(ERR_CERT_REVOKED, error); EXPECT_EQ(CERT_STATUS_REVOKED, verify_result2.cert_status); } TEST_F(CertDatabaseNSSTest, TrustIntermediateCa2) { if (NSS_VersionCheck("3.14.2") && !NSS_VersionCheck("3.15")) { // See http://bugzil.la/863947 for details. LOG(INFO) << "Skipping test for NSS 3.14.2 - NSS 3.15"; return; } NSSCertDatabase::ImportCertFailureList failed; CertificateList intermediate_certs = CreateCertificateListFromFile( GetTestCertsDirectory(), "2048-rsa-intermediate.pem", X509Certificate::FORMAT_AUTO); ASSERT_EQ(1U, intermediate_certs.size()); // Import Intermediate CA cert and trust it. EXPECT_TRUE(cert_db_->ImportCACerts(intermediate_certs, NSSCertDatabase::TRUSTED_SSL, &failed)); EXPECT_EQ(0U, failed.size()); CertificateList certs = CreateCertificateListFromFile( GetTestCertsDirectory(), "2048-rsa-ee-by-2048-rsa-intermediate.pem", X509Certificate::FORMAT_AUTO); ASSERT_EQ(1U, certs.size()); // Import server cert with default trust. EXPECT_TRUE(cert_db_->ImportServerCert( certs, NSSCertDatabase::TRUST_DEFAULT, &failed)); EXPECT_EQ(0U, failed.size()); EXPECT_EQ(NSSCertDatabase::TRUST_DEFAULT, cert_db_->GetCertTrust(certs[0].get(), SERVER_CERT)); // Server cert should verify. scoped_refptr<CertVerifyProc> verify_proc(new CertVerifyProcNSS()); int flags = 0; CertVerifyResult verify_result; int error = verify_proc->Verify(certs[0].get(), "127.0.0.1", flags, NULL, empty_cert_list_, &verify_result); EXPECT_EQ(OK, error); EXPECT_EQ(0U, verify_result.cert_status); // Without explicit trust of the intermediate, verification should fail. EXPECT_TRUE(cert_db_->SetCertTrust( intermediate_certs[0].get(), CA_CERT, NSSCertDatabase::TRUST_DEFAULT)); // Server cert should fail to verify. CertVerifyResult verify_result2; error = verify_proc->Verify(certs[0].get(), "127.0.0.1", flags, NULL, empty_cert_list_, &verify_result2); EXPECT_EQ(ERR_CERT_AUTHORITY_INVALID, error); EXPECT_EQ(CERT_STATUS_AUTHORITY_INVALID, verify_result2.cert_status); } TEST_F(CertDatabaseNSSTest, TrustIntermediateCa3) { if (NSS_VersionCheck("3.14.2") && !NSS_VersionCheck("3.15")) { // See http://bugzil.la/863947 for details. LOG(INFO) << "Skipping test for NSS 3.14.2 - NSS 3.15"; return; } NSSCertDatabase::ImportCertFailureList failed; CertificateList ca_certs = CreateCertificateListFromFile( GetTestCertsDirectory(), "2048-rsa-root.pem", X509Certificate::FORMAT_AUTO); ASSERT_EQ(1U, ca_certs.size()); // Import Root CA cert and default trust it. EXPECT_TRUE(cert_db_->ImportCACerts(ca_certs, NSSCertDatabase::TRUST_DEFAULT, &failed)); EXPECT_EQ(0U, failed.size()); CertificateList intermediate_certs = CreateCertificateListFromFile( GetTestCertsDirectory(), "2048-rsa-intermediate.pem", X509Certificate::FORMAT_AUTO); ASSERT_EQ(1U, intermediate_certs.size()); // Import Intermediate CA cert and trust it. EXPECT_TRUE(cert_db_->ImportCACerts(intermediate_certs, NSSCertDatabase::TRUSTED_SSL, &failed)); EXPECT_EQ(0U, failed.size()); CertificateList certs = CreateCertificateListFromFile( GetTestCertsDirectory(), "2048-rsa-ee-by-2048-rsa-intermediate.pem", X509Certificate::FORMAT_AUTO); ASSERT_EQ(1U, certs.size()); // Import server cert with default trust. EXPECT_TRUE(cert_db_->ImportServerCert( certs, NSSCertDatabase::TRUST_DEFAULT, &failed)); EXPECT_EQ(0U, failed.size()); EXPECT_EQ(NSSCertDatabase::TRUST_DEFAULT, cert_db_->GetCertTrust(certs[0].get(), SERVER_CERT)); // Server cert should verify. scoped_refptr<CertVerifyProc> verify_proc(new CertVerifyProcNSS()); int flags = 0; CertVerifyResult verify_result; int error = verify_proc->Verify(certs[0].get(), "127.0.0.1", flags, NULL, empty_cert_list_, &verify_result); EXPECT_EQ(OK, error); EXPECT_EQ(0U, verify_result.cert_status); // Without explicit trust of the intermediate, verification should fail. EXPECT_TRUE(cert_db_->SetCertTrust( intermediate_certs[0].get(), CA_CERT, NSSCertDatabase::TRUST_DEFAULT)); // Server cert should fail to verify. CertVerifyResult verify_result2; error = verify_proc->Verify(certs[0].get(), "127.0.0.1", flags, NULL, empty_cert_list_, &verify_result2); EXPECT_EQ(ERR_CERT_AUTHORITY_INVALID, error); EXPECT_EQ(CERT_STATUS_AUTHORITY_INVALID, verify_result2.cert_status); } TEST_F(CertDatabaseNSSTest, TrustIntermediateCa4) { // Explicit distrust only works starting in NSS 3.13. if (!NSS_VersionCheck("3.13")) { LOG(INFO) << "test skipped on NSS < 3.13"; return; } NSSCertDatabase::ImportCertFailureList failed; CertificateList ca_certs = CreateCertificateListFromFile( GetTestCertsDirectory(), "2048-rsa-root.pem", X509Certificate::FORMAT_AUTO); ASSERT_EQ(1U, ca_certs.size()); // Import Root CA cert and trust it. EXPECT_TRUE(cert_db_->ImportCACerts(ca_certs, NSSCertDatabase::TRUSTED_SSL, &failed)); EXPECT_EQ(0U, failed.size()); CertificateList intermediate_certs = CreateCertificateListFromFile( GetTestCertsDirectory(), "2048-rsa-intermediate.pem", X509Certificate::FORMAT_AUTO); ASSERT_EQ(1U, intermediate_certs.size()); // Import Intermediate CA cert and distrust it. EXPECT_TRUE(cert_db_->ImportCACerts( intermediate_certs, NSSCertDatabase::DISTRUSTED_SSL, &failed)); EXPECT_EQ(0U, failed.size()); CertificateList certs = CreateCertificateListFromFile( GetTestCertsDirectory(), "2048-rsa-ee-by-2048-rsa-intermediate.pem", X509Certificate::FORMAT_AUTO); ASSERT_EQ(1U, certs.size()); // Import server cert with default trust. EXPECT_TRUE(cert_db_->ImportServerCert( certs, NSSCertDatabase::TRUST_DEFAULT, &failed)); EXPECT_EQ(0U, failed.size()); EXPECT_EQ(NSSCertDatabase::TRUST_DEFAULT, cert_db_->GetCertTrust(certs[0].get(), SERVER_CERT)); // Server cert should not verify. scoped_refptr<CertVerifyProc> verify_proc(new CertVerifyProcNSS()); int flags = 0; CertVerifyResult verify_result; int error = verify_proc->Verify(certs[0].get(), "127.0.0.1", flags, NULL, empty_cert_list_, &verify_result); EXPECT_EQ(ERR_CERT_REVOKED, error); EXPECT_EQ(CERT_STATUS_REVOKED, verify_result.cert_status); // Without explicit distrust of the intermediate, verification should succeed. EXPECT_TRUE(cert_db_->SetCertTrust( intermediate_certs[0].get(), CA_CERT, NSSCertDatabase::TRUST_DEFAULT)); // Server cert should verify. CertVerifyResult verify_result2; error = verify_proc->Verify(certs[0].get(), "127.0.0.1", flags, NULL, empty_cert_list_, &verify_result2); EXPECT_EQ(OK, error); EXPECT_EQ(0U, verify_result2.cert_status); } // Importing two certificates with the same issuer and subject common name, // but overall distinct subject names, should succeed and generate a unique // nickname for the second certificate. TEST_F(CertDatabaseNSSTest, ImportDuplicateCommonName) { CertificateList certs = CreateCertificateListFromFile(GetTestCertsDirectory(), "duplicate_cn_1.pem", X509Certificate::FORMAT_AUTO); ASSERT_EQ(1U, certs.size()); EXPECT_EQ(0U, ListCertsInSlot(slot_->os_module_handle()).size()); // Import server cert with default trust. NSSCertDatabase::ImportCertFailureList failed; EXPECT_TRUE(cert_db_->ImportServerCert( certs, NSSCertDatabase::TRUST_DEFAULT, &failed)); EXPECT_EQ(0U, failed.size()); EXPECT_EQ(NSSCertDatabase::TRUST_DEFAULT, cert_db_->GetCertTrust(certs[0].get(), SERVER_CERT)); CertificateList new_certs = ListCertsInSlot(slot_->os_module_handle()); ASSERT_EQ(1U, new_certs.size()); // Now attempt to import a different certificate with the same common name. CertificateList certs2 = CreateCertificateListFromFile(GetTestCertsDirectory(), "duplicate_cn_2.pem", X509Certificate::FORMAT_AUTO); ASSERT_EQ(1U, certs2.size()); // Import server cert with default trust. EXPECT_TRUE(cert_db_->ImportServerCert( certs2, NSSCertDatabase::TRUST_DEFAULT, &failed)); EXPECT_EQ(0U, failed.size()); EXPECT_EQ(NSSCertDatabase::TRUST_DEFAULT, cert_db_->GetCertTrust(certs2[0].get(), SERVER_CERT)); new_certs = ListCertsInSlot(slot_->os_module_handle()); ASSERT_EQ(2U, new_certs.size()); EXPECT_STRNE(new_certs[0]->os_cert_handle()->nickname, new_certs[1]->os_cert_handle()->nickname); } } // namespace net