OLD | NEW |
---|---|
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/chromeos/attestation/attestation_policy_observer.h" | 5 #include "chrome/browser/chromeos/attestation/attestation_policy_observer.h" |
6 | 6 |
7 #include <string> | 7 #include <string> |
8 | 8 |
9 #include "base/bind.h" | 9 #include "base/bind.h" |
10 #include "base/callback.h" | 10 #include "base/callback.h" |
(...skipping 17 matching lines...) Expand all Loading... | |
28 namespace { | 28 namespace { |
29 | 29 |
30 const char kEnterpriseMachineKey[] = "attest-ent-machine"; | 30 const char kEnterpriseMachineKey[] = "attest-ent-machine"; |
31 | 31 |
32 // The number of days before a certificate expires during which it is | 32 // The number of days before a certificate expires during which it is |
33 // considered 'expiring soon' and replacement is initiated. The Chrome OS CA | 33 // considered 'expiring soon' and replacement is initiated. The Chrome OS CA |
34 // issues certificates with an expiry of at least two years. This value has | 34 // issues certificates with an expiry of at least two years. This value has |
35 // been set large enough so that the majority of users will have gone through | 35 // been set large enough so that the majority of users will have gone through |
36 // a full sign-in during the period. | 36 // a full sign-in during the period. |
37 const int kExpiryThresholdInDays = 30; | 37 const int kExpiryThresholdInDays = 30; |
38 const int kRetryDelay = 5; // Seconds. | |
39 const int kRetryLimit = 100; | |
38 | 40 |
39 // A dbus callback which handles a boolean result. | 41 // A dbus callback which handles a boolean result. |
40 // | 42 // |
41 // Parameters | 43 // Parameters |
42 // on_true - Called when status=success and value=true. | 44 // on_true - Called when status=success and value=true. |
43 // on_false - Called when status=success and value=false. | 45 // on_false - Called when status=success and value=false. |
44 // status - The dbus operation status. | 46 // status - The dbus operation status. |
45 // value - The value returned by the dbus operation. | 47 // value - The value returned by the dbus operation. |
46 void DBusBoolRedirectCallback(const base::Closure& on_true, | 48 void DBusBoolRedirectCallback(const base::Closure& on_true, |
47 const base::Closure& on_false, | 49 const base::Closure& on_false, |
50 const base::Closure& on_failure, | |
48 const tracked_objects::Location& from_here, | 51 const tracked_objects::Location& from_here, |
49 chromeos::DBusMethodCallStatus status, | 52 chromeos::DBusMethodCallStatus status, |
50 bool value) { | 53 bool value) { |
51 if (status != chromeos::DBUS_METHOD_CALL_SUCCESS) { | 54 if (status != chromeos::DBUS_METHOD_CALL_SUCCESS) { |
52 LOG(ERROR) << "Cryptohome DBus method failed: " << from_here.ToString() | 55 LOG(ERROR) << "Cryptohome DBus method failed: " << from_here.ToString() |
53 << " - " << status; | 56 << " - " << status; |
57 if (!on_failure.is_null()) | |
58 on_failure.Run(); | |
54 return; | 59 return; |
55 } | 60 } |
56 const base::Closure& task = value ? on_true : on_false; | 61 const base::Closure& task = value ? on_true : on_false; |
57 if (!task.is_null()) | 62 if (!task.is_null()) |
58 task.Run(); | 63 task.Run(); |
59 } | 64 } |
60 | 65 |
61 // A dbus callback which handles a string result. | 66 // A dbus callback which handles a string result. |
62 // | 67 // |
63 // Parameters | 68 // Parameters |
64 // on_success - Called when status=success and result=true. | 69 // on_success - Called when status=success and result=true. |
65 // status - The dbus operation status. | 70 // status - The dbus operation status. |
66 // result - The result returned by the dbus operation. | 71 // result - The result returned by the dbus operation. |
67 // data - The data returned by the dbus operation. | 72 // data - The data returned by the dbus operation. |
68 void DBusStringCallback( | 73 void DBusStringCallback( |
69 const base::Callback<void(const std::string&)> on_success, | 74 const base::Callback<void(const std::string&)> on_success, |
75 const base::Closure& on_failure, | |
70 const tracked_objects::Location& from_here, | 76 const tracked_objects::Location& from_here, |
71 chromeos::DBusMethodCallStatus status, | 77 chromeos::DBusMethodCallStatus status, |
72 bool result, | 78 bool result, |
73 const std::string& data) { | 79 const std::string& data) { |
74 if (status != chromeos::DBUS_METHOD_CALL_SUCCESS || !result) { | 80 if (status != chromeos::DBUS_METHOD_CALL_SUCCESS || !result) { |
75 LOG(ERROR) << "Cryptohome DBus method failed: " << from_here.ToString() | 81 LOG(ERROR) << "Cryptohome DBus method failed: " << from_here.ToString() |
76 << " - " << status << " - " << result; | 82 << " - " << status << " - " << result; |
83 if (!on_failure.is_null()) | |
84 on_failure.Run(); | |
77 return; | 85 return; |
78 } | 86 } |
79 on_success.Run(data); | 87 on_success.Run(data); |
80 } | 88 } |
81 | 89 |
82 } // namespace | 90 } // namespace |
83 | 91 |
84 namespace chromeos { | 92 namespace chromeos { |
85 namespace attestation { | 93 namespace attestation { |
86 | 94 |
87 AttestationPolicyObserver::AttestationPolicyObserver( | 95 AttestationPolicyObserver::AttestationPolicyObserver( |
88 policy::CloudPolicyClient* policy_client) | 96 policy::CloudPolicyClient* policy_client) |
89 : cros_settings_(CrosSettings::Get()), | 97 : cros_settings_(CrosSettings::Get()), |
90 policy_client_(policy_client), | 98 policy_client_(policy_client), |
91 cryptohome_client_(NULL), | 99 cryptohome_client_(NULL), |
92 attestation_flow_(NULL), | 100 attestation_flow_(NULL), |
101 num_retries_(0), | |
102 retry_delay_(kRetryDelay), | |
93 weak_factory_(this) { | 103 weak_factory_(this) { |
94 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | 104 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
95 cros_settings_->AddSettingsObserver(kDeviceAttestationEnabled, this); | 105 cros_settings_->AddSettingsObserver(kDeviceAttestationEnabled, this); |
96 Start(); | 106 Start(); |
97 } | 107 } |
98 | 108 |
99 AttestationPolicyObserver::AttestationPolicyObserver( | 109 AttestationPolicyObserver::AttestationPolicyObserver( |
100 policy::CloudPolicyClient* policy_client, | 110 policy::CloudPolicyClient* policy_client, |
101 CryptohomeClient* cryptohome_client, | 111 CryptohomeClient* cryptohome_client, |
102 AttestationFlow* attestation_flow) | 112 AttestationFlow* attestation_flow) |
103 : cros_settings_(CrosSettings::Get()), | 113 : cros_settings_(CrosSettings::Get()), |
104 policy_client_(policy_client), | 114 policy_client_(policy_client), |
105 cryptohome_client_(cryptohome_client), | 115 cryptohome_client_(cryptohome_client), |
106 attestation_flow_(attestation_flow), | 116 attestation_flow_(attestation_flow), |
117 num_retries_(0), | |
118 retry_delay_(kRetryDelay), | |
107 weak_factory_(this) { | 119 weak_factory_(this) { |
108 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | 120 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
109 cros_settings_->AddSettingsObserver(kDeviceAttestationEnabled, this); | 121 cros_settings_->AddSettingsObserver(kDeviceAttestationEnabled, this); |
110 Start(); | 122 Start(); |
111 } | 123 } |
112 | 124 |
113 AttestationPolicyObserver::~AttestationPolicyObserver() { | 125 AttestationPolicyObserver::~AttestationPolicyObserver() { |
114 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | 126 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
115 cros_settings_->RemoveSettingsObserver(kDeviceAttestationEnabled, this); | 127 cros_settings_->RemoveSettingsObserver(kDeviceAttestationEnabled, this); |
116 } | 128 } |
117 | 129 |
118 void AttestationPolicyObserver::Observe( | 130 void AttestationPolicyObserver::Observe( |
119 int type, | 131 int type, |
120 const content::NotificationSource& source, | 132 const content::NotificationSource& source, |
121 const content::NotificationDetails& details) { | 133 const content::NotificationDetails& details) { |
122 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | 134 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
123 std::string* path = content::Details<std::string>(details).ptr(); | 135 std::string* path = content::Details<std::string>(details).ptr(); |
124 if (type != chrome::NOTIFICATION_SYSTEM_SETTING_CHANGED || | 136 if (type != chrome::NOTIFICATION_SYSTEM_SETTING_CHANGED || |
125 *path != kDeviceAttestationEnabled) { | 137 *path != kDeviceAttestationEnabled) { |
126 LOG(WARNING) << "AttestationPolicyObserver: Unexpected event received."; | 138 LOG(WARNING) << "AttestationPolicyObserver: Unexpected event received."; |
127 return; | 139 return; |
128 } | 140 } |
141 num_retries_ = 0; | |
129 Start(); | 142 Start(); |
130 } | 143 } |
131 | 144 |
132 void AttestationPolicyObserver::Start() { | 145 void AttestationPolicyObserver::Start() { |
133 // If attestation is not enabled, there is nothing to do. | 146 // If attestation is not enabled, there is nothing to do. |
134 bool enabled = false; | 147 bool enabled = false; |
135 if (!cros_settings_->GetBoolean(kDeviceAttestationEnabled, &enabled) || | 148 if (!cros_settings_->GetBoolean(kDeviceAttestationEnabled, &enabled) || |
136 !enabled) | 149 !enabled) |
137 return; | 150 return; |
138 | 151 |
139 // We expect a registered CloudPolicyClient. | 152 // We expect a registered CloudPolicyClient. |
140 if (!policy_client_->is_registered()) { | 153 if (!policy_client_->is_registered()) { |
141 LOG(ERROR) << "AttestationPolicyObserver: Invalid CloudPolicyClient."; | 154 LOG(ERROR) << "AttestationPolicyObserver: Invalid CloudPolicyClient."; |
155 Reschedule(); | |
Mattias Nissler (ping if slow)
2013/07/02 08:18:07
Why is this needed?
dkrahn
2013/07/02 21:00:02
I haven't seen this fail but the idea was to resch
| |
142 return; | 156 return; |
143 } | 157 } |
144 | 158 |
145 if (!cryptohome_client_) | 159 if (!cryptohome_client_) |
146 cryptohome_client_ = DBusThreadManager::Get()->GetCryptohomeClient(); | 160 cryptohome_client_ = DBusThreadManager::Get()->GetCryptohomeClient(); |
147 | 161 |
148 if (!attestation_flow_) { | 162 if (!attestation_flow_) { |
149 scoped_ptr<ServerProxy> attestation_ca_client(new AttestationCAClient()); | 163 scoped_ptr<ServerProxy> attestation_ca_client(new AttestationCAClient()); |
150 default_attestation_flow_.reset(new AttestationFlow( | 164 default_attestation_flow_.reset(new AttestationFlow( |
151 cryptohome::AsyncMethodCaller::GetInstance(), | 165 cryptohome::AsyncMethodCaller::GetInstance(), |
152 cryptohome_client_, | 166 cryptohome_client_, |
153 attestation_ca_client.Pass())); | 167 attestation_ca_client.Pass())); |
154 attestation_flow_ = default_attestation_flow_.get(); | 168 attestation_flow_ = default_attestation_flow_.get(); |
155 } | 169 } |
156 | 170 |
157 // Start a dbus call to check if an Enterprise Machine Key already exists. | 171 // Start a dbus call to check if an Enterprise Machine Key already exists. |
158 base::Closure on_does_exist = | 172 base::Closure on_does_exist = |
159 base::Bind(&AttestationPolicyObserver::GetExistingCertificate, | 173 base::Bind(&AttestationPolicyObserver::GetExistingCertificate, |
160 weak_factory_.GetWeakPtr()); | 174 weak_factory_.GetWeakPtr()); |
161 base::Closure on_does_not_exist = | 175 base::Closure on_does_not_exist = |
162 base::Bind(&AttestationPolicyObserver::GetNewCertificate, | 176 base::Bind(&AttestationPolicyObserver::GetNewCertificate, |
163 weak_factory_.GetWeakPtr()); | 177 weak_factory_.GetWeakPtr()); |
164 cryptohome_client_->TpmAttestationDoesKeyExist( | 178 cryptohome_client_->TpmAttestationDoesKeyExist( |
165 KEY_DEVICE, | 179 KEY_DEVICE, |
166 kEnterpriseMachineKey, | 180 kEnterpriseMachineKey, |
167 base::Bind(DBusBoolRedirectCallback, | 181 base::Bind(DBusBoolRedirectCallback, |
168 on_does_exist, | 182 on_does_exist, |
169 on_does_not_exist, | 183 on_does_not_exist, |
184 base::Bind(&AttestationPolicyObserver::Reschedule, | |
185 weak_factory_.GetWeakPtr()), | |
170 FROM_HERE)); | 186 FROM_HERE)); |
171 } | 187 } |
172 | 188 |
173 void AttestationPolicyObserver::GetNewCertificate() { | 189 void AttestationPolicyObserver::GetNewCertificate() { |
174 // We can reuse the dbus callback handler logic. | 190 // We can reuse the dbus callback handler logic. |
175 attestation_flow_->GetCertificate( | 191 attestation_flow_->GetCertificate( |
176 PROFILE_ENTERPRISE_MACHINE_CERTIFICATE, | 192 PROFILE_ENTERPRISE_MACHINE_CERTIFICATE, |
177 true, // Force a new key to be generated. | 193 true, // Force a new key to be generated. |
178 base::Bind(DBusStringCallback, | 194 base::Bind(DBusStringCallback, |
179 base::Bind(&AttestationPolicyObserver::UploadCertificate, | 195 base::Bind(&AttestationPolicyObserver::UploadCertificate, |
180 weak_factory_.GetWeakPtr()), | 196 weak_factory_.GetWeakPtr()), |
197 base::Bind(&AttestationPolicyObserver::Reschedule, | |
198 weak_factory_.GetWeakPtr()), | |
181 FROM_HERE, | 199 FROM_HERE, |
182 DBUS_METHOD_CALL_SUCCESS)); | 200 DBUS_METHOD_CALL_SUCCESS)); |
183 } | 201 } |
184 | 202 |
185 void AttestationPolicyObserver::GetExistingCertificate() { | 203 void AttestationPolicyObserver::GetExistingCertificate() { |
186 cryptohome_client_->TpmAttestationGetCertificate( | 204 cryptohome_client_->TpmAttestationGetCertificate( |
187 KEY_DEVICE, | 205 KEY_DEVICE, |
188 kEnterpriseMachineKey, | 206 kEnterpriseMachineKey, |
189 base::Bind(DBusStringCallback, | 207 base::Bind(DBusStringCallback, |
190 base::Bind(&AttestationPolicyObserver::CheckCertificateExpiry, | 208 base::Bind(&AttestationPolicyObserver::CheckCertificateExpiry, |
191 weak_factory_.GetWeakPtr()), | 209 weak_factory_.GetWeakPtr()), |
210 base::Bind(&AttestationPolicyObserver::Reschedule, | |
211 weak_factory_.GetWeakPtr()), | |
192 FROM_HERE)); | 212 FROM_HERE)); |
193 } | 213 } |
194 | 214 |
195 void AttestationPolicyObserver::CheckCertificateExpiry( | 215 void AttestationPolicyObserver::CheckCertificateExpiry( |
196 const std::string& certificate) { | 216 const std::string& certificate) { |
197 scoped_refptr<net::X509Certificate> x509( | 217 scoped_refptr<net::X509Certificate> x509( |
198 net::X509Certificate::CreateFromBytes(certificate.data(), | 218 net::X509Certificate::CreateFromBytes(certificate.data(), |
199 certificate.length())); | 219 certificate.length())); |
200 if (!x509.get() || x509->valid_expiry().is_null()) { | 220 if (!x509.get() || x509->valid_expiry().is_null()) { |
201 LOG(WARNING) << "Failed to parse certificate, cannot check expiry."; | 221 LOG(WARNING) << "Failed to parse certificate, cannot check expiry."; |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
234 return; | 254 return; |
235 } | 255 } |
236 UploadCertificate(certificate); | 256 UploadCertificate(certificate); |
237 } | 257 } |
238 | 258 |
239 void AttestationPolicyObserver::GetKeyPayload( | 259 void AttestationPolicyObserver::GetKeyPayload( |
240 base::Callback<void(const std::string&)> callback) { | 260 base::Callback<void(const std::string&)> callback) { |
241 cryptohome_client_->TpmAttestationGetKeyPayload( | 261 cryptohome_client_->TpmAttestationGetKeyPayload( |
242 KEY_DEVICE, | 262 KEY_DEVICE, |
243 kEnterpriseMachineKey, | 263 kEnterpriseMachineKey, |
244 base::Bind(DBusStringCallback, callback, FROM_HERE)); | 264 base::Bind(DBusStringCallback, |
265 callback, | |
266 base::Bind(&AttestationPolicyObserver::Reschedule, | |
267 weak_factory_.GetWeakPtr()), | |
268 FROM_HERE)); | |
245 } | 269 } |
246 | 270 |
247 void AttestationPolicyObserver::OnUploadComplete(bool status) { | 271 void AttestationPolicyObserver::OnUploadComplete(bool status) { |
248 if (!status) | 272 if (!status) { |
273 Reschedule(); | |
Mattias Nissler (ping if slow)
2013/07/02 08:18:07
This is probably not a good idea. You'll hammer th
dkrahn
2013/07/02 21:00:02
You're right. This may be more work than I though
| |
249 return; | 274 return; |
275 } | |
276 LOG(INFO) << "Enterprise Machine Certificate uploaded to DMServer."; | |
250 GetKeyPayload(base::Bind(&AttestationPolicyObserver::MarkAsUploaded, | 277 GetKeyPayload(base::Bind(&AttestationPolicyObserver::MarkAsUploaded, |
251 weak_factory_.GetWeakPtr())); | 278 weak_factory_.GetWeakPtr())); |
252 } | 279 } |
253 | 280 |
254 void AttestationPolicyObserver::MarkAsUploaded(const std::string& key_payload) { | 281 void AttestationPolicyObserver::MarkAsUploaded(const std::string& key_payload) { |
255 AttestationKeyPayload payload_pb; | 282 AttestationKeyPayload payload_pb; |
256 if (!key_payload.empty()) | 283 if (!key_payload.empty()) |
257 payload_pb.ParseFromString(key_payload); | 284 payload_pb.ParseFromString(key_payload); |
258 payload_pb.set_is_certificate_uploaded(true); | 285 payload_pb.set_is_certificate_uploaded(true); |
259 std::string new_payload; | 286 std::string new_payload; |
260 if (!payload_pb.SerializeToString(&new_payload)) { | 287 if (!payload_pb.SerializeToString(&new_payload)) { |
261 LOG(WARNING) << "Failed to serialize key payload."; | 288 LOG(WARNING) << "Failed to serialize key payload."; |
262 return; | 289 return; |
263 } | 290 } |
264 cryptohome_client_->TpmAttestationSetKeyPayload( | 291 cryptohome_client_->TpmAttestationSetKeyPayload( |
265 KEY_DEVICE, | 292 KEY_DEVICE, |
266 kEnterpriseMachineKey, | 293 kEnterpriseMachineKey, |
267 new_payload, | 294 new_payload, |
268 base::Bind(DBusBoolRedirectCallback, | 295 base::Bind(DBusBoolRedirectCallback, |
269 base::Closure(), | 296 base::Closure(), |
270 base::Closure(), | 297 base::Closure(), |
298 base::Closure(), | |
271 FROM_HERE)); | 299 FROM_HERE)); |
272 } | 300 } |
273 | 301 |
302 void AttestationPolicyObserver::Reschedule() { | |
303 if (++num_retries_ < kRetryLimit) { | |
304 content::BrowserThread::PostDelayedTask( | |
305 content::BrowserThread::UI, FROM_HERE, | |
306 base::Bind(&AttestationPolicyObserver::Start, | |
307 weak_factory_.GetWeakPtr()), | |
308 base::TimeDelta::FromSeconds(retry_delay_)); | |
309 } else { | |
310 LOG(WARNING) << "AttestationPolicyObserver: Retry limit exceeded."; | |
311 } | |
312 } | |
313 | |
274 } // namespace attestation | 314 } // namespace attestation |
275 } // namespace chromeos | 315 } // namespace chromeos |
OLD | NEW |