// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef CHROME_BROWSER_POLICY_CLOUD_POLICY_VALIDATOR_H_ #define CHROME_BROWSER_POLICY_CLOUD_POLICY_VALIDATOR_H_ #include #include #include "base/basictypes.h" #include "base/callback.h" #include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" #include "base/time.h" namespace base { class MessageLoopProxy; } namespace google { namespace protobuf { class MessageLite; } } namespace enterprise_management { class ChromeDeviceSettingsProto; class CloudPolicySettings; class PolicyData; class PolicyFetchResponse; } namespace policy { // Helper class that implements the gory details of validating a policy blob. // Since signature checks are expensive, validation can happen on the FILE // thread. The pattern is to create a validator, configure its behavior through // the ValidateXYZ() functions, and then call StartValidation(). Alternatively, // RunValidation() can be used to perform validation on the current thread. class CloudPolicyValidatorBase { public: // Validation result codes. enum Status { // Indicates successful validation. VALIDATION_OK, // Bad signature. VALIDATION_BAD_SIGNATURE, // Policy blob contains error code. VALIDATION_ERROR_CODE_PRESENT, // Policy payload failed to decode. VALIDATION_PAYLOAD_PARSE_ERROR, // Unexpected policy type. VALIDATION_WRONG_POLICY_TYPE, // Time stamp from the future. VALIDATION_BAD_TIMESTAMP, // Token doesn't match. VALIDATION_WRONG_TOKEN, // Username doesn't match. VALIDATION_BAD_USERNAME, // Policy payload protobuf parse error. VALIDATION_POLICY_PARSE_ERROR, }; virtual ~CloudPolicyValidatorBase(); // Validation status which can be read after completion has been signaled. Status status() const { return status_; } bool success() const { return status_ == VALIDATION_OK; } // The policy objects owned by the validator. These are scoped_ptr // references, so ownership can be passed on once validation is complete. scoped_ptr& policy() { return policy_; } scoped_ptr& policy_data() { return policy_data_; } // Instructs the validator to check that the policy timestamp is not before // |not_before| and not after |now| + grace interval. void ValidateTimestamp(base::Time not_before, base::Time now, bool allow_missing_timestamp); // Validates the username in the policy blob matches |expected_user|. void ValidateUsername(const std::string& expected_user); // Validates the policy blob is addressed to |expected_domain|. This uses the // domain part of the username field in the policy for the check. void ValidateDomain(const std::string& expected_domain); // Makes sure the DM token on the policy matches |expected_token|. void ValidateDMToken(const std::string& dm_token); // Validates the policy type. void ValidatePolicyType(const std::string& policy_type); // Validates that the payload can be decoded successfully. void ValidatePayload(); // Verifies that the signature on the policy blob verifies against |key|. If | // |allow_key_rotation| is true and there is a key rotation present in the // policy blob, this checks the signature on the new key against |key| and the // policy blob against the new key. void ValidateSignature(const std::vector& key, bool allow_key_rotation); // Similar to StartSignatureVerification(), this checks the signature on the // policy blob. However, this variant expects a new policy key set in the // policy blob and makes sure the policy is signed using that key. This should // be called at setup time when there is no existing policy key present to // check against. void ValidateInitialKey(); // Convenience helper that configures timestamp and token validation based on // the current policy blob. |policy_data| may be NULL, in which case the // timestamp validation will drop the lower bound and no token validation will // be configured. void ValidateAgainstCurrentPolicy( const enterprise_management::PolicyData* policy_data, bool allow_missing_timestamp); // Immediately performs validation on the current thread. void RunValidation(); protected: // Create a new validator that checks |policy_response|. |payload| is the // message that the policy payload will be parsed to, and it needs to stay // valid for the lifetime of the validator. CloudPolicyValidatorBase( scoped_ptr policy_response, google::protobuf::MessageLite* payload); // Performs validation, called on a background thread. static void PerformValidation( scoped_ptr self, scoped_refptr message_loop, const base::Closure& completion_callback); private: // Internal flags indicating what to check. enum ValidationFlags { VALIDATE_TIMESTAMP = 1 << 0, VALIDATE_USERNAME = 1 << 1, VALIDATE_DOMAIN = 1 << 2, VALIDATE_TOKEN = 1 << 3, VALIDATE_POLICY_TYPE = 1 << 4, VALIDATE_PAYLOAD = 1 << 5, VALIDATE_SIGNATURE = 1 << 6, VALIDATE_INITIAL_KEY = 1 << 7, }; // Reports completion to the |completion_callback_|. static void ReportCompletion(scoped_ptr self, const base::Closure& completion_callback); // Invokes all the checks and reports the result. void RunChecks(); // Helper functions implementing individual checks. Status CheckTimestamp(); Status CheckUsername(); Status CheckDomain(); Status CheckToken(); Status CheckPolicyType(); Status CheckPayload(); Status CheckSignature(); Status CheckInitialKey(); // Verifies the SHA1/RSA |signature| on |data| against |key|. static bool VerifySignature(const std::string& data, const std::string& key, const std::string& signature); Status status_; scoped_ptr policy_; scoped_ptr policy_data_; google::protobuf::MessageLite* payload_; int validation_flags_; int64 timestamp_not_before_; int64 timestamp_not_after_; bool allow_missing_timestamp_; std::string user_; std::string domain_; std::string token_; std::string policy_type_; std::string key_; bool allow_key_rotation_; DISALLOW_COPY_AND_ASSIGN(CloudPolicyValidatorBase); }; // A simple type-parameterized extension of CloudPolicyValidator that // facilitates working with the actual protobuf payload type. template class CloudPolicyValidator : public CloudPolicyValidatorBase { public: typedef base::Callback*)> CompletionCallback; virtual ~CloudPolicyValidator(); // Creates a new validator. static CloudPolicyValidator* Create( scoped_ptr policy_response); scoped_ptr& payload() { return payload_; } // Kicks off asynchronous validation. |completion_callback| is invoked when // done. From this point on, the validator manages its own lifetime - this // allows callers to provide a WeakPtr in the callback without leaking the // validator. void StartValidation(const CompletionCallback& completion_callback); private: CloudPolicyValidator( scoped_ptr policy_response, scoped_ptr payload); scoped_ptr payload_; DISALLOW_COPY_AND_ASSIGN(CloudPolicyValidator); }; typedef CloudPolicyValidator DeviceCloudPolicyValidator; typedef CloudPolicyValidator UserCloudPolicyValidator; } // namespace policy #endif // CHROME_BROWSER_POLICY_CLOUD_POLICY_VALIDATOR_H_