mirror of
https://github.com/DarkFlippers/unleashed-firmware.git
synced 2025-12-13 13:09:49 +04:00
Merge remote-tracking branch 'OFW/dev' into dev
This commit is contained in:
@@ -384,8 +384,7 @@ BtTestParam* bt_test_param_add(
|
||||
|
||||
void bt_test_set_rssi(BtTest* bt_test, float rssi) {
|
||||
furi_assert(bt_test);
|
||||
with_view_model(
|
||||
bt_test->view, BtTestModel * model, { model->rssi = rssi; }, true);
|
||||
with_view_model(bt_test->view, BtTestModel * model, { model->rssi = rssi; }, true);
|
||||
}
|
||||
|
||||
void bt_test_set_packets_tx(BtTest* bt_test, uint32_t packets_num) {
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "iso7816_callbacks.h"
|
||||
#include "iso7816_t0_apdu.h"
|
||||
#include "iso7816_atr.h"
|
||||
#include "iso7816_response.h"
|
||||
|
||||
typedef enum {
|
||||
EventTypeInput,
|
||||
@@ -118,6 +119,76 @@ static const CcidCallbacks ccid_cb = {
|
||||
ccid_xfr_datablock_callback,
|
||||
};
|
||||
|
||||
//Instruction 1: returns an OK response unconditionally
|
||||
//APDU example: 0x01:0x01:0x00:0x00
|
||||
//response: SW1=0x90, SW2=0x00
|
||||
void handle_instruction_01(ISO7816_Response_APDU* responseAPDU) {
|
||||
responseAPDU->DataLen = 0;
|
||||
iso7816_set_response(responseAPDU, ISO7816_RESPONSE_OK);
|
||||
}
|
||||
|
||||
//Instruction 2: expect command with no body, replies wit with a body with two bytes
|
||||
//APDU example: 0x01:0x02:0x00:0x00:0x02
|
||||
//response: 'bc' (0x62, 0x63) SW1=0x90, SW2=0x00
|
||||
void handle_instruction_02(
|
||||
uint8_t p1,
|
||||
uint8_t p2,
|
||||
uint8_t lc,
|
||||
uint8_t le,
|
||||
ISO7816_Response_APDU* responseAPDU) {
|
||||
if(p1 == 0 && p2 == 0 && lc == 0 && le >= 2) {
|
||||
responseAPDU->Data[0] = 0x62;
|
||||
responseAPDU->Data[1] = 0x63;
|
||||
|
||||
responseAPDU->DataLen = 2;
|
||||
|
||||
iso7816_set_response(responseAPDU, ISO7816_RESPONSE_OK);
|
||||
} else if(p1 != 0 || p2 != 0) {
|
||||
iso7816_set_response(responseAPDU, ISO7816_RESPONSE_WRONG_PARAMETERS_P1_P2);
|
||||
} else {
|
||||
iso7816_set_response(responseAPDU, ISO7816_RESPONSE_WRONG_LENGTH);
|
||||
}
|
||||
}
|
||||
|
||||
//Instruction 3: sends a command with a body with two bytes, receives a response with no bytes
|
||||
//APDU example: 0x01:0x03:0x00:0x00:0x02:CA:FE
|
||||
//response SW1=0x90, SW2=0x00
|
||||
void handle_instruction_03(uint8_t p1, uint8_t p2, uint8_t lc, ISO7816_Response_APDU* responseAPDU) {
|
||||
if(p1 == 0 && p2 == 0 && lc == 2) {
|
||||
responseAPDU->DataLen = 0;
|
||||
iso7816_set_response(responseAPDU, ISO7816_RESPONSE_OK);
|
||||
} else if(p1 != 0 || p2 != 0) {
|
||||
iso7816_set_response(responseAPDU, ISO7816_RESPONSE_WRONG_PARAMETERS_P1_P2);
|
||||
} else {
|
||||
iso7816_set_response(responseAPDU, ISO7816_RESPONSE_WRONG_LENGTH);
|
||||
}
|
||||
}
|
||||
|
||||
//instruction 4: sends a command with a body with 'n' bytes, receives a response with 'n' bytes
|
||||
//APDU example: 0x01:0x04:0x00:0x00:0x04:0x01:0x02:0x03:0x04:0x04
|
||||
//receives (0x01, 0x02, 0x03, 0x04) SW1=0x90, SW2=0x00
|
||||
void handle_instruction_04(
|
||||
uint8_t p1,
|
||||
uint8_t p2,
|
||||
uint8_t lc,
|
||||
uint8_t le,
|
||||
const uint8_t* commandApduDataBuffer,
|
||||
ISO7816_Response_APDU* responseAPDU) {
|
||||
if(p1 == 0 && p2 == 0 && lc > 0 && le > 0 && le >= lc) {
|
||||
for(uint16_t i = 0; i < lc; i++) {
|
||||
responseAPDU->Data[i] = commandApduDataBuffer[i];
|
||||
}
|
||||
|
||||
responseAPDU->DataLen = lc;
|
||||
|
||||
iso7816_set_response(responseAPDU, ISO7816_RESPONSE_OK);
|
||||
} else if(p1 != 0 || p2 != 0) {
|
||||
iso7816_set_response(responseAPDU, ISO7816_RESPONSE_WRONG_PARAMETERS_P1_P2);
|
||||
} else {
|
||||
iso7816_set_response(responseAPDU, ISO7816_RESPONSE_WRONG_LENGTH);
|
||||
}
|
||||
}
|
||||
|
||||
void iso7816_answer_to_reset(Iso7816Atr* atr) {
|
||||
//minimum valid ATR: https://smartcard-atr.apdu.fr/parse?ATR=3B+00
|
||||
atr->TS = 0x3B;
|
||||
@@ -125,48 +196,38 @@ void iso7816_answer_to_reset(Iso7816Atr* atr) {
|
||||
}
|
||||
|
||||
void iso7816_process_command(
|
||||
const struct ISO7816_Command_APDU* commandAPDU,
|
||||
struct ISO7816_Response_APDU* responseAPDU,
|
||||
const uint8_t* commandApduDataBuffer,
|
||||
uint8_t commandApduDataBufferLen,
|
||||
uint8_t* responseApduDataBuffer,
|
||||
uint8_t* responseApduDataBufferLen) {
|
||||
const ISO7816_Command_APDU* commandAPDU,
|
||||
ISO7816_Response_APDU* responseAPDU) {
|
||||
//example 1: sends a command with no body, receives a response with no body
|
||||
//sends APDU 0x01:0x02:0x00:0x00
|
||||
//sends APDU 0x01:0x01:0x00:0x00
|
||||
//receives SW1=0x90, SW2=0x00
|
||||
if(commandAPDU->CLA == 0x01 && commandAPDU->INS == 0x01) {
|
||||
responseAPDU->SW1 = 0x90;
|
||||
responseAPDU->SW2 = 0x00;
|
||||
}
|
||||
//example 2: sends a command with no body, receives a response with a body with two bytes
|
||||
//sends APDU 0x01:0x02:0x00:0x00
|
||||
//receives 'bc' (0x62, 0x63) SW1=0x80, SW2=0x10
|
||||
else if(commandAPDU->CLA == 0x01 && commandAPDU->INS == 0x02) {
|
||||
responseApduDataBuffer[0] = 0x62;
|
||||
responseApduDataBuffer[1] = 0x63;
|
||||
|
||||
*responseApduDataBufferLen = 2;
|
||||
|
||||
responseAPDU->SW1 = 0x90;
|
||||
responseAPDU->SW2 = 0x00;
|
||||
}
|
||||
//example 3: ends a command with a body with two bytes, receives a response with a body with two bytes
|
||||
//sends APDU 0x01:0x03:0x00:0x00:0x02:CA:FE
|
||||
//receives (0xCA, 0xFE) SW1=0x90, SW2=0x02
|
||||
else if(
|
||||
commandAPDU->CLA == 0x01 && commandAPDU->INS == 0x03 && commandApduDataBufferLen == 2 &&
|
||||
commandAPDU->Lc == 2) {
|
||||
//echo command body to response body
|
||||
responseApduDataBuffer[0] = commandApduDataBuffer[0];
|
||||
responseApduDataBuffer[1] = commandApduDataBuffer[1];
|
||||
|
||||
*responseApduDataBufferLen = 2;
|
||||
|
||||
responseAPDU->SW1 = 0x90;
|
||||
responseAPDU->SW2 = 0x00;
|
||||
if(commandAPDU->CLA == 0x01) {
|
||||
switch(commandAPDU->INS) {
|
||||
case 0x01:
|
||||
handle_instruction_01(responseAPDU);
|
||||
break;
|
||||
case 0x02:
|
||||
handle_instruction_02(
|
||||
commandAPDU->P1, commandAPDU->P2, commandAPDU->Lc, commandAPDU->Le, responseAPDU);
|
||||
break;
|
||||
case 0x03:
|
||||
handle_instruction_03(commandAPDU->P1, commandAPDU->P2, commandAPDU->Lc, responseAPDU);
|
||||
break;
|
||||
case 0x04:
|
||||
handle_instruction_04(
|
||||
commandAPDU->P1,
|
||||
commandAPDU->P2,
|
||||
commandAPDU->Lc,
|
||||
commandAPDU->Le,
|
||||
commandAPDU->Data,
|
||||
responseAPDU);
|
||||
break;
|
||||
default:
|
||||
iso7816_set_response(responseAPDU, ISO7816_RESPONSE_INSTRUCTION_NOT_SUPPORTED);
|
||||
}
|
||||
} else {
|
||||
responseAPDU->SW1 = 0x6A;
|
||||
responseAPDU->SW2 = 0x00;
|
||||
iso7816_set_response(responseAPDU, ISO7816_RESPONSE_CLASS_NOT_SUPPORTED);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
116
applications/debug/ccid_test/client/ccid_client.py
Normal file
116
applications/debug/ccid_test/client/ccid_client.py
Normal file
@@ -0,0 +1,116 @@
|
||||
# pylint: disable=missing-module-docstring, too-many-arguments, consider-using-f-string, missing-function-docstring
|
||||
from smartcard.System import readers
|
||||
|
||||
|
||||
def test_apdu(connection, test_name, apdu, expected_sw1, expected_sw2, expected_data):
|
||||
print("Running test: [%s]" % test_name)
|
||||
data, sw1, sw2 = connection.transmit(apdu)
|
||||
|
||||
failed = []
|
||||
|
||||
if sw1 != expected_sw1:
|
||||
failed.append("SW1: Expected %x, actual %x" % (expected_sw1, sw1))
|
||||
|
||||
if sw2 != expected_sw2:
|
||||
failed.append("SW2: Expected %x, actual %x" % (expected_sw2, sw2))
|
||||
|
||||
if len(data) != len(expected_data):
|
||||
failed.append(
|
||||
"Data: Sizes differ: Expected %x, actual %x"
|
||||
% (len(expected_data), len(data))
|
||||
)
|
||||
print(data)
|
||||
elif len(data) > 0:
|
||||
data_matches = True
|
||||
for i, _ in enumerate(data):
|
||||
if data[i] != expected_data[i]:
|
||||
data_matches = False
|
||||
|
||||
if not data_matches:
|
||||
failed.append("Data: Expected %s, actual %s" % (expected_data, data))
|
||||
|
||||
if len(failed) > 0:
|
||||
print("Test failed: ")
|
||||
for failure in failed:
|
||||
print("- %s" % failure)
|
||||
else:
|
||||
print("Test passed!")
|
||||
|
||||
|
||||
def main():
|
||||
r = readers()
|
||||
print("Found following smartcard readers: ")
|
||||
|
||||
for i, sc in enumerate(r):
|
||||
print("[%d] %s" % (i, sc))
|
||||
|
||||
print("Select the smartcard reader you want to run tests against:")
|
||||
|
||||
reader_index = int(input())
|
||||
|
||||
if reader_index < len(r):
|
||||
connection = r[reader_index].createConnection()
|
||||
|
||||
connection.connect()
|
||||
|
||||
test_apdu(
|
||||
connection,
|
||||
"INS 0x01: No Lc, no Data, No Le. Expect no data in return",
|
||||
[0x01, 0x01, 0x00, 0x00],
|
||||
0x90,
|
||||
0x00,
|
||||
[],
|
||||
)
|
||||
|
||||
test_apdu(
|
||||
connection,
|
||||
"INS 0x02: No Lc, no Data, Le=2. Expect 2 byte data in return",
|
||||
[0x01, 0x02, 0x00, 0x00, 0x02],
|
||||
0x90,
|
||||
0x00,
|
||||
[0x62, 0x63],
|
||||
)
|
||||
|
||||
test_apdu(
|
||||
connection,
|
||||
"INS 0x03: Lc=2, data=[0xCA, 0xFE], No Le. Expect no data in return",
|
||||
[0x01, 0x03, 0x00, 0x00, 0x02, 0xCA, 0xFE],
|
||||
0x90,
|
||||
0x00,
|
||||
[],
|
||||
)
|
||||
|
||||
test_apdu(
|
||||
connection,
|
||||
"INS 0x04: Lc=2, data=[0xCA, 0xFE], Le=2. Expect 1 byte data in return",
|
||||
[0x01, 0x04, 0x00, 0x00, 0x02, 0xCA, 0xFE, 0x02],
|
||||
0x90,
|
||||
0x00,
|
||||
[0xCA, 0xFE],
|
||||
)
|
||||
|
||||
small_apdu = list(range(0, 0x0F))
|
||||
|
||||
test_apdu(
|
||||
connection,
|
||||
"INS 0x04: Lc=0x0F, data=small_apdu, Le=0x0F. Expect 14 bytes data in return",
|
||||
[0x01, 0x04, 0x00, 0x00, 0x0F] + small_apdu + [0x0F],
|
||||
0x90,
|
||||
0x00,
|
||||
small_apdu,
|
||||
)
|
||||
|
||||
max_apdu = list(range(0, 0x30))
|
||||
|
||||
test_apdu(
|
||||
connection,
|
||||
"INS 0x04: Lc=0x30, data=max_apdu, Le=0x30. Expect 0x30 bytes data in return",
|
||||
[0x01, 0x04, 0x00, 0x00, 0x30] + max_apdu + [0x30],
|
||||
0x90,
|
||||
0x00,
|
||||
max_apdu,
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
2
applications/debug/ccid_test/client/requirements.txt
Normal file
2
applications/debug/ccid_test/client/requirements.txt
Normal file
@@ -0,0 +1,2 @@
|
||||
pyscard
|
||||
# or sudo apt install python3-pyscard
|
||||
@@ -1,9 +1,6 @@
|
||||
#ifndef _ISO7816_ATR_H_
|
||||
#define _ISO7816_ATR_H_
|
||||
#pragma once
|
||||
|
||||
typedef struct {
|
||||
uint8_t TS;
|
||||
uint8_t T0;
|
||||
} Iso7816Atr;
|
||||
|
||||
#endif //_ISO7816_ATR_H_
|
||||
|
||||
@@ -1,17 +1,21 @@
|
||||
// transforms low level calls such as XFRCallback or ICC Power on to a structured one
|
||||
// an application can register these calls and listen for the callbacks defined in Iso7816Callbacks
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <furi.h>
|
||||
#include <furi_hal.h>
|
||||
|
||||
#include "iso7816_t0_apdu.h"
|
||||
#include "iso7816_atr.h"
|
||||
#include "iso7816_callbacks.h"
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <furi.h>
|
||||
|
||||
#define ISO7816_RESPONSE_BUFFER_SIZE 255
|
||||
#include "iso7816_response.h"
|
||||
|
||||
static Iso7816Callbacks* callbacks = NULL;
|
||||
|
||||
static uint8_t commandApduBuffer[sizeof(ISO7816_Command_APDU) + CCID_SHORT_APDU_SIZE];
|
||||
static uint8_t responseApduBuffer[sizeof(ISO7816_Response_APDU) + CCID_SHORT_APDU_SIZE];
|
||||
|
||||
void iso7816_set_callbacks(Iso7816Callbacks* cb) {
|
||||
callbacks = cb;
|
||||
}
|
||||
@@ -36,41 +40,26 @@ void iso7816_xfr_datablock_callback(
|
||||
uint32_t pcToReaderDataBlockLen,
|
||||
uint8_t* readerToPcDataBlock,
|
||||
uint32_t* readerToPcDataBlockLen) {
|
||||
struct ISO7816_Response_APDU responseAPDU;
|
||||
uint8_t responseApduDataBuffer[ISO7816_RESPONSE_BUFFER_SIZE];
|
||||
uint8_t responseApduDataBufferLen = 0;
|
||||
ISO7816_Response_APDU* responseAPDU = (ISO7816_Response_APDU*)&responseApduBuffer;
|
||||
|
||||
if(callbacks != NULL) {
|
||||
struct ISO7816_Command_APDU commandAPDU;
|
||||
ISO7816_Command_APDU* commandAPDU = (ISO7816_Command_APDU*)&commandApduBuffer;
|
||||
|
||||
const uint8_t* commandApduDataBuffer = NULL;
|
||||
uint8_t commandApduDataBufferLen = 0;
|
||||
uint8_t result =
|
||||
iso7816_read_command_apdu(commandAPDU, pcToReaderDataBlock, pcToReaderDataBlockLen);
|
||||
|
||||
iso7816_read_command_apdu(&commandAPDU, pcToReaderDataBlock, pcToReaderDataBlockLen);
|
||||
if(result == ISO7816_READ_COMMAND_APDU_OK) {
|
||||
callbacks->iso7816_process_command(commandAPDU, responseAPDU);
|
||||
|
||||
if(commandAPDU.Lc > 0) {
|
||||
commandApduDataBufferLen = commandAPDU.Lc;
|
||||
commandApduDataBuffer = &pcToReaderDataBlock[5];
|
||||
furi_assert(responseAPDU->DataLen < CCID_SHORT_APDU_SIZE);
|
||||
} else if(result == ISO7816_READ_COMMAND_APDU_ERROR_WRONG_LE) {
|
||||
iso7816_set_response(responseAPDU, ISO7816_RESPONSE_WRONG_LE);
|
||||
} else if(result == ISO7816_READ_COMMAND_APDU_ERROR_WRONG_LENGTH) {
|
||||
iso7816_set_response(responseAPDU, ISO7816_RESPONSE_WRONG_LENGTH);
|
||||
}
|
||||
|
||||
callbacks->iso7816_process_command(
|
||||
&commandAPDU,
|
||||
&responseAPDU,
|
||||
commandApduDataBuffer,
|
||||
commandApduDataBufferLen,
|
||||
responseApduDataBuffer,
|
||||
&responseApduDataBufferLen);
|
||||
|
||||
} else {
|
||||
//class not supported
|
||||
responseAPDU.SW1 = 0x6E;
|
||||
responseAPDU.SW2 = 0x00;
|
||||
iso7816_set_response(responseAPDU, ISO7816_RESPONSE_INTERNAL_EXCEPTION);
|
||||
}
|
||||
|
||||
iso7816_write_response_apdu(
|
||||
&responseAPDU,
|
||||
readerToPcDataBlock,
|
||||
readerToPcDataBlockLen,
|
||||
responseApduDataBuffer,
|
||||
responseApduDataBufferLen);
|
||||
iso7816_write_response_apdu(responseAPDU, readerToPcDataBlock, readerToPcDataBlockLen);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#ifndef _ISO7816_CALLBACKS_H_
|
||||
#define _ISO7816_CALLBACKS_H_
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include "iso7816_atr.h"
|
||||
@@ -8,12 +7,8 @@
|
||||
typedef struct {
|
||||
void (*iso7816_answer_to_reset)(Iso7816Atr* atr);
|
||||
void (*iso7816_process_command)(
|
||||
const struct ISO7816_Command_APDU* command,
|
||||
struct ISO7816_Response_APDU* response,
|
||||
const uint8_t* commandApduDataBuffer,
|
||||
uint8_t commandApduDataBufferLen,
|
||||
uint8_t* responseApduDataBuffer,
|
||||
uint8_t* responseApduDataBufferLen);
|
||||
const ISO7816_Command_APDU* command,
|
||||
ISO7816_Response_APDU* response);
|
||||
} Iso7816Callbacks;
|
||||
|
||||
void iso7816_set_callbacks(Iso7816Callbacks* cb);
|
||||
@@ -23,6 +18,4 @@ void iso7816_xfr_datablock_callback(
|
||||
const uint8_t* dataBlock,
|
||||
uint32_t dataBlockLen,
|
||||
uint8_t* responseDataBlock,
|
||||
uint32_t* responseDataBlockLen);
|
||||
|
||||
#endif //_ISO7816_CALLBACKS_H_
|
||||
uint32_t* responseDataBlockLen);
|
||||
8
applications/debug/ccid_test/iso7816_response.c
Normal file
8
applications/debug/ccid_test/iso7816_response.c
Normal file
@@ -0,0 +1,8 @@
|
||||
#include <stdint.h>
|
||||
#include "iso7816_t0_apdu.h"
|
||||
#include "iso7816_response.h"
|
||||
|
||||
void iso7816_set_response(ISO7816_Response_APDU* responseAPDU, uint16_t responseCode) {
|
||||
responseAPDU->SW1 = (responseCode >> (8 * 1)) & 0xff;
|
||||
responseAPDU->SW2 = (responseCode >> (8 * 0)) & 0xff;
|
||||
}
|
||||
12
applications/debug/ccid_test/iso7816_response.h
Normal file
12
applications/debug/ccid_test/iso7816_response.h
Normal file
@@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#define ISO7816_RESPONSE_OK 0x9000
|
||||
|
||||
#define ISO7816_RESPONSE_WRONG_LENGTH 0x6700
|
||||
#define ISO7816_RESPONSE_WRONG_PARAMETERS_P1_P2 0x6A00
|
||||
#define ISO7816_RESPONSE_WRONG_LE 0x6C00
|
||||
#define ISO7816_RESPONSE_INSTRUCTION_NOT_SUPPORTED 0x6D00
|
||||
#define ISO7816_RESPONSE_CLASS_NOT_SUPPORTED 0x6E00
|
||||
#define ISO7816_RESPONSE_INTERNAL_EXCEPTION 0x6F00
|
||||
|
||||
void iso7816_set_response(ISO7816_Response_APDU* responseAPDU, uint16_t responseCode);
|
||||
@@ -2,37 +2,73 @@
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <furi.h>
|
||||
#include <furi_hal.h>
|
||||
#include "iso7816_t0_apdu.h"
|
||||
|
||||
//reads dataBuffer with dataLen size, translate it into a ISO7816_Command_APDU type
|
||||
//extra data will be pointed to commandDataBuffer
|
||||
void iso7816_read_command_apdu(
|
||||
struct ISO7816_Command_APDU* command,
|
||||
uint8_t iso7816_read_command_apdu(
|
||||
ISO7816_Command_APDU* command,
|
||||
const uint8_t* dataBuffer,
|
||||
uint32_t dataLen) {
|
||||
UNUSED(dataLen);
|
||||
|
||||
command->CLA = dataBuffer[0];
|
||||
command->INS = dataBuffer[1];
|
||||
command->P1 = dataBuffer[2];
|
||||
command->P2 = dataBuffer[3];
|
||||
command->Lc = dataBuffer[4];
|
||||
|
||||
if(dataLen == 4) {
|
||||
command->Lc = 0;
|
||||
command->Le = 0;
|
||||
command->LePresent = false;
|
||||
|
||||
return ISO7816_READ_COMMAND_APDU_OK;
|
||||
} else if(dataLen == 5) {
|
||||
//short le
|
||||
|
||||
command->Lc = 0;
|
||||
command->Le = dataBuffer[4];
|
||||
command->LePresent = true;
|
||||
|
||||
return ISO7816_READ_COMMAND_APDU_OK;
|
||||
} else if(dataLen > 5 && dataBuffer[4] != 0x00) {
|
||||
//short lc
|
||||
|
||||
command->Lc = dataBuffer[4];
|
||||
if(command->Lc > 0 && command->Lc < CCID_SHORT_APDU_SIZE) { //-V560
|
||||
memcpy(command->Data, &dataBuffer[5], command->Lc);
|
||||
|
||||
//does it have a short le too?
|
||||
if(dataLen == (uint32_t)(command->Lc + 5)) {
|
||||
command->Le = 0;
|
||||
command->LePresent = false;
|
||||
return ISO7816_READ_COMMAND_APDU_OK;
|
||||
} else if(dataLen == (uint32_t)(command->Lc + 6)) {
|
||||
command->Le = dataBuffer[dataLen - 1];
|
||||
command->LePresent = true;
|
||||
|
||||
return ISO7816_READ_COMMAND_APDU_OK;
|
||||
} else {
|
||||
return ISO7816_READ_COMMAND_APDU_ERROR_WRONG_LENGTH;
|
||||
}
|
||||
} else {
|
||||
return ISO7816_READ_COMMAND_APDU_ERROR_WRONG_LENGTH;
|
||||
}
|
||||
} else {
|
||||
return ISO7816_READ_COMMAND_APDU_ERROR_WRONG_LENGTH;
|
||||
}
|
||||
}
|
||||
|
||||
//data buffer countains the whole APU response (response + trailer (SW1+SW2))
|
||||
//data buffer contains the whole APU response (response + trailer (SW1+SW2))
|
||||
void iso7816_write_response_apdu(
|
||||
const struct ISO7816_Response_APDU* response,
|
||||
const ISO7816_Response_APDU* response,
|
||||
uint8_t* readerToPcDataBlock,
|
||||
uint32_t* readerToPcDataBlockLen,
|
||||
uint8_t* responseDataBuffer,
|
||||
uint32_t responseDataLen) {
|
||||
uint32_t* readerToPcDataBlockLen) {
|
||||
uint32_t responseDataBufferIndex = 0;
|
||||
|
||||
//response body
|
||||
if(responseDataLen > 0) {
|
||||
while(responseDataBufferIndex < responseDataLen) {
|
||||
readerToPcDataBlock[responseDataBufferIndex] =
|
||||
responseDataBuffer[responseDataBufferIndex];
|
||||
if(response->DataLen > 0) {
|
||||
while(responseDataBufferIndex < response->DataLen) {
|
||||
readerToPcDataBlock[responseDataBufferIndex] = response->Data[responseDataBufferIndex];
|
||||
responseDataBufferIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
#ifndef _ISO7816_T0_APDU_H_
|
||||
#define _ISO7816_T0_APDU_H_
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include "iso7816_atr.h"
|
||||
#include "core/common_defines.h"
|
||||
|
||||
struct ISO7816_Command_APDU {
|
||||
#define ISO7816_READ_COMMAND_APDU_OK 0
|
||||
#define ISO7816_READ_COMMAND_APDU_ERROR_WRONG_LE 1
|
||||
#define ISO7816_READ_COMMAND_APDU_ERROR_WRONG_LENGTH 2
|
||||
|
||||
typedef struct {
|
||||
//header
|
||||
uint8_t CLA;
|
||||
uint8_t INS;
|
||||
@@ -13,24 +16,27 @@ struct ISO7816_Command_APDU {
|
||||
uint8_t P2;
|
||||
|
||||
//body
|
||||
uint8_t Lc;
|
||||
uint8_t Le;
|
||||
} FURI_PACKED;
|
||||
uint16_t Lc; //data length
|
||||
uint16_t Le; //maximum response data length expected by client
|
||||
|
||||
struct ISO7816_Response_APDU {
|
||||
//Le can have value of 0x00, which actually meand 0x100 = 256
|
||||
bool LePresent;
|
||||
uint8_t Data[0];
|
||||
} FURI_PACKED ISO7816_Command_APDU;
|
||||
|
||||
typedef struct {
|
||||
uint8_t SW1;
|
||||
uint8_t SW2;
|
||||
} FURI_PACKED;
|
||||
uint16_t DataLen;
|
||||
uint8_t Data[0];
|
||||
} FURI_PACKED ISO7816_Response_APDU;
|
||||
|
||||
void iso7816_answer_to_reset(Iso7816Atr* atr);
|
||||
void iso7816_read_command_apdu(
|
||||
struct ISO7816_Command_APDU* command,
|
||||
const uint8_t* dataBuffer,
|
||||
uint32_t dataLen);
|
||||
uint8_t iso7816_read_command_apdu(
|
||||
ISO7816_Command_APDU* command,
|
||||
const uint8_t* pcToReaderDataBlock,
|
||||
uint32_t pcToReaderDataBlockLen);
|
||||
void iso7816_write_response_apdu(
|
||||
const struct ISO7816_Response_APDU* response,
|
||||
const ISO7816_Response_APDU* response,
|
||||
uint8_t* readerToPcDataBlock,
|
||||
uint32_t* readerToPcDataBlockLen,
|
||||
uint8_t* responseDataBuffer,
|
||||
uint32_t responseDataLen);
|
||||
#endif //_ISO7816_T0_APDU_H_
|
||||
uint32_t* readerToPcDataBlockLen);
|
||||
|
||||
@@ -150,8 +150,7 @@ static void view_display_test_exit(void* context) {
|
||||
|
||||
static void view_display_test_timer_callback(void* context) {
|
||||
ViewDisplayTest* instance = context;
|
||||
with_view_model(
|
||||
instance->view, ViewDisplayTestModel * model, { model->counter++; }, true);
|
||||
with_view_model(instance->view, ViewDisplayTestModel * model, { model->counter++; }, true);
|
||||
}
|
||||
|
||||
ViewDisplayTest* view_display_test_alloc(void) {
|
||||
|
||||
@@ -223,16 +223,14 @@ bool lfrfid_debug_view_tune_is_dirty(LfRfidTuneView* tune_view) {
|
||||
|
||||
uint32_t lfrfid_debug_view_tune_get_arr(LfRfidTuneView* tune_view) {
|
||||
uint32_t result = false;
|
||||
with_view_model(
|
||||
tune_view->view, LfRfidTuneViewModel * model, { result = model->ARR; }, false);
|
||||
with_view_model(tune_view->view, LfRfidTuneViewModel * model, { result = model->ARR; }, false);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
uint32_t lfrfid_debug_view_tune_get_ccr(LfRfidTuneView* tune_view) {
|
||||
uint32_t result = false;
|
||||
with_view_model(
|
||||
tune_view->view, LfRfidTuneViewModel * model, { result = model->CCR; }, false);
|
||||
with_view_model(tune_view->view, LfRfidTuneViewModel * model, { result = model->CCR; }, false);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -206,8 +206,7 @@ static int32_t uart_echo_worker(void* context) {
|
||||
} while(length > 0);
|
||||
|
||||
notification_message(app->notification, &sequence_notification);
|
||||
with_view_model(
|
||||
app->view, UartDumpModel * model, { UNUSED(model); }, true);
|
||||
with_view_model(app->view, UartDumpModel * model, { UNUSED(model); }, true);
|
||||
}
|
||||
|
||||
if(events & WorkerEventRxIdle) {
|
||||
|
||||
@@ -74,7 +74,8 @@ MU_TEST(furi_hal_i2c_int_3b) {
|
||||
DATA_SIZE - 1,
|
||||
LP5562_I2C_TIMEOUT);
|
||||
mu_assert(ret, "4 rx failed");
|
||||
for(size_t i = 0; i < DATA_SIZE; i++) mu_assert(data_many[i] != 0, "4 invalid data_many");
|
||||
for(size_t i = 0; i < DATA_SIZE; i++)
|
||||
mu_assert(data_many[i] != 0, "4 invalid data_many");
|
||||
|
||||
ret = furi_hal_i2c_tx(
|
||||
&furi_hal_i2c_handle_power, LP5562_ADDRESS, data_many, DATA_SIZE, LP5562_I2C_TIMEOUT);
|
||||
@@ -90,7 +91,8 @@ MU_TEST(furi_hal_i2c_int_3b) {
|
||||
DATA_SIZE - 1,
|
||||
LP5562_I2C_TIMEOUT);
|
||||
mu_assert(ret, "7 rx failed");
|
||||
for(size_t i = 0; i < DATA_SIZE; i++) mu_assert(data_many[i] != 0, "7 invalid data_many");
|
||||
for(size_t i = 0; i < DATA_SIZE; i++)
|
||||
mu_assert(data_many[i] != 0, "7 invalid data_many");
|
||||
}
|
||||
|
||||
MU_TEST(furi_hal_i2c_int_1b_fail) {
|
||||
|
||||
@@ -6,8 +6,7 @@
|
||||
|
||||
#define LF_RFID_READ_TIMING_MULTIPLIER 8
|
||||
|
||||
#define EM_TEST_DATA \
|
||||
{ 0x58, 0x00, 0x85, 0x64, 0x02 }
|
||||
#define EM_TEST_DATA {0x58, 0x00, 0x85, 0x64, 0x02}
|
||||
#define EM_TEST_DATA_SIZE 5
|
||||
#define EM_TEST_EMULATION_TIMINGS_COUNT (64 * 2)
|
||||
|
||||
@@ -21,8 +20,7 @@ const int8_t em_test_timings[EM_TEST_EMULATION_TIMINGS_COUNT] = {
|
||||
-32, 32, 32, -32, -32, 32, -32, 32, -32, 32, -32, 32, -32, 32,
|
||||
};
|
||||
|
||||
#define HID10301_TEST_DATA \
|
||||
{ 0x8D, 0x48, 0xA8 }
|
||||
#define HID10301_TEST_DATA {0x8D, 0x48, 0xA8}
|
||||
#define HID10301_TEST_DATA_SIZE 3
|
||||
#define HID10301_TEST_EMULATION_TIMINGS_COUNT (541 * 2)
|
||||
|
||||
@@ -71,8 +69,7 @@ const int8_t hid10301_test_timings[HID10301_TEST_EMULATION_TIMINGS_COUNT] = {
|
||||
5, -5, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4,
|
||||
};
|
||||
|
||||
#define IOPROX_XSF_TEST_DATA \
|
||||
{ 0x65, 0x01, 0x05, 0x39 }
|
||||
#define IOPROX_XSF_TEST_DATA {0x65, 0x01, 0x05, 0x39}
|
||||
#define IOPROX_XSF_TEST_DATA_SIZE 4
|
||||
#define IOPROX_XSF_TEST_EMULATION_TIMINGS_COUNT (468 * 2)
|
||||
|
||||
@@ -116,8 +113,7 @@ const int8_t ioprox_xsf_test_timings[IOPROX_XSF_TEST_EMULATION_TIMINGS_COUNT] =
|
||||
};
|
||||
|
||||
#define INDALA26_EMULATION_TIMINGS_COUNT (1024 * 2)
|
||||
#define INDALA26_TEST_DATA \
|
||||
{ 0x3B, 0x73, 0x64, 0xA8 }
|
||||
#define INDALA26_TEST_DATA {0x3B, 0x73, 0x64, 0xA8}
|
||||
#define INDALA26_TEST_DATA_SIZE 4
|
||||
|
||||
const int8_t indala26_test_timings[INDALA26_EMULATION_TIMINGS_COUNT] = {
|
||||
@@ -209,8 +205,7 @@ const int8_t indala26_test_timings[INDALA26_EMULATION_TIMINGS_COUNT] = {
|
||||
-1, 1, -1, 1, -1, 1, -1, 1,
|
||||
};
|
||||
|
||||
#define FDXB_TEST_DATA \
|
||||
{ 0x44, 0x88, 0x23, 0xF2, 0x5A, 0x6F, 0x00, 0x01, 0x00, 0x00, 0x00 }
|
||||
#define FDXB_TEST_DATA {0x44, 0x88, 0x23, 0xF2, 0x5A, 0x6F, 0x00, 0x01, 0x00, 0x00, 0x00}
|
||||
#define FDXB_TEST_DATA_SIZE 11
|
||||
#define FDXB_TEST_EMULATION_TIMINGS_COUNT (206)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user