Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright 2014 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 "chrome/browser/chromeos/net/cert_verify_proc_chromeos.h" | |
| 6 | |
| 7 #include "crypto/nss_util.h" | |
| 8 #include "crypto/nss_util_internal.h" | |
| 9 #include "net/base/net_errors.h" | |
| 10 #include "net/base/test_data_directory.h" | |
| 11 #include "net/cert/cert_verify_proc.h" | |
| 12 #include "net/cert/cert_verify_result.h" | |
| 13 #include "net/cert/nss_cert_database_chromeos.h" | |
| 14 #include "net/test/cert_test_util.h" | |
| 15 #include "testing/gtest/include/gtest/gtest.h" | |
| 16 | |
| 17 namespace chromeos { | |
| 18 | |
| 19 class CertVerifyProcChromeOSTest : public testing::Test { | |
| 20 public: | |
| 21 CertVerifyProcChromeOSTest() : user_1_("user1"), user_2_("user2") {} | |
| 22 | |
| 23 virtual void SetUp() OVERRIDE { | |
| 24 // Initialize nss_util slots. | |
| 25 ASSERT_TRUE(user_1_.constructed_successfully()); | |
| 26 ASSERT_TRUE(user_2_.constructed_successfully()); | |
| 27 user_1_.FinishInit(); | |
| 28 user_2_.FinishInit(); | |
| 29 | |
| 30 // Create NSSCertDatabaseChromeOS for each user. | |
| 31 db_1_.reset(new net::NSSCertDatabaseChromeOS( | |
| 32 crypto::GetPublicSlotForChromeOSUser(user_1_.username_hash()), | |
| 33 crypto::GetPrivateSlotForChromeOSUser( | |
| 34 user_1_.username_hash(), | |
| 35 base::Callback<void(crypto::ScopedPK11Slot)>()))); | |
| 36 db_2_.reset(new net::NSSCertDatabaseChromeOS( | |
| 37 crypto::GetPublicSlotForChromeOSUser(user_2_.username_hash()), | |
| 38 crypto::GetPrivateSlotForChromeOSUser( | |
| 39 user_2_.username_hash(), | |
| 40 base::Callback<void(crypto::ScopedPK11Slot)>()))); | |
| 41 | |
| 42 // Create default verifier and for each user. | |
| 43 verify_proc_default_ = new CertVerifyProcChromeOS(); | |
| 44 verify_proc_1_ = new CertVerifyProcChromeOS( | |
| 45 crypto::GetPublicSlotForChromeOSUser(user_1_.username_hash())); | |
| 46 verify_proc_2_ = new CertVerifyProcChromeOS( | |
| 47 crypto::GetPublicSlotForChromeOSUser(user_2_.username_hash())); | |
|
Ryan Sleevi
2014/01/30 05:27:40
cache public slots as part of init? (Note lines 37
mattm
2014/02/04 05:31:21
That ended up being messier looking, but there is
| |
| 48 | |
| 49 // Load test cert chains from disk. | |
| 50 certs_1_ = | |
| 51 net::CreateCertificateListFromFile(net::GetTestCertsDirectory(), | |
| 52 "foo-chain1.pem", | |
| 53 net::X509Certificate::FORMAT_AUTO); | |
| 54 ASSERT_EQ(4U, certs_1_.size()); | |
| 55 | |
| 56 certs_2_ = | |
| 57 net::CreateCertificateListFromFile(net::GetTestCertsDirectory(), | |
| 58 "foo-chain2.pem", | |
| 59 net::X509Certificate::FORMAT_AUTO); | |
| 60 ASSERT_EQ(4U, certs_2_.size()); | |
| 61 | |
| 62 // The chains: | |
| 63 // 1. A (end-entity) -> B -> C -> D (self-signed root) | |
| 64 // 2. A (end-entity) -> B -> C2 -> E (self-signed root) | |
| 65 ASSERT_TRUE(certs_1_[0]->Equals(certs_2_[0])); | |
| 66 ASSERT_TRUE(certs_1_[1]->Equals(certs_2_[1])); | |
| 67 ASSERT_FALSE(certs_1_[2]->Equals(certs_2_[2])); | |
| 68 ASSERT_EQ("C CA", certs_1_[2]->subject().common_name); | |
| 69 ASSERT_EQ("C CA", certs_2_[2]->subject().common_name); | |
| 70 | |
| 71 root_1_.push_back(certs_1_.back()); | |
| 72 root_2_.push_back(certs_2_.back()); | |
| 73 | |
| 74 ASSERT_EQ("D Root CA", root_1_[0]->subject().common_name); | |
| 75 ASSERT_EQ("E Root CA", root_2_[0]->subject().common_name); | |
| 76 } | |
| 77 | |
| 78 int VerifyWithAdditionalTrustAnchors( | |
| 79 net::CertVerifyProc* verify_proc, | |
| 80 const net::CertificateList& additional_trust_anchors, | |
| 81 net::X509Certificate* cert, | |
| 82 std::string* root_subject_name) { | |
| 83 int flags = 0; | |
| 84 net::CertVerifyResult verify_result; | |
| 85 int error = verify_proc->Verify(cert, | |
| 86 "127.0.0.1", | |
| 87 flags, | |
| 88 NULL, | |
| 89 additional_trust_anchors, | |
| 90 &verify_result); | |
| 91 if (verify_result.verified_cert.get() && | |
| 92 !verify_result.verified_cert->GetIntermediateCertificates().empty()) { | |
| 93 net::X509Certificate::OSCertHandle root = | |
| 94 verify_result.verified_cert->GetIntermediateCertificates().back(); | |
| 95 *root_subject_name = root->subjectName; | |
|
Ryan Sleevi
2014/01/30 05:27:40
root_subject_name->assign() ?
mattm
2014/02/04 05:31:21
Done.
| |
| 96 } else { | |
| 97 *root_subject_name = ""; | |
|
Ryan Sleevi
2014/01/30 05:27:40
root_subject_name->clear()
mattm
2014/02/04 05:31:21
Done.
| |
| 98 } | |
| 99 return error; | |
| 100 } | |
| 101 | |
| 102 int Verify(net::CertVerifyProc* verify_proc, | |
| 103 net::X509Certificate* cert, | |
| 104 std::string* root_subject_name) { | |
| 105 net::CertificateList additional_trust_anchors; | |
| 106 return VerifyWithAdditionalTrustAnchors( | |
| 107 verify_proc, additional_trust_anchors, cert, root_subject_name); | |
| 108 } | |
| 109 | |
| 110 protected: | |
| 111 crypto::ScopedTestNSSChromeOSUser user_1_; | |
| 112 crypto::ScopedTestNSSChromeOSUser user_2_; | |
| 113 scoped_ptr<net::NSSCertDatabaseChromeOS> db_1_; | |
| 114 scoped_ptr<net::NSSCertDatabaseChromeOS> db_2_; | |
| 115 scoped_refptr<net::CertVerifyProc> verify_proc_default_; | |
| 116 scoped_refptr<net::CertVerifyProc> verify_proc_1_; | |
| 117 scoped_refptr<net::CertVerifyProc> verify_proc_2_; | |
| 118 net::CertificateList certs_1_; | |
| 119 net::CertificateList certs_2_; | |
| 120 net::CertificateList root_1_; | |
| 121 net::CertificateList root_2_; | |
| 122 }; | |
| 123 | |
| 124 // XXX | |
|
Ryan Sleevi
2014/01/30 05:27:40
XXX - Document :)
mattm
2014/02/04 05:31:21
Done.
| |
| 125 TEST_F(CertVerifyProcChromeOSTest, TestChainVerify) { | |
| 126 scoped_refptr<net::X509Certificate> server = certs_1_[0]; | |
| 127 std::string verify_root; | |
| 128 // Before either of the root certs have been trusted, all verifications should | |
| 129 // fail with CERT_AUTHORITY_INVALID. | |
| 130 EXPECT_EQ(net::ERR_CERT_AUTHORITY_INVALID, | |
| 131 Verify(verify_proc_default_.get(), server.get(), &verify_root)); | |
| 132 EXPECT_EQ(net::ERR_CERT_AUTHORITY_INVALID, | |
| 133 Verify(verify_proc_1_.get(), server.get(), &verify_root)); | |
| 134 EXPECT_EQ(net::ERR_CERT_AUTHORITY_INVALID, | |
| 135 Verify(verify_proc_2_.get(), server.get(), &verify_root)); | |
| 136 | |
| 137 // Import and trust the D root for user 1. | |
| 138 net::NSSCertDatabase::ImportCertFailureList failed; | |
| 139 EXPECT_TRUE(db_1_->ImportCACerts( | |
| 140 root_1_, net::NSSCertDatabase::TRUSTED_SSL, &failed)); | |
| 141 EXPECT_EQ(0U, failed.size()); | |
| 142 | |
| 143 // Imported CA certs are not trusted by default verifier. | |
| 144 EXPECT_EQ(net::ERR_CERT_AUTHORITY_INVALID, | |
| 145 Verify(verify_proc_default_.get(), server.get(), &verify_root)); | |
| 146 // User 1 should now verify successfully through the D root. | |
| 147 EXPECT_EQ(net::OK, Verify(verify_proc_1_.get(), server.get(), &verify_root)); | |
| 148 EXPECT_EQ("CN=D Root CA", verify_root); | |
| 149 // User 2 should still fail. | |
| 150 EXPECT_EQ(net::ERR_CERT_AUTHORITY_INVALID, | |
| 151 Verify(verify_proc_2_.get(), server.get(), &verify_root)); | |
| 152 | |
| 153 // Import and trust the E root for user 2. | |
| 154 failed.clear(); | |
| 155 EXPECT_TRUE(db_2_->ImportCACerts( | |
| 156 root_2_, net::NSSCertDatabase::TRUSTED_SSL, &failed)); | |
| 157 EXPECT_EQ(0U, failed.size()); | |
| 158 | |
| 159 // Imported CA certs are not trusted by default verifier. | |
| 160 EXPECT_EQ(net::ERR_CERT_AUTHORITY_INVALID, | |
| 161 Verify(verify_proc_default_.get(), server.get(), &verify_root)); | |
| 162 // User 1 should still verify successfully through the D root. | |
| 163 EXPECT_EQ(net::OK, Verify(verify_proc_1_.get(), server.get(), &verify_root)); | |
| 164 EXPECT_EQ("CN=D Root CA", verify_root); | |
| 165 // User 2 should now verify successfully through the E root. | |
| 166 EXPECT_EQ(net::OK, Verify(verify_proc_2_.get(), server.get(), &verify_root)); | |
| 167 EXPECT_EQ("CN=E Root CA", verify_root); | |
| 168 | |
| 169 // Delete D root. | |
| 170 EXPECT_TRUE(db_1_->DeleteCertAndKey(root_1_[0])); | |
| 171 EXPECT_EQ(net::ERR_CERT_AUTHORITY_INVALID, | |
| 172 Verify(verify_proc_default_.get(), server.get(), &verify_root)); | |
| 173 // User 1 should now fail to verify. | |
| 174 EXPECT_EQ(net::ERR_CERT_AUTHORITY_INVALID, | |
| 175 Verify(verify_proc_1_.get(), server.get(), &verify_root)); | |
| 176 // User 2 should still verify successfully through the E root. | |
| 177 EXPECT_EQ(net::OK, Verify(verify_proc_2_.get(), server.get(), &verify_root)); | |
| 178 EXPECT_EQ("CN=E Root CA", verify_root); | |
| 179 | |
| 180 // Delete E root. | |
| 181 EXPECT_TRUE(db_2_->DeleteCertAndKey(root_2_[0])); | |
| 182 EXPECT_EQ(net::ERR_CERT_AUTHORITY_INVALID, | |
| 183 Verify(verify_proc_default_.get(), server.get(), &verify_root)); | |
| 184 // User 1 should still fail to verify. | |
| 185 EXPECT_EQ(net::ERR_CERT_AUTHORITY_INVALID, | |
| 186 Verify(verify_proc_1_.get(), server.get(), &verify_root)); | |
| 187 // User 2 should now fail to verify. | |
| 188 EXPECT_EQ(net::ERR_CERT_AUTHORITY_INVALID, | |
| 189 Verify(verify_proc_2_.get(), server.get(), &verify_root)); | |
| 190 } | |
| 191 | |
| 192 TEST_F(CertVerifyProcChromeOSTest, TestAdditionalTrustAnchors) { | |
|
Ryan Sleevi
2014/01/30 05:27:40
Document?
mattm
2014/02/04 05:31:21
Done.
| |
| 193 EXPECT_TRUE(verify_proc_default_->SupportsAdditionalTrustAnchors()); | |
| 194 EXPECT_TRUE(verify_proc_1_->SupportsAdditionalTrustAnchors()); | |
| 195 | |
| 196 scoped_refptr<net::X509Certificate> server = certs_1_[0]; | |
| 197 std::string verify_root; | |
| 198 net::CertificateList additional_trust_anchors; | |
| 199 // Before either of the root certs have been trusted, all verifications should | |
| 200 // fail with CERT_AUTHORITY_INVALID. | |
| 201 EXPECT_EQ(net::ERR_CERT_AUTHORITY_INVALID, | |
| 202 VerifyWithAdditionalTrustAnchors(verify_proc_default_.get(), | |
| 203 additional_trust_anchors, | |
| 204 server.get(), | |
| 205 &verify_root)); | |
| 206 EXPECT_EQ(net::ERR_CERT_AUTHORITY_INVALID, | |
| 207 VerifyWithAdditionalTrustAnchors(verify_proc_1_.get(), | |
| 208 additional_trust_anchors, | |
| 209 server.get(), | |
| 210 &verify_root)); | |
| 211 | |
| 212 // Use B CA as additional trust anchor. Verifications should succeed now. | |
| 213 // XXX why doesn't this work with D Root CA? | |
|
Ryan Sleevi
2014/01/30 05:27:40
Yes. Why doesn't it? :)
mattm
2014/02/04 05:31:21
Done.
| |
| 214 additional_trust_anchors.push_back(certs_1_[1]); | |
| 215 EXPECT_EQ(net::OK, | |
| 216 VerifyWithAdditionalTrustAnchors(verify_proc_default_.get(), | |
| 217 additional_trust_anchors, | |
| 218 server.get(), | |
| 219 &verify_root)); | |
| 220 EXPECT_EQ("CN=B CA", verify_root); | |
| 221 EXPECT_EQ(net::OK, | |
| 222 VerifyWithAdditionalTrustAnchors(verify_proc_1_.get(), | |
| 223 additional_trust_anchors, | |
| 224 server.get(), | |
| 225 &verify_root)); | |
| 226 EXPECT_EQ("CN=B CA", verify_root); | |
|
Ryan Sleevi
2014/01/30 05:27:40
Test that User 2 is *not* succeeding (when an empt
mattm
2014/02/04 05:31:21
Done.
| |
| 227 | |
| 228 // Without additional trust anchors, verification should fail again. | |
| 229 additional_trust_anchors.clear(); | |
| 230 EXPECT_EQ(net::ERR_CERT_AUTHORITY_INVALID, | |
| 231 VerifyWithAdditionalTrustAnchors(verify_proc_default_.get(), | |
| 232 additional_trust_anchors, | |
| 233 server.get(), | |
| 234 &verify_root)); | |
| 235 EXPECT_EQ(net::ERR_CERT_AUTHORITY_INVALID, | |
| 236 VerifyWithAdditionalTrustAnchors(verify_proc_1_.get(), | |
| 237 additional_trust_anchors, | |
| 238 server.get(), | |
| 239 &verify_root)); | |
| 240 | |
| 241 // Import and trust the B CA for user 2. | |
| 242 net::CertificateList roots; | |
| 243 roots.push_back(certs_1_[1]); | |
| 244 net::NSSCertDatabase::ImportCertFailureList failed; | |
| 245 EXPECT_TRUE( | |
| 246 db_2_->ImportCACerts(roots, net::NSSCertDatabase::TRUSTED_SSL, &failed)); | |
| 247 EXPECT_EQ(0U, failed.size()); | |
| 248 | |
| 249 // Use B CA as additional trust anchor. Verifications should still | |
| 250 // succeed even if the cert is trusted by a different profile. | |
| 251 additional_trust_anchors.push_back(certs_1_[1]); | |
| 252 EXPECT_EQ(net::OK, | |
| 253 VerifyWithAdditionalTrustAnchors(verify_proc_default_.get(), | |
| 254 additional_trust_anchors, | |
| 255 server.get(), | |
| 256 &verify_root)); | |
| 257 EXPECT_EQ("CN=B CA", verify_root); | |
| 258 EXPECT_EQ(net::OK, | |
| 259 VerifyWithAdditionalTrustAnchors(verify_proc_1_.get(), | |
| 260 additional_trust_anchors, | |
| 261 server.get(), | |
| 262 &verify_root)); | |
| 263 EXPECT_EQ("CN=B CA", verify_root); | |
| 264 EXPECT_EQ(net::OK, | |
| 265 VerifyWithAdditionalTrustAnchors(verify_proc_2_.get(), | |
| 266 additional_trust_anchors, | |
| 267 server.get(), | |
| 268 &verify_root)); | |
| 269 EXPECT_EQ("CN=B CA", verify_root); | |
| 270 } | |
| 271 | |
| 272 class CertVerifyProcChromeOSOrderingTest | |
| 273 : public CertVerifyProcChromeOSTest, | |
| 274 public ::testing::WithParamInterface< | |
| 275 std::tr1::tuple<bool, int, std::string> > {}; | |
| 276 | |
| 277 TEST_P(CertVerifyProcChromeOSOrderingTest, TrustThenVerify) { | |
| 278 const ParamType& param = GetParam(); | |
| 279 const bool verify_first = std::tr1::get<0>(param); | |
| 280 const int trust_bitmask = std::tr1::get<1>(param); | |
| 281 const std::string test_order = std::tr1::get<2>(param); | |
| 282 DVLOG(1) << "verify_first: " << verify_first | |
| 283 << " trust_bitmask: " << trust_bitmask | |
| 284 << " test_order: " << test_order; | |
| 285 | |
| 286 scoped_refptr<net::X509Certificate> server = certs_1_[0]; | |
| 287 std::string verify_root; | |
| 288 | |
| 289 if (verify_first) { | |
| 290 // Before either of the root certs have been trusted, all verifications | |
| 291 // should fail with CERT_AUTHORITY_INVALID. | |
| 292 EXPECT_EQ(net::ERR_CERT_AUTHORITY_INVALID, | |
| 293 Verify(verify_proc_default_.get(), server.get(), &verify_root)); | |
| 294 EXPECT_EQ(net::ERR_CERT_AUTHORITY_INVALID, | |
| 295 Verify(verify_proc_1_.get(), server.get(), &verify_root)); | |
| 296 EXPECT_EQ(net::ERR_CERT_AUTHORITY_INVALID, | |
| 297 Verify(verify_proc_2_.get(), server.get(), &verify_root)); | |
| 298 } | |
| 299 | |
| 300 int expected_user1_result = net::ERR_CERT_AUTHORITY_INVALID; | |
| 301 int expected_user2_result = net::ERR_CERT_AUTHORITY_INVALID; | |
| 302 | |
| 303 if (trust_bitmask & 1) { | |
| 304 expected_user1_result = net::OK; | |
| 305 // Import and trust the D root for user 1. | |
| 306 net::NSSCertDatabase::ImportCertFailureList failed; | |
| 307 EXPECT_TRUE(db_1_->ImportCACerts( | |
| 308 root_1_, net::NSSCertDatabase::TRUSTED_SSL, &failed)); | |
| 309 EXPECT_EQ(0U, failed.size()); | |
| 310 } | |
| 311 | |
| 312 if (trust_bitmask & 2) { | |
| 313 expected_user2_result = net::OK; | |
| 314 // Import and trust the E root for user 2. | |
| 315 net::NSSCertDatabase::ImportCertFailureList failed; | |
| 316 EXPECT_TRUE(db_2_->ImportCACerts( | |
| 317 root_2_, net::NSSCertDatabase::TRUSTED_SSL, &failed)); | |
| 318 EXPECT_EQ(0U, failed.size()); | |
| 319 } | |
| 320 | |
| 321 // Repeat the tests twice, they should return the same each time. | |
| 322 for (int i = 0; i < 2; ++i) { | |
| 323 SCOPED_TRACE(i); | |
| 324 for (std::string::const_iterator j = test_order.begin(); | |
| 325 j != test_order.end(); | |
| 326 ++j) { | |
| 327 switch (*j) { | |
| 328 case 'd': | |
| 329 // Default verifier should always fail. | |
| 330 EXPECT_EQ( | |
| 331 net::ERR_CERT_AUTHORITY_INVALID, | |
| 332 Verify(verify_proc_default_.get(), server.get(), &verify_root)); | |
| 333 break; | |
| 334 case '1': | |
| 335 EXPECT_EQ(expected_user1_result, | |
| 336 Verify(verify_proc_1_.get(), server.get(), &verify_root)); | |
| 337 if (expected_user1_result == net::OK) | |
| 338 EXPECT_EQ("CN=D Root CA", verify_root); | |
| 339 break; | |
| 340 case '2': | |
| 341 EXPECT_EQ(expected_user2_result, | |
| 342 Verify(verify_proc_2_.get(), server.get(), &verify_root)); | |
| 343 if (expected_user2_result == net::OK) | |
| 344 EXPECT_EQ("CN=E Root CA", verify_root); | |
| 345 break; | |
| 346 default: | |
| 347 ASSERT_TRUE(false); | |
|
Ryan Sleevi
2014/01/30 05:27:40
s/ASSERT_TRUE(false)/FAIL()/ (or GTEST_FAIL if nee
mattm
2014/02/04 05:31:21
Done.
| |
| 348 } | |
| 349 } | |
| 350 } | |
| 351 } | |
| 352 | |
| 353 INSTANTIATE_TEST_CASE_P( | |
| 354 Variations, | |
| 355 CertVerifyProcChromeOSOrderingTest, | |
| 356 ::testing::Combine( | |
| 357 ::testing::Bool(), | |
| 358 ::testing::Range(0, 1 << 2), | |
| 359 ::testing::Values("d12", "d21", "1d2", "12d", "2d1", "21d"))); | |
| 360 | |
| 361 } // namespace chromeos | |
| OLD | NEW |