Home | History | Annotate | Download | only in cloud
      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.
    104   Status status() const { return status_; }
    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.
    109   scoped_ptr<enterprise_management::PolicyFetchResponse>& policy() {
    110     return policy_;
    111   }
    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 
    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.
    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 
    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.
    281   void StartValidation(const CompletionCallback& completion_callback) {
    282     PostValidationTask(base::Bind(completion_callback, this));
    283   }
    284 
    285  private:
    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