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
17namespace em = enterprise_management;
18
19namespace policy {
20
21namespace {
22
23// Grace interval for policy timestamp checks, in seconds.
24const int kTimestampGraceIntervalSeconds = 60;
25
26// DER-encoded ASN.1 object identifier for the SHA1-RSA signature algorithm.
27const 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).
34const uint8 kSHA256SignatureAlgorithm[] = {
35    0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
36    0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00
37};
38
39COMPILE_ASSERT(sizeof(kSHA256SignatureAlgorithm) ==
40               sizeof(kSHA1SignatureAlgorithm), invalid_algorithm_size);
41
42const int kSignatureAlgorithmSize = sizeof(kSHA1SignatureAlgorithm);
43
44const char kMetricPolicyKeyVerification[] = "Enterprise.PolicyKeyVerification";
45
46enum 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
63CloudPolicyValidatorBase::~CloudPolicyValidatorBase() {}
64
65void 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
80void 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
88void CloudPolicyValidatorBase::ValidateDomain(
89    const std::string& expected_domain) {
90  validation_flags_ |= VALIDATE_DOMAIN;
91  domain_ = gaia::CanonicalizeDomain(expected_domain);
92}
93
94void 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
102void CloudPolicyValidatorBase::ValidatePolicyType(
103    const std::string& policy_type) {
104  validation_flags_ |= VALIDATE_POLICY_TYPE;
105  policy_type_ = policy_type;
106}
107
108void CloudPolicyValidatorBase::ValidateSettingsEntityId(
109    const std::string& settings_entity_id) {
110  validation_flags_ |= VALIDATE_ENTITY_ID;
111  settings_entity_id_ = settings_entity_id;
112}
113
114void CloudPolicyValidatorBase::ValidatePayload() {
115  validation_flags_ |= VALIDATE_PAYLOAD;
116}
117
118
119void 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
130void 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
141void 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
148void 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
165CloudPolicyValidatorBase::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
181void 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
192void 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
208void CloudPolicyValidatorBase::ReportCompletion(
209    scoped_ptr<CloudPolicyValidatorBase> self,
210    const base::Closure& completion_callback) {
211  completion_callback.Run();
212}
213
214void CloudPolicyValidatorBase::RunValidation() {
215  policy_data_.reset(new em::PolicyData());
216  RunChecks();
217}
218
219void 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.
267bool 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
304bool 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
331std::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
341void 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
350CloudPolicyValidatorBase::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
377CloudPolicyValidatorBase::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
393CloudPolicyValidatorBase::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
405CloudPolicyValidatorBase::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
415CloudPolicyValidatorBase::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
427CloudPolicyValidatorBase::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
453CloudPolicyValidatorBase::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
471CloudPolicyValidatorBase::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
492CloudPolicyValidatorBase::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
507CloudPolicyValidatorBase::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
519bool 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
550template class CloudPolicyValidator<em::CloudPolicySettings>;
551
552#if !defined(OS_ANDROID) && !defined(OS_IOS)
553template class CloudPolicyValidator<em::ExternalPolicyData>;
554#endif
555
556}  // namespace policy
557