Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chromeos / attestation / attestation_flow.cc
blob7cfdc87530febf39269a91d4221543d922502f96
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.
5 #include "chromeos/attestation/attestation_flow.h"
7 #include "base/bind.h"
8 #include "chromeos/cryptohome/async_method_caller.h"
9 #include "chromeos/dbus/cryptohome_client.h"
11 namespace chromeos {
12 namespace attestation {
14 namespace {
16 // Redirects to one of three callbacks based on a boolean value and dbus call
17 // status.
19 // Parameters
20 // on_true - Called when status=succes and value=true.
21 // on_false - Called when status=success and value=false.
22 // on_fail - Called when status=failure.
23 // status - The D-Bus operation status.
24 // value - The value returned by the D-Bus operation.
25 void DBusBoolRedirectCallback(const base::Closure& on_true,
26 const base::Closure& on_false,
27 const base::Closure& on_fail,
28 DBusMethodCallStatus status,
29 bool value) {
30 if (status != DBUS_METHOD_CALL_SUCCESS) {
31 LOG(ERROR) << "Attestation: Failed to query enrollment state.";
32 if (!on_fail.is_null())
33 on_fail.Run();
34 return;
36 const base::Closure& task = value ? on_true : on_false;
37 if (!task.is_null())
38 task.Run();
41 void DBusDataMethodCallback(
42 const AttestationFlow::CertificateCallback& callback,
43 DBusMethodCallStatus status,
44 bool result,
45 const std::string& data) {
46 if (status != DBUS_METHOD_CALL_SUCCESS) {
47 LOG(ERROR) << "Attestation: DBus data operation failed.";
48 if (!callback.is_null())
49 callback.Run(false, "");
50 return;
52 if (!callback.is_null())
53 callback.Run(result, data);
56 AttestationKeyType GetKeyTypeForProfile(
57 AttestationCertificateProfile profile) {
58 switch (profile) {
59 case PROFILE_ENTERPRISE_MACHINE_CERTIFICATE:
60 return KEY_DEVICE;
61 case PROFILE_ENTERPRISE_USER_CERTIFICATE:
62 case PROFILE_CONTENT_PROTECTION_CERTIFICATE:
63 return KEY_USER;
65 NOTREACHED();
66 return KEY_USER;
69 std::string GetKeyNameForProfile(AttestationCertificateProfile profile,
70 const std::string& origin) {
71 switch (profile) {
72 case PROFILE_ENTERPRISE_MACHINE_CERTIFICATE:
73 return kEnterpriseMachineKey;
74 case PROFILE_ENTERPRISE_USER_CERTIFICATE:
75 return kEnterpriseUserKey;
76 case PROFILE_CONTENT_PROTECTION_CERTIFICATE:
77 return std::string(kContentProtectionKeyPrefix) + origin;
79 NOTREACHED();
80 return "";
83 } // namespace
85 AttestationFlow::AttestationFlow(cryptohome::AsyncMethodCaller* async_caller,
86 CryptohomeClient* cryptohome_client,
87 scoped_ptr<ServerProxy> server_proxy)
88 : async_caller_(async_caller),
89 cryptohome_client_(cryptohome_client),
90 server_proxy_(server_proxy.Pass()),
91 weak_factory_(this) {
94 AttestationFlow::~AttestationFlow() {
97 void AttestationFlow::GetCertificate(
98 AttestationCertificateProfile certificate_profile,
99 const std::string& user_id,
100 const std::string& request_origin,
101 bool force_new_key,
102 const CertificateCallback& callback) {
103 // If this device has not enrolled with the Privacy CA, we need to do that
104 // first. Once enrolled we can proceed with the certificate request.
105 base::Closure do_cert_request = base::Bind(
106 &AttestationFlow::StartCertificateRequest,
107 weak_factory_.GetWeakPtr(),
108 certificate_profile,
109 user_id,
110 request_origin,
111 force_new_key,
112 callback);
113 base::Closure on_enroll_failure = base::Bind(callback, false, "");
114 base::Closure do_enroll = base::Bind(&AttestationFlow::StartEnroll,
115 weak_factory_.GetWeakPtr(),
116 on_enroll_failure,
117 do_cert_request);
118 cryptohome_client_->TpmAttestationIsEnrolled(base::Bind(
119 &DBusBoolRedirectCallback,
120 do_cert_request, // If enrolled, proceed with cert request.
121 do_enroll, // If not enrolled, initiate enrollment.
122 on_enroll_failure));
125 void AttestationFlow::StartEnroll(const base::Closure& on_failure,
126 const base::Closure& next_task) {
127 // Get the attestation service to create a Privacy CA enrollment request.
128 async_caller_->AsyncTpmAttestationCreateEnrollRequest(
129 server_proxy_->GetType(),
130 base::Bind(&AttestationFlow::SendEnrollRequestToPCA,
131 weak_factory_.GetWeakPtr(),
132 on_failure,
133 next_task));
136 void AttestationFlow::SendEnrollRequestToPCA(const base::Closure& on_failure,
137 const base::Closure& next_task,
138 bool success,
139 const std::string& data) {
140 if (!success) {
141 LOG(ERROR) << "Attestation: Failed to create enroll request.";
142 if (!on_failure.is_null())
143 on_failure.Run();
144 return;
147 // Send the request to the Privacy CA.
148 server_proxy_->SendEnrollRequest(
149 data,
150 base::Bind(&AttestationFlow::SendEnrollResponseToDaemon,
151 weak_factory_.GetWeakPtr(),
152 on_failure,
153 next_task));
156 void AttestationFlow::SendEnrollResponseToDaemon(
157 const base::Closure& on_failure,
158 const base::Closure& next_task,
159 bool success,
160 const std::string& data) {
161 if (!success) {
162 LOG(ERROR) << "Attestation: Enroll request failed.";
163 if (!on_failure.is_null())
164 on_failure.Run();
165 return;
168 // Forward the response to the attestation service to complete enrollment.
169 async_caller_->AsyncTpmAttestationEnroll(
170 server_proxy_->GetType(),
171 data,
172 base::Bind(&AttestationFlow::OnEnrollComplete,
173 weak_factory_.GetWeakPtr(),
174 on_failure,
175 next_task));
178 void AttestationFlow::OnEnrollComplete(const base::Closure& on_failure,
179 const base::Closure& next_task,
180 bool success,
181 cryptohome::MountError /*not_used*/) {
182 if (!success) {
183 LOG(ERROR) << "Attestation: Failed to complete enrollment.";
184 if (!on_failure.is_null())
185 on_failure.Run();
186 return;
189 // Enrollment has successfully completed, we can move on to whatever is next.
190 if (!next_task.is_null())
191 next_task.Run();
194 void AttestationFlow::StartCertificateRequest(
195 AttestationCertificateProfile certificate_profile,
196 const std::string& user_id,
197 const std::string& request_origin,
198 bool generate_new_key,
199 const CertificateCallback& callback) {
200 AttestationKeyType key_type = GetKeyTypeForProfile(certificate_profile);
201 std::string key_name = GetKeyNameForProfile(certificate_profile,
202 request_origin);
203 if (generate_new_key) {
204 // Get the attestation service to create a Privacy CA certificate request.
205 async_caller_->AsyncTpmAttestationCreateCertRequest(
206 server_proxy_->GetType(),
207 certificate_profile,
208 user_id,
209 request_origin,
210 base::Bind(&AttestationFlow::SendCertificateRequestToPCA,
211 weak_factory_.GetWeakPtr(),
212 key_type,
213 user_id,
214 key_name,
215 callback));
216 } else {
217 // If the key already exists, query the existing certificate.
218 base::Closure on_key_exists = base::Bind(
219 &AttestationFlow::GetExistingCertificate,
220 weak_factory_.GetWeakPtr(),
221 key_type,
222 user_id,
223 key_name,
224 callback);
225 // If the key does not exist, call this method back with |generate_new_key|
226 // set to true.
227 base::Closure on_key_not_exists = base::Bind(
228 &AttestationFlow::StartCertificateRequest,
229 weak_factory_.GetWeakPtr(),
230 certificate_profile,
231 user_id,
232 request_origin,
233 true,
234 callback);
235 cryptohome_client_->TpmAttestationDoesKeyExist(
236 key_type,
237 user_id,
238 key_name,
239 base::Bind(&DBusBoolRedirectCallback,
240 on_key_exists,
241 on_key_not_exists,
242 base::Bind(callback, false, "")));
246 void AttestationFlow::SendCertificateRequestToPCA(
247 AttestationKeyType key_type,
248 const std::string& user_id,
249 const std::string& key_name,
250 const CertificateCallback& callback,
251 bool success,
252 const std::string& data) {
253 if (!success) {
254 LOG(ERROR) << "Attestation: Failed to create certificate request.";
255 if (!callback.is_null())
256 callback.Run(false, "");
257 return;
260 // Send the request to the Privacy CA.
261 server_proxy_->SendCertificateRequest(
262 data,
263 base::Bind(&AttestationFlow::SendCertificateResponseToDaemon,
264 weak_factory_.GetWeakPtr(),
265 key_type,
266 user_id,
267 key_name,
268 callback));
271 void AttestationFlow::SendCertificateResponseToDaemon(
272 AttestationKeyType key_type,
273 const std::string& user_id,
274 const std::string& key_name,
275 const CertificateCallback& callback,
276 bool success,
277 const std::string& data) {
278 if (!success) {
279 LOG(ERROR) << "Attestation: Certificate request failed.";
280 if (!callback.is_null())
281 callback.Run(false, "");
282 return;
285 // Forward the response to the attestation service to complete the operation.
286 async_caller_->AsyncTpmAttestationFinishCertRequest(data,
287 key_type,
288 user_id,
289 key_name,
290 base::Bind(callback));
293 void AttestationFlow::GetExistingCertificate(
294 AttestationKeyType key_type,
295 const std::string& user_id,
296 const std::string& key_name,
297 const CertificateCallback& callback) {
298 cryptohome_client_->TpmAttestationGetCertificate(
299 key_type,
300 user_id,
301 key_name,
302 base::Bind(&DBusDataMethodCallback, callback));
305 ServerProxy::~ServerProxy() {}
307 PrivacyCAType ServerProxy::GetType() {
308 return DEFAULT_PCA;
311 } // namespace attestation
312 } // namespace chromeos