Index: components/policy/core/common/cloud/cloud_policy_validator.cc |
diff --git a/components/policy/core/common/cloud/cloud_policy_validator.cc b/components/policy/core/common/cloud/cloud_policy_validator.cc |
index 5bbc6bc7c99f468ecc7423f7ab058b1b068c9623..f85561dc675a38ea16ae1b681f7bbfc51dfced4d 100644 |
--- a/components/policy/core/common/cloud/cloud_policy_validator.cc |
+++ b/components/policy/core/common/cloud/cloud_policy_validator.cc |
@@ -6,6 +6,7 @@ |
#include "base/bind_helpers.h" |
#include "base/message_loop/message_loop.h" |
+#include "base/metrics/histogram.h" |
#include "base/sequenced_task_runner.h" |
#include "base/stl_util.h" |
#include "components/policy/core/common/cloud/cloud_policy_constants.h" |
@@ -28,6 +29,23 @@ const uint8 kSignatureAlgorithm[] = { |
0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00 |
}; |
+const char kMetricPolicyKeyVerification[] = "Enterprise.PolicyKeyVerification"; |
+ |
+enum MetricPolicyKeyVerification { |
+ // UMA metric recorded when the client has no verification key. |
+ METRIC_POLICY_KEY_VERIFICATION_KEY_MISSING, |
+ // Recorded when the policy being verified has no key signature (e.g. policy |
+ // fetched before the server supported the verification key). |
+ METRIC_POLICY_KEY_VERIFICATION_SIGNATURE_MISSING, |
+ // Recorded when the key signature did not match the expected value (in |
+ // theory, this should only happen after key rotation or if the policy cached |
+ // on disk has been modified). |
+ METRIC_POLICY_KEY_VERIFICATION_FAILED, |
+ // Recorded when key verification succeeded. |
+ METRIC_POLICY_KEY_VERIFICATION_SUCCEEDED, |
+ METRIC_POLICY_KEY_VERIFICATION_SIZE // Must be the last. |
+}; |
+ |
} // namespace |
CloudPolicyValidatorBase::~CloudPolicyValidatorBase() {} |
@@ -83,16 +101,22 @@ void CloudPolicyValidatorBase::ValidatePayload() { |
validation_flags_ |= VALIDATE_PAYLOAD; |
} |
-void CloudPolicyValidatorBase::ValidateSignature(const std::vector<uint8>& key, |
- bool allow_key_rotation) { |
+void CloudPolicyValidatorBase::ValidateSignature( |
+ const std::string& key, |
+ const std::string& verification_key, |
+ const std::string& key_signature, |
+ bool allow_key_rotation) { |
validation_flags_ |= VALIDATE_SIGNATURE; |
- key_ = std::string(reinterpret_cast<const char*>(vector_as_array(&key)), |
- key.size()); |
+ set_verification_key(verification_key); |
+ key_ = key; |
+ key_signature_ = key_signature; |
allow_key_rotation_ = allow_key_rotation; |
} |
-void CloudPolicyValidatorBase::ValidateInitialKey() { |
+void CloudPolicyValidatorBase::ValidateInitialKey( |
+ const std::string& verification_key) { |
validation_flags_ |= VALIDATE_INITIAL_KEY; |
+ set_verification_key(verification_key); |
} |
void CloudPolicyValidatorBase::ValidateAgainstCurrentPolicy( |
@@ -210,6 +234,65 @@ void CloudPolicyValidatorBase::RunChecks() { |
} |
} |
+// Verifies the |new_public_key_verification_signature| for the |new_public_key| |
+// in the policy blob. |
+bool CloudPolicyValidatorBase::CheckNewPublicKeyVerificationSignature() { |
+ // If there's no local verification key, then just return true (no |
+ // validation possible). |
+ if (verification_key_.empty()) { |
+ UMA_HISTOGRAM_ENUMERATION(kMetricPolicyKeyVerification, |
+ METRIC_POLICY_KEY_VERIFICATION_KEY_MISSING, |
+ METRIC_POLICY_KEY_VERIFICATION_SIZE); |
+ return true; |
+ } |
+ |
+ if (!policy_->has_new_public_key_verification_signature()) { |
+ // Policy does not contain a verification signature, so log an error. |
+ LOG(ERROR) << "Policy is missing public_key_verification_signature"; |
+ UMA_HISTOGRAM_ENUMERATION(kMetricPolicyKeyVerification, |
+ METRIC_POLICY_KEY_VERIFICATION_SIGNATURE_MISSING, |
+ METRIC_POLICY_KEY_VERIFICATION_SIZE); |
+ // TODO(atwilson): Return an error on failed signature verification once |
+ // our test servers and unittests are returning policy with a verification |
+ // signature (http://crbug.com/275291). |
+ return true; |
+ } |
+ |
+ if (!CheckVerificationKeySignature( |
+ policy_->new_public_key(), |
+ verification_key_, |
+ policy_->new_public_key_verification_signature())) { |
+ LOG(ERROR) << "Signature verification failed"; |
+ UMA_HISTOGRAM_ENUMERATION(kMetricPolicyKeyVerification, |
+ METRIC_POLICY_KEY_VERIFICATION_FAILED, |
+ METRIC_POLICY_KEY_VERIFICATION_SIZE); |
+ // TODO(atwilson): Update this code to include the domain name in the |
+ // signature, and return an error once the server starts returning this. |
+ return true; |
+ } |
+ // Signature verification succeeded - return success to the caller. |
+ UMA_HISTOGRAM_ENUMERATION(kMetricPolicyKeyVerification, |
+ METRIC_POLICY_KEY_VERIFICATION_SUCCEEDED, |
+ METRIC_POLICY_KEY_VERIFICATION_SIZE); |
+ return true; |
+} |
+ |
+bool CloudPolicyValidatorBase::CheckVerificationKeySignature( |
+ const std::string& key, |
+ const std::string& verification_key, |
+ const std::string& signature) { |
+ // TODO(atwilson): Update this routine to include the domain name in the |
+ // signed data. |
+ return VerifySignature(key, verification_key, signature); |
+} |
+ |
+void CloudPolicyValidatorBase::set_verification_key( |
+ const std::string& verification_key) { |
+ // Make sure we aren't overwriting the verification key with a different key. |
+ DCHECK(verification_key_.empty() || verification_key_ == verification_key); |
+ verification_key_ = verification_key; |
+} |
+ |
CloudPolicyValidatorBase::Status CloudPolicyValidatorBase::CheckSignature() { |
const std::string* signature_key = &key_; |
if (policy_->has_new_public_key() && allow_key_rotation_) { |
@@ -217,9 +300,14 @@ CloudPolicyValidatorBase::Status CloudPolicyValidatorBase::CheckSignature() { |
if (!policy_->has_new_public_key_signature() || |
!VerifySignature(policy_->new_public_key(), key_, |
policy_->new_public_key_signature())) { |
- LOG(ERROR) << "New public key signature verification failed"; |
+ LOG(ERROR) << "New public key rotation signature verification failed"; |
return VALIDATION_BAD_SIGNATURE; |
} |
+ |
+ if (!CheckNewPublicKeyVerificationSignature()) { |
+ LOG(ERROR) << "New public key root verification failed"; |
+ return VALIDATION_BAD_KEY_VERIFICATION_SIGNATURE; |
+ } |
} |
if (!policy_->has_policy_data_signature() || |
@@ -229,6 +317,16 @@ CloudPolicyValidatorBase::Status CloudPolicyValidatorBase::CheckSignature() { |
return VALIDATION_BAD_SIGNATURE; |
} |
+ // If a key verification signature is available, then verify the base signing |
+ // key as well. |
+ if (!key_signature_.empty() && |
+ !CheckVerificationKeySignature(key_, verification_key_, key_signature_)) { |
Mattias Nissler (ping if slow)
2014/01/31 21:00:35
Wouldn't we fail here for the case where the verif
Andrew T Wilson (Slow)
2014/02/02 11:31:58
When we do key rotation, we'll need to add code on
|
+ LOG(ERROR) << "Verification key signature verification failed"; |
+ // TODO(atwilson): Update to return an error once the server is properly |
+ // generating a verification signature (http://crbug.com/275291). |
+ // return VALIDATION_BAD_KEY_VERIFICATION_SIGNATURE; |
+ } |
+ |
return VALIDATION_OK; |
} |
@@ -241,6 +339,10 @@ CloudPolicyValidatorBase::Status CloudPolicyValidatorBase::CheckInitialKey() { |
return VALIDATION_BAD_INITIAL_SIGNATURE; |
} |
+ if (!CheckNewPublicKeyVerificationSignature()) { |
+ LOG(ERROR) << "Initial policy root signature validation failed"; |
+ return VALIDATION_BAD_KEY_VERIFICATION_SIGNATURE; |
+ } |
return VALIDATION_OK; |
} |