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 #ifndef COMPONENTS_POLICY_CORE_COMMON_CLOUD_CLOUD_POLICY_VALIDATOR_H_ 6 #define COMPONENTS_POLICY_CORE_COMMON_CLOUD_CLOUD_POLICY_VALIDATOR_H_ 7 8 #include <string> 9 #include <vector> 10 11 #include "base/basictypes.h" 12 #include "base/bind.h" 13 #include "base/callback.h" 14 #include "base/memory/ref_counted.h" 15 #include "base/memory/scoped_ptr.h" 16 #include "base/sequenced_task_runner.h" 17 #include "base/time/time.h" 18 #include "components/policy/policy_export.h" 19 #include "policy/proto/cloud_policy.pb.h" 20 21 #if !defined(OS_ANDROID) && !defined(OS_IOS) 22 #include "policy/proto/chrome_extension_policy.pb.h" 23 #endif 24 25 namespace base { 26 class MessageLoopProxy; 27 } 28 29 namespace google { 30 namespace protobuf { 31 class MessageLite; 32 } 33 } 34 35 namespace enterprise_management { 36 class PolicyData; 37 class PolicyFetchResponse; 38 } 39 40 namespace policy { 41 42 // Helper class that implements the gory details of validating a policy blob. 43 // Since signature checks are expensive, validation can happen on a background 44 // thread. The pattern is to create a validator, configure its behavior through 45 // the ValidateXYZ() functions, and then call StartValidation(). Alternatively, 46 // RunValidation() can be used to perform validation on the current thread. 47 class POLICY_EXPORT CloudPolicyValidatorBase { 48 public: 49 // Validation result codes. These values are also used for UMA histograms by 50 // UserCloudPolicyStoreChromeOS and must stay stable - new elements should 51 // be added at the end before VALIDATION_STATUS_SIZE. Also update the 52 // associated enum definition in histograms.xml. 53 enum Status { 54 // Indicates successful validation. 55 VALIDATION_OK, 56 // Bad signature on the initial key. 57 VALIDATION_BAD_INITIAL_SIGNATURE, 58 // Bad signature. 59 VALIDATION_BAD_SIGNATURE, 60 // Policy blob contains error code. 61 VALIDATION_ERROR_CODE_PRESENT, 62 // Policy payload failed to decode. 63 VALIDATION_PAYLOAD_PARSE_ERROR, 64 // Unexpected policy type. 65 VALIDATION_WRONG_POLICY_TYPE, 66 // Unexpected settings entity id. 67 VALIDATION_WRONG_SETTINGS_ENTITY_ID, 68 // Time stamp from the future. 69 VALIDATION_BAD_TIMESTAMP, 70 // Token doesn't match. 71 VALIDATION_WRONG_TOKEN, 72 // Username doesn't match. 73 VALIDATION_BAD_USERNAME, 74 // Policy payload protobuf parse error. 75 VALIDATION_POLICY_PARSE_ERROR, 76 // Policy key signature could not be verified using the hard-coded 77 // verification key. 78 VALIDATION_BAD_KEY_VERIFICATION_SIGNATURE, 79 VALIDATION_STATUS_SIZE // MUST BE LAST 80 }; 81 82 enum ValidateDMTokenOption { 83 // The policy must have a non-empty DMToken. 84 DM_TOKEN_REQUIRED, 85 86 // The policy may have an empty or missing DMToken, if the expected token 87 // is also empty. 88 DM_TOKEN_NOT_REQUIRED, 89 }; 90 91 enum ValidateTimestampOption { 92 // The policy must have a timestamp field and it should be checked against 93 // both the start and end times. 94 TIMESTAMP_REQUIRED, 95 96 // The timestamp should only be compared vs the |not_before| value (this 97 // is appropriate for platforms with unreliable system times, where we want 98 // to ensure that fresh policy is newer than existing policy, but we can't 99 // do any other validation). 100 TIMESTAMP_NOT_BEFORE, 101 102 // No timestamp field is required. 103 TIMESTAMP_NOT_REQUIRED, 104 }; 105 106 virtual ~CloudPolicyValidatorBase(); 107 108 // Validation status which can be read after completion has been signaled. status()109 Status status() const { return status_; } success()110 bool success() const { return status_ == VALIDATION_OK; } 111 112 // The policy objects owned by the validator. These are scoped_ptr 113 // references, so ownership can be passed on once validation is complete. policy()114 scoped_ptr<enterprise_management::PolicyFetchResponse>& policy() { 115 return policy_; 116 } policy_data()117 scoped_ptr<enterprise_management::PolicyData>& policy_data() { 118 return policy_data_; 119 } 120 121 // Instructs the validator to check that the policy timestamp is not before 122 // |not_before| and not after |not_after| + grace interval. If 123 // |timestamp_option| is set to TIMESTAMP_REQUIRED, then the policy will fail 124 // validation if it does not have a timestamp field. 125 void ValidateTimestamp(base::Time not_before, 126 base::Time not_after, 127 ValidateTimestampOption timestamp_option); 128 129 // Validates that the username in the policy blob matches |expected_user|. If 130 // canonicalize is set to true, both values will be canonicalized before 131 // comparison. 132 void ValidateUsername(const std::string& expected_user, bool canonicalize); 133 134 // Validates the policy blob is addressed to |expected_domain|. This uses the 135 // domain part of the username field in the policy for the check. 136 void ValidateDomain(const std::string& expected_domain); 137 138 // Makes sure the DM token on the policy matches |expected_token|. 139 // If |dm_token_option| is DM_TOKEN_REQUIRED, then the policy will fail 140 // validation if it does not have a non-empty request_token field. 141 void ValidateDMToken(const std::string& dm_token, 142 ValidateDMTokenOption dm_token_option); 143 144 // Validates the policy type. 145 void ValidatePolicyType(const std::string& policy_type); 146 147 // Validates the settings_entity_id value. 148 void ValidateSettingsEntityId(const std::string& settings_entity_id); 149 150 // Validates that the payload can be decoded successfully. 151 void ValidatePayload(); 152 153 // Verifies that |cached_key| is valid, by verifying the 154 // |cached_key_signature| using the passed |owning_domain| and 155 // |verification_key|. 156 void ValidateCachedKey(const std::string& cached_key, 157 const std::string& cached_key_signature, 158 const std::string& verification_key, 159 const std::string& owning_domain); 160 161 // Verifies that the signature on the policy blob verifies against |key|. If 162 // |allow_key_rotation| is true and there is a key rotation present in the 163 // policy blob, this checks the signature on the new key against |key| and the 164 // policy blob against the new key. New key is also validated using the passed 165 // |verification_key| and |owning_domain|, and the 166 // |new_public_key_verification_signature| field. 167 void ValidateSignature(const std::string& key, 168 const std::string& verification_key, 169 const std::string& owning_domain, 170 bool allow_key_rotation); 171 172 // Similar to ValidateSignature(), this checks the signature on the 173 // policy blob. However, this variant expects a new policy key set in the 174 // policy blob and makes sure the policy is signed using that key. This should 175 // be called at setup time when there is no existing policy key present to 176 // check against. New key is validated using the passed |verification_key| and 177 // the new_public_key_verification_signature field. 178 void ValidateInitialKey(const std::string& verification_key, 179 const std::string& owning_domain); 180 181 // Convenience helper that configures timestamp and token validation based on 182 // the current policy blob. |policy_data| may be NULL, in which case the 183 // timestamp validation will drop the lower bound. |dm_token_option| 184 // and |timestamp_option| have the same effect as the corresponding 185 // parameters for ValidateTimestamp() and ValidateDMToken(). 186 void ValidateAgainstCurrentPolicy( 187 const enterprise_management::PolicyData* policy_data, 188 ValidateTimestampOption timestamp_option, 189 ValidateDMTokenOption dm_token_option); 190 191 // Immediately performs validation on the current thread. 192 void RunValidation(); 193 194 protected: 195 // Create a new validator that checks |policy_response|. |payload| is the 196 // message that the policy payload will be parsed to, and it needs to stay 197 // valid for the lifetime of the validator. 198 CloudPolicyValidatorBase( 199 scoped_ptr<enterprise_management::PolicyFetchResponse> policy_response, 200 google::protobuf::MessageLite* payload, 201 scoped_refptr<base::SequencedTaskRunner> background_task_runner); 202 203 // Posts an asynchronous calls to PerformValidation, which will eventually 204 // report its result via |completion_callback|. 205 void PostValidationTask(const base::Closure& completion_callback); 206 207 private: 208 // Internal flags indicating what to check. 209 enum ValidationFlags { 210 VALIDATE_TIMESTAMP = 1 << 0, 211 VALIDATE_USERNAME = 1 << 1, 212 VALIDATE_DOMAIN = 1 << 2, 213 VALIDATE_TOKEN = 1 << 3, 214 VALIDATE_POLICY_TYPE = 1 << 4, 215 VALIDATE_ENTITY_ID = 1 << 5, 216 VALIDATE_PAYLOAD = 1 << 6, 217 VALIDATE_SIGNATURE = 1 << 7, 218 VALIDATE_INITIAL_KEY = 1 << 8, 219 VALIDATE_CACHED_KEY = 1 << 9, 220 }; 221 222 enum SignatureType { 223 SHA1, 224 SHA256 225 }; 226 227 // Performs validation, called on a background thread. 228 static void PerformValidation( 229 scoped_ptr<CloudPolicyValidatorBase> self, 230 scoped_refptr<base::MessageLoopProxy> message_loop, 231 const base::Closure& completion_callback); 232 233 // Reports completion to the |completion_callback_|. 234 static void ReportCompletion(scoped_ptr<CloudPolicyValidatorBase> self, 235 const base::Closure& completion_callback); 236 237 // Invokes all the checks and reports the result. 238 void RunChecks(); 239 240 // Helper routine that verifies that the new public key in the policy blob 241 // is properly signed by the |verification_key_|. 242 bool CheckNewPublicKeyVerificationSignature(); 243 244 // Helper routine that performs a verification-key-based signature check, 245 // which includes the domain name associated with this policy. Returns true 246 // if the verification succeeds, or if |signature| is empty. 247 bool CheckVerificationKeySignature(const std::string& key_to_verify, 248 const std::string& server_key, 249 const std::string& signature); 250 251 // Returns the domain name from the policy being validated. Returns an 252 // empty string if the policy does not contain a username field. 253 std::string ExtractDomainFromPolicy(); 254 255 // Sets the key and domain used to verify new public keys, and ensures that 256 // callers don't try to set conflicting values. 257 void set_verification_key_and_domain(const std::string& verification_key, 258 const std::string& owning_domain); 259 260 // Helper functions implementing individual checks. 261 Status CheckTimestamp(); 262 Status CheckUsername(); 263 Status CheckDomain(); 264 Status CheckToken(); 265 Status CheckPolicyType(); 266 Status CheckEntityId(); 267 Status CheckPayload(); 268 Status CheckSignature(); 269 Status CheckInitialKey(); 270 Status CheckCachedKey(); 271 272 // Verifies the SHA1/ or SHA256/RSA |signature| on |data| against |key|. 273 // |signature_type| specifies the type of signature (SHA1 or SHA256). 274 static bool VerifySignature(const std::string& data, 275 const std::string& key, 276 const std::string& signature, 277 SignatureType signature_type); 278 279 Status status_; 280 scoped_ptr<enterprise_management::PolicyFetchResponse> policy_; 281 scoped_ptr<enterprise_management::PolicyData> policy_data_; 282 google::protobuf::MessageLite* payload_; 283 284 int validation_flags_; 285 int64 timestamp_not_before_; 286 int64 timestamp_not_after_; 287 ValidateTimestampOption timestamp_option_; 288 ValidateDMTokenOption dm_token_option_; 289 std::string user_; 290 bool canonicalize_user_; 291 std::string domain_; 292 std::string token_; 293 std::string policy_type_; 294 std::string settings_entity_id_; 295 std::string key_; 296 std::string cached_key_; 297 std::string cached_key_signature_; 298 std::string verification_key_; 299 std::string owning_domain_; 300 bool allow_key_rotation_; 301 scoped_refptr<base::SequencedTaskRunner> background_task_runner_; 302 303 DISALLOW_COPY_AND_ASSIGN(CloudPolicyValidatorBase); 304 }; 305 306 // A simple type-parameterized extension of CloudPolicyValidator that 307 // facilitates working with the actual protobuf payload type. 308 template<typename PayloadProto> 309 class POLICY_EXPORT CloudPolicyValidator : public CloudPolicyValidatorBase { 310 public: 311 typedef base::Callback<void(CloudPolicyValidator<PayloadProto>*)> 312 CompletionCallback; 313 ~CloudPolicyValidator()314 virtual ~CloudPolicyValidator() {} 315 316 // Creates a new validator. 317 // |background_task_runner| is optional; if RunValidation() is used directly 318 // and StartValidation() is not used then it can be NULL. Create(scoped_ptr<enterprise_management::PolicyFetchResponse> policy_response,scoped_refptr<base::SequencedTaskRunner> background_task_runner)319 static CloudPolicyValidator<PayloadProto>* Create( 320 scoped_ptr<enterprise_management::PolicyFetchResponse> policy_response, 321 scoped_refptr<base::SequencedTaskRunner> background_task_runner) { 322 return new CloudPolicyValidator( 323 policy_response.Pass(), 324 scoped_ptr<PayloadProto>(new PayloadProto()), 325 background_task_runner); 326 } 327 payload()328 scoped_ptr<PayloadProto>& payload() { 329 return payload_; 330 } 331 332 // Kicks off asynchronous validation. |completion_callback| is invoked when 333 // done. From this point on, the validator manages its own lifetime - this 334 // allows callers to provide a WeakPtr in the callback without leaking the 335 // validator. StartValidation(const CompletionCallback & completion_callback)336 void StartValidation(const CompletionCallback& completion_callback) { 337 PostValidationTask(base::Bind(completion_callback, this)); 338 } 339 340 private: CloudPolicyValidator(scoped_ptr<enterprise_management::PolicyFetchResponse> policy_response,scoped_ptr<PayloadProto> payload,scoped_refptr<base::SequencedTaskRunner> background_task_runner)341 CloudPolicyValidator( 342 scoped_ptr<enterprise_management::PolicyFetchResponse> policy_response, 343 scoped_ptr<PayloadProto> payload, 344 scoped_refptr<base::SequencedTaskRunner> background_task_runner) 345 : CloudPolicyValidatorBase(policy_response.Pass(), 346 payload.get(), 347 background_task_runner), 348 payload_(payload.Pass()) {} 349 350 scoped_ptr<PayloadProto> payload_; 351 352 DISALLOW_COPY_AND_ASSIGN(CloudPolicyValidator); 353 }; 354 355 typedef CloudPolicyValidator<enterprise_management::CloudPolicySettings> 356 UserCloudPolicyValidator; 357 358 #if !defined(OS_ANDROID) && !defined(OS_IOS) 359 typedef CloudPolicyValidator<enterprise_management::ExternalPolicyData> 360 ComponentCloudPolicyValidator; 361 #endif 362 363 } // namespace policy 364 365 #endif // COMPONENTS_POLICY_CORE_COMMON_CLOUD_CLOUD_POLICY_VALIDATOR_H_ 366