1218 lines
49 KiB
C++
1218 lines
49 KiB
C++
// Copyright 2012 The Chromium Authors
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
#include "net/cert/nss_cert_database.h"
|
|
|
|
#include <cert.h>
|
|
#include <certdb.h>
|
|
#include <pk11pub.h>
|
|
#include <seccomon.h>
|
|
|
|
#include <algorithm>
|
|
#include <memory>
|
|
#include <string>
|
|
|
|
#include "base/files/file_path.h"
|
|
#include "base/files/file_util.h"
|
|
#include "base/functional/bind.h"
|
|
#include "base/lazy_instance.h"
|
|
#include "base/run_loop.h"
|
|
#include "base/strings/string_util.h"
|
|
#include "base/strings/utf_string_conversions.h"
|
|
#include "base/test/test_future.h"
|
|
#include "crypto/scoped_nss_types.h"
|
|
#include "crypto/scoped_test_nss_db.h"
|
|
#include "net/base/features.h"
|
|
#include "net/base/hash_value.h"
|
|
#include "net/base/net_errors.h"
|
|
#include "net/cert/cert_net_fetcher.h"
|
|
#include "net/cert/cert_status_flags.h"
|
|
#include "net/cert/cert_verify_proc.h"
|
|
#include "net/cert/cert_verify_result.h"
|
|
#include "net/cert/crl_set.h"
|
|
#include "net/cert/x509_certificate.h"
|
|
#include "net/cert/x509_util_nss.h"
|
|
#include "net/log/net_log_with_source.h"
|
|
#include "net/test/cert_test_util.h"
|
|
#include "net/test/gtest_util.h"
|
|
#include "net/test/test_data_directory.h"
|
|
#include "net/test/test_with_task_environment.h"
|
|
#include "net/third_party/mozilla_security_manager/nsNSSCertificateDB.h"
|
|
#include "testing/gmock/include/gmock/gmock.h"
|
|
#include "testing/gtest/include/gtest/gtest.h"
|
|
|
|
using base::ASCIIToUTF16;
|
|
using net::test::IsError;
|
|
using net::test::IsOk;
|
|
|
|
namespace net {
|
|
|
|
namespace {
|
|
|
|
std::string GetSubjectCN(CERTCertificate* cert) {
|
|
char* cn = CERT_GetCommonName(&cert->subject);
|
|
std::string s = cn;
|
|
PORT_Free(cn);
|
|
return s;
|
|
}
|
|
|
|
bool GetCertIsPerm(const CERTCertificate* cert) {
|
|
PRBool is_perm;
|
|
CHECK_EQ(CERT_GetCertIsPerm(cert, &is_perm), SECSuccess);
|
|
return is_perm != PR_FALSE;
|
|
}
|
|
|
|
const NSSCertDatabase::CertInfo* FindCertInfoForCert(
|
|
const NSSCertDatabase::CertInfoList& cert_info_list,
|
|
CERTCertificate* target_cert) {
|
|
for (const auto& c : cert_info_list) {
|
|
if (x509_util::IsSameCertificate(c.cert.get(), target_cert)) {
|
|
return &c;
|
|
}
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
} // namespace
|
|
|
|
class CertDatabaseNSSTest : public TestWithTaskEnvironment {
|
|
public:
|
|
void SetUp() override {
|
|
ASSERT_TRUE(test_nssdb_.is_open());
|
|
cert_db_ = std::make_unique<NSSCertDatabase>(
|
|
crypto::ScopedPK11Slot(
|
|
PK11_ReferenceSlot(test_nssdb_.slot())) /* public slot */,
|
|
crypto::ScopedPK11Slot(
|
|
PK11_ReferenceSlot(test_nssdb_.slot())) /* private slot */);
|
|
public_slot_ = cert_db_->GetPublicSlot();
|
|
crl_set_ = CRLSet::BuiltinCRLSet();
|
|
|
|
// Test db should be empty at start of test.
|
|
EXPECT_EQ(0U, ListCerts().size());
|
|
}
|
|
|
|
void TearDown() override {
|
|
// 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::RunLoop().RunUntilIdle();
|
|
}
|
|
|
|
protected:
|
|
PK11SlotInfo* GetPublicSlot() { return public_slot_.get(); }
|
|
|
|
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,
|
|
ScopedCERTCertificateList* certs) {
|
|
ScopedCERTCertificate cert =
|
|
ImportCERTCertificateFromFile(GetTestCertsDirectory(), name);
|
|
if (!cert)
|
|
return false;
|
|
|
|
certs->push_back(std::move(cert));
|
|
return true;
|
|
}
|
|
|
|
ScopedCERTCertificateList ListCerts() {
|
|
ScopedCERTCertificateList result;
|
|
crypto::ScopedCERTCertList cert_list(
|
|
PK11_ListCertsInSlot(test_nssdb_.slot()));
|
|
if (!cert_list)
|
|
return result;
|
|
for (CERTCertListNode* node = CERT_LIST_HEAD(cert_list);
|
|
!CERT_LIST_END(node, cert_list);
|
|
node = CERT_LIST_NEXT(node)) {
|
|
result.push_back(x509_util::DupCERTCertificate(node->cert));
|
|
}
|
|
|
|
// Sort the result so that test comparisons can be deterministic.
|
|
std::sort(
|
|
result.begin(), result.end(),
|
|
[](const ScopedCERTCertificate& lhs, const ScopedCERTCertificate& rhs) {
|
|
return x509_util::CalculateFingerprint256(lhs.get()) <
|
|
x509_util::CalculateFingerprint256(rhs.get());
|
|
});
|
|
return result;
|
|
}
|
|
|
|
std::unique_ptr<NSSCertDatabase> cert_db_;
|
|
// When building with libstdc++, |empty_cert_list_| does not have a default
|
|
// constructor. Initialize it explicitly so that CertDatabaseNSSTest gets a
|
|
// default constructor.
|
|
const CertificateList empty_cert_list_ = CertificateList();
|
|
crypto::ScopedTestNSSDB test_nssdb_;
|
|
crypto::ScopedPK11Slot public_slot_;
|
|
scoped_refptr<CRLSet> crl_set_;
|
|
};
|
|
|
|
TEST_F(CertDatabaseNSSTest, ListCerts) {
|
|
// This test isn't terribly useful, though it might help with memory
|
|
// leak tests.
|
|
base::test::TestFuture<ScopedCERTCertificateList> future;
|
|
cert_db_->ListCerts(future.GetCallback());
|
|
|
|
ScopedCERTCertificateList certs = future.Take();
|
|
// 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, ListCertsInfo) {
|
|
// Since ListCertsInfo queries all the "permanent" certs NSS knows about,
|
|
// including NSS builtin trust anchors and any locally installed certs of the
|
|
// user running the test, it's hard to do really precise testing here. Try to
|
|
// do some general testing as well as testing that a cert added through
|
|
// ScopedTestNSSDB is handled properly.
|
|
|
|
// Load a test certificate
|
|
ScopedCERTCertificateList test_root_certs = CreateCERTCertificateListFromFile(
|
|
GetTestCertsDirectory(), "root_ca_cert.pem",
|
|
X509Certificate::FORMAT_AUTO);
|
|
ASSERT_EQ(1U, test_root_certs.size());
|
|
// Should be only a temp certificate at this point, and thus not be returned
|
|
// in the listed certs.
|
|
EXPECT_FALSE(GetCertIsPerm(test_root_certs[0].get()));
|
|
|
|
// Get lists of all certs both including and excluding NSS roots.
|
|
NSSCertDatabase::CertInfoList certs_including_nss;
|
|
NSSCertDatabase::CertInfoList certs_excluding_nss;
|
|
{
|
|
base::test::TestFuture<NSSCertDatabase::CertInfoList> future;
|
|
cert_db_->ListCertsInfo(future.GetCallback(),
|
|
NSSCertDatabase::NSSRootsHandling::kInclude);
|
|
certs_including_nss = future.Take();
|
|
}
|
|
{
|
|
base::test::TestFuture<NSSCertDatabase::CertInfoList> future;
|
|
cert_db_->ListCertsInfo(future.GetCallback(),
|
|
NSSCertDatabase::NSSRootsHandling::kExclude);
|
|
certs_excluding_nss = future.Take();
|
|
}
|
|
|
|
// The tests based on GetAnNssSslTrustedBuiltinRoot could be flaky in obscure
|
|
// local configurations (if the user running the test has manually imported
|
|
// the same certificate into their user NSS DB.) Oh well.
|
|
ScopedCERTCertificate nss_root = GetAnNssBuiltinSslTrustedRoot();
|
|
// (Also this will fail if we ever do the "don't load libnssckbi.so" thing.)
|
|
ASSERT_TRUE(nss_root);
|
|
{
|
|
const NSSCertDatabase::CertInfo* nss_root_info =
|
|
FindCertInfoForCert(certs_including_nss, nss_root.get());
|
|
ASSERT_TRUE(nss_root_info);
|
|
EXPECT_TRUE(nss_root_info->web_trust_anchor);
|
|
EXPECT_FALSE(nss_root_info->untrusted);
|
|
EXPECT_FALSE(nss_root_info->device_wide);
|
|
EXPECT_FALSE(nss_root_info->hardware_backed);
|
|
EXPECT_TRUE(nss_root_info->on_read_only_slot);
|
|
}
|
|
EXPECT_FALSE(FindCertInfoForCert(certs_excluding_nss, nss_root.get()));
|
|
|
|
// Test root cert should not be in the lists retrieved before it was imported.
|
|
EXPECT_FALSE(
|
|
FindCertInfoForCert(certs_including_nss, test_root_certs[0].get()));
|
|
EXPECT_FALSE(
|
|
FindCertInfoForCert(certs_excluding_nss, test_root_certs[0].get()));
|
|
|
|
// Import the NSS root into the test DB.
|
|
SECStatus srv =
|
|
PK11_ImportCert(test_nssdb_.slot(), nss_root.get(), CK_INVALID_HANDLE,
|
|
net::x509_util::GetDefaultUniqueNickname(
|
|
nss_root.get(), net::CA_CERT, test_nssdb_.slot())
|
|
.c_str(),
|
|
PR_FALSE /* includeTrust (unused) */);
|
|
ASSERT_EQ(SECSuccess, srv);
|
|
|
|
// Import test certificate to the test DB.
|
|
NSSCertDatabase::ImportCertFailureList failed;
|
|
EXPECT_TRUE(cert_db_->ImportCACerts(test_root_certs,
|
|
NSSCertDatabase::TRUSTED_SSL, &failed));
|
|
EXPECT_EQ(0U, failed.size());
|
|
|
|
// Get new lists of all certs both including and excluding NSS roots, which
|
|
// should now also include the test db certificates.
|
|
NSSCertDatabase::CertInfoList certs_including_nss_with_local;
|
|
NSSCertDatabase::CertInfoList certs_excluding_nss_with_local;
|
|
{
|
|
base::test::TestFuture<NSSCertDatabase::CertInfoList> future;
|
|
cert_db_->ListCertsInfo(future.GetCallback(),
|
|
NSSCertDatabase::NSSRootsHandling::kInclude);
|
|
certs_including_nss_with_local = future.Take();
|
|
}
|
|
{
|
|
base::test::TestFuture<NSSCertDatabase::CertInfoList> future;
|
|
cert_db_->ListCertsInfo(future.GetCallback(),
|
|
NSSCertDatabase::NSSRootsHandling::kExclude);
|
|
certs_excluding_nss_with_local = future.Take();
|
|
}
|
|
|
|
// After adding the certs to the test db, the number certs returned should be
|
|
// 1 more than before in kInclude and and 2 more in kExclude cases.
|
|
EXPECT_EQ(certs_including_nss_with_local.size(),
|
|
1 + certs_including_nss.size());
|
|
EXPECT_EQ(certs_excluding_nss_with_local.size(),
|
|
2 + certs_excluding_nss.size());
|
|
|
|
// Using kExclude should give a smaller number of results than kInclude.
|
|
// (Although this would be wrong if we ever do the "don't load libnssckbi.so"
|
|
// thing.)
|
|
EXPECT_LT(certs_excluding_nss_with_local.size(),
|
|
certs_including_nss_with_local.size());
|
|
|
|
// The NSS root that was imported to the test db should be in both lists now.
|
|
{
|
|
const NSSCertDatabase::CertInfo* nss_root_info =
|
|
FindCertInfoForCert(certs_including_nss_with_local, nss_root.get());
|
|
ASSERT_TRUE(nss_root_info);
|
|
EXPECT_TRUE(nss_root_info->web_trust_anchor);
|
|
EXPECT_FALSE(nss_root_info->untrusted);
|
|
EXPECT_FALSE(nss_root_info->device_wide);
|
|
EXPECT_FALSE(nss_root_info->hardware_backed);
|
|
// `on_read_only_slot` is not tested here as the way it is calculated could
|
|
// be potentially flaky if the cert exists on both a readonly and
|
|
// non-readonly slot.
|
|
}
|
|
{
|
|
const NSSCertDatabase::CertInfo* nss_root_info =
|
|
FindCertInfoForCert(certs_excluding_nss_with_local, nss_root.get());
|
|
ASSERT_TRUE(nss_root_info);
|
|
EXPECT_FALSE(nss_root_info->web_trust_anchor);
|
|
EXPECT_TRUE(nss_root_info->untrusted);
|
|
EXPECT_FALSE(nss_root_info->device_wide);
|
|
EXPECT_FALSE(nss_root_info->hardware_backed);
|
|
// `on_read_only_slot` is not tested here as the way it is calculated could
|
|
// be potentially flaky if the cert exists on both a readonly and
|
|
// non-readonly slot.
|
|
}
|
|
|
|
// Ensure the test root cert is present in the lists retrieved after it was
|
|
// imported, and that the info returned is as expected.
|
|
{
|
|
const NSSCertDatabase::CertInfo* test_cert_info = FindCertInfoForCert(
|
|
certs_including_nss_with_local, test_root_certs[0].get());
|
|
ASSERT_TRUE(test_cert_info);
|
|
EXPECT_TRUE(test_cert_info->web_trust_anchor);
|
|
EXPECT_FALSE(test_cert_info->untrusted);
|
|
EXPECT_FALSE(test_cert_info->device_wide);
|
|
EXPECT_FALSE(test_cert_info->hardware_backed);
|
|
EXPECT_FALSE(test_cert_info->on_read_only_slot);
|
|
}
|
|
{
|
|
const NSSCertDatabase::CertInfo* test_cert_info = FindCertInfoForCert(
|
|
certs_excluding_nss_with_local, test_root_certs[0].get());
|
|
ASSERT_TRUE(test_cert_info);
|
|
EXPECT_TRUE(test_cert_info->web_trust_anchor);
|
|
EXPECT_FALSE(test_cert_info->untrusted);
|
|
EXPECT_FALSE(test_cert_info->device_wide);
|
|
EXPECT_FALSE(test_cert_info->hardware_backed);
|
|
EXPECT_FALSE(test_cert_info->on_read_only_slot);
|
|
}
|
|
}
|
|
|
|
TEST_F(CertDatabaseNSSTest, ImportFromPKCS12WrongPassword) {
|
|
std::string pkcs12_data = ReadTestFile("client.p12");
|
|
|
|
EXPECT_EQ(
|
|
ERR_PKCS12_IMPORT_BAD_PASSWORD,
|
|
cert_db_->ImportFromPKCS12(GetPublicSlot(), pkcs12_data, std::u16string(),
|
|
true, // is_extractable
|
|
nullptr));
|
|
|
|
// Test db should still be empty.
|
|
EXPECT_EQ(0U, ListCerts().size());
|
|
}
|
|
|
|
TEST_F(CertDatabaseNSSTest, ImportFromPKCS12AsExtractableAndExportAgain) {
|
|
std::string pkcs12_data = ReadTestFile("client.p12");
|
|
|
|
EXPECT_EQ(OK,
|
|
cert_db_->ImportFromPKCS12(GetPublicSlot(), pkcs12_data, u"12345",
|
|
true, // is_extractable
|
|
nullptr));
|
|
|
|
ScopedCERTCertificateList cert_list = ListCerts();
|
|
ASSERT_EQ(1U, cert_list.size());
|
|
EXPECT_EQ("testusercert", GetSubjectCN(cert_list[0].get()));
|
|
|
|
// TODO(mattm): move export test to separate test case?
|
|
std::string exported_data;
|
|
EXPECT_EQ(1,
|
|
cert_db_->ExportToPKCS12(cert_list, u"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(GetPublicSlot(), pkcs12_data, u"12345",
|
|
true, // is_extractable
|
|
nullptr));
|
|
EXPECT_EQ(1U, ListCerts().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(GetPublicSlot(), pkcs12_data, u"12345",
|
|
true, // is_extractable
|
|
nullptr));
|
|
EXPECT_EQ(1U, ListCerts().size());
|
|
}
|
|
|
|
TEST_F(CertDatabaseNSSTest, ImportFromPKCS12AsUnextractableAndExportAgain) {
|
|
std::string pkcs12_data = ReadTestFile("client.p12");
|
|
|
|
EXPECT_EQ(OK,
|
|
cert_db_->ImportFromPKCS12(GetPublicSlot(), pkcs12_data, u"12345",
|
|
false, // is_extractable
|
|
nullptr));
|
|
|
|
ScopedCERTCertificateList cert_list = ListCerts();
|
|
ASSERT_EQ(1U, cert_list.size());
|
|
EXPECT_EQ("testusercert", GetSubjectCN(cert_list[0].get()));
|
|
|
|
std::string exported_data;
|
|
EXPECT_EQ(0,
|
|
cert_db_->ExportToPKCS12(cert_list, u"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(GetPublicSlot(), pkcs12_data, u"12345",
|
|
true, // is_extractable
|
|
nullptr));
|
|
|
|
ScopedCERTCertificateList cert_list = ListCerts();
|
|
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(GetPublicSlot(), pkcs12_data, u"12345",
|
|
false, // is_extractable
|
|
nullptr));
|
|
|
|
cert_list = ListCerts();
|
|
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, u"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(GetPublicSlot(), pkcs12_data, std::u16string(),
|
|
true, // is_extractable
|
|
nullptr));
|
|
|
|
// Test db should still be empty.
|
|
EXPECT_EQ(0U, ListCerts().size());
|
|
}
|
|
|
|
TEST_F(CertDatabaseNSSTest, ImportFromPKCS12EmptyPassword) {
|
|
std::string pkcs12_data = ReadTestFile("client-empty-password.p12");
|
|
|
|
EXPECT_EQ(OK, cert_db_->ImportFromPKCS12(GetPublicSlot(), pkcs12_data,
|
|
std::u16string(),
|
|
true, // is_extractable
|
|
nullptr));
|
|
EXPECT_EQ(1U, ListCerts().size());
|
|
}
|
|
|
|
TEST_F(CertDatabaseNSSTest, ImportFromPKCS12NullPassword) {
|
|
std::string pkcs12_data = ReadTestFile("client-null-password.p12");
|
|
|
|
EXPECT_EQ(OK, cert_db_->ImportFromPKCS12(GetPublicSlot(), pkcs12_data,
|
|
std::u16string(),
|
|
true, // is_extractable
|
|
nullptr));
|
|
EXPECT_EQ(1U, ListCerts().size());
|
|
}
|
|
|
|
TEST_F(CertDatabaseNSSTest, ImportCACert_SSLTrust) {
|
|
ScopedCERTCertificateList certs = CreateCERTCertificateListFromFile(
|
|
GetTestCertsDirectory(), "root_ca_cert.pem",
|
|
X509Certificate::FORMAT_AUTO);
|
|
ASSERT_EQ(1U, certs.size());
|
|
EXPECT_FALSE(GetCertIsPerm(certs[0].get()));
|
|
|
|
// Import it.
|
|
NSSCertDatabase::ImportCertFailureList failed;
|
|
EXPECT_TRUE(cert_db_->ImportCACerts(certs, NSSCertDatabase::TRUSTED_SSL,
|
|
&failed));
|
|
|
|
EXPECT_EQ(0U, failed.size());
|
|
|
|
ScopedCERTCertificateList cert_list = ListCerts();
|
|
ASSERT_EQ(1U, cert_list.size());
|
|
CERTCertificate* cert = cert_list[0].get();
|
|
EXPECT_EQ("Test Root CA", GetSubjectCN(cert));
|
|
|
|
EXPECT_EQ(NSSCertDatabase::TRUSTED_SSL,
|
|
cert_db_->GetCertTrust(cert, CA_CERT));
|
|
|
|
EXPECT_EQ(
|
|
unsigned(CERTDB_VALID_CA | CERTDB_TRUSTED_CA | CERTDB_TRUSTED_CLIENT_CA),
|
|
cert->trust->sslFlags);
|
|
EXPECT_EQ(unsigned(CERTDB_VALID_CA), cert->trust->emailFlags);
|
|
EXPECT_EQ(unsigned(CERTDB_VALID_CA), cert->trust->objectSigningFlags);
|
|
}
|
|
|
|
TEST_F(CertDatabaseNSSTest, ImportCACert_EmailTrust) {
|
|
ScopedCERTCertificateList certs = CreateCERTCertificateListFromFile(
|
|
GetTestCertsDirectory(), "root_ca_cert.pem",
|
|
X509Certificate::FORMAT_AUTO);
|
|
ASSERT_EQ(1U, certs.size());
|
|
EXPECT_FALSE(GetCertIsPerm(certs[0].get()));
|
|
|
|
// Import it.
|
|
NSSCertDatabase::ImportCertFailureList failed;
|
|
EXPECT_TRUE(cert_db_->ImportCACerts(certs, NSSCertDatabase::TRUSTED_EMAIL,
|
|
&failed));
|
|
|
|
EXPECT_EQ(0U, failed.size());
|
|
|
|
ScopedCERTCertificateList cert_list = ListCerts();
|
|
ASSERT_EQ(1U, cert_list.size());
|
|
CERTCertificate* cert = cert_list[0].get();
|
|
EXPECT_EQ("Test Root CA", GetSubjectCN(cert));
|
|
|
|
EXPECT_EQ(NSSCertDatabase::TRUSTED_EMAIL,
|
|
cert_db_->GetCertTrust(cert, CA_CERT));
|
|
|
|
EXPECT_EQ(unsigned(CERTDB_VALID_CA), cert->trust->sslFlags);
|
|
EXPECT_EQ(
|
|
unsigned(CERTDB_VALID_CA | CERTDB_TRUSTED_CA | CERTDB_TRUSTED_CLIENT_CA),
|
|
cert->trust->emailFlags);
|
|
EXPECT_EQ(unsigned(CERTDB_VALID_CA), cert->trust->objectSigningFlags);
|
|
}
|
|
|
|
TEST_F(CertDatabaseNSSTest, ImportCACert_ObjSignTrust) {
|
|
ScopedCERTCertificateList certs = CreateCERTCertificateListFromFile(
|
|
GetTestCertsDirectory(), "root_ca_cert.pem",
|
|
X509Certificate::FORMAT_AUTO);
|
|
ASSERT_EQ(1U, certs.size());
|
|
EXPECT_FALSE(GetCertIsPerm(certs[0].get()));
|
|
|
|
// Import it.
|
|
NSSCertDatabase::ImportCertFailureList failed;
|
|
EXPECT_TRUE(cert_db_->ImportCACerts(certs, NSSCertDatabase::TRUSTED_OBJ_SIGN,
|
|
&failed));
|
|
|
|
EXPECT_EQ(0U, failed.size());
|
|
|
|
ScopedCERTCertificateList cert_list = ListCerts();
|
|
ASSERT_EQ(1U, cert_list.size());
|
|
CERTCertificate* cert = cert_list[0].get();
|
|
EXPECT_EQ("Test Root CA", GetSubjectCN(cert));
|
|
|
|
EXPECT_EQ(NSSCertDatabase::TRUSTED_OBJ_SIGN,
|
|
cert_db_->GetCertTrust(cert, CA_CERT));
|
|
|
|
EXPECT_EQ(unsigned(CERTDB_VALID_CA), cert->trust->sslFlags);
|
|
EXPECT_EQ(unsigned(CERTDB_VALID_CA), cert->trust->emailFlags);
|
|
EXPECT_EQ(
|
|
unsigned(CERTDB_VALID_CA | CERTDB_TRUSTED_CA | CERTDB_TRUSTED_CLIENT_CA),
|
|
cert->trust->objectSigningFlags);
|
|
}
|
|
|
|
TEST_F(CertDatabaseNSSTest, ImportCA_NotCACert) {
|
|
ScopedCERTCertificateList certs = CreateCERTCertificateListFromFile(
|
|
GetTestCertsDirectory(), "ok_cert.pem", X509Certificate::FORMAT_AUTO);
|
|
ASSERT_EQ(1U, certs.size());
|
|
EXPECT_FALSE(GetCertIsPerm(certs[0].get()));
|
|
|
|
// 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 x509_util::CryptoBufferEqual should be used.
|
|
EXPECT_EQ(certs[0], failed[0].certificate);
|
|
EXPECT_THAT(failed[0].net_error, IsError(ERR_IMPORT_CA_CERT_NOT_CA));
|
|
|
|
EXPECT_EQ(0U, ListCerts().size());
|
|
}
|
|
|
|
TEST_F(CertDatabaseNSSTest, ImportCACertHierarchy) {
|
|
ScopedCERTCertificateList certs;
|
|
ASSERT_TRUE(ReadCertIntoList("multi-root-D-by-D.pem", &certs));
|
|
ASSERT_TRUE(ReadCertIntoList("multi-root-C-by-D.pem", &certs));
|
|
ASSERT_TRUE(ReadCertIntoList("multi-root-B-by-C.pem", &certs));
|
|
ASSERT_TRUE(ReadCertIntoList("multi-root-A-by-B.pem", &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(1U, failed.size());
|
|
EXPECT_EQ("127.0.0.1", GetSubjectCN(failed[0].certificate.get()));
|
|
EXPECT_THAT(failed[0].net_error, IsError(ERR_IMPORT_CA_CERT_NOT_CA));
|
|
|
|
ScopedCERTCertificateList cert_list = ListCerts();
|
|
ASSERT_EQ(3U, cert_list.size());
|
|
EXPECT_EQ("B CA - Multi-root", GetSubjectCN(cert_list[0].get()));
|
|
EXPECT_EQ("D Root CA - Multi-root", GetSubjectCN(cert_list[1].get()));
|
|
EXPECT_EQ("C CA - Multi-root", GetSubjectCN(cert_list[2].get()));
|
|
}
|
|
|
|
TEST_F(CertDatabaseNSSTest, ImportCACertHierarchyDupeRoot) {
|
|
ScopedCERTCertificateList certs;
|
|
ASSERT_TRUE(ReadCertIntoList("multi-root-D-by-D.pem", &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());
|
|
ScopedCERTCertificateList cert_list = ListCerts();
|
|
ASSERT_EQ(1U, cert_list.size());
|
|
EXPECT_EQ("D Root CA - Multi-root", GetSubjectCN(cert_list[0].get()));
|
|
|
|
ASSERT_TRUE(ReadCertIntoList("multi-root-C-by-D.pem", &certs));
|
|
ASSERT_TRUE(ReadCertIntoList("multi-root-B-by-C.pem", &certs));
|
|
ASSERT_TRUE(ReadCertIntoList("multi-root-A-by-B.pem", &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(2U, failed.size());
|
|
EXPECT_EQ("D Root CA - Multi-root",
|
|
GetSubjectCN(failed[0].certificate.get()));
|
|
EXPECT_THAT(failed[0].net_error, IsError(ERR_IMPORT_CERT_ALREADY_EXISTS));
|
|
EXPECT_EQ("127.0.0.1", GetSubjectCN(failed[1].certificate.get()));
|
|
EXPECT_THAT(failed[1].net_error, IsError(ERR_IMPORT_CA_CERT_NOT_CA));
|
|
|
|
cert_list = ListCerts();
|
|
ASSERT_EQ(3U, cert_list.size());
|
|
EXPECT_EQ("B CA - Multi-root", GetSubjectCN(cert_list[0].get()));
|
|
EXPECT_EQ("D Root CA - Multi-root", GetSubjectCN(cert_list[1].get()));
|
|
EXPECT_EQ("C CA - Multi-root", GetSubjectCN(cert_list[2].get()));
|
|
}
|
|
|
|
TEST_F(CertDatabaseNSSTest, ImportCACertHierarchyUntrusted) {
|
|
ScopedCERTCertificateList certs;
|
|
ASSERT_TRUE(ReadCertIntoList("multi-root-D-by-D.pem", &certs));
|
|
ASSERT_TRUE(ReadCertIntoList("multi-root-C-by-D.pem", &certs));
|
|
|
|
// Import it.
|
|
NSSCertDatabase::ImportCertFailureList failed;
|
|
EXPECT_TRUE(cert_db_->ImportCACerts(certs, NSSCertDatabase::TRUST_DEFAULT,
|
|
&failed));
|
|
|
|
ASSERT_EQ(1U, failed.size());
|
|
EXPECT_EQ("C CA - Multi-root", GetSubjectCN(failed[0].certificate.get()));
|
|
// TODO(mattm): should check for net error equivalent of
|
|
// SEC_ERROR_UNTRUSTED_ISSUER
|
|
EXPECT_THAT(failed[0].net_error, IsError(ERR_FAILED));
|
|
|
|
ScopedCERTCertificateList cert_list = ListCerts();
|
|
ASSERT_EQ(1U, cert_list.size());
|
|
EXPECT_EQ("D Root CA - Multi-root", GetSubjectCN(cert_list[0].get()));
|
|
}
|
|
|
|
TEST_F(CertDatabaseNSSTest, ImportCACertHierarchyTree) {
|
|
ScopedCERTCertificateList certs;
|
|
ASSERT_TRUE(ReadCertIntoList("multi-root-E-by-E.pem", &certs));
|
|
ASSERT_TRUE(ReadCertIntoList("multi-root-C-by-E.pem", &certs));
|
|
ASSERT_TRUE(ReadCertIntoList("multi-root-F-by-E.pem", &certs));
|
|
|
|
// Import it.
|
|
NSSCertDatabase::ImportCertFailureList failed;
|
|
EXPECT_TRUE(cert_db_->ImportCACerts(
|
|
certs, NSSCertDatabase::TRUSTED_SSL | NSSCertDatabase::TRUSTED_EMAIL,
|
|
&failed));
|
|
|
|
ScopedCERTCertificateList cert_list = ListCerts();
|
|
ASSERT_EQ(3U, cert_list.size());
|
|
EXPECT_EQ("F CA - Multi-root", GetSubjectCN(cert_list[0].get()));
|
|
EXPECT_EQ("C CA - Multi-root", GetSubjectCN(cert_list[1].get()));
|
|
EXPECT_EQ("E Root CA - Multi-root", GetSubjectCN(cert_list[2].get()));
|
|
}
|
|
|
|
TEST_F(CertDatabaseNSSTest, ImportCACertNotHierarchy) {
|
|
ScopedCERTCertificateList certs = CreateCERTCertificateListFromFile(
|
|
GetTestCertsDirectory(), "root_ca_cert.pem",
|
|
X509Certificate::FORMAT_AUTO);
|
|
ASSERT_EQ(1U, certs.size());
|
|
ASSERT_TRUE(ReadCertIntoList("multi-root-F-by-E.pem", &certs));
|
|
ASSERT_TRUE(ReadCertIntoList("multi-root-C-by-E.pem", &certs));
|
|
|
|
// Import it.
|
|
NSSCertDatabase::ImportCertFailureList failed;
|
|
EXPECT_TRUE(cert_db_->ImportCACerts(
|
|
certs, NSSCertDatabase::TRUSTED_SSL | NSSCertDatabase::TRUSTED_EMAIL,
|
|
&failed));
|
|
|
|
ASSERT_EQ(2U, failed.size());
|
|
// TODO(mattm): should check for net error equivalent of
|
|
// SEC_ERROR_UNKNOWN_ISSUER
|
|
EXPECT_EQ("F CA - Multi-root", GetSubjectCN(failed[0].certificate.get()));
|
|
EXPECT_THAT(failed[0].net_error, IsError(ERR_FAILED));
|
|
EXPECT_EQ("C CA - Multi-root", GetSubjectCN(failed[1].certificate.get()));
|
|
EXPECT_THAT(failed[1].net_error, IsError(ERR_FAILED));
|
|
|
|
ScopedCERTCertificateList cert_list = ListCerts();
|
|
ASSERT_EQ(1U, cert_list.size());
|
|
EXPECT_EQ("Test Root CA", GetSubjectCN(cert_list[0].get()));
|
|
}
|
|
|
|
// Test importing a server cert + chain to the NSS DB with default trust. After
|
|
// importing, all the certs should be found in the DB and should have default
|
|
// trust flags.
|
|
TEST_F(CertDatabaseNSSTest, ImportServerCert) {
|
|
// Import the server and its chain.
|
|
ScopedCERTCertificateList certs_to_import;
|
|
ASSERT_TRUE(
|
|
ReadCertIntoList("ok_cert_by_intermediate.pem", &certs_to_import));
|
|
ASSERT_TRUE(ReadCertIntoList("intermediate_ca_cert.pem", &certs_to_import));
|
|
ASSERT_TRUE(ReadCertIntoList("root_ca_cert.pem", &certs_to_import));
|
|
|
|
NSSCertDatabase::ImportCertFailureList failed;
|
|
EXPECT_TRUE(cert_db_->ImportServerCert(
|
|
certs_to_import, NSSCertDatabase::TRUST_DEFAULT, &failed));
|
|
EXPECT_EQ(0U, failed.size());
|
|
|
|
// All the certs in the imported list should now be found in the NSS DB.
|
|
ScopedCERTCertificateList cert_list = ListCerts();
|
|
ASSERT_EQ(3U, cert_list.size());
|
|
CERTCertificate* found_server_cert = nullptr;
|
|
CERTCertificate* found_intermediate_cert = nullptr;
|
|
CERTCertificate* found_root_cert = nullptr;
|
|
for (const auto& cert : cert_list) {
|
|
if (GetSubjectCN(cert.get()) == "127.0.0.1")
|
|
found_server_cert = cert.get();
|
|
else if (GetSubjectCN(cert.get()) == "Test Intermediate CA")
|
|
found_intermediate_cert = cert.get();
|
|
else if (GetSubjectCN(cert.get()) == "Test Root CA")
|
|
found_root_cert = cert.get();
|
|
}
|
|
ASSERT_TRUE(found_server_cert);
|
|
ASSERT_TRUE(found_intermediate_cert);
|
|
ASSERT_TRUE(found_root_cert);
|
|
|
|
EXPECT_EQ(NSSCertDatabase::TRUST_DEFAULT,
|
|
cert_db_->GetCertTrust(found_server_cert, SERVER_CERT));
|
|
EXPECT_EQ(0U, found_server_cert->trust->sslFlags);
|
|
EXPECT_EQ(NSSCertDatabase::TRUST_DEFAULT,
|
|
cert_db_->GetCertTrust(found_intermediate_cert, CA_CERT));
|
|
EXPECT_EQ(0U, found_intermediate_cert->trust->sslFlags);
|
|
EXPECT_EQ(NSSCertDatabase::TRUST_DEFAULT,
|
|
cert_db_->GetCertTrust(found_root_cert, CA_CERT));
|
|
EXPECT_EQ(0U, found_root_cert->trust->sslFlags);
|
|
|
|
// Verification fails, as the intermediate & CA certs are imported without
|
|
// trust.
|
|
scoped_refptr<X509Certificate> x509_found_server_cert =
|
|
x509_util::CreateX509CertificateFromCERTCertificate(found_server_cert);
|
|
ASSERT_TRUE(x509_found_server_cert);
|
|
scoped_refptr<CertVerifyProc> verify_proc(
|
|
CertVerifyProc::CreateBuiltinVerifyProc(/*cert_net_fetcher=*/nullptr,
|
|
crl_set_));
|
|
int flags = 0;
|
|
CertVerifyResult verify_result;
|
|
int error = verify_proc->Verify(
|
|
x509_found_server_cert.get(), "127.0.0.1",
|
|
/*ocsp_response=*/std::string(), /*sct_list=*/std::string(), flags,
|
|
empty_cert_list_, &verify_result, NetLogWithSource());
|
|
EXPECT_THAT(error, IsError(ERR_CERT_AUTHORITY_INVALID));
|
|
EXPECT_EQ(CERT_STATUS_AUTHORITY_INVALID, verify_result.cert_status);
|
|
}
|
|
|
|
TEST_F(CertDatabaseNSSTest, ImportServerCert_SelfSigned) {
|
|
ScopedCERTCertificateList certs;
|
|
ASSERT_TRUE(ReadCertIntoList("punycodetest.pem", &certs));
|
|
|
|
NSSCertDatabase::ImportCertFailureList failed;
|
|
EXPECT_TRUE(cert_db_->ImportServerCert(certs, NSSCertDatabase::TRUST_DEFAULT,
|
|
&failed));
|
|
|
|
EXPECT_EQ(0U, failed.size());
|
|
|
|
ScopedCERTCertificateList cert_list = ListCerts();
|
|
ASSERT_EQ(1U, cert_list.size());
|
|
CERTCertificate* puny_cert = cert_list[0].get();
|
|
|
|
EXPECT_EQ(NSSCertDatabase::TRUST_DEFAULT,
|
|
cert_db_->GetCertTrust(puny_cert, SERVER_CERT));
|
|
EXPECT_EQ(0U, puny_cert->trust->sslFlags);
|
|
|
|
scoped_refptr<X509Certificate> x509_puny_cert =
|
|
x509_util::CreateX509CertificateFromCERTCertificate(puny_cert);
|
|
ASSERT_TRUE(x509_puny_cert);
|
|
scoped_refptr<CertVerifyProc> verify_proc(
|
|
CertVerifyProc::CreateBuiltinVerifyProc(/*cert_net_fetcher=*/nullptr,
|
|
crl_set_));
|
|
int flags = 0;
|
|
CertVerifyResult verify_result;
|
|
int error = verify_proc->Verify(
|
|
x509_puny_cert.get(), "xn--wgv71a119e.com",
|
|
/*ocsp_response=*/std::string(), /*sct_list=*/std::string(), flags,
|
|
empty_cert_list_, &verify_result, NetLogWithSource());
|
|
EXPECT_THAT(error, IsError(ERR_CERT_AUTHORITY_INVALID));
|
|
EXPECT_EQ(CERT_STATUS_AUTHORITY_INVALID, verify_result.cert_status);
|
|
}
|
|
|
|
TEST_F(CertDatabaseNSSTest, ImportServerCert_SelfSigned_Trusted) {
|
|
ScopedCERTCertificateList certs;
|
|
ASSERT_TRUE(ReadCertIntoList("punycodetest.pem", &certs));
|
|
|
|
NSSCertDatabase::ImportCertFailureList failed;
|
|
EXPECT_TRUE(cert_db_->ImportServerCert(certs, NSSCertDatabase::TRUSTED_SSL,
|
|
&failed));
|
|
|
|
EXPECT_EQ(0U, failed.size());
|
|
|
|
ScopedCERTCertificateList cert_list = ListCerts();
|
|
ASSERT_EQ(1U, cert_list.size());
|
|
CERTCertificate* puny_cert = cert_list[0].get();
|
|
|
|
EXPECT_EQ(NSSCertDatabase::TRUSTED_SSL,
|
|
cert_db_->GetCertTrust(puny_cert, SERVER_CERT));
|
|
EXPECT_EQ(unsigned(CERTDB_TRUSTED | CERTDB_TERMINAL_RECORD),
|
|
puny_cert->trust->sslFlags);
|
|
|
|
scoped_refptr<X509Certificate> x509_puny_cert =
|
|
x509_util::CreateX509CertificateFromCERTCertificate(puny_cert);
|
|
ASSERT_TRUE(x509_puny_cert);
|
|
scoped_refptr<CertVerifyProc> verify_proc(
|
|
CertVerifyProc::CreateBuiltinVerifyProc(/*cert_net_fetcher=*/nullptr,
|
|
crl_set_));
|
|
int flags = 0;
|
|
CertVerifyResult verify_result;
|
|
int error = verify_proc->Verify(
|
|
x509_puny_cert.get(), "xn--wgv71a119e.com",
|
|
/*ocsp_response=*/std::string(), /*sct_list=*/std::string(), flags,
|
|
empty_cert_list_, &verify_result, NetLogWithSource());
|
|
if (base::FeatureList::IsEnabled(features::kTrustStoreTrustedLeafSupport)) {
|
|
EXPECT_THAT(error, IsOk());
|
|
EXPECT_EQ(0U, verify_result.cert_status);
|
|
} else {
|
|
EXPECT_THAT(error, IsError(ERR_CERT_AUTHORITY_INVALID));
|
|
EXPECT_EQ(CERT_STATUS_AUTHORITY_INVALID, verify_result.cert_status);
|
|
}
|
|
}
|
|
|
|
TEST_F(CertDatabaseNSSTest, ImportCaAndServerCert) {
|
|
ScopedCERTCertificateList ca_certs = CreateCERTCertificateListFromFile(
|
|
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());
|
|
|
|
ScopedCERTCertificateList certs = CreateCERTCertificateListFromFile(
|
|
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<X509Certificate> x509_server_cert =
|
|
x509_util::CreateX509CertificateFromCERTCertificate(certs[0].get());
|
|
ASSERT_TRUE(x509_server_cert);
|
|
scoped_refptr<CertVerifyProc> verify_proc(
|
|
CertVerifyProc::CreateBuiltinVerifyProc(/*cert_net_fetcher=*/nullptr,
|
|
crl_set_));
|
|
int flags = 0;
|
|
CertVerifyResult verify_result;
|
|
int error = verify_proc->Verify(
|
|
x509_server_cert.get(), "127.0.0.1",
|
|
/*ocsp_response=*/std::string(), /*sct_list=*/std::string(), flags,
|
|
empty_cert_list_, &verify_result, NetLogWithSource());
|
|
EXPECT_THAT(error, IsOk());
|
|
EXPECT_EQ(0U, verify_result.cert_status);
|
|
}
|
|
|
|
TEST_F(CertDatabaseNSSTest, ImportCaAndServerCert_DistrustServer) {
|
|
ScopedCERTCertificateList ca_certs = CreateCERTCertificateListFromFile(
|
|
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());
|
|
|
|
ScopedCERTCertificateList certs = CreateCERTCertificateListFromFile(
|
|
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]->trust->sslFlags);
|
|
|
|
// Server cert should fail to verify.
|
|
scoped_refptr<X509Certificate> x509_server_cert =
|
|
x509_util::CreateX509CertificateFromCERTCertificate(certs[0].get());
|
|
ASSERT_TRUE(x509_server_cert);
|
|
scoped_refptr<CertVerifyProc> verify_proc(
|
|
CertVerifyProc::CreateBuiltinVerifyProc(/*cert_net_fetcher=*/nullptr,
|
|
crl_set_));
|
|
int flags = 0;
|
|
CertVerifyResult verify_result;
|
|
int error = verify_proc->Verify(
|
|
x509_server_cert.get(), "127.0.0.1",
|
|
/*ocsp_response=*/std::string(), /*sct_list=*/std::string(), flags,
|
|
empty_cert_list_, &verify_result, NetLogWithSource());
|
|
EXPECT_THAT(error, IsError(ERR_CERT_AUTHORITY_INVALID));
|
|
EXPECT_EQ(CERT_STATUS_AUTHORITY_INVALID, verify_result.cert_status);
|
|
}
|
|
|
|
TEST_F(CertDatabaseNSSTest, TrustIntermediateCa) {
|
|
ScopedCERTCertificateList ca_certs = CreateCERTCertificateListFromFile(
|
|
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());
|
|
|
|
ScopedCERTCertificateList intermediate_certs =
|
|
CreateCERTCertificateListFromFile(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());
|
|
|
|
ScopedCERTCertificateList certs = CreateCERTCertificateListFromFile(
|
|
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<X509Certificate> x509_server_cert =
|
|
x509_util::CreateX509CertificateFromCERTCertificate(certs[0].get());
|
|
ASSERT_TRUE(x509_server_cert);
|
|
scoped_refptr<CertVerifyProc> verify_proc(
|
|
CertVerifyProc::CreateBuiltinVerifyProc(/*cert_net_fetcher=*/nullptr,
|
|
crl_set_));
|
|
int flags = 0;
|
|
CertVerifyResult verify_result;
|
|
int error = verify_proc->Verify(
|
|
x509_server_cert.get(), "127.0.0.1",
|
|
/*ocsp_response=*/std::string(), /*sct_list=*/std::string(), flags,
|
|
empty_cert_list_, &verify_result, NetLogWithSource());
|
|
EXPECT_THAT(error, IsOk());
|
|
EXPECT_EQ(0U, verify_result.cert_status);
|
|
|
|
// 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]->trust->sslFlags);
|
|
EXPECT_EQ(unsigned(CERTDB_VALID_CA), ca_certs[0]->trust->emailFlags);
|
|
EXPECT_EQ(unsigned(CERTDB_VALID_CA), ca_certs[0]->trust->objectSigningFlags);
|
|
EXPECT_EQ(unsigned(CERTDB_TERMINAL_RECORD),
|
|
intermediate_certs[0]->trust->sslFlags);
|
|
EXPECT_EQ(unsigned(CERTDB_VALID_CA),
|
|
intermediate_certs[0]->trust->emailFlags);
|
|
EXPECT_EQ(unsigned(CERTDB_VALID_CA),
|
|
intermediate_certs[0]->trust->objectSigningFlags);
|
|
|
|
// Server cert should fail to verify.
|
|
CertVerifyResult verify_result2;
|
|
error =
|
|
verify_proc->Verify(x509_server_cert.get(), "127.0.0.1",
|
|
/*ocsp_response=*/std::string(),
|
|
/*sct_list=*/std::string(), flags, empty_cert_list_,
|
|
&verify_result2, NetLogWithSource());
|
|
EXPECT_THAT(error, IsError(ERR_CERT_AUTHORITY_INVALID));
|
|
EXPECT_EQ(CERT_STATUS_AUTHORITY_INVALID, verify_result2.cert_status);
|
|
}
|
|
|
|
TEST_F(CertDatabaseNSSTest, TrustIntermediateCa2) {
|
|
NSSCertDatabase::ImportCertFailureList failed;
|
|
|
|
ScopedCERTCertificateList intermediate_certs =
|
|
CreateCERTCertificateListFromFile(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());
|
|
|
|
ScopedCERTCertificateList certs = CreateCERTCertificateListFromFile(
|
|
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<X509Certificate> x509_server_cert =
|
|
x509_util::CreateX509CertificateFromCERTCertificate(certs[0].get());
|
|
ASSERT_TRUE(x509_server_cert);
|
|
scoped_refptr<CertVerifyProc> verify_proc(
|
|
CertVerifyProc::CreateBuiltinVerifyProc(/*cert_net_fetcher=*/nullptr,
|
|
crl_set_));
|
|
int flags = 0;
|
|
CertVerifyResult verify_result;
|
|
int error = verify_proc->Verify(
|
|
x509_server_cert.get(), "127.0.0.1",
|
|
/*ocsp_response=*/std::string(), /*sct_list=*/std::string(), flags,
|
|
empty_cert_list_, &verify_result, NetLogWithSource());
|
|
EXPECT_THAT(error, IsOk());
|
|
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(x509_server_cert.get(), "127.0.0.1",
|
|
/*ocsp_response=*/std::string(),
|
|
/*sct_list=*/std::string(), flags, empty_cert_list_,
|
|
&verify_result2, NetLogWithSource());
|
|
EXPECT_THAT(error, IsError(ERR_CERT_AUTHORITY_INVALID));
|
|
EXPECT_EQ(CERT_STATUS_AUTHORITY_INVALID, verify_result2.cert_status);
|
|
}
|
|
|
|
TEST_F(CertDatabaseNSSTest, TrustIntermediateCa3) {
|
|
NSSCertDatabase::ImportCertFailureList failed;
|
|
|
|
ScopedCERTCertificateList ca_certs = CreateCERTCertificateListFromFile(
|
|
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());
|
|
|
|
ScopedCERTCertificateList intermediate_certs =
|
|
CreateCERTCertificateListFromFile(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());
|
|
|
|
ScopedCERTCertificateList certs = CreateCERTCertificateListFromFile(
|
|
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<X509Certificate> x509_server_cert =
|
|
x509_util::CreateX509CertificateFromCERTCertificate(certs[0].get());
|
|
ASSERT_TRUE(x509_server_cert);
|
|
scoped_refptr<CertVerifyProc> verify_proc(
|
|
CertVerifyProc::CreateBuiltinVerifyProc(/*cert_net_fetcher=*/nullptr,
|
|
crl_set_));
|
|
int flags = 0;
|
|
CertVerifyResult verify_result;
|
|
int error = verify_proc->Verify(
|
|
x509_server_cert.get(), "127.0.0.1",
|
|
/*ocsp_response=*/std::string(), /*sct_list=*/std::string(), flags,
|
|
empty_cert_list_, &verify_result, NetLogWithSource());
|
|
EXPECT_THAT(error, IsOk());
|
|
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(x509_server_cert.get(), "127.0.0.1",
|
|
/*ocsp_response=*/std::string(),
|
|
/*sct_list=*/std::string(), flags, empty_cert_list_,
|
|
&verify_result2, NetLogWithSource());
|
|
EXPECT_THAT(error, IsError(ERR_CERT_AUTHORITY_INVALID));
|
|
EXPECT_EQ(CERT_STATUS_AUTHORITY_INVALID, verify_result2.cert_status);
|
|
}
|
|
|
|
TEST_F(CertDatabaseNSSTest, TrustIntermediateCa4) {
|
|
NSSCertDatabase::ImportCertFailureList failed;
|
|
|
|
ScopedCERTCertificateList ca_certs = CreateCERTCertificateListFromFile(
|
|
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());
|
|
|
|
ScopedCERTCertificateList intermediate_certs =
|
|
CreateCERTCertificateListFromFile(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());
|
|
|
|
ScopedCERTCertificateList certs = CreateCERTCertificateListFromFile(
|
|
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<X509Certificate> x509_server_cert =
|
|
x509_util::CreateX509CertificateFromCERTCertificate(certs[0].get());
|
|
ASSERT_TRUE(x509_server_cert);
|
|
scoped_refptr<CertVerifyProc> verify_proc(
|
|
CertVerifyProc::CreateBuiltinVerifyProc(/*cert_net_fetcher=*/nullptr,
|
|
crl_set_));
|
|
int flags = 0;
|
|
CertVerifyResult verify_result;
|
|
int error = verify_proc->Verify(
|
|
x509_server_cert.get(), "127.0.0.1",
|
|
/*ocsp_response=*/std::string(), /*sct_list=*/std::string(), flags,
|
|
empty_cert_list_, &verify_result, NetLogWithSource());
|
|
EXPECT_THAT(error, IsError(ERR_CERT_AUTHORITY_INVALID));
|
|
EXPECT_EQ(CERT_STATUS_AUTHORITY_INVALID, 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(x509_server_cert.get(), "127.0.0.1",
|
|
/*ocsp_response=*/std::string(),
|
|
/*sct_list=*/std::string(), flags, empty_cert_list_,
|
|
&verify_result2, NetLogWithSource());
|
|
EXPECT_THAT(error, IsOk());
|
|
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) {
|
|
ScopedCERTCertificateList certs = CreateCERTCertificateListFromFile(
|
|
GetTestCertsDirectory(), "duplicate_cn_1.pem",
|
|
X509Certificate::FORMAT_AUTO);
|
|
ASSERT_EQ(1U, certs.size());
|
|
|
|
EXPECT_EQ(0U, ListCerts().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));
|
|
|
|
ScopedCERTCertificateList new_certs = ListCerts();
|
|
ASSERT_EQ(1U, new_certs.size());
|
|
|
|
// Now attempt to import a different certificate with the same common name.
|
|
ScopedCERTCertificateList certs2 = CreateCERTCertificateListFromFile(
|
|
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 = ListCerts();
|
|
ASSERT_EQ(2U, new_certs.size());
|
|
EXPECT_STRNE(new_certs[0]->nickname, new_certs[1]->nickname);
|
|
}
|
|
|
|
} // namespace net
|