summaryrefslogtreecommitdiffstats
path: root/chromeos/cryptohome
diff options
context:
space:
mode:
authorbartfab <bartfab@chromium.org>2014-08-29 03:50:23 -0700
committerCommit bot <commit-bot@chromium.org>2014-08-29 10:51:28 +0000
commit2401bb93e76413176246a41be2a51de1e43137a0 (patch)
treea5c0009d8851853e70d57f26f9e79430dec0d94a /chromeos/cryptohome
parent35f985b3b8388a4471d5f62a242b4ea0b4f6a9e7 (diff)
downloadchromium_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.cc25
-rw-r--r--chromeos/cryptohome/cryptohome_parameters.h34
-rw-r--r--chromeos/cryptohome/homedir_methods.cc130
-rw-r--r--chromeos/cryptohome/homedir_methods.h17
-rw-r--r--chromeos/cryptohome/homedir_methods_unittest.cc184
-rw-r--r--chromeos/cryptohome/mock_homedir_methods.h4
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,