diff --git a/fido2/apdu.h b/fido2/apdu.h new file mode 100644 index 0000000..d9687c7 --- /dev/null +++ b/fido2/apdu.h @@ -0,0 +1,30 @@ +#ifndef _APDU_H_ +#define _APDU_H_ + +#include + +typedef struct +{ + uint8_t cla; + uint8_t ins; + uint8_t p1; + uint8_t p2; + uint8_t lc; +} __attribute__((packed)) APDU_HEADER; + +#define APDU_FIDO_U2F_REGISTER 0x01 +#define APDU_FIDO_U2F_AUTHENTICATE 0x02 +#define APDU_FIDO_U2F_VERSION 0x03 +#define APDU_FIDO_NFCCTAP_MSG 0x10 +#define APDU_INS_SELECT 0xA4 +#define APDU_INS_READ_BINARY 0xB0 + +#define SW_SUCCESS 0x9000 +#define SW_GET_RESPONSE 0x6100 // Command successfully executed; 'XX' bytes of data are available and can be requested using GET RESPONSE. +#define SW_WRONG_LENGTH 0x6700 +#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_INTERNAL_EXCEPTION 0x6f00 + +#endif //_APDU_H_ diff --git a/fido2/main.c b/fido2/main.c index 51e15ec..3849633 100644 --- a/fido2/main.c +++ b/fido2/main.c @@ -50,7 +50,7 @@ int main(int argc, char * argv[]) // TAG_CP | // TAG_CTAP| // TAG_HID| - /*TAG_U2F|*/ + //TAG_U2F| // TAG_PARSE | // TAG_TIME| // TAG_DUMP| @@ -65,8 +65,6 @@ int main(int argc, char * argv[]) usbhid_init(); printf1(TAG_GEN,"init usb\n"); - nfc_init(); - ctaphid_init(); printf1(TAG_GEN,"init ctaphid\n"); diff --git a/fido2/u2f.c b/fido2/u2f.c index 2d79228..edc4451 100644 --- a/fido2/u2f.c +++ b/fido2/u2f.c @@ -26,24 +26,25 @@ #include "log.h" #include "device.h" #include "wallet.h" +#include "apdu.h" #include APP_CONFIG // void u2f_response_writeback(uint8_t * buf, uint8_t len); -static int16_t u2f_register(struct u2f_register_request * req); -static int16_t u2f_authenticate(struct u2f_authenticate_request * req, uint8_t control); +static int16_t u2f_register(struct u2f_register_request * req, bool fromNFC); +static int16_t u2f_authenticate(struct u2f_authenticate_request * req, uint8_t control, bool fromNFC); int8_t u2f_response_writeback(const uint8_t * buf, uint16_t len); void u2f_reset_response(); static CTAP_RESPONSE * _u2f_resp = NULL; -void u2f_request(struct u2f_request_apdu* req, CTAP_RESPONSE * resp) +void u2f_request_ex(APDU_HEADER *req, uint8_t *payload, uint32_t len, CTAP_RESPONSE * resp, bool fromNFC) { uint16_t rcode = 0; uint64_t t1,t2; - uint32_t len = ((req->LC3) | ((uint32_t)req->LC2 << 8) | ((uint32_t)req->LC1 << 16)); uint8_t byte; + ctap_response_init(resp); u2f_set_writeback_buffer(resp); if (req->cla != 0) @@ -69,7 +70,7 @@ void u2f_request(struct u2f_request_apdu* req, CTAP_RESPONSE * resp) else { t1 = millis(); - rcode = u2f_register((struct u2f_register_request*)req->payload); + rcode = u2f_register((struct u2f_register_request*)payload, fromNFC); t2 = millis(); printf1(TAG_TIME,"u2f_register time: %d ms\n", t2-t1); } @@ -77,7 +78,7 @@ void u2f_request(struct u2f_request_apdu* req, CTAP_RESPONSE * resp) case U2F_AUTHENTICATE: printf1(TAG_U2F, "U2F_AUTHENTICATE\n"); t1 = millis(); - rcode = u2f_authenticate((struct u2f_authenticate_request*)req->payload, req->p1); + rcode = u2f_authenticate((struct u2f_authenticate_request*)payload, req->p1, fromNFC); t2 = millis(); printf1(TAG_TIME,"u2f_authenticate time: %d ms\n", t2-t1); break; @@ -120,6 +121,22 @@ end: 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) +{ + if (len < 5 || !req) + return; + + uint32_t alen = req[4]; + + u2f_request_ex((APDU_HEADER *)req, &req[5], alen, resp, true); +} + +void u2f_request(struct u2f_request_apdu* req, CTAP_RESPONSE * resp) +{ + uint32_t len = ((req->LC3) | ((uint32_t)req->LC2 << 8) | ((uint32_t)req->LC1 << 16)); + + u2f_request_ex((APDU_HEADER *)req, req->payload, len, resp, false); +} int8_t u2f_response_writeback(const uint8_t * buf, uint16_t len) { @@ -196,7 +213,7 @@ static int8_t u2f_appid_eq(struct u2f_key_handle * kh, uint8_t * appid) -static int16_t u2f_authenticate(struct u2f_authenticate_request * req, uint8_t control) +static int16_t u2f_authenticate(struct u2f_authenticate_request * req, uint8_t control, bool fromNFC) { uint8_t up = 1; @@ -228,10 +245,13 @@ static int16_t u2f_authenticate(struct u2f_authenticate_request * req, uint8_t c - if (ctap_user_presence_test() == 0) - { - return U2F_SW_CONDITIONS_NOT_SATISFIED; - } + if(!fromNFC) + { + if (ctap_user_presence_test() == 0) + { + return U2F_SW_CONDITIONS_NOT_SATISFIED; + } + } count = ctap_atomic_count(0); @@ -254,7 +274,7 @@ static int16_t u2f_authenticate(struct u2f_authenticate_request * req, uint8_t c return U2F_SW_NO_ERROR; } -static int16_t u2f_register(struct u2f_register_request * req) +static int16_t u2f_register(struct u2f_register_request * req, bool fromNFC) { uint8_t i[] = {0x0,U2F_EC_FMT_UNCOMPRESSED}; @@ -266,10 +286,13 @@ static int16_t u2f_register(struct u2f_register_request * req) const uint16_t attest_size = attestation_cert_der_size; - if ( ! ctap_user_presence_test()) - { - return U2F_SW_CONDITIONS_NOT_SATISFIED; - } + if(!fromNFC) + { + if ( ! ctap_user_presence_test()) + { + return U2F_SW_CONDITIONS_NOT_SATISFIED; + } + } if ( u2f_new_keypair(&key_handle, req->app, pubkey) == -1) { diff --git a/fido2/u2f.h b/fido2/u2f.h index 94dbbb8..3f4f689 100644 --- a/fido2/u2f.h +++ b/fido2/u2f.h @@ -110,9 +110,14 @@ struct u2f_authenticate_request }; // u2f_request send a U2F message to U2F protocol -// @req U2F message +// @req U2F message 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); + int8_t u2f_response_writeback(const uint8_t * buf, uint16_t len); void u2f_reset_response(); diff --git a/targets/stm32l432/Makefile b/targets/stm32l432/Makefile index 017998f..9df352c 100644 --- a/targets/stm32l432/Makefile +++ b/targets/stm32l432/Makefile @@ -8,7 +8,7 @@ all: $(MAKE) -f application.mk -j8 solo.hex PREFIX=$(PREFIX) DEBUG=$(DEBUG) EXTRA_DEFINES='-DFLASH_ROP=1' all-hacker: - $(MAKE) -f application.mk -j8 solo.hex PREFIX=$(PREFIX) DEBUG=$(DEBUG) EXTRA_DEFINES='-DSOLO_HACKER -DFLASH_ROP=0' + $(MAKE) -f application.mk solo.hex PREFIX=$(PREFIX) DEBUG=$(DEBUG) EXTRA_DEFINES='-DSOLO_HACKER -DFLASH_ROP=0' all-locked: $(MAKE) -f application.mk -j8 solo.hex PREFIX=$(PREFIX) EXTRA_DEFINES='-DFLASH_ROP=2' diff --git a/targets/stm32l432/src/ams.c b/targets/stm32l432/src/ams.c index 1b2c87a..a342513 100644 --- a/targets/stm32l432/src/ams.c +++ b/targets/stm32l432/src/ams.c @@ -28,7 +28,7 @@ static void wait_for_rx() } -static void ams_print_device(AMS_DEVICE * dev) +void ams_print_device(AMS_DEVICE * dev) { printf1(TAG_NFC, "AMS_DEVICE:\r\n"); printf1(TAG_NFC, " io_conf: %02x\r\n",dev->regs.io_conf); @@ -252,7 +252,7 @@ void ams_print_int1(uint8_t int0) printf1(tag,"\r\n"); } -void ams_init() +bool ams_init() { uint8_t block[4]; @@ -273,13 +273,19 @@ void ams_init() ams_write_command(AMS_CMD_DEFAULT); ams_write_command(AMS_CMD_CLEAR_BUFFER); + // check connection + uint8_t productType = ams_read_reg(AMS_REG_PRODUCT_TYPE); + if (!productType) + { + printf1(TAG_NFC,"Have no product type. Connection error."); + return false; + } + printf1(TAG_NFC,"Product type 0x%02x.", productType); + // enable tunneling mode and RF configuration ams_write_reg(AMS_REG_IC_CONF2, AMS_RFCFG_EN | AMS_TUN_MOD); - ams_read_eeprom_block(0, block); - printf1(TAG_NFC,"UID: "); dump_hex1(TAG_NFC,block,4); - - ams_read_eeprom_block(0, block); + ams_read_eeprom_block(AMS_CONFIG_UID_ADDR, block); printf1(TAG_NFC,"UID: "); dump_hex1(TAG_NFC,block,4); ams_read_eeprom_block(AMS_CONFIG_BLOCK0_ADDR, block); @@ -336,5 +342,6 @@ void ams_init() ams_read_eeprom_block(0x7F, block); printf1(TAG_NFC,"conf1: "); dump_hex1(TAG_NFC,block,4); } - + + return true; } diff --git a/targets/stm32l432/src/ams.h b/targets/stm32l432/src/ams.h index 361cb0d..ad3b94f 100644 --- a/targets/stm32l432/src/ams.h +++ b/targets/stm32l432/src/ams.h @@ -1,8 +1,12 @@ +// AS3956 interface +// https://ams.com/as3956 +// https://ams.com/documents/20143/36005/AS3956_DS000546_7-00.pdf + #ifndef _AMS_H_ #define _AMS_H_ #include -#include +#include #include "stm32l4xx_ll_gpio.h" @@ -35,7 +39,7 @@ typedef union #define SELECT() LL_GPIO_ResetOutputPin(SOLO_AMS_CS_PORT,SOLO_AMS_CS_PIN) #define UNSELECT() LL_GPIO_SetOutputPin(SOLO_AMS_CS_PORT,SOLO_AMS_CS_PIN) -void ams_init(); +bool ams_init(); void ams_read_buffer(uint8_t * data, int len); void ams_write_buffer(uint8_t * data, int len); @@ -92,7 +96,14 @@ void ams_write_reg(uint8_t addr, uint8_t tx); #define AMS_REG_BUF2 0x0c #define AMS_BUF_LEN_MASK 0x1f #define AMS_BUF_INVALID 0x80 +#define AMS_REG_BUF1 0x0d +// ... // +#define AMS_REG_PRODUCT_TYPE 0x1c +#define AMS_REG_PRODUCT_SUBTYPE 0x1d +#define AMS_REG_VERSION_MAJOR 0x1e +#define AMS_REG_VERSION_MINOR 0x1f +#define AMS_CONFIG_UID_ADDR 0x00 #define AMS_CONFIG_BLOCK0_ADDR 0x7e #define AMS_CONFIG_BLOCK1_ADDR 0x7f diff --git a/targets/stm32l432/src/app.h b/targets/stm32l432/src/app.h index dadafc1..6afe0bb 100644 --- a/targets/stm32l432/src/app.h +++ b/targets/stm32l432/src/app.h @@ -38,7 +38,7 @@ //#define ENABLE_U2F_EXTENSIONS -// #define ENABLE_U2F +#define ENABLE_U2F #define DISABLE_CTAPHID_PING #define DISABLE_CTAPHID_WINK diff --git a/targets/stm32l432/src/device.c b/targets/stm32l432/src/device.c index 33d9113..b3fd58f 100644 --- a/targets/stm32l432/src/device.c +++ b/targets/stm32l432/src/device.c @@ -48,6 +48,7 @@ uint32_t __90_ms = 0; uint32_t __device_status = 0; uint32_t __last_update = 0; extern PCD_HandleTypeDef hpcd; +bool haveNFC = false; #define IS_BUTTON_PRESSED() (0 == (LL_GPIO_ReadInputPort(SOLO_BUTTON_PORT) & SOLO_BUTTON_PIN)) @@ -118,6 +119,12 @@ void device_init() #else flash_option_bytes_init(0); #endif + printf1(TAG_GEN,"init nfc\n"); + haveNFC = nfc_init(); + if (haveNFC) + printf1(TAG_GEN,"NFC OK.\n"); + else + printf1(TAG_GEN,"NFC not found.\n"); #endif printf1(TAG_GEN,"hello solo\r\n"); @@ -397,7 +404,8 @@ void device_manage() } #endif #ifndef IS_BOOTLOADER - nfc_loop(); + if(haveNFC) + nfc_loop(); #endif } diff --git a/targets/stm32l432/src/nfc.c b/targets/stm32l432/src/nfc.c index ed3e9d8..0b4cf5c 100644 --- a/targets/stm32l432/src/nfc.c +++ b/targets/stm32l432/src/nfc.c @@ -7,6 +7,10 @@ #include "log.h" #include "util.h" #include "device.h" +#include "u2f.h" + +#include "ctap_errors.h" + // Capability container @@ -39,12 +43,68 @@ void nfc_state_init() NFC_STATE.block_num = 1; } -void nfc_init() +bool nfc_init() { - - nfc_state_init(); - ams_init(); + return ams_init(); +} + +void process_int0(uint8_t int0) +{ + +} + +bool ams_wait_for_tx(uint32_t timeout_ms) +{ + uint32_t tstart = millis(); + while (tstart + timeout_ms > millis()) + { + uint8_t int0 = ams_read_reg(AMS_REG_INT0); + if (int0) process_int0(int0); + if (int0 & AMS_INT_TXE) + return true; + + delay(1); + } + + return false; +} + +//bool ams_receive_with_timeout(10, recbuf, sizeof(recbuf), &reclen)) +bool ams_receive_with_timeout(uint32_t timeout_ms, uint8_t * data, int maxlen, int *dlen) +{ + uint8_t buf[32]; + *dlen = 0; + + uint32_t tstart = millis(); + while (tstart + timeout_ms > millis()) + { + uint8_t int0 = ams_read_reg(AMS_REG_INT0); + uint8_t buffer_status2 = ams_read_reg(AMS_REG_BUF2); + + if (buffer_status2 && (int0 & AMS_INT_RXE)) + { + if (buffer_status2 & AMS_BUF_INVALID) + { + printf1(TAG_NFC,"Buffer being updated!\r\n"); + } + else + { + uint8_t len = buffer_status2 & AMS_BUF_LEN_MASK; + ams_read_buffer(buf, len); + printf1(TAG_NFC,">> "); dump_hex1(TAG_NFC, buf, len); + + *dlen = MIN(32, MIN(maxlen, len)); + memcpy(data, buf, *dlen); + + return true; + } + } + + delay(1); + } + + return false; } void nfc_write_frame(uint8_t * data, uint8_t len) @@ -57,6 +117,97 @@ void nfc_write_frame(uint8_t * data, uint8_t len) ams_write_buffer(data,len); ams_write_command(AMS_CMD_TRANSMIT_BUFFER); + printf1(TAG_NFC,"<< "); dump_hex1(TAG_NFC, data, len); +} + +bool nfc_write_response_ex(uint8_t req0, uint8_t * data, uint8_t len, uint16_t resp) +{ + uint8_t res[32]; + + if (len > 32 - 3) + return false; + + res[0] = NFC_CMD_IBLOCK | (req0 & 3); + + if (len && data) + memcpy(&res[1], data, len); + + res[len + 1] = resp >> 8; + res[len + 2] = resp & 0xff; + nfc_write_frame(res, 3 + len); + + return true; +} + +bool nfc_write_response(uint8_t req0, uint16_t resp) +{ + return nfc_write_response_ex(req0, NULL, 0, resp); +} + +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); + + if (len <= 31) + { + uint8_t res[32] = {0}; + res[0] = iBlock; + if (len && data) + memcpy(&res[1], data, len); + nfc_write_frame(res, len + 1); + } else { + do { + // transmit I block + int vlen = MIN(31, len - sendlen); + res[0] = iBlock; + memcpy(&res[1], &data[sendlen], vlen); + + // if not a last block + if (vlen + sendlen < len) + { + res[0] |= 0x10; + } + + // send data + nfc_write_frame(res, vlen + 1); + sendlen += vlen; + + // wait for transmit (32 bytes aprox 2,5ms) + if (!ams_wait_for_tx(10)) + { + printf1(TAG_NFC, "TX timeout. slen: %d \r\n", sendlen); + break; + } + + // if needs to receive R block (not a last block) + if (res[0] & 0x10) + { + uint8_t recbuf[32] = {0}; + int reclen; + if (!ams_receive_with_timeout(100, recbuf, sizeof(recbuf), &reclen)) + { + printf1(TAG_NFC, "R block RX timeout.\r\n"); + break; + } + + if (reclen != 1) + { + printf1(TAG_NFC, "R block length error. len: %d \r\n", reclen); + break; + } + + if (((recbuf[0] & 0x01) == (res[0] & 1)) && ((recbuf[0] & 0xf6) == 0xa2)) + { + printf1(TAG_NFC, "R block error. txdata: %02x rxdata: %02x \r\n", res[0], recbuf[0]); + break; + } + } + + iBlock ^= 0x01; + } while (sendlen < len); + } } int answer_rats(uint8_t parameter) @@ -74,8 +225,8 @@ int answer_rats(uint8_t parameter) else NFC_STATE.max_frame_size = 32; - uint8_t res[3]; - res[0] = 3; + uint8_t res[3 + 11]; + res[0] = sizeof(res); res[1] = 2 | (1<<5); // 2 FSCI == 32 byte frame size, TB is enabled // frame wait time = (256 * 16 / 13.56MHz) * 2^FWI @@ -86,8 +237,11 @@ int answer_rats(uint8_t parameter) // FWI=14, FMT=4949ms (max) res[2] = (12<<4) | (0); // TB (FWI << 4) | (SGTI) - - nfc_write_frame(res,3); + // historical bytes + memcpy(&res[3], (uint8_t *)"SoloKey tap", 11); + + nfc_write_frame(res, sizeof(res)); + ams_wait_for_tx(10); return 0; } @@ -102,37 +256,28 @@ void rblock_acknowledge() // Selects application. Returns 1 if success, 0 otherwise int select_applet(uint8_t * aid, int len) { - if (memcmp(aid,AID_NDEF_TYPE_4,sizeof(AID_NDEF_TYPE_4)) == 0) + if (memcmp(aid,AID_FIDO,sizeof(AID_FIDO)) == 0) { - NFC_STATE.selected_applet = APP_NDEF_TYPE_4; - return 1; - } else if (memcmp(aid,AID_NDEF_MIFARE_TYPE_4,sizeof(AID_NDEF_MIFARE_TYPE_4)) == 0) - { - NFC_STATE.selected_applet = APP_MIFARE_TYPE_4; - return 1; - } else if (memcmp(aid,AID_CAPABILITY_CONTAINER,sizeof(AID_CAPABILITY_CONTAINER)) == 0) - { - NFC_STATE.selected_applet = APP_CAPABILITY_CONTAINER; - return 1; - } else if (memcmp(aid,AID_NDEF_TAG,sizeof(AID_NDEF_TAG)) == 0) - { - NFC_STATE.selected_applet = APP_NDEF_TAG; + NFC_STATE.selected_applet = APP_FIDO; return 1; } - return 0; } void nfc_process_iblock(uint8_t * buf, int len) { - APDU_HEADER * apdu = (APDU_HEADER *)(buf+1); + APDU_HEADER * apdu = (APDU_HEADER *)(buf + 1); uint8_t * payload = buf + 1 + 5; uint8_t plen = apdu->lc; int selected; uint8_t res[32]; + uint32_t t1; - printf1(TAG_NFC,">> "); dump_hex1(TAG_NFC,buf,len); - + CTAP_RESPONSE ctap_resp; + int status; + + printf1(TAG_NFC,">> "); + dump_hex1(TAG_NFC, buf, len); // TODO this needs to be organized better switch(apdu->ins) @@ -150,8 +295,8 @@ void nfc_process_iblock(uint8_t * buf, int len) // NFC_STATE.selected_applet = APP_NDEF_TAG; // // Select NDEF file! // res[0] = NFC_CMD_IBLOCK | (buf[0] & 1); - // res[1] = APDU_STATUS_SUCCESS>>8; - // res[2] = APDU_STATUS_SUCCESS & 0xff; + // res[1] = SW_SUCCESS>>8; + // res[2] = SW_SUCCESS & 0xff; // nfc_write_frame(res, 3); // printf1(TAG_NFC,"<< "); dump_hex1(TAG_NFC,res, 3); // } @@ -160,23 +305,90 @@ void nfc_process_iblock(uint8_t * buf, int len) selected = select_applet(payload, plen); if (selected) { - // block = buf[0] & 1; // block = NFC_STATE.block_num; // block = !block; // NFC_STATE.block_num = block; - res[0] = NFC_CMD_IBLOCK | (buf[0] & 1); - res[1] = APDU_STATUS_SUCCESS>>8; - res[2] = APDU_STATUS_SUCCESS & 0xff; - nfc_write_frame(res, 3); - printf1(TAG_NFC,"<< "); dump_hex1(TAG_NFC,res, 3); - } + nfc_write_response_ex(buf[0], (uint8_t *)"U2F_V2", 6, SW_SUCCESS); + printf1(TAG_NFC, "FIDO applet selected.\r\n"); + } else { - printf1(TAG_NFC, "NOT selected\r\n"); + nfc_write_response(buf[0], SW_FILE_NOT_FOUND); + printf1(TAG_NFC, "NOT selected\r\n"); dump_hex1(TAG_NFC,res, 3); } } break; + + case APDU_FIDO_U2F_VERSION: + printf1(TAG_NFC, "U2F GetVersion command.\r\n"); + + nfc_write_response_ex(buf[0], (uint8_t *)"U2F_V2", 6, SW_SUCCESS); + break; + + case APDU_FIDO_U2F_REGISTER: + printf1(TAG_NFC, "U2F Register command.\r\n"); + + if (plen != 64) + { + printf1(TAG_NFC, "U2F Register request length error. len=%d.\r\n", plen); + nfc_write_response(buf[0], SW_WRONG_LENGTH); + return; + } + + t1 = millis(); + u2f_request_nfc(&buf[1], len, &ctap_resp); + + printf1(TAG_NFC, "U2F resp len: %d\r\n", ctap_resp.length); + printf1(TAG_NFC,"U2F Register processing %d (took %d)\r\n", millis(), millis() - t1); + nfc_write_response_chaining(buf[0], ctap_resp.data, ctap_resp.length); + printf1(TAG_NFC,"U2F Register answered %d (took %d)\r\n", millis(), millis() - t1); + break; + + case APDU_FIDO_U2F_AUTHENTICATE: + printf1(TAG_NFC, "U2F Authenticate command.\r\n"); + + if (plen != 64 + 1 + buf[6 + 64]) + { + delay(5); + printf1(TAG_NFC, "U2F Authenticate request length error. len=%d keyhlen=%d.\r\n", plen, buf[6 + 64]); + nfc_write_response(buf[0], SW_WRONG_LENGTH); + return; + } + + t1 = millis(); + u2f_request_nfc(&buf[1], len, &ctap_resp); + + printf1(TAG_NFC, "U2F resp len: %d\r\n", ctap_resp.length); + printf1(TAG_NFC,"U2F Authenticate processing %d (took %d)\r\n", millis(), millis() - t1); + nfc_write_response_chaining(buf[0], ctap_resp.data, ctap_resp.length); + printf1(TAG_NFC,"U2F Authenticate answered %d (took %d)\r\n", millis(), millis() - t1); + break; + + case APDU_FIDO_NFCCTAP_MSG: + t1 = millis(); + printf1(TAG_NFC, "FIDO2 CTAP message. %d\r\n", t1); + + ctap_response_init(&ctap_resp); + status = ctap_request(payload, plen, &ctap_resp); + printf1(TAG_NFC, "CTAP resp: %d len: %d\r\n", status, ctap_resp.length); + + if (status == CTAP1_ERR_SUCCESS) + { + memmove(&ctap_resp.data[1], &ctap_resp.data[0], ctap_resp.length); + ctap_resp.length += 3; + } else { + ctap_resp.length = 3; + } + ctap_resp.data[0] = status; + ctap_resp.data[ctap_resp.length - 2] = SW_SUCCESS >> 8; + ctap_resp.data[ctap_resp.length - 1] = SW_SUCCESS & 0xff; + + printf1(TAG_NFC,"CTAP processing %d (took %d)\r\n", millis(), millis() - t1); + nfc_write_response_chaining(buf[0], ctap_resp.data, ctap_resp.length); + printf1(TAG_NFC,"CTAP answered %d (took %d)\r\n", millis(), millis() - t1); + break; + case APDU_INS_READ_BINARY: @@ -207,14 +419,15 @@ void nfc_process_iblock(uint8_t * buf, int len) } res[0] = NFC_CMD_IBLOCK | (buf[0] & 1); - res[1+plen] = APDU_STATUS_SUCCESS>>8; - res[2+plen] = APDU_STATUS_SUCCESS & 0xff; + res[1+plen] = SW_SUCCESS>>8; + res[2+plen] = SW_SUCCESS & 0xff; nfc_write_frame(res, 3+plen); printf1(TAG_NFC,"APDU_INS_READ_BINARY\r\n"); printf1(TAG_NFC,"<< "); dump_hex1(TAG_NFC,res, 3+plen); break; default: printf1(TAG_NFC, "Unknown INS %02x\r\n", apdu->ins); + nfc_write_response(buf[0], SW_INS_INVALID); break; } @@ -223,14 +436,65 @@ void nfc_process_iblock(uint8_t * buf, int len) void nfc_process_block(uint8_t * buf, int len) { + static uint8_t ibuf[1024]; + static int ibuflen = 0; + + if (!len) + return; + if (IS_PPSS_CMD(buf[0])) { printf1(TAG_NFC, "NFC_CMD_PPSS\r\n"); } else if (IS_IBLOCK(buf[0])) { - nfc_process_iblock(buf,len); - printf1(TAG_NFC, "NFC_CMD_IBLOCK\r\n"); + if (buf[0] & 0x10) + { + printf1(TAG_NFC, "NFC_CMD_IBLOCK chaining blen=%d len=%d\r\n", ibuflen, len); + if (ibuflen + len > sizeof(ibuf)) + { + printf1(TAG_NFC, "I block memory error! must have %d but have only %d\r\n", ibuflen + len, sizeof(ibuf)); + nfc_write_response(buf[0], SW_INTERNAL_EXCEPTION); + return; + } + + printf1(TAG_NFC,"i> "); + dump_hex1(TAG_NFC, buf, len); + + if (len) + { + memcpy(&ibuf[ibuflen], &buf[1], len - 1); + ibuflen += len - 1; + } + + // send R block + uint8_t rb = NFC_CMD_RBLOCK | NFC_CMD_RBLOCK_ACK | (buf[0] & 3); + nfc_write_frame(&rb, 1); + } else { + if (ibuflen) + { + if (len) + { + memcpy(&ibuf[ibuflen], &buf[1], len - 1); + ibuflen += len - 1; + } + + memmove(&ibuf[1], ibuf, ibuflen); + ibuf[0] = buf[0]; + ibuflen++; + + printf1(TAG_NFC, "NFC_CMD_IBLOCK chaining last block. blen=%d len=%d\r\n", ibuflen, len); + + printf1(TAG_NFC,"i> "); + dump_hex1(TAG_NFC, buf, len); + + nfc_process_iblock(ibuf, ibuflen); + } else { + printf1(TAG_NFC, "NFC_CMD_IBLOCK\r\n"); + nfc_process_iblock(buf, len); + } + ibuflen = 0; + } } else if (IS_RBLOCK(buf[0])) { @@ -273,6 +537,9 @@ void nfc_loop() { t1 = millis(); read_reg_block(&ams); + + process_int0(ams.regs.int0); + // if (memcmp(def,ams.buf,sizeof(AMS_DEVICE)) != 0) // { // printf1(TAG_NFC,"regs: "); dump_hex1(TAG_NFC,ams.buf,sizeof(AMS_DEVICE)); @@ -321,6 +588,7 @@ void nfc_loop() printf1(TAG_NFC, "HLTA/Halt\r\n"); break; case NFC_CMD_RATS: + printf1(TAG_NFC,"RATS\r\n"); t1 = millis(); answer_rats(buf[1]); NFC_STATE.block_num = 1; diff --git a/targets/stm32l432/src/nfc.h b/targets/stm32l432/src/nfc.h index 8a91803..b425b28 100644 --- a/targets/stm32l432/src/nfc.h +++ b/targets/stm32l432/src/nfc.h @@ -2,9 +2,11 @@ #define _NFC_H_ #include +#include +#include "apdu.h" void nfc_loop(); -void nfc_init(); +bool nfc_init(); typedef struct { @@ -18,15 +20,6 @@ typedef struct uint8_t tlv[8]; } __attribute__((packed)) CAPABILITY_CONTAINER; -typedef struct -{ - uint8_t cla; - uint8_t ins; - uint8_t p1; - uint8_t p2; - uint8_t lc; -} __attribute__((packed)) APDU_HEADER; - #define NFC_CMD_REQA 0x26 #define NFC_CMD_WUPA 0x52 #define NFC_CMD_HLTA 0x50 @@ -34,22 +27,22 @@ typedef struct #define NFC_CMD_PPSS 0xd0 #define IS_PPSS_CMD(x) (((x) & 0xf0) == NFC_CMD_PPSS) -#define NFC_CMD_IBLOCK 0x02 -#define IS_IBLOCK(x) (((x) & 0xe2) == NFC_CMD_IBLOCK) -#define NFC_CMD_RBLOCK 0xa2 -#define IS_RBLOCK(x) (((x) & 0xe6) == NFC_CMD_RBLOCK) -#define NFC_CMD_SBLOCK 0xc2 -#define IS_SBLOCK(x) (((x) & 0xc7) == NFC_CMD_SBLOCK) +#define NFC_CMD_IBLOCK 0x00 +#define IS_IBLOCK(x) ( (((x) & 0xc0) == NFC_CMD_IBLOCK) && (((x) & 0x02) == 0x02) ) +#define NFC_CMD_RBLOCK 0x80 +#define NFC_CMD_RBLOCK_ACK 0x20 +#define IS_RBLOCK(x) ( (((x) & 0xc0) == NFC_CMD_RBLOCK) && (((x) & 0x02) == 0x02) ) +#define NFC_CMD_SBLOCK 0xc0 +#define IS_SBLOCK(x) ( (((x) & 0xc0) == NFC_CMD_SBLOCK) && (((x) & 0x02) == 0x02) ) -#define NFC_SBLOCK_DESELECT 0x30 - -#define APDU_INS_SELECT 0xA4 -#define APDU_INS_READ_BINARY 0xB0 +#define NFC_SBLOCK_DESELECT 0x32 +#define NFC_SBLOCK_WTX 0xf2 #define AID_NDEF_TYPE_4 "\xD2\x76\x00\x00\x85\x01\x01" #define AID_NDEF_MIFARE_TYPE_4 "\xD2\x76\x00\x00\x85\x01\x00" #define AID_CAPABILITY_CONTAINER "\xE1\x03" #define AID_NDEF_TAG "\x11\x11" +#define AID_FIDO "\xa0\x00\x00\x06\x47\x2f\x00\x01" typedef enum { @@ -57,8 +50,7 @@ typedef enum APP_MIFARE_TYPE_4, APP_CAPABILITY_CONTAINER, APP_NDEF_TAG, + APP_FIDO, } APPLETS; -#define APDU_STATUS_SUCCESS 0x9000 - #endif