From 13d17fc4f795290ff16feb58b4b5b8ac3386fb29 Mon Sep 17 00:00:00 2001 From: Pol Henarejos Date: Mon, 4 Apr 2022 15:46:53 +0200 Subject: [PATCH 01/41] Fixed class with USB-ICC specs, for legacy reasons. Signed-off-by: Pol Henarejos --- src/usb/ccid.h | 31 +++++-------------------------- 1 file changed, 5 insertions(+), 26 deletions(-) diff --git a/src/usb/ccid.h b/src/usb/ccid.h index 2c9f950..4149e4b 100644 --- a/src/usb/ccid.h +++ b/src/usb/ccid.h @@ -31,40 +31,19 @@ static const struct ccid_class_descriptor desc_ccid = { 0x02), // T=1 .dwDefaultClock = (0xDFC), .dwMaximumClock = (0xDFC), - .bNumClockSupport = 1, + .bNumClockSupport = 0, .dwDataRate = (0x2580), .dwMaxDataRate = (0x2580), - .bNumDataRatesSupported = 1, - .dwMaxIFSD = (0xFF), // IFSD is handled by the real reader driver + .bNumDataRatesSupported = 0, + .dwMaxIFSD = (0xFE), // IFSD is handled by the real reader driver .dwSynchProtocols = (0), .dwMechanical = (0), - .dwFeatures = ( - 0x00000002| // Automatic parameter configuration based on ATR data - 0x00000004| // Automatic activation of ICC on inserting - 0x00000008| // Automatic ICC voltage selection - 0x00000010| // Automatic ICC clock frequency change - 0x00000020| // Automatic baud rate change - 0x00000040| // Automatic parameters negotiation - 0x00000080| // Automatic PPS - 0x00000400| // Automatic IFSD exchange as first exchange - 0x00040000| // Short and Extended APDU level exchange with CCID - 0x00100000), // USB Wake up signaling supported - .dwMaxCCIDMessageLength = (CCID_EXT_APDU_MAX), + .dwFeatures = 0x40840, //USB-ICC, short & extended APDU + .dwMaxCCIDMessageLength = 65544+10, .bClassGetResponse = 0xFF, .bclassEnvelope = 0xFF, .wLcdLayout = 0x0, - /* - ( - 0xFF00| // Number of lines for the LCD display - 0x00FF), // Number of characters per line - */ .bPINSupport = 0x0, - /* - 0x1| // PIN Verification supported - 0x2| // PIN Modification supported - 0x10| // PIN PACE Capabilities supported - 0x20, // PIN PACE Verification supported - */ .bMaxCCIDBusySlots = 0x01, }; From d49e7be972c3a6aab8984ea671e9806e0768e949 Mon Sep 17 00:00:00 2001 From: Pol Henarejos Date: Mon, 4 Apr 2022 15:48:04 +0200 Subject: [PATCH 02/41] Added a new custom APDU (88h) for setting and retrieving datetime. Signed-off-by: Pol Henarejos --- src/hsm/hsm2040.c | 17 ++++++++++++++++- src/hsm/sc_hsm.c | 39 +++++++++++++++++++++++++++------------ 2 files changed, 43 insertions(+), 13 deletions(-) diff --git a/src/hsm/hsm2040.c b/src/hsm/hsm2040.c index 228b1d5..93d2cd6 100644 --- a/src/hsm/hsm2040.c +++ b/src/hsm/hsm2040.c @@ -1605,6 +1605,21 @@ void led_off_all() #endif } +void init_rtc() { + + rtc_init(); + datetime_t dt = { + .year = 2020, + .month = 1, + .day = 1, + .dotw = 3, // 0 is Sunday, so 5 is Friday + .hour = 00, + .min = 00, + .sec = 00 + }; + rtc_set_datetime(&dt); +} + extern void neug_task(); pico_unique_board_id_t unique_id; @@ -1641,7 +1656,7 @@ int main(void) low_flash_init(); - rtc_init(); + init_rtc(); while (1) { diff --git a/src/hsm/sc_hsm.c b/src/hsm/sc_hsm.c index 21c6ee6..24a0c3c 100644 --- a/src/hsm/sc_hsm.c +++ b/src/hsm/sc_hsm.c @@ -1717,18 +1717,33 @@ static int cmd_derive_asym() { static int cmd_datetime() { if (P1(apdu) != 0x0 || P2(apdu) != 0x0) return SW_INCORRECT_P1P2(); - if (apdu.cmd_apdu_data_len != 8) - return SW_WRONG_LENGTH(); - datetime_t dt; - dt.year = (apdu.cmd_apdu_data[0] << 8) | (apdu.cmd_apdu_data[1]); - dt.month = apdu.cmd_apdu_data[2]; - dt.day = apdu.cmd_apdu_data[3]; - dt.dotw = apdu.cmd_apdu_data[4]; - dt.hour = apdu.cmd_apdu_data[5]; - dt.min = apdu.cmd_apdu_data[6]; - dt.sec = apdu.cmd_apdu_data[7]; - if (!rtc_set_datetime(&dt)) - return SW_WRONG_DATA(); + if (apdu.cmd_apdu_data_len == 0) { + datetime_t dt; + if (!rtc_get_datetime(&dt)) + return SW_EXEC_ERROR(); + res_APDU[res_APDU_size++] = dt.year >> 8; + res_APDU[res_APDU_size++] = dt.year & 0xff; + res_APDU[res_APDU_size++] = dt.month; + res_APDU[res_APDU_size++] = dt.day; + res_APDU[res_APDU_size++] = dt.dotw; + res_APDU[res_APDU_size++] = dt.hour; + res_APDU[res_APDU_size++] = dt.min; + res_APDU[res_APDU_size++] = dt.sec; + } + else { + if (apdu.cmd_apdu_data_len != 8) + return SW_WRONG_LENGTH(); + datetime_t dt; + dt.year = (apdu.cmd_apdu_data[0] << 8) | (apdu.cmd_apdu_data[1]); + dt.month = apdu.cmd_apdu_data[2]; + dt.day = apdu.cmd_apdu_data[3]; + dt.dotw = apdu.cmd_apdu_data[4]; + dt.hour = apdu.cmd_apdu_data[5]; + dt.min = apdu.cmd_apdu_data[6]; + dt.sec = apdu.cmd_apdu_data[7]; + if (!rtc_set_datetime(&dt)) + return SW_WRONG_DATA(); + } return SW_OK(); } From 6e1c47ddf44d71b66ba0dd8b491f5c7dc97276da Mon Sep 17 00:00:00 2001 From: Pol Henarejos Date: Mon, 4 Apr 2022 22:00:29 +0200 Subject: [PATCH 03/41] Fix with ASN1 encapsulation for keypair generation. It only affects RSA 4096 bits. Signed-off-by: Pol Henarejos --- src/hsm/sc_hsm.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/hsm/sc_hsm.c b/src/hsm/sc_hsm.c index 24a0c3c..f9cf066 100644 --- a/src/hsm/sc_hsm.c +++ b/src/hsm/sc_hsm.c @@ -994,15 +994,19 @@ static int cmd_keypair_gen() { res_APDU[0] = 0x67; int outer_len = strlen(cvc.outer_car)+2+2+1+4; - int bytes_length = (cvclen+outer_len)/256; - if (cvclen%256 > 0) - bytes_length++; - if (cvclen < 128) + int bytes_length = 0; + if (cvclen+outer_len < 128) res_APDU[1] = cvclen+outer_len; + else if (cvclen+outer_len < 256) { + res_APDU[1] = 0x81; + res_APDU[2] = cvclen+outer_len; + bytes_length = 1; + } else { - res_APDU[1] = 0x80|bytes_length; - for (int b = 1; b <= bytes_length; b++) - res_APDU[1+b] = ((cvclen+outer_len)>>((bytes_length-b)*8))&0xff; + res_APDU[1] = 0x82; + res_APDU[2] = (cvclen+outer_len) >> 8; + res_APDU[3] = (cvclen+outer_len) & 0xff; + bytes_length = 2; } memcpy(res_APDU+bytes_length+2, cvcbin, cvclen); res_APDU[bytes_length+2+cvclen] = 0x42; From ce2a1c21de61a0708b262ef73cfe1cc67c5e8818 Mon Sep 17 00:00:00 2001 From: Pol Henarejos Date: Tue, 5 Apr 2022 17:28:22 +0200 Subject: [PATCH 04/41] Added support to write arbitrary data EF. Signed-off-by: Pol Henarejos --- src/hsm/sc_hsm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hsm/sc_hsm.c b/src/hsm/sc_hsm.c index f9cf066..7e22893 100644 --- a/src/hsm/sc_hsm.c +++ b/src/hsm/sc_hsm.c @@ -1036,7 +1036,7 @@ static int cmd_update_ef() { return SW_SECURITY_STATUS_NOT_SATISFIED(); if (fid == 0x0) ef = currentEF; - else if (p1 != EE_CERTIFICATE_PREFIX && p1 != PRKD_PREFIX && p1 != CA_CERTIFICATE_PREFIX && p1 != CD_PREFIX) + else if (p1 != EE_CERTIFICATE_PREFIX && p1 != PRKD_PREFIX && p1 != CA_CERTIFICATE_PREFIX && p1 != CD_PREFIX && p1 != DATA_PREFIX && p1 != DCOD_PREFIX && p1 != PROT_DATA_PREFIX) return SW_INCORRECT_P1P2(); if (ef && !authenticate_action(ef, ACL_OP_UPDATE_ERASE)) From 770097d6abb7e353f1b31efc31aeef7f403e6ddf Mon Sep 17 00:00:00 2001 From: Pol Henarejos Date: Tue, 5 Apr 2022 18:07:20 +0200 Subject: [PATCH 05/41] Added support for reading binary data. Signed-off-by: Pol Henarejos --- src/fs/file.c | 15 ++------------- src/hsm/sc_hsm.c | 26 ++++++++++++++++---------- 2 files changed, 18 insertions(+), 23 deletions(-) diff --git a/src/fs/file.c b/src/fs/file.c index ad2af10..5adb11a 100644 --- a/src/fs/file.c +++ b/src/fs/file.c @@ -262,19 +262,8 @@ void scan_flash() { file_t *file = (file_t *)search_by_fid(fid, NULL, SPECIFY_EF); if (!file) { file = file_new(fid); - if ((fid & 0xff00) == (KEY_PREFIX << 8)) { - //add_file_to_chain(file, &ef_kf); - } - else if ((fid & 0xff00) == (PRKD_PREFIX << 8)) { - //add_file_to_chain(file, &ef_prkdf); - } - else if ((fid & 0xff00) == (CD_PREFIX << 8)) { - //add_file_to_chain(file, &ef_cdf); - } - else if ((fid & 0xff00) == (EE_CERTIFICATE_PREFIX << 8)) { - //add_file_to_chain(file, &ef_pukdf); - } - else { + uint8_t pfx = fid >> 8; + if (pfx != KEY_PREFIX && pfx != PRKD_PREFIX && pfx != CD_PREFIX && pfx != EE_CERTIFICATE_PREFIX && pfx != DCOD_PREFIX && pfx != PROT_DATA_PREFIX && pfx != DATA_PREFIX) { TU_LOG1("SCAN FOUND ORPHAN FILE: %x\r\n",fid); continue; } diff --git a/src/hsm/sc_hsm.c b/src/hsm/sc_hsm.c index 7e22893..1203991 100644 --- a/src/hsm/sc_hsm.c +++ b/src/hsm/sc_hsm.c @@ -117,16 +117,14 @@ static int cmd_select() { //if ((fid & 0xff00) == (KEY_PREFIX << 8)) // fid = (PRKD_PREFIX << 8) | (fid & 0xff); - - if ((fid & 0xff00) == (PRKD_PREFIX << 8)) { - if (!(pe = search_dynamic_file(fid))) - return SW_FILE_NOT_FOUND(); - } - else if ((fid & 0xff00) == (CD_PREFIX << 8)) { - if (!(pe = search_dynamic_file(fid))) - return SW_FILE_NOT_FOUND(); - } - else if ((fid & 0xff00) == (EE_CERTIFICATE_PREFIX << 8)) { + + uint8_t pfx = fid >> 8; + if (pfx == PRKD_PREFIX || + pfx == CD_PREFIX || + pfx == EE_CERTIFICATE_PREFIX || + pfx == DCOD_PREFIX || + pfx == DATA_PREFIX || + pfx == PROT_DATA_PREFIX) { if (!(pe = search_dynamic_file(fid))) return SW_FILE_NOT_FOUND(); } @@ -297,6 +295,14 @@ static int cmd_list_keys() res_APDU[res_APDU_size++] = f->fid & 0xff; } } + + for (int i = 0; i < dynamic_files; i++) { + file_t *f = &dynamic_file[i]; + if ((f->fid & 0xff00) == (DCOD_PREFIX << 8)) { + res_APDU[res_APDU_size++] = DCOD_PREFIX; + res_APDU[res_APDU_size++] = f->fid & 0xff; + } + } return SW_OK(); } From 532d79bcc539382a9b76e56577a1d4a1959c9a32 Mon Sep 17 00:00:00 2001 From: Pol Henarejos Date: Wed, 6 Apr 2022 14:38:22 +0200 Subject: [PATCH 06/41] Added press button to confirm. Everytime a private/secret key is loaded, the Pico HSM waits for BOOTSEL button press. This mechanism guarantees that no private/secret operations are made without user consent. To confirm the operation, the user must press the BOOTSEL button. In the meanwhile, the device gets into waiting state and no other operation is performed. After release the button, the operation continues normally. Signed-off-by: Pol Henarejos --- src/hsm/hsm2040.c | 59 +++++++++++++++++++++++++++++++---------------- src/hsm/hsm2040.h | 22 ++++++++++++++++-- src/hsm/sc_hsm.c | 16 +++++++++++++ 3 files changed, 75 insertions(+), 22 deletions(-) diff --git a/src/hsm/hsm2040.c b/src/hsm/hsm2040.c index 93d2cd6..6b4e337 100644 --- a/src/hsm/hsm2040.c +++ b/src/hsm/hsm2040.c @@ -29,7 +29,6 @@ #include "tusb.h" #include "usb_descriptors.h" #include "device/usbd_pvt.h" -#include "pico/util/queue.h" #include "pico/multicore.h" #include "random.h" #include "hsm2040.h" @@ -94,7 +93,8 @@ app_t *current_app = NULL; extern void card_thread(); -static queue_t *card_comm; +queue_t *card_comm = NULL; +queue_t *ccid_comm = NULL; extern void low_flash_init_core1(); int register_app(app_t * (*select_aid)()) { @@ -374,18 +374,28 @@ usbd_class_driver_t const *usbd_app_driver_get_cb(uint8_t *driver_count) { return &ccid_driver; } -enum { - BLINK_NOT_MOUNTED = (250 << 16) | 250, - BLINK_MOUNTED = (250 << 16) | 250, - BLINK_SUSPENDED = (500 << 16) | 1000, - BLINK_PROCESSING = (50 << 16) | 50, - - BLINK_ALWAYS_ON = UINT32_MAX, - BLINK_ALWAYS_OFF = 0 -}; static uint32_t blink_interval_ms = BLINK_NOT_MOUNTED; +void led_set_blink(uint32_t mode) { + blink_interval_ms = mode; +} + +void execute_tasks(); + +static void wait_button() { + led_set_blink((1000 << 16) | 100); + while (board_button_read() == false) { + execute_tasks(); + //sleep_ms(10); + } + while (board_button_read() == true) { + execute_tasks(); + //sleep_ms(10); + } + led_set_blink(BLINK_PROCESSING); +} + void usb_tx_enable(const uint8_t *buf, uint32_t len) { if (len > 0) { @@ -485,7 +495,7 @@ static enum ccid_state ccid_power_on(struct ccid *c) DEBUG_INFO("ON\r\n"); c->tx_busy = 1; - blink_interval_ms = BLINK_MOUNTED; + led_set_blink(BLINK_MOUNTED); return CCID_STATE_WAIT; } @@ -532,7 +542,7 @@ static enum ccid_state ccid_power_off(struct ccid *c) ccid_send_status (c); DEBUG_INFO ("OFF\r\n"); c->tx_busy = 1; - blink_interval_ms = BLINK_SUSPENDED; + led_set_blink(BLINK_SUSPENDED); return CCID_STATE_START; } @@ -1376,7 +1386,7 @@ void prepare_ccid() } int process_apdu() { - blink_interval_ms = BLINK_PROCESSING; + led_set_blink(BLINK_PROCESSING); if (!current_app) { if (INS(apdu) == 0xA4 && P1(apdu) == 0x04 && (P2(apdu) == 0x00 || P2(apdu) == 0x4)) { //select by AID for (int a = 0; a < num_apps; a++) { @@ -1406,7 +1416,7 @@ static void card_init (void) void card_thread() { - queue_t *ccid_comm = (queue_t *)multicore_fifo_pop_blocking(); + ccid_comm = (queue_t *)multicore_fifo_pop_blocking(); card_comm = (queue_t *)multicore_fifo_pop_blocking(); card_init (); @@ -1531,7 +1541,7 @@ void ccid_task(void) { DEBUG_INFO ("ERR05\r\n"); } - blink_interval_ms = BLINK_MOUNTED; + led_set_blink(BLINK_MOUNTED); } else if (m == EV_TX_FINISHED) { @@ -1542,6 +1552,11 @@ void ccid_task(void) if (c->state == APDU_STATE_WAIT_COMMAND || c->state == APDU_STATE_COMMAND_CHAINING || c->state == APDU_STATE_RESULT_GET_RESPONSE) ccid_prepare_receive(c); } + else if (m == EV_PRESS_BUTTON) { + wait_button(); + uint32_t flag = EV_BUTTON_PRESSED; + queue_try_add(&c->card_comm, &flag); + } } else /* Timeout */ { @@ -1624,6 +1639,13 @@ extern void neug_task(); pico_unique_board_id_t unique_id; +void execute_tasks() { + prev_millis = board_millis(); + ccid_task(); + tud_task(); // tinyusb device task + led_blinking_task(); +} + int main(void) { struct apdu *a = &apdu; @@ -1660,10 +1682,7 @@ int main(void) while (1) { - prev_millis = board_millis(); - ccid_task(); - tud_task(); // tinyusb device task - led_blinking_task(); + execute_tasks(); neug_task(); do_flash(); } diff --git a/src/hsm/hsm2040.h b/src/hsm/hsm2040.h index 3e74ad2..996e29d 100644 --- a/src/hsm/hsm2040.h +++ b/src/hsm/hsm2040.h @@ -22,6 +22,7 @@ #include "tusb.h" #include "file.h" #include "pico/unique_id.h" +#include "pico/util/queue.h" #define USB_REQ_CCID 0xA1 @@ -79,13 +80,18 @@ struct apdu { #define EV_EXEC_ACK_REQUIRED 4 /* OpenPGPcard Execution ACK required */ #define EV_EXEC_FINISHED 8 /* OpenPGPcard Execution finished */ #define EV_RX_DATA_READY 16 /* USB Rx data available */ +#define EV_PRESS_BUTTON 32 -/* OpenPGPcard thread */ +/* SC HSM thread */ #define EV_MODIFY_CMD_AVAILABLE 1 #define EV_VERIFY_CMD_AVAILABLE 2 #define EV_CMD_AVAILABLE 4 #define EV_EXIT 8 -#define EV_PINPAD_INPUT_DONE 16 +#define EV_BUTTON_PRESSED 16 + +//Variables set by core1 +extern queue_t *ccid_comm; +extern queue_t *card_comm; enum ccid_state { CCID_STATE_NOCARD, /* No card available */ @@ -157,4 +163,16 @@ extern void low_flash_available(); extern int flash_clear_file(file_t *file); extern pico_unique_board_id_t unique_id; + +enum { + BLINK_NOT_MOUNTED = (250 << 16) | 250, + BLINK_MOUNTED = (250 << 16) | 250, + BLINK_SUSPENDED = (500 << 16) | 1000, + BLINK_PROCESSING = (50 << 16) | 50, + + BLINK_ALWAYS_ON = UINT32_MAX, + BLINK_ALWAYS_OFF = 0 +}; +extern void led_set_blink(uint32_t mode); + #endif \ No newline at end of file diff --git a/src/hsm/sc_hsm.c b/src/hsm/sc_hsm.c index 1203991..dd4076b 100644 --- a/src/hsm/sc_hsm.c +++ b/src/hsm/sc_hsm.c @@ -101,6 +101,17 @@ uint16_t get_device_options() { return 0x0; } +extern uint32_t board_button_read(void); + +static void wait_button() { + uint32_t val = EV_PRESS_BUTTON; + queue_try_add(ccid_comm, &val); + do { + queue_remove_blocking(card_comm, &val); + } + while (val != EV_BUTTON_PRESSED); +} + static int cmd_select() { uint8_t p1 = P1(apdu); uint8_t p2 = P2(apdu); @@ -1191,6 +1202,7 @@ static int cmd_key_gen() { } int load_private_key_rsa(mbedtls_rsa_context *ctx, file_t *fkey) { + wait_button(); int key_size = file_read_uint16(fkey->data); uint8_t kdata[4096/8]; memcpy(kdata, file_read(fkey->data+2), key_size); @@ -1225,6 +1237,7 @@ int load_private_key_rsa(mbedtls_rsa_context *ctx, file_t *fkey) { } int load_private_key_ecdsa(mbedtls_ecdsa_context *ctx, file_t *fkey) { + wait_button(); int key_size = file_read_uint16(fkey->data); uint8_t kdata[67]; //Worst case, 521 bit + 1byte memcpy(kdata, file_read(fkey->data+2), key_size); @@ -1417,6 +1430,7 @@ static int cmd_key_wrap() { } else if (*dprkd == P15_KEYTYPE_AES) { uint8_t kdata[32]; //maximum AES key size + wait_button(); int key_size = file_read_uint16(ef->data), aes_type = HSM_KEY_AES; memcpy(kdata, file_read(ef->data+2), key_size); if (dkek_decrypt(kdata, key_size) != 0) { @@ -1526,6 +1540,7 @@ static int cmd_decrypt_asym() { } else if (P2(apdu) == ALGO_EC_DH) { mbedtls_ecdh_context ctx; + wait_button(); int key_size = file_read_uint16(ef->data); uint8_t *kdata = (uint8_t *)calloc(1,key_size); memcpy(kdata, file_read(ef->data+2), key_size); @@ -1580,6 +1595,7 @@ static int cmd_cipher_sym() { if ((apdu.cmd_apdu_data_len % 16) != 0) { return SW_WRONG_LENGTH(); } + wait_button(); int key_size = file_read_uint16(ef->data); uint8_t kdata[32]; //maximum AES key size memcpy(kdata, file_read(ef->data+2), key_size); From 7060d2d2cab07b7b4f85a892008a1d30df67127e Mon Sep 17 00:00:00 2001 From: Pol Henarejos Date: Wed, 6 Apr 2022 14:41:09 +0200 Subject: [PATCH 07/41] Added custom INS (named EXTRAS) to support different extra commands. At this moment: - 0xA: gets/sets the datetime. - 0x6: enables/disables press to confirm (BOOTSEL). It allows other dynamic device options. At this moment, only press to confirm option is available. Signed-off-by: Pol Henarejos --- src/hsm/sc_hsm.c | 76 ++++++++++++++++++++++++++++++------------------ 1 file changed, 48 insertions(+), 28 deletions(-) diff --git a/src/hsm/sc_hsm.c b/src/hsm/sc_hsm.c index dd4076b..597aa58 100644 --- a/src/hsm/sc_hsm.c +++ b/src/hsm/sc_hsm.c @@ -1740,39 +1740,59 @@ static int cmd_derive_asym() { return SW_OK(); } -static int cmd_datetime() { - if (P1(apdu) != 0x0 || P2(apdu) != 0x0) +static int cmd_extras() { + if (P2(apdu) != 0x0) return SW_INCORRECT_P1P2(); - if (apdu.cmd_apdu_data_len == 0) { - datetime_t dt; - if (!rtc_get_datetime(&dt)) - return SW_EXEC_ERROR(); - res_APDU[res_APDU_size++] = dt.year >> 8; - res_APDU[res_APDU_size++] = dt.year & 0xff; - res_APDU[res_APDU_size++] = dt.month; - res_APDU[res_APDU_size++] = dt.day; - res_APDU[res_APDU_size++] = dt.dotw; - res_APDU[res_APDU_size++] = dt.hour; - res_APDU[res_APDU_size++] = dt.min; - res_APDU[res_APDU_size++] = dt.sec; + if (P1(apdu) == 0xA) { //datetime operations + if (apdu.cmd_apdu_data_len == 0) { + datetime_t dt; + if (!rtc_get_datetime(&dt)) + return SW_EXEC_ERROR(); + res_APDU[res_APDU_size++] = dt.year >> 8; + res_APDU[res_APDU_size++] = dt.year & 0xff; + res_APDU[res_APDU_size++] = dt.month; + res_APDU[res_APDU_size++] = dt.day; + res_APDU[res_APDU_size++] = dt.dotw; + res_APDU[res_APDU_size++] = dt.hour; + res_APDU[res_APDU_size++] = dt.min; + res_APDU[res_APDU_size++] = dt.sec; + } + else { + if (apdu.cmd_apdu_data_len != 8) + return SW_WRONG_LENGTH(); + datetime_t dt; + dt.year = (apdu.cmd_apdu_data[0] << 8) | (apdu.cmd_apdu_data[1]); + dt.month = apdu.cmd_apdu_data[2]; + dt.day = apdu.cmd_apdu_data[3]; + dt.dotw = apdu.cmd_apdu_data[4]; + dt.hour = apdu.cmd_apdu_data[5]; + dt.min = apdu.cmd_apdu_data[6]; + dt.sec = apdu.cmd_apdu_data[7]; + if (!rtc_set_datetime(&dt)) + return SW_WRONG_DATA(); + } } - else { - if (apdu.cmd_apdu_data_len != 8) + else if (P1(apdu) == 0x6) { //dynamic options + if (apdu.cmd_apdu_data_len > sizeof(uint8_t)) return SW_WRONG_LENGTH(); - datetime_t dt; - dt.year = (apdu.cmd_apdu_data[0] << 8) | (apdu.cmd_apdu_data[1]); - dt.month = apdu.cmd_apdu_data[2]; - dt.day = apdu.cmd_apdu_data[3]; - dt.dotw = apdu.cmd_apdu_data[4]; - dt.hour = apdu.cmd_apdu_data[5]; - dt.min = apdu.cmd_apdu_data[6]; - dt.sec = apdu.cmd_apdu_data[7]; - if (!rtc_set_datetime(&dt)) - return SW_WRONG_DATA(); + uint16_t opts = get_device_options(); + if (apdu.cmd_apdu_data_len == 0) { + res_APDU[res_APDU_size++] = opts >> 8; + res_APDU[res_APDU_size++] = opts & 0xff; + } + else { + uint8_t newopts[] = { apdu.cmd_apdu_data[0], (opts & 0xff) }; + file_t *tf = search_by_fid(EF_DEVOPS, NULL, SPECIFY_EF); + flash_write_data_to_file(tf, newopts, sizeof(newopts)); + low_flash_available(); + } } + else + return SW_INCORRECT_P1P2(); return SW_OK(); } + typedef struct cmd { uint8_t ins; @@ -1794,7 +1814,7 @@ typedef struct cmd #define INS_DERIVE_ASYM 0x76 #define INS_CIPHER_SYM 0x78 #define INS_CHALLENGE 0x84 -#define INS_DATETIME 0x88 +#define INS_EXTRAS 0x88 #define INS_SELECT_FILE 0xA4 #define INS_READ_BINARY 0xB0 #define INS_READ_BINARY_ODD 0xB1 @@ -1822,7 +1842,7 @@ static const cmd_t cmds[] = { { INS_DECRYPT_ASYM, cmd_decrypt_asym }, { INS_CIPHER_SYM, cmd_cipher_sym }, { INS_DERIVE_ASYM, cmd_derive_asym }, - { INS_DATETIME, cmd_datetime }, + { INS_EXTRAS, cmd_extras }, { 0x00, 0x0} }; From c16a7a3c5ca4a7ab84278fafe50f243c7d2e44fb Mon Sep 17 00:00:00 2001 From: Pol Henarejos Date: Wed, 6 Apr 2022 15:14:23 +0200 Subject: [PATCH 08/41] Added dynamic option to enable/disable press to confirm. Signed-off-by: Pol Henarejos --- src/hsm/sc_hsm.c | 13 ++++++++----- src/hsm/sc_hsm.h | 15 ++++++++------- 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/src/hsm/sc_hsm.c b/src/hsm/sc_hsm.c index 597aa58..7c365d4 100644 --- a/src/hsm/sc_hsm.c +++ b/src/hsm/sc_hsm.c @@ -104,12 +104,15 @@ uint16_t get_device_options() { extern uint32_t board_button_read(void); static void wait_button() { - uint32_t val = EV_PRESS_BUTTON; - queue_try_add(ccid_comm, &val); - do { - queue_remove_blocking(card_comm, &val); + uint16_t opts = get_device_options(); + if (opts & HSM_OPT_BOOTSEL_BUTTON) { + uint32_t val = EV_PRESS_BUTTON; + queue_try_add(ccid_comm, &val); + do { + queue_remove_blocking(card_comm, &val); + } + while (val != EV_BUTTON_PRESSED); } - while (val != EV_BUTTON_PRESSED); } static int cmd_select() { diff --git a/src/hsm/sc_hsm.h b/src/hsm/sc_hsm.h index 6ac44f1..061dc12 100644 --- a/src/hsm/sc_hsm.h +++ b/src/hsm/sc_hsm.h @@ -88,13 +88,14 @@ extern const uint8_t sc_hsm_aid[]; #define ALGO_AES_CMAC 0x18 #define ALGO_AES_DERIVE 0x99 -#define HSM_OPT_RRC 0x1 -#define HSM_OPT_TRANSPORT_PIN 0x2 -#define HSM_OPT_SESSION_PIN 0x4 -#define HSM_OPT_SESSION_PIN_EXPL 0xC -#define HSM_OPT_REPLACE_PKA 0x8 -#define HSM_OPT_COMBINED_AUTH 0x10 -#define HSM_OPT_RRC_RESET_ONLY 0x20 +#define HSM_OPT_RRC 0x0001 +#define HSM_OPT_TRANSPORT_PIN 0x0002 +#define HSM_OPT_SESSION_PIN 0x0004 +#define HSM_OPT_SESSION_PIN_EXPL 0x000C +#define HSM_OPT_REPLACE_PKA 0x0008 +#define HSM_OPT_COMBINED_AUTH 0x0010 +#define HSM_OPT_RRC_RESET_ONLY 0x0020 +#define HSM_OPT_BOOTSEL_BUTTON 0x0100 #define P15_KEYTYPE_RSA 0x30 #define P15_KEYTYPE_ECC 0xA0 From 1e6556ebdd7f3fa11593360ed9560accb0c30fb1 Mon Sep 17 00:00:00 2001 From: Pol Henarejos Date: Wed, 6 Apr 2022 19:16:28 +0200 Subject: [PATCH 09/41] Upgrading to version 1.12. Signed-off-by: Pol Henarejos --- build_pico_hsm.sh | 2 +- patch_vidpid.sh | 2 +- src/hsm/version.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/build_pico_hsm.sh b/build_pico_hsm.sh index 037ee77..43e1542 100755 --- a/build_pico_hsm.sh +++ b/build_pico_hsm.sh @@ -1,7 +1,7 @@ #!/bin/bash VERSION_MAJOR="1" -VERSION_MINOR="10" +VERSION_MINOR="12" rm -rf release/* cd build_release diff --git a/patch_vidpid.sh b/patch_vidpid.sh index dc1f379..df149d8 100755 --- a/patch_vidpid.sh +++ b/patch_vidpid.sh @@ -18,7 +18,7 @@ # VERSION_MAJOR="1" -VERSION_MINOR="0A" +VERSION_MINOR="0C" echo "----------------------------" echo "VID/PID patcher for Pico HSM" diff --git a/src/hsm/version.h b/src/hsm/version.h index 5340f9d..59582c6 100644 --- a/src/hsm/version.h +++ b/src/hsm/version.h @@ -18,7 +18,7 @@ #ifndef __VERSION_H_ #define __VERSION_H_ -#define HSM_VERSION 0x010A +#define HSM_VERSION 0x010C #define HSM_VERSION_MAJOR ((HSM_VERSION >> 8) & 0xff) #define HSM_VERSION_MINOR (HSM_VERSION & 0xff) From 98ad2e3d553ca5dec238fc208036d8ae6612427e Mon Sep 17 00:00:00 2001 From: Pol Henarejos Date: Thu, 7 Apr 2022 23:32:56 +0200 Subject: [PATCH 10/41] Fix returning card data when selected AID. Signed-off-by: Pol Henarejos --- src/hsm/sc_hsm.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/hsm/sc_hsm.c b/src/hsm/sc_hsm.c index 1d6132b..3190557 100644 --- a/src/hsm/sc_hsm.c +++ b/src/hsm/sc_hsm.c @@ -191,10 +191,11 @@ static int cmd_select() { process_fci(pe); if (pe == file_sc_hsm) { res_APDU[res_APDU_size++] = 0x85; - res_APDU[res_APDU_size++] = 4; + res_APDU[res_APDU_size++] = 5; uint16_t opts = get_device_options(); - res_APDU[res_APDU_size++] = opts & 0xff; res_APDU[res_APDU_size++] = opts >> 8; + res_APDU[res_APDU_size++] = opts & 0xff; + res_APDU[res_APDU_size++] = 0xFF; res_APDU[res_APDU_size++] = HSM_VERSION_MAJOR; res_APDU[res_APDU_size++] = HSM_VERSION_MINOR; res_APDU[1] = res_APDU_size-2; From 4e6bada892b0872647612084c6c0a1b4d718cf9b Mon Sep 17 00:00:00 2001 From: Pol Henarejos Date: Fri, 8 Apr 2022 00:29:15 +0200 Subject: [PATCH 11/41] Fix first AID load. Signed-off-by: Pol Henarejos --- src/hsm/sc_hsm.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/hsm/sc_hsm.c b/src/hsm/sc_hsm.c index 3190557..4269ba4 100644 --- a/src/hsm/sc_hsm.c +++ b/src/hsm/sc_hsm.c @@ -47,6 +47,7 @@ static int sc_hsm_process_apdu(); static void init_sc_hsm(); static int sc_hsm_unload(); +static int cmd_select(); app_t *sc_hsm_select_aid(app_t *a) { if (!memcmp(apdu.cmd_apdu_data, sc_hsm_aid+1, MIN(apdu.cmd_apdu_data_len,sc_hsm_aid[0]))) { @@ -67,6 +68,7 @@ void init_sc_hsm() { scan_flash(); has_session_pin = has_session_sopin = false; isUserAuthenticated = false; + cmd_select(); } int sc_hsm_unload() { From ce4d0bf102139ab82ec1e781c6b24716fd45d806 Mon Sep 17 00:00:00 2001 From: Pol Henarejos Date: Fri, 8 Apr 2022 00:38:03 +0200 Subject: [PATCH 12/41] INS 54h is also occupied too... let's try with 64h. Signed-off-by: Pol Henarejos --- doc/extra_command.md | 20 ++++++++++---------- src/hsm/sc_hsm.c | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/doc/extra_command.md b/doc/extra_command.md index ca80635..7cdd13d 100644 --- a/doc/extra_command.md +++ b/doc/extra_command.md @@ -4,12 +4,12 @@ Pico HSM supports a customized extra command to use with different options. Sinc To send a raw APDU command, `opensc-tool -s ` can be used. The `APDU` parameter is a string of hexadecimal numbers and it takes the following form: ``` -8054XX00YYZZZZRR +8064XX00YYZZZZRR ``` It composed by the following fields: - `80` to indicate that it is a custom vendor type command. -- `54` is the `INS` custom command. +- `64` is the `INS` custom command. - `XX` is the command to execute. It varies depending on the targeted command. - `00` is the parameter of the command. At this moment, no commands support parameters. - `YY` is the length of the data. If no data is provided, this field is absent. @@ -25,9 +25,9 @@ To obtain the current datetime (referenced to 00:00:00 2020/01/01), the `XX` par For example, to obtain the current datetime: ``` -$ opensc-tool -s 80540A0008 +$ opensc-tool -s 80640A0008 Using reader with a card: Free Software Initiative of Japan Gnuk -Sending: 80 54 0A 00 08 +Sending: 80 64 0A 00 08 Received (SW1=0x90, SW2=0x00): 07 E6 04 06 03 13 29 1E ......). ``` @@ -47,9 +47,9 @@ If the command is correctly received, `SW1=0x90` and `SW2=0x00`. Other values me To set the reference datetime, a datetime string must be provided. For example: ``` -$ opensc-tool -s 80540A000807E6040603132917 +$ opensc-tool -s 80640A000807E6040603132917 Using reader with a card: Free Software Initiative of Japan Gnuk -Sending: 80 54 0A 00 08 07 E6 04 06 03 13 29 17 +Sending: 80 64 0A 00 08 07 E6 04 06 03 13 29 17 Received (SW1=0x90, SW2=0x00) ``` @@ -66,9 +66,9 @@ Press-to-confirm button offers an extra security layer by requiring the user con This feature is disabled by default but can be enabled rapidly by setting the LSB bit to 1: ``` -$ opensc-tool -s 805406000101 +$ opensc-tool -s 806406000101 Using reader with a card: Free Software Initiative of Japan Gnuk -Sending: 80 54 06 00 01 01 +Sending: 80 64 06 00 01 01 Received (SW1=0x90, SW2=0x00) ``` @@ -77,9 +77,9 @@ At this moment, when a private/secret key is loaded, the Pico HSM will wait for To disable, the LSB bit must be set to 0: ``` -$ opensc-tool -s 805406000100 +$ opensc-tool -s 806406000100 Using reader with a card: Free Software Initiative of Japan Gnuk -Sending: 80 54 06 00 01 00 +Sending: 80 64 06 00 01 00 Received (SW1=0x90, SW2=0x00) ``` diff --git a/src/hsm/sc_hsm.c b/src/hsm/sc_hsm.c index 4269ba4..34fe80e 100644 --- a/src/hsm/sc_hsm.c +++ b/src/hsm/sc_hsm.c @@ -1812,9 +1812,9 @@ typedef struct cmd #define INS_KEY_GEN 0x48 #define INS_INITIALIZE 0x50 #define INS_IMPORT_DKEK 0x52 -#define INS_EXTRAS 0x54 #define INS_LIST_KEYS 0x58 #define INS_DECRYPT_ASYM 0x62 +#define INS_EXTRAS 0x64 #define INS_SIGNATURE 0x68 #define INS_WRAP 0x72 #define INS_UNWRAP 0x74 From dec3d54ddd34bd4995261cce418076defb8eb1dc Mon Sep 17 00:00:00 2001 From: Pol Henarejos Date: Sat, 9 Apr 2022 20:29:13 +0200 Subject: [PATCH 13/41] Adding more SW codes. Signed-off-by: Pol Henarejos --- src/hsm/sc_hsm.h | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/hsm/sc_hsm.h b/src/hsm/sc_hsm.h index 061dc12..e45290b 100644 --- a/src/hsm/sc_hsm.h +++ b/src/hsm/sc_hsm.h @@ -26,29 +26,56 @@ extern const uint8_t sc_hsm_aid[]; #define SW_BYTES_REMAINING_00() set_res_sw (0x61, 0x00) #define SW_WARNING_STATE_UNCHANGED() set_res_sw (0x62, 0x00) +#define SW_WARNING_CORRUPTED() set_res_sw (0x62, 0x81) +#define SW_WARNING_EOF() set_res_sw (0x62, 0x82) +#define SW_WARNING_EF_DEACTIVATED() set_res_sw (0x62, 0x83) +#define SW_WARNING_WRONG_FCI() set_res_sw (0x62, 0x84) +#define SW_WARNING_EF_TERMINATED() set_res_sw (0x62, 0x85) + +#define SW_WARNING_NOINFO() set_res_sw (0x63, 0x00) +#define SW_WARNING_FILLUP() set_res_sw (0x63, 0x81) + #define SW_EXEC_ERROR() set_res_sw (0x64, 0x00) + #define SW_MEMORY_FAILURE() set_res_sw (0x65, 0x81) + #define SW_WRONG_LENGTH() set_res_sw (0x67, 0x00) #define SW_WRONG_DATA() set_res_sw (0x67, 0x00) + #define SW_LOGICAL_CHANNEL_NOT_SUPPORTED() set_res_sw (0x68, 0x81) #define SW_SECURE_MESSAGING_NOT_SUPPORTED() set_res_sw (0x68, 0x82) + +#define SW_COMMAND_INCOMPATIBLE() set_res_sw (0x69, 0x81) #define SW_SECURITY_STATUS_NOT_SATISFIED() set_res_sw (0x69, 0x82) #define SW_PIN_BLOCKED() set_res_sw (0x69, 0x83) #define SW_DATA_INVALID() set_res_sw (0x69, 0x84) #define SW_CONDITIONS_NOT_SATISFIED() set_res_sw (0x69, 0x85) #define SW_COMMAND_NOT_ALLOWED() set_res_sw (0x69, 0x86) +#define SW_SECURE_MESSAGING_MISSING_DO() set_res_sw (0x69, 0x87) +#define SW_SECURE_MESSAGING_INCORRECT_DO() set_res_sw (0x69, 0x88) #define SW_APPLET_SELECT_FAILED() set_res_sw (0x69, 0x99) + +#define SW_INCORRECT_PARAMS() set_res_sw (0x6A, 0x80) #define SW_FUNC_NOT_SUPPORTED() set_res_sw (0x6A, 0x81) #define SW_FILE_NOT_FOUND() set_res_sw (0x6A, 0x82) #define SW_RECORD_NOT_FOUND() set_res_sw (0x6A, 0x83) #define SW_FILE_FULL() set_res_sw (0x6A, 0x84) +#define SW_WRONG_NE() set_res_sw (0x6A, 0x85) #define SW_INCORRECT_P1P2() set_res_sw (0x6A, 0x86) +#define SW_WRONG_NC() set_res_sw (0x6A, 0x87) #define SW_REFERENCE_NOT_FOUND() set_res_sw (0x6A, 0x88) +#define SW_FILE_EXISTS() set_res_sw (0x6A, 0x89) + #define SW_WRONG_P1P2() set_res_sw (0x6B, 0x00) + #define SW_CORRECT_LENGTH_00() set_res_sw (0x6C, 0x00) + #define SW_INS_NOT_SUPPORTED() set_res_sw (0x6D, 0x00) + #define SW_CLA_NOT_SUPPORTED() set_res_sw (0x6E, 0x00) + #define SW_UNKNOWN() set_res_sw (0x6F, 0x00) + #define SW_OK() set_res_sw (0x90, 0x00) #define HSM_OK 0 From b545a1618bcd28c62209a467ffab403ad31c2e80 Mon Sep 17 00:00:00 2001 From: Pol Henarejos Date: Sat, 9 Apr 2022 20:50:00 +0200 Subject: [PATCH 14/41] Added Manage Security Environment command. Signed-off-by: Pol Henarejos --- src/hsm/sc_hsm.c | 38 ++++++++++++++++++++++++++++++++++++++ src/hsm/sc_hsm.h | 2 ++ 2 files changed, 40 insertions(+) diff --git a/src/hsm/sc_hsm.c b/src/hsm/sc_hsm.c index 34fe80e..874609f 100644 --- a/src/hsm/sc_hsm.c +++ b/src/hsm/sc_hsm.c @@ -497,6 +497,9 @@ static int cmd_verify() { return SW_OK(); return set_res_sw(0x63, 0xc0 | file_read_uint8(file_retries_sopin->data+2)); } + else if (p2 == 0x85) { + return SW_OK(); + } return SW_REFERENCE_NOT_FOUND(); } @@ -1798,6 +1801,39 @@ static int cmd_extras() { return SW_OK(); } +enum MSE_protocol { + MSE_AES = 0, + MSE_3DES, + MSE_NONE +} mse_protocol; + +static int cmd_mse() { + int p1 = P1(apdu); + int p2 = P2(apdu); + if (p1 & 0x1) { //SET + if (p2 == 0xA4) { //AT + const uint8_t *p = apdu.cmd_apdu_data; + while (p-apdu.cmd_apdu_data < apdu.cmd_apdu_data_len) { + uint8_t tag = *p++; + uint8_t tag_len = *p++; + if (tag == 0x80) { + if (tag_len == 10 && memcmp(p, "\x04\x00\x7F\x00\x07\x02\x02\x03\x02\x02", tag_len) == 0) + mse_protocol = MSE_AES; + else if (tag_len == 10 && memcmp(p, "\x04\x00\x7F\x00\x07\x02\x02\x03\x02\x01", tag_len) == 0) + mse_protocol = MSE_3DES; + else + return SW_REFERENCE_NOT_FOUND(); + } + } + } + else + return SW_INCORRECT_P1P2(); + } + else + return SW_INCORRECT_P1P2(); + return SW_OK(); +} + typedef struct cmd { @@ -1806,6 +1842,7 @@ typedef struct cmd } cmd_t; #define INS_VERIFY 0x20 +#define INS_MSE 0x22 #define INS_CHANGE_PIN 0x24 #define INS_RESET_RETRY 0x2C #define INS_KEYPAIR_GEN 0x46 @@ -1849,6 +1886,7 @@ static const cmd_t cmds[] = { { INS_CIPHER_SYM, cmd_cipher_sym }, { INS_DERIVE_ASYM, cmd_derive_asym }, { INS_EXTRAS, cmd_extras }, + { INS_MSE, cmd_mse }, { 0x00, 0x0} }; diff --git a/src/hsm/sc_hsm.h b/src/hsm/sc_hsm.h index e45290b..31d612a 100644 --- a/src/hsm/sc_hsm.h +++ b/src/hsm/sc_hsm.h @@ -39,6 +39,8 @@ extern const uint8_t sc_hsm_aid[]; #define SW_MEMORY_FAILURE() set_res_sw (0x65, 0x81) +#define SW_SECURE_MESSAGE_EXEC_ERROR() set_res_sw (0x66, 0x00) + #define SW_WRONG_LENGTH() set_res_sw (0x67, 0x00) #define SW_WRONG_DATA() set_res_sw (0x67, 0x00) From 6c892af9f1ae6a4e81b942c8e9387047199c9848 Mon Sep 17 00:00:00 2001 From: Pol Henarejos Date: Sat, 9 Apr 2022 23:44:45 +0200 Subject: [PATCH 15/41] Adding authentication command. Not finished. Needs lot of work. Signed-off-by: Pol Henarejos --- src/hsm/sc_hsm.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/src/hsm/sc_hsm.c b/src/hsm/sc_hsm.c index 874609f..c1a2e92 100644 --- a/src/hsm/sc_hsm.c +++ b/src/hsm/sc_hsm.c @@ -1806,6 +1806,8 @@ enum MSE_protocol { MSE_3DES, MSE_NONE } mse_protocol; +uint8_t nonce[8]; +uint8_t auth_token[8]; static int cmd_mse() { int p1 = P1(apdu); @@ -1834,6 +1836,33 @@ static int cmd_mse() { return SW_OK(); } +int cmd_general_authenticate() { + if (P1(apdu) == 0x0 && P2(apdu) == 0x0) { + if (apdu.cmd_apdu_data[0] == 0x7C) { + const uint8_t *p = &apdu.cmd_apdu_data[2]; + int r = 0; + mbedtls_ecp_point P; + mbedtls_ecp_point_init(&P); + mbedtls_ecp_group grp; + mbedtls_ecp_group_init(&grp); + r = mbedtls_ecp_group_load(&grp, MBEDTLS_ECP_DP_SECP192R1); + if (r != 0) + return SW_EXEC_ERROR(); + while (p-apdu.cmd_apdu_data < apdu.cmd_apdu_data[1]) { + uint8_t tag = *p++; + uint8_t tag_len = *p++; + if (tag == 0x80) { + int r = mbedtls_ecp_point_read_binary(&grp, &P, p, tag_len); + if (r != 0) + return SW_WRONG_DATA(); + } + } + memcpy(nonce, random_bytes_get(8), 8); + } + } + return SW_OK(); +} + typedef struct cmd { @@ -1858,6 +1887,7 @@ typedef struct cmd #define INS_DERIVE_ASYM 0x76 #define INS_CIPHER_SYM 0x78 #define INS_CHALLENGE 0x84 +#define INS_GENERAL_AUTHENTICATE 0x86 #define INS_SELECT_FILE 0xA4 #define INS_READ_BINARY 0xB0 #define INS_READ_BINARY_ODD 0xB1 @@ -1887,6 +1917,7 @@ static const cmd_t cmds[] = { { INS_DERIVE_ASYM, cmd_derive_asym }, { INS_EXTRAS, cmd_extras }, { INS_MSE, cmd_mse }, + { INS_GENERAL_AUTHENTICATE, cmd_general_authenticate }, { 0x00, 0x0} }; From c098d80524a6f120ccb03f39767dfb2024c7366b Mon Sep 17 00:00:00 2001 From: Pol Henarejos Date: Sun, 10 Apr 2022 01:55:57 +0200 Subject: [PATCH 16/41] Adding private key of termca. It is the worst thing I can do, but first I need to develop the secure channel, which uses the private key of device. Later, I will figure out how to generate the private key and certificate during initialization, but it will be difficult, as it needs to be signed by the CA. Signed-off-by: Pol Henarejos --- src/hsm/cvcerts.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/hsm/cvcerts.h b/src/hsm/cvcerts.h index bdd4089..7f3dc3d 100644 --- a/src/hsm/cvcerts.h +++ b/src/hsm/cvcerts.h @@ -38,4 +38,10 @@ static const unsigned char dica[] = { 0xb7,0x33,0x70,0xd6,0x00,0xff,0x73,0x0c,0x5d }; +static const unsigned char termca_pk[] = { + 0x18, 0x00, + 0xD9,0xE5,0x1B,0x79,0xF2,0x80,0x49,0x2B,0x35,0xFC,0x8C,0xC4,0xFC,0x5C,0xF4,0x72, + 0x25,0xC7,0x5B,0x08,0xFD,0xBC,0xE1,0x13 +}; + #endif From 57d593561ac46d7c7402841e503fc23c460b8172 Mon Sep 17 00:00:00 2001 From: Pol Henarejos Date: Sun, 10 Apr 2022 19:00:52 +0200 Subject: [PATCH 17/41] Moving all SM stuff to EAC. Signed-off-by: Pol Henarejos --- CMakeLists.txt | 1 + src/hsm/eac.c | 67 ++++++++++++++++++++++++++++++++++++++ src/hsm/eac.h | 37 +++++++++++++++++++++ src/hsm/hsm2040.h | 2 +- src/hsm/sc_hsm.c | 83 +++++++++++++++++++++++++++++++++++------------ 5 files changed, 168 insertions(+), 22 deletions(-) create mode 100644 src/hsm/eac.c create mode 100644 src/hsm/eac.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 9910399..2952424 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -53,6 +53,7 @@ target_sources(pico_hsm PUBLIC ${CMAKE_CURRENT_LIST_DIR}/src/rng/neug.c ${CMAKE_CURRENT_LIST_DIR}/src/hsm/crypto_utils.c ${CMAKE_CURRENT_LIST_DIR}/src/hsm/dkek.c + ${CMAKE_CURRENT_LIST_DIR}/src/hsm/eac.c ${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/sha256.c ${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/aes.c diff --git a/src/hsm/eac.c b/src/hsm/eac.c new file mode 100644 index 0000000..a1bc696 --- /dev/null +++ b/src/hsm/eac.c @@ -0,0 +1,67 @@ +/* + * This file is part of the Pico HSM distribution (https://github.com/polhenarejos/pico-hsm). + * Copyright (c) 2022 Pol Henarejos. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "eac.h" +#include "crypto_utils.h" +#include "random.h" +#include "mbedtls/cmac.h" + +static uint8_t nonce[8]; +static uint8_t auth_token[8]; +static uint8_t sm_kmac[16]; +static uint8_t sm_kenc[16]; +static MSE_protocol sm_protocol; + +bool is_secured_apdu() { + return (CLA(apdu) & 0xC); +} + +void sm_derive_key(const uint8_t *input, size_t input_len, uint8_t counter, const uint8_t *nonce, size_t nonce_len, uint8_t *out) { + uint8_t *b = (uint8_t *)calloc(1, input_len+nonce_len+4); + if (input) + memcpy(b, input, input_len); + if (nonce) + memcpy(b+input_len, nonce, nonce_len); + b[input_len+nonce_len+3] = counter; + uint8_t digest[20]; + generic_hash(MBEDTLS_MD_SHA1, b, input_len+nonce_len+4, digest); + memcpy(out, digest, 16); + free(b); +} + +void sm_derive_all_keys(const uint8_t *derived, size_t derived_len) { + memcpy(nonce, random_bytes_get(8), 8); + sm_derive_key(derived, derived_len, 1, nonce, sizeof(nonce), sm_kenc); + sm_derive_key(derived, derived_len, 2, nonce, sizeof(nonce), sm_kmac); +} + +void sm_set_protocol(MSE_protocol proto) { + sm_protocol = proto; +} + +MSE_protocol sm_get_protocol() { + return sm_protocol; +} + +uint8_t *sm_get_nonce() { + return nonce; +} + +int sm_sign(uint8_t *in, size_t in_len, uint8_t *out) { + return mbedtls_cipher_cmac(mbedtls_cipher_info_from_type(MBEDTLS_CIPHER_AES_128_ECB), sm_kmac, 128, in, in_len, out); +} + diff --git a/src/hsm/eac.h b/src/hsm/eac.h new file mode 100644 index 0000000..0f02a8c --- /dev/null +++ b/src/hsm/eac.h @@ -0,0 +1,37 @@ +/* + * This file is part of the Pico HSM distribution (https://github.com/polhenarejos/pico-hsm). + * Copyright (c) 2022 Pol Henarejos. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef _EAC_H_ +#define _EAC_H_ + +#include +#include "pico/stdlib.h" +#include "hsm2040.h" + +typedef enum MSE_protocol { + MSE_AES = 0, + MSE_3DES, + MSE_NONE +}MSE_protocol; + +extern void sm_derive_all_keys(const uint8_t *input, size_t input_len); +extern void sm_set_protocol(MSE_protocol proto); +extern MSE_protocol sm_get_protocol(); +extern uint8_t *sm_get_nonce(); +extern int sm_sign(uint8_t *in, size_t in_len, uint8_t *out); + +#endif diff --git a/src/hsm/hsm2040.h b/src/hsm/hsm2040.h index 996e29d..0b48620 100644 --- a/src/hsm/hsm2040.h +++ b/src/hsm/hsm2040.h @@ -106,7 +106,7 @@ enum ccid_state { CCID_STATE_EXEC_REQUESTED, /* Exec requested */ }; -#define CLS(a) a.cmd_apdu_head[0] +#define CLA(a) a.cmd_apdu_head[0] #define INS(a) a.cmd_apdu_head[1] #define P1(a) a.cmd_apdu_head[2] #define P2(a) a.cmd_apdu_head[3] diff --git a/src/hsm/sc_hsm.c b/src/hsm/sc_hsm.c index c1a2e92..f92d89f 100644 --- a/src/hsm/sc_hsm.c +++ b/src/hsm/sc_hsm.c @@ -33,6 +33,7 @@ #include "crypto_utils.h" #include "dkek.h" #include "hardware/rtc.h" +#include "eac.h" const uint8_t sc_hsm_aid[] = { 11, @@ -1801,14 +1802,6 @@ static int cmd_extras() { return SW_OK(); } -enum MSE_protocol { - MSE_AES = 0, - MSE_3DES, - MSE_NONE -} mse_protocol; -uint8_t nonce[8]; -uint8_t auth_token[8]; - static int cmd_mse() { int p1 = P1(apdu); int p2 = P2(apdu); @@ -1820,12 +1813,13 @@ static int cmd_mse() { uint8_t tag_len = *p++; if (tag == 0x80) { if (tag_len == 10 && memcmp(p, "\x04\x00\x7F\x00\x07\x02\x02\x03\x02\x02", tag_len) == 0) - mse_protocol = MSE_AES; + sm_set_protocol(MSE_AES); else if (tag_len == 10 && memcmp(p, "\x04\x00\x7F\x00\x07\x02\x02\x03\x02\x01", tag_len) == 0) - mse_protocol = MSE_3DES; + sm_set_protocol(MSE_3DES); else return SW_REFERENCE_NOT_FOUND(); } + p += tag_len; } } else @@ -1841,23 +1835,70 @@ int cmd_general_authenticate() { if (apdu.cmd_apdu_data[0] == 0x7C) { const uint8_t *p = &apdu.cmd_apdu_data[2]; int r = 0; - mbedtls_ecp_point P; - mbedtls_ecp_point_init(&P); - mbedtls_ecp_group grp; - mbedtls_ecp_group_init(&grp); - r = mbedtls_ecp_group_load(&grp, MBEDTLS_ECP_DP_SECP192R1); - if (r != 0) - return SW_EXEC_ERROR(); + size_t pubkey_len = 0; + const uint8_t *pubkey = NULL; while (p-apdu.cmd_apdu_data < apdu.cmd_apdu_data[1]) { uint8_t tag = *p++; uint8_t tag_len = *p++; if (tag == 0x80) { - int r = mbedtls_ecp_point_read_binary(&grp, &P, p, tag_len); - if (r != 0) - return SW_WRONG_DATA(); + pubkey = p-1; //mbedtls ecdh starts reading one pos before + pubkey_len = tag_len+1; } + p += tag_len; } - memcpy(nonce, random_bytes_get(8), 8); + mbedtls_ecdh_context ctx; + int key_size = file_read_uint16(termca_pk); + mbedtls_ecdh_init(&ctx); + mbedtls_ecp_group_id gid = MBEDTLS_ECP_DP_SECP192R1; + r = mbedtls_ecdh_setup(&ctx, gid); + if (r != 0) { + mbedtls_ecdh_free(&ctx); + return SW_DATA_INVALID(); + } + r = mbedtls_mpi_read_binary(&ctx.ctx.mbed_ecdh.d, termca_pk+2, key_size); + if (r != 0) { + mbedtls_ecdh_free(&ctx); + return SW_DATA_INVALID(); + } + r = mbedtls_ecdh_read_public(&ctx, pubkey, pubkey_len); + if (r != 0) { + mbedtls_ecdh_free(&ctx); + return SW_DATA_INVALID(); + } + size_t olen = 0; + uint8_t derived[MBEDTLS_ECP_MAX_BYTES]; + r = mbedtls_ecdh_calc_secret(&ctx, &olen, derived, MBEDTLS_ECP_MAX_BYTES, random_gen, NULL); + mbedtls_ecdh_free(&ctx); + if (r != 0) { + return SW_EXEC_ERROR(); + } + + sm_derive_all_keys(derived, olen); + + uint8_t *t = (uint8_t *)calloc(1, pubkey_len+16); + memcpy(t, "\x7F\x49\x3F\x06\x0A", 5); + if (sm_get_protocol() == MSE_AES) + memcpy(t+5, "\x04\x00\x7F\x00\x07\x02\x02\x03\x02\x02", 10); + else if (sm_get_protocol() == MSE_3DES) + memcpy(t+5, "\x04\x00\x7F\x00\x07\x02\x02\x03\x02\x01", 10); + t[15] = 0x86; + memcpy(t+16, pubkey, pubkey_len); + + res_APDU[res_APDU_size++] = 0x7C; + res_APDU[res_APDU_size++] = 20; + res_APDU[res_APDU_size++] = 0x81; + res_APDU[res_APDU_size++] = 8; + memcpy(res_APDU+res_APDU_size, sm_get_nonce(), 8); + res_APDU_size += 8; + res_APDU[res_APDU_size++] = 0x82; + res_APDU[res_APDU_size++] = 8; + + r = sm_sign(t, pubkey_len+16, res_APDU+res_APDU_size); + + free(t); + if (r != HSM_OK) + return SW_EXEC_ERROR(); + res_APDU_size += 8; } } return SW_OK(); From c3a93a46ba6caf040af7c07cab4c6b41df6a1e3c Mon Sep 17 00:00:00 2001 From: Pol Henarejos Date: Sun, 10 Apr 2022 20:23:36 +0200 Subject: [PATCH 18/41] Adding unwrap(), to decrypt and verify secure APDU. Signed-off-by: Pol Henarejos --- src/hsm/eac.c | 142 ++++++++++++++++++++++++++++++++++++++++++++++- src/hsm/eac.h | 5 ++ src/hsm/sc_hsm.c | 1 + src/hsm/sc_hsm.h | 1 + 4 files changed, 148 insertions(+), 1 deletion(-) diff --git a/src/hsm/eac.c b/src/hsm/eac.c index a1bc696..b7cdbb1 100644 --- a/src/hsm/eac.c +++ b/src/hsm/eac.c @@ -16,6 +16,7 @@ */ #include "eac.h" +#include "sc_hsm.h" #include "crypto_utils.h" #include "random.h" #include "mbedtls/cmac.h" @@ -24,7 +25,10 @@ static uint8_t nonce[8]; static uint8_t auth_token[8]; static uint8_t sm_kmac[16]; static uint8_t sm_kenc[16]; -static MSE_protocol sm_protocol; +static MSE_protocol sm_protocol = MSE_NONE; +static mbedtls_mpi sm_mSSC; +static uint8_t sm_blocksize = 0; +static uint8_t sm_iv[16]; bool is_secured_apdu() { return (CLA(apdu) & 0xC); @@ -47,10 +51,18 @@ void sm_derive_all_keys(const uint8_t *derived, size_t derived_len) { memcpy(nonce, random_bytes_get(8), 8); sm_derive_key(derived, derived_len, 1, nonce, sizeof(nonce), sm_kenc); sm_derive_key(derived, derived_len, 2, nonce, sizeof(nonce), sm_kmac); + mbedtls_mpi_init(&sm_mSSC); + mbedtls_mpi_grow(&sm_mSSC, sm_blocksize); + mbedtls_mpi_lset(&sm_mSSC, 0); + memset(sm_iv, 0, sizeof(sm_iv)); } void sm_set_protocol(MSE_protocol proto) { sm_protocol = proto; + if (proto == MSE_AES) + sm_blocksize = 16; + else if (proto == MSE_3DES) + sm_blocksize = 8; } MSE_protocol sm_get_protocol() { @@ -65,3 +77,131 @@ int sm_sign(uint8_t *in, size_t in_len, uint8_t *out) { return mbedtls_cipher_cmac(mbedtls_cipher_info_from_type(MBEDTLS_CIPHER_AES_128_ECB), sm_kmac, 128, in, in_len, out); } +int sm_unwrap() { + uint8_t sm_indicator = (CLA(apdu) >> 2) & 0x3; + if (sm_indicator == 0) + return HSM_OK; + int r = sm_verify(); + if (r != HSM_OK) + return r; + int le = sm_get_le(); + if (le >= 0) + apdu.expected_res_size = le; + const uint8_t *p = apdu.cmd_apdu_data; + uint8_t *body = NULL; + size_t body_size = 0; + bool is87 = false; + while (p-apdu.cmd_apdu_data < apdu.cmd_apdu_data_len) { + uint8_t tag = *p++; + uint8_t tag_len = *p++; + if (tag == 0x87 || tag == 0x85) { + body = (uint8_t *)p; + body_size = tag_len; + if (tag == 0x87) { + is87 = true; + body_size--; + } + } + p += tag_len; + } + if (!body) + return HSM_WRONG_DATA; + if (is87 && *body++ != 0x1) { + return HSM_WRONG_PADDING; + } + sm_update_iv(); + aes_decrypt(sm_kenc, sm_iv, 128, HSM_AES_MODE_CBC, body, body_size); + memmove(apdu.cmd_apdu_data, body, body_size); + apdu.cmd_apdu_data_len = sm_remove_padding(apdu.cmd_apdu_data, body_size); + return HSM_OK; +} + +int sm_get_le() { + const uint8_t *p = apdu.cmd_apdu_data; + while (p-apdu.cmd_apdu_data < apdu.cmd_apdu_data_len) { + uint8_t tag = *p++; + uint8_t tag_len = *p++; + if (tag == 0x97) { + uint32_t le = 0; + for (int t = 1; t <= tag_len; t++) + le |= (*p++) << (tag_len-t); + return le; + } + p += tag_len; + } + return -1; +} + +void sm_update_iv() { + uint8_t tmp_iv[16]; + mbedtls_mpi_write_binary(&sm_mSSC, tmp_iv, sizeof(tmp_iv)); + aes_encrypt(sm_kenc, sm_iv, 128, HSM_AES_MODE_CBC, tmp_iv, sizeof(tmp_iv)); + memcpy(sm_iv, tmp_iv, sizeof(tmp_iv)); +} + +int sm_verify() { + uint8_t input[1024]; + memset(input, 0, sizeof(input)); + int input_len = 0, r = 0; + bool add_header = (CLA(apdu) & 0xC) == 0xC; + int data_len = (int)(apdu.cmd_apdu_data_len/sm_blocksize)*sm_blocksize; + if (data_len % sm_blocksize) + data_len += sm_blocksize; + if (data_len+(add_header ? sm_blocksize : 0) > 1024) + return HSM_WRONG_LENGTH; + mbedtls_mpi ssc; + mbedtls_mpi_init(&ssc); + mbedtls_mpi_add_int(&ssc, &sm_mSSC, 1); + mbedtls_mpi_copy(&sm_mSSC, &ssc); + r = mbedtls_mpi_write_binary(&ssc, input, sm_blocksize); + input_len += sm_blocksize; + mbedtls_mpi_free(&ssc); + if (r != 0) + return HSM_EXEC_ERROR; + if (add_header) { + input[input_len++] = CLA(apdu); + input[input_len++] = INS(apdu); + input[input_len++] = P1(apdu); + input[input_len++] = P2(apdu); + input[input_len++] = 0x80; + input_len += sm_blocksize-5; + } + bool some_added = false; + const uint8_t *p = apdu.cmd_apdu_data, *mac = NULL; + size_t mac_len = 0; + while (p-apdu.cmd_apdu_data < apdu.cmd_apdu_data_len) { + uint8_t tag = *p++; + uint8_t tag_len = *p++; + if (tag & 0x1) { + memcpy(input+input_len, p-2, tag_len+2); + input_len += tag_len+2; + some_added = true; + } + if (tag == 0x8E) { + mac = p; + mac_len = tag_len; + } + p += tag_len; + } + if (!mac) + return HSM_WRONG_DATA; + if (some_added) { + input[input_len++] = 0x80; + input_len += (sm_blocksize - (input_len%sm_blocksize)); + } + uint8_t signature[16]; + r = sm_sign(input, input_len, signature); + if (r != 0) + return HSM_EXEC_ERROR; + if (memcmp(signature, mac, mac_len) == 0) + return HSM_OK; + return HSM_VERIFICATION_FAILED; +} + +int sm_remove_padding(const uint8_t *data, size_t data_len) { + int i = data_len-1; + for (; i >= 0 && data[i] == 0; i--); + if (i < 0 || data[i] != 0x80) + return -1; + return i; +} \ No newline at end of file diff --git a/src/hsm/eac.h b/src/hsm/eac.h index 0f02a8c..e6c2662 100644 --- a/src/hsm/eac.h +++ b/src/hsm/eac.h @@ -33,5 +33,10 @@ extern void sm_set_protocol(MSE_protocol proto); extern MSE_protocol sm_get_protocol(); extern uint8_t *sm_get_nonce(); extern int sm_sign(uint8_t *in, size_t in_len, uint8_t *out); +int sm_verify(); +void sm_update_iv(); +int sm_get_le(); +extern int sm_unwrap(); +int sm_remove_padding(const uint8_t *data, size_t data_len); #endif diff --git a/src/hsm/sc_hsm.c b/src/hsm/sc_hsm.c index f92d89f..c290bb4 100644 --- a/src/hsm/sc_hsm.c +++ b/src/hsm/sc_hsm.c @@ -1963,6 +1963,7 @@ static const cmd_t cmds[] = { }; int sc_hsm_process_apdu() { + int r = sm_unwrap(); for (const cmd_t *cmd = cmds; cmd->ins != 0x00; cmd++) { if (cmd->ins == INS(apdu)) return cmd->cmd_handler(); diff --git a/src/hsm/sc_hsm.h b/src/hsm/sc_hsm.h index 31d612a..ffed95e 100644 --- a/src/hsm/sc_hsm.h +++ b/src/hsm/sc_hsm.h @@ -93,6 +93,7 @@ extern const uint8_t sc_hsm_aid[]; #define HSM_WRONG_DKEK -1009 #define HSM_WRONG_SIGNATURE -1010 #define HSM_WRONG_PADDING -1011 +#define HSM_VERIFICATION_FAILED -1012 #define ALGO_RSA_RAW 0x20 /* RSA signature with external padding */ #define ALGO_RSA_DECRYPT 0x21 /* RSA decrypt */ From 964af6a064b7ca0d8964035669c28a55f105f824 Mon Sep 17 00:00:00 2001 From: Pol Henarejos Date: Sun, 10 Apr 2022 20:58:54 +0200 Subject: [PATCH 19/41] Adding wrap() to encrypt and sign response APDU. Signed-off-by: Pol Henarejos --- src/hsm/eac.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++++ src/hsm/eac.h | 1 + src/hsm/sc_hsm.c | 7 ++++-- 3 files changed, 61 insertions(+), 2 deletions(-) diff --git a/src/hsm/eac.c b/src/hsm/eac.c index b7cdbb1..0d29525 100644 --- a/src/hsm/eac.c +++ b/src/hsm/eac.c @@ -116,6 +116,61 @@ int sm_unwrap() { return HSM_OK; } +int sm_wrap() { + uint8_t sm_indicator = (CLA(apdu) >> 2) & 0x3; + if (sm_indicator == 0) + return HSM_OK; + uint8_t wrap[1024], input[1024]; + size_t input_len = 0; + memset(input, 0, sizeof(input)); + mbedtls_mpi ssc; + mbedtls_mpi_init(&ssc); + mbedtls_mpi_add_int(&ssc, &sm_mSSC, 1); + mbedtls_mpi_copy(&sm_mSSC, &ssc); + int r = mbedtls_mpi_write_binary(&ssc, input, sm_blocksize); + input_len += sm_blocksize; + mbedtls_mpi_free(&ssc); + if (res_APDU_size > 0) { + res_APDU[res_APDU_size++] = 0x80; + memset(res_APDU+res_APDU_size, 0, (sm_blocksize - (res_APDU_size%sm_blocksize))); + res_APDU_size += (sm_blocksize - (res_APDU_size%sm_blocksize)); + sm_update_iv(); + aes_encrypt(sm_kenc, sm_iv, 128, HSM_AES_MODE_CBC, res_APDU, res_APDU_size); + memmove(res_APDU+1, res_APDU, res_APDU_size); + res_APDU[0] = 0x1; + res_APDU_size++; + if (res_APDU_size < 128) { + memmove(res_APDU+2, res_APDU, res_APDU_size); + res_APDU[1] = res_APDU_size; + } + else if (res_APDU_size < 256) { + memmove(res_APDU+3, res_APDU, res_APDU_size); + res_APDU[1] = 0x81; + res_APDU[2] = res_APDU_size; + } + else { + memmove(res_APDU+4, res_APDU, res_APDU_size); + res_APDU[1] = 0x82; + res_APDU[2] = res_APDU_size >> 8; + res_APDU[3] = res_APDU_size & 0xff; + } + res_APDU[0] = 0x87; + } + res_APDU[res_APDU_size++] = 0x99; + res_APDU[res_APDU_size++] = 2; + res_APDU[res_APDU_size++] = apdu.sw >> 8; + res_APDU[res_APDU_size++] = apdu.sw & 0xff; + memcpy(input+input_len, res_APDU, res_APDU_size); + input_len += res_APDU_size; + input[input_len++] = 0x80; + input_len += (sm_blocksize - (input_len%sm_blocksize)); + r = sm_sign(input, input_len, res_APDU+res_APDU_size+2); + res_APDU[res_APDU_size++] = 0x8E; + res_APDU[res_APDU_size++] = 8; + res_APDU_size += 8; + return HSM_OK; +} + int sm_get_le() { const uint8_t *p = apdu.cmd_apdu_data; while (p-apdu.cmd_apdu_data < apdu.cmd_apdu_data_len) { diff --git a/src/hsm/eac.h b/src/hsm/eac.h index e6c2662..207c5a5 100644 --- a/src/hsm/eac.h +++ b/src/hsm/eac.h @@ -38,5 +38,6 @@ void sm_update_iv(); int sm_get_le(); extern int sm_unwrap(); int sm_remove_padding(const uint8_t *data, size_t data_len); +extern int sm_wrap(); #endif diff --git a/src/hsm/sc_hsm.c b/src/hsm/sc_hsm.c index c290bb4..931f459 100644 --- a/src/hsm/sc_hsm.c +++ b/src/hsm/sc_hsm.c @@ -1965,8 +1965,11 @@ static const cmd_t cmds[] = { int sc_hsm_process_apdu() { int r = sm_unwrap(); for (const cmd_t *cmd = cmds; cmd->ins != 0x00; cmd++) { - if (cmd->ins == INS(apdu)) - return cmd->cmd_handler(); + if (cmd->ins == INS(apdu)) { + int r = cmd->cmd_handler(); + sm_wrap(); + return r; + } } return SW_INS_NOT_SUPPORTED(); } \ No newline at end of file From f26668b81d1ed53b98d6f5dad95ef2caadf3b7e8 Mon Sep 17 00:00:00 2001 From: Pol Henarejos Date: Mon, 11 Apr 2022 01:16:20 +0200 Subject: [PATCH 20/41] Fixed IV computation. IV is computed encrypting macCounter with a initial IV=0x0000. Signed-off-by: Pol Henarejos --- src/hsm/eac.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/hsm/eac.c b/src/hsm/eac.c index 0d29525..6fcc86d 100644 --- a/src/hsm/eac.c +++ b/src/hsm/eac.c @@ -113,6 +113,7 @@ int sm_unwrap() { aes_decrypt(sm_kenc, sm_iv, 128, HSM_AES_MODE_CBC, body, body_size); memmove(apdu.cmd_apdu_data, body, body_size); apdu.cmd_apdu_data_len = sm_remove_padding(apdu.cmd_apdu_data, body_size); + DEBUG_PAYLOAD(apdu.cmd_apdu_data, apdu.cmd_apdu_data_len); return HSM_OK; } @@ -120,7 +121,7 @@ int sm_wrap() { uint8_t sm_indicator = (CLA(apdu) >> 2) & 0x3; if (sm_indicator == 0) return HSM_OK; - uint8_t wrap[1024], input[1024]; + uint8_t input[1024]; size_t input_len = 0; memset(input, 0, sizeof(input)); mbedtls_mpi ssc; @@ -130,6 +131,7 @@ int sm_wrap() { int r = mbedtls_mpi_write_binary(&ssc, input, sm_blocksize); input_len += sm_blocksize; mbedtls_mpi_free(&ssc); + DEBUG_PAYLOAD(res_APDU, res_APDU_size); if (res_APDU_size > 0) { res_APDU[res_APDU_size++] = 0x80; memset(res_APDU+res_APDU_size, 0, (sm_blocksize - (res_APDU_size%sm_blocksize))); @@ -188,10 +190,11 @@ int sm_get_le() { } void sm_update_iv() { - uint8_t tmp_iv[16]; - mbedtls_mpi_write_binary(&sm_mSSC, tmp_iv, sizeof(tmp_iv)); - aes_encrypt(sm_kenc, sm_iv, 128, HSM_AES_MODE_CBC, tmp_iv, sizeof(tmp_iv)); - memcpy(sm_iv, tmp_iv, sizeof(tmp_iv)); + uint8_t tmp_iv[16], sc_counter[16]; + memset(tmp_iv, 0, sizeof(tmp_iv)); //IV is always 0 for encryption of IV based on counter + mbedtls_mpi_write_binary(&sm_mSSC, sc_counter, sizeof(sc_counter)); + aes_encrypt(sm_kenc, tmp_iv, 128, HSM_AES_MODE_CBC, sc_counter, sizeof(sc_counter)); + memcpy(sm_iv, sc_counter, sizeof(sc_counter)); } int sm_verify() { From c4c2bf86ba8b9c380d1697bdac727058ad753d38 Mon Sep 17 00:00:00 2001 From: Pol Henarejos Date: Mon, 11 Apr 2022 01:38:15 +0200 Subject: [PATCH 21/41] Fix response APDU in secure channel. Signed-off-by: Pol Henarejos --- src/hsm/eac.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/hsm/eac.c b/src/hsm/eac.c index 6fcc86d..32242e4 100644 --- a/src/hsm/eac.c +++ b/src/hsm/eac.c @@ -131,11 +131,11 @@ int sm_wrap() { int r = mbedtls_mpi_write_binary(&ssc, input, sm_blocksize); input_len += sm_blocksize; mbedtls_mpi_free(&ssc); - DEBUG_PAYLOAD(res_APDU, res_APDU_size); if (res_APDU_size > 0) { res_APDU[res_APDU_size++] = 0x80; memset(res_APDU+res_APDU_size, 0, (sm_blocksize - (res_APDU_size%sm_blocksize))); res_APDU_size += (sm_blocksize - (res_APDU_size%sm_blocksize)); + DEBUG_PAYLOAD(res_APDU, res_APDU_size); sm_update_iv(); aes_encrypt(sm_kenc, sm_iv, 128, HSM_AES_MODE_CBC, res_APDU, res_APDU_size); memmove(res_APDU+1, res_APDU, res_APDU_size); @@ -144,17 +144,20 @@ int sm_wrap() { if (res_APDU_size < 128) { memmove(res_APDU+2, res_APDU, res_APDU_size); res_APDU[1] = res_APDU_size; + res_APDU_size += 2; } else if (res_APDU_size < 256) { memmove(res_APDU+3, res_APDU, res_APDU_size); res_APDU[1] = 0x81; res_APDU[2] = res_APDU_size; + res_APDU_size += 3; } else { memmove(res_APDU+4, res_APDU, res_APDU_size); res_APDU[1] = 0x82; res_APDU[2] = res_APDU_size >> 8; res_APDU[3] = res_APDU_size & 0xff; + res_APDU_size += 4; } res_APDU[0] = 0x87; } From 2f1f8e0c90e14e4348703e6ee19a20c82549ca81 Mon Sep 17 00:00:00 2001 From: Pol Henarejos Date: Mon, 11 Apr 2022 01:44:18 +0200 Subject: [PATCH 22/41] Fix parsing TLV in signatures. Signed-off-by: Pol Henarejos --- src/hsm/eac.c | 34 ++++++++++++++++++++++++++++------ src/hsm/eac.h | 1 + 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/src/hsm/eac.c b/src/hsm/eac.c index 32242e4..7d87d54 100644 --- a/src/hsm/eac.c +++ b/src/hsm/eac.c @@ -93,7 +93,14 @@ int sm_unwrap() { bool is87 = false; while (p-apdu.cmd_apdu_data < apdu.cmd_apdu_data_len) { uint8_t tag = *p++; - uint8_t tag_len = *p++; + uint16_t tag_len = *p++; + if (tag_len == 0x82) { + tag_len = *p++ << 8; + tag_len |= *p++; + } + else if (tag_len == 0x81) { + tag_len = *p++; + } if (tag == 0x87 || tag == 0x85) { body = (uint8_t *)p; body_size = tag_len; @@ -180,7 +187,14 @@ int sm_get_le() { const uint8_t *p = apdu.cmd_apdu_data; while (p-apdu.cmd_apdu_data < apdu.cmd_apdu_data_len) { uint8_t tag = *p++; - uint8_t tag_len = *p++; + uint16_t tag_len = *p++; + if (tag_len == 0x82) { + tag_len = *p++ << 8; + tag_len |= *p++; + } + else if (tag_len == 0x81) { + tag_len = *p++; + } if (tag == 0x97) { uint32_t le = 0; for (int t = 1; t <= tag_len; t++) @@ -228,14 +242,22 @@ int sm_verify() { input_len += sm_blocksize-5; } bool some_added = false; - const uint8_t *p = apdu.cmd_apdu_data, *mac = NULL; + const uint8_t *p = apdu.cmd_apdu_data, *mac = NULL, *initag = NULL; size_t mac_len = 0; while (p-apdu.cmd_apdu_data < apdu.cmd_apdu_data_len) { + initag = p; uint8_t tag = *p++; - uint8_t tag_len = *p++; + uint16_t tag_len = *p++; + if (tag_len == 0x82) { + tag_len = *p++ << 8; + tag_len |= *p++; + } + else if (tag_len == 0x81) { + tag_len = *p++; + } if (tag & 0x1) { - memcpy(input+input_len, p-2, tag_len+2); - input_len += tag_len+2; + memcpy(input+input_len, initag, tag_len+(p-initag)); + input_len += tag_len+(p-initag); some_added = true; } if (tag == 0x8E) { diff --git a/src/hsm/eac.h b/src/hsm/eac.h index 207c5a5..82998e1 100644 --- a/src/hsm/eac.h +++ b/src/hsm/eac.h @@ -39,5 +39,6 @@ int sm_get_le(); extern int sm_unwrap(); int sm_remove_padding(const uint8_t *data, size_t data_len); extern int sm_wrap(); +extern bool is_secured_apdu(); #endif From 3781777138c8160e78f808aab7c663ca9ff08bb4 Mon Sep 17 00:00:00 2001 From: Pol Henarejos Date: Mon, 11 Apr 2022 11:37:41 +0200 Subject: [PATCH 23/41] Adding some kind of permanent flash memory that does not wipe out when initializing. Signed-off-by: Pol Henarejos --- src/fs/flash.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/fs/flash.c b/src/fs/flash.c index 4895eb2..569b275 100644 --- a/src/fs/flash.c +++ b/src/fs/flash.c @@ -35,11 +35,12 @@ */ #define FLASH_TARGET_OFFSET (PICO_FLASH_SIZE_BYTES >> 1) // DATA starts at the mid of flash #define FLASH_DATA_HEADER_SIZE (sizeof(uintptr_t)+sizeof(uint32_t)) +#define FLASH_PERMANENT_REGION (4*FLASH_SECTOR_SIZE) // 4 sectors (16kb) of permanent memory //To avoid possible future allocations, data region starts at the end of flash and goes upwards to the center region const uintptr_t start_data_pool = (XIP_BASE + FLASH_TARGET_OFFSET); -const uintptr_t end_data_pool = (XIP_BASE + PICO_FLASH_SIZE_BYTES)-FLASH_DATA_HEADER_SIZE; //This is a fixed value. DO NOT CHANGE +const uintptr_t end_data_pool = (XIP_BASE + PICO_FLASH_SIZE_BYTES)-FLASH_DATA_HEADER_SIZE-FLASH_PERMANENT_REGION; //This is a fixed value. DO NOT CHANGE #define FLASH_ADDR_DATA_STORAGE_START start_data_pool extern int flash_program_block(uintptr_t addr, const uint8_t *data, size_t len); From b61575bbc39c3bddb6a7a505513952a5d5c749bf Mon Sep 17 00:00:00 2001 From: Pol Henarejos Date: Mon, 11 Apr 2022 15:08:10 +0200 Subject: [PATCH 24/41] Adding some mutex to improve concurrency. Signed-off-by: Pol Henarejos --- src/fs/low_flash.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/fs/low_flash.c b/src/fs/low_flash.c index fe7ca72..4951fc6 100644 --- a/src/fs/low_flash.c +++ b/src/fs/low_flash.c @@ -153,8 +153,8 @@ int flash_program_block(uintptr_t addr, const uint8_t *data, size_t len) { } if (!(p = find_free_page(addr))) { - DEBUG_INFO("ERROR: FLASH CANNOT FIND A PAGE (rare error)\r\n"); mutex_exit(&mtx_flash); + DEBUG_INFO("ERROR: FLASH CANNOT FIND A PAGE (rare error)\r\n"); return HSM_ERR_MEMORY_FATAL; } memcpy(&p->page[addr&(FLASH_SECTOR_SIZE-1)], data, len); @@ -177,19 +177,19 @@ int flash_program_uintptr (uintptr_t addr, uintptr_t data) { uint8_t *flash_read(uintptr_t addr) { uintptr_t addr_alg = addr & -FLASH_SECTOR_SIZE; - //mutex_enter_blocking(&mtx_flash); + mutex_enter_blocking(&mtx_flash); if (ready_pages > 0) { for (int r = 0; r < TOTAL_FLASH_PAGES; r++) { if (flash_pages[r].ready && flash_pages[r].address == addr_alg) { uint8_t *v = &flash_pages[r].page[addr&(FLASH_SECTOR_SIZE-1)]; - //mutex_exit(&mtx_flash); + mutex_exit(&mtx_flash); return v; } } } uint8_t *v = (uint8_t *)addr; - //mutex_exit(&mtx_flash); + mutex_exit(&mtx_flash); return v; } From db5f5fd435b8fd8000fcf82b8549d65986a60eb5 Mon Sep 17 00:00:00 2001 From: Pol Henarejos Date: Mon, 11 Apr 2022 15:11:42 +0200 Subject: [PATCH 25/41] When working with SM, wrap() manipulates res_APDU. Thus, we cannot change the pointer of res_APDU anymore. Everything must be memcpy-ed. Signed-off-by: Pol Henarejos --- src/hsm/sc_hsm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hsm/sc_hsm.c b/src/hsm/sc_hsm.c index 83ece51..7915e18 100644 --- a/src/hsm/sc_hsm.c +++ b/src/hsm/sc_hsm.c @@ -388,7 +388,7 @@ static int cmd_read_binary() uint16_t maxle = data_len-offset; if (apdu.expected_res_size > maxle) apdu.expected_res_size = maxle; - res_APDU = file_read(ef->data+2+offset); + memcpy(res_APDU, file_read(ef->data+2+offset), data_len-offset); res_APDU_size = data_len-offset; } } @@ -569,7 +569,7 @@ static int cmd_challenge() { uint8_t *rb = (uint8_t *)random_bytes_get(apdu.expected_res_size); if (!rb) return SW_WRONG_LENGTH(); - res_APDU = rb; + memcpy(res_APDU, rb, apdu.expected_res_size); res_APDU_size = apdu.expected_res_size; return SW_OK(); } From af07f1d54975c90d18c177c94b2629b3cbb9464c Mon Sep 17 00:00:00 2001 From: Pol Henarejos Date: Mon, 11 Apr 2022 19:47:43 +0200 Subject: [PATCH 26/41] Added INS for session pin generation (needs randomization). Signed-off-by: Pol Henarejos --- src/hsm/eac.c | 4 ++++ src/hsm/eac.h | 2 ++ src/hsm/sc_hsm.c | 43 ++++++++++++++++++++++++++++++++++--------- 3 files changed, 40 insertions(+), 9 deletions(-) diff --git a/src/hsm/eac.c b/src/hsm/eac.c index 7d87d54..3bee3e9 100644 --- a/src/hsm/eac.c +++ b/src/hsm/eac.c @@ -29,6 +29,8 @@ static MSE_protocol sm_protocol = MSE_NONE; static mbedtls_mpi sm_mSSC; static uint8_t sm_blocksize = 0; static uint8_t sm_iv[16]; +size_t sm_session_pin_len = 0; +uint8_t sm_session_pin[16]; bool is_secured_apdu() { return (CLA(apdu) & 0xC); @@ -180,6 +182,8 @@ int sm_wrap() { res_APDU[res_APDU_size++] = 0x8E; res_APDU[res_APDU_size++] = 8; res_APDU_size += 8; + if (apdu.expected_res_size > 0) + apdu.expected_res_size = res_APDU_size; return HSM_OK; } diff --git a/src/hsm/eac.h b/src/hsm/eac.h index 82998e1..3270753 100644 --- a/src/hsm/eac.h +++ b/src/hsm/eac.h @@ -40,5 +40,7 @@ extern int sm_unwrap(); int sm_remove_padding(const uint8_t *data, size_t data_len); extern int sm_wrap(); extern bool is_secured_apdu(); +extern uint8_t sm_session_pin[16]; +extern size_t sm_session_pin_len; #endif diff --git a/src/hsm/sc_hsm.c b/src/hsm/sc_hsm.c index 7915e18..45f9b1f 100644 --- a/src/hsm/sc_hsm.c +++ b/src/hsm/sc_hsm.c @@ -440,15 +440,25 @@ int check_pin(const file_t *pin, const uint8_t *data, size_t len) { } isUserAuthenticated = false; has_session_pin = has_session_sopin = false; - uint8_t dhash[32]; - double_hash_pin(data, len, dhash); - if (sizeof(dhash) != file_read_uint16(pin->data)-1) //1 byte for pin len - return SW_CONDITIONS_NOT_SATISFIED(); - if (memcmp(file_read(pin->data+3), dhash, sizeof(dhash)) != 0) { - uint8_t retries; - if ((retries = pin_wrong_retry(pin)) < HSM_OK) - return SW_PIN_BLOCKED(); - return set_res_sw(0x63, 0xc0 | retries); + if (is_secured_apdu() && sm_session_pin_len > 0 && pin == file_pin1) { + if (len == sm_session_pin_len && memcmp(data, sm_session_pin, len) != 0) { + uint8_t retries; + if ((retries = pin_wrong_retry(pin)) < HSM_OK) + return SW_PIN_BLOCKED(); + return set_res_sw(0x63, 0xc0 | retries); + } + } + else { + uint8_t dhash[32]; + double_hash_pin(data, len, dhash); + if (sizeof(dhash) != file_read_uint16(pin->data)-1) //1 byte for pin len + return SW_CONDITIONS_NOT_SATISFIED(); + if (memcmp(file_read(pin->data+3), dhash, sizeof(dhash)) != 0) { + uint8_t retries; + if ((retries = pin_wrong_retry(pin)) < HSM_OK) + return SW_PIN_BLOCKED(); + return set_res_sw(0x63, 0xc0 | retries); + } } int r = pin_reset_retries(pin, false); if (r == HSM_ERR_BLOCKED) @@ -1905,6 +1915,19 @@ int cmd_general_authenticate() { return SW_OK(); } +int cmd_session_pin() { + if (P1(apdu) == 0x01 && P2(apdu) == 0x81) { + memcpy(sm_session_pin, "\x30\x31\x32\x33\x34\x35", 6); + sm_session_pin_len = 6; + + memcpy(res_APDU, sm_session_pin, sm_session_pin_len); + res_APDU_size = sm_session_pin_len; + apdu.expected_res_size = sm_session_pin_len; + } + else + return SW_INCORRECT_P1P2(); + return SW_OK(); +} typedef struct cmd { @@ -1921,6 +1944,7 @@ typedef struct cmd #define INS_INITIALIZE 0x50 #define INS_IMPORT_DKEK 0x52 #define INS_LIST_KEYS 0x58 +#define INS_SESSION_PIN 0x5A #define INS_DECRYPT_ASYM 0x62 #define INS_EXTRAS 0x64 #define INS_SIGNATURE 0x68 @@ -1960,6 +1984,7 @@ static const cmd_t cmds[] = { { INS_EXTRAS, cmd_extras }, { INS_MSE, cmd_mse }, { INS_GENERAL_AUTHENTICATE, cmd_general_authenticate }, + { INS_SESSION_PIN, cmd_session_pin }, { 0x00, 0x0} }; From 49d9ec7cf9ca793fbcc01c985aa9b214cbeac7cc Mon Sep 17 00:00:00 2001 From: Pol Henarejos Date: Wed, 13 Apr 2022 14:12:14 +0200 Subject: [PATCH 27/41] Session pin is randomized. Signed-off-by: Pol Henarejos --- src/hsm/sc_hsm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hsm/sc_hsm.c b/src/hsm/sc_hsm.c index 45f9b1f..db6ed28 100644 --- a/src/hsm/sc_hsm.c +++ b/src/hsm/sc_hsm.c @@ -1917,8 +1917,8 @@ int cmd_general_authenticate() { int cmd_session_pin() { if (P1(apdu) == 0x01 && P2(apdu) == 0x81) { - memcpy(sm_session_pin, "\x30\x31\x32\x33\x34\x35", 6); - sm_session_pin_len = 6; + memcpy(sm_session_pin, random_bytes_get(8), 8); + sm_session_pin_len = 8; memcpy(res_APDU, sm_session_pin, sm_session_pin_len); res_APDU_size = sm_session_pin_len; From da6c578973cda95173e23a204f28ed20e361abbc Mon Sep 17 00:00:00 2001 From: Pol Henarejos Date: Wed, 13 Apr 2022 14:14:06 +0200 Subject: [PATCH 28/41] Fix tag_len computation for all TLV. Signed-off-by: Pol Henarejos --- src/hsm/sc_hsm.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/hsm/sc_hsm.c b/src/hsm/sc_hsm.c index db6ed28..fb4091f 100644 --- a/src/hsm/sc_hsm.c +++ b/src/hsm/sc_hsm.c @@ -601,6 +601,13 @@ static int cmd_initialize() { while (p-apdu.cmd_apdu_data < apdu.cmd_apdu_data_len) { uint8_t tag = *p++; uint8_t tag_len = *p++; + if (tag_len == 0x82) { + tag_len = *p++ << 8; + tag_len |= *p++; + } + else if (tag_len == 0x81) { + tag_len = *p++; + } if (tag == 0x80) { //options file_t *tf = search_by_fid(EF_DEVOPS, NULL, SPECIFY_EF); flash_write_data_to_file(tf, p, tag_len); @@ -1822,6 +1829,20 @@ static int cmd_mse() { while (p-apdu.cmd_apdu_data < apdu.cmd_apdu_data_len) { uint8_t tag = *p++; uint8_t tag_len = *p++; + if (tag_len == 0x82) { + tag_len = *p++ << 8; + tag_len |= *p++; + } + else if (tag_len == 0x81) { + tag_len = *p++; + } + if (tag_len == 0x82) { + tag_len = *p++ << 8; + tag_len |= *p++; + } + else if (tag_len == 0x81) { + tag_len = *p++; + } if (tag == 0x80) { if (tag_len == 10 && memcmp(p, "\x04\x00\x7F\x00\x07\x02\x02\x03\x02\x02", tag_len) == 0) sm_set_protocol(MSE_AES); @@ -1851,6 +1872,13 @@ int cmd_general_authenticate() { while (p-apdu.cmd_apdu_data < apdu.cmd_apdu_data[1]) { uint8_t tag = *p++; uint8_t tag_len = *p++; + if (tag_len == 0x82) { + tag_len = *p++ << 8; + tag_len |= *p++; + } + else if (tag_len == 0x81) { + tag_len = *p++; + } if (tag == 0x80) { pubkey = p-1; //mbedtls ecdh starts reading one pos before pubkey_len = tag_len+1; From 9dfe0ee7b3723f179d6685133dfeeb7dd3cbabbd Mon Sep 17 00:00:00 2001 From: Pol Henarejos Date: Wed, 13 Apr 2022 14:25:44 +0200 Subject: [PATCH 29/41] Clear session pin on unload and new session. Signed-off-by: Pol Henarejos --- src/hsm/eac.c | 1 + src/hsm/sc_hsm.c | 1 + 2 files changed, 2 insertions(+) diff --git a/src/hsm/eac.c b/src/hsm/eac.c index 3bee3e9..fb28c55 100644 --- a/src/hsm/eac.c +++ b/src/hsm/eac.c @@ -57,6 +57,7 @@ void sm_derive_all_keys(const uint8_t *derived, size_t derived_len) { mbedtls_mpi_grow(&sm_mSSC, sm_blocksize); mbedtls_mpi_lset(&sm_mSSC, 0); memset(sm_iv, 0, sizeof(sm_iv)); + sm_session_pin_len = 0; } void sm_set_protocol(MSE_protocol proto) { diff --git a/src/hsm/sc_hsm.c b/src/hsm/sc_hsm.c index fb4091f..5bcdba4 100644 --- a/src/hsm/sc_hsm.c +++ b/src/hsm/sc_hsm.c @@ -75,6 +75,7 @@ void init_sc_hsm() { int sc_hsm_unload() { has_session_pin = has_session_sopin = false; isUserAuthenticated = false; + sm_session_pin_len = 0; return HSM_OK; } From b68920ff452223ed170b009e1baf41890d67deb0 Mon Sep 17 00:00:00 2001 From: Pol Henarejos Date: Wed, 13 Apr 2022 16:55:34 +0200 Subject: [PATCH 30/41] Added walker function for TLV parsing. Signed-off-by: Pol Henarejos --- src/hsm/eac.c | 60 ++++++------------- src/hsm/sc_hsm.c | 146 ++++++++++++++++++++++++----------------------- src/hsm/sc_hsm.h | 3 + 3 files changed, 96 insertions(+), 113 deletions(-) diff --git a/src/hsm/eac.c b/src/hsm/eac.c index fb28c55..99ddfc4 100644 --- a/src/hsm/eac.c +++ b/src/hsm/eac.c @@ -90,29 +90,20 @@ int sm_unwrap() { int le = sm_get_le(); if (le >= 0) apdu.expected_res_size = le; - const uint8_t *p = apdu.cmd_apdu_data; uint8_t *body = NULL; size_t body_size = 0; bool is87 = false; - while (p-apdu.cmd_apdu_data < apdu.cmd_apdu_data_len) { - uint8_t tag = *p++; - uint16_t tag_len = *p++; - if (tag_len == 0x82) { - tag_len = *p++ << 8; - tag_len |= *p++; - } - else if (tag_len == 0x81) { - tag_len = *p++; - } + uint8_t tag = 0x0, *tag_data = NULL, *p = NULL; + size_t tag_len = 0; + while (walk_tlv(apdu.cmd_apdu_data, apdu.cmd_apdu_data_len, &p, &tag, &tag_len, &tag_data)) { if (tag == 0x87 || tag == 0x85) { - body = (uint8_t *)p; + body = tag_data; body_size = tag_len; if (tag == 0x87) { is87 = true; body_size--; } } - p += tag_len; } if (!body) return HSM_WRONG_DATA; @@ -189,24 +180,15 @@ int sm_wrap() { } int sm_get_le() { - const uint8_t *p = apdu.cmd_apdu_data; - while (p-apdu.cmd_apdu_data < apdu.cmd_apdu_data_len) { - uint8_t tag = *p++; - uint16_t tag_len = *p++; - if (tag_len == 0x82) { - tag_len = *p++ << 8; - tag_len |= *p++; - } - else if (tag_len == 0x81) { - tag_len = *p++; - } + uint8_t tag = 0x0, *tag_data = NULL, *p = NULL; + size_t tag_len = 0; + while (walk_tlv(apdu.cmd_apdu_data, apdu.cmd_apdu_data_len, &p, &tag, &tag_len, &tag_data)) { if (tag == 0x97) { uint32_t le = 0; for (int t = 1; t <= tag_len; t++) - le |= (*p++) << (tag_len-t); + le |= (*tag_data++) << (tag_len-t); return le; } - p += tag_len; } return -1; } @@ -247,29 +229,23 @@ int sm_verify() { input_len += sm_blocksize-5; } bool some_added = false; - const uint8_t *p = apdu.cmd_apdu_data, *mac = NULL, *initag = NULL; + const uint8_t *mac = NULL; size_t mac_len = 0; - while (p-apdu.cmd_apdu_data < apdu.cmd_apdu_data_len) { - initag = p; - uint8_t tag = *p++; - uint16_t tag_len = *p++; - if (tag_len == 0x82) { - tag_len = *p++ << 8; - tag_len |= *p++; - } - else if (tag_len == 0x81) { - tag_len = *p++; - } + uint8_t tag = 0x0, *tag_data = NULL, *p = NULL; + size_t tag_len = 0; + while (walk_tlv(apdu.cmd_apdu_data, apdu.cmd_apdu_data_len, &p, &tag, &tag_len, &tag_data)) { if (tag & 0x1) { - memcpy(input+input_len, initag, tag_len+(p-initag)); - input_len += tag_len+(p-initag); + input[input_len++] = tag; + int tlen = format_tlv_len(tag_len, input+input_len); + input_len += tlen; + memcpy(input+input_len, tag_data, tag_len); + input_len += tag_len; some_added = true; } if (tag == 0x8E) { - mac = p; + mac = tag_data; mac_len = tag_len; } - p += tag_len; } if (!mac) return HSM_WRONG_DATA; diff --git a/src/hsm/sc_hsm.c b/src/hsm/sc_hsm.c index 5bcdba4..98178d3 100644 --- a/src/hsm/sc_hsm.c +++ b/src/hsm/sc_hsm.c @@ -119,6 +119,53 @@ static void wait_button() { } } +int format_tlv_len(size_t len, uint8_t *out) { + if (len < 128) { + *out = len; + return 1; + } + else if (len < 256) { + *out++ = 0x81; + *out++ = len; + return 2; + } + else { + *out++ = 0x82; + *out++ = (len >> 8) & 0xff; + *out++ = len & 0xff; + return 3; + } + return 0; +} + +int walk_tlv(const uint8_t *cdata, size_t cdata_len, uint8_t **p, uint8_t *tag, size_t *tag_len, uint8_t **data) { + if (!p) + return 0; + if (!*p) + *p = (uint8_t *)cdata; + if (*p-cdata >= cdata_len) + return 0; + uint8_t tg = 0x0; + size_t tgl = 0; + tg = *(*p)++; + tgl = *(*p)++; + if (tgl == 0x82) { + tgl = *(*p)++ << 8; + tgl |= *(*p)++; + } + else if (tgl == 0x81) { + tgl = *(*p)++; + } + if (tag) + *tag = tg; + if (tag_len) + *tag_len = tgl; + if (data) + *data = *p; + *p = *p+tgl; + return 1; +} + static int cmd_select() { uint8_t p1 = P1(apdu); uint8_t p2 = P2(apdu); @@ -598,28 +645,20 @@ static int cmd_initialize() { initialize_flash(true); scan_flash(); dkeks = current_dkeks = 0; - const uint8_t *p = apdu.cmd_apdu_data; - while (p-apdu.cmd_apdu_data < apdu.cmd_apdu_data_len) { - uint8_t tag = *p++; - uint8_t tag_len = *p++; - if (tag_len == 0x82) { - tag_len = *p++ << 8; - tag_len |= *p++; - } - else if (tag_len == 0x81) { - tag_len = *p++; - } + uint8_t tag = 0x0, *tag_data = NULL, *p = NULL; + size_t tag_len = 0; + while (walk_tlv(apdu.cmd_apdu_data, apdu.cmd_apdu_data_len, &p, &tag, &tag_len, &tag_data)) { if (tag == 0x80) { //options file_t *tf = search_by_fid(EF_DEVOPS, NULL, SPECIFY_EF); - flash_write_data_to_file(tf, p, tag_len); + flash_write_data_to_file(tf, tag_data, tag_len); } else if (tag == 0x81) { //user pin if (file_pin1 && file_pin1->data) { uint8_t dhash[33]; dhash[0] = tag_len; - double_hash_pin(p, tag_len, dhash+1); + double_hash_pin(tag_data, tag_len, dhash+1); flash_write_data_to_file(file_pin1, dhash, sizeof(dhash)); - hash_multi(p, tag_len, session_pin); + hash_multi(tag_data, tag_len, session_pin); has_session_pin = true; } } @@ -627,25 +666,24 @@ static int cmd_initialize() { if (file_sopin && file_sopin->data) { uint8_t dhash[33]; dhash[0] = tag_len; - double_hash_pin(p, tag_len, dhash+1); + double_hash_pin(tag_data, tag_len, dhash+1); flash_write_data_to_file(file_sopin, dhash, sizeof(dhash)); - hash_multi(p, tag_len, session_sopin); + hash_multi(tag_data, tag_len, session_sopin); has_session_sopin = true; } } else if (tag == 0x91) { //retries user pin file_t *tf = search_by_fid(0x1082, NULL, SPECIFY_EF); if (tf && tf->data) { - flash_write_data_to_file(tf, p, tag_len); + flash_write_data_to_file(tf, tag_data, tag_len); } if (file_retries_pin1 && file_retries_pin1->data) { - flash_write_data_to_file(file_retries_pin1, p, tag_len); + flash_write_data_to_file(file_retries_pin1, tag_data, tag_len); } } else if (tag == 0x92) { - dkeks = *p; + dkeks = *tag_data; } - p += tag_len; } if (dkeks == 0) { int r = save_dkek_key(random_bytes_get(32)); @@ -1074,7 +1112,7 @@ static int cmd_keypair_gen() { static int cmd_update_ef() { uint8_t p1 = P1(apdu), p2 = P2(apdu); uint16_t fid = (p1 << 8) | p2; - uint8_t *p = apdu.cmd_apdu_data, *data; + uint8_t *data; uint16_t offset = 0; uint16_t data_len = 0; file_t *ef = NULL; @@ -1088,25 +1126,16 @@ static int cmd_update_ef() { if (ef && !authenticate_action(ef, ACL_OP_UPDATE_ERASE)) return SW_SECURITY_STATUS_NOT_SATISFIED(); - while (p-apdu.cmd_apdu_data < apdu.cmd_apdu_data_len) { - uint8_t tag = *p++; - uint8_t taglen = *p++; + uint8_t tag = 0x0, *tag_data = NULL, *p = NULL; + size_t tag_len = 0; + while (walk_tlv(apdu.cmd_apdu_data, apdu.cmd_apdu_data_len, &p, &tag, &tag_len, &tag_data)) { if (tag == 0x54) { //ofset tag - for (int i = 0; i < taglen; i++) - offset |= (*p++ << (8*(taglen-i-1))); + for (int i = 1; i <= tag_len; i++) + offset |= (*tag_data++ << (8*(tag_len-i))); } else if (tag == 0x53) { //data - if (taglen == 0x82) { - data_len = *p++ << 8; - data_len |= *p++; - } - else if (taglen == 0x81) { - data_len = *p++; - } - else - data_len = taglen; - data = p; - p += data_len; + data_len = tag_len; + data = tag_data; } } if (data_len == 0 && offset == 0) { //new file @@ -1826,33 +1855,17 @@ static int cmd_mse() { int p2 = P2(apdu); if (p1 & 0x1) { //SET if (p2 == 0xA4) { //AT - const uint8_t *p = apdu.cmd_apdu_data; - while (p-apdu.cmd_apdu_data < apdu.cmd_apdu_data_len) { - uint8_t tag = *p++; - uint8_t tag_len = *p++; - if (tag_len == 0x82) { - tag_len = *p++ << 8; - tag_len |= *p++; - } - else if (tag_len == 0x81) { - tag_len = *p++; - } - if (tag_len == 0x82) { - tag_len = *p++ << 8; - tag_len |= *p++; - } - else if (tag_len == 0x81) { - tag_len = *p++; - } + uint8_t tag = 0x0, *tag_data = NULL, *p = NULL; + size_t tag_len = 0; + while (walk_tlv(apdu.cmd_apdu_data, apdu.cmd_apdu_data_len, &p, &tag, &tag_len, &tag_data)) { if (tag == 0x80) { - if (tag_len == 10 && memcmp(p, "\x04\x00\x7F\x00\x07\x02\x02\x03\x02\x02", tag_len) == 0) + if (tag_len == 10 && memcmp(tag_data, "\x04\x00\x7F\x00\x07\x02\x02\x03\x02\x02", tag_len) == 0) sm_set_protocol(MSE_AES); - else if (tag_len == 10 && memcmp(p, "\x04\x00\x7F\x00\x07\x02\x02\x03\x02\x01", tag_len) == 0) + else if (tag_len == 10 && memcmp(tag_data, "\x04\x00\x7F\x00\x07\x02\x02\x03\x02\x01", tag_len) == 0) sm_set_protocol(MSE_3DES); else return SW_REFERENCE_NOT_FOUND(); } - p += tag_len; } } else @@ -1866,25 +1879,16 @@ static int cmd_mse() { int cmd_general_authenticate() { if (P1(apdu) == 0x0 && P2(apdu) == 0x0) { if (apdu.cmd_apdu_data[0] == 0x7C) { - const uint8_t *p = &apdu.cmd_apdu_data[2]; int r = 0; size_t pubkey_len = 0; const uint8_t *pubkey = NULL; - while (p-apdu.cmd_apdu_data < apdu.cmd_apdu_data[1]) { - uint8_t tag = *p++; - uint8_t tag_len = *p++; - if (tag_len == 0x82) { - tag_len = *p++ << 8; - tag_len |= *p++; - } - else if (tag_len == 0x81) { - tag_len = *p++; - } + uint8_t tag = 0x0, *tag_data = NULL, *p = NULL; + size_t tag_len = 0; + while (walk_tlv(apdu.cmd_apdu_data+2, apdu.cmd_apdu_data_len-2, &p, &tag, &tag_len, &tag_data)) { if (tag == 0x80) { - pubkey = p-1; //mbedtls ecdh starts reading one pos before + pubkey = tag_data-1; //mbedtls ecdh starts reading one pos before pubkey_len = tag_len+1; } - p += tag_len; } mbedtls_ecdh_context ctx; int key_size = file_read_uint16(termca_pk); diff --git a/src/hsm/sc_hsm.h b/src/hsm/sc_hsm.h index ffed95e..522b662 100644 --- a/src/hsm/sc_hsm.h +++ b/src/hsm/sc_hsm.h @@ -138,6 +138,9 @@ extern void hash(const uint8_t *input, size_t len, uint8_t output[32]); extern void hash_multi(const uint8_t *input, size_t len, uint8_t output[32]); extern void double_hash_pin(const uint8_t *pin, size_t len, uint8_t output[32]); +extern int walk_tlv(const uint8_t *cdata, size_t cdata_len, uint8_t **p, uint8_t *tag, size_t *tag_len, uint8_t **data); +extern int format_tlv_len(size_t len, uint8_t *out); + extern uint8_t session_pin[32], session_sopin[32]; #define IV_SIZE 16 From 618966b7426325fc301e7de53f477f75758020d9 Mon Sep 17 00:00:00 2001 From: Pol Henarejos Date: Wed, 13 Apr 2022 18:49:13 +0200 Subject: [PATCH 31/41] Sanity check for keypair gen. Signed-off-by: Pol Henarejos --- src/hsm/sc_hsm.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/hsm/sc_hsm.c b/src/hsm/sc_hsm.c index 98178d3..bc25f56 100644 --- a/src/hsm/sc_hsm.c +++ b/src/hsm/sc_hsm.c @@ -1063,6 +1063,8 @@ static int cmd_keypair_gen() { } } + else + return SW_WRONG_DATA(); uint8_t *cvcbin; size_t cvclen; ret = sc_pkcs15emu_sc_hsm_encode_cvc(&p15card, &cvc, &cvcbin, &cvclen); From 69e869852ef98d4d2b992e7bbfac6377280b3f26 Mon Sep 17 00:00:00 2001 From: Pol Henarejos Date: Wed, 13 Apr 2022 19:03:33 +0200 Subject: [PATCH 32/41] Rewritten keypair_gen response (more friendly). Signed-off-by: Pol Henarejos --- src/hsm/sc_hsm.c | 37 +++++++++++++++---------------------- 1 file changed, 15 insertions(+), 22 deletions(-) diff --git a/src/hsm/sc_hsm.c b/src/hsm/sc_hsm.c index bc25f56..11cecea 100644 --- a/src/hsm/sc_hsm.c +++ b/src/hsm/sc_hsm.c @@ -1077,29 +1077,22 @@ static int cmd_keypair_gen() { return SW_EXEC_ERROR(); } - res_APDU[0] = 0x67; - int outer_len = strlen(cvc.outer_car)+2+2+1+4; - int bytes_length = 0; - if (cvclen+outer_len < 128) - res_APDU[1] = cvclen+outer_len; - else if (cvclen+outer_len < 256) { - res_APDU[1] = 0x81; - res_APDU[2] = cvclen+outer_len; - bytes_length = 1; - } - else { - res_APDU[1] = 0x82; - res_APDU[2] = (cvclen+outer_len) >> 8; - res_APDU[3] = (cvclen+outer_len) & 0xff; - bytes_length = 2; - } - memcpy(res_APDU+bytes_length+2, cvcbin, cvclen); - res_APDU[bytes_length+2+cvclen] = 0x42; - res_APDU[bytes_length+2+cvclen+1] = strlen(cvc.outer_car); - memcpy(res_APDU+bytes_length+2+cvclen+2, cvc.outer_car, strlen(cvc.outer_car)); - memcpy(res_APDU+bytes_length+2+cvclen+2+strlen(cvc.outer_car), "\x5F\x37\x04",3); + res_APDU[res_APDU_size++] = 0x67; + int outer_len = 2+strlen(cvc.outer_car)+3+4; + int bytes_length = format_tlv_len(cvclen+outer_len, res_APDU+res_APDU_size); + res_APDU_size += bytes_length; + memcpy(res_APDU+res_APDU_size, cvcbin, cvclen); + res_APDU_size += cvclen; + res_APDU[res_APDU_size++] = 0x42; + res_APDU[res_APDU_size++] = strlen(cvc.outer_car); + memcpy(res_APDU+res_APDU_size, cvc.outer_car, strlen(cvc.outer_car)); + res_APDU_size += strlen(cvc.outer_car); + memcpy(res_APDU+res_APDU_size, "\x5F\x37\x04",3); + res_APDU_size += 3; + memset(res_APDU+res_APDU_size, 0, 4); + res_APDU_size += 4; free(cvcbin); - res_APDU_size = cvclen+bytes_length+2+outer_len; + //res_APDU_size = cvclen+bytes_length+1+outer_len; apdu.expected_res_size = res_APDU_size; //sc_asn1_print_tags(res_APDU, res_APDU_size); From b9fb224d629c3c33a5976059e3280b89c7344c9a Mon Sep 17 00:00:00 2001 From: Pol Henarejos Date: Thu, 14 Apr 2022 01:03:03 +0200 Subject: [PATCH 33/41] Adding a tool to burn device CVC. It generates a new keypair and sends the public key to Pico HSM CA, which signs the request. The certificate, CA and private key are burned onto the firmware. Signed-off-by: Pol Henarejos --- burn-cvcerts.py | 72 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 burn-cvcerts.py diff --git a/burn-cvcerts.py b/burn-cvcerts.py new file mode 100644 index 0000000..6dc085f --- /dev/null +++ b/burn-cvcerts.py @@ -0,0 +1,72 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +Created on Wed Apr 13 20:15:01 2022 + +@author: Pol Henarejos +""" + +from cryptography.hazmat.backends import default_backend +from cryptography.hazmat.primitives import serialization +from cryptography.hazmat.primitives.asymmetric import ec +import base64 +import urllib.request +import json + +def print_var(v, name): + s = '\n' + s += "static const unsigned char "+name+"[] = {\n" + s += "\t0x{:02x},0x{:02x},\n".format((len(v) & 0xff),((len(v)>> 8) & 0xff)) + for i in range(len(v)): + if (i%16 == 0): + s += '\t' + s += "0x{:02x}".format((v[i])) + if (i < len(v)-1): + s += ',' + if (i%16 == 15): + s += '\n' + s += '\n' + s += '};\n' + return s + +private_key = ec.generate_private_key(ec.SECP192R1(), default_backend()) +public_key = private_key.public_key() +pub_num = public_key.public_numbers() +pbk = base64.urlsafe_b64encode(b'\x04'+pub_num.x.to_bytes(24,'big')+pub_num.y.to_bytes(24,'big')) + +user_agent = 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.0.7) Gecko/2009021910 Firefox/3.0.7' + +data = urllib.parse.urlencode({'pubkey':pbk}).encode() +req = urllib.request.Request("https://www.henarejos.me/pico-hsm.php", data, {'User-Agent':user_agent,} ) #The assembled request +response = urllib.request.urlopen(req) +resp = response.read().decode('utf-8') +j = json.loads(resp) +cvcert = base64.b64decode(j['cvcert']) + +dica = [ + 0x7f,0x21,0x81,0xc5,0x7f,0x4e,0x81,0x8e,0x5f,0x29,0x01,0x00,0x42,0x0e,0x45,0x53, + 0x43,0x56,0x43,0x41,0x48,0x53,0x4d,0x30,0x30,0x30,0x30,0x31,0x7f,0x49,0x3f,0x06, + 0x0a,0x04,0x00,0x7f,0x00,0x07,0x02,0x02,0x02,0x02,0x03,0x86,0x31,0x04,0x93,0x7e, + 0xdf,0xf1,0xa6,0xd2,0x40,0x7e,0xb4,0x71,0xb2,0x97,0x50,0xdb,0x7e,0xe1,0x70,0xfb, + 0x6c,0xcd,0x06,0x47,0x2a,0x3e,0x9c,0x8d,0x59,0x56,0x57,0xbe,0x11,0x11,0x0a,0x08, + 0x81,0x54,0xed,0x22,0xc0,0x83,0xac,0xa1,0x2e,0x39,0x7b,0xd4,0x65,0x1f,0x5f,0x20, + 0x0e,0x45,0x53,0x44,0x56,0x43,0x41,0x48,0x53,0x4d,0x30,0x30,0x30,0x30,0x31,0x7f, + 0x4c,0x12,0x06,0x09,0x04,0x00,0x7f,0x00,0x07,0x03,0x01,0x02,0x02,0x53,0x05,0x80, + 0x00,0x00,0x00,0x04,0x5f,0x25,0x06,0x02,0x02,0x00,0x03,0x02,0x07,0x5f,0x24,0x06, + 0x02,0x05,0x01,0x02,0x03,0x01,0x5f,0x37,0x30,0x8b,0xb2,0x01,0xb6,0x24,0xfe,0xe5, + 0x4e,0x65,0x3a,0x02,0xa2,0xb2,0x27,0x2d,0x3d,0xb4,0xb0,0xc9,0xdd,0xbf,0x10,0x6d, + 0x99,0x49,0x46,0xd6,0xd0,0x72,0xc1,0xf3,0x4c,0xab,0x4f,0x32,0x14,0x7c,0xb0,0x99, + 0xb7,0x33,0x70,0xd6,0x00,0xff,0x73,0x0c,0x5d +] + +s = '#ifndef _CVCERTS_H_\n#define _CVCERTS_H_\n' +s += print_var(dica,'dica') +s += print_var(cvcert,'termca') + +pvk = private_key.private_numbers().private_value.to_bytes(24,'big') +s += print_var(pvk,'termca_pk') +s += '\n#endif\n' + +f = open('src/hsm/cvcerts.h','w') +f.write(s) +f.close() \ No newline at end of file From e2f424d4abf7dc4026bdffb618d51ed6f354b488 Mon Sep 17 00:00:00 2001 From: Pol Henarejos Date: Thu, 14 Apr 2022 01:06:50 +0200 Subject: [PATCH 34/41] No more in the repo Signed-off-by: Pol Henarejos --- src/hsm/cvcerts.h | 47 ----------------------------------------------- 1 file changed, 47 deletions(-) delete mode 100644 src/hsm/cvcerts.h diff --git a/src/hsm/cvcerts.h b/src/hsm/cvcerts.h deleted file mode 100644 index 7f3dc3d..0000000 --- a/src/hsm/cvcerts.h +++ /dev/null @@ -1,47 +0,0 @@ -#ifndef CVCERTS_H_ -#define CVCERTS_H_ - -static const unsigned char termca[] = { - 0xfa, 0x00, - 0x7f,0x21,0x81,0xf6,0x7f,0x4e,0x81,0xbf,0x5f,0x29,0x01,0x00,0x42,0x0e,0x45,0x53, - 0x44,0x56,0x43,0x41,0x48,0x53,0x4d,0x30,0x30,0x30,0x30,0x31,0x7f,0x49,0x3f,0x06, - 0x0a,0x04,0x00,0x7f,0x00,0x07,0x02,0x02,0x02,0x02,0x03,0x86,0x31,0x04,0x0f,0x89, - 0xb4,0x00,0x97,0x5e,0xdd,0x2d,0x42,0x5a,0xbf,0x85,0xf2,0xfb,0xd3,0x18,0x77,0x9b, - 0x3d,0x85,0x47,0x5e,0x65,0xd4,0xd8,0x58,0x69,0xd3,0x04,0x14,0xb7,0x1f,0x16,0x1e, - 0xb0,0x40,0xd9,0xf7,0xa7,0xe3,0x73,0xa3,0x15,0xc7,0xd9,0x9a,0x51,0xf5,0x5f,0x20, - 0x0e,0x45,0x53,0x54,0x45,0x52,0x4d,0x48,0x53,0x4d,0x30,0x30,0x30,0x30,0x31,0x7f, - 0x4c,0x12,0x06,0x09,0x04,0x00,0x7f,0x00,0x07,0x03,0x01,0x02,0x02,0x53,0x05,0x00, - 0x00,0x00,0x00,0x04,0x5f,0x25,0x06,0x02,0x02,0x00,0x03,0x02,0x07,0x5f,0x24,0x06, - 0x02,0x03,0x01,0x02,0x03,0x01,0x65,0x2f,0x73,0x2d,0x06,0x09,0x04,0x00,0x7f,0x00, - 0x07,0x03,0x01,0x03,0x01,0x80,0x20,0x68,0x53,0x30,0xc7,0x9a,0x47,0xad,0xfd,0x37, - 0xaa,0xe8,0x53,0xf4,0xbd,0x77,0x3a,0x40,0x89,0x3a,0x79,0x7e,0x3c,0x27,0x18,0x3b, - 0x39,0x67,0xdf,0x8d,0x4f,0xe5,0x99,0x5f,0x37,0x30,0x10,0xff,0x17,0x96,0x0d,0x93, - 0x07,0xc0,0x69,0x8e,0x3a,0xa0,0x44,0x69,0x70,0x88,0xe6,0x9c,0xb4,0xd3,0x16,0x9a, - 0x22,0x4e,0x5c,0x77,0xa9,0xe7,0x83,0x75,0x9a,0xd2,0x7e,0x92,0xf2,0x04,0x93,0xb1, - 0xe9,0xc9,0xe5,0x10,0xc9,0x94,0xff,0x9d,0xe2,0x00 -}; - -static const unsigned char dica[] = { - 0xc9, 0x00, - 0x7f,0x21,0x81,0xc5,0x7f,0x4e,0x81,0x8e,0x5f,0x29,0x01,0x00,0x42,0x0e,0x45,0x53, - 0x43,0x56,0x43,0x41,0x48,0x53,0x4d,0x30,0x30,0x30,0x30,0x31,0x7f,0x49,0x3f,0x06, - 0x0a,0x04,0x00,0x7f,0x00,0x07,0x02,0x02,0x02,0x02,0x03,0x86,0x31,0x04,0x93,0x7e, - 0xdf,0xf1,0xa6,0xd2,0x40,0x7e,0xb4,0x71,0xb2,0x97,0x50,0xdb,0x7e,0xe1,0x70,0xfb, - 0x6c,0xcd,0x06,0x47,0x2a,0x3e,0x9c,0x8d,0x59,0x56,0x57,0xbe,0x11,0x11,0x0a,0x08, - 0x81,0x54,0xed,0x22,0xc0,0x83,0xac,0xa1,0x2e,0x39,0x7b,0xd4,0x65,0x1f,0x5f,0x20, - 0x0e,0x45,0x53,0x44,0x56,0x43,0x41,0x48,0x53,0x4d,0x30,0x30,0x30,0x30,0x31,0x7f, - 0x4c,0x12,0x06,0x09,0x04,0x00,0x7f,0x00,0x07,0x03,0x01,0x02,0x02,0x53,0x05,0x80, - 0x00,0x00,0x00,0x04,0x5f,0x25,0x06,0x02,0x02,0x00,0x03,0x02,0x07,0x5f,0x24,0x06, - 0x02,0x05,0x01,0x02,0x03,0x01,0x5f,0x37,0x30,0x8b,0xb2,0x01,0xb6,0x24,0xfe,0xe5, - 0x4e,0x65,0x3a,0x02,0xa2,0xb2,0x27,0x2d,0x3d,0xb4,0xb0,0xc9,0xdd,0xbf,0x10,0x6d, - 0x99,0x49,0x46,0xd6,0xd0,0x72,0xc1,0xf3,0x4c,0xab,0x4f,0x32,0x14,0x7c,0xb0,0x99, - 0xb7,0x33,0x70,0xd6,0x00,0xff,0x73,0x0c,0x5d -}; - -static const unsigned char termca_pk[] = { - 0x18, 0x00, - 0xD9,0xE5,0x1B,0x79,0xF2,0x80,0x49,0x2B,0x35,0xFC,0x8C,0xC4,0xFC,0x5C,0xF4,0x72, - 0x25,0xC7,0x5B,0x08,0xFD,0xBC,0xE1,0x13 -}; - -#endif From 1b010c8a685b9e48d5ba5b842cdad05f97726b24 Mon Sep 17 00:00:00 2001 From: Pol Henarejos Date: Thu, 14 Apr 2022 17:11:51 +0200 Subject: [PATCH 35/41] Specifying POST method Signed-off-by: Pol Henarejos --- burn-cvcerts.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/burn-cvcerts.py b/burn-cvcerts.py index 6dc085f..e1e06ae 100644 --- a/burn-cvcerts.py +++ b/burn-cvcerts.py @@ -37,7 +37,7 @@ pbk = base64.urlsafe_b64encode(b'\x04'+pub_num.x.to_bytes(24,'big')+pub_num.y.to user_agent = 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.0.7) Gecko/2009021910 Firefox/3.0.7' data = urllib.parse.urlencode({'pubkey':pbk}).encode() -req = urllib.request.Request("https://www.henarejos.me/pico-hsm.php", data, {'User-Agent':user_agent,} ) #The assembled request +req = urllib.request.Request("https://www.henarejos.me/pico-hsm.php", method='POST', data=data, headers={'User-Agent':user_agent,} ) #The assembled request response = urllib.request.urlopen(req) resp = response.read().decode('utf-8') j = json.loads(resp) From b09fc759136cdfd5b527f18ed4d4dea6a7f910d0 Mon Sep 17 00:00:00 2001 From: Pol Henarejos Date: Thu, 14 Apr 2022 18:31:39 +0200 Subject: [PATCH 36/41] CVCert is burn only if it does not exist. This check is only executed for first configuration. Signed-off-by: Pol Henarejos --- CMakeLists.txt | 10 +++++- burn-cvcerts.py | 88 ++++++++++++++++++++++++++----------------------- 2 files changed, 56 insertions(+), 42 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2952424..e46c84e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -41,6 +41,14 @@ set_source_files_properties( ${CMAKE_CURRENT_LIST_DIR}/OpenSC/src/libopensc/ctx.c PROPERTIES COMPILE_DEFINITIONS "PACKAGE_VERSION=\"0.22.0\";OPENSC_CONF_PATH=\".\"" ) + + +find_package( PythonInterp 3.7 REQUIRED ) + +if (NOT EXISTS ${CMAKE_CURRENT_LIST_DIR}/src/hsm/cvcerts.h) + execute_process(COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_LIST_DIR}/burn-cvcerts.py ${CMAKE_CURRENT_LIST_DIR}) + message("Burning CVCert") +endif() target_sources(pico_hsm PUBLIC ${CMAKE_CURRENT_LIST_DIR}/src/hsm/hsm2040.c @@ -115,7 +123,7 @@ target_include_directories(pico_hsm PUBLIC ${CMAKE_CURRENT_LIST_DIR}/mbedtls/include ${CMAKE_CURRENT_LIST_DIR}/mbedtls/library ) - + pico_add_extra_outputs(pico_hsm) #target_compile_definitions(pico_hsm PRIVATE MBEDTLS_ECDSA_DETERMINISTIC=1) diff --git a/burn-cvcerts.py b/burn-cvcerts.py index e1e06ae..05079e6 100644 --- a/burn-cvcerts.py +++ b/burn-cvcerts.py @@ -12,6 +12,7 @@ from cryptography.hazmat.primitives.asymmetric import ec import base64 import urllib.request import json +import sys def print_var(v, name): s = '\n' @@ -29,44 +30,49 @@ def print_var(v, name): s += '};\n' return s -private_key = ec.generate_private_key(ec.SECP192R1(), default_backend()) -public_key = private_key.public_key() -pub_num = public_key.public_numbers() -pbk = base64.urlsafe_b64encode(b'\x04'+pub_num.x.to_bytes(24,'big')+pub_num.y.to_bytes(24,'big')) - -user_agent = 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.0.7) Gecko/2009021910 Firefox/3.0.7' - -data = urllib.parse.urlencode({'pubkey':pbk}).encode() -req = urllib.request.Request("https://www.henarejos.me/pico-hsm.php", method='POST', data=data, headers={'User-Agent':user_agent,} ) #The assembled request -response = urllib.request.urlopen(req) -resp = response.read().decode('utf-8') -j = json.loads(resp) -cvcert = base64.b64decode(j['cvcert']) - -dica = [ - 0x7f,0x21,0x81,0xc5,0x7f,0x4e,0x81,0x8e,0x5f,0x29,0x01,0x00,0x42,0x0e,0x45,0x53, - 0x43,0x56,0x43,0x41,0x48,0x53,0x4d,0x30,0x30,0x30,0x30,0x31,0x7f,0x49,0x3f,0x06, - 0x0a,0x04,0x00,0x7f,0x00,0x07,0x02,0x02,0x02,0x02,0x03,0x86,0x31,0x04,0x93,0x7e, - 0xdf,0xf1,0xa6,0xd2,0x40,0x7e,0xb4,0x71,0xb2,0x97,0x50,0xdb,0x7e,0xe1,0x70,0xfb, - 0x6c,0xcd,0x06,0x47,0x2a,0x3e,0x9c,0x8d,0x59,0x56,0x57,0xbe,0x11,0x11,0x0a,0x08, - 0x81,0x54,0xed,0x22,0xc0,0x83,0xac,0xa1,0x2e,0x39,0x7b,0xd4,0x65,0x1f,0x5f,0x20, - 0x0e,0x45,0x53,0x44,0x56,0x43,0x41,0x48,0x53,0x4d,0x30,0x30,0x30,0x30,0x31,0x7f, - 0x4c,0x12,0x06,0x09,0x04,0x00,0x7f,0x00,0x07,0x03,0x01,0x02,0x02,0x53,0x05,0x80, - 0x00,0x00,0x00,0x04,0x5f,0x25,0x06,0x02,0x02,0x00,0x03,0x02,0x07,0x5f,0x24,0x06, - 0x02,0x05,0x01,0x02,0x03,0x01,0x5f,0x37,0x30,0x8b,0xb2,0x01,0xb6,0x24,0xfe,0xe5, - 0x4e,0x65,0x3a,0x02,0xa2,0xb2,0x27,0x2d,0x3d,0xb4,0xb0,0xc9,0xdd,0xbf,0x10,0x6d, - 0x99,0x49,0x46,0xd6,0xd0,0x72,0xc1,0xf3,0x4c,0xab,0x4f,0x32,0x14,0x7c,0xb0,0x99, - 0xb7,0x33,0x70,0xd6,0x00,0xff,0x73,0x0c,0x5d -] - -s = '#ifndef _CVCERTS_H_\n#define _CVCERTS_H_\n' -s += print_var(dica,'dica') -s += print_var(cvcert,'termca') - -pvk = private_key.private_numbers().private_value.to_bytes(24,'big') -s += print_var(pvk,'termca_pk') -s += '\n#endif\n' - -f = open('src/hsm/cvcerts.h','w') -f.write(s) -f.close() \ No newline at end of file +def main(): + args = sys.argv[1:] + + private_key = ec.generate_private_key(ec.SECP192R1(), default_backend()) + public_key = private_key.public_key() + pub_num = public_key.public_numbers() + pbk = base64.urlsafe_b64encode(b'\x04'+pub_num.x.to_bytes(24,'big')+pub_num.y.to_bytes(24,'big')) + + user_agent = 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.0.7) Gecko/2009021910 Firefox/3.0.7' + + data = urllib.parse.urlencode({'pubkey':pbk}).encode() + req = urllib.request.Request("https://www.henarejos.me/pico-hsm.php", method='POST', data=data, headers={'User-Agent':user_agent,} ) #The assembled request + response = urllib.request.urlopen(req) + resp = response.read().decode('utf-8') + j = json.loads(resp) + cvcert = base64.b64decode(j['cvcert']) + + dica = [ + 0x7f,0x21,0x81,0xc5,0x7f,0x4e,0x81,0x8e,0x5f,0x29,0x01,0x00,0x42,0x0e,0x45,0x53, + 0x43,0x56,0x43,0x41,0x48,0x53,0x4d,0x30,0x30,0x30,0x30,0x31,0x7f,0x49,0x3f,0x06, + 0x0a,0x04,0x00,0x7f,0x00,0x07,0x02,0x02,0x02,0x02,0x03,0x86,0x31,0x04,0x93,0x7e, + 0xdf,0xf1,0xa6,0xd2,0x40,0x7e,0xb4,0x71,0xb2,0x97,0x50,0xdb,0x7e,0xe1,0x70,0xfb, + 0x6c,0xcd,0x06,0x47,0x2a,0x3e,0x9c,0x8d,0x59,0x56,0x57,0xbe,0x11,0x11,0x0a,0x08, + 0x81,0x54,0xed,0x22,0xc0,0x83,0xac,0xa1,0x2e,0x39,0x7b,0xd4,0x65,0x1f,0x5f,0x20, + 0x0e,0x45,0x53,0x44,0x56,0x43,0x41,0x48,0x53,0x4d,0x30,0x30,0x30,0x30,0x31,0x7f, + 0x4c,0x12,0x06,0x09,0x04,0x00,0x7f,0x00,0x07,0x03,0x01,0x02,0x02,0x53,0x05,0x80, + 0x00,0x00,0x00,0x04,0x5f,0x25,0x06,0x02,0x02,0x00,0x03,0x02,0x07,0x5f,0x24,0x06, + 0x02,0x05,0x01,0x02,0x03,0x01,0x5f,0x37,0x30,0x8b,0xb2,0x01,0xb6,0x24,0xfe,0xe5, + 0x4e,0x65,0x3a,0x02,0xa2,0xb2,0x27,0x2d,0x3d,0xb4,0xb0,0xc9,0xdd,0xbf,0x10,0x6d, + 0x99,0x49,0x46,0xd6,0xd0,0x72,0xc1,0xf3,0x4c,0xab,0x4f,0x32,0x14,0x7c,0xb0,0x99, + 0xb7,0x33,0x70,0xd6,0x00,0xff,0x73,0x0c,0x5d + ] + + s = '#ifndef _CVCERTS_H_\n#define _CVCERTS_H_\n' + s += print_var(dica,'dica') + s += print_var(cvcert,'termca') + + pvk = private_key.private_numbers().private_value.to_bytes(24,'big') + s += print_var(pvk,'termca_pk') + s += '\n#endif\n' + f = open(args[0] + '/src/hsm/cvcerts.h','w') + f.write(s) + f.close() + +if __name__ == '__main__': + main() \ No newline at end of file From 522860f7363c6bfbba72e52a1e42a8bdc218bea8 Mon Sep 17 00:00:00 2001 From: Pol Henarejos Date: Tue, 19 Apr 2022 18:39:52 +0200 Subject: [PATCH 37/41] Splitting the core onto another repo, which can be reused by other smart applications. Signed-off-by: Pol Henarejos --- .gitmodules | 3 + CMakeLists.txt | 22 +- pico-ccid | 1 + src/fs/file.c | 416 -------- src/fs/file.h | 124 --- src/fs/flash.c | 134 --- src/fs/low_flash.c | 248 ----- src/hsm/crypto_utils.c | 4 +- src/hsm/dkek.c | 85 +- src/hsm/eac.c | 26 +- src/hsm/eac.h | 2 +- src/hsm/files.c | 60 ++ src/{rng/neug.h => hsm/files.h} | 25 +- src/hsm/hsm2040.c | 1691 ------------------------------- src/hsm/hsm2040.h | 178 ---- src/hsm/sc_hsm.c | 189 +++- src/hsm/sc_hsm.h | 72 +- src/rng/neug.c | 182 ---- src/rng/random.c | 109 -- src/rng/random.h | 38 - src/usb/ccid.h | 50 - src/usb/tusb_config.h | 119 --- src/usb/usb_descriptors.c | 209 ---- src/usb/usb_descriptors.h | 29 - 24 files changed, 286 insertions(+), 3730 deletions(-) create mode 160000 pico-ccid delete mode 100644 src/fs/file.c delete mode 100644 src/fs/file.h delete mode 100644 src/fs/flash.c delete mode 100644 src/fs/low_flash.c create mode 100644 src/hsm/files.c rename src/{rng/neug.h => hsm/files.h} (64%) delete mode 100644 src/hsm/hsm2040.c delete mode 100644 src/hsm/hsm2040.h delete mode 100644 src/rng/neug.c delete mode 100644 src/rng/random.c delete mode 100644 src/rng/random.h delete mode 100644 src/usb/ccid.h delete mode 100644 src/usb/tusb_config.h delete mode 100644 src/usb/usb_descriptors.c delete mode 100644 src/usb/usb_descriptors.h diff --git a/.gitmodules b/.gitmodules index 56fe23a..1cdae06 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,3 +4,6 @@ [submodule "mbedtls"] path = mbedtls url = https://github.com/ARMmbed/mbedtls +[submodule "pico-ccid"] + path = pico-ccid + url = git@github.com-polhenarejos:polhenarejos/pico-ccid diff --git a/CMakeLists.txt b/CMakeLists.txt index e46c84e..0047b02 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -51,14 +51,15 @@ if (NOT EXISTS ${CMAKE_CURRENT_LIST_DIR}/src/hsm/cvcerts.h) endif() target_sources(pico_hsm PUBLIC - ${CMAKE_CURRENT_LIST_DIR}/src/hsm/hsm2040.c + ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/src/ccid/ccid2040.c ${CMAKE_CURRENT_LIST_DIR}/src/hsm/sc_hsm.c - ${CMAKE_CURRENT_LIST_DIR}/src/usb/usb_descriptors.c - ${CMAKE_CURRENT_LIST_DIR}/src/fs/file.c - ${CMAKE_CURRENT_LIST_DIR}/src/fs/flash.c - ${CMAKE_CURRENT_LIST_DIR}/src/fs/low_flash.c - ${CMAKE_CURRENT_LIST_DIR}/src/rng/random.c - ${CMAKE_CURRENT_LIST_DIR}/src/rng/neug.c + ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/src/usb/usb_descriptors.c + ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/src/fs/file.c + ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/src/fs/flash.c + ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/src/fs/low_flash.c + ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/src/rng/random.c + ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/src/rng/neug.c + ${CMAKE_CURRENT_LIST_DIR}/src/hsm/files.c ${CMAKE_CURRENT_LIST_DIR}/src/hsm/crypto_utils.c ${CMAKE_CURRENT_LIST_DIR}/src/hsm/dkek.c ${CMAKE_CURRENT_LIST_DIR}/src/hsm/eac.c @@ -115,10 +116,11 @@ target_sources(pico_hsm PUBLIC ) target_include_directories(pico_hsm PUBLIC - ${CMAKE_CURRENT_LIST_DIR}/src/fs + ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/src/fs ${CMAKE_CURRENT_LIST_DIR}/src/hsm - ${CMAKE_CURRENT_LIST_DIR}/src/rng - ${CMAKE_CURRENT_LIST_DIR}/src/usb + ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/src/ccid + ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/src/rng + ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/src/usb ${CMAKE_CURRENT_LIST_DIR}/opensc/src ${CMAKE_CURRENT_LIST_DIR}/mbedtls/include ${CMAKE_CURRENT_LIST_DIR}/mbedtls/library diff --git a/pico-ccid b/pico-ccid new file mode 160000 index 0000000..cffee42 --- /dev/null +++ b/pico-ccid @@ -0,0 +1 @@ +Subproject commit cffee4264a531b52a5991c916e131280adeb1c9d diff --git a/src/fs/file.c b/src/fs/file.c deleted file mode 100644 index 5adb11a..0000000 --- a/src/fs/file.c +++ /dev/null @@ -1,416 +0,0 @@ -/* - * This file is part of the Pico HSM distribution (https://github.com/polhenarejos/pico-hsm). - * Copyright (c) 2022 Pol Henarejos. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 3. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "file.h" -#include "tusb.h" -#include "hsm2040.h" -#include "sc_hsm.h" -#include "libopensc/card-sc-hsm.h" -#include - -extern const uintptr_t end_data_pool; -extern const uintptr_t start_data_pool; -extern int flash_write_data_to_file(file_t *file, const uint8_t *data, uint16_t len); -extern int flash_program_halfword (uintptr_t addr, uint16_t data); -extern int flash_program_word (uintptr_t addr, uint32_t data); -extern int flash_program_uintptr (uintptr_t addr, uintptr_t data); -extern int flash_program_block(uintptr_t addr, const uint8_t *data, size_t len); -extern uintptr_t flash_read_uintptr(uintptr_t addr); -extern uint16_t flash_read_uint16(uintptr_t addr); -extern uint8_t flash_read_uint8(uintptr_t addr); -extern uint8_t *flash_read(uintptr_t addr); -extern void low_flash_available(); - -//puts FCI in the RAPDU -void process_fci(const file_t *pe) { - uint8_t *p = res_APDU; - uint8_t buf[64]; - res_APDU_size = 0; - res_APDU[res_APDU_size++] = 0x6f; - res_APDU[res_APDU_size++] = 0x00; //computed later - - res_APDU[res_APDU_size++] = 0x81; - res_APDU[res_APDU_size++] = 2; - if (pe->data) { - if ((pe->type & FILE_DATA_FUNC) == FILE_DATA_FUNC) { - uint16_t len = ((int (*)(const file_t *, int))(pe->data))(pe, 0); - res_APDU[res_APDU_size++] = (len >> 8) & 0xff; - res_APDU[res_APDU_size++] = len & 0xff; - } - else { - res_APDU[res_APDU_size++] = pe->data[1]; - res_APDU[res_APDU_size++] = pe->data[0]; - } - } - else { - memset(res_APDU+res_APDU_size, 0, 2); - res_APDU_size += 2; - } - - res_APDU[res_APDU_size++] = 0x82; - res_APDU[res_APDU_size++] = 1; - res_APDU[res_APDU_size] = 0; - if (pe->type == FILE_TYPE_INTERNAL_EF) - res_APDU[res_APDU_size++] |= 0x08; - else if (pe->type == FILE_TYPE_WORKING_EF) - res_APDU[res_APDU_size++] |= pe->ef_structure & 0x7; - else if (pe->type == FILE_TYPE_DF) - res_APDU[res_APDU_size++] |= 0x38; - - res_APDU[res_APDU_size++] = 0x83; - res_APDU[res_APDU_size++] = 2; - put_uint16_t(pe->fid, res_APDU+res_APDU_size); - res_APDU_size += 2; - res_APDU[1] = res_APDU_size-2; -} - -extern const uint8_t sc_hsm_aid[]; -extern int parse_token_info(const file_t *f, int mode); -extern int parse_cvca(const file_t *f, int mode); - -file_t file_entries[] = { - /* 0 */ { .fid = 0x3f00 , .parent = 0xff, .name = NULL, .type = FILE_TYPE_DF, .data = NULL, .ef_structure = 0, .acl = {0} }, // MF - /* 1 */ { .fid = 0x2f00 , .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.DIR - /* 2 */ { .fid = 0x2f01 , .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.ATR - /* 3 */ { .fid = 0x2f02 , .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF | FILE_DATA_FUNC,.data = (uint8_t *)parse_cvca, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.GDO - /* 4 */ { .fid = 0x2f03 , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF | FILE_DATA_FUNC,.data = (uint8_t *)parse_token_info, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.TokenInfo - /* 5 */ { .fid = 0x5015 , .parent = 0, .name = NULL, .type = FILE_TYPE_DF, .data = NULL, .ef_structure = 0, .acl = {0} }, //DF.PKCS15 - /* 6 */ { .fid = 0x5031 , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.ODF - /* 7 */ { .fid = 0x5032 , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.TokenInfo - /* 8 */ { .fid = 0x5033 , .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.UnusedSpace - /* 9 */ { .fid = 0x1081 , .parent = 5, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff} }, //PIN (PIN1) - /* 10 */ { .fid = 0x1082 , .parent = 5, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff} }, //max retries PIN (PIN1) - /* 11 */ { .fid = 0x1083 , .parent = 5, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff} }, //retries PIN (PIN1) - /* 12 */ { .fid = 0x1088 , .parent = 5, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff} }, //PIN (SOPIN) - /* 13 */ { .fid = 0x1089 , .parent = 5, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff} }, //max retries PIN (SOPIN) - /* 14 */ { .fid = 0x108A , .parent = 5, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff} }, //retries PIN (SOPIN) - /* 15 */ { .fid = EF_DKEK , .parent = 5, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff} }, //DKEK - /* 16 */ { .fid = EF_DEVOPS , .parent = 5, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff} }, //Device options - /* 17 */ { .fid = EF_PRKDFS , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.PrKDFs - /* 18 */ { .fid = EF_PUKDFS , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.PuKDFs - /* 19 */ { .fid = EF_CDFS , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.CDFs - /* 20 */ { .fid = EF_AODFS , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.AODFs - /* 21 */ { .fid = EF_DODFS , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.DODFs - /* 22 */ { .fid = EF_SKDFS , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.SKDFs - ///* 23 */ { .fid = 0x0000, .parent = 0, .name = openpgpcard_aid, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, - /* 24 */ { .fid = 0x0000, .parent = 5, .name = sc_hsm_aid, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, - /* 25 */ { .fid = 0x0000, .parent = 0xff, .name = NULL, .type = FILE_TYPE_UNKNOWN, .data = NULL, .ef_structure = 0, .acl = {0} } //end -}; - -const file_t *MF = &file_entries[0]; -const file_t *file_last = &file_entries[sizeof(file_entries)/sizeof(file_t)-1]; -const file_t *file_openpgp = &file_entries[sizeof(file_entries)/sizeof(file_t)-3]; -const file_t *file_sc_hsm = &file_entries[sizeof(file_entries)/sizeof(file_t)-2]; -file_t *file_pin1 = NULL; -file_t *file_retries_pin1 = NULL; -file_t *file_sopin = NULL; -file_t *file_retries_sopin = NULL; - -#define MAX_DYNAMIC_FILES 64 -uint16_t dynamic_files = 0; -file_t dynamic_file[MAX_DYNAMIC_FILES]; - -bool card_terminated = false; - -bool is_parent(const file_t *child, const file_t *parent) { - if (child == parent) - return true; - if (child == MF) - return false; - return is_parent(&file_entries[child->parent], parent); -} - -file_t *get_parent(file_t *f) { - return &file_entries[f->parent]; -} - -file_t *search_by_name(uint8_t *name, uint16_t namelen) { - for (file_t *p = file_entries; p != file_last; p++) { - if (p->name && *p->name == apdu.cmd_apdu_data_len && memcmp(p->name+1, name, namelen) == 0) { - return p; - } - } - return NULL; -} - -file_t *search_by_fid(const uint16_t fid, const file_t *parent, const uint8_t sp) { - - for (file_t *p = file_entries; p != file_last; p++) { - if (p->fid != 0x0000 && p->fid == fid) { - if (!parent || (parent && is_parent(p, parent))) { - if (!sp || sp == SPECIFY_ANY || (((sp & SPECIFY_EF) && (p->type & FILE_TYPE_INTERNAL_EF)) || ((sp & SPECIFY_DF) && p->type == FILE_TYPE_DF))) - return p; - } - } - } - return NULL; -} - -uint8_t make_path_buf(const file_t *pe, uint8_t *buf, uint8_t buflen, const file_t *top) { - if (!buflen) - return 0; - if (pe == top) //MF or relative DF - return 0; - put_uint16_t(pe->fid, buf); - return make_path_buf(&file_entries[pe->parent], buf+2, buflen-2, top)+2; -} - -uint8_t make_path(const file_t *pe, const file_t *top, uint8_t *path) { - uint8_t buf[MAX_DEPTH*2], *p = path; - put_uint16_t(pe->fid, buf); - uint8_t depth = make_path_buf(&file_entries[pe->parent], buf+2, sizeof(buf)-2, top)+2; - for (int d = depth-2; d >= 0; d -= 2) { - memcpy(p, buf+d, 2); - p += 2; - } - return depth; -} - -file_t *search_by_path(const uint8_t *pe_path, uint8_t pathlen, const file_t *parent) { - uint8_t path[MAX_DEPTH*2]; - if (pathlen > sizeof(path)) { - return NULL; - } - for (file_t *p = file_entries; p != file_last; p++) { - uint8_t depth = make_path(p, parent, path); - if (pathlen == depth && memcmp(path, pe_path, depth) == 0) - return p; - } - return NULL; -} - -file_t *currentEF = NULL; -file_t *currentDF = NULL; -const file_t *selected_applet = NULL; -bool isUserAuthenticated = false; - -bool authenticate_action(const file_t *ef, uint8_t op) { - uint8_t acl = ef->acl[op]; - if (acl == 0x0) - return true; - else if (acl == 0xff) - return false; - else if (acl == 0x90 || acl & 0x9F == 0x10) { - // PIN required. - if(isUserAuthenticated) { - return true; - } - else { - return false; - } - } - return false; -} - -#include "libopensc/pkcs15.h" - -void initialize_chain(file_chain_t **chain) { - file_chain_t *next; - for (file_chain_t *f = *chain; f; f = next) { - next = f->next; - free(f); - } - *chain = NULL; -} - -void initialize_flash(bool hard) { - if (hard) { - const uint8_t empty[8] = { 0 }; - flash_program_block(end_data_pool, empty, sizeof(empty)); - low_flash_available(); - } - for (file_t *f = file_entries; f != file_last; f++) { - if ((f->type & FILE_DATA_FLASH) == FILE_DATA_FLASH) - f->data = NULL; - } - dynamic_files = 0; -} - -void scan_flash() { - initialize_flash(false); //soft initialization - if (*(uintptr_t *)end_data_pool == 0xffffffff && *(uintptr_t *)(end_data_pool+sizeof(uintptr_t)) == 0xffffffff) - { - printf("First initialization (or corrupted!)\r\n"); - const uint8_t empty[8] = { 0 }; - flash_program_block(end_data_pool, empty, sizeof(empty)); - //low_flash_available(); - //wait_flash_finish(); - } - printf("SCAN\r\n"); - - uintptr_t base = flash_read_uintptr(end_data_pool); - for (uintptr_t base = flash_read_uintptr(end_data_pool); base >= start_data_pool; base = flash_read_uintptr(base)) { - if (base == 0x0) //all is empty - break; - - uint16_t fid = flash_read_uint16(base+sizeof(uintptr_t)+sizeof(uintptr_t)); - printf("[%x] scan fid %x, len %d\r\n",base,fid,flash_read_uint16(base+sizeof(uintptr_t)+sizeof(uintptr_t)+sizeof(uint16_t))); - file_t *file = (file_t *)search_by_fid(fid, NULL, SPECIFY_EF); - if (!file) { - file = file_new(fid); - uint8_t pfx = fid >> 8; - if (pfx != KEY_PREFIX && pfx != PRKD_PREFIX && pfx != CD_PREFIX && pfx != EE_CERTIFICATE_PREFIX && pfx != DCOD_PREFIX && pfx != PROT_DATA_PREFIX && pfx != DATA_PREFIX) { - TU_LOG1("SCAN FOUND ORPHAN FILE: %x\r\n",fid); - continue; - } - } - file->data = (uint8_t *)(base+sizeof(uintptr_t)+sizeof(uintptr_t)+sizeof(uint16_t)); - if (flash_read_uintptr(base) == 0x0) { - break; - } - } - file_pin1 = search_by_fid(0x1081, NULL, SPECIFY_EF); - if (file_pin1) { - if (!file_pin1->data) { - TU_LOG1("PIN1 is empty. Initializing with default password\r\n"); - const uint8_t empty[33] = { 0 }; - flash_write_data_to_file(file_pin1, empty, sizeof(empty)); - } - } - else { - TU_LOG1("FATAL ERROR: PIN1 not found in memory!\r\n"); - } - file_sopin = search_by_fid(0x1088, NULL, SPECIFY_EF); - if (file_sopin) { - if (!file_sopin->data) { - TU_LOG1("SOPIN is empty. Initializing with default password\r\n"); - const uint8_t empty[33] = { 0 }; - flash_write_data_to_file(file_sopin, empty, sizeof(empty)); - } - } - else { - TU_LOG1("FATAL ERROR: SOPIN not found in memory!\r\n"); - } - file_retries_pin1 = search_by_fid(0x1083, NULL, SPECIFY_EF); - if (file_retries_pin1) { - if (!file_retries_pin1->data) { - TU_LOG1("Retries PIN1 is empty. Initializing with default retriesr\n"); - const uint8_t retries = 3; - flash_write_data_to_file(file_retries_pin1, &retries, sizeof(uint8_t)); - } - } - else { - TU_LOG1("FATAL ERROR: Retries PIN1 not found in memory!\r\n"); - } - file_retries_sopin = search_by_fid(0x108A, NULL, SPECIFY_EF); - if (file_retries_sopin) { - if (!file_retries_sopin->data) { - TU_LOG1("Retries SOPIN is empty. Initializing with default retries\r\n"); - const uint8_t retries = 15; - flash_write_data_to_file(file_retries_sopin, &retries, sizeof(uint8_t)); - } - } - else { - TU_LOG1("FATAL ERROR: Retries SOPIN not found in memory!\r\n"); - } - file_t *tf = NULL; - - tf = search_by_fid(0x1082, NULL, SPECIFY_EF); - if (tf) { - if (!tf->data) { - TU_LOG1("Max retries PIN1 is empty. Initializing with default max retriesr\n"); - const uint8_t retries = 3; - flash_write_data_to_file(tf, &retries, sizeof(uint8_t)); - } - } - else { - TU_LOG1("FATAL ERROR: Max Retries PIN1 not found in memory!\r\n"); - } - tf = search_by_fid(0x1089, NULL, SPECIFY_EF); - if (tf) { - if (!tf->data) { - TU_LOG1("Max Retries SOPIN is empty. Initializing with default max retries\r\n"); - const uint8_t retries = 15; - flash_write_data_to_file(tf, &retries, sizeof(uint8_t)); - } - } - else { - TU_LOG1("FATAL ERROR: Retries SOPIN not found in memory!\r\n"); - } - low_flash_available(); -} - -uint8_t *file_read(const uint8_t *addr) { - return flash_read((uintptr_t)addr); -} -uint16_t file_read_uint16(const uint8_t *addr) { - return flash_read_uint16((uintptr_t)addr); -} -uint8_t file_read_uint8(const uint8_t *addr) { - return flash_read_uint8((uintptr_t)addr); -} - -file_t *search_dynamic_file(uint16_t fid) { - for (int i = 0; i < dynamic_files; i++) { - if (dynamic_file[i].fid == fid) - return &dynamic_file[i]; - } - return NULL; -} - -int delete_dynamic_file(file_t *f) { - for (int i = 0; i < dynamic_files; i++) { - if (dynamic_file[i].fid == f->fid) { - for (int j = i+1; j < dynamic_files; j++) - memcpy(&dynamic_file[j-1], &dynamic_file[j], sizeof(file_t)); - dynamic_files--; - return HSM_OK; - } - } - return HSM_ERR_FILE_NOT_FOUND; -} - -file_t *file_new(uint16_t fid) { - file_t *f; - if ((f = search_dynamic_file(fid))) - return f; - if (dynamic_files == MAX_DYNAMIC_FILES) - return NULL; - f = &dynamic_file[dynamic_files]; - dynamic_files++; - file_t file = { - .fid = fid, - .parent = 5, - .name = NULL, - .type = FILE_TYPE_WORKING_EF, - .ef_structure = FILE_EF_TRANSPARENT, - .data = NULL, - .acl = {0} - }; - memcpy(f, &file, sizeof(file_t)); - //memset((uint8_t *)f->acl, 0x90, sizeof(f->acl)); - return f; -} - -file_chain_t *add_file_to_chain(file_t *file, file_chain_t **chain) { - if (search_file_chain(file->fid, *chain)) - return NULL; - file_chain_t *fc = (file_chain_t *)malloc(sizeof(file_chain_t)); - fc->file = file; - fc->next = *chain; - *chain = fc; - return fc; -} - -file_t *search_file_chain(uint16_t fid, file_chain_t *chain) { - for (file_chain_t *fc = chain; fc; fc = fc->next) { - if (fid == fc->file->fid) { - return fc->file; - } - } - return NULL; -} \ No newline at end of file diff --git a/src/fs/file.h b/src/fs/file.h deleted file mode 100644 index 5b4175f..0000000 --- a/src/fs/file.h +++ /dev/null @@ -1,124 +0,0 @@ -/* - * This file is part of the Pico HSM distribution (https://github.com/polhenarejos/pico-hsm). - * Copyright (c) 2022 Pol Henarejos. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 3. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - - -#ifndef _FILE_H_ -#define _FILE_H_ - -#include -#include "pico/stdlib.h" - -#define FILE_TYPE_UNKNOWN 0x00 -#define FILE_TYPE_DF 0x04 -#define FILE_TYPE_INTERNAL_EF 0x03 -#define FILE_TYPE_WORKING_EF 0x01 -#define FILE_TYPE_BSO 0x10 -#define FILE_PERSISTENT 0x20 -#define FILE_DATA_FLASH 0x40 -#define FILE_DATA_FUNC 0x80 - -/* EF structures */ -#define FILE_EF_UNKNOWN 0x00 -#define FILE_EF_TRANSPARENT 0x01 -#define FILE_EF_LINEAR_FIXED 0x02 -#define FILE_EF_LINEAR_FIXED_TLV 0x03 -#define FILE_EF_LINEAR_VARIABLE 0x04 -#define FILE_EF_LINEAR_VARIABLE_TLV 0x05 -#define FILE_EF_CYCLIC 0x06 -#define FILE_EF_CYCLIC_TLV 0x07 - -#define ACL_OP_DELETE_SELF 0x00 -#define ACL_OP_CREATE_DF 0x01 -#define ACL_OP_CREATE_EF 0x02 -#define ACL_OP_DELETE_CHILD 0x03 -#define ACL_OP_WRITE 0x04 -#define ACL_OP_UPDATE_ERASE 0x05 -#define ACL_OP_READ_SEARCH 0x06 - -#define SPECIFY_EF 0x1 -#define SPECIFY_DF 0x2 -#define SPECIFY_ANY 0x3 - -#define EF_DKEK 0x108F -#define EF_PRKDFS 0x6040 -#define EF_PUKDFS 0x6041 -#define EF_CDFS 0x6042 -#define EF_AODFS 0x6043 -#define EF_DODFS 0x6044 -#define EF_SKDFS 0x6045 -#define EF_DEVOPS 0x100E - -#define MAX_DEPTH 4 - -typedef struct file -{ - const uint16_t fid; - const uint8_t parent; //entry number in the whole table!! - const uint8_t *name; - const uint8_t type; - const uint8_t ef_structure; - uint8_t *data; //should include 2 bytes len at begining - const uint8_t acl[7]; -} __attribute__((packed)) file_t; - -typedef struct file_chain -{ - file_t *file; - struct file_chain *next; -} file_chain_t; - -extern file_t *currentEF; -extern file_t *currentDF; -extern const file_t *selected_applet; - -extern const file_t *MF; -extern const file_t *file_last; -extern const file_t *file_openpgp; -extern const file_t *file_sc_hsm; -extern bool card_terminated; -extern file_t *file_pin1; -extern file_t *file_retries_pin1; -extern file_t *file_sopin; -extern file_t *file_retries_sopin; - -extern file_t *search_by_fid(const uint16_t fid, const file_t *parent, const uint8_t sp); -extern file_t *search_by_name(uint8_t *name, uint16_t namelen); -extern file_t *search_by_path(const uint8_t *pe_path, uint8_t pathlen, const file_t *parent); -extern bool authenticate_action(const file_t *ef, uint8_t op); -extern void process_fci(const file_t *pe); -extern void scan_flash(); -extern void initialize_flash(bool); - -extern file_t file_entries[]; - -extern uint8_t *file_read(const uint8_t *addr); -extern uint16_t file_read_uint16(const uint8_t *addr); -extern uint8_t file_read_uint8(const uint8_t *addr); -extern file_t *file_new(uint16_t); -file_t *get_parent(file_t *f); - -extern uint16_t dynamic_files; -extern file_t dynamic_file[]; -extern file_t *search_dynamic_file(uint16_t); -extern int delete_dynamic_file(file_t *f); - -extern file_chain_t *add_file_to_chain(file_t *file, file_chain_t **chain); -extern file_t *search_file_chain(uint16_t fid, file_chain_t *chain); -extern bool isUserAuthenticated; - -#endif - diff --git a/src/fs/flash.c b/src/fs/flash.c deleted file mode 100644 index 569b275..0000000 --- a/src/fs/flash.c +++ /dev/null @@ -1,134 +0,0 @@ -/* - * This file is part of the Pico HSM distribution (https://github.com/polhenarejos/pico-hsm). - * Copyright (c) 2022 Pol Henarejos. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 3. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - - -#include -#include - -#include "pico/stdlib.h" -#include "hardware/flash.h" -#include "hsm2040.h" -#include "tusb.h" -#include "file.h" -#include "sc_hsm.h" - -/* - * ------------------------------------------------------ - * | | - * | next_addr | prev_addr | fid | data (len + payload) | - * | | - * ------------------------------------------------------ - */ -#define FLASH_TARGET_OFFSET (PICO_FLASH_SIZE_BYTES >> 1) // DATA starts at the mid of flash -#define FLASH_DATA_HEADER_SIZE (sizeof(uintptr_t)+sizeof(uint32_t)) -#define FLASH_PERMANENT_REGION (4*FLASH_SECTOR_SIZE) // 4 sectors (16kb) of permanent memory - -//To avoid possible future allocations, data region starts at the end of flash and goes upwards to the center region - -const uintptr_t start_data_pool = (XIP_BASE + FLASH_TARGET_OFFSET); -const uintptr_t end_data_pool = (XIP_BASE + PICO_FLASH_SIZE_BYTES)-FLASH_DATA_HEADER_SIZE-FLASH_PERMANENT_REGION; //This is a fixed value. DO NOT CHANGE -#define FLASH_ADDR_DATA_STORAGE_START start_data_pool - -extern int flash_program_block(uintptr_t addr, const uint8_t *data, size_t len); -extern int flash_program_halfword (uintptr_t addr, uint16_t data); -extern int flash_program_uintptr(uintptr_t, uintptr_t); -extern uintptr_t flash_read_uintptr(uintptr_t addr); -extern uint16_t flash_read_uint16(uintptr_t addr); - -extern void low_flash_available(); - -uintptr_t allocate_free_addr(uint16_t size) { - if (size > FLASH_SECTOR_SIZE) - return 0x0; //ERROR - size_t real_size = size+sizeof(uint16_t)+sizeof(uintptr_t)+sizeof(uint16_t)+sizeof(uintptr_t); //len+len size+next address+fid+prev_addr size - uintptr_t next_base = 0x0; - for (uintptr_t base = end_data_pool; base >= start_data_pool; base = next_base) { - uintptr_t addr_alg = base & -FLASH_SECTOR_SIZE; //start address of sector - uintptr_t potential_addr = base-real_size; - next_base = flash_read_uintptr(base); - //printf("nb %x %x %x %x\r\n",base,next_base,addr_alg,potential_addr); - //printf("fid %x\r\n",flash_read_uint16(next_base+sizeof(uintptr_t))); - if (next_base == 0x0) { //we are at the end - //now we check if we fit in the current sector - if (addr_alg <= potential_addr) //it fits in the current sector - { - flash_program_uintptr(potential_addr, 0x0); - flash_program_uintptr(potential_addr+sizeof(uintptr_t), base); - flash_program_uintptr(base, potential_addr); - return potential_addr; - } - else if (addr_alg-FLASH_SECTOR_SIZE >= start_data_pool) { //check whether it fits in the next sector, so we take addr_aligned as the base - potential_addr = addr_alg-real_size; - flash_program_uintptr(potential_addr, 0x0); - flash_program_uintptr(potential_addr+sizeof(uintptr_t), base); - flash_program_uintptr(base, potential_addr); - return potential_addr; - } - return 0x0; - } - //we check if |base-(next_addr+size_next_addr)| > |base-potential_addr| only if fid != 1xxx (not size blocked) - else if (addr_alg <= potential_addr && base-(next_base+flash_read_uint16(next_base+sizeof(uintptr_t)+sizeof(uintptr_t)+sizeof(uint16_t))+2*sizeof(uint16_t)+2*sizeof(uintptr_t)) > base-potential_addr && flash_read_uint16(next_base+sizeof(uintptr_t)) & 0x1000 != 0x1000) { - flash_program_uintptr(potential_addr, next_base); - flash_program_uintptr(potential_addr+sizeof(uintptr_t), base); - flash_program_uintptr(base, potential_addr); - return potential_addr; - } - } - return 0x0; //probably never reached -} - -int flash_clear_file(file_t *file) { - uintptr_t base_addr = (uintptr_t)(file->data-sizeof(uintptr_t)-sizeof(uint16_t)-sizeof(uintptr_t)); - uintptr_t prev_addr = flash_read_uintptr(base_addr+sizeof(uintptr_t)); - uintptr_t next_addr = flash_read_uintptr(base_addr); - //printf("nc %x->%x %x->%x\r\n",prev_addr,flash_read_uintptr(prev_addr),base_addr,next_addr); - flash_program_uintptr(prev_addr, next_addr); - flash_program_halfword((uintptr_t)file->data, 0); - if (next_addr > 0) - flash_program_uintptr(next_addr+sizeof(uintptr_t), prev_addr); - //printf("na %x->%x\r\n",prev_addr,flash_read_uintptr(prev_addr)); - return HSM_OK; -} - -int flash_write_data_to_file(file_t *file, const uint8_t *data, uint16_t len) { - if (!file) - return HSM_ERR_NULL_PARAM; - if (len > FLASH_SECTOR_SIZE) - return HSM_ERR_NO_MEMORY; - if (file->data) { //already in flash - uint16_t size_file_flash = flash_read_uint16((uintptr_t)file->data); - if (len <= size_file_flash) { //it fits, no need to move it - flash_program_halfword((uintptr_t)file->data, len); - if (data) - flash_program_block((uintptr_t)file->data+sizeof(uint16_t), data, len); - return HSM_OK; - } - else { //we clear the old file - flash_clear_file(file); - } - } - uintptr_t new_addr = allocate_free_addr(len); - //printf("na %x\r\n",new_addr); - if (new_addr == 0x0) - return HSM_ERR_NO_MEMORY; - file->data = (uint8_t *)new_addr+sizeof(uintptr_t)+sizeof(uint16_t)+sizeof(uintptr_t); //next addr+fid+prev addr - flash_program_halfword(new_addr+sizeof(uintptr_t)+sizeof(uintptr_t), file->fid); - flash_program_halfword((uintptr_t)file->data, len); - if (data) - flash_program_block((uintptr_t)file->data+sizeof(uint16_t), data, len); - return HSM_OK; -} diff --git a/src/fs/low_flash.c b/src/fs/low_flash.c deleted file mode 100644 index 4951fc6..0000000 --- a/src/fs/low_flash.c +++ /dev/null @@ -1,248 +0,0 @@ -/* - * This file is part of the Pico HSM distribution (https://github.com/polhenarejos/pico-hsm). - * Copyright (c) 2022 Pol Henarejos. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 3. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - - -#include -#include -#include - -#include "pico/stdlib.h" -#include "hardware/flash.h" -#include "hardware/sync.h" -#include "pico/mutex.h" -#include "pico/sem.h" -#include "pico/multicore.h" -#include "hsm2040.h" -#include "sc_hsm.h" -#include - -#define TOTAL_FLASH_PAGES 4 - -typedef struct page_flash { - uint8_t page[FLASH_SECTOR_SIZE]; - uintptr_t address; - bool ready; - bool erase; - size_t page_size; //this param is for easy erase. It allows to erase with a single call. IT DOES NOT APPLY TO WRITE -} page_flash_t; - -static page_flash_t flash_pages[TOTAL_FLASH_PAGES]; - -static mutex_t mtx_flash; -static semaphore_t sem_wait; - -static uint8_t ready_pages = 0; - -bool flash_available = false; -static bool locked_out = false; - - -//this function has to be called from the core 0 -void do_flash() -{ - if (mutex_try_enter(&mtx_flash, NULL) == true) { - if (locked_out == true && flash_available == true && ready_pages > 0) { - //printf(" DO_FLASH AVAILABLE\r\n"); - for (int r = 0; r < TOTAL_FLASH_PAGES; r++) { - if (flash_pages[r].ready == true) { - //printf("WRITTING %X\r\n",flash_pages[r].address-XIP_BASE); - while (multicore_lockout_start_timeout_us(1000) == false); - //printf("WRITTING %X\r\n",flash_pages[r].address-XIP_BASE); - uint32_t ints = save_and_disable_interrupts(); - flash_range_erase(flash_pages[r].address-XIP_BASE, FLASH_SECTOR_SIZE); - flash_range_program(flash_pages[r].address-XIP_BASE, flash_pages[r].page, FLASH_SECTOR_SIZE); - restore_interrupts (ints); - while (multicore_lockout_end_timeout_us(1000) == false); - //printf("WRITEN %X !\r\n",flash_pages[r].address); - - flash_pages[r].ready = false; - ready_pages--; - } - else if (flash_pages[r].erase == true) { - while (multicore_lockout_start_timeout_us(1000) == false); - //printf("WRITTING\r\n"); - flash_range_erase(flash_pages[r].address-XIP_BASE, flash_pages[r].page_size ? ((int)(flash_pages[r].page_size/FLASH_SECTOR_SIZE))*FLASH_SECTOR_SIZE : FLASH_SECTOR_SIZE); - while (multicore_lockout_end_timeout_us(1000) == false); - flash_pages[r].erase = false; - ready_pages--; - } - } - flash_available = false; - if (ready_pages != 0) { - DEBUG_INFO("ERROR: DO FLASH DOES NOT HAVE ZERO PAGES"); - } - } - mutex_exit(&mtx_flash); - } - sem_release(&sem_wait); -} - -//this function has to be called from the core 0 -void low_flash_init() { - mutex_init(&mtx_flash); - sem_init(&sem_wait, 0, 1); - memset(flash_pages, 0, sizeof(page_flash_t)*TOTAL_FLASH_PAGES); -} - -void low_flash_init_core1() { - mutex_enter_blocking(&mtx_flash); - multicore_lockout_victim_init(); - locked_out = true; - mutex_exit(&mtx_flash); -} - -void wait_flash_finish() { - sem_acquire_blocking(&sem_wait); //blocks until released - //wake up - sem_acquire_blocking(&sem_wait); //decrease permits -} - -void low_flash_available() { - mutex_enter_blocking(&mtx_flash); - flash_available = true; - mutex_exit(&mtx_flash); -} - -page_flash_t *find_free_page(uintptr_t addr) { - uintptr_t addr_alg = addr & -FLASH_SECTOR_SIZE; - page_flash_t *p = NULL; - for (int r = 0; r < TOTAL_FLASH_PAGES; r++) - { - if ((!flash_pages[r].ready && !flash_pages[r].erase) || flash_pages[r].address == addr_alg) //first available - { - p = &flash_pages[r]; - if (!flash_pages[r].ready && !flash_pages[r].erase) - { - memcpy(p->page, (uint8_t *)addr_alg, FLASH_SECTOR_SIZE); - ready_pages++; - p->address = addr_alg; - p->ready = true; - } - return p; - } - } - return NULL; -} - -int flash_program_block(uintptr_t addr, const uint8_t *data, size_t len) { - uintptr_t addr_alg = addr & -FLASH_SECTOR_SIZE; - page_flash_t *p = NULL; - - if (!data || len == 0) - return HSM_ERR_NULL_PARAM; - - mutex_enter_blocking(&mtx_flash); - if (ready_pages == TOTAL_FLASH_PAGES) { - mutex_exit(&mtx_flash); - DEBUG_INFO("ERROR: ALL FLASH PAGES CACHED\r\n"); - return HSM_ERR_NO_MEMORY; - } - if (!(p = find_free_page(addr))) - { - mutex_exit(&mtx_flash); - DEBUG_INFO("ERROR: FLASH CANNOT FIND A PAGE (rare error)\r\n"); - return HSM_ERR_MEMORY_FATAL; - } - memcpy(&p->page[addr&(FLASH_SECTOR_SIZE-1)], data, len); - //printf("Flash: modified page %X with data %x at [%x] (top page %X)\r\n",addr_alg,data,addr&(FLASH_SECTOR_SIZE-1),addr); - mutex_exit(&mtx_flash); - return HSM_OK; -} - -int flash_program_halfword (uintptr_t addr, uint16_t data) { - return flash_program_block(addr, (const uint8_t *)&data, sizeof(uint16_t)); -} - -int flash_program_word (uintptr_t addr, uint32_t data) { - return flash_program_block(addr, (const uint8_t *)&data, sizeof(uint32_t)); -} - -int flash_program_uintptr (uintptr_t addr, uintptr_t data) { - return flash_program_block(addr, (const uint8_t *)&data, sizeof(uintptr_t)); -} - -uint8_t *flash_read(uintptr_t addr) { - uintptr_t addr_alg = addr & -FLASH_SECTOR_SIZE; - mutex_enter_blocking(&mtx_flash); - if (ready_pages > 0) { - for (int r = 0; r < TOTAL_FLASH_PAGES; r++) - { - if (flash_pages[r].ready && flash_pages[r].address == addr_alg) { - uint8_t *v = &flash_pages[r].page[addr&(FLASH_SECTOR_SIZE-1)]; - mutex_exit(&mtx_flash); - return v; - } - } - } - uint8_t *v = (uint8_t *)addr; - mutex_exit(&mtx_flash); - return v; -} - -uintptr_t flash_read_uintptr(uintptr_t addr) { - uint8_t *p = flash_read(addr); - uintptr_t v = 0x0; - for (int i = 0; i < sizeof(uintptr_t); i++) { - v |= (uintptr_t)p[i]<<(8*i); - } - return v; -} -uint16_t flash_read_uint16(uintptr_t addr) { - uint8_t *p = flash_read(addr); - uint16_t v = 0x0; - for (int i = 0; i < sizeof(uint16_t); i++) { - v |= p[i]<<(8*i); - } - return v; -} -uint8_t flash_read_uint8(uintptr_t addr) { - return *flash_read(addr); -} - -int flash_erase_page (uintptr_t addr, size_t page_size) { - uintptr_t addr_alg = addr & -FLASH_SECTOR_SIZE; - page_flash_t *p = NULL; - - mutex_enter_blocking(&mtx_flash); - if (ready_pages == TOTAL_FLASH_PAGES) { - mutex_exit(&mtx_flash); - DEBUG_INFO("ERROR: ALL FLASH PAGES CACHED\r\n"); - return HSM_ERR_NO_MEMORY; - } - if (!(p = find_free_page(addr))) { - DEBUG_INFO("ERROR: FLASH CANNOT FIND A PAGE (rare error)\r\n"); - mutex_exit(&mtx_flash); - return HSM_ERR_MEMORY_FATAL; - } - p->erase = true; - p->ready = false; - p->page_size = page_size; - mutex_exit(&mtx_flash); - - return HSM_OK; -} - -bool flash_check_blank(const uint8_t *p_start, size_t size) -{ - const uint8_t *p; - - for (p = p_start; p < p_start + size; p++) { - if (*p != 0xff) - return false; - } - return true; -} diff --git a/src/hsm/crypto_utils.c b/src/hsm/crypto_utils.c index 4df1811..287277e 100644 --- a/src/hsm/crypto_utils.c +++ b/src/hsm/crypto_utils.c @@ -85,7 +85,7 @@ int aes_encrypt(const uint8_t *key, const uint8_t *iv, int key_size, int mode, u memcpy(tmp_iv, iv, IV_SIZE); int r = mbedtls_aes_setkey_enc(&aes, key, key_size); if (r != 0) - return HSM_EXEC_ERROR; + return CCID_EXEC_ERROR; if (mode == HSM_AES_MODE_CBC) return mbedtls_aes_crypt_cbc(&aes, MBEDTLS_AES_ENCRYPT, len, tmp_iv, data, data); return mbedtls_aes_crypt_cfb128(&aes, MBEDTLS_AES_ENCRYPT, len, &iv_offset, tmp_iv, data, data); @@ -101,7 +101,7 @@ int aes_decrypt(const uint8_t *key, const uint8_t *iv, int key_size, int mode, u memcpy(tmp_iv, iv, IV_SIZE); int r = mbedtls_aes_setkey_dec(&aes, key, key_size); if (r != 0) - return HSM_EXEC_ERROR; + return CCID_EXEC_ERROR; if (mode == HSM_AES_MODE_CBC) return mbedtls_aes_crypt_cbc(&aes, MBEDTLS_AES_DECRYPT, len, tmp_iv, data, data); r = mbedtls_aes_setkey_enc(&aes, key, key_size); //CFB requires set_enc instead set_dec diff --git a/src/hsm/dkek.c b/src/hsm/dkek.c index cd89c65..d40d437 100644 --- a/src/hsm/dkek.c +++ b/src/hsm/dkek.c @@ -27,6 +27,7 @@ #include "mbedtls/cmac.h" #include "mbedtls/rsa.h" #include "mbedtls/ecdsa.h" +#include "files.h" static uint8_t dkek[IV_SIZE+32]; static uint8_t tmp_dkek[32]; @@ -35,15 +36,15 @@ extern uint8_t session_pin[32]; int load_dkek() { if (has_session_pin == false) - return HSM_NO_LOGIN; + return CCID_NO_LOGIN; file_t *tf = search_by_fid(EF_DKEK, NULL, SPECIFY_EF); if (!tf) - return HSM_ERR_FILE_NOT_FOUND; + return CCID_ERR_FILE_NOT_FOUND; memcpy(dkek, file_read(tf->data+sizeof(uint16_t)), IV_SIZE+32); int ret = aes_decrypt_cfb_256(session_pin, dkek, dkek+IV_SIZE, 32); if (ret != 0) - return HSM_EXEC_ERROR; - return HSM_OK; + return CCID_EXEC_ERROR; + return CCID_OK; } void release_dkek() { @@ -59,11 +60,11 @@ int store_dkek_key() { aes_encrypt_cfb_256(session_pin, dkek, dkek+IV_SIZE, 32); file_t *tf = search_by_fid(EF_DKEK, NULL, SPECIFY_EF); if (!tf) - return HSM_ERR_FILE_NOT_FOUND; + return CCID_ERR_FILE_NOT_FOUND; flash_write_data_to_file(tf, dkek, sizeof(dkek)); low_flash_available(); release_dkek(); - return HSM_OK; + return CCID_OK; } int save_dkek_key(const uint8_t *key) { @@ -83,43 +84,43 @@ void import_dkek_share(const uint8_t *share) { int dkek_kcv(uint8_t *kcv) { //kcv 8 bytes uint8_t hsh[32]; int r = load_dkek(); - if (r != HSM_OK) + if (r != CCID_OK) return r; hash256(dkek+IV_SIZE, 32, hsh); release_dkek(); memcpy(kcv, hsh, 8); - return HSM_OK; + return CCID_OK; } int dkek_kenc(uint8_t *kenc) { //kenc 32 bytes uint8_t buf[32+4]; int r = load_dkek(); - if (r != HSM_OK) + if (r != CCID_OK) return r; memcpy(buf, dkek+IV_SIZE, 32); release_dkek(); memcpy(buf+32, "\x0\x0\x0\x1", 4); hash256(buf, sizeof(buf), kenc); memset(buf, 0, sizeof(buf)); - return HSM_OK; + return CCID_OK; } int dkek_kmac(uint8_t *kmac) { //kmac 32 bytes uint8_t buf[32+4]; int r = load_dkek(); - if (r != HSM_OK) + if (r != CCID_OK) return r; memcpy(buf, dkek+IV_SIZE, 32); release_dkek(); memcpy(buf+32, "\x0\x0\x0\x2", 4); hash256(buf, sizeof(buf), kmac); memset(buf, 0, sizeof(buf)); - return HSM_OK; + return CCID_OK; } int dkek_encrypt(uint8_t *data, size_t len) { int r; - if ((r = load_dkek()) != HSM_OK) + if ((r = load_dkek()) != CCID_OK) return r; r = aes_encrypt_cfb_256(dkek+IV_SIZE, dkek, data, len); release_dkek(); @@ -128,7 +129,7 @@ int dkek_encrypt(uint8_t *data, size_t len) { int dkek_decrypt(uint8_t *data, size_t len) { int r; - if ((r = load_dkek()) != HSM_OK) + if ((r = load_dkek()) != CCID_OK) return r; r = aes_decrypt_cfb_256(dkek+IV_SIZE, dkek, data, len); release_dkek(); @@ -137,7 +138,7 @@ int dkek_decrypt(uint8_t *data, size_t len) { int dkek_encode_key(void *key_ctx, int key_type, uint8_t *out, size_t *out_len) { if (!(key_type & HSM_KEY_RSA) && !(key_type & HSM_KEY_EC) && !(key_type & HSM_KEY_AES)) - return HSM_WRONG_DATA; + return CCID_WRONG_DATA; uint8_t kb[8+2*4+2*4096/8+3+13]; //worst case: RSA-4096 (plus, 13 bytes padding) memset(kb, 0, sizeof(kb)); @@ -167,9 +168,9 @@ int dkek_encode_key(void *key_ctx, int key_type, uint8_t *out, size_t *out_len) kb_len = 32; if (kb_len != 16 && kb_len != 24 && kb_len != 32) - return HSM_WRONG_DATA; + return CCID_WRONG_DATA; if (*out_len < 8+1+10+6+4+(2+32+14)+16) - return HSM_WRONG_LENGTH; + return CCID_WRONG_LENGTH; put_uint16_t(kb_len, kb+8); memcpy(kb+10, key_ctx, kb_len); @@ -182,7 +183,7 @@ int dkek_encode_key(void *key_ctx, int key_type, uint8_t *out, size_t *out_len) } else if (key_type & HSM_KEY_RSA) { if (*out_len < 8+1+12+6+(8+2*4+2*4096/8+3+13)+16) //13 bytes pading - return HSM_WRONG_LENGTH; + return CCID_WRONG_LENGTH; mbedtls_rsa_context *rsa = (mbedtls_rsa_context *)key_ctx; kb_len = 0; put_uint16_t(mbedtls_rsa_get_len(rsa)*8, kb+8+kb_len); kb_len += 2; @@ -199,7 +200,7 @@ int dkek_encode_key(void *key_ctx, int key_type, uint8_t *out, size_t *out_len) } else if (key_type & HSM_KEY_EC) { if (*out_len < 8+1+12+6+(8+2*8+9*66+2+4)+16) //4 bytes pading - return HSM_WRONG_LENGTH; + return CCID_WRONG_LENGTH; mbedtls_ecdsa_context *ecdsa = (mbedtls_ecdsa_context *)key_ctx; kb_len = 0; put_uint16_t(mbedtls_mpi_size(&ecdsa->grp.P)*8, kb+8+kb_len); kb_len += 2; @@ -265,7 +266,7 @@ int dkek_encode_key(void *key_ctx, int key_type, uint8_t *out, size_t *out_len) kb[kb_len] = 0x80; } int r = aes_encrypt(kenc, NULL, 256, HSM_AES_MODE_CBC, kb, kb_len_pad); - if (r != HSM_OK) + if (r != CCID_OK) return r; memcpy(out+*out_len, kb, kb_len_pad); @@ -276,7 +277,7 @@ int dkek_encode_key(void *key_ctx, int key_type, uint8_t *out, size_t *out_len) *out_len += 16; if (r != 0) return r; - return HSM_OK; + return CCID_OK; } int dkek_type_key(const uint8_t *in) { @@ -303,27 +304,27 @@ int dkek_decode_key(void *key_ctx, const uint8_t *in, size_t in_len, int *key_si dkek_kenc(kenc); if (memcmp(kcv, in, 8) != 0) - return HSM_WRONG_DKEK; + return CCID_WRONG_DKEK; uint8_t signature[16]; int r = mbedtls_cipher_cmac(mbedtls_cipher_info_from_type(MBEDTLS_CIPHER_AES_256_ECB), kmac, 256, in, in_len-16, signature); if (r != 0) - return HSM_WRONG_SIGNATURE; + return CCID_WRONG_SIGNATURE; if (memcmp(signature, in+in_len-16, 16) != 0) - return HSM_WRONG_SIGNATURE; + return CCID_WRONG_SIGNATURE; int key_type = in[8]; if (key_type != 5 && key_type != 6 && key_type != 12 && key_type != 15) - return HSM_WRONG_DATA; + return CCID_WRONG_DATA; if ((key_type == 5 || key_type == 6) && memcmp(in+9, "\x00\x0A\x04\x00\x7F\x00\x07\x02\x02\x02\x01\x02", 12) != 0) - return HSM_WRONG_DATA; + return CCID_WRONG_DATA; if (key_type == 12 && memcmp(in+9, "\x00\x0A\x04\x00\x7F\x00\x07\x02\x02\x02\x02\x03", 12) != 0) - return HSM_WRONG_DATA; + return CCID_WRONG_DATA; if (key_type == 15 && memcmp(in+9, "\x00\x08\x60\x86\x48\x01\x65\x03\x04\x01", 10) != 0) - return HSM_WRONG_DATA; + return CCID_WRONG_DATA; size_t ofs = 9; @@ -344,12 +345,12 @@ int dkek_decode_key(void *key_ctx, const uint8_t *in, size_t in_len, int *key_si ofs += len+2; if ((in_len-16-ofs) % 16 != 0) - return HSM_WRONG_PADDING; + return CCID_WRONG_PADDING; uint8_t kb[8+2*4+2*4096/8+3+13]; //worst case: RSA-4096 (plus, 13 bytes padding) memset(kb, 0, sizeof(kb)); memcpy(kb, in+ofs, in_len-16-ofs); r = aes_decrypt(kenc, NULL, 256, HSM_AES_MODE_CBC, kb, in_len-16-ofs); - if (r != HSM_OK) + if (r != CCID_OK) return r; int key_size = get_uint16_t(kb, 8); @@ -364,14 +365,14 @@ int dkek_decode_key(void *key_ctx, const uint8_t *in, size_t in_len, int *key_si r = mbedtls_mpi_read_binary(&rsa->D, kb+ofs, len); ofs += len; if (r != 0) { mbedtls_rsa_free(rsa); - return HSM_WRONG_DATA; + return CCID_WRONG_DATA; } len = get_uint16_t(kb, ofs); ofs += 2; r = mbedtls_mpi_read_binary(&rsa->N, kb+ofs, len); ofs += len; if (r != 0) { mbedtls_rsa_free(rsa); - return HSM_WRONG_DATA; + return CCID_WRONG_DATA; } } else if (key_type == 6) { @@ -385,7 +386,7 @@ int dkek_decode_key(void *key_ctx, const uint8_t *in, size_t in_len, int *key_si r = mbedtls_mpi_read_binary(&rsa->P, kb+ofs, len); ofs += len; if (r != 0) { mbedtls_rsa_free(rsa); - return HSM_WRONG_DATA; + return CCID_WRONG_DATA; } //PQ @@ -395,7 +396,7 @@ int dkek_decode_key(void *key_ctx, const uint8_t *in, size_t in_len, int *key_si r = mbedtls_mpi_read_binary(&rsa->Q, kb+ofs, len); ofs += len; if (r != 0) { mbedtls_rsa_free(rsa); - return HSM_WRONG_DATA; + return CCID_WRONG_DATA; } //N len = get_uint16_t(kb, ofs); ofs += len+2; @@ -405,33 +406,33 @@ int dkek_decode_key(void *key_ctx, const uint8_t *in, size_t in_len, int *key_si r = mbedtls_mpi_read_binary(&rsa->E, kb+ofs, len); ofs += len; if (r != 0) { mbedtls_rsa_free(rsa); - return HSM_WRONG_DATA; + return CCID_WRONG_DATA; } if (key_type == 5) { r = mbedtls_rsa_import(rsa, &rsa->N, NULL, NULL, &rsa->D, &rsa->E); if (r != 0) { mbedtls_rsa_free(rsa); - return HSM_EXEC_ERROR; + return CCID_EXEC_ERROR; } } else if (key_type == 6) { r = mbedtls_rsa_import(rsa, NULL, &rsa->P, &rsa->Q, NULL, &rsa->E); if (r != 0) { mbedtls_rsa_free(rsa); - return HSM_EXEC_ERROR; + return CCID_EXEC_ERROR; } } r = mbedtls_rsa_complete(rsa); if (r != 0) { mbedtls_rsa_free(rsa); - return HSM_EXEC_ERROR; + return CCID_EXEC_ERROR; } r = mbedtls_rsa_check_privkey(rsa); if (r != 0) { mbedtls_rsa_free(rsa); - return HSM_EXEC_ERROR; + return CCID_EXEC_ERROR; } } else if (key_type == 12) { @@ -449,7 +450,7 @@ int dkek_decode_key(void *key_ctx, const uint8_t *in, size_t in_len, int *key_si mbedtls_ecp_group_id ec_id = ec_get_curve_from_prime(kb+ofs, len); if (ec_id == MBEDTLS_ECP_DP_NONE) { mbedtls_ecdsa_free(ecdsa); - return HSM_WRONG_DATA; + return CCID_WRONG_DATA; } ofs += len; @@ -464,11 +465,11 @@ int dkek_decode_key(void *key_ctx, const uint8_t *in, size_t in_len, int *key_si r = mbedtls_ecp_read_key(ec_id, ecdsa, kb+ofs, len); if (r != 0) { mbedtls_ecdsa_free(ecdsa); - return HSM_EXEC_ERROR; + return CCID_EXEC_ERROR; } } else if (key_type == 15) { memcpy(key_ctx, kb+ofs, key_size); } - return HSM_OK; + return CCID_OK; } \ No newline at end of file diff --git a/src/hsm/eac.c b/src/hsm/eac.c index 99ddfc4..2db30c0 100644 --- a/src/hsm/eac.c +++ b/src/hsm/eac.c @@ -83,9 +83,9 @@ int sm_sign(uint8_t *in, size_t in_len, uint8_t *out) { int sm_unwrap() { uint8_t sm_indicator = (CLA(apdu) >> 2) & 0x3; if (sm_indicator == 0) - return HSM_OK; + return CCID_OK; int r = sm_verify(); - if (r != HSM_OK) + if (r != CCID_OK) return r; int le = sm_get_le(); if (le >= 0) @@ -106,22 +106,22 @@ int sm_unwrap() { } } if (!body) - return HSM_WRONG_DATA; + return CCID_WRONG_DATA; if (is87 && *body++ != 0x1) { - return HSM_WRONG_PADDING; + return CCID_WRONG_PADDING; } sm_update_iv(); aes_decrypt(sm_kenc, sm_iv, 128, HSM_AES_MODE_CBC, body, body_size); memmove(apdu.cmd_apdu_data, body, body_size); apdu.cmd_apdu_data_len = sm_remove_padding(apdu.cmd_apdu_data, body_size); DEBUG_PAYLOAD(apdu.cmd_apdu_data, apdu.cmd_apdu_data_len); - return HSM_OK; + return CCID_OK; } int sm_wrap() { uint8_t sm_indicator = (CLA(apdu) >> 2) & 0x3; if (sm_indicator == 0) - return HSM_OK; + return CCID_OK; uint8_t input[1024]; size_t input_len = 0; memset(input, 0, sizeof(input)); @@ -176,7 +176,7 @@ int sm_wrap() { res_APDU_size += 8; if (apdu.expected_res_size > 0) apdu.expected_res_size = res_APDU_size; - return HSM_OK; + return CCID_OK; } int sm_get_le() { @@ -210,7 +210,7 @@ int sm_verify() { if (data_len % sm_blocksize) data_len += sm_blocksize; if (data_len+(add_header ? sm_blocksize : 0) > 1024) - return HSM_WRONG_LENGTH; + return CCID_WRONG_LENGTH; mbedtls_mpi ssc; mbedtls_mpi_init(&ssc); mbedtls_mpi_add_int(&ssc, &sm_mSSC, 1); @@ -219,7 +219,7 @@ int sm_verify() { input_len += sm_blocksize; mbedtls_mpi_free(&ssc); if (r != 0) - return HSM_EXEC_ERROR; + return CCID_EXEC_ERROR; if (add_header) { input[input_len++] = CLA(apdu); input[input_len++] = INS(apdu); @@ -248,7 +248,7 @@ int sm_verify() { } } if (!mac) - return HSM_WRONG_DATA; + return CCID_WRONG_DATA; if (some_added) { input[input_len++] = 0x80; input_len += (sm_blocksize - (input_len%sm_blocksize)); @@ -256,10 +256,10 @@ int sm_verify() { uint8_t signature[16]; r = sm_sign(input, input_len, signature); if (r != 0) - return HSM_EXEC_ERROR; + return CCID_EXEC_ERROR; if (memcmp(signature, mac, mac_len) == 0) - return HSM_OK; - return HSM_VERIFICATION_FAILED; + return CCID_OK; + return CCID_VERIFICATION_FAILED; } int sm_remove_padding(const uint8_t *data, size_t data_len) { diff --git a/src/hsm/eac.h b/src/hsm/eac.h index 3270753..c1e315a 100644 --- a/src/hsm/eac.h +++ b/src/hsm/eac.h @@ -20,7 +20,7 @@ #include #include "pico/stdlib.h" -#include "hsm2040.h" +#include "ccid2040.h" typedef enum MSE_protocol { MSE_AES = 0, diff --git a/src/hsm/files.c b/src/hsm/files.c new file mode 100644 index 0000000..12e30fc --- /dev/null +++ b/src/hsm/files.c @@ -0,0 +1,60 @@ +/* + * This file is part of the Pico HSM distribution (https://github.com/polhenarejos/pico-hsm). + * Copyright (c) 2022 Pol Henarejos. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "files.h" + +extern const uint8_t sc_hsm_aid[]; +extern int parse_token_info(const file_t *f, int mode); +extern int parse_cvca(const file_t *f, int mode); + +file_t file_entries[] = { + /* 0 */ { .fid = 0x3f00 , .parent = 0xff, .name = NULL, .type = FILE_TYPE_DF, .data = NULL, .ef_structure = 0, .acl = {0} }, // MF + /* 1 */ { .fid = 0x2f00 , .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.DIR + /* 2 */ { .fid = 0x2f01 , .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.ATR + /* 3 */ { .fid = 0x2f02 , .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF | FILE_DATA_FUNC,.data = (uint8_t *)parse_cvca, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.GDO + /* 4 */ { .fid = 0x2f03 , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF | FILE_DATA_FUNC,.data = (uint8_t *)parse_token_info, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.TokenInfo + /* 5 */ { .fid = 0x5015 , .parent = 0, .name = NULL, .type = FILE_TYPE_DF, .data = NULL, .ef_structure = 0, .acl = {0} }, //DF.PKCS15 + /* 6 */ { .fid = 0x5031 , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.ODF + /* 7 */ { .fid = 0x5032 , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.TokenInfo + /* 8 */ { .fid = 0x5033 , .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.UnusedSpace + /* 9 */ { .fid = 0x1081 , .parent = 5, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff} }, //PIN (PIN1) + /* 10 */ { .fid = 0x1082 , .parent = 5, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff} }, //max retries PIN (PIN1) + /* 11 */ { .fid = 0x1083 , .parent = 5, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff} }, //retries PIN (PIN1) + /* 12 */ { .fid = 0x1088 , .parent = 5, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff} }, //PIN (SOPIN) + /* 13 */ { .fid = 0x1089 , .parent = 5, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff} }, //max retries PIN (SOPIN) + /* 14 */ { .fid = 0x108A , .parent = 5, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff} }, //retries PIN (SOPIN) + /* 15 */ { .fid = EF_DKEK , .parent = 5, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff} }, //DKEK + /* 16 */ { .fid = EF_DEVOPS , .parent = 5, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff} }, //Device options + /* 17 */ { .fid = EF_PRKDFS , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.PrKDFs + /* 18 */ { .fid = EF_PUKDFS , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.PuKDFs + /* 19 */ { .fid = EF_CDFS , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.CDFs + /* 20 */ { .fid = EF_AODFS , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.AODFs + /* 21 */ { .fid = EF_DODFS , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.DODFs + /* 22 */ { .fid = EF_SKDFS , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.SKDFs + ///* 23 */ { .fid = 0x0000, .parent = 0, .name = openpgpcard_aid, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, + /* 24 */ { .fid = 0x0000, .parent = 5, .name = sc_hsm_aid, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, + /* 25 */ { .fid = 0x0000, .parent = 0xff, .name = NULL, .type = FILE_TYPE_UNKNOWN, .data = NULL, .ef_structure = 0, .acl = {0} } //end +}; + +const file_t *MF = &file_entries[0]; +const file_t *file_last = &file_entries[sizeof(file_entries)/sizeof(file_t)-1]; +const file_t *file_openpgp = &file_entries[sizeof(file_entries)/sizeof(file_t)-3]; +const file_t *file_sc_hsm = &file_entries[sizeof(file_entries)/sizeof(file_t)-2]; +file_t *file_pin1 = NULL; +file_t *file_retries_pin1 = NULL; +file_t *file_sopin = NULL; +file_t *file_retries_sopin = NULL; \ No newline at end of file diff --git a/src/rng/neug.h b/src/hsm/files.h similarity index 64% rename from src/rng/neug.h rename to src/hsm/files.h index 24fe1695..a1a51bd 100644 --- a/src/rng/neug.h +++ b/src/hsm/files.h @@ -15,15 +15,24 @@ * along with this program. If not, see . */ -#ifndef _NEUG_H_ -#define _NEUG_H_ -#define NEUG_PRE_LOOP 32 +#ifndef _FILES_H_ +#define _FILES_H_ -void neug_init(uint32_t *buf, uint8_t size); -uint32_t neug_get(); -void neug_flush(void); -void neug_wait_full(void); -void neug_fini(void); +#include "file.h" + +#define EF_DKEK 0x108F +#define EF_PRKDFS 0x6040 +#define EF_PUKDFS 0x6041 +#define EF_CDFS 0x6042 +#define EF_AODFS 0x6043 +#define EF_DODFS 0x6044 +#define EF_SKDFS 0x6045 +#define EF_DEVOPS 0x100E + +extern file_t *file_pin1; +extern file_t *file_retries_pin1; +extern file_t *file_sopin; +extern file_t *file_retries_sopin; #endif \ No newline at end of file diff --git a/src/hsm/hsm2040.c b/src/hsm/hsm2040.c deleted file mode 100644 index 6b4e337..0000000 --- a/src/hsm/hsm2040.c +++ /dev/null @@ -1,1691 +0,0 @@ -/* - * This file is part of the Pico HSM distribution (https://github.com/polhenarejos/pico-hsm). - * Copyright (c) 2022 Pol Henarejos. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 3. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - - -#include - -// Pico -#include "pico/stdlib.h" -#include - -// For memcpy -#include - -#include "bsp/board.h" -#include "tusb.h" -#include "usb_descriptors.h" -#include "device/usbd_pvt.h" -#include "pico/multicore.h" -#include "random.h" -#include "hsm2040.h" -#include "hardware/rtc.h" - -extern void do_flash(); -extern void low_flash_init(); - -static uint8_t itf_num; - -#if MAX_RES_APDU_DATA_SIZE > MAX_CMD_APDU_DATA_SIZE -#define USB_BUF_SIZE (MAX_RES_APDU_DATA_SIZE+20+9) -#else -#define USB_BUF_SIZE (MAX_CMD_APDU_DATA_SIZE+20+9) -#endif - -struct apdu apdu; -static struct ccid ccid; - -static uint8_t ccid_buffer[USB_BUF_SIZE]; - -#define CCID_SET_PARAMS 0x61 /* non-ICCD command */ -#define CCID_POWER_ON 0x62 -#define CCID_POWER_OFF 0x63 -#define CCID_SLOT_STATUS 0x65 /* non-ICCD command */ -#define CCID_SECURE 0x69 /* non-ICCD command */ -#define CCID_GET_PARAMS 0x6C /* non-ICCD command */ -#define CCID_RESET_PARAMS 0x6D /* non-ICCD command */ -#define CCID_XFR_BLOCK 0x6F -#define CCID_DATA_BLOCK_RET 0x80 -#define CCID_SLOT_STATUS_RET 0x81 /* non-ICCD result */ -#define CCID_PARAMS_RET 0x82 /* non-ICCD result */ - -#define CCID_MSG_SEQ_OFFSET 6 -#define CCID_MSG_STATUS_OFFSET 7 -#define CCID_MSG_ERROR_OFFSET 8 -#define CCID_MSG_CHAIN_OFFSET 9 -#define CCID_MSG_DATA_OFFSET 10 /* == CCID_MSG_HEADER_SIZE */ -#define CCID_MAX_MSG_DATA_SIZE USB_BUF_SIZE - -#define CCID_STATUS_RUN 0x00 -#define CCID_STATUS_PRESENT 0x01 -#define CCID_STATUS_NOTPRESENT 0x02 -#define CCID_CMD_STATUS_OK 0x00 -#define CCID_CMD_STATUS_ERROR 0x40 -#define CCID_CMD_STATUS_TIMEEXT 0x80 - -#define CCID_ERROR_XFR_OVERRUN 0xFC - -/* - * Since command-byte is at offset 0, - * error with offset 0 means "command not supported". - */ -#define CCID_OFFSET_CMD_NOT_SUPPORTED 0 -#define CCID_OFFSET_DATA_LEN 1 -#define CCID_OFFSET_PARAM 8 - -static app_t apps[4]; -static uint8_t num_apps = 0; - -app_t *current_app = NULL; - -extern void card_thread(); - -queue_t *card_comm = NULL; -queue_t *ccid_comm = NULL; -extern void low_flash_init_core1(); - -int register_app(app_t * (*select_aid)()) { - if (num_apps < sizeof(apps)/sizeof(app_t)) { - apps[num_apps].select_aid = select_aid; - num_apps++; - return 1; - } - return 0; -} - -struct ep_in { - uint8_t ep_num; - uint8_t tx_done; - const uint8_t *buf; - size_t cnt; - size_t buf_len; - void *priv; - void (*next_buf) (struct ep_in *epi, size_t len); -}; - -static void epi_init (struct ep_in *epi, int ep_num, void *priv) -{ - epi->ep_num = ep_num; - epi->tx_done = 0; - epi->buf = NULL; - epi->cnt = 0; - epi->buf_len = 0; - epi->priv = priv; - epi->next_buf = NULL; -} - -struct ep_out { - uint8_t ep_num; - uint8_t err; - uint8_t *buf; - size_t cnt; - size_t buf_len; - void *priv; - void (*next_buf) (struct ep_out *epo, size_t len); - int (*end_rx) (struct ep_out *epo, size_t orig_len); - uint8_t ready; -}; - -static struct ep_out endpoint_out; -static struct ep_in endpoint_in; - -static void epo_init (struct ep_out *epo, int ep_num, void *priv) -{ - epo->ep_num = ep_num; - epo->err = 0; - epo->buf = NULL; - epo->cnt = 0; - epo->buf_len = 0; - epo->priv = priv; - epo->next_buf = NULL; - epo->end_rx = NULL; - epo->ready = 0; -} - -struct ccid_header { - uint8_t msg_type; - uint32_t data_len; - uint8_t slot; - uint8_t seq; - uint8_t rsvd; - uint16_t param; -} __attribute__((packed)); - - -/* Data structure handled by CCID layer */ -struct ccid { - uint32_t ccid_state : 4; - uint32_t state : 4; - uint32_t err : 1; - uint32_t tx_busy : 1; - uint32_t timeout_cnt: 3; - - uint8_t *p; - size_t len; - - struct ccid_header ccid_header; - - uint8_t sw1sw2[2]; - uint8_t chained_cls_ins_p1_p2[4]; - - struct ep_out *epo; - struct ep_in *epi; - - queue_t ccid_comm; - queue_t card_comm; - - uint8_t application; - - struct apdu *a; -}; - -static uint8_t endp1_rx_buf[64]; -static uint8_t endp1_tx_buf[64]; - -#define APDU_STATE_WAIT_COMMAND 0 -#define APDU_STATE_COMMAND_CHAINING 1 -#define APDU_STATE_COMMAND_RECEIVED 2 -#define APDU_STATE_RESULT 3 -#define APDU_STATE_RESULT_GET_RESPONSE 4 - -static void ccid_prepare_receive (struct ccid *c); -static void apdu_init (struct apdu *a); - -static void ccid_reset (struct ccid *c) -{ - apdu_init(c->a); - c->err = 0; - c->tx_busy = 0; - c->state = APDU_STATE_WAIT_COMMAND; - c->p = c->a->cmd_apdu_data; - c->len = MAX_CMD_APDU_DATA_SIZE; - c->a->cmd_apdu_data_len = 0; - c->a->expected_res_size = 0; -} - -static void ccid_init(struct ccid *c, struct ep_in *epi, struct ep_out *epo, struct apdu *a) -{ - c->ccid_state = CCID_STATE_START; - c->err = 0; - c->tx_busy = 0; - c->state = APDU_STATE_WAIT_COMMAND; - c->p = a->cmd_apdu_data; - c->len = MAX_CMD_APDU_DATA_SIZE; - memset (&c->ccid_header, 0, sizeof (struct ccid_header)); - c->sw1sw2[0] = 0x90; - c->sw1sw2[1] = 0x00; - c->application = 0; - c->epi = epi; - c->epo = epo; - c->a = a; - - queue_init(&c->card_comm, sizeof(uint32_t), 64); - queue_init(&c->ccid_comm, sizeof(uint32_t), 64); -} - -#define CMD_APDU_HEAD_SIZE 5 - -static void apdu_init (struct apdu *a) -{ - a->seq = 0; /* will be set by lower layer */ - a->cmd_apdu_head = &ccid_buffer[0]; - a->cmd_apdu_data = &ccid_buffer[5]; - a->cmd_apdu_data_len = 0; /* will be set by lower layer */ - a->expected_res_size = 0; /* will be set by lower layer */ - - a->sw = 0x9000; /* will be set by upper layer */ - a->res_apdu_data = &ccid_buffer[5]; /* will be set by upper layer */ - a->res_apdu_data_len = 0; /* will be set by upper layer */ -} - -/* -!!!! IT USES ENDP2, Interruption - -#define NOTIFY_SLOT_CHANGE 0x50 -static void ccid_notify_slot_change(struct ccid *c) -{ - uint8_t msg; - uint8_t notification[2]; - - if (c->ccid_state == CCID_STATE_NOCARD) - msg = 0x02; - else - msg = 0x03; - - notification[0] = NOTIFY_SLOT_CHANGE; - notification[1] = msg; - - tud_vendor_write(notification, sizeof(notification)); -} -*/ - -#define USB_CCID_TIMEOUT (50) - -#define GPG_THREAD_TERMINATED 0xffff -#define GPG_ACK_TIMEOUT 0x6600 - -static void ccid_init_cb(void) { - struct ccid *c = &ccid; - TU_LOG1("-------- CCID INIT\r\n"); - vendord_init(); - - //ccid_notify_slot_change(c); -} - -static void ccid_reset_cb(uint8_t rhport) { - TU_LOG1("-------- CCID RESET\r\n"); - itf_num = 0; - vendord_reset(rhport); -} - -static uint16_t ccid_open(uint8_t rhport, tusb_desc_interface_t const *itf_desc, uint16_t max_len) { - uint8_t *itf_vendor = (uint8_t *)malloc(sizeof(uint8_t)*max_len); - TU_LOG1("-------- CCID OPEN\r\n"); - TU_VERIFY(itf_desc->bInterfaceClass == TUSB_CLASS_SMART_CARD && itf_desc->bInterfaceSubClass == 0 && itf_desc->bInterfaceProtocol == 0, 0); - - //vendord_open expects a CLASS_VENDOR interface class - memcpy(itf_vendor, itf_desc, sizeof(uint8_t)*max_len); - ((tusb_desc_interface_t *)itf_vendor)->bInterfaceClass = TUSB_CLASS_VENDOR_SPECIFIC; - vendord_open(rhport, (tusb_desc_interface_t *)itf_vendor, max_len); - free(itf_vendor); - - uint16_t const drv_len = sizeof(tusb_desc_interface_t) + sizeof(struct ccid_class_descriptor) + 2*sizeof(tusb_desc_endpoint_t); - TU_VERIFY(max_len >= drv_len, 0); - - itf_num = itf_desc->bInterfaceNumber; - return drv_len; -} - -// Support for parameterized reset via vendor interface control request -static bool ccid_control_xfer_cb(uint8_t __unused rhport, uint8_t stage, tusb_control_request_t const * request) { - // nothing to do with DATA & ACK stage - TU_LOG2("-------- CCID CTRL XFER\r\n"); - if (stage != CONTROL_STAGE_SETUP) return true; - - if (request->wIndex == itf_num) - { - TU_LOG2("-------- bmRequestType %x, bRequest %x, wValue %x, wLength %x\r\n",request->bmRequestType,request->bRequest, request->wValue, request->wLength); -/* -#if PICO_STDIO_USB_RESET_INTERFACE_SUPPORT_RESET_TO_BOOTSEL - if (request->bRequest == RESET_REQUEST_BOOTSEL) { -#ifdef PICO_STDIO_USB_RESET_BOOTSEL_ACTIVITY_LED - uint gpio_mask = 1u << PICO_STDIO_USB_RESET_BOOTSEL_ACTIVITY_LED; -#else - uint gpio_mask = 0u; -#endif -#if !PICO_STDIO_USB_RESET_BOOTSEL_FIXED_ACTIVITY_LED - if (request->wValue & 0x100) { - gpio_mask = 1u << (request->wValue >> 9u); - } -#endif - reset_usb_boot(gpio_mask, (request->wValue & 0x7f) | PICO_STDIO_USB_RESET_BOOTSEL_INTERFACE_DISABLE_MASK); - // does not return, otherwise we'd return true - } -#endif - -#if PICO_STDIO_USB_RESET_INTERFACE_SUPPORT_RESET_TO_FLASH_BOOT - if (request->bRequest == RESET_REQUEST_FLASH) { - watchdog_reboot(0, 0, PICO_STDIO_USB_RESET_RESET_TO_FLASH_DELAY_MS); - return true; - } -#endif -*/ - return true; - } - return false; -} - -static bool ccid_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) { - //TU_LOG2("------ CALLED XFER_CB\r\n"); - return vendord_xfer_cb(rhport, ep_addr, result, xferred_bytes); - //return true; -} - - -static usbd_class_driver_t const ccid_driver = -{ -#if CFG_TUSB_DEBUG >= 2 - .name = "CCID", -#endif - .init = ccid_init_cb, - .reset = ccid_reset_cb, - .open = ccid_open, - .control_xfer_cb = ccid_control_xfer_cb, - .xfer_cb = ccid_xfer_cb, - .sof = NULL -}; - -// Implement callback to add our custom driver -usbd_class_driver_t const *usbd_app_driver_get_cb(uint8_t *driver_count) { - *driver_count = 1; - return &ccid_driver; -} - - -static uint32_t blink_interval_ms = BLINK_NOT_MOUNTED; - -void led_set_blink(uint32_t mode) { - blink_interval_ms = mode; -} - -void execute_tasks(); - -static void wait_button() { - led_set_blink((1000 << 16) | 100); - while (board_button_read() == false) { - execute_tasks(); - //sleep_ms(10); - } - while (board_button_read() == true) { - execute_tasks(); - //sleep_ms(10); - } - led_set_blink(BLINK_PROCESSING); -} - -void usb_tx_enable(const uint8_t *buf, uint32_t len) -{ - if (len > 0) { - if (buf[0] != 0x81) - DEBUG_PAYLOAD(buf,len); - //DEBUG_PAYLOAD(buf,len); - tud_vendor_write(buf, len); - } -} - -/* - * ATR (Answer To Reset) string - * - * TS = 0x3b: Direct conversion - * T0 = 0xda: TA1, TC1 and TD1 follow, 10 historical bytes - * TA1 = 0x11: FI=1, DI=1 - * TC1 = 0xff - * TD1 = 0x81: TD2 follows, T=1 - * TD2 = 0xb1: TA3, TB3 and TD3 follow, T=1 - * TA3 = 0xFE: IFSC = 254 bytes - * TB3 = 0x55: BWI = 5, CWI = 5 (BWT timeout 3.2 sec) - * TD3 = 0x1f: TA4 follows, T=15 - * TA4 = 0x03: 5V or 3.3V - * - * Minimum: 0x3b, 0x8a, 0x80, 0x01 - * - */ -static const uint8_t ATR_head[] = { - 0x3b, 0xda, 0x11, 0xff, 0x81, 0xb1, 0xfe, 0x55, 0x1f, 0x03, - //0x3B,0xFE,0x18,0x00,0x00,0x81,0x31,0xFE,0x45,0x80,0x31,0x81,0x54,0x48,0x53,0x4D,0x31,0x73,0x80,0x21,0x40,0x81,0x07,0xFA -}; - -/* Send back ATR (Answer To Reset) */ -static enum ccid_state ccid_power_on(struct ccid *c) -{ - TU_LOG1("!!! CCID POWER ON %d\r\n",c->application); - uint8_t p[CCID_MSG_HEADER_SIZE+1]; /* >= size of historical_bytes -1 */ - int hist_len = historical_bytes[0]; - - //char atr_sc_hsm[] = { 0x3B,0x8E,0x80,0x01,0x80,0x31,0x81,0x54,0x48,0x53,0x4D,0x31,0x73,0x80,0x21,0x40,0x81,0x07,0x18 }; - //char atr_sc_hsm[] = { 0x3B, 0xDE, 0x18, 0xFF, 0x81, 0x91, 0xFE, 0x1F, 0xC3, 0x80, 0x31, 0x81, 0x54, 0x48, 0x53, 0x4D, 0x31, 0x73, 0x80, 0x21, 0x40, 0x81, 0x07, 0x1C }; - char atr_sc_hsm[] = { 0x3B,0xFE,0x18,0x00,0x00,0x81,0x31,0xFE,0x45,0x80,0x31,0x81,0x54,0x48,0x53,0x4D,0x31,0x73,0x80,0x21,0x40,0x81,0x07,0xFA }; - uint8_t mode = 1; //1 sc-hsm, 0 openpgp - size_t size_atr; - if (mode == 1) - size_atr = sizeof(atr_sc_hsm); - else - size_atr = sizeof (ATR_head) + hist_len + 1; - uint8_t xor_check = 0; - int i; - if (c->application == 0) - { - multicore_reset_core1(); - multicore_launch_core1(card_thread); - multicore_fifo_push_blocking((uint32_t)&c->ccid_comm); - multicore_fifo_push_blocking((uint32_t)&c->card_comm); - c->application = 1; - } - p[0] = CCID_DATA_BLOCK_RET; - p[1] = size_atr; - p[2] = 0x00; - p[3] = 0x00; - p[4] = 0x00; - p[5] = 0x00; /* Slot */ - p[CCID_MSG_SEQ_OFFSET] = c->ccid_header.seq; - p[CCID_MSG_STATUS_OFFSET] = 0x00; - p[CCID_MSG_ERROR_OFFSET] = 0x00; - p[CCID_MSG_CHAIN_OFFSET] = 0x00; - - memcpy(endp1_tx_buf, p, CCID_MSG_HEADER_SIZE); - if (mode == 1) - { - memcpy(endp1_tx_buf+CCID_MSG_HEADER_SIZE, atr_sc_hsm, sizeof(atr_sc_hsm)); - } - else - { - memcpy(endp1_tx_buf+CCID_MSG_HEADER_SIZE, ATR_head, sizeof (ATR_head)); - - for (i = 1; i < (int)sizeof (ATR_head); i++) - xor_check ^= ATR_head[i]; - memcpy (p, historical_bytes + 1, hist_len); -#ifdef LIFE_CYCLE_MANAGEMENT_SUPPORT - if (file_selection == 255) - p[7] = 0x03; -#endif - for (i = 0; i < hist_len; i++) - xor_check ^= p[i]; - p[i] = xor_check; - memcpy(endp1_tx_buf+CCID_MSG_HEADER_SIZE+sizeof (ATR_head), p, hist_len+1); - } - - /* This is a single packet Bulk-IN transaction */ - c->epi->buf = NULL; - c->epi->tx_done = 1; - - usb_tx_enable(endp1_tx_buf, CCID_MSG_HEADER_SIZE + size_atr); - - DEBUG_INFO("ON\r\n"); - c->tx_busy = 1; - led_set_blink(BLINK_MOUNTED); - return CCID_STATE_WAIT; -} - -static void ccid_send_status(struct ccid *c) -{ - uint8_t ccid_reply[CCID_MSG_HEADER_SIZE]; - - ccid_reply[0] = CCID_SLOT_STATUS_RET; - ccid_reply[1] = 0x00; - ccid_reply[2] = 0x00; - ccid_reply[3] = 0x00; - ccid_reply[4] = 0x00; - ccid_reply[5] = 0x00; /* Slot */ - ccid_reply[CCID_MSG_SEQ_OFFSET] = c->ccid_header.seq; - if (c->ccid_state == CCID_STATE_NOCARD) - ccid_reply[CCID_MSG_STATUS_OFFSET] = 2; /* 2: No ICC present */ - else if (c->ccid_state == CCID_STATE_START) - /* 1: ICC present but not activated */ - ccid_reply[CCID_MSG_STATUS_OFFSET] = 1; - else - ccid_reply[CCID_MSG_STATUS_OFFSET] = 0; /* An ICC is present and active */ - ccid_reply[CCID_MSG_ERROR_OFFSET] = 0x00; - ccid_reply[CCID_MSG_CHAIN_OFFSET] = 0x00; - - /* This is a single packet Bulk-IN transaction */ - c->epi->buf = NULL; - c->epi->tx_done = 1; - - memcpy(endp1_tx_buf, ccid_reply, CCID_MSG_HEADER_SIZE); - usb_tx_enable(endp1_tx_buf, CCID_MSG_HEADER_SIZE); - c->tx_busy = 1; -} - -static enum ccid_state ccid_power_off(struct ccid *c) -{ - if (c->application) - { - uint32_t flag = EV_EXIT; - queue_try_add(&c->card_comm, &flag); - c->application = 0; - } - - c->ccid_state = CCID_STATE_START; /* This status change should be here */ - ccid_send_status (c); - DEBUG_INFO ("OFF\r\n"); - c->tx_busy = 1; - led_set_blink(BLINK_SUSPENDED); - return CCID_STATE_START; -} - -static void no_buf (struct ep_in *epi, size_t len) -{ - (void)len; - epi->buf = NULL; - epi->cnt = 0; - epi->buf_len = 0; -} - -static void set_sw1sw2(struct ccid *c, size_t chunk_len) -{ - if (c->a->expected_res_size >= c->len) - { - c->sw1sw2[0] = 0x90; - c->sw1sw2[1] = 0x00; - } - else - { - c->sw1sw2[0] = 0x61; - if (c->len - chunk_len >= 256) - c->sw1sw2[1] = 0; - else - c->sw1sw2[1] = (uint8_t)(c->len - chunk_len); - } -} - -static void get_sw1sw2(struct ep_in *epi, size_t len) -{ - struct ccid *c = (struct ccid *)epi->priv; - - (void)len; - epi->buf = c->sw1sw2; - epi->cnt = 0; - epi->buf_len = 2; - epi->next_buf = no_buf; -} - -static void ccid_send_data_block_internal(struct ccid *c, uint8_t status, uint8_t error) -{ - int tx_size = USB_LL_BUF_SIZE; - uint8_t p[CCID_MSG_HEADER_SIZE]; - size_t len; - - if (status == 0) - len = c->a->res_apdu_data_len + 2; - else - len = 0; - - p[0] = CCID_DATA_BLOCK_RET; - p[1] = len & 0xFF; - p[2] = (len >> 8)& 0xFF; - p[3] = (len >> 16)& 0xFF; - p[4] = (len >> 24)& 0xFF; - p[5] = 0x00; /* Slot */ - p[CCID_MSG_SEQ_OFFSET] = c->a->seq; - p[CCID_MSG_STATUS_OFFSET] = status; - p[CCID_MSG_ERROR_OFFSET] = error; - p[CCID_MSG_CHAIN_OFFSET] = 0; - - memcpy(endp1_tx_buf, p, CCID_MSG_HEADER_SIZE); - - if (len == 0) - { - c->epi->buf = NULL; - c->epi->tx_done = 1; - usb_tx_enable(endp1_tx_buf, CCID_MSG_HEADER_SIZE); - c->tx_busy = 1; - return; - } - - if (CCID_MSG_HEADER_SIZE + len <= USB_LL_BUF_SIZE) - { - memcpy(endp1_tx_buf+CCID_MSG_HEADER_SIZE, c->a->res_apdu_data, c->a->res_apdu_data_len); - memcpy(endp1_tx_buf+CCID_MSG_HEADER_SIZE+c->a->res_apdu_data_len, c->sw1sw2, 2); - - c->epi->buf = NULL; - if (CCID_MSG_HEADER_SIZE + len < USB_LL_BUF_SIZE) - c->epi->tx_done = 1; - tx_size = CCID_MSG_HEADER_SIZE + len; - } - else if (CCID_MSG_HEADER_SIZE + len - 1 == USB_LL_BUF_SIZE) - { - memcpy(endp1_tx_buf+CCID_MSG_HEADER_SIZE, c->a->res_apdu_data, c->a->res_apdu_data_len); - memcpy(endp1_tx_buf+CCID_MSG_HEADER_SIZE+c->a->res_apdu_data_len, c->sw1sw2, 1); - - c->epi->buf = &c->sw1sw2[1]; - c->epi->cnt = 1; - c->epi->buf_len = 1; - c->epi->next_buf = no_buf; - } - else if (CCID_MSG_HEADER_SIZE + len - 2 == USB_LL_BUF_SIZE) - { - memcpy(endp1_tx_buf+CCID_MSG_HEADER_SIZE, c->a->res_apdu_data, c->a->res_apdu_data_len); - - c->epi->buf = &c->sw1sw2[0]; - c->epi->cnt = 0; - c->epi->buf_len = 2; - c->epi->next_buf = no_buf; - } - else - { - memcpy(endp1_tx_buf+CCID_MSG_HEADER_SIZE, c->a->res_apdu_data, USB_LL_BUF_SIZE - CCID_MSG_HEADER_SIZE); - - c->epi->buf = c->a->res_apdu_data + USB_LL_BUF_SIZE - CCID_MSG_HEADER_SIZE; - c->epi->cnt = USB_LL_BUF_SIZE - CCID_MSG_HEADER_SIZE; - c->epi->buf_len = c->a->res_apdu_data_len - (USB_LL_BUF_SIZE - CCID_MSG_HEADER_SIZE); - c->epi->next_buf = get_sw1sw2; - } - usb_tx_enable(endp1_tx_buf, tx_size); - c->tx_busy = 1; -} - -static void ccid_send_data_block(struct ccid *c) -{ - ccid_send_data_block_internal (c, 0, 0); -} - -static void ccid_send_data_block_time_extension(struct ccid *c) -{ - ccid_send_data_block_internal (c, CCID_CMD_STATUS_TIMEEXT, c->ccid_state == CCID_STATE_EXECUTE? 1: 0xff); -} - -static void ccid_send_data_block_0x9000(struct ccid *c) -{ - uint8_t p[CCID_MSG_HEADER_SIZE+2]; - size_t len = 2; - - p[0] = CCID_DATA_BLOCK_RET; - p[1] = len & 0xFF; - p[2] = (len >> 8)& 0xFF; - p[3] = (len >> 16)& 0xFF; - p[4] = (len >> 24)& 0xFF; - p[5] = 0x00; /* Slot */ - p[CCID_MSG_SEQ_OFFSET] = c->a->seq; - p[CCID_MSG_STATUS_OFFSET] = 0; - p[CCID_MSG_ERROR_OFFSET] = 0; - p[CCID_MSG_CHAIN_OFFSET] = 0; - p[CCID_MSG_CHAIN_OFFSET+1] = 0x90; - p[CCID_MSG_CHAIN_OFFSET+2] = 0x00; - - memcpy (endp1_tx_buf, p, CCID_MSG_HEADER_SIZE + len); - - c->epi->buf = NULL; - c->epi->tx_done = 1; - usb_tx_enable (endp1_tx_buf, CCID_MSG_HEADER_SIZE + len); - c->tx_busy = 1; -} - -static void ccid_send_data_block_gr(struct ccid *c, size_t chunk_len) -{ - int tx_size = USB_LL_BUF_SIZE; - uint8_t p[CCID_MSG_HEADER_SIZE]; - size_t len = chunk_len + 2; - - p[0] = CCID_DATA_BLOCK_RET; - p[1] = len & 0xFF; - p[2] = (len >> 8)& 0xFF; - p[3] = (len >> 16)& 0xFF; - p[4] = (len >> 24)& 0xFF; - p[5] = 0x00; /* Slot */ - p[CCID_MSG_SEQ_OFFSET] = c->a->seq; - p[CCID_MSG_STATUS_OFFSET] = 0; - p[CCID_MSG_ERROR_OFFSET] = 0; - p[CCID_MSG_CHAIN_OFFSET] = 0; - - memcpy (endp1_tx_buf, p, CCID_MSG_HEADER_SIZE); - - set_sw1sw2 (c, chunk_len); - - if (chunk_len <= USB_LL_BUF_SIZE - CCID_MSG_HEADER_SIZE) - { - int size_for_sw; - - if (chunk_len <= USB_LL_BUF_SIZE - CCID_MSG_HEADER_SIZE - 2) - size_for_sw = 2; - else if (chunk_len == USB_LL_BUF_SIZE - CCID_MSG_HEADER_SIZE - 1) - size_for_sw = 1; - else - size_for_sw = 0; - - memcpy (endp1_tx_buf+CCID_MSG_HEADER_SIZE, c->p, chunk_len); - - if (size_for_sw) - memcpy (endp1_tx_buf+CCID_MSG_HEADER_SIZE+chunk_len, c->sw1sw2, size_for_sw); - - tx_size = CCID_MSG_HEADER_SIZE + chunk_len + size_for_sw; - if (size_for_sw == 2) - { - c->epi->buf = NULL; - if (tx_size < USB_LL_BUF_SIZE) - c->epi->tx_done = 1; - /* Don't set epi->tx_done = 1, when it requires ZLP */ - } - else - { - c->epi->buf = c->sw1sw2 + size_for_sw; - c->epi->cnt = size_for_sw; - c->epi->buf_len = 2 - size_for_sw; - c->epi->next_buf = no_buf; - } - } - else - { - memcpy (endp1_tx_buf+CCID_MSG_HEADER_SIZE, c->p, USB_LL_BUF_SIZE - CCID_MSG_HEADER_SIZE); - - c->epi->buf = c->p + USB_LL_BUF_SIZE - CCID_MSG_HEADER_SIZE; - c->epi->cnt = 0; - c->epi->buf_len = chunk_len - (USB_LL_BUF_SIZE - CCID_MSG_HEADER_SIZE); - c->epi->next_buf = get_sw1sw2; - } - - c->p += chunk_len; - c->len -= chunk_len; - usb_tx_enable (endp1_tx_buf, tx_size); - c->tx_busy = 1; -} - -static void ccid_send_params(struct ccid *c) -{ - uint8_t p[CCID_MSG_HEADER_SIZE]; - const uint8_t params[] = { - 0x11, /* bmFindexDindex */ - 0x11, /* bmTCCKST1 */ - 0xFE, /* bGuardTimeT1 */ - 0x55, /* bmWaitingIntegersT1 */ - 0x03, /* bClockStop */ - 0xFE, /* bIFSC */ - 0 /* bNadValue */ - }; - - p[0] = CCID_PARAMS_RET; - p[1] = 0x07; /* Length = 0x00000007 */ - p[2] = 0; - p[3] = 0; - p[4] = 0; - p[5] = 0x00; /* Slot */ - p[CCID_MSG_SEQ_OFFSET] = c->ccid_header.seq; - p[CCID_MSG_STATUS_OFFSET] = 0; - p[CCID_MSG_ERROR_OFFSET] = 0; - p[CCID_MSG_CHAIN_OFFSET] = 0x01; /* ProtocolNum: T=1 */ - - memcpy (endp1_tx_buf, p, CCID_MSG_HEADER_SIZE); - memcpy (endp1_tx_buf+CCID_MSG_HEADER_SIZE, params, sizeof params); - - /* This is a single packet Bulk-IN transaction */ - c->epi->buf = NULL; - c->epi->tx_done = 1; - usb_tx_enable (endp1_tx_buf, CCID_MSG_HEADER_SIZE + sizeof params); - c->tx_busy = 1; -} - -static void ccid_error(struct ccid *c, int offset) -{ - uint8_t ccid_reply[CCID_MSG_HEADER_SIZE]; - - ccid_reply[0] = CCID_SLOT_STATUS_RET; /* Any value should be OK */ - ccid_reply[1] = 0x00; - ccid_reply[2] = 0x00; - ccid_reply[3] = 0x00; - ccid_reply[4] = 0x00; - ccid_reply[5] = 0x00; /* Slot */ - ccid_reply[CCID_MSG_SEQ_OFFSET] = c->ccid_header.seq; - if (c->ccid_state == CCID_STATE_NOCARD) - ccid_reply[CCID_MSG_STATUS_OFFSET] = 2; /* 2: No ICC present */ - else if (c->ccid_state == CCID_STATE_START) - /* 1: ICC present but not activated */ - ccid_reply[CCID_MSG_STATUS_OFFSET] = 1; - else - ccid_reply[CCID_MSG_STATUS_OFFSET] = 0; /* An ICC is present and active */ - ccid_reply[CCID_MSG_STATUS_OFFSET] |= CCID_CMD_STATUS_ERROR; /* Failed */ - ccid_reply[CCID_MSG_ERROR_OFFSET] = offset; - ccid_reply[CCID_MSG_CHAIN_OFFSET] = 0x00; - - /* This is a single packet Bulk-IN transaction */ - c->epi->buf = NULL; - c->epi->tx_done = 1; - memcpy (endp1_tx_buf, ccid_reply, CCID_MSG_HEADER_SIZE); - usb_tx_enable (endp1_tx_buf, CCID_MSG_HEADER_SIZE); - c->tx_busy = 1; -} - -#define INS_GET_RESPONSE 0xc0 - -static enum ccid_state ccid_handle_data(struct ccid *c) -{ - enum ccid_state next_state = c->ccid_state; - - TU_LOG3("---- CCID STATE %d,msg_type %x,start %d\r\n",c->ccid_state,c->ccid_header.msg_type,CCID_STATE_START); - if (c->err != 0) - { - ccid_reset(c); - ccid_error(c, CCID_OFFSET_DATA_LEN); - return next_state; - } - switch (c->ccid_state) - { - case CCID_STATE_NOCARD: - if (c->ccid_header.msg_type == CCID_SLOT_STATUS) - ccid_send_status(c); - else - { - DEBUG_INFO ("ERR00\r\n"); - ccid_error(c, CCID_OFFSET_CMD_NOT_SUPPORTED); - } - break; - case CCID_STATE_START: - if (c->ccid_header.msg_type == CCID_POWER_ON) - { - ccid_reset(c); - next_state = ccid_power_on(c); - } - else if (c->ccid_header.msg_type == CCID_POWER_OFF) - { - ccid_reset(c); - next_state = ccid_power_off(c); - } - else if (c->ccid_header.msg_type == CCID_SLOT_STATUS) - ccid_send_status (c); - else - { - DEBUG_INFO("ERR01\r\n"); - ccid_error(c, CCID_OFFSET_CMD_NOT_SUPPORTED); - } - break; - case CCID_STATE_WAIT: - if (c->ccid_header.msg_type == CCID_POWER_ON) - { - /* Not in the spec., but pcscd/libccid */ - ccid_reset(c); - next_state = ccid_power_on(c); - } - else if (c->ccid_header.msg_type == CCID_POWER_OFF) - { - ccid_reset(c); - next_state = ccid_power_off(c); - } - else if (c->ccid_header.msg_type == CCID_SLOT_STATUS) - ccid_send_status(c); - else if (c->ccid_header.msg_type == CCID_XFR_BLOCK) - { - if (c->ccid_header.param == 0) - { - if ((c->a->cmd_apdu_head[0] & 0x10) == 0) - { - if (c->state == APDU_STATE_COMMAND_CHAINING) - { /* command chaining finished */ - c->p += c->a->cmd_apdu_head[4]; - c->a->cmd_apdu_head[4] = 0; - DEBUG_INFO ("CMD chaning finished.\r\n"); - } - - if (c->a->cmd_apdu_head[1] == INS_GET_RESPONSE && c->state == APDU_STATE_RESULT_GET_RESPONSE) - { - size_t len = c->a->expected_res_size; - - if (c->len <= c->a->expected_res_size) - len = c->len; - - ccid_send_data_block_gr (c, len); - if (c->len == 0) - c->state = APDU_STATE_RESULT; - c->ccid_state = CCID_STATE_WAIT; - DEBUG_INFO ("GET Response.\r\n"); - } - else - { /* Give this message to GPG thread */ - c->state = APDU_STATE_COMMAND_RECEIVED; - - c->a->sw = 0x9000; - c->a->res_apdu_data_len = 0; - c->a->res_apdu_data = &ccid_buffer[5]; - - uint32_t flag = EV_CMD_AVAILABLE; - queue_try_add(&c->card_comm, &flag); - - next_state = CCID_STATE_EXECUTE; - } - } - else - { - if (c->state == APDU_STATE_WAIT_COMMAND) - { /* command chaining is started */ - c->a->cmd_apdu_head[0] &= ~0x10; - memcpy (c->chained_cls_ins_p1_p2, c->a->cmd_apdu_head, 4); - c->state = APDU_STATE_COMMAND_CHAINING; - } - - c->p += c->a->cmd_apdu_head[4]; - c->len -= c->a->cmd_apdu_head[4]; - ccid_send_data_block_0x9000 (c); - DEBUG_INFO ("CMD chaning...\r\n"); - } - } - else - { /* ICC block chaining is not supported. */ - DEBUG_INFO ("ERR02\r\n"); - ccid_error (c, CCID_OFFSET_PARAM); - } - } - else if (c->ccid_header.msg_type == CCID_SET_PARAMS || c->ccid_header.msg_type == CCID_GET_PARAMS || c->ccid_header.msg_type == CCID_RESET_PARAMS) - ccid_send_params(c); - else - { - DEBUG_INFO ("ERR03\r\n"); - DEBUG_BYTE (c->ccid_header.msg_type); - ccid_error (c, CCID_OFFSET_CMD_NOT_SUPPORTED); - } - break; - case CCID_STATE_EXECUTE: - case CCID_STATE_ACK_REQUIRED_0: - case CCID_STATE_ACK_REQUIRED_1: - if (c->ccid_header.msg_type == CCID_POWER_OFF) - next_state = ccid_power_off (c); - else if (c->ccid_header.msg_type == CCID_SLOT_STATUS) - ccid_send_status (c); - else - { - DEBUG_INFO ("ERR04\r\n"); - DEBUG_BYTE (c->ccid_header.msg_type); - ccid_error (c, CCID_OFFSET_CMD_NOT_SUPPORTED); - } - break; - default: - next_state = CCID_STATE_START; - DEBUG_INFO ("ERR10\r\n"); - break; - } - - return next_state; -} - -static enum ccid_state ccid_handle_timeout(struct ccid *c) -{ - enum ccid_state next_state = c->ccid_state; - switch (c->ccid_state) - { - case CCID_STATE_EXECUTE: - case CCID_STATE_ACK_REQUIRED_0: - case CCID_STATE_ACK_REQUIRED_1: - ccid_send_data_block_time_extension(c); - break; - default: - break; - } - - return next_state; -} - - -static void notify_icc (struct ep_out *epo) -{ - struct ccid *c = (struct ccid *)epo->priv; - c->err = epo->err; - uint32_t val = EV_RX_DATA_READY; - queue_try_add(&c->ccid_comm, &val); -} - -static int end_ccid_rx (struct ep_out *epo, size_t orig_len) -{ - (void)orig_len; - if (epo->cnt < sizeof (struct ccid_header)) - /* short packet, just ignore */ - return 1; - - /* icc message with no abdata */ - return 0; -} - -static int end_abdata (struct ep_out *epo, size_t orig_len) -{ - struct ccid *c = (struct ccid *)epo->priv; - size_t len = epo->cnt; - - if (orig_len == USB_LL_BUF_SIZE && len < c->ccid_header.data_len) - /* more packet comes */ - return 1; - - if (len != c->ccid_header.data_len) - epo->err = 1; - - return 0; -} - -static int end_cmd_apdu_head (struct ep_out *epo, size_t orig_len) -{ - struct ccid *c = (struct ccid *)epo->priv; - - (void)orig_len; - - if (epo->cnt < 4 || epo->cnt != c->ccid_header.data_len) - { - epo->err = 1; - return 0; - } - - if ((c->state == APDU_STATE_COMMAND_CHAINING) - && (c->chained_cls_ins_p1_p2[0] != (c->a->cmd_apdu_head[0] & ~0x10) - || c->chained_cls_ins_p1_p2[1] != c->a->cmd_apdu_head[1] - || c->chained_cls_ins_p1_p2[2] != c->a->cmd_apdu_head[2] - || c->chained_cls_ins_p1_p2[3] != c->a->cmd_apdu_head[3])) - /* - * Handling exceptional request. - * - * Host stops sending command APDU using command chaining, - * and start another command APDU. - * - * Discard old one, and start handling new one. - */ - { - c->state = APDU_STATE_WAIT_COMMAND; - c->p = c->a->cmd_apdu_data; - c->len = MAX_CMD_APDU_DATA_SIZE; - } - - if (epo->cnt == 4) - /* No Lc and Le */ - c->a->expected_res_size = 0; - else if (epo->cnt == 5) - { - /* No Lc but Le */ - c->a->expected_res_size = c->a->cmd_apdu_head[4]; - if (c->a->expected_res_size == 0) - c->a->expected_res_size = 256; - c->a->cmd_apdu_head[4] = 0; - } - else if (epo->cnt == 9) { //extended - c->a->expected_res_size = (c->a->cmd_apdu_head[7] << 8) | c->a->cmd_apdu_head[8]; - if (c->a->expected_res_size == 0) - c->a->expected_res_size = 65536; - } - - c->a->cmd_apdu_data_len = 0; - return 0; -} - -static int end_nomore_data (struct ep_out *epo, size_t orig_len) -{ - (void)epo; - if (orig_len == USB_LL_BUF_SIZE) - return 1; - else - return 0; -} - -static int end_cmd_apdu_data (struct ep_out *epo, size_t orig_len) -{ - struct ccid *c = (struct ccid *)epo->priv; - size_t len = epo->cnt; - - if (orig_len == USB_LL_BUF_SIZE && CMD_APDU_HEAD_SIZE + len < c->ccid_header.data_len) - /* more packet comes */ - return 1; - - if (CMD_APDU_HEAD_SIZE + len != c->ccid_header.data_len) - goto error; - //len is the length after lc (whole APDU = len+5) - if (c->a->cmd_apdu_head[4] == 0 && len >= 2) { //extended - if (len == 2) { - c->a->expected_res_size = (c->a->cmd_apdu_head[5] << 8) | c->a->cmd_apdu_head[6]; - if (c->a->expected_res_size == 0) - c->a->expected_res_size = 0xffff+1; - } - else { - c->a->cmd_apdu_data_len = (c->a->cmd_apdu_data[0] << 8) | c->a->cmd_apdu_data[1]; - len -= 2; - if (len < c->a->cmd_apdu_data_len) - goto error; - c->a->cmd_apdu_data += 2; - if (len == c->a->cmd_apdu_data_len) //no LE - c->a->expected_res_size = 0; - else { - if (len - c->a->cmd_apdu_data_len < 2) - goto error; - c->a->expected_res_size = (c->a->cmd_apdu_data[c->a->cmd_apdu_data_len] << 8) | c->a->cmd_apdu_data[c->a->cmd_apdu_data_len+1]; - if (c->a->expected_res_size == 0) - c->a->expected_res_size = 0xffff+1; - } - } - } - else { - - if (len == c->a->cmd_apdu_head[4]) - /* No Le field*/ - c->a->expected_res_size = 0; - else if (len == (size_t)c->a->cmd_apdu_head[4] + 1) - { - /* it has Le field*/ - c->a->expected_res_size = epo->buf[-1]; - if (c->a->expected_res_size == 0) - c->a->expected_res_size = 256; - len--; - } - else - { - error: - DEBUG_INFO("APDU header size error"); - epo->err = 1; - return 0; - } - - c->a->cmd_apdu_data_len += len; - } - return 0; -} - -static void nomore_data (struct ep_out *epo, size_t len) -{ - (void)len; - epo->err = 1; - epo->end_rx = end_nomore_data; - epo->buf = NULL; - epo->buf_len = 0; - epo->cnt = 0; - epo->next_buf = nomore_data; - epo->ready = 0; -} - -static void ccid_cmd_apdu_data (struct ep_out *epo, size_t len) -{ - struct ccid *c = (struct ccid *)epo->priv; - - (void)len; - if (c->state == APDU_STATE_RESULT_GET_RESPONSE && c->a->cmd_apdu_head[1] != INS_GET_RESPONSE) - { - /* - * Handling exceptional request. - * - * Host didn't finish receiving the whole response APDU by GET RESPONSE, - * but initiates another command. - */ - - c->state = APDU_STATE_WAIT_COMMAND; - c->p = c->a->cmd_apdu_data; - c->len = MAX_CMD_APDU_DATA_SIZE; - } - else if (c->state == APDU_STATE_COMMAND_CHAINING) - { - if (c->chained_cls_ins_p1_p2[0] != (c->a->cmd_apdu_head[0] & ~0x10) - || c->chained_cls_ins_p1_p2[1] != c->a->cmd_apdu_head[1] - || c->chained_cls_ins_p1_p2[2] != c->a->cmd_apdu_head[2] - || c->chained_cls_ins_p1_p2[3] != c->a->cmd_apdu_head[3]) - /* - * Handling exceptional request. - * - * Host stops sending command APDU using command chaining, - * and start another command APDU. - * - * Discard old one, and start handling new one. - */ - { - c->state = APDU_STATE_WAIT_COMMAND; - c->p = c->a->cmd_apdu_data; - c->len = MAX_CMD_APDU_DATA_SIZE; - c->a->cmd_apdu_data_len = 0; - } - } - - epo->end_rx = end_cmd_apdu_data; - epo->buf = c->p; - epo->buf_len = c->len; - epo->cnt = 0; - epo->next_buf = nomore_data; -} - -static void ccid_abdata (struct ep_out *epo, size_t len) -{ - struct ccid *c = (struct ccid *)epo->priv; - - (void)len; - c->a->seq = c->ccid_header.seq; - if (c->ccid_header.msg_type == CCID_XFR_BLOCK) - { - c->a->seq = c->ccid_header.seq; - epo->end_rx = end_cmd_apdu_head; - epo->buf = c->a->cmd_apdu_head; - epo->buf_len = 5; - epo->cnt = 0; - epo->next_buf = ccid_cmd_apdu_data; - } - else - { - epo->end_rx = end_abdata; - epo->buf = c->p; - epo->buf_len = c->len; - epo->cnt = 0; - epo->next_buf = nomore_data; - } -} - -static void ccid_prepare_receive (struct ccid *c) -{ - c->epo->err = 0; - c->epo->buf = (uint8_t *)&c->ccid_header; - c->epo->buf_len = sizeof (struct ccid_header); - c->epo->cnt = 0; - c->epo->next_buf = ccid_abdata; - c->epo->end_rx = end_ccid_rx; - c->epo->ready = 1; -} - -static void ccid_rx_ready (uint16_t len) -{ - /* - * If we support multiple CCID interfaces, we select endpoint object - * by EP_NUM. Because it has only single CCID interface now, it's - * hard-coded, here. - */ - struct ep_out *epo = &endpoint_out; - int offset = 0; - int cont; - size_t orig_len = len; - while (epo->err == 0) - { - if (len == 0) - break; - else if (len <= epo->buf_len) - { - memcpy (epo->buf, endp1_rx_buf + offset, len); - epo->buf += len; - epo->cnt += len; - epo->buf_len -= len; - break; - } - else /* len > buf_len */ - { - memcpy (epo->buf, endp1_rx_buf + offset, epo->buf_len); - len -= epo->buf_len; - offset += epo->buf_len; - epo->next_buf (epo, len); /* Update epo->buf, cnt, buf_len */ - } - } - - /* - * ORIG_LEN to distingush ZLP and the end of transaction - * (ORIG_LEN != USB_LL_BUF_SIZE) - */ - cont = epo->end_rx (epo, orig_len); - - if (cont == 0) - notify_icc (epo); - else - epo->ready = 1; -} - -static void notify_tx (struct ep_in *epi) -{ - struct ccid *c = (struct ccid *)epi->priv; - - /* The sequence of Bulk-IN transactions finished */ - uint32_t flag = EV_TX_FINISHED; - queue_try_add(&c->ccid_comm, &flag); - c->tx_busy = 0; -} - -static void ccid_tx_done () -{ - /* - * If we support multiple CCID interfaces, we select endpoint object - * by EP_NUM. Because it has only single CCID interface now, it's - * hard-coded, here. - */ - struct ep_in *epi = &endpoint_in; - if (epi->buf == NULL) - { - if (epi->tx_done) - notify_tx (epi); - else - { - epi->tx_done = 1; - usb_tx_enable (endp1_tx_buf, 0); - } - } - else - { - int tx_size = 0; - size_t remain = USB_LL_BUF_SIZE; - int offset = 0; - - while (epi->buf) - { - if (epi->buf_len < remain) - { - memcpy (endp1_tx_buf+offset, epi->buf, epi->buf_len); - offset += epi->buf_len; - remain -= epi->buf_len; - tx_size += epi->buf_len; - epi->next_buf (epi, remain); /* Update epi->buf, cnt, buf_len */ - } - else - { - memcpy (endp1_tx_buf+offset, epi->buf, remain); - epi->buf += remain; - epi->cnt += remain; - epi->buf_len -= remain; - tx_size += remain; - break; - } - } - if (tx_size < USB_LL_BUF_SIZE) - epi->tx_done = 1; - - usb_tx_enable (endp1_tx_buf, tx_size); - } -} - -static int usb_event_handle(struct ccid *c) -{ - TU_LOG3("!!! tx %d, vendor %d, cfg %d, rx %d\r\n",c->tx_busy,tud_vendor_n_write_available(0),CFG_TUD_VENDOR_TX_BUFSIZE,tud_vendor_available()); - if (c->tx_busy == 1 && tud_vendor_n_write_available(0) == CFG_TUD_VENDOR_TX_BUFSIZE) - { - ccid_tx_done (); - } - if (tud_vendor_available() && c->epo->ready) - { - uint32_t count = tud_vendor_read(endp1_rx_buf, sizeof(endp1_rx_buf)); - if (endp1_rx_buf[0] != 0x65) - DEBUG_PAYLOAD(endp1_rx_buf, count); - //DEBUG_PAYLOAD(endp1_rx_buf, count); - ccid_rx_ready(count); - } - return 0; -} - -uint32_t timeout = USB_CCID_TIMEOUT; -static uint32_t prev_millis = 0; - -void prepare_ccid() -{ - struct ep_in *epi = &endpoint_in; - struct ep_out *epo = &endpoint_out; - struct ccid *c = &ccid; - struct apdu *a = &apdu; - - epi_init (epi, 1, c); - epo_init (epo, 2, c); - - apdu_init(a); - ccid_init (c, epi, epo, a); -} - -int process_apdu() { - led_set_blink(BLINK_PROCESSING); - if (!current_app) { - if (INS(apdu) == 0xA4 && P1(apdu) == 0x04 && (P2(apdu) == 0x00 || P2(apdu) == 0x4)) { //select by AID - for (int a = 0; a < num_apps; a++) { - if ((current_app = apps[a].select_aid(&apps[a]))) { - return set_res_sw(0x90,0x00); - } - } - } - return set_res_sw(0x6a, 0x82); - } - if (current_app->process_apdu) - return current_app->process_apdu(); - return set_res_sw (0x6D, 0x00); -} - -uint16_t set_res_sw (uint8_t sw1, uint8_t sw2) -{ - apdu.sw = (sw1 << 8) | sw2; - return make_uint16_t(sw1, sw2); -} - -static void card_init (void) -{ - //gpg_data_scan (flash_do_start, flash_do_end); - low_flash_init_core1(); -} - -void card_thread() -{ - ccid_comm = (queue_t *)multicore_fifo_pop_blocking(); - card_comm = (queue_t *)multicore_fifo_pop_blocking(); - - card_init (); - - while (1) - { - uint32_t m; - queue_remove_blocking(card_comm, &m); - - if (m == EV_VERIFY_CMD_AVAILABLE || m == EV_MODIFY_CMD_AVAILABLE) - { - set_res_sw (0x6f, 0x00); - goto done; - } - else if (m == EV_EXIT) { - if (current_app && current_app->unload) - current_app->unload(); - break; - } - - process_apdu(); - - done:; - uint32_t flag = EV_EXEC_FINISHED; - queue_add_blocking(ccid_comm, &flag); - } - - if (current_app && current_app->unload) - current_app->unload(); -} - - -void ccid_task(void) -{ - struct ccid *c = &ccid; - if (tud_vendor_mounted()) - { - // connected and there are data available - if ((c->epo->ready && tud_vendor_available()) || (tud_vendor_n_write_available(0) == CFG_TUD_VENDOR_TX_BUFSIZE && c->tx_busy == 1)) - { - if (usb_event_handle (c) != 0) - { - if (c->application) - { - uint32_t flag = EV_EXIT; - queue_try_add(&c->ccid_comm, &flag); - c->application = 0; - } - prepare_ccid(); - return; - } - } - if (timeout == 0) - { - timeout = USB_CCID_TIMEOUT; - c->timeout_cnt++; - } - uint32_t m = 0x0; - bool has_m = queue_try_remove(&c->ccid_comm, &m); - if (m != 0) - TU_LOG3("\r\n ------ M = %d\r\n",m); - if (has_m) - { - if (m == EV_CARD_CHANGE) - { - if (c->ccid_state == CCID_STATE_NOCARD) - /* Inserted! */ - c->ccid_state = CCID_STATE_START; - else - { /* Removed! */ - if (c->application) - { - uint32_t flag = EV_EXIT; - queue_try_add(&c->card_comm, &flag); - c->application = 0; - } - c->ccid_state = CCID_STATE_NOCARD; - } - //ccid_notify_slot_change (c); - } - else if (m == EV_RX_DATA_READY) - { - c->ccid_state = ccid_handle_data(c); - timeout = 0; - c->timeout_cnt = 0; - } - else if (m == EV_EXEC_FINISHED) - { - if (c->ccid_state == CCID_STATE_EXECUTE) - { - exec_done: - if (c->a->sw == GPG_THREAD_TERMINATED) - { - c->sw1sw2[0] = 0x90; - c->sw1sw2[1] = 0x00; - c->state = APDU_STATE_RESULT; - ccid_send_data_block(c); - c->ccid_state = CCID_STATE_EXITED; - c->application = 0; - return; - } - - c->a->cmd_apdu_data_len = 0; - c->sw1sw2[0] = c->a->sw >> 8; - c->sw1sw2[1] = c->a->sw & 0xff; - if (c->a->res_apdu_data_len <= c->a->expected_res_size) - { - c->state = APDU_STATE_RESULT; - ccid_send_data_block(c); - c->ccid_state = CCID_STATE_WAIT; - } - else - { - c->state = APDU_STATE_RESULT_GET_RESPONSE; - c->p = c->a->res_apdu_data; - c->len = c->a->res_apdu_data_len; - ccid_send_data_block_gr(c, c->a->expected_res_size); - c->ccid_state = CCID_STATE_WAIT; - } - } - else - { - DEBUG_INFO ("ERR05\r\n"); - } - led_set_blink(BLINK_MOUNTED); - } - else if (m == EV_TX_FINISHED) - { - if (c->state == APDU_STATE_RESULT) - ccid_reset(c); - else - c->tx_busy = 0; - if (c->state == APDU_STATE_WAIT_COMMAND || c->state == APDU_STATE_COMMAND_CHAINING || c->state == APDU_STATE_RESULT_GET_RESPONSE) - ccid_prepare_receive(c); - } - else if (m == EV_PRESS_BUTTON) { - wait_button(); - uint32_t flag = EV_BUTTON_PRESSED; - queue_try_add(&c->card_comm, &flag); - } - } - else /* Timeout */ - { - timeout -= MIN(board_millis()-prev_millis,timeout); - if (timeout == 0) - { - if (c->timeout_cnt == 7 && c->ccid_state == CCID_STATE_ACK_REQUIRED_1) - { - c->a->sw = GPG_ACK_TIMEOUT; - c->a->res_apdu_data_len = 0; - c->a->sw = GPG_ACK_TIMEOUT; - c->a->res_apdu_data_len = 0; - - goto exec_done; - } - else - c->ccid_state = ccid_handle_timeout(c); - } - } - } -} - -void tud_mount_cb() -{ - ccid_prepare_receive (&ccid); -} - -void led_blinking_task() -{ -#ifdef PICO_DEFAULT_LED_PIN - static uint32_t start_ms = 0; - static uint8_t led_state = false; - static uint8_t led_color = PICO_DEFAULT_LED_PIN; -#ifdef PICO_DEFAULT_LED_PIN_INVERTED - uint32_t interval = !led_state ? blink_interval_ms & 0xffff : blink_interval_ms >> 16; -#else - uint32_t interval = led_state ? blink_interval_ms & 0xffff : blink_interval_ms >> 16; -#endif - - - // Blink every interval ms - if (board_millis() - start_ms < interval) - return; // not enough time - start_ms += interval; - - gpio_put(led_color, led_state); - led_state ^= 1; // toggle -#endif -} - -void led_off_all() -{ -#ifdef PIMORONI_TINY2040 - gpio_put(TINY2040_LED_R_PIN, 1); - gpio_put(TINY2040_LED_G_PIN, 1); - gpio_put(TINY2040_LED_B_PIN, 1); -#else -#ifdef PICO_DEFAULT_LED_PIN - gpio_put(PICO_DEFAULT_LED_PIN, 0); -#endif -#endif -} - -void init_rtc() { - - rtc_init(); - datetime_t dt = { - .year = 2020, - .month = 1, - .day = 1, - .dotw = 3, // 0 is Sunday, so 5 is Friday - .hour = 00, - .min = 00, - .sec = 00 - }; - rtc_set_datetime(&dt); -} - -extern void neug_task(); - -pico_unique_board_id_t unique_id; - -void execute_tasks() { - prev_millis = board_millis(); - ccid_task(); - tud_task(); // tinyusb device task - led_blinking_task(); -} - -int main(void) -{ - struct apdu *a = &apdu; - struct ccid *c = &ccid; - - board_init(); - -#ifdef PIMORONI_TINY2040 - gpio_init(TINY2040_LED_R_PIN); - gpio_set_dir(TINY2040_LED_R_PIN, GPIO_OUT); - gpio_init(TINY2040_LED_G_PIN); - gpio_set_dir(TINY2040_LED_G_PIN, GPIO_OUT); - gpio_init(TINY2040_LED_B_PIN); - gpio_set_dir(TINY2040_LED_B_PIN, GPIO_OUT); -#else -#ifdef PICO_DEFAULT_LED_PIN - gpio_init(PICO_DEFAULT_LED_PIN); - gpio_set_dir(PICO_DEFAULT_LED_PIN, GPIO_OUT); -#endif -#endif - - - led_off_all(); - - tusb_init(); - - prepare_ccid(); - - random_init(); - - low_flash_init(); - - init_rtc(); - - while (1) - { - execute_tasks(); - neug_task(); - do_flash(); - } - - return 0; -} \ No newline at end of file diff --git a/src/hsm/hsm2040.h b/src/hsm/hsm2040.h deleted file mode 100644 index 0b48620..0000000 --- a/src/hsm/hsm2040.h +++ /dev/null @@ -1,178 +0,0 @@ -/* - * This file is part of the Pico HSM distribution (https://github.com/polhenarejos/pico-hsm). - * Copyright (c) 2022 Pol Henarejos. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 3. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef _HSM2040_H_ -#define _HSM2040_H_ - -#include "ccid.h" -#include "tusb.h" -#include "file.h" -#include "pico/unique_id.h" -#include "pico/util/queue.h" - -#define USB_REQ_CCID 0xA1 - -typedef struct app { - const uint8_t *aid; - int (*process_apdu)(); - struct app* (*select_aid)(); - int (*unload)(); -} app_t; - -extern int register_app(app_t * (*)()); - -extern const uint8_t historical_bytes[]; - -#define DEBUG_PAYLOAD(p,s) { \ - printf("Payload %s (%d bytes):\r\n", #p,s);\ - for (int i = 0; i < s; i += 16) {\ - printf("%07Xh : ",i+p);\ - for (int j = 0; j < 16; j++) {\ - if (j < s-i) printf("%02X ",(p)[i+j]);\ - else printf(" ");\ - if (j == 7) printf(" ");\ - } printf(": "); \ - for (int j = 0; j < MIN(16,s-i); j++) {\ - printf("%c",(p)[i+j] == 0x0a || (p)[i+j] == 0x0d ? '\\' : (p)[i+j]);\ - if (j == 7) printf(" ");\ - }\ - printf("\r\n");\ - } printf("\r\n"); \ - } - -struct apdu { - uint8_t seq; - - /* command APDU */ - uint8_t *cmd_apdu_head; /* CLS INS P1 P2 [ internal Lc ] */ - uint8_t *cmd_apdu_data; - size_t cmd_apdu_data_len; /* Nc, calculated by Lc field */ - size_t expected_res_size; /* Ne, calculated by Le field */ - - /* response APDU */ - uint16_t sw; - uint16_t res_apdu_data_len; - uint8_t *res_apdu_data; -}; - -#define MAX_CMD_APDU_DATA_SIZE (24+4+512*4) -#define MAX_RES_APDU_DATA_SIZE (5+9+512*4) -#define CCID_MSG_HEADER_SIZE 10 -#define USB_LL_BUF_SIZE 64 - -/* CCID thread */ -#define EV_CARD_CHANGE 1 -#define EV_TX_FINISHED 2 /* CCID Tx finished */ -#define EV_EXEC_ACK_REQUIRED 4 /* OpenPGPcard Execution ACK required */ -#define EV_EXEC_FINISHED 8 /* OpenPGPcard Execution finished */ -#define EV_RX_DATA_READY 16 /* USB Rx data available */ -#define EV_PRESS_BUTTON 32 - -/* SC HSM thread */ -#define EV_MODIFY_CMD_AVAILABLE 1 -#define EV_VERIFY_CMD_AVAILABLE 2 -#define EV_CMD_AVAILABLE 4 -#define EV_EXIT 8 -#define EV_BUTTON_PRESSED 16 - -//Variables set by core1 -extern queue_t *ccid_comm; -extern queue_t *card_comm; - -enum ccid_state { - CCID_STATE_NOCARD, /* No card available */ - CCID_STATE_START, /* Initial */ - CCID_STATE_WAIT, /* Waiting APDU */ - - CCID_STATE_EXECUTE, /* Executing command */ - CCID_STATE_ACK_REQUIRED_0, /* Ack required (executing)*/ - CCID_STATE_ACK_REQUIRED_1, /* Waiting user's ACK (execution finished) */ - - CCID_STATE_EXITED, /* CCID Thread Terminated */ - CCID_STATE_EXEC_REQUESTED, /* Exec requested */ -}; - -#define CLA(a) a.cmd_apdu_head[0] -#define INS(a) a.cmd_apdu_head[1] -#define P1(a) a.cmd_apdu_head[2] -#define P2(a) a.cmd_apdu_head[3] - -#define res_APDU apdu.res_apdu_data -#define res_APDU_size apdu.res_apdu_data_len - -extern struct apdu apdu; - -uint16_t set_res_sw (uint8_t sw1, uint8_t sw2); - - -static inline const uint16_t make_uint16_t(uint8_t b1, uint8_t b2) { - return (b1 << 8) | b2; -} -static inline const uint16_t get_uint16_t(const uint8_t *b, uint16_t offset) { - return make_uint16_t(b[offset], b[offset+1]); -} -static inline const void put_uint16_t(uint16_t n, uint8_t *b) { - *b++ = (n >> 8) & 0xff; - *b = n & 0xff; -} - - -#ifdef DEBUG -void stdout_init (void); -#define DEBUG_MORE 1 -/* - * Debug functions in debug.c - */ -void put_byte (uint8_t b); -void put_byte_with_no_nl (uint8_t b); -void put_short (uint16_t x); -void put_word (uint32_t x); -void put_int (uint32_t x); -void put_string (const char *s); -void put_binary (const char *s, int len); - -#define DEBUG_INFO(msg) put_string (msg) -#define DEBUG_WORD(w) put_word (w) -#define DEBUG_SHORT(h) put_short (h) -#define DEBUG_BYTE(b) put_byte (b) -#define DEBUG_BINARY(s,len) put_binary ((const char *)s,len) -#else -#define DEBUG_INFO(msg) -#define DEBUG_WORD(w) -#define DEBUG_SHORT(h) -#define DEBUG_BYTE(b) -#define DEBUG_BINARY(s,len) -#endif - -extern int flash_write_data_to_file(file_t *file, const uint8_t *data, uint16_t len); -extern void low_flash_available(); -extern int flash_clear_file(file_t *file); - -extern pico_unique_board_id_t unique_id; - -enum { - BLINK_NOT_MOUNTED = (250 << 16) | 250, - BLINK_MOUNTED = (250 << 16) | 250, - BLINK_SUSPENDED = (500 << 16) | 1000, - BLINK_PROCESSING = (50 << 16) | 50, - - BLINK_ALWAYS_ON = UINT32_MAX, - BLINK_ALWAYS_OFF = 0 -}; -extern void led_set_blink(uint32_t mode); - -#endif \ No newline at end of file diff --git a/src/hsm/sc_hsm.c b/src/hsm/sc_hsm.c index 11cecea..eb4abab 100644 --- a/src/hsm/sc_hsm.c +++ b/src/hsm/sc_hsm.c @@ -16,7 +16,7 @@ */ #include "sc_hsm.h" -#include "file.h" +#include "files.h" #include "libopensc/card-sc-hsm.h" #include "random.h" #include "common.h" @@ -65,8 +65,85 @@ void __attribute__ ((constructor)) sc_hsm_ctor() { register_app(sc_hsm_select_aid); } -void init_sc_hsm() { +void scan_files() { + file_pin1 = search_by_fid(0x1081, NULL, SPECIFY_EF); + if (file_pin1) { + if (!file_pin1->data) { + TU_LOG1("PIN1 is empty. Initializing with default password\r\n"); + const uint8_t empty[33] = { 0 }; + flash_write_data_to_file(file_pin1, empty, sizeof(empty)); + } + } + else { + TU_LOG1("FATAL ERROR: PIN1 not found in memory!\r\n"); + } + file_sopin = search_by_fid(0x1088, NULL, SPECIFY_EF); + if (file_sopin) { + if (!file_sopin->data) { + TU_LOG1("SOPIN is empty. Initializing with default password\r\n"); + const uint8_t empty[33] = { 0 }; + flash_write_data_to_file(file_sopin, empty, sizeof(empty)); + } + } + else { + TU_LOG1("FATAL ERROR: SOPIN not found in memory!\r\n"); + } + file_retries_pin1 = search_by_fid(0x1083, NULL, SPECIFY_EF); + if (file_retries_pin1) { + if (!file_retries_pin1->data) { + TU_LOG1("Retries PIN1 is empty. Initializing with default retriesr\n"); + const uint8_t retries = 3; + flash_write_data_to_file(file_retries_pin1, &retries, sizeof(uint8_t)); + } + } + else { + TU_LOG1("FATAL ERROR: Retries PIN1 not found in memory!\r\n"); + } + file_retries_sopin = search_by_fid(0x108A, NULL, SPECIFY_EF); + if (file_retries_sopin) { + if (!file_retries_sopin->data) { + TU_LOG1("Retries SOPIN is empty. Initializing with default retries\r\n"); + const uint8_t retries = 15; + flash_write_data_to_file(file_retries_sopin, &retries, sizeof(uint8_t)); + } + } + else { + TU_LOG1("FATAL ERROR: Retries SOPIN not found in memory!\r\n"); + } + file_t *tf = NULL; + + tf = search_by_fid(0x1082, NULL, SPECIFY_EF); + if (tf) { + if (!tf->data) { + TU_LOG1("Max retries PIN1 is empty. Initializing with default max retriesr\n"); + const uint8_t retries = 3; + flash_write_data_to_file(tf, &retries, sizeof(uint8_t)); + } + } + else { + TU_LOG1("FATAL ERROR: Max Retries PIN1 not found in memory!\r\n"); + } + tf = search_by_fid(0x1089, NULL, SPECIFY_EF); + if (tf) { + if (!tf->data) { + TU_LOG1("Max Retries SOPIN is empty. Initializing with default max retries\r\n"); + const uint8_t retries = 15; + flash_write_data_to_file(tf, &retries, sizeof(uint8_t)); + } + } + else { + TU_LOG1("FATAL ERROR: Retries SOPIN not found in memory!\r\n"); + } + low_flash_available(); +} + +void scan_all() { scan_flash(); + scan_files(); +} + +void init_sc_hsm() { + scan_all(); has_session_pin = has_session_sopin = false; isUserAuthenticated = false; cmd_select(); @@ -76,7 +153,7 @@ int sc_hsm_unload() { has_session_pin = has_session_sopin = false; isUserAuthenticated = false; sm_session_pin_len = 0; - return HSM_OK; + return CCID_OK; } void select_file(file_t *pe) { @@ -302,7 +379,7 @@ int cvc_prepare_signatures(sc_pkcs15_card_t *p15card, sc_cvc_t *cvc, size_t sig_ } hash256(cvcbin, cvclen, hsh); free(cvcbin); - return HSM_OK; + return CCID_OK; } int parse_token_info(const file_t *f, int mode) { @@ -446,14 +523,14 @@ static int cmd_read_binary() int pin_reset_retries(const file_t *pin, bool force) { if (!pin) - return HSM_ERR_NULL_PARAM; + return CCID_ERR_NULL_PARAM; const file_t *max = search_by_fid(pin->fid+1, NULL, SPECIFY_EF); const file_t *act = search_by_fid(pin->fid+2, NULL, SPECIFY_EF); if (!max || !act) - return HSM_ERR_FILE_NOT_FOUND; + return CCID_ERR_FILE_NOT_FOUND; uint8_t retries = file_read_uint8(act->data+2); if (retries == 0 && force == false) //blocked - return HSM_ERR_BLOCKED; + return CCID_ERR_BLOCKED; retries = file_read_uint8(max->data+2); int r = flash_write_data_to_file((file_t *)act, &retries, sizeof(retries)); low_flash_available(); @@ -462,22 +539,22 @@ int pin_reset_retries(const file_t *pin, bool force) { int pin_wrong_retry(const file_t *pin) { if (!pin) - return HSM_ERR_NULL_PARAM; + return CCID_ERR_NULL_PARAM; const file_t *act = search_by_fid(pin->fid+2, NULL, SPECIFY_EF); if (!act) - return HSM_ERR_FILE_NOT_FOUND; + return CCID_ERR_FILE_NOT_FOUND; uint8_t retries = file_read_uint8(act->data+2); if (retries > 0) { retries -= 1; int r = flash_write_data_to_file((file_t *)act, &retries, sizeof(retries)); - if (r != HSM_OK) + if (r != CCID_OK) return r; low_flash_available(); if (retries == 0) - return HSM_ERR_BLOCKED; + return CCID_ERR_BLOCKED; return retries; } - return HSM_ERR_BLOCKED; + return CCID_ERR_BLOCKED; } int check_pin(const file_t *pin, const uint8_t *data, size_t len) { @@ -491,7 +568,7 @@ int check_pin(const file_t *pin, const uint8_t *data, size_t len) { if (is_secured_apdu() && sm_session_pin_len > 0 && pin == file_pin1) { if (len == sm_session_pin_len && memcmp(data, sm_session_pin, len) != 0) { uint8_t retries; - if ((retries = pin_wrong_retry(pin)) < HSM_OK) + if ((retries = pin_wrong_retry(pin)) < CCID_OK) return SW_PIN_BLOCKED(); return set_res_sw(0x63, 0xc0 | retries); } @@ -503,15 +580,15 @@ int check_pin(const file_t *pin, const uint8_t *data, size_t len) { return SW_CONDITIONS_NOT_SATISFIED(); if (memcmp(file_read(pin->data+3), dhash, sizeof(dhash)) != 0) { uint8_t retries; - if ((retries = pin_wrong_retry(pin)) < HSM_OK) + if ((retries = pin_wrong_retry(pin)) < CCID_OK) return SW_PIN_BLOCKED(); return set_res_sw(0x63, 0xc0 | retries); } } int r = pin_reset_retries(pin, false); - if (r == HSM_ERR_BLOCKED) + if (r == CCID_ERR_BLOCKED) return SW_PIN_BLOCKED(); - if (r != HSM_OK) + if (r != CCID_OK) return SW_MEMORY_FAILURE(); isUserAuthenticated = true; hash_multi(data, len, session_pin); @@ -595,7 +672,7 @@ static int cmd_reset_retry() { dhash[0] = newpin_len; double_hash_pin(apdu.cmd_apdu_data+(apdu.cmd_apdu_data_len-newpin_len), newpin_len, dhash+1); flash_write_data_to_file(file_pin1, dhash, sizeof(dhash)); - if (pin_reset_retries(file_pin1, true) != HSM_OK) + if (pin_reset_retries(file_pin1, true) != CCID_OK) return SW_MEMORY_FAILURE(); low_flash_available(); return SW_OK(); @@ -616,7 +693,7 @@ static int cmd_reset_retry() { if (apdu.cmd_apdu_data_len != 0) return SW_WRONG_LENGTH(); } - if (pin_reset_retries(file_pin1, true) != HSM_OK) + if (pin_reset_retries(file_pin1, true) != CCID_OK) return SW_MEMORY_FAILURE(); return SW_OK(); } @@ -643,7 +720,7 @@ int heapLeft() { static int cmd_initialize() { if (apdu.cmd_apdu_data_len > 0) { initialize_flash(true); - scan_flash(); + scan_all(); dkeks = current_dkeks = 0; uint8_t tag = 0x0, *tag_data = NULL, *p = NULL; size_t tag_len = 0; @@ -687,7 +764,7 @@ static int cmd_initialize() { } if (dkeks == 0) { int r = save_dkek_key(random_bytes_get(32)); - if (r != HSM_OK) + if (r != CCID_OK) return SW_EXEC_ERROR(); } else @@ -723,7 +800,7 @@ static int cmd_import_dkek() { return SW_WRONG_LENGTH(); import_dkek_share(apdu.cmd_apdu_data); if (++current_dkeks == dkeks) { - if (save_dkek_key(NULL) != HSM_OK) + if (save_dkek_key(NULL) != CCID_OK) return SW_FILE_NOT_FOUND(); } @@ -765,14 +842,14 @@ int store_keys(void *key_ctx, int type, uint8_t key_id, sc_context_t *ctx) { memcpy(kdata, key_ctx, key_size); } r = dkek_encrypt(kdata, key_size); - if (r != HSM_OK) { + if (r != CCID_OK) { return r; } file_t *fpk = file_new((KEY_PREFIX << 8) | key_id); if (!fpk) return SW_MEMORY_FAILURE(); r = flash_write_data_to_file(fpk, kdata, key_size); - if (r != HSM_OK) + if (r != CCID_OK) return r; //add_file_to_chain(fpk, &ef_kf); if (type == SC_PKCS15_TYPE_PRKEY_RSA || type == SC_PKCS15_TYPE_PRKEY_EC) { @@ -806,7 +883,7 @@ int store_keys(void *key_ctx, int type, uint8_t key_id, sc_context_t *ctx) { r = flash_write_data_to_file(fpk, asn1bin, asn1len); if (asn1bin) free(asn1bin); - if (r != HSM_OK) + if (r != CCID_OK) return r; //add_file_to_chain(fpk, &ef_prkdf); /* @@ -837,12 +914,12 @@ int store_keys(void *key_ctx, int type, uint8_t key_id, sc_context_t *ctx) { fpk = file_new((EE_CERTIFICATE_PREFIX << 8) | key_id); r = flash_write_data_to_file(fpk, asn1bin, asn1len); free(asn1bin); - if (r != HSM_OK) + if (r != CCID_OK) return r; //add_file_to_chain(fpk, &ef_cdf); */ low_flash_available(); - return HSM_OK; + return CCID_OK; } static int cmd_keypair_gen() { @@ -909,7 +986,7 @@ static int cmd_keypair_gen() { uint8_t hsh[32]; ret = cvc_prepare_signatures(&p15card, &cvc, key_size/8, hsh); - if (ret != HSM_OK) { + if (ret != CCID_OK) { sc_pkcs15emu_sc_hsm_free_cvc(&cvc); mbedtls_rsa_free(&rsa); free(ctx); @@ -925,7 +1002,7 @@ static int cmd_keypair_gen() { return SW_EXEC_ERROR(); } ret = store_keys(&rsa, SC_PKCS15_TYPE_PRKEY_RSA, key_id, ctx); - if (ret != HSM_OK) { + if (ret != CCID_OK) { sc_pkcs15emu_sc_hsm_free_cvc(&cvc); mbedtls_rsa_free(&rsa); free(ctx); @@ -1034,7 +1111,7 @@ static int cmd_keypair_gen() { uint8_t hsh[32]; ret = cvc_prepare_signatures(&p15card, &cvc, ecdsa.grp.pbits*2/8+9, hsh); - if (ret != HSM_OK) { + if (ret != CCID_OK) { sc_pkcs15emu_sc_hsm_free_cvc(&cvc); mbedtls_ecdsa_free(&ecdsa); free(ctx); @@ -1051,7 +1128,7 @@ static int cmd_keypair_gen() { } ret = store_keys(&ecdsa, SC_PKCS15_TYPE_PRKEY_EC, key_id, ctx); - if (ret != HSM_OK) { + if (ret != CCID_OK) { sc_pkcs15emu_sc_hsm_free_cvc(&cvc); mbedtls_ecdsa_free(&ecdsa); free(ctx); @@ -1148,7 +1225,7 @@ static int cmd_update_ef() { } if (offset == 0) { int r = flash_write_data_to_file(ef, data, data_len); - if (r != HSM_OK) + if (r != CCID_OK) return SW_MEMORY_FAILURE(); } else { @@ -1159,7 +1236,7 @@ static int cmd_update_ef() { memcpy(data_merge+offset, data, data_len); int r = flash_write_data_to_file(ef, data_merge, offset+data_len); free(data_merge); - if (r != HSM_OK) + if (r != CCID_OK) return SW_MEMORY_FAILURE(); } low_flash_available(); @@ -1184,9 +1261,9 @@ static int cmd_delete_file() { } if (!authenticate_action(ef, ACL_OP_DELETE_SELF)) return SW_SECURITY_STATUS_NOT_SATISFIED(); - if (flash_clear_file(ef) != HSM_OK) + if (flash_clear_file(ef) != CCID_OK) return SW_EXEC_ERROR(); - if (delete_dynamic_file(ef) != HSM_OK) + if (delete_dynamic_file(ef) != CCID_OK) return SW_EXEC_ERROR(); low_flash_available(); return SW_OK(); @@ -1205,12 +1282,12 @@ static int cmd_change_pin() { uint16_t r = check_pin(file_pin1, apdu.cmd_apdu_data, pin_len); if (r != 0x9000) return r; - if (load_dkek() != HSM_OK) //loads the DKEK with old pin + if (load_dkek() != CCID_OK) //loads the DKEK with old pin return SW_EXEC_ERROR(); //encrypt DKEK with new pin hash_multi(apdu.cmd_apdu_data+pin_len, apdu.cmd_apdu_data_len-pin_len, session_pin); has_session_pin = true; - if (store_dkek_key() != HSM_OK) + if (store_dkek_key() != CCID_OK) return SW_EXEC_ERROR(); uint8_t dhash[33]; dhash[0] = apdu.cmd_apdu_data_len-pin_len; @@ -1248,7 +1325,7 @@ static int cmd_key_gen() { sc_context_t *card_ctx = create_context(); r = store_keys(aes_key, aes_type, key_id, card_ctx); free(card_ctx); - if (r != HSM_OK) + if (r != CCID_OK) return SW_MEMORY_FAILURE(); low_flash_available(); return SW_OK(); @@ -1286,7 +1363,7 @@ int load_private_key_rsa(mbedtls_rsa_context *ctx, file_t *fkey) { mbedtls_rsa_free(ctx); return SW_DATA_INVALID(); } - return HSM_OK; + return CCID_OK; } int load_private_key_ecdsa(mbedtls_ecdsa_context *ctx, file_t *fkey) { @@ -1295,15 +1372,15 @@ int load_private_key_ecdsa(mbedtls_ecdsa_context *ctx, file_t *fkey) { uint8_t kdata[67]; //Worst case, 521 bit + 1byte memcpy(kdata, file_read(fkey->data+2), key_size); if (dkek_decrypt(kdata, key_size) != 0) { - return HSM_EXEC_ERROR; + return CCID_EXEC_ERROR; } mbedtls_ecp_group_id gid = kdata[0]; int r = mbedtls_ecp_read_key(gid, ctx, kdata+1, key_size-1); if (r != 0) { mbedtls_ecdsa_free(ctx); - return HSM_EXEC_ERROR; + return CCID_EXEC_ERROR; } - return HSM_OK; + return CCID_OK; } static int cmd_signature() { @@ -1332,7 +1409,7 @@ static int cmd_signature() { int r; r = load_private_key_rsa(&ctx, fkey); - if (r != HSM_OK) + if (r != CCID_OK) return SW_EXEC_ERROR(); const uint8_t *hash = apdu.cmd_apdu_data; size_t hash_len = apdu.cmd_apdu_data_len; @@ -1428,7 +1505,7 @@ static int cmd_signature() { md = MBEDTLS_MD_SHA256; int r; r = load_private_key_ecdsa(&ctx, fkey); - if (r != HSM_OK) + if (r != CCID_OK) return SW_CONDITIONS_NOT_SATISFIED(); size_t olen = 0; uint8_t buf[MBEDTLS_ECDSA_MAX_LEN]; @@ -1463,7 +1540,7 @@ static int cmd_key_wrap() { mbedtls_rsa_context ctx; mbedtls_rsa_init(&ctx); r = load_private_key_rsa(&ctx, ef); - if (r != HSM_OK) { + if (r != CCID_OK) { mbedtls_rsa_free(&ctx); return SW_EXEC_ERROR(); } @@ -1474,7 +1551,7 @@ static int cmd_key_wrap() { mbedtls_ecdsa_context ctx; mbedtls_ecdsa_init(&ctx); r = load_private_key_ecdsa(&ctx, ef); - if (r != HSM_OK) { + if (r != CCID_OK) { mbedtls_ecdsa_free(&ctx); return SW_EXEC_ERROR(); } @@ -1497,7 +1574,7 @@ static int cmd_key_wrap() { aes_type = HSM_KEY_AES_128; r = dkek_encode_key(kdata, aes_type, res_APDU, &wrap_len); } - if (r != HSM_OK) + if (r != CCID_OK) return SW_EXEC_ERROR(); res_APDU_size = wrap_len; return SW_OK(); @@ -1516,7 +1593,7 @@ static int cmd_key_unwrap() { mbedtls_rsa_context ctx; mbedtls_rsa_init(&ctx); r = dkek_decode_key(&ctx, apdu.cmd_apdu_data, apdu.cmd_apdu_data_len, NULL); - if (r != HSM_OK) { + if (r != CCID_OK) { mbedtls_rsa_free(&ctx); return SW_EXEC_ERROR(); } @@ -1524,7 +1601,7 @@ static int cmd_key_unwrap() { r = store_keys(&ctx, SC_PKCS15_TYPE_PRKEY_RSA, key_id, card_ctx); free(card_ctx); mbedtls_rsa_free(&ctx); - if (r != HSM_OK) { + if (r != CCID_OK) { return SW_EXEC_ERROR(); } } @@ -1532,7 +1609,7 @@ static int cmd_key_unwrap() { mbedtls_ecdsa_context ctx; mbedtls_ecdsa_init(&ctx); r = dkek_decode_key(&ctx, apdu.cmd_apdu_data, apdu.cmd_apdu_data_len, NULL); - if (r != HSM_OK) { + if (r != CCID_OK) { mbedtls_ecdsa_free(&ctx); return SW_EXEC_ERROR(); } @@ -1540,7 +1617,7 @@ static int cmd_key_unwrap() { r = store_keys(&ctx, SC_PKCS15_TYPE_PRKEY_EC, key_id, card_ctx); free(card_ctx); mbedtls_ecdsa_free(&ctx); - if (r != HSM_OK) { + if (r != CCID_OK) { return SW_EXEC_ERROR(); } } @@ -1548,7 +1625,7 @@ static int cmd_key_unwrap() { uint8_t aes_key[32]; int key_size = 0, aes_type; r = dkek_decode_key(aes_key, apdu.cmd_apdu_data, apdu.cmd_apdu_data_len, &key_size); - if (r != HSM_OK) { + if (r != CCID_OK) { return SW_EXEC_ERROR(); } if (key_size == 32) @@ -1560,7 +1637,7 @@ static int cmd_key_unwrap() { sc_context_t *card_ctx = create_context(); r = store_keys(aes_key, aes_type, key_id, card_ctx); free(card_ctx); - if (r != HSM_OK) { + if (r != CCID_OK) { return SW_EXEC_ERROR(); } } @@ -1578,7 +1655,7 @@ static int cmd_decrypt_asym() { mbedtls_rsa_context ctx; mbedtls_rsa_init(&ctx); int r = load_private_key_rsa(&ctx, ef); - if (r != HSM_OK) + if (r != CCID_OK) return SW_EXEC_ERROR(); int key_size = file_read_uint16(ef->data); if (apdu.cmd_apdu_data_len < key_size) //needs padding @@ -1747,7 +1824,7 @@ static int cmd_derive_asym() { int r; r = load_private_key_ecdsa(&ctx, fkey); - if (r != HSM_OK) { + if (r != CCID_OK) { mbedtls_ecdsa_free(&ctx); return SW_EXEC_ERROR(); } @@ -1778,7 +1855,7 @@ static int cmd_derive_asym() { sc_context_t *card_ctx = create_context(); r = store_keys(&ctx, SC_PKCS15_TYPE_PRKEY_EC, dest_id, card_ctx); free(card_ctx); - if (r != HSM_OK) { + if (r != CCID_OK) { mbedtls_ecdsa_free(&ctx); mbedtls_mpi_free(&a); mbedtls_mpi_free(&nd); @@ -1935,7 +2012,7 @@ int cmd_general_authenticate() { r = sm_sign(t, pubkey_len+16, res_APDU+res_APDU_size); free(t); - if (r != HSM_OK) + if (r != CCID_OK) return SW_EXEC_ERROR(); res_APDU_size += 8; } diff --git a/src/hsm/sc_hsm.h b/src/hsm/sc_hsm.h index 522b662..24c8d17 100644 --- a/src/hsm/sc_hsm.h +++ b/src/hsm/sc_hsm.h @@ -20,80 +20,10 @@ #include #include "pico/stdlib.h" -#include "hsm2040.h" +#include "ccid2040.h" extern const uint8_t sc_hsm_aid[]; -#define SW_BYTES_REMAINING_00() set_res_sw (0x61, 0x00) -#define SW_WARNING_STATE_UNCHANGED() set_res_sw (0x62, 0x00) -#define SW_WARNING_CORRUPTED() set_res_sw (0x62, 0x81) -#define SW_WARNING_EOF() set_res_sw (0x62, 0x82) -#define SW_WARNING_EF_DEACTIVATED() set_res_sw (0x62, 0x83) -#define SW_WARNING_WRONG_FCI() set_res_sw (0x62, 0x84) -#define SW_WARNING_EF_TERMINATED() set_res_sw (0x62, 0x85) - -#define SW_WARNING_NOINFO() set_res_sw (0x63, 0x00) -#define SW_WARNING_FILLUP() set_res_sw (0x63, 0x81) - -#define SW_EXEC_ERROR() set_res_sw (0x64, 0x00) - -#define SW_MEMORY_FAILURE() set_res_sw (0x65, 0x81) - -#define SW_SECURE_MESSAGE_EXEC_ERROR() set_res_sw (0x66, 0x00) - -#define SW_WRONG_LENGTH() set_res_sw (0x67, 0x00) -#define SW_WRONG_DATA() set_res_sw (0x67, 0x00) - -#define SW_LOGICAL_CHANNEL_NOT_SUPPORTED() set_res_sw (0x68, 0x81) -#define SW_SECURE_MESSAGING_NOT_SUPPORTED() set_res_sw (0x68, 0x82) - -#define SW_COMMAND_INCOMPATIBLE() set_res_sw (0x69, 0x81) -#define SW_SECURITY_STATUS_NOT_SATISFIED() set_res_sw (0x69, 0x82) -#define SW_PIN_BLOCKED() set_res_sw (0x69, 0x83) -#define SW_DATA_INVALID() set_res_sw (0x69, 0x84) -#define SW_CONDITIONS_NOT_SATISFIED() set_res_sw (0x69, 0x85) -#define SW_COMMAND_NOT_ALLOWED() set_res_sw (0x69, 0x86) -#define SW_SECURE_MESSAGING_MISSING_DO() set_res_sw (0x69, 0x87) -#define SW_SECURE_MESSAGING_INCORRECT_DO() set_res_sw (0x69, 0x88) -#define SW_APPLET_SELECT_FAILED() set_res_sw (0x69, 0x99) - -#define SW_INCORRECT_PARAMS() set_res_sw (0x6A, 0x80) -#define SW_FUNC_NOT_SUPPORTED() set_res_sw (0x6A, 0x81) -#define SW_FILE_NOT_FOUND() set_res_sw (0x6A, 0x82) -#define SW_RECORD_NOT_FOUND() set_res_sw (0x6A, 0x83) -#define SW_FILE_FULL() set_res_sw (0x6A, 0x84) -#define SW_WRONG_NE() set_res_sw (0x6A, 0x85) -#define SW_INCORRECT_P1P2() set_res_sw (0x6A, 0x86) -#define SW_WRONG_NC() set_res_sw (0x6A, 0x87) -#define SW_REFERENCE_NOT_FOUND() set_res_sw (0x6A, 0x88) -#define SW_FILE_EXISTS() set_res_sw (0x6A, 0x89) - -#define SW_WRONG_P1P2() set_res_sw (0x6B, 0x00) - -#define SW_CORRECT_LENGTH_00() set_res_sw (0x6C, 0x00) - -#define SW_INS_NOT_SUPPORTED() set_res_sw (0x6D, 0x00) - -#define SW_CLA_NOT_SUPPORTED() set_res_sw (0x6E, 0x00) - -#define SW_UNKNOWN() set_res_sw (0x6F, 0x00) - -#define SW_OK() set_res_sw (0x90, 0x00) - -#define HSM_OK 0 -#define HSM_ERR_NO_MEMORY -1000 -#define HSM_ERR_MEMORY_FATAL -1001 -#define HSM_ERR_NULL_PARAM -1002 -#define HSM_ERR_FILE_NOT_FOUND -1003 -#define HSM_ERR_BLOCKED -1004 -#define HSM_NO_LOGIN -1005 -#define HSM_EXEC_ERROR -1006 -#define HSM_WRONG_LENGTH -1007 -#define HSM_WRONG_DATA -1008 -#define HSM_WRONG_DKEK -1009 -#define HSM_WRONG_SIGNATURE -1010 -#define HSM_WRONG_PADDING -1011 -#define HSM_VERIFICATION_FAILED -1012 #define ALGO_RSA_RAW 0x20 /* RSA signature with external padding */ #define ALGO_RSA_DECRYPT 0x21 /* RSA decrypt */ diff --git a/src/rng/neug.c b/src/rng/neug.c deleted file mode 100644 index dabe713..0000000 --- a/src/rng/neug.c +++ /dev/null @@ -1,182 +0,0 @@ -/* - * This file is part of the Pico HSM distribution (https://github.com/polhenarejos/pico-hsm). - * Copyright (c) 2022 Pol Henarejos. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 3. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -//Part of the code is taken from GnuK (GPLv3) - - -#include -#include -#include -#include "pico/stdlib.h" - -#include "neug.h" -#include "hardware/structs/rosc.h" -#include "hardware/gpio.h" -#include "hardware/adc.h" -#include "bsp/board.h" -#include "pico/unique_id.h" - -void adc_start() { - adc_init(); - adc_gpio_init(27); - adc_select_input(1); -} - -void adc_stop() { -} - -static uint64_t random_word = 0xcbf29ce484222325; -static uint8_t ep_round = 0; - -static void ep_init() { - random_word = 0xcbf29ce484222325; - ep_round = 0; -} - -/* Here, we assume a little endian architecture. */ -static int ep_process () { - if (ep_round == 0) { - ep_init(); - } - uint64_t word = 0x0; - for (int n = 0; n < 64; n++) { - uint8_t bit1, bit2; - do - { - bit1 = rosc_hw->randombit&0xff; - //sleep_ms(1); - bit2 = rosc_hw->randombit&0xff; - } while(bit1 == bit2); - word = (word << 1) | bit1; - } - random_word ^= word^board_millis()^adc_read(); - random_word *= 0x00000100000001B3; - if (++ep_round == 8) { - ep_round = 0; - return 2; //2 words - } - return 0; -} - -static const uint32_t *ep_output() { - return (uint32_t *)&random_word; -} - -struct rng_rb { - uint32_t *buf; - uint8_t head, tail; - uint8_t size; - unsigned int full :1; - unsigned int empty :1; -}; - -static void rb_init(struct rng_rb *rb, uint32_t *p, uint8_t size) { - rb->buf = p; - rb->size = size; - rb->head = rb->tail = 0; - rb->full = 0; - rb->empty = 1; -} - -static void rb_add(struct rng_rb *rb, uint32_t v) { - rb->buf[rb->tail++] = v; - if (rb->tail == rb->size) - rb->tail = 0; - if (rb->tail == rb->head) - rb->full = 1; - rb->empty = 0; -} - -static uint32_t rb_del(struct rng_rb *rb) { - uint32_t v = rb->buf[rb->head++]; - - if (rb->head == rb->size) - rb->head = 0; - if (rb->head == rb->tail) - rb->empty = 1; - rb->full = 0; - - return v; -} - -static struct rng_rb the_ring_buffer; - -void *neug_task() { - struct rng_rb *rb = &the_ring_buffer; - - int n; - - if ((n = ep_process())) { - int i; - const uint32_t *vp; - - vp = ep_output(); - - for (i = 0; i < n; i++) { - rb_add (rb, *vp++); - if (rb->full) - break; - } - } - - return NULL; -} - -void neug_init(uint32_t *buf, uint8_t size) { - pico_unique_board_id_t unique_id; - pico_get_unique_board_id(&unique_id); - const uint32_t *u = (const uint32_t *)unique_id.id; - struct rng_rb *rb = &the_ring_buffer; - int i; - - rb_init(rb, buf, size); - - adc_start(); - - ep_init(); -} - -void neug_flush(void) { - struct rng_rb *rb = &the_ring_buffer; - - while (!rb->empty) - rb_del (rb); -} - -uint32_t neug_get(int kick) { - struct rng_rb *rb = &the_ring_buffer; - uint32_t v; - - while (rb->empty) - neug_task(); - v = rb_del(rb); - - return v; -} - -void neug_wait_full(void) { //should be called only on core1 - struct rng_rb *rb = &the_ring_buffer; - - while (!rb->full) { - sleep_ms(1); - } -} - -void neug_fini(void) { - neug_get(1); -} - diff --git a/src/rng/random.c b/src/rng/random.c deleted file mode 100644 index e0c08bf..0000000 --- a/src/rng/random.c +++ /dev/null @@ -1,109 +0,0 @@ -/* - * This file is part of the Pico HSM distribution (https://github.com/polhenarejos/pico-hsm). - * Copyright (c) 2022 Pol Henarejos. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 3. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - - -#include -#include - -#include "neug.h" - -#define RANDOM_BYTES_LENGTH 32 -static uint32_t random_word[RANDOM_BYTES_LENGTH/sizeof (uint32_t)]; - -void random_init(void) { - int i; - - neug_init(random_word, RANDOM_BYTES_LENGTH/sizeof (uint32_t)); - - for (i = 0; i < NEUG_PRE_LOOP; i++) - neug_get(); -} - -void random_fini(void) { - neug_fini (); -} - -/* - * Return pointer to random 32-byte - */ -void random_bytes_free (const uint8_t *p); -#define MAX_RANDOM_BUFFER 1024 -const uint8_t * random_bytes_get(size_t len) { - if (len > MAX_RANDOM_BUFFER) - return NULL; - static uint32_t return_word[MAX_RANDOM_BUFFER/sizeof(uint32_t)]; - for (int ix = 0; ix < len; ix += RANDOM_BYTES_LENGTH) { - neug_wait_full(); - memcpy(return_word+ix/sizeof(uint32_t), random_word, RANDOM_BYTES_LENGTH); - random_bytes_free((const uint8_t *)random_word); - } - return (const uint8_t *)return_word; -} - -/* - * Free pointer to random 32-byte - */ -void random_bytes_free(const uint8_t *p) { - (void)p; - memset(random_word, 0, RANDOM_BYTES_LENGTH); - neug_flush(); -} - -/* - * Return 4-byte salt - */ -void random_get_salt(uint8_t *p) { - uint32_t rnd; - - rnd = neug_get(); - memcpy(p, &rnd, sizeof (uint32_t)); - rnd = neug_get(); - memcpy(p + sizeof (uint32_t), &rnd, sizeof (uint32_t)); -} - - -/* - * Random byte iterator - */ -int random_gen(void *arg, unsigned char *out, size_t out_len) { - uint8_t *index_p = (uint8_t *)arg; - uint8_t index = index_p ? *index_p : 0; - size_t n; - - while (out_len) { - neug_wait_full(); - - n = RANDOM_BYTES_LENGTH - index; - if (n > out_len) - n = out_len; - - memcpy(out, ((unsigned char *)random_word) + index, n); - out += n; - out_len -= n; - index += n; - - if (index >= RANDOM_BYTES_LENGTH) { - index = 0; - neug_flush(); - } - } - - if (index_p) - *index_p = index; - - return 0; -} diff --git a/src/rng/random.h b/src/rng/random.h deleted file mode 100644 index d13c415..0000000 --- a/src/rng/random.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * This file is part of the Pico HSM distribution (https://github.com/polhenarejos/pico-hsm). - * Copyright (c) 2022 Pol Henarejos. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 3. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - - -#ifndef _RANDOM_H_ -#define _RANDOM_H_ - -#include "stdlib.h" -#include "pico/stdlib.h" - -void random_init (void); -void random_fini (void); - -/* 32-byte random bytes */ -const uint8_t *random_bytes_get (size_t); -void random_bytes_free (const uint8_t *p); - -/* 8-byte salt */ -void random_get_salt (uint8_t *p); - -/* iterator returning a byta at a time */ -int random_gen (void *arg, unsigned char *output, size_t output_len); - -#endif \ No newline at end of file diff --git a/src/usb/ccid.h b/src/usb/ccid.h deleted file mode 100644 index 4149e4b..0000000 --- a/src/usb/ccid.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * This file is part of the Pico HSM distribution (https://github.com/polhenarejos/pico-hsm). - * Copyright (c) 2022 Pol Henarejos. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 3. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef _CCID_H_ -#define _CCID_H_ - -#include "libopensc/ccid-types.h" - -static const struct ccid_class_descriptor desc_ccid = { - .bLength = sizeof(struct ccid_class_descriptor), - .bDescriptorType = 0x21, - .bcdCCID = (0x0110), - .bMaxSlotIndex = 0, - .bVoltageSupport = 0x01, // 5.0V - .dwProtocols = ( - 0x01| // T=0 - 0x02), // T=1 - .dwDefaultClock = (0xDFC), - .dwMaximumClock = (0xDFC), - .bNumClockSupport = 0, - .dwDataRate = (0x2580), - .dwMaxDataRate = (0x2580), - .bNumDataRatesSupported = 0, - .dwMaxIFSD = (0xFE), // IFSD is handled by the real reader driver - .dwSynchProtocols = (0), - .dwMechanical = (0), - .dwFeatures = 0x40840, //USB-ICC, short & extended APDU - .dwMaxCCIDMessageLength = 65544+10, - .bClassGetResponse = 0xFF, - .bclassEnvelope = 0xFF, - .wLcdLayout = 0x0, - .bPINSupport = 0x0, - .bMaxCCIDBusySlots = 0x01, -}; - -#endif \ No newline at end of file diff --git a/src/usb/tusb_config.h b/src/usb/tusb_config.h deleted file mode 100644 index 69b5534..0000000 --- a/src/usb/tusb_config.h +++ /dev/null @@ -1,119 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - */ - -#ifndef _TUSB_CONFIG_H_ -#define _TUSB_CONFIG_H_ - -#ifdef __cplusplus - extern "C" { -#endif - -//-------------------------------------------------------------------- -// COMMON CONFIGURATION -//-------------------------------------------------------------------- - -// defined by board.mk -#ifndef CFG_TUSB_MCU - #error CFG_TUSB_MCU must be defined -#endif - -// RHPort number used for device can be defined by board.mk, default to port 0 -#ifndef BOARD_DEVICE_RHPORT_NUM - #define BOARD_DEVICE_RHPORT_NUM 0 -#endif - -// RHPort max operational speed can defined by board.mk -// Default to Highspeed for MCU with internal HighSpeed PHY (can be port specific), otherwise FullSpeed -#ifndef BOARD_DEVICE_RHPORT_SPEED - #if (CFG_TUSB_MCU == OPT_MCU_LPC18XX || CFG_TUSB_MCU == OPT_MCU_LPC43XX || CFG_TUSB_MCU == OPT_MCU_MIMXRT10XX || \ - CFG_TUSB_MCU == OPT_MCU_NUC505 || CFG_TUSB_MCU == OPT_MCU_CXD56 || CFG_TUSB_MCU == OPT_MCU_SAMX7X) - #define BOARD_DEVICE_RHPORT_SPEED OPT_MODE_HIGH_SPEED - #else - #define BOARD_DEVICE_RHPORT_SPEED OPT_MODE_FULL_SPEED - #endif -#endif - -// Device mode with rhport and speed defined by board.mk -#if BOARD_DEVICE_RHPORT_NUM == 0 - #define CFG_TUSB_RHPORT0_MODE (OPT_MODE_DEVICE | BOARD_DEVICE_RHPORT_SPEED) -#elif BOARD_DEVICE_RHPORT_NUM == 1 - #define CFG_TUSB_RHPORT1_MODE (OPT_MODE_DEVICE | BOARD_DEVICE_RHPORT_SPEED) -#else - #error "Incorrect RHPort configuration" -#endif - -#ifndef CFG_TUSB_OS -#define CFG_TUSB_OS OPT_OS_PICO -#endif - -// CFG_TUSB_DEBUG is defined by compiler in DEBUG build -// #define CFG_TUSB_DEBUG 0 - -/* USB DMA on some MCUs can only access a specific SRAM region with restriction on alignment. - * Tinyusb use follows macros to declare transferring memory so that they can be put - * into those specific section. - * e.g - * - CFG_TUSB_MEM SECTION : __attribute__ (( section(".usb_ram") )) - * - CFG_TUSB_MEM_ALIGN : __attribute__ ((aligned(4))) - */ -#ifndef CFG_TUSB_MEM_SECTION -#define CFG_TUSB_MEM_SECTION -#endif - -#ifndef CFG_TUSB_MEM_ALIGN -#define CFG_TUSB_MEM_ALIGN __attribute__ ((aligned(4))) -#endif - -//-------------------------------------------------------------------- -// DEVICE CONFIGURATION -//-------------------------------------------------------------------- - -#ifndef CFG_TUD_ENDPOINT0_SIZE -#define CFG_TUD_ENDPOINT0_SIZE 64 -#endif - -//------------- CLASS -------------// -#define CFG_TUD_HID 0 -#define CFG_TUD_CDC 0 -#define CFG_TUD_MSC 0 -#define CFG_TUD_MIDI 0 -#define CFG_TUD_VENDOR 1 - -// HID buffer size Should be sufficient to hold ID (if any) + Data -#define CFG_TUD_HID_EP_BUFSIZE 16 - -#define CFG_TUD_VENDOR_RX_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64) -#define CFG_TUD_VENDOR_TX_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64) - -#include "pico/types.h" - -static inline uint16_t tu_u32_high16(uint32_t ui32) { return (uint16_t) (ui32 >> 16); } -static inline uint16_t tu_u32_low16 (uint32_t ui32) { return (uint16_t) (ui32 & 0x0000ffffu); } - -#ifdef __cplusplus - } -#endif - -#endif /* _TUSB_CONFIG_H_ */ diff --git a/src/usb/usb_descriptors.c b/src/usb/usb_descriptors.c deleted file mode 100644 index 49d021f..0000000 --- a/src/usb/usb_descriptors.c +++ /dev/null @@ -1,209 +0,0 @@ -/* - * This file is part of the Pico HSM distribution (https://github.com/polhenarejos/pico-hsm). - * Copyright (c) 2022 Pol Henarejos. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 3. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "tusb.h" -#include "usb_descriptors.h" -#include "ccid.h" -#include "pico/unique_id.h" -#include "version.h" - - -#ifndef USB_VID -#define USB_VID 0xFEFF -#endif -#ifndef USB_PID -#define USB_PID 0xFCFD -#endif - -#define USB_BCD 0x0200 - -#define USB_CONFIG_ATT_ONE TU_BIT(7) - -#define MAX_USB_POWER 1 - - -//--------------------------------------------------------------------+ -// Device Descriptors -//--------------------------------------------------------------------+ -tusb_desc_device_t const desc_device = -{ - .bLength = sizeof(tusb_desc_device_t), - .bDescriptorType = TUSB_DESC_DEVICE, - .bcdUSB = (USB_BCD), - - .bDeviceClass = 0x00, - .bDeviceSubClass = 0, - .bDeviceProtocol = 0, - .bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE, - - .idVendor = (USB_VID), - .idProduct = (USB_PID), - .bcdDevice = HSM_VERSION, - - .iManufacturer = 1, - .iProduct = 2, - .iSerialNumber = 3, - - .bNumConfigurations = 1 -}; - -uint8_t const * tud_descriptor_device_cb(void) -{ - return (uint8_t const *) &desc_device; -} - -tusb_desc_interface_t const desc_interface = -{ - .bLength = sizeof(tusb_desc_interface_t), - .bDescriptorType = TUSB_DESC_INTERFACE, - .bInterfaceNumber = 0, - .bAlternateSetting = 0, - .bNumEndpoints = 2, - .bInterfaceClass = TUSB_CLASS_SMART_CARD, - .bInterfaceSubClass = 0, - .bInterfaceProtocol = 0, - .iInterface = 5, -}; - -//--------------------------------------------------------------------+ -// Configuration Descriptor -//--------------------------------------------------------------------+ - -tusb_desc_configuration_t const desc_config = -{ - .bLength = sizeof(tusb_desc_configuration_t), - .bDescriptorType = TUSB_DESC_CONFIGURATION, - .wTotalLength = (sizeof(tusb_desc_configuration_t) + sizeof(tusb_desc_interface_t) + sizeof(struct ccid_class_descriptor) + 2*sizeof(tusb_desc_endpoint_t)), - .bNumInterfaces = 1, - .bConfigurationValue = 1, - .iConfiguration = 4, - .bmAttributes = USB_CONFIG_ATT_ONE | TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, - .bMaxPower = TUSB_DESC_CONFIG_POWER_MA(MAX_USB_POWER+1), -}; - -tusb_desc_endpoint_t const desc_ep1 = -{ - .bLength = sizeof(tusb_desc_endpoint_t), - .bDescriptorType = TUSB_DESC_ENDPOINT, - .bEndpointAddress = TUSB_DIR_IN_MASK | 1, - .bmAttributes.xfer = TUSB_XFER_BULK, - .wMaxPacketSize.size = (64), - .bInterval = 0 -}; - -tusb_desc_endpoint_t const desc_ep2 = -{ - .bLength = sizeof(tusb_desc_endpoint_t), - .bDescriptorType = TUSB_DESC_ENDPOINT, - .bEndpointAddress = 2, - .bmAttributes.xfer = TUSB_XFER_BULK, - .wMaxPacketSize.size = (64), - .bInterval = 0 -}; - -static uint8_t desc_config_extended[sizeof(tusb_desc_configuration_t) + sizeof(tusb_desc_interface_t) + sizeof(struct ccid_class_descriptor) + 2*sizeof(tusb_desc_endpoint_t)]; - -uint8_t const * tud_descriptor_configuration_cb(uint8_t index) -{ - (void) index; // for multiple configurations - - static uint8_t initd = 0; - if (initd == 0) - { - uint8_t *p = desc_config_extended; - memcpy(p, &desc_config, sizeof(tusb_desc_configuration_t)); p += sizeof(tusb_desc_configuration_t); - memcpy(p, &desc_interface, sizeof(tusb_desc_interface_t)); p += sizeof(tusb_desc_interface_t); - memcpy(p, &desc_ccid, sizeof(struct ccid_class_descriptor)); p += sizeof(struct ccid_class_descriptor); - memcpy(p, &desc_ep1, sizeof(tusb_desc_endpoint_t)); p += sizeof(tusb_desc_endpoint_t); - memcpy(p, &desc_ep2, sizeof(tusb_desc_endpoint_t)); p += sizeof(tusb_desc_endpoint_t); - initd = 1; - } - return (const uint8_t *)desc_config_extended; -} - -#define BOS_TOTAL_LEN (TUD_BOS_DESC_LEN) - -#define MS_OS_20_DESC_LEN 0xB2 - -uint8_t const desc_bos[] = -{ - // total length, number of device caps - TUD_BOS_DESCRIPTOR(BOS_TOTAL_LEN, 2) -}; - -uint8_t const * tud_descriptor_bos_cb(void) -{ - return desc_bos; -} - -//--------------------------------------------------------------------+ -// String Descriptors -//--------------------------------------------------------------------+ - -// array of pointer to string descriptors -char const* string_desc_arr [] = -{ - (const char[]) { 0x09, 0x04 }, // 0: is supported language is English (0x0409) - "Pol Henarejos", // 1: Manufacturer - "Pico HSM", // 2: Product - "11223344", // 3: Serials, should use chip ID - "Pico HSM Config", // 4: Vendor Interface - "Pico HSM Interface" -}; - -static uint16_t _desc_str[32]; - -uint16_t const* tud_descriptor_string_cb(uint8_t index, uint16_t langid) -{ - (void) langid; - - uint8_t chr_count; - - if (index == 0) { - memcpy(&_desc_str[1], string_desc_arr[0], 2); - chr_count = 1; - } - else { - // Note: the 0xEE index string is a Microsoft OS 1.0 Descriptors. - // https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/microsoft-defined-usb-descriptors - - if ( !(index < sizeof(string_desc_arr)/sizeof(string_desc_arr[0])) ) - return NULL; - - const char* str = string_desc_arr[index]; - char unique_id_str[2 * PICO_UNIQUE_BOARD_ID_SIZE_BYTES + 1]; - if (index == 3) { - pico_unique_board_id_t unique_id; - pico_get_unique_board_id(&unique_id); - pico_get_unique_board_id_string(unique_id_str, 2 * PICO_UNIQUE_BOARD_ID_SIZE_BYTES + 1); - str = unique_id_str; - } - - chr_count = strlen(str); - if ( chr_count > 31 ) - chr_count = 31; - - // Convert ASCII string into UTF-16 - for(uint8_t i=0; i. - */ - -#ifndef USB_DESCRIPTORS_H_ -#define USB_DESCRIPTORS_H_ - -enum -{ - VENDOR_REQUEST_WEBUSB = 1, - VENDOR_REQUEST_MICROSOFT = 2 -}; - -extern uint8_t const desc_ms_os_20[]; - -#endif /* USB_DESCRIPTORS_H_ */ From b9c08d72c41b069c21ebfe603033ba8de9da7131 Mon Sep 17 00:00:00 2001 From: Pol Henarejos <55573252+polhenarejos@users.noreply.github.com> Date: Tue, 19 Apr 2022 18:42:48 +0200 Subject: [PATCH 38/41] Update .gitmodules Updating module for pico-ccid --- .gitmodules | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitmodules b/.gitmodules index 1cdae06..5c7a3a7 100644 --- a/.gitmodules +++ b/.gitmodules @@ -6,4 +6,4 @@ url = https://github.com/ARMmbed/mbedtls [submodule "pico-ccid"] path = pico-ccid - url = git@github.com-polhenarejos:polhenarejos/pico-ccid + url = https://github.com/polhenarejos/pico-ccid From 302f287967640141ae4e4926909ee90a768eb89c Mon Sep 17 00:00:00 2001 From: Pol Henarejos Date: Tue, 19 Apr 2022 19:16:29 +0200 Subject: [PATCH 39/41] Moving EAC and crypto to core. Signed-off-by: Pol Henarejos --- .gitmodules | 3 - CMakeLists.txt | 4 +- pico-ccid | 2 +- src/hsm/crypto_utils.c | 142 --------------------- src/hsm/crypto_utils.h | 46 ------- src/hsm/eac.c | 271 ----------------------------------------- src/hsm/eac.h | 46 ------- src/hsm/sc_hsm.c | 53 +------- src/hsm/sc_hsm.h | 5 - 9 files changed, 9 insertions(+), 563 deletions(-) delete mode 100644 src/hsm/crypto_utils.c delete mode 100644 src/hsm/crypto_utils.h delete mode 100644 src/hsm/eac.c delete mode 100644 src/hsm/eac.h diff --git a/.gitmodules b/.gitmodules index 5c7a3a7..6f7c861 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,9 +1,6 @@ [submodule "OpenSC"] path = OpenSC url = https://github.com/polhenarejos/OpenSC -[submodule "mbedtls"] - path = mbedtls - url = https://github.com/ARMmbed/mbedtls [submodule "pico-ccid"] path = pico-ccid url = https://github.com/polhenarejos/pico-ccid diff --git a/CMakeLists.txt b/CMakeLists.txt index 0047b02..2e14549 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -60,9 +60,9 @@ target_sources(pico_hsm PUBLIC ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/src/rng/random.c ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/src/rng/neug.c ${CMAKE_CURRENT_LIST_DIR}/src/hsm/files.c - ${CMAKE_CURRENT_LIST_DIR}/src/hsm/crypto_utils.c + ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/src/ccid/crypto_utils.c ${CMAKE_CURRENT_LIST_DIR}/src/hsm/dkek.c - ${CMAKE_CURRENT_LIST_DIR}/src/hsm/eac.c + ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/src/ccid/eac.c ${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/sha256.c ${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/aes.c diff --git a/pico-ccid b/pico-ccid index cffee42..5e51c9a 160000 --- a/pico-ccid +++ b/pico-ccid @@ -1 +1 @@ -Subproject commit cffee4264a531b52a5991c916e131280adeb1c9d +Subproject commit 5e51c9a072fecc7113702b74e13b8a2d346186b2 diff --git a/src/hsm/crypto_utils.c b/src/hsm/crypto_utils.c deleted file mode 100644 index 287277e..0000000 --- a/src/hsm/crypto_utils.c +++ /dev/null @@ -1,142 +0,0 @@ -/* - * This file is part of the Pico HSM distribution (https://github.com/polhenarejos/pico-hsm). - * Copyright (c) 2022 Pol Henarejos. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 3. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include -#include "mbedtls/md.h" -#include "mbedtls/sha256.h" -#include "mbedtls/aes.h" -#include "crypto_utils.h" -#include "sc_hsm.h" -#include "libopensc/card-sc-hsm.h" - -void double_hash_pin(const uint8_t *pin, size_t len, uint8_t output[32]) { - uint8_t o1[32]; - hash_multi(pin, len, o1); - for (int i = 0; i < sizeof(o1); i++) - o1[i] ^= pin[i%len]; - hash_multi(o1, sizeof(o1), output); -} - -void hash_multi(const uint8_t *input, size_t len, uint8_t output[32]) { - mbedtls_sha256_context ctx; - mbedtls_sha256_init(&ctx); - int iters = 256; - pico_unique_board_id_t unique_id; - - pico_get_unique_board_id(&unique_id); - - mbedtls_sha256_starts (&ctx, 0); - mbedtls_sha256_update (&ctx, unique_id.id, sizeof(unique_id.id)); - - while (iters > len) - { - mbedtls_sha256_update (&ctx, input, len); - iters -= len; - } - if (iters > 0) // remaining iterations - mbedtls_sha256_update (&ctx, input, iters); - mbedtls_sha256_finish (&ctx, output); - mbedtls_sha256_free (&ctx); -} - -void hash256(const uint8_t *input, size_t len, uint8_t output[32]) { - mbedtls_sha256_context ctx; - mbedtls_sha256_init(&ctx); - - mbedtls_sha256_starts (&ctx, 0); - mbedtls_sha256_update (&ctx, input, len); - - mbedtls_sha256_finish (&ctx, output); - mbedtls_sha256_free (&ctx); -} - -void generic_hash(mbedtls_md_type_t md, const uint8_t *input, size_t len, uint8_t *output) { - mbedtls_md_context_t ctx; - mbedtls_md_init(&ctx); - const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type(md); - mbedtls_md_setup(&ctx, md_info, 0); - mbedtls_md_starts(&ctx); - mbedtls_md_update(&ctx, input, len); - mbedtls_md_finish(&ctx, output); - mbedtls_md_free(&ctx); -} - -int aes_encrypt(const uint8_t *key, const uint8_t *iv, int key_size, int mode, uint8_t *data, int len) { - mbedtls_aes_context aes; - mbedtls_aes_init(&aes); - uint8_t tmp_iv[IV_SIZE]; - size_t iv_offset = 0; - memset(tmp_iv, 0, IV_SIZE); - if (iv) - memcpy(tmp_iv, iv, IV_SIZE); - int r = mbedtls_aes_setkey_enc(&aes, key, key_size); - if (r != 0) - return CCID_EXEC_ERROR; - if (mode == HSM_AES_MODE_CBC) - return mbedtls_aes_crypt_cbc(&aes, MBEDTLS_AES_ENCRYPT, len, tmp_iv, data, data); - return mbedtls_aes_crypt_cfb128(&aes, MBEDTLS_AES_ENCRYPT, len, &iv_offset, tmp_iv, data, data); -} - -int aes_decrypt(const uint8_t *key, const uint8_t *iv, int key_size, int mode, uint8_t *data, int len) { - mbedtls_aes_context aes; - mbedtls_aes_init(&aes); - uint8_t tmp_iv[IV_SIZE]; - size_t iv_offset = 0; - memset(tmp_iv, 0, IV_SIZE); - if (iv) - memcpy(tmp_iv, iv, IV_SIZE); - int r = mbedtls_aes_setkey_dec(&aes, key, key_size); - if (r != 0) - return CCID_EXEC_ERROR; - if (mode == HSM_AES_MODE_CBC) - return mbedtls_aes_crypt_cbc(&aes, MBEDTLS_AES_DECRYPT, len, tmp_iv, data, data); - r = mbedtls_aes_setkey_enc(&aes, key, key_size); //CFB requires set_enc instead set_dec - return mbedtls_aes_crypt_cfb128(&aes, MBEDTLS_AES_DECRYPT, len, &iv_offset, tmp_iv, data, data); -} - -int aes_encrypt_cfb_256(const uint8_t *key, const uint8_t *iv, uint8_t *data, int len) { - return aes_encrypt(key, iv, 256, HSM_AES_MODE_CFB, data, len); -} -int aes_decrypt_cfb_256(const uint8_t *key, const uint8_t *iv, uint8_t *data, int len) { - return aes_decrypt(key, iv, 256, HSM_AES_MODE_CFB, data, len); -} - -struct ec_curve_mbed_id { - struct sc_lv_data curve; - mbedtls_ecp_group_id id; -}; -struct ec_curve_mbed_id ec_curves_mbed[] = { - { { (unsigned char *) "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFE\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 24}, MBEDTLS_ECP_DP_SECP192R1 }, - { { (unsigned char *) "\xFF\xFF\xFF\xFF\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 32}, MBEDTLS_ECP_DP_SECP256R1 }, - { { (unsigned char *) "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFE\xFF\xFF\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF\xFF", 48}, MBEDTLS_ECP_DP_SECP384R1 }, - { { (unsigned char *) "\x01\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 66}, MBEDTLS_ECP_DP_SECP521R1 }, - { { (unsigned char *) "\xA9\xFB\x57\xDB\xA1\xEE\xA9\xBC\x3E\x66\x0A\x90\x9D\x83\x8D\x72\x6E\x3B\xF6\x23\xD5\x26\x20\x28\x20\x13\x48\x1D\x1F\x6E\x53\x77", 32}, MBEDTLS_ECP_DP_BP256R1 }, - { { (unsigned char *) "\x8C\xB9\x1E\x82\xA3\x38\x6D\x28\x0F\x5D\x6F\x7E\x50\xE6\x41\xDF\x15\x2F\x71\x09\xED\x54\x56\xB4\x12\xB1\xDA\x19\x7F\xB7\x11\x23\xAC\xD3\xA7\x29\x90\x1D\x1A\x71\x87\x47\x00\x13\x31\x07\xEC\x53", 48}, MBEDTLS_ECP_DP_BP384R1 }, - { { (unsigned char *) "\xAA\xDD\x9D\xB8\xDB\xE9\xC4\x8B\x3F\xD4\xE6\xAE\x33\xC9\xFC\x07\xCB\x30\x8D\xB3\xB3\xC9\xD2\x0E\xD6\x63\x9C\xCA\x70\x33\x08\x71\x7D\x4D\x9B\x00\x9B\xC6\x68\x42\xAE\xCD\xA1\x2A\xE6\xA3\x80\xE6\x28\x81\xFF\x2F\x2D\x82\xC6\x85\x28\xAA\x60\x56\x58\x3A\x48\xF3", 64}, MBEDTLS_ECP_DP_BP512R1 }, - { { (unsigned char *) "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFE\xFF\xFF\xEE\x37", 24}, MBEDTLS_ECP_DP_SECP192K1 }, - { { (unsigned char *) "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFE\xFF\xFF\xFC\x2F", 32}, MBEDTLS_ECP_DP_SECP256K1 }, - { { NULL, 0 }, MBEDTLS_ECP_DP_NONE } -}; - -mbedtls_ecp_group_id ec_get_curve_from_prime(const uint8_t *prime, size_t prime_len) { - for (struct ec_curve_mbed_id *ec = ec_curves_mbed; ec->id != MBEDTLS_ECP_DP_NONE; ec++) { - if (prime_len == ec->curve.len && memcmp(prime, ec->curve.value, prime_len) == 0) { - return ec->id; - } - } - return MBEDTLS_ECP_DP_NONE; -} \ No newline at end of file diff --git a/src/hsm/crypto_utils.h b/src/hsm/crypto_utils.h deleted file mode 100644 index 3b686c1..0000000 --- a/src/hsm/crypto_utils.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * This file is part of the Pico HSM distribution (https://github.com/polhenarejos/pico-hsm). - * Copyright (c) 2022 Pol Henarejos. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 3. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef _CRYPTO_UTILS_H_ -#define _CRYPTO_UTILS_H_ - -#include "stdlib.h" -#include "pico/stdlib.h" -#include "mbedtls/ecp.h" -#include "mbedtls/md.h" - -#define HSM_KEY_RSA 0x1 -#define HSM_KEY_EC 0x10 -#define HSM_KEY_AES 0x100 -#define HSM_KEY_AES_128 0x300 -#define HSM_KEY_AES_192 0x500 -#define HSM_KEY_AES_256 0x900 - -#define HSM_AES_MODE_CBC 1 -#define HSM_AES_MODE_CFB 2 - -extern void double_hash_pin(const uint8_t *pin, size_t len, uint8_t output[32]); -extern void hash_multi(const uint8_t *input, size_t len, uint8_t output[32]); -extern void hash256(const uint8_t *input, size_t len, uint8_t output[32]); -extern void generic_hash(mbedtls_md_type_t md, const uint8_t *input, size_t len, uint8_t *output); -extern int aes_encrypt(const uint8_t *key, const uint8_t *iv, int key_size, int mode, uint8_t *data, int len); -extern int aes_decrypt(const uint8_t *key, const uint8_t *iv, int key_size, int mode, uint8_t *data, int len); -extern int aes_encrypt_cfb_256(const uint8_t *key, const uint8_t *iv, uint8_t *data, int len); -extern int aes_decrypt_cfb_256(const uint8_t *key, const uint8_t *iv, uint8_t *data, int len); -extern mbedtls_ecp_group_id ec_get_curve_from_prime(const uint8_t *prime, size_t prime_len); - -#endif diff --git a/src/hsm/eac.c b/src/hsm/eac.c deleted file mode 100644 index 2db30c0..0000000 --- a/src/hsm/eac.c +++ /dev/null @@ -1,271 +0,0 @@ -/* - * This file is part of the Pico HSM distribution (https://github.com/polhenarejos/pico-hsm). - * Copyright (c) 2022 Pol Henarejos. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 3. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "eac.h" -#include "sc_hsm.h" -#include "crypto_utils.h" -#include "random.h" -#include "mbedtls/cmac.h" - -static uint8_t nonce[8]; -static uint8_t auth_token[8]; -static uint8_t sm_kmac[16]; -static uint8_t sm_kenc[16]; -static MSE_protocol sm_protocol = MSE_NONE; -static mbedtls_mpi sm_mSSC; -static uint8_t sm_blocksize = 0; -static uint8_t sm_iv[16]; -size_t sm_session_pin_len = 0; -uint8_t sm_session_pin[16]; - -bool is_secured_apdu() { - return (CLA(apdu) & 0xC); -} - -void sm_derive_key(const uint8_t *input, size_t input_len, uint8_t counter, const uint8_t *nonce, size_t nonce_len, uint8_t *out) { - uint8_t *b = (uint8_t *)calloc(1, input_len+nonce_len+4); - if (input) - memcpy(b, input, input_len); - if (nonce) - memcpy(b+input_len, nonce, nonce_len); - b[input_len+nonce_len+3] = counter; - uint8_t digest[20]; - generic_hash(MBEDTLS_MD_SHA1, b, input_len+nonce_len+4, digest); - memcpy(out, digest, 16); - free(b); -} - -void sm_derive_all_keys(const uint8_t *derived, size_t derived_len) { - memcpy(nonce, random_bytes_get(8), 8); - sm_derive_key(derived, derived_len, 1, nonce, sizeof(nonce), sm_kenc); - sm_derive_key(derived, derived_len, 2, nonce, sizeof(nonce), sm_kmac); - mbedtls_mpi_init(&sm_mSSC); - mbedtls_mpi_grow(&sm_mSSC, sm_blocksize); - mbedtls_mpi_lset(&sm_mSSC, 0); - memset(sm_iv, 0, sizeof(sm_iv)); - sm_session_pin_len = 0; -} - -void sm_set_protocol(MSE_protocol proto) { - sm_protocol = proto; - if (proto == MSE_AES) - sm_blocksize = 16; - else if (proto == MSE_3DES) - sm_blocksize = 8; -} - -MSE_protocol sm_get_protocol() { - return sm_protocol; -} - -uint8_t *sm_get_nonce() { - return nonce; -} - -int sm_sign(uint8_t *in, size_t in_len, uint8_t *out) { - return mbedtls_cipher_cmac(mbedtls_cipher_info_from_type(MBEDTLS_CIPHER_AES_128_ECB), sm_kmac, 128, in, in_len, out); -} - -int sm_unwrap() { - uint8_t sm_indicator = (CLA(apdu) >> 2) & 0x3; - if (sm_indicator == 0) - return CCID_OK; - int r = sm_verify(); - if (r != CCID_OK) - return r; - int le = sm_get_le(); - if (le >= 0) - apdu.expected_res_size = le; - uint8_t *body = NULL; - size_t body_size = 0; - bool is87 = false; - uint8_t tag = 0x0, *tag_data = NULL, *p = NULL; - size_t tag_len = 0; - while (walk_tlv(apdu.cmd_apdu_data, apdu.cmd_apdu_data_len, &p, &tag, &tag_len, &tag_data)) { - if (tag == 0x87 || tag == 0x85) { - body = tag_data; - body_size = tag_len; - if (tag == 0x87) { - is87 = true; - body_size--; - } - } - } - if (!body) - return CCID_WRONG_DATA; - if (is87 && *body++ != 0x1) { - return CCID_WRONG_PADDING; - } - sm_update_iv(); - aes_decrypt(sm_kenc, sm_iv, 128, HSM_AES_MODE_CBC, body, body_size); - memmove(apdu.cmd_apdu_data, body, body_size); - apdu.cmd_apdu_data_len = sm_remove_padding(apdu.cmd_apdu_data, body_size); - DEBUG_PAYLOAD(apdu.cmd_apdu_data, apdu.cmd_apdu_data_len); - return CCID_OK; -} - -int sm_wrap() { - uint8_t sm_indicator = (CLA(apdu) >> 2) & 0x3; - if (sm_indicator == 0) - return CCID_OK; - uint8_t input[1024]; - size_t input_len = 0; - memset(input, 0, sizeof(input)); - mbedtls_mpi ssc; - mbedtls_mpi_init(&ssc); - mbedtls_mpi_add_int(&ssc, &sm_mSSC, 1); - mbedtls_mpi_copy(&sm_mSSC, &ssc); - int r = mbedtls_mpi_write_binary(&ssc, input, sm_blocksize); - input_len += sm_blocksize; - mbedtls_mpi_free(&ssc); - if (res_APDU_size > 0) { - res_APDU[res_APDU_size++] = 0x80; - memset(res_APDU+res_APDU_size, 0, (sm_blocksize - (res_APDU_size%sm_blocksize))); - res_APDU_size += (sm_blocksize - (res_APDU_size%sm_blocksize)); - DEBUG_PAYLOAD(res_APDU, res_APDU_size); - sm_update_iv(); - aes_encrypt(sm_kenc, sm_iv, 128, HSM_AES_MODE_CBC, res_APDU, res_APDU_size); - memmove(res_APDU+1, res_APDU, res_APDU_size); - res_APDU[0] = 0x1; - res_APDU_size++; - if (res_APDU_size < 128) { - memmove(res_APDU+2, res_APDU, res_APDU_size); - res_APDU[1] = res_APDU_size; - res_APDU_size += 2; - } - else if (res_APDU_size < 256) { - memmove(res_APDU+3, res_APDU, res_APDU_size); - res_APDU[1] = 0x81; - res_APDU[2] = res_APDU_size; - res_APDU_size += 3; - } - else { - memmove(res_APDU+4, res_APDU, res_APDU_size); - res_APDU[1] = 0x82; - res_APDU[2] = res_APDU_size >> 8; - res_APDU[3] = res_APDU_size & 0xff; - res_APDU_size += 4; - } - res_APDU[0] = 0x87; - } - res_APDU[res_APDU_size++] = 0x99; - res_APDU[res_APDU_size++] = 2; - res_APDU[res_APDU_size++] = apdu.sw >> 8; - res_APDU[res_APDU_size++] = apdu.sw & 0xff; - memcpy(input+input_len, res_APDU, res_APDU_size); - input_len += res_APDU_size; - input[input_len++] = 0x80; - input_len += (sm_blocksize - (input_len%sm_blocksize)); - r = sm_sign(input, input_len, res_APDU+res_APDU_size+2); - res_APDU[res_APDU_size++] = 0x8E; - res_APDU[res_APDU_size++] = 8; - res_APDU_size += 8; - if (apdu.expected_res_size > 0) - apdu.expected_res_size = res_APDU_size; - return CCID_OK; -} - -int sm_get_le() { - uint8_t tag = 0x0, *tag_data = NULL, *p = NULL; - size_t tag_len = 0; - while (walk_tlv(apdu.cmd_apdu_data, apdu.cmd_apdu_data_len, &p, &tag, &tag_len, &tag_data)) { - if (tag == 0x97) { - uint32_t le = 0; - for (int t = 1; t <= tag_len; t++) - le |= (*tag_data++) << (tag_len-t); - return le; - } - } - return -1; -} - -void sm_update_iv() { - uint8_t tmp_iv[16], sc_counter[16]; - memset(tmp_iv, 0, sizeof(tmp_iv)); //IV is always 0 for encryption of IV based on counter - mbedtls_mpi_write_binary(&sm_mSSC, sc_counter, sizeof(sc_counter)); - aes_encrypt(sm_kenc, tmp_iv, 128, HSM_AES_MODE_CBC, sc_counter, sizeof(sc_counter)); - memcpy(sm_iv, sc_counter, sizeof(sc_counter)); -} - -int sm_verify() { - uint8_t input[1024]; - memset(input, 0, sizeof(input)); - int input_len = 0, r = 0; - bool add_header = (CLA(apdu) & 0xC) == 0xC; - int data_len = (int)(apdu.cmd_apdu_data_len/sm_blocksize)*sm_blocksize; - if (data_len % sm_blocksize) - data_len += sm_blocksize; - if (data_len+(add_header ? sm_blocksize : 0) > 1024) - return CCID_WRONG_LENGTH; - mbedtls_mpi ssc; - mbedtls_mpi_init(&ssc); - mbedtls_mpi_add_int(&ssc, &sm_mSSC, 1); - mbedtls_mpi_copy(&sm_mSSC, &ssc); - r = mbedtls_mpi_write_binary(&ssc, input, sm_blocksize); - input_len += sm_blocksize; - mbedtls_mpi_free(&ssc); - if (r != 0) - return CCID_EXEC_ERROR; - if (add_header) { - input[input_len++] = CLA(apdu); - input[input_len++] = INS(apdu); - input[input_len++] = P1(apdu); - input[input_len++] = P2(apdu); - input[input_len++] = 0x80; - input_len += sm_blocksize-5; - } - bool some_added = false; - const uint8_t *mac = NULL; - size_t mac_len = 0; - uint8_t tag = 0x0, *tag_data = NULL, *p = NULL; - size_t tag_len = 0; - while (walk_tlv(apdu.cmd_apdu_data, apdu.cmd_apdu_data_len, &p, &tag, &tag_len, &tag_data)) { - if (tag & 0x1) { - input[input_len++] = tag; - int tlen = format_tlv_len(tag_len, input+input_len); - input_len += tlen; - memcpy(input+input_len, tag_data, tag_len); - input_len += tag_len; - some_added = true; - } - if (tag == 0x8E) { - mac = tag_data; - mac_len = tag_len; - } - } - if (!mac) - return CCID_WRONG_DATA; - if (some_added) { - input[input_len++] = 0x80; - input_len += (sm_blocksize - (input_len%sm_blocksize)); - } - uint8_t signature[16]; - r = sm_sign(input, input_len, signature); - if (r != 0) - return CCID_EXEC_ERROR; - if (memcmp(signature, mac, mac_len) == 0) - return CCID_OK; - return CCID_VERIFICATION_FAILED; -} - -int sm_remove_padding(const uint8_t *data, size_t data_len) { - int i = data_len-1; - for (; i >= 0 && data[i] == 0; i--); - if (i < 0 || data[i] != 0x80) - return -1; - return i; -} \ No newline at end of file diff --git a/src/hsm/eac.h b/src/hsm/eac.h deleted file mode 100644 index c1e315a..0000000 --- a/src/hsm/eac.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * This file is part of the Pico HSM distribution (https://github.com/polhenarejos/pico-hsm). - * Copyright (c) 2022 Pol Henarejos. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 3. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef _EAC_H_ -#define _EAC_H_ - -#include -#include "pico/stdlib.h" -#include "ccid2040.h" - -typedef enum MSE_protocol { - MSE_AES = 0, - MSE_3DES, - MSE_NONE -}MSE_protocol; - -extern void sm_derive_all_keys(const uint8_t *input, size_t input_len); -extern void sm_set_protocol(MSE_protocol proto); -extern MSE_protocol sm_get_protocol(); -extern uint8_t *sm_get_nonce(); -extern int sm_sign(uint8_t *in, size_t in_len, uint8_t *out); -int sm_verify(); -void sm_update_iv(); -int sm_get_le(); -extern int sm_unwrap(); -int sm_remove_padding(const uint8_t *data, size_t data_len); -extern int sm_wrap(); -extern bool is_secured_apdu(); -extern uint8_t sm_session_pin[16]; -extern size_t sm_session_pin_len; - -#endif diff --git a/src/hsm/sc_hsm.c b/src/hsm/sc_hsm.c index eb4abab..73c0d98 100644 --- a/src/hsm/sc_hsm.c +++ b/src/hsm/sc_hsm.c @@ -40,6 +40,11 @@ const uint8_t sc_hsm_aid[] = { 0xE8,0x2B,0x06,0x01,0x04,0x01,0x81,0xC3,0x1F,0x02,0x01 }; +char atr_sc_hsm[] = { + 24, + 0x3B,0xFE,0x18,0x00,0x00,0x81,0x31,0xFE,0x45,0x80,0x31,0x81,0x54,0x48,0x53,0x4D,0x31,0x73,0x80,0x21,0x40,0x81,0x07,0xFA +}; + uint8_t session_pin[32], session_sopin[32]; bool has_session_pin = false, has_session_sopin = false; static uint8_t dkeks = 0, current_dkeks = 0; @@ -62,6 +67,7 @@ app_t *sc_hsm_select_aid(app_t *a) { } void __attribute__ ((constructor)) sc_hsm_ctor() { + ccid_atr = atr_sc_hsm; register_app(sc_hsm_select_aid); } @@ -196,53 +202,6 @@ static void wait_button() { } } -int format_tlv_len(size_t len, uint8_t *out) { - if (len < 128) { - *out = len; - return 1; - } - else if (len < 256) { - *out++ = 0x81; - *out++ = len; - return 2; - } - else { - *out++ = 0x82; - *out++ = (len >> 8) & 0xff; - *out++ = len & 0xff; - return 3; - } - return 0; -} - -int walk_tlv(const uint8_t *cdata, size_t cdata_len, uint8_t **p, uint8_t *tag, size_t *tag_len, uint8_t **data) { - if (!p) - return 0; - if (!*p) - *p = (uint8_t *)cdata; - if (*p-cdata >= cdata_len) - return 0; - uint8_t tg = 0x0; - size_t tgl = 0; - tg = *(*p)++; - tgl = *(*p)++; - if (tgl == 0x82) { - tgl = *(*p)++ << 8; - tgl |= *(*p)++; - } - else if (tgl == 0x81) { - tgl = *(*p)++; - } - if (tag) - *tag = tg; - if (tag_len) - *tag_len = tgl; - if (data) - *data = *p; - *p = *p+tgl; - return 1; -} - static int cmd_select() { uint8_t p1 = P1(apdu); uint8_t p2 = P2(apdu); diff --git a/src/hsm/sc_hsm.h b/src/hsm/sc_hsm.h index 24c8d17..df05535 100644 --- a/src/hsm/sc_hsm.h +++ b/src/hsm/sc_hsm.h @@ -68,11 +68,6 @@ extern void hash(const uint8_t *input, size_t len, uint8_t output[32]); extern void hash_multi(const uint8_t *input, size_t len, uint8_t output[32]); extern void double_hash_pin(const uint8_t *pin, size_t len, uint8_t output[32]); -extern int walk_tlv(const uint8_t *cdata, size_t cdata_len, uint8_t **p, uint8_t *tag, size_t *tag_len, uint8_t **data); -extern int format_tlv_len(size_t len, uint8_t *out); - extern uint8_t session_pin[32], session_sopin[32]; -#define IV_SIZE 16 - #endif \ No newline at end of file From 77971ac7e6e6bbc80b963d122b3f301fe3d37379 Mon Sep 17 00:00:00 2001 From: Pol Henarejos Date: Tue, 19 Apr 2022 19:19:16 +0200 Subject: [PATCH 40/41] Using MBEDTLS from pico ccid. Signed-off-by: Pol Henarejos --- CMakeLists.txt | 68 +++++++++++++++++++++++++------------------------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2e14549..33c7532 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -64,38 +64,38 @@ target_sources(pico_hsm PUBLIC ${CMAKE_CURRENT_LIST_DIR}/src/hsm/dkek.c ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/src/ccid/eac.c - ${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/sha256.c - ${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/aes.c - ${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/sha512.c - ${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/rsa.c - ${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/bignum.c - ${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/platform_util.c - ${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/md.c - ${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/oid.c - ${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/rsa_alt_helpers.c - ${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/constant_time.c - ${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/ecdsa.c - ${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/ecp.c - ${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/ecp_curves.c - ${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/asn1write.c - ${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/hmac_drbg.c - ${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/md5.c - ${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/ripemd160.c - ${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/sha1.c - ${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/ecdh.c - ${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/cmac.c - ${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/cipher.c - ${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/cipher_wrap.c - ${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/chachapoly.c - ${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/camellia.c - ${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/chacha20.c - ${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/aria.c - ${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/poly1305.c - ${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/gcm.c - ${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/ccm.c - ${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/des.c - ${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/nist_kw.c - ${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/hkdf.c + ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/sha256.c + ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/aes.c + ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/sha512.c + ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/rsa.c + ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/bignum.c + ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/platform_util.c + ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/md.c + ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/oid.c + ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/rsa_alt_helpers.c + ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/constant_time.c + ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/ecdsa.c + ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/ecp.c + ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/ecp_curves.c + ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/asn1write.c + ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/hmac_drbg.c + ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/md5.c + ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/ripemd160.c + ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/sha1.c + ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/ecdh.c + ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/cmac.c + ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/cipher.c + ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/cipher_wrap.c + ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/chachapoly.c + ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/camellia.c + ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/chacha20.c + ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/aria.c + ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/poly1305.c + ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/gcm.c + ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/ccm.c + ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/des.c + ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/nist_kw.c + ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/hkdf.c ${CMAKE_CURRENT_LIST_DIR}/OpenSC/src/libopensc/pkcs15.c ${CMAKE_CURRENT_LIST_DIR}/OpenSC/src/libopensc/pkcs15-prkey.c @@ -122,8 +122,8 @@ target_include_directories(pico_hsm PUBLIC ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/src/rng ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/src/usb ${CMAKE_CURRENT_LIST_DIR}/opensc/src - ${CMAKE_CURRENT_LIST_DIR}/mbedtls/include - ${CMAKE_CURRENT_LIST_DIR}/mbedtls/library + ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/include + ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library ) pico_add_extra_outputs(pico_hsm) From 86298f3421f71530ba564b19447ce83349d59b01 Mon Sep 17 00:00:00 2001 From: Pol Henarejos Date: Tue, 19 Apr 2022 19:24:10 +0200 Subject: [PATCH 41/41] Upgrading to version 2.0. --- build_pico_hsm.sh | 4 ++-- patch_vidpid.sh | 4 ++-- src/hsm/version.h | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/build_pico_hsm.sh b/build_pico_hsm.sh index 43e1542..62ad4d2 100755 --- a/build_pico_hsm.sh +++ b/build_pico_hsm.sh @@ -1,7 +1,7 @@ #!/bin/bash -VERSION_MAJOR="1" -VERSION_MINOR="12" +VERSION_MAJOR="2" +VERSION_MINOR="0" rm -rf release/* cd build_release diff --git a/patch_vidpid.sh b/patch_vidpid.sh index df149d8..60a81fb 100755 --- a/patch_vidpid.sh +++ b/patch_vidpid.sh @@ -17,8 +17,8 @@ # along with this program. If not, see . # -VERSION_MAJOR="1" -VERSION_MINOR="0C" +VERSION_MAJOR="2" +VERSION_MINOR="0" echo "----------------------------" echo "VID/PID patcher for Pico HSM" diff --git a/src/hsm/version.h b/src/hsm/version.h index 59582c6..f074940 100644 --- a/src/hsm/version.h +++ b/src/hsm/version.h @@ -18,7 +18,7 @@ #ifndef __VERSION_H_ #define __VERSION_H_ -#define HSM_VERSION 0x010C +#define HSM_VERSION 0x0200 #define HSM_VERSION_MAJOR ((HSM_VERSION >> 8) & 0xff) #define HSM_VERSION_MINOR (HSM_VERSION & 0xff)