diff options
author | bartfab <bartfab@chromium.org> | 2014-08-29 03:50:23 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2014-08-29 10:51:28 +0000 |
commit | 2401bb93e76413176246a41be2a51de1e43137a0 (patch) | |
tree | a5c0009d8851853e70d57f26f9e79430dec0d94a /chromeos/cryptohome | |
parent | 35f985b3b8388a4471d5f62a242b4ea0b4f6a9e7 (diff) | |
download | chromium_src-2401bb93e76413176246a41be2a51de1e43137a0.zip chromium_src-2401bb93e76413176246a41be2a51de1e43137a0.tar.gz chromium_src-2401bb93e76413176246a41be2a51de1e43137a0.tar.bz2 |
Wire up GetKeyDataEx() in Chrome
This CL wires up cryptohomed's GetKeyDataEx() as
HomedirMethods::GetKeyDataEx() in Chrome. The method will be used to
retrieve metadata such as the hashing algorithm and salt used for a
key.
BUG=367847
TEST=New homedir_methods_unittest.cc
Review URL: https://codereview.chromium.org/506943002
Cr-Commit-Position: refs/heads/master@{#292602}
Diffstat (limited to 'chromeos/cryptohome')
-rw-r--r-- | chromeos/cryptohome/cryptohome_parameters.cc | 25 | ||||
-rw-r--r-- | chromeos/cryptohome/cryptohome_parameters.h | 34 | ||||
-rw-r--r-- | chromeos/cryptohome/homedir_methods.cc | 130 | ||||
-rw-r--r-- | chromeos/cryptohome/homedir_methods.h | 17 | ||||
-rw-r--r-- | chromeos/cryptohome/homedir_methods_unittest.cc | 184 | ||||
-rw-r--r-- | chromeos/cryptohome/mock_homedir_methods.h | 4 |
6 files changed, 389 insertions, 5 deletions
diff --git a/chromeos/cryptohome/cryptohome_parameters.cc b/chromeos/cryptohome/cryptohome_parameters.cc index eb6d906..41246f3 100644 --- a/chromeos/cryptohome/cryptohome_parameters.cc +++ b/chromeos/cryptohome/cryptohome_parameters.cc @@ -4,8 +4,9 @@ #include "chromeos/cryptohome/cryptohome_parameters.h" -namespace cryptohome { +#include "chromeos/dbus/cryptohome/key.pb.h" +namespace cryptohome { Identification::Identification(const std::string& user_id) : user_id(user_id) { } @@ -49,14 +50,32 @@ bool Authorization::operator==(const Authorization& other) const { return key == other.key && label == other.label; } -MountParameters::MountParameters(bool ephemeral) : ephemeral(ephemeral) { +RetrievedKeyData::ProviderData::ProviderData(const std::string& name) + : name(name) { } -MountParameters::~MountParameters() { +RetrievedKeyData::ProviderData::~ProviderData() { +} + +RetrievedKeyData::RetrievedKeyData(Type type, + const std::string& label, + int64 revision) : type(type), + label(label), + privileges(0), + revision(revision) { +} + +RetrievedKeyData::~RetrievedKeyData() { +} + +MountParameters::MountParameters(bool ephemeral) : ephemeral(ephemeral) { } bool MountParameters::operator==(const MountParameters& other) const { return ephemeral == other.ephemeral && create_keys == other.create_keys; } +MountParameters::~MountParameters() { +} + } // namespace cryptohome diff --git a/chromeos/cryptohome/cryptohome_parameters.h b/chromeos/cryptohome/cryptohome_parameters.h index d74d5fc..fe43f2c 100644 --- a/chromeos/cryptohome/cryptohome_parameters.h +++ b/chromeos/cryptohome/cryptohome_parameters.h @@ -9,6 +9,8 @@ #include <vector> #include "base/basictypes.h" +#include "base/memory/scoped_ptr.h" +#include "base/memory/scoped_vector.h" #include "chromeos/chromeos_export.h" namespace cryptohome { @@ -64,6 +66,38 @@ struct CHROMEOS_EXPORT Authorization { std::string label; }; +// Information about keys returned by GetKeyDataEx(). +struct CHROMEOS_EXPORT RetrievedKeyData { + enum Type { + TYPE_PASSWORD = 0 + }; + + enum AuthorizationType { + AUTHORIZATION_TYPE_HMACSHA256 = 0, + AUTHORIZATION_TYPE_AES256CBC_HMACSHA256 + }; + + struct ProviderData { + explicit ProviderData(const std::string& name); + ~ProviderData(); + + std::string name; + scoped_ptr<int64> number; + scoped_ptr<std::string> bytes; + }; + + RetrievedKeyData(Type type, const std::string& label, int64 revision); + ~RetrievedKeyData(); + + Type type; + std::string label; + // Privileges associated with key. Combination of |AuthKeyPrivileges| values. + int privileges; + int64 revision; + std::vector<AuthorizationType> authorization_types; + ScopedVector<ProviderData> provider_data; +}; + // Parameters for Mount call. class CHROMEOS_EXPORT MountParameters { public: diff --git a/chromeos/cryptohome/homedir_methods.cc b/chromeos/cryptohome/homedir_methods.cc index cd12218..73a741b 100644 --- a/chromeos/cryptohome/homedir_methods.cc +++ b/chromeos/cryptohome/homedir_methods.cc @@ -5,12 +5,20 @@ #include "chromeos/cryptohome/homedir_methods.h" #include "base/bind.h" +#include "base/logging.h" #include "chromeos/dbus/cryptohome/key.pb.h" #include "chromeos/dbus/cryptohome/rpc.pb.h" #include "chromeos/dbus/cryptohome_client.h" #include "chromeos/dbus/dbus_thread_manager.h" +#if defined(USE_SYSTEM_PROTOBUF) +#include <google/protobuf/repeated_field.h> +#else +#include "third_party/protobuf/src/google/protobuf/repeated_field.h" +#endif + using chromeos::DBusThreadManager; +using google::protobuf::RepeatedPtrField; namespace cryptohome { @@ -109,6 +117,25 @@ class HomedirMethodsImpl : public HomedirMethods { virtual ~HomedirMethodsImpl() {} + virtual void GetKeyDataEx(const Identification& id, + const std::string& label, + const GetKeyDataCallback& callback) OVERRIDE { + cryptohome::AccountIdentifier id_proto; + cryptohome::AuthorizationRequest kEmptyAuthProto; + cryptohome::GetKeyDataRequest request; + + FillIdentificationProtobuf(id, &id_proto); + request.mutable_key()->mutable_data()->set_label(label); + + DBusThreadManager::Get()->GetCryptohomeClient()->GetKeyDataEx( + id_proto, + kEmptyAuthProto, + request, + base::Bind(&HomedirMethodsImpl::OnGetKeyDataExCallback, + weak_ptr_factory_.GetWeakPtr(), + callback)); + } + virtual void CheckKeyEx(const Identification& id, const Authorization& auth, const Callback& callback) OVERRIDE { @@ -225,6 +252,109 @@ class HomedirMethodsImpl : public HomedirMethods { } private: + void OnGetKeyDataExCallback(const GetKeyDataCallback& callback, + chromeos::DBusMethodCallStatus call_status, + bool result, + const BaseReply& reply) { + if (call_status != chromeos::DBUS_METHOD_CALL_SUCCESS) { + callback.Run(false, MOUNT_ERROR_FATAL, ScopedVector<RetrievedKeyData>()); + return; + } + if (reply.has_error()) { + if (reply.error() != CRYPTOHOME_ERROR_NOT_SET) { + callback.Run(false, + MapError(reply.error()), + ScopedVector<RetrievedKeyData>()); + return; + } + } + + if (!reply.HasExtension(GetKeyDataReply::reply)) { + callback.Run(false, MOUNT_ERROR_FATAL, ScopedVector<RetrievedKeyData>()); + return; + } + + // Extract the contents of the |KeyData| protos returned. + const RepeatedPtrField<KeyData>& key_data_proto = + reply.GetExtension(GetKeyDataReply::reply).key_data(); + ScopedVector<RetrievedKeyData> key_data_list; + for (RepeatedPtrField<KeyData>::const_iterator it = key_data_proto.begin(); + it != key_data_proto.end(); ++it) { + + // Extract |type|, |label| and |revision|. + DCHECK_EQ(KeyData::KEY_TYPE_PASSWORD, it->type()); + key_data_list.push_back(new RetrievedKeyData( + RetrievedKeyData::TYPE_PASSWORD, + it->label(), + it->revision())); + RetrievedKeyData* key_data = key_data_list.back(); + + // Extract |privileges|. + const KeyPrivileges& privileges = it->privileges(); + if (privileges.mount()) + key_data->privileges |= PRIV_MOUNT; + if (privileges.add()) + key_data->privileges |= PRIV_ADD; + if (privileges.remove()) + key_data->privileges |= PRIV_REMOVE; + if (privileges.update()) + key_data->privileges |= PRIV_MIGRATE; + if (privileges.authorized_update()) + key_data->privileges |= PRIV_AUTHORIZED_UPDATE; + + // Extract |authorization_data|. + for (RepeatedPtrField<KeyAuthorizationData>::const_iterator auth_it = + it->authorization_data().begin(); + auth_it != it->authorization_data().end(); ++auth_it) { + switch (auth_it->type()) { + case KeyAuthorizationData::KEY_AUTHORIZATION_TYPE_HMACSHA256: + key_data->authorization_types.push_back( + RetrievedKeyData::AUTHORIZATION_TYPE_HMACSHA256); + break; + case KeyAuthorizationData:: + KEY_AUTHORIZATION_TYPE_AES256CBC_HMACSHA256: + key_data->authorization_types.push_back( + RetrievedKeyData::AUTHORIZATION_TYPE_AES256CBC_HMACSHA256); + break; + default: + NOTREACHED(); + break; + } + } + + // Extract |provider_data|. + for (RepeatedPtrField<KeyProviderData::Entry>::const_iterator + provider_data_it = it->provider_data().entry().begin(); + provider_data_it != it->provider_data().entry().end(); + ++provider_data_it) { + // Extract |name|. + key_data->provider_data.push_back( + new RetrievedKeyData::ProviderData(provider_data_it->name())); + RetrievedKeyData::ProviderData* provider_data = + key_data->provider_data.back(); + + int data_items = 0; + + // Extract |number|. + if (provider_data_it->has_number()) { + provider_data->number.reset(new int64(provider_data_it->number())); + ++data_items; + } + + // Extract |bytes|. + if (provider_data_it->has_bytes()) { + provider_data->bytes.reset( + new std::string(provider_data_it->bytes())); + ++data_items; + } + + DCHECK_EQ(1, data_items); + } + } + + callback.Run(true, MOUNT_ERROR_NONE, key_data_list.Pass()); + } + void OnMountExCallback(const MountCallback& callback, chromeos::DBusMethodCallStatus call_status, bool result, diff --git a/chromeos/cryptohome/homedir_methods.h b/chromeos/cryptohome/homedir_methods.h index 0276f1b..e55e30b 100644 --- a/chromeos/cryptohome/homedir_methods.h +++ b/chromeos/cryptohome/homedir_methods.h @@ -9,25 +9,38 @@ #include "base/basictypes.h" #include "base/callback_forward.h" +#include "base/memory/scoped_vector.h" #include "chromeos/chromeos_export.h" #include "chromeos/cryptohome/cryptohome_parameters.h" #include "chromeos/dbus/cryptohome_client.h" #include "third_party/cros_system_api/dbus/service_constants.h" namespace cryptohome { + // This class manages calls to Cryptohome service's home directory methods: // Mount, CheckKey, Add/UpdateKey. class CHROMEOS_EXPORT HomedirMethods { public: - // A callback type which is called back on the UI thread when the results of - // method calls are ready. + // Callbacks that are called back on the UI thread when the results of the + // respective method calls are ready. typedef base::Callback<void(bool success, MountError return_code)> Callback; + typedef base::Callback<void( + bool success, + MountError return_code, + ScopedVector<RetrievedKeyData> key_data)> GetKeyDataCallback; typedef base::Callback< void(bool success, MountError return_code, const std::string& mount_hash)> MountCallback; virtual ~HomedirMethods() {} + // Asks cryptohomed to return data about the key identified by |label| for the + // user identified by |id|. At present, this does not return any secret + // information and the request does not need to be authenticated. + virtual void GetKeyDataEx(const Identification& id, + const std::string& label, + const GetKeyDataCallback& callback) = 0; + // Asks cryptohomed to attempt authorization for user identified by |id| using // |auth|. This can be used to unlock a user session. virtual void CheckKeyEx(const Identification& id, diff --git a/chromeos/cryptohome/homedir_methods_unittest.cc b/chromeos/cryptohome/homedir_methods_unittest.cc new file mode 100644 index 0000000..96a86f4 --- /dev/null +++ b/chromeos/cryptohome/homedir_methods_unittest.cc @@ -0,0 +1,184 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chromeos/cryptohome/homedir_methods.h" + +#include "base/bind.h" +#include "base/bind_helpers.h" +#include "base/compiler_specific.h" +#include "base/memory/scoped_ptr.h" +#include "chromeos/dbus/cryptohome/rpc.pb.h" +#include "chromeos/dbus/cryptohome_client.h" +#include "chromeos/dbus/dbus_method_call_status.h" +#include "chromeos/dbus/dbus_thread_manager.h" +#include "chromeos/dbus/mock_cryptohome_client.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +using testing::_; +using testing::Invoke; +using testing::WithArg; + +namespace cryptohome { + +namespace { + +MATCHER_P(EqualsProto, expected_proto, "") { + std::string expected_value; + expected_proto.SerializeToString(&expected_value); + std::string actual_value; + arg.SerializeToString(&actual_value); + return actual_value == expected_value; +} + +} // namespace + +const char kUserID[] = "user@example.com"; +const char kKeyLabel[] = "key_label"; + +const int64 kKeyRevision = 123; +const char kProviderData1Name[] = "data_1"; +const int64 kProviderData1Number = 12345; +const char kProviderData2Name[] = "data_2"; +const char kProviderData2Bytes[] = "data_2 bytes"; + +class HomedirMethodsTest : public testing::Test { + public: + HomedirMethodsTest(); + virtual ~HomedirMethodsTest(); + + // testing::Test: + virtual void SetUp() OVERRIDE; + virtual void TearDown() OVERRIDE; + + void RunProtobufMethodCallback( + const chromeos::CryptohomeClient::ProtobufMethodCallback& callback); + + void StoreGetKeyDataExResult(bool success, + MountError return_code, + ScopedVector<RetrievedKeyData> key_data); + + protected: + chromeos::MockCryptohomeClient* cryptohome_client_; + + // The reply that |cryptohome_client_| will make. + cryptohome::BaseReply cryptohome_reply_; + + // The results of the most recent |HomedirMethods| method call. + bool success_; + MountError return_code_; + ScopedVector<RetrievedKeyData> key_data_; + + private: + DISALLOW_COPY_AND_ASSIGN(HomedirMethodsTest); +}; + +HomedirMethodsTest::HomedirMethodsTest() : cryptohome_client_(NULL), + success_(false), + return_code_(MOUNT_ERROR_FATAL) { +} + +HomedirMethodsTest::~HomedirMethodsTest() { +} + +void HomedirMethodsTest::SetUp() { + scoped_ptr<chromeos::MockCryptohomeClient> cryptohome_client( + new chromeos::MockCryptohomeClient); + cryptohome_client_ = cryptohome_client.get(); + chromeos::DBusThreadManager::GetSetterForTesting()->SetCryptohomeClient( + cryptohome_client.PassAs<chromeos::CryptohomeClient>()); + HomedirMethods::Initialize(); +} + +void HomedirMethodsTest::TearDown() { + HomedirMethods::Shutdown(); + chromeos::DBusThreadManager::Shutdown(); +} + +void HomedirMethodsTest::RunProtobufMethodCallback( + const chromeos::CryptohomeClient::ProtobufMethodCallback& callback) { + callback.Run(chromeos::DBUS_METHOD_CALL_SUCCESS, + true, + cryptohome_reply_); +} + +void HomedirMethodsTest::StoreGetKeyDataExResult( + bool success, + MountError return_code, + ScopedVector<RetrievedKeyData> key_data) { + success_ = success; + return_code_ = return_code; + key_data_.swap(key_data); +} + +// Verifies that the result of a GetKeyDataEx() call is correctly parsed. +TEST_F(HomedirMethodsTest, GetKeyDataEx) { + AccountIdentifier expected_id; + expected_id.set_email(kUserID); + const cryptohome::AuthorizationRequest expected_auth; + cryptohome::GetKeyDataRequest expected_request; + expected_request.mutable_key()->mutable_data()->set_label(kKeyLabel); + + EXPECT_CALL(*cryptohome_client_, + GetKeyDataEx(EqualsProto(expected_id), + EqualsProto(expected_auth), + EqualsProto(expected_request), + _)) + .Times(1) + .WillOnce(WithArg<3>(Invoke( + this, + &HomedirMethodsTest::RunProtobufMethodCallback))); + + // Set up the reply that |cryptohome_client_| will make. + cryptohome::GetKeyDataReply* reply = + cryptohome_reply_.MutableExtension(cryptohome::GetKeyDataReply::reply); + KeyData* key_data = reply->add_key_data(); + key_data->set_type(KeyData::KEY_TYPE_PASSWORD); + key_data->set_label(kKeyLabel); + key_data->mutable_privileges()->set_update(false); + key_data->set_revision(kKeyRevision); + key_data->add_authorization_data()->set_type( + KeyAuthorizationData::KEY_AUTHORIZATION_TYPE_HMACSHA256); + KeyProviderData* data = key_data->mutable_provider_data(); + KeyProviderData::Entry* entry = data->add_entry(); + entry->set_name(kProviderData1Name); + entry->set_number(kProviderData1Number); + entry = data->add_entry(); + entry->set_name(kProviderData2Name); + entry->set_bytes(kProviderData2Bytes); + + // Call GetKeyDataEx(). + HomedirMethods::GetInstance()->GetKeyDataEx( + Identification(kUserID), + kKeyLabel, + base::Bind(&HomedirMethodsTest::StoreGetKeyDataExResult, + base::Unretained(this))); + + // Verify that the call was successful and the result was correctly parsed. + EXPECT_TRUE(success_); + EXPECT_EQ(MOUNT_ERROR_NONE, return_code_); + ASSERT_EQ(1u, key_data_.size()); + const RetrievedKeyData* retrieved_key_data = key_data_.front(); + EXPECT_EQ(RetrievedKeyData::TYPE_PASSWORD, retrieved_key_data->type); + EXPECT_EQ(PRIV_MOUNT | PRIV_ADD | PRIV_REMOVE, + retrieved_key_data->privileges); + EXPECT_EQ(kKeyRevision, retrieved_key_data->revision); + ASSERT_EQ(1u, retrieved_key_data->authorization_types.size()); + EXPECT_EQ(RetrievedKeyData::AUTHORIZATION_TYPE_HMACSHA256, + retrieved_key_data->authorization_types.front()); + ASSERT_EQ(2u, retrieved_key_data->provider_data.size()); + const RetrievedKeyData::ProviderData* provider_data = + retrieved_key_data->provider_data[0]; + EXPECT_EQ(kProviderData1Name, provider_data->name); + ASSERT_TRUE(provider_data->number); + EXPECT_EQ(kProviderData1Number, *provider_data->number.get()); + EXPECT_FALSE(provider_data->bytes); + provider_data = retrieved_key_data->provider_data[1]; + EXPECT_EQ(kProviderData2Name, provider_data->name); + EXPECT_FALSE(provider_data->number); + ASSERT_TRUE(provider_data->bytes); + EXPECT_EQ(kProviderData2Bytes, *provider_data->bytes.get()); +} + +} // namespace cryptohome diff --git a/chromeos/cryptohome/mock_homedir_methods.h b/chromeos/cryptohome/mock_homedir_methods.h index 450acd2..1798911 100644 --- a/chromeos/cryptohome/mock_homedir_methods.h +++ b/chromeos/cryptohome/mock_homedir_methods.h @@ -21,6 +21,10 @@ class CHROMEOS_EXPORT MockHomedirMethods : public HomedirMethods { void SetUp(bool success, MountError return_code); + MOCK_METHOD3(GetKeyDataEx, + void(const Identification& id, + const std::string& label, + const GetKeyDataCallback& callback)); MOCK_METHOD3(CheckKeyEx, void(const Identification& id, const Authorization& key, |