mock_fido_device.cc 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. // Copyright 2017 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. #include "device/fido/mock_fido_device.h"
  5. #include <utility>
  6. #include "base/bind.h"
  7. #include "base/location.h"
  8. #include "base/strings/strcat.h"
  9. #include "base/threading/thread_task_runner_handle.h"
  10. #include "components/apdu/apdu_response.h"
  11. #include "components/cbor/writer.h"
  12. #include "device/fido/device_response_converter.h"
  13. #include "device/fido/fido_constants.h"
  14. #include "device/fido/fido_parsing_utils.h"
  15. #include "device/fido/fido_test_data.h"
  16. namespace device {
  17. namespace {
  18. AuthenticatorGetInfoResponse DefaultAuthenticatorInfo() {
  19. return *ReadCTAPGetInfoResponse(test_data::kTestAuthenticatorGetInfoResponse);
  20. }
  21. } // namespace
  22. // static
  23. std::unique_ptr<MockFidoDevice> MockFidoDevice::MakeU2f() {
  24. return std::make_unique<MockFidoDevice>(ProtocolVersion::kU2f, absl::nullopt);
  25. }
  26. // static
  27. std::unique_ptr<MockFidoDevice> MockFidoDevice::MakeCtap(
  28. absl::optional<AuthenticatorGetInfoResponse> device_info) {
  29. if (!device_info) {
  30. device_info = DefaultAuthenticatorInfo();
  31. }
  32. auto device = std::make_unique<MockFidoDevice>(ProtocolVersion::kCtap2,
  33. std::move(*device_info));
  34. device->StubGetDisplayName();
  35. return device;
  36. }
  37. // static
  38. std::unique_ptr<MockFidoDevice>
  39. MockFidoDevice::MakeU2fWithGetInfoExpectation() {
  40. auto device = std::make_unique<MockFidoDevice>();
  41. device->StubGetId();
  42. device->StubGetDisplayName();
  43. device->ExpectWinkedAtLeastOnce();
  44. device->ExpectCtap2CommandAndRespondWith(
  45. CtapRequestCommand::kAuthenticatorGetInfo, absl::nullopt);
  46. return device;
  47. }
  48. // static
  49. std::unique_ptr<MockFidoDevice> MockFidoDevice::MakeCtapWithGetInfoExpectation(
  50. absl::optional<base::span<const uint8_t>> get_info_response) {
  51. if (!get_info_response) {
  52. get_info_response = test_data::kTestAuthenticatorGetInfoResponse;
  53. }
  54. auto get_info = ReadCTAPGetInfoResponse(*get_info_response);
  55. CHECK(get_info);
  56. auto device = MockFidoDevice::MakeCtap(std::move(*get_info));
  57. device->StubGetId();
  58. device->StubGetDisplayName();
  59. device->ExpectCtap2CommandAndRespondWith(
  60. CtapRequestCommand::kAuthenticatorGetInfo, std::move(get_info_response));
  61. return device;
  62. }
  63. std::vector<uint8_t> MockFidoDevice::EncodeCBORRequest(
  64. std::pair<CtapRequestCommand, absl::optional<cbor::Value>> request) {
  65. std::vector<uint8_t> request_bytes;
  66. if (request.second) {
  67. absl::optional<std::vector<uint8_t>> cbor_bytes =
  68. cbor::Writer::Write(*request.second);
  69. DCHECK(cbor_bytes);
  70. request_bytes = std::move(*cbor_bytes);
  71. }
  72. request_bytes.insert(request_bytes.begin(),
  73. static_cast<uint8_t>(request.first));
  74. return request_bytes;
  75. }
  76. // Matcher to compare the first byte of the incoming requests.
  77. MATCHER_P(IsCtap2Command, expected_command, "") {
  78. return !arg.empty() && arg[0] == base::strict_cast<uint8_t>(expected_command);
  79. }
  80. MockFidoDevice::MockFidoDevice() = default;
  81. MockFidoDevice::MockFidoDevice(
  82. ProtocolVersion protocol_version,
  83. absl::optional<AuthenticatorGetInfoResponse> device_info)
  84. : MockFidoDevice() {
  85. set_supported_protocol(protocol_version);
  86. if (device_info) {
  87. SetDeviceInfo(std::move(*device_info));
  88. }
  89. }
  90. MockFidoDevice::~MockFidoDevice() = default;
  91. FidoDevice::CancelToken MockFidoDevice::DeviceTransact(
  92. std::vector<uint8_t> command,
  93. DeviceCallback cb) {
  94. return DeviceTransactPtr(command, cb);
  95. }
  96. void MockFidoDevice::TryWink(base::OnceClosure cb) {
  97. TryWinkRef(cb);
  98. }
  99. FidoTransportProtocol MockFidoDevice::DeviceTransport() const {
  100. return transport_protocol_;
  101. }
  102. base::WeakPtr<FidoDevice> MockFidoDevice::GetWeakPtr() {
  103. return weak_factory_.GetWeakPtr();
  104. }
  105. void MockFidoDevice::ExpectWinkedAtLeastOnce() {
  106. EXPECT_CALL(*this, TryWinkRef(::testing::_))
  107. .Times(::testing::AtLeast(1))
  108. .WillRepeatedly([](base::OnceClosure& cb) { std::move(cb).Run(); });
  109. }
  110. void MockFidoDevice::StubGetId() {
  111. // Use a counter to keep the device ID unique.
  112. static size_t i = 0;
  113. EXPECT_CALL(*this, GetId())
  114. .WillRepeatedly(
  115. testing::Return(base::StrCat({"mockdevice", std::to_string(i++)})));
  116. }
  117. void MockFidoDevice::ExpectCtap2CommandAndRespondWith(
  118. CtapRequestCommand command,
  119. absl::optional<base::span<const uint8_t>> response,
  120. base::TimeDelta delay,
  121. testing::Matcher<base::span<const uint8_t>> request_matcher) {
  122. auto data = fido_parsing_utils::MaterializeOrNull(response);
  123. auto send_response = [ data(std::move(data)), delay ](DeviceCallback & cb) {
  124. base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
  125. FROM_HERE, base::BindOnce(std::move(cb), std::move(data)), delay);
  126. };
  127. EXPECT_CALL(*this,
  128. DeviceTransactPtr(AllOf(IsCtap2Command(command), request_matcher),
  129. ::testing::_))
  130. .WillOnce(::testing::DoAll(
  131. ::testing::WithArg<1>(::testing::Invoke(send_response)),
  132. ::testing::Return(0)));
  133. }
  134. void MockFidoDevice::ExpectCtap2CommandAndRespondWithError(
  135. CtapRequestCommand command,
  136. CtapDeviceResponseCode response_code,
  137. base::TimeDelta delay) {
  138. std::array<uint8_t, 1> data{base::strict_cast<uint8_t>(response_code)};
  139. return ExpectCtap2CommandAndRespondWith(std::move(command), data, delay);
  140. }
  141. void MockFidoDevice::ExpectRequestAndRespondWith(
  142. base::span<const uint8_t> request,
  143. absl::optional<base::span<const uint8_t>> response,
  144. base::TimeDelta delay) {
  145. auto data = fido_parsing_utils::MaterializeOrNull(response);
  146. auto send_response = [ data(std::move(data)), delay ](DeviceCallback & cb) {
  147. base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
  148. FROM_HERE, base::BindOnce(std::move(cb), std::move(data)), delay);
  149. };
  150. auto request_as_vector = fido_parsing_utils::Materialize(request);
  151. EXPECT_CALL(*this,
  152. DeviceTransactPtr(std::move(request_as_vector), ::testing::_))
  153. .WillOnce(::testing::DoAll(
  154. ::testing::WithArg<1>(::testing::Invoke(send_response)),
  155. ::testing::Return(0)));
  156. }
  157. void MockFidoDevice::ExpectCtap2CommandAndDoNotRespond(
  158. CtapRequestCommand command) {
  159. EXPECT_CALL(*this, DeviceTransactPtr(IsCtap2Command(command), ::testing::_))
  160. .WillOnce(::testing::Return(0));
  161. }
  162. void MockFidoDevice::ExpectRequestAndDoNotRespond(
  163. base::span<const uint8_t> request) {
  164. auto request_as_vector = fido_parsing_utils::Materialize(request);
  165. EXPECT_CALL(*this,
  166. DeviceTransactPtr(std::move(request_as_vector), ::testing::_))
  167. .WillOnce(::testing::Return(0));
  168. }
  169. void MockFidoDevice::SetDeviceTransport(
  170. FidoTransportProtocol transport_protocol) {
  171. transport_protocol_ = transport_protocol;
  172. }
  173. void MockFidoDevice::StubGetDisplayName() {
  174. EXPECT_CALL(*this, GetDisplayName())
  175. .WillRepeatedly(testing::Return(std::string()));
  176. }
  177. } // namespace device