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(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
    304