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