blob: 67b7eea5287c47fedf2abd3ed5dc7d4451541aa9 [file] [log] [blame]
// Copyright 2014 The Chromium OS 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 <stdint.h>
#include <base/bind.h>
#include <base/callback.h>
#include <base/memory/ref_counted.h>
#include <base/memory/scoped_ptr.h>
#include <base/message_loop/message_loop.h>
#include <base/run_loop.h>
#include <chromeos/dbus/service_constants.h>
#include <dbus/message.h>
#include <dbus/mock_bus.h>
#include <dbus/mock_exported_object.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include "easy-unlock/daemon.h"
#include "easy-unlock/fake_easy_unlock_service.h"
using ::testing::_;
using ::testing::AnyNumber;
using ::testing::Invoke;
using ::testing::Return;
namespace {
class MethodCallHandlers {
public:
typedef base::Callback<void (dbus::MethodCall* method_call,
dbus::ExportedObject::ResponseSender sender)>
Handler;
MethodCallHandlers() {}
~MethodCallHandlers() {}
bool SetGenerateEcP256KeyPairHandler(const std::string& interface,
const std::string& method,
Handler handler) {
generate_ec_p256_key_pair_handler_ = handler;
return true;
}
bool SetWrapPublicKeyHandler(const std::string& interface,
const std::string& method,
Handler handler) {
wrap_public_key_handler_ = handler;
return true;
}
bool SetPerformECDHKeyAgreementHandler(const std::string& interface,
const std::string& method,
Handler handler) {
perform_ecdh_key_agreement_handler_ = handler;
return true;
}
bool SetCreateSecureMessageHandler(const std::string& interface,
const std::string& method,
Handler handler) {
create_secure_message_handler_ = handler;
return true;
}
bool SetUnwrapSecureMessageHandler(const std::string& interface,
const std::string& method,
Handler handler) {
unwrap_secure_message_handler_ = handler;
return true;
}
void CallGenerateEcP256KeyPair(
dbus::MethodCall* method_call,
const dbus::ExportedObject::ResponseSender& sender) {
ASSERT_FALSE(generate_ec_p256_key_pair_handler_.is_null());
generate_ec_p256_key_pair_handler_.Run(method_call, sender);
}
void CallWrapPublicKey(
dbus::MethodCall* method_call,
const dbus::ExportedObject::ResponseSender& sender) {
ASSERT_FALSE(wrap_public_key_handler_.is_null());
wrap_public_key_handler_.Run(method_call, sender);
}
void CallPerformECDHKeyAgreement(
dbus::MethodCall* method_call,
const dbus::ExportedObject::ResponseSender& sender) {
ASSERT_FALSE(perform_ecdh_key_agreement_handler_.is_null());
perform_ecdh_key_agreement_handler_.Run(method_call, sender);
}
void CallCreateSecureMessage(
dbus::MethodCall* method_call,
const dbus::ExportedObject::ResponseSender& sender) {
ASSERT_FALSE(create_secure_message_handler_.is_null());
create_secure_message_handler_.Run(method_call, sender);
}
void CallUnwrapSecureMessage(
dbus::MethodCall* method_call,
const dbus::ExportedObject::ResponseSender& sender) {
ASSERT_FALSE(unwrap_secure_message_handler_.is_null());
unwrap_secure_message_handler_.Run(method_call, sender);
}
private:
Handler generate_ec_p256_key_pair_handler_;
Handler wrap_public_key_handler_;
Handler perform_ecdh_key_agreement_handler_;
Handler create_secure_message_handler_;
Handler unwrap_secure_message_handler_;
DISALLOW_COPY_AND_ASSIGN(MethodCallHandlers);
};
class EasyUnlockTest : public ::testing::Test {
public:
EasyUnlockTest() : method_call_handlers_(new MethodCallHandlers()) {}
virtual ~EasyUnlockTest() {}
virtual void SetUp() {
dbus::Bus::Options options;
options.bus_type = dbus::Bus::SYSTEM;
bus_ = new dbus::MockBus(options);
// Create a mock exported object that behaves as
// org.chromium.EasyUnlock DBus service.
exported_object_ =
new dbus::MockExportedObject(
bus_.get(),
dbus::ObjectPath(easy_unlock::kEasyUnlockServicePath));
ASSERT_TRUE(InitializeDaemon());
}
virtual void TearDown() {
if (daemon_)
daemon_->Finalize();
}
void VerifyGenerateEcP256KeyPairResponse(
scoped_ptr<dbus::Response> response) {
ASSERT_TRUE(response);
dbus::MessageReader reader(response.get());
const uint8_t* bytes = nullptr;
size_t length = 0;
ASSERT_TRUE(reader.PopArrayOfBytes(&bytes, &length));
ASSERT_EQ("private_key_1",
std::string(reinterpret_cast<const char*>(bytes), length));
ASSERT_TRUE(reader.PopArrayOfBytes(&bytes, &length));
ASSERT_EQ("public_key_1",
std::string(reinterpret_cast<const char*>(bytes), length));
}
void VerifyDataResponse(const std::string& expected_content,
scoped_ptr<dbus::Response> response) {
ASSERT_TRUE(response);
dbus::MessageReader reader(response.get());
const uint8_t* bytes = nullptr;
size_t length = 0;
ASSERT_TRUE(reader.PopArrayOfBytes(&bytes, &length));
ASSERT_EQ(expected_content,
std::string(reinterpret_cast<const char*>(bytes), length));
}
protected:
scoped_ptr<MethodCallHandlers> method_call_handlers_;
private:
void SetUpExportedObject() {
EXPECT_CALL(*exported_object_,
ExportMethodAndBlock(
easy_unlock::kEasyUnlockServiceInterface,
easy_unlock::kGenerateEcP256KeyPairMethod,
_))
.WillOnce(
Invoke(method_call_handlers_.get(),
&MethodCallHandlers::SetGenerateEcP256KeyPairHandler));
EXPECT_CALL(*exported_object_,
ExportMethodAndBlock(
easy_unlock::kEasyUnlockServiceInterface,
easy_unlock::kWrapPublicKeyMethod,
_))
.WillOnce(
Invoke(method_call_handlers_.get(),
&MethodCallHandlers::SetWrapPublicKeyHandler));
EXPECT_CALL(*exported_object_,
ExportMethodAndBlock(
easy_unlock::kEasyUnlockServiceInterface,
easy_unlock::kPerformECDHKeyAgreementMethod,
_))
.WillOnce(
Invoke(method_call_handlers_.get(),
&MethodCallHandlers::SetPerformECDHKeyAgreementHandler));
EXPECT_CALL(*exported_object_,
ExportMethodAndBlock(
easy_unlock::kEasyUnlockServiceInterface,
easy_unlock::kCreateSecureMessageMethod,
_))
.WillOnce(
Invoke(method_call_handlers_.get(),
&MethodCallHandlers::SetCreateSecureMessageHandler));
EXPECT_CALL(*exported_object_,
ExportMethodAndBlock(
easy_unlock::kEasyUnlockServiceInterface,
easy_unlock::kUnwrapSecureMessageMethod,
_))
.WillOnce(
Invoke(method_call_handlers_.get(),
&MethodCallHandlers::SetUnwrapSecureMessageHandler));
EXPECT_CALL(*exported_object_,
ExportMethodAndBlock(
"org.freedesktop.DBus.Introspectable",
"Introspect",
_)).WillOnce(Return(true));
}
bool InitializeDaemon() {
EXPECT_CALL(*bus_, Connect()).WillOnce(Return(true));
EXPECT_CALL(*bus_, SetUpAsyncOperations()).WillOnce(Return(true));
EXPECT_CALL(*bus_,
RequestOwnershipAndBlock(easy_unlock::kEasyUnlockServiceName,
dbus::Bus::REQUIRE_PRIMARY))
.WillOnce(Return(true));
// Should get called on during daemon shutdown.
EXPECT_CALL(*bus_.get(), ShutdownAndBlock()).WillOnce(Return());
// |bus_|'s GetExportedObject() will return |exported_object_|
// for the given service name and the object path.
EXPECT_CALL(*bus_.get(),
GetExportedObject(dbus::ObjectPath(
easy_unlock::kEasyUnlockServicePath)))
.WillOnce(Return(exported_object_.get()));
SetUpExportedObject();
scoped_ptr<easy_unlock::FakeService> fake_service(
new easy_unlock::FakeService());
daemon_.reset(
new easy_unlock::Daemon(
scoped_ptr<easy_unlock::Service>(new easy_unlock::FakeService()),
bus_,
base::Closure(),
false));
return daemon_->Initialize();
}
base::MessageLoopForIO message_loop_;
scoped_refptr<dbus::MockBus> bus_;
scoped_refptr<dbus::MockExportedObject> exported_object_;
scoped_ptr<easy_unlock::Daemon> daemon_;
};
TEST_F(EasyUnlockTest, GenerateEcP256KeyPair) {
dbus::MethodCall method_call(easy_unlock::kEasyUnlockServiceInterface,
easy_unlock::kGenerateEcP256KeyPairMethod);
// Set serial to an arbitrary value.
method_call.SetSerial(231);
method_call_handlers_->CallGenerateEcP256KeyPair(
&method_call,
base::Bind(&EasyUnlockTest::VerifyGenerateEcP256KeyPairResponse,
base::Unretained(this)));
}
TEST_F(EasyUnlockTest, WrapPublicKeyRSA) {
dbus::MethodCall method_call(easy_unlock::kEasyUnlockServiceInterface,
easy_unlock::kWrapPublicKeyMethod);
// Set serial to an arbitrary value.
method_call.SetSerial(231);
const std::string public_key = "key";
dbus::MessageWriter writer(&method_call);
writer.AppendString(easy_unlock::kKeyAlgorithmRSA);
writer.AppendArrayOfBytes(
reinterpret_cast<const uint8_t*>(public_key.data()),
public_key.length());
method_call_handlers_->CallWrapPublicKey(
&method_call,
base::Bind(
&EasyUnlockTest::VerifyDataResponse,
base::Unretained(this),
"public_key_RSA_key"));
}
TEST_F(EasyUnlockTest, PerformECDHKeyAgreement) {
dbus::MethodCall method_call(easy_unlock::kEasyUnlockServiceInterface,
easy_unlock::kPerformECDHKeyAgreementMethod);
// Set serial to an arbitrary value.
method_call.SetSerial(231);
const std::string private_key = "private_key_1";
const std::string public_key = "public_key_2";
dbus::MessageWriter writer(&method_call);
writer.AppendArrayOfBytes(
reinterpret_cast<const uint8_t*>(private_key.data()),
private_key.length());
writer.AppendArrayOfBytes(reinterpret_cast<const uint8_t*>(public_key.data()),
public_key.length());
method_call_handlers_->CallPerformECDHKeyAgreement(
&method_call,
base::Bind(
&EasyUnlockTest::VerifyDataResponse,
base::Unretained(this),
"secret_key:{private_key:private_key_1,public_key:public_key_2}"));
}
TEST_F(EasyUnlockTest, CreateSecureMessage) {
dbus::MethodCall method_call(easy_unlock::kEasyUnlockServiceInterface,
easy_unlock::kCreateSecureMessageMethod);
// Set serial to an arbitrary value.
method_call.SetSerial(231);
const std::string payload = "cleartext message";
const std::string key = "secret key";
const std::string associated_data = "ad";
const std::string public_metadata = "pm";
const std::string verification_key_id = "key";
const std::string decryption_key_id = "key1";
dbus::MessageWriter writer(&method_call);
writer.AppendArrayOfBytes(reinterpret_cast<const uint8_t*>(payload.data()),
payload.length());
writer.AppendArrayOfBytes(reinterpret_cast<const uint8_t*>(key.data()),
key.length());
writer.AppendArrayOfBytes(
reinterpret_cast<const uint8_t*>(associated_data.data()),
associated_data.length());
writer.AppendArrayOfBytes(
reinterpret_cast<const uint8_t*>(public_metadata.data()),
public_metadata.length());
writer.AppendArrayOfBytes(
reinterpret_cast<const uint8_t*>(verification_key_id.data()),
verification_key_id.length());
writer.AppendArrayOfBytes(
reinterpret_cast<const uint8_t*>(decryption_key_id.data()),
decryption_key_id.length());
writer.AppendString(easy_unlock::kEncryptionTypeAES256CBC);
writer.AppendString(easy_unlock::kSignatureTypeHMACSHA256);
const std::string expected_response =
"securemessage:{"
"payload:cleartext message,"
"key:secret key,"
"associated_data:ad,"
"public_metadata:pm,"
"verification_key_id:key,"
"decryption_key_id:key1,"
"encryption:AES,"
"signature:HMAC"
"}";
method_call_handlers_->CallCreateSecureMessage(
&method_call,
base::Bind(&EasyUnlockTest::VerifyDataResponse,
base::Unretained(this),
expected_response));
}
TEST_F(EasyUnlockTest, CreateSecureMessage_NoDecryptionKeyId) {
dbus::MethodCall method_call(easy_unlock::kEasyUnlockServiceInterface,
easy_unlock::kCreateSecureMessageMethod);
// Set serial to an arbitrary value.
method_call.SetSerial(231);
const std::string payload = "cleartext message";
const std::string key = "secret key";
const std::string associated_data = "ad";
const std::string public_metadata = "pm";
const std::string verification_key_id = "key";
dbus::MessageWriter writer(&method_call);
writer.AppendArrayOfBytes(reinterpret_cast<const uint8_t*>(payload.data()),
payload.length());
writer.AppendArrayOfBytes(reinterpret_cast<const uint8_t*>(key.data()),
key.length());
writer.AppendArrayOfBytes(
reinterpret_cast<const uint8_t*>(associated_data.data()),
associated_data.length());
writer.AppendArrayOfBytes(
reinterpret_cast<const uint8_t*>(public_metadata.data()),
public_metadata.length());
writer.AppendArrayOfBytes(
reinterpret_cast<const uint8_t*>(verification_key_id.data()),
verification_key_id.length());
writer.AppendString(easy_unlock::kEncryptionTypeAES256CBC);
writer.AppendString(easy_unlock::kSignatureTypeHMACSHA256);
const std::string expected_response =
"securemessage:{"
"payload:cleartext message,"
"key:secret key,"
"associated_data:ad,"
"public_metadata:pm,"
"verification_key_id:key,"
"decryption_key_id:,"
"encryption:AES,"
"signature:HMAC"
"}";
method_call_handlers_->CallCreateSecureMessage(
&method_call,
base::Bind(&EasyUnlockTest::VerifyDataResponse,
base::Unretained(this),
expected_response));
}
TEST_F(EasyUnlockTest, CreateSecureMessage_Invalid_MissingParameter) {
dbus::MethodCall method_call(easy_unlock::kEasyUnlockServiceInterface,
easy_unlock::kCreateSecureMessageMethod);
// Set serial to an arbitrary value.
method_call.SetSerial(231);
const std::string payload = "cleartext message";
const std::string key = "secret key";
const std::string associated_data = "ad";
const std::string verification_key_id = "key";
dbus::MessageWriter writer(&method_call);
writer.AppendArrayOfBytes(reinterpret_cast<const uint8_t*>(payload.data()),
payload.length());
writer.AppendArrayOfBytes(reinterpret_cast<const uint8_t*>(key.data()),
key.length());
writer.AppendArrayOfBytes(
reinterpret_cast<const uint8_t*>(associated_data.data()),
associated_data.length());
writer.AppendArrayOfBytes(
reinterpret_cast<const uint8_t*>(verification_key_id.data()),
verification_key_id.length());
writer.AppendString(easy_unlock::kEncryptionTypeAES256CBC);
writer.AppendString(easy_unlock::kSignatureTypeHMACSHA256);
method_call_handlers_->CallCreateSecureMessage(
&method_call,
base::Bind(&EasyUnlockTest::VerifyDataResponse,
base::Unretained(this),
""));
}
TEST_F(EasyUnlockTest, CreateSecureMessage_Invalid_UnknownEncryptionType) {
dbus::MethodCall method_call(easy_unlock::kEasyUnlockServiceInterface,
easy_unlock::kCreateSecureMessageMethod);
// Set serial to an arbitrary value.
method_call.SetSerial(231);
const std::string payload = "cleartext message";
const std::string key = "secret key";
const std::string associated_data = "ad";
const std::string public_metadata = "pm";
const std::string verification_key_id = "key";
dbus::MessageWriter writer(&method_call);
writer.AppendArrayOfBytes(reinterpret_cast<const uint8_t*>(payload.data()),
payload.length());
writer.AppendArrayOfBytes(reinterpret_cast<const uint8_t*>(key.data()),
key.length());
writer.AppendArrayOfBytes(
reinterpret_cast<const uint8_t*>(associated_data.data()),
associated_data.length());
writer.AppendArrayOfBytes(
reinterpret_cast<const uint8_t*>(public_metadata.data()),
public_metadata.length());
writer.AppendArrayOfBytes(
reinterpret_cast<const uint8_t*>(verification_key_id.data()),
verification_key_id.length());
writer.AppendString("UNKNOWN");
writer.AppendString(easy_unlock::kSignatureTypeHMACSHA256);
method_call_handlers_->CallCreateSecureMessage(
&method_call,
base::Bind(&EasyUnlockTest::VerifyDataResponse,
base::Unretained(this),
""));
}
TEST_F(EasyUnlockTest, CreateSecureMessage_Invalid_UnknownSignatureType) {
dbus::MethodCall method_call(easy_unlock::kEasyUnlockServiceInterface,
easy_unlock::kCreateSecureMessageMethod);
// Set serial to an arbitrary value.
method_call.SetSerial(231);
const std::string payload = "cleartext message";
const std::string key = "secret key";
const std::string associated_data = "ad";
const std::string public_metadata = "pm";
const std::string verification_key_id = "key";
dbus::MessageWriter writer(&method_call);
writer.AppendArrayOfBytes(reinterpret_cast<const uint8_t*>(payload.data()),
payload.length());
writer.AppendArrayOfBytes(reinterpret_cast<const uint8_t*>(key.data()),
key.length());
writer.AppendArrayOfBytes(
reinterpret_cast<const uint8_t*>(associated_data.data()),
associated_data.length());
writer.AppendArrayOfBytes(
reinterpret_cast<const uint8_t*>(public_metadata.data()),
public_metadata.length());
writer.AppendArrayOfBytes(
reinterpret_cast<const uint8_t*>(verification_key_id.data()),
verification_key_id.length());
writer.AppendString(easy_unlock::kEncryptionTypeAES256CBC);
writer.AppendString("UNKOWN");
method_call_handlers_->CallCreateSecureMessage(
&method_call,
base::Bind(&EasyUnlockTest::VerifyDataResponse,
base::Unretained(this),
""));
}
TEST_F(EasyUnlockTest, UnwrapSecureMessage) {
dbus::MethodCall method_call(easy_unlock::kEasyUnlockServiceInterface,
easy_unlock::kUnwrapSecureMessageMethod);
// Set serial to an arbitrary value.
method_call.SetSerial(231);
const std::string message = "secure message";
const std::string key = "secret key";
const std::string associated_data = "ad";
dbus::MessageWriter writer(&method_call);
writer.AppendArrayOfBytes(reinterpret_cast<const uint8_t*>(message.data()),
message.length());
writer.AppendArrayOfBytes(reinterpret_cast<const uint8_t*>(key.data()),
key.length());
writer.AppendArrayOfBytes(
reinterpret_cast<const uint8_t*>(associated_data.data()),
associated_data.length());
writer.AppendString(easy_unlock::kEncryptionTypeAES256CBC);
writer.AppendString(easy_unlock::kSignatureTypeHMACSHA256);
const std::string expected_response =
"unwrappedmessage:{"
"original:secure message,"
"key:secret key,"
"associated_data:ad,"
"encryption:AES,"
"signature:HMAC"
"}";
method_call_handlers_->CallUnwrapSecureMessage(
&method_call,
base::Bind(&EasyUnlockTest::VerifyDataResponse,
base::Unretained(this),
expected_response));
}
} // namespace