Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 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/cert/internal/cert_issuer_source_aia.h" | 5 #include "net/cert/internal/cert_issuer_source_aia.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "net/cert/cert_net_fetcher.h" | 8 #include "net/cert/cert_net_fetcher.h" |
| 9 #include "net/cert/internal/cert_errors.h" | 9 #include "net/cert/internal/cert_errors.h" |
| 10 #include "url/gurl.h" | 10 #include "url/gurl.h" |
| 11 | 11 |
| 12 namespace net { | 12 namespace net { |
| 13 | 13 |
| 14 namespace { | 14 namespace { |
| 15 | 15 |
| 16 // TODO(mattm): These are arbitrary choices. Re-evaluate. | 16 // TODO(mattm): These are arbitrary choices. Re-evaluate. |
| 17 const int kTimeoutMilliseconds = 10000; | 17 const int kTimeoutMilliseconds = 10000; |
| 18 const int kMaxResponseBytes = 65536; | 18 const int kMaxResponseBytes = 65536; |
| 19 const int kMaxFetchesPerCert = 5; | 19 const int kMaxFetchesPerCert = 5; |
| 20 | 20 |
| 21 class AiaRequest : public CertIssuerSource::Request { | 21 class AiaRequest : public CertIssuerSource::Request { |
| 22 public: | 22 public: |
| 23 explicit AiaRequest(const CertIssuerSource::IssuerCallback& issuers_callback); | 23 AiaRequest() {} |
| 24 ~AiaRequest() override; | 24 ~AiaRequest() override; |
| 25 | 25 |
| 26 // CertIssuerSource::Request implementation. | 26 // CertIssuerSource::Request implementation. |
| 27 CompletionStatus GetNext(scoped_refptr<ParsedCertificate>* out_cert) override; | 27 void GetNext(ParsedCertificateList* issuers) override; |
| 28 | 28 |
| 29 void AddCertFetcherRequest( | 29 void AddCertFetcherRequest( |
| 30 std::unique_ptr<CertNetFetcher::Request> cert_fetcher_request); | 30 std::unique_ptr<CertNetFetcher::Request> cert_fetcher_request); |
| 31 | 31 |
| 32 void OnFetchCompleted(Error error, const std::vector<uint8_t>& fetched_bytes); | 32 bool OnFetchCompleted(Error error, |
| 33 std::vector<uint8_t> fetched_bytes, | |
| 34 ParsedCertificateList* results); | |
| 33 | 35 |
| 34 private: | 36 private: |
| 35 bool HasNext() const { return current_result_ < results_.size(); } | |
| 36 | |
| 37 CertIssuerSource::IssuerCallback issuers_callback_; | |
| 38 std::vector<std::unique_ptr<CertNetFetcher::Request>> cert_fetcher_requests_; | 37 std::vector<std::unique_ptr<CertNetFetcher::Request>> cert_fetcher_requests_; |
| 39 size_t pending_requests_ = 0; | 38 size_t current_request_ = 0; |
| 40 ParsedCertificateList results_; | |
| 41 size_t current_result_ = 0; | |
| 42 | 39 |
| 43 DISALLOW_COPY_AND_ASSIGN(AiaRequest); | 40 DISALLOW_COPY_AND_ASSIGN(AiaRequest); |
| 44 }; | 41 }; |
| 45 | 42 |
| 46 AiaRequest::AiaRequest(const CertIssuerSource::IssuerCallback& issuers_callback) | |
| 47 : issuers_callback_(issuers_callback) {} | |
| 48 | |
| 49 AiaRequest::~AiaRequest() = default; | 43 AiaRequest::~AiaRequest() = default; |
| 50 | 44 |
| 51 CompletionStatus AiaRequest::GetNext( | 45 void AiaRequest::GetNext(ParsedCertificateList* out_certs) { |
| 52 scoped_refptr<ParsedCertificate>* out_cert) { | 46 // TODO(eroman): Rather than blocking in FIFO order, select the one that |
| 53 if (HasNext()) { | 47 // completes first. |
| 54 *out_cert = std::move(results_[current_result_++]); | 48 while (current_request_ < cert_fetcher_requests_.size()) { |
| 55 return CompletionStatus::SYNC; | 49 Error error; |
| 50 std::vector<uint8_t> bytes; | |
| 51 auto req = std::move(cert_fetcher_requests_[current_request_++]); | |
| 52 req->WaitForResult(&error, &bytes); | |
| 53 | |
| 54 if (OnFetchCompleted(error, std::move(bytes), out_certs)) | |
| 55 return; | |
| 56 } | 56 } |
| 57 *out_cert = nullptr; | |
| 58 if (pending_requests_) | |
| 59 return CompletionStatus::ASYNC; | |
| 60 return CompletionStatus::SYNC; | |
| 61 } | 57 } |
| 62 | 58 |
| 63 void AiaRequest::AddCertFetcherRequest( | 59 void AiaRequest::AddCertFetcherRequest( |
| 64 std::unique_ptr<CertNetFetcher::Request> cert_fetcher_request) { | 60 std::unique_ptr<CertNetFetcher::Request> cert_fetcher_request) { |
| 65 DCHECK(cert_fetcher_request); | 61 DCHECK(cert_fetcher_request); |
| 66 cert_fetcher_requests_.push_back(std::move(cert_fetcher_request)); | 62 cert_fetcher_requests_.push_back(std::move(cert_fetcher_request)); |
| 67 pending_requests_++; | |
| 68 } | 63 } |
| 69 | 64 |
| 70 void AiaRequest::OnFetchCompleted(Error error, | 65 bool AiaRequest::OnFetchCompleted(Error error, |
|
mattm
2016/10/28 02:11:55
Wondering if this should be renamed, since it make
eroman
2016/11/23 22:10:21
Done -- renamed to AddCompletedFetchToResults()
| |
| 71 const std::vector<uint8_t>& fetched_bytes) { | 66 std::vector<uint8_t> fetched_bytes, |
| 72 DCHECK_GT(pending_requests_, 0U); | 67 ParsedCertificateList* results) { |
| 73 pending_requests_--; | |
| 74 bool client_waiting_for_callback = !HasNext(); | |
| 75 if (error != OK) { | 68 if (error != OK) { |
| 76 // TODO(mattm): propagate error info. | 69 // TODO(mattm): propagate error info. |
| 77 LOG(ERROR) << "AiaRequest::OnFetchCompleted got error " << error; | 70 LOG(ERROR) << "AiaRequest::OnFetchCompleted got error " << error; |
| 78 } else { | 71 return false; |
| 79 // RFC 5280 section 4.2.2.1: | |
| 80 // | |
| 81 // Conforming applications that support HTTP or FTP for accessing | |
| 82 // certificates MUST be able to accept individual DER encoded | |
| 83 // certificates and SHOULD be able to accept "certs-only" CMS messages. | |
| 84 // | |
| 85 // TODO(mattm): Is supporting CMS message format important? | |
| 86 // | |
| 87 // TODO(mattm): Avoid copying bytes. Change the CertNetFetcher and | |
| 88 // ParsedCertificate interface to allow passing through ownership of the | |
| 89 // bytes. | |
| 90 CertErrors errors; | |
| 91 if (!ParsedCertificate::CreateAndAddToVector(fetched_bytes.data(), | |
| 92 fetched_bytes.size(), {}, | |
| 93 &results_, &errors)) { | |
| 94 // TODO(crbug.com/634443): propagate error info. | |
| 95 LOG(ERROR) << "Error parsing cert retrieved from AIA:\n" | |
| 96 << errors.ToDebugString(); | |
| 97 } | |
| 98 } | 72 } |
| 99 // If the client is waiting for results, need to run callback if: | 73 // RFC 5280 section 4.2.2.1: |
| 100 // * Some are available now. | 74 // |
| 101 // * The last fetch finished, even with no results. (Client needs to know to | 75 // Conforming applications that support HTTP or FTP for accessing |
| 102 // stop waiting.) | 76 // certificates MUST be able to accept individual DER encoded |
| 103 if (client_waiting_for_callback && (HasNext() || pending_requests_ == 0)) | 77 // certificates and SHOULD be able to accept "certs-only" CMS messages. |
| 104 issuers_callback_.Run(this); | 78 // |
| 79 // TODO(mattm): Is supporting CMS message format important? | |
| 80 // | |
| 81 // TODO(eroman): Avoid copying bytes in the certificate? | |
| 82 CertErrors errors; | |
| 83 if (!ParsedCertificate::CreateAndAddToVector( | |
| 84 fetched_bytes.data(), fetched_bytes.size(), {}, results, &errors)) { | |
| 85 // TODO(crbug.com/634443): propagate error info. | |
| 86 LOG(ERROR) << "Error parsing cert retrieved from AIA:\n" | |
| 87 << errors.ToDebugString(); | |
| 88 return false; | |
| 89 } | |
| 90 | |
| 91 return true; | |
| 105 } | 92 } |
| 106 | 93 |
| 107 } // namespace | 94 } // namespace |
| 108 | 95 |
| 109 CertIssuerSourceAia::CertIssuerSourceAia(CertNetFetcher* cert_fetcher) | 96 CertIssuerSourceAia::CertIssuerSourceAia(CertNetFetcher* cert_fetcher) |
| 110 : cert_fetcher_(cert_fetcher) {} | 97 : cert_fetcher_(cert_fetcher) {} |
| 111 | 98 |
| 112 CertIssuerSourceAia::~CertIssuerSourceAia() = default; | 99 CertIssuerSourceAia::~CertIssuerSourceAia() = default; |
| 113 | 100 |
| 114 void CertIssuerSourceAia::SyncGetIssuersOf(const ParsedCertificate* cert, | 101 void CertIssuerSourceAia::SyncGetIssuersOf(const ParsedCertificate* cert, |
| 115 ParsedCertificateList* issuers) { | 102 ParsedCertificateList* issuers) { |
| 116 // CertIssuerSourceAia never returns synchronous results. | 103 // CertIssuerSourceAia never returns synchronous results. |
| 117 } | 104 } |
| 118 | 105 |
| 119 void CertIssuerSourceAia::AsyncGetIssuersOf( | 106 void CertIssuerSourceAia::AsyncGetIssuersOf(const ParsedCertificate* cert, |
| 120 const ParsedCertificate* cert, | 107 std::unique_ptr<Request>* out_req) { |
| 121 const IssuerCallback& issuers_callback, | |
| 122 std::unique_ptr<Request>* out_req) { | |
| 123 out_req->reset(); | 108 out_req->reset(); |
| 124 | 109 |
| 125 if (!cert->has_authority_info_access()) | 110 if (!cert->has_authority_info_access()) |
| 126 return; | 111 return; |
| 127 | 112 |
| 128 // RFC 5280 section 4.2.2.1: | 113 // RFC 5280 section 4.2.2.1: |
| 129 // | 114 // |
| 130 // An authorityInfoAccess extension may include multiple instances of | 115 // An authorityInfoAccess extension may include multiple instances of |
| 131 // the id-ad-caIssuers accessMethod. The different instances may | 116 // the id-ad-caIssuers accessMethod. The different instances may |
| 132 // specify different methods for accessing the same information or may | 117 // specify different methods for accessing the same information or may |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 145 LOG(ERROR) << "kMaxFetchesPerCert exceeded, skipping"; | 130 LOG(ERROR) << "kMaxFetchesPerCert exceeded, skipping"; |
| 146 } | 131 } |
| 147 } else { | 132 } else { |
| 148 // TODO(mattm): propagate error info. | 133 // TODO(mattm): propagate error info. |
| 149 LOG(ERROR) << "invalid AIA URL: " << uri; | 134 LOG(ERROR) << "invalid AIA URL: " << uri; |
| 150 } | 135 } |
| 151 } | 136 } |
| 152 if (urls.empty()) | 137 if (urls.empty()) |
| 153 return; | 138 return; |
| 154 | 139 |
| 155 std::unique_ptr<AiaRequest> aia_request(new AiaRequest(issuers_callback)); | 140 std::unique_ptr<AiaRequest> aia_request(new AiaRequest()); |
| 156 | 141 |
| 157 for (const auto& url : urls) { | 142 for (const auto& url : urls) { |
| 158 // TODO(mattm): add synchronous failure mode to FetchCaIssuers interface so | 143 // TODO(mattm): add synchronous failure mode to FetchCaIssuers interface so |
| 159 // that this doesn't need to wait for async callback just to tell that an | 144 // that this doesn't need to wait for async callback just to tell that an |
| 160 // URL has an unsupported scheme? | 145 // URL has an unsupported scheme? |
| 161 aia_request->AddCertFetcherRequest(cert_fetcher_->FetchCaIssuers( | 146 aia_request->AddCertFetcherRequest(cert_fetcher_->FetchCaIssuers( |
| 162 url, kTimeoutMilliseconds, kMaxResponseBytes, | 147 url, kTimeoutMilliseconds, kMaxResponseBytes)); |
| 163 base::Bind(&AiaRequest::OnFetchCompleted, | |
| 164 base::Unretained(aia_request.get())))); | |
| 165 } | 148 } |
| 166 | 149 |
| 167 *out_req = std::move(aia_request); | 150 *out_req = std::move(aia_request); |
| 168 } | 151 } |
| 169 | 152 |
| 170 } // namespace net | 153 } // namespace net |
| OLD | NEW |