| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
| 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/cert_verify_proc.h" | |
| 6 | |
| 7 #include <vector> | |
| 8 | |
| 9 #include "base/callback_helpers.h" | |
| 10 #include "base/files/file_path.h" | |
| 11 #include "base/files/file_util.h" | |
| 12 #include "base/logging.h" | |
| 13 #include "base/sha1.h" | |
| 14 #include "base/strings/string_number_conversions.h" | |
| 15 #include "crypto/sha2.h" | |
| 16 #include "net/base/net_errors.h" | |
| 17 #include "net/base/test_data_directory.h" | |
| 18 #include "net/cert/asn1_util.h" | |
| 19 #include "net/cert/cert_status_flags.h" | |
| 20 #include "net/cert/cert_verifier.h" | |
| 21 #include "net/cert/cert_verify_result.h" | |
| 22 #include "net/cert/crl_set.h" | |
| 23 #include "net/cert/crl_set_storage.h" | |
| 24 #include "net/cert/test_root_certs.h" | |
| 25 #include "net/cert/x509_certificate.h" | |
| 26 #include "net/test/cert_test_util.h" | |
| 27 #include "net/test/test_certificate_data.h" | |
| 28 #include "testing/gtest/include/gtest/gtest.h" | |
| 29 | |
| 30 #if defined(OS_WIN) | |
| 31 #include "base/win/windows_version.h" | |
| 32 #elif defined(OS_ANDROID) | |
| 33 #include "base/android/build_info.h" | |
| 34 #endif | |
| 35 | |
| 36 using base::HexEncode; | |
| 37 | |
| 38 namespace net { | |
| 39 | |
| 40 namespace { | |
| 41 | |
| 42 // A certificate for www.paypal.com with a NULL byte in the common name. | |
| 43 // From http://www.gossamer-threads.com/lists/fulldisc/full-disclosure/70363 | |
| 44 unsigned char paypal_null_fingerprint[] = { | |
| 45 0x4c, 0x88, 0x9e, 0x28, 0xd7, 0x7a, 0x44, 0x1e, 0x13, 0xf2, 0x6a, 0xba, | |
| 46 0x1f, 0xe8, 0x1b, 0xd6, 0xab, 0x7b, 0xe8, 0xd7 | |
| 47 }; | |
| 48 | |
| 49 // Mock CertVerifyProc that will set |verify_result->is_issued_by_known_root| | |
| 50 // for all certificates that are Verified. | |
| 51 class WellKnownCaCertVerifyProc : public CertVerifyProc { | |
| 52 public: | |
| 53 // Initialize a CertVerifyProc that will set | |
| 54 // |verify_result->is_issued_by_known_root| to |is_well_known|. | |
| 55 explicit WellKnownCaCertVerifyProc(bool is_well_known) | |
| 56 : is_well_known_(is_well_known) {} | |
| 57 | |
| 58 // CertVerifyProc implementation: | |
| 59 bool SupportsAdditionalTrustAnchors() const override { return false; } | |
| 60 | |
| 61 protected: | |
| 62 ~WellKnownCaCertVerifyProc() override {} | |
| 63 | |
| 64 private: | |
| 65 int VerifyInternal(X509Certificate* cert, | |
| 66 const std::string& hostname, | |
| 67 int flags, | |
| 68 CRLSet* crl_set, | |
| 69 const CertificateList& additional_trust_anchors, | |
| 70 CertVerifyResult* verify_result) override; | |
| 71 | |
| 72 const bool is_well_known_; | |
| 73 | |
| 74 DISALLOW_COPY_AND_ASSIGN(WellKnownCaCertVerifyProc); | |
| 75 }; | |
| 76 | |
| 77 int WellKnownCaCertVerifyProc::VerifyInternal( | |
| 78 X509Certificate* cert, | |
| 79 const std::string& hostname, | |
| 80 int flags, | |
| 81 CRLSet* crl_set, | |
| 82 const CertificateList& additional_trust_anchors, | |
| 83 CertVerifyResult* verify_result) { | |
| 84 verify_result->is_issued_by_known_root = is_well_known_; | |
| 85 return OK; | |
| 86 } | |
| 87 | |
| 88 bool SupportsReturningVerifiedChain() { | |
| 89 #if defined(OS_ANDROID) | |
| 90 // Before API level 17, Android does not expose the APIs necessary to get at | |
| 91 // the verified certificate chain. | |
| 92 if (base::android::BuildInfo::GetInstance()->sdk_int() < 17) | |
| 93 return false; | |
| 94 #endif | |
| 95 return true; | |
| 96 } | |
| 97 | |
| 98 bool SupportsDetectingKnownRoots() { | |
| 99 #if defined(OS_ANDROID) | |
| 100 // Before API level 17, Android does not expose the APIs necessary to get at | |
| 101 // the verified certificate chain and detect known roots. | |
| 102 if (base::android::BuildInfo::GetInstance()->sdk_int() < 17) | |
| 103 return false; | |
| 104 #endif | |
| 105 return true; | |
| 106 } | |
| 107 | |
| 108 } // namespace | |
| 109 | |
| 110 class CertVerifyProcTest : public testing::Test { | |
| 111 public: | |
| 112 CertVerifyProcTest() | |
| 113 : verify_proc_(CertVerifyProc::CreateDefault()) { | |
| 114 } | |
| 115 ~CertVerifyProcTest() override {} | |
| 116 | |
| 117 protected: | |
| 118 bool SupportsAdditionalTrustAnchors() { | |
| 119 return verify_proc_->SupportsAdditionalTrustAnchors(); | |
| 120 } | |
| 121 | |
| 122 int Verify(X509Certificate* cert, | |
| 123 const std::string& hostname, | |
| 124 int flags, | |
| 125 CRLSet* crl_set, | |
| 126 const CertificateList& additional_trust_anchors, | |
| 127 CertVerifyResult* verify_result) { | |
| 128 return verify_proc_->Verify(cert, hostname, flags, crl_set, | |
| 129 additional_trust_anchors, verify_result); | |
| 130 } | |
| 131 | |
| 132 const CertificateList empty_cert_list_; | |
| 133 scoped_refptr<CertVerifyProc> verify_proc_; | |
| 134 }; | |
| 135 | |
| 136 TEST_F(CertVerifyProcTest, DISABLED_WithoutRevocationChecking) { | |
| 137 // Check that verification without revocation checking works. | |
| 138 CertificateList certs = CreateCertificateListFromFile( | |
| 139 GetTestCertsDirectory(), | |
| 140 "googlenew.chain.pem", | |
| 141 X509Certificate::FORMAT_PEM_CERT_SEQUENCE); | |
| 142 | |
| 143 X509Certificate::OSCertHandles intermediates; | |
| 144 intermediates.push_back(certs[1]->os_cert_handle()); | |
| 145 | |
| 146 scoped_refptr<X509Certificate> google_full_chain = | |
| 147 X509Certificate::CreateFromHandle(certs[0]->os_cert_handle(), | |
| 148 intermediates); | |
| 149 | |
| 150 CertVerifyResult verify_result; | |
| 151 EXPECT_EQ(OK, | |
| 152 Verify(google_full_chain.get(), | |
| 153 "www.google.com", | |
| 154 0 /* flags */, | |
| 155 NULL, | |
| 156 empty_cert_list_, | |
| 157 &verify_result)); | |
| 158 } | |
| 159 | |
| 160 #if defined(OS_ANDROID) || defined(USE_OPENSSL_CERTS) | |
| 161 // TODO(jnd): http://crbug.com/117478 - EV verification is not yet supported. | |
| 162 #define MAYBE_EVVerification DISABLED_EVVerification | |
| 163 #else | |
| 164 #define MAYBE_EVVerification EVVerification | |
| 165 #endif | |
| 166 TEST_F(CertVerifyProcTest, MAYBE_EVVerification) { | |
| 167 CertificateList certs = CreateCertificateListFromFile( | |
| 168 GetTestCertsDirectory(), | |
| 169 "comodo.chain.pem", | |
| 170 X509Certificate::FORMAT_PEM_CERT_SEQUENCE); | |
| 171 ASSERT_EQ(3U, certs.size()); | |
| 172 | |
| 173 X509Certificate::OSCertHandles intermediates; | |
| 174 intermediates.push_back(certs[1]->os_cert_handle()); | |
| 175 intermediates.push_back(certs[2]->os_cert_handle()); | |
| 176 | |
| 177 scoped_refptr<X509Certificate> comodo_chain = | |
| 178 X509Certificate::CreateFromHandle(certs[0]->os_cert_handle(), | |
| 179 intermediates); | |
| 180 | |
| 181 scoped_refptr<CRLSet> crl_set(CRLSet::ForTesting(false, NULL, "")); | |
| 182 CertVerifyResult verify_result; | |
| 183 int flags = CertVerifier::VERIFY_EV_CERT; | |
| 184 int error = Verify(comodo_chain.get(), | |
| 185 "comodo.com", | |
| 186 flags, | |
| 187 crl_set.get(), | |
| 188 empty_cert_list_, | |
| 189 &verify_result); | |
| 190 EXPECT_EQ(OK, error); | |
| 191 EXPECT_TRUE(verify_result.cert_status & CERT_STATUS_IS_EV); | |
| 192 } | |
| 193 | |
| 194 TEST_F(CertVerifyProcTest, PaypalNullCertParsing) { | |
| 195 scoped_refptr<X509Certificate> paypal_null_cert( | |
| 196 X509Certificate::CreateFromBytes( | |
| 197 reinterpret_cast<const char*>(paypal_null_der), | |
| 198 sizeof(paypal_null_der))); | |
| 199 | |
| 200 ASSERT_NE(static_cast<X509Certificate*>(NULL), paypal_null_cert.get()); | |
| 201 | |
| 202 const SHA1HashValue& fingerprint = | |
| 203 paypal_null_cert->fingerprint(); | |
| 204 for (size_t i = 0; i < 20; ++i) | |
| 205 EXPECT_EQ(paypal_null_fingerprint[i], fingerprint.data[i]); | |
| 206 | |
| 207 int flags = 0; | |
| 208 CertVerifyResult verify_result; | |
| 209 int error = Verify(paypal_null_cert.get(), | |
| 210 "www.paypal.com", | |
| 211 flags, | |
| 212 NULL, | |
| 213 empty_cert_list_, | |
| 214 &verify_result); | |
| 215 #if defined(USE_NSS) || defined(OS_IOS) || defined(OS_ANDROID) | |
| 216 EXPECT_EQ(ERR_CERT_COMMON_NAME_INVALID, error); | |
| 217 #else | |
| 218 // TOOD(bulach): investigate why macosx and win aren't returning | |
| 219 // ERR_CERT_INVALID or ERR_CERT_COMMON_NAME_INVALID. | |
| 220 EXPECT_EQ(ERR_CERT_AUTHORITY_INVALID, error); | |
| 221 #endif | |
| 222 // Either the system crypto library should correctly report a certificate | |
| 223 // name mismatch, or our certificate blacklist should cause us to report an | |
| 224 // invalid certificate. | |
| 225 #if defined(USE_NSS) || defined(OS_WIN) || defined(OS_IOS) | |
| 226 EXPECT_TRUE(verify_result.cert_status & | |
| 227 (CERT_STATUS_COMMON_NAME_INVALID | CERT_STATUS_INVALID)); | |
| 228 #endif | |
| 229 } | |
| 230 | |
| 231 // A regression test for http://crbug.com/31497. | |
| 232 #if defined(OS_ANDROID) | |
| 233 // Disabled on Android, as the Android verification libraries require an | |
| 234 // explicit policy to be specified, even when anyPolicy is permitted. | |
| 235 #define MAYBE_IntermediateCARequireExplicitPolicy \ | |
| 236 DISABLED_IntermediateCARequireExplicitPolicy | |
| 237 #else | |
| 238 #define MAYBE_IntermediateCARequireExplicitPolicy \ | |
| 239 IntermediateCARequireExplicitPolicy | |
| 240 #endif | |
| 241 TEST_F(CertVerifyProcTest, MAYBE_IntermediateCARequireExplicitPolicy) { | |
| 242 base::FilePath certs_dir = GetTestCertsDirectory(); | |
| 243 | |
| 244 CertificateList certs = CreateCertificateListFromFile( | |
| 245 certs_dir, "explicit-policy-chain.pem", | |
| 246 X509Certificate::FORMAT_AUTO); | |
| 247 ASSERT_EQ(3U, certs.size()); | |
| 248 | |
| 249 X509Certificate::OSCertHandles intermediates; | |
| 250 intermediates.push_back(certs[1]->os_cert_handle()); | |
| 251 | |
| 252 scoped_refptr<X509Certificate> cert = | |
| 253 X509Certificate::CreateFromHandle(certs[0]->os_cert_handle(), | |
| 254 intermediates); | |
| 255 ASSERT_TRUE(cert.get()); | |
| 256 | |
| 257 ScopedTestRoot scoped_root(certs[2].get()); | |
| 258 | |
| 259 int flags = 0; | |
| 260 CertVerifyResult verify_result; | |
| 261 int error = Verify(cert.get(), | |
| 262 "policy_test.example", | |
| 263 flags, | |
| 264 NULL, | |
| 265 empty_cert_list_, | |
| 266 &verify_result); | |
| 267 EXPECT_EQ(OK, error); | |
| 268 EXPECT_EQ(0u, verify_result.cert_status); | |
| 269 } | |
| 270 | |
| 271 // Test for bug 58437. | |
| 272 // This certificate will expire on 2011-12-21. The test will still | |
| 273 // pass if error == ERR_CERT_DATE_INVALID. | |
| 274 // This test is DISABLED because it appears that we cannot do | |
| 275 // certificate revocation checking when running all of the net unit tests. | |
| 276 // This test passes when run individually, but when run with all of the net | |
| 277 // unit tests, the call to PKIXVerifyCert returns the NSS error -8180, which is | |
| 278 // SEC_ERROR_REVOKED_CERTIFICATE. This indicates a lack of revocation | |
| 279 // status, i.e. that the revocation check is failing for some reason. | |
| 280 TEST_F(CertVerifyProcTest, DISABLED_GlobalSignR3EVTest) { | |
| 281 base::FilePath certs_dir = GetTestCertsDirectory(); | |
| 282 | |
| 283 scoped_refptr<X509Certificate> server_cert = | |
| 284 ImportCertFromFile(certs_dir, "2029_globalsign_com_cert.pem"); | |
| 285 ASSERT_NE(static_cast<X509Certificate*>(NULL), server_cert.get()); | |
| 286 | |
| 287 scoped_refptr<X509Certificate> intermediate_cert = | |
| 288 ImportCertFromFile(certs_dir, "globalsign_ev_sha256_ca_cert.pem"); | |
| 289 ASSERT_NE(static_cast<X509Certificate*>(NULL), intermediate_cert.get()); | |
| 290 | |
| 291 X509Certificate::OSCertHandles intermediates; | |
| 292 intermediates.push_back(intermediate_cert->os_cert_handle()); | |
| 293 scoped_refptr<X509Certificate> cert_chain = | |
| 294 X509Certificate::CreateFromHandle(server_cert->os_cert_handle(), | |
| 295 intermediates); | |
| 296 | |
| 297 CertVerifyResult verify_result; | |
| 298 int flags = CertVerifier::VERIFY_REV_CHECKING_ENABLED | | |
| 299 CertVerifier::VERIFY_EV_CERT; | |
| 300 int error = Verify(cert_chain.get(), | |
| 301 "2029.globalsign.com", | |
| 302 flags, | |
| 303 NULL, | |
| 304 empty_cert_list_, | |
| 305 &verify_result); | |
| 306 if (error == OK) | |
| 307 EXPECT_TRUE(verify_result.cert_status & CERT_STATUS_IS_EV); | |
| 308 else | |
| 309 EXPECT_EQ(ERR_CERT_DATE_INVALID, error); | |
| 310 } | |
| 311 | |
| 312 // Test that verifying an ECDSA certificate doesn't crash on XP. (See | |
| 313 // crbug.com/144466). | |
| 314 TEST_F(CertVerifyProcTest, ECDSA_RSA) { | |
| 315 base::FilePath certs_dir = GetTestCertsDirectory(); | |
| 316 | |
| 317 scoped_refptr<X509Certificate> cert = | |
| 318 ImportCertFromFile(certs_dir, | |
| 319 "prime256v1-ecdsa-ee-by-1024-rsa-intermediate.pem"); | |
| 320 | |
| 321 CertVerifyResult verify_result; | |
| 322 Verify(cert.get(), "127.0.0.1", 0, NULL, empty_cert_list_, &verify_result); | |
| 323 | |
| 324 // We don't check verify_result because the certificate is signed by an | |
| 325 // unknown CA and will be considered invalid on XP because of the ECDSA | |
| 326 // public key. | |
| 327 } | |
| 328 | |
| 329 // Currently, only RSA and DSA keys are checked for weakness, and our example | |
| 330 // weak size is 768. These could change in the future. | |
| 331 // | |
| 332 // Note that this means there may be false negatives: keys for other | |
| 333 // algorithms and which are weak will pass this test. | |
| 334 static bool IsWeakKeyType(const std::string& key_type) { | |
| 335 size_t pos = key_type.find("-"); | |
| 336 std::string size = key_type.substr(0, pos); | |
| 337 std::string type = key_type.substr(pos + 1); | |
| 338 | |
| 339 if (type == "rsa" || type == "dsa") | |
| 340 return size == "768"; | |
| 341 | |
| 342 return false; | |
| 343 } | |
| 344 | |
| 345 TEST_F(CertVerifyProcTest, RejectWeakKeys) { | |
| 346 base::FilePath certs_dir = GetTestCertsDirectory(); | |
| 347 typedef std::vector<std::string> Strings; | |
| 348 Strings key_types; | |
| 349 | |
| 350 // generate-weak-test-chains.sh currently has: | |
| 351 // key_types="768-rsa 1024-rsa 2048-rsa prime256v1-ecdsa" | |
| 352 // We must use the same key types here. The filenames generated look like: | |
| 353 // 2048-rsa-ee-by-768-rsa-intermediate.pem | |
| 354 key_types.push_back("768-rsa"); | |
| 355 key_types.push_back("1024-rsa"); | |
| 356 key_types.push_back("2048-rsa"); | |
| 357 | |
| 358 bool use_ecdsa = true; | |
| 359 #if defined(OS_WIN) | |
| 360 use_ecdsa = base::win::GetVersion() > base::win::VERSION_XP; | |
| 361 #endif | |
| 362 | |
| 363 if (use_ecdsa) | |
| 364 key_types.push_back("prime256v1-ecdsa"); | |
| 365 | |
| 366 // Add the root that signed the intermediates for this test. | |
| 367 scoped_refptr<X509Certificate> root_cert = | |
| 368 ImportCertFromFile(certs_dir, "2048-rsa-root.pem"); | |
| 369 ASSERT_NE(static_cast<X509Certificate*>(NULL), root_cert.get()); | |
| 370 ScopedTestRoot scoped_root(root_cert.get()); | |
| 371 | |
| 372 // Now test each chain. | |
| 373 for (Strings::const_iterator ee_type = key_types.begin(); | |
| 374 ee_type != key_types.end(); ++ee_type) { | |
| 375 for (Strings::const_iterator signer_type = key_types.begin(); | |
| 376 signer_type != key_types.end(); ++signer_type) { | |
| 377 std::string basename = *ee_type + "-ee-by-" + *signer_type + | |
| 378 "-intermediate.pem"; | |
| 379 SCOPED_TRACE(basename); | |
| 380 scoped_refptr<X509Certificate> ee_cert = | |
| 381 ImportCertFromFile(certs_dir, basename); | |
| 382 ASSERT_NE(static_cast<X509Certificate*>(NULL), ee_cert.get()); | |
| 383 | |
| 384 basename = *signer_type + "-intermediate.pem"; | |
| 385 scoped_refptr<X509Certificate> intermediate = | |
| 386 ImportCertFromFile(certs_dir, basename); | |
| 387 ASSERT_NE(static_cast<X509Certificate*>(NULL), intermediate.get()); | |
| 388 | |
| 389 X509Certificate::OSCertHandles intermediates; | |
| 390 intermediates.push_back(intermediate->os_cert_handle()); | |
| 391 scoped_refptr<X509Certificate> cert_chain = | |
| 392 X509Certificate::CreateFromHandle(ee_cert->os_cert_handle(), | |
| 393 intermediates); | |
| 394 | |
| 395 CertVerifyResult verify_result; | |
| 396 int error = Verify(cert_chain.get(), | |
| 397 "127.0.0.1", | |
| 398 0, | |
| 399 NULL, | |
| 400 empty_cert_list_, | |
| 401 &verify_result); | |
| 402 | |
| 403 if (IsWeakKeyType(*ee_type) || IsWeakKeyType(*signer_type)) { | |
| 404 EXPECT_NE(OK, error); | |
| 405 EXPECT_EQ(CERT_STATUS_WEAK_KEY, | |
| 406 verify_result.cert_status & CERT_STATUS_WEAK_KEY); | |
| 407 EXPECT_NE(CERT_STATUS_INVALID, | |
| 408 verify_result.cert_status & CERT_STATUS_INVALID); | |
| 409 } else { | |
| 410 EXPECT_EQ(OK, error); | |
| 411 EXPECT_EQ(0U, verify_result.cert_status & CERT_STATUS_WEAK_KEY); | |
| 412 } | |
| 413 } | |
| 414 } | |
| 415 } | |
| 416 | |
| 417 // Regression test for http://crbug.com/108514. | |
| 418 #if defined(OS_MACOSX) && !defined(OS_IOS) | |
| 419 // Disabled on OS X - Security.framework doesn't ignore superflous certificates | |
| 420 // provided by servers. See CertVerifyProcTest.CybertrustGTERoot for further | |
| 421 // details. | |
| 422 #define MAYBE_ExtraneousMD5RootCert DISABLED_ExtraneousMD5RootCert | |
| 423 #else | |
| 424 #define MAYBE_ExtraneousMD5RootCert ExtraneousMD5RootCert | |
| 425 #endif | |
| 426 TEST_F(CertVerifyProcTest, MAYBE_ExtraneousMD5RootCert) { | |
| 427 if (!SupportsReturningVerifiedChain()) { | |
| 428 LOG(INFO) << "Skipping this test in this platform."; | |
| 429 return; | |
| 430 } | |
| 431 | |
| 432 base::FilePath certs_dir = GetTestCertsDirectory(); | |
| 433 | |
| 434 scoped_refptr<X509Certificate> server_cert = | |
| 435 ImportCertFromFile(certs_dir, "cross-signed-leaf.pem"); | |
| 436 ASSERT_NE(static_cast<X509Certificate*>(NULL), server_cert.get()); | |
| 437 | |
| 438 scoped_refptr<X509Certificate> extra_cert = | |
| 439 ImportCertFromFile(certs_dir, "cross-signed-root-md5.pem"); | |
| 440 ASSERT_NE(static_cast<X509Certificate*>(NULL), extra_cert.get()); | |
| 441 | |
| 442 scoped_refptr<X509Certificate> root_cert = | |
| 443 ImportCertFromFile(certs_dir, "cross-signed-root-sha1.pem"); | |
| 444 ASSERT_NE(static_cast<X509Certificate*>(NULL), root_cert.get()); | |
| 445 | |
| 446 ScopedTestRoot scoped_root(root_cert.get()); | |
| 447 | |
| 448 X509Certificate::OSCertHandles intermediates; | |
| 449 intermediates.push_back(extra_cert->os_cert_handle()); | |
| 450 scoped_refptr<X509Certificate> cert_chain = | |
| 451 X509Certificate::CreateFromHandle(server_cert->os_cert_handle(), | |
| 452 intermediates); | |
| 453 | |
| 454 CertVerifyResult verify_result; | |
| 455 int flags = 0; | |
| 456 int error = Verify(cert_chain.get(), | |
| 457 "127.0.0.1", | |
| 458 flags, | |
| 459 NULL, | |
| 460 empty_cert_list_, | |
| 461 &verify_result); | |
| 462 EXPECT_EQ(OK, error); | |
| 463 | |
| 464 // The extra MD5 root should be discarded | |
| 465 ASSERT_TRUE(verify_result.verified_cert.get()); | |
| 466 ASSERT_EQ(1u, | |
| 467 verify_result.verified_cert->GetIntermediateCertificates().size()); | |
| 468 EXPECT_TRUE(X509Certificate::IsSameOSCert( | |
| 469 verify_result.verified_cert->GetIntermediateCertificates().front(), | |
| 470 root_cert->os_cert_handle())); | |
| 471 | |
| 472 EXPECT_FALSE(verify_result.has_md5); | |
| 473 } | |
| 474 | |
| 475 // Test for bug 94673. | |
| 476 TEST_F(CertVerifyProcTest, GoogleDigiNotarTest) { | |
| 477 base::FilePath certs_dir = GetTestCertsDirectory(); | |
| 478 | |
| 479 scoped_refptr<X509Certificate> server_cert = | |
| 480 ImportCertFromFile(certs_dir, "google_diginotar.pem"); | |
| 481 ASSERT_NE(static_cast<X509Certificate*>(NULL), server_cert.get()); | |
| 482 | |
| 483 scoped_refptr<X509Certificate> intermediate_cert = | |
| 484 ImportCertFromFile(certs_dir, "diginotar_public_ca_2025.pem"); | |
| 485 ASSERT_NE(static_cast<X509Certificate*>(NULL), intermediate_cert.get()); | |
| 486 | |
| 487 X509Certificate::OSCertHandles intermediates; | |
| 488 intermediates.push_back(intermediate_cert->os_cert_handle()); | |
| 489 scoped_refptr<X509Certificate> cert_chain = | |
| 490 X509Certificate::CreateFromHandle(server_cert->os_cert_handle(), | |
| 491 intermediates); | |
| 492 | |
| 493 CertVerifyResult verify_result; | |
| 494 int flags = CertVerifier::VERIFY_REV_CHECKING_ENABLED; | |
| 495 int error = Verify(cert_chain.get(), | |
| 496 "mail.google.com", | |
| 497 flags, | |
| 498 NULL, | |
| 499 empty_cert_list_, | |
| 500 &verify_result); | |
| 501 EXPECT_NE(OK, error); | |
| 502 | |
| 503 // Now turn off revocation checking. Certificate verification should still | |
| 504 // fail. | |
| 505 flags = 0; | |
| 506 error = Verify(cert_chain.get(), | |
| 507 "mail.google.com", | |
| 508 flags, | |
| 509 NULL, | |
| 510 empty_cert_list_, | |
| 511 &verify_result); | |
| 512 EXPECT_NE(OK, error); | |
| 513 } | |
| 514 | |
| 515 TEST_F(CertVerifyProcTest, DigiNotarCerts) { | |
| 516 static const char* const kDigiNotarFilenames[] = { | |
| 517 "diginotar_root_ca.pem", | |
| 518 "diginotar_cyber_ca.pem", | |
| 519 "diginotar_services_1024_ca.pem", | |
| 520 "diginotar_pkioverheid.pem", | |
| 521 "diginotar_pkioverheid_g2.pem", | |
| 522 NULL, | |
| 523 }; | |
| 524 | |
| 525 base::FilePath certs_dir = GetTestCertsDirectory(); | |
| 526 | |
| 527 for (size_t i = 0; kDigiNotarFilenames[i]; i++) { | |
| 528 scoped_refptr<X509Certificate> diginotar_cert = | |
| 529 ImportCertFromFile(certs_dir, kDigiNotarFilenames[i]); | |
| 530 std::string der_bytes; | |
| 531 ASSERT_TRUE(X509Certificate::GetDEREncoded( | |
| 532 diginotar_cert->os_cert_handle(), &der_bytes)); | |
| 533 | |
| 534 base::StringPiece spki; | |
| 535 ASSERT_TRUE(asn1::ExtractSPKIFromDERCert(der_bytes, &spki)); | |
| 536 | |
| 537 std::string spki_sha1 = base::SHA1HashString(spki.as_string()); | |
| 538 | |
| 539 HashValueVector public_keys; | |
| 540 HashValue hash(HASH_VALUE_SHA1); | |
| 541 ASSERT_EQ(hash.size(), spki_sha1.size()); | |
| 542 memcpy(hash.data(), spki_sha1.data(), spki_sha1.size()); | |
| 543 public_keys.push_back(hash); | |
| 544 | |
| 545 EXPECT_TRUE(CertVerifyProc::IsPublicKeyBlacklisted(public_keys)) << | |
| 546 "Public key not blocked for " << kDigiNotarFilenames[i]; | |
| 547 } | |
| 548 } | |
| 549 | |
| 550 TEST_F(CertVerifyProcTest, NameConstraintsOk) { | |
| 551 CertificateList ca_cert_list = | |
| 552 CreateCertificateListFromFile(GetTestCertsDirectory(), | |
| 553 "root_ca_cert.pem", | |
| 554 X509Certificate::FORMAT_AUTO); | |
| 555 ASSERT_EQ(1U, ca_cert_list.size()); | |
| 556 ScopedTestRoot test_root(ca_cert_list[0].get()); | |
| 557 | |
| 558 CertificateList cert_list = CreateCertificateListFromFile( | |
| 559 GetTestCertsDirectory(), "name_constraint_good.pem", | |
| 560 X509Certificate::FORMAT_AUTO); | |
| 561 ASSERT_EQ(1U, cert_list.size()); | |
| 562 | |
| 563 X509Certificate::OSCertHandles intermediates; | |
| 564 scoped_refptr<X509Certificate> leaf = | |
| 565 X509Certificate::CreateFromHandle(cert_list[0]->os_cert_handle(), | |
| 566 intermediates); | |
| 567 | |
| 568 int flags = 0; | |
| 569 CertVerifyResult verify_result; | |
| 570 int error = Verify(leaf.get(), | |
| 571 "test.example.com", | |
| 572 flags, | |
| 573 NULL, | |
| 574 empty_cert_list_, | |
| 575 &verify_result); | |
| 576 EXPECT_EQ(OK, error); | |
| 577 EXPECT_EQ(0U, verify_result.cert_status); | |
| 578 } | |
| 579 | |
| 580 TEST_F(CertVerifyProcTest, NameConstraintsFailure) { | |
| 581 if (!SupportsReturningVerifiedChain()) { | |
| 582 LOG(INFO) << "Skipping this test in this platform."; | |
| 583 return; | |
| 584 } | |
| 585 | |
| 586 CertificateList ca_cert_list = | |
| 587 CreateCertificateListFromFile(GetTestCertsDirectory(), | |
| 588 "root_ca_cert.pem", | |
| 589 X509Certificate::FORMAT_AUTO); | |
| 590 ASSERT_EQ(1U, ca_cert_list.size()); | |
| 591 ScopedTestRoot test_root(ca_cert_list[0].get()); | |
| 592 | |
| 593 CertificateList cert_list = CreateCertificateListFromFile( | |
| 594 GetTestCertsDirectory(), "name_constraint_bad.pem", | |
| 595 X509Certificate::FORMAT_AUTO); | |
| 596 ASSERT_EQ(1U, cert_list.size()); | |
| 597 | |
| 598 X509Certificate::OSCertHandles intermediates; | |
| 599 scoped_refptr<X509Certificate> leaf = | |
| 600 X509Certificate::CreateFromHandle(cert_list[0]->os_cert_handle(), | |
| 601 intermediates); | |
| 602 | |
| 603 int flags = 0; | |
| 604 CertVerifyResult verify_result; | |
| 605 int error = Verify(leaf.get(), | |
| 606 "test.example.com", | |
| 607 flags, | |
| 608 NULL, | |
| 609 empty_cert_list_, | |
| 610 &verify_result); | |
| 611 EXPECT_EQ(ERR_CERT_NAME_CONSTRAINT_VIOLATION, error); | |
| 612 EXPECT_EQ(CERT_STATUS_NAME_CONSTRAINT_VIOLATION, | |
| 613 verify_result.cert_status & CERT_STATUS_NAME_CONSTRAINT_VIOLATION); | |
| 614 } | |
| 615 | |
| 616 TEST_F(CertVerifyProcTest, TestHasTooLongValidity) { | |
| 617 struct { | |
| 618 const char* const file; | |
| 619 bool is_valid_too_long; | |
| 620 } tests[] = { | |
| 621 {"twitter-chain.pem", false}, | |
| 622 {"start_after_expiry.pem", true}, | |
| 623 {"pre_br_validity_ok.pem", false}, | |
| 624 {"pre_br_validity_bad_121.pem", true}, | |
| 625 {"pre_br_validity_bad_2020.pem", true}, | |
| 626 {"10_year_validity.pem", false}, | |
| 627 {"11_year_validity.pem", true}, | |
| 628 {"39_months_after_2015_04.pem", false}, | |
| 629 {"40_months_after_2015_04.pem", true}, | |
| 630 {"60_months_after_2012_07.pem", false}, | |
| 631 {"61_months_after_2012_07.pem", true}, | |
| 632 }; | |
| 633 | |
| 634 base::FilePath certs_dir = GetTestCertsDirectory(); | |
| 635 | |
| 636 for (size_t i = 0; i < arraysize(tests); ++i) { | |
| 637 scoped_refptr<X509Certificate> certificate = | |
| 638 ImportCertFromFile(certs_dir, tests[i].file); | |
| 639 SCOPED_TRACE(tests[i].file); | |
| 640 ASSERT_TRUE(certificate); | |
| 641 EXPECT_EQ(tests[i].is_valid_too_long, | |
| 642 CertVerifyProc::HasTooLongValidity(*certificate)); | |
| 643 } | |
| 644 } | |
| 645 | |
| 646 TEST_F(CertVerifyProcTest, TestKnownRoot) { | |
| 647 if (!SupportsDetectingKnownRoots()) { | |
| 648 LOG(INFO) << "Skipping this test on this platform."; | |
| 649 return; | |
| 650 } | |
| 651 | |
| 652 base::FilePath certs_dir = GetTestCertsDirectory(); | |
| 653 CertificateList certs = CreateCertificateListFromFile( | |
| 654 certs_dir, "twitter-chain.pem", X509Certificate::FORMAT_AUTO); | |
| 655 ASSERT_EQ(3U, certs.size()); | |
| 656 | |
| 657 X509Certificate::OSCertHandles intermediates; | |
| 658 intermediates.push_back(certs[1]->os_cert_handle()); | |
| 659 | |
| 660 scoped_refptr<X509Certificate> cert_chain = | |
| 661 X509Certificate::CreateFromHandle(certs[0]->os_cert_handle(), | |
| 662 intermediates); | |
| 663 | |
| 664 int flags = 0; | |
| 665 CertVerifyResult verify_result; | |
| 666 // This will blow up, May 9th, 2016. Sorry! Please disable and file a bug | |
| 667 // against agl. See also PublicKeyHashes. | |
| 668 int error = Verify(cert_chain.get(), "twitter.com", flags, NULL, | |
| 669 empty_cert_list_, &verify_result); | |
| 670 EXPECT_EQ(OK, error); | |
| 671 EXPECT_TRUE(verify_result.is_issued_by_known_root); | |
| 672 } | |
| 673 | |
| 674 TEST_F(CertVerifyProcTest, PublicKeyHashes) { | |
| 675 if (!SupportsReturningVerifiedChain()) { | |
| 676 LOG(INFO) << "Skipping this test in this platform."; | |
| 677 return; | |
| 678 } | |
| 679 | |
| 680 base::FilePath certs_dir = GetTestCertsDirectory(); | |
| 681 CertificateList certs = CreateCertificateListFromFile( | |
| 682 certs_dir, "twitter-chain.pem", X509Certificate::FORMAT_AUTO); | |
| 683 ASSERT_EQ(3U, certs.size()); | |
| 684 | |
| 685 X509Certificate::OSCertHandles intermediates; | |
| 686 intermediates.push_back(certs[1]->os_cert_handle()); | |
| 687 | |
| 688 scoped_refptr<X509Certificate> cert_chain = | |
| 689 X509Certificate::CreateFromHandle(certs[0]->os_cert_handle(), | |
| 690 intermediates); | |
| 691 int flags = 0; | |
| 692 CertVerifyResult verify_result; | |
| 693 | |
| 694 // This will blow up, May 9th, 2016. Sorry! Please disable and file a bug | |
| 695 // against agl. See also TestKnownRoot. | |
| 696 int error = Verify(cert_chain.get(), "twitter.com", flags, NULL, | |
| 697 empty_cert_list_, &verify_result); | |
| 698 EXPECT_EQ(OK, error); | |
| 699 ASSERT_LE(3U, verify_result.public_key_hashes.size()); | |
| 700 | |
| 701 HashValueVector sha1_hashes; | |
| 702 for (size_t i = 0; i < verify_result.public_key_hashes.size(); ++i) { | |
| 703 if (verify_result.public_key_hashes[i].tag != HASH_VALUE_SHA1) | |
| 704 continue; | |
| 705 sha1_hashes.push_back(verify_result.public_key_hashes[i]); | |
| 706 } | |
| 707 ASSERT_LE(3u, sha1_hashes.size()); | |
| 708 | |
| 709 for (size_t i = 0; i < 3; ++i) { | |
| 710 EXPECT_EQ(HexEncode(kTwitterSPKIs[i], base::kSHA1Length), | |
| 711 HexEncode(sha1_hashes[i].data(), base::kSHA1Length)); | |
| 712 } | |
| 713 | |
| 714 HashValueVector sha256_hashes; | |
| 715 for (size_t i = 0; i < verify_result.public_key_hashes.size(); ++i) { | |
| 716 if (verify_result.public_key_hashes[i].tag != HASH_VALUE_SHA256) | |
| 717 continue; | |
| 718 sha256_hashes.push_back(verify_result.public_key_hashes[i]); | |
| 719 } | |
| 720 ASSERT_LE(3u, sha256_hashes.size()); | |
| 721 | |
| 722 for (size_t i = 0; i < 3; ++i) { | |
| 723 EXPECT_EQ(HexEncode(kTwitterSPKIsSHA256[i], crypto::kSHA256Length), | |
| 724 HexEncode(sha256_hashes[i].data(), crypto::kSHA256Length)); | |
| 725 } | |
| 726 } | |
| 727 | |
| 728 // A regression test for http://crbug.com/70293. | |
| 729 // The Key Usage extension in this RSA SSL server certificate does not have | |
| 730 // the keyEncipherment bit. | |
| 731 TEST_F(CertVerifyProcTest, InvalidKeyUsage) { | |
| 732 base::FilePath certs_dir = GetTestCertsDirectory(); | |
| 733 | |
| 734 scoped_refptr<X509Certificate> server_cert = | |
| 735 ImportCertFromFile(certs_dir, "invalid_key_usage_cert.der"); | |
| 736 ASSERT_NE(static_cast<X509Certificate*>(NULL), server_cert.get()); | |
| 737 | |
| 738 int flags = 0; | |
| 739 CertVerifyResult verify_result; | |
| 740 int error = Verify(server_cert.get(), | |
| 741 "jira.aquameta.com", | |
| 742 flags, | |
| 743 NULL, | |
| 744 empty_cert_list_, | |
| 745 &verify_result); | |
| 746 #if defined(USE_OPENSSL_CERTS) && !defined(OS_ANDROID) | |
| 747 // This certificate has two errors: "invalid key usage" and "untrusted CA". | |
| 748 // However, OpenSSL returns only one (the latter), and we can't detect | |
| 749 // the other errors. | |
| 750 EXPECT_EQ(ERR_CERT_AUTHORITY_INVALID, error); | |
| 751 #else | |
| 752 EXPECT_EQ(ERR_CERT_INVALID, error); | |
| 753 EXPECT_TRUE(verify_result.cert_status & CERT_STATUS_INVALID); | |
| 754 #endif | |
| 755 // TODO(wtc): fix http://crbug.com/75520 to get all the certificate errors | |
| 756 // from NSS. | |
| 757 #if !defined(USE_NSS) && !defined(OS_IOS) && !defined(OS_ANDROID) | |
| 758 // The certificate is issued by an unknown CA. | |
| 759 EXPECT_TRUE(verify_result.cert_status & CERT_STATUS_AUTHORITY_INVALID); | |
| 760 #endif | |
| 761 } | |
| 762 | |
| 763 // Basic test for returning the chain in CertVerifyResult. Note that the | |
| 764 // returned chain may just be a reflection of the originally supplied chain; | |
| 765 // that is, if any errors occur, the default chain returned is an exact copy | |
| 766 // of the certificate to be verified. The remaining VerifyReturn* tests are | |
| 767 // used to ensure that the actual, verified chain is being returned by | |
| 768 // Verify(). | |
| 769 TEST_F(CertVerifyProcTest, VerifyReturnChainBasic) { | |
| 770 if (!SupportsReturningVerifiedChain()) { | |
| 771 LOG(INFO) << "Skipping this test in this platform."; | |
| 772 return; | |
| 773 } | |
| 774 | |
| 775 base::FilePath certs_dir = GetTestCertsDirectory(); | |
| 776 CertificateList certs = CreateCertificateListFromFile( | |
| 777 certs_dir, "x509_verify_results.chain.pem", | |
| 778 X509Certificate::FORMAT_AUTO); | |
| 779 ASSERT_EQ(3U, certs.size()); | |
| 780 | |
| 781 X509Certificate::OSCertHandles intermediates; | |
| 782 intermediates.push_back(certs[1]->os_cert_handle()); | |
| 783 intermediates.push_back(certs[2]->os_cert_handle()); | |
| 784 | |
| 785 ScopedTestRoot scoped_root(certs[2].get()); | |
| 786 | |
| 787 scoped_refptr<X509Certificate> google_full_chain = | |
| 788 X509Certificate::CreateFromHandle(certs[0]->os_cert_handle(), | |
| 789 intermediates); | |
| 790 ASSERT_NE(static_cast<X509Certificate*>(NULL), google_full_chain.get()); | |
| 791 ASSERT_EQ(2U, google_full_chain->GetIntermediateCertificates().size()); | |
| 792 | |
| 793 CertVerifyResult verify_result; | |
| 794 EXPECT_EQ(static_cast<X509Certificate*>(NULL), | |
| 795 verify_result.verified_cert.get()); | |
| 796 int error = Verify(google_full_chain.get(), | |
| 797 "127.0.0.1", | |
| 798 0, | |
| 799 NULL, | |
| 800 empty_cert_list_, | |
| 801 &verify_result); | |
| 802 EXPECT_EQ(OK, error); | |
| 803 ASSERT_NE(static_cast<X509Certificate*>(NULL), | |
| 804 verify_result.verified_cert.get()); | |
| 805 | |
| 806 EXPECT_NE(google_full_chain, verify_result.verified_cert); | |
| 807 EXPECT_TRUE(X509Certificate::IsSameOSCert( | |
| 808 google_full_chain->os_cert_handle(), | |
| 809 verify_result.verified_cert->os_cert_handle())); | |
| 810 const X509Certificate::OSCertHandles& return_intermediates = | |
| 811 verify_result.verified_cert->GetIntermediateCertificates(); | |
| 812 ASSERT_EQ(2U, return_intermediates.size()); | |
| 813 EXPECT_TRUE(X509Certificate::IsSameOSCert(return_intermediates[0], | |
| 814 certs[1]->os_cert_handle())); | |
| 815 EXPECT_TRUE(X509Certificate::IsSameOSCert(return_intermediates[1], | |
| 816 certs[2]->os_cert_handle())); | |
| 817 } | |
| 818 | |
| 819 // Test that certificates issued for 'intranet' names (that is, containing no | |
| 820 // known public registry controlled domain information) issued by well-known | |
| 821 // CAs are flagged appropriately, while certificates that are issued by | |
| 822 // internal CAs are not flagged. | |
| 823 TEST_F(CertVerifyProcTest, IntranetHostsRejected) { | |
| 824 if (!SupportsDetectingKnownRoots()) { | |
| 825 LOG(INFO) << "Skipping this test in this platform."; | |
| 826 return; | |
| 827 } | |
| 828 | |
| 829 CertificateList cert_list = CreateCertificateListFromFile( | |
| 830 GetTestCertsDirectory(), "reject_intranet_hosts.pem", | |
| 831 X509Certificate::FORMAT_AUTO); | |
| 832 ASSERT_EQ(1U, cert_list.size()); | |
| 833 scoped_refptr<X509Certificate> cert(cert_list[0]); | |
| 834 | |
| 835 CertVerifyResult verify_result; | |
| 836 int error = 0; | |
| 837 | |
| 838 // Intranet names for public CAs should be flagged: | |
| 839 verify_proc_ = new WellKnownCaCertVerifyProc(true); | |
| 840 error = | |
| 841 Verify(cert.get(), "intranet", 0, NULL, empty_cert_list_, &verify_result); | |
| 842 EXPECT_EQ(OK, error); | |
| 843 EXPECT_TRUE(verify_result.cert_status & CERT_STATUS_NON_UNIQUE_NAME); | |
| 844 | |
| 845 // However, if the CA is not well known, these should not be flagged: | |
| 846 verify_proc_ = new WellKnownCaCertVerifyProc(false); | |
| 847 error = | |
| 848 Verify(cert.get(), "intranet", 0, NULL, empty_cert_list_, &verify_result); | |
| 849 EXPECT_EQ(OK, error); | |
| 850 EXPECT_FALSE(verify_result.cert_status & CERT_STATUS_NON_UNIQUE_NAME); | |
| 851 } | |
| 852 | |
| 853 // Test that the certificate returned in CertVerifyResult is able to reorder | |
| 854 // certificates that are not ordered from end-entity to root. While this is | |
| 855 // a protocol violation if sent during a TLS handshake, if multiple sources | |
| 856 // of intermediate certificates are combined, it's possible that order may | |
| 857 // not be maintained. | |
| 858 TEST_F(CertVerifyProcTest, VerifyReturnChainProperlyOrdered) { | |
| 859 if (!SupportsReturningVerifiedChain()) { | |
| 860 LOG(INFO) << "Skipping this test in this platform."; | |
| 861 return; | |
| 862 } | |
| 863 | |
| 864 base::FilePath certs_dir = GetTestCertsDirectory(); | |
| 865 CertificateList certs = CreateCertificateListFromFile( | |
| 866 certs_dir, "x509_verify_results.chain.pem", | |
| 867 X509Certificate::FORMAT_AUTO); | |
| 868 ASSERT_EQ(3U, certs.size()); | |
| 869 | |
| 870 // Construct the chain out of order. | |
| 871 X509Certificate::OSCertHandles intermediates; | |
| 872 intermediates.push_back(certs[2]->os_cert_handle()); | |
| 873 intermediates.push_back(certs[1]->os_cert_handle()); | |
| 874 | |
| 875 ScopedTestRoot scoped_root(certs[2].get()); | |
| 876 | |
| 877 scoped_refptr<X509Certificate> google_full_chain = | |
| 878 X509Certificate::CreateFromHandle(certs[0]->os_cert_handle(), | |
| 879 intermediates); | |
| 880 ASSERT_NE(static_cast<X509Certificate*>(NULL), google_full_chain.get()); | |
| 881 ASSERT_EQ(2U, google_full_chain->GetIntermediateCertificates().size()); | |
| 882 | |
| 883 CertVerifyResult verify_result; | |
| 884 EXPECT_EQ(static_cast<X509Certificate*>(NULL), | |
| 885 verify_result.verified_cert.get()); | |
| 886 int error = Verify(google_full_chain.get(), | |
| 887 "127.0.0.1", | |
| 888 0, | |
| 889 NULL, | |
| 890 empty_cert_list_, | |
| 891 &verify_result); | |
| 892 EXPECT_EQ(OK, error); | |
| 893 ASSERT_NE(static_cast<X509Certificate*>(NULL), | |
| 894 verify_result.verified_cert.get()); | |
| 895 | |
| 896 EXPECT_NE(google_full_chain, verify_result.verified_cert); | |
| 897 EXPECT_TRUE(X509Certificate::IsSameOSCert( | |
| 898 google_full_chain->os_cert_handle(), | |
| 899 verify_result.verified_cert->os_cert_handle())); | |
| 900 const X509Certificate::OSCertHandles& return_intermediates = | |
| 901 verify_result.verified_cert->GetIntermediateCertificates(); | |
| 902 ASSERT_EQ(2U, return_intermediates.size()); | |
| 903 EXPECT_TRUE(X509Certificate::IsSameOSCert(return_intermediates[0], | |
| 904 certs[1]->os_cert_handle())); | |
| 905 EXPECT_TRUE(X509Certificate::IsSameOSCert(return_intermediates[1], | |
| 906 certs[2]->os_cert_handle())); | |
| 907 } | |
| 908 | |
| 909 // Test that Verify() filters out certificates which are not related to | |
| 910 // or part of the certificate chain being verified. | |
| 911 TEST_F(CertVerifyProcTest, VerifyReturnChainFiltersUnrelatedCerts) { | |
| 912 if (!SupportsReturningVerifiedChain()) { | |
| 913 LOG(INFO) << "Skipping this test in this platform."; | |
| 914 return; | |
| 915 } | |
| 916 | |
| 917 base::FilePath certs_dir = GetTestCertsDirectory(); | |
| 918 CertificateList certs = CreateCertificateListFromFile( | |
| 919 certs_dir, "x509_verify_results.chain.pem", | |
| 920 X509Certificate::FORMAT_AUTO); | |
| 921 ASSERT_EQ(3U, certs.size()); | |
| 922 ScopedTestRoot scoped_root(certs[2].get()); | |
| 923 | |
| 924 scoped_refptr<X509Certificate> unrelated_certificate = | |
| 925 ImportCertFromFile(certs_dir, "duplicate_cn_1.pem"); | |
| 926 scoped_refptr<X509Certificate> unrelated_certificate2 = | |
| 927 ImportCertFromFile(certs_dir, "aia-cert.pem"); | |
| 928 ASSERT_NE(static_cast<X509Certificate*>(NULL), unrelated_certificate.get()); | |
| 929 ASSERT_NE(static_cast<X509Certificate*>(NULL), unrelated_certificate2.get()); | |
| 930 | |
| 931 // Interject unrelated certificates into the list of intermediates. | |
| 932 X509Certificate::OSCertHandles intermediates; | |
| 933 intermediates.push_back(unrelated_certificate->os_cert_handle()); | |
| 934 intermediates.push_back(certs[1]->os_cert_handle()); | |
| 935 intermediates.push_back(unrelated_certificate2->os_cert_handle()); | |
| 936 intermediates.push_back(certs[2]->os_cert_handle()); | |
| 937 | |
| 938 scoped_refptr<X509Certificate> google_full_chain = | |
| 939 X509Certificate::CreateFromHandle(certs[0]->os_cert_handle(), | |
| 940 intermediates); | |
| 941 ASSERT_NE(static_cast<X509Certificate*>(NULL), google_full_chain.get()); | |
| 942 ASSERT_EQ(4U, google_full_chain->GetIntermediateCertificates().size()); | |
| 943 | |
| 944 CertVerifyResult verify_result; | |
| 945 EXPECT_EQ(static_cast<X509Certificate*>(NULL), | |
| 946 verify_result.verified_cert.get()); | |
| 947 int error = Verify(google_full_chain.get(), | |
| 948 "127.0.0.1", | |
| 949 0, | |
| 950 NULL, | |
| 951 empty_cert_list_, | |
| 952 &verify_result); | |
| 953 EXPECT_EQ(OK, error); | |
| 954 ASSERT_NE(static_cast<X509Certificate*>(NULL), | |
| 955 verify_result.verified_cert.get()); | |
| 956 | |
| 957 EXPECT_NE(google_full_chain, verify_result.verified_cert); | |
| 958 EXPECT_TRUE(X509Certificate::IsSameOSCert( | |
| 959 google_full_chain->os_cert_handle(), | |
| 960 verify_result.verified_cert->os_cert_handle())); | |
| 961 const X509Certificate::OSCertHandles& return_intermediates = | |
| 962 verify_result.verified_cert->GetIntermediateCertificates(); | |
| 963 ASSERT_EQ(2U, return_intermediates.size()); | |
| 964 EXPECT_TRUE(X509Certificate::IsSameOSCert(return_intermediates[0], | |
| 965 certs[1]->os_cert_handle())); | |
| 966 EXPECT_TRUE(X509Certificate::IsSameOSCert(return_intermediates[1], | |
| 967 certs[2]->os_cert_handle())); | |
| 968 } | |
| 969 | |
| 970 TEST_F(CertVerifyProcTest, AdditionalTrustAnchors) { | |
| 971 if (!SupportsAdditionalTrustAnchors()) { | |
| 972 LOG(INFO) << "Skipping this test in this platform."; | |
| 973 return; | |
| 974 } | |
| 975 | |
| 976 // |ca_cert| is the issuer of |cert|. | |
| 977 CertificateList ca_cert_list = CreateCertificateListFromFile( | |
| 978 GetTestCertsDirectory(), "root_ca_cert.pem", | |
| 979 X509Certificate::FORMAT_AUTO); | |
| 980 ASSERT_EQ(1U, ca_cert_list.size()); | |
| 981 scoped_refptr<X509Certificate> ca_cert(ca_cert_list[0]); | |
| 982 | |
| 983 CertificateList cert_list = CreateCertificateListFromFile( | |
| 984 GetTestCertsDirectory(), "ok_cert.pem", | |
| 985 X509Certificate::FORMAT_AUTO); | |
| 986 ASSERT_EQ(1U, cert_list.size()); | |
| 987 scoped_refptr<X509Certificate> cert(cert_list[0]); | |
| 988 | |
| 989 // Verification of |cert| fails when |ca_cert| is not in the trust anchors | |
| 990 // list. | |
| 991 int flags = 0; | |
| 992 CertVerifyResult verify_result; | |
| 993 int error = Verify( | |
| 994 cert.get(), "127.0.0.1", flags, NULL, empty_cert_list_, &verify_result); | |
| 995 EXPECT_EQ(ERR_CERT_AUTHORITY_INVALID, error); | |
| 996 EXPECT_EQ(CERT_STATUS_AUTHORITY_INVALID, verify_result.cert_status); | |
| 997 EXPECT_FALSE(verify_result.is_issued_by_additional_trust_anchor); | |
| 998 | |
| 999 // Now add the |ca_cert| to the |trust_anchors|, and verification should pass. | |
| 1000 CertificateList trust_anchors; | |
| 1001 trust_anchors.push_back(ca_cert); | |
| 1002 error = Verify( | |
| 1003 cert.get(), "127.0.0.1", flags, NULL, trust_anchors, &verify_result); | |
| 1004 EXPECT_EQ(OK, error); | |
| 1005 EXPECT_EQ(0U, verify_result.cert_status); | |
| 1006 EXPECT_TRUE(verify_result.is_issued_by_additional_trust_anchor); | |
| 1007 | |
| 1008 // Clearing the |trust_anchors| makes verification fail again (the cache | |
| 1009 // should be skipped). | |
| 1010 error = Verify( | |
| 1011 cert.get(), "127.0.0.1", flags, NULL, empty_cert_list_, &verify_result); | |
| 1012 EXPECT_EQ(ERR_CERT_AUTHORITY_INVALID, error); | |
| 1013 EXPECT_EQ(CERT_STATUS_AUTHORITY_INVALID, verify_result.cert_status); | |
| 1014 EXPECT_FALSE(verify_result.is_issued_by_additional_trust_anchor); | |
| 1015 } | |
| 1016 | |
| 1017 // Tests that certificates issued by user-supplied roots are not flagged as | |
| 1018 // issued by a known root. This should pass whether or not the platform supports | |
| 1019 // detecting known roots. | |
| 1020 TEST_F(CertVerifyProcTest, IsIssuedByKnownRootIgnoresTestRoots) { | |
| 1021 // Load root_ca_cert.pem into the test root store. | |
| 1022 TestRootCerts* root_certs = TestRootCerts::GetInstance(); | |
| 1023 root_certs->AddFromFile( | |
| 1024 GetTestCertsDirectory().AppendASCII("root_ca_cert.pem")); | |
| 1025 | |
| 1026 CertificateList cert_list = CreateCertificateListFromFile( | |
| 1027 GetTestCertsDirectory(), "ok_cert.pem", | |
| 1028 X509Certificate::FORMAT_AUTO); | |
| 1029 ASSERT_EQ(1U, cert_list.size()); | |
| 1030 scoped_refptr<X509Certificate> cert(cert_list[0]); | |
| 1031 | |
| 1032 // Verification should pass. | |
| 1033 int flags = 0; | |
| 1034 CertVerifyResult verify_result; | |
| 1035 int error = Verify( | |
| 1036 cert.get(), "127.0.0.1", flags, NULL, empty_cert_list_, &verify_result); | |
| 1037 EXPECT_EQ(OK, error); | |
| 1038 EXPECT_EQ(0U, verify_result.cert_status); | |
| 1039 // But should not be marked as a known root. | |
| 1040 EXPECT_FALSE(verify_result.is_issued_by_known_root); | |
| 1041 | |
| 1042 root_certs->Clear(); | |
| 1043 EXPECT_TRUE(root_certs->IsEmpty()); | |
| 1044 } | |
| 1045 | |
| 1046 #if defined(OS_MACOSX) && !defined(OS_IOS) | |
| 1047 // Tests that, on OS X, issues with a cross-certified Baltimore CyberTrust | |
| 1048 // Root can be successfully worked around once Apple completes removing the | |
| 1049 // older GTE CyberTrust Root from its trusted root store. | |
| 1050 // | |
| 1051 // The issue is caused by servers supplying the cross-certified intermediate | |
| 1052 // (necessary for certain mobile platforms), which OS X does not recognize | |
| 1053 // as already existing within its trust store. | |
| 1054 TEST_F(CertVerifyProcTest, CybertrustGTERoot) { | |
| 1055 CertificateList certs = CreateCertificateListFromFile( | |
| 1056 GetTestCertsDirectory(), | |
| 1057 "cybertrust_omniroot_chain.pem", | |
| 1058 X509Certificate::FORMAT_PEM_CERT_SEQUENCE); | |
| 1059 ASSERT_EQ(2U, certs.size()); | |
| 1060 | |
| 1061 X509Certificate::OSCertHandles intermediates; | |
| 1062 intermediates.push_back(certs[1]->os_cert_handle()); | |
| 1063 | |
| 1064 scoped_refptr<X509Certificate> cybertrust_basic = | |
| 1065 X509Certificate::CreateFromHandle(certs[0]->os_cert_handle(), | |
| 1066 intermediates); | |
| 1067 ASSERT_TRUE(cybertrust_basic.get()); | |
| 1068 | |
| 1069 scoped_refptr<X509Certificate> baltimore_root = | |
| 1070 ImportCertFromFile(GetTestCertsDirectory(), | |
| 1071 "cybertrust_baltimore_root.pem"); | |
| 1072 ASSERT_TRUE(baltimore_root.get()); | |
| 1073 | |
| 1074 ScopedTestRoot scoped_root(baltimore_root.get()); | |
| 1075 | |
| 1076 // Ensure that ONLY the Baltimore CyberTrust Root is trusted. This | |
| 1077 // simulates Keychain removing support for the GTE CyberTrust Root. | |
| 1078 TestRootCerts::GetInstance()->SetAllowSystemTrust(false); | |
| 1079 base::ScopedClosureRunner reset_system_trust( | |
| 1080 base::Bind(&TestRootCerts::SetAllowSystemTrust, | |
| 1081 base::Unretained(TestRootCerts::GetInstance()), | |
| 1082 true)); | |
| 1083 | |
| 1084 // First, make sure a simple certificate chain from | |
| 1085 // EE -> Public SureServer SV -> Baltimore CyberTrust | |
| 1086 // works. Only the first two certificates are included in the chain. | |
| 1087 int flags = 0; | |
| 1088 CertVerifyResult verify_result; | |
| 1089 int error = Verify(cybertrust_basic.get(), | |
| 1090 "cacert.omniroot.com", | |
| 1091 flags, | |
| 1092 NULL, | |
| 1093 empty_cert_list_, | |
| 1094 &verify_result); | |
| 1095 EXPECT_EQ(OK, error); | |
| 1096 EXPECT_EQ(CERT_STATUS_SHA1_SIGNATURE_PRESENT, verify_result.cert_status); | |
| 1097 | |
| 1098 // Attempt to verify with the first known cross-certified intermediate | |
| 1099 // provided. | |
| 1100 scoped_refptr<X509Certificate> baltimore_intermediate_1 = | |
| 1101 ImportCertFromFile(GetTestCertsDirectory(), | |
| 1102 "cybertrust_baltimore_cross_certified_1.pem"); | |
| 1103 ASSERT_TRUE(baltimore_intermediate_1.get()); | |
| 1104 | |
| 1105 X509Certificate::OSCertHandles intermediate_chain_1 = | |
| 1106 cybertrust_basic->GetIntermediateCertificates(); | |
| 1107 intermediate_chain_1.push_back(baltimore_intermediate_1->os_cert_handle()); | |
| 1108 | |
| 1109 scoped_refptr<X509Certificate> baltimore_chain_1 = | |
| 1110 X509Certificate::CreateFromHandle(cybertrust_basic->os_cert_handle(), | |
| 1111 intermediate_chain_1); | |
| 1112 error = Verify(baltimore_chain_1.get(), | |
| 1113 "cacert.omniroot.com", | |
| 1114 flags, | |
| 1115 NULL, | |
| 1116 empty_cert_list_, | |
| 1117 &verify_result); | |
| 1118 EXPECT_EQ(OK, error); | |
| 1119 EXPECT_EQ(CERT_STATUS_SHA1_SIGNATURE_PRESENT, verify_result.cert_status); | |
| 1120 | |
| 1121 // Attempt to verify with the second known cross-certified intermediate | |
| 1122 // provided. | |
| 1123 scoped_refptr<X509Certificate> baltimore_intermediate_2 = | |
| 1124 ImportCertFromFile(GetTestCertsDirectory(), | |
| 1125 "cybertrust_baltimore_cross_certified_2.pem"); | |
| 1126 ASSERT_TRUE(baltimore_intermediate_2.get()); | |
| 1127 | |
| 1128 X509Certificate::OSCertHandles intermediate_chain_2 = | |
| 1129 cybertrust_basic->GetIntermediateCertificates(); | |
| 1130 intermediate_chain_2.push_back(baltimore_intermediate_2->os_cert_handle()); | |
| 1131 | |
| 1132 scoped_refptr<X509Certificate> baltimore_chain_2 = | |
| 1133 X509Certificate::CreateFromHandle(cybertrust_basic->os_cert_handle(), | |
| 1134 intermediate_chain_2); | |
| 1135 error = Verify(baltimore_chain_2.get(), | |
| 1136 "cacert.omniroot.com", | |
| 1137 flags, | |
| 1138 NULL, | |
| 1139 empty_cert_list_, | |
| 1140 &verify_result); | |
| 1141 EXPECT_EQ(OK, error); | |
| 1142 EXPECT_EQ(CERT_STATUS_SHA1_SIGNATURE_PRESENT, verify_result.cert_status); | |
| 1143 | |
| 1144 // Attempt to verify when both a cross-certified intermediate AND | |
| 1145 // the legacy GTE root are provided. | |
| 1146 scoped_refptr<X509Certificate> cybertrust_root = | |
| 1147 ImportCertFromFile(GetTestCertsDirectory(), | |
| 1148 "cybertrust_gte_root.pem"); | |
| 1149 ASSERT_TRUE(cybertrust_root.get()); | |
| 1150 | |
| 1151 intermediate_chain_2.push_back(cybertrust_root->os_cert_handle()); | |
| 1152 scoped_refptr<X509Certificate> baltimore_chain_with_root = | |
| 1153 X509Certificate::CreateFromHandle(cybertrust_basic->os_cert_handle(), | |
| 1154 intermediate_chain_2); | |
| 1155 error = Verify(baltimore_chain_with_root.get(), | |
| 1156 "cacert.omniroot.com", | |
| 1157 flags, | |
| 1158 NULL, | |
| 1159 empty_cert_list_, | |
| 1160 &verify_result); | |
| 1161 EXPECT_EQ(OK, error); | |
| 1162 EXPECT_EQ(CERT_STATUS_SHA1_SIGNATURE_PRESENT, verify_result.cert_status); | |
| 1163 | |
| 1164 TestRootCerts::GetInstance()->Clear(); | |
| 1165 EXPECT_TRUE(TestRootCerts::GetInstance()->IsEmpty()); | |
| 1166 } | |
| 1167 #endif | |
| 1168 | |
| 1169 #if defined(USE_NSS) || defined(OS_IOS) || defined(OS_WIN) || defined(OS_MACOSX) | |
| 1170 // Test that CRLSets are effective in making a certificate appear to be | |
| 1171 // revoked. | |
| 1172 TEST_F(CertVerifyProcTest, CRLSet) { | |
| 1173 CertificateList ca_cert_list = | |
| 1174 CreateCertificateListFromFile(GetTestCertsDirectory(), | |
| 1175 "root_ca_cert.pem", | |
| 1176 X509Certificate::FORMAT_AUTO); | |
| 1177 ASSERT_EQ(1U, ca_cert_list.size()); | |
| 1178 ScopedTestRoot test_root(ca_cert_list[0].get()); | |
| 1179 | |
| 1180 CertificateList cert_list = CreateCertificateListFromFile( | |
| 1181 GetTestCertsDirectory(), "ok_cert.pem", X509Certificate::FORMAT_AUTO); | |
| 1182 ASSERT_EQ(1U, cert_list.size()); | |
| 1183 scoped_refptr<X509Certificate> cert(cert_list[0]); | |
| 1184 | |
| 1185 int flags = 0; | |
| 1186 CertVerifyResult verify_result; | |
| 1187 int error = Verify( | |
| 1188 cert.get(), "127.0.0.1", flags, NULL, empty_cert_list_, &verify_result); | |
| 1189 EXPECT_EQ(OK, error); | |
| 1190 EXPECT_EQ(0U, verify_result.cert_status); | |
| 1191 | |
| 1192 scoped_refptr<CRLSet> crl_set; | |
| 1193 std::string crl_set_bytes; | |
| 1194 | |
| 1195 // First test blocking by SPKI. | |
| 1196 EXPECT_TRUE(base::ReadFileToString( | |
| 1197 GetTestCertsDirectory().AppendASCII("crlset_by_leaf_spki.raw"), | |
| 1198 &crl_set_bytes)); | |
| 1199 ASSERT_TRUE(CRLSetStorage::Parse(crl_set_bytes, &crl_set)); | |
| 1200 | |
| 1201 error = Verify(cert.get(), | |
| 1202 "127.0.0.1", | |
| 1203 flags, | |
| 1204 crl_set.get(), | |
| 1205 empty_cert_list_, | |
| 1206 &verify_result); | |
| 1207 EXPECT_EQ(ERR_CERT_REVOKED, error); | |
| 1208 | |
| 1209 // Second, test revocation by serial number of a cert directly under the | |
| 1210 // root. | |
| 1211 crl_set_bytes.clear(); | |
| 1212 EXPECT_TRUE(base::ReadFileToString( | |
| 1213 GetTestCertsDirectory().AppendASCII("crlset_by_root_serial.raw"), | |
| 1214 &crl_set_bytes)); | |
| 1215 ASSERT_TRUE(CRLSetStorage::Parse(crl_set_bytes, &crl_set)); | |
| 1216 | |
| 1217 error = Verify(cert.get(), | |
| 1218 "127.0.0.1", | |
| 1219 flags, | |
| 1220 crl_set.get(), | |
| 1221 empty_cert_list_, | |
| 1222 &verify_result); | |
| 1223 EXPECT_EQ(ERR_CERT_REVOKED, error); | |
| 1224 } | |
| 1225 | |
| 1226 TEST_F(CertVerifyProcTest, CRLSetLeafSerial) { | |
| 1227 CertificateList ca_cert_list = | |
| 1228 CreateCertificateListFromFile(GetTestCertsDirectory(), | |
| 1229 "quic_root.crt", | |
| 1230 X509Certificate::FORMAT_AUTO); | |
| 1231 ASSERT_EQ(1U, ca_cert_list.size()); | |
| 1232 ScopedTestRoot test_root(ca_cert_list[0].get()); | |
| 1233 | |
| 1234 CertificateList intermediate_cert_list = | |
| 1235 CreateCertificateListFromFile(GetTestCertsDirectory(), | |
| 1236 "quic_intermediate.crt", | |
| 1237 X509Certificate::FORMAT_AUTO); | |
| 1238 ASSERT_EQ(1U, intermediate_cert_list.size()); | |
| 1239 X509Certificate::OSCertHandles intermediates; | |
| 1240 intermediates.push_back(intermediate_cert_list[0]->os_cert_handle()); | |
| 1241 | |
| 1242 CertificateList cert_list = CreateCertificateListFromFile( | |
| 1243 GetTestCertsDirectory(), "quic_test.example.com.crt", | |
| 1244 X509Certificate::FORMAT_AUTO); | |
| 1245 ASSERT_EQ(1U, cert_list.size()); | |
| 1246 | |
| 1247 scoped_refptr<X509Certificate> leaf = | |
| 1248 X509Certificate::CreateFromHandle(cert_list[0]->os_cert_handle(), | |
| 1249 intermediates); | |
| 1250 | |
| 1251 int flags = 0; | |
| 1252 CertVerifyResult verify_result; | |
| 1253 int error = Verify(leaf.get(), | |
| 1254 "test.example.com", | |
| 1255 flags, | |
| 1256 NULL, | |
| 1257 empty_cert_list_, | |
| 1258 &verify_result); | |
| 1259 EXPECT_EQ(OK, error); | |
| 1260 EXPECT_EQ(CERT_STATUS_SHA1_SIGNATURE_PRESENT, verify_result.cert_status); | |
| 1261 | |
| 1262 // Test revocation by serial number of a certificate not under the root. | |
| 1263 scoped_refptr<CRLSet> crl_set; | |
| 1264 std::string crl_set_bytes; | |
| 1265 ASSERT_TRUE(base::ReadFileToString( | |
| 1266 GetTestCertsDirectory().AppendASCII("crlset_by_intermediate_serial.raw"), | |
| 1267 &crl_set_bytes)); | |
| 1268 ASSERT_TRUE(CRLSetStorage::Parse(crl_set_bytes, &crl_set)); | |
| 1269 | |
| 1270 error = Verify(leaf.get(), | |
| 1271 "test.example.com", | |
| 1272 flags, | |
| 1273 crl_set.get(), | |
| 1274 empty_cert_list_, | |
| 1275 &verify_result); | |
| 1276 EXPECT_EQ(ERR_CERT_REVOKED, error); | |
| 1277 } | |
| 1278 #endif | |
| 1279 | |
| 1280 enum ExpectedAlgorithms { | |
| 1281 EXPECT_MD2 = 1 << 0, | |
| 1282 EXPECT_MD4 = 1 << 1, | |
| 1283 EXPECT_MD5 = 1 << 2, | |
| 1284 EXPECT_SHA1 = 1 << 3 | |
| 1285 }; | |
| 1286 | |
| 1287 struct WeakDigestTestData { | |
| 1288 const char* root_cert_filename; | |
| 1289 const char* intermediate_cert_filename; | |
| 1290 const char* ee_cert_filename; | |
| 1291 int expected_algorithms; | |
| 1292 }; | |
| 1293 | |
| 1294 // GTest 'magic' pretty-printer, so that if/when a test fails, it knows how | |
| 1295 // to output the parameter that was passed. Without this, it will simply | |
| 1296 // attempt to print out the first twenty bytes of the object, which depending | |
| 1297 // on platform and alignment, may result in an invalid read. | |
| 1298 void PrintTo(const WeakDigestTestData& data, std::ostream* os) { | |
| 1299 *os << "root: " | |
| 1300 << (data.root_cert_filename ? data.root_cert_filename : "none") | |
| 1301 << "; intermediate: " << data.intermediate_cert_filename | |
| 1302 << "; end-entity: " << data.ee_cert_filename; | |
| 1303 } | |
| 1304 | |
| 1305 class CertVerifyProcWeakDigestTest | |
| 1306 : public CertVerifyProcTest, | |
| 1307 public testing::WithParamInterface<WeakDigestTestData> { | |
| 1308 public: | |
| 1309 CertVerifyProcWeakDigestTest() {} | |
| 1310 virtual ~CertVerifyProcWeakDigestTest() {} | |
| 1311 }; | |
| 1312 | |
| 1313 TEST_P(CertVerifyProcWeakDigestTest, Verify) { | |
| 1314 WeakDigestTestData data = GetParam(); | |
| 1315 base::FilePath certs_dir = GetTestCertsDirectory(); | |
| 1316 | |
| 1317 ScopedTestRoot test_root; | |
| 1318 if (data.root_cert_filename) { | |
| 1319 scoped_refptr<X509Certificate> root_cert = | |
| 1320 ImportCertFromFile(certs_dir, data.root_cert_filename); | |
| 1321 ASSERT_NE(static_cast<X509Certificate*>(NULL), root_cert.get()); | |
| 1322 test_root.Reset(root_cert.get()); | |
| 1323 } | |
| 1324 | |
| 1325 scoped_refptr<X509Certificate> intermediate_cert = | |
| 1326 ImportCertFromFile(certs_dir, data.intermediate_cert_filename); | |
| 1327 ASSERT_NE(static_cast<X509Certificate*>(NULL), intermediate_cert.get()); | |
| 1328 scoped_refptr<X509Certificate> ee_cert = | |
| 1329 ImportCertFromFile(certs_dir, data.ee_cert_filename); | |
| 1330 ASSERT_NE(static_cast<X509Certificate*>(NULL), ee_cert.get()); | |
| 1331 | |
| 1332 X509Certificate::OSCertHandles intermediates; | |
| 1333 intermediates.push_back(intermediate_cert->os_cert_handle()); | |
| 1334 | |
| 1335 scoped_refptr<X509Certificate> ee_chain = | |
| 1336 X509Certificate::CreateFromHandle(ee_cert->os_cert_handle(), | |
| 1337 intermediates); | |
| 1338 ASSERT_NE(static_cast<X509Certificate*>(NULL), ee_chain.get()); | |
| 1339 | |
| 1340 int flags = 0; | |
| 1341 CertVerifyResult verify_result; | |
| 1342 int rv = Verify(ee_chain.get(), | |
| 1343 "127.0.0.1", | |
| 1344 flags, | |
| 1345 NULL, | |
| 1346 empty_cert_list_, | |
| 1347 &verify_result); | |
| 1348 EXPECT_EQ(!!(data.expected_algorithms & EXPECT_MD2), verify_result.has_md2); | |
| 1349 EXPECT_EQ(!!(data.expected_algorithms & EXPECT_MD4), verify_result.has_md4); | |
| 1350 EXPECT_EQ(!!(data.expected_algorithms & EXPECT_MD5), verify_result.has_md5); | |
| 1351 EXPECT_EQ(!!(data.expected_algorithms & EXPECT_SHA1), verify_result.has_sha1); | |
| 1352 | |
| 1353 EXPECT_FALSE(verify_result.is_issued_by_additional_trust_anchor); | |
| 1354 | |
| 1355 // Ensure that MD4 and MD2 are tagged as invalid. | |
| 1356 if (data.expected_algorithms & (EXPECT_MD2 | EXPECT_MD4)) { | |
| 1357 EXPECT_EQ(CERT_STATUS_INVALID, | |
| 1358 verify_result.cert_status & CERT_STATUS_INVALID); | |
| 1359 } | |
| 1360 | |
| 1361 // Ensure that MD5 is flagged as weak. | |
| 1362 if (data.expected_algorithms & EXPECT_MD5) { | |
| 1363 EXPECT_EQ( | |
| 1364 CERT_STATUS_WEAK_SIGNATURE_ALGORITHM, | |
| 1365 verify_result.cert_status & CERT_STATUS_WEAK_SIGNATURE_ALGORITHM); | |
| 1366 } | |
| 1367 | |
| 1368 // If a root cert is present, then check that the chain was rejected if any | |
| 1369 // weak algorithms are present. This is only checked when a root cert is | |
| 1370 // present because the error reported for incomplete chains with weak | |
| 1371 // algorithms depends on which implementation was used to validate (NSS, | |
| 1372 // OpenSSL, CryptoAPI, Security.framework) and upon which weak algorithm | |
| 1373 // present (MD2, MD4, MD5). | |
| 1374 if (data.root_cert_filename) { | |
| 1375 if (data.expected_algorithms & (EXPECT_MD2 | EXPECT_MD4)) { | |
| 1376 EXPECT_EQ(ERR_CERT_INVALID, rv); | |
| 1377 } else if (data.expected_algorithms & EXPECT_MD5) { | |
| 1378 EXPECT_EQ(ERR_CERT_WEAK_SIGNATURE_ALGORITHM, rv); | |
| 1379 } else { | |
| 1380 EXPECT_EQ(OK, rv); | |
| 1381 } | |
| 1382 } | |
| 1383 } | |
| 1384 | |
| 1385 // Unlike TEST/TEST_F, which are macros that expand to further macros, | |
| 1386 // INSTANTIATE_TEST_CASE_P is a macro that expands directly to code that | |
| 1387 // stringizes the arguments. As a result, macros passed as parameters (such as | |
| 1388 // prefix or test_case_name) will not be expanded by the preprocessor. To work | |
| 1389 // around this, indirect the macro for INSTANTIATE_TEST_CASE_P, so that the | |
| 1390 // pre-processor will expand macros such as MAYBE_test_name before | |
| 1391 // instantiating the test. | |
| 1392 #define WRAPPED_INSTANTIATE_TEST_CASE_P(prefix, test_case_name, generator) \ | |
| 1393 INSTANTIATE_TEST_CASE_P(prefix, test_case_name, generator) | |
| 1394 | |
| 1395 // The signature algorithm of the root CA should not matter. | |
| 1396 const WeakDigestTestData kVerifyRootCATestData[] = { | |
| 1397 { "weak_digest_md5_root.pem", "weak_digest_sha1_intermediate.pem", | |
| 1398 "weak_digest_sha1_ee.pem", EXPECT_SHA1 }, | |
| 1399 #if defined(USE_OPENSSL_CERTS) || defined(OS_WIN) | |
| 1400 // MD4 is not supported by OS X / NSS | |
| 1401 { "weak_digest_md4_root.pem", "weak_digest_sha1_intermediate.pem", | |
| 1402 "weak_digest_sha1_ee.pem", EXPECT_SHA1 }, | |
| 1403 #endif | |
| 1404 { "weak_digest_md2_root.pem", "weak_digest_sha1_intermediate.pem", | |
| 1405 "weak_digest_sha1_ee.pem", EXPECT_SHA1 }, | |
| 1406 }; | |
| 1407 INSTANTIATE_TEST_CASE_P(VerifyRoot, CertVerifyProcWeakDigestTest, | |
| 1408 testing::ValuesIn(kVerifyRootCATestData)); | |
| 1409 | |
| 1410 // The signature algorithm of intermediates should be properly detected. | |
| 1411 const WeakDigestTestData kVerifyIntermediateCATestData[] = { | |
| 1412 { "weak_digest_sha1_root.pem", "weak_digest_md5_intermediate.pem", | |
| 1413 "weak_digest_sha1_ee.pem", EXPECT_MD5 | EXPECT_SHA1 }, | |
| 1414 #if defined(USE_OPENSSL_CERTS) || defined(OS_WIN) | |
| 1415 // MD4 is not supported by OS X / NSS | |
| 1416 { "weak_digest_sha1_root.pem", "weak_digest_md4_intermediate.pem", | |
| 1417 "weak_digest_sha1_ee.pem", EXPECT_MD4 | EXPECT_SHA1 }, | |
| 1418 #endif | |
| 1419 { "weak_digest_sha1_root.pem", "weak_digest_md2_intermediate.pem", | |
| 1420 "weak_digest_sha1_ee.pem", EXPECT_MD2 | EXPECT_SHA1 }, | |
| 1421 }; | |
| 1422 // Disabled on NSS - MD4 is not supported, and MD2 and MD5 are disabled. | |
| 1423 #if defined(USE_NSS) || defined(OS_IOS) | |
| 1424 #define MAYBE_VerifyIntermediate DISABLED_VerifyIntermediate | |
| 1425 #else | |
| 1426 #define MAYBE_VerifyIntermediate VerifyIntermediate | |
| 1427 #endif | |
| 1428 WRAPPED_INSTANTIATE_TEST_CASE_P( | |
| 1429 MAYBE_VerifyIntermediate, | |
| 1430 CertVerifyProcWeakDigestTest, | |
| 1431 testing::ValuesIn(kVerifyIntermediateCATestData)); | |
| 1432 | |
| 1433 // The signature algorithm of end-entity should be properly detected. | |
| 1434 const WeakDigestTestData kVerifyEndEntityTestData[] = { | |
| 1435 { "weak_digest_sha1_root.pem", "weak_digest_sha1_intermediate.pem", | |
| 1436 "weak_digest_md5_ee.pem", EXPECT_MD5 | EXPECT_SHA1 }, | |
| 1437 #if defined(USE_OPENSSL_CERTS) || defined(OS_WIN) | |
| 1438 // MD4 is not supported by OS X / NSS | |
| 1439 { "weak_digest_sha1_root.pem", "weak_digest_sha1_intermediate.pem", | |
| 1440 "weak_digest_md4_ee.pem", EXPECT_MD4 | EXPECT_SHA1 }, | |
| 1441 #endif | |
| 1442 { "weak_digest_sha1_root.pem", "weak_digest_sha1_intermediate.pem", | |
| 1443 "weak_digest_md2_ee.pem", EXPECT_MD2 | EXPECT_SHA1 }, | |
| 1444 }; | |
| 1445 // Disabled on NSS - NSS caches chains/signatures in such a way that cannot | |
| 1446 // be cleared until NSS is cleanly shutdown, which is not presently supported | |
| 1447 // in Chromium. | |
| 1448 #if defined(USE_NSS) || defined(OS_IOS) | |
| 1449 #define MAYBE_VerifyEndEntity DISABLED_VerifyEndEntity | |
| 1450 #else | |
| 1451 #define MAYBE_VerifyEndEntity VerifyEndEntity | |
| 1452 #endif | |
| 1453 WRAPPED_INSTANTIATE_TEST_CASE_P(MAYBE_VerifyEndEntity, | |
| 1454 CertVerifyProcWeakDigestTest, | |
| 1455 testing::ValuesIn(kVerifyEndEntityTestData)); | |
| 1456 | |
| 1457 // Incomplete chains should still report the status of the intermediate. | |
| 1458 const WeakDigestTestData kVerifyIncompleteIntermediateTestData[] = { | |
| 1459 { NULL, "weak_digest_md5_intermediate.pem", "weak_digest_sha1_ee.pem", | |
| 1460 EXPECT_MD5 | EXPECT_SHA1 }, | |
| 1461 #if defined(USE_OPENSSL_CERTS) || defined(OS_WIN) | |
| 1462 // MD4 is not supported by OS X / NSS | |
| 1463 { NULL, "weak_digest_md4_intermediate.pem", "weak_digest_sha1_ee.pem", | |
| 1464 EXPECT_MD4 | EXPECT_SHA1 }, | |
| 1465 #endif | |
| 1466 { NULL, "weak_digest_md2_intermediate.pem", "weak_digest_sha1_ee.pem", | |
| 1467 EXPECT_MD2 | EXPECT_SHA1 }, | |
| 1468 }; | |
| 1469 // Disabled on NSS - libpkix does not return constructed chains on error, | |
| 1470 // preventing us from detecting/inspecting the verified chain. | |
| 1471 #if defined(USE_NSS) || defined(OS_IOS) | |
| 1472 #define MAYBE_VerifyIncompleteIntermediate \ | |
| 1473 DISABLED_VerifyIncompleteIntermediate | |
| 1474 #else | |
| 1475 #define MAYBE_VerifyIncompleteIntermediate VerifyIncompleteIntermediate | |
| 1476 #endif | |
| 1477 WRAPPED_INSTANTIATE_TEST_CASE_P( | |
| 1478 MAYBE_VerifyIncompleteIntermediate, | |
| 1479 CertVerifyProcWeakDigestTest, | |
| 1480 testing::ValuesIn(kVerifyIncompleteIntermediateTestData)); | |
| 1481 | |
| 1482 // Incomplete chains should still report the status of the end-entity. | |
| 1483 const WeakDigestTestData kVerifyIncompleteEETestData[] = { | |
| 1484 { NULL, "weak_digest_sha1_intermediate.pem", "weak_digest_md5_ee.pem", | |
| 1485 EXPECT_MD5 | EXPECT_SHA1 }, | |
| 1486 #if defined(USE_OPENSSL_CERTS) || defined(OS_WIN) | |
| 1487 // MD4 is not supported by OS X / NSS | |
| 1488 { NULL, "weak_digest_sha1_intermediate.pem", "weak_digest_md4_ee.pem", | |
| 1489 EXPECT_MD4 | EXPECT_SHA1 }, | |
| 1490 #endif | |
| 1491 { NULL, "weak_digest_sha1_intermediate.pem", "weak_digest_md2_ee.pem", | |
| 1492 EXPECT_MD2 | EXPECT_SHA1 }, | |
| 1493 }; | |
| 1494 // Disabled on NSS - libpkix does not return constructed chains on error, | |
| 1495 // preventing us from detecting/inspecting the verified chain. | |
| 1496 #if defined(USE_NSS) || defined(OS_IOS) | |
| 1497 #define MAYBE_VerifyIncompleteEndEntity DISABLED_VerifyIncompleteEndEntity | |
| 1498 #else | |
| 1499 #define MAYBE_VerifyIncompleteEndEntity VerifyIncompleteEndEntity | |
| 1500 #endif | |
| 1501 WRAPPED_INSTANTIATE_TEST_CASE_P( | |
| 1502 MAYBE_VerifyIncompleteEndEntity, | |
| 1503 CertVerifyProcWeakDigestTest, | |
| 1504 testing::ValuesIn(kVerifyIncompleteEETestData)); | |
| 1505 | |
| 1506 // Differing algorithms between the intermediate and the EE should still be | |
| 1507 // reported. | |
| 1508 const WeakDigestTestData kVerifyMixedTestData[] = { | |
| 1509 { "weak_digest_sha1_root.pem", "weak_digest_md5_intermediate.pem", | |
| 1510 "weak_digest_md2_ee.pem", EXPECT_MD2 | EXPECT_MD5 }, | |
| 1511 { "weak_digest_sha1_root.pem", "weak_digest_md2_intermediate.pem", | |
| 1512 "weak_digest_md5_ee.pem", EXPECT_MD2 | EXPECT_MD5 }, | |
| 1513 #if defined(USE_OPENSSL_CERTS) || defined(OS_WIN) | |
| 1514 // MD4 is not supported by OS X / NSS | |
| 1515 { "weak_digest_sha1_root.pem", "weak_digest_md4_intermediate.pem", | |
| 1516 "weak_digest_md2_ee.pem", EXPECT_MD2 | EXPECT_MD4 }, | |
| 1517 #endif | |
| 1518 }; | |
| 1519 // NSS does not support MD4 and does not enable MD2 by default, making all | |
| 1520 // permutations invalid. | |
| 1521 #if defined(USE_NSS) || defined(OS_IOS) | |
| 1522 #define MAYBE_VerifyMixed DISABLED_VerifyMixed | |
| 1523 #else | |
| 1524 #define MAYBE_VerifyMixed VerifyMixed | |
| 1525 #endif | |
| 1526 WRAPPED_INSTANTIATE_TEST_CASE_P( | |
| 1527 MAYBE_VerifyMixed, | |
| 1528 CertVerifyProcWeakDigestTest, | |
| 1529 testing::ValuesIn(kVerifyMixedTestData)); | |
| 1530 | |
| 1531 // For the list of valid hostnames, see | |
| 1532 // net/cert/data/ssl/certificates/subjectAltName_sanity_check.pem | |
| 1533 static const struct CertVerifyProcNameData { | |
| 1534 const char* hostname; | |
| 1535 bool valid; // Whether or not |hostname| matches a subjectAltName. | |
| 1536 } kVerifyNameData[] = { | |
| 1537 { "127.0.0.1", false }, // Don't match the common name | |
| 1538 { "127.0.0.2", true }, // Matches the iPAddress SAN (IPv4) | |
| 1539 { "FE80:0:0:0:0:0:0:1", true }, // Matches the iPAddress SAN (IPv6) | |
| 1540 { "[FE80:0:0:0:0:0:0:1]", false }, // Should not match the iPAddress SAN | |
| 1541 { "FE80::1", true }, // Compressed form matches the iPAddress SAN (IPv6) | |
| 1542 { "::127.0.0.2", false }, // IPv6 mapped form should NOT match iPAddress SAN | |
| 1543 { "test.example", true }, // Matches the dNSName SAN | |
| 1544 { "test.example.", true }, // Matches the dNSName SAN (trailing . ignored) | |
| 1545 { "www.test.example", false }, // Should not match the dNSName SAN | |
| 1546 { "test..example", false }, // Should not match the dNSName SAN | |
| 1547 { "test.example..", false }, // Should not match the dNSName SAN | |
| 1548 { ".test.example.", false }, // Should not match the dNSName SAN | |
| 1549 { ".test.example", false }, // Should not match the dNSName SAN | |
| 1550 }; | |
| 1551 | |
| 1552 // GTest 'magic' pretty-printer, so that if/when a test fails, it knows how | |
| 1553 // to output the parameter that was passed. Without this, it will simply | |
| 1554 // attempt to print out the first twenty bytes of the object, which depending | |
| 1555 // on platform and alignment, may result in an invalid read. | |
| 1556 void PrintTo(const CertVerifyProcNameData& data, std::ostream* os) { | |
| 1557 *os << "Hostname: " << data.hostname << "; valid=" << data.valid; | |
| 1558 } | |
| 1559 | |
| 1560 class CertVerifyProcNameTest | |
| 1561 : public CertVerifyProcTest, | |
| 1562 public testing::WithParamInterface<CertVerifyProcNameData> { | |
| 1563 public: | |
| 1564 CertVerifyProcNameTest() {} | |
| 1565 virtual ~CertVerifyProcNameTest() {} | |
| 1566 }; | |
| 1567 | |
| 1568 TEST_P(CertVerifyProcNameTest, VerifyCertName) { | |
| 1569 CertVerifyProcNameData data = GetParam(); | |
| 1570 | |
| 1571 CertificateList cert_list = CreateCertificateListFromFile( | |
| 1572 GetTestCertsDirectory(), "subjectAltName_sanity_check.pem", | |
| 1573 X509Certificate::FORMAT_AUTO); | |
| 1574 ASSERT_EQ(1U, cert_list.size()); | |
| 1575 scoped_refptr<X509Certificate> cert(cert_list[0]); | |
| 1576 | |
| 1577 ScopedTestRoot scoped_root(cert.get()); | |
| 1578 | |
| 1579 CertVerifyResult verify_result; | |
| 1580 int error = Verify(cert.get(), data.hostname, 0, NULL, empty_cert_list_, | |
| 1581 &verify_result); | |
| 1582 if (data.valid) { | |
| 1583 EXPECT_EQ(OK, error); | |
| 1584 EXPECT_FALSE(verify_result.cert_status & CERT_STATUS_COMMON_NAME_INVALID); | |
| 1585 } else { | |
| 1586 EXPECT_EQ(ERR_CERT_COMMON_NAME_INVALID, error); | |
| 1587 EXPECT_TRUE(verify_result.cert_status & CERT_STATUS_COMMON_NAME_INVALID); | |
| 1588 } | |
| 1589 } | |
| 1590 | |
| 1591 WRAPPED_INSTANTIATE_TEST_CASE_P( | |
| 1592 VerifyName, | |
| 1593 CertVerifyProcNameTest, | |
| 1594 testing::ValuesIn(kVerifyNameData)); | |
| 1595 | |
| 1596 } // namespace net | |
| OLD | NEW |