Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 "extensions/common/cast/cast_cert_validator.h" | 5 #include "extensions/common/cast/cast_cert_validator.h" |
| 6 | 6 |
| 7 #include <stddef.h> | 7 #include <stddef.h> |
| 8 #include <stdint.h> | 8 #include <stdint.h> |
| 9 #include <algorithm> | 9 #include <algorithm> |
| 10 #include <utility> | 10 #include <utility> |
| 11 | 11 |
| 12 #include "base/memory/singleton.h" | |
| 12 #include "net/cert/internal/certificate_policies.h" | 13 #include "net/cert/internal/certificate_policies.h" |
| 13 #include "net/cert/internal/extended_key_usage.h" | 14 #include "net/cert/internal/extended_key_usage.h" |
| 14 #include "net/cert/internal/parse_certificate.h" | 15 #include "net/cert/internal/parse_certificate.h" |
| 15 #include "net/cert/internal/parse_name.h" | 16 #include "net/cert/internal/parse_name.h" |
| 16 #include "net/cert/internal/signature_algorithm.h" | 17 #include "net/cert/internal/signature_algorithm.h" |
| 17 #include "net/cert/internal/signature_policy.h" | 18 #include "net/cert/internal/signature_policy.h" |
| 18 #include "net/cert/internal/verify_certificate_chain.h" | 19 #include "net/cert/internal/verify_certificate_chain.h" |
| 19 #include "net/cert/internal/verify_signed_data.h" | 20 #include "net/cert/internal/verify_signed_data.h" |
| 20 #include "net/der/input.h" | 21 #include "net/der/input.h" |
| 21 | 22 |
| 22 namespace extensions { | 23 namespace extensions { |
| 23 namespace api { | 24 namespace api { |
| 24 namespace cast_crypto { | 25 namespace cast_crypto { |
| 25 namespace { | 26 namespace { |
| 26 | 27 |
| 27 // ------------------------------------------------------------------------- | 28 // ------------------------------------------------------------------------- |
| 28 // Cast trust anchors. | 29 // Cast trust anchors. |
| 29 // ------------------------------------------------------------------------- | 30 // ------------------------------------------------------------------------- |
| 30 | 31 |
| 31 // There are two trusted roots for Cast certificate chains: | 32 // There are two trusted roots for Cast certificate chains: |
| 32 // | 33 // |
| 33 // (1) CN=Cast Root CA | 34 // (1) CN=Cast Root CA |
|
mattm
2016/04/16 02:40:29
Add "(kCastRootCaDer)" ? Or maybe just combine the
eroman
2016/04/18 20:43:03
Done.
| |
| 34 // (2) CN=Eureka Root CA | 35 // (2) CN=Eureka Root CA (kEurekaRootCaDer) |
| 35 // | |
| 36 // Note that only the subject/spki are saved here, not the full certificate. | |
| 37 // See the TODO in CreateCastTrustStore(). | |
| 38 | 36 |
| 39 unsigned char kCastRootCaSubjectDer[119] = { | 37 // Define kCastRootCaDer. |
| 40 0x30, 0x75, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, | 38 #include "extensions/common/cast/cast_root_ca_cert_der-inc.h" |
| 41 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, | 39 |
| 42 0x0C, 0x0A, 0x43, 0x61, 0x6C, 0x69, 0x66, 0x6F, 0x72, 0x6E, 0x69, 0x61, | 40 // Define kEurekaRootCaDer |
| 43 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0C, 0x0D, 0x4D, | 41 #include "extensions/common/cast/eureka_root_ca_der-inc.h" |
| 44 0x6F, 0x75, 0x6E, 0x74, 0x61, 0x69, 0x6E, 0x20, 0x56, 0x69, 0x65, 0x77, | 42 |
| 45 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x0A, 0x0C, 0x0A, 0x47, | 43 // Singleton for the Cast trust store. |
| 46 0x6F, 0x6F, 0x67, 0x6C, 0x65, 0x20, 0x49, 0x6E, 0x63, 0x31, 0x0D, 0x30, | 44 class CastTrustStore { |
| 47 0x0B, 0x06, 0x03, 0x55, 0x04, 0x0B, 0x0C, 0x04, 0x43, 0x61, 0x73, 0x74, | 45 public: |
| 48 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0C, 0x0C, 0x43, | 46 static CastTrustStore* GetInstance() { |
| 49 0x61, 0x73, 0x74, 0x20, 0x52, 0x6F, 0x6F, 0x74, 0x20, 0x43, 0x41, | 47 return base::Singleton<CastTrustStore, |
| 48 base::LeakySingletonTraits<CastTrustStore>>::get(); | |
| 49 } | |
| 50 | |
| 51 static net::TrustStore& Get() { | |
| 52 return GetInstance()->store_; | |
| 53 } | |
| 54 | |
| 55 private: | |
| 56 | |
| 57 friend struct base::DefaultSingletonTraits<CastTrustStore>; | |
| 58 | |
| 59 CastTrustStore() { | |
| 60 // Initialize the trust store with two root certificates. | |
| 61 CHECK(store_.AddTrustedCertificateWithoutCopying(kCastRootCaDer, | |
| 62 sizeof(kCastRootCaDer))); | |
| 63 CHECK(store_.AddTrustedCertificateWithoutCopying(kEurekaRootCaDer, | |
| 64 sizeof(kEurekaRootCaDer))); | |
| 65 } | |
| 66 | |
| 67 net::TrustStore store_; | |
| 68 DISALLOW_COPY_AND_ASSIGN(CastTrustStore); | |
| 50 }; | 69 }; |
| 51 | 70 |
| 52 unsigned char kCastRootCaSpkiDer[294] = { | |
| 53 0x30, 0x82, 0x01, 0x22, 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, | |
| 54 0xF7, 0x0D, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0F, 0x00, | |
| 55 0x30, 0x82, 0x01, 0x0A, 0x02, 0x82, 0x01, 0x01, 0x00, 0xBA, 0xD9, 0x65, | |
| 56 0x9D, 0xDA, 0x39, 0xD3, 0xC1, 0x77, 0xF6, 0xD4, 0xD0, 0xAE, 0x8F, 0x58, | |
| 57 0x08, 0x68, 0x39, 0x4A, 0x95, 0xED, 0x70, 0xCF, 0xFD, 0x79, 0x08, 0xA9, | |
| 58 0xAA, 0xE5, 0xE9, 0xB8, 0xA7, 0x2D, 0xA0, 0x67, 0x47, 0x8A, 0x9E, 0xC9, | |
| 59 0xCF, 0x70, 0xB3, 0x05, 0x87, 0x69, 0x11, 0xEC, 0x70, 0x98, 0x97, 0xC3, | |
| 60 0xE6, 0xC3, 0xC3, 0xEB, 0xBD, 0xC6, 0xB0, 0x3D, 0xFC, 0x4F, 0xC1, 0x5E, | |
| 61 0x38, 0x9F, 0xDA, 0xCF, 0x73, 0x30, 0x06, 0x5B, 0x79, 0x37, 0xC1, 0x5E, | |
| 62 0x8C, 0x87, 0x47, 0x94, 0x9A, 0x41, 0x92, 0x2A, 0xD6, 0x95, 0xC4, 0x71, | |
| 63 0x5C, 0x27, 0x5D, 0x08, 0xB1, 0x80, 0xC6, 0x92, 0xBD, 0x1B, 0xE3, 0x41, | |
| 64 0x97, 0xA1, 0xEC, 0x75, 0x9F, 0x55, 0x9E, 0x3E, 0x9F, 0x8F, 0x1C, 0xC7, | |
| 65 0x65, 0x64, 0x07, 0xD3, 0xB3, 0x96, 0xA1, 0x04, 0x9F, 0x91, 0xC4, 0xDE, | |
| 66 0x0A, 0x7B, 0x6C, 0xD9, 0xC8, 0xC0, 0x78, 0x31, 0xA0, 0x19, 0x42, 0xA9, | |
| 67 0xE8, 0x83, 0xE3, 0xCE, 0xFC, 0xF1, 0xCE, 0xC2, 0x2E, 0x24, 0x46, 0x95, | |
| 68 0x09, 0x19, 0xCA, 0xC0, 0x46, 0xB2, 0xE5, 0x01, 0xBA, 0xD7, 0x4F, 0xF3, | |
| 69 0xBF, 0xF6, 0x69, 0xAD, 0x99, 0x04, 0xFA, 0xA0, 0x07, 0x39, 0x0E, 0xE6, | |
| 70 0xDF, 0x51, 0x47, 0x07, 0xC0, 0xE4, 0xA9, 0x5C, 0x4B, 0x94, 0xC5, 0x2F, | |
| 71 0xB3, 0xA0, 0x30, 0x7F, 0xE7, 0x95, 0x6B, 0xB2, 0xAF, 0x32, 0x0D, 0xF1, | |
| 72 0x8C, 0xD5, 0x6D, 0xCB, 0x7B, 0x47, 0xA7, 0x08, 0xAB, 0xCB, 0x27, 0xA3, | |
| 73 0x4D, 0xCF, 0x4A, 0x5A, 0xF1, 0x05, 0xD1, 0xF8, 0x62, 0xC5, 0x10, 0x2A, | |
| 74 0x74, 0x69, 0xAA, 0xE6, 0x4B, 0x96, 0xFB, 0x9B, 0xD8, 0x63, 0xE4, 0x58, | |
| 75 0x66, 0xD3, 0xAD, 0x8A, 0x6E, 0xFF, 0x7B, 0x5E, 0xF9, 0xA5, 0x56, 0x1E, | |
| 76 0x2D, 0x82, 0x31, 0x5B, 0xF0, 0xE2, 0x24, 0xE6, 0x41, 0x4A, 0x1F, 0xAE, | |
| 77 0x13, 0x02, 0x03, 0x01, 0x00, 0x01, | |
| 78 }; | |
| 79 | |
| 80 unsigned char kEurekaRootCaSubjectDer[126] = { | |
| 81 0x30, 0x7C, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, | |
| 82 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, | |
| 83 0x0C, 0x0A, 0x43, 0x61, 0x6C, 0x69, 0x66, 0x6F, 0x72, 0x6E, 0x69, 0x61, | |
| 84 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0C, 0x0D, 0x4D, | |
| 85 0x6F, 0x75, 0x6E, 0x74, 0x61, 0x69, 0x6E, 0x20, 0x56, 0x69, 0x65, 0x77, | |
| 86 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x0A, 0x0C, 0x0A, 0x47, | |
| 87 0x6F, 0x6F, 0x67, 0x6C, 0x65, 0x20, 0x49, 0x6E, 0x63, 0x31, 0x12, 0x30, | |
| 88 0x10, 0x06, 0x03, 0x55, 0x04, 0x0B, 0x0C, 0x09, 0x47, 0x6F, 0x6F, 0x67, | |
| 89 0x6C, 0x65, 0x20, 0x54, 0x56, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, | |
| 90 0x04, 0x03, 0x0C, 0x0E, 0x45, 0x75, 0x72, 0x65, 0x6B, 0x61, 0x20, 0x52, | |
| 91 0x6F, 0x6F, 0x74, 0x20, 0x43, 0x41, | |
| 92 }; | |
| 93 | |
| 94 unsigned char kEurekaRootCaSpkiDer[294] = { | |
| 95 0x30, 0x82, 0x01, 0x22, 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, | |
| 96 0xF7, 0x0D, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0F, 0x00, | |
| 97 0x30, 0x82, 0x01, 0x0A, 0x02, 0x82, 0x01, 0x01, 0x00, 0xB9, 0x11, 0xD0, | |
| 98 0xEA, 0x12, 0xDC, 0x32, 0xE1, 0xDF, 0x5C, 0x33, 0x6B, 0x19, 0x73, 0x1D, | |
| 99 0x9D, 0x9E, 0xD0, 0x39, 0x76, 0xBF, 0xA5, 0x84, 0x09, 0xA6, 0xFD, 0x6E, | |
| 100 0x6D, 0xE9, 0xDC, 0x8F, 0x36, 0x4E, 0xE9, 0x88, 0x02, 0xBD, 0x9F, 0xF4, | |
| 101 0xE8, 0x44, 0xFD, 0x4C, 0xF5, 0x9A, 0x02, 0x56, 0x6A, 0x47, 0x2A, 0x63, | |
| 102 0x6C, 0x58, 0x45, 0xCC, 0x7C, 0x66, 0x24, 0xDC, 0x79, 0x79, 0xC3, 0x2A, | |
| 103 0xA4, 0xB2, 0x8B, 0xA0, 0xF7, 0xA2, 0xB5, 0xCD, 0x06, 0x7E, 0xDB, 0xBE, | |
| 104 0xEC, 0x0C, 0x86, 0xF2, 0x0D, 0x24, 0x60, 0x74, 0x84, 0xCA, 0x29, 0x23, | |
| 105 0x84, 0x02, 0xD8, 0xA7, 0xED, 0x3B, 0xF1, 0xEC, 0x26, 0x47, 0x54, 0xE3, | |
| 106 0xB1, 0x2D, 0xE6, 0x64, 0x0F, 0xF6, 0x72, 0xC5, 0xE9, 0x98, 0x52, 0x17, | |
| 107 0xC0, 0xFC, 0xF2, 0x2C, 0x20, 0xC8, 0x40, 0xF8, 0x47, 0xC9, 0x32, 0x9E, | |
| 108 0x3B, 0x97, 0xB1, 0x8B, 0xF5, 0x98, 0x24, 0x70, 0x63, 0x66, 0x19, 0xC1, | |
| 109 0x52, 0xE8, 0x04, 0x05, 0x3D, 0x5F, 0x8D, 0xBC, 0xD8, 0x4B, 0xAF, 0x77, | |
| 110 0x98, 0x6F, 0x1F, 0x78, 0xD1, 0xB6, 0x50, 0x27, 0x4D, 0xE4, 0xEC, 0x14, | |
| 111 0x69, 0x67, 0x1F, 0x58, 0xAF, 0xA9, 0xA0, 0x11, 0x26, 0x3C, 0x94, 0x32, | |
| 112 0x07, 0x7F, 0xD7, 0xE9, 0x69, 0x1F, 0xAE, 0x3F, 0x4F, 0x63, 0x8A, 0x8F, | |
| 113 0x89, 0xD6, 0xF2, 0x19, 0x78, 0x5C, 0x21, 0x8E, 0xB1, 0xB6, 0x57, 0xD8, | |
| 114 0xC0, 0xE1, 0xEE, 0x7D, 0x6E, 0xDD, 0xF1, 0x3A, 0x0A, 0x6A, 0xF1, 0xBA, | |
| 115 0xFF, 0xF9, 0x83, 0x2F, 0xDC, 0xB5, 0xA4, 0x20, 0x17, 0x63, 0x36, 0xEF, | |
| 116 0xC8, 0x62, 0x19, 0xCC, 0x56, 0xCE, 0xB2, 0xEA, 0x31, 0x89, 0x4B, 0x78, | |
| 117 0x58, 0xC1, 0xBF, 0x03, 0x13, 0x99, 0xE0, 0x12, 0xF2, 0x88, 0xAA, 0x9B, | |
| 118 0x94, 0xDA, 0xDD, 0x76, 0x79, 0x17, 0x1E, 0x34, 0xD1, 0x0A, 0xC4, 0x07, | |
| 119 0x45, 0x02, 0x03, 0x01, 0x00, 0x01, | |
| 120 }; | |
| 121 | |
| 122 // Helper function that creates and initializes a TrustAnchor struct given | |
| 123 // arrays for the subject's DER and the SPKI's DER. | |
| 124 template <size_t SubjectSize, size_t SpkiSize> | |
| 125 net::TrustAnchor CreateTrustAnchor(const uint8_t (&subject)[SubjectSize], | |
| 126 const uint8_t (&spki)[SpkiSize]) { | |
| 127 net::TrustAnchor anchor; | |
| 128 anchor.name = std::string(subject, subject + SubjectSize); | |
| 129 anchor.spki = std::string(spki, spki + SpkiSize); | |
| 130 return anchor; | |
| 131 } | |
| 132 | |
| 133 // Creates a trust store with the two Cast roots. | |
| 134 // | |
| 135 // TODO(eroman): The root certificates themselves are not included in the trust | |
| 136 // store (just their subject/SPKI). The problem with this approach is any | |
| 137 // restrictions encoded in their (like path length, or policy) are not known | |
| 138 // when verifying, and hence not enforced. | |
| 139 net::TrustStore CreateCastTrustStore() { | |
| 140 net::TrustStore store; | |
| 141 store.anchors.push_back( | |
| 142 CreateTrustAnchor(kEurekaRootCaSubjectDer, kEurekaRootCaSpkiDer)); | |
| 143 store.anchors.push_back( | |
| 144 CreateTrustAnchor(kCastRootCaSubjectDer, kCastRootCaSpkiDer)); | |
| 145 return store; | |
| 146 } | |
| 147 | |
| 148 using ExtensionsMap = std::map<net::der::Input, net::ParsedExtension>; | 71 using ExtensionsMap = std::map<net::der::Input, net::ParsedExtension>; |
| 149 | 72 |
| 150 // Helper that looks up an extension by OID given a map of extensions. | 73 // Helper that looks up an extension by OID given a map of extensions. |
| 151 bool GetExtensionValue(const ExtensionsMap& extensions, | 74 bool GetExtensionValue(const ExtensionsMap& extensions, |
| 152 const net::der::Input& oid, | 75 const net::der::Input& oid, |
| 153 net::der::Input* value) { | 76 net::der::Input* value) { |
| 154 auto it = extensions.find(oid); | 77 auto it = extensions.find(oid); |
| 155 if (it == extensions.end()) | 78 if (it == extensions.end()) |
| 156 return false; | 79 return false; |
| 157 *value = it->second.value; | 80 *value = it->second.value; |
| (...skipping 175 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 333 result.seconds = exploded.second; | 256 result.seconds = exploded.second; |
| 334 return result; | 257 return result; |
| 335 } | 258 } |
| 336 | 259 |
| 337 } // namespace | 260 } // namespace |
| 338 | 261 |
| 339 bool VerifyDeviceCert(const std::vector<std::string>& certs, | 262 bool VerifyDeviceCert(const std::vector<std::string>& certs, |
| 340 const base::Time::Exploded& time, | 263 const base::Time::Exploded& time, |
| 341 scoped_ptr<CertVerificationContext>* context, | 264 scoped_ptr<CertVerificationContext>* context, |
| 342 CastDeviceCertPolicy* policy) { | 265 CastDeviceCertPolicy* policy) { |
| 343 // Initialize the trust store used for verifying Cast | |
| 344 // device certificates. | |
| 345 // | |
| 346 // Performance: This code is re-building a TrustStore object each | |
| 347 // time a chain needs to be verified rather than caching it, to | |
| 348 // avoid memory bloat. | |
| 349 auto trust_store = CreateCastTrustStore(); | |
| 350 | |
| 351 // The underlying verification function expects a sequence of | 266 // The underlying verification function expects a sequence of |
| 352 // der::Input, so wrap the data in it (cheap). | 267 // der::Input, so wrap the data in it (cheap). |
| 353 std::vector<net::der::Input> input_chain; | 268 std::vector<net::der::Input> input_chain; |
| 354 for (const auto& cert : certs) | 269 for (const auto& cert : certs) |
| 355 input_chain.push_back(net::der::Input(&cert)); | 270 input_chain.push_back(net::der::Input(&cert)); |
| 356 | 271 |
| 357 // Use a signature policy compatible with Cast's PKI. | 272 // Use a signature policy compatible with Cast's PKI. |
| 358 auto signature_policy = CreateCastSignaturePolicy(); | 273 auto signature_policy = CreateCastSignaturePolicy(); |
| 359 | 274 |
| 360 // Do RFC 5280 compatible certificate verification using the two Cast | 275 // Do RFC 5280 compatible certificate verification using the two Cast |
| 361 // trust anchors and Cast signature policy. | 276 // trust anchors and Cast signature policy. |
| 362 if (!net::VerifyCertificateChain(input_chain, trust_store, | 277 if (!net::VerifyCertificateChain(input_chain, CastTrustStore::Get(), |
| 363 signature_policy.get(), | 278 signature_policy.get(), |
| 364 ConvertExplodedTime(time))) { | 279 ConvertExplodedTime(time))) { |
| 365 return false; | 280 return false; |
| 366 } | 281 } |
| 367 | 282 |
| 368 // Check properties of the leaf certificate (key usage, policy), and construct | 283 // Check properties of the leaf certificate (key usage, policy), and construct |
| 369 // a CertVerificationContext that uses its public key. | 284 // a CertVerificationContext that uses its public key. |
| 370 return CheckTargetCertificate(input_chain[0], context, policy); | 285 return CheckTargetCertificate(input_chain[0], context, policy); |
| 371 } | 286 } |
| 372 | 287 |
| 373 scoped_ptr<CertVerificationContext> CertVerificationContextImplForTest( | 288 scoped_ptr<CertVerificationContext> CertVerificationContextImplForTest( |
| 374 const base::StringPiece& spki) { | 289 const base::StringPiece& spki) { |
| 375 // Use a bogus CommonName, since this is just exposed for testing signature | 290 // Use a bogus CommonName, since this is just exposed for testing signature |
| 376 // verification by unittests. | 291 // verification by unittests. |
| 377 return make_scoped_ptr( | 292 return make_scoped_ptr( |
| 378 new CertVerificationContextImpl(net::der::Input(spki), "CommonName")); | 293 new CertVerificationContextImpl(net::der::Input(spki), "CommonName")); |
| 379 } | 294 } |
| 380 | 295 |
| 381 } // namespace cast_crypto | 296 } // namespace cast_crypto |
| 382 } // namespace api | 297 } // namespace api |
| 383 } // namespace extensions | 298 } // namespace extensions |
| OLD | NEW |