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/ssl/server_bound_cert_service.h" 6 7 #include <string> 8 #include <vector> 9 10 #include "base/bind.h" 11 #include "base/memory/scoped_ptr.h" 12 #include "base/message_loop/message_loop.h" 13 #include "base/task_runner.h" 14 #include "base/threading/sequenced_worker_pool.h" 15 #include "crypto/ec_private_key.h" 16 #include "net/base/net_errors.h" 17 #include "net/base/test_completion_callback.h" 18 #include "net/cert/asn1_util.h" 19 #include "net/cert/x509_certificate.h" 20 #include "net/ssl/default_server_bound_cert_store.h" 21 #include "testing/gtest/include/gtest/gtest.h" 22 23 namespace net { 24 25 namespace { 26 27 void FailTest(int /* result */) { 28 FAIL(); 29 } 30 31 class ServerBoundCertServiceTest : public testing::Test { 32 public: 33 ServerBoundCertServiceTest() 34 : sequenced_worker_pool_(new base::SequencedWorkerPool( 35 3, "ServerBoundCertServiceTest")), 36 service_(new ServerBoundCertService( 37 new DefaultServerBoundCertStore(NULL), 38 sequenced_worker_pool_)) { 39 } 40 41 virtual ~ServerBoundCertServiceTest() { 42 if (sequenced_worker_pool_.get()) 43 sequenced_worker_pool_->Shutdown(); 44 } 45 46 protected: 47 scoped_refptr<base::SequencedWorkerPool> sequenced_worker_pool_; 48 scoped_ptr<ServerBoundCertService> service_; 49 }; 50 51 class MockServerBoundCertStoreWithAsyncGet 52 : public DefaultServerBoundCertStore { 53 public: 54 MockServerBoundCertStoreWithAsyncGet() 55 : DefaultServerBoundCertStore(NULL), cert_count_(0) {} 56 57 virtual int GetServerBoundCert(const std::string& server_identifier, 58 base::Time* expiration_time, 59 std::string* private_key_result, 60 std::string* cert_result, 61 const GetCertCallback& callback) OVERRIDE; 62 63 virtual void SetServerBoundCert(const std::string& server_identifier, 64 base::Time creation_time, 65 base::Time expiration_time, 66 const std::string& private_key, 67 const std::string& cert) OVERRIDE { 68 cert_count_ = 1; 69 } 70 71 virtual int GetCertCount() OVERRIDE { return cert_count_; } 72 73 void CallGetServerBoundCertCallbackWithResult(int err, 74 base::Time expiration_time, 75 const std::string& private_key, 76 const std::string& cert); 77 78 private: 79 GetCertCallback callback_; 80 std::string server_identifier_; 81 int cert_count_; 82 }; 83 84 int MockServerBoundCertStoreWithAsyncGet::GetServerBoundCert( 85 const std::string& server_identifier, 86 base::Time* expiration_time, 87 std::string* private_key_result, 88 std::string* cert_result, 89 const GetCertCallback& callback) { 90 server_identifier_ = server_identifier; 91 callback_ = callback; 92 // Reset the cert count, it'll get incremented in either SetServerBoundCert or 93 // CallGetServerBoundCertCallbackWithResult. 94 cert_count_ = 0; 95 // Do nothing else: the results to be provided will be specified through 96 // CallGetServerBoundCertCallbackWithResult. 97 return ERR_IO_PENDING; 98 } 99 100 void 101 MockServerBoundCertStoreWithAsyncGet::CallGetServerBoundCertCallbackWithResult( 102 int err, 103 base::Time expiration_time, 104 const std::string& private_key, 105 const std::string& cert) { 106 if (err == OK) 107 cert_count_ = 1; 108 base::MessageLoop::current()->PostTask(FROM_HERE, 109 base::Bind(callback_, 110 err, 111 server_identifier_, 112 expiration_time, 113 private_key, 114 cert)); 115 } 116 117 TEST_F(ServerBoundCertServiceTest, GetDomainForHost) { 118 EXPECT_EQ("google.com", 119 ServerBoundCertService::GetDomainForHost("google.com")); 120 EXPECT_EQ("google.com", 121 ServerBoundCertService::GetDomainForHost("www.google.com")); 122 EXPECT_EQ("foo.appspot.com", 123 ServerBoundCertService::GetDomainForHost("foo.appspot.com")); 124 EXPECT_EQ("bar.appspot.com", 125 ServerBoundCertService::GetDomainForHost("foo.bar.appspot.com")); 126 EXPECT_EQ("appspot.com", 127 ServerBoundCertService::GetDomainForHost("appspot.com")); 128 EXPECT_EQ("google.com", 129 ServerBoundCertService::GetDomainForHost("www.mail.google.com")); 130 EXPECT_EQ("goto", 131 ServerBoundCertService::GetDomainForHost("goto")); 132 EXPECT_EQ("127.0.0.1", 133 ServerBoundCertService::GetDomainForHost("127.0.0.1")); 134 } 135 136 // See http://crbug.com/91512 - implement OpenSSL version of CreateSelfSigned. 137 #if !defined(USE_OPENSSL) 138 139 TEST_F(ServerBoundCertServiceTest, CacheHit) { 140 std::string host("encrypted.google.com"); 141 142 int error; 143 TestCompletionCallback callback; 144 ServerBoundCertService::RequestHandle request_handle; 145 146 // Asynchronous completion. 147 std::string private_key_info1, der_cert1; 148 EXPECT_EQ(0, service_->cert_count()); 149 error = service_->GetDomainBoundCert( 150 host, &private_key_info1, &der_cert1, 151 callback.callback(), &request_handle); 152 EXPECT_EQ(ERR_IO_PENDING, error); 153 EXPECT_TRUE(request_handle.is_active()); 154 error = callback.WaitForResult(); 155 EXPECT_EQ(OK, error); 156 EXPECT_EQ(1, service_->cert_count()); 157 EXPECT_FALSE(private_key_info1.empty()); 158 EXPECT_FALSE(der_cert1.empty()); 159 EXPECT_FALSE(request_handle.is_active()); 160 161 // Synchronous completion. 162 std::string private_key_info2, der_cert2; 163 error = service_->GetDomainBoundCert( 164 host, &private_key_info2, &der_cert2, 165 callback.callback(), &request_handle); 166 EXPECT_FALSE(request_handle.is_active()); 167 EXPECT_EQ(OK, error); 168 EXPECT_EQ(1, service_->cert_count()); 169 EXPECT_EQ(private_key_info1, private_key_info2); 170 EXPECT_EQ(der_cert1, der_cert2); 171 172 EXPECT_EQ(2u, service_->requests()); 173 EXPECT_EQ(1u, service_->cert_store_hits()); 174 EXPECT_EQ(0u, service_->inflight_joins()); 175 } 176 177 TEST_F(ServerBoundCertServiceTest, StoreCerts) { 178 int error; 179 TestCompletionCallback callback; 180 ServerBoundCertService::RequestHandle request_handle; 181 182 std::string host1("encrypted.google.com"); 183 std::string private_key_info1, der_cert1; 184 EXPECT_EQ(0, service_->cert_count()); 185 error = service_->GetDomainBoundCert( 186 host1, &private_key_info1, &der_cert1, 187 callback.callback(), &request_handle); 188 EXPECT_EQ(ERR_IO_PENDING, error); 189 EXPECT_TRUE(request_handle.is_active()); 190 error = callback.WaitForResult(); 191 EXPECT_EQ(OK, error); 192 EXPECT_EQ(1, service_->cert_count()); 193 194 std::string host2("www.verisign.com"); 195 std::string private_key_info2, der_cert2; 196 error = service_->GetDomainBoundCert( 197 host2, &private_key_info2, &der_cert2, 198 callback.callback(), &request_handle); 199 EXPECT_EQ(ERR_IO_PENDING, error); 200 EXPECT_TRUE(request_handle.is_active()); 201 error = callback.WaitForResult(); 202 EXPECT_EQ(OK, error); 203 EXPECT_EQ(2, service_->cert_count()); 204 205 std::string host3("www.twitter.com"); 206 std::string private_key_info3, der_cert3; 207 error = service_->GetDomainBoundCert( 208 host3, &private_key_info3, &der_cert3, 209 callback.callback(), &request_handle); 210 EXPECT_EQ(ERR_IO_PENDING, error); 211 EXPECT_TRUE(request_handle.is_active()); 212 error = callback.WaitForResult(); 213 EXPECT_EQ(OK, error); 214 EXPECT_EQ(3, service_->cert_count()); 215 216 EXPECT_NE(private_key_info1, private_key_info2); 217 EXPECT_NE(der_cert1, der_cert2); 218 EXPECT_NE(private_key_info1, private_key_info3); 219 EXPECT_NE(der_cert1, der_cert3); 220 EXPECT_NE(private_key_info2, private_key_info3); 221 EXPECT_NE(der_cert2, der_cert3); 222 } 223 224 // Tests an inflight join. 225 TEST_F(ServerBoundCertServiceTest, InflightJoin) { 226 std::string host("encrypted.google.com"); 227 int error; 228 229 std::string private_key_info1, der_cert1; 230 TestCompletionCallback callback1; 231 ServerBoundCertService::RequestHandle request_handle1; 232 233 std::string private_key_info2, der_cert2; 234 TestCompletionCallback callback2; 235 ServerBoundCertService::RequestHandle request_handle2; 236 237 error = service_->GetDomainBoundCert( 238 host, &private_key_info1, &der_cert1, 239 callback1.callback(), &request_handle1); 240 EXPECT_EQ(ERR_IO_PENDING, error); 241 EXPECT_TRUE(request_handle1.is_active()); 242 // Should join with the original request. 243 error = service_->GetDomainBoundCert( 244 host, &private_key_info2, &der_cert2, 245 callback2.callback(), &request_handle2); 246 EXPECT_EQ(ERR_IO_PENDING, error); 247 EXPECT_TRUE(request_handle2.is_active()); 248 249 error = callback1.WaitForResult(); 250 EXPECT_EQ(OK, error); 251 error = callback2.WaitForResult(); 252 EXPECT_EQ(OK, error); 253 254 EXPECT_EQ(2u, service_->requests()); 255 EXPECT_EQ(0u, service_->cert_store_hits()); 256 EXPECT_EQ(1u, service_->inflight_joins()); 257 } 258 259 TEST_F(ServerBoundCertServiceTest, ExtractValuesFromBytesEC) { 260 std::string host("encrypted.google.com"); 261 std::string private_key_info, der_cert; 262 int error; 263 TestCompletionCallback callback; 264 ServerBoundCertService::RequestHandle request_handle; 265 266 error = service_->GetDomainBoundCert( 267 host, &private_key_info, &der_cert, callback.callback(), 268 &request_handle); 269 EXPECT_EQ(ERR_IO_PENDING, error); 270 EXPECT_TRUE(request_handle.is_active()); 271 error = callback.WaitForResult(); 272 EXPECT_EQ(OK, error); 273 274 base::StringPiece spki_piece; 275 ASSERT_TRUE(asn1::ExtractSPKIFromDERCert(der_cert, &spki_piece)); 276 std::vector<uint8> spki( 277 spki_piece.data(), 278 spki_piece.data() + spki_piece.size()); 279 280 // Check that we can retrieve the key from the bytes. 281 std::vector<uint8> key_vec(private_key_info.begin(), private_key_info.end()); 282 scoped_ptr<crypto::ECPrivateKey> private_key( 283 crypto::ECPrivateKey::CreateFromEncryptedPrivateKeyInfo( 284 ServerBoundCertService::kEPKIPassword, key_vec, spki)); 285 EXPECT_TRUE(private_key != NULL); 286 287 // Check that we can retrieve the cert from the bytes. 288 scoped_refptr<X509Certificate> x509cert( 289 X509Certificate::CreateFromBytes(der_cert.data(), der_cert.size())); 290 EXPECT_TRUE(x509cert.get() != NULL); 291 } 292 293 // Tests that the callback of a canceled request is never made. 294 TEST_F(ServerBoundCertServiceTest, CancelRequest) { 295 std::string host("encrypted.google.com"); 296 std::string private_key_info, der_cert; 297 int error; 298 ServerBoundCertService::RequestHandle request_handle; 299 300 error = service_->GetDomainBoundCert(host, 301 &private_key_info, 302 &der_cert, 303 base::Bind(&FailTest), 304 &request_handle); 305 EXPECT_EQ(ERR_IO_PENDING, error); 306 EXPECT_TRUE(request_handle.is_active()); 307 request_handle.Cancel(); 308 EXPECT_FALSE(request_handle.is_active()); 309 310 // Wait for generation to finish. 311 sequenced_worker_pool_->FlushForTesting(); 312 // Wait for reply from ServerBoundCertServiceWorker to be posted back to the 313 // ServerBoundCertService. 314 base::MessageLoop::current()->RunUntilIdle(); 315 316 // Even though the original request was cancelled, the service will still 317 // store the result, it just doesn't call the callback. 318 EXPECT_EQ(1, service_->cert_count()); 319 } 320 321 // Tests that destructing the RequestHandle cancels the request. 322 TEST_F(ServerBoundCertServiceTest, CancelRequestByHandleDestruction) { 323 std::string host("encrypted.google.com"); 324 std::string private_key_info, der_cert; 325 int error; 326 { 327 ServerBoundCertService::RequestHandle request_handle; 328 329 error = service_->GetDomainBoundCert(host, 330 &private_key_info, 331 &der_cert, 332 base::Bind(&FailTest), 333 &request_handle); 334 EXPECT_EQ(ERR_IO_PENDING, error); 335 EXPECT_TRUE(request_handle.is_active()); 336 } 337 338 // Wait for generation to finish. 339 sequenced_worker_pool_->FlushForTesting(); 340 // Wait for reply from ServerBoundCertServiceWorker to be posted back to the 341 // ServerBoundCertService. 342 base::MessageLoop::current()->RunUntilIdle(); 343 344 // Even though the original request was cancelled, the service will still 345 // store the result, it just doesn't call the callback. 346 EXPECT_EQ(1, service_->cert_count()); 347 } 348 349 TEST_F(ServerBoundCertServiceTest, DestructionWithPendingRequest) { 350 std::string host("encrypted.google.com"); 351 std::string private_key_info, der_cert; 352 int error; 353 ServerBoundCertService::RequestHandle request_handle; 354 355 error = service_->GetDomainBoundCert(host, 356 &private_key_info, 357 &der_cert, 358 base::Bind(&FailTest), 359 &request_handle); 360 EXPECT_EQ(ERR_IO_PENDING, error); 361 EXPECT_TRUE(request_handle.is_active()); 362 363 // Cancel request and destroy the ServerBoundCertService. 364 request_handle.Cancel(); 365 service_.reset(); 366 367 // Wait for generation to finish. 368 sequenced_worker_pool_->FlushForTesting(); 369 // ServerBoundCertServiceWorker should not post anything back to the 370 // non-existant ServerBoundCertService, but run the loop just to be sure it 371 // doesn't. 372 base::MessageLoop::current()->RunUntilIdle(); 373 374 // If we got here without crashing or a valgrind error, it worked. 375 } 376 377 // Tests that shutting down the sequenced worker pool and then making new 378 // requests gracefully fails. 379 // This is a regression test for http://crbug.com/236387 380 TEST_F(ServerBoundCertServiceTest, RequestAfterPoolShutdown) { 381 // Shutdown the pool immediately. 382 sequenced_worker_pool_->Shutdown(); 383 sequenced_worker_pool_ = NULL; 384 385 // Ensure any shutdown code is processed. 386 base::MessageLoop::current()->RunUntilIdle(); 387 388 // Make a request that will force synchronous completion. 389 std::string host("encrypted.google.com"); 390 std::string private_key_info, der_cert; 391 int error; 392 ServerBoundCertService::RequestHandle request_handle; 393 394 error = service_->GetDomainBoundCert(host, 395 &private_key_info, 396 &der_cert, 397 base::Bind(&FailTest), 398 &request_handle); 399 // If we got here without crashing or a valgrind error, it worked. 400 ASSERT_EQ(ERR_INSUFFICIENT_RESOURCES, error); 401 EXPECT_FALSE(request_handle.is_active()); 402 } 403 404 // Tests that simultaneous creation of different certs works. 405 TEST_F(ServerBoundCertServiceTest, SimultaneousCreation) { 406 int error; 407 408 std::string host1("encrypted.google.com"); 409 std::string private_key_info1, der_cert1; 410 TestCompletionCallback callback1; 411 ServerBoundCertService::RequestHandle request_handle1; 412 413 std::string host2("foo.com"); 414 std::string private_key_info2, der_cert2; 415 TestCompletionCallback callback2; 416 ServerBoundCertService::RequestHandle request_handle2; 417 418 std::string host3("bar.com"); 419 std::string private_key_info3, der_cert3; 420 TestCompletionCallback callback3; 421 ServerBoundCertService::RequestHandle request_handle3; 422 423 error = service_->GetDomainBoundCert(host1, 424 &private_key_info1, 425 &der_cert1, 426 callback1.callback(), 427 &request_handle1); 428 EXPECT_EQ(ERR_IO_PENDING, error); 429 EXPECT_TRUE(request_handle1.is_active()); 430 431 error = service_->GetDomainBoundCert(host2, 432 &private_key_info2, 433 &der_cert2, 434 callback2.callback(), 435 &request_handle2); 436 EXPECT_EQ(ERR_IO_PENDING, error); 437 EXPECT_TRUE(request_handle2.is_active()); 438 439 error = service_->GetDomainBoundCert(host3, 440 &private_key_info3, 441 &der_cert3, 442 callback3.callback(), 443 &request_handle3); 444 EXPECT_EQ(ERR_IO_PENDING, error); 445 EXPECT_TRUE(request_handle3.is_active()); 446 447 error = callback1.WaitForResult(); 448 EXPECT_EQ(OK, error); 449 EXPECT_FALSE(private_key_info1.empty()); 450 EXPECT_FALSE(der_cert1.empty()); 451 452 error = callback2.WaitForResult(); 453 EXPECT_EQ(OK, error); 454 EXPECT_FALSE(private_key_info2.empty()); 455 EXPECT_FALSE(der_cert2.empty()); 456 457 error = callback3.WaitForResult(); 458 EXPECT_EQ(OK, error); 459 EXPECT_FALSE(private_key_info3.empty()); 460 EXPECT_FALSE(der_cert3.empty()); 461 462 EXPECT_NE(private_key_info1, private_key_info2); 463 EXPECT_NE(der_cert1, der_cert2); 464 465 EXPECT_NE(private_key_info1, private_key_info3); 466 EXPECT_NE(der_cert1, der_cert3); 467 468 EXPECT_NE(private_key_info2, private_key_info3); 469 EXPECT_NE(der_cert2, der_cert3); 470 471 EXPECT_EQ(3, service_->cert_count()); 472 } 473 474 TEST_F(ServerBoundCertServiceTest, Expiration) { 475 ServerBoundCertStore* store = service_->GetCertStore(); 476 base::Time now = base::Time::Now(); 477 store->SetServerBoundCert("good", 478 now, 479 now + base::TimeDelta::FromDays(1), 480 "a", 481 "b"); 482 store->SetServerBoundCert("expired", 483 now - base::TimeDelta::FromDays(2), 484 now - base::TimeDelta::FromDays(1), 485 "c", 486 "d"); 487 EXPECT_EQ(2, service_->cert_count()); 488 489 int error; 490 TestCompletionCallback callback; 491 ServerBoundCertService::RequestHandle request_handle; 492 493 // Cert is valid - synchronous completion. 494 std::string private_key_info1, der_cert1; 495 error = service_->GetDomainBoundCert( 496 "good", &private_key_info1, &der_cert1, 497 callback.callback(), &request_handle); 498 EXPECT_EQ(OK, error); 499 EXPECT_FALSE(request_handle.is_active()); 500 EXPECT_EQ(2, service_->cert_count()); 501 EXPECT_STREQ("a", private_key_info1.c_str()); 502 EXPECT_STREQ("b", der_cert1.c_str()); 503 504 // Expired cert is valid as well - synchronous completion. 505 std::string private_key_info2, der_cert2; 506 error = service_->GetDomainBoundCert( 507 "expired", &private_key_info2, &der_cert2, 508 callback.callback(), &request_handle); 509 EXPECT_EQ(OK, error); 510 EXPECT_FALSE(request_handle.is_active()); 511 EXPECT_EQ(2, service_->cert_count()); 512 EXPECT_STREQ("c", private_key_info2.c_str()); 513 EXPECT_STREQ("d", der_cert2.c_str()); 514 } 515 516 TEST_F(ServerBoundCertServiceTest, AsyncStoreGetNoCertsInStore) { 517 MockServerBoundCertStoreWithAsyncGet* mock_store = 518 new MockServerBoundCertStoreWithAsyncGet(); 519 service_ = scoped_ptr<ServerBoundCertService>( 520 new ServerBoundCertService(mock_store, sequenced_worker_pool_)); 521 522 std::string host("encrypted.google.com"); 523 524 int error; 525 TestCompletionCallback callback; 526 ServerBoundCertService::RequestHandle request_handle; 527 528 // Asynchronous completion with no certs in the store. 529 std::string private_key_info, der_cert; 530 EXPECT_EQ(0, service_->cert_count()); 531 error = service_->GetDomainBoundCert( 532 host, &private_key_info, &der_cert, callback.callback(), &request_handle); 533 EXPECT_EQ(ERR_IO_PENDING, error); 534 EXPECT_TRUE(request_handle.is_active()); 535 536 mock_store->CallGetServerBoundCertCallbackWithResult( 537 ERR_FILE_NOT_FOUND, base::Time(), std::string(), std::string()); 538 539 error = callback.WaitForResult(); 540 EXPECT_EQ(OK, error); 541 EXPECT_EQ(1, service_->cert_count()); 542 EXPECT_FALSE(private_key_info.empty()); 543 EXPECT_FALSE(der_cert.empty()); 544 EXPECT_FALSE(request_handle.is_active()); 545 } 546 547 TEST_F(ServerBoundCertServiceTest, AsyncStoreGetOneCertInStore) { 548 MockServerBoundCertStoreWithAsyncGet* mock_store = 549 new MockServerBoundCertStoreWithAsyncGet(); 550 service_ = scoped_ptr<ServerBoundCertService>( 551 new ServerBoundCertService(mock_store, sequenced_worker_pool_)); 552 553 std::string host("encrypted.google.com"); 554 555 int error; 556 TestCompletionCallback callback; 557 ServerBoundCertService::RequestHandle request_handle; 558 559 // Asynchronous completion with a cert in the store. 560 std::string private_key_info, der_cert; 561 EXPECT_EQ(0, service_->cert_count()); 562 error = service_->GetDomainBoundCert( 563 host, &private_key_info, &der_cert, callback.callback(), &request_handle); 564 EXPECT_EQ(ERR_IO_PENDING, error); 565 EXPECT_TRUE(request_handle.is_active()); 566 567 mock_store->CallGetServerBoundCertCallbackWithResult( 568 OK, base::Time(), "ab", "cd"); 569 570 error = callback.WaitForResult(); 571 EXPECT_EQ(OK, error); 572 EXPECT_EQ(1, service_->cert_count()); 573 EXPECT_EQ(1u, service_->requests()); 574 EXPECT_EQ(1u, service_->cert_store_hits()); 575 // Because the cert was found in the store, no new workers should have been 576 // created. 577 EXPECT_EQ(0u, service_->workers_created()); 578 EXPECT_STREQ("ab", private_key_info.c_str()); 579 EXPECT_STREQ("cd", der_cert.c_str()); 580 EXPECT_FALSE(request_handle.is_active()); 581 } 582 583 #endif // !defined(USE_OPENSSL) 584 585 } // namespace 586 587 } // namespace net 588