1 // Copyright (c) 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 "net/http/disk_based_cert_cache.h" 6 7 #include "base/bind.h" 8 #include "base/callback_helpers.h" 9 #include "net/base/completion_callback.h" 10 #include "net/base/io_buffer.h" 11 #include "net/base/net_errors.h" 12 #include "net/base/test_completion_callback.h" 13 #include "net/base/test_data_directory.h" 14 #include "net/disk_cache/memory/mem_backend_impl.h" 15 #include "net/http/mock_http_cache.h" 16 #include "net/test/cert_test_util.h" 17 #include "testing/gtest/include/gtest/gtest.h" 18 19 namespace net { 20 21 namespace { 22 23 // Testing the DiskBasedCertCache requires constant use of the 24 // certificates in GetTestCertsDirectory(). The TestCertMetaData 25 // struct stores metadata relevant to the DiskBasedCertCache for 26 // each used test certificate. 27 struct TestCertMetaData { 28 const char* file_name; 29 const char* cache_key; 30 }; 31 32 const TestCertMetaData kCert1 = { 33 "root_ca_cert.pem", "cert:738D348A8AFCEC4F79C3E4B1845D985AF601AB0F"}; 34 35 const TestCertMetaData kCert2 = { 36 "ok_cert.pem", "cert:6C9DFD2CFA9885C71BE6DE0EA0CF962AC8F9131B"}; 37 38 // MockTransactions are required to use the MockDiskCache backend. 39 // |key| is a cache key, and is equivalent to the key that will be 40 // used to store or retrieve certificates in the cache. |test_mode| 41 // is an integer that is used to indicate properties of the test 42 // transaction, mostly whether or not it is synchronous. 43 // For testing the DiskBasedCertCache, other data members of the struct 44 // are irrelevant. Only one MockTransaction per certificate can be used 45 // at a time. 46 MockTransaction CreateMockTransaction(const char* key, int test_mode) { 47 MockTransaction transaction = {key, "", base::Time(), "", LOAD_NORMAL, 48 "", "", base::Time(), "", test_mode, 49 NULL, 0, OK}; 50 51 return transaction; 52 } 53 54 // Helper class, for use with DiskBasedCertCache::GetCertificate, that will 55 // store the returned certificate handle and allow users to WaitForResult of 56 // DiskBasedCertCache::GetCertificate. 57 class TestGetCallback { 58 public: 59 TestGetCallback() : cert_handle_(NULL) {} 60 ~TestGetCallback() { 61 if (cert_handle_) 62 X509Certificate::FreeOSCertHandle(cert_handle_); 63 } 64 65 // Blocks until the underlying GetCertificate() operation has succeeded. 66 void WaitForResult() { cb_.WaitForResult(); } 67 68 // Returns a Callback suitable for use with 69 // DiskBasedCertCache::GetCertificate(). The returned callback is only valid 70 // while the TestGetCallback object is still valid. 71 DiskBasedCertCache::GetCallback callback() { 72 return base::Bind(&TestGetCallback::OnGetComplete, base::Unretained(this)); 73 } 74 75 // Returns the associated certificate handle. 76 const X509Certificate::OSCertHandle& cert_handle() const { 77 return cert_handle_; 78 } 79 80 private: 81 void OnGetComplete(const X509Certificate::OSCertHandle handle) { 82 if (handle) 83 cert_handle_ = X509Certificate::DupOSCertHandle(handle); 84 cb_.callback().Run(OK); 85 } 86 87 TestCompletionCallback cb_; 88 X509Certificate::OSCertHandle cert_handle_; 89 }; 90 91 // Helper class, for use with DiskBasedCertCache::SetCertificate, that will 92 // store the returned key and allow a user to WaitForResult of 93 // DiskBasedCertCache::SetCertificate. 94 class TestSetCallback { 95 public: 96 TestSetCallback() {} 97 ~TestSetCallback() {} 98 99 // Blocks until the underlying SetCertificate() operation has succeeded. 100 void WaitForResult() { cb_.WaitForResult(); } 101 102 // Returns a Callback suitable for use with 103 // DiskBasedCertCache::SetCertificate(). The returned callback is only valid 104 // while the TestSetCallback object is still valid. 105 DiskBasedCertCache::SetCallback callback() { 106 return base::Bind(&TestSetCallback::OnSetComplete, base::Unretained(this)); 107 } 108 109 // Returns the associated certificate handle. 110 const std::string& key() const { return key_; } 111 112 private: 113 void OnSetComplete(const std::string& key) { 114 key_ = key; 115 cb_.callback().Run(OK); 116 } 117 118 TestCompletionCallback cb_; 119 std::string key_; 120 }; 121 122 // Stores the certificate corresponding to |cert_data| in |backend|. If 123 // |corrupt_data| is true, the certificate will be imported with errors 124 // so as to mimic a corrupted file on disk. 125 void ImportCert(disk_cache::Backend* backend, 126 const TestCertMetaData& cert_data, 127 bool corrupt_data) { 128 disk_cache::Entry* entry; 129 TestCompletionCallback callback; 130 int rv = 131 backend->CreateEntry(cert_data.cache_key, &entry, callback.callback()); 132 EXPECT_EQ(OK, callback.GetResult(rv)); 133 scoped_refptr<X509Certificate> cert( 134 ImportCertFromFile(GetTestCertsDirectory(), cert_data.file_name)); 135 std::string write_data; 136 bool encoded = 137 X509Certificate::GetDEREncoded(cert->os_cert_handle(), &write_data); 138 ASSERT_TRUE(encoded); 139 if (corrupt_data) { 140 for (size_t i = 0; i < write_data.size(); i += 20) 141 ++write_data[i]; 142 } 143 scoped_refptr<IOBuffer> buffer(new IOBuffer(write_data.size())); 144 memcpy(buffer->data(), write_data.data(), write_data.size()); 145 rv = entry->WriteData(0 /* index */, 146 0 /* offset */, 147 buffer.get(), 148 write_data.size(), 149 callback.callback(), 150 true /* truncate */); 151 ASSERT_EQ(static_cast<int>(write_data.size()), callback.GetResult(rv)); 152 entry->Close(); 153 } 154 155 // Checks that the the certificate corresponding to |cert_data| is an existing, 156 // correctly cached entry in |backend|. 157 void CheckCertCached(disk_cache::Backend* backend, 158 const TestCertMetaData& cert_data) { 159 disk_cache::Entry* entry; 160 TestCompletionCallback callback; 161 int rv = backend->OpenEntry(cert_data.cache_key, &entry, callback.callback()); 162 EXPECT_EQ(OK, callback.GetResult(rv)); 163 scoped_refptr<X509Certificate> cert( 164 ImportCertFromFile(GetTestCertsDirectory(), cert_data.file_name)); 165 std::string write_data; 166 bool encoded = 167 X509Certificate::GetDEREncoded(cert->os_cert_handle(), &write_data); 168 ASSERT_TRUE(encoded); 169 int entry_size = entry->GetDataSize(0 /* index */); 170 scoped_refptr<IOBuffer> buffer(new IOBuffer(entry_size)); 171 rv = entry->ReadData(0 /* index */, 172 0 /* offset */, 173 buffer.get(), 174 entry_size, 175 callback.callback()); 176 EXPECT_EQ(entry_size, callback.GetResult(rv)); 177 entry->Close(); 178 X509Certificate::OSCertHandle cached_cert_handle = 179 X509Certificate::CreateOSCertHandleFromBytes(buffer->data(), entry_size); 180 EXPECT_TRUE(X509Certificate::IsSameOSCert(cached_cert_handle, 181 cert->os_cert_handle())); 182 X509Certificate::FreeOSCertHandle(cached_cert_handle); 183 } 184 185 } // namespace 186 187 // ---------------------------------------------------------------------------- 188 189 // Tests that a certificate can be stored in the cache. 190 TEST(DiskBasedCertCache, SetCert) { 191 ScopedMockTransaction trans1( 192 CreateMockTransaction(kCert1.cache_key, TEST_MODE_NORMAL)); 193 MockDiskCache backend; 194 DiskBasedCertCache cache(&backend); 195 scoped_refptr<X509Certificate> cert( 196 ImportCertFromFile(GetTestCertsDirectory(), kCert1.file_name)); 197 ASSERT_TRUE(cert.get()); 198 TestSetCallback set_callback; 199 200 cache.SetCertificate(cert->os_cert_handle(), set_callback.callback()); 201 set_callback.WaitForResult(); 202 EXPECT_EQ(kCert1.cache_key, set_callback.key()); 203 ASSERT_NO_FATAL_FAILURE(CheckCertCached(&backend, kCert1)); 204 } 205 206 // Tests that a certificate can be retrieved from the cache. 207 TEST(DiskBasedCertCache, GetCert) { 208 ScopedMockTransaction trans1( 209 CreateMockTransaction(kCert1.cache_key, TEST_MODE_NORMAL)); 210 MockDiskCache backend; 211 ASSERT_NO_FATAL_FAILURE( 212 ImportCert(&backend, kCert1, false /* not corrupted */)); 213 DiskBasedCertCache cache(&backend); 214 TestGetCallback get_callback; 215 216 cache.GetCertificate(kCert1.cache_key, get_callback.callback()); 217 get_callback.WaitForResult(); 218 219 scoped_refptr<X509Certificate> cert( 220 ImportCertFromFile(GetTestCertsDirectory(), kCert1.file_name)); 221 EXPECT_TRUE(X509Certificate::IsSameOSCert(get_callback.cert_handle(), 222 cert->os_cert_handle())); 223 } 224 225 // Tests that the DiskBasedCertCache successfully writes to the cache 226 // if the cache acts synchronously 227 TEST(DiskBasedCertCache, SyncSet) { 228 ScopedMockTransaction trans1( 229 CreateMockTransaction(kCert1.cache_key, TEST_MODE_SYNC_ALL)); 230 MockDiskCache backend; 231 DiskBasedCertCache cache(&backend); 232 scoped_refptr<X509Certificate> cert( 233 ImportCertFromFile(GetTestCertsDirectory(), kCert1.file_name)); 234 ASSERT_TRUE(cert.get()); 235 236 TestSetCallback set_callback; 237 cache.SetCertificate(cert->os_cert_handle(), set_callback.callback()); 238 set_callback.WaitForResult(); 239 EXPECT_EQ(kCert1.cache_key, set_callback.key()); 240 ASSERT_NO_FATAL_FAILURE(CheckCertCached(&backend, kCert1)); 241 } 242 243 // Tests that the DiskBasedCertCache successfully reads from the cache 244 // if the cache acts synchronously 245 TEST(DiskBasedCertCache, SyncGet) { 246 ScopedMockTransaction trans1( 247 CreateMockTransaction(kCert1.cache_key, TEST_MODE_SYNC_ALL)); 248 MockDiskCache backend; 249 ASSERT_NO_FATAL_FAILURE( 250 (ImportCert(&backend, kCert1, false /* not corrupted */))); 251 DiskBasedCertCache cache(&backend); 252 scoped_refptr<X509Certificate> cert( 253 ImportCertFromFile(GetTestCertsDirectory(), kCert1.file_name)); 254 ASSERT_TRUE(cert.get()); 255 256 TestGetCallback get_callback; 257 cache.GetCertificate(kCert1.cache_key, get_callback.callback()); 258 get_callback.WaitForResult(); 259 EXPECT_TRUE(X509Certificate::IsSameOSCert(get_callback.cert_handle(), 260 cert->os_cert_handle())); 261 } 262 263 // Tests that GetCertificate will fail on a corrupted certificate. 264 TEST(DiskBasedCertCache, GetBrokenCert) { 265 ScopedMockTransaction trans1( 266 CreateMockTransaction(kCert1.cache_key, TEST_MODE_NORMAL)); 267 MockDiskCache backend; 268 ASSERT_NO_FATAL_FAILURE(ImportCert(&backend, kCert1, true /* corrupted */)); 269 DiskBasedCertCache cache(&backend); 270 TestGetCallback get_callback; 271 272 cache.GetCertificate(kCert1.cache_key, get_callback.callback()); 273 get_callback.WaitForResult(); 274 275 EXPECT_FALSE(get_callback.cert_handle()); 276 } 277 278 // Tests that attempting to retrieve a cert that is not in the cache will 279 // return NULL. 280 TEST(DiskBasedCertCache, GetUncachedCert) { 281 ScopedMockTransaction trans1( 282 CreateMockTransaction(kCert1.cache_key, TEST_MODE_NORMAL)); 283 MockDiskCache backend; 284 DiskBasedCertCache cache(&backend); 285 TestGetCallback get_callback; 286 287 cache.GetCertificate(kCert1.cache_key, get_callback.callback()); 288 get_callback.WaitForResult(); 289 EXPECT_EQ(NULL, get_callback.cert_handle()); 290 } 291 292 // Issues two requests to store a certificate in the cache 293 // (simultaneously), and checks that the DiskBasedCertCache stores the 294 // certificate to the cache (in one write rather than two). 295 TEST(DiskBasedCertCache, SetMultiple) { 296 ScopedMockTransaction trans1( 297 CreateMockTransaction(kCert1.cache_key, TEST_MODE_NORMAL)); 298 MockDiskCache backend; 299 DiskBasedCertCache cache(&backend); 300 scoped_refptr<X509Certificate> cert( 301 ImportCertFromFile(GetTestCertsDirectory(), kCert1.file_name)); 302 ASSERT_TRUE(cert.get()); 303 TestSetCallback set_callback1, set_callback2; 304 305 // Behind the scenes, these two operations will be combined 306 // into one operation. IgnoreCallbacks guarantees that the 307 // first SetCertificate operation is not yet complete when the second 308 // SetCertificate is called, and then IgnoreCallbacks(false) continues the 309 // (combined) operation in the |cache|. 310 MockDiskEntry::IgnoreCallbacks(true); 311 cache.SetCertificate(cert->os_cert_handle(), set_callback1.callback()); 312 cache.SetCertificate(cert->os_cert_handle(), set_callback2.callback()); 313 MockDiskEntry::IgnoreCallbacks(false); 314 315 set_callback1.WaitForResult(); 316 set_callback2.WaitForResult(); 317 EXPECT_EQ(set_callback1.key(), set_callback2.key()); 318 ASSERT_NO_FATAL_FAILURE(CheckCertCached(&backend, kCert1)); 319 } 320 321 // Issues two requests to store a certificate in the cache 322 // because the first transaction finishes before the second 323 // one is issued, the first cache write is overwritten. 324 TEST(DiskBasedCertCache, SetOverwrite) { 325 ScopedMockTransaction trans1( 326 CreateMockTransaction(kCert1.cache_key, TEST_MODE_NORMAL)); 327 MockDiskCache backend; 328 backend.set_double_create_check(false); 329 DiskBasedCertCache cache(&backend); 330 scoped_refptr<X509Certificate> cert( 331 ImportCertFromFile(GetTestCertsDirectory(), kCert1.file_name)); 332 ASSERT_TRUE(cert.get()); 333 TestSetCallback set_callback1, set_callback2; 334 335 cache.SetCertificate(cert->os_cert_handle(), set_callback1.callback()); 336 set_callback1.WaitForResult(); 337 cache.SetCertificate(cert->os_cert_handle(), set_callback2.callback()); 338 set_callback2.WaitForResult(); 339 340 EXPECT_EQ(set_callback1.key(), set_callback2.key()); 341 ASSERT_NO_FATAL_FAILURE(CheckCertCached(&backend, kCert1)); 342 } 343 344 // Stores a certificate in the DiskBasedCertCache, then retrieves it 345 // and makes sure it was retrieved successfully. 346 TEST(DiskBasedCertCache, SimpleSetAndGet) { 347 ScopedMockTransaction trans1( 348 CreateMockTransaction(kCert1.cache_key, TEST_MODE_NORMAL)); 349 MockDiskCache backend; 350 DiskBasedCertCache cache(&backend); 351 scoped_refptr<X509Certificate> cert( 352 ImportCertFromFile(GetTestCertsDirectory(), kCert1.file_name)); 353 ASSERT_TRUE(cert.get()); 354 TestSetCallback set_callback; 355 TestGetCallback get_callback; 356 357 cache.SetCertificate(cert->os_cert_handle(), set_callback.callback()); 358 set_callback.WaitForResult(); 359 cache.GetCertificate(set_callback.key(), get_callback.callback()); 360 get_callback.WaitForResult(); 361 EXPECT_TRUE(X509Certificate::IsSameOSCert(get_callback.cert_handle(), 362 cert->os_cert_handle())); 363 } 364 365 // Tests some basic functionality of the DiskBasedCertCache, with multiple 366 // set and get operations. 367 TEST(DiskBasedCertCache, BasicUsage) { 368 ScopedMockTransaction trans1( 369 CreateMockTransaction(kCert1.cache_key, TEST_MODE_SYNC_CACHE_START)); 370 ScopedMockTransaction trans2( 371 CreateMockTransaction(kCert2.cache_key, TEST_MODE_NORMAL)); 372 MockDiskCache backend; 373 DiskBasedCertCache cache(&backend); 374 scoped_refptr<X509Certificate> cert1( 375 ImportCertFromFile(GetTestCertsDirectory(), kCert1.file_name)); 376 scoped_refptr<X509Certificate> cert2( 377 ImportCertFromFile(GetTestCertsDirectory(), kCert2.file_name)); 378 ASSERT_TRUE(cert1.get()); 379 ASSERT_TRUE(cert2.get()); 380 ASSERT_FALSE(X509Certificate::IsSameOSCert(cert1->os_cert_handle(), 381 cert2->os_cert_handle())); 382 TestSetCallback set_callback1, set_callback2; 383 384 // Callbacks are temporarily ignored here to guarantee the asynchronous 385 // operations of the DiskBasedCertCache are always executed in the same 386 // order. 387 MockDiskEntry::IgnoreCallbacks(true); 388 cache.SetCertificate(cert1->os_cert_handle(), set_callback1.callback()); 389 cache.SetCertificate(cert2->os_cert_handle(), set_callback2.callback()); 390 MockDiskEntry::IgnoreCallbacks(false); 391 set_callback1.WaitForResult(); 392 set_callback2.WaitForResult(); 393 394 TestGetCallback get_callback1, get_callback2; 395 396 MockDiskEntry::IgnoreCallbacks(true); 397 cache.GetCertificate(set_callback1.key(), get_callback1.callback()); 398 cache.GetCertificate(set_callback2.key(), get_callback2.callback()); 399 MockDiskEntry::IgnoreCallbacks(false); 400 get_callback1.WaitForResult(); 401 get_callback2.WaitForResult(); 402 403 EXPECT_TRUE(X509Certificate::IsSameOSCert(cert1->os_cert_handle(), 404 get_callback1.cert_handle())); 405 EXPECT_TRUE(X509Certificate::IsSameOSCert(cert2->os_cert_handle(), 406 get_callback2.cert_handle())); 407 } 408 409 // Test the result of simultaneous requests to store and retrieve a 410 // certificate from the cache, with the get operation attempting to 411 // open the cache first and therefore failing to open the entry. 412 TEST(DiskBasedCertCache, SimultaneousGetSet) { 413 ScopedMockTransaction trans1( 414 CreateMockTransaction(kCert1.cache_key, TEST_MODE_SYNC_CACHE_START)); 415 MockDiskCache backend; 416 DiskBasedCertCache cache(&backend); 417 scoped_refptr<X509Certificate> cert( 418 ImportCertFromFile(GetTestCertsDirectory(), kCert1.file_name)); 419 ASSERT_TRUE(cert.get()); 420 421 TestGetCallback get_callback; 422 TestSetCallback set_callback; 423 424 MockDiskEntry::IgnoreCallbacks(true); 425 cache.GetCertificate(kCert1.cache_key, get_callback.callback()); 426 cache.SetCertificate(cert->os_cert_handle(), set_callback.callback()); 427 MockDiskEntry::IgnoreCallbacks(false); 428 get_callback.WaitForResult(); 429 set_callback.WaitForResult(); 430 431 EXPECT_EQ(NULL, get_callback.cert_handle()); 432 EXPECT_EQ(kCert1.cache_key, set_callback.key()); 433 } 434 435 // Test the result of simultaneous requests to store and retrieve a 436 // certificate from the cache, with the get operation opening the cache 437 // after the set operation, leading to a successful read. 438 TEST(DiskBasedCertCache, SimultaneousSetGet) { 439 ScopedMockTransaction trans1( 440 CreateMockTransaction(kCert1.cache_key, TEST_MODE_SYNC_CACHE_START)); 441 MockDiskCache backend; 442 DiskBasedCertCache cache(&backend); 443 scoped_refptr<X509Certificate> cert( 444 ImportCertFromFile(GetTestCertsDirectory(), kCert1.file_name)); 445 ASSERT_TRUE(cert.get()); 446 447 TestSetCallback set_callback; 448 TestGetCallback get_callback; 449 450 MockDiskEntry::IgnoreCallbacks(true); 451 cache.SetCertificate(cert->os_cert_handle(), set_callback.callback()); 452 cache.GetCertificate(kCert1.cache_key, get_callback.callback()); 453 MockDiskEntry::IgnoreCallbacks(false); 454 set_callback.WaitForResult(); 455 get_callback.WaitForResult(); 456 457 EXPECT_EQ(kCert1.cache_key, set_callback.key()); 458 EXPECT_TRUE(X509Certificate::IsSameOSCert(cert->os_cert_handle(), 459 get_callback.cert_handle())); 460 } 461 462 // Tests that the DiskBasedCertCache can be deleted without issues when 463 // there are pending operations in the disk cache. 464 TEST(DiskBasedCertCache, DeletedCertCache) { 465 ScopedMockTransaction trans1( 466 CreateMockTransaction(kCert1.cache_key, TEST_MODE_NORMAL)); 467 MockDiskCache backend; 468 scoped_ptr<DiskBasedCertCache> cache(new DiskBasedCertCache(&backend)); 469 scoped_refptr<X509Certificate> cert( 470 ImportCertFromFile(GetTestCertsDirectory(), kCert1.file_name)); 471 ASSERT_TRUE(cert.get()); 472 TestSetCallback set_callback; 473 474 cache->SetCertificate(cert->os_cert_handle(), set_callback.callback()); 475 cache.reset(); 476 set_callback.WaitForResult(); 477 EXPECT_EQ(std::string(), set_callback.key()); 478 } 479 480 // Issues two successive read requests for a certificate, and then 481 // checks that the DiskBasedCertCache correctly read and recorded 482 // reading through the in-memory MRU cache. 483 TEST(DiskBasedCertCache, MemCacheGet) { 484 ScopedMockTransaction trans1( 485 CreateMockTransaction(kCert1.cache_key, TEST_MODE_NORMAL)); 486 MockDiskCache backend; 487 ASSERT_NO_FATAL_FAILURE( 488 ImportCert(&backend, kCert1, false /* not corrupted */)); 489 DiskBasedCertCache cache(&backend); 490 491 TestGetCallback get_callback1, get_callback2; 492 cache.GetCertificate(kCert1.cache_key, get_callback1.callback()); 493 get_callback1.WaitForResult(); 494 EXPECT_EQ(0U, cache.mem_cache_hits_for_testing()); 495 cache.GetCertificate(kCert1.cache_key, get_callback2.callback()); 496 get_callback2.WaitForResult(); 497 EXPECT_EQ(1U, cache.mem_cache_hits_for_testing()); 498 EXPECT_TRUE(X509Certificate::IsSameOSCert(get_callback1.cert_handle(), 499 get_callback2.cert_handle())); 500 } 501 502 // Reads a corrupted certificate from the disk cache, and then overwrites 503 // it and checks that the uncorrupted version was stored in the in-memory 504 // cache. 505 TEST(DiskBasedCertCache, CorruptOverwrite) { 506 ScopedMockTransaction trans1( 507 CreateMockTransaction(kCert1.cache_key, TEST_MODE_NORMAL)); 508 MockDiskCache backend; 509 backend.set_double_create_check(false); 510 ASSERT_NO_FATAL_FAILURE(ImportCert(&backend, kCert1, true /* corrupted */)); 511 DiskBasedCertCache cache(&backend); 512 TestGetCallback get_callback1, get_callback2; 513 514 cache.GetCertificate(kCert1.cache_key, get_callback1.callback()); 515 get_callback1.WaitForResult(); 516 EXPECT_FALSE(get_callback2.cert_handle()); 517 518 scoped_refptr<X509Certificate> cert( 519 ImportCertFromFile(GetTestCertsDirectory(), kCert1.file_name)); 520 TestSetCallback set_callback; 521 522 cache.SetCertificate(cert->os_cert_handle(), set_callback.callback()); 523 set_callback.WaitForResult(); 524 EXPECT_EQ(kCert1.cache_key, set_callback.key()); 525 EXPECT_EQ(0U, cache.mem_cache_hits_for_testing()); 526 527 cache.GetCertificate(kCert1.cache_key, get_callback2.callback()); 528 get_callback2.WaitForResult(); 529 EXPECT_TRUE(X509Certificate::IsSameOSCert(get_callback2.cert_handle(), 530 cert->os_cert_handle())); 531 EXPECT_EQ(1U, cache.mem_cache_hits_for_testing()); 532 ASSERT_NO_FATAL_FAILURE(CheckCertCached(&backend, kCert1)); 533 } 534 535 } // namespace net 536