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

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: . Created 4 years, 7 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
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 CHECK(root = net::ParsedCertificate::CreateFromCertificateData(
60 CHECK(store_.AddTrustedCertificateWithoutCopying(kEurekaRootCaDer, 62 kCastRootCaDer, sizeof(kCastRootCaDer),
61 sizeof(kEurekaRootCaDer))); 63 net::ParsedCertificate::DataSource::EXTERNAL_REFERENCE));
64 store_.AddTrustedCertificate(std::move(root));
eroman 2016/05/12 18:12:29 Rather than needing "root" temporary, how about mo
Ryan Sleevi 2016/05/12 20:41:46 Why? That's the recommended style.
mattm 2016/05/13 02:17:36 I think in this case the CHECK makes sense since i
65 CHECK(root = net::ParsedCertificate::CreateFromCertificateData(
66 kEurekaRootCaDer, sizeof(kEurekaRootCaDer),
67 net::ParsedCertificate::DataSource::EXTERNAL_REFERENCE));
68 store_.AddTrustedCertificate(std::move(root));
62 } 69 }
63 70
64 net::TrustStore store_; 71 net::TrustStore store_;
65 DISALLOW_COPY_AND_ASSIGN(CastTrustStore); 72 DISALLOW_COPY_AND_ASSIGN(CastTrustStore);
66 }; 73 };
67 74
68 using ExtensionsMap = std::map<net::der::Input, net::ParsedExtension>; 75 using ExtensionsMap = std::map<net::der::Input, net::ParsedExtension>;
69 76
70 // Helper that looks up an extension by OID given a map of extensions. 77 // Helper that looks up an extension by OID given a map of extensions.
71 bool GetExtensionValue(const ExtensionsMap& extensions, 78 bool GetExtensionValue(const ExtensionsMap& extensions,
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after
164 return false; 171 return false;
165 } 172 }
166 173
167 // Checks properties on the target certificate. 174 // Checks properties on the target certificate.
168 // 175 //
169 // * The Key Usage must include Digital Signature 176 // * The Key Usage must include Digital Signature
170 // * THe Extended Key Usage must includ TLS Client Auth 177 // * THe Extended Key Usage must includ TLS Client Auth
171 // * May have the policy 1.3.6.1.4.1.11129.2.5.2 to indicate it 178 // * May have the policy 1.3.6.1.4.1.11129.2.5.2 to indicate it
172 // is an audio-only device. 179 // is an audio-only device.
173 WARN_UNUSED_RESULT bool CheckTargetCertificate( 180 WARN_UNUSED_RESULT bool CheckTargetCertificate(
174 const net::der::Input& cert_der, 181 const net::ParsedCertificate* cert,
175 std::unique_ptr<CertVerificationContext>* context, 182 std::unique_ptr<CertVerificationContext>* context,
176 CastDeviceCertPolicy* policy) { 183 CastDeviceCertPolicy* policy) {
177 // TODO(eroman): Simplify this. The certificate chain verification
eroman 2016/05/12 18:12:29 nice, much better!
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. 184 // Get the Key Usage extension.
201 if (!GetExtensionValue(extensions, net::KeyUsageOid(), &extension_value)) 185 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; 186 return false;
206 187
207 // Ensure Key Usage contains digitalSignature. 188 // Ensure Key Usage contains digitalSignature.
208 if (!key_usage.AssertsBit(net::KEY_USAGE_BIT_DIGITAL_SIGNATURE)) 189 if (!cert->key_usage().AssertsBit(net::KEY_USAGE_BIT_DIGITAL_SIGNATURE))
209 return false; 190 return false;
210 191
211 // Get the Extended Key Usage extension. 192 // Get the Extended Key Usage extension.
212 if (!GetExtensionValue(extensions, net::ExtKeyUsageOid(), &extension_value)) 193 net::der::Input extension_value;
194 if (!GetExtensionValue(cert->unconsumed_extensions(), net::ExtKeyUsageOid(),
eroman 2016/05/12 18:12:29 This doesn't seem right, are you sure? I believe
mattm 2016/05/13 02:17:35 ParsedCertificate extracts KeyUsage extension, but
195 &extension_value))
213 return false; 196 return false;
214 std::vector<net::der::Input> ekus; 197 std::vector<net::der::Input> ekus;
215 if (!net::ParseEKUExtension(extension_value, &ekus)) 198 if (!net::ParseEKUExtension(extension_value, &ekus))
216 return false; 199 return false;
217 200
218 // Ensure Extended Key Usage contains client auth. 201 // Ensure Extended Key Usage contains client auth.
219 if (!HasClientAuth(ekus)) 202 if (!HasClientAuth(ekus))
220 return false; 203 return false;
221 204
222 // Check for an optional audio-only policy extension. 205 // Check for an optional audio-only policy extension.
223 *policy = CastDeviceCertPolicy::NONE; 206 *policy = CastDeviceCertPolicy::NONE;
224 if (GetExtensionValue(extensions, net::CertificatePoliciesOid(), 207 if (GetExtensionValue(cert->unconsumed_extensions(),
eroman 2016/05/12 18:12:29 Same here.
mattm 2016/05/13 02:17:35 CertificatePolicies isn't currently consumed by Pa
225 &extension_value)) { 208 net::CertificatePoliciesOid(), &extension_value)) {
226 std::vector<net::der::Input> policies; 209 std::vector<net::der::Input> policies;
227 if (!net::ParseCertificatePoliciesExtension(extension_value, &policies)) 210 if (!net::ParseCertificatePoliciesExtension(extension_value, &policies))
228 return false; 211 return false;
229 212
230 // Look for an audio-only policy. Disregard any other policy found. 213 // Look for an audio-only policy. Disregard any other policy found.
231 if (std::find(policies.begin(), policies.end(), AudioOnlyPolicyOid()) != 214 if (std::find(policies.begin(), policies.end(), AudioOnlyPolicyOid()) !=
232 policies.end()) { 215 policies.end()) {
233 *policy = CastDeviceCertPolicy::AUDIO_ONLY; 216 *policy = CastDeviceCertPolicy::AUDIO_ONLY;
234 } 217 }
235 } 218 }
236 219
237 // Get the Common Name for the certificate. 220 // Get the Common Name for the certificate.
238 std::string common_name; 221 std::string common_name;
239 if (!GetCommonNameFromSubject(tbs.subject_tlv, &common_name)) 222 if (!GetCommonNameFromSubject(cert->parsed_tbs().subject_tlv, &common_name))
240 return false; 223 return false;
241 224
242 context->reset(new CertVerificationContextImpl(tbs.spki_tlv, common_name)); 225 context->reset(new CertVerificationContextImpl(cert->parsed_tbs().spki_tlv,
226 common_name));
243 return true; 227 return true;
244 } 228 }
245 229
246 // Converts a base::Time::Exploded to a net::der::GeneralizedTime. 230 // Converts a base::Time::Exploded to a net::der::GeneralizedTime.
247 net::der::GeneralizedTime ConvertExplodedTime( 231 net::der::GeneralizedTime ConvertExplodedTime(
248 const base::Time::Exploded& exploded) { 232 const base::Time::Exploded& exploded) {
249 net::der::GeneralizedTime result; 233 net::der::GeneralizedTime result;
250 result.year = exploded.year; 234 result.year = exploded.year;
251 result.month = exploded.month; 235 result.month = exploded.month;
252 result.day = exploded.day_of_month; 236 result.day = exploded.day_of_month;
253 result.hours = exploded.hour; 237 result.hours = exploded.hour;
254 result.minutes = exploded.minute; 238 result.minutes = exploded.minute;
255 result.seconds = exploded.second; 239 result.seconds = exploded.second;
256 return result; 240 return result;
257 } 241 }
258 242
259 } // namespace 243 } // namespace
260 244
261 bool VerifyDeviceCert(const std::vector<std::string>& certs, 245 bool VerifyDeviceCert(const std::vector<std::string>& certs,
262 const base::Time::Exploded& time, 246 const base::Time::Exploded& time,
263 std::unique_ptr<CertVerificationContext>* context, 247 std::unique_ptr<CertVerificationContext>* context,
264 CastDeviceCertPolicy* policy) { 248 CastDeviceCertPolicy* policy) {
265 // The underlying verification function expects a sequence of 249 // The underlying verification function expects a sequence of
266 // der::Input, so wrap the data in it (cheap). 250 // ParsedCertificate.
267 std::vector<net::der::Input> input_chain; 251 std::vector<scoped_refptr<net::ParsedCertificate>> input_chain;
268 for (const auto& cert : certs) 252 for (const std::string& cert_der : certs) {
Ryan Sleevi 2016/05/12 20:41:46 fwiw, const auto& is also fine here
mattm 2016/05/13 02:17:35 Done.
269 input_chain.push_back(net::der::Input(&cert)); 253 // No reference to the ParsedCertificate is kept past the end of this
254 // function, so using EXTERNAL_REFERENCE here is safe.
255 scoped_refptr<net::ParsedCertificate> cert(
256 net::ParsedCertificate::CreateFromCertificateData(
257 reinterpret_cast<const uint8_t*>(cert_der.data()), cert_der.size(),
258 net::ParsedCertificate::DataSource::EXTERNAL_REFERENCE));
259 if (!cert)
260 return false;
261 input_chain.push_back(std::move(cert));
262 }
270 263
271 // Use a signature policy compatible with Cast's PKI. 264 // Use a signature policy compatible with Cast's PKI.
272 auto signature_policy = CreateCastSignaturePolicy(); 265 auto signature_policy = CreateCastSignaturePolicy();
273 266
274 // Do RFC 5280 compatible certificate verification using the two Cast 267 // Do RFC 5280 compatible certificate verification using the two Cast
275 // trust anchors and Cast signature policy. 268 // trust anchors and Cast signature policy.
276 if (!net::VerifyCertificateChain(input_chain, CastTrustStore::Get(), 269 if (!net::VerifyCertificateChain(input_chain, CastTrustStore::Get(),
277 signature_policy.get(), 270 signature_policy.get(),
278 ConvertExplodedTime(time))) { 271 ConvertExplodedTime(time))) {
279 return false; 272 return false;
280 } 273 }
281 274
282 // Check properties of the leaf certificate (key usage, policy), and construct 275 // Check properties of the leaf certificate (key usage, policy), and construct
283 // a CertVerificationContext that uses its public key. 276 // a CertVerificationContext that uses its public key.
284 return CheckTargetCertificate(input_chain[0], context, policy); 277 return CheckTargetCertificate(input_chain[0].get(), context, policy);
285 } 278 }
286 279
287 std::unique_ptr<CertVerificationContext> CertVerificationContextImplForTest( 280 std::unique_ptr<CertVerificationContext> CertVerificationContextImplForTest(
288 const base::StringPiece& spki) { 281 const base::StringPiece& spki) {
289 // Use a bogus CommonName, since this is just exposed for testing signature 282 // Use a bogus CommonName, since this is just exposed for testing signature
290 // verification by unittests. 283 // verification by unittests.
291 return base::WrapUnique( 284 return base::WrapUnique(
292 new CertVerificationContextImpl(net::der::Input(spki), "CommonName")); 285 new CertVerificationContextImpl(net::der::Input(spki), "CommonName"));
293 } 286 }
294 287
295 bool AddTrustAnchorForTest(const uint8_t* data, size_t length) { 288 bool AddTrustAnchorForTest(const uint8_t* data, size_t length) {
296 return CastTrustStore::Get().AddTrustedCertificateWithoutCopying(data, 289 scoped_refptr<net::ParsedCertificate> anchor(
297 length); 290 net::ParsedCertificate::CreateFromCertificateData(
291 kCastRootCaDer, sizeof(kCastRootCaDer),
292 net::ParsedCertificate::DataSource::INTERNAL_COPY));
eroman 2016/05/12 18:12:29 EXTERNAL_REFERENCE to match previous code.
Ryan Sleevi 2016/05/12 20:41:46 Why would EXTERNAL_REFERENCE be safe here? |anchor
eroman 2016/05/12 20:55:55 It is safe because the function mandates those lif
mattm 2016/05/13 02:17:35 Done.
293 if (!anchor)
294 return false;
295 CastTrustStore::Get().AddTrustedCertificate(std::move(anchor));
296 return true;
298 } 297 }
299 298
300 } // namespace cast_certificate 299 } // namespace cast_certificate
OLDNEW
« no previous file with comments | « no previous file | net/cert/internal/parse_certificate.h » ('j') | net/cert/internal/parsed_certificate.h » ('J')

Powered by Google App Engine
This is Rietveld 408576698