From 00172841038ac652902281a8354987b19273f78b Mon Sep 17 00:00:00 2001 From: Pol Henarejos Date: Sun, 13 Feb 2022 01:17:14 +0100 Subject: [PATCH] Starting migration from gnuk to own solution. gnuk/openpgp will be left as another pkcs15 app. Lots of work has been done in the meanwhile. Signed-off-by: Pol Henarejos --- CMakeLists.txt | 25 +- ac.c | 1 + call-rsa.c | 1 + file.c | 87 ++++- file.h | 1 + flash.c | 16 +- flash_openpgp.c | 763 +++++++++++++++++++++++++++++++++++++++++++ gnuk.h | 63 +--- hsm2040.c | 182 ++++++++++- hsm2040.h | 79 +++++ low_flash.c | 1 + neug.c | 225 +++++-------- neug.h | 19 -- openpgp-do.c | 155 ++++++--- openpgp.c | 852 ++++++++++++++++-------------------------------- random.c | 92 +++--- sc_hsm.c | 229 +++++++++++++ sc_hsm.h | 35 ++ status-code.h | 50 +-- 19 files changed, 1910 insertions(+), 966 deletions(-) create mode 100644 flash_openpgp.c create mode 100644 sc_hsm.c create mode 100644 sc_hsm.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 6847ba5..ef9f61f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,6 +11,11 @@ pico_sdk_init() add_executable(hsm2040) +set_source_files_properties( + ${CMAKE_CURRENT_LIST_DIR}/OpenSC/src/libopensc/ctx.c + PROPERTIES COMPILE_DEFINITIONS "PACKAGE_VERSION=\"0.22.0\";OPENSC_CONF_PATH=\".\"" + ) + target_sources(hsm2040 PUBLIC ${CMAKE_CURRENT_LIST_DIR}/hsm2040.c ${CMAKE_CURRENT_LIST_DIR}/usb_descriptors.c @@ -20,6 +25,7 @@ target_sources(hsm2040 PUBLIC ${CMAKE_CURRENT_LIST_DIR}/ac.c ${CMAKE_CURRENT_LIST_DIR}/file.c ${CMAKE_CURRENT_LIST_DIR}/flash.c + ${CMAKE_CURRENT_LIST_DIR}/flash_openpgp.c ${CMAKE_CURRENT_LIST_DIR}/low_flash.c ${CMAKE_CURRENT_LIST_DIR}/call-rsa.c ${CMAKE_CURRENT_LIST_DIR}/call-ec_p256k1.c @@ -47,10 +53,27 @@ target_sources(hsm2040 PUBLIC ${CMAKE_CURRENT_LIST_DIR}/oid.c ${CMAKE_CURRENT_LIST_DIR}/rsa_alt_helpers.c ${CMAKE_CURRENT_LIST_DIR}/constant_time.c + ${CMAKE_CURRENT_LIST_DIR}/sc_hsm.c + ${CMAKE_CURRENT_LIST_DIR}/OpenSC/src/libopensc/pkcs15.c + ${CMAKE_CURRENT_LIST_DIR}/OpenSC/src/libopensc/pkcs15-prkey.c + ${CMAKE_CURRENT_LIST_DIR}/OpenSC/src/libopensc/pkcs15-algo.c + ${CMAKE_CURRENT_LIST_DIR}/OpenSC/src/libopensc/pkcs15-cert.c + ${CMAKE_CURRENT_LIST_DIR}/OpenSC/src/libopensc/pkcs15-data.c + ${CMAKE_CURRENT_LIST_DIR}/OpenSC/src/libopensc/pkcs15-pin.c + ${CMAKE_CURRENT_LIST_DIR}/OpenSC/src/libopensc/pkcs15-pubkey.c + ${CMAKE_CURRENT_LIST_DIR}/OpenSC/src/libopensc/pkcs15-sec.c + ${CMAKE_CURRENT_LIST_DIR}/OpenSC/src/libopensc/pkcs15-skey.c + ${CMAKE_CURRENT_LIST_DIR}/OpenSC/src/libopensc/asn1.c + ${CMAKE_CURRENT_LIST_DIR}/OpenSC/src/libopensc/log.c + ${CMAKE_CURRENT_LIST_DIR}/OpenSC/src/libopensc/errors.c + ${CMAKE_CURRENT_LIST_DIR}/OpenSC/src/libopensc/sc.c + ${CMAKE_CURRENT_LIST_DIR}/OpenSC/src/libopensc/ctx.c ) target_include_directories(hsm2040 PUBLIC - ${CMAKE_CURRENT_LIST_DIR}) + ${CMAKE_CURRENT_LIST_DIR} + ${CMAKE_CURRENT_LIST_DIR}/opensc/src + ) pico_add_extra_outputs(hsm2040) target_link_libraries(hsm2040 PRIVATE pico_stdlib tinyusb_device tinyusb_board pico_multicore hardware_flash hardware_sync hardware_adc) diff --git a/ac.c b/ac.c index d4ee100..69a32b1 100644 --- a/ac.c +++ b/ac.c @@ -29,6 +29,7 @@ #include "gnuk.h" #include "mbedtls/sha256.h" #include "random.h" +#include "hsm2040.h" uint8_t volatile auth_status; /* Initialized to AC_NONE_AUTHORIZED */ diff --git a/call-rsa.c b/call-rsa.c index 1a6474b..c826410 100644 --- a/call-rsa.c +++ b/call-rsa.c @@ -36,6 +36,7 @@ #include "random.h" //#include "polarssl/config.h" #include "mbedtls/rsa.h" +#include "hsm2040.h" static mbedtls_rsa_context rsa_ctx; //static struct chx_cleanup clp; diff --git a/file.c b/file.c index 59b6c06..6b35972 100644 --- a/file.c +++ b/file.c @@ -57,23 +57,31 @@ const uint8_t token_info[] = { 0x30, 0x26, 0x2, 0x1, 0x1, 0x4, 0x4, 0xd, 0x0, 0x0, 0x0, 0xc, 0xd, 0x50, 0x6f, 0x6c, 0x20, 0x48, 0x65, 0x6e, 0x61, 0x72, 0x65, 0x6a, 0x6f, 0x73, 0x80, 0x8, 0x48, 0x53, 0x4d, 0x20, 0x32, 0x30, 0x34, 0x30, 0x3, 0x2, 0x4, 0xf0 }; +extern const uint8_t sc_hsm_aid[]; + file_t file_entries[] = { - { .fid = 0x3f00, .parent = 0xff, .name = NULL, .type = FILE_TYPE_DF, .data = NULL, .ef_structure = 0, .acl = {0} }, // MF - { .fid = 0x2f00, .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.DIR - { .fid = 0x2f01, .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.ATR - { .fid = 0x2f02, .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF,.data = (uint8_t *)t, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.GDO - { .fid = 0x2f03, .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF,.data = (uint8_t *)token_info, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.TokenInfo - { .fid = 0x5015, .parent = 0, .name = NULL, .type = FILE_TYPE_DF, .data = NULL, .ef_structure = 0, .acl = {0} }, //DF.PKCS15 - { .fid = 0x5031, .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.ODF - { .fid = 0x5032, .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.TokenInfo - { .fid = 0x5033, .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.UnusedSpace - { .fid = 0x1081, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff} }, //PIN 0x5 (PIN1) - { .fid = 0x1088, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff} }, //PIN 0x6 (SOPIN) - { .fid = 0x1085, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff} }, //retries PIN 0x5 (PIN1) - { .fid = 0x1086, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff} }, //retries PIN 0x6 (SOPIN) - { .fid = 0x0000, .parent = 0, .name = openpgpcard_aid, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, - { .fid = 0x0000, .parent = 0, .name = sc_hsm_aid, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, - { .fid = 0x0000, .parent = 0xff, .name = NULL, .type = FILE_TYPE_UNKNOWN, .data = NULL, .ef_structure = 0, .acl = {0} } //end + /* 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,.data = (uint8_t *)t, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.GDO + /* 4 */ { .fid = 0x2f03, .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF,.data = (uint8_t *)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 = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff} }, //PIN 0x5 (PIN1) + /* 10 */ { .fid = 0x1088, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff} }, //PIN 0x6 (SOPIN) + /* 11 */ { .fid = 0x1085, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff} }, //retries PIN 0x5 (PIN1) + /* 12 */ { .fid = 0x1086, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff} }, //retries PIN 0x6 (SOPIN) + /* 13 */ { .fid = 0x6040, .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.PrKDFs + /* 14 */ { .fid = 0x6041, .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.PuKDFs + /* 15 */ { .fid = 0x6042, .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.CDFs + /* 16 */ { .fid = 0x6043, .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.AODFs + /* 17 */ { .fid = 0x6044, .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.DODFs + /* 18 */ { .fid = 0x6045, .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.SKDFs + ///* 19 */ { .fid = 0x0000, .parent = 0, .name = openpgpcard_aid, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, + /* 20 */ { .fid = 0x0000, .parent = 5, .name = sc_hsm_aid, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, + /* 21 */ { .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]; @@ -150,7 +158,6 @@ file_t *search_by_path(const uint8_t *pe_path, uint8_t pathlen, const file_t *pa return NULL; } -uint8_t file_selection; file_t *currentEF = NULL; file_t *currentDF = NULL; const file_t *selected_applet = NULL; @@ -174,6 +181,9 @@ bool authenticate_action(const file_t *ef, uint8_t op) { return false; } +#include "libopensc/pkcs15.h" + + void scan_flash() { if (*(uintptr_t *)end_data_pool == 0xffffffff && *(uintptr_t *)(end_data_pool+sizeof(uintptr_t)) == 0xffffffff) { @@ -184,6 +194,49 @@ void scan_flash() { //wait_flash_finish(); } printf("SCAN\r\n"); + + sc_context_t *ctx; + sc_context_param_t ctx_opts; + memset(&ctx_opts, 0, sizeof(sc_context_param_t)); + sc_thread_context_t sc_thread_ctx = { + 0, NULL, NULL, + NULL, NULL, NULL + }; + ctx_opts.ver = 0; + ctx_opts.app_name = "opensc-pkcs11"; + ctx_opts.thread_ctx = &sc_thread_ctx; + int r = sc_context_create(&ctx, &ctx_opts); + ctx->debug = 9; + + + struct sc_pkcs15_object obj; + memset(&obj, 0, sizeof(obj)); + obj.type = SC_PKCS15_TYPE_PRKEY_RSA; + struct sc_pkcs15_prkey_info info; + + /* Fill in defaults */ + memset(&info, 0, sizeof(info)); + info.key_reference = 0x2a; + info.native = 1; + char id[] = "0309"; + info.id.len = sizeof(id); + memcpy(info.id.value, id, sizeof(id)); + info.usage = 1; + info.access_flags = 1; + obj.data = malloc(sizeof(info)); + if (obj.data == NULL) { + int r = SC_ERROR_OUT_OF_MEMORY; + TU_LOG1("Out of memory"); + + return ; + } + memcpy(obj.data, &info, sizeof(info)); + + u8 *buf; + size_t len; + r = sc_pkcs15_encode_prkdf_entry(ctx, &obj, &buf, &len); + printf("r %d, len %d\r\n",r,len); + DEBUG_PAYLOAD(buf, len); 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 diff --git a/file.h b/file.h index 0c94b02..1aefda5 100644 --- a/file.h +++ b/file.h @@ -64,6 +64,7 @@ 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 file_t file_entries[]; diff --git a/flash.c b/flash.c index 62cd930..b7a5b1b 100644 --- a/flash.c +++ b/flash.c @@ -56,6 +56,8 @@ const uintptr_t end_data_pool = (XIP_BASE + PICO_FLASH_SIZE_BYTES)-FLASH_DATA_HE 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(); @@ -118,7 +120,7 @@ uintptr_t allocate_free_addr(uint16_t size) { } int flash_clear_file(file_t *file) { - uintptr_t prev_addr = (uintptr_t)(file->data+flash_read_uint16(file->data)+sizeof(uint16_t)); + uintptr_t prev_addr = (uintptr_t)(file->data+flash_read_uint16((uintptr_t)file->data)+sizeof(uint16_t)); uintptr_t base_addr = (uintptr_t)file->data-sizeof(uintptr_t); uintptr_t next_addr = flash_read_uintptr(base_addr); flash_program_uintptr(prev_addr, next_addr); @@ -130,7 +132,7 @@ int flash_write_data_to_file(file_t *file, const uint8_t *data, uint16_t len) { if (len > FLASH_SECTOR_SIZE) return 1; if (file->data) { //already in flash - uint16_t size_file_flash = flash_read_uint16(file->data); + 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); flash_program_block((uintptr_t)file->data+sizeof(uint16_t), data, len); @@ -149,13 +151,3 @@ int flash_write_data_to_file(file_t *file, const uint8_t *data, uint16_t len) { flash_program_block((uintptr_t)file->data+sizeof(uint16_t), data, len); return 0; } - -void flash_warning (const char *msg) -{ - (void)msg; - DEBUG_INFO ("FLASH: "); - DEBUG_INFO (msg); - DEBUG_INFO ("\r\n"); -} - - diff --git a/flash_openpgp.c b/flash_openpgp.c new file mode 100644 index 0000000..65eef1a --- /dev/null +++ b/flash_openpgp.c @@ -0,0 +1,763 @@ +/* + * flash.c -- Data Objects (DO) and GPG Key handling on Flash ROM + * + * Copyright (C) 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 + * Free Software Initiative of Japan + * Author: NIIBE Yutaka + * + * This file is a part of Gnuk, a GnuPG USB Token implementation. + * + * Gnuk 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, either version 3 of the License, or + * (at your option) any later version. + * + * Gnuk 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 . + * + */ + +/* + * We assume single DO size is less than 256. + * + * NOTE: "Card holder certificate" (which size is larger than 256) is + * not put into data pool, but is implemented by its own flash + * page(s). + */ + +#include +#include + +#include "config.h" + +#include "sys.h" +#include "gnuk.h" + +#include "pico/stdlib.h" +#include "hardware/flash.h" +#include "hsm2040.h" +#include "tusb.h" + +extern void low_flash_available(); + +/* + * Flash memory map + * + * _text + * .text + * .ctors + * .dtors + * _etext + * .data + * _bss_start + * .bss + * _end + * + * ch_certificate_startp + * <2048 bytes> + * _keystore_pool + * Three flash pages for keystore + * a page contains a key data of: + * For RSA-2048: 512-byte (p, q and N) + * For RSA-4096: 1024-byte (p, q and N) + * For ECDSA/ECDH and EdDSA, there are padding after public key + * _data_pool + * + */ + +#define FLASH_DATA_POOL_HEADER_SIZE 2 +#define FLASH_DATA_POOL_SIZE (2048*1024) + +static uint16_t flash_page_size; +static const uint8_t *data_pool; +static uint8_t *last_p; + +/* The first halfword is generation for the data page (little endian) */ +const uint8_t flash_data[4] __attribute__ ((section (".gnuk_data"))) = { + 0x00, 0x00, 0xff, 0xff +}; + +#define FLASH_TARGET_OFFSET (PICO_FLASH_SIZE_BYTES >> 1) // DATA starts at the mid of flash + + +const uint8_t *flash_addr_key_storage_start = (const uint8_t *) (XIP_BASE + FLASH_TARGET_OFFSET); +const uint8_t *flash_addr_data_storage_start = (const uint8_t *) (XIP_BASE + FLASH_TARGET_OFFSET + 2048 * 1024); // 2 MB +const uint8_t *ch_certificate_start = (const uint8_t *) (XIP_BASE + FLASH_TARGET_OFFSET - FLASH_SECTOR_SIZE); +#define FLASH_ADDR_KEY_STORAGE_START flash_addr_key_storage_start +#define FLASH_ADDR_DATA_STORAGE_START flash_addr_data_storage_start + +extern int flash_erase_page (uintptr_t addr); +extern int flash_program_halfword (uintptr_t addr, uint16_t data); +extern int flash_check_blank (const uint8_t *p_start, size_t size); +extern int flash_write (uintptr_t dst_addr, const uint8_t *src, size_t len); + +static int key_available_at (const uint8_t *k, int key_size) +{ + int i; + + for (i = 0; i < key_size; i++) + if (k[i]) + break; + if (i == key_size) /* It's ZERO. Released key. */ + return 0; + + for (i = 0; i < key_size; i++) + if (k[i] != 0xff) + break; + if (i == key_size) /* It's FULL. Unused key. */ + return 0; + + return 1; +} + +void +flash_do_storage_init (const uint8_t **p_do_start, const uint8_t **p_do_end) +{ + uint16_t gen0, gen1; + uint16_t *gen0_p = (uint16_t *)FLASH_ADDR_DATA_STORAGE_START; + uint16_t *gen1_p; + + flash_page_size = FLASH_SECTOR_SIZE * 8; // 32 KB + + gen1_p = (uint16_t *)(FLASH_ADDR_DATA_STORAGE_START + flash_page_size); + data_pool = FLASH_ADDR_DATA_STORAGE_START; + + /* Check data pool generation and choose the page */ + gen0 = *gen0_p; + gen1 = *gen1_p; + + if (gen0 == 0xffff && gen1 == 0xffff) + { + gen0 = 0x0000; + *gen0_p = gen0; + } + + if (gen0 == 0xffff) + /* Use another page if a page is erased. */ + data_pool = FLASH_ADDR_DATA_STORAGE_START + flash_page_size; + else if (gen1 == 0xffff) + /* Or use different page if another page is erased. */ + data_pool = FLASH_ADDR_DATA_STORAGE_START; + else if ((gen0 == 0xfffe && gen1 == 0) || gen1 > gen0) + /* When both pages have valid header, use newer page. */ + data_pool = FLASH_ADDR_DATA_STORAGE_START + flash_page_size; + + *p_do_start = data_pool + FLASH_DATA_POOL_HEADER_SIZE; + *p_do_end = data_pool + flash_page_size; +} + +static uint8_t *flash_key_getpage (enum kind_of_key kk); + +void +flash_terminate (void) +{ + int i; + + for (i = 0; i < 3; i++) + flash_erase_page ((uintptr_t)flash_key_getpage (i)); + flash_erase_page ((uintptr_t)FLASH_ADDR_DATA_STORAGE_START); + flash_erase_page ((uintptr_t)(FLASH_ADDR_DATA_STORAGE_START + flash_page_size)); + data_pool = FLASH_ADDR_DATA_STORAGE_START; + last_p = (uint8_t *)FLASH_ADDR_DATA_STORAGE_START + FLASH_DATA_POOL_HEADER_SIZE; +#if defined(CERTDO_SUPPORT) + flash_erase_page ((uintptr_t)ch_certificate_start); + if (FLASH_CH_CERTIFICATE_SIZE > flash_page_size) + flash_erase_page ((uintptr_t)(ch_certificate_start + flash_page_size)); +#endif +} + +void +flash_activate (void) +{ + flash_program_halfword ((uintptr_t)FLASH_ADDR_DATA_STORAGE_START, 0); + low_flash_available(); +} + + +void +flash_key_storage_init (void) +{ + const uint8_t *p; + int i; + + /* For each key, find its address. */ + p = FLASH_ADDR_KEY_STORAGE_START; + for (i = 0; i < 3; i++) + { + const uint8_t *k; + int key_size = gpg_get_algo_attr_key_size (i, GPG_KEY_STORAGE); + + kd[i].pubkey = NULL; + for (k = p; k < p + flash_page_size; k += key_size) + if (key_available_at (k, key_size)) + { + int prv_len = gpg_get_algo_attr_key_size (i, GPG_KEY_PRIVATE); + + kd[i].pubkey = k + prv_len; + break; + } + + p += flash_page_size; + } +} + +/* + * Flash data pool managenent + * + * Flash data pool consists of two parts: + * 2-byte header + * contents + * + * Flash data pool objects: + * Data Object (DO) (of smart card) + * Internal objects: + * NONE (0x0000) + * 123-counter + * 14-bit counter + * bool object + * small enum + * + * Format of a Data Object: + * NR: 8-bit tag_number + * LEN: 8-bit length + * DATA: data * LEN + * PAD: optional byte for 16-bit alignment + */ + +void +flash_set_data_pool_last (const uint8_t *p) +{ + last_p = (uint8_t *)p; +} + +/* + * We use two pages + */ +static int +flash_copying_gc (void) +{ + uint8_t *src, *dst; + uint16_t generation; + + if (data_pool == FLASH_ADDR_DATA_STORAGE_START) + { + src = (uint8_t *)FLASH_ADDR_DATA_STORAGE_START; + dst = (uint8_t *)FLASH_ADDR_DATA_STORAGE_START + flash_page_size; + } + else + { + src = (uint8_t *)FLASH_ADDR_DATA_STORAGE_START + flash_page_size; + dst = (uint8_t *)FLASH_ADDR_DATA_STORAGE_START; + } + + generation = *(uint16_t *)src; + data_pool = dst; + gpg_data_copy (data_pool + FLASH_DATA_POOL_HEADER_SIZE); + if (generation == 0xfffe) + generation = 0; + else + generation++; + flash_program_halfword ((uintptr_t)dst, generation); + flash_erase_page ((uintptr_t)src); + low_flash_available(); + return 0; +} + +static int +is_data_pool_full (size_t size) +{ + return last_p + size > data_pool + flash_page_size; +} + +static uint8_t * +flash_data_pool_allocate (size_t size) +{ + uint8_t *p; + + size = (size + 1) & ~1; /* allocation unit is 1-halfword (2-byte) */ + + if (is_data_pool_full (size)) + if (flash_copying_gc () < 0 || /*still*/ is_data_pool_full (size)) + TU_LOG1 ("!!!! FATAL: %d\r\n",FATAL_FLASH); + + p = last_p; + last_p += size; + return p; +} + +void +flash_do_write_internal (const uint8_t *p, int nr, const uint8_t *data, int len) +{ + uint16_t hw; + uintptr_t addr; + int i; + + addr = (uintptr_t)p; + hw = nr | (len << 8); + if (flash_program_halfword (addr, hw) != 0) + flash_warning ("DO WRITE ERROR"); + addr += 2; + + for (i = 0; i < len/2; i++) + { + hw = data[i*2] | (data[i*2+1]<<8); + if (flash_program_halfword (addr, hw) != 0) + flash_warning ("DO WRITE ERROR"); + addr += 2; + } + + if ((len & 1)) + { + hw = data[i*2] | 0xff00; + if (flash_program_halfword (addr, hw) != 0) + flash_warning ("DO WRITE ERROR"); + } + + low_flash_available(); +} + +const uint8_t * +flash_do_write (uint8_t nr, const uint8_t *data, int len) +{ + const uint8_t *p; + + DEBUG_INFO ("flash DO\r\n"); + + p = flash_data_pool_allocate (2 + len); + if (p == NULL) + { + DEBUG_INFO ("flash data pool allocation failure.\r\n"); + return NULL; + } + + flash_do_write_internal (p, nr, data, len); + DEBUG_INFO ("flash DO...done\r\n"); + return p + 1; +} + +void +flash_warning (const char *msg) +{ + (void)msg; + DEBUG_INFO ("FLASH: "); + DEBUG_INFO (msg); + DEBUG_INFO ("\r\n"); +} + +void +flash_do_release (const uint8_t *do_data) +{ + uintptr_t addr = (uintptr_t)do_data - 1; + uintptr_t addr_tag = addr; + int i; + int len = do_data[0]; + + /* Don't filling zero for data in code (such as ds_count_initial_value) */ + if (do_data < FLASH_ADDR_DATA_STORAGE_START + || do_data > FLASH_ADDR_DATA_STORAGE_START + FLASH_DATA_POOL_SIZE) + return; + + addr += 2; + + /* Fill zero for content and pad */ + for (i = 0; i < len/2; i ++) + { + if (flash_program_halfword (addr, 0) != 0) + flash_warning ("fill-zero failure"); + addr += 2; + } + + if ((len & 1)) + { + if (flash_program_halfword (addr, 0) != 0) + flash_warning ("fill-zero pad failure"); + } + + /* Fill 0x0000 for "tag_number and length" word */ + if (flash_program_halfword (addr_tag, 0) != 0) + flash_warning ("fill-zero tag_nr failure"); + + //CAUTION: flash_do_release is followed by a flash_write. Thus, we can avoid a single write + //low_flash_available(); +} + + +static uint8_t * +flash_key_getpage (enum kind_of_key kk) +{ + /* There is a page for each KK. */ + return (uint8_t *)FLASH_ADDR_KEY_STORAGE_START + (flash_page_size * kk); +} + +uint8_t * +flash_key_alloc (enum kind_of_key kk) +{ + uint8_t *k, *k0 = flash_key_getpage (kk); + int i; + int key_size = gpg_get_algo_attr_key_size (kk, GPG_KEY_STORAGE); + + /* Seek free space in the page. */ + for (k = k0; k < k0 + flash_page_size; k += key_size) + { + const uint32_t *p = (const uint32_t *)k; + + for (i = 0; i < key_size/4; i++) + if (p[i] != 0xffffffff) + break; + + if (i == key_size/4) /* Yes, it's empty. */ + return k; + } + + /* Should not happen as we have enough free space all time, but just + in case. */ + return NULL; +} + +int +flash_key_write (uint8_t *key_addr, + const uint8_t *key_data, int key_data_len, + const uint8_t *pubkey, int pubkey_len) +{ + uint16_t hw; + uintptr_t addr; + int i; + + addr = (uintptr_t)key_addr; + for (i = 0; i < key_data_len/2; i ++) + { + hw = key_data[i*2] | (key_data[i*2+1]<<8); + if (flash_program_halfword (addr, hw) != 0) + return -1; + addr += 2; + } + + for (i = 0; i < pubkey_len/2; i ++) + { + hw = pubkey[i*2] | (pubkey[i*2+1]<<8); + if (flash_program_halfword (addr, hw) != 0) + return -1; + addr += 2; + } + + low_flash_available(); + return 0; +} + +static int +flash_check_all_other_keys_released (const uint8_t *key_addr, int key_size) +{ + uintptr_t start = (uintptr_t)key_addr & ~(flash_page_size - 1); + const uint32_t *p = (const uint32_t *)start; + + while (p < (const uint32_t *)(start + flash_page_size)) + if (p == (const uint32_t *)key_addr) + p += key_size/4; + else + if (*p) + return 0; + else + p++; + + return 1; +} + +static void +flash_key_fill_zero_as_released (uint8_t *key_addr, int key_size) +{ + int i; + uintptr_t addr = (uintptr_t)key_addr; + + for (i = 0; i < key_size/2; i++) + flash_program_halfword (addr + i*2, 0); + + low_flash_available(); +} + +void +flash_key_release (uint8_t *key_addr, int key_size) +{ + if (flash_check_all_other_keys_released (key_addr, key_size)) + flash_erase_page (((uintptr_t)key_addr & ~(flash_page_size - 1))); + else + flash_key_fill_zero_as_released (key_addr, key_size); +} + +void +flash_key_release_page (enum kind_of_key kk) +{ + flash_erase_page ((uintptr_t)flash_key_getpage (kk)); +} + + +void +flash_clear_halfword (uintptr_t addr) +{ + flash_program_halfword (addr, 0); + low_flash_available(); +} + + +void +flash_put_data_internal (const uint8_t *p, uint16_t hw) +{ + flash_program_halfword ((uintptr_t)p, hw); + low_flash_available(); +} + +void +flash_put_data (uint16_t hw) +{ + uint8_t *p; + + p = flash_data_pool_allocate (2); + if (p == NULL) + { + DEBUG_INFO ("data allocation failure.\r\n"); + } + + flash_program_halfword ((uintptr_t)p, hw); + low_flash_available(); +} + + +void +flash_bool_clear (const uint8_t **addr_p) +{ + const uint8_t *p; + + if ((p = *addr_p) == NULL) + return; + + flash_program_halfword ((uintptr_t)p, 0); + *addr_p = NULL; + low_flash_available(); +} + +void +flash_bool_write_internal (const uint8_t *p, int nr) +{ + flash_program_halfword ((uintptr_t)p, nr); + low_flash_available(); +} + +const uint8_t * +flash_bool_write (uint8_t nr) +{ + uint8_t *p; + uint16_t hw = nr; + + p = flash_data_pool_allocate (2); + if (p == NULL) + { + DEBUG_INFO ("bool allocation failure.\r\n"); + return NULL; + } + + flash_program_halfword ((uintptr_t)p, hw); + low_flash_available(); + return p; +} + + +void +flash_enum_clear (const uint8_t **addr_p) +{ + flash_bool_clear (addr_p); +} + +void +flash_enum_write_internal (const uint8_t *p, int nr, uint8_t v) +{ + uint16_t hw = nr | (v << 8); + + flash_program_halfword ((uintptr_t)p, hw); + low_flash_available(); +} + +const uint8_t * +flash_enum_write (uint8_t nr, uint8_t v) +{ + uint8_t *p; + uint16_t hw = nr | (v << 8); + + p = flash_data_pool_allocate (2); + if (p == NULL) + { + DEBUG_INFO ("enum allocation failure.\r\n"); + return NULL; + } + + flash_program_halfword ((uintptr_t)p, hw); + low_flash_available(); + return p; +} + + +int +flash_cnt123_get_value (const uint8_t *p) +{ + if (p == NULL) + return 0; + else + { + uint8_t v = *p; + + /* + * After erase, a halfword in flash memory becomes 0xffff. + * The halfword can be programmed to any value. + * Then, the halfword can be programmed to zero. + * + * Thus, we can represent value 1, 2, and 3. + */ + if (v == 0xff) + return 1; + else if (v == 0x00) + return 3; + else + return 2; + } +} + +void +flash_cnt123_write_internal (const uint8_t *p, int which, int v) +{ + uint16_t hw; + + hw = NR_COUNTER_123 | (which << 8); + flash_program_halfword ((uintptr_t)p, hw); + + if (v == 1) + return; + else if (v == 2) + flash_program_halfword ((uintptr_t)p+2, 0xc3c3); + else /* v == 3 */ + flash_program_halfword ((uintptr_t)p+2, 0); + low_flash_available(); +} + +void +flash_cnt123_increment (uint8_t which, const uint8_t **addr_p) +{ + const uint8_t *p; + uint16_t hw; + + if ((p = *addr_p) == NULL) + { + p = flash_data_pool_allocate (4); + if (p == NULL) + { + DEBUG_INFO ("cnt123 allocation failure.\r\n"); + return; + } + hw = NR_COUNTER_123 | (which << 8); + flash_program_halfword ((uintptr_t)p, hw); + *addr_p = p + 2; + } + else + { + uint8_t v = *p; + + if (v == 0) + return; + + if (v == 0xff) + hw = 0xc3c3; + else + hw = 0; + + flash_program_halfword ((uintptr_t)p, hw); + } + low_flash_available(); +} + +void +flash_cnt123_clear (const uint8_t **addr_p) +{ + const uint8_t *p; + + if ((p = *addr_p) == NULL) + return; + + flash_program_halfword ((uintptr_t)p, 0); + p -= 2; + flash_program_halfword ((uintptr_t)p, 0); + *addr_p = NULL; + low_flash_available(); +} + + +#if defined(CERTDO_SUPPORT) +int +flash_erase_binary (uint8_t file_id) +{ + if (file_id == FILEID_CH_CERTIFICATE) + { + const uint8_t *p = ch_certificate_start; + if (flash_check_blank (p, FLASH_CH_CERTIFICATE_SIZE) == 0) + { + flash_erase_page ((uintptr_t)p); + if (FLASH_CH_CERTIFICATE_SIZE > flash_page_size) + flash_erase_page ((uintptr_t)p + flash_page_size); + } + low_flash_available(); + + return 0; + } + + return -1; +} +#endif + + +int +flash_write_binary (uint8_t file_id, const uint8_t *data, + uint16_t len, uint16_t offset) +{ + uint16_t maxsize; + const uint8_t *p; + + if (file_id == FILEID_SERIAL_NO) + { + maxsize = 6; + p = &openpgpcard_aid[8]; + } +#if defined(CERTDO_SUPPORT) + else if (file_id == FILEID_CH_CERTIFICATE) + { + maxsize = FLASH_CH_CERTIFICATE_SIZE; + p = ch_certificate_start; + } +#endif + else + return -1; + + if (offset + len > maxsize || (offset&1) || (len&1)) + return -1; + else + { + uint16_t hw; + uintptr_t addr; + int i; + + if (flash_check_blank (p + offset, len) == 0) + return -1; + + addr = (uintptr_t)p + offset; + for (i = 0; i < len/2; i++) + { + hw = data[i*2] | (data[i*2+1]<<8); + if (flash_program_halfword (addr, hw) != 0) + flash_warning ("DO WRITE ERROR"); + addr += 2; + } + + low_flash_available(); + return 0; + } +} diff --git a/gnuk.h b/gnuk.h index 6e7d8a5..b9a3a6f 100644 --- a/gnuk.h +++ b/gnuk.h @@ -5,28 +5,7 @@ /* * Application layer <-> CCID layer data structure */ -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 CLS(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] - -extern struct apdu apdu; #define CARD_CHANGE_INSERT 0 #define CARD_CHANGE_REMOVE 1 @@ -54,8 +33,7 @@ void ccid_card_change_signal (int how); #define CCID_MSG_HEADER_SIZE 10 -#define res_APDU apdu.res_apdu_data -#define res_APDU_size apdu.res_apdu_data_len + /* USB buffer size of LL (Low-level): size of single Bulk transaction */ #define USB_LL_BUF_SIZE 64 @@ -107,7 +85,6 @@ void ac_reset_admin (void); void ac_fini (void); -uint16_t set_res_sw (uint8_t sw1, uint8_t sw2); extern uint8_t file_selection; extern const uint8_t historical_bytes[]; extern uint16_t data_objects_number_of_bytes; @@ -246,32 +223,6 @@ int gpg_change_keystring (int who_old, const uint8_t *old_ks, extern struct key_data kd[3]; -#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 int rsa_sign (const uint8_t *, uint8_t *, int, struct key_data *, int); int modulus_calc (const uint8_t *, int, uint8_t *); @@ -431,7 +382,6 @@ extern uint8_t admin_authorized; #endif extern const uint8_t openpgpcard_aid[]; -extern const uint8_t sc_hsm_aid[]; void flash_bool_clear (const uint8_t **addr_p); const uint8_t *flash_bool_write (uint8_t nr); @@ -510,17 +460,6 @@ unique_device_id (void) return id; } -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(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; -} - #endif \ No newline at end of file diff --git a/hsm2040.c b/hsm2040.c index 3053706..d60aa48 100644 --- a/hsm2040.c +++ b/hsm2040.c @@ -39,7 +39,6 @@ static uint8_t itf_num; struct apdu apdu; static struct ccid ccid; -extern void openpgp_card_thread(); static uint8_t ccid_buffer[USB_BUF_SIZE]; @@ -79,6 +78,25 @@ static uint8_t ccid_buffer[USB_BUF_SIZE]; #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(); + +static queue_t *card_comm; +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; @@ -158,7 +176,7 @@ struct ccid { struct ep_in *epi; queue_t ccid_comm; - queue_t openpgp_comm; + queue_t card_comm; uint8_t application; @@ -203,7 +221,7 @@ static void ccid_init(struct ccid *c, struct ep_in *epi, struct ep_out *epo, str c->epo = epo; c->a = a; - queue_init(&c->openpgp_comm, sizeof(uint32_t), 64); + queue_init(&c->card_comm, sizeof(uint32_t), 64); queue_init(&c->ccid_comm, sizeof(uint32_t), 64); } @@ -362,7 +380,7 @@ static uint32_t blink_interval_ms = BLINK_NOT_MOUNTED; void usb_tx_enable(const void *buf, uint32_t len) { - DEBUG_PAYLOAD(((uint8_t *)buf),len); + //DEBUG_PAYLOAD(((uint8_t *)buf),len); tud_vendor_write(buf, len); } @@ -407,9 +425,9 @@ static enum ccid_state ccid_power_on (struct ccid *c) if (c->application == 0) { multicore_reset_core1(); - multicore_launch_core1(openpgp_card_thread); + multicore_launch_core1(card_thread); multicore_fifo_push_blocking((uint32_t)&c->ccid_comm); - multicore_fifo_push_blocking((uint32_t)&c->openpgp_comm); + multicore_fifo_push_blocking((uint32_t)&c->card_comm); c->application = 1; } p[0] = CCID_DATA_BLOCK_RET; @@ -491,7 +509,7 @@ static enum ccid_state ccid_power_off (struct ccid *c) if (c->application) { uint32_t flag = EV_EXIT; - queue_try_add(&c->openpgp_comm, &flag); + queue_try_add(&c->card_comm, &flag); c->application = 0; } @@ -874,7 +892,7 @@ TU_LOG3("---- CCID STATE %d,msg_type %x,start %d\r\n",c->ccid_state,c->ccid_head c->a->res_apdu_data = &ccid_buffer[5]; uint32_t flag = EV_CMD_AVAILABLE; - queue_try_add(&c->openpgp_comm, &flag); + queue_try_add(&c->card_comm, &flag); next_state = CCID_STATE_EXECUTE; } @@ -935,7 +953,7 @@ TU_LOG3("---- CCID STATE %d,msg_type %x,start %d\r\n",c->ccid_state,c->ccid_head c->state = APDU_STATE_COMMAND_RECEIVED; uint32_t flag = EV_VERIFY_CMD_AVAILABLE; - queue_try_add(&c->openpgp_comm, &flag); + queue_try_add(&c->card_comm, &flag); next_state = CCID_STATE_EXECUTE; } else if (c->p[10-10] == 0x01) /* PIN Modification */ @@ -971,7 +989,7 @@ TU_LOG3("---- CCID STATE %d,msg_type %x,start %d\r\n",c->ccid_state,c->ccid_head c->state = APDU_STATE_COMMAND_RECEIVED; uint32_t flag = EV_MODIFY_CMD_AVAILABLE; - queue_try_add(&c->openpgp_comm, &flag); + queue_try_add(&c->card_comm, &flag); next_state = CCID_STATE_EXECUTE; } else @@ -1389,7 +1407,7 @@ static int usb_event_handle(struct ccid *c) else if (tud_vendor_available() && c->epo->ready) { uint32_t count = tud_vendor_read(endp1_rx_buf, sizeof(endp1_rx_buf)); - DEBUG_PAYLOAD(endp1_rx_buf, count); + //DEBUG_PAYLOAD(endp1_rx_buf, count); ccid_rx_ready(count); } return 0; @@ -1411,7 +1429,145 @@ void prepare_ccid() apdu_init(a); ccid_init (c, epi, epo, a); } -#include "hardware/structs/rosc.h" + +int process_apdu() { + if (!current_app) { + if (INS(apdu) == 0xA4 && P1(apdu) == 0x04 && P2(apdu) == 0x00) { //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(); +} + + +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() +{ + queue_t *ccid_comm = (queue_t *)multicore_fifo_pop_blocking(); + card_comm = (queue_t *)multicore_fifo_pop_blocking(); + + card_init (); + + while (1) + { +#if defined(PINPAD_SUPPORT) + int len, pw_len, newpw_len; +#endif + + uint32_t m; + queue_remove_blocking(card_comm, &m); + + if (m == EV_VERIFY_CMD_AVAILABLE) + { +#if defined(PINPAD_SUPPORT) + if (INS (apdu) != INS_VERIFY) + { + GPG_CONDITION_NOT_SATISFIED (); + goto done; + } + + pw_len = get_pinpad_input (PIN_INPUT_CURRENT); + if (pw_len < 0) + { + set_res_sw (0x6f, 0x00); + goto done; + } + memcpy (apdu.cmd_apdu_data, pin_input_buffer, pw_len); + apdu.cmd_apdu_data_len = pw_len; +#else + set_res_sw (0x6f, 0x00); + goto done; +#endif + } + else if (m == EV_MODIFY_CMD_AVAILABLE) + { +#if defined(PINPAD_SUPPORT) + uint8_t bConfirmPIN = apdu.cmd_apdu_data[0]; + uint8_t *p = apdu.cmd_apdu_data; + + if (INS (apdu) != INS_CHANGE_REFERENCE_DATA + && INS (apdu) != INS_RESET_RETRY_COUNTER + && INS (apdu) != INS_PUT_DATA) + { + GPG_CONDITION_NOT_SATISFIED (); + goto done; + } + + if ((bConfirmPIN & 2)) /* Require old PIN */ + { + pw_len = get_pinpad_input (PIN_INPUT_CURRENT); + if (pw_len < 0) + { + set_res_sw (0x6f, 0x00); + goto done; + } + memcpy (p, pin_input_buffer, pw_len); + p += pw_len; + } + else + pw_len = 0; + + newpw_len = get_pinpad_input (PIN_INPUT_NEW); + if (newpw_len < 0) + { + set_res_sw (0x6f, 0x00); + goto done; + } + memcpy (p, pin_input_buffer, newpw_len); + + if ((bConfirmPIN & 1)) /* New PIN twice */ + { + len = get_pinpad_input (PIN_INPUT_CONFIRM); + if (len < 0) + { + set_res_sw (0x6f, 0x00); + goto done; + } + + if (len != newpw_len || memcmp (p, pin_input_buffer, len) != 0) + { + GPG_SECURITY_FAILURE (); + goto done; + } + } + + apdu.cmd_apdu_data_len = pw_len + newpw_len; +#else + set_res_sw (0x6f, 0x00); + goto done; +#endif + } + else if (m == EV_EXIT) + 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; @@ -1453,7 +1609,7 @@ void ccid_task(void) if (c->application) { uint32_t flag = EV_EXIT; - queue_try_add(&c->openpgp_comm, &flag); + queue_try_add(&c->card_comm, &flag); c->application = 0; } c->ccid_state = CCID_STATE_NOCARD; diff --git a/hsm2040.h b/hsm2040.h index 1373dac..4ae85b7 100644 --- a/hsm2040.h +++ b/hsm2040.h @@ -8,9 +8,19 @@ #define _HSM2040_H_ #include "ccid.h" +#include "tusb.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) { \ @@ -29,6 +39,75 @@ extern const uint8_t historical_bytes[]; TU_LOG1("\r\n");\ } TU_LOG1("\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 CLS(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 + #endif \ No newline at end of file diff --git a/low_flash.c b/low_flash.c index 7789ad4..61e4f0c 100644 --- a/low_flash.c +++ b/low_flash.c @@ -9,6 +9,7 @@ #include "pico/sem.h" #include "pico/multicore.h" #include "gnuk.h" +#include "hsm2040.h" #include #define TOTAL_FLASH_PAGES 4 diff --git a/neug.c b/neug.c index 5d9993f..39d317b 100644 --- a/neug.c +++ b/neug.c @@ -55,8 +55,8 @@ static uint8_t ep_round = 0; static void ep_init (int mode) { - random_word = 0xcbf29ce484222325; - ep_round = 0; + random_word = 0xcbf29ce484222325; + ep_round = 0; } /* Here, we assume a little endian architecture. */ @@ -88,7 +88,6 @@ static int ep_process (int mode) return 0; } - static const uint32_t *ep_output (int mode) { (void) mode; @@ -99,49 +98,49 @@ static const uint32_t *ep_output (int mode) * Ring buffer, filled by generator, consumed by neug_get routine. */ struct rng_rb { - uint32_t *buf; - //chopstx_mutex_t m; - //chopstx_cond_t data_available; - //chopstx_cond_t space_available; - uint8_t head, tail; - uint8_t size; - unsigned int full :1; - unsigned int empty :1; + uint32_t *buf; + //chopstx_mutex_t m; + //chopstx_cond_t data_available; + //chopstx_cond_t space_available; + 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; - //chopstx_mutex_init (&rb->m); - //chopstx_cond_init (&rb->data_available); - //chopstx_cond_init (&rb->space_available); - rb->head = rb->tail = 0; - rb->full = 0; - rb->empty = 1; + rb->buf = p; + rb->size = size; + //chopstx_mutex_init (&rb->m); + //chopstx_cond_init (&rb->data_available); + //chopstx_cond_init (&rb->space_available); + 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; + 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++]; + 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; + if (rb->head == rb->size) + rb->head = 0; + if (rb->head == rb->tail) + rb->empty = 1; + rb->full = 0; - return v; + return v; } uint8_t neug_mode; @@ -154,13 +153,12 @@ static struct rng_rb the_ring_buffer; /** * @brief Random number generation thread. */ -void * -neug_task () +void *neug_task () { - struct rng_rb *rb = &the_ring_buffer; - int mode = neug_mode; + struct rng_rb *rb = &the_ring_buffer; + int mode = neug_mode; - rng_should_terminate = 0; + rng_should_terminate = 0; //chopstx_mutex_init (&mode_mtx); //chopstx_cond_init (&mode_cond); @@ -170,20 +168,20 @@ neug_task () if ((n = ep_process (mode))) { - int i; - const uint32_t *vp; + int i; + const uint32_t *vp; - vp = ep_output (mode); + vp = ep_output (mode); //chopstx_mutex_lock (&rb->m); //while (rb->full) //chopstx_cond_wait (&rb->space_available, &rb->m); - for (i = 0; i < n; i++) + for (i = 0; i < n; i++) { - rb_add (rb, *vp++); - if (rb->full) - break; + rb_add (rb, *vp++); + if (rb->full) + break; } //chopstx_cond_signal (&rb->data_available); @@ -193,32 +191,31 @@ neug_task () //adc_stop (); - return NULL; + return NULL; } /** * @brief Initialize NeuG. */ -void -neug_init (uint32_t *buf, uint8_t size) +void neug_init (uint32_t *buf, uint8_t size) { - const uint32_t *u = (const uint32_t *)unique_device_id (); - struct rng_rb *rb = &the_ring_buffer; - int i; - - - /* - * This initialization ensures that it generates different sequence - * even if all physical conditions are same. - */ - - neug_mode = NEUG_MODE_CONDITIONED; - rb_init (rb, buf, size); - - /* Enable ADCs */ - adc_start (); - - ep_init (neug_mode); + const uint32_t *u = (const uint32_t *)unique_device_id (); + struct rng_rb *rb = &the_ring_buffer; + int i; + + + /* + * This initialization ensures that it generates different sequence + * even if all physical conditions are same. + */ + + neug_mode = NEUG_MODE_CONDITIONED; + rb_init (rb, buf, size); + + /* Enable ADCs */ + adc_start (); + + ep_init (neug_mode); //rng_thread = chopstx_create (PRIO_RNG, STACK_ADDR_RNG, STACK_SIZE_RNG, // rng, rb); @@ -227,14 +224,13 @@ neug_init (uint32_t *buf, uint8_t size) /** * @breif Flush random bytes. */ -void -neug_flush (void) +void neug_flush (void) { - struct rng_rb *rb = &the_ring_buffer; - - //chopstx_mutex_lock (&rb->m); - while (!rb->empty) - (void)rb_del (rb); + struct rng_rb *rb = &the_ring_buffer; + + //chopstx_mutex_lock (&rb->m); + while (!rb->empty) + rb_del (rb); //chopstx_cond_signal (&rb->space_available); //chopstx_mutex_unlock (&rb->m); } @@ -247,95 +243,36 @@ neug_flush (void) * With NEUG_NO_KICK, it doesn't wake up RNG thread automatically, * it is needed to call neug_kick_filling later. */ -uint32_t -neug_get (int kick) +uint32_t neug_get (int kick) { - struct rng_rb *rb = &the_ring_buffer; - uint32_t v; + struct rng_rb *rb = &the_ring_buffer; + uint32_t v; //chopstx_mutex_lock (&rb->m); - while (rb->empty) - neug_task(); //chopstx_cond_wait (&rb->data_available, &rb->m); - v = rb_del (rb); + while (rb->empty) + neug_task(); //chopstx_cond_wait (&rb->data_available, &rb->m); + v = rb_del (rb); //if (kick) //chopstx_cond_signal (&rb->space_available); //chopstx_mutex_unlock (&rb->m); - return v; + return v; } -int -neug_get_nonblock (uint32_t *p) +void neug_wait_full (void) { - struct rng_rb *rb = &the_ring_buffer; - int r = 0; + struct rng_rb *rb = &the_ring_buffer; //chopstx_mutex_lock (&rb->m); - if (rb->empty) - { - r = -1; - //chopstx_cond_signal (&rb->space_available); - } - else - *p = rb_del (rb); - //chopstx_mutex_unlock (&rb->m); - - return r; -} - -int neug_consume_random (void (*proc) (uint32_t, int)) -{ - int i = 0; - struct rng_rb *rb = &the_ring_buffer; - - //chopstx_mutex_lock (&rb->m); - while (!rb->empty) - { - uint32_t v; - - v = rb_del (rb); - proc (v, i); - i++; - } - //chopstx_cond_signal (&rb->space_available); - //chopstx_mutex_unlock (&rb->m); - - return i; -} - -void -neug_wait_full (void) -{ - struct rng_rb *rb = &the_ring_buffer; - - //chopstx_mutex_lock (&rb->m); - while (!rb->full) - neug_task(); //chopstx_cond_wait (&rb->data_available, &rb->m); + while (!rb->full) + neug_task(); //chopstx_cond_wait (&rb->data_available, &rb->m); //chopstx_mutex_unlock (&rb->m); } -void -neug_fini (void) +void neug_fini (void) { - rng_should_terminate = 1; - neug_get (1); + rng_should_terminate = 1; + neug_get (1); //chopstx_join (rng_thread, NULL); } -void -neug_mode_select (uint8_t mode) -{ - if (neug_mode == mode) - return; - - neug_wait_full (); - - //chopstx_mutex_lock (&mode_mtx); - neug_mode = mode; - neug_flush (); - //chopstx_cond_wait (&mode_cond, &mode_mtx); - //chopstx_mutex_unlock (&mode_mtx); - - neug_wait_full (); - neug_flush (); -} diff --git a/neug.h b/neug.h index 38aadc0..7479b31 100644 --- a/neug.h +++ b/neug.h @@ -7,27 +7,8 @@ #define NEUG_MODE_RAW 1 /* CRC-32 filtered sample data. */ #define NEUG_MODE_RAW_DATA 2 /* Sample data directly. */ -extern uint8_t neug_mode; -extern uint16_t neug_err_cnt; -extern uint16_t neug_err_cnt_rc; -extern uint16_t neug_err_cnt_p64; -extern uint16_t neug_err_cnt_p4k; -extern uint16_t neug_rc_max; -extern uint16_t neug_p64_max; -extern uint16_t neug_p4k_max; - void neug_init (uint32_t *buf, uint8_t size); uint32_t neug_get (int kick); -int neug_get_nonblock (uint32_t *p); -void neug_kick_filling (void); void neug_flush (void); void neug_wait_full (void); void neug_fini (void); -void neug_mode_select (uint8_t mode); - -int neug_consume_random (void (*proc) (uint32_t, int)); - -void crc32_rv_reset (void); -void crc32_rv_step (uint32_t v); -uint32_t crc32_rv_get (void); -uint32_t rbit (uint32_t v); diff --git a/openpgp-do.c b/openpgp-do.c index cd008a1..3d6f076 100644 --- a/openpgp-do.c +++ b/openpgp-do.c @@ -37,6 +37,7 @@ #include "mbedtls/aes.h" #include "mbedtls/sha512.h" #include "shake256.h" +#include "hsm2040.h" /* Forward declaration */ #define CLEAN_PAGE_FULL 1 @@ -50,8 +51,7 @@ static const uint8_t *pw_err_counter_p[3]; static int gpg_pw_get_err_counter (uint8_t which) { - //return flash_cnt123_get_value (pw_err_counter_p[which]); - return 3; + return flash_cnt123_get_value (pw_err_counter_p[which]); } int @@ -77,7 +77,7 @@ gpg_pw_locked (uint8_t which) void gpg_pw_reset_err_counter (uint8_t which) { - //flash_cnt123_clear (&pw_err_counter_p[which]); + flash_cnt123_clear (&pw_err_counter_p[which]); if (pw_err_counter_p[which] != NULL) GPG_MEMORY_FAILURE (); } @@ -85,7 +85,7 @@ gpg_pw_reset_err_counter (uint8_t which) void gpg_pw_increment_err_counter (uint8_t which) { - //flash_cnt123_increment (which, &pw_err_counter_p[which]); + flash_cnt123_increment (which, &pw_err_counter_p[which]); } @@ -386,15 +386,15 @@ gpg_write_digital_signature_counter (const uint8_t *p, uint32_t dsc) if ((dsc >> 10) == 0) { /* no upper bits */ hw1 = NR_COUNTER_DS_LSB | ((dsc & 0x0300) >> 8) | ((dsc & 0x00ff) << 8); - //flash_put_data_internal (p, hw1); + flash_put_data_internal (p, hw1); return p+2; } else { hw0 = NR_COUNTER_DS | ((dsc & 0xfc0000) >> 18) | ((dsc & 0x03fc00) >> 2); hw1 = NR_COUNTER_DS_LSB | ((dsc & 0x0300) >> 8) | ((dsc & 0x00ff) << 8); - //flash_put_data_internal (p, hw0); - //flash_put_data_internal (p+2, hw1); + flash_put_data_internal (p, hw0); + flash_put_data_internal (p+2, hw1); return p+4; } } @@ -404,8 +404,8 @@ gpg_reset_digital_signature_counter (void) { if (digital_signature_counter != 0) { - //flash_put_data (NR_COUNTER_DS); - //flash_put_data (NR_COUNTER_DS_LSB); + flash_put_data (NR_COUNTER_DS); + flash_put_data (NR_COUNTER_DS_LSB); digital_signature_counter = 0; } } @@ -420,13 +420,13 @@ gpg_increment_digital_signature_counter (void) { /* carry occurs from l10 to h14 */ hw0 = NR_COUNTER_DS | ((dsc & 0xfc0000) >> 18) | ((dsc & 0x03fc00) >> 2); hw1 = NR_COUNTER_DS_LSB; /* zero */ - //flash_put_data (hw0); - //flash_put_data (hw1); + flash_put_data (hw0); + flash_put_data (hw1); } else { hw1 = NR_COUNTER_DS_LSB | ((dsc & 0x0300) >> 8) | ((dsc & 0x00ff) << 8); - //flash_put_data (hw1); + flash_put_data (hw1); } digital_signature_counter = dsc; @@ -658,7 +658,6 @@ do_kgtime_all (uint16_t tag, int with_tag) } const uint8_t openpgpcard_aid[] = { - 14, //len 0xd2, 0x76, /* D: National, 276: DEU ISO 3166-1 */ 0x00, 0x01, 0x24, /* Registered Application Provider Identifier */ 0x01, /* Application: OpenPGPcard */ @@ -667,11 +666,6 @@ const uint8_t openpgpcard_aid[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* To be overwritten */ }; -const uint8_t sc_hsm_aid[] = { - 11, - 0xE8,0x2B,0x06,0x01,0x04,0x01,0x81,0xC3,0x1F,0x02,0x01 -}; - static void do_openpgpcard_aid (uint16_t tag, int with_tag) { @@ -772,13 +766,13 @@ rw_pw_status (uint16_t tag, int with_tag, /* The first byte of DATA specifies the lifetime. */ if (data[0] == 0 && pw1_lifetime_p != NULL) { - //flash_bool_clear (&pw1_lifetime_p); + flash_bool_clear (&pw1_lifetime_p); if (pw1_lifetime_p != NULL) /* No change after update */ return 0; } else if (pw1_lifetime_p == NULL) { - //pw1_lifetime_p = flash_bool_write (NR_BOOL_PW1_LIFETIME); + pw1_lifetime_p = flash_bool_write (NR_BOOL_PW1_LIFETIME); if (pw1_lifetime_p == NULL) /* No change after update */ return 0; } @@ -853,7 +847,7 @@ rw_algorithm_attr (uint16_t tag, int with_tag, gpg_reset_algo_attr (kk); /* Read it again, since GC may occur. */ algo_attr_pp = get_algo_attr_pointer (kk); - //flash_enum_clear (algo_attr_pp); + flash_enum_clear (algo_attr_pp); if (*algo_attr_pp != NULL) return 0; } @@ -863,9 +857,9 @@ rw_algorithm_attr (uint16_t tag, int with_tag, gpg_reset_algo_attr (kk); /* Read it again, since GC may occur. */ algo_attr_pp = get_algo_attr_pointer (kk); - //if (*algo_attr_pp) - // flash_enum_clear (algo_attr_pp); - //*algo_attr_pp = flash_enum_write (kk_to_nr (kk), algo); + if (*algo_attr_pp) + flash_enum_clear (algo_attr_pp); + *algo_attr_pp = flash_enum_write (kk_to_nr (kk), algo); if (*algo_attr_pp == NULL) return 0; } @@ -992,8 +986,8 @@ rw_kdf (uint16_t tag, int with_tag, const uint8_t *data, int len, int is_write) && data[42] == 0x87 && data[76] == 0x88)))) return 0; - //if (*do_data_p) - //flash_do_release (*do_data_p); + if (*do_data_p) + flash_do_release (*do_data_p); /* Clear all keystrings and auth states */ gpg_do_write_simple (NR_DO_KEYSTRING_PW1, NULL, 0); @@ -1010,7 +1004,7 @@ rw_kdf (uint16_t tag, int with_tag, const uint8_t *data, int len, int is_write) } else { - //*do_data_p = flash_do_write (NR_DO_KDF, data, len); + *do_data_p = flash_do_write (NR_DO_KDF, data, len); if (*do_data_p) return 1; else @@ -1332,20 +1326,20 @@ gpg_do_delete_prvkey (enum kind_of_key kk, int clean_page_full) if (do_data == NULL) { - // if (clean_page_full) - //flash_key_release_page (kk); + if (clean_page_full) + flash_key_release_page (kk); return; } do_ptr[nr] = NULL; - //flash_do_release (do_data); + flash_do_release (do_data); key_addr = (uint8_t *)kd[kk].pubkey - prvkey_len; kd[kk].pubkey = NULL; - /*if (clean_page_full) + if (clean_page_full) flash_key_release_page (kk); else flash_key_release (key_addr, key_size); -*/ + if (admin_authorized == BY_ADMIN && kk == GPG_KEY_FOR_SIGNING) { /* Recover admin keystring DO. */ const uint8_t *ks_pw3 = gpg_do_read_simple (NR_DO_KEYSTRING_PW3); @@ -1462,7 +1456,7 @@ gpg_do_write_prvkey (enum kind_of_key kk, const uint8_t *key_data, } DEBUG_INFO ("Getting keystore address...\r\n"); - //key_addr = flash_key_alloc (kk); + key_addr = flash_key_alloc (kk); if (key_addr == NULL) return -1; @@ -1522,7 +1516,7 @@ gpg_do_write_prvkey (enum kind_of_key kk, const uint8_t *key_data, else memset (pd->dek_encrypted_3, 0, DATA_ENCRYPTION_KEY_SIZE); - //p = flash_do_write (nr, (const uint8_t *)pd, sizeof (struct prvkey_data)); + p = flash_do_write (nr, (const uint8_t *)pd, sizeof (struct prvkey_data)); do_ptr[nr] = p; random_bytes_free (dek); @@ -1599,9 +1593,9 @@ gpg_do_chks_prvkey (enum kind_of_key kk, { const uint8_t *p; - //flash_do_release (do_data); + flash_do_release (do_data); do_ptr[nr] = NULL; - //p = flash_do_write (nr, (const uint8_t *)pd, sizeof (struct prvkey_data)); + p = flash_do_write (nr, (const uint8_t *)pd, sizeof (struct prvkey_data)); do_ptr[nr] = p; if (p == NULL) r = -1; @@ -2009,7 +2003,7 @@ gpg_data_scan (const uint8_t *do_start, const uint8_t *do_end) } } - //flash_set_data_pool_last (p); + flash_set_data_pool_last (p); num_prv_keys = 0; if (do_ptr[NR_DO_PRVKEY_SIG] != NULL) @@ -2044,6 +2038,79 @@ gpg_data_scan (const uint8_t *do_start, const uint8_t *do_end) digital_signature_counter = (dsc_h14 << 10) | dsc_l10; } +/* + * Write all data to newly allocated Flash ROM page (from P_START), + * updating PW1_LIFETIME_P, PW_ERR_COUNTER_P, and DO_PTR. + * Called by flash_copying_gc. + */ +void +gpg_data_copy (const uint8_t *p_start) +{ + const uint8_t *p; + int i; + int v; + + p = gpg_write_digital_signature_counter (p_start, digital_signature_counter); + + if (pw1_lifetime_p != NULL) + { + flash_bool_write_internal (p, NR_BOOL_PW1_LIFETIME); + pw1_lifetime_p = p; + p += 2; + } + + if (algo_attr_sig_p != NULL) + { + flash_enum_write_internal (p, NR_KEY_ALGO_ATTR_SIG, algo_attr_sig_p[1]); + algo_attr_sig_p = p; + p += 2; + } + + if (algo_attr_dec_p != NULL) + { + flash_enum_write_internal (p, NR_KEY_ALGO_ATTR_DEC, algo_attr_dec_p[1]); + algo_attr_dec_p = p; + p += 2; + } + + if (algo_attr_aut_p != NULL) + { + flash_enum_write_internal (p, NR_KEY_ALGO_ATTR_AUT, algo_attr_aut_p[1]); + algo_attr_aut_p = p; + p += 2; + } + + for (i = 0; i < 3; i++) + if ((v = flash_cnt123_get_value (pw_err_counter_p[i])) != 0) + { + flash_cnt123_write_internal (p, i, v); + pw_err_counter_p[i] = p + 2; + p += 4; + } + + for (i = 0; i < 3; i++) + if ((v = (uif_flags >> (i * 2)) & 3)) + { + flash_enum_write_internal (p, NR_DO_UIF_SIG + i, v); + p += 2; + } + + data_objects_number_of_bytes = 0; + for (i = 0; i < NR_DO__LAST__; i++) + if (do_ptr[i] != NULL) + { + const uint8_t *do_data = do_ptr[i]; + int len = do_data[0]; + + flash_do_write_internal (p, i, &do_data[1], len); + do_ptr[i] = p + 1; + p += 2 + ((len + 1) & ~1); + data_objects_number_of_bytes += len; + } + + flash_set_data_pool_last (p); +} + static const struct do_table_entry * get_do_entry (uint16_t tag) { @@ -2170,7 +2237,7 @@ gpg_do_get_data (uint16_t tag, int with_tag) #if defined(CERTDO_SUPPORT) if (tag == GPG_DO_CH_CERTIFICATE) { - //apdu.res_apdu_data = (uint8_t *)ch_certificate_start; + apdu.res_apdu_data = (uint8_t *)ch_certificate_start; apdu.res_apdu_data_len = ((apdu.res_apdu_data[2] << 8) | apdu.res_apdu_data[3]); if (apdu.res_apdu_data_len == 0xffff) { @@ -2234,8 +2301,8 @@ gpg_do_put_data (uint16_t tag, const uint8_t *data, int len) { const uint8_t **do_data_p = (const uint8_t **)do_p->obj; - // if (*do_data_p) - // flash_do_release (*do_data_p); + if (*do_data_p) + flash_do_release (*do_data_p); if (len == 0) { @@ -2254,7 +2321,7 @@ gpg_do_put_data (uint16_t tag, const uint8_t *data, int len) else { *do_data_p = NULL; - //*do_data_p = flash_do_write (nr, data, len); + *do_data_p = flash_do_write (nr, data, len); if (*do_data_p) GPG_SUCCESS (); else @@ -2410,13 +2477,13 @@ gpg_do_write_simple (uint8_t nr, const uint8_t *data, int size) const uint8_t **do_data_p; do_data_p = (const uint8_t **)&do_ptr[nr]; - //if (*do_data_p) - // flash_do_release (*do_data_p); + if (*do_data_p) + flash_do_release (*do_data_p); if (data != NULL) { *do_data_p = NULL; - //*do_data_p = flash_do_write (nr, data, size); + *do_data_p = flash_do_write (nr, data, size); if (*do_data_p == NULL) flash_warning ("DO WRITE ERROR"); } diff --git a/openpgp.c b/openpgp.c index 910abc1..d703fd0 100644 --- a/openpgp.c +++ b/openpgp.c @@ -37,8 +37,27 @@ #include "pico/multicore.h" #include "hsm2040.h" #include "tusb.h" +#include "file.h" +#include "libopensc/card-sc-hsm.h" + +extern const uint8_t openpgpcard_aid[]; +static int openpgp_process_apdu(); +static int gpg_fini(); + +app_t *openpgp_select_aid(app_t *a) { + if (!memcmp(apdu.cmd_apdu_data, openpgpcard_aid+1, MIN(apdu.cmd_apdu_data_len,openpgpcard_aid[0]))) { + a->aid = openpgpcard_aid; + a->process_apdu = openpgp_process_apdu; + a->unload = gpg_fini; + return a; + } + return NULL; +} + +void __attribute__ ((constructor)) openpgp_ctor() { + register_app(openpgp_select_aid); +} -static queue_t *openpgp_comm; #define USER_PASSWD_MINLEN 6 #define ADMIN_PASSWD_MINLEN 8 @@ -82,11 +101,6 @@ select_file_TOP_result[] __attribute__ ((aligned (1))) = { 0x00, 0x00 /* PIN status: OK, PIN blocked?: No */ }; -uint16_t set_res_sw (uint8_t sw1, uint8_t sw2) -{ - apdu.sw = (sw1 << 8) | sw2; - return make_uint16_t(sw1, sw2); -} #define FILE_NONE 0 #define FILE_DF_OPENPGP 1 @@ -101,218 +115,31 @@ uint16_t set_res_sw (uint8_t sw1, uint8_t sw2) #define FILE_DF_SC_HSM 10 #define FILE_CARD_TERMINATED 255 -#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 - -/* 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 - -typedef struct pkcs15_entry -{ - 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 *data; //should include 2 bytes len at begining - const uint8_t ef_structure; - const uint8_t acl[7]; -} pkcs15_entry_t; - -//puts FCI in the RAPDU -void process_fci(const pkcs15_entry_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) - memcpy(res_APDU+res_APDU_size, pe->data, 2); - 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; -} - -const uint8_t t[] = { - 0x01,0xbb, - 0x7F,0x21,0x82,0x01,0xB6,0x7F,0x4E,0x82,0x01,0x6E,0x5F,0x29,0x01,0x00,0x42,0x0E,0x44,0x45,0x43,0x56,0x43,0x41,0x65,0x49,0x44,0x30,0x30,0x31,0x30,0x32,0x7F,0x49,0x82,0x01,0x1D,0x06,0x0A,0x04,0x00,0x7F,0x00,0x07,0x02,0x02,0x02,0x02,0x03,0x81,0x20,0xA9,0xFB,0x57,0xDB,0xA1,0xEE,0xA9,0xBC,0x3E,0x66,0x0A,0x90,0x9D,0x83,0x8D,0x72,0x6E,0x3B,0xF6,0x23,0xD5,0x26,0x20,0x28,0x20,0x13,0x48,0x1D,0x1F,0x6E,0x53,0x77,0x82,0x20,0x7D,0x5A,0x09,0x75,0xFC,0x2C,0x30,0x57,0xEE,0xF6,0x75,0x30,0x41,0x7A,0xFF,0xE7,0xFB,0x80,0x55,0xC1,0x26,0xDC,0x5C,0x6C,0xE9,0x4A,0x4B,0x44,0xF3,0x30,0xB5,0xD9,0x83,0x20,0x26,0xDC,0x5C,0x6C,0xE9,0x4A,0x4B,0x44,0xF3,0x30,0xB5,0xD9,0xBB,0xD7,0x7C,0xBF,0x95,0x84,0x16,0x29,0x5C,0xF7,0xE1,0xCE,0x6B,0xCC,0xDC,0x18,0xFF,0x8C,0x07,0xB6,0x84,0x41,0x04,0x8B,0xD2,0xAE,0xB9,0xCB,0x7E,0x57,0xCB,0x2C,0x4B,0x48,0x2F,0xFC,0x81,0xB7,0xAF,0xB9,0xDE,0x27,0xE1,0xE3,0xBD,0x23,0xC2,0x3A,0x44,0x53,0xBD,0x9A,0xCE,0x32,0x62,0x54,0x7E,0xF8,0x35,0xC3,0xDA,0xC4,0xFD,0x97,0xF8,0x46,0x1A,0x14,0x61,0x1D,0xC9,0xC2,0x77,0x45,0x13,0x2D,0xED,0x8E,0x54,0x5C,0x1D,0x54,0xC7,0x2F,0x04,0x69,0x97,0x85,0x20,0xA9,0xFB,0x57,0xDB,0xA1,0xEE,0xA9,0xBC,0x3E,0x66,0x0A,0x90,0x9D,0x83,0x8D,0x71,0x8C,0x39,0x7A,0xA3,0xB5,0x61,0xA6,0xF7,0x90,0x1E,0x0E,0x82,0x97,0x48,0x56,0xA7,0x86,0x41,0x04,0x33,0x47,0xEC,0xF9,0x6F,0xFB,0x4B,0xD9,0xB8,0x55,0x4E,0xFB,0xCC,0xFC,0x7D,0x0B,0x24,0x2F,0x10,0x71,0xE2,0x9B,0x4C,0x9C,0x62,0x2C,0x79,0xE3,0x39,0xD8,0x40,0xAF,0x67,0xBE,0xB9,0xB9,0x12,0x69,0x22,0x65,0xD9,0xC1,0x6C,0x62,0x57,0x3F,0x45,0x79,0xFF,0xD4,0xDE,0x2D,0xE9,0x2B,0xAB,0x40,0x9D,0xD5,0xC5,0xD4,0x82,0x44,0xA9,0xF7,0x87,0x01,0x01,0x5F,0x20,0x0E,0x44,0x45,0x43,0x56,0x43,0x41,0x65,0x49,0x44,0x30,0x30,0x31,0x30,0x32,0x7F,0x4C,0x12,0x06,0x09,0x04,0x00,0x7F,0x00,0x07,0x03,0x01,0x02,0x02,0x53,0x05,0xFE,0x0F,0x01,0xFF,0xFF,0x5F,0x25,0x06,0x01,0x00,0x01,0x00,0x01,0x08,0x5F,0x24,0x06,0x01,0x03,0x01,0x00,0x01,0x08,0x5F,0x37,0x40,0x50,0x67,0x14,0x5C,0x68,0xCA,0xE9,0x52,0x0F,0x5B,0xB3,0x48,0x17,0xF1,0xCA,0x9C,0x43,0x59,0x3D,0xB5,0x64,0x06,0xC6,0xA3,0xB0,0x06,0xCB,0xF3,0xF3,0x14,0xE7,0x34,0x9A,0xCF,0x0C,0xC6,0xBF,0xEB,0xCB,0xDE,0xFD,0x10,0xB4,0xDC,0xF0,0xF2,0x31,0xDA,0x56,0x97,0x7D,0x88,0xF9,0xF9,0x01,0x82,0xD1,0x99,0x07,0x6A,0x56,0x50,0x64,0x51 - }; -const uint8_t token_info[] = { - 0x0, 0x1f, - 0x30, 0x1d, 0x2, 0x1, 0x2, 0x4, 0x4, 0x6, 0x0, 0x0, 0x0, 0xc, 0x6, 0x4d, 0x61, 0x6e, 0x75, 0x49, 0x44, 0x80, 0x6, 0x50, 0x61, 0x74, 0x61, 0x74, 0x61, 0x3, 0x2, 0x7, 0x80 -}; - -const pkcs15_entry_t pkcs15_entries[] = { - { .fid = 0x3f00, .parent = 0xff, .name = NULL, .type = FILE_TYPE_DF, .data = NULL, .ef_structure = 0, .acl = {0} }, // MF - { .fid = 0x2f00, .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.DIR - { .fid = 0x2f01, .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.ATR - { .fid = 0x2f02, .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF,.data = t, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.GDO - { .fid = 0x2f03, .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF,.data = token_info, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.TokenInfo - { .fid = 0x5015, .parent = 0, .name = NULL, .type = FILE_TYPE_DF, .data = NULL, .ef_structure = 0, .acl = {0} }, //DF.PKCS15 - { .fid = 0x5031, .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.ODF - { .fid = 0x5032, .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.TokenInfo - { .fid = 0x5033, .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.UnusedSpace - { .fid = 0x0000, .parent = 0, .name = openpgpcard_aid, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, - { .fid = 0x0000, .parent = 0, .name = sc_hsm_aid, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, - { .fid = 0x0000, .parent = 0xff, .name = NULL, .type = FILE_TYPE_UNKNOWN, .data = NULL, .ef_structure = 0, .acl = {0} } //end -}; - -const pkcs15_entry_t *MF = &pkcs15_entries[0]; -const pkcs15_entry_t *pkcs15_last = &pkcs15_entries[sizeof(pkcs15_entries)/sizeof(pkcs15_entry_t)-1]; -const pkcs15_entry_t *pkcs15_openpgp = &pkcs15_entries[sizeof(pkcs15_entries)/sizeof(pkcs15_entry_t)-3]; -const pkcs15_entry_t *pkcs15_sc_hsm = &pkcs15_entries[sizeof(pkcs15_entries)/sizeof(pkcs15_entry_t)-2]; - -extern const pkcs15_entry_t *search_by_fid(const uint16_t, const pkcs15_entry_t *, const uint8_t); - -bool card_terminated = false; - -#define SPECIFY_EF 0x1 -#define SPECIFY_DF 0x2 -#define SPECIFY_ANY 0x3 - -#define MAX_DEPTH 4 - -bool is_parent(const pkcs15_entry_t *child, const pkcs15_entry_t *parent) { - if (child == parent) - return true; - if (child == MF) - return false; - return is_parent(&pkcs15_entries[child->parent], parent); -} - -const pkcs15_entry_t *search_by_name(uint8_t *name, uint16_t namelen) { - for (const pkcs15_entry_t *p = pkcs15_entries; p != pkcs15_last; p++) { - if (p->name && *p->name == apdu.cmd_apdu_data_len && memcmp(p->name+1, name, namelen) == 0) { - return p; - } - } - return NULL; -} - -const pkcs15_entry_t *search_by_fid(const uint16_t fid, const pkcs15_entry_t *parent, const uint8_t sp) { - - for (const pkcs15_entry_t *p = pkcs15_entries; p != pkcs15_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 pkcs15_entry_t *pe, uint8_t *buf, uint8_t buflen, const pkcs15_entry_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(&pkcs15_entries[pe->parent], buf+2, buflen-2, top)+2; -} - -uint8_t make_path(const pkcs15_entry_t *pe, const pkcs15_entry_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(&pkcs15_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; -} - -const pkcs15_entry_t *search_by_path(const uint8_t *pe_path, uint8_t pathlen, const pkcs15_entry_t *parent) { - uint8_t path[MAX_DEPTH*2]; - if (pathlen > sizeof(path)) { - return NULL; - } - for (const pkcs15_entry_t *p = pkcs15_entries; p != pkcs15_last; p++) { - uint8_t depth = make_path(p, parent, path); - if (pathlen == depth && memcmp(path, pe_path, depth)) - return p; - } - return NULL; -} - uint8_t file_selection; -const pkcs15_entry_t *currentEF = NULL; -const pkcs15_entry_t *currentDF = NULL; -const pkcs15_entry_t *selected_applet = NULL; -bool isUserAuthenticated = false; -bool authenticate_action(const pkcs15_entry_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; +static void +gpg_init (void) +{ + const uint8_t *flash_do_start; + const uint8_t *flash_do_end; + + flash_do_storage_init (&flash_do_start, &flash_do_end); + + if (flash_do_start == NULL) + file_selection = FILE_CARD_TERMINATED; + else + file_selection = FILE_NONE; + + gpg_data_scan (flash_do_start, flash_do_end); + flash_key_storage_init (); + multicore_lockout_victim_init(); } -static void gpg_init (void) +static int +gpg_fini (void) { - const uint8_t *flash_do_start; - const uint8_t *flash_do_end; - - flash_do_storage_init (&flash_do_start, &flash_do_end); - - if (flash_do_start == NULL) - card_terminated = true; - - gpg_data_scan (flash_do_start, flash_do_end); - flash_key_storage_init (); - multicore_lockout_victim_init(); -} - -static void gpg_fini (void) -{ - ac_fini (); + ac_fini (); + return 0; } #if defined(PINPAD_SUPPORT) @@ -333,90 +160,85 @@ get_pinpad_input (int msg_code) } #endif -static int cmd_verify (queue_t *ccid_comm) +static void cmd_verify (queue_t *ccid_comm) { - int len; - uint8_t p1 = P1 (apdu); - uint8_t p2 = P2 (apdu); - int r; - const uint8_t *pw; - - (void)ccid_comm; - DEBUG_INFO (" - VERIFY\r\n"); - DEBUG_BYTE (p2); - - len = apdu.cmd_apdu_data_len; - pw = apdu.cmd_apdu_data; - printf("%X %X %X\r\n",selected_applet,pkcs15_openpgp,pkcs15_sc_hsm); - - if (selected_applet == pkcs15_openpgp) { - if (len == 0) - { - if (p1 == 0) - { /* This is to examine status. */ - if (p2 == 0x81) - r = ac_check_status (AC_PSO_CDS_AUTHORIZED); - else if (p2 == 0x82) - r = ac_check_status (AC_OTHER_AUTHORIZED); - else - r = ac_check_status (AC_ADMIN_AUTHORIZED); - - if (r) - /* If authentication done already, return success. */ - return GPG_SUCCESS (); - else - { /* If not, return retry counter, encoded. */ - r = gpg_pw_get_retry_counter (p2); - set_res_sw (0x63, 0xc0 | (r&0x0f)); - } - } - else if (p1 == 0xff) - { /* Reset the status. */ - if (p2 == 0x81) - ac_reset_pso_cds (); - else if (p2 == 0x82) - ac_reset_other (); - else - ac_reset_admin (); - return GPG_SUCCESS (); - } - else - return GPG_BAD_P1_P2 (); - } - - if (gpg_do_kdf_check (len, 1) == 0) - { - return GPG_CONDITION_NOT_SATISFIED (); - } - - /* This is real authentication. */ - if (p2 == 0x81) - r = verify_pso_cds (pw, len); - else if (p2 == 0x82) - r = verify_other (pw, len); - else - r = verify_admin (pw, len); - - if (r < 0) - { - DEBUG_INFO ("failed\r\n"); - return GPG_SECURITY_FAILURE (); - } - else if (r == 0) - { - DEBUG_INFO ("blocked\r\n"); - return GPG_SECURITY_AUTH_BLOCKED (); - } - else - { - DEBUG_INFO ("good\r\n"); - return GPG_SUCCESS (); - } + int len; + uint8_t p1 = P1 (apdu); + uint8_t p2 = P2 (apdu); + int r; + const uint8_t *pw; + + (void)ccid_comm; + DEBUG_INFO (" - VERIFY\r\n"); + DEBUG_BYTE (p2); + + len = apdu.cmd_apdu_data_len; + pw = apdu.cmd_apdu_data; + + if (len == 0) + { + if (p1 == 0) + { /* This is to examine status. */ + if (p2 == 0x81) + r = ac_check_status (AC_PSO_CDS_AUTHORIZED); + else if (p2 == 0x82) + r = ac_check_status (AC_OTHER_AUTHORIZED); + else + r = ac_check_status (AC_ADMIN_AUTHORIZED); + + if (r) + /* If authentication done already, return success. */ + GPG_SUCCESS (); + else + { /* If not, return retry counter, encoded. */ + r = gpg_pw_get_retry_counter (p2); + set_res_sw (0x63, 0xc0 | (r&0x0f)); + } + } + else if (p1 == 0xff) + { /* Reset the status. */ + if (p2 == 0x81) + ac_reset_pso_cds (); + else if (p2 == 0x82) + ac_reset_other (); + else + ac_reset_admin (); + GPG_SUCCESS (); + } + else + GPG_BAD_P1_P2 (); + return; } - else if (selected_applet == pkcs15_sc_hsm) { - return GPG_BAD_P1_P2(); + + if (gpg_do_kdf_check (len, 1) == 0) + { + GPG_CONDITION_NOT_SATISFIED (); + return; + } + + /* This is real authentication. */ + if (p2 == 0x81) + r = verify_pso_cds (pw, len); + else if (p2 == 0x82) + r = verify_other (pw, len); + else + r = verify_admin (pw, len); + + if (r < 0) + { + DEBUG_INFO ("failed\r\n"); + GPG_SECURITY_FAILURE (); + } + else if (r == 0) + { + DEBUG_INFO ("blocked\r\n"); + GPG_SECURITY_AUTH_BLOCKED (); + } + else + { + DEBUG_INFO ("good\r\n"); + GPG_SUCCESS (); } - return 0; } int @@ -959,149 +781,152 @@ gpg_get_firmware_update_key (uint8_t keyno) #define FILEID_CH_CERTIFICATE_IS_VALID 0 #endif -static int cmd_read_binary (queue_t *ccid_comm) +static void +cmd_read_binary (queue_t *ccid_comm) { - uint16_t fid; - uint32_t offset; - uint8_t ins = INS(apdu), p1 = P1(apdu), p2 = P2(apdu); - const pkcs15_entry_t *ef = NULL; - - (void)ccid_comm; - DEBUG_INFO (" - Read binary\r\n"); - - if ((ins & 0x1) == 0) - { - if ((p1 & 0x80) != 0) { - if (!(ef = search_by_fid(p1&0x1f, NULL, SPECIFY_EF))) - return SW_FILE_NOT_FOUND (); - offset = p2; - } - else { - offset = make_uint16_t(p1, p2) & 0x7fff; - ef = currentEF; - } - } - else { - if (p1 == 0 && (p2 & 0xE0) == 0 && (p2 & 0x1f) != 0 && (p2 & 0x1f) != 0x1f) { - if (!(ef = search_by_fid(p2&0x1f, NULL, SPECIFY_EF))) - return SW_FILE_NOT_FOUND (); - } - else { - uint16_t file_id = make_uint16_t(p1, p2) & 0x7fff; - if (file_id == 0x0) - ef = currentEF; - else if (!(ef = search_by_fid(file_id, NULL, SPECIFY_EF))) - return SW_FILE_NOT_FOUND (); - - if (apdu.cmd_apdu_data[0] != 0x54) - return SW_WRONG_DATA(); - - offset = 0; - for (int d = 0; d < apdu.cmd_apdu_data[1]; d++) - offset |= apdu.cmd_apdu_data[2+d]<<(apdu.cmd_apdu_data[1]-1-d)*8; - } - - } - - if (!authenticate_action(ef, ACL_OP_READ_SEARCH)) { - return SW_SECURITY_STATUS_NOT_SATISFIED(); - } - if (ef->data) { - uint16_t data_len = get_uint16_t(ef->data, 0); - if (offset > data_len) - return SW_WRONG_P1P2(); - - uint16_t maxle = data_len-offset; - if (apdu.expected_res_size > maxle) - apdu.expected_res_size = maxle; - res_APDU = ef->data+2+offset; - res_APDU_size = data_len-offset; - } + int is_short_EF = (P1 (apdu) & 0x80) != 0; + uint8_t file_id; + uint16_t offset; - return GPG_SUCCESS (); -} -void select_file(const pkcs15_entry_t *pe) { - if (!pe) + (void)ccid_comm; + DEBUG_INFO (" - Read binary\r\n"); + + if (is_short_EF) + file_id = (P1 (apdu) & 0x1f); + else + file_id = file_selection - FILE_EF_SERIAL_NO + FILEID_SERIAL_NO; + + if (is_short_EF) { - currentDF = MF; - currentEF = NULL; + file_selection = file_id - FILEID_SERIAL_NO + FILE_EF_SERIAL_NO; + offset = P2 (apdu); } - else if (pe->type & FILE_TYPE_INTERNAL_EF) { - currentEF = pe; - currentDF = &pkcs15_entries[pe->parent]; + else + offset = (P1 (apdu) << 8) | P2 (apdu); + + if (file_id == FILEID_SERIAL_NO) + { + if (offset != 0) + GPG_BAD_P1_P2 (); + else + { + gpg_do_get_data (0x004f, 1); /* Get AID... */ + res_APDU[0] = 0x5a; /* ... and overwrite the first byte of data. */ + } + return; } - else { - currentDF = pe; +#ifdef FLASH_UPGRADE_SUPPORT + else if (file_id >= FILEID_UPDATE_KEY_0 && file_id <= FILEID_UPDATE_KEY_3) + { + if (offset != 0) + GPG_MEMORY_FAILURE (); + else + { + const uint8_t *p; + + p = gpg_get_firmware_update_key (file_id - FILEID_UPDATE_KEY_0); + res_APDU_size = FIRMWARE_UPDATE_KEY_CONTENT_LEN; + memcpy (res_APDU, p, FIRMWARE_UPDATE_KEY_CONTENT_LEN); + GPG_SUCCESS (); + } + } +#endif +#if defined(CERTDO_SUPPORT) + else if (file_id == FILEID_CH_CERTIFICATE) + { + const uint8_t *p; + uint16_t len = 256; + + p = ch_certificate_start; + if (offset >= FLASH_CH_CERTIFICATE_SIZE) + GPG_MEMORY_FAILURE (); + else + { + if (offset + len >= FLASH_CH_CERTIFICATE_SIZE) + len = FLASH_CH_CERTIFICATE_SIZE - offset; + + res_APDU_size = len; + memcpy (res_APDU, p + offset, len); + GPG_SUCCESS (); + } + } +#endif + else + { + GPG_NO_FILE (); + return; } - if (currentEF == pkcs15_openpgp || currentEF == pkcs15_sc_hsm) - selected_applet = currentEF; } -static uint16_t cmd_select_file (queue_t *ccid_comm) + +static void +cmd_select_file (queue_t *ccid_comm) { - (void)ccid_comm; - uint8_t p1 = P1(apdu); - uint8_t p2 = P2(apdu); - const pkcs15_entry_t *pe = NULL; - uint16_t fid = 0x0; - - // Only "first or only occurence" supported - //if ((p2 & 0xF3) != 0x00) { - // return SW_INCORRECT_P1P2(); - //} - - if (apdu.cmd_apdu_data_len >= 2) - fid = get_uint16_t(apdu.cmd_apdu_data, 0); - - if (p1 == 0x0) { //Select MF, DF or EF - File identifier or absent - if (apdu.cmd_apdu_data_len == 0) { - pe = MF; - ac_fini(); - } - else if (apdu.cmd_apdu_data_len == 2) { - if (!(pe = search_by_fid(fid, NULL, SPECIFY_ANY))) { - return GPG_NO_FILE (); - } - } + (void)ccid_comm; + if (P1 (apdu) == 4) /* Selection by DF name */ + { + DEBUG_INFO (" - select DF by name\r\n"); + + /* name = D2 76 00 01 24 01 */ + if (apdu.cmd_apdu_data_len != 6 + || memcmp (openpgpcard_aid, apdu.cmd_apdu_data, 6) != 0) + { + DEBUG_SHORT (apdu.cmd_apdu_data_len); + DEBUG_BINARY (apdu.cmd_apdu_data, apdu.cmd_apdu_data_len); + + GPG_NO_FILE (); + return; + } + + if (file_selection == FILE_CARD_TERMINATED) + { + GPG_APPLICATION_TERMINATED (); + return; + } + + file_selection = FILE_DF_OPENPGP; + + /* Behave just like original OpenPGP card. */ + GPG_SUCCESS (); } - else if (p1 == 0x01) { //Select child DF - DF identifier - if (!(pe = search_by_fid(fid, currentDF, SPECIFY_DF))) { - return GPG_NO_FILE (); - } + else if (apdu.cmd_apdu_data_len == 2 + && apdu.cmd_apdu_data[0] == 0x2f && apdu.cmd_apdu_data[1] == 0x02) + { + DEBUG_INFO (" - select 0x2f02 EF\r\n"); + /* + * MF.EF-GDO -- Serial number of the card and name of the owner + */ + GPG_SUCCESS (); + file_selection = FILE_EF_SERIAL_NO; } - else if (p1 == 0x02) { //Select EF under the current DF - EF identifier - if (!(pe = search_by_fid(fid, currentDF, SPECIFY_EF))) { - return GPG_NO_FILE (); - } + else if (apdu.cmd_apdu_data_len == 2 + && apdu.cmd_apdu_data[0] == 0x3f && apdu.cmd_apdu_data[1] == 0x00) + { + DEBUG_INFO (" - select ROOT MF\r\n"); + if (P2 (apdu) == 0x0c) + { + GPG_SUCCESS (); + } + else + { + int len = sizeof (select_file_TOP_result); + + res_APDU_size = len; + memcpy (res_APDU, select_file_TOP_result, len); + res_APDU[2] = (data_objects_number_of_bytes & 0xff); + res_APDU[3] = (data_objects_number_of_bytes >> 8); + GPG_SUCCESS (); + } + + file_selection = FILE_MF; + ac_fini (); /* Reset authentication */ } - else if (p1 == 0x03) { //Select parent DF of the current DF - Absent - if (apdu.cmd_apdu_data_len != 0) - return GPG_NO_FILE (); + else + { + DEBUG_INFO (" - select ?? \r\n"); + + file_selection = FILE_NONE; + GPG_NO_FILE (); } - else if (p1 == 0x04) { //Select by DF name - e.g., [truncated] application identifier - if (!(pe = search_by_name(apdu.cmd_apdu_data, apdu.cmd_apdu_data_len))) { - return GPG_NO_FILE (); - } - if (card_terminated) { - return GPG_APPLICATION_TERMINATED (); - } - } - else if (p1 == 0x08) { //Select from the MF - Path without the MF identifier - if (!(pe = search_by_path(apdu.cmd_apdu_data, apdu.cmd_apdu_data_len, MF))) { - return GPG_NO_FILE (); - } - } - else if (p1 == 0x09) { //Select from the current DF - Path without the current DF identifier - if (!(pe = search_by_path(apdu.cmd_apdu_data, apdu.cmd_apdu_data_len, currentDF))) { - return GPG_NO_FILE (); - } - } - if ((p2 & 0xfc) == 0x00 || (p2 & 0xfc) == 0x04) { - process_fci(pe); - } - else - return SW_INCORRECT_P1P2(); - select_file(pe); - return GPG_SUCCESS (); } static void @@ -1541,6 +1366,7 @@ modify_binary (uint8_t op, uint8_t p1, uint8_t p2, int len) } + #if defined(CERTDO_SUPPORT) static void cmd_update_binary (queue_t *ccid_comm) @@ -1606,7 +1432,7 @@ cmd_external_authenticate (queue_t *ccid_comm) return; } - eventflag_signal (openpgp_comm, EV_EXIT); /* signal to self. */ + //eventflag_signal (openpgp_comm, EV_EXIT); /* signal to self. */ set_res_sw (0xff, 0xff); DEBUG_INFO ("EXTERNAL AUTHENTICATE done.\r\n"); } @@ -1659,8 +1485,7 @@ cmd_activate_file (queue_t *ccid_comm) } flash_activate (); - //file_selection = FILE_DF_OPENPGP; - file_selection = FILE_DF_SC_HSM; + file_selection = FILE_DF_OPENPGP; GPG_SUCCESS (); } @@ -1672,8 +1497,7 @@ cmd_terminate_df (queue_t *ccid_comm) uint8_t p2 = P2 (apdu); (void)ccid_comm; - //if (file_selection != FILE_DF_OPENPGP) - if (file_selection != FILE_DF_SC_HSM) + if (file_selection != FILE_DF_OPENPGP) { GPG_NO_RECORD (); return; @@ -1716,42 +1540,41 @@ cmd_terminate_df (queue_t *ccid_comm) struct command { uint8_t command; - void (*cmd_handler) (queue_t *ccid_comm); + void (*cmd_handler) (); }; const struct command cmds[] = { - { INS_VERIFY, cmd_verify }, - { INS_CHANGE_REFERENCE_DATA, cmd_change_password }, - { INS_PSO, cmd_pso }, - { INS_RESET_RETRY_COUNTER, cmd_reset_user_password }, -#ifdef LIFE_CYCLE_MANAGEMENT_SUPPORT - { INS_ACTIVATE_FILE, cmd_activate_file }, -#endif - { INS_PGP_GENERATE_ASYMMETRIC_KEY_PAIR, cmd_pgp_gakp }, -#ifdef FLASH_UPGRADE_SUPPORT - { INS_EXTERNAL_AUTHENTICATE, /* Not in OpenPGP card protocol */ + { INS_VERIFY, cmd_verify }, + { INS_CHANGE_REFERENCE_DATA, cmd_change_password }, + { INS_PSO, cmd_pso }, + { INS_RESET_RETRY_COUNTER, cmd_reset_user_password }, + #ifdef LIFE_CYCLE_MANAGEMENT_SUPPORT + { INS_ACTIVATE_FILE, cmd_activate_file }, + #endif + { INS_PGP_GENERATE_ASYMMETRIC_KEY_PAIR, cmd_pgp_gakp }, + #ifdef FLASH_UPGRADE_SUPPORT + { INS_EXTERNAL_AUTHENTICATE, /* Not in OpenPGP card protocol */ cmd_external_authenticate }, -#endif - { INS_GET_CHALLENGE, cmd_get_challenge }, /* Not in OpenPGP card protocol */ - { INS_INTERNAL_AUTHENTICATE, cmd_internal_authenticate }, - { INS_SELECT_FILE, cmd_select_file }, - { INS_READ_BINARY, cmd_read_binary }, /* Not in OpenPGP card protocol */ - { INS_READ_BINARY_ODD, cmd_read_binary }, /* Not in OpenPGP card protocol */ - { INS_GET_DATA, cmd_get_data }, - { INS_WRITE_BINARY, cmd_write_binary}, /* Not in OpenPGP card protocol */ -#if defined(CERTDO_SUPPORT) - { INS_UPDATE_BINARY, cmd_update_binary }, /* Not in OpenPGP card protocol */ -#endif - { INS_PUT_DATA, cmd_put_data }, - { INS_PUT_DATA_ODD, cmd_put_data }, -#ifdef LIFE_CYCLE_MANAGEMENT_SUPPORT - { INS_TERMINATE_DF, cmd_terminate_df}, -#endif + #endif + { INS_GET_CHALLENGE, cmd_get_challenge }, /* Not in OpenPGP card protocol */ + { INS_INTERNAL_AUTHENTICATE, cmd_internal_authenticate }, + { INS_SELECT_FILE, cmd_select_file }, + { INS_READ_BINARY, cmd_read_binary }, /* Not in OpenPGP card protocol */ + { INS_READ_BINARY_ODD, cmd_read_binary }, /* Not in OpenPGP card protocol */ + { INS_GET_DATA, cmd_get_data }, + { INS_WRITE_BINARY, cmd_write_binary}, /* Not in OpenPGP card protocol */ + #if defined(CERTDO_SUPPORT) + { INS_UPDATE_BINARY, cmd_update_binary }, /* Not in OpenPGP card protocol */ + #endif + { INS_PUT_DATA, cmd_put_data }, + { INS_PUT_DATA_ODD, cmd_put_data }, + #ifdef LIFE_CYCLE_MANAGEMENT_SUPPORT + { INS_TERMINATE_DF, cmd_terminate_df}, + #endif }; #define NUM_CMDS ((int)(sizeof (cmds) / sizeof (struct command))) -static void -process_command_apdu (queue_t *ccid_comm) +int openpgp_process_apdu() { int i; uint8_t cmd = INS (apdu); @@ -1774,7 +1597,7 @@ process_command_apdu (queue_t *ccid_comm) GPG_NO_RECORD (); else { - cmds[i].cmd_handler (ccid_comm); + cmds[i].cmd_handler (); } } else @@ -1785,112 +1608,3 @@ process_command_apdu (queue_t *ccid_comm) } } -void openpgp_card_thread () -{ - queue_t *ccid_comm = (queue_t *)multicore_fifo_pop_blocking(); - openpgp_comm = (queue_t *)multicore_fifo_pop_blocking(); - - gpg_init (); - - while (1) - { -#if defined(PINPAD_SUPPORT) - int len, pw_len, newpw_len; -#endif - - uint32_t m; - queue_remove_blocking(openpgp_comm, &m); - - DEBUG_INFO ("GPG!: "); - - if (m == EV_VERIFY_CMD_AVAILABLE) - { -#if defined(PINPAD_SUPPORT) - if (INS (apdu) != INS_VERIFY) - { - GPG_CONDITION_NOT_SATISFIED (); - goto done; - } - - pw_len = get_pinpad_input (PIN_INPUT_CURRENT); - if (pw_len < 0) - { - GPG_ERROR (); - goto done; - } - memcpy (apdu.cmd_apdu_data, pin_input_buffer, pw_len); - apdu.cmd_apdu_data_len = pw_len; -#else - GPG_ERROR (); - goto done; -#endif - } - else if (m == EV_MODIFY_CMD_AVAILABLE) - { -#if defined(PINPAD_SUPPORT) - uint8_t bConfirmPIN = apdu.cmd_apdu_data[0]; - uint8_t *p = apdu.cmd_apdu_data; - - if (INS (apdu) != INS_CHANGE_REFERENCE_DATA - && INS (apdu) != INS_RESET_RETRY_COUNTER - && INS (apdu) != INS_PUT_DATA) - { - GPG_CONDITION_NOT_SATISFIED (); - goto done; - } - - if ((bConfirmPIN & 2)) /* Require old PIN */ - { - pw_len = get_pinpad_input (PIN_INPUT_CURRENT); - if (pw_len < 0) - { - GPG_ERROR (); - goto done; - } - memcpy (p, pin_input_buffer, pw_len); - p += pw_len; - } - else - pw_len = 0; - - newpw_len = get_pinpad_input (PIN_INPUT_NEW); - if (newpw_len < 0) - { - GPG_ERROR (); - goto done; - } - memcpy (p, pin_input_buffer, newpw_len); - - if ((bConfirmPIN & 1)) /* New PIN twice */ - { - len = get_pinpad_input (PIN_INPUT_CONFIRM); - if (len < 0) - { - GPG_ERROR (); - goto done; - } - - if (len != newpw_len || memcmp (p, pin_input_buffer, len) != 0) - { - GPG_SECURITY_FAILURE (); - goto done; - } - } - - apdu.cmd_apdu_data_len = pw_len + newpw_len; -#else - GPG_ERROR (); - goto done; -#endif - } - else if (m == EV_EXIT) - break; - - process_command_apdu (ccid_comm); - done:; - uint32_t flag = EV_EXEC_FINISHED; - queue_add_blocking(ccid_comm, &flag); - } - - gpg_fini (); -} diff --git a/random.c b/random.c index d51992c..1c37d7c 100644 --- a/random.c +++ b/random.c @@ -31,93 +31,87 @@ #define RANDOM_BYTES_LENGTH 32 static uint32_t random_word[RANDOM_BYTES_LENGTH/sizeof (uint32_t)]; -void -random_init (void) +void random_init (void) { - int i; + int i; - neug_init (random_word, RANDOM_BYTES_LENGTH/sizeof (uint32_t)); + neug_init (random_word, RANDOM_BYTES_LENGTH/sizeof (uint32_t)); - for (i = 0; i < NEUG_PRE_LOOP; i++) - (void)neug_get (NEUG_KICK_FILLING); + for (i = 0; i < NEUG_PRE_LOOP; i++) + neug_get (NEUG_KICK_FILLING); } -void -random_fini (void) +void random_fini (void) { - neug_fini (); + neug_fini (); } /* * Return pointer to random 32-byte */ -const uint8_t * -random_bytes_get (void) +const uint8_t * random_bytes_get (void) { - static uint32_t return_word[RANDOM_BYTES_LENGTH/sizeof (uint32_t)]; - neug_wait_full (); - memcpy(return_word, random_word, sizeof(return_word)); - return (const uint8_t *)return_word; + static uint32_t return_word[RANDOM_BYTES_LENGTH/sizeof (uint32_t)]; + neug_wait_full (); + memcpy(return_word, random_word, sizeof(return_word)); + return (const uint8_t *)return_word; } /* * Free pointer to random 32-byte */ -void -random_bytes_free (const uint8_t *p) +void random_bytes_free (const uint8_t *p) { - (void)p; - memset (random_word, 0, RANDOM_BYTES_LENGTH); - neug_flush (); + (void)p; + memset (random_word, 0, RANDOM_BYTES_LENGTH); + neug_flush (); } /* * Return 4-byte salt */ -void -random_get_salt (uint8_t *p) +void random_get_salt (uint8_t *p) { - uint32_t rnd; + uint32_t rnd; - rnd = neug_get (NEUG_KICK_FILLING); - memcpy (p, &rnd, sizeof (uint32_t)); - rnd = neug_get (NEUG_KICK_FILLING); - memcpy (p + sizeof (uint32_t), &rnd, sizeof (uint32_t)); + rnd = neug_get (NEUG_KICK_FILLING); + memcpy (p, &rnd, sizeof (uint32_t)); + rnd = neug_get (NEUG_KICK_FILLING); + memcpy (p + sizeof (uint32_t), &rnd, sizeof (uint32_t)); } /* * Random byte iterator */ -int -random_gen (void *arg, unsigned char *out, size_t out_len) +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; + uint8_t *index_p = (uint8_t *)arg; + uint8_t index = index_p ? *index_p : 0; + size_t n; - while (out_len) + while (out_len) { - neug_wait_full (); + neug_wait_full (); - n = RANDOM_BYTES_LENGTH - index; - if (n > out_len) - n = out_len; + 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; + 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 >= RANDOM_BYTES_LENGTH) + { + index = 0; + neug_flush (); + } } - if (index_p) - *index_p = index; + if (index_p) + *index_p = index; - return 0; + return 0; } diff --git a/sc_hsm.c b/sc_hsm.c new file mode 100644 index 0000000..7c8cbf7 --- /dev/null +++ b/sc_hsm.c @@ -0,0 +1,229 @@ +#include "sc_hsm.h" +#include "file.h" +#include "libopensc/card-sc-hsm.h" + +const uint8_t sc_hsm_aid[] = { + 11, + 0xE8,0x2B,0x06,0x01,0x04,0x01,0x81,0xC3,0x1F,0x02,0x01 +}; + +static int sc_hsm_process_apdu(); + +static void init_sc_hsm(); + +app_t *sc_hsm_select_aid(app_t *a) { + if (!memcmp(apdu.cmd_apdu_data, sc_hsm_aid+1, MIN(apdu.cmd_apdu_data_len,sc_hsm_aid[0]))) { + a->aid = sc_hsm_aid; + a->process_apdu = sc_hsm_process_apdu; + init_sc_hsm(); + return a; + } + return NULL; +} + +void __attribute__ ((constructor)) sc_hsm_ctor() { + register_app(sc_hsm_select_aid); +} + +void init_sc_hsm() { + scan_flash(); +} + +static int cmd_verify() { + uint8_t p1 = P1(apdu); + uint8_t p2 = P2(apdu); + + if (p1 != 0x0 || (p2 & 0x60) != 0x0) + return SW_WRONG_P1P2(); + uint8_t qualifier = p2&0x1f; + if (p2 == 0x81) { //UserPin + if (!file_retries_pin1) { + return SW_REFERENCE_NOT_FOUND(); + } + return set_res_sw (0x63, 0xc0 | file_retries_pin1->data[2]); + } + else if (p2 == 0x88) { //SOPin + } + return SW_REFERENCE_NOT_FOUND(); +} + + +void select_file(file_t *pe) { + if (!pe) + { + currentDF = (file_t *)MF; + currentEF = NULL; + } + else if (pe->type & FILE_TYPE_INTERNAL_EF) { + currentEF = pe; + currentDF = &file_entries[pe->parent]; + } + else { + currentDF = pe; + } + if (currentEF == file_openpgp || currentEF == file_sc_hsm) + selected_applet = currentEF; +} +static int cmd_select() { + uint8_t p1 = P1(apdu); + uint8_t p2 = P2(apdu); + file_t *pe = NULL; + uint16_t fid = 0x0; + + // Only "first or only occurence" supported + //if ((p2 & 0xF3) != 0x00) { + // return SW_INCORRECT_P1P2(); + //} + + if (apdu.cmd_apdu_data_len >= 2) + fid = get_uint16_t(apdu.cmd_apdu_data, 0); + + if (p1 == 0x0) { //Select MF, DF or EF - File identifier or absent + if (apdu.cmd_apdu_data_len == 0) { + pe = (file_t *)MF; + //ac_fini(); + } + else if (apdu.cmd_apdu_data_len == 2) { + if (!(pe = search_by_fid(fid, NULL, SPECIFY_ANY))) { + return SW_FILE_NOT_FOUND(); + } + } + } + else if (p1 == 0x01) { //Select child DF - DF identifier + if (!(pe = search_by_fid(fid, currentDF, SPECIFY_DF))) { + return SW_FILE_NOT_FOUND(); + } + } + else if (p1 == 0x02) { //Select EF under the current DF - EF identifier + if (!(pe = search_by_fid(fid, currentDF, SPECIFY_EF))) { + return SW_FILE_NOT_FOUND(); + } + } + else if (p1 == 0x03) { //Select parent DF of the current DF - Absent + if (apdu.cmd_apdu_data_len != 0) + return SW_FILE_NOT_FOUND(); + } + else if (p1 == 0x04) { //Select by DF name - e.g., [truncated] application identifier + if (!(pe = search_by_name(apdu.cmd_apdu_data, apdu.cmd_apdu_data_len))) { + return SW_FILE_NOT_FOUND(); + } + if (card_terminated) { + return set_res_sw (0x62, 0x85); + } + } + else if (p1 == 0x08) { //Select from the MF - Path without the MF identifier + if (!(pe = search_by_path(apdu.cmd_apdu_data, apdu.cmd_apdu_data_len, MF))) { + return SW_FILE_NOT_FOUND(); + } + } + else if (p1 == 0x09) { //Select from the current DF - Path without the current DF identifier + if (!(pe = search_by_path(apdu.cmd_apdu_data, apdu.cmd_apdu_data_len, currentDF))) { + return SW_FILE_NOT_FOUND(); + } + } + if ((p2 & 0xfc) == 0x00 || (p2 & 0xfc) == 0x04) { + process_fci(pe); + } + else + return SW_INCORRECT_P1P2(); + select_file(pe); + return SW_OK (); +} + + +static int cmd_list_keys() +{ + static uint16_t r[] = { KEY_PREFIX | 0x100, KEY_PREFIX | 0x200, DCOD_PREFIX | 0x100, CD_PREFIX | 0x300 }; + res_APDU = (uint8_t *)r; + res_APDU_size = sizeof(r); + return SW_OK(); +} + +static int cmd_read_binary() +{ + uint16_t fid; + uint32_t offset; + uint8_t ins = INS(apdu), p1 = P1(apdu), p2 = P2(apdu); + const file_t *ef = NULL; + + DEBUG_INFO (" - Read binary\r\n"); + + if ((ins & 0x1) == 0) + { + if ((p1 & 0x80) != 0) { + if (!(ef = search_by_fid(p1&0x1f, NULL, SPECIFY_EF))) + return SW_FILE_NOT_FOUND (); + offset = p2; + } + else { + offset = make_uint16_t(p1, p2) & 0x7fff; + ef = currentEF; + } + } + else { + if (p1 == 0 && (p2 & 0xE0) == 0 && (p2 & 0x1f) != 0 && (p2 & 0x1f) != 0x1f) { + if (!(ef = search_by_fid(p2&0x1f, NULL, SPECIFY_EF))) + return SW_FILE_NOT_FOUND (); + } + else { + uint16_t file_id = make_uint16_t(p1, p2) & 0x7fff; + if (file_id == 0x0) + ef = currentEF; + else if (!(ef = search_by_fid(file_id, NULL, SPECIFY_EF))) + return SW_FILE_NOT_FOUND (); + + if (apdu.cmd_apdu_data[0] != 0x54) + return SW_WRONG_DATA(); + + offset = 0; + for (int d = 0; d < apdu.cmd_apdu_data[1]; d++) + offset |= apdu.cmd_apdu_data[2+d]<<(apdu.cmd_apdu_data[1]-1-d)*8; + } + + } + + if (!authenticate_action(ef, ACL_OP_READ_SEARCH)) { + return SW_SECURITY_STATUS_NOT_SATISFIED(); + } + if (ef->data) { + uint16_t data_len = get_uint16_t(ef->data, 0); + if (offset > data_len) + return SW_WRONG_P1P2(); + + uint16_t maxle = data_len-offset; + if (apdu.expected_res_size > maxle) + apdu.expected_res_size = maxle; + res_APDU = ef->data+2+offset; + res_APDU_size = data_len-offset; + } + + return SW_OK(); +} + +typedef struct cmd +{ + uint8_t ins; + int (*cmd_handler)(); +} cmd_t; + +#define INS_SELECT_FILE 0xA4 +#define INS_READ_BINARY 0xB0 +#define INS_READ_BINARY_ODD 0xB1 +#define INS_VERIFY 0x20 + +static const cmd_t cmds[] = { + { INS_SELECT_FILE, cmd_select }, + { 0x58, cmd_list_keys }, + { INS_READ_BINARY, cmd_read_binary }, + { INS_READ_BINARY_ODD, cmd_read_binary }, + { INS_VERIFY, cmd_verify }, + { 0x00, 0x0} +}; + +int sc_hsm_process_apdu() { + for (const cmd_t *cmd = cmds; cmd->ins != 0x00; cmd++) { + if (cmd->ins == INS(apdu)) + return cmd->cmd_handler(); + } + return SW_INS_NOT_SUPPORTED(); +} \ No newline at end of file diff --git a/sc_hsm.h b/sc_hsm.h new file mode 100644 index 0000000..f151e4b --- /dev/null +++ b/sc_hsm.h @@ -0,0 +1,35 @@ +#ifndef _SC_HSM_H_ +#define _SC_HSM_H_ + +#include +#include "pico/stdlib.h" +#include "hsm2040.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_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_SECURITY_STATUS_NOT_SATISFIED() set_res_sw (0x69, 0x82) +#define SW_FILE_INVALID () 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_APPLET_SELECT_FAILED() set_res_sw (0x69, 0x99) +#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_INCORRECT_P1P2() set_res_sw (0x6A, 0x86) +#define SW_REFERENCE_NOT_FOUND() set_res_sw (0x6A, 0x88) +#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) + +#endif \ No newline at end of file diff --git a/status-code.h b/status-code.h index 9943279..79e9ec1 100644 --- a/status-code.h +++ b/status-code.h @@ -1,36 +1,14 @@ -#define SW_BYTES_REMAINING_00() set_res_sw (0x61, 0x00) -#define SW_WARNING_STATE_UNCHANGED() set_res_sw (0x62, 0x00) -#define GPG_APPLICATION_TERMINATED() set_res_sw (0x62, 0x85) -#define GPG_MEMORY_FAILURE() set_res_sw (0x65, 0x81) -#define GPG_WRONG_LENGTH() set_res_sw (0x67, 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 GPG_SECURITY_FAILURE() set_res_sw (0x69, 0x82) -#define SW_SECURITY_STATUS_NOT_SATISFIED() set_res_sw (0x69, 0x82) -#define GPG_SECURITY_AUTH_BLOCKED() set_res_sw (0x69, 0x83) -#define SW_FILE_INVALID () set_res_sw (0x69, 0x83) -#define SW_DATA_INVALID () set_res_sw (0x69, 0x84) -#define GPG_CONDITION_NOT_SATISFIED() set_res_sw (0x69, 0x85) -#define SW_CONDITIONS_NOT_SATISFIED set_res_sw (0x69, 0x85) -#define GPG_COMMAND_NOT_ALLOWED() set_res_sw (0x69, 0x86) -#define SW_COMMAND_NOT_ALLOWED() set_res_sw (0x69, 0x86) -#define SW_APPLET_SELECT_FAILED() set_res_sw (0x69, 0x99) -#define GPG_FUNCTION_NOT_SUPPORTED() set_res_sw (0x6a, 0x81) -#define SW_FUNC_NOT_SUPPORTED() set_res_sw (0x6A, 0x81) -#define GPG_NO_FILE() set_res_sw (0x6a, 0x82) -#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_INCORRECT_P1P2() set_res_sw (0x6A, 0x86) -#define GPG_NO_RECORD() set_res_sw (0x6a, 0x88) -#define GPG_BAD_P1_P2() set_res_sw (0x6b, 0x00) -#define SW_WRONG_P1P2() set_res_sw (0x6B, 0x00) -#define SW_CORRECT_LENGTH_00() set_res_sw (0x6C, 0x00) -#define GPG_NO_INS() set_res_sw (0x6d, 0x00) -#define SW_INS_NOT_SUPPORTED() set_res_sw (0x6D, 0x00) -#define SW_CLA_NOT_SUPPORTED() set_res_sw (0x6E, 0x00) -#define GPG_ERROR() set_res_sw (0x6f, 0x00) -#define SW_UNKNOWN() set_res_sw (0x6F, 0x00) -#define GPG_SUCCESS() set_res_sw (0x90, 0x00) +#define GPG_APPLICATION_TERMINATED() set_res_sw (0x62, 0x85) +#define GPG_MEMORY_FAILURE() set_res_sw (0x65, 0x81) +#define GPG_WRONG_LENGTH() set_res_sw (0x67, 0x00) +#define GPG_SECURITY_FAILURE() set_res_sw (0x69, 0x82) +#define GPG_SECURITY_AUTH_BLOCKED() set_res_sw (0x69, 0x83) +#define GPG_CONDITION_NOT_SATISFIED() set_res_sw (0x69, 0x85) +#define GPG_COMMAND_NOT_ALLOWED() set_res_sw (0x69, 0x86) +#define GPG_FUNCTION_NOT_SUPPORTED() set_res_sw (0x6a, 0x81) +#define GPG_NO_FILE() set_res_sw (0x6a, 0x82) +#define GPG_NO_RECORD() set_res_sw (0x6a, 0x88) +#define GPG_BAD_P1_P2() set_res_sw (0x6b, 0x00) +#define GPG_NO_INS() set_res_sw (0x6d, 0x00) +#define GPG_ERROR() set_res_sw (0x6f, 0x00) +#define GPG_SUCCESS() set_res_sw (0x90, 0x00) \ No newline at end of file