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