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 3 // found in the LICENSE file. 4 5 #include "components/policy/core/common/cloud/cloud_policy_validator.h" 6 7 #include "base/bind_helpers.h" 8 #include "base/message_loop/message_loop.h" 9 #include "base/metrics/histogram.h" 10 #include "base/sequenced_task_runner.h" 11 #include "base/stl_util.h" 12 #include "components/policy/core/common/cloud/cloud_policy_constants.h" 13 #include "crypto/signature_verifier.h" 14 #include "google_apis/gaia/gaia_auth_util.h" 15 #include "policy/proto/device_management_backend.pb.h" 16 17 namespace em = enterprise_management; 18 19 namespace policy { 20 21 namespace { 22 23 // Grace interval for policy timestamp checks, in seconds. 24 const int kTimestampGraceIntervalSeconds = 60; 25 26 // DER-encoded ASN.1 object identifier for the SHA1-RSA signature algorithm. 27 const uint8 kSHA1SignatureAlgorithm[] = { 28 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 29 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00 30 }; 31 32 // DER-encoded ASN.1 object identifier for the SHA256-RSA signature algorithm 33 // (source: http://tools.ietf.org/html/rfc5754 section 3.2). 34 const uint8 kSHA256SignatureAlgorithm[] = { 35 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 36 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00 37 }; 38 39 COMPILE_ASSERT(sizeof(kSHA256SignatureAlgorithm) == 40 sizeof(kSHA1SignatureAlgorithm), invalid_algorithm_size); 41 42 const int kSignatureAlgorithmSize = sizeof(kSHA1SignatureAlgorithm); 43 44 const char kMetricPolicyKeyVerification[] = "Enterprise.PolicyKeyVerification"; 45 46 enum MetricPolicyKeyVerification { 47 // UMA metric recorded when the client has no verification key. 48 METRIC_POLICY_KEY_VERIFICATION_KEY_MISSING, 49 // Recorded when the policy being verified has no key signature (e.g. policy 50 // fetched before the server supported the verification key). 51 METRIC_POLICY_KEY_VERIFICATION_SIGNATURE_MISSING, 52 // Recorded when the key signature did not match the expected value (in 53 // theory, this should only happen after key rotation or if the policy cached 54 // on disk has been modified). 55 METRIC_POLICY_KEY_VERIFICATION_FAILED, 56 // Recorded when key verification succeeded. 57 METRIC_POLICY_KEY_VERIFICATION_SUCCEEDED, 58 METRIC_POLICY_KEY_VERIFICATION_SIZE // Must be the last. 59 }; 60 61 } // namespace 62 63 CloudPolicyValidatorBase::~CloudPolicyValidatorBase() {} 64 65 void CloudPolicyValidatorBase::ValidateTimestamp( 66 base::Time not_before, 67 base::Time now, 68 ValidateTimestampOption timestamp_option) { 69 // Timestamp should be from the past. We allow for a 1-minute grace interval 70 // to cover clock drift. 71 validation_flags_ |= VALIDATE_TIMESTAMP; 72 timestamp_not_before_ = 73 (not_before - base::Time::UnixEpoch()).InMilliseconds(); 74 timestamp_not_after_ = 75 ((now + base::TimeDelta::FromSeconds(kTimestampGraceIntervalSeconds)) - 76 base::Time::UnixEpoch()).InMillisecondsRoundedUp(); 77 timestamp_option_ = timestamp_option; 78 } 79 80 void CloudPolicyValidatorBase::ValidateUsername( 81 const std::string& expected_user, 82 bool canonicalize) { 83 validation_flags_ |= VALIDATE_USERNAME; 84 user_ = expected_user; 85 canonicalize_user_ = canonicalize; 86 } 87 88 void CloudPolicyValidatorBase::ValidateDomain( 89 const std::string& expected_domain) { 90 validation_flags_ |= VALIDATE_DOMAIN; 91 domain_ = gaia::CanonicalizeDomain(expected_domain); 92 } 93 94 void CloudPolicyValidatorBase::ValidateDMToken( 95 const std::string& token, 96 ValidateDMTokenOption dm_token_option) { 97 validation_flags_ |= VALIDATE_TOKEN; 98 token_ = token; 99 dm_token_option_ = dm_token_option; 100 } 101 102 void CloudPolicyValidatorBase::ValidatePolicyType( 103 const std::string& policy_type) { 104 validation_flags_ |= VALIDATE_POLICY_TYPE; 105 policy_type_ = policy_type; 106 } 107 108 void CloudPolicyValidatorBase::ValidateSettingsEntityId( 109 const std::string& settings_entity_id) { 110 validation_flags_ |= VALIDATE_ENTITY_ID; 111 settings_entity_id_ = settings_entity_id; 112 } 113 114 void CloudPolicyValidatorBase::ValidatePayload() { 115 validation_flags_ |= VALIDATE_PAYLOAD; 116 } 117 118 119 void CloudPolicyValidatorBase::ValidateCachedKey( 120 const std::string& cached_key, 121 const std::string& cached_key_signature, 122 const std::string& verification_key, 123 const std::string& owning_domain) { 124 validation_flags_ |= VALIDATE_CACHED_KEY; 125 set_verification_key_and_domain(verification_key, owning_domain); 126 cached_key_ = cached_key; 127 cached_key_signature_ = cached_key_signature; 128 } 129 130 void CloudPolicyValidatorBase::ValidateSignature( 131 const std::string& key, 132 const std::string& verification_key, 133 const std::string& owning_domain, 134 bool allow_key_rotation) { 135 validation_flags_ |= VALIDATE_SIGNATURE; 136 set_verification_key_and_domain(verification_key, owning_domain); 137 key_ = key; 138 allow_key_rotation_ = allow_key_rotation; 139 } 140 141 void CloudPolicyValidatorBase::ValidateInitialKey( 142 const std::string& verification_key, 143 const std::string& owning_domain) { 144 validation_flags_ |= VALIDATE_INITIAL_KEY; 145 set_verification_key_and_domain(verification_key, owning_domain); 146 } 147 148 void CloudPolicyValidatorBase::ValidateAgainstCurrentPolicy( 149 const em::PolicyData* policy_data, 150 ValidateTimestampOption timestamp_option, 151 ValidateDMTokenOption dm_token_option) { 152 base::Time last_policy_timestamp; 153 std::string expected_dm_token; 154 if (policy_data) { 155 last_policy_timestamp = 156 base::Time::UnixEpoch() + 157 base::TimeDelta::FromMilliseconds(policy_data->timestamp()); 158 expected_dm_token = policy_data->request_token(); 159 } 160 ValidateTimestamp(last_policy_timestamp, base::Time::NowFromSystemTime(), 161 timestamp_option); 162 ValidateDMToken(expected_dm_token, dm_token_option); 163 } 164 165 CloudPolicyValidatorBase::CloudPolicyValidatorBase( 166 scoped_ptr<em::PolicyFetchResponse> policy_response, 167 google::protobuf::MessageLite* payload, 168 scoped_refptr<base::SequencedTaskRunner> background_task_runner) 169 : status_(VALIDATION_OK), 170 policy_(policy_response.Pass()), 171 payload_(payload), 172 validation_flags_(0), 173 timestamp_not_before_(0), 174 timestamp_not_after_(0), 175 timestamp_option_(TIMESTAMP_REQUIRED), 176 dm_token_option_(DM_TOKEN_REQUIRED), 177 canonicalize_user_(false), 178 allow_key_rotation_(false), 179 background_task_runner_(background_task_runner) {} 180 181 void CloudPolicyValidatorBase::PostValidationTask( 182 const base::Closure& completion_callback) { 183 background_task_runner_->PostTask( 184 FROM_HERE, 185 base::Bind(&CloudPolicyValidatorBase::PerformValidation, 186 base::Passed(scoped_ptr<CloudPolicyValidatorBase>(this)), 187 base::MessageLoop::current()->message_loop_proxy(), 188 completion_callback)); 189 } 190 191 // static 192 void CloudPolicyValidatorBase::PerformValidation( 193 scoped_ptr<CloudPolicyValidatorBase> self, 194 scoped_refptr<base::MessageLoopProxy> message_loop, 195 const base::Closure& completion_callback) { 196 // Run the validation activities on this thread. 197 self->RunValidation(); 198 199 // Report completion on |message_loop|. 200 message_loop->PostTask( 201 FROM_HERE, 202 base::Bind(&CloudPolicyValidatorBase::ReportCompletion, 203 base::Passed(&self), 204 completion_callback)); 205 } 206 207 // static 208 void CloudPolicyValidatorBase::ReportCompletion( 209 scoped_ptr<CloudPolicyValidatorBase> self, 210 const base::Closure& completion_callback) { 211 completion_callback.Run(); 212 } 213 214 void CloudPolicyValidatorBase::RunValidation() { 215 policy_data_.reset(new em::PolicyData()); 216 RunChecks(); 217 } 218 219 void CloudPolicyValidatorBase::RunChecks() { 220 status_ = VALIDATION_OK; 221 if ((policy_->has_error_code() && policy_->error_code() != 200) || 222 (policy_->has_error_message() && !policy_->error_message().empty())) { 223 LOG(ERROR) << "Error in policy blob." 224 << " code: " << policy_->error_code() 225 << " message: " << policy_->error_message(); 226 status_ = VALIDATION_ERROR_CODE_PRESENT; 227 return; 228 } 229 230 // Parse policy data. 231 if (!policy_data_->ParseFromString(policy_->policy_data()) || 232 !policy_data_->IsInitialized()) { 233 LOG(ERROR) << "Failed to parse policy response"; 234 status_ = VALIDATION_PAYLOAD_PARSE_ERROR; 235 return; 236 } 237 238 // Table of checks we run. These are sorted by descending severity of the 239 // error, s.t. the most severe check will determine the validation status. 240 static const struct { 241 int flag; 242 Status (CloudPolicyValidatorBase::* checkFunction)(); 243 } kCheckFunctions[] = { 244 { VALIDATE_SIGNATURE, &CloudPolicyValidatorBase::CheckSignature }, 245 { VALIDATE_INITIAL_KEY, &CloudPolicyValidatorBase::CheckInitialKey }, 246 { VALIDATE_CACHED_KEY, &CloudPolicyValidatorBase::CheckCachedKey }, 247 { VALIDATE_POLICY_TYPE, &CloudPolicyValidatorBase::CheckPolicyType }, 248 { VALIDATE_ENTITY_ID, &CloudPolicyValidatorBase::CheckEntityId }, 249 { VALIDATE_TOKEN, &CloudPolicyValidatorBase::CheckToken }, 250 { VALIDATE_USERNAME, &CloudPolicyValidatorBase::CheckUsername }, 251 { VALIDATE_DOMAIN, &CloudPolicyValidatorBase::CheckDomain }, 252 { VALIDATE_TIMESTAMP, &CloudPolicyValidatorBase::CheckTimestamp }, 253 { VALIDATE_PAYLOAD, &CloudPolicyValidatorBase::CheckPayload }, 254 }; 255 256 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kCheckFunctions); ++i) { 257 if (validation_flags_ & kCheckFunctions[i].flag) { 258 status_ = (this->*(kCheckFunctions[i].checkFunction))(); 259 if (status_ != VALIDATION_OK) 260 break; 261 } 262 } 263 } 264 265 // Verifies the |new_public_key_verification_signature| for the |new_public_key| 266 // in the policy blob. 267 bool CloudPolicyValidatorBase::CheckNewPublicKeyVerificationSignature() { 268 // If there's no local verification key, then just return true (no 269 // validation possible). 270 if (verification_key_.empty()) { 271 UMA_HISTOGRAM_ENUMERATION(kMetricPolicyKeyVerification, 272 METRIC_POLICY_KEY_VERIFICATION_KEY_MISSING, 273 METRIC_POLICY_KEY_VERIFICATION_SIZE); 274 return true; 275 } 276 277 if (!policy_->has_new_public_key_verification_signature()) { 278 // Policy does not contain a verification signature, so log an error. 279 LOG(ERROR) << "Policy is missing public_key_verification_signature"; 280 UMA_HISTOGRAM_ENUMERATION(kMetricPolicyKeyVerification, 281 METRIC_POLICY_KEY_VERIFICATION_SIGNATURE_MISSING, 282 METRIC_POLICY_KEY_VERIFICATION_SIZE); 283 return false; 284 } 285 286 if (!CheckVerificationKeySignature( 287 policy_->new_public_key(), 288 verification_key_, 289 policy_->new_public_key_verification_signature())) { 290 LOG(ERROR) << "Signature verification failed"; 291 UMA_HISTOGRAM_ENUMERATION(kMetricPolicyKeyVerification, 292 METRIC_POLICY_KEY_VERIFICATION_FAILED, 293 METRIC_POLICY_KEY_VERIFICATION_SIZE); 294 return false; 295 } 296 // Signature verification succeeded - return success to the caller. 297 DVLOG(1) << "Signature verification succeeded"; 298 UMA_HISTOGRAM_ENUMERATION(kMetricPolicyKeyVerification, 299 METRIC_POLICY_KEY_VERIFICATION_SUCCEEDED, 300 METRIC_POLICY_KEY_VERIFICATION_SIZE); 301 return true; 302 } 303 304 bool CloudPolicyValidatorBase::CheckVerificationKeySignature( 305 const std::string& key, 306 const std::string& verification_key, 307 const std::string& signature) { 308 DCHECK(!verification_key.empty()); 309 em::PolicyPublicKeyAndDomain signed_data; 310 signed_data.set_new_public_key(key); 311 312 // If no owning_domain_ supplied, try extracting the domain from the policy 313 // itself (this happens on certain platforms during startup, when we validate 314 // cached policy before prefs are loaded). 315 std::string domain = owning_domain_.empty() ? 316 ExtractDomainFromPolicy() : owning_domain_; 317 if (domain.empty()) { 318 LOG(ERROR) << "Policy does not contain a domain"; 319 return false; 320 } 321 signed_data.set_domain(domain); 322 std::string signed_data_as_string; 323 if (!signed_data.SerializeToString(&signed_data_as_string)) { 324 DLOG(ERROR) << "Could not serialize verification key to string"; 325 return false; 326 } 327 return VerifySignature(signed_data_as_string, verification_key, signature, 328 SHA256); 329 } 330 331 std::string CloudPolicyValidatorBase::ExtractDomainFromPolicy() { 332 std::string domain; 333 if (policy_data_->has_username()) { 334 domain = gaia::ExtractDomainName( 335 gaia::CanonicalizeEmail( 336 gaia::SanitizeEmail(policy_data_->username()))); 337 } 338 return domain; 339 } 340 341 void CloudPolicyValidatorBase::set_verification_key_and_domain( 342 const std::string& verification_key, const std::string& owning_domain) { 343 // Make sure we aren't overwriting the verification key with a different key. 344 DCHECK(verification_key_.empty() || verification_key_ == verification_key); 345 DCHECK(owning_domain_.empty() || owning_domain_ == owning_domain); 346 verification_key_ = verification_key; 347 owning_domain_ = owning_domain; 348 } 349 350 CloudPolicyValidatorBase::Status CloudPolicyValidatorBase::CheckSignature() { 351 const std::string* signature_key = &key_; 352 if (policy_->has_new_public_key() && allow_key_rotation_) { 353 signature_key = &policy_->new_public_key(); 354 if (!policy_->has_new_public_key_signature() || 355 !VerifySignature(policy_->new_public_key(), key_, 356 policy_->new_public_key_signature(), SHA1)) { 357 LOG(ERROR) << "New public key rotation signature verification failed"; 358 return VALIDATION_BAD_SIGNATURE; 359 } 360 361 if (!CheckNewPublicKeyVerificationSignature()) { 362 LOG(ERROR) << "New public key root verification failed"; 363 return VALIDATION_BAD_KEY_VERIFICATION_SIGNATURE; 364 } 365 } 366 367 if (!policy_->has_policy_data_signature() || 368 !VerifySignature(policy_->policy_data(), *signature_key, 369 policy_->policy_data_signature(), SHA1)) { 370 LOG(ERROR) << "Policy signature validation failed"; 371 return VALIDATION_BAD_SIGNATURE; 372 } 373 374 return VALIDATION_OK; 375 } 376 377 CloudPolicyValidatorBase::Status CloudPolicyValidatorBase::CheckInitialKey() { 378 if (!policy_->has_new_public_key() || 379 !policy_->has_policy_data_signature() || 380 !VerifySignature(policy_->policy_data(), policy_->new_public_key(), 381 policy_->policy_data_signature(), SHA1)) { 382 LOG(ERROR) << "Initial policy signature validation failed"; 383 return VALIDATION_BAD_INITIAL_SIGNATURE; 384 } 385 386 if (!CheckNewPublicKeyVerificationSignature()) { 387 LOG(ERROR) << "Initial policy root signature validation failed"; 388 return VALIDATION_BAD_KEY_VERIFICATION_SIGNATURE; 389 } 390 return VALIDATION_OK; 391 } 392 393 CloudPolicyValidatorBase::Status CloudPolicyValidatorBase::CheckCachedKey() { 394 if (!verification_key_.empty() && 395 !CheckVerificationKeySignature(cached_key_, verification_key_, 396 cached_key_signature_)) { 397 LOG(ERROR) << "Cached key signature verification failed"; 398 return VALIDATION_BAD_KEY_VERIFICATION_SIGNATURE; 399 } else { 400 DVLOG(1) << "Cached key signature verification succeeded"; 401 } 402 return VALIDATION_OK; 403 } 404 405 CloudPolicyValidatorBase::Status CloudPolicyValidatorBase::CheckPolicyType() { 406 if (!policy_data_->has_policy_type() || 407 policy_data_->policy_type() != policy_type_) { 408 LOG(ERROR) << "Wrong policy type " << policy_data_->policy_type(); 409 return VALIDATION_WRONG_POLICY_TYPE; 410 } 411 412 return VALIDATION_OK; 413 } 414 415 CloudPolicyValidatorBase::Status CloudPolicyValidatorBase::CheckEntityId() { 416 if (!policy_data_->has_settings_entity_id() || 417 policy_data_->settings_entity_id() != settings_entity_id_) { 418 LOG(ERROR) << "Wrong settings_entity_id " 419 << policy_data_->settings_entity_id() << ", expected " 420 << settings_entity_id_; 421 return VALIDATION_WRONG_SETTINGS_ENTITY_ID; 422 } 423 424 return VALIDATION_OK; 425 } 426 427 CloudPolicyValidatorBase::Status CloudPolicyValidatorBase::CheckTimestamp() { 428 if (!policy_data_->has_timestamp()) { 429 if (timestamp_option_ == TIMESTAMP_NOT_REQUIRED) { 430 return VALIDATION_OK; 431 } else { 432 LOG(ERROR) << "Policy timestamp missing"; 433 return VALIDATION_BAD_TIMESTAMP; 434 } 435 } 436 437 if (timestamp_option_ != TIMESTAMP_NOT_REQUIRED && 438 policy_data_->timestamp() < timestamp_not_before_) { 439 // If |timestamp_option_| is TIMESTAMP_REQUIRED or TIMESTAMP_NOT_BEFORE 440 // then this is a failure. 441 LOG(ERROR) << "Policy too old: " << policy_data_->timestamp(); 442 return VALIDATION_BAD_TIMESTAMP; 443 } 444 if (timestamp_option_ == TIMESTAMP_REQUIRED && 445 policy_data_->timestamp() > timestamp_not_after_) { 446 LOG(ERROR) << "Policy from the future: " << policy_data_->timestamp(); 447 return VALIDATION_BAD_TIMESTAMP; 448 } 449 450 return VALIDATION_OK; 451 } 452 453 CloudPolicyValidatorBase::Status CloudPolicyValidatorBase::CheckToken() { 454 // Make sure the token matches the expected token (if any) and also 455 // make sure the token itself is valid (non-empty if DM_TOKEN_REQUIRED). 456 if (dm_token_option_ == DM_TOKEN_REQUIRED && 457 (!policy_data_->has_request_token() || 458 policy_data_->request_token().empty())) { 459 LOG(ERROR) << "Empty DM token encountered - expected: " << token_; 460 return VALIDATION_WRONG_TOKEN; 461 } 462 if (!token_.empty() && policy_data_->request_token() != token_) { 463 LOG(ERROR) << "Invalid DM token: " << policy_data_->request_token() 464 << " - expected: " << token_; 465 return VALIDATION_WRONG_TOKEN; 466 } 467 468 return VALIDATION_OK; 469 } 470 471 CloudPolicyValidatorBase::Status CloudPolicyValidatorBase::CheckUsername() { 472 if (!policy_data_->has_username()) { 473 LOG(ERROR) << "Policy is missing user name"; 474 return VALIDATION_BAD_USERNAME; 475 } 476 477 std::string expected = user_; 478 std::string actual = policy_data_->username(); 479 if (canonicalize_user_) { 480 expected = gaia::CanonicalizeEmail(gaia::SanitizeEmail(expected)); 481 actual = gaia::CanonicalizeEmail(gaia::SanitizeEmail(actual)); 482 } 483 484 if (expected != actual) { 485 LOG(ERROR) << "Invalid user name " << policy_data_->username(); 486 return VALIDATION_BAD_USERNAME; 487 } 488 489 return VALIDATION_OK; 490 } 491 492 CloudPolicyValidatorBase::Status CloudPolicyValidatorBase::CheckDomain() { 493 std::string policy_domain = ExtractDomainFromPolicy(); 494 if (policy_domain.empty()) { 495 LOG(ERROR) << "Policy is missing user name"; 496 return VALIDATION_BAD_USERNAME; 497 } 498 499 if (domain_ != policy_domain) { 500 LOG(ERROR) << "Invalid user name " << policy_data_->username(); 501 return VALIDATION_BAD_USERNAME; 502 } 503 504 return VALIDATION_OK; 505 } 506 507 CloudPolicyValidatorBase::Status CloudPolicyValidatorBase::CheckPayload() { 508 if (!policy_data_->has_policy_value() || 509 !payload_->ParseFromString(policy_data_->policy_value()) || 510 !payload_->IsInitialized()) { 511 LOG(ERROR) << "Failed to decode policy payload protobuf"; 512 return VALIDATION_POLICY_PARSE_ERROR; 513 } 514 515 return VALIDATION_OK; 516 } 517 518 // static 519 bool CloudPolicyValidatorBase::VerifySignature(const std::string& data, 520 const std::string& key, 521 const std::string& signature, 522 SignatureType signature_type) { 523 crypto::SignatureVerifier verifier; 524 const uint8* algorithm = NULL; 525 switch (signature_type) { 526 case SHA1: 527 algorithm = kSHA1SignatureAlgorithm; 528 break; 529 case SHA256: 530 algorithm = kSHA256SignatureAlgorithm; 531 break; 532 default: 533 NOTREACHED() << "Invalid signature type: " << signature_type; 534 return false; 535 } 536 537 if (!verifier.VerifyInit(algorithm, kSignatureAlgorithmSize, 538 reinterpret_cast<const uint8*>(signature.c_str()), 539 signature.size(), 540 reinterpret_cast<const uint8*>(key.c_str()), 541 key.size())) { 542 DLOG(ERROR) << "Invalid verification signature/key format"; 543 return false; 544 } 545 verifier.VerifyUpdate(reinterpret_cast<const uint8*>(data.c_str()), 546 data.size()); 547 return verifier.VerifyFinal(); 548 } 549 550 template class CloudPolicyValidator<em::CloudPolicySettings>; 551 552 #if !defined(OS_ANDROID) && !defined(OS_IOS) 553 template class CloudPolicyValidator<em::ExternalPolicyData>; 554 #endif 555 556 } // namespace policy 557