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 "base/logging.h"
      9 #include "chromeos/dbus/cryptohome/key.pb.h"
     10 #include "chromeos/dbus/cryptohome/rpc.pb.h"
     11 #include "chromeos/dbus/cryptohome_client.h"
     12 #include "chromeos/dbus/dbus_thread_manager.h"
     13 
     14 #if defined(USE_SYSTEM_PROTOBUF)
     15 #include <google/protobuf/repeated_field.h>
     16 #else
     17 #include "third_party/protobuf/src/google/protobuf/repeated_field.h"
     18 #endif
     19 
     20 using chromeos::DBusThreadManager;
     21 using google::protobuf::RepeatedPtrField;
     22 
     23 namespace cryptohome {
     24 
     25 namespace {
     26 
     27 HomedirMethods* g_homedir_methods = NULL;
     28 
     29 void FillKeyProtobuf(const KeyDefinition& key_def, Key* key) {
     30   key->set_secret(key_def.secret);
     31   KeyData* data = key->mutable_data();
     32   DCHECK_EQ(KeyDefinition::TYPE_PASSWORD, key_def.type);
     33   data->set_type(KeyData::KEY_TYPE_PASSWORD);
     34   data->set_label(key_def.label);
     35 
     36   if (key_def.revision > 0)
     37     data->set_revision(key_def.revision);
     38 
     39   if (key_def.privileges != 0) {
     40     KeyPrivileges* privileges = data->mutable_privileges();
     41     privileges->set_mount(key_def.privileges & PRIV_MOUNT);
     42     privileges->set_add(key_def.privileges & PRIV_ADD);
     43     privileges->set_remove(key_def.privileges & PRIV_REMOVE);
     44     privileges->set_update(key_def.privileges & PRIV_MIGRATE);
     45     privileges->set_authorized_update(key_def.privileges &
     46                                       PRIV_AUTHORIZED_UPDATE);
     47   }
     48 
     49   for (std::vector<KeyDefinition::AuthorizationData>::const_iterator auth_it =
     50           key_def.authorization_data.begin();
     51        auth_it != key_def.authorization_data.end(); ++auth_it) {
     52     KeyAuthorizationData* auth_data = data->add_authorization_data();
     53     switch (auth_it->type) {
     54       case KeyDefinition::AuthorizationData::TYPE_HMACSHA256:
     55         auth_data->set_type(
     56             KeyAuthorizationData::KEY_AUTHORIZATION_TYPE_HMACSHA256);
     57         break;
     58       case KeyDefinition::AuthorizationData::TYPE_AES256CBC_HMACSHA256:
     59         auth_data->set_type(
     60             KeyAuthorizationData::KEY_AUTHORIZATION_TYPE_AES256CBC_HMACSHA256);
     61         break;
     62       default:
     63         NOTREACHED();
     64         break;
     65     }
     66 
     67     for (std::vector<KeyDefinition::AuthorizationData::Secret>::const_iterator
     68              secret_it = auth_it->secrets.begin();
     69          secret_it != auth_it->secrets.end(); ++secret_it) {
     70       KeyAuthorizationSecret* secret = auth_data->add_secrets();
     71       secret->mutable_usage()->set_encrypt(secret_it->encrypt);
     72       secret->mutable_usage()->set_sign(secret_it->sign);
     73       if (!secret_it->symmetric_key.empty())
     74         secret->set_symmetric_key(secret_it->symmetric_key);
     75       if (!secret_it->public_key.empty())
     76         secret->set_public_key(secret_it->public_key);
     77       secret->set_wrapped(secret_it->wrapped);
     78     }
     79   }
     80 
     81   for (std::vector<KeyDefinition::ProviderData>::const_iterator it =
     82            key_def.provider_data.begin(); it != key_def.provider_data.end();
     83        ++it) {
     84     KeyProviderData::Entry* entry =
     85         data->mutable_provider_data()->add_entry();
     86     entry->set_name(it->name);
     87     if (it->number)
     88       entry->set_number(*it->number);
     89     if (it->bytes)
     90       entry->set_bytes(*it->bytes);
     91   }
     92 }
     93 
     94 // Fill identification protobuffer.
     95 void FillIdentificationProtobuf(const Identification& id,
     96                                 cryptohome::AccountIdentifier* id_proto) {
     97   id_proto->set_email(id.user_id);
     98 }
     99 
    100 // Fill authorization protobuffer.
    101 void FillAuthorizationProtobuf(const Authorization& auth,
    102                                cryptohome::AuthorizationRequest* auth_proto) {
    103   Key* key = auth_proto->mutable_key();
    104   if (!auth.label.empty()) {
    105     key->mutable_data()->set_label(auth.label);
    106   }
    107   key->set_secret(auth.key);
    108 }
    109 
    110 void ParseAuthorizationDataProtobuf(
    111     const KeyAuthorizationData& authorization_data_proto,
    112     KeyDefinition::AuthorizationData* authorization_data) {
    113   switch (authorization_data_proto.type()) {
    114     case KeyAuthorizationData::KEY_AUTHORIZATION_TYPE_HMACSHA256:
    115       authorization_data->type =
    116           KeyDefinition::AuthorizationData::TYPE_HMACSHA256;
    117       break;
    118     case KeyAuthorizationData::KEY_AUTHORIZATION_TYPE_AES256CBC_HMACSHA256:
    119       authorization_data->type =
    120           KeyDefinition::AuthorizationData::TYPE_AES256CBC_HMACSHA256;
    121       break;
    122     default:
    123       NOTREACHED();
    124       return;
    125   }
    126 
    127   for (RepeatedPtrField<KeyAuthorizationSecret>::const_iterator it =
    128           authorization_data_proto.secrets().begin();
    129        it != authorization_data_proto.secrets().end(); ++it) {
    130     authorization_data->secrets.push_back(
    131         KeyDefinition::AuthorizationData::Secret(it->usage().encrypt(),
    132                                                  it->usage().sign(),
    133                                                  it->symmetric_key(),
    134                                                  it->public_key(),
    135                                                  it->wrapped()));
    136   }
    137 }
    138 
    139 MountError MapError(CryptohomeErrorCode code) {
    140   switch (code) {
    141     case CRYPTOHOME_ERROR_NOT_SET:
    142       return MOUNT_ERROR_NONE;
    143     case CRYPTOHOME_ERROR_ACCOUNT_NOT_FOUND:
    144       return MOUNT_ERROR_USER_DOES_NOT_EXIST;
    145     case CRYPTOHOME_ERROR_NOT_IMPLEMENTED:
    146     case CRYPTOHOME_ERROR_MOUNT_FATAL:
    147     case CRYPTOHOME_ERROR_KEY_QUOTA_EXCEEDED:
    148     case CRYPTOHOME_ERROR_BACKING_STORE_FAILURE:
    149       return MOUNT_ERROR_FATAL;
    150     case CRYPTOHOME_ERROR_AUTHORIZATION_KEY_NOT_FOUND:
    151     case CRYPTOHOME_ERROR_KEY_NOT_FOUND:
    152     case CRYPTOHOME_ERROR_AUTHORIZATION_KEY_FAILED:
    153       return MOUNT_ERROR_KEY_FAILURE;
    154     case CRYPTOHOME_ERROR_TPM_COMM_ERROR:
    155       return MOUNT_ERROR_TPM_COMM_ERROR;
    156     case CRYPTOHOME_ERROR_TPM_DEFEND_LOCK:
    157       return MOUNT_ERROR_TPM_DEFEND_LOCK;
    158     case CRYPTOHOME_ERROR_MOUNT_MOUNT_POINT_BUSY:
    159       return MOUNT_ERROR_MOUNT_POINT_BUSY;
    160     case CRYPTOHOME_ERROR_TPM_NEEDS_REBOOT:
    161       return MOUNT_ERROR_TPM_NEEDS_REBOOT;
    162     case CRYPTOHOME_ERROR_AUTHORIZATION_KEY_DENIED:
    163     case CRYPTOHOME_ERROR_KEY_LABEL_EXISTS:
    164     case CRYPTOHOME_ERROR_UPDATE_SIGNATURE_INVALID:
    165       return MOUNT_ERROR_KEY_FAILURE;
    166     default:
    167       NOTREACHED();
    168       return MOUNT_ERROR_FATAL;
    169   }
    170 }
    171 
    172 // The implementation of HomedirMethods
    173 class HomedirMethodsImpl : public HomedirMethods {
    174  public:
    175   HomedirMethodsImpl() : weak_ptr_factory_(this) {}
    176 
    177   virtual ~HomedirMethodsImpl() {}
    178 
    179   virtual void GetKeyDataEx(const Identification& id,
    180                             const std::string& label,
    181                             const GetKeyDataCallback& callback) OVERRIDE {
    182     cryptohome::AccountIdentifier id_proto;
    183     cryptohome::AuthorizationRequest kEmptyAuthProto;
    184     cryptohome::GetKeyDataRequest request;
    185 
    186     FillIdentificationProtobuf(id, &id_proto);
    187     request.mutable_key()->mutable_data()->set_label(label);
    188 
    189     DBusThreadManager::Get()->GetCryptohomeClient()->GetKeyDataEx(
    190         id_proto,
    191         kEmptyAuthProto,
    192         request,
    193         base::Bind(&HomedirMethodsImpl::OnGetKeyDataExCallback,
    194                    weak_ptr_factory_.GetWeakPtr(),
    195                    callback));
    196   }
    197 
    198   virtual void CheckKeyEx(const Identification& id,
    199                           const Authorization& auth,
    200                           const Callback& callback) OVERRIDE {
    201     cryptohome::AccountIdentifier id_proto;
    202     cryptohome::AuthorizationRequest auth_proto;
    203     cryptohome::CheckKeyRequest request;
    204 
    205     FillIdentificationProtobuf(id, &id_proto);
    206     FillAuthorizationProtobuf(auth, &auth_proto);
    207 
    208     DBusThreadManager::Get()->GetCryptohomeClient()->CheckKeyEx(
    209         id_proto,
    210         auth_proto,
    211         request,
    212         base::Bind(&HomedirMethodsImpl::OnBaseReplyCallback,
    213                    weak_ptr_factory_.GetWeakPtr(),
    214                    callback));
    215   }
    216 
    217   virtual void MountEx(const Identification& id,
    218                        const Authorization& auth,
    219                        const MountParameters& request,
    220                        const MountCallback& callback) OVERRIDE {
    221     cryptohome::AccountIdentifier id_proto;
    222     cryptohome::AuthorizationRequest auth_proto;
    223     cryptohome::MountRequest request_proto;
    224 
    225     FillIdentificationProtobuf(id, &id_proto);
    226     FillAuthorizationProtobuf(auth, &auth_proto);
    227 
    228     if (request.ephemeral)
    229       request_proto.set_require_ephemeral(true);
    230 
    231     if (!request.create_keys.empty()) {
    232       CreateRequest* create = request_proto.mutable_create();
    233       for (size_t i = 0; i < request.create_keys.size(); ++i)
    234         FillKeyProtobuf(request.create_keys[i], create->add_keys());
    235     }
    236 
    237     DBusThreadManager::Get()->GetCryptohomeClient()->MountEx(
    238         id_proto,
    239         auth_proto,
    240         request_proto,
    241         base::Bind(&HomedirMethodsImpl::OnMountExCallback,
    242                    weak_ptr_factory_.GetWeakPtr(),
    243                    callback));
    244   }
    245 
    246   virtual void AddKeyEx(const Identification& id,
    247                         const Authorization& auth,
    248                         const KeyDefinition& new_key,
    249                         bool clobber_if_exists,
    250                         const Callback& callback) OVERRIDE {
    251     cryptohome::AccountIdentifier id_proto;
    252     cryptohome::AuthorizationRequest auth_proto;
    253     cryptohome::AddKeyRequest request;
    254 
    255     FillIdentificationProtobuf(id, &id_proto);
    256     FillAuthorizationProtobuf(auth, &auth_proto);
    257     FillKeyProtobuf(new_key, request.mutable_key());
    258     request.set_clobber_if_exists(clobber_if_exists);
    259 
    260     DBusThreadManager::Get()->GetCryptohomeClient()->AddKeyEx(
    261         id_proto,
    262         auth_proto,
    263         request,
    264         base::Bind(&HomedirMethodsImpl::OnBaseReplyCallback,
    265                    weak_ptr_factory_.GetWeakPtr(),
    266                    callback));
    267   }
    268 
    269   virtual void RemoveKeyEx(const Identification& id,
    270                            const Authorization& auth,
    271                            const std::string& label,
    272                            const Callback& callback) OVERRIDE {
    273     cryptohome::AccountIdentifier id_proto;
    274     cryptohome::AuthorizationRequest auth_proto;
    275     cryptohome::RemoveKeyRequest request;
    276 
    277     FillIdentificationProtobuf(id, &id_proto);
    278     FillAuthorizationProtobuf(auth, &auth_proto);
    279     request.mutable_key()->mutable_data()->set_label(label);
    280 
    281     DBusThreadManager::Get()->GetCryptohomeClient()->RemoveKeyEx(
    282         id_proto,
    283         auth_proto,
    284         request,
    285         base::Bind(&HomedirMethodsImpl::OnBaseReplyCallback,
    286                    weak_ptr_factory_.GetWeakPtr(),
    287                    callback));
    288   }
    289 
    290   virtual void UpdateKeyEx(const Identification& id,
    291                            const Authorization& auth,
    292                            const KeyDefinition& new_key,
    293                            const std::string& signature,
    294                            const Callback& callback) OVERRIDE {
    295     cryptohome::AccountIdentifier id_proto;
    296     cryptohome::AuthorizationRequest auth_proto;
    297     cryptohome::UpdateKeyRequest pb_update_key;
    298 
    299     FillIdentificationProtobuf(id, &id_proto);
    300     FillAuthorizationProtobuf(auth, &auth_proto);
    301     FillKeyProtobuf(new_key, pb_update_key.mutable_changes());
    302     pb_update_key.set_authorization_signature(signature);
    303 
    304     DBusThreadManager::Get()->GetCryptohomeClient()->UpdateKeyEx(
    305         id_proto,
    306         auth_proto,
    307         pb_update_key,
    308         base::Bind(&HomedirMethodsImpl::OnBaseReplyCallback,
    309                    weak_ptr_factory_.GetWeakPtr(),
    310                    callback));
    311   }
    312 
    313  private:
    314   void OnGetKeyDataExCallback(const GetKeyDataCallback& callback,
    315                               chromeos::DBusMethodCallStatus call_status,
    316                               bool result,
    317                               const BaseReply& reply) {
    318     if (call_status != chromeos::DBUS_METHOD_CALL_SUCCESS) {
    319       callback.Run(false, MOUNT_ERROR_FATAL, std::vector<KeyDefinition>());
    320       return;
    321     }
    322     if (reply.has_error()) {
    323       if (reply.error() != CRYPTOHOME_ERROR_NOT_SET) {
    324         callback.Run(false,
    325                      MapError(reply.error()),
    326                      std::vector<KeyDefinition>());
    327         return;
    328       }
    329     }
    330 
    331     if (!reply.HasExtension(GetKeyDataReply::reply)) {
    332       callback.Run(false, MOUNT_ERROR_FATAL, std::vector<KeyDefinition>());
    333       return;
    334     }
    335 
    336     // Extract the contents of the |KeyData| protos returned.
    337     const RepeatedPtrField<KeyData>& key_data =
    338         reply.GetExtension(GetKeyDataReply::reply).key_data();
    339     std::vector<KeyDefinition> key_definitions;
    340     for (RepeatedPtrField<KeyData>::const_iterator it = key_data.begin();
    341          it != key_data.end(); ++it) {
    342 
    343       // Extract |type|, |label| and |revision|.
    344       DCHECK_EQ(KeyData::KEY_TYPE_PASSWORD, it->type());
    345       key_definitions.push_back(KeyDefinition(std::string() /* secret */,
    346                                               it->label(),
    347                                               0 /* privileges */));
    348       KeyDefinition& key_definition = key_definitions.back();
    349       key_definition.revision = it->revision();
    350 
    351       // Extract |privileges|.
    352       const KeyPrivileges& privileges = it->privileges();
    353       if (privileges.mount())
    354         key_definition.privileges |= PRIV_MOUNT;
    355       if (privileges.add())
    356         key_definition.privileges |= PRIV_ADD;
    357       if (privileges.remove())
    358         key_definition.privileges |= PRIV_REMOVE;
    359       if (privileges.update())
    360         key_definition.privileges |= PRIV_MIGRATE;
    361       if (privileges.authorized_update())
    362         key_definition.privileges |= PRIV_AUTHORIZED_UPDATE;
    363 
    364       // Extract |authorization_data|.
    365       for (RepeatedPtrField<KeyAuthorizationData>::const_iterator auth_it =
    366                it->authorization_data().begin();
    367            auth_it != it->authorization_data().end(); ++auth_it) {
    368         key_definition.authorization_data.push_back(
    369             KeyDefinition::AuthorizationData());
    370         ParseAuthorizationDataProtobuf(
    371             *auth_it,
    372             &key_definition.authorization_data.back());
    373       }
    374 
    375       // Extract |provider_data|.
    376       for (RepeatedPtrField<KeyProviderData::Entry>::const_iterator
    377               provider_data_it = it->provider_data().entry().begin();
    378            provider_data_it != it->provider_data().entry().end();
    379            ++provider_data_it) {
    380         // Extract |name|.
    381         key_definition.provider_data.push_back(
    382             KeyDefinition::ProviderData(provider_data_it->name()));
    383         KeyDefinition::ProviderData& provider_data =
    384             key_definition.provider_data.back();
    385 
    386         int data_items = 0;
    387 
    388         // Extract |number|.
    389         if (provider_data_it->has_number()) {
    390           provider_data.number.reset(new int64(provider_data_it->number()));
    391           ++data_items;
    392         }
    393 
    394         // Extract |bytes|.
    395         if (provider_data_it->has_bytes()) {
    396           provider_data.bytes.reset(
    397               new std::string(provider_data_it->bytes()));
    398           ++data_items;
    399         }
    400 
    401         DCHECK_EQ(1, data_items);
    402       }
    403     }
    404 
    405     callback.Run(true, MOUNT_ERROR_NONE, key_definitions);
    406   }
    407 
    408   void OnMountExCallback(const MountCallback& callback,
    409                          chromeos::DBusMethodCallStatus call_status,
    410                          bool result,
    411                          const BaseReply& reply) {
    412     if (call_status != chromeos::DBUS_METHOD_CALL_SUCCESS) {
    413       callback.Run(false, MOUNT_ERROR_FATAL, std::string());
    414       return;
    415     }
    416     if (reply.has_error()) {
    417       if (reply.error() != CRYPTOHOME_ERROR_NOT_SET) {
    418         callback.Run(false, MapError(reply.error()), std::string());
    419         return;
    420       }
    421     }
    422     if (!reply.HasExtension(MountReply::reply)) {
    423       callback.Run(false, MOUNT_ERROR_FATAL, std::string());
    424       return;
    425     }
    426 
    427     std::string mount_hash;
    428     mount_hash = reply.GetExtension(MountReply::reply).sanitized_username();
    429     callback.Run(true, MOUNT_ERROR_NONE, mount_hash);
    430   }
    431 
    432   void OnBaseReplyCallback(const Callback& callback,
    433                            chromeos::DBusMethodCallStatus call_status,
    434                            bool result,
    435                            const BaseReply& reply) {
    436     if (call_status != chromeos::DBUS_METHOD_CALL_SUCCESS) {
    437       callback.Run(false, MOUNT_ERROR_FATAL);
    438       return;
    439     }
    440     if (reply.has_error()) {
    441       if (reply.error() != CRYPTOHOME_ERROR_NOT_SET) {
    442         callback.Run(false, MapError(reply.error()));
    443         return;
    444       }
    445     }
    446     callback.Run(true, MOUNT_ERROR_NONE);
    447   }
    448 
    449   base::WeakPtrFactory<HomedirMethodsImpl> weak_ptr_factory_;
    450 
    451   DISALLOW_COPY_AND_ASSIGN(HomedirMethodsImpl);
    452 };
    453 
    454 }  // namespace
    455 
    456 // static
    457 void HomedirMethods::Initialize() {
    458   if (g_homedir_methods) {
    459     LOG(WARNING) << "HomedirMethods was already initialized";
    460     return;
    461   }
    462   g_homedir_methods = new HomedirMethodsImpl();
    463   VLOG(1) << "HomedirMethods initialized";
    464 }
    465 
    466 // static
    467 void HomedirMethods::InitializeForTesting(HomedirMethods* homedir_methods) {
    468   if (g_homedir_methods) {
    469     LOG(WARNING) << "HomedirMethods was already initialized";
    470     return;
    471   }
    472   g_homedir_methods = homedir_methods;
    473   VLOG(1) << "HomedirMethods initialized";
    474 }
    475 
    476 // static
    477 void HomedirMethods::Shutdown() {
    478   if (!g_homedir_methods) {
    479     LOG(WARNING) << "AsyncMethodCaller::Shutdown() called with NULL manager";
    480     return;
    481   }
    482   delete g_homedir_methods;
    483   g_homedir_methods = NULL;
    484   VLOG(1) << "HomedirMethods Shutdown completed";
    485 }
    486 
    487 // static
    488 HomedirMethods* HomedirMethods::GetInstance() { return g_homedir_methods; }
    489 
    490 }  // namespace cryptohome
    491