blob: e4a3427e1b47d0e1de4e183d1e9b1ff46401ad80 [file] [log] [blame]
Louis Collard99e40242019-08-30 14:57:39 +08001// Copyright 2019 The Chromium OS 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
5#include "u2fd/u2f_msg_handler.h"
6
7#include <iostream>
8#include <memory>
9#include <regex> // NOLINT(build/c++11)
10#include <string>
11
Qijiang Fan713061e2021-03-08 15:45:12 +090012#include <base/check.h>
Louis Collard99e40242019-08-30 14:57:39 +080013#include <base/strings/string_number_conversions.h>
14#include <gmock/gmock.h>
15#include <gtest/gtest.h>
16#include <metrics/metrics_library_mock.h>
17
Louis Collardd4ee40d2019-10-01 14:19:01 +080018#include "u2fd/mock_allowlisting_util.h"
Louis Collard99e40242019-08-30 14:57:39 +080019#include "u2fd/mock_tpm_vendor_cmd.h"
20#include "u2fd/mock_user_state.h"
21
22namespace u2f {
23namespace {
24
25using ::testing::_;
26using ::testing::ContainsRegex;
Mike Frysinger4663bea2021-01-06 12:48:36 -050027using ::testing::DoAll;
Yicheng Li5ca11f52020-05-14 16:49:48 -070028using ::testing::Matcher;
Louis Collard99e40242019-08-30 14:57:39 +080029using ::testing::MatchesRegex;
30using ::testing::NiceMock;
31using ::testing::Return;
32using ::testing::SaveArg;
33using ::testing::SetArgPointee;
34using ::testing::StrictMock;
35
36std::string AdpuToHexString(const U2fResponseAdpu& adpu) {
37 std::string adpu_str;
38 adpu.ToString(&adpu_str);
39 return base::HexEncode(adpu_str.c_str(), adpu_str.size());
40}
41
42brillo::SecureBlob ArrayToSecureBlob(const char* array) {
43 brillo::SecureBlob blob;
44 CHECK(brillo::SecureBlob::HexStringToSecureBlob(array, &blob));
45 return blob;
46}
47
48MATCHER_P(MsgEqStr, expected, "") {
49 std::string match_hex = AdpuToHexString(arg);
50
51 if (match_hex == expected) {
52 return true;
53 }
54
55 *result_listener << match_hex
56 << " did not match expected value: " << expected;
57
58 return false;
59}
60
61MATCHER_P(StructEqStr, expected, "") {
62 std::string arg_hex = base::HexEncode(&arg, sizeof(arg));
63
64 if (arg_hex == expected) {
65 return true;
66 }
67
68 *result_listener << arg_hex << " did not match expected value: " << expected;
69
70 return false;
71}
72
73MATCHER_P(StructMatchesRegex, pattern, "") {
74 std::string arg_hex = base::HexEncode(&arg, sizeof(arg));
75
76 if (std::regex_match(arg_hex, std::regex(pattern))) {
77 return true;
78 }
79
80 *result_listener << arg_hex << " did not match regex: " << pattern;
81
82 return false;
83}
84
85// Dummy User State.
86constexpr char kUserSecret[65] = {[0 ... 63] = 'E', '\0'};
87constexpr uint8_t kCounter = 37;
88
89class U2fMessageHandlerTest : public ::testing::Test {
90 public:
91 void SetUp() override { CreateHandler(false, false); }
92
Louis Collardd4ee40d2019-10-01 14:19:01 +080093 void TearDown() override {
94 EXPECT_EQ(presence_requested_expected_, presence_requested_count_);
95 }
96
Louis Collard99e40242019-08-30 14:57:39 +080097 protected:
98 void CreateHandler(bool allow_legacy_kh, bool allow_g2f_attestation) {
Louis Collardd4ee40d2019-10-01 14:19:01 +080099 mock_allowlisting_util_ = new StrictMock<MockAllowlistingUtil>();
Louis Collard99e40242019-08-30 14:57:39 +0800100
101 handler_.reset(new U2fMessageHandler(
Louis Collardd4ee40d2019-10-01 14:19:01 +0800102 std::unique_ptr<AllowlistingUtil>(mock_allowlisting_util_),
Louis Collarda5fa3c32019-10-07 15:02:25 +0800103 [this]() { presence_requested_count_++; }, &mock_user_state_,
104 &mock_tpm_proxy_, &mock_metrics_, allow_legacy_kh,
105 allow_g2f_attestation));
Louis Collard99e40242019-08-30 14:57:39 +0800106 }
107
108 void ExpectGetUserSecret() { ExpectGetUserSecretForTimes(1); }
109
110 void ExpectGetUserSecretForTimes(int times) {
Louis Collarda5fa3c32019-10-07 15:02:25 +0800111 EXPECT_CALL(mock_user_state_, GetUserSecret())
Louis Collard99e40242019-08-30 14:57:39 +0800112 .Times(times)
113 .WillRepeatedly(Return(ArrayToSecureBlob(kUserSecret)));
114 }
115
116 void ExpectGetUserSecretFails() {
Louis Collarda5fa3c32019-10-07 15:02:25 +0800117 EXPECT_CALL(mock_user_state_, GetUserSecret())
Louis Collard99e40242019-08-30 14:57:39 +0800118 .WillOnce(Return(base::Optional<brillo::SecureBlob>()));
119 }
120
121 void ExpectGetCounter() {
Louis Collarda5fa3c32019-10-07 15:02:25 +0800122 EXPECT_CALL(mock_user_state_, GetCounter())
Louis Collard99e40242019-08-30 14:57:39 +0800123 .WillOnce(Return(base::Optional<std::vector<uint8_t>>({kCounter})));
124 }
125
126 void ExpectGetCounterFails() {
Louis Collarda5fa3c32019-10-07 15:02:25 +0800127 EXPECT_CALL(mock_user_state_, GetCounter())
Louis Collard99e40242019-08-30 14:57:39 +0800128 .WillOnce(Return(base::Optional<std::vector<uint8_t>>()));
129 }
130
131 void ExpectIncrementCounter() {
Louis Collarda5fa3c32019-10-07 15:02:25 +0800132 EXPECT_CALL(mock_user_state_, IncrementCounter()).WillOnce(Return(true));
Louis Collard99e40242019-08-30 14:57:39 +0800133 }
134
135 void ExpectIncrementCounterFails() {
Louis Collarda5fa3c32019-10-07 15:02:25 +0800136 EXPECT_CALL(mock_user_state_, IncrementCounter()).WillOnce(Return(false));
Louis Collard99e40242019-08-30 14:57:39 +0800137 }
138
139 U2fResponseAdpu ProcessMsg(const std::string& hex) {
140 std::vector<uint8_t> bytes;
141 CHECK(base::HexStringToBytes(hex, &bytes));
142
143 return handler_->ProcessMsg(std::string(bytes.begin(), bytes.end()));
144 }
145
146 U2fResponseAdpu ProcessMsg(const std::string& hex,
147 const std::string& hex2,
148 const std::string& hex3,
149 const std::string& hex4) {
150 return ProcessMsg(hex + hex2 + hex3 + hex4);
151 }
152
153 void CheckResponseForMsg(const std::string& request,
154 const std::string& response) {
155 EXPECT_THAT(ProcessMsg(request), MsgEqStr(response));
156 }
157
158 void CheckResponseForMsg(const std::string& request,
159 const std::string& request2,
160 const std::string& request3,
161 const std::string& request4,
162 const std::string& response) {
163 EXPECT_THAT(ProcessMsg(request, request2, request3, request4),
164 MsgEqStr(response));
165 }
166
Louis Collardd4ee40d2019-10-01 14:19:01 +0800167 StrictMock<MockAllowlistingUtil>* mock_allowlisting_util_; // Not Owned.
Louis Collard99e40242019-08-30 14:57:39 +0800168 StrictMock<MockTpmVendorCommandProxy> mock_tpm_proxy_;
Louis Collarda5fa3c32019-10-07 15:02:25 +0800169 StrictMock<MockUserState> mock_user_state_;
Louis Collard99e40242019-08-30 14:57:39 +0800170 NiceMock<MetricsLibraryMock> mock_metrics_;
171
172 std::unique_ptr<U2fMessageHandler> handler_;
173
Louis Collardd4ee40d2019-10-01 14:19:01 +0800174 int presence_requested_expected_ = 0;
175
176 private:
Louis Collard99e40242019-08-30 14:57:39 +0800177 int presence_requested_count_ = 0;
178};
179
180// U2F Error Codes.
181constexpr char kErrorResponseWrongData[] = "6A80";
182constexpr char kErrorResponseConditionsNotSatisfied[] = "6985";
183constexpr char kErrorResponseWrongLength[] = "6700";
184constexpr char kErrorResponseInsNotSupported[] = "6D00";
185constexpr char kErrorResponseClaNotSupported[] = "6E00";
186constexpr char kErrorResponseWtf[] = "6F00";
187
188// Dummy U2F Message Parameters
189constexpr char kAppId[65] = {[0 ... 63] = 'A', '\0'};
190constexpr char kChallenge[65] = {[0 ... 63] = 'C', '\0'};
191constexpr char kMaxResponseSize[] = "FF";
192
193// Cr50 Response Codes
194constexpr uint32_t kCr50Success = 0;
195constexpr uint32_t kCr50NotAllowed = 0x507;
196constexpr uint32_t kCr50PasswordRequired = 0x50a;
197
198// U2F_REGISTER
199//
200////////////////////////////////////////////////////////////////////////////////
201
202// Message format: CLA,INS{U2F_REGISTER},P1{U2F_AUTH_ENFORCE},P2,MSG_SIZE
203// All fields one byte.
204constexpr char kRequestRegisterPrefix[] = "0001030040";
205constexpr char kRequestRegisterShort[] = "0001030000";
206
207TEST_F(U2fMessageHandlerTest, RegisterSuccess) {
208 ExpectGetUserSecret();
209
210 // See U2F_GENERATE_REQ in //platform/ec/include/u2f.h
211 std::string expected_cr50_request_regex =
Yicheng Li519a56d2020-09-17 19:16:31 +0000212 "(AA){32}" // AppId
213 "(EE){32}" // User Secret
214 "03" // U2F_AUTH_ENFORCE
215 "(00){32}"; // Auth-time secret hash (unused)
Louis Collard99e40242019-08-30 14:57:39 +0800216
Yicheng Li44a9d4c2020-07-02 14:25:04 -0700217 struct u2f_generate_resp cr50_response = {
218 .keyHandle = {.origin_seed = {[0 ... 31] = 0xFD},
219 .hmac = {[0 ... 31] = 0xFD}}};
Louis Collard99e40242019-08-30 14:57:39 +0800220
Yicheng Li5ca11f52020-05-14 16:49:48 -0700221 EXPECT_CALL(mock_tpm_proxy_,
222 SendU2fGenerate(StructMatchesRegex(expected_cr50_request_regex),
223 Matcher<u2f_generate_resp*>(_)))
Louis Collard99e40242019-08-30 14:57:39 +0800224 .WillOnce(DoAll(SetArgPointee<1>(cr50_response), Return(kCr50Success)));
225
226 std::string adpu_response = AdpuToHexString(
227 ProcessMsg(kRequestRegisterPrefix, kChallenge, kAppId, kMaxResponseSize));
228
229 // See U2F Raw Message Formats Spec
230 std::string expected_response_regex =
231 "05" // Reserved Byte
232 "[0-9A-F]{130}" // Public Key
233 "40(FD){64}" // Key Handle (matches cr50 response)
234 ".*" // Attestation Cert + Signature
235 "9000"; // U2F_SW_NO_ERROR
236
237 // Just a basic sanity check, the correctness of message contents is tested by
238 // integration tests.
239 EXPECT_THAT(adpu_response, MatchesRegex(expected_response_regex));
Louis Collard99e40242019-08-30 14:57:39 +0800240}
241
242// Errors detected during parsing; should not read user state or call cr50.
243
244TEST_F(U2fMessageHandlerTest, RegisterShortMsg) {
245 CheckResponseForMsg(kRequestRegisterShort, kErrorResponseWrongLength);
246}
247
248TEST_F(U2fMessageHandlerTest, RegisterInvalidFlags) {
249 std::string prefix = kRequestRegisterPrefix;
250 prefix[5] = '0'; // Set invalid P1 flag.
251
252 CheckResponseForMsg(prefix, kChallenge, kAppId, kMaxResponseSize,
253 kErrorResponseWtf);
254}
255
256TEST_F(U2fMessageHandlerTest, RegisterChromeDummyWinkRequest) {
257 std::string app_id;
258 std::string challenge;
259
260 // Chrome Sends a bogus request with these parameters, see chromium
261 // //src/device/fido/fido_constants.cc
262 for (int i = 0; i < 32; i++) {
263 app_id.append("41");
264 challenge.append("42");
265 }
266
267 CheckResponseForMsg(kRequestRegisterPrefix, challenge, app_id,
268 kMaxResponseSize, kErrorResponseConditionsNotSatisfied);
269}
270
271// Errors while reading state, should not call cr50.
272
273TEST_F(U2fMessageHandlerTest, RegisterSecretNotAvailable) {
274 ExpectGetUserSecretFails();
275
276 CheckResponseForMsg(kRequestRegisterPrefix, kChallenge, kAppId,
277 kMaxResponseSize, kErrorResponseWtf);
278}
279
280// Errors returned by cr50.
281
282TEST_F(U2fMessageHandlerTest, RegisterNoPresence) {
283 ExpectGetUserSecret();
284
Yicheng Li5ca11f52020-05-14 16:49:48 -0700285 EXPECT_CALL(mock_tpm_proxy_,
286 SendU2fGenerate(_, Matcher<u2f_generate_resp*>(_)))
Louis Collard99e40242019-08-30 14:57:39 +0800287 .WillOnce(Return(kCr50NotAllowed));
288
289 CheckResponseForMsg(kRequestRegisterPrefix, kChallenge, kAppId,
290 kMaxResponseSize, kErrorResponseConditionsNotSatisfied);
291
Louis Collardd4ee40d2019-10-01 14:19:01 +0800292 presence_requested_expected_ = 1;
Louis Collard99e40242019-08-30 14:57:39 +0800293}
294
295TEST_F(U2fMessageHandlerTest, RegisterCr50UnknownError) {
296 ExpectGetUserSecret();
297
Yicheng Li5ca11f52020-05-14 16:49:48 -0700298 EXPECT_CALL(mock_tpm_proxy_,
299 SendU2fGenerate(_, Matcher<u2f_generate_resp*>(_)))
Louis Collard99e40242019-08-30 14:57:39 +0800300 .WillOnce(Return(4324523 /* Random Unknown Error */));
301
302 CheckResponseForMsg(kRequestRegisterPrefix, kChallenge, kAppId,
303 kMaxResponseSize, kErrorResponseWtf);
304}
305
306// U2F_REGISTER with G2F Attestation
307//
308////////////////////////////////////////////////////////////////////////////////
309
310// Message format:
311// CLA,INS{U2F_REGISTER},P1{U2F_AUTH_ENFORCE|G2F_ATTEST},P2,MSG_SIZE All fields
312// one byte.
313constexpr char kRequestRegisterG2fPrefix[] = "0001830040";
314
Louis Collardd4ee40d2019-10-01 14:19:01 +0800315// See U2F_GENERATE_REQ in //platform/ec/include/u2f.h
316constexpr char kCr50ExpectedGenReqRegex[] =
Yicheng Li519a56d2020-09-17 19:16:31 +0000317 "(AA){32}" // AppId
318 "(EE){32}" // User Secret
319 "03" // U2F_AUTH_ENFORCE | G2F_ATTEST
320 "(00){32}"; // Auth-time secret hash (unused)
Louis Collardd4ee40d2019-10-01 14:19:01 +0800321
322// Dummy generate response.
Louis Collardbe159282020-02-12 15:29:56 +0800323constexpr struct u2f_generate_resp kCr50GenResp = {
Yicheng Li44a9d4c2020-07-02 14:25:04 -0700324 .keyHandle = {.origin_seed = {[0 ... 31] = 0xFD},
325 .hmac = {[0 ... 31] = 0xFD}}}; // cr50_gen_resp
Louis Collardd4ee40d2019-10-01 14:19:01 +0800326
Louis Collard99e40242019-08-30 14:57:39 +0800327// Example of a cert that would be returned by cr50.
328constexpr char kDummyG2fCert[] =
329 "308201363081DDA0030201020210442D32429223D041240350303716EE6B300A06082A8648"
330 "CE3D040302300F310D300B06035504031304637235303022180F3230303030313031303030"
331 "3030305A180F32303939313233313233353935395A300F310D300B06035504031304637235"
332 "303059301306072A8648CE3D020106082A8648CE3D030107034200045165719A9975F6FD30"
333 "CC2516C22FE841F65F9D2EE7B8B72F76807AEBD8CA3376005C7FA86453E4B10DB7BFAD5D2B"
334 "D00DB4A7C4845AD06D686ACD0252387618ECA31730153013060B2B0601040182E51C020101"
335 "040403020308300A06082A8648CE3D0403020348003045022100F09976F373920FEF8205C4"
336 "B1FB1DA21EB9F3F176B7DF433A1ADE0F3F38B721960220179D9B9051BFCCCC90BA6BB42B86"
337 "111D7A9C4FB56DFD39FB426081DD027AD609";
338
Louis Collard99e40242019-08-30 14:57:39 +0800339std::string GetDummyG2fCert() {
340 static std::string cert_str = []() {
341 std::vector<uint8_t> cert;
342 base::HexStringToBytes(kDummyG2fCert, &cert);
343 return std::string(reinterpret_cast<char*>(cert.data()), cert.size());
344 }();
345
346 return cert_str;
347}
348
349TEST_F(U2fMessageHandlerTest, RegisterG2fWhenDisabledSuccess) {
350 // G2F Attestation is disabled (default flags set in test fixture), so we
351 // should not see any additional calls to cr50 for G2F attestation.
352
353 ExpectGetUserSecret();
354
355 EXPECT_CALL(mock_tpm_proxy_,
Yicheng Li5ca11f52020-05-14 16:49:48 -0700356 SendU2fGenerate(StructMatchesRegex(kCr50ExpectedGenReqRegex),
357 Matcher<u2f_generate_resp*>(_)))
Louis Collard99e40242019-08-30 14:57:39 +0800358 .WillOnce(DoAll(SetArgPointee<1>(kCr50GenResp), Return(kCr50Success)));
359
360 std::string adpu_response = AdpuToHexString(ProcessMsg(
361 kRequestRegisterG2fPrefix, kChallenge, kAppId, kMaxResponseSize));
362
363 // See U2F Raw Message Formats Spec
364 std::string expected_response_regex =
365 "05" // Reserved Byte
366 "[0-9A-F]{130}" // Public Key
367 "40(FD){64}" // Key Handle (matches kCr50GenResp)
368 ".*" // Attestation Cert + Signature
369 "9000"; // U2F_SW_NO_ERROR
370
371 // Just a basic sanity check, the correctness of message contents is tested by
372 // integration tests.
373 EXPECT_THAT(adpu_response, MatchesRegex(expected_response_regex));
374}
375
376TEST_F(U2fMessageHandlerTest, RegisterG2fSuccess) {
377 CreateHandler(false /* legacy fallback */, true /* g2f_attest */);
378
379 // Once to create the key, once for attestation.
380 ExpectGetUserSecretForTimes(2);
381
382 EXPECT_CALL(mock_tpm_proxy_,
Yicheng Li5ca11f52020-05-14 16:49:48 -0700383 SendU2fGenerate(StructMatchesRegex(kCr50ExpectedGenReqRegex),
384 Matcher<u2f_generate_resp*>(_)))
Louis Collard99e40242019-08-30 14:57:39 +0800385 .WillOnce(DoAll(SetArgPointee<1>(kCr50GenResp), Return(kCr50Success)));
386
387 EXPECT_CALL(mock_tpm_proxy_, GetG2fCertificate(_))
388 .WillOnce(DoAll(SetArgPointee<0>(GetDummyG2fCert()), Return(0)));
389
Louis Collardd4ee40d2019-10-01 14:19:01 +0800390 EXPECT_CALL(*mock_allowlisting_util_, AppendDataToCert(_))
391 .WillOnce(Return(true));
392
Louis Collard99e40242019-08-30 14:57:39 +0800393 // See U2F_ATTEST_REQ in //platform/ec/include/u2f.h
394 std::string expected_cr50_attest_req_regex =
395 "(EE){32}" // User Secret
396 "00" // Format
397 "C2" // Data Length
398 // See U2F Raw Message formats for format of data to sign.
399 "00(A){64}(C){64}(FD){64}(0){254}"; // Data
400
Louis Collardbe159282020-02-12 15:29:56 +0800401 struct u2f_attest_resp cr50_attest_resp = {.sig_r = {[0 ... 31] = 0xFF},
402 .sig_s = {[0 ... 31] = 0x55}};
Louis Collard99e40242019-08-30 14:57:39 +0800403
404 EXPECT_CALL(
405 mock_tpm_proxy_,
406 SendU2fAttest(StructMatchesRegex(expected_cr50_attest_req_regex), _))
407 .WillOnce(
408 DoAll(SetArgPointee<1>(cr50_attest_resp), Return(kCr50Success)));
409
410 std::string adpu_response = AdpuToHexString(ProcessMsg(
411 kRequestRegisterG2fPrefix, kChallenge, kAppId, kMaxResponseSize));
412
413 // See U2F Raw Message Formats Spec
414 std::string expected_response_regex =
415 "05" // Reserved Byte
416 "[0-9A-F]{130}" // Public Key
417 "40(FD){64}" // Key Handle (matches kCr50GenResp)
418 ".*" // Attestation Cert + Signature
419 "9000"; // U2F_SW_NO_ERROR
420
421 // Just a basic sanity check, the correctness of message contents is tested by
422 // integration tests.
423 EXPECT_THAT(adpu_response, MatchesRegex(expected_response_regex));
Louis Collard99e40242019-08-30 14:57:39 +0800424}
425
426// Error from cr50
427
428TEST_F(U2fMessageHandlerTest, RegisterG2fNoPresence) {
429 CreateHandler(false /* legacy fallback */, true /* g2f_attest */);
430
431 ExpectGetUserSecret();
432
Yicheng Li5ca11f52020-05-14 16:49:48 -0700433 EXPECT_CALL(mock_tpm_proxy_,
434 SendU2fGenerate(_, Matcher<u2f_generate_resp*>(_)))
Louis Collard99e40242019-08-30 14:57:39 +0800435 .WillOnce(Return(kCr50NotAllowed));
436
437 CheckResponseForMsg(kRequestRegisterG2fPrefix, kChallenge, kAppId,
438 kMaxResponseSize, kErrorResponseConditionsNotSatisfied);
439
Louis Collardd4ee40d2019-10-01 14:19:01 +0800440 presence_requested_expected_ = 1;
Louis Collard99e40242019-08-30 14:57:39 +0800441}
442
443TEST_F(U2fMessageHandlerTest, RegisterG2fAttestSecretNotAvailable) {
444 CreateHandler(false /* legacy fallback */, true /* g2f_attest */);
445
446 // Called first to create the key, succeed.
447 // Called again for attestation, fail.
Louis Collarda5fa3c32019-10-07 15:02:25 +0800448 EXPECT_CALL(mock_user_state_, GetUserSecret())
Louis Collard99e40242019-08-30 14:57:39 +0800449 .WillOnce(Return(ArrayToSecureBlob(kUserSecret)))
450 .WillOnce(Return(base::Optional<brillo::SecureBlob>()));
451
452 EXPECT_CALL(mock_tpm_proxy_,
Yicheng Li5ca11f52020-05-14 16:49:48 -0700453 SendU2fGenerate(StructMatchesRegex(kCr50ExpectedGenReqRegex),
454 Matcher<u2f_generate_resp*>(_)))
Louis Collard99e40242019-08-30 14:57:39 +0800455 .WillOnce(DoAll(SetArgPointee<1>(kCr50GenResp), Return(kCr50Success)));
456
457 EXPECT_CALL(mock_tpm_proxy_, GetG2fCertificate(_))
458 .WillOnce(DoAll(SetArgPointee<0>(GetDummyG2fCert()), Return(0)));
459
460 CheckResponseForMsg(kRequestRegisterG2fPrefix, kChallenge, kAppId,
461 kMaxResponseSize, kErrorResponseWtf);
462}
463
464TEST_F(U2fMessageHandlerTest, RegisterG2fAttestFails) {
465 CreateHandler(false /* legacy fallback */, true /* g2f_attest */);
466
467 // Once to create the key, once for attestation.
468 ExpectGetUserSecretForTimes(2);
469
470 EXPECT_CALL(mock_tpm_proxy_,
Yicheng Li5ca11f52020-05-14 16:49:48 -0700471 SendU2fGenerate(StructMatchesRegex(kCr50ExpectedGenReqRegex),
472 Matcher<u2f_generate_resp*>(_)))
Louis Collard99e40242019-08-30 14:57:39 +0800473 .WillOnce(DoAll(SetArgPointee<1>(kCr50GenResp), Return(kCr50Success)));
474
475 EXPECT_CALL(mock_tpm_proxy_, GetG2fCertificate(_))
476 .WillOnce(DoAll(SetArgPointee<0>(GetDummyG2fCert()), Return(0)));
477
478 EXPECT_CALL(mock_tpm_proxy_, SendU2fAttest(_, _))
479 .WillOnce(Return(kCr50NotAllowed));
480
481 CheckResponseForMsg(kRequestRegisterG2fPrefix, kChallenge, kAppId,
482 kMaxResponseSize, kErrorResponseWtf);
483}
484
485// U2F_AUTHENTICATE
486//
487////////////////////////////////////////////////////////////////////////////////
488
489// Message format: CLA,INS{U2F_AUTHENTICATE},P1{U2F_AUTH_ENFORCE},P2,MSG_SIZE
490constexpr char kRequestAuthenticatePrefix[] = "0002030042";
491
492// Message format: KH_LENGTH,KH_BYTE
493constexpr char kRequestAuthenticateKeyHandle[] = "0100";
494
495// All fields one byte.
496
497TEST_F(U2fMessageHandlerTest, AuthenticateSuccess) {
498 ExpectGetCounter();
499 ExpectGetUserSecret();
500
501 std::string expected_cr50_request_regex =
502 "(AA){32}" // AppId
503 "(EE){32}" // User Secret
504 "(00){64}" // Key Handle
505 "[0-9A-F]{64}" // Hash
506 "03"; // U2F_AUTH_ENFORCE
507
Louis Collardbe159282020-02-12 15:29:56 +0800508 struct u2f_sign_resp cr50_response = {.sig_r = {[0 ... 31] = 0xFF},
509 .sig_s = {[0 ... 31] = 0x55}};
Louis Collard99e40242019-08-30 14:57:39 +0800510
511 EXPECT_CALL(mock_tpm_proxy_,
Yicheng Li5ca11f52020-05-14 16:49:48 -0700512 SendU2fSign(Matcher<const u2f_sign_req&>(
513 StructMatchesRegex(expected_cr50_request_regex)),
514 _))
Louis Collard99e40242019-08-30 14:57:39 +0800515 .WillOnce(DoAll(SetArgPointee<1>(cr50_response), Return(kCr50Success)));
516
517 ExpectIncrementCounter();
518
519 std::string adpu_response =
520 AdpuToHexString(ProcessMsg(kRequestAuthenticatePrefix, kChallenge, kAppId,
521 kRequestAuthenticateKeyHandle));
522
523 // Just basic sanity check, validity of the message is tested in integration
524 // tests.
525 std::string expected_response_regex =
526 "01" // User Presence Asserted
527 ".*" // DER encoding
528 "(FF){32}" // sig_r
529 ".*" // DER encoding
530 "(55){32}" // sig_s
531 "9000"; // U2F_SW_NO_ERRROR
532
533 EXPECT_THAT(adpu_response, MatchesRegex(expected_response_regex));
534}
535
536TEST_F(U2fMessageHandlerTest, AuthenticateWithFallbackSuccess) {
537 CreateHandler(true /* legacy kh fallback */, false /* g2f attestation */);
538
539 ExpectGetCounter();
540 ExpectGetUserSecret();
541
542 // The purpose of this test is to check that the LEGACY_KH_FALLBACK flag is
543 // passed to cr50.
544
545 std::string expected_cr50_request_regex =
546 "(AA){32}" // AppId
547 "(EE){32}" // User Secret
548 "(00){64}" // Key Handle
549 "[0-9A-F]{64}" // Hash
550 "43"; // U2F_AUTH_ENFORCE | LEGACY_KH_FALLBACK
551
552 EXPECT_CALL(mock_tpm_proxy_,
Yicheng Li5ca11f52020-05-14 16:49:48 -0700553 SendU2fSign(Matcher<const u2f_sign_req&>(
554 StructMatchesRegex(expected_cr50_request_regex)),
555 _))
Louis Collard99e40242019-08-30 14:57:39 +0800556 .WillOnce(Return(kCr50Success));
557
558 ExpectIncrementCounter();
559
560 std::string adpu_response =
561 AdpuToHexString(ProcessMsg(kRequestAuthenticatePrefix, kChallenge, kAppId,
562 kRequestAuthenticateKeyHandle));
563
564 // Just check that is succeeds; the rest is tested in the previous test case.
565 EXPECT_THAT(adpu_response, MatchesRegex(".*9000"));
566}
567
568// Errors reading state, should not call cr50.
569
570TEST_F(U2fMessageHandlerTest, AuthenticateSecretNotAvailable) {
571 ExpectGetCounter();
572 ExpectGetUserSecretFails();
573
574 CheckResponseForMsg(kRequestAuthenticatePrefix, kChallenge, kAppId,
575 kRequestAuthenticateKeyHandle, kErrorResponseWtf);
576}
577
578TEST_F(U2fMessageHandlerTest, AuthenticateCounterNotAvailable) {
579 ExpectGetCounterFails();
580
581 CheckResponseForMsg(kRequestAuthenticatePrefix, kChallenge, kAppId,
582 kRequestAuthenticateKeyHandle, kErrorResponseWtf);
583}
584
585// Errors returned by cr50.
586
587TEST_F(U2fMessageHandlerTest, AuthenticateNoPresence) {
588 ExpectGetCounter();
589 ExpectGetUserSecret();
590
Yicheng Li5ca11f52020-05-14 16:49:48 -0700591 EXPECT_CALL(mock_tpm_proxy_, SendU2fSign(Matcher<const u2f_sign_req&>(_), _))
Louis Collard99e40242019-08-30 14:57:39 +0800592 .WillOnce(Return(kCr50NotAllowed));
593
594 CheckResponseForMsg(kRequestAuthenticatePrefix, kChallenge, kAppId,
595 kRequestAuthenticateKeyHandle,
596 kErrorResponseConditionsNotSatisfied);
597
Louis Collardd4ee40d2019-10-01 14:19:01 +0800598 presence_requested_expected_ = 1;
Louis Collard99e40242019-08-30 14:57:39 +0800599}
600
601TEST_F(U2fMessageHandlerTest, AuthenticateInvalidKeyHandle) {
602 ExpectGetCounter();
603 ExpectGetUserSecret();
604
Yicheng Li5ca11f52020-05-14 16:49:48 -0700605 EXPECT_CALL(mock_tpm_proxy_, SendU2fSign(Matcher<const u2f_sign_req&>(_), _))
Louis Collard99e40242019-08-30 14:57:39 +0800606 .WillOnce(Return(kCr50PasswordRequired));
607
608 CheckResponseForMsg(kRequestAuthenticatePrefix, kChallenge, kAppId,
609 kRequestAuthenticateKeyHandle, kErrorResponseWrongData);
610}
611
612TEST_F(U2fMessageHandlerTest, AuthenticateCr50UnknownError) {
613 ExpectGetCounter();
614 ExpectGetUserSecret();
615
Yicheng Li5ca11f52020-05-14 16:49:48 -0700616 EXPECT_CALL(mock_tpm_proxy_, SendU2fSign(Matcher<const u2f_sign_req&>(_), _))
Louis Collard99e40242019-08-30 14:57:39 +0800617 .WillOnce(Return(43423 /* Random Unknown Error */));
618
619 CheckResponseForMsg(kRequestAuthenticatePrefix, kChallenge, kAppId,
620 kRequestAuthenticateKeyHandle, kErrorResponseWtf);
621}
622
623// Error updating state.
624
625TEST_F(U2fMessageHandlerTest, AuthenticateCounterCouldNotUpdate) {
626 ExpectGetCounter();
627 ExpectGetUserSecret();
628
Louis Collardbe159282020-02-12 15:29:56 +0800629 struct u2f_sign_resp cr50_response = {.sig_r = {[0 ... 31] = 0xFF},
630 .sig_s = {[0 ... 31] = 0x55}};
Louis Collard99e40242019-08-30 14:57:39 +0800631
Yicheng Li5ca11f52020-05-14 16:49:48 -0700632 EXPECT_CALL(mock_tpm_proxy_, SendU2fSign(Matcher<const u2f_sign_req&>(_), _))
Louis Collard99e40242019-08-30 14:57:39 +0800633 .WillOnce(DoAll(SetArgPointee<1>(cr50_response), Return(kCr50Success)));
634
635 ExpectIncrementCounterFails();
636
637 CheckResponseForMsg(kRequestAuthenticatePrefix, kChallenge, kAppId,
638 kRequestAuthenticateKeyHandle, kErrorResponseWtf);
639}
640
641// U2F_AUTHENTICATE "Check Only"
642//
643////////////////////////////////////////////////////////////////////////////////
644
645// Message format: CLA,INS{U2F_AUTHENTICATE},P1{U2F_AUTH_CHECK_ONLY},P2,MSG_SIZE
646constexpr char kRequestAuthenticateCheckOnlyPrefix[] = "0002070042";
647
648TEST_F(U2fMessageHandlerTest, AuthenticateCheckOnlySuccess) {
649 ExpectGetUserSecret();
650
651 std::string expected_cr50_request_regex =
652 "(AA){32}" // AppId
653 "(EE){32}" // User Secret
654 "(00){64}" // Key Handle
655 "[0-9A-F]{64}" // Hash
656 "07"; // U2F_AUTH_CHECK_ONLY
657
Yicheng Li5ca11f52020-05-14 16:49:48 -0700658 EXPECT_CALL(mock_tpm_proxy_,
659 SendU2fSign(Matcher<const u2f_sign_req&>(
660 StructMatchesRegex(expected_cr50_request_regex)),
661 nullptr))
Louis Collard99e40242019-08-30 14:57:39 +0800662 .WillOnce(Return(kCr50Success));
663
664 // A success response for this kind of message is indicate by a 'presence
665 // required' error.
666 CheckResponseForMsg(kRequestAuthenticateCheckOnlyPrefix, kChallenge, kAppId,
667 kRequestAuthenticateKeyHandle,
668 kErrorResponseConditionsNotSatisfied);
669}
670
671TEST_F(U2fMessageHandlerTest, AuthenticateCheckOnlyInvalidKeyHandle) {
672 ExpectGetUserSecret();
673
674 std::string expected_cr50_request_regex =
675 "(AA){32}" // AppId
676 "(EE){32}" // User Secret
677 "(00){64}" // Key Handle
678 "[0-9A-F]{64}" // Hash
679 "07"; // U2F_AUTH_CHECK_ONLY
680
Yicheng Li5ca11f52020-05-14 16:49:48 -0700681 EXPECT_CALL(mock_tpm_proxy_,
682 SendU2fSign(Matcher<const u2f_sign_req&>(
683 StructMatchesRegex(expected_cr50_request_regex)),
684 nullptr))
Louis Collard99e40242019-08-30 14:57:39 +0800685 .WillOnce(Return(kCr50PasswordRequired));
686
687 CheckResponseForMsg(kRequestAuthenticateCheckOnlyPrefix, kChallenge, kAppId,
688 kRequestAuthenticateKeyHandle, kErrorResponseWrongData);
689}
690
691TEST_F(U2fMessageHandlerTest, AuthenticateCheckOnlySecretNotAvailable) {
692 ExpectGetUserSecretFails();
693
694 CheckResponseForMsg(kRequestAuthenticateCheckOnlyPrefix, kChallenge, kAppId,
695 kRequestAuthenticateKeyHandle, kErrorResponseWtf);
696}
697
698// U2F_VERSION
699//
700////////////////////////////////////////////////////////////////////////////////
701
702// Message format: CLA,INS{U2F_VERSION},P1,P1,MSG_LENGTH,[RESPONSE_LENGTH]
703// All fields one byte.
704constexpr char kRequestVersion[] = "0003000000";
705constexpr char kRequestVersionInvalidLength[] = "0003000001FF00";
706
707// "U2F_V2", plus U2F_SW_NO_ERROR response code.
708constexpr char kSuccessResponseVersion[] = "5532465F56329000";
709
710TEST_F(U2fMessageHandlerTest, Version) {
711 CheckResponseForMsg(kRequestVersion, kSuccessResponseVersion);
712}
713
714TEST_F(U2fMessageHandlerTest, VersionInvalidMsg) {
715 CheckResponseForMsg(kRequestVersionInvalidLength, kErrorResponseWrongLength);
716}
717
718// Misc Invalid Messages
719//
720////////////////////////////////////////////////////////////////////////////////
721
722// Message format: CLA,INS,P1,P2.
723// All fields occupy byte.
724constexpr char kRequestInvalidIns[] = "00430000";
725constexpr char kRequestInvalidCla[] = "FFFFFFFF";
726constexpr char kRequestInvalidMsg[] = "00";
727
728TEST_F(U2fMessageHandlerTest, UnknownIns) {
729 CheckResponseForMsg(kRequestInvalidIns, kErrorResponseInsNotSupported);
730}
731
732TEST_F(U2fMessageHandlerTest, InvalidCla) {
733 CheckResponseForMsg(kRequestInvalidCla, kErrorResponseClaNotSupported);
734}
735
736TEST_F(U2fMessageHandlerTest, InvalidMsg) {
737 CheckResponseForMsg(kRequestInvalidMsg, kErrorResponseWtf);
738}
739
740} // namespace
741} // namespace u2f