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"
8 #include "chromeos/cryptohome/async_method_caller.h"
9 #include "chromeos/dbus/cryptohome_client.h"
12 namespace attestation {
16 // Redirects to one of three callbacks based on a boolean value and dbus call
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,
30 if (status != DBUS_METHOD_CALL_SUCCESS) {
31 LOG(ERROR) << "Attestation: Failed to query enrollment state.";
32 if (!on_fail.is_null())
36 const base::Closure& task = value ? on_true : on_false;
41 void DBusDataMethodCallback(
42 const AttestationFlow::CertificateCallback& callback,
43 DBusMethodCallStatus status,
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, "");
52 if (!callback.is_null())
53 callback.Run(result, data);
56 AttestationKeyType GetKeyTypeForProfile(
57 AttestationCertificateProfile profile) {
59 case PROFILE_ENTERPRISE_MACHINE_CERTIFICATE:
61 case PROFILE_ENTERPRISE_USER_CERTIFICATE:
62 case PROFILE_CONTENT_PROTECTION_CERTIFICATE:
69 std::string GetKeyNameForProfile(AttestationCertificateProfile profile,
70 const std::string& origin) {
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;
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()),
94 AttestationFlow::~AttestationFlow() {
97 void AttestationFlow::GetCertificate(
98 AttestationCertificateProfile certificate_profile,
99 const std::string& user_id,
100 const std::string& request_origin,
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(),
113 base::Closure on_enroll_failure = base::Bind(callback, false, "");
114 base::Closure do_enroll = base::Bind(&AttestationFlow::StartEnroll,
115 weak_factory_.GetWeakPtr(),
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.
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(),
135 void AttestationFlow::SendEnrollRequestToPCA(const base::Closure& on_failure,
136 const base::Closure& next_task,
138 const std::string& data) {
140 LOG(ERROR) << "Attestation: Failed to create enroll request.";
141 if (!on_failure.is_null())
146 // Send the request to the Privacy CA.
147 server_proxy_->SendEnrollRequest(
149 base::Bind(&AttestationFlow::SendEnrollResponseToDaemon,
150 weak_factory_.GetWeakPtr(),
155 void AttestationFlow::SendEnrollResponseToDaemon(
156 const base::Closure& on_failure,
157 const base::Closure& next_task,
159 const std::string& data) {
161 LOG(ERROR) << "Attestation: Enroll request failed.";
162 if (!on_failure.is_null())
167 // Forward the response to the attestation service to complete enrollment.
168 async_caller_->AsyncTpmAttestationEnroll(
170 base::Bind(&AttestationFlow::OnEnrollComplete,
171 weak_factory_.GetWeakPtr(),
176 void AttestationFlow::OnEnrollComplete(const base::Closure& on_failure,
177 const base::Closure& next_task,
179 cryptohome::MountError /*not_used*/) {
181 LOG(ERROR) << "Attestation: Failed to complete enrollment.";
182 if (!on_failure.is_null())
187 // Enrollment has successfully completed, we can move on to whatever is next.
188 if (!next_task.is_null())
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,
201 if (generate_new_key) {
202 // Get the attestation service to create a Privacy CA certificate request.
203 async_caller_->AsyncTpmAttestationCreateCertRequest(
207 base::Bind(&AttestationFlow::SendCertificateRequestToPCA,
208 weak_factory_.GetWeakPtr(),
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(),
222 // If the key does not exist, call this method back with |generate_new_key|
224 base::Closure on_key_not_exists = base::Bind(
225 &AttestationFlow::StartCertificateRequest,
226 weak_factory_.GetWeakPtr(),
232 cryptohome_client_->TpmAttestationDoesKeyExist(
236 base::Bind(&DBusBoolRedirectCallback,
239 base::Bind(callback, false, "")));
243 void AttestationFlow::SendCertificateRequestToPCA(
244 AttestationKeyType key_type,
245 const std::string& user_id,
246 const std::string& key_name,
247 const CertificateCallback& callback,
249 const std::string& data) {
251 LOG(ERROR) << "Attestation: Failed to create certificate request.";
252 if (!callback.is_null())
253 callback.Run(false, "");
257 // Send the request to the Privacy CA.
258 server_proxy_->SendCertificateRequest(
260 base::Bind(&AttestationFlow::SendCertificateResponseToDaemon,
261 weak_factory_.GetWeakPtr(),
268 void AttestationFlow::SendCertificateResponseToDaemon(
269 AttestationKeyType key_type,
270 const std::string& user_id,
271 const std::string& key_name,
272 const CertificateCallback& callback,
274 const std::string& data) {
276 LOG(ERROR) << "Attestation: Certificate request failed.";
277 if (!callback.is_null())
278 callback.Run(false, "");
282 // Forward the response to the attestation service to complete the operation.
283 async_caller_->AsyncTpmAttestationFinishCertRequest(data,
287 base::Bind(callback));
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(
299 base::Bind(&DBusDataMethodCallback, callback));
302 } // namespace attestation
303 } // namespace chromeos