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

Side by Side Diff: extensions/browser/api/cast_channel/cast_auth_util.cc

Issue 2303673004: Hook up Chrome Cast sender to Cast CRL. (Closed)
Patch Set: VerifyDeviceCertUsingCustomTrustStore and ParseAndVerifyCRLUsingCustomTrustStore Created 4 years, 3 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 "extensions/browser/api/cast_channel/cast_auth_util.h" 5 #include "extensions/browser/api/cast_channel/cast_auth_util.h"
6 6
7 #include <vector> 7 #include <vector>
8 8
9 #include "base/logging.h" 9 #include "base/logging.h"
10 #include "base/macros.h" 10 #include "base/macros.h"
11 #include "base/memory/singleton.h"
11 #include "base/strings/string_number_conversions.h" 12 #include "base/strings/string_number_conversions.h"
12 #include "base/strings/stringprintf.h" 13 #include "base/strings/stringprintf.h"
13 #include "components/cast_certificate/cast_cert_validator.h" 14 #include "components/cast_certificate/cast_cert_validator.h"
15 #include "components/cast_certificate/cast_crl.h"
16 #include "crypto/sha2.h"
14 #include "extensions/browser/api/cast_channel/cast_message_util.h" 17 #include "extensions/browser/api/cast_channel/cast_message_util.h"
15 #include "extensions/common/api/cast_channel/cast_channel.pb.h" 18 #include "extensions/common/api/cast_channel/cast_channel.pb.h"
16 #include "net/cert/x509_certificate.h" 19 #include "net/cert/x509_certificate.h"
17 #include "net/der/parse_values.h" 20 #include "net/der/parse_values.h"
18 21
19 namespace extensions { 22 namespace extensions {
20 namespace api { 23 namespace api {
21 namespace cast_channel { 24 namespace cast_channel {
22 namespace { 25 namespace {
23 26
24 const char* const kParseErrorPrefix = "Failed to parse auth message: "; 27 const char* const kParseErrorPrefix = "Failed to parse auth message: ";
25 28
26 // The maximum number of days a cert can live for. 29 // The maximum number of days a cert can live for.
27 const int kMaxSelfSignedCertLifetimeInDays = 4; 30 const int kMaxSelfSignedCertLifetimeInDays = 4;
28 31
32 // Enforce certificate revocation when set to true.
33 // If set to false, then any revocation failures are ignored.
34 const bool kEnforceRevocationCheck = false;
eroman 2016/09/10 01:03:23 Who is the intended consumer that would set this t
ryanchung 2016/09/14 18:53:39 This is for a future switchover. Eventually, we'll
35
29 namespace cast_crypto = ::cast_certificate; 36 namespace cast_crypto = ::cast_certificate;
30 37
31 // Extracts an embedded DeviceAuthMessage payload from an auth challenge reply 38 // Extracts an embedded DeviceAuthMessage payload from an auth challenge reply
32 // message. 39 // message.
33 AuthResult ParseAuthMessage(const CastMessage& challenge_reply, 40 AuthResult ParseAuthMessage(const CastMessage& challenge_reply,
34 DeviceAuthMessage* auth_message) { 41 DeviceAuthMessage* auth_message) {
35 if (challenge_reply.payload_type() != CastMessage_PayloadType_BINARY) { 42 if (challenge_reply.payload_type() != CastMessage_PayloadType_BINARY) {
36 return AuthResult::CreateWithParseError( 43 return AuthResult::CreateWithParseError(
37 "Wrong payload type in challenge reply", 44 "Wrong payload type in challenge reply",
38 AuthResult::ERROR_WRONG_PAYLOAD_TYPE); 45 AuthResult::ERROR_WRONG_PAYLOAD_TYPE);
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after
119 if (expiry > lifetime_limit) { 126 if (expiry > lifetime_limit) {
120 return AuthResult::CreateWithParseError( 127 return AuthResult::CreateWithParseError(
121 "Peer cert lifetime is too long.", 128 "Peer cert lifetime is too long.",
122 AuthResult::ERROR_VALIDITY_PERIOD_TOO_LONG); 129 AuthResult::ERROR_VALIDITY_PERIOD_TOO_LONG);
123 } 130 }
124 131
125 const AuthResponse& response = auth_message.response(); 132 const AuthResponse& response = auth_message.response();
126 return VerifyCredentials(response, peer_cert_der); 133 return VerifyCredentials(response, peer_cert_der);
127 } 134 }
128 135
136 // Singleton for the Cast CRL cache.
137 class CastCRLCache {
138 public:
139 static CastCRLCache* GetInstance() {
140 return base::Singleton<CastCRLCache,
141 base::LeakySingletonTraits<CastCRLCache>>::get();
142 }
143
144 static cast_crypto::CastCRL* Get(const std::string& crl_bundle) {
145 if (crl_bundle.empty())
146 return nullptr;
147 CastCRLCache* cache = GetInstance();
148 std::string crl_bundle_hash = crypto::SHA256HashString(crl_bundle);
149 if (cache->hash_.compare(crl_bundle_hash) == 0) {
eroman 2016/09/10 01:03:23 Does this work: cache->hash == crl_bundle_hash
ryanchung 2016/09/14 18:53:39 Done.
150 return cache->crl_.get();
151 } else {
152 return nullptr;
153 }
154 }
155
156 static cast_crypto::CastCRL* Put(const std::string& crl_bundle,
157 std::unique_ptr<cast_crypto::CastCRL> crl) {
158 if (crl_bundle.empty() || crl == nullptr)
159 return nullptr;
160 CastCRLCache* cache = GetInstance();
161 cache->hash_ = crypto::SHA256HashString(crl_bundle);
162 cache->crl_ = std::move(crl);
163 return cache->crl_.get();
164 }
165
166 private:
167 friend struct base::DefaultSingletonTraits<CastCRLCache>;
168
169 CastCRLCache() : crl_(nullptr), hash_() {}
170
171 std::unique_ptr<cast_crypto::CastCRL> crl_;
172 std::string hash_;
173 DISALLOW_COPY_AND_ASSIGN(CastCRLCache);
174 };
175
129 // This function does the following 176 // This function does the following
130 // 177 //
131 // * Verifies that the certificate chain |response.client_auth_certificate| + 178 // * Verifies that the certificate chain |response.client_auth_certificate| +
132 // |response.intermediate_certificate| is valid and chains to a trusted 179 // |response.intermediate_certificate| is valid and chains to a trusted
133 // Cast root. 180 // Cast root. The list of trusted Cast roots can be overrided by providing a
181 // non-nullptr |cast_trust_store|. The certificate is verified at
182 // |cert_verification_time|.
183 //
184 // * Verifies that none of the certificates in the chain are revoked based on
185 // the CRL provided in the response |response.crl|. The CRL is verified to be
186 // valid and its issuer certificate chains to a trusted Cast CRL root. The
187 // list of trusted Cast CRL roots can be overrided by providing a non-nullptr
188 // |crl_trust_store|. If |crl_policy| is CRL_OPTIONAL then the result of
189 // revocation checking is ignored. The CRL is verified at
190 // |crl_verification_time|.
134 // 191 //
135 // * Verifies that |response.signature| matches the signature 192 // * Verifies that |response.signature| matches the signature
136 // of |signature_input| by |response.client_auth_certificate|'s public 193 // of |signature_input| by |response.client_auth_certificate|'s public
137 // key. 194 // key.
138 AuthResult VerifyCredentials(const AuthResponse& response, 195 AuthResult VerifyCredentialsImpl(const AuthResponse& response,
139 const std::string& signature_input) { 196 const std::string& signature_input,
197 const cast_crypto::CRLPolicy& crl_policy,
198 net::TrustStore* cast_trust_store,
199 net::TrustStore* crl_trust_store,
200 const base::Time& cert_verification_time,
201 const base::Time& crl_verification_time) {
140 // Verify the certificate 202 // Verify the certificate
141 std::unique_ptr<cast_crypto::CertVerificationContext> verification_context; 203 std::unique_ptr<cast_crypto::CertVerificationContext> verification_context;
142 204
143 // Build a single vector containing the certificate chain. 205 // Build a single vector containing the certificate chain.
144 std::vector<std::string> cert_chain; 206 std::vector<std::string> cert_chain;
145 cert_chain.push_back(response.client_auth_certificate()); 207 cert_chain.push_back(response.client_auth_certificate());
146 cert_chain.insert(cert_chain.end(), 208 cert_chain.insert(cert_chain.end(),
147 response.intermediate_certificate().begin(), 209 response.intermediate_certificate().begin(),
148 response.intermediate_certificate().end()); 210 response.intermediate_certificate().end());
149 211
150 // Use the current time when checking certificate validity. 212 // Parse the CRL.
151 base::Time now = base::Time::Now(); 213 cast_crypto::CastCRL* crl = CastCRLCache::Get(response.crl());
214 if (crl == nullptr) {
215 std::unique_ptr<cast_crypto::CastCRL> crl_parsed;
216 if (crl_trust_store) {
217 crl_parsed = cast_crypto::ParseAndVerifyCRLUsingCustomTrustStore(
218 response.crl(), crl_verification_time, crl_trust_store);
219 } else {
220 crl_parsed =
221 cast_crypto::ParseAndVerifyCRL(response.crl(), crl_verification_time);
222 }
152 223
153 // CRL should not be enforced until it is served. 224 crl = CastCRLCache::Put(response.crl(), std::move(crl_parsed));
154 cast_crypto::CastDeviceCertPolicy device_policy; 225 }
155 if (!cast_crypto::VerifyDeviceCert( 226 if (!crl && crl_policy == cast_crypto::CRLPolicy::CRL_REQUIRED) {
156 cert_chain, now, &verification_context, &device_policy, nullptr, 227 // CRL is invalid.
157 cast_certificate::CRLPolicy::CRL_OPTIONAL)) { 228 return AuthResult("Failed verifying Cast CRL.",
158 // TODO(eroman): The error information was lost; this error is ambiguous. 229 AuthResult::ERROR_CRL_INVALID);
159 return AuthResult("Failed verifying cast device certificate",
160 AuthResult::ERROR_CERT_NOT_SIGNED_BY_TRUSTED_CA);
161 } 230 }
162 231
232 cast_crypto::CastDeviceCertPolicy device_policy;
233 bool verification_success;
234 if (cast_trust_store) {
235 verification_success = cast_crypto::VerifyDeviceCertUsingCustomTrustStore(
236 cert_chain, cert_verification_time, &verification_context,
237 &device_policy, crl, crl_policy, cast_trust_store);
238 } else {
239 verification_success = cast_crypto::VerifyDeviceCert(
240 cert_chain, cert_verification_time, &verification_context,
241 &device_policy, crl, crl_policy);
242 }
243 if (!verification_success) {
244 // TODO(ryanchung): Once this feature is completely rolled-out, remove the
245 // reverification step and use error reporting to get verification errors
246 // for metrics.
247 bool verification_no_crl_success;
248 if (cast_trust_store) {
249 verification_no_crl_success =
250 cast_crypto::VerifyDeviceCertUsingCustomTrustStore(
251 cert_chain, cert_verification_time, &verification_context,
252 &device_policy, nullptr, cast_crypto::CRLPolicy::CRL_OPTIONAL,
253 cast_trust_store);
254 } else {
255 verification_no_crl_success = cast_crypto::VerifyDeviceCert(
256 cert_chain, cert_verification_time, &verification_context,
257 &device_policy, nullptr, cast_crypto::CRLPolicy::CRL_OPTIONAL);
258 }
259 if (!verification_no_crl_success) {
260 // TODO(eroman): The error information was lost; this error is ambiguous.
261 return AuthResult("Failed verifying cast device certificate",
262 AuthResult::ERROR_CERT_NOT_SIGNED_BY_TRUSTED_CA);
263 }
264 if (crl_policy == cast_crypto::CRLPolicy::CRL_REQUIRED) {
265 // Device is revoked.
266 return AuthResult("Failed certificate revocation check.",
267 AuthResult::ERROR_CERT_REVOKED);
268 }
269 }
163 if (!verification_context->VerifySignatureOverData(response.signature(), 270 if (!verification_context->VerifySignatureOverData(response.signature(),
164 signature_input)) { 271 signature_input)) {
165 return AuthResult("Failed verifying signature over data", 272 return AuthResult("Failed verifying signature over data",
166 AuthResult::ERROR_SIGNED_BLOBS_MISMATCH); 273 AuthResult::ERROR_SIGNED_BLOBS_MISMATCH);
167 } 274 }
168 275
169 AuthResult success; 276 AuthResult success;
170 277
171 // Set the policy into the result. 278 // Set the policy into the result.
172 switch (device_policy) { 279 switch (device_policy) {
173 case cast_crypto::CastDeviceCertPolicy::AUDIO_ONLY: 280 case cast_crypto::CastDeviceCertPolicy::AUDIO_ONLY:
174 success.channel_policies = AuthResult::POLICY_AUDIO_ONLY; 281 success.channel_policies = AuthResult::POLICY_AUDIO_ONLY;
175 break; 282 break;
176 case cast_crypto::CastDeviceCertPolicy::NONE: 283 case cast_crypto::CastDeviceCertPolicy::NONE:
177 success.channel_policies = AuthResult::POLICY_NONE; 284 success.channel_policies = AuthResult::POLICY_NONE;
178 break; 285 break;
179 } 286 }
180 287
181 return success; 288 return success;
182 } 289 }
183 290
291 AuthResult VerifyCredentials(const AuthResponse& response,
292 const std::string& signature_input) {
293 base::Time now = base::Time::Now();
294 cast_crypto::CRLPolicy policy = cast_crypto::CRLPolicy::CRL_REQUIRED;
295 if (!kEnforceRevocationCheck) {
296 policy = cast_crypto::CRLPolicy::CRL_OPTIONAL;
297 }
298 return VerifyCredentialsImpl(response, signature_input, policy, nullptr,
299 nullptr, now, now);
300 }
301
302 AuthResult VerifyCredentialsForTest(const AuthResponse& response,
303 const std::string& signature_input,
304 const cast_crypto::CRLPolicy& crl_policy,
305 net::TrustStore* cast_trust_store,
306 net::TrustStore* crl_trust_store,
307 const base::Time& cert_verification_time,
308 const base::Time& crl_verification_time) {
309 return VerifyCredentialsImpl(response, signature_input, crl_policy,
310 cast_trust_store, crl_trust_store,
311 cert_verification_time, crl_verification_time);
312 }
313
184 } // namespace cast_channel 314 } // namespace cast_channel
185 } // namespace api 315 } // namespace api
186 } // namespace extensions 316 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698