• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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