205 lines
8.6 KiB
C++
205 lines
8.6 KiB
C++
// 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 "net/cert/x509_util_apple.h"
|
|
|
|
#include "build/build_config.h"
|
|
#include "net/cert/x509_certificate.h"
|
|
#include "net/cert/x509_util.h"
|
|
#include "net/test/cert_test_util.h"
|
|
#include "net/test/test_data_directory.h"
|
|
#include "testing/gtest/include/gtest/gtest.h"
|
|
|
|
namespace net {
|
|
|
|
namespace x509_util {
|
|
|
|
namespace {
|
|
|
|
std::string BytesForSecCert(SecCertificateRef sec_cert) {
|
|
std::string result;
|
|
base::ScopedCFTypeRef<CFDataRef> der_data(SecCertificateCopyData(sec_cert));
|
|
if (!der_data) {
|
|
ADD_FAILURE();
|
|
return result;
|
|
}
|
|
result.assign(reinterpret_cast<const char*>(CFDataGetBytePtr(der_data)),
|
|
CFDataGetLength(der_data));
|
|
return result;
|
|
}
|
|
|
|
std::string BytesForSecCert(const void* sec_cert) {
|
|
return BytesForSecCert(
|
|
reinterpret_cast<SecCertificateRef>(const_cast<void*>(sec_cert)));
|
|
}
|
|
|
|
} // namespace
|
|
|
|
TEST(X509UtilTest, CreateSecCertificateArrayForX509Certificate) {
|
|
scoped_refptr<X509Certificate> cert = CreateCertificateChainFromFile(
|
|
GetTestCertsDirectory(), "multi-root-chain1.pem",
|
|
X509Certificate::FORMAT_PEM_CERT_SEQUENCE);
|
|
ASSERT_TRUE(cert);
|
|
EXPECT_EQ(3U, cert->intermediate_buffers().size());
|
|
|
|
base::ScopedCFTypeRef<CFMutableArrayRef> sec_certs(
|
|
CreateSecCertificateArrayForX509Certificate(cert.get()));
|
|
ASSERT_TRUE(sec_certs);
|
|
ASSERT_EQ(4, CFArrayGetCount(sec_certs.get()));
|
|
for (int i = 0; i < 4; ++i)
|
|
ASSERT_TRUE(CFArrayGetValueAtIndex(sec_certs.get(), i));
|
|
|
|
EXPECT_EQ(x509_util::CryptoBufferAsStringPiece(cert->cert_buffer()),
|
|
BytesForSecCert(CFArrayGetValueAtIndex(sec_certs.get(), 0)));
|
|
EXPECT_EQ(x509_util::CryptoBufferAsStringPiece(
|
|
cert->intermediate_buffers()[0].get()),
|
|
BytesForSecCert(CFArrayGetValueAtIndex(sec_certs.get(), 1)));
|
|
EXPECT_EQ(x509_util::CryptoBufferAsStringPiece(
|
|
cert->intermediate_buffers()[1].get()),
|
|
BytesForSecCert(CFArrayGetValueAtIndex(sec_certs.get(), 2)));
|
|
EXPECT_EQ(x509_util::CryptoBufferAsStringPiece(
|
|
cert->intermediate_buffers()[2].get()),
|
|
BytesForSecCert(CFArrayGetValueAtIndex(sec_certs.get(), 3)));
|
|
}
|
|
|
|
TEST(X509UtilTest, CreateSecCertificateArrayForX509CertificateErrors) {
|
|
scoped_refptr<X509Certificate> ok_cert(
|
|
ImportCertFromFile(GetTestCertsDirectory(), "ok_cert.pem"));
|
|
ASSERT_TRUE(ok_cert);
|
|
|
|
bssl::UniquePtr<CRYPTO_BUFFER> bad_cert =
|
|
x509_util::CreateCryptoBuffer(base::StringPiece("invalid"));
|
|
ASSERT_TRUE(bad_cert);
|
|
|
|
scoped_refptr<X509Certificate> ok_cert2(
|
|
ImportCertFromFile(GetTestCertsDirectory(), "root_ca_cert.pem"));
|
|
ASSERT_TRUE(ok_cert);
|
|
|
|
std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediates;
|
|
intermediates.push_back(bssl::UpRef(bad_cert));
|
|
intermediates.push_back(bssl::UpRef(ok_cert2->cert_buffer()));
|
|
scoped_refptr<X509Certificate> cert_with_intermediates(
|
|
X509Certificate::CreateFromBuffer(bssl::UpRef(ok_cert->cert_buffer()),
|
|
std::move(intermediates)));
|
|
ASSERT_TRUE(cert_with_intermediates);
|
|
EXPECT_EQ(2U, cert_with_intermediates->intermediate_buffers().size());
|
|
|
|
// With InvalidIntermediateBehavior::kIgnore, invalid intermediate certs
|
|
// should be silently dropped.
|
|
base::ScopedCFTypeRef<CFMutableArrayRef> sec_certs(
|
|
CreateSecCertificateArrayForX509Certificate(
|
|
cert_with_intermediates.get(), InvalidIntermediateBehavior::kIgnore));
|
|
ASSERT_TRUE(sec_certs);
|
|
for (int i = 0; i < CFArrayGetCount(sec_certs.get()); ++i)
|
|
ASSERT_TRUE(CFArrayGetValueAtIndex(sec_certs.get(), i));
|
|
|
|
if (CFArrayGetCount(sec_certs.get()) == 2) {
|
|
EXPECT_EQ(x509_util::CryptoBufferAsStringPiece(ok_cert->cert_buffer()),
|
|
BytesForSecCert(CFArrayGetValueAtIndex(sec_certs.get(), 0)));
|
|
EXPECT_EQ(x509_util::CryptoBufferAsStringPiece(ok_cert2->cert_buffer()),
|
|
BytesForSecCert(CFArrayGetValueAtIndex(sec_certs.get(), 1)));
|
|
|
|
// Normal CreateSecCertificateArrayForX509Certificate should fail with
|
|
// invalid certs in chain.
|
|
EXPECT_FALSE(CreateSecCertificateArrayForX509Certificate(
|
|
cert_with_intermediates.get()));
|
|
} else if (CFArrayGetCount(sec_certs.get()) == 3) {
|
|
// On older macOS versions that do lazy parsing of SecCertificates, the
|
|
// invalid certificate may be accepted, which is okay. The test is just
|
|
// verifying that *if* creating a SecCertificate from one of the
|
|
// intermediates fails, that cert is ignored and the other certs are still
|
|
// returned.
|
|
EXPECT_EQ(x509_util::CryptoBufferAsStringPiece(ok_cert->cert_buffer()),
|
|
BytesForSecCert(CFArrayGetValueAtIndex(sec_certs.get(), 0)));
|
|
EXPECT_EQ(x509_util::CryptoBufferAsStringPiece(bad_cert.get()),
|
|
BytesForSecCert(CFArrayGetValueAtIndex(sec_certs.get(), 1)));
|
|
EXPECT_EQ(x509_util::CryptoBufferAsStringPiece(ok_cert2->cert_buffer()),
|
|
BytesForSecCert(CFArrayGetValueAtIndex(sec_certs.get(), 2)));
|
|
|
|
// Normal CreateSecCertificateArrayForX509Certificate should also
|
|
// succeed in this case.
|
|
EXPECT_TRUE(CreateSecCertificateArrayForX509Certificate(
|
|
cert_with_intermediates.get()));
|
|
} else {
|
|
ADD_FAILURE() << "CFArrayGetCount(sec_certs.get()) = "
|
|
<< CFArrayGetCount(sec_certs.get());
|
|
}
|
|
}
|
|
|
|
TEST(X509UtilTest,
|
|
CreateSecCertificateFromBytesAndCreateX509CertificateFromSecCertificate) {
|
|
CertificateList certs = CreateCertificateListFromFile(
|
|
GetTestCertsDirectory(), "multi-root-chain1.pem",
|
|
X509Certificate::FORMAT_PEM_CERT_SEQUENCE);
|
|
ASSERT_EQ(4u, certs.size());
|
|
|
|
std::string bytes_cert0(
|
|
x509_util::CryptoBufferAsStringPiece(certs[0]->cert_buffer()));
|
|
std::string bytes_cert1(
|
|
x509_util::CryptoBufferAsStringPiece(certs[1]->cert_buffer()));
|
|
std::string bytes_cert2(
|
|
x509_util::CryptoBufferAsStringPiece(certs[2]->cert_buffer()));
|
|
std::string bytes_cert3(
|
|
x509_util::CryptoBufferAsStringPiece(certs[3]->cert_buffer()));
|
|
|
|
base::ScopedCFTypeRef<SecCertificateRef> sec_cert0(
|
|
CreateSecCertificateFromBytes(
|
|
reinterpret_cast<const uint8_t*>(bytes_cert0.data()),
|
|
bytes_cert0.length()));
|
|
ASSERT_TRUE(sec_cert0);
|
|
EXPECT_EQ(bytes_cert0, BytesForSecCert(sec_cert0));
|
|
|
|
base::ScopedCFTypeRef<SecCertificateRef> sec_cert1(
|
|
CreateSecCertificateFromBytes(
|
|
reinterpret_cast<const uint8_t*>(bytes_cert1.data()),
|
|
bytes_cert1.length()));
|
|
ASSERT_TRUE(sec_cert1);
|
|
EXPECT_EQ(bytes_cert1, BytesForSecCert(sec_cert1));
|
|
|
|
base::ScopedCFTypeRef<SecCertificateRef> sec_cert2(
|
|
CreateSecCertificateFromX509Certificate(certs[2].get()));
|
|
ASSERT_TRUE(sec_cert2);
|
|
EXPECT_EQ(bytes_cert2, BytesForSecCert(sec_cert2));
|
|
|
|
base::ScopedCFTypeRef<SecCertificateRef> sec_cert3(
|
|
CreateSecCertificateFromX509Certificate(certs[3].get()));
|
|
ASSERT_TRUE(sec_cert3);
|
|
EXPECT_EQ(bytes_cert3, BytesForSecCert(sec_cert3));
|
|
|
|
scoped_refptr<X509Certificate> x509_cert_no_intermediates =
|
|
CreateX509CertificateFromSecCertificate(sec_cert0, {});
|
|
ASSERT_TRUE(x509_cert_no_intermediates);
|
|
EXPECT_EQ(0U, x509_cert_no_intermediates->intermediate_buffers().size());
|
|
EXPECT_EQ(bytes_cert0, x509_util::CryptoBufferAsStringPiece(
|
|
x509_cert_no_intermediates->cert_buffer()));
|
|
|
|
scoped_refptr<X509Certificate> x509_cert_one_intermediate =
|
|
CreateX509CertificateFromSecCertificate(sec_cert0, {sec_cert1});
|
|
ASSERT_TRUE(x509_cert_one_intermediate);
|
|
EXPECT_EQ(bytes_cert0, x509_util::CryptoBufferAsStringPiece(
|
|
x509_cert_one_intermediate->cert_buffer()));
|
|
ASSERT_EQ(1U, x509_cert_one_intermediate->intermediate_buffers().size());
|
|
EXPECT_EQ(bytes_cert1,
|
|
x509_util::CryptoBufferAsStringPiece(
|
|
x509_cert_one_intermediate->intermediate_buffers()[0].get()));
|
|
|
|
scoped_refptr<X509Certificate> x509_cert_two_intermediates =
|
|
CreateX509CertificateFromSecCertificate(sec_cert0,
|
|
{sec_cert1, sec_cert2});
|
|
ASSERT_TRUE(x509_cert_two_intermediates);
|
|
EXPECT_EQ(bytes_cert0, x509_util::CryptoBufferAsStringPiece(
|
|
x509_cert_two_intermediates->cert_buffer()));
|
|
ASSERT_EQ(2U, x509_cert_two_intermediates->intermediate_buffers().size());
|
|
EXPECT_EQ(bytes_cert1,
|
|
x509_util::CryptoBufferAsStringPiece(
|
|
x509_cert_two_intermediates->intermediate_buffers()[0].get()));
|
|
EXPECT_EQ(bytes_cert2,
|
|
x509_util::CryptoBufferAsStringPiece(
|
|
x509_cert_two_intermediates->intermediate_buffers()[1].get()));
|
|
}
|
|
|
|
} // namespace x509_util
|
|
|
|
} // namespace net
|