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) && !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.
    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.
    308 template<typename PayloadProto>
    309 class 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 
    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