u2f_register_operation_unittest.cc 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  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 "device/fido/u2f_register_operation.h"
  5. #include <memory>
  6. #include <utility>
  7. #include "base/test/task_environment.h"
  8. #include "device/fido/authenticator_make_credential_response.h"
  9. #include "device/fido/ctap_make_credential_request.h"
  10. #include "device/fido/fido_constants.h"
  11. #include "device/fido/fido_parsing_utils.h"
  12. #include "device/fido/fido_test_data.h"
  13. #include "device/fido/mock_fido_device.h"
  14. #include "device/fido/test_callback_receiver.h"
  15. #include "device/fido/virtual_u2f_device.h"
  16. #include "testing/gmock/include/gmock/gmock.h"
  17. #include "testing/gtest/include/gtest/gtest.h"
  18. namespace device {
  19. using ::testing::_;
  20. namespace {
  21. // Creates a CtapMakeCredentialRequest with given |registered_keys| as
  22. // exclude list.
  23. CtapMakeCredentialRequest CreateRegisterRequestWithRegisteredKeys(
  24. std::vector<PublicKeyCredentialDescriptor> registered_keys,
  25. bool is_individual_attestation = false) {
  26. PublicKeyCredentialRpEntity rp(test_data::kRelyingPartyId);
  27. PublicKeyCredentialUserEntity user(
  28. fido_parsing_utils::Materialize(test_data::kUserId));
  29. CtapMakeCredentialRequest request(
  30. test_data::kClientDataJson, std::move(rp), std::move(user),
  31. PublicKeyCredentialParams(
  32. std::vector<PublicKeyCredentialParams::CredentialInfo>(1)));
  33. request.exclude_list = std::move(registered_keys);
  34. if (is_individual_attestation) {
  35. request.attestation_preference =
  36. AttestationConveyancePreference::kEnterpriseApprovedByBrowser;
  37. }
  38. return request;
  39. }
  40. // Creates a CtapMakeCredentialRequest with an empty exclude list.
  41. CtapMakeCredentialRequest CreateRegisterRequest(
  42. bool is_individual_attestation = false) {
  43. return CreateRegisterRequestWithRegisteredKeys(
  44. std::vector<PublicKeyCredentialDescriptor>(), is_individual_attestation);
  45. }
  46. using TestRegisterCallback = ::device::test::StatusAndValueCallbackReceiver<
  47. CtapDeviceResponseCode,
  48. absl::optional<AuthenticatorMakeCredentialResponse>>;
  49. } // namespace
  50. class U2fRegisterOperationTest : public ::testing::Test {
  51. public:
  52. TestRegisterCallback& register_callback_receiver() {
  53. return register_callback_receiver_;
  54. }
  55. private:
  56. base::test::TaskEnvironment task_environment_;
  57. TestRegisterCallback register_callback_receiver_;
  58. };
  59. TEST_F(U2fRegisterOperationTest, TestRegisterSuccess) {
  60. auto request = CreateRegisterRequest();
  61. auto device = std::make_unique<MockFidoDevice>();
  62. EXPECT_CALL(*device, GetId()).WillRepeatedly(testing::Return("device"));
  63. device->ExpectWinkedAtLeastOnce();
  64. device->ExpectRequestAndRespondWith(
  65. test_data::kU2fRegisterCommandApdu,
  66. test_data::kApduEncodedNoErrorRegisterResponse);
  67. auto u2f_register = std::make_unique<U2fRegisterOperation>(
  68. device.get(), std::move(request),
  69. register_callback_receiver().callback());
  70. u2f_register->Start();
  71. register_callback_receiver().WaitForCallback();
  72. EXPECT_EQ(CtapDeviceResponseCode::kSuccess,
  73. register_callback_receiver().status());
  74. ASSERT_TRUE(register_callback_receiver().value());
  75. EXPECT_THAT(register_callback_receiver()
  76. .value()
  77. ->attestation_object()
  78. .GetCredentialId(),
  79. ::testing::ElementsAreArray(test_data::kU2fSignKeyHandle));
  80. }
  81. TEST_F(U2fRegisterOperationTest, TestRegisterSuccessWithFake) {
  82. auto request = CreateRegisterRequest();
  83. auto device = std::make_unique<VirtualU2fDevice>();
  84. auto u2f_register = std::make_unique<U2fRegisterOperation>(
  85. device.get(), std::move(request),
  86. register_callback_receiver().callback());
  87. u2f_register->Start();
  88. register_callback_receiver().WaitForCallback();
  89. EXPECT_EQ(CtapDeviceResponseCode::kSuccess,
  90. register_callback_receiver().status());
  91. // We don't verify the response from the fake, but do a quick sanity check.
  92. ASSERT_TRUE(register_callback_receiver().value());
  93. EXPECT_EQ(32ul, register_callback_receiver()
  94. .value()
  95. ->attestation_object()
  96. .GetCredentialId()
  97. .size());
  98. }
  99. TEST_F(U2fRegisterOperationTest, TestDelayedSuccess) {
  100. auto request = CreateRegisterRequest();
  101. auto device = std::make_unique<MockFidoDevice>();
  102. EXPECT_CALL(*device, GetId()).WillRepeatedly(testing::Return("device"));
  103. device->ExpectWinkedAtLeastOnce();
  104. // Device error out once waiting for user presence before retrying.
  105. ::testing::InSequence s;
  106. device->ExpectRequestAndRespondWith(
  107. test_data::kU2fRegisterCommandApdu,
  108. test_data::kU2fConditionNotSatisfiedApduResponse);
  109. device->ExpectRequestAndRespondWith(
  110. test_data::kU2fRegisterCommandApdu,
  111. test_data::kApduEncodedNoErrorRegisterResponse);
  112. auto u2f_register = std::make_unique<U2fRegisterOperation>(
  113. device.get(), std::move(request),
  114. register_callback_receiver().callback());
  115. u2f_register->Start();
  116. register_callback_receiver().WaitForCallback();
  117. EXPECT_EQ(CtapDeviceResponseCode::kSuccess,
  118. register_callback_receiver().status());
  119. ASSERT_TRUE(register_callback_receiver().value());
  120. EXPECT_THAT(register_callback_receiver()
  121. .value()
  122. ->attestation_object()
  123. .GetCredentialId(),
  124. ::testing::ElementsAreArray(test_data::kU2fSignKeyHandle));
  125. }
  126. // Tests a scenario where a single device is connected and registration call
  127. // is received with two unknown key handles. We expect that two check
  128. // only sign-in calls be processed before registration.
  129. TEST_F(U2fRegisterOperationTest, TestRegistrationWithExclusionList) {
  130. auto request = CreateRegisterRequestWithRegisteredKeys(
  131. {PublicKeyCredentialDescriptor(
  132. CredentialType::kPublicKey,
  133. fido_parsing_utils::Materialize(test_data::kKeyHandleAlpha)),
  134. PublicKeyCredentialDescriptor(
  135. CredentialType::kPublicKey,
  136. fido_parsing_utils::Materialize(test_data::kKeyHandleBeta))});
  137. auto device = std::make_unique<MockFidoDevice>();
  138. EXPECT_CALL(*device, GetId()).WillRepeatedly(::testing::Return("device"));
  139. device->ExpectWinkedAtLeastOnce();
  140. // DeviceTransact() will be called three times including two sign-in calls
  141. // with bogus challenges and one registration call. For the first two calls,
  142. // device will invoke MockFidoDevice::WrongData/WrongLength as the
  143. // authenticator did not create the two key handles provided in the exclude
  144. // list. At the third call, MockFidoDevice::NoErrorRegister will be invoked
  145. // after registration.
  146. ::testing::InSequence s;
  147. device->ExpectRequestAndRespondWith(
  148. test_data::kU2fSignCommandApduWithKeyAlphaAndBogusChallenge,
  149. test_data::kU2fWrongDataApduResponse);
  150. device->ExpectRequestAndRespondWith(
  151. test_data::kU2fSignCommandApduWithKeyBetaAndBogusChallenge,
  152. test_data::kU2fWrongLengthApduResponse);
  153. device->ExpectRequestAndRespondWith(
  154. test_data::kU2fRegisterCommandApdu,
  155. test_data::kApduEncodedNoErrorRegisterResponse);
  156. auto u2f_register = std::make_unique<U2fRegisterOperation>(
  157. device.get(), std::move(request),
  158. register_callback_receiver().callback());
  159. u2f_register->Start();
  160. register_callback_receiver().WaitForCallback();
  161. ASSERT_TRUE(register_callback_receiver().value());
  162. EXPECT_EQ(CtapDeviceResponseCode::kSuccess,
  163. register_callback_receiver().status());
  164. EXPECT_THAT(register_callback_receiver()
  165. .value()
  166. ->attestation_object()
  167. .GetCredentialId(),
  168. ::testing::ElementsAreArray(test_data::kU2fSignKeyHandle));
  169. }
  170. // Tests a scenario where single device is connected and registration is
  171. // called with a key in the exclude list that was created by this device. We
  172. // assume that the duplicate key is the last key handle in the exclude list.
  173. // Therefore, after duplicate key handle is found, the process is expected to
  174. // terminate after calling bogus registration which checks for user presence.
  175. TEST_F(U2fRegisterOperationTest, TestRegistrationWithDuplicateHandle) {
  176. // Simulate two unknown key handles followed by a duplicate key.
  177. auto request = CreateRegisterRequestWithRegisteredKeys(
  178. {PublicKeyCredentialDescriptor(
  179. CredentialType::kPublicKey,
  180. fido_parsing_utils::Materialize(test_data::kKeyHandleAlpha)),
  181. PublicKeyCredentialDescriptor(
  182. CredentialType::kPublicKey,
  183. fido_parsing_utils::Materialize(test_data::kKeyHandleBeta)),
  184. PublicKeyCredentialDescriptor(
  185. CredentialType::kPublicKey,
  186. fido_parsing_utils::Materialize(test_data::kKeyHandleGamma))});
  187. auto device = std::make_unique<MockFidoDevice>();
  188. EXPECT_CALL(*device, GetId()).WillRepeatedly(::testing::Return("device"));
  189. device->ExpectWinkedAtLeastOnce();
  190. // For three keys in exclude list, the first two keys will return
  191. // SW_WRONG_DATA and the final duplicate key handle will invoke
  192. // SW_NO_ERROR. This means user presence has already been collected, so the
  193. // request is concluded with Ctap2ErrCredentialExcluded.
  194. ::testing::InSequence s;
  195. device->ExpectRequestAndRespondWith(
  196. test_data::kU2fSignCommandApduWithKeyAlphaAndBogusChallenge,
  197. test_data::kU2fWrongDataApduResponse);
  198. device->ExpectRequestAndRespondWith(
  199. test_data::kU2fSignCommandApduWithKeyBetaAndBogusChallenge,
  200. test_data::kU2fWrongDataApduResponse);
  201. // The signature in the response is intentionally incorrect since nothing
  202. // should depend on it being correct.
  203. device->ExpectRequestAndRespondWith(
  204. test_data::kU2fSignCommandApduWithKeyGammaAndBogusChallenge,
  205. test_data::kApduEncodedNoErrorSignResponse);
  206. auto u2f_register = std::make_unique<U2fRegisterOperation>(
  207. device.get(), std::move(request),
  208. register_callback_receiver().callback());
  209. u2f_register->Start();
  210. register_callback_receiver().WaitForCallback();
  211. EXPECT_EQ(CtapDeviceResponseCode::kCtap2ErrCredentialExcluded,
  212. register_callback_receiver().status());
  213. EXPECT_FALSE(register_callback_receiver().value());
  214. }
  215. MATCHER_P(IndicatesIndividualAttestation, expected, "") {
  216. return arg.size() > 2 && ((arg[2] & 0x80) == 0x80) == expected;
  217. }
  218. TEST_F(U2fRegisterOperationTest, TestIndividualAttestation) {
  219. // Test that the individual attestation flag is correctly reflected in the
  220. // resulting registration APDU.
  221. for (const auto& individual_attestation : {false, true}) {
  222. SCOPED_TRACE(individual_attestation);
  223. TestRegisterCallback cb;
  224. auto request = CreateRegisterRequest(individual_attestation);
  225. auto device = std::make_unique<MockFidoDevice>();
  226. EXPECT_CALL(*device, GetId()).WillRepeatedly(::testing::Return("device"));
  227. device->ExpectWinkedAtLeastOnce();
  228. device->ExpectRequestAndRespondWith(
  229. individual_attestation
  230. ? test_data::kU2fRegisterCommandApduWithIndividualAttestation
  231. : test_data::kU2fRegisterCommandApdu,
  232. test_data::kApduEncodedNoErrorRegisterResponse);
  233. auto u2f_register = std::make_unique<U2fRegisterOperation>(
  234. device.get(), std::move(request), cb.callback());
  235. u2f_register->Start();
  236. cb.WaitForCallback();
  237. EXPECT_EQ(CtapDeviceResponseCode::kSuccess, cb.status());
  238. ASSERT_TRUE(cb.value());
  239. EXPECT_THAT(cb.value()->attestation_object().GetCredentialId(),
  240. ::testing::ElementsAreArray(test_data::kU2fSignKeyHandle));
  241. }
  242. }
  243. } // namespace device