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_nss.h"
6
7 #include "base/files/file_path.h"
8 #include "base/files/file_util.h"
9 #include "base/time/time.h"
10 #include "net/cert/scoped_nss_types.h"
11 #include "net/cert/x509_certificate.h"
12 #include "net/cert/x509_util.h"
13 #include "net/test/cert_test_util.h"
14 #include "net/test/test_certificate_data.h"
15 #include "net/test/test_data_directory.h"
16 #include "testing/gtest/include/gtest/gtest.h"
17
18 namespace net {
19
20 namespace {
21
BytesForNSSCert(CERTCertificate * cert)22 std::string BytesForNSSCert(CERTCertificate* cert) {
23 std::string der_encoded;
24 if (!x509_util::GetDEREncoded(cert, &der_encoded))
25 ADD_FAILURE();
26 return der_encoded;
27 }
28
29 } // namespace
30
TEST(X509UtilNSSTest,IsSameCertificate)31 TEST(X509UtilNSSTest, IsSameCertificate) {
32 ScopedCERTCertificate google_nss_cert(
33 x509_util::CreateCERTCertificateFromBytes(google_der));
34 ASSERT_TRUE(google_nss_cert);
35
36 ScopedCERTCertificate google_nss_cert2(
37 x509_util::CreateCERTCertificateFromBytes(google_der));
38 ASSERT_TRUE(google_nss_cert2);
39
40 ScopedCERTCertificate webkit_nss_cert(
41 x509_util::CreateCERTCertificateFromBytes(webkit_der));
42 ASSERT_TRUE(webkit_nss_cert);
43
44 scoped_refptr<X509Certificate> google_x509_cert(
45 X509Certificate::CreateFromBytes(google_der));
46 ASSERT_TRUE(google_x509_cert);
47
48 scoped_refptr<X509Certificate> webkit_x509_cert(
49 X509Certificate::CreateFromBytes(webkit_der));
50 ASSERT_TRUE(webkit_x509_cert);
51
52 EXPECT_TRUE(x509_util::IsSameCertificate(google_nss_cert.get(),
53 google_nss_cert.get()));
54 EXPECT_TRUE(x509_util::IsSameCertificate(google_nss_cert.get(),
55 google_nss_cert2.get()));
56 EXPECT_TRUE(x509_util::IsSameCertificate(google_nss_cert.get(),
57 google_x509_cert.get()));
58 EXPECT_TRUE(x509_util::IsSameCertificate(google_x509_cert.get(),
59 google_nss_cert.get()));
60
61 EXPECT_TRUE(x509_util::IsSameCertificate(webkit_nss_cert.get(),
62 webkit_nss_cert.get()));
63 EXPECT_TRUE(x509_util::IsSameCertificate(webkit_nss_cert.get(),
64 webkit_x509_cert.get()));
65 EXPECT_TRUE(x509_util::IsSameCertificate(webkit_x509_cert.get(),
66 webkit_nss_cert.get()));
67
68 EXPECT_FALSE(x509_util::IsSameCertificate(google_nss_cert.get(),
69 webkit_nss_cert.get()));
70 EXPECT_FALSE(x509_util::IsSameCertificate(google_nss_cert.get(),
71 webkit_x509_cert.get()));
72 EXPECT_FALSE(x509_util::IsSameCertificate(google_x509_cert.get(),
73 webkit_nss_cert.get()));
74 }
75
TEST(X509UtilNSSTest,CreateCERTCertificateFromBytes)76 TEST(X509UtilNSSTest, CreateCERTCertificateFromBytes) {
77 ScopedCERTCertificate google_cert(
78 x509_util::CreateCERTCertificateFromBytes(google_der));
79 ASSERT_TRUE(google_cert);
80 EXPECT_STREQ(
81 "CN=www.google.com,O=Google Inc,L=Mountain View,ST=California,C=US",
82 google_cert->subjectName);
83 }
84
TEST(X509UtilNSSTest,CreateCERTCertificateFromBytesGarbage)85 TEST(X509UtilNSSTest, CreateCERTCertificateFromBytesGarbage) {
86 EXPECT_EQ(nullptr, x509_util::CreateCERTCertificateFromBytes(
87 base::span<const uint8_t>()));
88
89 static const uint8_t garbage_data[] = "garbage";
90 EXPECT_EQ(nullptr, x509_util::CreateCERTCertificateFromBytes(garbage_data));
91 }
92
TEST(X509UtilNSSTest,CreateCERTCertificateFromX509Certificate)93 TEST(X509UtilNSSTest, CreateCERTCertificateFromX509Certificate) {
94 scoped_refptr<X509Certificate> x509_cert =
95 ImportCertFromFile(GetTestCertsDirectory(), "ok_cert.pem");
96 ASSERT_TRUE(x509_cert);
97 ScopedCERTCertificate nss_cert =
98 x509_util::CreateCERTCertificateFromX509Certificate(x509_cert.get());
99 ASSERT_TRUE(nss_cert);
100 EXPECT_STREQ("CN=127.0.0.1,O=Test CA,L=Mountain View,ST=California,C=US",
101 nss_cert->subjectName);
102 }
103
TEST(X509UtilNSSTest,CreateCERTCertificateListFromX509Certificate)104 TEST(X509UtilNSSTest, CreateCERTCertificateListFromX509Certificate) {
105 scoped_refptr<X509Certificate> x509_cert = CreateCertificateChainFromFile(
106 GetTestCertsDirectory(), "multi-root-chain1.pem",
107 X509Certificate::FORMAT_PEM_CERT_SEQUENCE);
108 ASSERT_TRUE(x509_cert);
109 EXPECT_EQ(3U, x509_cert->intermediate_buffers().size());
110
111 ScopedCERTCertificateList nss_certs =
112 x509_util::CreateCERTCertificateListFromX509Certificate(x509_cert.get());
113 ASSERT_EQ(4U, nss_certs.size());
114 for (int i = 0; i < 4; ++i)
115 ASSERT_TRUE(nss_certs[i]);
116
117 EXPECT_EQ(x509_util::CryptoBufferAsStringPiece(x509_cert->cert_buffer()),
118 BytesForNSSCert(nss_certs[0].get()));
119 EXPECT_EQ(x509_util::CryptoBufferAsStringPiece(
120 x509_cert->intermediate_buffers()[0].get()),
121 BytesForNSSCert(nss_certs[1].get()));
122 EXPECT_EQ(x509_util::CryptoBufferAsStringPiece(
123 x509_cert->intermediate_buffers()[1].get()),
124 BytesForNSSCert(nss_certs[2].get()));
125 EXPECT_EQ(x509_util::CryptoBufferAsStringPiece(
126 x509_cert->intermediate_buffers()[2].get()),
127 BytesForNSSCert(nss_certs[3].get()));
128 }
129
TEST(X509UtilTest,CreateCERTCertificateListFromX509CertificateErrors)130 TEST(X509UtilTest, CreateCERTCertificateListFromX509CertificateErrors) {
131 scoped_refptr<X509Certificate> ok_cert(
132 ImportCertFromFile(GetTestCertsDirectory(), "ok_cert.pem"));
133 ASSERT_TRUE(ok_cert);
134
135 bssl::UniquePtr<CRYPTO_BUFFER> bad_cert =
136 x509_util::CreateCryptoBuffer(base::StringPiece("invalid"));
137 ASSERT_TRUE(bad_cert);
138
139 scoped_refptr<X509Certificate> ok_cert2(
140 ImportCertFromFile(GetTestCertsDirectory(), "root_ca_cert.pem"));
141 ASSERT_TRUE(ok_cert);
142
143 std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediates;
144 intermediates.push_back(std::move(bad_cert));
145 intermediates.push_back(bssl::UpRef(ok_cert2->cert_buffer()));
146 scoped_refptr<X509Certificate> cert_with_intermediates(
147 X509Certificate::CreateFromBuffer(bssl::UpRef(ok_cert->cert_buffer()),
148 std::move(intermediates)));
149 ASSERT_TRUE(cert_with_intermediates);
150 EXPECT_EQ(2U, cert_with_intermediates->intermediate_buffers().size());
151
152 // Normal CreateCERTCertificateListFromX509Certificate fails with invalid
153 // certs in chain.
154 ScopedCERTCertificateList nss_certs =
155 x509_util::CreateCERTCertificateListFromX509Certificate(
156 cert_with_intermediates.get());
157 EXPECT_TRUE(nss_certs.empty());
158
159 // With InvalidIntermediateBehavior::kIgnore, invalid intermediate certs
160 // should be silently dropped.
161 nss_certs = x509_util::CreateCERTCertificateListFromX509Certificate(
162 cert_with_intermediates.get(),
163 x509_util::InvalidIntermediateBehavior::kIgnore);
164 ASSERT_EQ(2U, nss_certs.size());
165 for (const auto& nss_cert : nss_certs)
166 ASSERT_TRUE(nss_cert.get());
167
168 EXPECT_EQ(x509_util::CryptoBufferAsStringPiece(ok_cert->cert_buffer()),
169 BytesForNSSCert(nss_certs[0].get()));
170 EXPECT_EQ(x509_util::CryptoBufferAsStringPiece(ok_cert2->cert_buffer()),
171 BytesForNSSCert(nss_certs[1].get()));
172 }
173
TEST(X509UtilNSSTest,CreateCERTCertificateListFromBytes)174 TEST(X509UtilNSSTest, CreateCERTCertificateListFromBytes) {
175 base::FilePath cert_path =
176 GetTestCertsDirectory().AppendASCII("multi-root-chain1.pem");
177 std::string cert_data;
178 ASSERT_TRUE(base::ReadFileToString(cert_path, &cert_data));
179
180 ScopedCERTCertificateList certs =
181 x509_util::CreateCERTCertificateListFromBytes(
182 cert_data.data(), cert_data.size(), X509Certificate::FORMAT_AUTO);
183 ASSERT_EQ(4U, certs.size());
184 EXPECT_STREQ("CN=127.0.0.1,O=Test CA,L=Mountain View,ST=California,C=US",
185 certs[0]->subjectName);
186 EXPECT_STREQ("CN=B CA - Multi-root", certs[1]->subjectName);
187 EXPECT_STREQ("CN=C CA - Multi-root", certs[2]->subjectName);
188 EXPECT_STREQ("CN=D Root CA - Multi-root", certs[3]->subjectName);
189 }
190
TEST(X509UtilNSSTest,DupCERTCertificate)191 TEST(X509UtilNSSTest, DupCERTCertificate) {
192 ScopedCERTCertificate cert(
193 x509_util::CreateCERTCertificateFromBytes(google_der));
194 ASSERT_TRUE(cert);
195
196 ScopedCERTCertificate cert2 = x509_util::DupCERTCertificate(cert.get());
197 // Both handles should hold a reference to the same CERTCertificate object.
198 ASSERT_EQ(cert.get(), cert2.get());
199
200 // Release the initial handle.
201 cert.reset();
202 // The duped handle should still be safe to access.
203 EXPECT_STREQ(
204 "CN=www.google.com,O=Google Inc,L=Mountain View,ST=California,C=US",
205 cert2->subjectName);
206 }
207
TEST(X509UtilNSSTest,DupCERTCertificateList)208 TEST(X509UtilNSSTest, DupCERTCertificateList) {
209 ScopedCERTCertificate cert(
210 x509_util::CreateCERTCertificateFromBytes(google_der));
211 ASSERT_TRUE(cert);
212 ScopedCERTCertificate cert2(
213 x509_util::CreateCERTCertificateFromBytes(webkit_der));
214 ASSERT_TRUE(cert2);
215 ScopedCERTCertificateList certs;
216 certs.push_back(std::move(cert));
217 certs.push_back(std::move(cert2));
218
219 ScopedCERTCertificateList certs_dup =
220 x509_util::DupCERTCertificateList(certs);
221 ASSERT_EQ(2U, certs_dup.size());
222 ASSERT_EQ(certs[0].get(), certs_dup[0].get());
223 ASSERT_EQ(certs[1].get(), certs_dup[1].get());
224
225 // Release the initial handles.
226 certs.clear();
227 // The duped handles should still be safe to access.
228 EXPECT_STREQ(
229 "CN=www.google.com,O=Google Inc,L=Mountain View,ST=California,C=US",
230 certs_dup[0]->subjectName);
231 EXPECT_STREQ(
232 "CN=*.webkit.org,OU=Mac OS Forge,O=Apple "
233 "Inc.,L=Cupertino,ST=California,C=US",
234 certs_dup[1]->subjectName);
235 }
236
TEST(X509UtilNSSTest,DupCERTCertificateList_EmptyList)237 TEST(X509UtilNSSTest, DupCERTCertificateList_EmptyList) {
238 EXPECT_EQ(0U, x509_util::DupCERTCertificateList({}).size());
239 }
240
TEST(X509UtilNSSTest,CreateX509CertificateFromCERTCertificate_NoChain)241 TEST(X509UtilNSSTest, CreateX509CertificateFromCERTCertificate_NoChain) {
242 ScopedCERTCertificate nss_cert(
243 x509_util::CreateCERTCertificateFromBytes(google_der));
244 ASSERT_TRUE(nss_cert);
245 scoped_refptr<X509Certificate> x509_cert =
246 x509_util::CreateX509CertificateFromCERTCertificate(nss_cert.get());
247 EXPECT_EQ(BytesForNSSCert(nss_cert.get()),
248 x509_util::CryptoBufferAsStringPiece(x509_cert->cert_buffer()));
249 EXPECT_TRUE(x509_cert->intermediate_buffers().empty());
250 }
251
TEST(X509UtilNSSTest,CreateX509CertificateFromCERTCertificate_EmptyChain)252 TEST(X509UtilNSSTest, CreateX509CertificateFromCERTCertificate_EmptyChain) {
253 ScopedCERTCertificate nss_cert(
254 x509_util::CreateCERTCertificateFromBytes(google_der));
255 ASSERT_TRUE(nss_cert);
256 scoped_refptr<X509Certificate> x509_cert =
257 x509_util::CreateX509CertificateFromCERTCertificate(
258 nss_cert.get(), std::vector<CERTCertificate*>());
259 EXPECT_EQ(BytesForNSSCert(nss_cert.get()),
260 x509_util::CryptoBufferAsStringPiece(x509_cert->cert_buffer()));
261 EXPECT_TRUE(x509_cert->intermediate_buffers().empty());
262 }
263
TEST(X509UtilNSSTest,CreateX509CertificateFromCERTCertificate_WithChain)264 TEST(X509UtilNSSTest, CreateX509CertificateFromCERTCertificate_WithChain) {
265 ScopedCERTCertificate nss_cert(
266 x509_util::CreateCERTCertificateFromBytes(google_der));
267 ASSERT_TRUE(nss_cert);
268 ScopedCERTCertificate nss_cert2(
269 x509_util::CreateCERTCertificateFromBytes(webkit_der));
270 ASSERT_TRUE(nss_cert2);
271
272 std::vector<CERTCertificate*> chain;
273 chain.push_back(nss_cert2.get());
274
275 scoped_refptr<X509Certificate> x509_cert =
276 x509_util::CreateX509CertificateFromCERTCertificate(nss_cert.get(),
277 chain);
278 EXPECT_EQ(BytesForNSSCert(nss_cert.get()),
279 x509_util::CryptoBufferAsStringPiece(x509_cert->cert_buffer()));
280 ASSERT_EQ(1U, x509_cert->intermediate_buffers().size());
281 EXPECT_EQ(x509_util::CryptoBufferAsStringPiece(
282 x509_cert->intermediate_buffers()[0].get()),
283 BytesForNSSCert(nss_cert2.get()));
284 }
285
TEST(X509UtilNSSTest,CreateX509CertificateListFromCERTCertificates)286 TEST(X509UtilNSSTest, CreateX509CertificateListFromCERTCertificates) {
287 ScopedCERTCertificate nss_cert(
288 x509_util::CreateCERTCertificateFromBytes(google_der));
289 ASSERT_TRUE(nss_cert);
290 ScopedCERTCertificate nss_cert2(
291 x509_util::CreateCERTCertificateFromBytes(webkit_der));
292 ASSERT_TRUE(nss_cert2);
293 ScopedCERTCertificateList nss_certs;
294 nss_certs.push_back(std::move(nss_cert));
295 nss_certs.push_back(std::move(nss_cert2));
296
297 CertificateList x509_certs =
298 x509_util::CreateX509CertificateListFromCERTCertificates(nss_certs);
299 ASSERT_EQ(2U, x509_certs.size());
300
301 EXPECT_EQ(BytesForNSSCert(nss_certs[0].get()),
302 x509_util::CryptoBufferAsStringPiece(x509_certs[0]->cert_buffer()));
303 EXPECT_EQ(BytesForNSSCert(nss_certs[1].get()),
304 x509_util::CryptoBufferAsStringPiece(x509_certs[1]->cert_buffer()));
305 }
306
TEST(X509UtilNSSTest,CreateX509CertificateListFromCERTCertificates_EmptyList)307 TEST(X509UtilNSSTest, CreateX509CertificateListFromCERTCertificates_EmptyList) {
308 ScopedCERTCertificateList nss_certs;
309 CertificateList x509_certs =
310 x509_util::CreateX509CertificateListFromCERTCertificates(nss_certs);
311 ASSERT_EQ(0U, x509_certs.size());
312 }
313
TEST(X509UtilNSSTest,GetDEREncoded)314 TEST(X509UtilNSSTest, GetDEREncoded) {
315 ScopedCERTCertificate google_cert(
316 x509_util::CreateCERTCertificateFromBytes(google_der));
317 ASSERT_TRUE(google_cert);
318 std::string der_encoded;
319 ASSERT_TRUE(x509_util::GetDEREncoded(google_cert.get(), &der_encoded));
320 EXPECT_EQ(std::string(reinterpret_cast<const char*>(google_der),
321 std::size(google_der)),
322 der_encoded);
323 }
324
TEST(X509UtilNSSTest,GetDefaultNickname)325 TEST(X509UtilNSSTest, GetDefaultNickname) {
326 base::FilePath certs_dir = GetTestCertsDirectory();
327
328 ScopedCERTCertificate test_cert = ImportCERTCertificateFromFile(
329 certs_dir, "no_subject_common_name_cert.pem");
330 ASSERT_TRUE(test_cert);
331
332 std::string nickname = x509_util::GetDefaultUniqueNickname(
333 test_cert.get(), USER_CERT, nullptr /*slot*/);
334 EXPECT_EQ(
335 "wtc@google.com's COMODO Client Authentication and "
336 "Secure Email CA ID",
337 nickname);
338 }
339
TEST(X509UtilNSSTest,GetCERTNameDisplayName_CN)340 TEST(X509UtilNSSTest, GetCERTNameDisplayName_CN) {
341 base::FilePath certs_dir = GetTestCertsDirectory();
342
343 ScopedCERTCertificate test_cert =
344 ImportCERTCertificateFromFile(certs_dir, "ok_cert.pem");
345 ASSERT_TRUE(test_cert);
346 scoped_refptr<X509Certificate> x509_test_cert =
347 ImportCertFromFile(certs_dir, "ok_cert.pem");
348 ASSERT_TRUE(x509_test_cert);
349
350 std::string name = x509_util::GetCERTNameDisplayName(&test_cert->subject);
351 EXPECT_EQ("127.0.0.1", name);
352 EXPECT_EQ(x509_test_cert->subject().GetDisplayName(), name);
353 }
354
TEST(X509UtilNSSTest,GetCERTNameDisplayName_O)355 TEST(X509UtilNSSTest, GetCERTNameDisplayName_O) {
356 base::FilePath certs_dir =
357 GetTestNetDataDirectory().AppendASCII("parse_certificate_unittest");
358
359 ScopedCERTCertificate test_cert =
360 ImportCERTCertificateFromFile(certs_dir, "subject_t61string.pem");
361 ASSERT_TRUE(test_cert);
362 scoped_refptr<X509Certificate> x509_test_cert =
363 ImportCertFromFile(certs_dir, "subject_t61string.pem");
364 ASSERT_TRUE(x509_test_cert);
365
366 std::string name = x509_util::GetCERTNameDisplayName(&test_cert->subject);
367 EXPECT_EQ(
368 " !\"#$%&'()*+,-./"
369 "0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`"
370 "abcdefghijklmnopqrstuvwxyz{|}~"
371 " ¡¢£¤¥¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæç"
372 "èéêëìíîïðñòóôõö÷øùúûüýþÿ",
373 name);
374 EXPECT_EQ(x509_test_cert->subject().GetDisplayName(), name);
375 }
376
TEST(X509UtilNSSTest,ParseClientSubjectAltNames)377 TEST(X509UtilNSSTest, ParseClientSubjectAltNames) {
378 base::FilePath certs_dir = GetTestCertsDirectory();
379
380 // This cert contains one rfc822Name field, and one Microsoft UPN
381 // otherName field.
382 ScopedCERTCertificate san_cert =
383 ImportCERTCertificateFromFile(certs_dir, "client_3.pem");
384 ASSERT_TRUE(san_cert);
385
386 std::vector<std::string> rfc822_names;
387 x509_util::GetRFC822SubjectAltNames(san_cert.get(), &rfc822_names);
388 ASSERT_EQ(1U, rfc822_names.size());
389 EXPECT_EQ("santest@example.com", rfc822_names[0]);
390
391 std::vector<std::string> upn_names;
392 x509_util::GetUPNSubjectAltNames(san_cert.get(), &upn_names);
393 ASSERT_EQ(1U, upn_names.size());
394 EXPECT_EQ("santest@ad.corp.example.com", upn_names[0]);
395 }
396
TEST(X509UtilNSSTest,GetValidityTimes)397 TEST(X509UtilNSSTest, GetValidityTimes) {
398 ScopedCERTCertificate google_cert(
399 x509_util::CreateCERTCertificateFromBytes(google_der));
400 ASSERT_TRUE(google_cert);
401
402 base::Time not_before, not_after;
403 EXPECT_TRUE(
404 x509_util::GetValidityTimes(google_cert.get(), ¬_before, ¬_after));
405
406 // Constants copied from x509_certificate_unittest.cc.
407 EXPECT_EQ(1238192407, // Mar 27 22:20:07 2009 GMT
408 not_before.InSecondsFSinceUnixEpoch());
409 EXPECT_EQ(1269728407, // Mar 27 22:20:07 2010 GMT
410 not_after.InSecondsFSinceUnixEpoch());
411 }
412
TEST(X509UtilNSSTest,GetValidityTimesOptionalArgs)413 TEST(X509UtilNSSTest, GetValidityTimesOptionalArgs) {
414 ScopedCERTCertificate google_cert(
415 x509_util::CreateCERTCertificateFromBytes(google_der));
416 ASSERT_TRUE(google_cert);
417
418 base::Time not_before;
419 EXPECT_TRUE(
420 x509_util::GetValidityTimes(google_cert.get(), ¬_before, nullptr));
421 // Constants copied from x509_certificate_unittest.cc.
422 EXPECT_EQ(1238192407, // Mar 27 22:20:07 2009 GMT
423 not_before.InSecondsFSinceUnixEpoch());
424
425 base::Time not_after;
426 EXPECT_TRUE(
427 x509_util::GetValidityTimes(google_cert.get(), nullptr, ¬_after));
428 EXPECT_EQ(1269728407, // Mar 27 22:20:07 2010 GMT
429 not_after.InSecondsFSinceUnixEpoch());
430 }
431
TEST(X509UtilNSSTest,CalculateFingerprint256)432 TEST(X509UtilNSSTest, CalculateFingerprint256) {
433 static const SHA256HashValue google_fingerprint = {
434 {0x21, 0xaf, 0x58, 0x74, 0xea, 0x6b, 0xad, 0xbd, 0xe4, 0xb3, 0xb1,
435 0xaa, 0x53, 0x32, 0x80, 0x8f, 0xbf, 0x8a, 0x24, 0x7d, 0x98, 0xec,
436 0x7f, 0x77, 0x49, 0x38, 0x42, 0x81, 0x26, 0x7f, 0xed, 0x38}};
437
438 ScopedCERTCertificate google_cert(
439 x509_util::CreateCERTCertificateFromBytes(google_der));
440 ASSERT_TRUE(google_cert);
441
442 EXPECT_EQ(google_fingerprint,
443 x509_util::CalculateFingerprint256(google_cert.get()));
444 }
445
446 } // namespace net
447