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_ */