• 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) && !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. 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.
status()109   Status status() const { return status_; }
success()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.
policy()114   scoped_ptr<enterprise_management::PolicyFetchResponse>& policy() {
115     return policy_;
116   }
policy_data()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.
308 template<typename PayloadProto>
309 class POLICY_EXPORT CloudPolicyValidator : public CloudPolicyValidatorBase {
310  public:
311   typedef base::Callback<void(CloudPolicyValidator<PayloadProto>*)>
312       CompletionCallback;
313 
~CloudPolicyValidator()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.
Create(scoped_ptr<enterprise_management::PolicyFetchResponse> policy_response,scoped_refptr<base::SequencedTaskRunner> background_task_runner)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 
payload()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.
StartValidation(const CompletionCallback & completion_callback)336   void StartValidation(const CompletionCallback& completion_callback) {
337     PostValidationTask(base::Bind(completion_callback, this));
338   }
339 
340  private:
CloudPolicyValidator(scoped_ptr<enterprise_management::PolicyFetchResponse> policy_response,scoped_ptr<PayloadProto> payload,scoped_refptr<base::SequencedTaskRunner> background_task_runner)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 
355 typedef CloudPolicyValidator<enterprise_management::CloudPolicySettings>
356     UserCloudPolicyValidator;
357 
358 #if !defined(OS_ANDROID) && !defined(OS_IOS)
359 typedef 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