Home | History | Annotate | Download | only in attestation
      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(
    129       server_proxy_->GetType(),
    130       base::Bind(&AttestationFlow::SendEnrollRequestToPCA,
    131                  weak_factory_.GetWeakPtr(),
    132                  on_failure,
    133                  next_task));
    134 }
    135 
    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;
    145   }
    146 
    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));
    154 }
    155 
    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;
    166   }
    167 
    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));
    176 }
    177 
    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;
    187   }
    188 
    189   // Enrollment has successfully completed, we can move on to whatever is next.
    190   if (!next_task.is_null())
    191     next_task.Run();
    192 }
    193 
    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, "")));
    243   }
    244 }
    245 
    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;
    258   }
    259 
    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));
    269 }
    270 
    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;
    283   }
    284 
    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));
    291 }
    292 
    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));
    303 }
    304 
    305 ServerProxy::~ServerProxy() {}
    306 
    307 PrivacyCAType ServerProxy::GetType() {
    308   return DEFAULT_PCA;
    309 }
    310 
    311 }  // namespace attestation
    312 }  // namespace chromeos
    313