OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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/policy/core/common/cloud/cloud_policy_validator.h" | 5 #include "components/policy/core/common/cloud/cloud_policy_validator.h" |
6 | 6 |
7 #include "base/bind_helpers.h" | 7 #include "base/bind_helpers.h" |
8 #include "base/message_loop/message_loop.h" | 8 #include "base/message_loop/message_loop.h" |
9 #include "base/metrics/histogram.h" | |
9 #include "base/sequenced_task_runner.h" | 10 #include "base/sequenced_task_runner.h" |
10 #include "base/stl_util.h" | 11 #include "base/stl_util.h" |
11 #include "components/policy/core/common/cloud/cloud_policy_constants.h" | 12 #include "components/policy/core/common/cloud/cloud_policy_constants.h" |
12 #include "crypto/signature_verifier.h" | 13 #include "crypto/signature_verifier.h" |
13 #include "google_apis/gaia/gaia_auth_util.h" | 14 #include "google_apis/gaia/gaia_auth_util.h" |
14 #include "policy/proto/device_management_backend.pb.h" | 15 #include "policy/proto/device_management_backend.pb.h" |
15 | 16 |
16 namespace em = enterprise_management; | 17 namespace em = enterprise_management; |
17 | 18 |
18 namespace policy { | 19 namespace policy { |
19 | 20 |
20 namespace { | 21 namespace { |
21 | 22 |
22 // Grace interval for policy timestamp checks, in seconds. | 23 // Grace interval for policy timestamp checks, in seconds. |
23 const int kTimestampGraceIntervalSeconds = 60; | 24 const int kTimestampGraceIntervalSeconds = 60; |
24 | 25 |
25 // DER-encoded ASN.1 object identifier for the SHA1-RSA signature algorithm. | 26 // DER-encoded ASN.1 object identifier for the SHA1-RSA signature algorithm. |
26 const uint8 kSignatureAlgorithm[] = { | 27 const uint8 kSignatureAlgorithm[] = { |
27 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, | 28 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, |
28 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00 | 29 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00 |
29 }; | 30 }; |
30 | 31 |
32 const char kMetricPolicyKeyVerification[] = "Enterprise.PolicyKeyVerification"; | |
33 | |
34 enum MetricPolicyKeyVerification { | |
35 // UMA metric recorded when the client has no verification key. | |
36 METRIC_POLICY_KEY_VERIFICATION_KEY_MISSING, | |
37 // Recorded when the policy being verified has no key signature (e.g. policy | |
38 // fetched before the server supported the verification key). | |
39 METRIC_POLICY_KEY_VERIFICATION_SIGNATURE_MISSING, | |
40 // Recorded when the key signature did not match the expected value (in | |
41 // theory, this should only happen after key rotation or if the policy cached | |
42 // on disk has been modified). | |
43 METRIC_POLICY_KEY_VERIFICATION_FAILED, | |
44 // Recorded when key verification succeeded. | |
45 METRIC_POLICY_KEY_VERIFICATION_SUCCEEDED, | |
46 METRIC_POLICY_KEY_VERIFICATION_SIZE // Must be the last. | |
47 }; | |
48 | |
31 } // namespace | 49 } // namespace |
32 | 50 |
33 CloudPolicyValidatorBase::~CloudPolicyValidatorBase() {} | 51 CloudPolicyValidatorBase::~CloudPolicyValidatorBase() {} |
34 | 52 |
35 void CloudPolicyValidatorBase::ValidateTimestamp( | 53 void CloudPolicyValidatorBase::ValidateTimestamp( |
36 base::Time not_before, | 54 base::Time not_before, |
37 base::Time now, | 55 base::Time now, |
38 ValidateTimestampOption timestamp_option) { | 56 ValidateTimestampOption timestamp_option) { |
39 // Timestamp should be from the past. We allow for a 1-minute grace interval | 57 // Timestamp should be from the past. We allow for a 1-minute grace interval |
40 // to cover clock drift. | 58 // to cover clock drift. |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
76 void CloudPolicyValidatorBase::ValidateSettingsEntityId( | 94 void CloudPolicyValidatorBase::ValidateSettingsEntityId( |
77 const std::string& settings_entity_id) { | 95 const std::string& settings_entity_id) { |
78 validation_flags_ |= VALIDATE_ENTITY_ID; | 96 validation_flags_ |= VALIDATE_ENTITY_ID; |
79 settings_entity_id_ = settings_entity_id; | 97 settings_entity_id_ = settings_entity_id; |
80 } | 98 } |
81 | 99 |
82 void CloudPolicyValidatorBase::ValidatePayload() { | 100 void CloudPolicyValidatorBase::ValidatePayload() { |
83 validation_flags_ |= VALIDATE_PAYLOAD; | 101 validation_flags_ |= VALIDATE_PAYLOAD; |
84 } | 102 } |
85 | 103 |
86 void CloudPolicyValidatorBase::ValidateSignature(const std::vector<uint8>& key, | 104 void CloudPolicyValidatorBase::ValidateSignature( |
87 bool allow_key_rotation) { | 105 const std::string& key, |
106 const std::string& verification_key, | |
107 const std::string& key_signature, | |
108 bool allow_key_rotation) { | |
88 validation_flags_ |= VALIDATE_SIGNATURE; | 109 validation_flags_ |= VALIDATE_SIGNATURE; |
89 key_ = std::string(reinterpret_cast<const char*>(vector_as_array(&key)), | 110 set_verification_key(verification_key); |
90 key.size()); | 111 key_ = key; |
112 key_signature_ = key_signature; | |
91 allow_key_rotation_ = allow_key_rotation; | 113 allow_key_rotation_ = allow_key_rotation; |
92 } | 114 } |
93 | 115 |
94 void CloudPolicyValidatorBase::ValidateInitialKey() { | 116 void CloudPolicyValidatorBase::ValidateInitialKey( |
117 const std::string& verification_key) { | |
95 validation_flags_ |= VALIDATE_INITIAL_KEY; | 118 validation_flags_ |= VALIDATE_INITIAL_KEY; |
119 set_verification_key(verification_key); | |
96 } | 120 } |
97 | 121 |
98 void CloudPolicyValidatorBase::ValidateAgainstCurrentPolicy( | 122 void CloudPolicyValidatorBase::ValidateAgainstCurrentPolicy( |
99 const em::PolicyData* policy_data, | 123 const em::PolicyData* policy_data, |
100 ValidateTimestampOption timestamp_option, | 124 ValidateTimestampOption timestamp_option, |
101 ValidateDMTokenOption dm_token_option) { | 125 ValidateDMTokenOption dm_token_option) { |
102 base::Time last_policy_timestamp; | 126 base::Time last_policy_timestamp; |
103 std::string expected_dm_token; | 127 std::string expected_dm_token; |
104 if (policy_data) { | 128 if (policy_data) { |
105 last_policy_timestamp = | 129 last_policy_timestamp = |
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
203 | 227 |
204 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kCheckFunctions); ++i) { | 228 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kCheckFunctions); ++i) { |
205 if (validation_flags_ & kCheckFunctions[i].flag) { | 229 if (validation_flags_ & kCheckFunctions[i].flag) { |
206 status_ = (this->*(kCheckFunctions[i].checkFunction))(); | 230 status_ = (this->*(kCheckFunctions[i].checkFunction))(); |
207 if (status_ != VALIDATION_OK) | 231 if (status_ != VALIDATION_OK) |
208 break; | 232 break; |
209 } | 233 } |
210 } | 234 } |
211 } | 235 } |
212 | 236 |
237 // Verifies the |new_public_key_verification_signature| for the |new_public_key| | |
238 // in the policy blob. | |
239 bool CloudPolicyValidatorBase::CheckNewPublicKeyVerificationSignature() { | |
240 // If there's no local verification key, then just return true (no | |
241 // validation possible). | |
242 if (verification_key_.empty()) { | |
243 UMA_HISTOGRAM_ENUMERATION(kMetricPolicyKeyVerification, | |
244 METRIC_POLICY_KEY_VERIFICATION_KEY_MISSING, | |
245 METRIC_POLICY_KEY_VERIFICATION_SIZE); | |
246 return true; | |
247 } | |
248 | |
249 if (!policy_->has_new_public_key_verification_signature()) { | |
250 // Policy does not contain a verification signature, so log an error. | |
251 LOG(ERROR) << "Policy is missing public_key_verification_signature"; | |
252 UMA_HISTOGRAM_ENUMERATION(kMetricPolicyKeyVerification, | |
253 METRIC_POLICY_KEY_VERIFICATION_SIGNATURE_MISSING, | |
254 METRIC_POLICY_KEY_VERIFICATION_SIZE); | |
255 // TODO(atwilson): Return an error on failed signature verification once | |
256 // our test servers and unittests are returning policy with a verification | |
257 // signature (http://crbug.com/275291). | |
258 return true; | |
259 } | |
260 | |
261 if (!CheckVerificationKeySignature( | |
262 policy_->new_public_key(), | |
263 verification_key_, | |
264 policy_->new_public_key_verification_signature())) { | |
265 LOG(ERROR) << "Signature verification failed"; | |
266 UMA_HISTOGRAM_ENUMERATION(kMetricPolicyKeyVerification, | |
267 METRIC_POLICY_KEY_VERIFICATION_FAILED, | |
268 METRIC_POLICY_KEY_VERIFICATION_SIZE); | |
269 // TODO(atwilson): Update this code to include the domain name in the | |
270 // signature, and return an error once the server starts returning this. | |
271 return true; | |
272 } | |
273 // Signature verification succeeded - return success to the caller. | |
274 UMA_HISTOGRAM_ENUMERATION(kMetricPolicyKeyVerification, | |
275 METRIC_POLICY_KEY_VERIFICATION_SUCCEEDED, | |
276 METRIC_POLICY_KEY_VERIFICATION_SIZE); | |
277 return true; | |
278 } | |
279 | |
280 bool CloudPolicyValidatorBase::CheckVerificationKeySignature( | |
281 const std::string& key, | |
282 const std::string& verification_key, | |
283 const std::string& signature) { | |
284 // TODO(atwilson): Update this routine to include the domain name in the | |
285 // signed data. | |
286 return VerifySignature(key, verification_key, signature); | |
287 } | |
288 | |
289 void CloudPolicyValidatorBase::set_verification_key( | |
290 const std::string& verification_key) { | |
291 // Make sure we aren't overwriting the verification key with a different key. | |
292 DCHECK(verification_key_.empty() || verification_key_ == verification_key); | |
293 verification_key_ = verification_key; | |
294 } | |
295 | |
213 CloudPolicyValidatorBase::Status CloudPolicyValidatorBase::CheckSignature() { | 296 CloudPolicyValidatorBase::Status CloudPolicyValidatorBase::CheckSignature() { |
214 const std::string* signature_key = &key_; | 297 const std::string* signature_key = &key_; |
215 if (policy_->has_new_public_key() && allow_key_rotation_) { | 298 if (policy_->has_new_public_key() && allow_key_rotation_) { |
216 signature_key = &policy_->new_public_key(); | 299 signature_key = &policy_->new_public_key(); |
217 if (!policy_->has_new_public_key_signature() || | 300 if (!policy_->has_new_public_key_signature() || |
218 !VerifySignature(policy_->new_public_key(), key_, | 301 !VerifySignature(policy_->new_public_key(), key_, |
219 policy_->new_public_key_signature())) { | 302 policy_->new_public_key_signature())) { |
220 LOG(ERROR) << "New public key signature verification failed"; | 303 LOG(ERROR) << "New public key rotation signature verification failed"; |
221 return VALIDATION_BAD_SIGNATURE; | 304 return VALIDATION_BAD_SIGNATURE; |
222 } | 305 } |
306 | |
307 if (!CheckNewPublicKeyVerificationSignature()) { | |
308 LOG(ERROR) << "New public key root verification failed"; | |
309 return VALIDATION_BAD_KEY_VERIFICATION_SIGNATURE; | |
310 } | |
223 } | 311 } |
224 | 312 |
225 if (!policy_->has_policy_data_signature() || | 313 if (!policy_->has_policy_data_signature() || |
226 !VerifySignature(policy_->policy_data(), *signature_key, | 314 !VerifySignature(policy_->policy_data(), *signature_key, |
227 policy_->policy_data_signature())) { | 315 policy_->policy_data_signature())) { |
228 LOG(ERROR) << "Policy signature validation failed"; | 316 LOG(ERROR) << "Policy signature validation failed"; |
229 return VALIDATION_BAD_SIGNATURE; | 317 return VALIDATION_BAD_SIGNATURE; |
230 } | 318 } |
231 | 319 |
320 // If a key verification signature is available, then verify the base signing | |
321 // key as well. | |
322 if (!key_signature_.empty() && | |
323 !CheckVerificationKeySignature(key_, verification_key_, key_signature_)) { | |
Mattias Nissler (ping if slow)
2014/01/31 21:00:35
Wouldn't we fail here for the case where the verif
Andrew T Wilson (Slow)
2014/02/02 11:31:58
When we do key rotation, we'll need to add code on
| |
324 LOG(ERROR) << "Verification key signature verification failed"; | |
325 // TODO(atwilson): Update to return an error once the server is properly | |
326 // generating a verification signature (http://crbug.com/275291). | |
327 // return VALIDATION_BAD_KEY_VERIFICATION_SIGNATURE; | |
328 } | |
329 | |
232 return VALIDATION_OK; | 330 return VALIDATION_OK; |
233 } | 331 } |
234 | 332 |
235 CloudPolicyValidatorBase::Status CloudPolicyValidatorBase::CheckInitialKey() { | 333 CloudPolicyValidatorBase::Status CloudPolicyValidatorBase::CheckInitialKey() { |
236 if (!policy_->has_new_public_key() || | 334 if (!policy_->has_new_public_key() || |
237 !policy_->has_policy_data_signature() || | 335 !policy_->has_policy_data_signature() || |
238 !VerifySignature(policy_->policy_data(), policy_->new_public_key(), | 336 !VerifySignature(policy_->policy_data(), policy_->new_public_key(), |
239 policy_->policy_data_signature())) { | 337 policy_->policy_data_signature())) { |
240 LOG(ERROR) << "Initial policy signature validation failed"; | 338 LOG(ERROR) << "Initial policy signature validation failed"; |
241 return VALIDATION_BAD_INITIAL_SIGNATURE; | 339 return VALIDATION_BAD_INITIAL_SIGNATURE; |
242 } | 340 } |
243 | 341 |
342 if (!CheckNewPublicKeyVerificationSignature()) { | |
343 LOG(ERROR) << "Initial policy root signature validation failed"; | |
344 return VALIDATION_BAD_KEY_VERIFICATION_SIGNATURE; | |
345 } | |
244 return VALIDATION_OK; | 346 return VALIDATION_OK; |
245 } | 347 } |
246 | 348 |
247 CloudPolicyValidatorBase::Status CloudPolicyValidatorBase::CheckPolicyType() { | 349 CloudPolicyValidatorBase::Status CloudPolicyValidatorBase::CheckPolicyType() { |
248 if (!policy_data_->has_policy_type() || | 350 if (!policy_data_->has_policy_type() || |
249 policy_data_->policy_type() != policy_type_) { | 351 policy_data_->policy_type() != policy_type_) { |
250 LOG(ERROR) << "Wrong policy type " << policy_data_->policy_type(); | 352 LOG(ERROR) << "Wrong policy type " << policy_data_->policy_type(); |
251 return VALIDATION_WRONG_POLICY_TYPE; | 353 return VALIDATION_WRONG_POLICY_TYPE; |
252 } | 354 } |
253 | 355 |
(...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
376 return verifier.VerifyFinal(); | 478 return verifier.VerifyFinal(); |
377 } | 479 } |
378 | 480 |
379 template class CloudPolicyValidator<em::CloudPolicySettings>; | 481 template class CloudPolicyValidator<em::CloudPolicySettings>; |
380 | 482 |
381 #if !defined(OS_ANDROID) && !defined(OS_IOS) | 483 #if !defined(OS_ANDROID) && !defined(OS_IOS) |
382 template class CloudPolicyValidator<em::ExternalPolicyData>; | 484 template class CloudPolicyValidator<em::ExternalPolicyData>; |
383 #endif | 485 #endif |
384 | 486 |
385 } // namespace policy | 487 } // namespace policy |
OLD | NEW |