Chromium Code Reviews| 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 |