Skip to content

Commit df2f950

Browse files
authored
Merge pull request #217 from merlokk/extapdu
Extended length apdu, iso14443 chaining and select
2 parents ddbe317 + 10bf424 commit df2f950

File tree

14 files changed

+322
-110
lines changed

14 files changed

+322
-110
lines changed

.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -83,3 +83,5 @@ targets/*/docs/
8383
main
8484

8585
builds/*
86+
tools/testing/.idea/*
87+
tools/testing/tests/__pycache__/*

fido2/apdu.c

+122
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
// Copyright 2019 SoloKeys Developers
2+
//
3+
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
4+
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
5+
// http://opensource.org/licenses/MIT>, at your option. This file may not be
6+
// copied, modified, or distributed except according to those terms.
7+
8+
// iso7816:2013. 5.3.2 Decoding conventions for command bodies
9+
10+
#include "apdu.h"
11+
12+
int apdu_decode(uint8_t *data, size_t len, APDU_STRUCT *apdu)
13+
{
14+
EXT_APDU_HEADER *hapdu = (EXT_APDU_HEADER *)data;
15+
16+
apdu->cla = hapdu->cla;
17+
apdu->ins = hapdu->ins;
18+
apdu->p1 = hapdu->p1;
19+
apdu->p2 = hapdu->p2;
20+
21+
apdu->lc = 0;
22+
apdu->data = NULL;
23+
apdu->le = 0;
24+
apdu->extended_apdu = false;
25+
apdu->case_type = 0x00;
26+
27+
uint8_t b0 = hapdu->lc[0];
28+
29+
// case 1
30+
if (len == 4)
31+
{
32+
apdu->case_type = 0x01;
33+
}
34+
35+
// case 2S (Le)
36+
if (len == 5)
37+
{
38+
apdu->case_type = 0x02;
39+
apdu->le = b0;
40+
if (!apdu->le)
41+
apdu->le = 0x100;
42+
}
43+
44+
// case 3S (Lc + data)
45+
if (len == 5U + b0 && b0 != 0)
46+
{
47+
apdu->case_type = 0x03;
48+
apdu->lc = b0;
49+
}
50+
51+
// case 4S (Lc + data + Le)
52+
if (len == 5U + b0 + 1U && b0 != 0)
53+
{
54+
apdu->case_type = 0x04;
55+
apdu->lc = b0;
56+
apdu->le = data[len - 1];
57+
if (!apdu->le)
58+
apdu->le = 0x100;
59+
}
60+
61+
// extended length apdu
62+
if (len >= 7 && b0 == 0)
63+
{
64+
uint16_t extlen = (hapdu->lc[1] << 8) + hapdu->lc[2];
65+
66+
// case 2E (Le) - extended
67+
if (len == 7)
68+
{
69+
apdu->case_type = 0x12;
70+
apdu->extended_apdu = true;
71+
apdu->le = extlen;
72+
if (!apdu->le)
73+
apdu->le = 0x10000;
74+
}
75+
76+
// case 3E (Lc + data) - extended
77+
if (len == 7U + extlen)
78+
{
79+
apdu->case_type = 0x13;
80+
apdu->extended_apdu = true;
81+
apdu->lc = extlen;
82+
}
83+
84+
// case 4E (Lc + data + Le) - extended 2-byte Le
85+
if (len == 7U + extlen + 2U)
86+
{
87+
apdu->case_type = 0x14;
88+
apdu->extended_apdu = true;
89+
apdu->lc = extlen;
90+
apdu->le = (data[len - 2] << 8) + data[len - 1];
91+
if (!apdu->le)
92+
apdu->le = 0x10000;
93+
}
94+
95+
// case 4E (Lc + data + Le) - extended 3-byte Le
96+
if (len == 7U + extlen + 3U && data[len - 3] == 0)
97+
{
98+
apdu->case_type = 0x24;
99+
apdu->extended_apdu = true;
100+
apdu->lc = extlen;
101+
apdu->le = (data[len - 2] << 8) + data[len - 1];
102+
if (!apdu->le)
103+
apdu->le = 0x10000;
104+
}
105+
}
106+
107+
if (!apdu->case_type)
108+
return 1;
109+
110+
if (apdu->lc)
111+
{
112+
if (apdu->extended_apdu)
113+
{
114+
apdu->data = data + 7;
115+
} else {
116+
apdu->data = data + 5;
117+
}
118+
119+
}
120+
121+
return 0;
122+
}

fido2/apdu.h

+27
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
#define _APDU_H_
33

44
#include <stdint.h>
5+
#include <stdbool.h>
6+
#include <stddef.h>
57

68
typedef struct
79
{
@@ -12,6 +14,30 @@ typedef struct
1214
uint8_t lc;
1315
} __attribute__((packed)) APDU_HEADER;
1416

17+
typedef struct
18+
{
19+
uint8_t cla;
20+
uint8_t ins;
21+
uint8_t p1;
22+
uint8_t p2;
23+
uint8_t lc[3];
24+
} __attribute__((packed)) EXT_APDU_HEADER;
25+
26+
typedef struct
27+
{
28+
uint8_t cla;
29+
uint8_t ins;
30+
uint8_t p1;
31+
uint8_t p2;
32+
uint16_t lc;
33+
uint8_t *data;
34+
uint32_t le;
35+
bool extended_apdu;
36+
uint8_t case_type;
37+
} __attribute__((packed)) APDU_STRUCT;
38+
39+
extern int apdu_decode(uint8_t *data, size_t len, APDU_STRUCT *apdu);
40+
1541
#define APDU_FIDO_U2F_REGISTER 0x01
1642
#define APDU_FIDO_U2F_AUTHENTICATE 0x02
1743
#define APDU_FIDO_U2F_VERSION 0x03
@@ -25,6 +51,7 @@ typedef struct
2551
#define SW_COND_USE_NOT_SATISFIED 0x6985
2652
#define SW_FILE_NOT_FOUND 0x6a82
2753
#define SW_INS_INVALID 0x6d00 // Instruction code not supported or invalid
54+
#define SW_CLA_INVALID 0x6e00
2855
#define SW_INTERNAL_EXCEPTION 0x6f00
2956

3057
#endif //_APDU_H_

fido2/device.h

+2
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,8 @@ void device_set_clock_rate(DEVICE_CLOCK_RATE param);
105105
#define NFC_IS_AVAILABLE 2
106106
int device_is_nfc();
107107

108+
void request_from_nfc(bool request_active);
109+
108110
void device_init_button();
109111

110112
#endif

fido2/u2f.c

+5-5
Original file line numberDiff line numberDiff line change
@@ -113,14 +113,14 @@ void u2f_request_ex(APDU_HEADER *req, uint8_t *payload, uint32_t len, CTAP_RESPO
113113
printf1(TAG_U2F,"u2f resp: "); dump_hex1(TAG_U2F, _u2f_resp->data, _u2f_resp->length);
114114
}
115115

116-
void u2f_request_nfc(uint8_t * req, int len, CTAP_RESPONSE * resp)
116+
void u2f_request_nfc(uint8_t * header, uint8_t * data, int datalen, CTAP_RESPONSE * resp)
117117
{
118-
if (len < 5 || !req)
118+
if (!header)
119119
return;
120120

121-
uint32_t alen = req[4];
122-
123-
u2f_request_ex((APDU_HEADER *)req, &req[5], alen, resp);
121+
request_from_nfc(true); // disable presence test
122+
u2f_request_ex((APDU_HEADER *)header, data, datalen, resp);
123+
request_from_nfc(false); // enable presence test
124124
}
125125

126126
void u2f_request(struct u2f_request_apdu* req, CTAP_RESPONSE * resp)

fido2/u2f.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ void u2f_request(struct u2f_request_apdu* req, CTAP_RESPONSE * resp);
101101
// u2f_request send a U2F message to NFC protocol
102102
// @req data with iso7816 apdu message
103103
// @len data length
104-
void u2f_request_nfc(uint8_t * req, int len, CTAP_RESPONSE * resp);
104+
void u2f_request_nfc(uint8_t * header, uint8_t * data, int datalen, CTAP_RESPONSE * resp);
105105

106106
int8_t u2f_authenticate_credential(struct u2f_key_handle * kh, uint8_t * appid);
107107

targets/stm32l432/build/application.mk

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ SRC += src/startup_stm32l432xx.s src/system_stm32l4xx.c
77
SRC += $(DRIVER_LIBS) $(USB_LIB)
88

99
# FIDO2 lib
10-
SRC += ../../fido2/util.c ../../fido2/u2f.c ../../fido2/test_power.c
10+
SRC += ../../fido2/apdu.c ../../fido2/util.c ../../fido2/u2f.c ../../fido2/test_power.c
1111
SRC += ../../fido2/stubs.c ../../fido2/log.c ../../fido2/ctaphid.c ../../fido2/ctap.c
1212
SRC += ../../fido2/ctap_parse.c ../../fido2/main.c
1313
SRC += ../../fido2/extensions/extensions.c ../../fido2/extensions/solo.c

targets/stm32l432/src/app.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
// #define DISABLE_CTAPHID_WINK
3232
// #define DISABLE_CTAPHID_CBOR
3333

34-
#define ENABLE_SERIAL_PRINTING
34+
// #define ENABLE_SERIAL_PRINTING
3535

3636
#if defined(SOLO_HACKER)
3737
#define SOLO_PRODUCT_NAME "Solo Hacker " SOLO_VERSION

targets/stm32l432/src/device.c

+6-1
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ uint32_t __last_update = 0;
4343
extern PCD_HandleTypeDef hpcd;
4444
static int _NFC_status = 0;
4545
static bool isLowFreq = 0;
46+
static bool _RequestComeFromNFC = false;
4647

4748
// #define IS_BUTTON_PRESSED() (0 == (LL_GPIO_ReadInputPort(SOLO_BUTTON_PORT) & SOLO_BUTTON_PIN))
4849
static int is_physical_button_pressed()
@@ -57,6 +58,10 @@ static int is_touch_button_pressed()
5758

5859
int (*IS_BUTTON_PRESSED)() = is_physical_button_pressed;
5960

61+
void request_from_nfc(bool request_active) {
62+
_RequestComeFromNFC = request_active;
63+
}
64+
6065
// Timer6 overflow handler. happens every ~90ms.
6166
void TIM6_DAC_IRQHandler()
6267
{
@@ -491,7 +496,7 @@ static int handle_packets()
491496
int ctap_user_presence_test(uint32_t up_delay)
492497
{
493498
int ret;
494-
if (device_is_nfc() == NFC_IS_ACTIVE)
499+
if (device_is_nfc() == NFC_IS_ACTIVE || _RequestComeFromNFC)
495500
{
496501
return 1;
497502
}

0 commit comments

Comments
 (0)