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
25namespace base {
26class MessageLoopProxy;
27}
28
29namespace google {
30namespace protobuf {
31class MessageLite;
32}
33}
34
35namespace enterprise_management {
36class PolicyData;
37class PolicyFetchResponse;
38}
39
40namespace 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.
47class 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. Also update the
52  // associated enum definition in histograms.xml.
53  enum Status {
54    // Indicates successful validation.
55    VALIDATION_OK,
56    // Bad signature on the initial key.
57    VALIDATION_BAD_INITIAL_SIGNATURE,
58    // Bad signature.
59    VALIDATION_BAD_SIGNATURE,
60    // Policy blob contains error code.
61    VALIDATION_ERROR_CODE_PRESENT,
62    // Policy payload failed to decode.
63    VALIDATION_PAYLOAD_PARSE_ERROR,
64    // Unexpected policy type.
65    VALIDATION_WRONG_POLICY_TYPE,
66    // Unexpected settings entity id.
67    VALIDATION_WRONG_SETTINGS_ENTITY_ID,
68    // Time stamp from the future.
69    VALIDATION_BAD_TIMESTAMP,
70    // Token doesn't match.
71    VALIDATION_WRONG_TOKEN,
72    // Username doesn't match.
73    VALIDATION_BAD_USERNAME,
74    // Policy payload protobuf parse error.
75    VALIDATION_POLICY_PARSE_ERROR,
76    // Policy key signature could not be verified using the hard-coded
77    // verification key.
78    VALIDATION_BAD_KEY_VERIFICATION_SIGNATURE,
79    VALIDATION_STATUS_SIZE  // MUST BE LAST
80  };
81
82  enum ValidateDMTokenOption {
83    // The policy must have a non-empty DMToken.
84    DM_TOKEN_REQUIRED,
85
86    // The policy may have an empty or missing DMToken, if the expected token
87    // is also empty.
88    DM_TOKEN_NOT_REQUIRED,
89  };
90
91  enum ValidateTimestampOption {
92    // The policy must have a timestamp field and it should be checked against
93    // both the start and end times.
94    TIMESTAMP_REQUIRED,
95
96    // The timestamp should only be compared vs the |not_before| value (this
97    // is appropriate for platforms with unreliable system times, where we want
98    // to ensure that fresh policy is newer than existing policy, but we can't
99    // do any other validation).
100    TIMESTAMP_NOT_BEFORE,
101
102    // No timestamp field is required.
103    TIMESTAMP_NOT_REQUIRED,
104  };
105
106  virtual ~CloudPolicyValidatorBase();
107
108  // Validation status which can be read after completion has been signaled.
109  Status status() const { return status_; }
110  bool success() const { return status_ == VALIDATION_OK; }
111
112  // The policy objects owned by the validator. These are scoped_ptr
113  // references, so ownership can be passed on once validation is complete.
114  scoped_ptr<enterprise_management::PolicyFetchResponse>& policy() {
115    return policy_;
116  }
117  scoped_ptr<enterprise_management::PolicyData>& policy_data() {
118    return policy_data_;
119  }
120
121  // Instructs the validator to check that the policy timestamp is not before
122  // |not_before| and not after |not_after| + grace interval. If
123  // |timestamp_option| is set to TIMESTAMP_REQUIRED, then the policy will fail
124  // validation if it does not have a timestamp field.
125  void ValidateTimestamp(base::Time not_before,
126                         base::Time not_after,
127                         ValidateTimestampOption timestamp_option);
128
129  // Validates that the username in the policy blob matches |expected_user|. If
130  // canonicalize is set to true, both values will be canonicalized before
131  // comparison.
132  void ValidateUsername(const std::string& expected_user, bool canonicalize);
133
134  // Validates the policy blob is addressed to |expected_domain|. This uses the
135  // domain part of the username field in the policy for the check.
136  void ValidateDomain(const std::string& expected_domain);
137
138  // Makes sure the DM token on the policy matches |expected_token|.
139  // If |dm_token_option| is DM_TOKEN_REQUIRED, then the policy will fail
140  // validation if it does not have a non-empty request_token field.
141  void ValidateDMToken(const std::string& dm_token,
142                       ValidateDMTokenOption dm_token_option);
143
144  // Validates the policy type.
145  void ValidatePolicyType(const std::string& policy_type);
146
147  // Validates the settings_entity_id value.
148  void ValidateSettingsEntityId(const std::string& settings_entity_id);
149
150  // Validates that the payload can be decoded successfully.
151  void ValidatePayload();
152
153  // Verifies that |cached_key| is valid, by verifying the
154  // |cached_key_signature| using the passed |owning_domain| and
155  // |verification_key|.
156  void ValidateCachedKey(const std::string& cached_key,
157                         const std::string& cached_key_signature,
158                         const std::string& verification_key,
159                         const std::string& owning_domain);
160
161  // Verifies that the signature on the policy blob verifies against |key|. If
162  // |allow_key_rotation| is true and there is a key rotation present in the
163  // policy blob, this checks the signature on the new key against |key| and the
164  // policy blob against the new key. New key is also validated using the passed
165  // |verification_key| and |owning_domain|, and the
166  // |new_public_key_verification_signature| field.
167  void ValidateSignature(const std::string& key,
168                         const std::string& verification_key,
169                         const std::string& owning_domain,
170                         bool allow_key_rotation);
171
172  // Similar to ValidateSignature(), this checks the signature on the
173  // policy blob. However, this variant expects a new policy key set in the
174  // policy blob and makes sure the policy is signed using that key. This should
175  // be called at setup time when there is no existing policy key present to
176  // check against. New key is validated using the passed |verification_key| and
177  // the new_public_key_verification_signature field.
178  void ValidateInitialKey(const std::string& verification_key,
179                          const std::string& owning_domain);
180
181  // Convenience helper that configures timestamp and token validation based on
182  // the current policy blob. |policy_data| may be NULL, in which case the
183  // timestamp validation will drop the lower bound. |dm_token_option|
184  // and |timestamp_option| have the same effect as the corresponding
185  // parameters for ValidateTimestamp() and ValidateDMToken().
186  void ValidateAgainstCurrentPolicy(
187      const enterprise_management::PolicyData* policy_data,
188      ValidateTimestampOption timestamp_option,
189      ValidateDMTokenOption dm_token_option);
190
191  // Immediately performs validation on the current thread.
192  void RunValidation();
193
194 protected:
195  // Create a new validator that checks |policy_response|. |payload| is the
196  // message that the policy payload will be parsed to, and it needs to stay
197  // valid for the lifetime of the validator.
198  CloudPolicyValidatorBase(
199      scoped_ptr<enterprise_management::PolicyFetchResponse> policy_response,
200      google::protobuf::MessageLite* payload,
201      scoped_refptr<base::SequencedTaskRunner> background_task_runner);
202
203  // Posts an asynchronous calls to PerformValidation, which will eventually
204  // report its result via |completion_callback|.
205  void PostValidationTask(const base::Closure& completion_callback);
206
207 private:
208  // Internal flags indicating what to check.
209  enum ValidationFlags {
210    VALIDATE_TIMESTAMP   = 1 << 0,
211    VALIDATE_USERNAME    = 1 << 1,
212    VALIDATE_DOMAIN      = 1 << 2,
213    VALIDATE_TOKEN       = 1 << 3,
214    VALIDATE_POLICY_TYPE = 1 << 4,
215    VALIDATE_ENTITY_ID   = 1 << 5,
216    VALIDATE_PAYLOAD     = 1 << 6,
217    VALIDATE_SIGNATURE   = 1 << 7,
218    VALIDATE_INITIAL_KEY = 1 << 8,
219    VALIDATE_CACHED_KEY  = 1 << 9,
220  };
221
222  enum SignatureType {
223    SHA1,
224    SHA256
225  };
226
227  // Performs validation, called on a background thread.
228  static void PerformValidation(
229      scoped_ptr<CloudPolicyValidatorBase> self,
230      scoped_refptr<base::MessageLoopProxy> message_loop,
231      const base::Closure& completion_callback);
232
233  // Reports completion to the |completion_callback_|.
234  static void ReportCompletion(scoped_ptr<CloudPolicyValidatorBase> self,
235                               const base::Closure& completion_callback);
236
237  // Invokes all the checks and reports the result.
238  void RunChecks();
239
240  // Helper routine that verifies that the new public key in the policy blob
241  // is properly signed by the |verification_key_|.
242  bool CheckNewPublicKeyVerificationSignature();
243
244  // Helper routine that performs a verification-key-based signature check,
245  // which includes the domain name associated with this policy. Returns true
246  // if the verification succeeds, or if |signature| is empty.
247  bool CheckVerificationKeySignature(const std::string& key_to_verify,
248                                     const std::string& server_key,
249                                     const std::string& signature);
250
251  // Returns the domain name from the policy being validated. Returns an
252  // empty string if the policy does not contain a username field.
253  std::string ExtractDomainFromPolicy();
254
255  // Sets the key and domain used to verify new public keys, and ensures that
256  // callers don't try to set conflicting values.
257  void set_verification_key_and_domain(const std::string& verification_key,
258                                       const std::string& owning_domain);
259
260  // Helper functions implementing individual checks.
261  Status CheckTimestamp();
262  Status CheckUsername();
263  Status CheckDomain();
264  Status CheckToken();
265  Status CheckPolicyType();
266  Status CheckEntityId();
267  Status CheckPayload();
268  Status CheckSignature();
269  Status CheckInitialKey();
270  Status CheckCachedKey();
271
272  // Verifies the SHA1/ or SHA256/RSA |signature| on |data| against |key|.
273  // |signature_type| specifies the type of signature (SHA1 or SHA256).
274  static bool VerifySignature(const std::string& data,
275                              const std::string& key,
276                              const std::string& signature,
277                              SignatureType signature_type);
278
279  Status status_;
280  scoped_ptr<enterprise_management::PolicyFetchResponse> policy_;
281  scoped_ptr<enterprise_management::PolicyData> policy_data_;
282  google::protobuf::MessageLite* payload_;
283
284  int validation_flags_;
285  int64 timestamp_not_before_;
286  int64 timestamp_not_after_;
287  ValidateTimestampOption timestamp_option_;
288  ValidateDMTokenOption dm_token_option_;
289  std::string user_;
290  bool canonicalize_user_;
291  std::string domain_;
292  std::string token_;
293  std::string policy_type_;
294  std::string settings_entity_id_;
295  std::string key_;
296  std::string cached_key_;
297  std::string cached_key_signature_;
298  std::string verification_key_;
299  std::string owning_domain_;
300  bool allow_key_rotation_;
301  scoped_refptr<base::SequencedTaskRunner> background_task_runner_;
302
303  DISALLOW_COPY_AND_ASSIGN(CloudPolicyValidatorBase);
304};
305
306// A simple type-parameterized extension of CloudPolicyValidator that
307// facilitates working with the actual protobuf payload type.
308template<typename PayloadProto>
309class POLICY_EXPORT CloudPolicyValidator : public CloudPolicyValidatorBase {
310 public:
311  typedef base::Callback<void(CloudPolicyValidator<PayloadProto>*)>
312      CompletionCallback;
313
314  virtual ~CloudPolicyValidator() {}
315
316  // Creates a new validator.
317  // |background_task_runner| is optional; if RunValidation() is used directly
318  // and StartValidation() is not used then it can be NULL.
319  static CloudPolicyValidator<PayloadProto>* Create(
320      scoped_ptr<enterprise_management::PolicyFetchResponse> policy_response,
321      scoped_refptr<base::SequencedTaskRunner> background_task_runner) {
322    return new CloudPolicyValidator(
323        policy_response.Pass(),
324        scoped_ptr<PayloadProto>(new PayloadProto()),
325        background_task_runner);
326  }
327
328  scoped_ptr<PayloadProto>& payload() {
329    return payload_;
330  }
331
332  // Kicks off asynchronous validation. |completion_callback| is invoked when
333  // done. From this point on, the validator manages its own lifetime - this
334  // allows callers to provide a WeakPtr in the callback without leaking the
335  // validator.
336  void StartValidation(const CompletionCallback& completion_callback) {
337    PostValidationTask(base::Bind(completion_callback, this));
338  }
339
340 private:
341  CloudPolicyValidator(
342      scoped_ptr<enterprise_management::PolicyFetchResponse> policy_response,
343      scoped_ptr<PayloadProto> payload,
344      scoped_refptr<base::SequencedTaskRunner> background_task_runner)
345      : CloudPolicyValidatorBase(policy_response.Pass(),
346                                 payload.get(),
347                                 background_task_runner),
348        payload_(payload.Pass()) {}
349
350  scoped_ptr<PayloadProto> payload_;
351
352  DISALLOW_COPY_AND_ASSIGN(CloudPolicyValidator);
353};
354
355typedef CloudPolicyValidator<enterprise_management::CloudPolicySettings>
356    UserCloudPolicyValidator;
357
358#if !defined(OS_ANDROID) && !defined(OS_IOS)
359typedef CloudPolicyValidator<enterprise_management::ExternalPolicyData>
360    ComponentCloudPolicyValidator;
361#endif
362
363}  // namespace policy
364
365#endif  // COMPONENTS_POLICY_CORE_COMMON_CLOUD_CLOUD_POLICY_VALIDATOR_H_
366