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.
5 #ifndef COMPONENTS_POLICY_CORE_COMMON_CLOUD_CLOUD_POLICY_VALIDATOR_H_
6 #define COMPONENTS_POLICY_CORE_COMMON_CLOUD_CLOUD_POLICY_VALIDATOR_H_
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"
21 #if !defined(OS_ANDROID) && !defined(OS_IOS)
22 #include "policy/proto/chrome_extension_policy.pb.h"
26 class MessageLoopProxy;
35 namespace enterprise_management {
37 class PolicyFetchResponse;
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 {
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.
53 // Indicates successful validation.
55 // Bad signature on the initial key.
56 VALIDATION_BAD_INITIAL_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
77 VALIDATION_BAD_KEY_VERIFICATION_SIGNATURE,
78 VALIDATION_STATUS_SIZE // MUST BE LAST
81 enum ValidateDMTokenOption {
82 // The policy must have a non-empty DMToken.
85 // The policy may have an empty or missing DMToken, if the expected token
87 DM_TOKEN_NOT_REQUIRED,
90 enum ValidateTimestampOption {
91 // The policy must have a timestamp field and it should be checked against
92 // both the start and end times.
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).
101 // No timestamp field is required.
102 TIMESTAMP_NOT_REQUIRED,
105 virtual ~CloudPolicyValidatorBase();
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; }
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() {
116 scoped_ptr<enterprise_management::PolicyData>& policy_data() {
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);
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
131 void ValidateUsername(const std::string& expected_user, bool canonicalize);
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);
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);
143 // Validates the policy type.
144 void ValidatePolicyType(const std::string& policy_type);
146 // Validates the settings_entity_id value.
147 void ValidateSettingsEntityId(const std::string& settings_entity_id);
149 // Validates that the payload can be decoded successfully.
150 void ValidatePayload();
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);
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);
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);
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);
190 // Immediately performs validation on the current thread.
191 void RunValidation();
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);
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);
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,
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);
232 // Reports completion to the |completion_callback_|.
233 static void ReportCompletion(scoped_ptr<CloudPolicyValidatorBase> self,
234 const base::Closure& completion_callback);
236 // Invokes all the checks and reports the result.
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();
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);
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();
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);
259 // Helper functions implementing individual checks.
260 Status CheckTimestamp();
261 Status CheckUsername();
262 Status CheckDomain();
264 Status CheckPolicyType();
265 Status CheckEntityId();
266 Status CheckPayload();
267 Status CheckSignature();
268 Status CheckInitialKey();
269 Status CheckCachedKey();
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);
279 scoped_ptr<enterprise_management::PolicyFetchResponse> policy_;
280 scoped_ptr<enterprise_management::PolicyData> policy_data_;
281 google::protobuf::MessageLite* payload_;
283 int validation_flags_;
284 int64 timestamp_not_before_;
285 int64 timestamp_not_after_;
286 ValidateTimestampOption timestamp_option_;
287 ValidateDMTokenOption dm_token_option_;
289 bool canonicalize_user_;
292 std::string policy_type_;
293 std::string settings_entity_id_;
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_;
302 DISALLOW_COPY_AND_ASSIGN(CloudPolicyValidatorBase);
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 {
310 typedef base::Callback<void(CloudPolicyValidator<PayloadProto>*)>
313 virtual ~CloudPolicyValidator() {}
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);
327 scoped_ptr<PayloadProto>& payload() {
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
335 void StartValidation(const CompletionCallback& completion_callback) {
336 PostValidationTask(base::Bind(completion_callback, this));
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(),
346 background_task_runner),
347 payload_(payload.Pass()) {}
349 scoped_ptr<PayloadProto> payload_;
351 DISALLOW_COPY_AND_ASSIGN(CloudPolicyValidator);
354 typedef CloudPolicyValidator<enterprise_management::CloudPolicySettings>
355 UserCloudPolicyValidator;
357 #if !defined(OS_ANDROID) && !defined(OS_IOS)
358 typedef CloudPolicyValidator<enterprise_management::ExternalPolicyData>
359 ComponentCloudPolicyValidator;
362 } // namespace policy
364 #endif // COMPONENTS_POLICY_CORE_COMMON_CLOUD_CLOUD_POLICY_VALIDATOR_H_