diff --git a/.all-contributorsrc b/.all-contributorsrc index aed6148..253fb36 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -168,6 +168,16 @@ "infra", "tool" ] + }, + { + "login": "kimusan", + "name": "Kim Schulz", + "avatar_url": "https://avatars1.githubusercontent.com/u/1150049?v=4", + "profile": "http://www.schulz.dk", + "contributions": [ + "business", + "ideas" + ] } ], "contributorsPerLine": 7, diff --git a/README.md b/README.md index ba13ea7..a86fb7b 100644 --- a/README.md +++ b/README.md @@ -134,6 +134,7 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d Piotr Esden-Tempski
Piotr Esden-Tempski

💼 f.m3hm00d
f.m3hm00d

📖 Richard Hughes
Richard Hughes

🤔 💻 🚇 🔧 + Kim Schulz
Kim Schulz

💼 🤔 @@ -167,7 +168,7 @@ You can buy Solo, Solo Tap, and Solo for Hackers at [solokeys.com](https://solok
[![License](https://img.shields.io/github/license/solokeys/solo.svg)](https://github.com/solokeys/solo/blob/master/LICENSE) -[![All Contributors](https://img.shields.io/badge/all_contributors-17-orange.svg?style=flat-square)](#contributors) +[![All Contributors](https://img.shields.io/badge/all_contributors-18-orange.svg?style=flat-square)](#contributors) [![Build Status](https://travis-ci.com/solokeys/solo.svg?branch=master)](https://travis-ci.com/solokeys/solo) [![Discourse Users](https://img.shields.io/discourse/https/discourse.solokeys.com/users.svg)](https://discourse.solokeys.com) [![Keybase Chat](https://img.shields.io/badge/chat-on%20keybase-brightgreen.svg)](https://keybase.io/team/solokeys.public) diff --git a/fido2/apdu.c b/fido2/apdu.c index df89099..3d5bf49 100644 --- a/fido2/apdu.c +++ b/fido2/apdu.c @@ -13,7 +13,7 @@ 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->cla = hapdu->cla & 0xef; // mask chaining bit if any apdu->ins = hapdu->ins; apdu->p1 = hapdu->p1; apdu->p2 = hapdu->p2; diff --git a/fido2/apdu.h b/fido2/apdu.h index 7ce8477..420fea6 100644 --- a/fido2/apdu.h +++ b/fido2/apdu.h @@ -42,6 +42,10 @@ extern int apdu_decode(uint8_t *data, size_t len, APDU_STRUCT *apdu); #define APDU_FIDO_U2F_AUTHENTICATE 0x02 #define APDU_FIDO_U2F_VERSION 0x03 #define APDU_FIDO_NFCCTAP_MSG 0x10 +#define APDU_FIDO_U2F_VENDOR_FIRST 0xc0 // First vendor defined command +#define APDU_FIDO_U2F_VENDOR_LAST 0xff // Last vendor defined command +#define APDU_SOLO_RESET 0xee + #define APDU_INS_SELECT 0xA4 #define APDU_INS_READ_BINARY 0xB0 #define APDU_GET_RESPONSE 0xC0 diff --git a/fido2/ctap.c b/fido2/ctap.c index 8edf591..f721990 100644 --- a/fido2/ctap.c +++ b/fido2/ctap.c @@ -437,7 +437,19 @@ static unsigned int get_credential_id_size(CTAP_credentialDescriptor * cred) static int ctap2_user_presence_test() { device_set_status(CTAPHID_STATUS_UPNEEDED); - return ctap_user_presence_test(CTAP2_UP_DELAY_MS); + int ret = ctap_user_presence_test(CTAP2_UP_DELAY_MS); + if ( ret > 0 ) + { + return CTAP1_ERR_SUCCESS; + } + else if (ret < 0) + { + return CTAP2_ERR_KEEPALIVE_CANCEL; + } + else + { + return CTAP2_ERR_ACTION_TIMEOUT; + } } static int ctap_make_auth_data(struct rpId * rp, CborEncoder * map, uint8_t * auth_data_buf, uint32_t * len, CTAP_credInfo * credInfo) @@ -470,19 +482,11 @@ static int ctap_make_auth_data(struct rpId * rp, CborEncoder * map, uint8_t * au int but; but = ctap2_user_presence_test(CTAP2_UP_DELAY_MS); - - if (!but) - { - return CTAP2_ERR_OPERATION_DENIED; - } - else if (but < 0) // Cancel - { - return CTAP2_ERR_KEEPALIVE_CANCEL; - } + check_retr(but); device_set_status(CTAPHID_STATUS_PROCESSING); - authData->head.flags = (but << 0); + authData->head.flags = (1 << 0); // User presence authData->head.flags |= (ctap_is_pin_set() << 2); @@ -707,10 +711,7 @@ uint8_t ctap_make_credential(CborEncoder * encoder, uint8_t * request, int lengt } if (MC.pinAuthEmpty) { - if (!ctap2_user_presence_test(CTAP2_UP_DELAY_MS)) - { - return CTAP2_ERR_OPERATION_DENIED; - } + check_retr( ctap2_user_presence_test(CTAP2_UP_DELAY_MS) ); return ctap_is_pin_set() == 1 ? CTAP2_ERR_PIN_AUTH_INVALID : CTAP2_ERR_PIN_NOT_SET; } if ((MC.paramsParsed & MC_requiredMask) != MC_requiredMask) @@ -1143,10 +1144,7 @@ uint8_t ctap_get_assertion(CborEncoder * encoder, uint8_t * request, int length) if (GA.pinAuthEmpty) { - if (!ctap2_user_presence_test(CTAP2_UP_DELAY_MS)) - { - return CTAP2_ERR_OPERATION_DENIED; - } + check_retr( ctap2_user_presence_test(CTAP2_UP_DELAY_MS) ); return ctap_is_pin_set() == 1 ? CTAP2_ERR_PIN_AUTH_INVALID : CTAP2_ERR_PIN_NOT_SET; } if (GA.pinAuthPresent) @@ -1656,14 +1654,11 @@ uint8_t ctap_request(uint8_t * pkt_raw, int length, CTAP_RESPONSE * resp) break; case CTAP_RESET: printf1(TAG_CTAP,"CTAP_RESET\n"); - if (ctap2_user_presence_test(CTAP2_UP_DELAY_MS)) + status = ctap2_user_presence_test(CTAP2_UP_DELAY_MS); + if (status == CTAP1_ERR_SUCCESS) { ctap_reset(); } - else - { - status = CTAP2_ERR_OPERATION_DENIED; - } break; case GET_NEXT_ASSERTION: printf1(TAG_CTAP,"CTAP_NEXT_ASSERTION\n"); @@ -1685,7 +1680,7 @@ uint8_t ctap_request(uint8_t * pkt_raw, int length, CTAP_RESPONSE * resp) break; default: status = CTAP1_ERR_INVALID_COMMAND; - printf2(TAG_ERR,"error, invalid cmd: %x\n", cmd); + printf2(TAG_ERR,"error, invalid cmd: 0x%02x\n", cmd); } done: diff --git a/fido2/ctap.h b/fido2/ctap.h index 51a5c11..6bfdf57 100644 --- a/fido2/ctap.h +++ b/fido2/ctap.h @@ -131,7 +131,7 @@ #define PIN_LOCKOUT_ATTEMPTS 8 // Number of attempts total #define PIN_BOOT_ATTEMPTS 3 // number of attempts per boot -#define CTAP2_UP_DELAY_MS 5000 +#define CTAP2_UP_DELAY_MS 29000 typedef struct { diff --git a/fido2/ctap_errors.h b/fido2/ctap_errors.h index a749651..fc2f257 100644 --- a/fido2/ctap_errors.h +++ b/fido2/ctap_errors.h @@ -49,6 +49,7 @@ #define CTAP2_ERR_PIN_POLICY_VIOLATION 0x37 #define CTAP2_ERR_PIN_TOKEN_EXPIRED 0x38 #define CTAP2_ERR_REQUEST_TOO_LARGE 0x39 +#define CTAP2_ERR_ACTION_TIMEOUT 0x3A #define CTAP1_ERR_OTHER 0x7F #define CTAP2_ERR_SPEC_LAST 0xDF #define CTAP2_ERR_EXTENSION_FIRST 0xE0 diff --git a/fido2/device.h b/fido2/device.h index 0c11fe8..d440ca6 100644 --- a/fido2/device.h +++ b/fido2/device.h @@ -30,6 +30,7 @@ void main_loop_delay(); void heartbeat(); +void device_reboot(); void authenticator_read_state(AuthenticatorState * ); diff --git a/pc/device.c b/pc/device.c index 0944254..cf91610 100644 --- a/pc/device.c +++ b/pc/device.c @@ -43,7 +43,11 @@ void device_set_status(uint32_t status) __device_status = status; } - +void device_reboot() +{ + printf1(TAG_RED, "REBOOT command recieved!\r\n"); + exit(100); +} int udp_server() { diff --git a/targets/stm32l432/src/device.c b/targets/stm32l432/src/device.c index 49bbfe7..e6f14e3 100644 --- a/targets/stm32l432/src/device.c +++ b/targets/stm32l432/src/device.c @@ -55,11 +55,43 @@ static int is_physical_button_pressed() static int is_touch_button_pressed() { - return tsc_read_button(0) || tsc_read_button(1); + int is_pressed = (tsc_read_button(0) || tsc_read_button(1)); +#ifndef IS_BOOTLOADER + if (is_pressed) + { + // delay for debounce, and longer than polling timer period. + delay(95); + return (tsc_read_button(0) || tsc_read_button(1)); + } +#endif + return is_pressed; } int (*IS_BUTTON_PRESSED)() = is_physical_button_pressed; +static void edge_detect_touch_button() +{ + static uint8_t last_touch = 0; + uint8_t current_touch = 0; + if (is_touch_button_pressed == IS_BUTTON_PRESSED) + { + current_touch = (tsc_read_button(0) || tsc_read_button(1)); + + // 1 sample per 25 ms + if ((millis() - __last_button_bounce_time) > 25) + { + // Detect "touch / rising edge" + if (!last_touch && current_touch) + { + __last_button_press_time = millis(); + } + __last_button_bounce_time = millis(); + last_touch = current_touch; + } + } + +} + void request_from_nfc(bool request_active) { _RequestComeFromNFC = request_active; } @@ -78,19 +110,7 @@ void TIM6_DAC_IRQHandler() } } - - if (is_touch_button_pressed == IS_BUTTON_PRESSED) - { - if (IS_BUTTON_PRESSED()) - { - // Only allow 1 press per 25 ms. - if ((millis() - __last_button_bounce_time) > 25) - { - __last_button_press_time = millis(); - } - __last_button_bounce_time = millis(); - } - } + edge_detect_touch_button(); #ifndef IS_BOOTLOADER // NFC sending WTX if needs @@ -142,7 +162,6 @@ void device_set_status(uint32_t status) int device_is_button_pressed() { - return IS_BUTTON_PRESSED(); } diff --git a/targets/stm32l432/src/nfc.c b/targets/stm32l432/src/nfc.c index 1d935b0..6a3cab3 100644 --- a/targets/stm32l432/src/nfc.c +++ b/targets/stm32l432/src/nfc.c @@ -15,8 +15,9 @@ #define IS_IRQ_ACTIVE() (1 == (LL_GPIO_ReadInputPort(SOLO_AMS_IRQ_PORT) & SOLO_AMS_IRQ_PIN)) // chain buffer for 61XX responses -static uint8_t resp_chain_buffer[2048] = {0}; -static size_t resp_chain_buffer_len = 0; +static uint8_t chain_buffer[2048] = {0}; +static size_t chain_buffer_len = 0; +static bool chain_buffer_tx = false; uint8_t p14443_block_offset(uint8_t pcb) { uint8_t offset = 1; @@ -298,7 +299,8 @@ void append_get_response(uint8_t *data, size_t rest_len) void nfc_write_response_chaining(uint8_t req0, uint8_t * data, int len, bool extapdu) { - resp_chain_buffer_len = 0; + chain_buffer_len = 0; + chain_buffer_tx = true; // if we dont need to break data to parts that need to exchange via GET RESPONSE command (ISO 7816-4 7.1.3) if (len <= 255 || extapdu) @@ -306,16 +308,16 @@ void nfc_write_response_chaining(uint8_t req0, uint8_t * data, int len, bool ext nfc_write_response_chaining_plain(req0, data, len); } else { size_t pcklen = MIN(253, len); - resp_chain_buffer_len = len - pcklen; - printf1(TAG_NFC, "61XX chaining %d/%d.\r\n", pcklen, resp_chain_buffer_len); + chain_buffer_len = len - pcklen; + printf1(TAG_NFC, "61XX chaining %d/%d.\r\n", pcklen, chain_buffer_len); - memmove(resp_chain_buffer, data, pcklen); - append_get_response(&resp_chain_buffer[pcklen], resp_chain_buffer_len); + memmove(chain_buffer, data, pcklen); + append_get_response(&chain_buffer[pcklen], chain_buffer_len); - nfc_write_response_chaining_plain(req0, resp_chain_buffer, pcklen + 2); // 2 for 61XX + nfc_write_response_chaining_plain(req0, chain_buffer, pcklen + 2); // 2 for 61XX // put the rest data into chain buffer - memmove(resp_chain_buffer, &data[pcklen], resp_chain_buffer_len); + memmove(chain_buffer, &data[pcklen], chain_buffer_len); } } @@ -518,50 +520,39 @@ int select_applet(uint8_t * aid, int len) return APP_NOTHING; } -void nfc_process_iblock(uint8_t * buf, int len) +void apdu_process(uint8_t buf0, uint8_t *apduptr, APDU_STRUCT *apdu) { int selected; CTAP_RESPONSE ctap_resp; int status; uint16_t reslen; - 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); + if (apdu->cla != 0x00 && apdu->cla != 0x80) { + printf1(TAG_NFC, "Unknown CLA %02x\r\n", apdu->cla); + nfc_write_response(buf0, SW_CLA_INVALID); return; } // TODO this needs to be organized better - switch(apdu.ins) + switch(apdu->ins) { // ISO 7816. 7.1 GET RESPONSE command case APDU_GET_RESPONSE: - if (apdu.p1 != 0x00 || apdu.p2 != 0x00) + if (apdu->p1 != 0x00 || apdu->p2 != 0x00) { - nfc_write_response(buf[0], SW_INCORRECT_P1P2); + nfc_write_response(buf0, SW_INCORRECT_P1P2); printf1(TAG_NFC, "P1 or P2 error\r\n"); return; } // too many bytes needs. 0x00 and 0x100 - any length - if (apdu.le != 0 && apdu.le != 0x100 && apdu.le > resp_chain_buffer_len) + if (apdu->le != 0 && apdu->le != 0x100 && apdu->le > chain_buffer_len) { uint16_t wlresp = SW_WRONG_LENGTH; // here can be 6700, 6C00, 6FXX. but the most standard way - 67XX or 6700 - if (resp_chain_buffer_len <= 0xff) - wlresp += resp_chain_buffer_len & 0xff; - nfc_write_response(buf[0], wlresp); + if (chain_buffer_len <= 0xff) + wlresp += chain_buffer_len & 0xff; + nfc_write_response(buf0, wlresp); printf1(TAG_NFC, "buffer length less than requesteds\r\n"); return; } @@ -569,28 +560,28 @@ void nfc_process_iblock(uint8_t * buf, int len) // create temporary packet uint8_t pck[255] = {0}; size_t pcklen = 253; - if (apdu.le) - pcklen = apdu.le; - if (pcklen > resp_chain_buffer_len) - pcklen = resp_chain_buffer_len; + if (apdu->le) + pcklen = apdu->le; + if (pcklen > chain_buffer_len) + pcklen = chain_buffer_len; - printf1(TAG_NFC, "GET RESPONSE. pck len: %d buffer len: %d\r\n", pcklen, resp_chain_buffer_len); + printf1(TAG_NFC, "GET RESPONSE. pck len: %d buffer len: %d\r\n", pcklen, chain_buffer_len); // create packet and add 61XX there if we have another portion(s) of data - memmove(pck, resp_chain_buffer, pcklen); + memmove(pck, chain_buffer, pcklen); size_t dlen = 0; - if (resp_chain_buffer_len - pcklen) + if (chain_buffer_len - pcklen) { - append_get_response(&pck[pcklen], resp_chain_buffer_len - pcklen); + append_get_response(&pck[pcklen], chain_buffer_len - pcklen); dlen = 2; } // send - nfc_write_response_chaining_plain(buf[0], pck, pcklen + dlen); // dlen for 61XX + nfc_write_response_chaining_plain(buf0, pck, pcklen + dlen); // dlen for 61XX // shift the buffer - resp_chain_buffer_len -= pcklen; - memmove(resp_chain_buffer, &resp_chain_buffer[pcklen], resp_chain_buffer_len); + chain_buffer_len -= pcklen; + memmove(chain_buffer, &chain_buffer[pcklen], chain_buffer_len); break; case APDU_INS_SELECT: @@ -608,49 +599,49 @@ void nfc_process_iblock(uint8_t * buf, int len) // } // else { - selected = select_applet(apdu.data, apdu.lc); + selected = select_applet(apdu->data, apdu->lc); if (selected == APP_FIDO) { - nfc_write_response_ex(buf[0], (uint8_t *)"U2F_V2", 6, SW_SUCCESS); + nfc_write_response_ex(buf0, (uint8_t *)"U2F_V2", 6, SW_SUCCESS); printf1(TAG_NFC, "FIDO applet selected.\r\n"); } else if (selected != APP_NOTHING) { - nfc_write_response(buf[0], SW_SUCCESS); + nfc_write_response(buf0, SW_SUCCESS); printf1(TAG_NFC, "SELECTED %d\r\n", selected); } else { - nfc_write_response(buf[0], SW_FILE_NOT_FOUND); - printf1(TAG_NFC, "NOT selected "); dump_hex1(TAG_NFC, apdu.data, apdu.lc); + nfc_write_response(buf0, SW_FILE_NOT_FOUND); + printf1(TAG_NFC, "NOT selected "); dump_hex1(TAG_NFC, apdu->data, apdu->lc); } } break; case APDU_FIDO_U2F_VERSION: if (NFC_STATE.selected_applet != APP_FIDO) { - nfc_write_response(buf[0], SW_INS_INVALID); + nfc_write_response(buf0, SW_INS_INVALID); break; } printf1(TAG_NFC, "U2F GetVersion command.\r\n"); - u2f_request_nfc(&buf[block_offset], apdu.data, apdu.lc, &ctap_resp); - nfc_write_response_chaining(buf[0], ctap_resp.data, ctap_resp.length, apdu.extended_apdu); + u2f_request_nfc(apduptr, apdu->data, apdu->lc, &ctap_resp); + nfc_write_response_chaining(buf0, ctap_resp.data, ctap_resp.length, apdu->extended_apdu); break; case APDU_FIDO_U2F_REGISTER: if (NFC_STATE.selected_applet != APP_FIDO) { - nfc_write_response(buf[0], SW_INS_INVALID); + nfc_write_response(buf0, SW_INS_INVALID); break; } printf1(TAG_NFC, "U2F Register command.\r\n"); - if (apdu.lc != 64) + if (apdu->lc != 64) { - printf1(TAG_NFC, "U2F Register request length error. len=%d.\r\n", apdu.lc); - nfc_write_response(buf[0], SW_WRONG_LENGTH); + printf1(TAG_NFC, "U2F Register request length error. len=%d.\r\n", apdu->lc); + nfc_write_response(buf0, SW_WRONG_LENGTH); return; } @@ -661,49 +652,49 @@ void nfc_process_iblock(uint8_t * buf, int len) // SystemClock_Config_LF32(); // delay(300); 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); + u2f_request_nfc(apduptr, 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, apdu.extended_apdu); + nfc_write_response_chaining(buf0, ctap_resp.data, ctap_resp.length, apdu->extended_apdu); printf1(TAG_NFC,"U2F Register answered %d (took %d)\r\n", millis(), timestamp()); break; case APDU_FIDO_U2F_AUTHENTICATE: if (NFC_STATE.selected_applet != APP_FIDO) { - nfc_write_response(buf[0], SW_INS_INVALID); + nfc_write_response(buf0, SW_INS_INVALID); break; } printf1(TAG_NFC, "U2F Authenticate command.\r\n"); - if (apdu.lc != 64 + 1 + apdu.data[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", apdu.lc, apdu.data[64]); - nfc_write_response(buf[0], SW_WRONG_LENGTH); + printf1(TAG_NFC, "U2F Authenticate request length error. len=%d keyhlen=%d.\r\n", apdu->lc, apdu->data[64]); + nfc_write_response(buf0, SW_WRONG_LENGTH); return; } timestamp(); // WTX_on(WTX_TIME_DEFAULT); - u2f_request_nfc(&buf[block_offset], apdu.data, apdu.lc, &ctap_resp); + u2f_request_nfc(apduptr, apdu->data, apdu->lc, &ctap_resp); // if (!WTX_off()) // return; printf1(TAG_NFC, "U2F resp len: %d\r\n", ctap_resp.length); printf1(TAG_NFC,"U2F Authenticate processing %d (took %d)\r\n", millis(), timestamp()); - nfc_write_response_chaining(buf[0], ctap_resp.data, ctap_resp.length, apdu.extended_apdu); + nfc_write_response_chaining(buf0, ctap_resp.data, ctap_resp.length, apdu->extended_apdu); printf1(TAG_NFC,"U2F Authenticate answered %d (took %d)\r\n", millis(), timestamp); break; case APDU_FIDO_NFCCTAP_MSG: if (NFC_STATE.selected_applet != APP_FIDO) { - nfc_write_response(buf[0], SW_INS_INVALID); + nfc_write_response(buf0, SW_INS_INVALID); return; } @@ -712,7 +703,7 @@ void nfc_process_iblock(uint8_t * buf, int len) // WTX_on(WTX_TIME_DEFAULT); request_from_nfc(true); ctap_response_init(&ctap_resp); - status = ctap_request(apdu.data, apdu.lc, &ctap_resp); + status = ctap_request(apdu->data, apdu->lc, &ctap_resp); request_from_nfc(false); // if (!WTX_off()) // return; @@ -731,42 +722,101 @@ void nfc_process_iblock(uint8_t * buf, int len) ctap_resp.data[ctap_resp.length - 1] = SW_SUCCESS & 0xff; printf1(TAG_NFC,"CTAP processing %d (took %d)\r\n", millis(), timestamp()); - nfc_write_response_chaining(buf[0], ctap_resp.data, ctap_resp.length, apdu.extended_apdu); + nfc_write_response_chaining(buf0, ctap_resp.data, ctap_resp.length, apdu->extended_apdu); printf1(TAG_NFC,"CTAP answered %d (took %d)\r\n", millis(), timestamp()); break; case APDU_INS_READ_BINARY: // response length - reslen = apdu.le & 0xffff; + reslen = apdu->le & 0xffff; switch(NFC_STATE.selected_applet) { case APP_CAPABILITY_CONTAINER: printf1(TAG_NFC,"APP_CAPABILITY_CONTAINER\r\n"); if (reslen == 0 || reslen > sizeof(NFC_CC)) reslen = sizeof(NFC_CC); - nfc_write_response_ex(buf[0], (uint8_t *)&NFC_CC, reslen, SW_SUCCESS); + nfc_write_response_ex(buf0, (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 (reslen == 0 || reslen > sizeof(NDEF_SAMPLE) - 1) reslen = sizeof(NDEF_SAMPLE) - 1; - nfc_write_response_ex(buf[0], NDEF_SAMPLE, reslen, SW_SUCCESS); + nfc_write_response_ex(buf0, NDEF_SAMPLE, reslen, SW_SUCCESS); ams_wait_for_tx(10); break; default: - nfc_write_response(buf[0], SW_FILE_NOT_FOUND); + nfc_write_response(buf0, SW_FILE_NOT_FOUND); printf1(TAG_ERR, "No binary applet selected!\r\n"); return; break; } break; + case APDU_SOLO_RESET: + if (apdu->lc == 4 && !memcmp(apdu->data, "\x12\x56\xab\xf0", 4)) { + printf1(TAG_NFC, "Reset...\r\n"); + nfc_write_response(buf0, SW_SUCCESS); + delay(20); + device_reboot(); + while(1); + } else { + printf1(TAG_NFC, "Reset FAIL\r\n"); + nfc_write_response(buf0, SW_INS_INVALID); + } + break; + default: - printf1(TAG_NFC, "Unknown INS %02x\r\n", apdu.ins); - nfc_write_response(buf[0], SW_INS_INVALID); + printf1(TAG_NFC, "Unknown INS %02x\r\n", apdu->ins); + nfc_write_response(buf0, SW_INS_INVALID); break; } +} + +void nfc_process_iblock(uint8_t * buf, int len) +{ + uint8_t block_offset = p14443_block_offset(buf[0]); + + // clear tx chain buffer if we have some other command than GET RESPONSE + if (chain_buffer_tx && buf[block_offset + 1] != APDU_GET_RESPONSE) { + chain_buffer_len = 0; + chain_buffer_tx = false; + } + + 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); + + // APDU level chaining. ISO7816-4, 5.1.1. class byte + if (!chain_buffer_tx && buf[block_offset] & 0x10) { + + if (chain_buffer_len + len > sizeof(chain_buffer)) { + nfc_write_response(buf[0], SW_WRONG_LENGTH); + return; + } + + memmove(&chain_buffer[chain_buffer_len], apdu.data, apdu.lc); + chain_buffer_len += apdu.lc; + nfc_write_response(buf[0], SW_SUCCESS); + printf1(TAG_NFC, "APDU chaining ok. %d/%d\r\n", apdu.lc, chain_buffer_len); + return; + } + + // if we have ISO 7816 APDU chain - move there all the data + if (!chain_buffer_tx && chain_buffer_len > 0) { + memmove(&apdu.data[chain_buffer_len], apdu.data, apdu.lc); + memmove(apdu.data, chain_buffer, chain_buffer_len); + apdu.lc += chain_buffer_len; // here apdu struct does not match with memory! + printf1(TAG_NFC, "APDU chaining merge. %d/%d\r\n", chain_buffer_len, apdu.lc); + } + + + apdu_process(buf[0], &buf[block_offset], &apdu); printf1(TAG_NFC,"prev.Iblock: "); dump_hex1(TAG_NFC, buf, len); @@ -803,7 +853,7 @@ void nfc_process_block(uint8_t * buf, unsigned int len) 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); + printf1(TAG_NFC_APDU, "NFC_CMD_IBLOCK chaining blen=%d len=%d offs=%d\r\n", ibuflen, len, block_offset); 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)); @@ -836,14 +886,15 @@ void nfc_process_block(uint8_t * buf, unsigned int len) 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); + printf1(TAG_NFC_APDU, "NFC_CMD_IBLOCK chaining last block. blen=%d len=%d offset=%d\r\n", ibuflen, len, block_offset); printf1(TAG_NFC_APDU,"i> "); dump_hex1(TAG_NFC_APDU, buf, len); nfc_process_iblock(ibuf, ibuflen); } else { - nfc_process_iblock(buf, len); + memcpy(ibuf, buf, len); // because buf only 32b + nfc_process_iblock(ibuf, len); } clear_ibuf(); }