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 CHROME_BROWSER_POLICY_CLOUD_CLOUD_POLICY_VALIDATOR_H_
      6 #define CHROME_BROWSER_POLICY_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/time/time.h"
     17 #include "chrome/browser/policy/proto/cloud/chrome_extension_policy.pb.h"
     18 #include "policy/proto/cloud_policy.pb.h"
     19 
     20 namespace base {
     21 class MessageLoopProxy;
     22 }
     23 
     24 namespace google {
     25 namespace protobuf {
     26 class MessageLite;
     27 }
     28 }
     29 
     30 namespace enterprise_management {
     31 class PolicyData;
     32 class PolicyFetchResponse;
     33 }
     34 
     35 namespace policy {
     36 
     37 // Helper class that implements the gory details of validating a policy blob.
     38 // Since signature checks are expensive, validation can happen on the FILE
     39 // thread. The pattern is to create a validator, configure its behavior through
     40 // the ValidateXYZ() functions, and then call StartValidation(). Alternatively,
     41 // RunValidation() can be used to perform validation on the current thread.
     42 class CloudPolicyValidatorBase {
     43  public:
     44   // Validation result codes. These values are also used for UMA histograms;
     45   // they must stay stable, and the UMA counters must be updated if new elements
     46   // are appended at the end.
     47   enum Status {
     48     // Indicates successful validation.
     49     VALIDATION_OK,
     50     // Bad signature on the initial key.
     51     VALIDATION_BAD_INITIAL_SIGNATURE,
     52     // Bad signature.
     53     VALIDATION_BAD_SIGNATURE,
     54     // Policy blob contains error code.
     55     VALIDATION_ERROR_CODE_PRESENT,
     56     // Policy payload failed to decode.
     57     VALIDATION_PAYLOAD_PARSE_ERROR,
     58     // Unexpected policy type.
     59     VALIDATION_WRONG_POLICY_TYPE,
     60     // Unexpected settings entity id.
     61     VALIDATION_WRONG_SETTINGS_ENTITY_ID,
     62     // Time stamp from the future.
     63     VALIDATION_BAD_TIMESTAMP,
     64     // Token doesn't match.
     65     VALIDATION_WRONG_TOKEN,
     66     // Username doesn't match.
     67     VALIDATION_BAD_USERNAME,
     68     // Policy payload protobuf parse error.
     69     VALIDATION_POLICY_PARSE_ERROR,
     70   };
     71 
     72   enum ValidateDMTokenOption {
     73     // The policy must have a non-empty DMToken.
     74     DM_TOKEN_REQUIRED,
     75 
     76     // The policy may have an empty or missing DMToken, if the expected token
     77     // is also empty.
     78     DM_TOKEN_NOT_REQUIRED,
     79   };
     80 
     81   enum ValidateTimestampOption {
     82     // The policy must have a timestamp field.
     83     TIMESTAMP_REQUIRED,
     84 
     85     // No timestamp field is required.
     86     TIMESTAMP_NOT_REQUIRED,
     87   };
     88 
     89   virtual ~CloudPolicyValidatorBase();
     90 
     91   // Validation status which can be read after completion has been signaled.
     92   Status status() const { return status_; }
     93   bool success() const { return status_ == VALIDATION_OK; }
     94 
     95   // The policy objects owned by the validator. These are scoped_ptr
     96   // references, so ownership can be passed on once validation is complete.
     97   scoped_ptr<enterprise_management::PolicyFetchResponse>& policy() {
     98     return policy_;
     99   }
    100   scoped_ptr<enterprise_management::PolicyData>& policy_data() {
    101     return policy_data_;
    102   }
    103 
    104   // Instructs the validator to check that the policy timestamp is not before
    105   // |not_before| and not after |now| + grace interval. If
    106   // |timestamp_option| is set to TIMESTAMP_REQUIRED, then the policy will fail
    107   // validation if it does not have a timestamp field.
    108   void ValidateTimestamp(base::Time not_before,
    109                          base::Time now,
    110                          ValidateTimestampOption timestamp_option);
    111 
    112   // Validates the username in the policy blob matches |expected_user|.
    113   void ValidateUsername(const std::string& expected_user);
    114 
    115   // Validates the policy blob is addressed to |expected_domain|. This uses the
    116   // domain part of the username field in the policy for the check.
    117   void ValidateDomain(const std::string& expected_domain);
    118 
    119   // Makes sure the DM token on the policy matches |expected_token|.
    120   // If |dm_token_option| is DM_TOKEN_REQUIRED, then the policy will fail
    121   // validation if it does not have a non-empty request_token field.
    122   void ValidateDMToken(const std::string& dm_token,
    123                        ValidateDMTokenOption dm_token_option);
    124 
    125   // Validates the policy type.
    126   void ValidatePolicyType(const std::string& policy_type);
    127 
    128   // Validates the settings_entity_id value.
    129   void ValidateSettingsEntityId(const std::string& settings_entity_id);
    130 
    131   // Validates that the payload can be decoded successfully.
    132   void ValidatePayload();
    133 
    134   // Verifies that the signature on the policy blob verifies against |key|. If |
    135   // |allow_key_rotation| is true and there is a key rotation present in the
    136   // policy blob, this checks the signature on the new key against |key| and the
    137   // policy blob against the new key.
    138   void ValidateSignature(const std::vector<uint8>& key,
    139                          bool allow_key_rotation);
    140 
    141   // Similar to StartSignatureVerification(), this checks the signature on the
    142   // policy blob. However, this variant expects a new policy key set in the
    143   // policy blob and makes sure the policy is signed using that key. This should
    144   // be called at setup time when there is no existing policy key present to
    145   // check against.
    146   void ValidateInitialKey();
    147 
    148   // Convenience helper that configures timestamp and token validation based on
    149   // the current policy blob. |policy_data| may be NULL, in which case the
    150   // timestamp validation will drop the lower bound. |dm_token_option|
    151   // and |timestamp_option| have the same effect as the corresponding
    152   // parameters for ValidateTimestamp() and ValidateDMToken().
    153   void ValidateAgainstCurrentPolicy(
    154       const enterprise_management::PolicyData* policy_data,
    155       ValidateTimestampOption timestamp_option,
    156       ValidateDMTokenOption dm_token_option);
    157 
    158   // Immediately performs validation on the current thread.
    159   void RunValidation();
    160 
    161  protected:
    162   // Create a new validator that checks |policy_response|. |payload| is the
    163   // message that the policy payload will be parsed to, and it needs to stay
    164   // valid for the lifetime of the validator.
    165   CloudPolicyValidatorBase(
    166       scoped_ptr<enterprise_management::PolicyFetchResponse> policy_response,
    167       google::protobuf::MessageLite* payload);
    168 
    169   // Posts an asynchronous calls to PerformValidation, which will eventually
    170   // report its result via |completion_callback|.
    171   void PostValidationTask(const base::Closure& completion_callback);
    172 
    173  private:
    174   // Internal flags indicating what to check.
    175   enum ValidationFlags {
    176     VALIDATE_TIMESTAMP   = 1 << 0,
    177     VALIDATE_USERNAME    = 1 << 1,
    178     VALIDATE_DOMAIN      = 1 << 2,
    179     VALIDATE_TOKEN       = 1 << 3,
    180     VALIDATE_POLICY_TYPE = 1 << 4,
    181     VALIDATE_ENTITY_ID   = 1 << 5,
    182     VALIDATE_PAYLOAD     = 1 << 6,
    183     VALIDATE_SIGNATURE   = 1 << 7,
    184     VALIDATE_INITIAL_KEY = 1 << 8,
    185   };
    186 
    187   // Performs validation, called on a background thread.
    188   static void PerformValidation(
    189       scoped_ptr<CloudPolicyValidatorBase> self,
    190       scoped_refptr<base::MessageLoopProxy> message_loop,
    191       const base::Closure& completion_callback);
    192 
    193   // Reports completion to the |completion_callback_|.
    194   static void ReportCompletion(scoped_ptr<CloudPolicyValidatorBase> self,
    195                                const base::Closure& completion_callback);
    196 
    197   // Invokes all the checks and reports the result.
    198   void RunChecks();
    199 
    200   // Helper functions implementing individual checks.
    201   Status CheckTimestamp();
    202   Status CheckUsername();
    203   Status CheckDomain();
    204   Status CheckToken();
    205   Status CheckPolicyType();
    206   Status CheckEntityId();
    207   Status CheckPayload();
    208   Status CheckSignature();
    209   Status CheckInitialKey();
    210 
    211   // Verifies the SHA1/RSA |signature| on |data| against |key|.
    212   static bool VerifySignature(const std::string& data,
    213                               const std::string& key,
    214                               const std::string& signature);
    215 
    216   Status status_;
    217   scoped_ptr<enterprise_management::PolicyFetchResponse> policy_;
    218   scoped_ptr<enterprise_management::PolicyData> policy_data_;
    219   google::protobuf::MessageLite* payload_;
    220 
    221   int validation_flags_;
    222   int64 timestamp_not_before_;
    223   int64 timestamp_not_after_;
    224   ValidateTimestampOption timestamp_option_;
    225   ValidateDMTokenOption dm_token_option_;
    226   std::string user_;
    227   std::string domain_;
    228   std::string token_;
    229   std::string policy_type_;
    230   std::string settings_entity_id_;
    231   std::string key_;
    232   bool allow_key_rotation_;
    233 
    234   DISALLOW_COPY_AND_ASSIGN(CloudPolicyValidatorBase);
    235 };
    236 
    237 // A simple type-parameterized extension of CloudPolicyValidator that
    238 // facilitates working with the actual protobuf payload type.
    239 template<typename PayloadProto>
    240 class CloudPolicyValidator : public CloudPolicyValidatorBase {
    241  public:
    242   typedef base::Callback<void(CloudPolicyValidator<PayloadProto>*)>
    243       CompletionCallback;
    244 
    245   virtual ~CloudPolicyValidator() {}
    246 
    247   // Creates a new validator.
    248   static CloudPolicyValidator<PayloadProto>* Create(
    249       scoped_ptr<enterprise_management::PolicyFetchResponse> policy_response) {
    250     return new CloudPolicyValidator(
    251         policy_response.Pass(),
    252         scoped_ptr<PayloadProto>(new PayloadProto()));
    253   }
    254 
    255   scoped_ptr<PayloadProto>& payload() {
    256     return payload_;
    257   }
    258 
    259   // Kicks off asynchronous validation. |completion_callback| is invoked when
    260   // done. From this point on, the validator manages its own lifetime - this
    261   // allows callers to provide a WeakPtr in the callback without leaking the
    262   // validator.
    263   void StartValidation(const CompletionCallback& completion_callback) {
    264     PostValidationTask(base::Bind(completion_callback, this));
    265   }
    266 
    267  private:
    268   CloudPolicyValidator(
    269       scoped_ptr<enterprise_management::PolicyFetchResponse> policy_response,
    270       scoped_ptr<PayloadProto> payload)
    271       : CloudPolicyValidatorBase(policy_response.Pass(), payload.get()),
    272         payload_(payload.Pass()) {}
    273 
    274   scoped_ptr<PayloadProto> payload_;
    275 
    276   DISALLOW_COPY_AND_ASSIGN(CloudPolicyValidator);
    277 };
    278 
    279 typedef CloudPolicyValidator<enterprise_management::CloudPolicySettings>
    280     UserCloudPolicyValidator;
    281 typedef CloudPolicyValidator<enterprise_management::ExternalPolicyData>
    282     ComponentCloudPolicyValidator;
    283 
    284 }  // namespace policy
    285 
    286 #endif  // CHROME_BROWSER_POLICY_CLOUD_CLOUD_POLICY_VALIDATOR_H_
    287