diff --git a/Makefile b/Makefile index 64ff79a..8226890 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,3 @@ - - all: gitsub asn1 build gitsub: diff --git a/ccid.c b/ccid.c index 7d12076..9360a09 100644 --- a/ccid.c +++ b/ccid.c @@ -158,16 +158,35 @@ void seader_ccid_XfrBlockToSlot( uint8_t slot, uint8_t* data, size_t len) { - bool in_scratchpad = (data >= seader_uart->tx_buf && data < seader_uart->tx_buf + SEADER_UART_RX_BUF_SIZE); uint8_t header_len = 2 + 10; + if(len > ((size_t)SEADER_UART_RX_BUF_SIZE - header_len)) { + FURI_LOG_E(TAG, "CCID frame too long: %d", (int)(header_len + len)); + return; + } + + uintptr_t tx_start = (uintptr_t)seader_uart->tx_buf; + uintptr_t tx_end = tx_start + SEADER_UART_RX_BUF_SIZE; + uintptr_t data_addr = (uintptr_t)data; + bool in_scratchpad = false; + if(data_addr >= tx_start + header_len && data_addr <= tx_end) { + size_t available = (size_t)(tx_end - data_addr); + in_scratchpad = len <= available; + } uint8_t* frame; if(in_scratchpad) { frame = data - header_len; + seader_uart->tx_len = header_len + len; + // Shift frame to start of tx_buf for UART worker + if(frame != seader_uart->tx_buf) { + memmove(seader_uart->tx_buf, frame, seader_uart->tx_len); + frame = seader_uart->tx_buf; + } } else { frame = seader_uart->tx_buf; memset(frame, 0, header_len); memcpy(frame + header_len, data, len); + seader_uart->tx_len = header_len + len; } frame[0] = SYNC; @@ -183,7 +202,6 @@ void seader_ccid_XfrBlockToSlot( frame[2 + 8] = 0; frame[2 + 9] = 0; - seader_uart->tx_len = header_len + len; seader_uart->tx_len = seader_add_lrc(frame, seader_uart->tx_len); /* diff --git a/sam_api.c b/sam_api.c index 0804f51..42d3da4 100644 --- a/sam_api.c +++ b/sam_api.c @@ -185,16 +185,28 @@ bool seader_send_apdu( bool extended = seader_uart->T == 1; uint8_t header_len = extended ? 7 : 5; - if(header_len + payloadLen > SEADER_UART_RX_BUF_SIZE) { + // Must account for MAX_FRAME_HEADERS headroom in scratchpad mode + if(MAX_FRAME_HEADERS + header_len + payloadLen > SEADER_UART_RX_BUF_SIZE) { FURI_LOG_E(TAG, "Cannot send message, too long: %d", header_len + payloadLen); return false; } uint8_t length = header_len + payloadLen; uint8_t* apdu; + bool must_free = false; + uintptr_t tx_start = (uintptr_t)seader_uart->tx_buf; + uintptr_t tx_end = tx_start + SEADER_UART_RX_BUF_SIZE; + uintptr_t payload_addr = (uintptr_t)payload; + bool scratchpad_payload = false; - if(in_scratchpad) { - apdu = payload - header_len; + // in_scratchpad is only valid when the full payload range is inside tx_buf. + if(in_scratchpad && payload_addr >= tx_start + header_len && payload_addr <= tx_end) { + size_t available = (size_t)(tx_end - payload_addr); + scratchpad_payload = payloadLen <= available; + } + + if(scratchpad_payload) { + apdu = (uint8_t*)(payload_addr - header_len); } else { apdu = malloc(length); if(!apdu) { @@ -202,6 +214,7 @@ bool seader_send_apdu( return false; } memcpy(apdu + header_len, payload, payloadLen); + must_free = true; } apdu[0] = CLA; @@ -225,7 +238,7 @@ bool seader_send_apdu( seader_ccid_XfrBlock(seader_uart, apdu, length); } - if(!in_scratchpad) { + if(must_free) { free(apdu); } @@ -257,9 +270,41 @@ void seader_send_payload( uint8_t* scratchpad = seader_uart->tx_buf + MAX_FRAME_HEADERS; size_t scratchpad_size = SEADER_UART_RX_BUF_SIZE - MAX_FRAME_HEADERS; + size_t max_der_len = UINT8_MAX - ASN1_PREFIX; + uint8_t* payload_buf = scratchpad; + bool payload_in_scratchpad = true; asn_enc_rval_t er = - der_encode_to_buffer(&asn_DEF_Payload, payload, scratchpad + ASN1_PREFIX, scratchpad_size - ASN1_PREFIX); + der_encode_to_buffer( + &asn_DEF_Payload, payload, scratchpad + ASN1_PREFIX, scratchpad_size - ASN1_PREFIX); + + if(er.encoded < 0 || ((size_t)er.encoded + ASN1_PREFIX) > UINT8_MAX) { + payload_buf = malloc(ASN1_PREFIX + max_der_len); + if(!payload_buf) { + FURI_LOG_E(TAG, "Failed to allocate DER fallback buffer"); + return; + } + payload_in_scratchpad = false; + + er = der_encode_to_buffer(&asn_DEF_Payload, payload, payload_buf + ASN1_PREFIX, max_der_len); + } + + if(er.encoded < 0) { + FURI_LOG_E(TAG, "Failed to encode payload"); + if(!payload_in_scratchpad) { + free(payload_buf); + } + return; + } + + size_t apdu_payload_len = ASN1_PREFIX + (size_t)er.encoded; + if(apdu_payload_len > UINT8_MAX) { + FURI_LOG_E(TAG, "Encoded payload too large for APDU: %d", (int)apdu_payload_len); + if(!payload_in_scratchpad) { + free(payload_buf); + } + return; + } #ifdef ASN1_DEBUG if(er.encoded > -1) { @@ -277,14 +322,26 @@ void seader_send_payload( #endif //0xa0, 0xda, 0x02, 0x63, 0x00, 0x00, 0x0a, //0x44, 0x0a, 0x44, 0x00, 0x00, 0x00, 0xa0, 0x02, 0x96, 0x00 - scratchpad[0] = from; - scratchpad[1] = to; - scratchpad[2] = replyTo; - scratchpad[3] = 0x00; - scratchpad[4] = 0x00; - scratchpad[5] = 0x00; + payload_buf[0] = from; + payload_buf[1] = to; + payload_buf[2] = replyTo; + payload_buf[3] = 0x00; + payload_buf[4] = 0x00; + payload_buf[5] = 0x00; - seader_send_apdu(seader, 0xA0, 0xDA, 0x02, 0x63, scratchpad, 6 + er.encoded, true); + seader_send_apdu( + seader, + 0xA0, + 0xDA, + 0x02, + 0x63, + payload_buf, + (uint8_t)apdu_payload_len, + payload_in_scratchpad); + + if(!payload_in_scratchpad) { + free(payload_buf); + } } void seader_send_process_config_card(Seader* seader) { diff --git a/seader_bridge.h b/seader_bridge.h index 32eefa8..df7dec9 100644 --- a/seader_bridge.h +++ b/seader_bridge.h @@ -10,7 +10,7 @@ #include // https://ww1.microchip.com/downloads/en/DeviceDoc/00001561C.pdf -#define SEADER_UART_RX_BUF_SIZE (261) +#define SEADER_UART_RX_BUF_SIZE (300) typedef struct { uint8_t uart_ch; diff --git a/t_1.c b/t_1.c index 7009691..d87a6c2 100644 --- a/t_1.c +++ b/t_1.c @@ -125,7 +125,8 @@ void seader_send_t1_scratchpad(SeaderUartBridge* seader_uart, uint8_t PCB, uint8 void seader_send_t1(SeaderUartBridge* seader_uart, uint8_t* apdu, size_t len) { uint8_t ifsc = seader_uart->IFSC; - bool in_scratchpad = (apdu >= seader_uart->tx_buf && apdu < seader_uart->tx_buf + SEADER_UART_RX_BUF_SIZE); + bool in_scratchpad = (apdu >= seader_uart->tx_buf + 3 && + apdu < seader_uart->tx_buf + SEADER_UART_RX_BUF_SIZE); if(len > ifsc) { if(seader_t_1_tx_buffer == NULL) {