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