Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(29)

Side by Side Diff: components/policy/core/common/cloud/cloud_policy_validator.cc

Issue 116273002: Added support for signed policy blobs on desktop. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fix for ios. Created 6 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "components/policy/core/common/cloud/cloud_policy_validator.h" 5 #include "components/policy/core/common/cloud/cloud_policy_validator.h"
6 6
7 #include "base/bind_helpers.h" 7 #include "base/bind_helpers.h"
8 #include "base/message_loop/message_loop.h" 8 #include "base/message_loop/message_loop.h"
9 #include "base/metrics/histogram.h"
9 #include "base/sequenced_task_runner.h" 10 #include "base/sequenced_task_runner.h"
10 #include "base/stl_util.h" 11 #include "base/stl_util.h"
11 #include "components/policy/core/common/cloud/cloud_policy_constants.h" 12 #include "components/policy/core/common/cloud/cloud_policy_constants.h"
12 #include "crypto/signature_verifier.h" 13 #include "crypto/signature_verifier.h"
13 #include "google_apis/gaia/gaia_auth_util.h" 14 #include "google_apis/gaia/gaia_auth_util.h"
14 #include "policy/proto/device_management_backend.pb.h" 15 #include "policy/proto/device_management_backend.pb.h"
15 16
16 namespace em = enterprise_management; 17 namespace em = enterprise_management;
17 18
18 namespace policy { 19 namespace policy {
19 20
20 namespace { 21 namespace {
21 22
22 // Grace interval for policy timestamp checks, in seconds. 23 // Grace interval for policy timestamp checks, in seconds.
23 const int kTimestampGraceIntervalSeconds = 60; 24 const int kTimestampGraceIntervalSeconds = 60;
24 25
25 // DER-encoded ASN.1 object identifier for the SHA1-RSA signature algorithm. 26 // DER-encoded ASN.1 object identifier for the SHA1-RSA signature algorithm.
26 const uint8 kSignatureAlgorithm[] = { 27 const uint8 kSignatureAlgorithm[] = {
27 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 28 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
28 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00 29 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00
29 }; 30 };
30 31
32 const char kMetricPolicyKeyVerification[] = "Enterprise.PolicyKeyVerification";
33
34 enum MetricPolicyKeyVerification {
35 // UMA metric recorded when the client has no verification key.
36 METRIC_POLICY_KEY_VERIFICATION_KEY_MISSING,
37 // Recorded when the policy being verified has no key signature (e.g. policy
38 // fetched before the server supported the verification key).
39 METRIC_POLICY_KEY_VERIFICATION_SIGNATURE_MISSING,
40 // Recorded when the key signature did not match the expected value (in
41 // theory, this should only happen after key rotation or if the policy cached
42 // on disk has been modified).
43 METRIC_POLICY_KEY_VERIFICATION_FAILED,
44 // Recorded when key verification succeeded.
45 METRIC_POLICY_KEY_VERIFICATION_SUCCEEDED,
46 METRIC_POLICY_KEY_VERIFICATION_SIZE // Must be the last.
47 };
48
31 } // namespace 49 } // namespace
32 50
33 CloudPolicyValidatorBase::~CloudPolicyValidatorBase() {} 51 CloudPolicyValidatorBase::~CloudPolicyValidatorBase() {}
34 52
35 void CloudPolicyValidatorBase::ValidateTimestamp( 53 void CloudPolicyValidatorBase::ValidateTimestamp(
36 base::Time not_before, 54 base::Time not_before,
37 base::Time now, 55 base::Time now,
38 ValidateTimestampOption timestamp_option) { 56 ValidateTimestampOption timestamp_option) {
39 // Timestamp should be from the past. We allow for a 1-minute grace interval 57 // Timestamp should be from the past. We allow for a 1-minute grace interval
40 // to cover clock drift. 58 // to cover clock drift.
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
76 void CloudPolicyValidatorBase::ValidateSettingsEntityId( 94 void CloudPolicyValidatorBase::ValidateSettingsEntityId(
77 const std::string& settings_entity_id) { 95 const std::string& settings_entity_id) {
78 validation_flags_ |= VALIDATE_ENTITY_ID; 96 validation_flags_ |= VALIDATE_ENTITY_ID;
79 settings_entity_id_ = settings_entity_id; 97 settings_entity_id_ = settings_entity_id;
80 } 98 }
81 99
82 void CloudPolicyValidatorBase::ValidatePayload() { 100 void CloudPolicyValidatorBase::ValidatePayload() {
83 validation_flags_ |= VALIDATE_PAYLOAD; 101 validation_flags_ |= VALIDATE_PAYLOAD;
84 } 102 }
85 103
86 void CloudPolicyValidatorBase::ValidateSignature(const std::vector<uint8>& key, 104 void CloudPolicyValidatorBase::ValidateSignature(
87 bool allow_key_rotation) { 105 const std::string& key,
106 const std::string& verification_key,
107 const std::string& key_signature,
108 bool allow_key_rotation) {
88 validation_flags_ |= VALIDATE_SIGNATURE; 109 validation_flags_ |= VALIDATE_SIGNATURE;
89 key_ = std::string(reinterpret_cast<const char*>(vector_as_array(&key)), 110 set_verification_key(verification_key);
90 key.size()); 111 key_ = key;
112 key_signature_ = key_signature;
91 allow_key_rotation_ = allow_key_rotation; 113 allow_key_rotation_ = allow_key_rotation;
92 } 114 }
93 115
94 void CloudPolicyValidatorBase::ValidateInitialKey() { 116 void CloudPolicyValidatorBase::ValidateInitialKey(
117 const std::string& verification_key) {
95 validation_flags_ |= VALIDATE_INITIAL_KEY; 118 validation_flags_ |= VALIDATE_INITIAL_KEY;
119 set_verification_key(verification_key);
96 } 120 }
97 121
98 void CloudPolicyValidatorBase::ValidateAgainstCurrentPolicy( 122 void CloudPolicyValidatorBase::ValidateAgainstCurrentPolicy(
99 const em::PolicyData* policy_data, 123 const em::PolicyData* policy_data,
100 ValidateTimestampOption timestamp_option, 124 ValidateTimestampOption timestamp_option,
101 ValidateDMTokenOption dm_token_option) { 125 ValidateDMTokenOption dm_token_option) {
102 base::Time last_policy_timestamp; 126 base::Time last_policy_timestamp;
103 std::string expected_dm_token; 127 std::string expected_dm_token;
104 if (policy_data) { 128 if (policy_data) {
105 last_policy_timestamp = 129 last_policy_timestamp =
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after
203 227
204 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kCheckFunctions); ++i) { 228 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kCheckFunctions); ++i) {
205 if (validation_flags_ & kCheckFunctions[i].flag) { 229 if (validation_flags_ & kCheckFunctions[i].flag) {
206 status_ = (this->*(kCheckFunctions[i].checkFunction))(); 230 status_ = (this->*(kCheckFunctions[i].checkFunction))();
207 if (status_ != VALIDATION_OK) 231 if (status_ != VALIDATION_OK)
208 break; 232 break;
209 } 233 }
210 } 234 }
211 } 235 }
212 236
237 // Verifies the |new_public_key_verification_signature| for the |new_public_key|
238 // in the policy blob.
239 bool CloudPolicyValidatorBase::CheckNewPublicKeyVerificationSignature() {
240 // If there's no local verification key, then just return true (no
241 // validation possible).
242 if (verification_key_.empty()) {
243 UMA_HISTOGRAM_ENUMERATION(kMetricPolicyKeyVerification,
244 METRIC_POLICY_KEY_VERIFICATION_KEY_MISSING,
245 METRIC_POLICY_KEY_VERIFICATION_SIZE);
246 return true;
247 }
248
249 if (!policy_->has_new_public_key_verification_signature()) {
250 // Policy does not contain a verification signature, so log an error.
251 LOG(ERROR) << "Policy is missing public_key_verification_signature";
252 UMA_HISTOGRAM_ENUMERATION(kMetricPolicyKeyVerification,
253 METRIC_POLICY_KEY_VERIFICATION_SIGNATURE_MISSING,
254 METRIC_POLICY_KEY_VERIFICATION_SIZE);
255 // TODO(atwilson): Return an error on failed signature verification once
256 // our test servers and unittests are returning policy with a verification
257 // signature (http://crbug.com/275291).
258 return true;
259 }
260
261 if (!CheckVerificationKeySignature(
262 policy_->new_public_key(),
263 verification_key_,
264 policy_->new_public_key_verification_signature())) {
265 LOG(ERROR) << "Signature verification failed";
266 UMA_HISTOGRAM_ENUMERATION(kMetricPolicyKeyVerification,
267 METRIC_POLICY_KEY_VERIFICATION_FAILED,
268 METRIC_POLICY_KEY_VERIFICATION_SIZE);
269 // TODO(atwilson): Update this code to include the domain name in the
270 // signature, and return an error once the server starts returning this.
271 return true;
272 }
273 // Signature verification succeeded - return success to the caller.
274 UMA_HISTOGRAM_ENUMERATION(kMetricPolicyKeyVerification,
275 METRIC_POLICY_KEY_VERIFICATION_SUCCEEDED,
276 METRIC_POLICY_KEY_VERIFICATION_SIZE);
277 return true;
278 }
279
280 bool CloudPolicyValidatorBase::CheckVerificationKeySignature(
281 const std::string& key,
282 const std::string& verification_key,
283 const std::string& signature) {
284 // TODO(atwilson): Update this routine to include the domain name in the
285 // signed data.
286 return VerifySignature(key, verification_key, signature);
287 }
288
289 void CloudPolicyValidatorBase::set_verification_key(
290 const std::string& verification_key) {
291 // Make sure we aren't overwriting the verification key with a different key.
292 DCHECK(verification_key_.empty() || verification_key_ == verification_key);
293 verification_key_ = verification_key;
294 }
295
213 CloudPolicyValidatorBase::Status CloudPolicyValidatorBase::CheckSignature() { 296 CloudPolicyValidatorBase::Status CloudPolicyValidatorBase::CheckSignature() {
214 const std::string* signature_key = &key_; 297 const std::string* signature_key = &key_;
215 if (policy_->has_new_public_key() && allow_key_rotation_) { 298 if (policy_->has_new_public_key() && allow_key_rotation_) {
216 signature_key = &policy_->new_public_key(); 299 signature_key = &policy_->new_public_key();
217 if (!policy_->has_new_public_key_signature() || 300 if (!policy_->has_new_public_key_signature() ||
218 !VerifySignature(policy_->new_public_key(), key_, 301 !VerifySignature(policy_->new_public_key(), key_,
219 policy_->new_public_key_signature())) { 302 policy_->new_public_key_signature())) {
220 LOG(ERROR) << "New public key signature verification failed"; 303 LOG(ERROR) << "New public key rotation signature verification failed";
221 return VALIDATION_BAD_SIGNATURE; 304 return VALIDATION_BAD_SIGNATURE;
222 } 305 }
306
307 if (!CheckNewPublicKeyVerificationSignature()) {
308 LOG(ERROR) << "New public key root verification failed";
309 return VALIDATION_BAD_KEY_VERIFICATION_SIGNATURE;
310 }
223 } 311 }
224 312
225 if (!policy_->has_policy_data_signature() || 313 if (!policy_->has_policy_data_signature() ||
226 !VerifySignature(policy_->policy_data(), *signature_key, 314 !VerifySignature(policy_->policy_data(), *signature_key,
227 policy_->policy_data_signature())) { 315 policy_->policy_data_signature())) {
228 LOG(ERROR) << "Policy signature validation failed"; 316 LOG(ERROR) << "Policy signature validation failed";
229 return VALIDATION_BAD_SIGNATURE; 317 return VALIDATION_BAD_SIGNATURE;
230 } 318 }
231 319
320 // If a key verification signature is available, then verify the base signing
321 // key as well.
322 if (!key_signature_.empty() &&
323 !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
324 LOG(ERROR) << "Verification key signature verification failed";
325 // TODO(atwilson): Update to return an error once the server is properly
326 // generating a verification signature (http://crbug.com/275291).
327 // return VALIDATION_BAD_KEY_VERIFICATION_SIGNATURE;
328 }
329
232 return VALIDATION_OK; 330 return VALIDATION_OK;
233 } 331 }
234 332
235 CloudPolicyValidatorBase::Status CloudPolicyValidatorBase::CheckInitialKey() { 333 CloudPolicyValidatorBase::Status CloudPolicyValidatorBase::CheckInitialKey() {
236 if (!policy_->has_new_public_key() || 334 if (!policy_->has_new_public_key() ||
237 !policy_->has_policy_data_signature() || 335 !policy_->has_policy_data_signature() ||
238 !VerifySignature(policy_->policy_data(), policy_->new_public_key(), 336 !VerifySignature(policy_->policy_data(), policy_->new_public_key(),
239 policy_->policy_data_signature())) { 337 policy_->policy_data_signature())) {
240 LOG(ERROR) << "Initial policy signature validation failed"; 338 LOG(ERROR) << "Initial policy signature validation failed";
241 return VALIDATION_BAD_INITIAL_SIGNATURE; 339 return VALIDATION_BAD_INITIAL_SIGNATURE;
242 } 340 }
243 341
342 if (!CheckNewPublicKeyVerificationSignature()) {
343 LOG(ERROR) << "Initial policy root signature validation failed";
344 return VALIDATION_BAD_KEY_VERIFICATION_SIGNATURE;
345 }
244 return VALIDATION_OK; 346 return VALIDATION_OK;
245 } 347 }
246 348
247 CloudPolicyValidatorBase::Status CloudPolicyValidatorBase::CheckPolicyType() { 349 CloudPolicyValidatorBase::Status CloudPolicyValidatorBase::CheckPolicyType() {
248 if (!policy_data_->has_policy_type() || 350 if (!policy_data_->has_policy_type() ||
249 policy_data_->policy_type() != policy_type_) { 351 policy_data_->policy_type() != policy_type_) {
250 LOG(ERROR) << "Wrong policy type " << policy_data_->policy_type(); 352 LOG(ERROR) << "Wrong policy type " << policy_data_->policy_type();
251 return VALIDATION_WRONG_POLICY_TYPE; 353 return VALIDATION_WRONG_POLICY_TYPE;
252 } 354 }
253 355
(...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after
376 return verifier.VerifyFinal(); 478 return verifier.VerifyFinal();
377 } 479 }
378 480
379 template class CloudPolicyValidator<em::CloudPolicySettings>; 481 template class CloudPolicyValidator<em::CloudPolicySettings>;
380 482
381 #if !defined(OS_ANDROID) && !defined(OS_IOS) 483 #if !defined(OS_ANDROID) && !defined(OS_IOS)
382 template class CloudPolicyValidator<em::ExternalPolicyData>; 484 template class CloudPolicyValidator<em::ExternalPolicyData>;
383 #endif 485 #endif
384 486
385 } // namespace policy 487 } // namespace policy
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698