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 #include "components/policy/core/common/cloud/cloud_policy_validator.h"
6
7 #include "base/bind_helpers.h"
8 #include "base/message_loop/message_loop.h"
9 #include "base/metrics/histogram.h"
10 #include "base/sequenced_task_runner.h"
11 #include "base/stl_util.h"
12 #include "components/policy/core/common/cloud/cloud_policy_constants.h"
13 #include "crypto/signature_verifier.h"
14 #include "google_apis/gaia/gaia_auth_util.h"
15 #include "policy/proto/device_management_backend.pb.h"
16
17 namespace em = enterprise_management;
18
19 namespace policy {
20
21 namespace {
22
23 // Grace interval for policy timestamp checks, in seconds.
24 const int kTimestampGraceIntervalSeconds = 60;
25
26 // DER-encoded ASN.1 object identifier for the SHA1-RSA signature algorithm.
27 const uint8 kSHA1SignatureAlgorithm[] = {
28 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
29 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00
30 };
31
32 // DER-encoded ASN.1 object identifier for the SHA256-RSA signature algorithm
33 // (source: http://tools.ietf.org/html/rfc5754 section 3.2).
34 const uint8 kSHA256SignatureAlgorithm[] = {
35 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
36 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00
37 };
38
39 COMPILE_ASSERT(sizeof(kSHA256SignatureAlgorithm) ==
40 sizeof(kSHA1SignatureAlgorithm), invalid_algorithm_size);
41
42 const int kSignatureAlgorithmSize = sizeof(kSHA1SignatureAlgorithm);
43
44 const char kMetricPolicyKeyVerification[] = "Enterprise.PolicyKeyVerification";
45
46 enum MetricPolicyKeyVerification {
47 // UMA metric recorded when the client has no verification key.
48 METRIC_POLICY_KEY_VERIFICATION_KEY_MISSING,
49 // Recorded when the policy being verified has no key signature (e.g. policy
50 // fetched before the server supported the verification key).
51 METRIC_POLICY_KEY_VERIFICATION_SIGNATURE_MISSING,
52 // Recorded when the key signature did not match the expected value (in
53 // theory, this should only happen after key rotation or if the policy cached
54 // on disk has been modified).
55 METRIC_POLICY_KEY_VERIFICATION_FAILED,
56 // Recorded when key verification succeeded.
57 METRIC_POLICY_KEY_VERIFICATION_SUCCEEDED,
58 METRIC_POLICY_KEY_VERIFICATION_SIZE // Must be the last.
59 };
60
61 } // namespace
62
~CloudPolicyValidatorBase()63 CloudPolicyValidatorBase::~CloudPolicyValidatorBase() {}
64
ValidateTimestamp(base::Time not_before,base::Time now,ValidateTimestampOption timestamp_option)65 void CloudPolicyValidatorBase::ValidateTimestamp(
66 base::Time not_before,
67 base::Time now,
68 ValidateTimestampOption timestamp_option) {
69 // Timestamp should be from the past. We allow for a 1-minute grace interval
70 // to cover clock drift.
71 validation_flags_ |= VALIDATE_TIMESTAMP;
72 timestamp_not_before_ =
73 (not_before - base::Time::UnixEpoch()).InMilliseconds();
74 timestamp_not_after_ =
75 ((now + base::TimeDelta::FromSeconds(kTimestampGraceIntervalSeconds)) -
76 base::Time::UnixEpoch()).InMillisecondsRoundedUp();
77 timestamp_option_ = timestamp_option;
78 }
79
ValidateUsername(const std::string & expected_user,bool canonicalize)80 void CloudPolicyValidatorBase::ValidateUsername(
81 const std::string& expected_user,
82 bool canonicalize) {
83 validation_flags_ |= VALIDATE_USERNAME;
84 user_ = expected_user;
85 canonicalize_user_ = canonicalize;
86 }
87
ValidateDomain(const std::string & expected_domain)88 void CloudPolicyValidatorBase::ValidateDomain(
89 const std::string& expected_domain) {
90 validation_flags_ |= VALIDATE_DOMAIN;
91 domain_ = gaia::CanonicalizeDomain(expected_domain);
92 }
93
ValidateDMToken(const std::string & token,ValidateDMTokenOption dm_token_option)94 void CloudPolicyValidatorBase::ValidateDMToken(
95 const std::string& token,
96 ValidateDMTokenOption dm_token_option) {
97 validation_flags_ |= VALIDATE_TOKEN;
98 token_ = token;
99 dm_token_option_ = dm_token_option;
100 }
101
ValidatePolicyType(const std::string & policy_type)102 void CloudPolicyValidatorBase::ValidatePolicyType(
103 const std::string& policy_type) {
104 validation_flags_ |= VALIDATE_POLICY_TYPE;
105 policy_type_ = policy_type;
106 }
107
ValidateSettingsEntityId(const std::string & settings_entity_id)108 void CloudPolicyValidatorBase::ValidateSettingsEntityId(
109 const std::string& settings_entity_id) {
110 validation_flags_ |= VALIDATE_ENTITY_ID;
111 settings_entity_id_ = settings_entity_id;
112 }
113
ValidatePayload()114 void CloudPolicyValidatorBase::ValidatePayload() {
115 validation_flags_ |= VALIDATE_PAYLOAD;
116 }
117
118
ValidateCachedKey(const std::string & cached_key,const std::string & cached_key_signature,const std::string & verification_key,const std::string & owning_domain)119 void CloudPolicyValidatorBase::ValidateCachedKey(
120 const std::string& cached_key,
121 const std::string& cached_key_signature,
122 const std::string& verification_key,
123 const std::string& owning_domain) {
124 validation_flags_ |= VALIDATE_CACHED_KEY;
125 set_verification_key_and_domain(verification_key, owning_domain);
126 cached_key_ = cached_key;
127 cached_key_signature_ = cached_key_signature;
128 }
129
ValidateSignature(const std::string & key,const std::string & verification_key,const std::string & owning_domain,bool allow_key_rotation)130 void CloudPolicyValidatorBase::ValidateSignature(
131 const std::string& key,
132 const std::string& verification_key,
133 const std::string& owning_domain,
134 bool allow_key_rotation) {
135 validation_flags_ |= VALIDATE_SIGNATURE;
136 set_verification_key_and_domain(verification_key, owning_domain);
137 key_ = key;
138 allow_key_rotation_ = allow_key_rotation;
139 }
140
ValidateInitialKey(const std::string & verification_key,const std::string & owning_domain)141 void CloudPolicyValidatorBase::ValidateInitialKey(
142 const std::string& verification_key,
143 const std::string& owning_domain) {
144 validation_flags_ |= VALIDATE_INITIAL_KEY;
145 set_verification_key_and_domain(verification_key, owning_domain);
146 }
147
ValidateAgainstCurrentPolicy(const em::PolicyData * policy_data,ValidateTimestampOption timestamp_option,ValidateDMTokenOption dm_token_option)148 void CloudPolicyValidatorBase::ValidateAgainstCurrentPolicy(
149 const em::PolicyData* policy_data,
150 ValidateTimestampOption timestamp_option,
151 ValidateDMTokenOption dm_token_option) {
152 base::Time last_policy_timestamp;
153 std::string expected_dm_token;
154 if (policy_data) {
155 last_policy_timestamp =
156 base::Time::UnixEpoch() +
157 base::TimeDelta::FromMilliseconds(policy_data->timestamp());
158 expected_dm_token = policy_data->request_token();
159 }
160 ValidateTimestamp(last_policy_timestamp, base::Time::NowFromSystemTime(),
161 timestamp_option);
162 ValidateDMToken(expected_dm_token, dm_token_option);
163 }
164
CloudPolicyValidatorBase(scoped_ptr<em::PolicyFetchResponse> policy_response,google::protobuf::MessageLite * payload,scoped_refptr<base::SequencedTaskRunner> background_task_runner)165 CloudPolicyValidatorBase::CloudPolicyValidatorBase(
166 scoped_ptr<em::PolicyFetchResponse> policy_response,
167 google::protobuf::MessageLite* payload,
168 scoped_refptr<base::SequencedTaskRunner> background_task_runner)
169 : status_(VALIDATION_OK),
170 policy_(policy_response.Pass()),
171 payload_(payload),
172 validation_flags_(0),
173 timestamp_not_before_(0),
174 timestamp_not_after_(0),
175 timestamp_option_(TIMESTAMP_REQUIRED),
176 dm_token_option_(DM_TOKEN_REQUIRED),
177 canonicalize_user_(false),
178 allow_key_rotation_(false),
179 background_task_runner_(background_task_runner) {}
180
PostValidationTask(const base::Closure & completion_callback)181 void CloudPolicyValidatorBase::PostValidationTask(
182 const base::Closure& completion_callback) {
183 background_task_runner_->PostTask(
184 FROM_HERE,
185 base::Bind(&CloudPolicyValidatorBase::PerformValidation,
186 base::Passed(scoped_ptr<CloudPolicyValidatorBase>(this)),
187 base::MessageLoop::current()->message_loop_proxy(),
188 completion_callback));
189 }
190
191 // static
PerformValidation(scoped_ptr<CloudPolicyValidatorBase> self,scoped_refptr<base::MessageLoopProxy> message_loop,const base::Closure & completion_callback)192 void CloudPolicyValidatorBase::PerformValidation(
193 scoped_ptr<CloudPolicyValidatorBase> self,
194 scoped_refptr<base::MessageLoopProxy> message_loop,
195 const base::Closure& completion_callback) {
196 // Run the validation activities on this thread.
197 self->RunValidation();
198
199 // Report completion on |message_loop|.
200 message_loop->PostTask(
201 FROM_HERE,
202 base::Bind(&CloudPolicyValidatorBase::ReportCompletion,
203 base::Passed(&self),
204 completion_callback));
205 }
206
207 // static
ReportCompletion(scoped_ptr<CloudPolicyValidatorBase> self,const base::Closure & completion_callback)208 void CloudPolicyValidatorBase::ReportCompletion(
209 scoped_ptr<CloudPolicyValidatorBase> self,
210 const base::Closure& completion_callback) {
211 completion_callback.Run();
212 }
213
RunValidation()214 void CloudPolicyValidatorBase::RunValidation() {
215 policy_data_.reset(new em::PolicyData());
216 RunChecks();
217 }
218
RunChecks()219 void CloudPolicyValidatorBase::RunChecks() {
220 status_ = VALIDATION_OK;
221 if ((policy_->has_error_code() && policy_->error_code() != 200) ||
222 (policy_->has_error_message() && !policy_->error_message().empty())) {
223 LOG(ERROR) << "Error in policy blob."
224 << " code: " << policy_->error_code()
225 << " message: " << policy_->error_message();
226 status_ = VALIDATION_ERROR_CODE_PRESENT;
227 return;
228 }
229
230 // Parse policy data.
231 if (!policy_data_->ParseFromString(policy_->policy_data()) ||
232 !policy_data_->IsInitialized()) {
233 LOG(ERROR) << "Failed to parse policy response";
234 status_ = VALIDATION_PAYLOAD_PARSE_ERROR;
235 return;
236 }
237
238 // Table of checks we run. These are sorted by descending severity of the
239 // error, s.t. the most severe check will determine the validation status.
240 static const struct {
241 int flag;
242 Status (CloudPolicyValidatorBase::* checkFunction)();
243 } kCheckFunctions[] = {
244 { VALIDATE_SIGNATURE, &CloudPolicyValidatorBase::CheckSignature },
245 { VALIDATE_INITIAL_KEY, &CloudPolicyValidatorBase::CheckInitialKey },
246 { VALIDATE_CACHED_KEY, &CloudPolicyValidatorBase::CheckCachedKey },
247 { VALIDATE_POLICY_TYPE, &CloudPolicyValidatorBase::CheckPolicyType },
248 { VALIDATE_ENTITY_ID, &CloudPolicyValidatorBase::CheckEntityId },
249 { VALIDATE_TOKEN, &CloudPolicyValidatorBase::CheckToken },
250 { VALIDATE_USERNAME, &CloudPolicyValidatorBase::CheckUsername },
251 { VALIDATE_DOMAIN, &CloudPolicyValidatorBase::CheckDomain },
252 { VALIDATE_TIMESTAMP, &CloudPolicyValidatorBase::CheckTimestamp },
253 { VALIDATE_PAYLOAD, &CloudPolicyValidatorBase::CheckPayload },
254 };
255
256 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kCheckFunctions); ++i) {
257 if (validation_flags_ & kCheckFunctions[i].flag) {
258 status_ = (this->*(kCheckFunctions[i].checkFunction))();
259 if (status_ != VALIDATION_OK)
260 break;
261 }
262 }
263 }
264
265 // Verifies the |new_public_key_verification_signature| for the |new_public_key|
266 // in the policy blob.
CheckNewPublicKeyVerificationSignature()267 bool CloudPolicyValidatorBase::CheckNewPublicKeyVerificationSignature() {
268 // If there's no local verification key, then just return true (no
269 // validation possible).
270 if (verification_key_.empty()) {
271 UMA_HISTOGRAM_ENUMERATION(kMetricPolicyKeyVerification,
272 METRIC_POLICY_KEY_VERIFICATION_KEY_MISSING,
273 METRIC_POLICY_KEY_VERIFICATION_SIZE);
274 return true;
275 }
276
277 if (!policy_->has_new_public_key_verification_signature()) {
278 // Policy does not contain a verification signature, so log an error.
279 LOG(ERROR) << "Policy is missing public_key_verification_signature";
280 UMA_HISTOGRAM_ENUMERATION(kMetricPolicyKeyVerification,
281 METRIC_POLICY_KEY_VERIFICATION_SIGNATURE_MISSING,
282 METRIC_POLICY_KEY_VERIFICATION_SIZE);
283 return false;
284 }
285
286 if (!CheckVerificationKeySignature(
287 policy_->new_public_key(),
288 verification_key_,
289 policy_->new_public_key_verification_signature())) {
290 LOG(ERROR) << "Signature verification failed";
291 UMA_HISTOGRAM_ENUMERATION(kMetricPolicyKeyVerification,
292 METRIC_POLICY_KEY_VERIFICATION_FAILED,
293 METRIC_POLICY_KEY_VERIFICATION_SIZE);
294 return false;
295 }
296 // Signature verification succeeded - return success to the caller.
297 DVLOG(1) << "Signature verification succeeded";
298 UMA_HISTOGRAM_ENUMERATION(kMetricPolicyKeyVerification,
299 METRIC_POLICY_KEY_VERIFICATION_SUCCEEDED,
300 METRIC_POLICY_KEY_VERIFICATION_SIZE);
301 return true;
302 }
303
CheckVerificationKeySignature(const std::string & key,const std::string & verification_key,const std::string & signature)304 bool CloudPolicyValidatorBase::CheckVerificationKeySignature(
305 const std::string& key,
306 const std::string& verification_key,
307 const std::string& signature) {
308 DCHECK(!verification_key.empty());
309 em::PolicyPublicKeyAndDomain signed_data;
310 signed_data.set_new_public_key(key);
311
312 // If no owning_domain_ supplied, try extracting the domain from the policy
313 // itself (this happens on certain platforms during startup, when we validate
314 // cached policy before prefs are loaded).
315 std::string domain = owning_domain_.empty() ?
316 ExtractDomainFromPolicy() : owning_domain_;
317 if (domain.empty()) {
318 LOG(ERROR) << "Policy does not contain a domain";
319 return false;
320 }
321 signed_data.set_domain(domain);
322 std::string signed_data_as_string;
323 if (!signed_data.SerializeToString(&signed_data_as_string)) {
324 DLOG(ERROR) << "Could not serialize verification key to string";
325 return false;
326 }
327 return VerifySignature(signed_data_as_string, verification_key, signature,
328 SHA256);
329 }
330
ExtractDomainFromPolicy()331 std::string CloudPolicyValidatorBase::ExtractDomainFromPolicy() {
332 std::string domain;
333 if (policy_data_->has_username()) {
334 domain = gaia::ExtractDomainName(
335 gaia::CanonicalizeEmail(
336 gaia::SanitizeEmail(policy_data_->username())));
337 }
338 return domain;
339 }
340
set_verification_key_and_domain(const std::string & verification_key,const std::string & owning_domain)341 void CloudPolicyValidatorBase::set_verification_key_and_domain(
342 const std::string& verification_key, const std::string& owning_domain) {
343 // Make sure we aren't overwriting the verification key with a different key.
344 DCHECK(verification_key_.empty() || verification_key_ == verification_key);
345 DCHECK(owning_domain_.empty() || owning_domain_ == owning_domain);
346 verification_key_ = verification_key;
347 owning_domain_ = owning_domain;
348 }
349
CheckSignature()350 CloudPolicyValidatorBase::Status CloudPolicyValidatorBase::CheckSignature() {
351 const std::string* signature_key = &key_;
352 if (policy_->has_new_public_key() && allow_key_rotation_) {
353 signature_key = &policy_->new_public_key();
354 if (!policy_->has_new_public_key_signature() ||
355 !VerifySignature(policy_->new_public_key(), key_,
356 policy_->new_public_key_signature(), SHA1)) {
357 LOG(ERROR) << "New public key rotation signature verification failed";
358 return VALIDATION_BAD_SIGNATURE;
359 }
360
361 if (!CheckNewPublicKeyVerificationSignature()) {
362 LOG(ERROR) << "New public key root verification failed";
363 return VALIDATION_BAD_KEY_VERIFICATION_SIGNATURE;
364 }
365 }
366
367 if (!policy_->has_policy_data_signature() ||
368 !VerifySignature(policy_->policy_data(), *signature_key,
369 policy_->policy_data_signature(), SHA1)) {
370 LOG(ERROR) << "Policy signature validation failed";
371 return VALIDATION_BAD_SIGNATURE;
372 }
373
374 return VALIDATION_OK;
375 }
376
CheckInitialKey()377 CloudPolicyValidatorBase::Status CloudPolicyValidatorBase::CheckInitialKey() {
378 if (!policy_->has_new_public_key() ||
379 !policy_->has_policy_data_signature() ||
380 !VerifySignature(policy_->policy_data(), policy_->new_public_key(),
381 policy_->policy_data_signature(), SHA1)) {
382 LOG(ERROR) << "Initial policy signature validation failed";
383 return VALIDATION_BAD_INITIAL_SIGNATURE;
384 }
385
386 if (!CheckNewPublicKeyVerificationSignature()) {
387 LOG(ERROR) << "Initial policy root signature validation failed";
388 return VALIDATION_BAD_KEY_VERIFICATION_SIGNATURE;
389 }
390 return VALIDATION_OK;
391 }
392
CheckCachedKey()393 CloudPolicyValidatorBase::Status CloudPolicyValidatorBase::CheckCachedKey() {
394 if (!verification_key_.empty() &&
395 !CheckVerificationKeySignature(cached_key_, verification_key_,
396 cached_key_signature_)) {
397 LOG(ERROR) << "Cached key signature verification failed";
398 return VALIDATION_BAD_KEY_VERIFICATION_SIGNATURE;
399 } else {
400 DVLOG(1) << "Cached key signature verification succeeded";
401 }
402 return VALIDATION_OK;
403 }
404
CheckPolicyType()405 CloudPolicyValidatorBase::Status CloudPolicyValidatorBase::CheckPolicyType() {
406 if (!policy_data_->has_policy_type() ||
407 policy_data_->policy_type() != policy_type_) {
408 LOG(ERROR) << "Wrong policy type " << policy_data_->policy_type();
409 return VALIDATION_WRONG_POLICY_TYPE;
410 }
411
412 return VALIDATION_OK;
413 }
414
CheckEntityId()415 CloudPolicyValidatorBase::Status CloudPolicyValidatorBase::CheckEntityId() {
416 if (!policy_data_->has_settings_entity_id() ||
417 policy_data_->settings_entity_id() != settings_entity_id_) {
418 LOG(ERROR) << "Wrong settings_entity_id "
419 << policy_data_->settings_entity_id() << ", expected "
420 << settings_entity_id_;
421 return VALIDATION_WRONG_SETTINGS_ENTITY_ID;
422 }
423
424 return VALIDATION_OK;
425 }
426
CheckTimestamp()427 CloudPolicyValidatorBase::Status CloudPolicyValidatorBase::CheckTimestamp() {
428 if (!policy_data_->has_timestamp()) {
429 if (timestamp_option_ == TIMESTAMP_NOT_REQUIRED) {
430 return VALIDATION_OK;
431 } else {
432 LOG(ERROR) << "Policy timestamp missing";
433 return VALIDATION_BAD_TIMESTAMP;
434 }
435 }
436
437 if (timestamp_option_ != TIMESTAMP_NOT_REQUIRED &&
438 policy_data_->timestamp() < timestamp_not_before_) {
439 // If |timestamp_option_| is TIMESTAMP_REQUIRED or TIMESTAMP_NOT_BEFORE
440 // then this is a failure.
441 LOG(ERROR) << "Policy too old: " << policy_data_->timestamp();
442 return VALIDATION_BAD_TIMESTAMP;
443 }
444 if (timestamp_option_ == TIMESTAMP_REQUIRED &&
445 policy_data_->timestamp() > timestamp_not_after_) {
446 LOG(ERROR) << "Policy from the future: " << policy_data_->timestamp();
447 return VALIDATION_BAD_TIMESTAMP;
448 }
449
450 return VALIDATION_OK;
451 }
452
CheckToken()453 CloudPolicyValidatorBase::Status CloudPolicyValidatorBase::CheckToken() {
454 // Make sure the token matches the expected token (if any) and also
455 // make sure the token itself is valid (non-empty if DM_TOKEN_REQUIRED).
456 if (dm_token_option_ == DM_TOKEN_REQUIRED &&
457 (!policy_data_->has_request_token() ||
458 policy_data_->request_token().empty())) {
459 LOG(ERROR) << "Empty DM token encountered - expected: " << token_;
460 return VALIDATION_WRONG_TOKEN;
461 }
462 if (!token_.empty() && policy_data_->request_token() != token_) {
463 LOG(ERROR) << "Invalid DM token: " << policy_data_->request_token()
464 << " - expected: " << token_;
465 return VALIDATION_WRONG_TOKEN;
466 }
467
468 return VALIDATION_OK;
469 }
470
CheckUsername()471 CloudPolicyValidatorBase::Status CloudPolicyValidatorBase::CheckUsername() {
472 if (!policy_data_->has_username()) {
473 LOG(ERROR) << "Policy is missing user name";
474 return VALIDATION_BAD_USERNAME;
475 }
476
477 std::string expected = user_;
478 std::string actual = policy_data_->username();
479 if (canonicalize_user_) {
480 expected = gaia::CanonicalizeEmail(gaia::SanitizeEmail(expected));
481 actual = gaia::CanonicalizeEmail(gaia::SanitizeEmail(actual));
482 }
483
484 if (expected != actual) {
485 LOG(ERROR) << "Invalid user name " << policy_data_->username();
486 return VALIDATION_BAD_USERNAME;
487 }
488
489 return VALIDATION_OK;
490 }
491
CheckDomain()492 CloudPolicyValidatorBase::Status CloudPolicyValidatorBase::CheckDomain() {
493 std::string policy_domain = ExtractDomainFromPolicy();
494 if (policy_domain.empty()) {
495 LOG(ERROR) << "Policy is missing user name";
496 return VALIDATION_BAD_USERNAME;
497 }
498
499 if (domain_ != policy_domain) {
500 LOG(ERROR) << "Invalid user name " << policy_data_->username();
501 return VALIDATION_BAD_USERNAME;
502 }
503
504 return VALIDATION_OK;
505 }
506
CheckPayload()507 CloudPolicyValidatorBase::Status CloudPolicyValidatorBase::CheckPayload() {
508 if (!policy_data_->has_policy_value() ||
509 !payload_->ParseFromString(policy_data_->policy_value()) ||
510 !payload_->IsInitialized()) {
511 LOG(ERROR) << "Failed to decode policy payload protobuf";
512 return VALIDATION_POLICY_PARSE_ERROR;
513 }
514
515 return VALIDATION_OK;
516 }
517
518 // static
VerifySignature(const std::string & data,const std::string & key,const std::string & signature,SignatureType signature_type)519 bool CloudPolicyValidatorBase::VerifySignature(const std::string& data,
520 const std::string& key,
521 const std::string& signature,
522 SignatureType signature_type) {
523 crypto::SignatureVerifier verifier;
524 const uint8* algorithm = NULL;
525 switch (signature_type) {
526 case SHA1:
527 algorithm = kSHA1SignatureAlgorithm;
528 break;
529 case SHA256:
530 algorithm = kSHA256SignatureAlgorithm;
531 break;
532 default:
533 NOTREACHED() << "Invalid signature type: " << signature_type;
534 return false;
535 }
536
537 if (!verifier.VerifyInit(algorithm, kSignatureAlgorithmSize,
538 reinterpret_cast<const uint8*>(signature.c_str()),
539 signature.size(),
540 reinterpret_cast<const uint8*>(key.c_str()),
541 key.size())) {
542 DLOG(ERROR) << "Invalid verification signature/key format";
543 return false;
544 }
545 verifier.VerifyUpdate(reinterpret_cast<const uint8*>(data.c_str()),
546 data.size());
547 return verifier.VerifyFinal();
548 }
549
550 template class CloudPolicyValidator<em::CloudPolicySettings>;
551
552 #if !defined(OS_ANDROID) && !defined(OS_IOS)
553 template class CloudPolicyValidator<em::ExternalPolicyData>;
554 #endif
555
556 } // namespace policy
557