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) 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 target_sources(hsm2040 PUBLIC
${CMAKE_CURRENT_LIST_DIR}/hsm2040.c ${CMAKE_CURRENT_LIST_DIR}/hsm2040.c
${CMAKE_CURRENT_LIST_DIR}/usb_descriptors.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}/ac.c
${CMAKE_CURRENT_LIST_DIR}/file.c ${CMAKE_CURRENT_LIST_DIR}/file.c
${CMAKE_CURRENT_LIST_DIR}/flash.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}/low_flash.c
${CMAKE_CURRENT_LIST_DIR}/call-rsa.c ${CMAKE_CURRENT_LIST_DIR}/call-rsa.c
${CMAKE_CURRENT_LIST_DIR}/call-ec_p256k1.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}/oid.c
${CMAKE_CURRENT_LIST_DIR}/rsa_alt_helpers.c ${CMAKE_CURRENT_LIST_DIR}/rsa_alt_helpers.c
${CMAKE_CURRENT_LIST_DIR}/constant_time.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 target_include_directories(hsm2040 PUBLIC
${CMAKE_CURRENT_LIST_DIR}) ${CMAKE_CURRENT_LIST_DIR}
${CMAKE_CURRENT_LIST_DIR}/opensc/src
)
pico_add_extra_outputs(hsm2040) pico_add_extra_outputs(hsm2040)
target_link_libraries(hsm2040 PRIVATE pico_stdlib tinyusb_device tinyusb_board pico_multicore hardware_flash hardware_sync hardware_adc) 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 "gnuk.h"
#include "mbedtls/sha256.h" #include "mbedtls/sha256.h"
#include "random.h" #include "random.h"
#include "hsm2040.h"
uint8_t volatile auth_status; /* Initialized to AC_NONE_AUTHORIZED */ uint8_t volatile auth_status; /* Initialized to AC_NONE_AUTHORIZED */

View File

@@ -36,6 +36,7 @@
#include "random.h" #include "random.h"
//#include "polarssl/config.h" //#include "polarssl/config.h"
#include "mbedtls/rsa.h" #include "mbedtls/rsa.h"
#include "hsm2040.h"
static mbedtls_rsa_context rsa_ctx; static mbedtls_rsa_context rsa_ctx;
//static struct chx_cleanup clp; //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 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[] = { file_t file_entries[] = {
{ .fid = 0x3f00, .parent = 0xff, .name = NULL, .type = FILE_TYPE_DF, .data = NULL, .ef_structure = 0, .acl = {0} }, // MF /* 0 */ { .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 /* 1 */ { .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 /* 2 */ { .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 /* 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
{ .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 /* 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
{ .fid = 0x5015, .parent = 0, .name = NULL, .type = FILE_TYPE_DF, .data = NULL, .ef_structure = 0, .acl = {0} }, //DF.PKCS15 /* 5 */ { .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 /* 6 */ { .fid = 0x5031, .parent = 5, .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 /* 7 */ { .fid = 0x5032, .parent = 5, .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 /* 8 */ { .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) /* 9 */ { .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) /* 10 */ { .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) /* 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)
{ .fid = 0x1086, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff} }, //retries PIN 0x6 (SOPIN) /* 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)
{ .fid = 0x0000, .parent = 0, .name = openpgpcard_aid, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, /* 13 */ { .fid = 0x6040, .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.PrKDFs
{ .fid = 0x0000, .parent = 0, .name = sc_hsm_aid, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, /* 14 */ { .fid = 0x6041, .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.PuKDFs
{ .fid = 0x0000, .parent = 0xff, .name = NULL, .type = FILE_TYPE_UNKNOWN, .data = NULL, .ef_structure = 0, .acl = {0} } //end /* 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]; 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; return NULL;
} }
uint8_t file_selection;
file_t *currentEF = NULL; file_t *currentEF = NULL;
file_t *currentDF = NULL; file_t *currentDF = NULL;
const file_t *selected_applet = NULL; const file_t *selected_applet = NULL;
@@ -174,6 +181,9 @@ bool authenticate_action(const file_t *ef, uint8_t op) {
return false; return false;
} }
#include "libopensc/pkcs15.h"
void scan_flash() { void scan_flash() {
if (*(uintptr_t *)end_data_pool == 0xffffffff && *(uintptr_t *)(end_data_pool+sizeof(uintptr_t)) == 0xffffffff) 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(); //wait_flash_finish();
} }
printf("SCAN\r\n"); 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); 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)) { 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 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 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 bool authenticate_action(const file_t *ef, uint8_t op);
extern void process_fci(const file_t *pe); extern void process_fci(const file_t *pe);
extern void scan_flash();
extern file_t file_entries[]; 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_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_halfword (uintptr_t addr, uint16_t data);
extern int flash_program_uintptr(uintptr_t, uintptr_t); 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(); extern void low_flash_available();
@@ -118,7 +120,7 @@ uintptr_t allocate_free_addr(uint16_t size) {
} }
int flash_clear_file(file_t *file) { 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 base_addr = (uintptr_t)file->data-sizeof(uintptr_t);
uintptr_t next_addr = flash_read_uintptr(base_addr); uintptr_t next_addr = flash_read_uintptr(base_addr);
flash_program_uintptr(prev_addr, next_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) if (len > FLASH_SECTOR_SIZE)
return 1; return 1;
if (file->data) { //already in flash 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 if (len <= size_file_flash) { //it fits, no need to move it
flash_program_halfword((uintptr_t)file->data, len); flash_program_halfword((uintptr_t)file->data, len);
flash_program_block((uintptr_t)file->data+sizeof(uint16_t), 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); flash_program_block((uintptr_t)file->data+sizeof(uint16_t), data, len);
return 0; 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 * 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_INSERT 0
#define CARD_CHANGE_REMOVE 1 #define CARD_CHANGE_REMOVE 1
@@ -54,8 +33,7 @@ void ccid_card_change_signal (int how);
#define CCID_MSG_HEADER_SIZE 10 #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 */ /* USB buffer size of LL (Low-level): size of single Bulk transaction */
#define USB_LL_BUF_SIZE 64 #define USB_LL_BUF_SIZE 64
@@ -107,7 +85,6 @@ void ac_reset_admin (void);
void ac_fini (void); void ac_fini (void);
uint16_t set_res_sw (uint8_t sw1, uint8_t sw2);
extern uint8_t file_selection; extern uint8_t file_selection;
extern const uint8_t historical_bytes[]; extern const uint8_t historical_bytes[];
extern uint16_t data_objects_number_of_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]; 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 rsa_sign (const uint8_t *, uint8_t *, int, struct key_data *, int);
int modulus_calc (const uint8_t *, int, uint8_t *); int modulus_calc (const uint8_t *, int, uint8_t *);
@@ -431,7 +382,6 @@ extern uint8_t admin_authorized;
#endif #endif
extern const uint8_t openpgpcard_aid[]; extern const uint8_t openpgpcard_aid[];
extern const uint8_t sc_hsm_aid[];
void flash_bool_clear (const uint8_t **addr_p); void flash_bool_clear (const uint8_t **addr_p);
const uint8_t *flash_bool_write (uint8_t nr); const uint8_t *flash_bool_write (uint8_t nr);
@@ -510,17 +460,6 @@ unique_device_id (void)
return id; 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 #endif

182
hsm2040.c
View File

@@ -39,7 +39,6 @@ static uint8_t itf_num;
struct apdu apdu; struct apdu apdu;
static struct ccid ccid; static struct ccid ccid;
extern void openpgp_card_thread();
static uint8_t ccid_buffer[USB_BUF_SIZE]; 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_DATA_LEN 1
#define CCID_OFFSET_PARAM 8 #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 { struct ep_in {
uint8_t ep_num; uint8_t ep_num;
uint8_t tx_done; uint8_t tx_done;
@@ -158,7 +176,7 @@ struct ccid {
struct ep_in *epi; struct ep_in *epi;
queue_t ccid_comm; queue_t ccid_comm;
queue_t openpgp_comm; queue_t card_comm;
uint8_t application; 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->epo = epo;
c->a = a; 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); 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) 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); tud_vendor_write(buf, len);
} }
@@ -407,9 +425,9 @@ static enum ccid_state ccid_power_on (struct ccid *c)
if (c->application == 0) if (c->application == 0)
{ {
multicore_reset_core1(); 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->ccid_comm);
multicore_fifo_push_blocking((uint32_t)&c->openpgp_comm); multicore_fifo_push_blocking((uint32_t)&c->card_comm);
c->application = 1; c->application = 1;
} }
p[0] = CCID_DATA_BLOCK_RET; p[0] = CCID_DATA_BLOCK_RET;
@@ -491,7 +509,7 @@ static enum ccid_state ccid_power_off (struct ccid *c)
if (c->application) if (c->application)
{ {
uint32_t flag = EV_EXIT; uint32_t flag = EV_EXIT;
queue_try_add(&c->openpgp_comm, &flag); queue_try_add(&c->card_comm, &flag);
c->application = 0; 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]; c->a->res_apdu_data = &ccid_buffer[5];
uint32_t flag = EV_CMD_AVAILABLE; 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; 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; c->state = APDU_STATE_COMMAND_RECEIVED;
uint32_t flag = EV_VERIFY_CMD_AVAILABLE; 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; next_state = CCID_STATE_EXECUTE;
} }
else if (c->p[10-10] == 0x01) /* PIN Modification */ 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; c->state = APDU_STATE_COMMAND_RECEIVED;
uint32_t flag = EV_MODIFY_CMD_AVAILABLE; 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; next_state = CCID_STATE_EXECUTE;
} }
else else
@@ -1389,7 +1407,7 @@ static int usb_event_handle(struct ccid *c)
else if (tud_vendor_available() && c->epo->ready) else if (tud_vendor_available() && c->epo->ready)
{ {
uint32_t count = tud_vendor_read(endp1_rx_buf, sizeof(endp1_rx_buf)); 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); ccid_rx_ready(count);
} }
return 0; return 0;
@@ -1411,7 +1429,145 @@ void prepare_ccid()
apdu_init(a); apdu_init(a);
ccid_init (c, epi, epo, 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) void ccid_task(void)
{ {
struct ccid *c = &ccid; struct ccid *c = &ccid;
@@ -1453,7 +1609,7 @@ void ccid_task(void)
if (c->application) if (c->application)
{ {
uint32_t flag = EV_EXIT; uint32_t flag = EV_EXIT;
queue_try_add(&c->openpgp_comm, &flag); queue_try_add(&c->card_comm, &flag);
c->application = 0; c->application = 0;
} }
c->ccid_state = CCID_STATE_NOCARD; c->ccid_state = CCID_STATE_NOCARD;

View File

@@ -8,9 +8,19 @@
#define _HSM2040_H_ #define _HSM2040_H_
#include "ccid.h" #include "ccid.h"
#include "tusb.h"
#define USB_REQ_CCID 0xA1 #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[]; extern const uint8_t historical_bytes[];
#define DEBUG_PAYLOAD(p,s) { \ #define DEBUG_PAYLOAD(p,s) { \
@@ -29,6 +39,75 @@ extern const uint8_t historical_bytes[];
TU_LOG1("\r\n");\ TU_LOG1("\r\n");\
} 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 #endif

View File

@@ -9,6 +9,7 @@
#include "pico/sem.h" #include "pico/sem.h"
#include "pico/multicore.h" #include "pico/multicore.h"
#include "gnuk.h" #include "gnuk.h"
#include "hsm2040.h"
#include <string.h> #include <string.h>
#define TOTAL_FLASH_PAGES 4 #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) static void ep_init (int mode)
{ {
random_word = 0xcbf29ce484222325; random_word = 0xcbf29ce484222325;
ep_round = 0; ep_round = 0;
} }
/* Here, we assume a little endian architecture. */ /* Here, we assume a little endian architecture. */
@@ -88,7 +88,6 @@ static int ep_process (int mode)
return 0; return 0;
} }
static const uint32_t *ep_output (int mode) static const uint32_t *ep_output (int mode)
{ {
(void) 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. * Ring buffer, filled by generator, consumed by neug_get routine.
*/ */
struct rng_rb { struct rng_rb {
uint32_t *buf; uint32_t *buf;
//chopstx_mutex_t m; //chopstx_mutex_t m;
//chopstx_cond_t data_available; //chopstx_cond_t data_available;
//chopstx_cond_t space_available; //chopstx_cond_t space_available;
uint8_t head, tail; uint8_t head, tail;
uint8_t size; uint8_t size;
unsigned int full :1; unsigned int full :1;
unsigned int empty :1; unsigned int empty :1;
}; };
static void rb_init (struct rng_rb *rb, uint32_t *p, uint8_t size) static void rb_init (struct rng_rb *rb, uint32_t *p, uint8_t size)
{ {
rb->buf = p; rb->buf = p;
rb->size = size; rb->size = size;
//chopstx_mutex_init (&rb->m); //chopstx_mutex_init (&rb->m);
//chopstx_cond_init (&rb->data_available); //chopstx_cond_init (&rb->data_available);
//chopstx_cond_init (&rb->space_available); //chopstx_cond_init (&rb->space_available);
rb->head = rb->tail = 0; rb->head = rb->tail = 0;
rb->full = 0; rb->full = 0;
rb->empty = 1; rb->empty = 1;
} }
static void rb_add (struct rng_rb *rb, uint32_t v) static void rb_add (struct rng_rb *rb, uint32_t v)
{ {
rb->buf[rb->tail++] = v; rb->buf[rb->tail++] = v;
if (rb->tail == rb->size) if (rb->tail == rb->size)
rb->tail = 0; rb->tail = 0;
if (rb->tail == rb->head) if (rb->tail == rb->head)
rb->full = 1; rb->full = 1;
rb->empty = 0; rb->empty = 0;
} }
static uint32_t rb_del (struct rng_rb *rb) 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) if (rb->head == rb->size)
rb->head = 0; rb->head = 0;
if (rb->head == rb->tail) if (rb->head == rb->tail)
rb->empty = 1; rb->empty = 1;
rb->full = 0; rb->full = 0;
return v; return v;
} }
uint8_t neug_mode; uint8_t neug_mode;
@@ -154,13 +153,12 @@ static struct rng_rb the_ring_buffer;
/** /**
* @brief Random number generation thread. * @brief Random number generation thread.
*/ */
void * void *neug_task ()
neug_task ()
{ {
struct rng_rb *rb = &the_ring_buffer; struct rng_rb *rb = &the_ring_buffer;
int mode = neug_mode; int mode = neug_mode;
rng_should_terminate = 0; rng_should_terminate = 0;
//chopstx_mutex_init (&mode_mtx); //chopstx_mutex_init (&mode_mtx);
//chopstx_cond_init (&mode_cond); //chopstx_cond_init (&mode_cond);
@@ -170,20 +168,20 @@ neug_task ()
if ((n = ep_process (mode))) if ((n = ep_process (mode)))
{ {
int i; int i;
const uint32_t *vp; const uint32_t *vp;
vp = ep_output (mode); vp = ep_output (mode);
//chopstx_mutex_lock (&rb->m); //chopstx_mutex_lock (&rb->m);
//while (rb->full) //while (rb->full)
//chopstx_cond_wait (&rb->space_available, &rb->m); //chopstx_cond_wait (&rb->space_available, &rb->m);
for (i = 0; i < n; i++) for (i = 0; i < n; i++)
{ {
rb_add (rb, *vp++); rb_add (rb, *vp++);
if (rb->full) if (rb->full)
break; break;
} }
//chopstx_cond_signal (&rb->data_available); //chopstx_cond_signal (&rb->data_available);
@@ -193,32 +191,31 @@ neug_task ()
//adc_stop (); //adc_stop ();
return NULL; return NULL;
} }
/** /**
* @brief Initialize NeuG. * @brief Initialize NeuG.
*/ */
void void neug_init (uint32_t *buf, uint8_t size)
neug_init (uint32_t *buf, uint8_t size)
{ {
const uint32_t *u = (const uint32_t *)unique_device_id (); const uint32_t *u = (const uint32_t *)unique_device_id ();
struct rng_rb *rb = &the_ring_buffer; struct rng_rb *rb = &the_ring_buffer;
int i; int i;
/* /*
* This initialization ensures that it generates different sequence * This initialization ensures that it generates different sequence
* even if all physical conditions are same. * even if all physical conditions are same.
*/ */
neug_mode = NEUG_MODE_CONDITIONED; neug_mode = NEUG_MODE_CONDITIONED;
rb_init (rb, buf, size); rb_init (rb, buf, size);
/* Enable ADCs */ /* Enable ADCs */
adc_start (); adc_start ();
ep_init (neug_mode); ep_init (neug_mode);
//rng_thread = chopstx_create (PRIO_RNG, STACK_ADDR_RNG, STACK_SIZE_RNG, //rng_thread = chopstx_create (PRIO_RNG, STACK_ADDR_RNG, STACK_SIZE_RNG,
// rng, rb); // rng, rb);
@@ -227,14 +224,13 @@ neug_init (uint32_t *buf, uint8_t size)
/** /**
* @breif Flush random bytes. * @breif Flush random bytes.
*/ */
void void neug_flush (void)
neug_flush (void)
{ {
struct rng_rb *rb = &the_ring_buffer; struct rng_rb *rb = &the_ring_buffer;
//chopstx_mutex_lock (&rb->m); //chopstx_mutex_lock (&rb->m);
while (!rb->empty) while (!rb->empty)
(void)rb_del (rb); rb_del (rb);
//chopstx_cond_signal (&rb->space_available); //chopstx_cond_signal (&rb->space_available);
//chopstx_mutex_unlock (&rb->m); //chopstx_mutex_unlock (&rb->m);
} }
@@ -247,95 +243,36 @@ neug_flush (void)
* With NEUG_NO_KICK, it doesn't wake up RNG thread automatically, * With NEUG_NO_KICK, it doesn't wake up RNG thread automatically,
* it is needed to call neug_kick_filling later. * it is needed to call neug_kick_filling later.
*/ */
uint32_t uint32_t neug_get (int kick)
neug_get (int kick)
{ {
struct rng_rb *rb = &the_ring_buffer; struct rng_rb *rb = &the_ring_buffer;
uint32_t v; uint32_t v;
//chopstx_mutex_lock (&rb->m); //chopstx_mutex_lock (&rb->m);
while (rb->empty) while (rb->empty)
neug_task(); //chopstx_cond_wait (&rb->data_available, &rb->m); neug_task(); //chopstx_cond_wait (&rb->data_available, &rb->m);
v = rb_del (rb); v = rb_del (rb);
//if (kick) //if (kick)
//chopstx_cond_signal (&rb->space_available); //chopstx_cond_signal (&rb->space_available);
//chopstx_mutex_unlock (&rb->m); //chopstx_mutex_unlock (&rb->m);
return v; return v;
} }
int void neug_wait_full (void)
neug_get_nonblock (uint32_t *p)
{ {
struct rng_rb *rb = &the_ring_buffer; struct rng_rb *rb = &the_ring_buffer;
int r = 0;
//chopstx_mutex_lock (&rb->m); //chopstx_mutex_lock (&rb->m);
if (rb->empty) while (!rb->full)
{ neug_task(); //chopstx_cond_wait (&rb->data_available, &rb->m);
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);
//chopstx_mutex_unlock (&rb->m); //chopstx_mutex_unlock (&rb->m);
} }
void void neug_fini (void)
neug_fini (void)
{ {
rng_should_terminate = 1; rng_should_terminate = 1;
neug_get (1); neug_get (1);
//chopstx_join (rng_thread, NULL); //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 1 /* CRC-32 filtered sample data. */
#define NEUG_MODE_RAW_DATA 2 /* Sample data directly. */ #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); void neug_init (uint32_t *buf, uint8_t size);
uint32_t neug_get (int kick); uint32_t neug_get (int kick);
int neug_get_nonblock (uint32_t *p);
void neug_kick_filling (void);
void neug_flush (void); void neug_flush (void);
void neug_wait_full (void); void neug_wait_full (void);
void neug_fini (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/aes.h"
#include "mbedtls/sha512.h" #include "mbedtls/sha512.h"
#include "shake256.h" #include "shake256.h"
#include "hsm2040.h"
/* Forward declaration */ /* Forward declaration */
#define CLEAN_PAGE_FULL 1 #define CLEAN_PAGE_FULL 1
@@ -50,8 +51,7 @@ static const uint8_t *pw_err_counter_p[3];
static int static int
gpg_pw_get_err_counter (uint8_t which) gpg_pw_get_err_counter (uint8_t which)
{ {
//return flash_cnt123_get_value (pw_err_counter_p[which]); return flash_cnt123_get_value (pw_err_counter_p[which]);
return 3;
} }
int int
@@ -77,7 +77,7 @@ gpg_pw_locked (uint8_t which)
void void
gpg_pw_reset_err_counter (uint8_t which) 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) if (pw_err_counter_p[which] != NULL)
GPG_MEMORY_FAILURE (); GPG_MEMORY_FAILURE ();
} }
@@ -85,7 +85,7 @@ gpg_pw_reset_err_counter (uint8_t which)
void void
gpg_pw_increment_err_counter (uint8_t which) 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) if ((dsc >> 10) == 0)
{ /* no upper bits */ { /* no upper bits */
hw1 = NR_COUNTER_DS_LSB | ((dsc & 0x0300) >> 8) | ((dsc & 0x00ff) << 8); 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; return p+2;
} }
else else
{ {
hw0 = NR_COUNTER_DS | ((dsc & 0xfc0000) >> 18) | ((dsc & 0x03fc00) >> 2); hw0 = NR_COUNTER_DS | ((dsc & 0xfc0000) >> 18) | ((dsc & 0x03fc00) >> 2);
hw1 = NR_COUNTER_DS_LSB | ((dsc & 0x0300) >> 8) | ((dsc & 0x00ff) << 8); hw1 = NR_COUNTER_DS_LSB | ((dsc & 0x0300) >> 8) | ((dsc & 0x00ff) << 8);
//flash_put_data_internal (p, hw0); flash_put_data_internal (p, hw0);
//flash_put_data_internal (p+2, hw1); flash_put_data_internal (p+2, hw1);
return p+4; return p+4;
} }
} }
@@ -404,8 +404,8 @@ gpg_reset_digital_signature_counter (void)
{ {
if (digital_signature_counter != 0) if (digital_signature_counter != 0)
{ {
//flash_put_data (NR_COUNTER_DS); flash_put_data (NR_COUNTER_DS);
//flash_put_data (NR_COUNTER_DS_LSB); flash_put_data (NR_COUNTER_DS_LSB);
digital_signature_counter = 0; digital_signature_counter = 0;
} }
} }
@@ -420,13 +420,13 @@ gpg_increment_digital_signature_counter (void)
{ /* carry occurs from l10 to h14 */ { /* carry occurs from l10 to h14 */
hw0 = NR_COUNTER_DS | ((dsc & 0xfc0000) >> 18) | ((dsc & 0x03fc00) >> 2); hw0 = NR_COUNTER_DS | ((dsc & 0xfc0000) >> 18) | ((dsc & 0x03fc00) >> 2);
hw1 = NR_COUNTER_DS_LSB; /* zero */ hw1 = NR_COUNTER_DS_LSB; /* zero */
//flash_put_data (hw0); flash_put_data (hw0);
//flash_put_data (hw1); flash_put_data (hw1);
} }
else else
{ {
hw1 = NR_COUNTER_DS_LSB | ((dsc & 0x0300) >> 8) | ((dsc & 0x00ff) << 8); hw1 = NR_COUNTER_DS_LSB | ((dsc & 0x0300) >> 8) | ((dsc & 0x00ff) << 8);
//flash_put_data (hw1); flash_put_data (hw1);
} }
digital_signature_counter = dsc; digital_signature_counter = dsc;
@@ -658,7 +658,6 @@ do_kgtime_all (uint16_t tag, int with_tag)
} }
const uint8_t openpgpcard_aid[] = { const uint8_t openpgpcard_aid[] = {
14, //len
0xd2, 0x76, /* D: National, 276: DEU ISO 3166-1 */ 0xd2, 0x76, /* D: National, 276: DEU ISO 3166-1 */
0x00, 0x01, 0x24, /* Registered Application Provider Identifier */ 0x00, 0x01, 0x24, /* Registered Application Provider Identifier */
0x01, /* Application: OpenPGPcard */ 0x01, /* Application: OpenPGPcard */
@@ -667,11 +666,6 @@ const uint8_t openpgpcard_aid[] = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* To be overwritten */ 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 static void
do_openpgpcard_aid (uint16_t tag, int with_tag) 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. */ /* The first byte of DATA specifies the lifetime. */
if (data[0] == 0 && pw1_lifetime_p != NULL) 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 */ if (pw1_lifetime_p != NULL) /* No change after update */
return 0; return 0;
} }
else if (pw1_lifetime_p == NULL) 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 */ if (pw1_lifetime_p == NULL) /* No change after update */
return 0; return 0;
} }
@@ -853,7 +847,7 @@ rw_algorithm_attr (uint16_t tag, int with_tag,
gpg_reset_algo_attr (kk); gpg_reset_algo_attr (kk);
/* Read it again, since GC may occur. */ /* Read it again, since GC may occur. */
algo_attr_pp = get_algo_attr_pointer (kk); 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) if (*algo_attr_pp != NULL)
return 0; return 0;
} }
@@ -863,9 +857,9 @@ rw_algorithm_attr (uint16_t tag, int with_tag,
gpg_reset_algo_attr (kk); gpg_reset_algo_attr (kk);
/* Read it again, since GC may occur. */ /* Read it again, since GC may occur. */
algo_attr_pp = get_algo_attr_pointer (kk); algo_attr_pp = get_algo_attr_pointer (kk);
//if (*algo_attr_pp) if (*algo_attr_pp)
// flash_enum_clear (algo_attr_pp); flash_enum_clear (algo_attr_pp);
//*algo_attr_pp = flash_enum_write (kk_to_nr (kk), algo); *algo_attr_pp = flash_enum_write (kk_to_nr (kk), algo);
if (*algo_attr_pp == NULL) if (*algo_attr_pp == NULL)
return 0; 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)))) && data[42] == 0x87 && data[76] == 0x88))))
return 0; return 0;
//if (*do_data_p) if (*do_data_p)
//flash_do_release (*do_data_p); flash_do_release (*do_data_p);
/* Clear all keystrings and auth states */ /* Clear all keystrings and auth states */
gpg_do_write_simple (NR_DO_KEYSTRING_PW1, NULL, 0); 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 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) if (*do_data_p)
return 1; return 1;
else else
@@ -1332,20 +1326,20 @@ gpg_do_delete_prvkey (enum kind_of_key kk, int clean_page_full)
if (do_data == NULL) if (do_data == NULL)
{ {
// if (clean_page_full) if (clean_page_full)
//flash_key_release_page (kk); flash_key_release_page (kk);
return; return;
} }
do_ptr[nr] = NULL; do_ptr[nr] = NULL;
//flash_do_release (do_data); flash_do_release (do_data);
key_addr = (uint8_t *)kd[kk].pubkey - prvkey_len; key_addr = (uint8_t *)kd[kk].pubkey - prvkey_len;
kd[kk].pubkey = NULL; kd[kk].pubkey = NULL;
/*if (clean_page_full) if (clean_page_full)
flash_key_release_page (kk); flash_key_release_page (kk);
else else
flash_key_release (key_addr, key_size); flash_key_release (key_addr, key_size);
*/
if (admin_authorized == BY_ADMIN && kk == GPG_KEY_FOR_SIGNING) if (admin_authorized == BY_ADMIN && kk == GPG_KEY_FOR_SIGNING)
{ /* Recover admin keystring DO. */ { /* Recover admin keystring DO. */
const uint8_t *ks_pw3 = gpg_do_read_simple (NR_DO_KEYSTRING_PW3); 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"); DEBUG_INFO ("Getting keystore address...\r\n");
//key_addr = flash_key_alloc (kk); key_addr = flash_key_alloc (kk);
if (key_addr == NULL) if (key_addr == NULL)
return -1; return -1;
@@ -1522,7 +1516,7 @@ gpg_do_write_prvkey (enum kind_of_key kk, const uint8_t *key_data,
else else
memset (pd->dek_encrypted_3, 0, DATA_ENCRYPTION_KEY_SIZE); 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; do_ptr[nr] = p;
random_bytes_free (dek); random_bytes_free (dek);
@@ -1599,9 +1593,9 @@ gpg_do_chks_prvkey (enum kind_of_key kk,
{ {
const uint8_t *p; const uint8_t *p;
//flash_do_release (do_data); flash_do_release (do_data);
do_ptr[nr] = NULL; 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; do_ptr[nr] = p;
if (p == NULL) if (p == NULL)
r = -1; 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; num_prv_keys = 0;
if (do_ptr[NR_DO_PRVKEY_SIG] != NULL) 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; 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 * static const struct do_table_entry *
get_do_entry (uint16_t tag) 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 defined(CERTDO_SUPPORT)
if (tag == GPG_DO_CH_CERTIFICATE) 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]); apdu.res_apdu_data_len = ((apdu.res_apdu_data[2] << 8) | apdu.res_apdu_data[3]);
if (apdu.res_apdu_data_len == 0xffff) 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; const uint8_t **do_data_p = (const uint8_t **)do_p->obj;
// if (*do_data_p) if (*do_data_p)
// flash_do_release (*do_data_p); flash_do_release (*do_data_p);
if (len == 0) if (len == 0)
{ {
@@ -2254,7 +2321,7 @@ gpg_do_put_data (uint16_t tag, const uint8_t *data, int len)
else else
{ {
*do_data_p = NULL; *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) if (*do_data_p)
GPG_SUCCESS (); GPG_SUCCESS ();
else else
@@ -2410,13 +2477,13 @@ gpg_do_write_simple (uint8_t nr, const uint8_t *data, int size)
const uint8_t **do_data_p; const uint8_t **do_data_p;
do_data_p = (const uint8_t **)&do_ptr[nr]; do_data_p = (const uint8_t **)&do_ptr[nr];
//if (*do_data_p) if (*do_data_p)
// flash_do_release (*do_data_p); flash_do_release (*do_data_p);
if (data != NULL) if (data != NULL)
{ {
*do_data_p = 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) if (*do_data_p == NULL)
flash_warning ("DO WRITE ERROR"); flash_warning ("DO WRITE ERROR");
} }

852
openpgp.c
View File

@@ -37,8 +37,27 @@
#include "pico/multicore.h" #include "pico/multicore.h"
#include "hsm2040.h" #include "hsm2040.h"
#include "tusb.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 USER_PASSWD_MINLEN 6
#define ADMIN_PASSWD_MINLEN 8 #define ADMIN_PASSWD_MINLEN 8
@@ -82,11 +101,6 @@ select_file_TOP_result[] __attribute__ ((aligned (1))) = {
0x00, 0x00 /* PIN status: OK, PIN blocked?: No */ 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_NONE 0
#define FILE_DF_OPENPGP 1 #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_DF_SC_HSM 10
#define FILE_CARD_TERMINATED 255 #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; 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) { static void
uint8_t acl = ef->acl[op]; gpg_init (void)
if (acl == 0x0) {
return true; const uint8_t *flash_do_start;
else if (acl == 0xff) const uint8_t *flash_do_end;
return false;
else if (acl == 0x90 || acl & 0x9F == 0x10) { flash_do_storage_init (&flash_do_start, &flash_do_end);
// PIN required.
if(isUserAuthenticated) { if (flash_do_start == NULL)
return true; file_selection = FILE_CARD_TERMINATED;
} else
else { file_selection = FILE_NONE;
return false;
} gpg_data_scan (flash_do_start, flash_do_end);
} flash_key_storage_init ();
return false; multicore_lockout_victim_init();
} }
static void gpg_init (void) static int
gpg_fini (void)
{ {
const uint8_t *flash_do_start; ac_fini ();
const uint8_t *flash_do_end; return 0;
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 ();
} }
#if defined(PINPAD_SUPPORT) #if defined(PINPAD_SUPPORT)
@@ -333,90 +160,85 @@ get_pinpad_input (int msg_code)
} }
#endif #endif
static int cmd_verify (queue_t *ccid_comm) static void cmd_verify (queue_t *ccid_comm)
{ {
int len; int len;
uint8_t p1 = P1 (apdu); uint8_t p1 = P1 (apdu);
uint8_t p2 = P2 (apdu); uint8_t p2 = P2 (apdu);
int r; int r;
const uint8_t *pw; const uint8_t *pw;
(void)ccid_comm; (void)ccid_comm;
DEBUG_INFO (" - VERIFY\r\n"); DEBUG_INFO (" - VERIFY\r\n");
DEBUG_BYTE (p2); DEBUG_BYTE (p2);
len = apdu.cmd_apdu_data_len; len = apdu.cmd_apdu_data_len;
pw = apdu.cmd_apdu_data; pw = apdu.cmd_apdu_data;
printf("%X %X %X\r\n",selected_applet,pkcs15_openpgp,pkcs15_sc_hsm);
if (len == 0)
if (selected_applet == pkcs15_openpgp) { {
if (len == 0) if (p1 == 0)
{ { /* This is to examine status. */
if (p1 == 0) if (p2 == 0x81)
{ /* This is to examine status. */ r = ac_check_status (AC_PSO_CDS_AUTHORIZED);
if (p2 == 0x81) else if (p2 == 0x82)
r = ac_check_status (AC_PSO_CDS_AUTHORIZED); r = ac_check_status (AC_OTHER_AUTHORIZED);
else if (p2 == 0x82) else
r = ac_check_status (AC_OTHER_AUTHORIZED); r = ac_check_status (AC_ADMIN_AUTHORIZED);
else
r = ac_check_status (AC_ADMIN_AUTHORIZED); if (r)
/* If authentication done already, return success. */
if (r) GPG_SUCCESS ();
/* If authentication done already, return success. */ else
return GPG_SUCCESS (); { /* If not, return retry counter, encoded. */
else r = gpg_pw_get_retry_counter (p2);
{ /* If not, return retry counter, encoded. */ set_res_sw (0x63, 0xc0 | (r&0x0f));
r = gpg_pw_get_retry_counter (p2); }
set_res_sw (0x63, 0xc0 | (r&0x0f)); }
} else if (p1 == 0xff)
} { /* Reset the status. */
else if (p1 == 0xff) if (p2 == 0x81)
{ /* Reset the status. */ ac_reset_pso_cds ();
if (p2 == 0x81) else if (p2 == 0x82)
ac_reset_pso_cds (); ac_reset_other ();
else if (p2 == 0x82) else
ac_reset_other (); ac_reset_admin ();
else GPG_SUCCESS ();
ac_reset_admin (); }
return GPG_SUCCESS (); else
} GPG_BAD_P1_P2 ();
else return;
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 ();
}
} }
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 int
@@ -959,149 +781,152 @@ gpg_get_firmware_update_key (uint8_t keyno)
#define FILEID_CH_CERTIFICATE_IS_VALID 0 #define FILEID_CH_CERTIFICATE_IS_VALID 0
#endif #endif
static int cmd_read_binary (queue_t *ccid_comm) static void
cmd_read_binary (queue_t *ccid_comm)
{ {
uint16_t fid; int is_short_EF = (P1 (apdu) & 0x80) != 0;
uint32_t offset; uint8_t file_id;
uint8_t ins = INS(apdu), p1 = P1(apdu), p2 = P2(apdu); uint16_t offset;
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;
}
return GPG_SUCCESS (); (void)ccid_comm;
} DEBUG_INFO (" - Read binary\r\n");
void select_file(const pkcs15_entry_t *pe) {
if (!pe) 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; file_selection = file_id - FILEID_SERIAL_NO + FILE_EF_SERIAL_NO;
currentEF = NULL; offset = P2 (apdu);
} }
else if (pe->type & FILE_TYPE_INTERNAL_EF) { else
currentEF = pe; offset = (P1 (apdu) << 8) | P2 (apdu);
currentDF = &pkcs15_entries[pe->parent];
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 { #ifdef FLASH_UPGRADE_SUPPORT
currentDF = pe; 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; (void)ccid_comm;
uint8_t p1 = P1(apdu); if (P1 (apdu) == 4) /* Selection by DF name */
uint8_t p2 = P2(apdu); {
const pkcs15_entry_t *pe = NULL; DEBUG_INFO (" - select DF by name\r\n");
uint16_t fid = 0x0;
/* name = D2 76 00 01 24 01 */
// Only "first or only occurence" supported if (apdu.cmd_apdu_data_len != 6
//if ((p2 & 0xF3) != 0x00) { || memcmp (openpgpcard_aid, apdu.cmd_apdu_data, 6) != 0)
// return SW_INCORRECT_P1P2(); {
//} DEBUG_SHORT (apdu.cmd_apdu_data_len);
DEBUG_BINARY (apdu.cmd_apdu_data, apdu.cmd_apdu_data_len);
if (apdu.cmd_apdu_data_len >= 2)
fid = get_uint16_t(apdu.cmd_apdu_data, 0); GPG_NO_FILE ();
return;
if (p1 == 0x0) { //Select MF, DF or EF - File identifier or absent }
if (apdu.cmd_apdu_data_len == 0) {
pe = MF; if (file_selection == FILE_CARD_TERMINATED)
ac_fini(); {
} GPG_APPLICATION_TERMINATED ();
else if (apdu.cmd_apdu_data_len == 2) { return;
if (!(pe = search_by_fid(fid, NULL, SPECIFY_ANY))) { }
return GPG_NO_FILE ();
} file_selection = FILE_DF_OPENPGP;
}
/* Behave just like original OpenPGP card. */
GPG_SUCCESS ();
} }
else if (p1 == 0x01) { //Select child DF - DF identifier else if (apdu.cmd_apdu_data_len == 2
if (!(pe = search_by_fid(fid, currentDF, SPECIFY_DF))) { && apdu.cmd_apdu_data[0] == 0x2f && apdu.cmd_apdu_data[1] == 0x02)
return GPG_NO_FILE (); {
} 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 else if (apdu.cmd_apdu_data_len == 2
if (!(pe = search_by_fid(fid, currentDF, SPECIFY_EF))) { && apdu.cmd_apdu_data[0] == 0x3f && apdu.cmd_apdu_data[1] == 0x00)
return GPG_NO_FILE (); {
} 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 else
if (apdu.cmd_apdu_data_len != 0) {
return GPG_NO_FILE (); 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 static void
@@ -1541,6 +1366,7 @@ modify_binary (uint8_t op, uint8_t p1, uint8_t p2, int len)
} }
#if defined(CERTDO_SUPPORT) #if defined(CERTDO_SUPPORT)
static void static void
cmd_update_binary (queue_t *ccid_comm) cmd_update_binary (queue_t *ccid_comm)
@@ -1606,7 +1432,7 @@ cmd_external_authenticate (queue_t *ccid_comm)
return; return;
} }
eventflag_signal (openpgp_comm, EV_EXIT); /* signal to self. */ //eventflag_signal (openpgp_comm, EV_EXIT); /* signal to self. */
set_res_sw (0xff, 0xff); set_res_sw (0xff, 0xff);
DEBUG_INFO ("EXTERNAL AUTHENTICATE done.\r\n"); DEBUG_INFO ("EXTERNAL AUTHENTICATE done.\r\n");
} }
@@ -1659,8 +1485,7 @@ cmd_activate_file (queue_t *ccid_comm)
} }
flash_activate (); flash_activate ();
//file_selection = FILE_DF_OPENPGP; file_selection = FILE_DF_OPENPGP;
file_selection = FILE_DF_SC_HSM;
GPG_SUCCESS (); GPG_SUCCESS ();
} }
@@ -1672,8 +1497,7 @@ cmd_terminate_df (queue_t *ccid_comm)
uint8_t p2 = P2 (apdu); uint8_t p2 = P2 (apdu);
(void)ccid_comm; (void)ccid_comm;
//if (file_selection != FILE_DF_OPENPGP) if (file_selection != FILE_DF_OPENPGP)
if (file_selection != FILE_DF_SC_HSM)
{ {
GPG_NO_RECORD (); GPG_NO_RECORD ();
return; return;
@@ -1716,42 +1540,41 @@ cmd_terminate_df (queue_t *ccid_comm)
struct command struct command
{ {
uint8_t command; uint8_t command;
void (*cmd_handler) (queue_t *ccid_comm); void (*cmd_handler) ();
}; };
const struct command cmds[] = { const struct command cmds[] = {
{ INS_VERIFY, cmd_verify }, { INS_VERIFY, cmd_verify },
{ INS_CHANGE_REFERENCE_DATA, cmd_change_password }, { INS_CHANGE_REFERENCE_DATA, cmd_change_password },
{ INS_PSO, cmd_pso }, { INS_PSO, cmd_pso },
{ INS_RESET_RETRY_COUNTER, cmd_reset_user_password }, { INS_RESET_RETRY_COUNTER, cmd_reset_user_password },
#ifdef LIFE_CYCLE_MANAGEMENT_SUPPORT #ifdef LIFE_CYCLE_MANAGEMENT_SUPPORT
{ INS_ACTIVATE_FILE, cmd_activate_file }, { INS_ACTIVATE_FILE, cmd_activate_file },
#endif #endif
{ INS_PGP_GENERATE_ASYMMETRIC_KEY_PAIR, cmd_pgp_gakp }, { INS_PGP_GENERATE_ASYMMETRIC_KEY_PAIR, cmd_pgp_gakp },
#ifdef FLASH_UPGRADE_SUPPORT #ifdef FLASH_UPGRADE_SUPPORT
{ INS_EXTERNAL_AUTHENTICATE, /* Not in OpenPGP card protocol */ { INS_EXTERNAL_AUTHENTICATE, /* Not in OpenPGP card protocol */
cmd_external_authenticate }, cmd_external_authenticate },
#endif #endif
{ INS_GET_CHALLENGE, cmd_get_challenge }, /* Not in OpenPGP card protocol */ { INS_GET_CHALLENGE, cmd_get_challenge }, /* Not in OpenPGP card protocol */
{ INS_INTERNAL_AUTHENTICATE, cmd_internal_authenticate }, { INS_INTERNAL_AUTHENTICATE, cmd_internal_authenticate },
{ INS_SELECT_FILE, cmd_select_file }, { INS_SELECT_FILE, cmd_select_file },
{ INS_READ_BINARY, cmd_read_binary }, /* Not in OpenPGP card protocol */ { INS_READ_BINARY, cmd_read_binary }, /* Not in OpenPGP card protocol */
{ INS_READ_BINARY_ODD, 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_GET_DATA, cmd_get_data },
{ INS_WRITE_BINARY, cmd_write_binary}, /* Not in OpenPGP card protocol */ { INS_WRITE_BINARY, cmd_write_binary}, /* Not in OpenPGP card protocol */
#if defined(CERTDO_SUPPORT) #if defined(CERTDO_SUPPORT)
{ INS_UPDATE_BINARY, cmd_update_binary }, /* Not in OpenPGP card protocol */ { INS_UPDATE_BINARY, cmd_update_binary }, /* Not in OpenPGP card protocol */
#endif #endif
{ INS_PUT_DATA, cmd_put_data }, { INS_PUT_DATA, cmd_put_data },
{ INS_PUT_DATA_ODD, cmd_put_data }, { INS_PUT_DATA_ODD, cmd_put_data },
#ifdef LIFE_CYCLE_MANAGEMENT_SUPPORT #ifdef LIFE_CYCLE_MANAGEMENT_SUPPORT
{ INS_TERMINATE_DF, cmd_terminate_df}, { INS_TERMINATE_DF, cmd_terminate_df},
#endif #endif
}; };
#define NUM_CMDS ((int)(sizeof (cmds) / sizeof (struct command))) #define NUM_CMDS ((int)(sizeof (cmds) / sizeof (struct command)))
static void int openpgp_process_apdu()
process_command_apdu (queue_t *ccid_comm)
{ {
int i; int i;
uint8_t cmd = INS (apdu); uint8_t cmd = INS (apdu);
@@ -1774,7 +1597,7 @@ process_command_apdu (queue_t *ccid_comm)
GPG_NO_RECORD (); GPG_NO_RECORD ();
else else
{ {
cmds[i].cmd_handler (ccid_comm); cmds[i].cmd_handler ();
} }
} }
else 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 #define RANDOM_BYTES_LENGTH 32
static uint32_t random_word[RANDOM_BYTES_LENGTH/sizeof (uint32_t)]; static uint32_t random_word[RANDOM_BYTES_LENGTH/sizeof (uint32_t)];
void void random_init (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++) for (i = 0; i < NEUG_PRE_LOOP; i++)
(void)neug_get (NEUG_KICK_FILLING); neug_get (NEUG_KICK_FILLING);
} }
void void random_fini (void)
random_fini (void)
{ {
neug_fini (); neug_fini ();
} }
/* /*
* Return pointer to random 32-byte * Return pointer to random 32-byte
*/ */
const uint8_t * const uint8_t * random_bytes_get (void)
random_bytes_get (void)
{ {
static uint32_t return_word[RANDOM_BYTES_LENGTH/sizeof (uint32_t)]; static uint32_t return_word[RANDOM_BYTES_LENGTH/sizeof (uint32_t)];
neug_wait_full (); neug_wait_full ();
memcpy(return_word, random_word, sizeof(return_word)); memcpy(return_word, random_word, sizeof(return_word));
return (const uint8_t *)return_word; return (const uint8_t *)return_word;
} }
/* /*
* Free pointer to random 32-byte * Free pointer to random 32-byte
*/ */
void void random_bytes_free (const uint8_t *p)
random_bytes_free (const uint8_t *p)
{ {
(void)p; (void)p;
memset (random_word, 0, RANDOM_BYTES_LENGTH); memset (random_word, 0, RANDOM_BYTES_LENGTH);
neug_flush (); neug_flush ();
} }
/* /*
* Return 4-byte salt * Return 4-byte salt
*/ */
void void random_get_salt (uint8_t *p)
random_get_salt (uint8_t *p)
{ {
uint32_t rnd; uint32_t rnd;
rnd = neug_get (NEUG_KICK_FILLING); rnd = neug_get (NEUG_KICK_FILLING);
memcpy (p, &rnd, sizeof (uint32_t)); memcpy (p, &rnd, sizeof (uint32_t));
rnd = neug_get (NEUG_KICK_FILLING); rnd = neug_get (NEUG_KICK_FILLING);
memcpy (p + sizeof (uint32_t), &rnd, sizeof (uint32_t)); memcpy (p + sizeof (uint32_t), &rnd, sizeof (uint32_t));
} }
/* /*
* Random byte iterator * Random byte iterator
*/ */
int int random_gen (void *arg, unsigned char *out, size_t out_len)
random_gen (void *arg, unsigned char *out, size_t out_len)
{ {
uint8_t *index_p = (uint8_t *)arg; uint8_t *index_p = (uint8_t *)arg;
uint8_t index = index_p ? *index_p : 0; uint8_t index = index_p ? *index_p : 0;
size_t n; size_t n;
while (out_len) while (out_len)
{ {
neug_wait_full (); neug_wait_full ();
n = RANDOM_BYTES_LENGTH - index; n = RANDOM_BYTES_LENGTH - index;
if (n > out_len) if (n > out_len)
n = out_len; n = out_len;
memcpy (out, ((unsigned char *)random_word) + index, n); memcpy (out, ((unsigned char *)random_word) + index, n);
out += n; out += n;
out_len -= n; out_len -= n;
index += n; index += n;
if (index >= RANDOM_BYTES_LENGTH) if (index >= RANDOM_BYTES_LENGTH)
{ {
index = 0; index = 0;
neug_flush (); neug_flush ();
} }
} }
if (index_p) if (index_p)
*index_p = index; *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 GPG_APPLICATION_TERMINATED() set_res_sw (0x62, 0x85)
#define SW_WARNING_STATE_UNCHANGED() set_res_sw (0x62, 0x00) #define GPG_MEMORY_FAILURE() set_res_sw (0x65, 0x81)
#define GPG_APPLICATION_TERMINATED() set_res_sw (0x62, 0x85) #define GPG_WRONG_LENGTH() set_res_sw (0x67, 0x00)
#define GPG_MEMORY_FAILURE() set_res_sw (0x65, 0x81) #define GPG_SECURITY_FAILURE() set_res_sw (0x69, 0x82)
#define GPG_WRONG_LENGTH() set_res_sw (0x67, 0x00) #define GPG_SECURITY_AUTH_BLOCKED() set_res_sw (0x69, 0x83)
#define SW_WRONG_LENGTH() set_res_sw (0x67, 0x00) #define GPG_CONDITION_NOT_SATISFIED() set_res_sw (0x69, 0x85)
#define SW_WRONG_DATA() set_res_sw (0x67, 0x00) #define GPG_COMMAND_NOT_ALLOWED() set_res_sw (0x69, 0x86)
#define SW_LOGICAL_CHANNEL_NOT_SUPPORTED() set_res_sw (0x68, 0x81) #define GPG_FUNCTION_NOT_SUPPORTED() set_res_sw (0x6a, 0x81)
#define SW_SECURE_MESSAGING_NOT_SUPPORTED() set_res_sw (0x68, 0x82) #define GPG_NO_FILE() set_res_sw (0x6a, 0x82)
#define GPG_SECURITY_FAILURE() set_res_sw (0x69, 0x82) #define GPG_NO_RECORD() set_res_sw (0x6a, 0x88)
#define SW_SECURITY_STATUS_NOT_SATISFIED() set_res_sw (0x69, 0x82) #define GPG_BAD_P1_P2() set_res_sw (0x6b, 0x00)
#define GPG_SECURITY_AUTH_BLOCKED() set_res_sw (0x69, 0x83) #define GPG_NO_INS() set_res_sw (0x6d, 0x00)
#define SW_FILE_INVALID () set_res_sw (0x69, 0x83) #define GPG_ERROR() set_res_sw (0x6f, 0x00)
#define SW_DATA_INVALID () set_res_sw (0x69, 0x84) #define GPG_SUCCESS() set_res_sw (0x90, 0x00)
#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)