- add sources.
[platform/framework/web/crosswalk.git] / src / chromeos / attestation / attestation_flow.cc
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 "chromeos/attestation/attestation_flow.h"
6
7 #include "base/bind.h"
8 #include "chromeos/cryptohome/async_method_caller.h"
9 #include "chromeos/dbus/cryptohome_client.h"
10
11 namespace chromeos {
12 namespace attestation {
13
14 namespace {
15
16 // Redirects to one of three callbacks based on a boolean value and dbus call
17 // status.
18 //
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;
35   }
36   const base::Closure& task = value ? on_true : on_false;
37   if (!task.is_null())
38     task.Run();
39 }
40
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;
51   }
52   if (!callback.is_null())
53     callback.Run(result, data);
54 }
55
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;
64   }
65   NOTREACHED();
66   return KEY_USER;
67 }
68
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;
78   }
79   NOTREACHED();
80   return "";
81 }
82
83 }  // namespace
84
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) {
92 }
93
94 AttestationFlow::~AttestationFlow() {
95 }
96
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));
123 }
124
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(base::Bind(
129       &AttestationFlow::SendEnrollRequestToPCA,
130       weak_factory_.GetWeakPtr(),
131       on_failure,
132       next_task));
133 }
134
135 void AttestationFlow::SendEnrollRequestToPCA(const base::Closure& on_failure,
136                                              const base::Closure& next_task,
137                                              bool success,
138                                              const std::string& data) {
139   if (!success) {
140     LOG(ERROR) << "Attestation: Failed to create enroll request.";
141     if (!on_failure.is_null())
142       on_failure.Run();
143     return;
144   }
145
146   // Send the request to the Privacy CA.
147   server_proxy_->SendEnrollRequest(
148       data,
149       base::Bind(&AttestationFlow::SendEnrollResponseToDaemon,
150                  weak_factory_.GetWeakPtr(),
151                  on_failure,
152                  next_task));
153 }
154
155 void AttestationFlow::SendEnrollResponseToDaemon(
156     const base::Closure& on_failure,
157     const base::Closure& next_task,
158     bool success,
159     const std::string& data) {
160   if (!success) {
161     LOG(ERROR) << "Attestation: Enroll request failed.";
162     if (!on_failure.is_null())
163       on_failure.Run();
164     return;
165   }
166
167   // Forward the response to the attestation service to complete enrollment.
168   async_caller_->AsyncTpmAttestationEnroll(
169       data,
170       base::Bind(&AttestationFlow::OnEnrollComplete,
171                  weak_factory_.GetWeakPtr(),
172                  on_failure,
173                  next_task));
174 }
175
176 void AttestationFlow::OnEnrollComplete(const base::Closure& on_failure,
177                                        const base::Closure& next_task,
178                                        bool success,
179                                        cryptohome::MountError /*not_used*/) {
180   if (!success) {
181     LOG(ERROR) << "Attestation: Failed to complete enrollment.";
182     if (!on_failure.is_null())
183       on_failure.Run();
184     return;
185   }
186
187   // Enrollment has successfully completed, we can move on to whatever is next.
188   if (!next_task.is_null())
189     next_task.Run();
190 }
191
192 void AttestationFlow::StartCertificateRequest(
193     AttestationCertificateProfile certificate_profile,
194     const std::string& user_id,
195     const std::string& request_origin,
196     bool generate_new_key,
197     const CertificateCallback& callback) {
198   AttestationKeyType key_type = GetKeyTypeForProfile(certificate_profile);
199   std::string key_name = GetKeyNameForProfile(certificate_profile,
200                                               request_origin);
201   if (generate_new_key) {
202     // Get the attestation service to create a Privacy CA certificate request.
203     async_caller_->AsyncTpmAttestationCreateCertRequest(
204         certificate_profile,
205         user_id,
206         request_origin,
207         base::Bind(&AttestationFlow::SendCertificateRequestToPCA,
208                    weak_factory_.GetWeakPtr(),
209                    key_type,
210                    user_id,
211                    key_name,
212                    callback));
213   } else {
214     // If the key already exists, query the existing certificate.
215     base::Closure on_key_exists = base::Bind(
216         &AttestationFlow::GetExistingCertificate,
217         weak_factory_.GetWeakPtr(),
218         key_type,
219         user_id,
220         key_name,
221         callback);
222     // If the key does not exist, call this method back with |generate_new_key|
223     // set to true.
224     base::Closure on_key_not_exists = base::Bind(
225         &AttestationFlow::StartCertificateRequest,
226         weak_factory_.GetWeakPtr(),
227         certificate_profile,
228         user_id,
229         request_origin,
230         true,
231         callback);
232     cryptohome_client_->TpmAttestationDoesKeyExist(
233         key_type,
234         user_id,
235         key_name,
236         base::Bind(&DBusBoolRedirectCallback,
237             on_key_exists,
238             on_key_not_exists,
239             base::Bind(callback, false, "")));
240   }
241 }
242
243 void AttestationFlow::SendCertificateRequestToPCA(
244     AttestationKeyType key_type,
245     const std::string& user_id,
246     const std::string& key_name,
247     const CertificateCallback& callback,
248     bool success,
249     const std::string& data) {
250   if (!success) {
251     LOG(ERROR) << "Attestation: Failed to create certificate request.";
252     if (!callback.is_null())
253       callback.Run(false, "");
254     return;
255   }
256
257   // Send the request to the Privacy CA.
258   server_proxy_->SendCertificateRequest(
259       data,
260       base::Bind(&AttestationFlow::SendCertificateResponseToDaemon,
261                  weak_factory_.GetWeakPtr(),
262                  key_type,
263                  user_id,
264                  key_name,
265                  callback));
266 }
267
268 void AttestationFlow::SendCertificateResponseToDaemon(
269     AttestationKeyType key_type,
270     const std::string& user_id,
271     const std::string& key_name,
272     const CertificateCallback& callback,
273     bool success,
274     const std::string& data) {
275   if (!success) {
276     LOG(ERROR) << "Attestation: Certificate request failed.";
277     if (!callback.is_null())
278       callback.Run(false, "");
279     return;
280   }
281
282   // Forward the response to the attestation service to complete the operation.
283   async_caller_->AsyncTpmAttestationFinishCertRequest(data,
284                                                       key_type,
285                                                       user_id,
286                                                       key_name,
287                                                       base::Bind(callback));
288 }
289
290 void AttestationFlow::GetExistingCertificate(
291     AttestationKeyType key_type,
292     const std::string& user_id,
293     const std::string& key_name,
294     const CertificateCallback& callback) {
295   cryptohome_client_->TpmAttestationGetCertificate(
296       key_type,
297       user_id,
298       key_name,
299       base::Bind(&DBusDataMethodCallback, callback));
300 }
301
302 }  // namespace attestation
303 }  // namespace chromeos