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 <pol.henarejos@cttc.es>
This commit is contained in:
Pol Henarejos
2022-02-13 01:17:14 +01:00
parent 210fa98ca4
commit 0017284103
19 changed files with 1910 additions and 966 deletions

View File

@@ -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)

1
ac.c
View File

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

View File

@@ -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;

87
file.c
View File

@@ -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

1
file.h
View File

@@ -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[];

16
flash.c
View File

@@ -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");
}

763
flash_openpgp.c Normal file
View File

@@ -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 <gniibe@fsij.org>
*
* 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 <http://www.gnu.org/licenses/>.
*
*/
/*
* 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 <stdint.h>
#include <string.h>
#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
* <alignment to page>
* 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
* <two pages>
*/
#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;
}
}

63
gnuk.h
View File

@@ -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

182
hsm2040.c
View File

@@ -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;

View File

@@ -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

View File

@@ -9,6 +9,7 @@
#include "pico/sem.h"
#include "pico/multicore.h"
#include "gnuk.h"
#include "hsm2040.h"
#include <string.h>
#define TOTAL_FLASH_PAGES 4

225
neug.c
View File

@@ -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 ();
}

19
neug.h
View File

@@ -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);

View File

@@ -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");
}

852
openpgp.c
View File

@@ -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 ();
}

View File

@@ -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;
}

229
sc_hsm.c Normal file
View File

@@ -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();
}

35
sc_hsm.h Normal file
View File

@@ -0,0 +1,35 @@
#ifndef _SC_HSM_H_
#define _SC_HSM_H_
#include <stdlib.h>
#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

View File

@@ -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)