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/time/time.h" 17 #include "chrome/browser/policy/proto/cloud/chrome_extension_policy.pb.h" 18 #include "policy/proto/cloud_policy.pb.h" 19 20 namespace base { 21 class MessageLoopProxy; 22 } 23 24 namespace google { 25 namespace protobuf { 26 class MessageLite; 27 } 28 } 29 30 namespace enterprise_management { 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 // Posts an asynchronous calls to PerformValidation, which will eventually 170 // report its result via |completion_callback|. 171 void PostValidationTask(const base::Closure& completion_callback); 172 173 private: 174 // Internal flags indicating what to check. 175 enum ValidationFlags { 176 VALIDATE_TIMESTAMP = 1 << 0, 177 VALIDATE_USERNAME = 1 << 1, 178 VALIDATE_DOMAIN = 1 << 2, 179 VALIDATE_TOKEN = 1 << 3, 180 VALIDATE_POLICY_TYPE = 1 << 4, 181 VALIDATE_ENTITY_ID = 1 << 5, 182 VALIDATE_PAYLOAD = 1 << 6, 183 VALIDATE_SIGNATURE = 1 << 7, 184 VALIDATE_INITIAL_KEY = 1 << 8, 185 }; 186 187 // Performs validation, called on a background thread. 188 static void PerformValidation( 189 scoped_ptr<CloudPolicyValidatorBase> self, 190 scoped_refptr<base::MessageLoopProxy> message_loop, 191 const base::Closure& completion_callback); 192 193 // Reports completion to the |completion_callback_|. 194 static void ReportCompletion(scoped_ptr<CloudPolicyValidatorBase> self, 195 const base::Closure& completion_callback); 196 197 // Invokes all the checks and reports the result. 198 void RunChecks(); 199 200 // Helper functions implementing individual checks. 201 Status CheckTimestamp(); 202 Status CheckUsername(); 203 Status CheckDomain(); 204 Status CheckToken(); 205 Status CheckPolicyType(); 206 Status CheckEntityId(); 207 Status CheckPayload(); 208 Status CheckSignature(); 209 Status CheckInitialKey(); 210 211 // Verifies the SHA1/RSA |signature| on |data| against |key|. 212 static bool VerifySignature(const std::string& data, 213 const std::string& key, 214 const std::string& signature); 215 216 Status status_; 217 scoped_ptr<enterprise_management::PolicyFetchResponse> policy_; 218 scoped_ptr<enterprise_management::PolicyData> policy_data_; 219 google::protobuf::MessageLite* payload_; 220 221 int validation_flags_; 222 int64 timestamp_not_before_; 223 int64 timestamp_not_after_; 224 ValidateTimestampOption timestamp_option_; 225 ValidateDMTokenOption dm_token_option_; 226 std::string user_; 227 std::string domain_; 228 std::string token_; 229 std::string policy_type_; 230 std::string settings_entity_id_; 231 std::string key_; 232 bool allow_key_rotation_; 233 234 DISALLOW_COPY_AND_ASSIGN(CloudPolicyValidatorBase); 235 }; 236 237 // A simple type-parameterized extension of CloudPolicyValidator that 238 // facilitates working with the actual protobuf payload type. 239 template<typename PayloadProto> 240 class CloudPolicyValidator : public CloudPolicyValidatorBase { 241 public: 242 typedef base::Callback<void(CloudPolicyValidator<PayloadProto>*)> 243 CompletionCallback; 244 245 virtual ~CloudPolicyValidator() {} 246 247 // Creates a new validator. 248 static CloudPolicyValidator<PayloadProto>* Create( 249 scoped_ptr<enterprise_management::PolicyFetchResponse> policy_response) { 250 return new CloudPolicyValidator( 251 policy_response.Pass(), 252 scoped_ptr<PayloadProto>(new PayloadProto())); 253 } 254 255 scoped_ptr<PayloadProto>& payload() { 256 return payload_; 257 } 258 259 // Kicks off asynchronous validation. |completion_callback| is invoked when 260 // done. From this point on, the validator manages its own lifetime - this 261 // allows callers to provide a WeakPtr in the callback without leaking the 262 // validator. 263 void StartValidation(const CompletionCallback& completion_callback) { 264 PostValidationTask(base::Bind(completion_callback, this)); 265 } 266 267 private: 268 CloudPolicyValidator( 269 scoped_ptr<enterprise_management::PolicyFetchResponse> policy_response, 270 scoped_ptr<PayloadProto> payload) 271 : CloudPolicyValidatorBase(policy_response.Pass(), payload.get()), 272 payload_(payload.Pass()) {} 273 274 scoped_ptr<PayloadProto> payload_; 275 276 DISALLOW_COPY_AND_ASSIGN(CloudPolicyValidator); 277 }; 278 279 typedef CloudPolicyValidator<enterprise_management::CloudPolicySettings> 280 UserCloudPolicyValidator; 281 typedef CloudPolicyValidator<enterprise_management::ExternalPolicyData> 282 ComponentCloudPolicyValidator; 283 284 } // namespace policy 285 286 #endif // CHROME_BROWSER_POLICY_CLOUD_CLOUD_POLICY_VALIDATOR_H_ 287