blob: bb252130c87632dd95719893862a07fe1e3d2869 [file] [log] [blame] [edit]
// 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 <string>
#include <vector>
#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 is happening on the FILE
// thread. The pattern is to create a validator, configure its behavior through
// the ValidateXYZ() functions, and then call StartValidation().
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<enterprise_management::PolicyFetchResponse>& policy() {
return policy_;
}
scoped_ptr<enterprise_management::PolicyData>& 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<uint8>& 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);
// Kicks off validation. From this point on, the validator manages its own
// lifetime. |completion_callback| is invoked when done.
void StartValidation();
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<enterprise_management::PolicyFetchResponse> policy_response,
google::protobuf::MessageLite* payload,
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,
};
// Performs validation, called on a background thread.
static void PerformValidation(
scoped_ptr<CloudPolicyValidatorBase> self,
scoped_refptr<base::MessageLoopProxy> message_loop);
// Reports completion to |self|'s |completion_callback_|.
static void ReportCompletion(scoped_ptr<CloudPolicyValidatorBase> self);
// 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<enterprise_management::PolicyFetchResponse> policy_;
scoped_ptr<enterprise_management::PolicyData> policy_data_;
google::protobuf::MessageLite* payload_;
base::Closure completion_callback_;
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<typename PayloadProto>
class CloudPolicyValidator : public CloudPolicyValidatorBase {
public:
typedef base::Callback<void(CloudPolicyValidator<PayloadProto>*)>
CompletionCallback;
virtual ~CloudPolicyValidator();
// Creates a new validator.
static CloudPolicyValidator<PayloadProto>* Create(
scoped_ptr<enterprise_management::PolicyFetchResponse> policy_response,
const CompletionCallback& completion_callback);
scoped_ptr<PayloadProto>& payload() {
return payload_;
}
private:
CloudPolicyValidator(
scoped_ptr<enterprise_management::PolicyFetchResponse> policy_response,
scoped_ptr<PayloadProto> payload,
const CompletionCallback& completion_callback);
scoped_ptr<PayloadProto> payload_;
DISALLOW_COPY_AND_ASSIGN(CloudPolicyValidator);
};
typedef CloudPolicyValidator<enterprise_management::ChromeDeviceSettingsProto>
DeviceCloudPolicyValidator;
typedef CloudPolicyValidator<enterprise_management::CloudPolicySettings>
UserCloudPolicyValidator;
} // namespace policy
#endif // CHROME_BROWSER_POLICY_CLOUD_POLICY_VALIDATOR_H_