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 <vector> 6 7 #include "base/bind.h" 8 #include "base/memory/scoped_ptr.h" 9 #include "base/message_loop/message_loop.h" 10 #include "base/message_loop/message_loop_proxy.h" 11 #include "base/stl_util.h" 12 #include "base/strings/string_util.h" 13 #include "components/policy/core/common/cloud/cloud_policy_constants.h" 14 #include "components/policy/core/common/cloud/cloud_policy_validator.h" 15 #include "components/policy/core/common/cloud/policy_builder.h" 16 #include "components/policy/core/common/policy_switches.h" 17 #include "crypto/rsa_private_key.h" 18 #include "policy/proto/device_management_backend.pb.h" 19 #include "testing/gmock/include/gmock/gmock.h" 20 #include "testing/gtest/include/gtest/gtest.h" 21 22 namespace em = enterprise_management; 23 24 using testing::Invoke; 25 using testing::Mock; 26 27 namespace policy { 28 29 namespace { 30 31 ACTION_P(CheckStatus, expected_status) { 32 EXPECT_EQ(expected_status, arg0->status()); 33 }; 34 35 class CloudPolicyValidatorTest : public testing::Test { 36 public: 37 CloudPolicyValidatorTest() 38 : timestamp_(base::Time::UnixEpoch() + 39 base::TimeDelta::FromMilliseconds( 40 PolicyBuilder::kFakeTimestamp)), 41 timestamp_option_(CloudPolicyValidatorBase::TIMESTAMP_REQUIRED), 42 ignore_missing_dm_token_(CloudPolicyValidatorBase::DM_TOKEN_REQUIRED), 43 allow_key_rotation_(true), 44 existing_dm_token_(PolicyBuilder::kFakeToken), 45 owning_domain_(PolicyBuilder::kFakeDomain), 46 cached_key_signature_(PolicyBuilder::GetTestSigningKeySignature()) { 47 policy_.SetDefaultNewSigningKey(); 48 } 49 50 void Validate(testing::Action<void(UserCloudPolicyValidator*)> check_action) { 51 policy_.Build(); 52 ValidatePolicy(check_action, policy_.GetCopy()); 53 } 54 55 void ValidatePolicy( 56 testing::Action<void(UserCloudPolicyValidator*)> check_action, 57 scoped_ptr<enterprise_management::PolicyFetchResponse> policy_response) { 58 // Create a validator. 59 scoped_ptr<UserCloudPolicyValidator> validator = CreateValidator( 60 policy_response.Pass()); 61 62 // Run validation and check the result. 63 EXPECT_CALL(*this, ValidationCompletion(validator.get())).WillOnce( 64 check_action); 65 validator.release()->StartValidation( 66 base::Bind(&CloudPolicyValidatorTest::ValidationCompletion, 67 base::Unretained(this))); 68 loop_.RunUntilIdle(); 69 Mock::VerifyAndClearExpectations(this); 70 } 71 72 scoped_ptr<UserCloudPolicyValidator> CreateValidator( 73 scoped_ptr<enterprise_management::PolicyFetchResponse> policy_response) { 74 std::vector<uint8> public_key_bytes; 75 EXPECT_TRUE( 76 PolicyBuilder::CreateTestSigningKey()->ExportPublicKey( 77 &public_key_bytes)); 78 79 // Convert from bytes to string format (which is what ValidateSignature() 80 // takes). 81 std::string public_key = std::string( 82 reinterpret_cast<const char*>(vector_as_array(&public_key_bytes)), 83 public_key_bytes.size()); 84 85 UserCloudPolicyValidator* validator = UserCloudPolicyValidator::Create( 86 policy_response.Pass(), base::MessageLoopProxy::current()); 87 validator->ValidateTimestamp(timestamp_, timestamp_, 88 timestamp_option_); 89 validator->ValidateUsername(PolicyBuilder::kFakeUsername, true); 90 if (!owning_domain_.empty()) 91 validator->ValidateDomain(owning_domain_); 92 validator->ValidateDMToken(existing_dm_token_, ignore_missing_dm_token_); 93 validator->ValidatePolicyType(dm_protocol::kChromeUserPolicyType); 94 validator->ValidatePayload(); 95 validator->ValidateCachedKey(public_key, 96 cached_key_signature_, 97 GetPolicyVerificationKey(), 98 owning_domain_); 99 validator->ValidateSignature(public_key, 100 GetPolicyVerificationKey(), 101 owning_domain_, 102 allow_key_rotation_); 103 if (allow_key_rotation_) 104 validator->ValidateInitialKey(GetPolicyVerificationKey(), owning_domain_); 105 return make_scoped_ptr(validator); 106 } 107 108 109 void CheckSuccessfulValidation(UserCloudPolicyValidator* validator) { 110 EXPECT_TRUE(validator->success()); 111 EXPECT_EQ(policy_.policy().SerializeAsString(), 112 validator->policy()->SerializeAsString()); 113 EXPECT_EQ(policy_.policy_data().SerializeAsString(), 114 validator->policy_data()->SerializeAsString()); 115 EXPECT_EQ(policy_.payload().SerializeAsString(), 116 validator->payload()->SerializeAsString()); 117 } 118 119 base::MessageLoopForUI loop_; 120 base::Time timestamp_; 121 CloudPolicyValidatorBase::ValidateTimestampOption timestamp_option_; 122 CloudPolicyValidatorBase::ValidateDMTokenOption ignore_missing_dm_token_; 123 std::string signing_key_; 124 bool allow_key_rotation_; 125 std::string existing_dm_token_; 126 std::string owning_domain_; 127 std::string cached_key_signature_; 128 129 UserPolicyBuilder policy_; 130 131 private: 132 MOCK_METHOD1(ValidationCompletion, void(UserCloudPolicyValidator* validator)); 133 134 DISALLOW_COPY_AND_ASSIGN(CloudPolicyValidatorTest); 135 }; 136 137 TEST_F(CloudPolicyValidatorTest, SuccessfulValidation) { 138 Validate(Invoke(this, &CloudPolicyValidatorTest::CheckSuccessfulValidation)); 139 } 140 141 TEST_F(CloudPolicyValidatorTest, SuccessfulRunValidation) { 142 policy_.Build(); 143 scoped_ptr<UserCloudPolicyValidator> validator = CreateValidator( 144 policy_.GetCopy()); 145 // Run validation immediately (no background tasks). 146 validator->RunValidation(); 147 CheckSuccessfulValidation(validator.get()); 148 } 149 150 TEST_F(CloudPolicyValidatorTest, SuccessfulRunValidationWithNoExistingDMToken) { 151 existing_dm_token_.clear(); 152 Validate(Invoke(this, &CloudPolicyValidatorTest::CheckSuccessfulValidation)); 153 } 154 155 TEST_F(CloudPolicyValidatorTest, SuccessfulRunValidationWithNoDMTokens) { 156 existing_dm_token_.clear(); 157 policy_.policy_data().clear_request_token(); 158 ignore_missing_dm_token_ = CloudPolicyValidatorBase::DM_TOKEN_NOT_REQUIRED; 159 Validate(Invoke(this, &CloudPolicyValidatorTest::CheckSuccessfulValidation)); 160 } 161 162 TEST_F(CloudPolicyValidatorTest, UsernameCanonicalization) { 163 policy_.policy_data().set_username( 164 StringToUpperASCII(std::string(PolicyBuilder::kFakeUsername))); 165 Validate(CheckStatus(CloudPolicyValidatorBase::VALIDATION_OK)); 166 } 167 168 TEST_F(CloudPolicyValidatorTest, ErrorNoPolicyType) { 169 policy_.policy_data().clear_policy_type(); 170 Validate(CheckStatus(CloudPolicyValidatorBase::VALIDATION_WRONG_POLICY_TYPE)); 171 } 172 173 TEST_F(CloudPolicyValidatorTest, ErrorWrongPolicyType) { 174 policy_.policy_data().set_policy_type("invalid"); 175 Validate(CheckStatus(CloudPolicyValidatorBase::VALIDATION_WRONG_POLICY_TYPE)); 176 } 177 178 TEST_F(CloudPolicyValidatorTest, ErrorNoTimestamp) { 179 policy_.policy_data().clear_timestamp(); 180 Validate(CheckStatus(CloudPolicyValidatorBase::VALIDATION_BAD_TIMESTAMP)); 181 } 182 183 TEST_F(CloudPolicyValidatorTest, IgnoreMissingTimestamp) { 184 timestamp_option_ = CloudPolicyValidatorBase::TIMESTAMP_NOT_REQUIRED; 185 policy_.policy_data().clear_timestamp(); 186 Validate(CheckStatus(CloudPolicyValidatorBase::VALIDATION_OK)); 187 } 188 189 TEST_F(CloudPolicyValidatorTest, ErrorOldTimestamp) { 190 base::Time timestamp(timestamp_ - base::TimeDelta::FromMinutes(5)); 191 policy_.policy_data().set_timestamp( 192 (timestamp - base::Time::UnixEpoch()).InMilliseconds()); 193 Validate(CheckStatus(CloudPolicyValidatorBase::VALIDATION_BAD_TIMESTAMP)); 194 } 195 196 TEST_F(CloudPolicyValidatorTest, ErrorTimestampFromTheFuture) { 197 base::Time timestamp(timestamp_ + base::TimeDelta::FromMinutes(5)); 198 policy_.policy_data().set_timestamp( 199 (timestamp - base::Time::UnixEpoch()).InMilliseconds()); 200 Validate(CheckStatus(CloudPolicyValidatorBase::VALIDATION_BAD_TIMESTAMP)); 201 } 202 203 TEST_F(CloudPolicyValidatorTest, IgnoreErrorTimestampFromTheFuture) { 204 base::Time timestamp(timestamp_ + base::TimeDelta::FromMinutes(5)); 205 timestamp_option_ = 206 CloudPolicyValidatorBase::TIMESTAMP_NOT_BEFORE; 207 policy_.policy_data().set_timestamp( 208 (timestamp - base::Time::UnixEpoch()).InMilliseconds()); 209 Validate(CheckStatus(CloudPolicyValidatorBase::VALIDATION_OK)); 210 } 211 212 TEST_F(CloudPolicyValidatorTest, ErrorNoRequestToken) { 213 policy_.policy_data().clear_request_token(); 214 Validate(CheckStatus(CloudPolicyValidatorBase::VALIDATION_WRONG_TOKEN)); 215 } 216 217 TEST_F(CloudPolicyValidatorTest, ErrorNoRequestTokenNotRequired) { 218 // Even though DMTokens are not required, if the existing policy has a token, 219 // we should still generate an error if the new policy has none. 220 policy_.policy_data().clear_request_token(); 221 ignore_missing_dm_token_ = CloudPolicyValidatorBase::DM_TOKEN_NOT_REQUIRED; 222 Validate(CheckStatus(CloudPolicyValidatorBase::VALIDATION_WRONG_TOKEN)); 223 } 224 225 TEST_F(CloudPolicyValidatorTest, ErrorNoRequestTokenNoTokenPassed) { 226 // Mimic the first fetch of policy (no existing DM token) - should still 227 // complain about not having any DMToken. 228 existing_dm_token_.clear(); 229 policy_.policy_data().clear_request_token(); 230 Validate(CheckStatus(CloudPolicyValidatorBase::VALIDATION_WRONG_TOKEN)); 231 } 232 233 TEST_F(CloudPolicyValidatorTest, ErrorInvalidRequestToken) { 234 policy_.policy_data().set_request_token("invalid"); 235 Validate(CheckStatus(CloudPolicyValidatorBase::VALIDATION_WRONG_TOKEN)); 236 } 237 238 TEST_F(CloudPolicyValidatorTest, ErrorNoPolicyValue) { 239 policy_.clear_payload(); 240 Validate( 241 CheckStatus(CloudPolicyValidatorBase::VALIDATION_POLICY_PARSE_ERROR)); 242 } 243 244 TEST_F(CloudPolicyValidatorTest, ErrorInvalidPolicyValue) { 245 policy_.clear_payload(); 246 policy_.policy_data().set_policy_value("invalid"); 247 Validate( 248 CheckStatus(CloudPolicyValidatorBase::VALIDATION_POLICY_PARSE_ERROR)); 249 } 250 251 TEST_F(CloudPolicyValidatorTest, ErrorNoUsername) { 252 policy_.policy_data().clear_username(); 253 Validate(CheckStatus(CloudPolicyValidatorBase::VALIDATION_BAD_USERNAME)); 254 } 255 256 TEST_F(CloudPolicyValidatorTest, ErrorInvalidUsername) { 257 policy_.policy_data().set_username("invalid (at) example.com"); 258 Validate(CheckStatus(CloudPolicyValidatorBase::VALIDATION_BAD_USERNAME)); 259 } 260 261 TEST_F(CloudPolicyValidatorTest, ErrorErrorMessage) { 262 policy_.policy().set_error_message("error"); 263 Validate( 264 CheckStatus(CloudPolicyValidatorBase::VALIDATION_ERROR_CODE_PRESENT)); 265 } 266 267 TEST_F(CloudPolicyValidatorTest, ErrorErrorCode) { 268 policy_.policy().set_error_code(42); 269 Validate( 270 CheckStatus(CloudPolicyValidatorBase::VALIDATION_ERROR_CODE_PRESENT)); 271 } 272 273 TEST_F(CloudPolicyValidatorTest, ErrorNoSignature) { 274 policy_.UnsetSigningKey(); 275 policy_.UnsetNewSigningKey(); 276 policy_.policy().clear_policy_data_signature(); 277 Validate(CheckStatus(CloudPolicyValidatorBase::VALIDATION_BAD_SIGNATURE)); 278 } 279 280 TEST_F(CloudPolicyValidatorTest, ErrorInvalidSignature) { 281 policy_.UnsetSigningKey(); 282 policy_.UnsetNewSigningKey(); 283 policy_.policy().set_policy_data_signature("invalid"); 284 Validate(CheckStatus(CloudPolicyValidatorBase::VALIDATION_BAD_SIGNATURE)); 285 } 286 287 TEST_F(CloudPolicyValidatorTest, ErrorNoPublicKey) { 288 policy_.UnsetSigningKey(); 289 policy_.UnsetNewSigningKey(); 290 policy_.policy().clear_new_public_key(); 291 Validate(CheckStatus(CloudPolicyValidatorBase::VALIDATION_BAD_SIGNATURE)); 292 } 293 294 TEST_F(CloudPolicyValidatorTest, ErrorInvalidPublicKey) { 295 policy_.UnsetSigningKey(); 296 policy_.UnsetNewSigningKey(); 297 policy_.policy().set_new_public_key("invalid"); 298 Validate(CheckStatus(CloudPolicyValidatorBase::VALIDATION_BAD_SIGNATURE)); 299 } 300 301 TEST_F(CloudPolicyValidatorTest, ErrorNoPublicKeySignature) { 302 policy_.UnsetSigningKey(); 303 policy_.UnsetNewSigningKey(); 304 policy_.policy().clear_new_public_key_signature(); 305 Validate(CheckStatus(CloudPolicyValidatorBase::VALIDATION_BAD_SIGNATURE)); 306 } 307 308 TEST_F(CloudPolicyValidatorTest, ErrorInvalidPublicKeySignature) { 309 policy_.UnsetSigningKey(); 310 policy_.UnsetNewSigningKey(); 311 policy_.policy().set_new_public_key_signature("invalid"); 312 Validate(CheckStatus(CloudPolicyValidatorBase::VALIDATION_BAD_SIGNATURE)); 313 } 314 315 #if !defined(OS_CHROMEOS) 316 // Validation key is not currently checked on Chrome OS 317 // (http://crbug.com/328038). 318 TEST_F(CloudPolicyValidatorTest, ErrorInvalidPublicKeyVerificationSignature) { 319 policy_.Build(); 320 policy_.policy().set_new_public_key_verification_signature("invalid"); 321 ValidatePolicy(CheckStatus( 322 CloudPolicyValidatorBase::VALIDATION_BAD_KEY_VERIFICATION_SIGNATURE), 323 policy_.GetCopy()); 324 } 325 326 TEST_F(CloudPolicyValidatorTest, ErrorDomainMismatchForKeyVerification) { 327 policy_.Build(); 328 // Generate a non-matching owning_domain, which should cause a validation 329 // failure. 330 owning_domain_ = "invalid.com"; 331 ValidatePolicy(CheckStatus( 332 CloudPolicyValidatorBase::VALIDATION_BAD_KEY_VERIFICATION_SIGNATURE), 333 policy_.GetCopy()); 334 } 335 336 TEST_F(CloudPolicyValidatorTest, ErrorDomainExtractedFromUsernameMismatch) { 337 // Generate a non-matching username domain, which should cause a validation 338 // failure when we try to verify the signing key with it. 339 policy_.policy_data().set_username("wonky (at) invalid.com"); 340 policy_.Build(); 341 // Pass an empty domain to tell validator to extract the domain from the 342 // policy's |username| field. 343 owning_domain_ = ""; 344 ValidatePolicy(CheckStatus( 345 CloudPolicyValidatorBase::VALIDATION_BAD_KEY_VERIFICATION_SIGNATURE), 346 policy_.GetCopy()); 347 } 348 349 TEST_F(CloudPolicyValidatorTest, ErrorNoCachedKeySignature) { 350 // Generate an empty cached_key_signature_ and this should cause a validation 351 // error when we try to verify the signing key with it. 352 cached_key_signature_ = ""; 353 Validate(CheckStatus( 354 CloudPolicyValidatorBase::VALIDATION_BAD_KEY_VERIFICATION_SIGNATURE)); 355 } 356 357 TEST_F(CloudPolicyValidatorTest, ErrorInvalidCachedKeySignature) { 358 // Generate a key signature for a different key (one that does not match 359 // the signing key) and this should cause a validation error when we try to 360 // verify the signing key with it. 361 cached_key_signature_ = PolicyBuilder::GetTestOtherSigningKeySignature(); 362 Validate(CheckStatus( 363 CloudPolicyValidatorBase::VALIDATION_BAD_KEY_VERIFICATION_SIGNATURE)); 364 } 365 #endif 366 367 TEST_F(CloudPolicyValidatorTest, SuccessfulNoDomainValidation) { 368 // Don't pass in a domain - this tells the validation code to instead 369 // extract the domain from the username. 370 owning_domain_ = ""; 371 Validate(Invoke(this, &CloudPolicyValidatorTest::CheckSuccessfulValidation)); 372 } 373 374 TEST_F(CloudPolicyValidatorTest, ErrorNoRotationAllowed) { 375 allow_key_rotation_ = false; 376 Validate(CheckStatus(CloudPolicyValidatorBase::VALIDATION_BAD_SIGNATURE)); 377 } 378 379 TEST_F(CloudPolicyValidatorTest, NoRotation) { 380 allow_key_rotation_ = false; 381 policy_.UnsetNewSigningKey(); 382 Validate(CheckStatus(CloudPolicyValidatorBase::VALIDATION_OK)); 383 } 384 385 } // namespace 386 387 } // namespace policy 388