Home | History | Annotate | Download | only in cryptohome
      1 // Copyright 2014 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/cryptohome/homedir_methods.h"
      6 
      7 #include "base/bind.h"
      8 #include "chromeos/dbus/cryptohome/key.pb.h"
      9 #include "chromeos/dbus/cryptohome/rpc.pb.h"
     10 #include "chromeos/dbus/cryptohome_client.h"
     11 #include "chromeos/dbus/dbus_thread_manager.h"
     12 
     13 using chromeos::DBusThreadManager;
     14 
     15 namespace cryptohome {
     16 
     17 namespace {
     18 
     19 HomedirMethods* g_homedir_methods = NULL;
     20 
     21 void FillKeyProtobuf(const KeyDefinition& key_def, Key* key) {
     22   key->set_secret(key_def.key);
     23   KeyData* data = key->mutable_data();
     24   data->set_label(key_def.label);
     25 
     26   if (key_def.revision > 0)
     27     data->set_revision(key_def.revision);
     28 
     29   if (key_def.privileges != 0) {
     30     KeyPrivileges* privileges = data->mutable_privileges();
     31     privileges->set_mount(key_def.privileges & PRIV_MOUNT);
     32     privileges->set_add(key_def.privileges & PRIV_ADD);
     33     privileges->set_remove(key_def.privileges & PRIV_REMOVE);
     34     privileges->set_update(key_def.privileges & PRIV_MIGRATE);
     35     privileges->set_authorized_update(key_def.privileges &
     36                                       PRIV_AUTHORIZED_UPDATE);
     37   }
     38 
     39   if (key_def.encryption_key.empty() && key_def.signature_key.empty())
     40     return;
     41 
     42   KeyAuthorizationData* auth_data = data->add_authorization_data();
     43   auth_data->set_type(KeyAuthorizationData::KEY_AUTHORIZATION_TYPE_HMACSHA256);
     44   if (!key_def.encryption_key.empty()) {
     45     KeyAuthorizationSecret* secret = auth_data->add_secrets();
     46     secret->mutable_usage()->set_encrypt(true);
     47     secret->set_symmetric_key(key_def.encryption_key);
     48   }
     49   if (!key_def.signature_key.empty()) {
     50     KeyAuthorizationSecret* secret = auth_data->add_secrets();
     51     secret->mutable_usage()->set_sign(true);
     52     secret->set_symmetric_key(key_def.signature_key);
     53   }
     54 }
     55 
     56 // Fill identification protobuffer.
     57 void FillIdentificationProtobuf(const Identification& id,
     58                                 cryptohome::AccountIdentifier* id_proto) {
     59   id_proto->set_email(id.user_id);
     60 }
     61 
     62 // Fill authorization protobuffer.
     63 void FillAuthorizationProtobuf(const Authorization& auth,
     64                                cryptohome::AuthorizationRequest* auth_proto) {
     65   Key* key = auth_proto->mutable_key();
     66   if (!auth.label.empty()) {
     67     key->mutable_data()->set_label(auth.label);
     68   }
     69   key->set_secret(auth.key);
     70 }
     71 
     72 MountError MapError(CryptohomeErrorCode code) {
     73   switch (code) {
     74     case CRYPTOHOME_ERROR_NOT_SET:
     75       return MOUNT_ERROR_NONE;
     76     case CRYPTOHOME_ERROR_ACCOUNT_NOT_FOUND:
     77       return MOUNT_ERROR_USER_DOES_NOT_EXIST;
     78     case CRYPTOHOME_ERROR_NOT_IMPLEMENTED:
     79     case CRYPTOHOME_ERROR_MOUNT_FATAL:
     80     case CRYPTOHOME_ERROR_KEY_QUOTA_EXCEEDED:
     81     case CRYPTOHOME_ERROR_BACKING_STORE_FAILURE:
     82       return MOUNT_ERROR_FATAL;
     83     case CRYPTOHOME_ERROR_AUTHORIZATION_KEY_NOT_FOUND:
     84     case CRYPTOHOME_ERROR_KEY_NOT_FOUND:
     85     case CRYPTOHOME_ERROR_AUTHORIZATION_KEY_FAILED:
     86       return MOUNT_ERROR_KEY_FAILURE;
     87     case CRYPTOHOME_ERROR_TPM_COMM_ERROR:
     88       return MOUNT_ERROR_TPM_COMM_ERROR;
     89     case CRYPTOHOME_ERROR_TPM_DEFEND_LOCK:
     90       return MOUNT_ERROR_TPM_DEFEND_LOCK;
     91     case CRYPTOHOME_ERROR_MOUNT_MOUNT_POINT_BUSY:
     92       return MOUNT_ERROR_MOUNT_POINT_BUSY;
     93     case CRYPTOHOME_ERROR_TPM_NEEDS_REBOOT:
     94       return MOUNT_ERROR_TPM_NEEDS_REBOOT;
     95     case CRYPTOHOME_ERROR_AUTHORIZATION_KEY_DENIED:
     96     case CRYPTOHOME_ERROR_KEY_LABEL_EXISTS:
     97     case CRYPTOHOME_ERROR_UPDATE_SIGNATURE_INVALID:
     98       return MOUNT_ERROR_KEY_FAILURE;
     99     default:
    100       NOTREACHED();
    101       return MOUNT_ERROR_FATAL;
    102   }
    103 }
    104 
    105 // The implementation of HomedirMethods
    106 class HomedirMethodsImpl : public HomedirMethods {
    107  public:
    108   HomedirMethodsImpl() : weak_ptr_factory_(this) {}
    109 
    110   virtual ~HomedirMethodsImpl() {}
    111 
    112   virtual void CheckKeyEx(const Identification& id,
    113                           const Authorization& auth,
    114                           const Callback& callback) OVERRIDE {
    115     cryptohome::AccountIdentifier id_proto;
    116     cryptohome::AuthorizationRequest auth_proto;
    117     cryptohome::CheckKeyRequest request;
    118 
    119     FillIdentificationProtobuf(id, &id_proto);
    120     FillAuthorizationProtobuf(auth, &auth_proto);
    121 
    122     DBusThreadManager::Get()->GetCryptohomeClient()->CheckKeyEx(
    123         id_proto,
    124         auth_proto,
    125         request,
    126         base::Bind(&HomedirMethodsImpl::OnBaseReplyCallback,
    127                    weak_ptr_factory_.GetWeakPtr(),
    128                    callback));
    129   }
    130 
    131   virtual void MountEx(const Identification& id,
    132                        const Authorization& auth,
    133                        const MountParameters& request,
    134                        const MountCallback& callback) OVERRIDE {
    135     cryptohome::AccountIdentifier id_proto;
    136     cryptohome::AuthorizationRequest auth_proto;
    137     cryptohome::MountRequest request_proto;
    138 
    139     FillIdentificationProtobuf(id, &id_proto);
    140     FillAuthorizationProtobuf(auth, &auth_proto);
    141 
    142     if (request.ephemeral)
    143       request_proto.set_require_ephemeral(true);
    144 
    145     if (!request.create_keys.empty()) {
    146       CreateRequest* create = request_proto.mutable_create();
    147       for (size_t i = 0; i < request.create_keys.size(); ++i)
    148         FillKeyProtobuf(request.create_keys[i], create->add_keys());
    149     }
    150 
    151     DBusThreadManager::Get()->GetCryptohomeClient()->MountEx(
    152         id_proto,
    153         auth_proto,
    154         request_proto,
    155         base::Bind(&HomedirMethodsImpl::OnMountExCallback,
    156                    weak_ptr_factory_.GetWeakPtr(),
    157                    callback));
    158   }
    159 
    160   virtual void AddKeyEx(const Identification& id,
    161                         const Authorization& auth,
    162                         const KeyDefinition& new_key,
    163                         bool clobber_if_exists,
    164                         const Callback& callback) OVERRIDE {
    165     cryptohome::AccountIdentifier id_proto;
    166     cryptohome::AuthorizationRequest auth_proto;
    167     cryptohome::AddKeyRequest request;
    168 
    169     FillIdentificationProtobuf(id, &id_proto);
    170     FillAuthorizationProtobuf(auth, &auth_proto);
    171     FillKeyProtobuf(new_key, request.mutable_key());
    172     request.set_clobber_if_exists(clobber_if_exists);
    173 
    174     DBusThreadManager::Get()->GetCryptohomeClient()->AddKeyEx(
    175         id_proto,
    176         auth_proto,
    177         request,
    178         base::Bind(&HomedirMethodsImpl::OnBaseReplyCallback,
    179                    weak_ptr_factory_.GetWeakPtr(),
    180                    callback));
    181   }
    182 
    183   virtual void RemoveKeyEx(const Identification& id,
    184                            const Authorization& auth,
    185                            const std::string& label,
    186                            const Callback& callback) OVERRIDE {
    187     cryptohome::AccountIdentifier id_proto;
    188     cryptohome::AuthorizationRequest auth_proto;
    189     cryptohome::RemoveKeyRequest request;
    190 
    191     FillIdentificationProtobuf(id, &id_proto);
    192     FillAuthorizationProtobuf(auth, &auth_proto);
    193     request.mutable_key()->mutable_data()->set_label(label);
    194 
    195     DBusThreadManager::Get()->GetCryptohomeClient()->RemoveKeyEx(
    196         id_proto,
    197         auth_proto,
    198         request,
    199         base::Bind(&HomedirMethodsImpl::OnBaseReplyCallback,
    200                    weak_ptr_factory_.GetWeakPtr(),
    201                    callback));
    202   }
    203 
    204   virtual void UpdateKeyEx(const Identification& id,
    205                            const Authorization& auth,
    206                            const KeyDefinition& new_key,
    207                            const std::string& signature,
    208                            const Callback& callback) OVERRIDE {
    209     cryptohome::AccountIdentifier id_proto;
    210     cryptohome::AuthorizationRequest auth_proto;
    211     cryptohome::UpdateKeyRequest pb_update_key;
    212 
    213     FillIdentificationProtobuf(id, &id_proto);
    214     FillAuthorizationProtobuf(auth, &auth_proto);
    215     FillKeyProtobuf(new_key, pb_update_key.mutable_changes());
    216     pb_update_key.set_authorization_signature(signature);
    217 
    218     DBusThreadManager::Get()->GetCryptohomeClient()->UpdateKeyEx(
    219         id_proto,
    220         auth_proto,
    221         pb_update_key,
    222         base::Bind(&HomedirMethodsImpl::OnBaseReplyCallback,
    223                    weak_ptr_factory_.GetWeakPtr(),
    224                    callback));
    225   }
    226 
    227  private:
    228   void OnMountExCallback(const MountCallback& callback,
    229                          chromeos::DBusMethodCallStatus call_status,
    230                          bool result,
    231                          const BaseReply& reply) {
    232     if (call_status != chromeos::DBUS_METHOD_CALL_SUCCESS) {
    233       callback.Run(false, MOUNT_ERROR_FATAL, std::string());
    234       return;
    235     }
    236     if (reply.has_error()) {
    237       if (reply.error() != CRYPTOHOME_ERROR_NOT_SET) {
    238         callback.Run(false, MapError(reply.error()), std::string());
    239         return;
    240       }
    241     }
    242     if (!reply.HasExtension(MountReply::reply)) {
    243       callback.Run(false, MOUNT_ERROR_FATAL, std::string());
    244       return;
    245     }
    246 
    247     std::string mount_hash;
    248     mount_hash = reply.GetExtension(MountReply::reply).sanitized_username();
    249     callback.Run(true, MOUNT_ERROR_NONE, mount_hash);
    250   }
    251 
    252   void OnBaseReplyCallback(const Callback& callback,
    253                            chromeos::DBusMethodCallStatus call_status,
    254                            bool result,
    255                            const BaseReply& reply) {
    256     if (call_status != chromeos::DBUS_METHOD_CALL_SUCCESS) {
    257       callback.Run(false, MOUNT_ERROR_FATAL);
    258       return;
    259     }
    260     if (reply.has_error()) {
    261       if (reply.error() != CRYPTOHOME_ERROR_NOT_SET) {
    262         callback.Run(false, MapError(reply.error()));
    263         return;
    264       }
    265     }
    266     callback.Run(true, MOUNT_ERROR_NONE);
    267   }
    268 
    269   base::WeakPtrFactory<HomedirMethodsImpl> weak_ptr_factory_;
    270 
    271   DISALLOW_COPY_AND_ASSIGN(HomedirMethodsImpl);
    272 };
    273 
    274 }  // namespace
    275 
    276 // static
    277 void HomedirMethods::Initialize() {
    278   if (g_homedir_methods) {
    279     LOG(WARNING) << "HomedirMethods was already initialized";
    280     return;
    281   }
    282   g_homedir_methods = new HomedirMethodsImpl();
    283   VLOG(1) << "HomedirMethods initialized";
    284 }
    285 
    286 // static
    287 void HomedirMethods::InitializeForTesting(HomedirMethods* homedir_methods) {
    288   if (g_homedir_methods) {
    289     LOG(WARNING) << "HomedirMethods was already initialized";
    290     return;
    291   }
    292   g_homedir_methods = homedir_methods;
    293   VLOG(1) << "HomedirMethods initialized";
    294 }
    295 
    296 // static
    297 void HomedirMethods::Shutdown() {
    298   if (!g_homedir_methods) {
    299     LOG(WARNING) << "AsyncMethodCaller::Shutdown() called with NULL manager";
    300     return;
    301   }
    302   delete g_homedir_methods;
    303   g_homedir_methods = NULL;
    304   VLOG(1) << "HomedirMethods Shutdown completed";
    305 }
    306 
    307 // static
    308 HomedirMethods* HomedirMethods::GetInstance() { return g_homedir_methods; }
    309 
    310 }  // namespace cryptohome
    311