1 // Copyright 2017 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "net/cert/x509_util_apple.h"
6
7 #include <string_view>
8
9 #include "base/apple/foundation_util.h"
10 #include "base/containers/span.h"
11 #include "build/build_config.h"
12 #include "net/cert/x509_certificate.h"
13 #include "net/cert/x509_util.h"
14 #include "net/test/cert_test_util.h"
15 #include "net/test/test_data_directory.h"
16 #include "testing/gtest/include/gtest/gtest.h"
17
18 namespace net {
19
20 namespace x509_util {
21
22 namespace {
23
BytesForSecCert(SecCertificateRef sec_cert)24 std::string BytesForSecCert(SecCertificateRef sec_cert) {
25 std::string result;
26 base::apple::ScopedCFTypeRef<CFDataRef> der_data(
27 SecCertificateCopyData(sec_cert));
28 if (!der_data) {
29 ADD_FAILURE();
30 return result;
31 }
32
33 return std::string(
34 base::as_string_view(base::apple::CFDataToSpan(der_data.get())));
35 }
36
BytesForSecCert(const void * sec_cert)37 std::string BytesForSecCert(const void* sec_cert) {
38 return BytesForSecCert(
39 reinterpret_cast<SecCertificateRef>(const_cast<void*>(sec_cert)));
40 }
41
42 } // namespace
43
TEST(X509UtilTest,CreateSecCertificateArrayForX509Certificate)44 TEST(X509UtilTest, CreateSecCertificateArrayForX509Certificate) {
45 scoped_refptr<X509Certificate> cert = CreateCertificateChainFromFile(
46 GetTestCertsDirectory(), "multi-root-chain1.pem",
47 X509Certificate::FORMAT_PEM_CERT_SEQUENCE);
48 ASSERT_TRUE(cert);
49 EXPECT_EQ(3U, cert->intermediate_buffers().size());
50
51 base::apple::ScopedCFTypeRef<CFMutableArrayRef> sec_certs(
52 CreateSecCertificateArrayForX509Certificate(cert.get()));
53 ASSERT_TRUE(sec_certs);
54 ASSERT_EQ(4, CFArrayGetCount(sec_certs.get()));
55 for (int i = 0; i < 4; ++i)
56 ASSERT_TRUE(CFArrayGetValueAtIndex(sec_certs.get(), i));
57
58 EXPECT_EQ(x509_util::CryptoBufferAsStringPiece(cert->cert_buffer()),
59 BytesForSecCert(CFArrayGetValueAtIndex(sec_certs.get(), 0)));
60 EXPECT_EQ(x509_util::CryptoBufferAsStringPiece(
61 cert->intermediate_buffers()[0].get()),
62 BytesForSecCert(CFArrayGetValueAtIndex(sec_certs.get(), 1)));
63 EXPECT_EQ(x509_util::CryptoBufferAsStringPiece(
64 cert->intermediate_buffers()[1].get()),
65 BytesForSecCert(CFArrayGetValueAtIndex(sec_certs.get(), 2)));
66 EXPECT_EQ(x509_util::CryptoBufferAsStringPiece(
67 cert->intermediate_buffers()[2].get()),
68 BytesForSecCert(CFArrayGetValueAtIndex(sec_certs.get(), 3)));
69 }
70
TEST(X509UtilTest,CreateSecCertificateArrayForX509CertificateErrors)71 TEST(X509UtilTest, CreateSecCertificateArrayForX509CertificateErrors) {
72 scoped_refptr<X509Certificate> ok_cert(
73 ImportCertFromFile(GetTestCertsDirectory(), "ok_cert.pem"));
74 ASSERT_TRUE(ok_cert);
75
76 bssl::UniquePtr<CRYPTO_BUFFER> bad_cert =
77 x509_util::CreateCryptoBuffer(std::string_view("invalid"));
78 ASSERT_TRUE(bad_cert);
79
80 scoped_refptr<X509Certificate> ok_cert2(
81 ImportCertFromFile(GetTestCertsDirectory(), "root_ca_cert.pem"));
82 ASSERT_TRUE(ok_cert);
83
84 std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediates;
85 intermediates.push_back(bssl::UpRef(bad_cert));
86 intermediates.push_back(bssl::UpRef(ok_cert2->cert_buffer()));
87 scoped_refptr<X509Certificate> cert_with_intermediates(
88 X509Certificate::CreateFromBuffer(bssl::UpRef(ok_cert->cert_buffer()),
89 std::move(intermediates)));
90 ASSERT_TRUE(cert_with_intermediates);
91 EXPECT_EQ(2U, cert_with_intermediates->intermediate_buffers().size());
92
93 // With InvalidIntermediateBehavior::kIgnore, invalid intermediate certs
94 // should be silently dropped.
95 base::apple::ScopedCFTypeRef<CFMutableArrayRef> sec_certs(
96 CreateSecCertificateArrayForX509Certificate(
97 cert_with_intermediates.get(), InvalidIntermediateBehavior::kIgnore));
98 ASSERT_TRUE(sec_certs);
99 for (int i = 0; i < CFArrayGetCount(sec_certs.get()); ++i)
100 ASSERT_TRUE(CFArrayGetValueAtIndex(sec_certs.get(), i));
101
102 if (CFArrayGetCount(sec_certs.get()) == 2) {
103 EXPECT_EQ(x509_util::CryptoBufferAsStringPiece(ok_cert->cert_buffer()),
104 BytesForSecCert(CFArrayGetValueAtIndex(sec_certs.get(), 0)));
105 EXPECT_EQ(x509_util::CryptoBufferAsStringPiece(ok_cert2->cert_buffer()),
106 BytesForSecCert(CFArrayGetValueAtIndex(sec_certs.get(), 1)));
107
108 // Normal CreateSecCertificateArrayForX509Certificate should fail with
109 // invalid certs in chain.
110 EXPECT_FALSE(CreateSecCertificateArrayForX509Certificate(
111 cert_with_intermediates.get()));
112 } else if (CFArrayGetCount(sec_certs.get()) == 3) {
113 // On older macOS versions that do lazy parsing of SecCertificates, the
114 // invalid certificate may be accepted, which is okay. The test is just
115 // verifying that *if* creating a SecCertificate from one of the
116 // intermediates fails, that cert is ignored and the other certs are still
117 // returned.
118 EXPECT_EQ(x509_util::CryptoBufferAsStringPiece(ok_cert->cert_buffer()),
119 BytesForSecCert(CFArrayGetValueAtIndex(sec_certs.get(), 0)));
120 EXPECT_EQ(x509_util::CryptoBufferAsStringPiece(bad_cert.get()),
121 BytesForSecCert(CFArrayGetValueAtIndex(sec_certs.get(), 1)));
122 EXPECT_EQ(x509_util::CryptoBufferAsStringPiece(ok_cert2->cert_buffer()),
123 BytesForSecCert(CFArrayGetValueAtIndex(sec_certs.get(), 2)));
124
125 // Normal CreateSecCertificateArrayForX509Certificate should also
126 // succeed in this case.
127 EXPECT_TRUE(CreateSecCertificateArrayForX509Certificate(
128 cert_with_intermediates.get()));
129 } else {
130 ADD_FAILURE() << "CFArrayGetCount(sec_certs.get()) = "
131 << CFArrayGetCount(sec_certs.get());
132 }
133 }
134
TEST(X509UtilTest,CreateSecCertificateFromBytesAndCreateX509CertificateFromSecCertificate)135 TEST(X509UtilTest,
136 CreateSecCertificateFromBytesAndCreateX509CertificateFromSecCertificate) {
137 CertificateList certs = CreateCertificateListFromFile(
138 GetTestCertsDirectory(), "multi-root-chain1.pem",
139 X509Certificate::FORMAT_PEM_CERT_SEQUENCE);
140 ASSERT_EQ(4u, certs.size());
141
142 std::string bytes_cert0(
143 x509_util::CryptoBufferAsStringPiece(certs[0]->cert_buffer()));
144 std::string bytes_cert1(
145 x509_util::CryptoBufferAsStringPiece(certs[1]->cert_buffer()));
146 std::string bytes_cert2(
147 x509_util::CryptoBufferAsStringPiece(certs[2]->cert_buffer()));
148 std::string bytes_cert3(
149 x509_util::CryptoBufferAsStringPiece(certs[3]->cert_buffer()));
150
151 base::apple::ScopedCFTypeRef<SecCertificateRef> sec_cert0(
152 CreateSecCertificateFromBytes(base::as_byte_span(bytes_cert0)));
153 ASSERT_TRUE(sec_cert0);
154 EXPECT_EQ(bytes_cert0, BytesForSecCert(sec_cert0.get()));
155
156 base::apple::ScopedCFTypeRef<SecCertificateRef> sec_cert1(
157 CreateSecCertificateFromBytes(base::as_byte_span(bytes_cert1)));
158 ASSERT_TRUE(sec_cert1);
159 EXPECT_EQ(bytes_cert1, BytesForSecCert(sec_cert1.get()));
160
161 base::apple::ScopedCFTypeRef<SecCertificateRef> sec_cert2(
162 CreateSecCertificateFromX509Certificate(certs[2].get()));
163 ASSERT_TRUE(sec_cert2);
164 EXPECT_EQ(bytes_cert2, BytesForSecCert(sec_cert2.get()));
165
166 base::apple::ScopedCFTypeRef<SecCertificateRef> sec_cert3(
167 CreateSecCertificateFromX509Certificate(certs[3].get()));
168 ASSERT_TRUE(sec_cert3);
169 EXPECT_EQ(bytes_cert3, BytesForSecCert(sec_cert3.get()));
170
171 scoped_refptr<X509Certificate> x509_cert_no_intermediates =
172 CreateX509CertificateFromSecCertificate(sec_cert0, {});
173 ASSERT_TRUE(x509_cert_no_intermediates);
174 EXPECT_EQ(0U, x509_cert_no_intermediates->intermediate_buffers().size());
175 EXPECT_EQ(bytes_cert0, x509_util::CryptoBufferAsStringPiece(
176 x509_cert_no_intermediates->cert_buffer()));
177
178 scoped_refptr<X509Certificate> x509_cert_one_intermediate =
179 CreateX509CertificateFromSecCertificate(sec_cert0, {sec_cert1});
180 ASSERT_TRUE(x509_cert_one_intermediate);
181 EXPECT_EQ(bytes_cert0, x509_util::CryptoBufferAsStringPiece(
182 x509_cert_one_intermediate->cert_buffer()));
183 ASSERT_EQ(1U, x509_cert_one_intermediate->intermediate_buffers().size());
184 EXPECT_EQ(bytes_cert1,
185 x509_util::CryptoBufferAsStringPiece(
186 x509_cert_one_intermediate->intermediate_buffers()[0].get()));
187
188 scoped_refptr<X509Certificate> x509_cert_two_intermediates =
189 CreateX509CertificateFromSecCertificate(sec_cert0,
190 {sec_cert1, sec_cert2});
191 ASSERT_TRUE(x509_cert_two_intermediates);
192 EXPECT_EQ(bytes_cert0, x509_util::CryptoBufferAsStringPiece(
193 x509_cert_two_intermediates->cert_buffer()));
194 ASSERT_EQ(2U, x509_cert_two_intermediates->intermediate_buffers().size());
195 EXPECT_EQ(bytes_cert1,
196 x509_util::CryptoBufferAsStringPiece(
197 x509_cert_two_intermediates->intermediate_buffers()[0].get()));
198 EXPECT_EQ(bytes_cert2,
199 x509_util::CryptoBufferAsStringPiece(
200 x509_cert_two_intermediates->intermediate_buffers()[1].get()));
201 }
202
203 } // namespace x509_util
204
205 } // namespace net
206