make_credential_task_unittest.cc 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. // Copyright 2018 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 <memory>
  5. #include <string>
  6. #include <utility>
  7. #include "base/bind.h"
  8. #include "base/numerics/safe_conversions.h"
  9. #include "base/run_loop.h"
  10. #include "base/test/task_environment.h"
  11. #include "device/base/features.h"
  12. #include "device/fido/authenticator_make_credential_response.h"
  13. #include "device/fido/ctap_make_credential_request.h"
  14. #include "device/fido/device_response_converter.h"
  15. #include "device/fido/fido_constants.h"
  16. #include "device/fido/fido_parsing_utils.h"
  17. #include "device/fido/fido_test_data.h"
  18. #include "device/fido/make_credential_task.h"
  19. #include "device/fido/mock_fido_device.h"
  20. #include "device/fido/test_callback_receiver.h"
  21. #include "device/fido/virtual_ctap2_device.h"
  22. #include "testing/gmock/include/gmock/gmock.h"
  23. #include "testing/gtest/include/gtest/gtest.h"
  24. using ::testing::_;
  25. namespace device {
  26. namespace {
  27. constexpr std::array<uint8_t, kAaguidLength> kTestDeviceAaguid = {
  28. {0xF8, 0xA0, 0x11, 0xF3, 0x8C, 0x0A, 0x4D, 0x15, 0x80, 0x06, 0x17, 0x11,
  29. 0x1F, 0x9E, 0xDC, 0x7D}};
  30. using TestMakeCredentialTaskCallback =
  31. ::device::test::StatusAndValueCallbackReceiver<
  32. CtapDeviceResponseCode,
  33. absl::optional<AuthenticatorMakeCredentialResponse>>;
  34. class FidoMakeCredentialTaskTest : public testing::Test {
  35. public:
  36. FidoMakeCredentialTaskTest() = default;
  37. std::unique_ptr<MakeCredentialTask> CreateMakeCredentialTask(
  38. FidoDevice* device) {
  39. PublicKeyCredentialRpEntity rp(test_data::kRelyingPartyId);
  40. PublicKeyCredentialUserEntity user(
  41. fido_parsing_utils::Materialize(test_data::kUserId));
  42. return std::make_unique<MakeCredentialTask>(
  43. device,
  44. CtapMakeCredentialRequest(
  45. test_data::kClientDataJson, std::move(rp), std::move(user),
  46. PublicKeyCredentialParams(
  47. std::vector<PublicKeyCredentialParams::CredentialInfo>(1))),
  48. MakeCredentialOptions(), callback_receiver_.callback());
  49. }
  50. TestMakeCredentialTaskCallback& make_credential_callback_receiver() {
  51. return callback_receiver_;
  52. }
  53. protected:
  54. base::test::TaskEnvironment task_environment_;
  55. TestMakeCredentialTaskCallback callback_receiver_;
  56. };
  57. TEST_F(FidoMakeCredentialTaskTest, MakeCredentialSuccess) {
  58. auto device = MockFidoDevice::MakeCtap();
  59. device->ExpectCtap2CommandAndRespondWith(
  60. CtapRequestCommand::kAuthenticatorMakeCredential,
  61. test_data::kTestMakeCredentialResponse);
  62. const auto task = CreateMakeCredentialTask(device.get());
  63. make_credential_callback_receiver().WaitForCallback();
  64. EXPECT_EQ(CtapDeviceResponseCode::kSuccess,
  65. make_credential_callback_receiver().status());
  66. EXPECT_TRUE(make_credential_callback_receiver().value());
  67. EXPECT_EQ(device->supported_protocol(), ProtocolVersion::kCtap2);
  68. EXPECT_TRUE(device->device_info());
  69. }
  70. TEST_F(FidoMakeCredentialTaskTest, TestRegisterSuccessWithFake) {
  71. auto device = std::make_unique<VirtualCtap2Device>();
  72. test::TestCallbackReceiver<> done_init;
  73. device->DiscoverSupportedProtocolAndDeviceInfo(done_init.callback());
  74. done_init.WaitForCallback();
  75. const auto task = CreateMakeCredentialTask(device.get());
  76. make_credential_callback_receiver().WaitForCallback();
  77. EXPECT_EQ(CtapDeviceResponseCode::kSuccess,
  78. make_credential_callback_receiver().status());
  79. // We don't verify the response from the fake, but do a quick sanity check.
  80. ASSERT_TRUE(make_credential_callback_receiver().value());
  81. EXPECT_EQ(32u, make_credential_callback_receiver()
  82. .value()
  83. ->attestation_object()
  84. .GetCredentialId()
  85. .size());
  86. }
  87. TEST_F(FidoMakeCredentialTaskTest, FallbackToU2fRegisterSuccess) {
  88. auto device = MockFidoDevice::MakeU2f();
  89. device->ExpectWinkedAtLeastOnce();
  90. device->ExpectRequestAndRespondWith(
  91. test_data::kU2fRegisterCommandApdu,
  92. test_data::kApduEncodedNoErrorRegisterResponse);
  93. const auto task = CreateMakeCredentialTask(device.get());
  94. make_credential_callback_receiver().WaitForCallback();
  95. EXPECT_EQ(ProtocolVersion::kU2f, device->supported_protocol());
  96. EXPECT_EQ(CtapDeviceResponseCode::kSuccess,
  97. make_credential_callback_receiver().status());
  98. }
  99. TEST_F(FidoMakeCredentialTaskTest, DefaultToU2fWhenClientPinSet) {
  100. AuthenticatorGetInfoResponse device_info(
  101. {ProtocolVersion::kCtap2, ProtocolVersion::kU2f},
  102. {Ctap2Version::kCtap2_0}, kTestDeviceAaguid);
  103. AuthenticatorSupportedOptions options;
  104. options.client_pin_availability =
  105. AuthenticatorSupportedOptions::ClientPinAvailability::kSupportedAndPinSet;
  106. device_info.options = std::move(options);
  107. auto device = MockFidoDevice::MakeCtap(std::move(device_info));
  108. device->ExpectWinkedAtLeastOnce();
  109. device->ExpectRequestAndRespondWith(
  110. test_data::kU2fRegisterCommandApdu,
  111. test_data::kApduEncodedNoErrorRegisterResponse);
  112. const auto task = CreateMakeCredentialTask(device.get());
  113. make_credential_callback_receiver().WaitForCallback();
  114. EXPECT_EQ(CtapDeviceResponseCode::kSuccess,
  115. make_credential_callback_receiver().status());
  116. EXPECT_TRUE(make_credential_callback_receiver().value());
  117. }
  118. TEST_F(FidoMakeCredentialTaskTest, EnforceClientPinWhenUserVerificationSet) {
  119. AuthenticatorGetInfoResponse device_info(
  120. {ProtocolVersion::kCtap2, ProtocolVersion::kU2f},
  121. {Ctap2Version::kCtap2_0}, kTestDeviceAaguid);
  122. AuthenticatorSupportedOptions options;
  123. options.client_pin_availability =
  124. AuthenticatorSupportedOptions::ClientPinAvailability::kSupportedAndPinSet;
  125. device_info.options = std::move(options);
  126. auto device = MockFidoDevice::MakeCtap(std::move(device_info));
  127. device->ExpectCtap2CommandAndRespondWith(
  128. CtapRequestCommand::kAuthenticatorMakeCredential, absl::nullopt);
  129. PublicKeyCredentialRpEntity rp(test_data::kRelyingPartyId);
  130. PublicKeyCredentialUserEntity user(
  131. fido_parsing_utils::Materialize(test_data::kUserId));
  132. auto request = CtapMakeCredentialRequest(
  133. test_data::kClientDataJson, std::move(rp), std::move(user),
  134. PublicKeyCredentialParams(
  135. std::vector<PublicKeyCredentialParams::CredentialInfo>(1)));
  136. request.user_verification = UserVerificationRequirement::kRequired;
  137. const auto task = std::make_unique<MakeCredentialTask>(
  138. device.get(), std::move(request), MakeCredentialOptions(),
  139. callback_receiver_.callback());
  140. make_credential_callback_receiver().WaitForCallback();
  141. EXPECT_EQ(CtapDeviceResponseCode::kCtap2ErrOther,
  142. make_credential_callback_receiver().status());
  143. EXPECT_FALSE(make_credential_callback_receiver().value());
  144. }
  145. TEST_F(FidoMakeCredentialTaskTest, TestU2fOnly) {
  146. // Regardless of the device's supported protocol, it should receive a U2F
  147. // request, because the task is instantiated in U2F-only mode.
  148. auto device = MockFidoDevice::MakeCtap();
  149. device->ExpectWinkedAtLeastOnce();
  150. device->ExpectRequestAndRespondWith(
  151. test_data::kU2fRegisterCommandApdu,
  152. test_data::kApduEncodedNoErrorRegisterResponse);
  153. PublicKeyCredentialRpEntity rp(test_data::kRelyingPartyId);
  154. PublicKeyCredentialUserEntity user(
  155. fido_parsing_utils::Materialize(test_data::kUserId));
  156. auto request = CtapMakeCredentialRequest(
  157. test_data::kClientDataJson, std::move(rp), std::move(user),
  158. PublicKeyCredentialParams(
  159. std::vector<PublicKeyCredentialParams::CredentialInfo>(1)));
  160. MakeCredentialOptions request_options;
  161. request_options.make_u2f_api_credential = true;
  162. const auto task = std::make_unique<MakeCredentialTask>(
  163. device.get(), std::move(request), std::move(request_options),
  164. callback_receiver_.callback());
  165. make_credential_callback_receiver().WaitForCallback();
  166. EXPECT_EQ(CtapDeviceResponseCode::kSuccess,
  167. make_credential_callback_receiver().status());
  168. EXPECT_TRUE(make_credential_callback_receiver().value());
  169. }
  170. } // namespace
  171. } // namespace device