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) 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; 50 // they must stay stable, and the UMA counters must be updated if new elements 51 // are appended at the end. 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 }; 76 77 enum ValidateDMTokenOption { 78 // The policy must have a non-empty DMToken. 79 DM_TOKEN_REQUIRED, 80 81 // The policy may have an empty or missing DMToken, if the expected token 82 // is also empty. 83 DM_TOKEN_NOT_REQUIRED, 84 }; 85 86 enum ValidateTimestampOption { 87 // The policy must have a timestamp field and it should be checked against 88 // both the start and end times. 89 TIMESTAMP_REQUIRED, 90 91 // The timestamp should only be compared vs the |not_before| value (this 92 // is appropriate for platforms with unreliable system times, where we want 93 // to ensure that fresh policy is newer than existing policy, but we can't 94 // do any other validation). 95 TIMESTAMP_NOT_BEFORE, 96 97 // No timestamp field is required. 98 TIMESTAMP_NOT_REQUIRED, 99 }; 100 101 virtual ~CloudPolicyValidatorBase(); 102 103 // Validation status which can be read after completion has been signaled. 104 Status status() const { return status_; } 105 bool success() const { return status_ == VALIDATION_OK; } 106 107 // The policy objects owned by the validator. These are scoped_ptr 108 // references, so ownership can be passed on once validation is complete. 109 scoped_ptr<enterprise_management::PolicyFetchResponse>& policy() { 110 return policy_; 111 } 112 scoped_ptr<enterprise_management::PolicyData>& policy_data() { 113 return policy_data_; 114 } 115 116 // Instructs the validator to check that the policy timestamp is not before 117 // |not_before| and not after |not_after| + grace interval. If 118 // |timestamp_option| is set to TIMESTAMP_REQUIRED, then the policy will fail 119 // validation if it does not have a timestamp field. 120 void ValidateTimestamp(base::Time not_before, 121 base::Time not_after, 122 ValidateTimestampOption timestamp_option); 123 124 // Validates the username in the policy blob matches |expected_user|. 125 void ValidateUsername(const std::string& expected_user); 126 127 // Validates the policy blob is addressed to |expected_domain|. This uses the 128 // domain part of the username field in the policy for the check. 129 void ValidateDomain(const std::string& expected_domain); 130 131 // Makes sure the DM token on the policy matches |expected_token|. 132 // If |dm_token_option| is DM_TOKEN_REQUIRED, then the policy will fail 133 // validation if it does not have a non-empty request_token field. 134 void ValidateDMToken(const std::string& dm_token, 135 ValidateDMTokenOption dm_token_option); 136 137 // Validates the policy type. 138 void ValidatePolicyType(const std::string& policy_type); 139 140 // Validates the settings_entity_id value. 141 void ValidateSettingsEntityId(const std::string& settings_entity_id); 142 143 // Validates that the payload can be decoded successfully. 144 void ValidatePayload(); 145 146 // Verifies that the signature on the policy blob verifies against |key|. If | 147 // |allow_key_rotation| is true and there is a key rotation present in the 148 // policy blob, this checks the signature on the new key against |key| and the 149 // policy blob against the new key. 150 void ValidateSignature(const std::vector<uint8>& key, 151 bool allow_key_rotation); 152 153 // Similar to StartSignatureVerification(), this checks the signature on the 154 // policy blob. However, this variant expects a new policy key set in the 155 // policy blob and makes sure the policy is signed using that key. This should 156 // be called at setup time when there is no existing policy key present to 157 // check against. 158 void ValidateInitialKey(); 159 160 // Convenience helper that configures timestamp and token validation based on 161 // the current policy blob. |policy_data| may be NULL, in which case the 162 // timestamp validation will drop the lower bound. |dm_token_option| 163 // and |timestamp_option| have the same effect as the corresponding 164 // parameters for ValidateTimestamp() and ValidateDMToken(). 165 void ValidateAgainstCurrentPolicy( 166 const enterprise_management::PolicyData* policy_data, 167 ValidateTimestampOption timestamp_option, 168 ValidateDMTokenOption dm_token_option); 169 170 // Immediately performs validation on the current thread. 171 void RunValidation(); 172 173 protected: 174 // Create a new validator that checks |policy_response|. |payload| is the 175 // message that the policy payload will be parsed to, and it needs to stay 176 // valid for the lifetime of the validator. 177 CloudPolicyValidatorBase( 178 scoped_ptr<enterprise_management::PolicyFetchResponse> policy_response, 179 google::protobuf::MessageLite* payload, 180 scoped_refptr<base::SequencedTaskRunner> background_task_runner); 181 182 // Posts an asynchronous calls to PerformValidation, which will eventually 183 // report its result via |completion_callback|. 184 void PostValidationTask(const base::Closure& completion_callback); 185 186 private: 187 // Internal flags indicating what to check. 188 enum ValidationFlags { 189 VALIDATE_TIMESTAMP = 1 << 0, 190 VALIDATE_USERNAME = 1 << 1, 191 VALIDATE_DOMAIN = 1 << 2, 192 VALIDATE_TOKEN = 1 << 3, 193 VALIDATE_POLICY_TYPE = 1 << 4, 194 VALIDATE_ENTITY_ID = 1 << 5, 195 VALIDATE_PAYLOAD = 1 << 6, 196 VALIDATE_SIGNATURE = 1 << 7, 197 VALIDATE_INITIAL_KEY = 1 << 8, 198 }; 199 200 // Performs validation, called on a background thread. 201 static void PerformValidation( 202 scoped_ptr<CloudPolicyValidatorBase> self, 203 scoped_refptr<base::MessageLoopProxy> message_loop, 204 const base::Closure& completion_callback); 205 206 // Reports completion to the |completion_callback_|. 207 static void ReportCompletion(scoped_ptr<CloudPolicyValidatorBase> self, 208 const base::Closure& completion_callback); 209 210 // Invokes all the checks and reports the result. 211 void RunChecks(); 212 213 // Helper functions implementing individual checks. 214 Status CheckTimestamp(); 215 Status CheckUsername(); 216 Status CheckDomain(); 217 Status CheckToken(); 218 Status CheckPolicyType(); 219 Status CheckEntityId(); 220 Status CheckPayload(); 221 Status CheckSignature(); 222 Status CheckInitialKey(); 223 224 // Verifies the SHA1/RSA |signature| on |data| against |key|. 225 static bool VerifySignature(const std::string& data, 226 const std::string& key, 227 const std::string& signature); 228 229 Status status_; 230 scoped_ptr<enterprise_management::PolicyFetchResponse> policy_; 231 scoped_ptr<enterprise_management::PolicyData> policy_data_; 232 google::protobuf::MessageLite* payload_; 233 234 int validation_flags_; 235 int64 timestamp_not_before_; 236 int64 timestamp_not_after_; 237 ValidateTimestampOption timestamp_option_; 238 ValidateDMTokenOption dm_token_option_; 239 std::string user_; 240 std::string domain_; 241 std::string token_; 242 std::string policy_type_; 243 std::string settings_entity_id_; 244 std::string key_; 245 bool allow_key_rotation_; 246 scoped_refptr<base::SequencedTaskRunner> background_task_runner_; 247 248 DISALLOW_COPY_AND_ASSIGN(CloudPolicyValidatorBase); 249 }; 250 251 // A simple type-parameterized extension of CloudPolicyValidator that 252 // facilitates working with the actual protobuf payload type. 253 template<typename PayloadProto> 254 class POLICY_EXPORT CloudPolicyValidator : public CloudPolicyValidatorBase { 255 public: 256 typedef base::Callback<void(CloudPolicyValidator<PayloadProto>*)> 257 CompletionCallback; 258 259 virtual ~CloudPolicyValidator() {} 260 261 // Creates a new validator. 262 // |background_task_runner| is optional; if RunValidation() is used directly 263 // and StartValidation() is not used then it can be NULL. 264 static CloudPolicyValidator<PayloadProto>* Create( 265 scoped_ptr<enterprise_management::PolicyFetchResponse> policy_response, 266 scoped_refptr<base::SequencedTaskRunner> background_task_runner) { 267 return new CloudPolicyValidator( 268 policy_response.Pass(), 269 scoped_ptr<PayloadProto>(new PayloadProto()), 270 background_task_runner); 271 } 272 273 scoped_ptr<PayloadProto>& payload() { 274 return payload_; 275 } 276 277 // Kicks off asynchronous validation. |completion_callback| is invoked when 278 // done. From this point on, the validator manages its own lifetime - this 279 // allows callers to provide a WeakPtr in the callback without leaking the 280 // validator. 281 void StartValidation(const CompletionCallback& completion_callback) { 282 PostValidationTask(base::Bind(completion_callback, this)); 283 } 284 285 private: 286 CloudPolicyValidator( 287 scoped_ptr<enterprise_management::PolicyFetchResponse> policy_response, 288 scoped_ptr<PayloadProto> payload, 289 scoped_refptr<base::SequencedTaskRunner> background_task_runner) 290 : CloudPolicyValidatorBase(policy_response.Pass(), 291 payload.get(), 292 background_task_runner), 293 payload_(payload.Pass()) {} 294 295 scoped_ptr<PayloadProto> payload_; 296 297 DISALLOW_COPY_AND_ASSIGN(CloudPolicyValidator); 298 }; 299 300 typedef CloudPolicyValidator<enterprise_management::CloudPolicySettings> 301 UserCloudPolicyValidator; 302 303 #if !defined(OS_ANDROID) 304 typedef CloudPolicyValidator<enterprise_management::ExternalPolicyData> 305 ComponentCloudPolicyValidator; 306 #endif 307 308 } // namespace policy 309 310 #endif // COMPONENTS_POLICY_CORE_COMMON_CLOUD_CLOUD_POLICY_VALIDATOR_H_ 311