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 |