| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219 |
- #include "t_1.h"
- #define TAG "Seader:T=1"
- // http://www.sat-digest.com/SatXpress/SmartCard/ISO7816-4.htm
- /* I know my T=1 is terrible, but I'm also only targetting one specific 'card' */
- #define MORE_BIT 0x20
- #define IFSD_VALUE 0xfe
- #define IFSC_VALUE 0xfe // Fom the SAM ATR
- #define R_BLOCK 0x80
- #define R_SEQUENCE_NUMBER_MASK 0x10
- // TODO: T1 struct
- uint8_t NAD = 0x00;
- uint8_t dPCB = 0x40; // Init to 0x40 so first call to next_pcb will return 0x00
- uint8_t cPCB = 0x00; // Init to 0x40 so first call to next_pcb will return 0x00
- uint8_t seader_next_dpcb() {
- uint8_t next_pcb = dPCB ^ 0x40;
- //FURI_LOG_D(TAG, "dPCB was: %02X, current dPCB: %02X", dPCB, next_pcb);
- dPCB = next_pcb;
- return dPCB;
- }
- uint8_t seader_next_cpcb() {
- uint8_t next_pcb = cPCB ^ 0x40;
- //FURI_LOG_D(TAG, "cPCB was: %02X, current cPCB: %02X", cPCB, next_pcb);
- cPCB = next_pcb;
- return cPCB;
- }
- void seader_t_1_set_IFSD(Seader* seader) {
- SeaderWorker* seader_worker = seader->worker;
- SeaderUartBridge* seader_uart = seader_worker->uart;
- uint8_t frame[5];
- uint8_t frame_len = 0;
- frame[0] = NAD;
- frame[1] = 0xC1; // S(IFS request)
- frame[2] = 0x01;
- frame[3] = IFSD_VALUE;
- frame_len = 4;
- frame_len = seader_add_lrc(frame, frame_len);
- seader_ccid_XfrBlock(seader_uart, frame, frame_len);
- }
- void seader_t_1_send_ack(Seader* seader) {
- SeaderWorker* seader_worker = seader->worker;
- SeaderUartBridge* seader_uart = seader_worker->uart;
- uint8_t frame[4];
- uint8_t frame_len = 0;
- frame[0] = NAD;
- frame[1] = R_BLOCK | (seader_next_cpcb() >> 2);
- frame[2] = 0x00;
- frame_len = 3;
- frame_len = seader_add_lrc(frame, frame_len);
- //FURI_LOG_D(TAG, "Sending R-Block ACK: PCB: %02x", frame[1]);
- seader_ccid_XfrBlock(seader_uart, frame, frame_len);
- }
- BitBuffer* seader_t_1_tx_buffer;
- size_t seader_t_1_tx_buffer_offset = 0;
- void seader_send_t1_chunk(SeaderUartBridge* seader_uart, uint8_t PCB, uint8_t* chunk, size_t len) {
- uint8_t* frame = malloc(3 + len + 1);
- uint8_t frame_len = 0;
- frame[0] = NAD;
- frame[1] = PCB;
- frame[2] = len;
- frame_len = 3;
- if(len > 0) {
- memcpy(frame + frame_len, chunk, len);
- frame_len += len;
- }
- frame_len = seader_add_lrc(frame, frame_len);
- seader_ccid_XfrBlock(seader_uart, frame, frame_len);
- free(frame);
- }
- void seader_send_t1(SeaderUartBridge* seader_uart, uint8_t* apdu, size_t len) {
- if(len > IFSC_VALUE) {
- if(seader_t_1_tx_buffer == NULL) {
- seader_t_1_tx_buffer = bit_buffer_alloc(768);
- bit_buffer_copy_bytes(seader_t_1_tx_buffer, apdu, len);
- }
- size_t remaining =
- (bit_buffer_get_size_bytes(seader_t_1_tx_buffer) - seader_t_1_tx_buffer_offset);
- size_t copy_length = remaining > IFSC_VALUE ? IFSC_VALUE : remaining;
- uint8_t* chunk =
- (uint8_t*)bit_buffer_get_data(seader_t_1_tx_buffer) + seader_t_1_tx_buffer_offset;
- if(remaining > IFSC_VALUE) {
- uint8_t PCB = seader_next_dpcb() | MORE_BIT;
- seader_send_t1_chunk(seader_uart, PCB, chunk, copy_length);
- } else {
- uint8_t PCB = seader_next_dpcb();
- seader_send_t1_chunk(seader_uart, PCB, chunk, copy_length);
- }
- seader_t_1_tx_buffer_offset += copy_length;
- if(seader_t_1_tx_buffer_offset >= bit_buffer_get_size_bytes(seader_t_1_tx_buffer)) {
- bit_buffer_free(seader_t_1_tx_buffer);
- seader_t_1_tx_buffer = NULL;
- seader_t_1_tx_buffer_offset = 0;
- }
- return;
- }
- seader_send_t1_chunk(seader_uart, seader_next_dpcb(), apdu, len);
- }
- BitBuffer* seader_t_1_rx_buffer;
- bool seader_recv_t1(Seader* seader, CCID_Message* message) {
- // remove/validate NAD, PCB, LEN, LRC
- if(message->dwLength < 4) {
- FURI_LOG_W(TAG, "Invalid T=1 frame: too short");
- return false;
- }
- //uint8_t NAD = message->payload[0];
- uint8_t rPCB = message->payload[1];
- uint8_t LEN = message->payload[2];
- //uint8_t LRC = message->payload[3 + LEN];
- //FURI_LOG_D(TAG, "NAD: %02X, rPCB: %02X, LEN: %02X, LRC: %02X", NAD, rPCB, LEN, LRC);
- if(rPCB == 0xE1) {
- // S(IFS response)
- seader_worker_send_version(seader);
- SeaderWorker* seader_worker = seader->worker;
- if(seader_worker->callback) {
- seader_worker->callback(SeaderWorkerEventSamPresent, seader_worker->context);
- }
- return false;
- }
- if(rPCB == cPCB) {
- seader_next_cpcb();
- if(seader_t_1_rx_buffer != NULL) {
- bit_buffer_append_bytes(seader_t_1_rx_buffer, message->payload + 3, LEN);
- // TODO: validate LRC
- seader_worker_process_sam_message(
- seader,
- (uint8_t*)bit_buffer_get_data(seader_t_1_rx_buffer),
- bit_buffer_get_size_bytes(seader_t_1_rx_buffer));
- bit_buffer_free(seader_t_1_rx_buffer);
- seader_t_1_rx_buffer = NULL;
- return true;
- }
- if(seader_validate_lrc(message->payload, message->dwLength) == false) {
- return false;
- }
- // Skip NAD, PCB, LEN
- message->payload = message->payload + 3;
- message->dwLength = LEN;
- if(message->dwLength == 0) {
- //FURI_LOG_D(TAG, "Received T=1 frame with no data");
- return true;
- }
- return seader_worker_process_sam_message(seader, message->payload, message->dwLength);
- } else if(rPCB == (cPCB | MORE_BIT)) {
- //FURI_LOG_D(TAG, "Received T=1 frame with more bit set");
- if(seader_t_1_rx_buffer == NULL) {
- seader_t_1_rx_buffer = bit_buffer_alloc(512);
- }
- bit_buffer_append_bytes(seader_t_1_rx_buffer, message->payload + 3, LEN);
- seader_t_1_send_ack(seader);
- return false;
- } else if((rPCB & R_BLOCK) == R_BLOCK) {
- uint8_t R_SEQ = (rPCB & R_SEQUENCE_NUMBER_MASK) >> 4;
- uint8_t I_SEQ = (dPCB ^ 0x40) >> 6;
- if(R_SEQ != I_SEQ) {
- /*
- FURI_LOG_D(
- TAG,
- "Received R-Block: Incorrect sequence. Expected: %02X, Received: %02X",
- I_SEQ,
- R_SEQ);
- */
- // When this happens, the flipper freezes if it is doing NFC and my attempts to do events to stop that have failed
- return false;
- }
- if(seader_t_1_tx_buffer != NULL) {
- // Send more data, re-using the buffer to trigger the code path that sends the next block
- SeaderWorker* seader_worker = seader->worker;
- SeaderUartBridge* seader_uart = seader_worker->uart;
- seader_send_t1(
- seader_uart,
- (uint8_t*)bit_buffer_get_data(seader_t_1_tx_buffer),
- bit_buffer_get_size_bytes(seader_t_1_tx_buffer));
- return false;
- }
- } else {
- FURI_LOG_W(
- TAG, "Invalid T=1 frame: PCB mismatch. Expected: %02X, Received: %02X", cPCB, rPCB);
- }
- return false;
- }
|