| Index: device/u2f/u2f_sign_unittest.cc
|
| diff --git a/device/u2f/u2f_sign_unittest.cc b/device/u2f/u2f_sign_unittest.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..df9edf26a4ce175f1311f3b0dd45c6a39fb2bf37
|
| --- /dev/null
|
| +++ b/device/u2f/u2f_sign_unittest.cc
|
| @@ -0,0 +1,212 @@
|
| +// Copyright 2017 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 <list>
|
| +
|
| +#include "base/run_loop.h"
|
| +#include "base/test/test_io_thread.h"
|
| +#include "device/base/mock_device_client.h"
|
| +#include "device/hid/mock_hid_service.h"
|
| +#include "device/test/test_device_client.h"
|
| +#include "mock_u2f_device.h"
|
| +#include "testing/gtest/include/gtest/gtest.h"
|
| +#include "u2f_sign.h"
|
| +
|
| +namespace device {
|
| +class U2fSignTest : public testing::Test {
|
| + public:
|
| + void SetUp() override {
|
| + message_loop_.reset(new base::MessageLoopForUI());
|
| + io_thread_.reset(new base::TestIOThread(base::TestIOThread::kAutoStart));
|
| + device_client_.reset(new MockDeviceClient());
|
| + MockHidService* hid_service = device_client_->hid_service();
|
| + hid_service->FirstEnumerationComplete();
|
| + }
|
| +
|
| + protected:
|
| + std::unique_ptr<base::MessageLoopForUI> message_loop_;
|
| + std::unique_ptr<base::TestIOThread> io_thread_;
|
| + std::unique_ptr<device::MockDeviceClient> device_client_;
|
| +};
|
| +
|
| +class TestSignCallback {
|
| + public:
|
| + TestSignCallback()
|
| + : closure_(),
|
| + callback_(base::Bind(&TestSignCallback::ReceivedCallback,
|
| + base::Unretained(this))),
|
| + run_loop_() {}
|
| + ~TestSignCallback() {}
|
| +
|
| + void ReceivedCallback(uint8_t status_code, std::vector<uint8_t> response) {
|
| + response_ = std::make_pair(status_code, response);
|
| + closure_.Run();
|
| + }
|
| +
|
| + std::pair<uint8_t, std::vector<uint8_t>>& WaitForCallback() {
|
| + closure_ = run_loop_.QuitClosure();
|
| + run_loop_.Run();
|
| + return response_;
|
| + }
|
| +
|
| + const U2fRequest::ResponseCallback& callback() { return callback_; }
|
| +
|
| + private:
|
| + std::pair<uint8_t, std::vector<uint8_t>> response_;
|
| + base::Closure closure_;
|
| + U2fRequest::ResponseCallback callback_;
|
| + base::RunLoop run_loop_;
|
| +};
|
| +
|
| +TEST_F(U2fSignTest, TestSignSuccess) {
|
| + std::vector<uint8_t> key(32, 0xA);
|
| + std::vector<std::vector<uint8_t>> handles = {key};
|
| + std::unique_ptr<MockU2fDevice> device(new MockU2fDevice());
|
| + EXPECT_CALL(*device.get(), DeviceTransactPtr(testing::_, testing::_))
|
| + .WillOnce(testing::Invoke(MockU2fDevice::NoErrorSign));
|
| + EXPECT_CALL(*device.get(), TryWink(testing::_))
|
| + .WillOnce(testing::Invoke(MockU2fDevice::WinkDoNothing));
|
| + TestSignCallback cb;
|
| + U2fSign request(handles, std::vector<uint8_t>(32), std::vector<uint8_t>(32),
|
| + cb.callback());
|
| + request.U2fRequest::devices_.push_back(std::move(device));
|
| + request.Start();
|
| + std::pair<uint8_t, std::vector<uint8_t>>& response = cb.WaitForCallback();
|
| + EXPECT_EQ(static_cast<uint8_t>(U2fDevice::ReturnCode::SUCCESS),
|
| + response.first);
|
| + // Correct key was sent so a sign response is expected
|
| + ASSERT_LT(static_cast<size_t>(0), response.second.size());
|
| + EXPECT_EQ(static_cast<uint8_t>(MockU2fDevice::kSign), response.second[0]);
|
| +}
|
| +
|
| +TEST_F(U2fSignTest, TestDelayedSuccess) {
|
| + std::vector<uint8_t> key(32, 0xA);
|
| + std::vector<std::vector<uint8_t>> handles = {key};
|
| + std::unique_ptr<MockU2fDevice> device(new MockU2fDevice());
|
| +
|
| + // Go through the state machine twice before success
|
| + EXPECT_CALL(*device.get(), DeviceTransactPtr(testing::_, testing::_))
|
| + .WillOnce(testing::Invoke(MockU2fDevice::NotSatisfied))
|
| + .WillOnce(testing::Invoke(MockU2fDevice::NoErrorSign));
|
| + EXPECT_CALL(*device.get(), TryWink(testing::_))
|
| + .Times(2)
|
| + .WillRepeatedly(testing::Invoke(MockU2fDevice::WinkDoNothing));
|
| + TestSignCallback cb;
|
| +
|
| + U2fSign request(handles, std::vector<uint8_t>(32), std::vector<uint8_t>(32),
|
| + cb.callback());
|
| + request.U2fRequest::devices_.push_back(std::move(device));
|
| + request.Start();
|
| + std::pair<uint8_t, std::vector<uint8_t>>& response = cb.WaitForCallback();
|
| + EXPECT_EQ(static_cast<uint8_t>(U2fDevice::ReturnCode::SUCCESS),
|
| + response.first);
|
| + // Correct key was sent so a sign response is expected
|
| + ASSERT_LT(static_cast<size_t>(0), response.second.size());
|
| + EXPECT_EQ(static_cast<uint8_t>(MockU2fDevice::kSign), response.second[0]);
|
| +}
|
| +
|
| +TEST_F(U2fSignTest, TestMultipleHandles) {
|
| + std::vector<uint8_t> key(32, 0xA);
|
| + std::vector<uint8_t> wrong_key0(32, 0xB);
|
| + std::vector<uint8_t> wrong_key1(32, 0xC);
|
| + std::vector<uint8_t> wrong_key2(32, 0xD);
|
| + // Put wrong key first to ensure that it will be tested before the correct key
|
| + std::vector<std::vector<uint8_t>> handles = {wrong_key0, wrong_key1,
|
| + wrong_key2, key};
|
| + std::unique_ptr<MockU2fDevice> device(new MockU2fDevice());
|
| +
|
| + // Wrong key would respond with SW_WRONG_DATA
|
| + EXPECT_CALL(*device.get(), DeviceTransactPtr(testing::_, testing::_))
|
| + .WillOnce(testing::Invoke(MockU2fDevice::WrongData))
|
| + .WillOnce(testing::Invoke(MockU2fDevice::WrongData))
|
| + .WillOnce(testing::Invoke(MockU2fDevice::WrongData))
|
| + .WillOnce(testing::Invoke(MockU2fDevice::NoErrorSign));
|
| + // Only one wink expected per device
|
| + EXPECT_CALL(*device.get(), TryWink(testing::_))
|
| + .WillOnce(testing::Invoke(MockU2fDevice::WinkDoNothing));
|
| +
|
| + TestSignCallback cb;
|
| + U2fSign request(handles, std::vector<uint8_t>(32), std::vector<uint8_t>(32),
|
| + cb.callback());
|
| + request.U2fRequest::devices_.push_back(std::move(device));
|
| + request.Start();
|
| + std::pair<uint8_t, std::vector<uint8_t>>& response = cb.WaitForCallback();
|
| + EXPECT_EQ(static_cast<uint8_t>(U2fDevice::ReturnCode::SUCCESS),
|
| + response.first);
|
| + // Correct key was sent so a sign response is expected
|
| + ASSERT_LT(static_cast<size_t>(0), response.second.size());
|
| + EXPECT_EQ(static_cast<uint8_t>(MockU2fDevice::kSign), response.second[0]);
|
| +}
|
| +
|
| +TEST_F(U2fSignTest, TestMultipleDevices) {
|
| + std::vector<uint8_t> key0(32, 0xA);
|
| + std::vector<uint8_t> key1(32, 0xB);
|
| + // Second device will have a successful touch
|
| + std::vector<std::vector<uint8_t>> handles = {key0, key1};
|
| + std::unique_ptr<MockU2fDevice> device0(new MockU2fDevice());
|
| + std::unique_ptr<MockU2fDevice> device1(new MockU2fDevice());
|
| +
|
| + EXPECT_CALL(*device0.get(), DeviceTransactPtr(testing::_, testing::_))
|
| + .WillOnce(testing::Invoke(MockU2fDevice::WrongData))
|
| + .WillOnce(testing::Invoke(MockU2fDevice::NotSatisfied));
|
| + // One wink per device
|
| + EXPECT_CALL(*device0.get(), TryWink(testing::_))
|
| + .WillOnce(testing::Invoke(MockU2fDevice::WinkDoNothing));
|
| + EXPECT_CALL(*device1.get(), DeviceTransactPtr(testing::_, testing::_))
|
| + .WillOnce(testing::Invoke(MockU2fDevice::NoErrorSign));
|
| + EXPECT_CALL(*device1.get(), TryWink(testing::_))
|
| + .WillOnce(testing::Invoke(MockU2fDevice::WinkDoNothing));
|
| +
|
| + TestSignCallback cb;
|
| + U2fSign request(handles, std::vector<uint8_t>(32), std::vector<uint8_t>(32),
|
| + cb.callback());
|
| + request.U2fRequest::devices_.push_back(std::move(device0));
|
| + request.U2fRequest::devices_.push_back(std::move(device1));
|
| + request.Start();
|
| + std::pair<uint8_t, std::vector<uint8_t>>& response = cb.WaitForCallback();
|
| + EXPECT_EQ(static_cast<uint8_t>(U2fDevice::ReturnCode::SUCCESS),
|
| + response.first);
|
| + // Correct key was sent so a sign response is expected
|
| + ASSERT_LT(static_cast<size_t>(0), response.second.size());
|
| + EXPECT_EQ(static_cast<uint8_t>(MockU2fDevice::kSign), response.second[0]);
|
| +}
|
| +
|
| +TEST_F(U2fSignTest, TestFakeEnroll) {
|
| + std::vector<uint8_t> key0(32, 0xA);
|
| + std::vector<uint8_t> key1(32, 0xB);
|
| + // Second device will be have a successful touch
|
| + std::vector<std::vector<uint8_t>> handles = {key0, key1};
|
| + std::unique_ptr<MockU2fDevice> device0(new MockU2fDevice());
|
| + std::unique_ptr<MockU2fDevice> device1(new MockU2fDevice());
|
| +
|
| + EXPECT_CALL(*device0.get(), DeviceTransactPtr(testing::_, testing::_))
|
| + .WillOnce(testing::Invoke(MockU2fDevice::WrongData))
|
| + .WillOnce(testing::Invoke(MockU2fDevice::NotSatisfied));
|
| + // One wink per device
|
| + EXPECT_CALL(*device0.get(), TryWink(testing::_))
|
| + .WillOnce(testing::Invoke(MockU2fDevice::WinkDoNothing));
|
| + // Both keys will be tried, when both fail, register is tried on that device
|
| + EXPECT_CALL(*device1.get(), DeviceTransactPtr(testing::_, testing::_))
|
| + .WillOnce(testing::Invoke(MockU2fDevice::WrongData))
|
| + .WillOnce(testing::Invoke(MockU2fDevice::WrongData))
|
| + .WillOnce(testing::Invoke(MockU2fDevice::NoErrorRegister));
|
| + EXPECT_CALL(*device1.get(), TryWink(testing::_))
|
| + .WillOnce(testing::Invoke(MockU2fDevice::WinkDoNothing));
|
| +
|
| + TestSignCallback cb;
|
| + U2fSign request(handles, std::vector<uint8_t>(32), std::vector<uint8_t>(32),
|
| + cb.callback());
|
| + request.U2fRequest::devices_.push_back(std::move(device0));
|
| + request.U2fRequest::devices_.push_back(std::move(device1));
|
| + request.Start();
|
| + std::pair<uint8_t, std::vector<uint8_t>>& response = cb.WaitForCallback();
|
| + EXPECT_EQ(static_cast<uint8_t>(U2fDevice::ReturnCode::SUCCESS),
|
| + response.first);
|
| + // Device that responded had no correct keys, so a registration response is
|
| + // expected
|
| + ASSERT_LT(static_cast<size_t>(0), response.second.size());
|
| + EXPECT_EQ(static_cast<uint8_t>(MockU2fDevice::kRegister), response.second[0]);
|
| +}
|
| +
|
| +} // namespace device
|
|
|