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