• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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)
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;
50   // they must stay stable, and the UMA counters must be updated if new elements
51   // are appended at the end.
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   };
76 
77   enum ValidateDMTokenOption {
78     // The policy must have a non-empty DMToken.
79     DM_TOKEN_REQUIRED,
80 
81     // The policy may have an empty or missing DMToken, if the expected token
82     // is also empty.
83     DM_TOKEN_NOT_REQUIRED,
84   };
85 
86   enum ValidateTimestampOption {
87     // The policy must have a timestamp field and it should be checked against
88     // both the start and end times.
89     TIMESTAMP_REQUIRED,
90 
91     // The timestamp should only be compared vs the |not_before| value (this
92     // is appropriate for platforms with unreliable system times, where we want
93     // to ensure that fresh policy is newer than existing policy, but we can't
94     // do any other validation).
95     TIMESTAMP_NOT_BEFORE,
96 
97     // No timestamp field is required.
98     TIMESTAMP_NOT_REQUIRED,
99   };
100 
101   virtual ~CloudPolicyValidatorBase();
102 
103   // Validation status which can be read after completion has been signaled.
status()104   Status status() const { return status_; }
success()105   bool success() const { return status_ == VALIDATION_OK; }
106 
107   // The policy objects owned by the validator. These are scoped_ptr
108   // references, so ownership can be passed on once validation is complete.
policy()109   scoped_ptr<enterprise_management::PolicyFetchResponse>& policy() {
110     return policy_;
111   }
policy_data()112   scoped_ptr<enterprise_management::PolicyData>& policy_data() {
113     return policy_data_;
114   }
115 
116   // Instructs the validator to check that the policy timestamp is not before
117   // |not_before| and not after |not_after| + grace interval. If
118   // |timestamp_option| is set to TIMESTAMP_REQUIRED, then the policy will fail
119   // validation if it does not have a timestamp field.
120   void ValidateTimestamp(base::Time not_before,
121                          base::Time not_after,
122                          ValidateTimestampOption timestamp_option);
123 
124   // Validates the username in the policy blob matches |expected_user|.
125   void ValidateUsername(const std::string& expected_user);
126 
127   // Validates the policy blob is addressed to |expected_domain|. This uses the
128   // domain part of the username field in the policy for the check.
129   void ValidateDomain(const std::string& expected_domain);
130 
131   // Makes sure the DM token on the policy matches |expected_token|.
132   // If |dm_token_option| is DM_TOKEN_REQUIRED, then the policy will fail
133   // validation if it does not have a non-empty request_token field.
134   void ValidateDMToken(const std::string& dm_token,
135                        ValidateDMTokenOption dm_token_option);
136 
137   // Validates the policy type.
138   void ValidatePolicyType(const std::string& policy_type);
139 
140   // Validates the settings_entity_id value.
141   void ValidateSettingsEntityId(const std::string& settings_entity_id);
142 
143   // Validates that the payload can be decoded successfully.
144   void ValidatePayload();
145 
146   // Verifies that the signature on the policy blob verifies against |key|. If |
147   // |allow_key_rotation| is true and there is a key rotation present in the
148   // policy blob, this checks the signature on the new key against |key| and the
149   // policy blob against the new key.
150   void ValidateSignature(const std::vector<uint8>& key,
151                          bool allow_key_rotation);
152 
153   // Similar to StartSignatureVerification(), this checks the signature on the
154   // policy blob. However, this variant expects a new policy key set in the
155   // policy blob and makes sure the policy is signed using that key. This should
156   // be called at setup time when there is no existing policy key present to
157   // check against.
158   void ValidateInitialKey();
159 
160   // Convenience helper that configures timestamp and token validation based on
161   // the current policy blob. |policy_data| may be NULL, in which case the
162   // timestamp validation will drop the lower bound. |dm_token_option|
163   // and |timestamp_option| have the same effect as the corresponding
164   // parameters for ValidateTimestamp() and ValidateDMToken().
165   void ValidateAgainstCurrentPolicy(
166       const enterprise_management::PolicyData* policy_data,
167       ValidateTimestampOption timestamp_option,
168       ValidateDMTokenOption dm_token_option);
169 
170   // Immediately performs validation on the current thread.
171   void RunValidation();
172 
173  protected:
174   // Create a new validator that checks |policy_response|. |payload| is the
175   // message that the policy payload will be parsed to, and it needs to stay
176   // valid for the lifetime of the validator.
177   CloudPolicyValidatorBase(
178       scoped_ptr<enterprise_management::PolicyFetchResponse> policy_response,
179       google::protobuf::MessageLite* payload,
180       scoped_refptr<base::SequencedTaskRunner> background_task_runner);
181 
182   // Posts an asynchronous calls to PerformValidation, which will eventually
183   // report its result via |completion_callback|.
184   void PostValidationTask(const base::Closure& completion_callback);
185 
186  private:
187   // Internal flags indicating what to check.
188   enum ValidationFlags {
189     VALIDATE_TIMESTAMP   = 1 << 0,
190     VALIDATE_USERNAME    = 1 << 1,
191     VALIDATE_DOMAIN      = 1 << 2,
192     VALIDATE_TOKEN       = 1 << 3,
193     VALIDATE_POLICY_TYPE = 1 << 4,
194     VALIDATE_ENTITY_ID   = 1 << 5,
195     VALIDATE_PAYLOAD     = 1 << 6,
196     VALIDATE_SIGNATURE   = 1 << 7,
197     VALIDATE_INITIAL_KEY = 1 << 8,
198   };
199 
200   // Performs validation, called on a background thread.
201   static void PerformValidation(
202       scoped_ptr<CloudPolicyValidatorBase> self,
203       scoped_refptr<base::MessageLoopProxy> message_loop,
204       const base::Closure& completion_callback);
205 
206   // Reports completion to the |completion_callback_|.
207   static void ReportCompletion(scoped_ptr<CloudPolicyValidatorBase> self,
208                                const base::Closure& completion_callback);
209 
210   // Invokes all the checks and reports the result.
211   void RunChecks();
212 
213   // Helper functions implementing individual checks.
214   Status CheckTimestamp();
215   Status CheckUsername();
216   Status CheckDomain();
217   Status CheckToken();
218   Status CheckPolicyType();
219   Status CheckEntityId();
220   Status CheckPayload();
221   Status CheckSignature();
222   Status CheckInitialKey();
223 
224   // Verifies the SHA1/RSA |signature| on |data| against |key|.
225   static bool VerifySignature(const std::string& data,
226                               const std::string& key,
227                               const std::string& signature);
228 
229   Status status_;
230   scoped_ptr<enterprise_management::PolicyFetchResponse> policy_;
231   scoped_ptr<enterprise_management::PolicyData> policy_data_;
232   google::protobuf::MessageLite* payload_;
233 
234   int validation_flags_;
235   int64 timestamp_not_before_;
236   int64 timestamp_not_after_;
237   ValidateTimestampOption timestamp_option_;
238   ValidateDMTokenOption dm_token_option_;
239   std::string user_;
240   std::string domain_;
241   std::string token_;
242   std::string policy_type_;
243   std::string settings_entity_id_;
244   std::string key_;
245   bool allow_key_rotation_;
246   scoped_refptr<base::SequencedTaskRunner> background_task_runner_;
247 
248   DISALLOW_COPY_AND_ASSIGN(CloudPolicyValidatorBase);
249 };
250 
251 // A simple type-parameterized extension of CloudPolicyValidator that
252 // facilitates working with the actual protobuf payload type.
253 template<typename PayloadProto>
254 class POLICY_EXPORT CloudPolicyValidator : public CloudPolicyValidatorBase {
255  public:
256   typedef base::Callback<void(CloudPolicyValidator<PayloadProto>*)>
257       CompletionCallback;
258 
~CloudPolicyValidator()259   virtual ~CloudPolicyValidator() {}
260 
261   // Creates a new validator.
262   // |background_task_runner| is optional; if RunValidation() is used directly
263   // and StartValidation() is not used then it can be NULL.
Create(scoped_ptr<enterprise_management::PolicyFetchResponse> policy_response,scoped_refptr<base::SequencedTaskRunner> background_task_runner)264   static CloudPolicyValidator<PayloadProto>* Create(
265       scoped_ptr<enterprise_management::PolicyFetchResponse> policy_response,
266       scoped_refptr<base::SequencedTaskRunner> background_task_runner) {
267     return new CloudPolicyValidator(
268         policy_response.Pass(),
269         scoped_ptr<PayloadProto>(new PayloadProto()),
270         background_task_runner);
271   }
272 
payload()273   scoped_ptr<PayloadProto>& payload() {
274     return payload_;
275   }
276 
277   // Kicks off asynchronous validation. |completion_callback| is invoked when
278   // done. From this point on, the validator manages its own lifetime - this
279   // allows callers to provide a WeakPtr in the callback without leaking the
280   // validator.
StartValidation(const CompletionCallback & completion_callback)281   void StartValidation(const CompletionCallback& completion_callback) {
282     PostValidationTask(base::Bind(completion_callback, this));
283   }
284 
285  private:
CloudPolicyValidator(scoped_ptr<enterprise_management::PolicyFetchResponse> policy_response,scoped_ptr<PayloadProto> payload,scoped_refptr<base::SequencedTaskRunner> background_task_runner)286   CloudPolicyValidator(
287       scoped_ptr<enterprise_management::PolicyFetchResponse> policy_response,
288       scoped_ptr<PayloadProto> payload,
289       scoped_refptr<base::SequencedTaskRunner> background_task_runner)
290       : CloudPolicyValidatorBase(policy_response.Pass(),
291                                  payload.get(),
292                                  background_task_runner),
293         payload_(payload.Pass()) {}
294 
295   scoped_ptr<PayloadProto> payload_;
296 
297   DISALLOW_COPY_AND_ASSIGN(CloudPolicyValidator);
298 };
299 
300 typedef CloudPolicyValidator<enterprise_management::CloudPolicySettings>
301     UserCloudPolicyValidator;
302 
303 #if !defined(OS_ANDROID)
304 typedef CloudPolicyValidator<enterprise_management::ExternalPolicyData>
305     ComponentCloudPolicyValidator;
306 #endif
307 
308 }  // namespace policy
309 
310 #endif  // COMPONENTS_POLICY_CORE_COMMON_CLOUD_CLOUD_POLICY_VALIDATOR_H_
311