diff --git a/.gitignore b/.gitignore index e80f85c0..41478aa8 100644 --- a/.gitignore +++ b/.gitignore @@ -83,3 +83,5 @@ targets/*/docs/ main builds/* +tools/testing/.idea/* +tools/testing/tests/__pycache__/* diff --git a/fido2/apdu.c b/fido2/apdu.c new file mode 100644 index 00000000..df890999 --- /dev/null +++ b/fido2/apdu.c @@ -0,0 +1,122 @@ +// Copyright 2019 SoloKeys Developers +// +// Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be +// copied, modified, or distributed except according to those terms. + +// iso7816:2013. 5.3.2 Decoding conventions for command bodies + +#include "apdu.h" + +int apdu_decode(uint8_t *data, size_t len, APDU_STRUCT *apdu) +{ + EXT_APDU_HEADER *hapdu = (EXT_APDU_HEADER *)data; + + apdu->cla = hapdu->cla; + apdu->ins = hapdu->ins; + apdu->p1 = hapdu->p1; + apdu->p2 = hapdu->p2; + + apdu->lc = 0; + apdu->data = NULL; + apdu->le = 0; + apdu->extended_apdu = false; + apdu->case_type = 0x00; + + uint8_t b0 = hapdu->lc[0]; + + // case 1 + if (len == 4) + { + apdu->case_type = 0x01; + } + + // case 2S (Le) + if (len == 5) + { + apdu->case_type = 0x02; + apdu->le = b0; + if (!apdu->le) + apdu->le = 0x100; + } + + // case 3S (Lc + data) + if (len == 5U + b0 && b0 != 0) + { + apdu->case_type = 0x03; + apdu->lc = b0; + } + + // case 4S (Lc + data + Le) + if (len == 5U + b0 + 1U && b0 != 0) + { + apdu->case_type = 0x04; + apdu->lc = b0; + apdu->le = data[len - 1]; + if (!apdu->le) + apdu->le = 0x100; + } + + // extended length apdu + if (len >= 7 && b0 == 0) + { + uint16_t extlen = (hapdu->lc[1] << 8) + hapdu->lc[2]; + + // case 2E (Le) - extended + if (len == 7) + { + apdu->case_type = 0x12; + apdu->extended_apdu = true; + apdu->le = extlen; + if (!apdu->le) + apdu->le = 0x10000; + } + + // case 3E (Lc + data) - extended + if (len == 7U + extlen) + { + apdu->case_type = 0x13; + apdu->extended_apdu = true; + apdu->lc = extlen; + } + + // case 4E (Lc + data + Le) - extended 2-byte Le + if (len == 7U + extlen + 2U) + { + apdu->case_type = 0x14; + apdu->extended_apdu = true; + apdu->lc = extlen; + apdu->le = (data[len - 2] << 8) + data[len - 1]; + if (!apdu->le) + apdu->le = 0x10000; + } + + // case 4E (Lc + data + Le) - extended 3-byte Le + if (len == 7U + extlen + 3U && data[len - 3] == 0) + { + apdu->case_type = 0x24; + apdu->extended_apdu = true; + apdu->lc = extlen; + apdu->le = (data[len - 2] << 8) + data[len - 1]; + if (!apdu->le) + apdu->le = 0x10000; + } + } + + if (!apdu->case_type) + return 1; + + if (apdu->lc) + { + if (apdu->extended_apdu) + { + apdu->data = data + 7; + } else { + apdu->data = data + 5; + } + + } + + return 0; +} diff --git a/fido2/apdu.h b/fido2/apdu.h index d9687c79..44029b33 100644 --- a/fido2/apdu.h +++ b/fido2/apdu.h @@ -2,6 +2,8 @@ #define _APDU_H_ #include +#include +#include typedef struct { @@ -12,6 +14,30 @@ typedef struct uint8_t lc; } __attribute__((packed)) APDU_HEADER; +typedef struct +{ + uint8_t cla; + uint8_t ins; + uint8_t p1; + uint8_t p2; + uint8_t lc[3]; +} __attribute__((packed)) EXT_APDU_HEADER; + +typedef struct +{ + uint8_t cla; + uint8_t ins; + uint8_t p1; + uint8_t p2; + uint16_t lc; + uint8_t *data; + uint32_t le; + bool extended_apdu; + uint8_t case_type; +} __attribute__((packed)) APDU_STRUCT; + +extern int apdu_decode(uint8_t *data, size_t len, APDU_STRUCT *apdu); + #define APDU_FIDO_U2F_REGISTER 0x01 #define APDU_FIDO_U2F_AUTHENTICATE 0x02 #define APDU_FIDO_U2F_VERSION 0x03 @@ -25,6 +51,7 @@ typedef struct #define SW_COND_USE_NOT_SATISFIED 0x6985 #define SW_FILE_NOT_FOUND 0x6a82 #define SW_INS_INVALID 0x6d00 // Instruction code not supported or invalid +#define SW_CLA_INVALID 0x6e00 #define SW_INTERNAL_EXCEPTION 0x6f00 #endif //_APDU_H_ diff --git a/fido2/device.h b/fido2/device.h index dfb95ec3..0c11fe8a 100644 --- a/fido2/device.h +++ b/fido2/device.h @@ -105,6 +105,8 @@ void device_set_clock_rate(DEVICE_CLOCK_RATE param); #define NFC_IS_AVAILABLE 2 int device_is_nfc(); +void request_from_nfc(bool request_active); + void device_init_button(); #endif diff --git a/fido2/u2f.c b/fido2/u2f.c index 14cb8485..7999ab20 100644 --- a/fido2/u2f.c +++ b/fido2/u2f.c @@ -113,14 +113,14 @@ void u2f_request_ex(APDU_HEADER *req, uint8_t *payload, uint32_t len, CTAP_RESPO printf1(TAG_U2F,"u2f resp: "); dump_hex1(TAG_U2F, _u2f_resp->data, _u2f_resp->length); } -void u2f_request_nfc(uint8_t * req, int len, CTAP_RESPONSE * resp) +void u2f_request_nfc(uint8_t * header, uint8_t * data, int datalen, CTAP_RESPONSE * resp) { - if (len < 5 || !req) + if (!header) return; - uint32_t alen = req[4]; - - u2f_request_ex((APDU_HEADER *)req, &req[5], alen, resp); + request_from_nfc(true); // disable presence test + u2f_request_ex((APDU_HEADER *)header, data, datalen, resp); + request_from_nfc(false); // enable presence test } void u2f_request(struct u2f_request_apdu* req, CTAP_RESPONSE * resp) diff --git a/fido2/u2f.h b/fido2/u2f.h index 9055b36c..ad73cc93 100644 --- a/fido2/u2f.h +++ b/fido2/u2f.h @@ -101,7 +101,7 @@ void u2f_request(struct u2f_request_apdu* req, CTAP_RESPONSE * resp); // u2f_request send a U2F message to NFC protocol // @req data with iso7816 apdu message // @len data length -void u2f_request_nfc(uint8_t * req, int len, CTAP_RESPONSE * resp); +void u2f_request_nfc(uint8_t * header, uint8_t * data, int datalen, CTAP_RESPONSE * resp); int8_t u2f_authenticate_credential(struct u2f_key_handle * kh, uint8_t * appid); diff --git a/targets/stm32l432/build/application.mk b/targets/stm32l432/build/application.mk index e482f877..848887f1 100644 --- a/targets/stm32l432/build/application.mk +++ b/targets/stm32l432/build/application.mk @@ -7,7 +7,7 @@ SRC += src/startup_stm32l432xx.s src/system_stm32l4xx.c SRC += $(DRIVER_LIBS) $(USB_LIB) # FIDO2 lib -SRC += ../../fido2/util.c ../../fido2/u2f.c ../../fido2/test_power.c +SRC += ../../fido2/apdu.c ../../fido2/util.c ../../fido2/u2f.c ../../fido2/test_power.c SRC += ../../fido2/stubs.c ../../fido2/log.c ../../fido2/ctaphid.c ../../fido2/ctap.c SRC += ../../fido2/ctap_parse.c ../../fido2/main.c SRC += ../../fido2/extensions/extensions.c ../../fido2/extensions/solo.c diff --git a/targets/stm32l432/src/app.h b/targets/stm32l432/src/app.h index 3bcfac2b..308e5f60 100644 --- a/targets/stm32l432/src/app.h +++ b/targets/stm32l432/src/app.h @@ -31,7 +31,7 @@ // #define DISABLE_CTAPHID_WINK // #define DISABLE_CTAPHID_CBOR -#define ENABLE_SERIAL_PRINTING +// #define ENABLE_SERIAL_PRINTING #if defined(SOLO_HACKER) #define SOLO_PRODUCT_NAME "Solo Hacker " SOLO_VERSION diff --git a/targets/stm32l432/src/device.c b/targets/stm32l432/src/device.c index ae441fc7..62891890 100644 --- a/targets/stm32l432/src/device.c +++ b/targets/stm32l432/src/device.c @@ -43,6 +43,7 @@ uint32_t __last_update = 0; extern PCD_HandleTypeDef hpcd; static int _NFC_status = 0; static bool isLowFreq = 0; +static bool _RequestComeFromNFC = false; // #define IS_BUTTON_PRESSED() (0 == (LL_GPIO_ReadInputPort(SOLO_BUTTON_PORT) & SOLO_BUTTON_PIN)) static int is_physical_button_pressed() @@ -57,6 +58,10 @@ static int is_touch_button_pressed() int (*IS_BUTTON_PRESSED)() = is_physical_button_pressed; +void request_from_nfc(bool request_active) { + _RequestComeFromNFC = request_active; +} + // Timer6 overflow handler. happens every ~90ms. void TIM6_DAC_IRQHandler() { @@ -491,7 +496,7 @@ static int handle_packets() int ctap_user_presence_test(uint32_t up_delay) { int ret; - if (device_is_nfc() == NFC_IS_ACTIVE) + if (device_is_nfc() == NFC_IS_ACTIVE || _RequestComeFromNFC) { return 1; } diff --git a/targets/stm32l432/src/nfc.c b/targets/stm32l432/src/nfc.c index 51e34bb2..a2233787 100644 --- a/targets/stm32l432/src/nfc.c +++ b/targets/stm32l432/src/nfc.c @@ -14,6 +14,16 @@ #define IS_IRQ_ACTIVE() (1 == (LL_GPIO_ReadInputPort(SOLO_AMS_IRQ_PORT) & SOLO_AMS_IRQ_PIN)) +uint8_t p14443_block_offset(uint8_t pcb) { + uint8_t offset = 1; + // NAD following + if (pcb & 0x04) offset++; + // CID following + if (pcb & 0x08) offset++; + + return offset; +} + // Capability container const CAPABILITY_CONTAINER NFC_CC = { .cclen_hi = 0x00, .cclen_lo = 0x0f, @@ -112,6 +122,7 @@ bool ams_receive_with_timeout(uint32_t timeout_ms, uint8_t * data, int maxlen, i while (tstart + timeout_ms > millis()) { uint8_t int0 = ams_read_reg(AMS_REG_INT0); + if (int0) process_int0(int0); uint8_t buffer_status2 = ams_read_reg(AMS_REG_BUF2); if (buffer_status2 && (int0 & AMS_INT_RXE)) @@ -161,14 +172,18 @@ bool nfc_write_response_ex(uint8_t req0, uint8_t * data, uint8_t len, uint16_t r if (len > 32 - 3) return false; - res[0] = NFC_CMD_IBLOCK | (req0 & 3); + res[0] = NFC_CMD_IBLOCK | (req0 & 0x0f); + res[1] = 0; + res[2] = 0; + + uint8_t block_offset = p14443_block_offset(req0); if (len && data) - memcpy(&res[1], data, len); + memcpy(&res[block_offset], data, len); - res[len + 1] = resp >> 8; - res[len + 2] = resp & 0xff; - nfc_write_frame(res, 3 + len); + res[len + block_offset + 0] = resp >> 8; + res[len + block_offset + 1] = resp & 0xff; + nfc_write_frame(res, block_offset + len + 2); return true; } @@ -182,21 +197,24 @@ void nfc_write_response_chaining(uint8_t req0, uint8_t * data, int len) { uint8_t res[32 + 2]; int sendlen = 0; - uint8_t iBlock = NFC_CMD_IBLOCK | (req0 & 3); + uint8_t iBlock = NFC_CMD_IBLOCK | (req0 & 0x0f); + uint8_t block_offset = p14443_block_offset(req0); if (len <= 31) { uint8_t res[32] = {0}; - res[0] = iBlock; + res[0] = iBlock; if (len && data) - memcpy(&res[1], data, len); - nfc_write_frame(res, len + 1); + memcpy(&res[block_offset], data, len); + nfc_write_frame(res, len + block_offset); } else { do { // transmit I block - int vlen = MIN(31, len - sendlen); - res[0] = iBlock; - memcpy(&res[1], &data[sendlen], vlen); + int vlen = MIN(32 - block_offset, len - sendlen); + res[0] = iBlock; + res[1] = 0; + res[2] = 0; + memcpy(&res[block_offset], &data[sendlen], vlen); // if not a last block if (vlen + sendlen < len) @@ -205,7 +223,7 @@ void nfc_write_response_chaining(uint8_t req0, uint8_t * data, int len) } // send data - nfc_write_frame(res, vlen + 1); + nfc_write_frame(res, vlen + block_offset); sendlen += vlen; // wait for transmit (32 bytes aprox 2,5ms) @@ -226,9 +244,10 @@ void nfc_write_response_chaining(uint8_t req0, uint8_t * data, int len) break; } - if (reclen != 1) + uint8_t rblock_offset = p14443_block_offset(recbuf[0]); + if (reclen != rblock_offset) { - printf1(TAG_NFC, "R block length error. len: %d. %d/%d \r\n", reclen,sendlen,len); + printf1(TAG_NFC, "R block length error. len: %d. %d/%d \r\n", reclen, sendlen, len); dump_hex1(TAG_NFC, recbuf, reclen); break; } @@ -371,39 +390,72 @@ int answer_rats(uint8_t parameter) nfc_write_frame(res, sizeof(res)); - ams_wait_for_tx(10); + if (!ams_wait_for_tx(10)) + { + printf1(TAG_NFC, "RATS TX timeout.\r\n"); + ams_write_command(AMS_CMD_DEFAULT); + return 1; + } return 0; } -void rblock_acknowledge() +void rblock_acknowledge(uint8_t req0, bool ack) { - uint8_t buf[32]; + uint8_t buf[32] = {0}; + + uint8_t block_offset = p14443_block_offset(req0); NFC_STATE.block_num = !NFC_STATE.block_num; - buf[0] = NFC_CMD_RBLOCK | NFC_STATE.block_num; - nfc_write_frame(buf,1); + + buf[0] = NFC_CMD_RBLOCK | (req0 & 0x0f); + if (ack) + buf[0] |= NFC_CMD_RBLOCK_ACK; + + nfc_write_frame(buf, block_offset); +} + +// international AID = RID:PIX +// RID length == 5 bytes +// usually aid length must be between 5 and 16 bytes +int applet_cmp(uint8_t * aid, int len, uint8_t * const_aid, int const_len) +{ + if (len > const_len) + return 10; + + // if international AID + if ((const_aid[0] & 0xf0) == 0xa0) + { + if (len < 5) + return 11; + return memcmp(aid, const_aid, MIN(len, const_len)); + } else { + if (len != const_len) + return 11; + + return memcmp(aid, const_aid, const_len); + } } // Selects application. Returns 1 if success, 0 otherwise int select_applet(uint8_t * aid, int len) { - if (memcmp(aid,AID_FIDO,sizeof(AID_FIDO)) == 0) + if (applet_cmp(aid, len, (uint8_t *)AID_FIDO, sizeof(AID_FIDO) - 1) == 0) { NFC_STATE.selected_applet = APP_FIDO; return APP_FIDO; } - else if (memcmp(aid,AID_NDEF_TYPE_4,sizeof(AID_NDEF_TYPE_4)) == 0) + else if (applet_cmp(aid, len, (uint8_t *)AID_NDEF_TYPE_4, sizeof(AID_NDEF_TYPE_4) - 1) == 0) { NFC_STATE.selected_applet = APP_NDEF_TYPE_4; return APP_NDEF_TYPE_4; } - else if (memcmp(aid,AID_CAPABILITY_CONTAINER,sizeof(AID_CAPABILITY_CONTAINER)) == 0) + else if (applet_cmp(aid, len, (uint8_t *)AID_CAPABILITY_CONTAINER, sizeof(AID_CAPABILITY_CONTAINER) - 1) == 0) { NFC_STATE.selected_applet = APP_CAPABILITY_CONTAINER; return APP_CAPABILITY_CONTAINER; } - else if (memcmp(aid,AID_NDEF_TAG,sizeof(AID_NDEF_TAG)) == 0) + else if (applet_cmp(aid, len, (uint8_t *)AID_NDEF_TAG, sizeof(AID_NDEF_TAG) - 1) == 0) { NFC_STATE.selected_applet = APP_NDEF_TAG; return APP_NDEF_TAG; @@ -413,25 +465,36 @@ int select_applet(uint8_t * aid, int len) void nfc_process_iblock(uint8_t * buf, int len) { - APDU_HEADER * apdu = (APDU_HEADER *)(buf + 1); - uint8_t * payload = buf + 1 + 5; - uint8_t plen = apdu->lc; int selected; CTAP_RESPONSE ctap_resp; int status; - + uint16_t reslen; + printf1(TAG_NFC,"Iblock: "); dump_hex1(TAG_NFC, buf, len); + uint8_t block_offset = p14443_block_offset(buf[0]); + + APDU_STRUCT apdu; + if (apdu_decode(buf + block_offset, len - block_offset, &apdu)) { + printf1(TAG_NFC,"apdu decode error\r\n"); + nfc_write_response(buf[0], SW_COND_USE_NOT_SATISFIED); + return; + } + printf1(TAG_NFC,"apdu ok. %scase=%02x cla=%02x ins=%02x p1=%02x p2=%02x lc=%d le=%d\r\n", + apdu.extended_apdu ? "[e]":"", apdu.case_type, apdu.cla, apdu.ins, apdu.p1, apdu.p2, apdu.lc, apdu.le); + + // check CLA + if (apdu.cla != 0x00 && apdu.cla != 0x80) { + printf1(TAG_NFC, "Unknown CLA %02x\r\n", apdu.cla); + nfc_write_response(buf[0], SW_CLA_INVALID); + return; + } + // TODO this needs to be organized better - switch(apdu->ins) + switch(apdu.ins) { case APDU_INS_SELECT: - if (plen > len - 6) - { - printf1(TAG_ERR, "Truncating APDU length %d\r\n", apdu->lc); - plen = len-6; - } // if (apdu->p1 == 0 && apdu->p2 == 0x0c) // { // printf1(TAG_NFC,"Select NDEF\r\n"); @@ -446,14 +509,9 @@ void nfc_process_iblock(uint8_t * buf, int len) // } // else { - selected = select_applet(payload, plen); + selected = select_applet(apdu.data, apdu.lc); if (selected == APP_FIDO) { - // block = buf[0] & 1; - // block = NFC_STATE.block_num; - // block = !block; - // NFC_STATE.block_num = block; - // NFC_STATE.block_num = block; nfc_write_response_ex(buf[0], (uint8_t *)"U2F_V2", 6, SW_SUCCESS); printf1(TAG_NFC, "FIDO applet selected.\r\n"); } @@ -465,7 +523,7 @@ void nfc_process_iblock(uint8_t * buf, int len) else { nfc_write_response(buf[0], SW_FILE_NOT_FOUND); - printf1(TAG_NFC, "NOT selected\r\n"); dump_hex1(TAG_NFC,payload, plen); + printf1(TAG_NFC, "NOT selected "); dump_hex1(TAG_NFC, apdu.data, apdu.lc); } } break; @@ -478,7 +536,8 @@ void nfc_process_iblock(uint8_t * buf, int len) printf1(TAG_NFC, "U2F GetVersion command.\r\n"); - nfc_write_response_ex(buf[0], (uint8_t *)"U2F_V2", 6, SW_SUCCESS); + u2f_request_nfc(&buf[block_offset], apdu.data, apdu.lc, &ctap_resp); + nfc_write_response_chaining(buf[0], ctap_resp.data, ctap_resp.length); break; case APDU_FIDO_U2F_REGISTER: @@ -489,9 +548,9 @@ void nfc_process_iblock(uint8_t * buf, int len) printf1(TAG_NFC, "U2F Register command.\r\n"); - if (plen != 64) + if (apdu.lc != 64) { - printf1(TAG_NFC, "U2F Register request length error. len=%d.\r\n", plen); + printf1(TAG_NFC, "U2F Register request length error. len=%d.\r\n", apdu.lc); nfc_write_response(buf[0], SW_WRONG_LENGTH); return; } @@ -502,20 +561,16 @@ void nfc_process_iblock(uint8_t * buf, int len) // WTX_on(WTX_TIME_DEFAULT); // SystemClock_Config_LF32(); // delay(300); - if (device_is_nfc()) device_set_clock_rate(DEVICE_LOW_POWER_FAST);; - u2f_request_nfc(&buf[1], len, &ctap_resp); - if (device_is_nfc()) device_set_clock_rate(DEVICE_LOW_POWER_IDLE);; + if (device_is_nfc() == NFC_IS_ACTIVE) device_set_clock_rate(DEVICE_LOW_POWER_FAST); + u2f_request_nfc(&buf[block_offset], apdu.data, apdu.lc, &ctap_resp); + if (device_is_nfc() == NFC_IS_ACTIVE) device_set_clock_rate(DEVICE_LOW_POWER_IDLE); // if (!WTX_off()) // return; + printf1(TAG_NFC, "U2F resp len: %d\r\n", ctap_resp.length); printf1(TAG_NFC,"U2F Register P2 took %d\r\n", timestamp()); nfc_write_response_chaining(buf[0], ctap_resp.data, ctap_resp.length); - // printf1(TAG_NFC, "U2F resp len: %d\r\n", ctap_resp.length); - - - - printf1(TAG_NFC,"U2F Register answered %d (took %d)\r\n", millis(), timestamp()); break; @@ -527,17 +582,17 @@ void nfc_process_iblock(uint8_t * buf, int len) printf1(TAG_NFC, "U2F Authenticate command.\r\n"); - if (plen != 64 + 1 + buf[6 + 64]) + if (apdu.lc != 64 + 1 + apdu.data[64]) { delay(5); - printf1(TAG_NFC, "U2F Authenticate request length error. len=%d keyhlen=%d.\r\n", plen, buf[6 + 64]); + printf1(TAG_NFC, "U2F Authenticate request length error. len=%d keyhlen=%d.\r\n", apdu.lc, apdu.data[64]); nfc_write_response(buf[0], SW_WRONG_LENGTH); return; } timestamp(); // WTX_on(WTX_TIME_DEFAULT); - u2f_request_nfc(&buf[1], len, &ctap_resp); + u2f_request_nfc(&buf[block_offset], apdu.data, apdu.lc, &ctap_resp); // if (!WTX_off()) // return; @@ -550,14 +605,16 @@ void nfc_process_iblock(uint8_t * buf, int len) case APDU_FIDO_NFCCTAP_MSG: if (NFC_STATE.selected_applet != APP_FIDO) { nfc_write_response(buf[0], SW_INS_INVALID); - break; + return; } printf1(TAG_NFC, "FIDO2 CTAP message. %d\r\n", timestamp()); WTX_on(WTX_TIME_DEFAULT); + request_from_nfc(true); ctap_response_init(&ctap_resp); - status = ctap_request(payload, plen, &ctap_resp); + status = ctap_request(apdu.data, apdu.lc, &ctap_resp); + request_from_nfc(false); if (!WTX_off()) return; @@ -580,44 +637,37 @@ void nfc_process_iblock(uint8_t * buf, int len) break; case APDU_INS_READ_BINARY: - - + // response length + reslen = apdu.le & 0xffff; switch(NFC_STATE.selected_applet) { case APP_CAPABILITY_CONTAINER: printf1(TAG_NFC,"APP_CAPABILITY_CONTAINER\r\n"); - if (plen > 15) - { - printf1(TAG_ERR, "Truncating requested CC length %d\r\n", apdu->lc); - plen = 15; - } - nfc_write_response_ex(buf[0], (uint8_t *)&NFC_CC, plen, SW_SUCCESS); + if (reslen == 0 || reslen > sizeof(NFC_CC)) + reslen = sizeof(NFC_CC); + nfc_write_response_ex(buf[0], (uint8_t *)&NFC_CC, reslen, SW_SUCCESS); ams_wait_for_tx(10); break; case APP_NDEF_TAG: printf1(TAG_NFC,"APP_NDEF_TAG\r\n"); - if (plen > (sizeof(NDEF_SAMPLE) - 1)) - { - printf1(TAG_ERR, "Truncating requested CC length %d\r\n", apdu->lc); - plen = sizeof(NDEF_SAMPLE) - 1; - } - nfc_write_response_ex(buf[0], NDEF_SAMPLE, plen, SW_SUCCESS); + if (reslen == 0 || reslen > sizeof(NDEF_SAMPLE) - 1) + reslen = sizeof(NDEF_SAMPLE) - 1; + nfc_write_response_ex(buf[0], NDEF_SAMPLE, reslen, SW_SUCCESS); ams_wait_for_tx(10); break; default: + nfc_write_response(buf[0], SW_FILE_NOT_FOUND); printf1(TAG_ERR, "No binary applet selected!\r\n"); return; break; } - break; + default: - printf1(TAG_NFC, "Unknown INS %02x\r\n", apdu->ins); + printf1(TAG_NFC, "Unknown INS %02x\r\n", apdu.ins); nfc_write_response(buf[0], SW_INS_INVALID); break; } - - } static uint8_t ibuf[1024]; @@ -631,7 +681,7 @@ void clear_ibuf() void nfc_process_block(uint8_t * buf, unsigned int len) { - + printf1(TAG_NFC, "-----\r\n"); if (!len) return; @@ -641,6 +691,7 @@ void nfc_process_block(uint8_t * buf, unsigned int len) } else if (IS_IBLOCK(buf[0])) { + uint8_t block_offset = p14443_block_offset(buf[0]); if (buf[0] & 0x10) { printf1(TAG_NFC_APDU, "NFC_CMD_IBLOCK chaining blen=%d len=%d\r\n", ibuflen, len); @@ -654,27 +705,27 @@ void nfc_process_block(uint8_t * buf, unsigned int len) printf1(TAG_NFC_APDU,"i> "); dump_hex1(TAG_NFC_APDU, buf, len); - if (len) + if (len > block_offset) { - memcpy(&ibuf[ibuflen], &buf[1], len - 1); - ibuflen += len - 1; + memcpy(&ibuf[ibuflen], &buf[block_offset], len - block_offset); + ibuflen += len - block_offset; } // send R block - uint8_t rb = NFC_CMD_RBLOCK | NFC_CMD_RBLOCK_ACK | (buf[0] & 3); - nfc_write_frame(&rb, 1); + rblock_acknowledge(buf[0], true); } else { if (ibuflen) { - if (len) + if (len > block_offset) { - memcpy(&ibuf[ibuflen], &buf[1], len - 1); - ibuflen += len - 1; + memcpy(&ibuf[ibuflen], &buf[block_offset], len - block_offset); + ibuflen += len - block_offset; } - memmove(&ibuf[1], ibuf, ibuflen); - ibuf[0] = buf[0]; - ibuflen++; + // add last chaining to top of the block + memmove(&ibuf[block_offset], ibuf, ibuflen); + memmove(ibuf, buf, block_offset); + ibuflen += block_offset; printf1(TAG_NFC_APDU, "NFC_CMD_IBLOCK chaining last block. blen=%d len=%d\r\n", ibuflen, len); @@ -683,7 +734,6 @@ void nfc_process_block(uint8_t * buf, unsigned int len) nfc_process_iblock(ibuf, ibuflen); } else { - // printf1(TAG_NFC, "NFC_CMD_IBLOCK\r\n"); nfc_process_iblock(buf, len); } clear_ibuf(); @@ -691,7 +741,7 @@ void nfc_process_block(uint8_t * buf, unsigned int len) } else if (IS_RBLOCK(buf[0])) { - rblock_acknowledge(); + rblock_acknowledge(buf[0], false); printf1(TAG_NFC, "NFC_CMD_RBLOCK\r\n"); } else if (IS_SBLOCK(buf[0])) @@ -710,6 +760,7 @@ void nfc_process_block(uint8_t * buf, unsigned int len) else { printf1(TAG_NFC, "NFC_CMD_SBLOCK, Unknown. len[%d]\r\n", len); + nfc_write_response(buf[0], SW_COND_USE_NOT_SATISFIED); } dump_hex1(TAG_NFC, buf, len); } diff --git a/targets/stm32l432/src/nfc.h b/targets/stm32l432/src/nfc.h index 98715371..f284a8e3 100644 --- a/targets/stm32l432/src/nfc.h +++ b/targets/stm32l432/src/nfc.h @@ -40,6 +40,8 @@ typedef struct #define NFC_CMD_SBLOCK 0xc0 #define IS_SBLOCK(x) ( (((x) & 0xc0) == NFC_CMD_SBLOCK) && (((x) & 0x02) == 0x02) ) +extern uint8_t p14443_block_offset(uint8_t pcb); + #define NFC_SBLOCK_DESELECT 0x30 #define NFC_SBLOCK_WTX 0x30 diff --git a/tools/testing/tests/fido2.py b/tools/testing/tests/fido2.py index 94a361d1..3b5b5571 100644 --- a/tools/testing/tests/fido2.py +++ b/tools/testing/tests/fido2.py @@ -222,9 +222,7 @@ def test_extensions(self,): ) with Test("Get shared secret"): - key_agreement, shared_secret = ( - self.client.pin_protocol._init_shared_secret() - ) + key_agreement, shared_secret = self.client.pin_protocol.get_shared_secret() cipher = Cipher( algorithms.AES(shared_secret), modes.CBC(b"\x00" * 16), diff --git a/tools/testing/tests/tester.py b/tools/testing/tests/tester.py index 011c1c2f..a99dda5f 100644 --- a/tools/testing/tests/tester.py +++ b/tools/testing/tests/tester.py @@ -51,6 +51,7 @@ def __init__(self, tester=None): self.host = "examplo.org" self.user_count = 10 self.is_sim = False + self.nfc_interface_only = False if tester: self.initFromTester(tester) @@ -61,23 +62,23 @@ def initFromTester(self, tester): self.ctap = tester.ctap self.ctap1 = tester.ctap1 self.client = tester.client + self.nfc_interface_only = tester.nfc_interface_only def find_device(self, nfcInterfaceOnly=False): dev = None + self.nfc_interface_only = nfcInterfaceOnly if not nfcInterfaceOnly: print("--- HID ---") print(list(CtapHidDevice.list_devices())) dev = next(CtapHidDevice.list_devices(), None) if not dev: - try: - from fido2.pcsc import CtapPcscDevice + from fido2.pcsc import CtapPcscDevice + + print("--- NFC ---") + print(list(CtapPcscDevice.list_devices())) + dev = next(CtapPcscDevice.list_devices(), None) - print("--- NFC ---") - print(list(CtapPcscDevice.list_devices())) - dev = next(CtapPcscDevice.list_devices(), None) - except (ModuleNotFoundError, ImportError): - print("One of NFC library is not installed properly.") if not dev: raise RuntimeError("No FIDO device found") self.dev = dev @@ -102,7 +103,7 @@ def reboot(self,): else: print("Please reboot authentictor and hit enter") input() - self.find_device() + self.find_device(self.nfc_interface_only) def send_data(self, cmd, data): if not isinstance(data, bytes): @@ -196,7 +197,7 @@ def testReset(self,): print("You must power cycle authentictor. Hit enter when done.") input() time.sleep(0.2) - self.find_device() + self.find_device(self.nfc_interface_only) self.ctap.reset() def testMC(self, test, *args, **kwargs): diff --git a/tools/testing/tests/u2f.py b/tools/testing/tests/u2f.py index d1e80331..367ee4a0 100644 --- a/tools/testing/tests/u2f.py +++ b/tools/testing/tests/u2f.py @@ -42,12 +42,14 @@ def test_u2f(self,): with Test("Check bad INS"): try: self.ctap1.send_apdu(0, 0, 0, 0, b"") + assert False except ApduError as e: assert e.code == 0x6D00 with Test("Check bad CLA"): try: self.ctap1.send_apdu(1, CTAP1.INS.VERSION, 0, 0, b"abc") + assert False except ApduError as e: assert e.code == 0x6E00