1c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Copyright (c) 2013 The Chromium Authors. All rights reserved.
2c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
3c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// found in the LICENSE file.
4c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
5c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/browser/chromeos/attestation/attestation_policy_observer.h"
6c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
7c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include <string>
8c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
9c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/bind.h"
10c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/callback.h"
11c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/location.h"
12eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/time/time.h"
137dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "chrome/browser/chrome_notification_types.h"
14c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/browser/chromeos/attestation/attestation_ca_client.h"
15c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/browser/chromeos/attestation/attestation_key_payload.pb.h"
16c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/browser/chromeos/settings/cros_settings.h"
17c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chromeos/attestation/attestation_flow.h"
18c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chromeos/cryptohome/async_method_caller.h"
19c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chromeos/dbus/cryptohome_client.h"
20c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chromeos/dbus/dbus_method_call_status.h"
21c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chromeos/dbus/dbus_thread_manager.h"
22a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "components/policy/core/common/cloud/cloud_policy_client.h"
23a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "components/policy/core/common/cloud/cloud_policy_manager.h"
24c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "content/public/browser/browser_thread.h"
25c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "content/public/browser/notification_details.h"
26c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "net/cert/x509_certificate.h"
27c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
28c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)namespace {
29c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
30c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// The number of days before a certificate expires during which it is
31c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// considered 'expiring soon' and replacement is initiated.  The Chrome OS CA
32c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// issues certificates with an expiry of at least two years.  This value has
33c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// been set large enough so that the majority of users will have gone through
34c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// a full sign-in during the period.
35c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)const int kExpiryThresholdInDays = 30;
36eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochconst int kRetryDelay = 5;  // Seconds.
37eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochconst int kRetryLimit = 100;
38c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
39c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// A dbus callback which handles a boolean result.
40c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)//
41c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Parameters
42c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)//   on_true - Called when status=success and value=true.
43c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)//   on_false - Called when status=success and value=false.
44c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)//   status - The dbus operation status.
45c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)//   value - The value returned by the dbus operation.
46c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void DBusBoolRedirectCallback(const base::Closure& on_true,
47c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                              const base::Closure& on_false,
48eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                              const base::Closure& on_failure,
49c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                              const tracked_objects::Location& from_here,
50c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                              chromeos::DBusMethodCallStatus status,
51c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                              bool value) {
52c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (status != chromeos::DBUS_METHOD_CALL_SUCCESS) {
53c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    LOG(ERROR) << "Cryptohome DBus method failed: " << from_here.ToString()
54c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)               << " - " << status;
55eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    if (!on_failure.is_null())
56eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      on_failure.Run();
57c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
58c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
59c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  const base::Closure& task = value ? on_true : on_false;
60c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!task.is_null())
61c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    task.Run();
62c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
63c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
64c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// A dbus callback which handles a string result.
65c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)//
66c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Parameters
67c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)//   on_success - Called when status=success and result=true.
68c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)//   status - The dbus operation status.
69c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)//   result - The result returned by the dbus operation.
70c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)//   data - The data returned by the dbus operation.
71c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void DBusStringCallback(
72c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const base::Callback<void(const std::string&)> on_success,
73eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    const base::Closure& on_failure,
74c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const tracked_objects::Location& from_here,
75c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    chromeos::DBusMethodCallStatus status,
76c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    bool result,
77c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const std::string& data) {
78c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (status != chromeos::DBUS_METHOD_CALL_SUCCESS || !result) {
79c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    LOG(ERROR) << "Cryptohome DBus method failed: " << from_here.ToString()
80c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)               << " - " << status << " - " << result;
81eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    if (!on_failure.is_null())
82eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      on_failure.Run();
83c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
84c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
85c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  on_success.Run(data);
86c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
87c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
88c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}  // namespace
89c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
90c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)namespace chromeos {
91c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)namespace attestation {
92c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
93c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)AttestationPolicyObserver::AttestationPolicyObserver(
94c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    policy::CloudPolicyClient* policy_client)
95c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    : cros_settings_(CrosSettings::Get()),
96c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      policy_client_(policy_client),
97c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      cryptohome_client_(NULL),
98c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      attestation_flow_(NULL),
99eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      num_retries_(0),
100eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      retry_delay_(kRetryDelay),
101c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      weak_factory_(this) {
102c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
10368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  attestation_subscription_ = cros_settings_->AddSettingsObserver(
10468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      kDeviceAttestationEnabled,
10568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      base::Bind(&AttestationPolicyObserver::AttestationSettingChanged,
10668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                 base::Unretained(this)));
107c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  Start();
108c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
109c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
110c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)AttestationPolicyObserver::AttestationPolicyObserver(
111c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    policy::CloudPolicyClient* policy_client,
112c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    CryptohomeClient* cryptohome_client,
113c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    AttestationFlow* attestation_flow)
114c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    : cros_settings_(CrosSettings::Get()),
115c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      policy_client_(policy_client),
116c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      cryptohome_client_(cryptohome_client),
117c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      attestation_flow_(attestation_flow),
118eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      num_retries_(0),
119eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      retry_delay_(kRetryDelay),
120c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      weak_factory_(this) {
121c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
12268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  attestation_subscription_ = cros_settings_->AddSettingsObserver(
12368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      kDeviceAttestationEnabled,
12468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      base::Bind(&AttestationPolicyObserver::AttestationSettingChanged,
12568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                 base::Unretained(this)));
126c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  Start();
127c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
128c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
129c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)AttestationPolicyObserver::~AttestationPolicyObserver() {
130c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
131c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
132c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
13368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)void AttestationPolicyObserver::AttestationSettingChanged() {
134c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
135eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  num_retries_ = 0;
136c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  Start();
137c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
138c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
139c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void AttestationPolicyObserver::Start() {
140c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // If attestation is not enabled, there is nothing to do.
141c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  bool enabled = false;
142c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!cros_settings_->GetBoolean(kDeviceAttestationEnabled, &enabled) ||
143c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      !enabled)
144c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
145c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
146c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // We expect a registered CloudPolicyClient.
147c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!policy_client_->is_registered()) {
148c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    LOG(ERROR) << "AttestationPolicyObserver: Invalid CloudPolicyClient.";
149c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
150c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
151c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
152c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!cryptohome_client_)
153c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    cryptohome_client_ = DBusThreadManager::Get()->GetCryptohomeClient();
154c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
155c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!attestation_flow_) {
156c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    scoped_ptr<ServerProxy> attestation_ca_client(new AttestationCAClient());
157c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    default_attestation_flow_.reset(new AttestationFlow(
158c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        cryptohome::AsyncMethodCaller::GetInstance(),
159c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        cryptohome_client_,
160c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        attestation_ca_client.Pass()));
161c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    attestation_flow_ = default_attestation_flow_.get();
162c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
163c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
164c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Start a dbus call to check if an Enterprise Machine Key already exists.
165c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::Closure on_does_exist =
166c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      base::Bind(&AttestationPolicyObserver::GetExistingCertificate,
167c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                 weak_factory_.GetWeakPtr());
168c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::Closure on_does_not_exist =
169c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      base::Bind(&AttestationPolicyObserver::GetNewCertificate,
170c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                 weak_factory_.GetWeakPtr());
171c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  cryptohome_client_->TpmAttestationDoesKeyExist(
172c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      KEY_DEVICE,
1738bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      std::string(),  // Not used.
174c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      kEnterpriseMachineKey,
175c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      base::Bind(DBusBoolRedirectCallback,
176c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                 on_does_exist,
177c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                 on_does_not_exist,
178eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                 base::Bind(&AttestationPolicyObserver::Reschedule,
179eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                            weak_factory_.GetWeakPtr()),
180c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                 FROM_HERE));
181c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
182c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
183c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void AttestationPolicyObserver::GetNewCertificate() {
184c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // We can reuse the dbus callback handler logic.
185c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  attestation_flow_->GetCertificate(
186c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      PROFILE_ENTERPRISE_MACHINE_CERTIFICATE,
1873551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      std::string(),  // Not used.
1883551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      std::string(),  // Not used.
189c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      true,  // Force a new key to be generated.
190c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      base::Bind(DBusStringCallback,
191c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                 base::Bind(&AttestationPolicyObserver::UploadCertificate,
192c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                            weak_factory_.GetWeakPtr()),
193eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                 base::Bind(&AttestationPolicyObserver::Reschedule,
194eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                            weak_factory_.GetWeakPtr()),
195c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                 FROM_HERE,
196c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                 DBUS_METHOD_CALL_SUCCESS));
197c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
198c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
199c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void AttestationPolicyObserver::GetExistingCertificate() {
200c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  cryptohome_client_->TpmAttestationGetCertificate(
201c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      KEY_DEVICE,
2028bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      std::string(),  // Not used.
203c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      kEnterpriseMachineKey,
204c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      base::Bind(DBusStringCallback,
205c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                 base::Bind(&AttestationPolicyObserver::CheckCertificateExpiry,
206c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                            weak_factory_.GetWeakPtr()),
207eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                 base::Bind(&AttestationPolicyObserver::Reschedule,
208eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                            weak_factory_.GetWeakPtr()),
209c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                 FROM_HERE));
210c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
211c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
212c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void AttestationPolicyObserver::CheckCertificateExpiry(
213c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const std::string& certificate) {
214c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  scoped_refptr<net::X509Certificate> x509(
215c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      net::X509Certificate::CreateFromBytes(certificate.data(),
216c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                            certificate.length()));
217c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!x509.get() || x509->valid_expiry().is_null()) {
218c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    LOG(WARNING) << "Failed to parse certificate, cannot check expiry.";
219c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  } else {
220c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const base::TimeDelta threshold =
221c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        base::TimeDelta::FromDays(kExpiryThresholdInDays);
222c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if ((base::Time::Now() + threshold) > x509->valid_expiry()) {
223c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      // The certificate has expired or will soon, replace it.
224c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      GetNewCertificate();
225c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      return;
226c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
227c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
228c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
229c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Get the payload and check if the certificate has already been uploaded.
230c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  GetKeyPayload(base::Bind(&AttestationPolicyObserver::CheckIfUploaded,
231c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                           weak_factory_.GetWeakPtr(),
232c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                           certificate));
233c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
234c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
235c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void AttestationPolicyObserver::UploadCertificate(
236c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const std::string& certificate) {
237c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  policy_client_->UploadCertificate(
238c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      certificate,
239c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      base::Bind(&AttestationPolicyObserver::OnUploadComplete,
240c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                 weak_factory_.GetWeakPtr()));
241c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
242c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
243c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void AttestationPolicyObserver::CheckIfUploaded(
244c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const std::string& certificate,
245c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const std::string& key_payload) {
246c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  AttestationKeyPayload payload_pb;
247c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!key_payload.empty() &&
248c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      payload_pb.ParseFromString(key_payload) &&
249c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      payload_pb.is_certificate_uploaded()) {
250c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // Already uploaded... nothing more to do.
251c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
252c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
253c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  UploadCertificate(certificate);
254c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
255c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
256c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void AttestationPolicyObserver::GetKeyPayload(
257c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    base::Callback<void(const std::string&)> callback) {
258c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  cryptohome_client_->TpmAttestationGetKeyPayload(
259c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      KEY_DEVICE,
2608bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      std::string(),  // Not used.
261c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      kEnterpriseMachineKey,
262eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      base::Bind(DBusStringCallback,
263eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                 callback,
264eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                 base::Bind(&AttestationPolicyObserver::Reschedule,
265eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                            weak_factory_.GetWeakPtr()),
266eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                 FROM_HERE));
267c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
268c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
269c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void AttestationPolicyObserver::OnUploadComplete(bool status) {
270c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!status)
271c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
272a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  VLOG(1) << "Enterprise Machine Certificate uploaded to DMServer.";
273c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  GetKeyPayload(base::Bind(&AttestationPolicyObserver::MarkAsUploaded,
274c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                           weak_factory_.GetWeakPtr()));
275c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
276c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
277c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void AttestationPolicyObserver::MarkAsUploaded(const std::string& key_payload) {
278c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  AttestationKeyPayload payload_pb;
279c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!key_payload.empty())
280c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    payload_pb.ParseFromString(key_payload);
281c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  payload_pb.set_is_certificate_uploaded(true);
282c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  std::string new_payload;
283c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!payload_pb.SerializeToString(&new_payload)) {
284c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    LOG(WARNING) << "Failed to serialize key payload.";
285c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
286c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
287c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  cryptohome_client_->TpmAttestationSetKeyPayload(
288c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      KEY_DEVICE,
2898bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      std::string(),  // Not used.
290c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      kEnterpriseMachineKey,
291c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      new_payload,
292c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      base::Bind(DBusBoolRedirectCallback,
293c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                 base::Closure(),
294c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                 base::Closure(),
295eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                 base::Closure(),
296c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                 FROM_HERE));
297c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
298c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
299eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid AttestationPolicyObserver::Reschedule() {
300eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (++num_retries_ < kRetryLimit) {
301eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    content::BrowserThread::PostDelayedTask(
302eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        content::BrowserThread::UI, FROM_HERE,
303eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        base::Bind(&AttestationPolicyObserver::Start,
304eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                   weak_factory_.GetWeakPtr()),
305eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        base::TimeDelta::FromSeconds(retry_delay_));
306eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  } else {
307eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    LOG(WARNING) << "AttestationPolicyObserver: Retry limit exceeded.";
308eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
309eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
310eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
311c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}  // namespace attestation
312c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}  // namespace chromeos
313