Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(968)

Side by Side Diff: components/cast_certificate/cast_cert_validator.cc

Issue 1976433002: Add new ParsedCertificate class, move TrustStore to own file. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@cert-parsing-remove-old-parsedcertificate
Patch Set: ScopedCheckUnreferencedCerts Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | net/cert/internal/parse_certificate.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 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 "components/cast_certificate/cast_cert_validator.h" 5 #include "components/cast_certificate/cast_cert_validator.h"
6 6
7 #include <stddef.h> 7 #include <stddef.h>
8 #include <stdint.h> 8 #include <stdint.h>
9 9
10 #include <algorithm> 10 #include <algorithm>
11 #include <memory> 11 #include <memory>
12 #include <utility> 12 #include <utility>
13 13
14 #include "base/memory/ptr_util.h" 14 #include "base/memory/ptr_util.h"
15 #include "base/memory/singleton.h" 15 #include "base/memory/singleton.h"
16 #include "net/cert/internal/certificate_policies.h" 16 #include "net/cert/internal/certificate_policies.h"
17 #include "net/cert/internal/extended_key_usage.h" 17 #include "net/cert/internal/extended_key_usage.h"
18 #include "net/cert/internal/parse_certificate.h" 18 #include "net/cert/internal/parse_certificate.h"
19 #include "net/cert/internal/parse_name.h" 19 #include "net/cert/internal/parse_name.h"
20 #include "net/cert/internal/parsed_certificate.h"
20 #include "net/cert/internal/signature_algorithm.h" 21 #include "net/cert/internal/signature_algorithm.h"
21 #include "net/cert/internal/signature_policy.h" 22 #include "net/cert/internal/signature_policy.h"
23 #include "net/cert/internal/trust_store.h"
22 #include "net/cert/internal/verify_certificate_chain.h" 24 #include "net/cert/internal/verify_certificate_chain.h"
23 #include "net/cert/internal/verify_signed_data.h" 25 #include "net/cert/internal/verify_signed_data.h"
24 #include "net/der/input.h" 26 #include "net/der/input.h"
25 27
26 namespace cast_certificate { 28 namespace cast_certificate {
27 namespace { 29 namespace {
28 30
29 // ------------------------------------------------------------------------- 31 // -------------------------------------------------------------------------
30 // Cast trust anchors. 32 // Cast trust anchors.
31 // ------------------------------------------------------------------------- 33 // -------------------------------------------------------------------------
(...skipping 16 matching lines...) Expand all
48 base::LeakySingletonTraits<CastTrustStore>>::get(); 50 base::LeakySingletonTraits<CastTrustStore>>::get();
49 } 51 }
50 52
51 static net::TrustStore& Get() { return GetInstance()->store_; } 53 static net::TrustStore& Get() { return GetInstance()->store_; }
52 54
53 private: 55 private:
54 friend struct base::DefaultSingletonTraits<CastTrustStore>; 56 friend struct base::DefaultSingletonTraits<CastTrustStore>;
55 57
56 CastTrustStore() { 58 CastTrustStore() {
57 // Initialize the trust store with two root certificates. 59 // Initialize the trust store with two root certificates.
58 CHECK(store_.AddTrustedCertificateWithoutCopying(kCastRootCaDer, 60 scoped_refptr<net::ParsedCertificate> root =
59 sizeof(kCastRootCaDer))); 61 net::ParsedCertificate::CreateFromCertificateData(
60 CHECK(store_.AddTrustedCertificateWithoutCopying(kEurekaRootCaDer, 62 kCastRootCaDer, sizeof(kCastRootCaDer),
61 sizeof(kEurekaRootCaDer))); 63 net::ParsedCertificate::DataSource::EXTERNAL_REFERENCE);
64 CHECK(root);
65 store_.AddTrustedCertificate(std::move(root));
66
67 root = net::ParsedCertificate::CreateFromCertificateData(
68 kEurekaRootCaDer, sizeof(kEurekaRootCaDer),
69 net::ParsedCertificate::DataSource::EXTERNAL_REFERENCE);
70 CHECK(root);
71 store_.AddTrustedCertificate(std::move(root));
62 } 72 }
63 73
64 net::TrustStore store_; 74 net::TrustStore store_;
65 DISALLOW_COPY_AND_ASSIGN(CastTrustStore); 75 DISALLOW_COPY_AND_ASSIGN(CastTrustStore);
66 }; 76 };
67 77
68 using ExtensionsMap = std::map<net::der::Input, net::ParsedExtension>; 78 using ExtensionsMap = std::map<net::der::Input, net::ParsedExtension>;
69 79
70 // Helper that looks up an extension by OID given a map of extensions. 80 // Helper that looks up an extension by OID given a map of extensions.
71 bool GetExtensionValue(const ExtensionsMap& extensions, 81 bool GetExtensionValue(const ExtensionsMap& extensions,
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after
160 for (const auto& oid : ekus) { 170 for (const auto& oid : ekus) {
161 if (oid == net::ClientAuth()) 171 if (oid == net::ClientAuth())
162 return true; 172 return true;
163 } 173 }
164 return false; 174 return false;
165 } 175 }
166 176
167 // Checks properties on the target certificate. 177 // Checks properties on the target certificate.
168 // 178 //
169 // * The Key Usage must include Digital Signature 179 // * The Key Usage must include Digital Signature
170 // * THe Extended Key Usage must includ TLS Client Auth 180 // * The Extended Key Usage must include TLS Client Auth
171 // * May have the policy 1.3.6.1.4.1.11129.2.5.2 to indicate it 181 // * May have the policy 1.3.6.1.4.1.11129.2.5.2 to indicate it
172 // is an audio-only device. 182 // is an audio-only device.
173 WARN_UNUSED_RESULT bool CheckTargetCertificate( 183 WARN_UNUSED_RESULT bool CheckTargetCertificate(
174 const net::der::Input& cert_der, 184 const net::ParsedCertificate* cert,
175 std::unique_ptr<CertVerificationContext>* context, 185 std::unique_ptr<CertVerificationContext>* context,
176 CastDeviceCertPolicy* policy) { 186 CastDeviceCertPolicy* policy) {
177 // TODO(eroman): Simplify this. The certificate chain verification
178 // function already parses this stuff, awkward to re-do it here.
179
180 net::der::Input tbs_certificate_tlv;
181 net::der::Input signature_algorithm_tlv;
182 net::der::BitString signature_value;
183 if (!net::ParseCertificate(cert_der, &tbs_certificate_tlv,
184 &signature_algorithm_tlv, &signature_value))
185 return false;
186
187 net::ParsedTbsCertificate tbs;
188 if (!net::ParseTbsCertificate(tbs_certificate_tlv, &tbs))
189 return false;
190
191 // Get the extensions.
192 if (!tbs.has_extensions)
193 return false;
194 ExtensionsMap extensions;
195 if (!net::ParseExtensions(tbs.extensions_tlv, &extensions))
196 return false;
197
198 net::der::Input extension_value;
199
200 // Get the Key Usage extension. 187 // Get the Key Usage extension.
201 if (!GetExtensionValue(extensions, net::KeyUsageOid(), &extension_value)) 188 if (!cert->has_key_usage())
202 return false;
203 net::der::BitString key_usage;
204 if (!net::ParseKeyUsage(extension_value, &key_usage))
205 return false; 189 return false;
206 190
207 // Ensure Key Usage contains digitalSignature. 191 // Ensure Key Usage contains digitalSignature.
208 if (!key_usage.AssertsBit(net::KEY_USAGE_BIT_DIGITAL_SIGNATURE)) 192 if (!cert->key_usage().AssertsBit(net::KEY_USAGE_BIT_DIGITAL_SIGNATURE))
209 return false; 193 return false;
210 194
211 // Get the Extended Key Usage extension. 195 // Get the Extended Key Usage extension.
212 if (!GetExtensionValue(extensions, net::ExtKeyUsageOid(), &extension_value)) 196 net::der::Input extension_value;
197 if (!GetExtensionValue(cert->unparsed_extensions(), net::ExtKeyUsageOid(),
198 &extension_value)) {
213 return false; 199 return false;
200 }
214 std::vector<net::der::Input> ekus; 201 std::vector<net::der::Input> ekus;
215 if (!net::ParseEKUExtension(extension_value, &ekus)) 202 if (!net::ParseEKUExtension(extension_value, &ekus))
216 return false; 203 return false;
217 204
218 // Ensure Extended Key Usage contains client auth. 205 // Ensure Extended Key Usage contains client auth.
219 if (!HasClientAuth(ekus)) 206 if (!HasClientAuth(ekus))
220 return false; 207 return false;
221 208
222 // Check for an optional audio-only policy extension. 209 // Check for an optional audio-only policy extension.
223 *policy = CastDeviceCertPolicy::NONE; 210 *policy = CastDeviceCertPolicy::NONE;
224 if (GetExtensionValue(extensions, net::CertificatePoliciesOid(), 211 if (GetExtensionValue(cert->unparsed_extensions(),
225 &extension_value)) { 212 net::CertificatePoliciesOid(), &extension_value)) {
226 std::vector<net::der::Input> policies; 213 std::vector<net::der::Input> policies;
227 if (!net::ParseCertificatePoliciesExtension(extension_value, &policies)) 214 if (!net::ParseCertificatePoliciesExtension(extension_value, &policies))
228 return false; 215 return false;
229 216
230 // Look for an audio-only policy. Disregard any other policy found. 217 // Look for an audio-only policy. Disregard any other policy found.
231 if (std::find(policies.begin(), policies.end(), AudioOnlyPolicyOid()) != 218 if (std::find(policies.begin(), policies.end(), AudioOnlyPolicyOid()) !=
232 policies.end()) { 219 policies.end()) {
233 *policy = CastDeviceCertPolicy::AUDIO_ONLY; 220 *policy = CastDeviceCertPolicy::AUDIO_ONLY;
234 } 221 }
235 } 222 }
236 223
237 // Get the Common Name for the certificate. 224 // Get the Common Name for the certificate.
238 std::string common_name; 225 std::string common_name;
239 if (!GetCommonNameFromSubject(tbs.subject_tlv, &common_name)) 226 if (!GetCommonNameFromSubject(cert->tbs().subject_tlv, &common_name))
240 return false; 227 return false;
241 228
242 context->reset(new CertVerificationContextImpl(tbs.spki_tlv, common_name)); 229 context->reset(
230 new CertVerificationContextImpl(cert->tbs().spki_tlv, common_name));
243 return true; 231 return true;
244 } 232 }
245 233
246 // Converts a base::Time::Exploded to a net::der::GeneralizedTime. 234 // Converts a base::Time::Exploded to a net::der::GeneralizedTime.
247 net::der::GeneralizedTime ConvertExplodedTime( 235 net::der::GeneralizedTime ConvertExplodedTime(
248 const base::Time::Exploded& exploded) { 236 const base::Time::Exploded& exploded) {
249 net::der::GeneralizedTime result; 237 net::der::GeneralizedTime result;
250 result.year = exploded.year; 238 result.year = exploded.year;
251 result.month = exploded.month; 239 result.month = exploded.month;
252 result.day = exploded.day_of_month; 240 result.day = exploded.day_of_month;
253 result.hours = exploded.hour; 241 result.hours = exploded.hour;
254 result.minutes = exploded.minute; 242 result.minutes = exploded.minute;
255 result.seconds = exploded.second; 243 result.seconds = exploded.second;
256 return result; 244 return result;
257 } 245 }
258 246
247 class ScopedCheckUnreferencedCerts {
248 public:
249 explicit ScopedCheckUnreferencedCerts(
250 std::vector<scoped_refptr<net::ParsedCertificate>>* certs)
251 : certs_(certs) {}
252 ~ScopedCheckUnreferencedCerts() {
253 for (const auto& cert : *certs_)
254 DCHECK(cert->HasOneRef());
255 }
256
257 private:
258 std::vector<scoped_refptr<net::ParsedCertificate>>* certs_;
259 };
260
259 } // namespace 261 } // namespace
260 262
261 bool VerifyDeviceCert(const std::vector<std::string>& certs, 263 bool VerifyDeviceCert(const std::vector<std::string>& certs,
262 const base::Time::Exploded& time, 264 const base::Time::Exploded& time,
263 std::unique_ptr<CertVerificationContext>* context, 265 std::unique_ptr<CertVerificationContext>* context,
264 CastDeviceCertPolicy* policy) { 266 CastDeviceCertPolicy* policy) {
265 // The underlying verification function expects a sequence of 267 // The underlying verification function expects a sequence of
266 // der::Input, so wrap the data in it (cheap). 268 // ParsedCertificate.
267 std::vector<net::der::Input> input_chain; 269 std::vector<scoped_refptr<net::ParsedCertificate>> input_chain;
268 for (const auto& cert : certs) 270 // Verify that nothing saves a reference to the input certs, since the backing
269 input_chain.push_back(net::der::Input(&cert)); 271 // data will go out of scope when the function finishes.
272 ScopedCheckUnreferencedCerts ref_checker(&input_chain);
273
274 for (const auto& cert_der : certs) {
275 // No reference to the ParsedCertificate is kept past the end of this
276 // function, so using EXTERNAL_REFERENCE here is safe.
277 if (!net::ParsedCertificate::CreateAndAddToVector(
278 reinterpret_cast<const uint8_t*>(cert_der.data()), cert_der.size(),
279 net::ParsedCertificate::DataSource::EXTERNAL_REFERENCE,
280 &input_chain)) {
281 return false;
282 }
283 }
270 284
271 // Use a signature policy compatible with Cast's PKI. 285 // Use a signature policy compatible with Cast's PKI.
272 auto signature_policy = CreateCastSignaturePolicy(); 286 auto signature_policy = CreateCastSignaturePolicy();
273 287
274 // Do RFC 5280 compatible certificate verification using the two Cast 288 // Do RFC 5280 compatible certificate verification using the two Cast
275 // trust anchors and Cast signature policy. 289 // trust anchors and Cast signature policy.
276 if (!net::VerifyCertificateChain(input_chain, CastTrustStore::Get(), 290 if (!net::VerifyCertificateChain(input_chain, CastTrustStore::Get(),
277 signature_policy.get(), 291 signature_policy.get(),
278 ConvertExplodedTime(time))) { 292 ConvertExplodedTime(time))) {
279 return false; 293 return false;
280 } 294 }
281 295
282 // Check properties of the leaf certificate (key usage, policy), and construct 296 // Check properties of the leaf certificate (key usage, policy), and construct
283 // a CertVerificationContext that uses its public key. 297 // a CertVerificationContext that uses its public key.
284 return CheckTargetCertificate(input_chain[0], context, policy); 298 return CheckTargetCertificate(input_chain[0].get(), context, policy);
285 } 299 }
286 300
287 std::unique_ptr<CertVerificationContext> CertVerificationContextImplForTest( 301 std::unique_ptr<CertVerificationContext> CertVerificationContextImplForTest(
288 const base::StringPiece& spki) { 302 const base::StringPiece& spki) {
289 // Use a bogus CommonName, since this is just exposed for testing signature 303 // Use a bogus CommonName, since this is just exposed for testing signature
290 // verification by unittests. 304 // verification by unittests.
291 return base::WrapUnique( 305 return base::WrapUnique(
292 new CertVerificationContextImpl(net::der::Input(spki), "CommonName")); 306 new CertVerificationContextImpl(net::der::Input(spki), "CommonName"));
293 } 307 }
294 308
295 bool AddTrustAnchorForTest(const uint8_t* data, size_t length) { 309 bool AddTrustAnchorForTest(const uint8_t* data, size_t length) {
sheretov 2016/06/03 22:08:02 This looks strange to me. The old code was adding
eroman 2016/06/03 22:10:27 Agreed, this is wrong. I should have noticed durin
mattm 2016/06/03 22:26:12 Eek, thanks. Fixed.
296 return CastTrustStore::Get().AddTrustedCertificateWithoutCopying(data, 310 scoped_refptr<net::ParsedCertificate> anchor(
297 length); 311 net::ParsedCertificate::CreateFromCertificateData(
312 kCastRootCaDer, sizeof(kCastRootCaDer),
313 net::ParsedCertificate::DataSource::EXTERNAL_REFERENCE));
314 if (!anchor)
315 return false;
316 CastTrustStore::Get().AddTrustedCertificate(std::move(anchor));
317 return true;
298 } 318 }
299 319
300 } // namespace cast_certificate 320 } // namespace cast_certificate
OLDNEW
« no previous file with comments | « no previous file | net/cert/internal/parse_certificate.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698