OLD | NEW |
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "net/ocsp/nss_ocsp.h" | 5 #include "net/ocsp/nss_ocsp.h" |
6 | 6 |
7 #include <certt.h> | 7 #include <certt.h> |
8 #include <certdb.h> | 8 #include <certdb.h> |
9 #include <ocsp.h> | 9 #include <ocsp.h> |
10 #include <nspr.h> | 10 #include <nspr.h> |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
90 return request_context_; | 90 return request_context_; |
91 } | 91 } |
92 | 92 |
93 private: | 93 private: |
94 friend struct DefaultSingletonTraits<OCSPInitSingleton>; | 94 friend struct DefaultSingletonTraits<OCSPInitSingleton>; |
95 | 95 |
96 OCSPInitSingleton() | 96 OCSPInitSingleton() |
97 : io_loop_(MessageLoopForIO::current()) { | 97 : io_loop_(MessageLoopForIO::current()) { |
98 DCHECK(io_loop_); | 98 DCHECK(io_loop_); |
99 io_loop_->AddDestructionObserver(this); | 99 io_loop_->AddDestructionObserver(this); |
| 100 |
| 101 // NSS calls the functions in the function table to download certificates |
| 102 // or CRLs or talk to OCSP responders over HTTP. These functions must |
| 103 // set an NSS/NSPR error code when they fail. Otherwise NSS will get the |
| 104 // residual error code from an earlier failed function call. |
100 client_fcn_.version = 1; | 105 client_fcn_.version = 1; |
101 SEC_HttpClientFcnV1Struct *ft = &client_fcn_.fcnTable.ftable1; | 106 SEC_HttpClientFcnV1Struct *ft = &client_fcn_.fcnTable.ftable1; |
102 ft->createSessionFcn = OCSPCreateSession; | 107 ft->createSessionFcn = OCSPCreateSession; |
103 ft->keepAliveSessionFcn = OCSPKeepAliveSession; | 108 ft->keepAliveSessionFcn = OCSPKeepAliveSession; |
104 ft->freeSessionFcn = OCSPFreeSession; | 109 ft->freeSessionFcn = OCSPFreeSession; |
105 ft->createFcn = OCSPCreate; | 110 ft->createFcn = OCSPCreate; |
106 ft->setPostDataFcn = OCSPSetPostData; | 111 ft->setPostDataFcn = OCSPSetPostData; |
107 ft->addHeaderFcn = OCSPAddHeader; | 112 ft->addHeaderFcn = OCSPAddHeader; |
108 ft->trySendAndReceiveFcn = OCSPTrySendAndReceive; | 113 ft->trySendAndReceiveFcn = OCSPTrySendAndReceive; |
109 ft->cancelFcn = NULL; | 114 ft->cancelFcn = NULL; |
(...skipping 304 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
414 : host_(host), port_(port) {} | 419 : host_(host), port_(port) {} |
415 ~OCSPServerSession() {} | 420 ~OCSPServerSession() {} |
416 | 421 |
417 OCSPRequestSession* CreateRequest(const char* http_protocol_variant, | 422 OCSPRequestSession* CreateRequest(const char* http_protocol_variant, |
418 const char* path_and_query_string, | 423 const char* path_and_query_string, |
419 const char* http_request_method, | 424 const char* http_request_method, |
420 const PRIntervalTime timeout) { | 425 const PRIntervalTime timeout) { |
421 // We dont' support "https" because we haven't thought about | 426 // We dont' support "https" because we haven't thought about |
422 // whether it's safe to re-enter this code from talking to an OCSP | 427 // whether it's safe to re-enter this code from talking to an OCSP |
423 // responder over SSL. | 428 // responder over SSL. |
424 if (strcmp(http_protocol_variant, "http") != 0) | 429 if (strcmp(http_protocol_variant, "http") != 0) { |
| 430 PORT_SetError(PR_NOT_IMPLEMENTED_ERROR); |
425 return NULL; | 431 return NULL; |
| 432 } |
426 | 433 |
427 // TODO(ukai): If |host| is an IPv6 literal, we need to quote it with | 434 // TODO(ukai): If |host| is an IPv6 literal, we need to quote it with |
428 // square brackets []. | 435 // square brackets []. |
429 std::string url_string(StringPrintf("%s://%s:%d%s", | 436 std::string url_string(StringPrintf("%s://%s:%d%s", |
430 http_protocol_variant, | 437 http_protocol_variant, |
431 host_.c_str(), | 438 host_.c_str(), |
432 port_, | 439 port_, |
433 path_and_query_string)); | 440 path_and_query_string)); |
434 LOG(INFO) << "URL [" << url_string << "]"; | 441 LOG(INFO) << "URL [" << url_string << "]"; |
435 GURL url(url_string); | 442 GURL url(url_string); |
(...skipping 12 matching lines...) Expand all Loading... |
448 | 455 |
449 | 456 |
450 // OCSP Http Client functions. | 457 // OCSP Http Client functions. |
451 // Our Http Client functions operate in blocking mode. | 458 // Our Http Client functions operate in blocking mode. |
452 SECStatus OCSPCreateSession(const char* host, PRUint16 portnum, | 459 SECStatus OCSPCreateSession(const char* host, PRUint16 portnum, |
453 SEC_HTTP_SERVER_SESSION* pSession) { | 460 SEC_HTTP_SERVER_SESSION* pSession) { |
454 LOG(INFO) << "OCSP create session: host=" << host << " port=" << portnum; | 461 LOG(INFO) << "OCSP create session: host=" << host << " port=" << portnum; |
455 DCHECK(!MessageLoop::current()); | 462 DCHECK(!MessageLoop::current()); |
456 if (OCSPInitSingleton::url_request_context() == NULL) { | 463 if (OCSPInitSingleton::url_request_context() == NULL) { |
457 LOG(ERROR) << "No URLRequestContext for OCSP handler."; | 464 LOG(ERROR) << "No URLRequestContext for OCSP handler."; |
| 465 // The application failed to call SetURLRequestContextForOCSP, so we |
| 466 // can't create and use URLRequest. PR_NOT_IMPLEMENTED_ERROR is not an |
| 467 // accurate error code for this error condition, but is close enough. |
| 468 PORT_SetError(PR_NOT_IMPLEMENTED_ERROR); |
458 return SECFailure; | 469 return SECFailure; |
459 } | 470 } |
460 *pSession = new OCSPServerSession(host, portnum); | 471 *pSession = new OCSPServerSession(host, portnum); |
461 return SECSuccess; | 472 return SECSuccess; |
462 } | 473 } |
463 | 474 |
464 SECStatus OCSPKeepAliveSession(SEC_HTTP_SERVER_SESSION session, | 475 SECStatus OCSPKeepAliveSession(SEC_HTTP_SERVER_SESSION session, |
465 PRPollDesc **pPollDesc) { | 476 PRPollDesc **pPollDesc) { |
466 LOG(INFO) << "OCSP keep alive"; | 477 LOG(INFO) << "OCSP keep alive"; |
467 DCHECK(!MessageLoop::current()); | 478 DCHECK(!MessageLoop::current()); |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
525 OCSPRequestSession* req = reinterpret_cast<OCSPRequestSession*>(request); | 536 OCSPRequestSession* req = reinterpret_cast<OCSPRequestSession*>(request); |
526 | 537 |
527 req->AddHeader(http_header_name, http_header_value); | 538 req->AddHeader(http_header_name, http_header_value); |
528 return SECSuccess; | 539 return SECSuccess; |
529 } | 540 } |
530 | 541 |
531 // Sets response of |req| in the output parameters. | 542 // Sets response of |req| in the output parameters. |
532 // It is helper routine for OCSP trySendAndReceiveFcn. | 543 // It is helper routine for OCSP trySendAndReceiveFcn. |
533 // |http_response_data_len| could be used as input parameter. If it has | 544 // |http_response_data_len| could be used as input parameter. If it has |
534 // non-zero value, it is considered as maximum size of |http_response_data|. | 545 // non-zero value, it is considered as maximum size of |http_response_data|. |
535 bool OCSPSetResponse(OCSPRequestSession* req, | 546 SECStatus OCSPSetResponse(OCSPRequestSession* req, |
536 PRUint16* http_response_code, | 547 PRUint16* http_response_code, |
537 const char** http_response_content_type, | 548 const char** http_response_content_type, |
538 const char** http_response_headers, | 549 const char** http_response_headers, |
539 const char** http_response_data, | 550 const char** http_response_data, |
540 PRUint32* http_response_data_len) { | 551 PRUint32* http_response_data_len) { |
541 DCHECK(req->Finished()); | 552 DCHECK(req->Finished()); |
542 const std::string& data = req->http_response_data(); | 553 const std::string& data = req->http_response_data(); |
543 if (http_response_data_len && *http_response_data_len) { | 554 if (http_response_data_len && *http_response_data_len) { |
544 if (*http_response_data_len < data.size()) { | 555 if (*http_response_data_len < data.size()) { |
545 LOG(ERROR) << "data size too large: " << *http_response_data_len | 556 LOG(ERROR) << "response body too large: " << *http_response_data_len |
546 << " < " << data.size(); | 557 << " < " << data.size(); |
547 *http_response_data_len = data.size(); | 558 *http_response_data_len = data.size(); |
548 return false; | 559 PORT_SetError(SEC_ERROR_BAD_HTTP_RESPONSE); |
| 560 return SECFailure; |
549 } | 561 } |
550 } | 562 } |
551 LOG(INFO) << "OCSP response " | 563 LOG(INFO) << "OCSP response " |
552 << " response_code=" << req->http_response_code() | 564 << " response_code=" << req->http_response_code() |
553 << " content_type=" << req->http_response_content_type() | 565 << " content_type=" << req->http_response_content_type() |
554 << " header=" << req->http_response_headers() | 566 << " header=" << req->http_response_headers() |
555 << " data_len=" << data.size(); | 567 << " data_len=" << data.size(); |
556 if (http_response_code) | 568 if (http_response_code) |
557 *http_response_code = req->http_response_code(); | 569 *http_response_code = req->http_response_code(); |
558 if (http_response_content_type) | 570 if (http_response_content_type) |
559 *http_response_content_type = req->http_response_content_type().c_str(); | 571 *http_response_content_type = req->http_response_content_type().c_str(); |
560 if (http_response_headers) | 572 if (http_response_headers) |
561 *http_response_headers = req->http_response_headers().c_str(); | 573 *http_response_headers = req->http_response_headers().c_str(); |
562 if (http_response_data) | 574 if (http_response_data) |
563 *http_response_data = data.data(); | 575 *http_response_data = data.data(); |
564 if (http_response_data_len) | 576 if (http_response_data_len) |
565 *http_response_data_len = data.size(); | 577 *http_response_data_len = data.size(); |
566 return true; | 578 return SECSuccess; |
567 } | 579 } |
568 | 580 |
569 SECStatus OCSPTrySendAndReceive(SEC_HTTP_REQUEST_SESSION request, | 581 SECStatus OCSPTrySendAndReceive(SEC_HTTP_REQUEST_SESSION request, |
570 PRPollDesc** pPollDesc, | 582 PRPollDesc** pPollDesc, |
571 PRUint16* http_response_code, | 583 PRUint16* http_response_code, |
572 const char** http_response_content_type, | 584 const char** http_response_content_type, |
573 const char** http_response_headers, | 585 const char** http_response_headers, |
574 const char** http_response_data, | 586 const char** http_response_data, |
575 PRUint32* http_response_data_len) { | 587 PRUint32* http_response_data_len) { |
576 LOG(INFO) << "OCSP try send and receive"; | 588 LOG(INFO) << "OCSP try send and receive"; |
(...skipping 15 matching lines...) Expand all Loading... |
592 | 604 |
593 // If the response code is -1, the request failed and there is no response. | 605 // If the response code is -1, the request failed and there is no response. |
594 if (req->http_response_code() == static_cast<PRUint16>(-1)) | 606 if (req->http_response_code() == static_cast<PRUint16>(-1)) |
595 goto failed; | 607 goto failed; |
596 | 608 |
597 return OCSPSetResponse( | 609 return OCSPSetResponse( |
598 req, http_response_code, | 610 req, http_response_code, |
599 http_response_content_type, | 611 http_response_content_type, |
600 http_response_headers, | 612 http_response_headers, |
601 http_response_data, | 613 http_response_data, |
602 http_response_data_len) ? SECSuccess : SECFailure; | 614 http_response_data_len); |
603 | 615 |
604 failed: | 616 failed: |
605 if (http_response_data_len) { | 617 if (http_response_data_len) { |
606 // We must always set an output value, even on failure. The output value 0 | 618 // We must always set an output value, even on failure. The output value 0 |
607 // means the failure was unrelated to the acceptable response data length. | 619 // means the failure was unrelated to the acceptable response data length. |
608 *http_response_data_len = 0; | 620 *http_response_data_len = 0; |
609 } | 621 } |
| 622 PORT_SetError(SEC_ERROR_BAD_HTTP_RESPONSE); // Simple approximation. |
610 return SECFailure; | 623 return SECFailure; |
611 } | 624 } |
612 | 625 |
613 SECStatus OCSPFree(SEC_HTTP_REQUEST_SESSION request) { | 626 SECStatus OCSPFree(SEC_HTTP_REQUEST_SESSION request) { |
614 LOG(INFO) << "OCSP free"; | 627 LOG(INFO) << "OCSP free"; |
615 DCHECK(!MessageLoop::current()); | 628 DCHECK(!MessageLoop::current()); |
616 OCSPRequestSession* req = reinterpret_cast<OCSPRequestSession*>(request); | 629 OCSPRequestSession* req = reinterpret_cast<OCSPRequestSession*>(request); |
617 req->Cancel(); | 630 req->Cancel(); |
618 req->Release(); | 631 req->Release(); |
619 return SECSuccess; | 632 return SECSuccess; |
(...skipping 10 matching lines...) Expand all Loading... |
630 // This function would be called before NSS initialization. | 643 // This function would be called before NSS initialization. |
631 void SetURLRequestContextForOCSP(URLRequestContext* request_context) { | 644 void SetURLRequestContextForOCSP(URLRequestContext* request_context) { |
632 OCSPInitSingleton::set_url_request_context(request_context); | 645 OCSPInitSingleton::set_url_request_context(request_context); |
633 } | 646 } |
634 | 647 |
635 URLRequestContext* GetURLRequestContextForOCSP() { | 648 URLRequestContext* GetURLRequestContextForOCSP() { |
636 return OCSPInitSingleton::url_request_context(); | 649 return OCSPInitSingleton::url_request_context(); |
637 } | 650 } |
638 | 651 |
639 } // namespace net | 652 } // namespace net |
OLD | NEW |