9eb781c7c13c5a08e1adb0cfda64d59612602661
[platform/framework/web/crosswalk.git] / src / components / policy / core / common / cloud / cloud_policy_validator.h
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) && !defined(OS_IOS)
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 by
50   // UserCloudPolicyStoreChromeOS and must stay stable - new elements should
51   // be added at the end before VALIDATION_STATUS_SIZE.
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     // Policy key signature could not be verified using the hard-coded
76     // verification key.
77     VALIDATION_BAD_KEY_VERIFICATION_SIGNATURE,
78     VALIDATION_STATUS_SIZE  // MUST BE LAST
79   };
80
81   enum ValidateDMTokenOption {
82     // The policy must have a non-empty DMToken.
83     DM_TOKEN_REQUIRED,
84
85     // The policy may have an empty or missing DMToken, if the expected token
86     // is also empty.
87     DM_TOKEN_NOT_REQUIRED,
88   };
89
90   enum ValidateTimestampOption {
91     // The policy must have a timestamp field and it should be checked against
92     // both the start and end times.
93     TIMESTAMP_REQUIRED,
94
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).
99     TIMESTAMP_NOT_BEFORE,
100
101     // No timestamp field is required.
102     TIMESTAMP_NOT_REQUIRED,
103   };
104
105   virtual ~CloudPolicyValidatorBase();
106
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; }
110
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() {
114     return policy_;
115   }
116   scoped_ptr<enterprise_management::PolicyData>& policy_data() {
117     return policy_data_;
118   }
119
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);
127
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
130   // comparison.
131   void ValidateUsername(const std::string& expected_user, bool canonicalize);
132
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);
136
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);
142
143   // Validates the policy type.
144   void ValidatePolicyType(const std::string& policy_type);
145
146   // Validates the settings_entity_id value.
147   void ValidateSettingsEntityId(const std::string& settings_entity_id);
148
149   // Validates that the payload can be decoded successfully.
150   void ValidatePayload();
151
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);
159
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);
170
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);
179
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);
189
190   // Immediately performs validation on the current thread.
191   void RunValidation();
192
193  protected:
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);
201
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);
205
206  private:
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,
219   };
220
221   enum SignatureType {
222     SHA1,
223     SHA256
224   };
225
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);
231
232   // Reports completion to the |completion_callback_|.
233   static void ReportCompletion(scoped_ptr<CloudPolicyValidatorBase> self,
234                                const base::Closure& completion_callback);
235
236   // Invokes all the checks and reports the result.
237   void RunChecks();
238
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();
242
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);
249
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();
253
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);
258
259   // Helper functions implementing individual checks.
260   Status CheckTimestamp();
261   Status CheckUsername();
262   Status CheckDomain();
263   Status CheckToken();
264   Status CheckPolicyType();
265   Status CheckEntityId();
266   Status CheckPayload();
267   Status CheckSignature();
268   Status CheckInitialKey();
269   Status CheckCachedKey();
270
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);
277
278   Status status_;
279   scoped_ptr<enterprise_management::PolicyFetchResponse> policy_;
280   scoped_ptr<enterprise_management::PolicyData> policy_data_;
281   google::protobuf::MessageLite* payload_;
282
283   int validation_flags_;
284   int64 timestamp_not_before_;
285   int64 timestamp_not_after_;
286   ValidateTimestampOption timestamp_option_;
287   ValidateDMTokenOption dm_token_option_;
288   std::string user_;
289   bool canonicalize_user_;
290   std::string domain_;
291   std::string token_;
292   std::string policy_type_;
293   std::string settings_entity_id_;
294   std::string key_;
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_;
301
302   DISALLOW_COPY_AND_ASSIGN(CloudPolicyValidatorBase);
303 };
304
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 {
309  public:
310   typedef base::Callback<void(CloudPolicyValidator<PayloadProto>*)>
311       CompletionCallback;
312
313   virtual ~CloudPolicyValidator() {}
314
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);
325   }
326
327   scoped_ptr<PayloadProto>& payload() {
328     return payload_;
329   }
330
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
334   // validator.
335   void StartValidation(const CompletionCallback& completion_callback) {
336     PostValidationTask(base::Bind(completion_callback, this));
337   }
338
339  private:
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(),
345                                  payload.get(),
346                                  background_task_runner),
347         payload_(payload.Pass()) {}
348
349   scoped_ptr<PayloadProto> payload_;
350
351   DISALLOW_COPY_AND_ASSIGN(CloudPolicyValidator);
352 };
353
354 typedef CloudPolicyValidator<enterprise_management::CloudPolicySettings>
355     UserCloudPolicyValidator;
356
357 #if !defined(OS_ANDROID) && !defined(OS_IOS)
358 typedef CloudPolicyValidator<enterprise_management::ExternalPolicyData>
359     ComponentCloudPolicyValidator;
360 #endif
361
362 }  // namespace policy
363
364 #endif  // COMPONENTS_POLICY_CORE_COMMON_CLOUD_CLOUD_POLICY_VALIDATOR_H_