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
5 #include <algorithm>
6
7 #include "base/stl_util.h"
8 #include "components/cbor/reader.h"
9 #include "components/cbor/values.h"
10 #include "components/cbor/writer.h"
11 #include "device/fido/attestation_statement_formats.h"
12 #include "device/fido/authenticator_get_assertion_response.h"
13 #include "device/fido/authenticator_make_credential_response.h"
14 #include "device/fido/device_response_converter.h"
15 #include "device/fido/ec_public_key.h"
16 #include "device/fido/fido_constants.h"
17 #include "device/fido/fido_parsing_utils.h"
18 #include "device/fido/fido_test_data.h"
19 #include "device/fido/opaque_attestation_statement.h"
20 #include "device/fido/opaque_public_key.h"
21 #include "testing/gmock/include/gmock/gmock.h"
22 #include "testing/gtest/include/gtest/gtest.h"
23
24 namespace device {
25
26 namespace {
27
28 constexpr uint8_t kTestAuthenticatorGetInfoResponseWithNoVersion[] = {
29 // Success status byte
30 0x00,
31 // Map of 6 elements
32 0xA6,
33 // Key(01) - versions
34 0x01,
35 // Array(0)
36 0x80,
37 // Key(02) - extensions
38 0x02,
39 // Array(2)
40 0x82,
41 // "uvm"
42 0x63, 0x75, 0x76, 0x6D,
43 // "hmac-secret"
44 0x6B, 0x68, 0x6D, 0x61, 0x63, 0x2D, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74,
45 // Key(03) - AAGUID
46 0x03,
47 // Bytes(16)
48 0x50, 0xF8, 0xA0, 0x11, 0xF3, 0x8C, 0x0A, 0x4D, 0x15, 0x80, 0x06, 0x17,
49 0x11, 0x1F, 0x9E, 0xDC, 0x7D,
50 // Key(04) - options
51 0x04,
52 // Map(05)
53 0xA5,
54 // Key - "rk"
55 0x62, 0x72, 0x6B,
56 // true
57 0xF5,
58 // Key - "up"
59 0x62, 0x75, 0x70,
60 // true
61 0xF5,
62 // Key - "uv"
63 0x62, 0x75, 0x76,
64 // true
65 0xF5,
66 // Key - "plat"
67 0x64, 0x70, 0x6C, 0x61, 0x74,
68 // true
69 0xF5,
70 // Key - "clientPin"
71 0x69, 0x63, 0x6C, 0x69, 0x65, 0x6E, 0x74, 0x50, 0x69, 0x6E,
72 // false
73 0xF4,
74 // Key(05) - Max message size
75 0x05,
76 // 1200
77 0x19, 0x04, 0xB0,
78 // Key(06) - Pin protocols
79 0x06,
80 // Array[1]
81 0x81, 0x01,
82 };
83
84 constexpr uint8_t kTestAuthenticatorGetInfoResponseWithDuplicateVersion[] = {
85 // Success status byte
86 0x00,
87 // Map of 6 elements
88 0xA6,
89 // Key(01) - versions
90 0x01,
91 // Array(03)
92 0x83,
93 // "U2F_V9"
94 0x66, 0x55, 0x32, 0x46, 0x5F, 0x56, 0x39,
95 // "U2F_V9"
96 0x66, 0x55, 0x32, 0x46, 0x5F, 0x56, 0x39,
97 // "U2F_V2"
98 0x66, 0x55, 0x32, 0x46, 0x5F, 0x56, 0x32,
99 // Key(02) - extensions
100 0x02,
101 // Array(2)
102 0x82,
103 // "uvm"
104 0x63, 0x75, 0x76, 0x6D,
105 // "hmac-secret"
106 0x6B, 0x68, 0x6D, 0x61, 0x63, 0x2D, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74,
107 // Key(03) - AAGUID
108 0x03,
109 // Bytes(16)
110 0x50, 0xF8, 0xA0, 0x11, 0xF3, 0x8C, 0x0A, 0x4D, 0x15, 0x80, 0x06, 0x17,
111 0x11, 0x1F, 0x9E, 0xDC, 0x7D,
112 // Key(04) - options
113 0x04,
114 // Map(05)
115 0xA5,
116 // Key - "rk"
117 0x62, 0x72, 0x6B,
118 // true
119 0xF5,
120 // Key - "up"
121 0x62, 0x75, 0x70,
122 // true
123 0xF5,
124 // Key - "uv"
125 0x62, 0x75, 0x76,
126 // true
127 0xF5,
128 // Key - "plat"
129 0x64, 0x70, 0x6C, 0x61, 0x74,
130 // true
131 0xF5,
132 // Key - "clientPin"
133 0x69, 0x63, 0x6C, 0x69, 0x65, 0x6E, 0x74, 0x50, 0x69, 0x6E,
134 // false
135 0xF4,
136 // Key(05) - Max message size
137 0x05,
138 // 1200
139 0x19, 0x04, 0xB0,
140 // Key(06) - Pin protocols
141 0x06,
142 // Array[1]
143 0x81, 0x01,
144 };
145
146 constexpr uint8_t kTestAuthenticatorGetInfoResponseWithIncorrectAaguid[] = {
147 // Success status byte
148 0x00,
149 // Map of 6 elements
150 0xA6,
151 // Key(01) - versions
152 0x01,
153 // Array(01)
154 0x81,
155 // "U2F_V2"
156 0x66, 0x55, 0x32, 0x46, 0x5F, 0x56, 0x32,
157 // Key(02) - extensions
158 0x02,
159 // Array(2)
160 0x82,
161 // "uvm"
162 0x63, 0x75, 0x76, 0x6D,
163 // "hmac-secret"
164 0x6B, 0x68, 0x6D, 0x61, 0x63, 0x2D, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74,
165 // Key(03) - AAGUID
166 0x03,
167 // Bytes(17) - FIDO2 device AAGUID must be 16 bytes long in order to be
168 // correct.
169 0x51, 0xF8, 0xA0, 0x11, 0xF3, 0x8C, 0x0A, 0x4D, 0x15, 0x80, 0x06, 0x17,
170 0x11, 0x1F, 0x9E, 0xDC, 0x7D, 0x00,
171 // Key(04) - options
172 0x04,
173 // Map(05)
174 0xA5,
175 // Key - "rk"
176 0x62, 0x72, 0x6B,
177 // true
178 0xF5,
179 // Key - "up"
180 0x62, 0x75, 0x70,
181 // true
182 0xF5,
183 // Key - "uv"
184 0x62, 0x75, 0x76,
185 // true
186 0xF5,
187 // Key - "plat"
188 0x64, 0x70, 0x6C, 0x61, 0x74,
189 // true
190 0xF5,
191 // Key - "clientPin"
192 0x69, 0x63, 0x6C, 0x69, 0x65, 0x6E, 0x74, 0x50, 0x69, 0x6E,
193 // false
194 0xF4,
195 // Key(05) - Max message size
196 0x05,
197 // 1200
198 0x19, 0x04, 0xB0,
199 // Key(06) - Pin protocols
200 0x06,
201 // Array[1]
202 0x81, 0x01,
203 };
204
205 // The attested credential data, excluding the public key bytes. Append
206 // with kTestECPublicKeyCOSE to get the complete attestation data.
207 constexpr uint8_t kTestAttestedCredentialDataPrefix[] = {
208 // 16-byte aaguid
209 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
210 0x00, 0x00, 0x00, 0x00,
211 // 2-byte length
212 0x00, 0x40,
213 // 64-byte key handle
214 0x3E, 0xBD, 0x89, 0xBF, 0x77, 0xEC, 0x50, 0x97, 0x55, 0xEE, 0x9C, 0x26,
215 0x35, 0xEF, 0xAA, 0xAC, 0x7B, 0x2B, 0x9C, 0x5C, 0xEF, 0x17, 0x36, 0xC3,
216 0x71, 0x7D, 0xA4, 0x85, 0x34, 0xC8, 0xC6, 0xB6, 0x54, 0xD7, 0xFF, 0x94,
217 0x5F, 0x50, 0xB5, 0xCC, 0x4E, 0x78, 0x05, 0x5B, 0xDD, 0x39, 0x6B, 0x64,
218 0xF7, 0x8D, 0xA2, 0xC5, 0xF9, 0x62, 0x00, 0xCC, 0xD4, 0x15, 0xCD, 0x08,
219 0xFE, 0x42, 0x00, 0x38,
220 };
221
222 // The authenticator data, excluding the attested credential data bytes. Append
223 // with attested credential data to get the complete authenticator data.
224 constexpr uint8_t kTestAuthenticatorDataPrefix[] = {
225 // sha256 hash of rp id.
226 0x11, 0x94, 0x22, 0x8D, 0xA8, 0xFD, 0xBD, 0xEE, 0xFD, 0x26, 0x1B, 0xD7,
227 0xB6, 0x59, 0x5C, 0xFD, 0x70, 0xA5, 0x0D, 0x70, 0xC6, 0x40, 0x7B, 0xCF,
228 0x01, 0x3D, 0xE9, 0x6D, 0x4E, 0xFB, 0x17, 0xDE,
229 // flags (TUP and AT bits set)
230 0x41,
231 // counter
232 0x00, 0x00, 0x00, 0x00};
233
234 // Components of the CBOR needed to form an authenticator object.
235 // Combined diagnostic notation:
236 // {"fmt": "fido-u2f", "attStmt": {"sig": h'30...}, "authData": h'D4C9D9...'}
237 constexpr uint8_t kFormatFidoU2fCBOR[] = {
238 // map(3)
239 0xA3,
240 // text(3)
241 0x63,
242 // "fmt"
243 0x66, 0x6D, 0x74,
244 // text(8)
245 0x68,
246 // "fido-u2f"
247 0x66, 0x69, 0x64, 0x6F, 0x2D, 0x75, 0x32, 0x66};
248
249 constexpr uint8_t kAttStmtCBOR[] = {
250 // text(7)
251 0x67,
252 // "attStmt"
253 0x61, 0x74, 0x74, 0x53, 0x74, 0x6D, 0x74};
254
255 constexpr uint8_t kAuthDataCBOR[] = {
256 // text(8)
257 0x68,
258 // "authData"
259 0x61, 0x75, 0x74, 0x68, 0x44, 0x61, 0x74, 0x61,
260 // bytes(196). i.e., the authenticator_data byte array corresponding to
261 // kTestAuthenticatorDataPrefix|, |kTestAttestedCredentialDataPrefix|,
262 // and test_data::kTestECPublicKeyCOSE.
263 0x58, 0xC4};
264
265 constexpr std::array<uint8_t, kAaguidLength> kTestDeviceAaguid = {
266 {0xF8, 0xA0, 0x11, 0xF3, 0x8C, 0x0A, 0x4D, 0x15, 0x80, 0x06, 0x17, 0x11,
267 0x1F, 0x9E, 0xDC, 0x7D}};
268
GetTestAttestedCredentialDataBytes()269 std::vector<uint8_t> GetTestAttestedCredentialDataBytes() {
270 // Combine kTestAttestedCredentialDataPrefix and kTestECPublicKeyCOSE.
271 auto test_attested_data =
272 fido_parsing_utils::Materialize(kTestAttestedCredentialDataPrefix);
273 fido_parsing_utils::Append(&test_attested_data,
274 test_data::kTestECPublicKeyCOSE);
275 return test_attested_data;
276 }
277
GetTestAuthenticatorDataBytes()278 std::vector<uint8_t> GetTestAuthenticatorDataBytes() {
279 // Build the test authenticator data.
280 auto test_authenticator_data =
281 fido_parsing_utils::Materialize(kTestAuthenticatorDataPrefix);
282 auto test_attested_data = GetTestAttestedCredentialDataBytes();
283 fido_parsing_utils::Append(&test_authenticator_data, test_attested_data);
284 return test_authenticator_data;
285 }
286
GetTestAttestationObjectBytes()287 std::vector<uint8_t> GetTestAttestationObjectBytes() {
288 auto test_authenticator_object =
289 fido_parsing_utils::Materialize(kFormatFidoU2fCBOR);
290 fido_parsing_utils::Append(&test_authenticator_object, kAttStmtCBOR);
291 fido_parsing_utils::Append(&test_authenticator_object,
292 test_data::kU2fAttestationStatementCBOR);
293 fido_parsing_utils::Append(&test_authenticator_object, kAuthDataCBOR);
294 auto test_authenticator_data = GetTestAuthenticatorDataBytes();
295 fido_parsing_utils::Append(&test_authenticator_object,
296 test_authenticator_data);
297 return test_authenticator_object;
298 }
299
GetTestSignResponse()300 std::vector<uint8_t> GetTestSignResponse() {
301 return fido_parsing_utils::Materialize(test_data::kTestU2fSignResponse);
302 }
303
304 // Get a subset of the response for testing error handling.
GetTestCorruptedSignResponse(size_t length)305 std::vector<uint8_t> GetTestCorruptedSignResponse(size_t length) {
306 DCHECK_LE(length, base::size(test_data::kTestU2fSignResponse));
307 return fido_parsing_utils::Materialize(fido_parsing_utils::ExtractSpan(
308 test_data::kTestU2fSignResponse, 0, length));
309 }
310
311 // Return a key handle used for GetAssertion request.
GetTestCredentialRawIdBytes()312 std::vector<uint8_t> GetTestCredentialRawIdBytes() {
313 return fido_parsing_utils::Materialize(test_data::kU2fSignKeyHandle);
314 }
315
316 // DecodeCBOR parses a CBOR structure, ignoring the first byte of |in|, which is
317 // assumed to be a CTAP2 status byte.
DecodeCBOR(base::span<const uint8_t> in)318 base::Optional<cbor::Value> DecodeCBOR(base::span<const uint8_t> in) {
319 CHECK(!in.empty());
320 return cbor::Reader::Read(in.subspan(1));
321 }
322
323 } // namespace
324
325 // Leveraging example 4 of section 6.1 of the spec https://fidoalliance.org
326 // /specs/fido-v2.0-rd-20170927/fido-client-to-authenticator-protocol-v2.0-rd-
327 // 20170927.html
TEST(CTAPResponseTest,TestReadMakeCredentialResponse)328 TEST(CTAPResponseTest, TestReadMakeCredentialResponse) {
329 auto make_credential_response = ReadCTAPMakeCredentialResponse(
330 FidoTransportProtocol::kUsbHumanInterfaceDevice,
331 DecodeCBOR(test_data::kTestMakeCredentialResponse));
332 ASSERT_TRUE(make_credential_response);
333 auto cbor_attestation_object = cbor::Reader::Read(
334 make_credential_response->GetCBOREncodedAttestationObject());
335 ASSERT_TRUE(cbor_attestation_object);
336 ASSERT_TRUE(cbor_attestation_object->is_map());
337
338 const auto& attestation_object_map = cbor_attestation_object->GetMap();
339 auto it = attestation_object_map.find(cbor::Value(kFormatKey));
340 ASSERT_TRUE(it != attestation_object_map.end());
341 ASSERT_TRUE(it->second.is_string());
342 EXPECT_EQ(it->second.GetString(), "packed");
343
344 it = attestation_object_map.find(cbor::Value(kAuthDataKey));
345 ASSERT_TRUE(it != attestation_object_map.end());
346 ASSERT_TRUE(it->second.is_bytestring());
347 EXPECT_THAT(
348 it->second.GetBytestring(),
349 ::testing::ElementsAreArray(test_data::kCtap2MakeCredentialAuthData));
350
351 it = attestation_object_map.find(cbor::Value(kAttestationStatementKey));
352 ASSERT_TRUE(it != attestation_object_map.end());
353 ASSERT_TRUE(it->second.is_map());
354
355 const auto& attestation_statement_map = it->second.GetMap();
356 auto attStmt_it = attestation_statement_map.find(cbor::Value("alg"));
357
358 ASSERT_TRUE(attStmt_it != attestation_statement_map.end());
359 ASSERT_TRUE(attStmt_it->second.is_integer());
360 EXPECT_EQ(attStmt_it->second.GetInteger(), -7);
361
362 attStmt_it = attestation_statement_map.find(cbor::Value("sig"));
363 ASSERT_TRUE(attStmt_it != attestation_statement_map.end());
364 ASSERT_TRUE(attStmt_it->second.is_bytestring());
365 EXPECT_THAT(
366 attStmt_it->second.GetBytestring(),
367 ::testing::ElementsAreArray(test_data::kCtap2MakeCredentialSignature));
368
369 attStmt_it = attestation_statement_map.find(cbor::Value("x5c"));
370 ASSERT_TRUE(attStmt_it != attestation_statement_map.end());
371 const auto& certificate = attStmt_it->second;
372 ASSERT_TRUE(certificate.is_array());
373 ASSERT_EQ(certificate.GetArray().size(), 1u);
374 ASSERT_TRUE(certificate.GetArray()[0].is_bytestring());
375 EXPECT_THAT(
376 certificate.GetArray()[0].GetBytestring(),
377 ::testing::ElementsAreArray(test_data::kCtap2MakeCredentialCertificate));
378 EXPECT_THAT(
379 make_credential_response->raw_credential_id(),
380 ::testing::ElementsAreArray(test_data::kCtap2MakeCredentialCredentialId));
381 }
382
TEST(CTAPResponseTest,TestMakeCredentialNoneAttestationResponse)383 TEST(CTAPResponseTest, TestMakeCredentialNoneAttestationResponse) {
384 auto make_credential_response = ReadCTAPMakeCredentialResponse(
385 FidoTransportProtocol::kUsbHumanInterfaceDevice,
386 DecodeCBOR(test_data::kTestMakeCredentialResponse));
387 ASSERT_TRUE(make_credential_response);
388 make_credential_response->EraseAttestationStatement(
389 AttestationObject::AAGUID::kErase);
390 EXPECT_THAT(make_credential_response->GetCBOREncodedAttestationObject(),
391 ::testing::ElementsAreArray(test_data::kNoneAttestationResponse));
392 }
393
394 // Leveraging example 5 of section 6.1 of the CTAP spec.
395 // https://fidoalliance.org/specs/fido-v2.0-rd-20170927/fido-client-to-authenticator-protocol-v2.0-rd-20170927.html
TEST(CTAPResponseTest,TestReadGetAssertionResponse)396 TEST(CTAPResponseTest, TestReadGetAssertionResponse) {
397 auto get_assertion_response = ReadCTAPGetAssertionResponse(
398 DecodeCBOR(test_data::kDeviceGetAssertionResponse));
399 ASSERT_TRUE(get_assertion_response);
400 ASSERT_TRUE(get_assertion_response->num_credentials());
401 EXPECT_EQ(*get_assertion_response->num_credentials(), 1u);
402
403 EXPECT_THAT(
404 get_assertion_response->auth_data().SerializeToByteArray(),
405 ::testing::ElementsAreArray(test_data::kCtap2GetAssertionAuthData));
406 EXPECT_THAT(
407 get_assertion_response->signature(),
408 ::testing::ElementsAreArray(test_data::kCtap2GetAssertionSignature));
409 }
410
411 // Test that U2F register response is properly parsed.
TEST(CTAPResponseTest,TestParseRegisterResponseData)412 TEST(CTAPResponseTest, TestParseRegisterResponseData) {
413 auto response =
414 AuthenticatorMakeCredentialResponse::CreateFromU2fRegisterResponse(
415 FidoTransportProtocol::kUsbHumanInterfaceDevice,
416 test_data::kApplicationParameter,
417 test_data::kTestU2fRegisterResponse);
418 ASSERT_TRUE(response);
419 EXPECT_THAT(response->raw_credential_id(),
420 ::testing::ElementsAreArray(test_data::kU2fSignKeyHandle));
421 EXPECT_EQ(GetTestAttestationObjectBytes(),
422 response->GetCBOREncodedAttestationObject());
423 }
424
425 // These test the parsing of the U2F raw bytes of the registration response.
426 // Test that an EC public key serializes to CBOR properly.
TEST(CTAPResponseTest,TestSerializedPublicKey)427 TEST(CTAPResponseTest, TestSerializedPublicKey) {
428 auto public_key = ECPublicKey::ExtractFromU2fRegistrationResponse(
429 fido_parsing_utils::kEs256, test_data::kTestU2fRegisterResponse);
430 ASSERT_TRUE(public_key);
431 EXPECT_THAT(public_key->EncodeAsCOSEKey(),
432 ::testing::ElementsAreArray(test_data::kTestECPublicKeyCOSE));
433 }
434
435 // Test that the attestation statement cbor map is constructed properly.
TEST(CTAPResponseTest,TestParseU2fAttestationStatementCBOR)436 TEST(CTAPResponseTest, TestParseU2fAttestationStatementCBOR) {
437 auto fido_attestation_statement =
438 FidoAttestationStatement::CreateFromU2fRegisterResponse(
439 test_data::kTestU2fRegisterResponse);
440 ASSERT_TRUE(fido_attestation_statement);
441 auto cbor = cbor::Writer::Write(AsCBOR(*fido_attestation_statement));
442 ASSERT_TRUE(cbor);
443 EXPECT_THAT(*cbor, ::testing::ElementsAreArray(
444 test_data::kU2fAttestationStatementCBOR));
445 }
446
447 // Tests that well-formed attested credential data serializes properly.
TEST(CTAPResponseTest,TestSerializeAttestedCredentialData)448 TEST(CTAPResponseTest, TestSerializeAttestedCredentialData) {
449 auto public_key = ECPublicKey::ExtractFromU2fRegistrationResponse(
450 fido_parsing_utils::kEs256, test_data::kTestU2fRegisterResponse);
451 auto attested_data = AttestedCredentialData::CreateFromU2fRegisterResponse(
452 test_data::kTestU2fRegisterResponse, std::move(public_key));
453 ASSERT_TRUE(attested_data);
454 EXPECT_EQ(GetTestAttestedCredentialDataBytes(),
455 attested_data->SerializeAsBytes());
456 }
457
458 // Tests that well-formed authenticator data serializes properly.
TEST(CTAPResponseTest,TestSerializeAuthenticatorData)459 TEST(CTAPResponseTest, TestSerializeAuthenticatorData) {
460 auto public_key = ECPublicKey::ExtractFromU2fRegistrationResponse(
461 fido_parsing_utils::kEs256, test_data::kTestU2fRegisterResponse);
462 auto attested_data = AttestedCredentialData::CreateFromU2fRegisterResponse(
463 test_data::kTestU2fRegisterResponse, std::move(public_key));
464
465 constexpr uint8_t flags =
466 static_cast<uint8_t>(AuthenticatorData::Flag::kTestOfUserPresence) |
467 static_cast<uint8_t>(AuthenticatorData::Flag::kAttestation);
468
469 AuthenticatorData authenticator_data(test_data::kApplicationParameter, flags,
470 std::array<uint8_t, 4>{} /* counter */,
471 std::move(attested_data));
472
473 EXPECT_EQ(GetTestAuthenticatorDataBytes(),
474 authenticator_data.SerializeToByteArray());
475 }
476
477 // Tests that a U2F attestation object serializes properly.
TEST(CTAPResponseTest,TestSerializeU2fAttestationObject)478 TEST(CTAPResponseTest, TestSerializeU2fAttestationObject) {
479 auto public_key = ECPublicKey::ExtractFromU2fRegistrationResponse(
480 fido_parsing_utils::kEs256, test_data::kTestU2fRegisterResponse);
481 auto attested_data = AttestedCredentialData::CreateFromU2fRegisterResponse(
482 test_data::kTestU2fRegisterResponse, std::move(public_key));
483
484 constexpr uint8_t flags =
485 static_cast<uint8_t>(AuthenticatorData::Flag::kTestOfUserPresence) |
486 static_cast<uint8_t>(AuthenticatorData::Flag::kAttestation);
487 AuthenticatorData authenticator_data(test_data::kApplicationParameter, flags,
488 std::array<uint8_t, 4>{} /* counter */,
489 std::move(attested_data));
490
491 // Construct the attestation statement.
492 auto fido_attestation_statement =
493 FidoAttestationStatement::CreateFromU2fRegisterResponse(
494 test_data::kTestU2fRegisterResponse);
495
496 // Construct the attestation object.
497 auto attestation_object = std::make_unique<AttestationObject>(
498 std::move(authenticator_data), std::move(fido_attestation_statement));
499
500 ASSERT_TRUE(attestation_object);
501 EXPECT_EQ(GetTestAttestationObjectBytes(),
502 cbor::Writer::Write(AsCBOR(*attestation_object))
503 .value_or(std::vector<uint8_t>()));
504 }
505
506 // Tests that U2F authenticator data is properly serialized.
TEST(CTAPResponseTest,TestSerializeAuthenticatorDataForSign)507 TEST(CTAPResponseTest, TestSerializeAuthenticatorDataForSign) {
508 constexpr uint8_t flags =
509 static_cast<uint8_t>(AuthenticatorData::Flag::kTestOfUserPresence);
510
511 EXPECT_THAT(
512 AuthenticatorData(test_data::kApplicationParameter, flags,
513 test_data::kTestSignatureCounter, base::nullopt)
514 .SerializeToByteArray(),
515 ::testing::ElementsAreArray(test_data::kTestSignAuthenticatorData));
516 }
517
TEST(CTAPResponseTest,TestParseSignResponseData)518 TEST(CTAPResponseTest, TestParseSignResponseData) {
519 auto response = AuthenticatorGetAssertionResponse::CreateFromU2fSignResponse(
520 test_data::kApplicationParameter, GetTestSignResponse(),
521 GetTestCredentialRawIdBytes());
522 ASSERT_TRUE(response);
523 EXPECT_EQ(GetTestCredentialRawIdBytes(), response->raw_credential_id());
524 EXPECT_THAT(
525 response->auth_data().SerializeToByteArray(),
526 ::testing::ElementsAreArray(test_data::kTestSignAuthenticatorData));
527 EXPECT_THAT(response->signature(),
528 ::testing::ElementsAreArray(test_data::kU2fSignature));
529 }
530
TEST(CTAPResponseTest,TestParseU2fSignWithNullNullKeyHandle)531 TEST(CTAPResponseTest, TestParseU2fSignWithNullNullKeyHandle) {
532 auto response = AuthenticatorGetAssertionResponse::CreateFromU2fSignResponse(
533 test_data::kApplicationParameter, GetTestSignResponse(),
534 std::vector<uint8_t>());
535 EXPECT_FALSE(response);
536 }
537
TEST(CTAPResponseTest,TestParseU2fSignWithNullResponse)538 TEST(CTAPResponseTest, TestParseU2fSignWithNullResponse) {
539 auto response = AuthenticatorGetAssertionResponse::CreateFromU2fSignResponse(
540 test_data::kApplicationParameter, std::vector<uint8_t>(),
541 GetTestCredentialRawIdBytes());
542 EXPECT_FALSE(response);
543 }
544
TEST(CTAPResponseTest,TestParseU2fSignWithCTAP2Flags)545 TEST(CTAPResponseTest, TestParseU2fSignWithCTAP2Flags) {
546 std::vector<uint8_t> sign_response = GetTestSignResponse();
547 // Set two flags that should only be set in CTAP2 responses and expect parsing
548 // to fail.
549 sign_response[0] |=
550 static_cast<uint8_t>(AuthenticatorData::Flag::kExtensionDataIncluded);
551 sign_response[0] |=
552 static_cast<uint8_t>(AuthenticatorData::Flag::kAttestation);
553
554 auto response = AuthenticatorGetAssertionResponse::CreateFromU2fSignResponse(
555 test_data::kApplicationParameter, sign_response,
556 GetTestCredentialRawIdBytes());
557 EXPECT_FALSE(response);
558 }
559
TEST(CTAPResponseTest,TestParseU2fSignWithNullCorruptedCounter)560 TEST(CTAPResponseTest, TestParseU2fSignWithNullCorruptedCounter) {
561 // A sign response of less than 5 bytes.
562 auto response = AuthenticatorGetAssertionResponse::CreateFromU2fSignResponse(
563 test_data::kApplicationParameter, GetTestCorruptedSignResponse(3),
564 GetTestCredentialRawIdBytes());
565 EXPECT_FALSE(response);
566 }
567
TEST(CTAPResponseTest,TestParseU2fSignWithNullCorruptedSignature)568 TEST(CTAPResponseTest, TestParseU2fSignWithNullCorruptedSignature) {
569 // A sign response no more than 5 bytes.
570 auto response = AuthenticatorGetAssertionResponse::CreateFromU2fSignResponse(
571 test_data::kApplicationParameter, GetTestCorruptedSignResponse(5),
572 GetTestCredentialRawIdBytes());
573 EXPECT_FALSE(response);
574 }
575
TEST(CTAPResponseTest,TestReadGetInfoResponse)576 TEST(CTAPResponseTest, TestReadGetInfoResponse) {
577 auto get_info_response =
578 ReadCTAPGetInfoResponse(test_data::kTestGetInfoResponsePlatformDevice);
579 ASSERT_TRUE(get_info_response);
580 ASSERT_TRUE(get_info_response->max_msg_size);
581 EXPECT_EQ(*get_info_response->max_msg_size, 1200u);
582 EXPECT_TRUE(
583 base::Contains(get_info_response->versions, ProtocolVersion::kCtap2));
584 EXPECT_TRUE(
585 base::Contains(get_info_response->versions, ProtocolVersion::kU2f));
586 EXPECT_TRUE(get_info_response->options.is_platform_device);
587 EXPECT_TRUE(get_info_response->options.supports_resident_key);
588 EXPECT_TRUE(get_info_response->options.supports_user_presence);
589 EXPECT_EQ(AuthenticatorSupportedOptions::UserVerificationAvailability::
590 kSupportedAndConfigured,
591 get_info_response->options.user_verification_availability);
592 EXPECT_EQ(AuthenticatorSupportedOptions::ClientPinAvailability::
593 kSupportedButPinNotSet,
594 get_info_response->options.client_pin_availability);
595 }
596
TEST(CTAPResponseTest,TestReadGetInfoResponseWithDuplicateVersion)597 TEST(CTAPResponseTest, TestReadGetInfoResponseWithDuplicateVersion) {
598 uint8_t
599 get_info[sizeof(kTestAuthenticatorGetInfoResponseWithDuplicateVersion)];
600 memcpy(get_info, kTestAuthenticatorGetInfoResponseWithDuplicateVersion,
601 sizeof(get_info));
602 // Should fail to parse with duplicate versions.
603 EXPECT_FALSE(ReadCTAPGetInfoResponse(get_info));
604
605 // Find the first of the duplicate versions and change it to a different
606 // value. That should be sufficient to make the data parsable.
607 static const char kU2Fv9[] = "U2F_V9";
608 uint8_t* first_version =
609 std::search(get_info, get_info + sizeof(get_info), kU2Fv9, kU2Fv9 + 6);
610 ASSERT_TRUE(first_version);
611 memcpy(first_version, "U2F_V3", 6);
612 base::Optional<AuthenticatorGetInfoResponse> response =
613 ReadCTAPGetInfoResponse(get_info);
614 ASSERT_TRUE(response);
615 EXPECT_EQ(1u, response->versions.size());
616 EXPECT_TRUE(response->versions.contains(ProtocolVersion::kU2f));
617 }
618
TEST(CTAPResponseTest,TestReadGetInfoResponseWithIncorrectFormat)619 TEST(CTAPResponseTest, TestReadGetInfoResponseWithIncorrectFormat) {
620 EXPECT_FALSE(
621 ReadCTAPGetInfoResponse(kTestAuthenticatorGetInfoResponseWithNoVersion));
622 EXPECT_FALSE(ReadCTAPGetInfoResponse(
623 kTestAuthenticatorGetInfoResponseWithIncorrectAaguid));
624 }
625
TEST(CTAPResponseTest,TestSerializeGetInfoResponse)626 TEST(CTAPResponseTest, TestSerializeGetInfoResponse) {
627 AuthenticatorGetInfoResponse response(
628 {ProtocolVersion::kCtap2, ProtocolVersion::kU2f}, kTestDeviceAaguid);
629 response.extensions.emplace({std::string("uvm"), std::string("hmac-secret")});
630 AuthenticatorSupportedOptions options;
631 options.supports_resident_key = true;
632 options.is_platform_device = true;
633 options.client_pin_availability = AuthenticatorSupportedOptions::
634 ClientPinAvailability::kSupportedButPinNotSet;
635 options.user_verification_availability = AuthenticatorSupportedOptions::
636 UserVerificationAvailability::kSupportedAndConfigured;
637 response.options = std::move(options);
638 response.max_msg_size = 1200;
639 response.pin_protocols.emplace({static_cast<uint8_t>(1)});
640
641 EXPECT_THAT(AuthenticatorGetInfoResponse::EncodeToCBOR(response),
642 ::testing::ElementsAreArray(
643 base::make_span(test_data::kTestGetInfoResponsePlatformDevice)
644 .subspan(1)));
645 }
646
TEST(CTAPResponseTest,TestSerializeMakeCredentialResponse)647 TEST(CTAPResponseTest, TestSerializeMakeCredentialResponse) {
648 constexpr uint8_t kCoseEncodedPublicKey[] = {
649 // map(3)
650 0xa3,
651 // "x"
652 0x61, 0x78,
653 // byte(32)
654 0x58, 0x20, 0xf7, 0xc4, 0xf4, 0xa6, 0xf1, 0xd7, 0x95, 0x38, 0xdf, 0xa4,
655 0xc9, 0xac, 0x50, 0x84, 0x8d, 0xf7, 0x08, 0xbc, 0x1c, 0x99, 0xf5, 0xe6,
656 0x0e, 0x51, 0xb4, 0x2a, 0x52, 0x1b, 0x35, 0xd3, 0xb6, 0x9a,
657 // "y"
658 0x61, 0x79,
659 // byte(32)
660 0x58, 0x20, 0xde, 0x7b, 0x7d, 0x6c, 0xa5, 0x64, 0xe7, 0x0e, 0xa3, 0x21,
661 0xa4, 0xd5, 0xd9, 0x6e, 0xa0, 0x0e, 0xf0, 0xe2, 0xdb, 0x89, 0xdd, 0x61,
662 0xd4, 0x89, 0x4c, 0x15, 0xac, 0x58, 0x5b, 0xd2, 0x36, 0x84,
663 // "fmt"
664 0x63, 0x61, 0x6c, 0x67,
665 // "ES256"
666 0x65, 0x45, 0x53, 0x32, 0x35, 0x36,
667 };
668
669 const auto application_parameter =
670 base::make_span(test_data::kApplicationParameter)
671 .subspan<0, kRpIdHashLength>();
672 // Starting signature counter value set by example 4 of the CTAP spec. The
673 // signature counter can start at any value but it should never decrease.
674 // https://fidoalliance.org/specs/fido-v2.0-rd-20170927/fido-client-to-authenticator-protocol-v2.0-rd-20170927.html
675 std::array<uint8_t, kSignCounterLength> signature_counter = {
676 {0x00, 0x00, 0x00, 0x0b}};
677 auto flag =
678 base::strict_cast<uint8_t>(AuthenticatorData::Flag::kTestOfUserPresence) |
679 base::strict_cast<uint8_t>(AuthenticatorData::Flag::kAttestation);
680 AttestedCredentialData attested_credential_data(
681 kTestDeviceAaguid,
682 std::array<uint8_t, kCredentialIdLengthLength>{
683 {0x00, 0x10}} /* credential_id_length */,
684 fido_parsing_utils::Materialize(
685 test_data::kCtap2MakeCredentialCredentialId),
686 std::make_unique<OpaquePublicKey>(kCoseEncodedPublicKey));
687 AuthenticatorData authenticator_data(application_parameter, flag,
688 signature_counter,
689 std::move(attested_credential_data));
690
691 cbor::Value::MapValue attestation_map;
692 attestation_map.emplace("alg", -7);
693 attestation_map.emplace("sig", fido_parsing_utils::Materialize(
694 test_data::kCtap2MakeCredentialSignature));
695 cbor::Value::ArrayValue certificate_chain;
696 certificate_chain.emplace_back(fido_parsing_utils::Materialize(
697 test_data::kCtap2MakeCredentialCertificate));
698 attestation_map.emplace("x5c", std::move(certificate_chain));
699 AuthenticatorMakeCredentialResponse response(
700 FidoTransportProtocol::kUsbHumanInterfaceDevice,
701 AttestationObject(
702 std::move(authenticator_data),
703 std::make_unique<OpaqueAttestationStatement>(
704 "packed", cbor::Value(std::move(attestation_map)))));
705 EXPECT_THAT(
706 AsCTAPStyleCBORBytes(response),
707 ::testing::ElementsAreArray(
708 base::make_span(test_data::kTestMakeCredentialResponse).subspan(1)));
709 }
710
711 } // namespace device
712