1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131
|
// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/net/nss_temp_certs_cache_chromeos.h"
#include <cert.h>
#include <certdb.h>
#include <secitem.h>
#include <string>
#include <vector>
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "net/cert/x509_certificate.h"
#include "net/test/test_data_directory.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/boringssl/src/pki/cert_errors.h"
#include "third_party/boringssl/src/pki/input.h"
#include "third_party/boringssl/src/pki/parse_certificate.h"
#include "third_party/boringssl/src/pki/pem.h"
namespace network {
namespace {
class NSSTempCertsCacheChromeOSTest : public testing::Test {
public:
NSSTempCertsCacheChromeOSTest() = default;
NSSTempCertsCacheChromeOSTest(const NSSTempCertsCacheChromeOSTest&) = delete;
NSSTempCertsCacheChromeOSTest& operator=(
const NSSTempCertsCacheChromeOSTest&) = delete;
~NSSTempCertsCacheChromeOSTest() override = default;
protected:
// Checks if the certificate stored in |pem_cert_file| can be found in the
// default NSS certificate database using CERT_FindCertByName.
// Stores the result in *|out_available|.
// Note: This funcion uses ASSERT_ macros, so the caller must verify for
// failures after it returns.
void CheckIsCertificateAvailable(const base::FilePath& pem_cert_file,
bool* out_available) {
std::string cert_contents_buffer;
bssl::der::Input subject;
ASSERT_NO_FATAL_FAILURE(GetCertificateSubjectDN(
pem_cert_file, &cert_contents_buffer, &subject));
SECItem subject_item;
subject_item.len = subject.size();
subject_item.data = const_cast<unsigned char*>(subject.data());
net::ScopedCERTCertificate found_cert(
CERT_FindCertByName(CERT_GetDefaultCertDB(), &subject_item));
*out_available = static_cast<bool>(found_cert);
}
// Determines the subject DN of the certificate stored in
// |pem_cert_file|. Stores the result in *|out_subject|.
// The der::Input data structure contains unowned pointers into the
// certificate data buffer. The caller must pass a buffer in
// |cert_contents_buffer| and ensure to only use *|out_subject| while
// *|cert_contents_buffer| is in scope.
// Note: This function uses ASSERT_ macros, so the caller must verify for
// failures after it returns.
void GetCertificateSubjectDN(const base::FilePath& pem_cert_file,
std::string* cert_contents_buffer,
bssl::der::Input* out_subject) {
std::string file_data;
ASSERT_TRUE(base::ReadFileToString(pem_cert_file, &file_data));
std::vector<std::string> pem_headers;
pem_headers.push_back("CERTIFICATE");
bssl::PEMTokenizer pem_tokenizer(file_data, pem_headers);
ASSERT_TRUE(pem_tokenizer.GetNext());
*cert_contents_buffer = pem_tokenizer.data();
// Parsing the certificate.
bssl::der::Input tbs_certificate_tlv;
bssl::der::Input signature_algorithm_tlv;
bssl::der::BitString signature_value;
bssl::CertErrors errors;
ASSERT_TRUE(bssl::ParseCertificate(
bssl::der::Input(*cert_contents_buffer), &tbs_certificate_tlv,
&signature_algorithm_tlv, &signature_value, &errors));
bssl::ParsedTbsCertificate tbs;
bssl::ParseCertificateOptions options;
options.allow_invalid_serial_numbers = true;
ASSERT_TRUE(
bssl::ParseTbsCertificate(tbs_certificate_tlv, options, &tbs, nullptr));
*out_subject = tbs.subject_tlv;
}
};
// Checks that a certificate made available through the
// NSSTempCertsCacheChromeOS can be found by NSS. We specifically check for
// lookup through the CERT_FindCertByName function, as this is what is used in
// client certificate matching (see MatchClientCertificateIssuers in
// net/third_party/nss/ssl/cmpcert.cc). Additionally, checks that the
// certificate is not available after the NSSTempCertsCacheChromeOS goes out of
// scope.
TEST_F(NSSTempCertsCacheChromeOSTest, CertMadeAvailable) {
base::FilePath cert_file_path =
net::GetTestCertsDirectory().AppendASCII("client_1_ca.pem");
{
std::string x509_authority_cert;
ASSERT_TRUE(base::ReadFileToString(cert_file_path, &x509_authority_cert));
net::CertificateList x509_authority_certs =
net::X509Certificate::CreateCertificateListFromBytes(
base::as_byte_span(x509_authority_cert),
net::X509Certificate::Format::FORMAT_AUTO);
NSSTempCertsCacheChromeOS cache(x509_authority_certs);
bool cert_available = false;
ASSERT_NO_FATAL_FAILURE(
CheckIsCertificateAvailable(cert_file_path, &cert_available));
EXPECT_TRUE(cert_available);
}
bool cert_available_no_cache = true;
ASSERT_NO_FATAL_FAILURE(
CheckIsCertificateAvailable(cert_file_path, &cert_available_no_cache));
EXPECT_FALSE(cert_available_no_cache);
}
} // namespace
} // namespace network
|