Splitting the core onto another repo, which can be reused by other smart applications.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
This commit is contained in:
Pol Henarejos 2022-04-19 18:39:52 +02:00
parent b09fc75913
commit 522860f736
No known key found for this signature in database
GPG Key ID: C0095B7870A4CCD3
24 changed files with 286 additions and 3730 deletions

3
.gitmodules vendored
View File

@ -4,3 +4,6 @@
[submodule "mbedtls"]
path = mbedtls
url = https://github.com/ARMmbed/mbedtls
[submodule "pico-ccid"]
path = pico-ccid
url = git@github.com-polhenarejos:polhenarejos/pico-ccid

View File

@ -51,14 +51,15 @@ if (NOT EXISTS ${CMAKE_CURRENT_LIST_DIR}/src/hsm/cvcerts.h)
endif()
target_sources(pico_hsm PUBLIC
${CMAKE_CURRENT_LIST_DIR}/src/hsm/hsm2040.c
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/src/ccid/ccid2040.c
${CMAKE_CURRENT_LIST_DIR}/src/hsm/sc_hsm.c
${CMAKE_CURRENT_LIST_DIR}/src/usb/usb_descriptors.c
${CMAKE_CURRENT_LIST_DIR}/src/fs/file.c
${CMAKE_CURRENT_LIST_DIR}/src/fs/flash.c
${CMAKE_CURRENT_LIST_DIR}/src/fs/low_flash.c
${CMAKE_CURRENT_LIST_DIR}/src/rng/random.c
${CMAKE_CURRENT_LIST_DIR}/src/rng/neug.c
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/src/usb/usb_descriptors.c
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/src/fs/file.c
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/src/fs/flash.c
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/src/fs/low_flash.c
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/src/rng/random.c
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/src/rng/neug.c
${CMAKE_CURRENT_LIST_DIR}/src/hsm/files.c
${CMAKE_CURRENT_LIST_DIR}/src/hsm/crypto_utils.c
${CMAKE_CURRENT_LIST_DIR}/src/hsm/dkek.c
${CMAKE_CURRENT_LIST_DIR}/src/hsm/eac.c
@ -115,10 +116,11 @@ target_sources(pico_hsm PUBLIC
)
target_include_directories(pico_hsm PUBLIC
${CMAKE_CURRENT_LIST_DIR}/src/fs
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/src/fs
${CMAKE_CURRENT_LIST_DIR}/src/hsm
${CMAKE_CURRENT_LIST_DIR}/src/rng
${CMAKE_CURRENT_LIST_DIR}/src/usb
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/src/ccid
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/src/rng
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/src/usb
${CMAKE_CURRENT_LIST_DIR}/opensc/src
${CMAKE_CURRENT_LIST_DIR}/mbedtls/include
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library

1
pico-ccid Submodule

@ -0,0 +1 @@
Subproject commit cffee4264a531b52a5991c916e131280adeb1c9d

View File

@ -1,416 +0,0 @@
/*
* This file is part of the Pico HSM distribution (https://github.com/polhenarejos/pico-hsm).
* Copyright (c) 2022 Pol Henarejos.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "file.h"
#include "tusb.h"
#include "hsm2040.h"
#include "sc_hsm.h"
#include "libopensc/card-sc-hsm.h"
#include <string.h>
extern const uintptr_t end_data_pool;
extern const uintptr_t start_data_pool;
extern int flash_write_data_to_file(file_t *file, const uint8_t *data, uint16_t len);
extern int flash_program_halfword (uintptr_t addr, uint16_t data);
extern int flash_program_word (uintptr_t addr, uint32_t data);
extern int flash_program_uintptr (uintptr_t addr, uintptr_t data);
extern int flash_program_block(uintptr_t addr, const uint8_t *data, size_t len);
extern uintptr_t flash_read_uintptr(uintptr_t addr);
extern uint16_t flash_read_uint16(uintptr_t addr);
extern uint8_t flash_read_uint8(uintptr_t addr);
extern uint8_t *flash_read(uintptr_t addr);
extern void low_flash_available();
//puts FCI in the RAPDU
void process_fci(const file_t *pe) {
uint8_t *p = res_APDU;
uint8_t buf[64];
res_APDU_size = 0;
res_APDU[res_APDU_size++] = 0x6f;
res_APDU[res_APDU_size++] = 0x00; //computed later
res_APDU[res_APDU_size++] = 0x81;
res_APDU[res_APDU_size++] = 2;
if (pe->data) {
if ((pe->type & FILE_DATA_FUNC) == FILE_DATA_FUNC) {
uint16_t len = ((int (*)(const file_t *, int))(pe->data))(pe, 0);
res_APDU[res_APDU_size++] = (len >> 8) & 0xff;
res_APDU[res_APDU_size++] = len & 0xff;
}
else {
res_APDU[res_APDU_size++] = pe->data[1];
res_APDU[res_APDU_size++] = pe->data[0];
}
}
else {
memset(res_APDU+res_APDU_size, 0, 2);
res_APDU_size += 2;
}
res_APDU[res_APDU_size++] = 0x82;
res_APDU[res_APDU_size++] = 1;
res_APDU[res_APDU_size] = 0;
if (pe->type == FILE_TYPE_INTERNAL_EF)
res_APDU[res_APDU_size++] |= 0x08;
else if (pe->type == FILE_TYPE_WORKING_EF)
res_APDU[res_APDU_size++] |= pe->ef_structure & 0x7;
else if (pe->type == FILE_TYPE_DF)
res_APDU[res_APDU_size++] |= 0x38;
res_APDU[res_APDU_size++] = 0x83;
res_APDU[res_APDU_size++] = 2;
put_uint16_t(pe->fid, res_APDU+res_APDU_size);
res_APDU_size += 2;
res_APDU[1] = res_APDU_size-2;
}
extern const uint8_t sc_hsm_aid[];
extern int parse_token_info(const file_t *f, int mode);
extern int parse_cvca(const file_t *f, int mode);
file_t file_entries[] = {
/* 0 */ { .fid = 0x3f00 , .parent = 0xff, .name = NULL, .type = FILE_TYPE_DF, .data = NULL, .ef_structure = 0, .acl = {0} }, // MF
/* 1 */ { .fid = 0x2f00 , .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.DIR
/* 2 */ { .fid = 0x2f01 , .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.ATR
/* 3 */ { .fid = 0x2f02 , .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF | FILE_DATA_FUNC,.data = (uint8_t *)parse_cvca, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.GDO
/* 4 */ { .fid = 0x2f03 , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF | FILE_DATA_FUNC,.data = (uint8_t *)parse_token_info, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.TokenInfo
/* 5 */ { .fid = 0x5015 , .parent = 0, .name = NULL, .type = FILE_TYPE_DF, .data = NULL, .ef_structure = 0, .acl = {0} }, //DF.PKCS15
/* 6 */ { .fid = 0x5031 , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.ODF
/* 7 */ { .fid = 0x5032 , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.TokenInfo
/* 8 */ { .fid = 0x5033 , .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.UnusedSpace
/* 9 */ { .fid = 0x1081 , .parent = 5, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff} }, //PIN (PIN1)
/* 10 */ { .fid = 0x1082 , .parent = 5, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff} }, //max retries PIN (PIN1)
/* 11 */ { .fid = 0x1083 , .parent = 5, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff} }, //retries PIN (PIN1)
/* 12 */ { .fid = 0x1088 , .parent = 5, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff} }, //PIN (SOPIN)
/* 13 */ { .fid = 0x1089 , .parent = 5, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff} }, //max retries PIN (SOPIN)
/* 14 */ { .fid = 0x108A , .parent = 5, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff} }, //retries PIN (SOPIN)
/* 15 */ { .fid = EF_DKEK , .parent = 5, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff} }, //DKEK
/* 16 */ { .fid = EF_DEVOPS , .parent = 5, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff} }, //Device options
/* 17 */ { .fid = EF_PRKDFS , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.PrKDFs
/* 18 */ { .fid = EF_PUKDFS , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.PuKDFs
/* 19 */ { .fid = EF_CDFS , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.CDFs
/* 20 */ { .fid = EF_AODFS , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.AODFs
/* 21 */ { .fid = EF_DODFS , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.DODFs
/* 22 */ { .fid = EF_SKDFS , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.SKDFs
///* 23 */ { .fid = 0x0000, .parent = 0, .name = openpgpcard_aid, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} },
/* 24 */ { .fid = 0x0000, .parent = 5, .name = sc_hsm_aid, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} },
/* 25 */ { .fid = 0x0000, .parent = 0xff, .name = NULL, .type = FILE_TYPE_UNKNOWN, .data = NULL, .ef_structure = 0, .acl = {0} } //end
};
const file_t *MF = &file_entries[0];
const file_t *file_last = &file_entries[sizeof(file_entries)/sizeof(file_t)-1];
const file_t *file_openpgp = &file_entries[sizeof(file_entries)/sizeof(file_t)-3];
const file_t *file_sc_hsm = &file_entries[sizeof(file_entries)/sizeof(file_t)-2];
file_t *file_pin1 = NULL;
file_t *file_retries_pin1 = NULL;
file_t *file_sopin = NULL;
file_t *file_retries_sopin = NULL;
#define MAX_DYNAMIC_FILES 64
uint16_t dynamic_files = 0;
file_t dynamic_file[MAX_DYNAMIC_FILES];
bool card_terminated = false;
bool is_parent(const file_t *child, const file_t *parent) {
if (child == parent)
return true;
if (child == MF)
return false;
return is_parent(&file_entries[child->parent], parent);
}
file_t *get_parent(file_t *f) {
return &file_entries[f->parent];
}
file_t *search_by_name(uint8_t *name, uint16_t namelen) {
for (file_t *p = file_entries; p != file_last; p++) {
if (p->name && *p->name == apdu.cmd_apdu_data_len && memcmp(p->name+1, name, namelen) == 0) {
return p;
}
}
return NULL;
}
file_t *search_by_fid(const uint16_t fid, const file_t *parent, const uint8_t sp) {
for (file_t *p = file_entries; p != file_last; p++) {
if (p->fid != 0x0000 && p->fid == fid) {
if (!parent || (parent && is_parent(p, parent))) {
if (!sp || sp == SPECIFY_ANY || (((sp & SPECIFY_EF) && (p->type & FILE_TYPE_INTERNAL_EF)) || ((sp & SPECIFY_DF) && p->type == FILE_TYPE_DF)))
return p;
}
}
}
return NULL;
}
uint8_t make_path_buf(const file_t *pe, uint8_t *buf, uint8_t buflen, const file_t *top) {
if (!buflen)
return 0;
if (pe == top) //MF or relative DF
return 0;
put_uint16_t(pe->fid, buf);
return make_path_buf(&file_entries[pe->parent], buf+2, buflen-2, top)+2;
}
uint8_t make_path(const file_t *pe, const file_t *top, uint8_t *path) {
uint8_t buf[MAX_DEPTH*2], *p = path;
put_uint16_t(pe->fid, buf);
uint8_t depth = make_path_buf(&file_entries[pe->parent], buf+2, sizeof(buf)-2, top)+2;
for (int d = depth-2; d >= 0; d -= 2) {
memcpy(p, buf+d, 2);
p += 2;
}
return depth;
}
file_t *search_by_path(const uint8_t *pe_path, uint8_t pathlen, const file_t *parent) {
uint8_t path[MAX_DEPTH*2];
if (pathlen > sizeof(path)) {
return NULL;
}
for (file_t *p = file_entries; p != file_last; p++) {
uint8_t depth = make_path(p, parent, path);
if (pathlen == depth && memcmp(path, pe_path, depth) == 0)
return p;
}
return NULL;
}
file_t *currentEF = NULL;
file_t *currentDF = NULL;
const file_t *selected_applet = NULL;
bool isUserAuthenticated = false;
bool authenticate_action(const file_t *ef, uint8_t op) {
uint8_t acl = ef->acl[op];
if (acl == 0x0)
return true;
else if (acl == 0xff)
return false;
else if (acl == 0x90 || acl & 0x9F == 0x10) {
// PIN required.
if(isUserAuthenticated) {
return true;
}
else {
return false;
}
}
return false;
}
#include "libopensc/pkcs15.h"
void initialize_chain(file_chain_t **chain) {
file_chain_t *next;
for (file_chain_t *f = *chain; f; f = next) {
next = f->next;
free(f);
}
*chain = NULL;
}
void initialize_flash(bool hard) {
if (hard) {
const uint8_t empty[8] = { 0 };
flash_program_block(end_data_pool, empty, sizeof(empty));
low_flash_available();
}
for (file_t *f = file_entries; f != file_last; f++) {
if ((f->type & FILE_DATA_FLASH) == FILE_DATA_FLASH)
f->data = NULL;
}
dynamic_files = 0;
}
void scan_flash() {
initialize_flash(false); //soft initialization
if (*(uintptr_t *)end_data_pool == 0xffffffff && *(uintptr_t *)(end_data_pool+sizeof(uintptr_t)) == 0xffffffff)
{
printf("First initialization (or corrupted!)\r\n");
const uint8_t empty[8] = { 0 };
flash_program_block(end_data_pool, empty, sizeof(empty));
//low_flash_available();
//wait_flash_finish();
}
printf("SCAN\r\n");
uintptr_t base = flash_read_uintptr(end_data_pool);
for (uintptr_t base = flash_read_uintptr(end_data_pool); base >= start_data_pool; base = flash_read_uintptr(base)) {
if (base == 0x0) //all is empty
break;
uint16_t fid = flash_read_uint16(base+sizeof(uintptr_t)+sizeof(uintptr_t));
printf("[%x] scan fid %x, len %d\r\n",base,fid,flash_read_uint16(base+sizeof(uintptr_t)+sizeof(uintptr_t)+sizeof(uint16_t)));
file_t *file = (file_t *)search_by_fid(fid, NULL, SPECIFY_EF);
if (!file) {
file = file_new(fid);
uint8_t pfx = fid >> 8;
if (pfx != KEY_PREFIX && pfx != PRKD_PREFIX && pfx != CD_PREFIX && pfx != EE_CERTIFICATE_PREFIX && pfx != DCOD_PREFIX && pfx != PROT_DATA_PREFIX && pfx != DATA_PREFIX) {
TU_LOG1("SCAN FOUND ORPHAN FILE: %x\r\n",fid);
continue;
}
}
file->data = (uint8_t *)(base+sizeof(uintptr_t)+sizeof(uintptr_t)+sizeof(uint16_t));
if (flash_read_uintptr(base) == 0x0) {
break;
}
}
file_pin1 = search_by_fid(0x1081, NULL, SPECIFY_EF);
if (file_pin1) {
if (!file_pin1->data) {
TU_LOG1("PIN1 is empty. Initializing with default password\r\n");
const uint8_t empty[33] = { 0 };
flash_write_data_to_file(file_pin1, empty, sizeof(empty));
}
}
else {
TU_LOG1("FATAL ERROR: PIN1 not found in memory!\r\n");
}
file_sopin = search_by_fid(0x1088, NULL, SPECIFY_EF);
if (file_sopin) {
if (!file_sopin->data) {
TU_LOG1("SOPIN is empty. Initializing with default password\r\n");
const uint8_t empty[33] = { 0 };
flash_write_data_to_file(file_sopin, empty, sizeof(empty));
}
}
else {
TU_LOG1("FATAL ERROR: SOPIN not found in memory!\r\n");
}
file_retries_pin1 = search_by_fid(0x1083, NULL, SPECIFY_EF);
if (file_retries_pin1) {
if (!file_retries_pin1->data) {
TU_LOG1("Retries PIN1 is empty. Initializing with default retriesr\n");
const uint8_t retries = 3;
flash_write_data_to_file(file_retries_pin1, &retries, sizeof(uint8_t));
}
}
else {
TU_LOG1("FATAL ERROR: Retries PIN1 not found in memory!\r\n");
}
file_retries_sopin = search_by_fid(0x108A, NULL, SPECIFY_EF);
if (file_retries_sopin) {
if (!file_retries_sopin->data) {
TU_LOG1("Retries SOPIN is empty. Initializing with default retries\r\n");
const uint8_t retries = 15;
flash_write_data_to_file(file_retries_sopin, &retries, sizeof(uint8_t));
}
}
else {
TU_LOG1("FATAL ERROR: Retries SOPIN not found in memory!\r\n");
}
file_t *tf = NULL;
tf = search_by_fid(0x1082, NULL, SPECIFY_EF);
if (tf) {
if (!tf->data) {
TU_LOG1("Max retries PIN1 is empty. Initializing with default max retriesr\n");
const uint8_t retries = 3;
flash_write_data_to_file(tf, &retries, sizeof(uint8_t));
}
}
else {
TU_LOG1("FATAL ERROR: Max Retries PIN1 not found in memory!\r\n");
}
tf = search_by_fid(0x1089, NULL, SPECIFY_EF);
if (tf) {
if (!tf->data) {
TU_LOG1("Max Retries SOPIN is empty. Initializing with default max retries\r\n");
const uint8_t retries = 15;
flash_write_data_to_file(tf, &retries, sizeof(uint8_t));
}
}
else {
TU_LOG1("FATAL ERROR: Retries SOPIN not found in memory!\r\n");
}
low_flash_available();
}
uint8_t *file_read(const uint8_t *addr) {
return flash_read((uintptr_t)addr);
}
uint16_t file_read_uint16(const uint8_t *addr) {
return flash_read_uint16((uintptr_t)addr);
}
uint8_t file_read_uint8(const uint8_t *addr) {
return flash_read_uint8((uintptr_t)addr);
}
file_t *search_dynamic_file(uint16_t fid) {
for (int i = 0; i < dynamic_files; i++) {
if (dynamic_file[i].fid == fid)
return &dynamic_file[i];
}
return NULL;
}
int delete_dynamic_file(file_t *f) {
for (int i = 0; i < dynamic_files; i++) {
if (dynamic_file[i].fid == f->fid) {
for (int j = i+1; j < dynamic_files; j++)
memcpy(&dynamic_file[j-1], &dynamic_file[j], sizeof(file_t));
dynamic_files--;
return HSM_OK;
}
}
return HSM_ERR_FILE_NOT_FOUND;
}
file_t *file_new(uint16_t fid) {
file_t *f;
if ((f = search_dynamic_file(fid)))
return f;
if (dynamic_files == MAX_DYNAMIC_FILES)
return NULL;
f = &dynamic_file[dynamic_files];
dynamic_files++;
file_t file = {
.fid = fid,
.parent = 5,
.name = NULL,
.type = FILE_TYPE_WORKING_EF,
.ef_structure = FILE_EF_TRANSPARENT,
.data = NULL,
.acl = {0}
};
memcpy(f, &file, sizeof(file_t));
//memset((uint8_t *)f->acl, 0x90, sizeof(f->acl));
return f;
}
file_chain_t *add_file_to_chain(file_t *file, file_chain_t **chain) {
if (search_file_chain(file->fid, *chain))
return NULL;
file_chain_t *fc = (file_chain_t *)malloc(sizeof(file_chain_t));
fc->file = file;
fc->next = *chain;
*chain = fc;
return fc;
}
file_t *search_file_chain(uint16_t fid, file_chain_t *chain) {
for (file_chain_t *fc = chain; fc; fc = fc->next) {
if (fid == fc->file->fid) {
return fc->file;
}
}
return NULL;
}

View File

@ -1,124 +0,0 @@
/*
* This file is part of the Pico HSM distribution (https://github.com/polhenarejos/pico-hsm).
* Copyright (c) 2022 Pol Henarejos.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _FILE_H_
#define _FILE_H_
#include <stdlib.h>
#include "pico/stdlib.h"
#define FILE_TYPE_UNKNOWN 0x00
#define FILE_TYPE_DF 0x04
#define FILE_TYPE_INTERNAL_EF 0x03
#define FILE_TYPE_WORKING_EF 0x01
#define FILE_TYPE_BSO 0x10
#define FILE_PERSISTENT 0x20
#define FILE_DATA_FLASH 0x40
#define FILE_DATA_FUNC 0x80
/* EF structures */
#define FILE_EF_UNKNOWN 0x00
#define FILE_EF_TRANSPARENT 0x01
#define FILE_EF_LINEAR_FIXED 0x02
#define FILE_EF_LINEAR_FIXED_TLV 0x03
#define FILE_EF_LINEAR_VARIABLE 0x04
#define FILE_EF_LINEAR_VARIABLE_TLV 0x05
#define FILE_EF_CYCLIC 0x06
#define FILE_EF_CYCLIC_TLV 0x07
#define ACL_OP_DELETE_SELF 0x00
#define ACL_OP_CREATE_DF 0x01
#define ACL_OP_CREATE_EF 0x02
#define ACL_OP_DELETE_CHILD 0x03
#define ACL_OP_WRITE 0x04
#define ACL_OP_UPDATE_ERASE 0x05
#define ACL_OP_READ_SEARCH 0x06
#define SPECIFY_EF 0x1
#define SPECIFY_DF 0x2
#define SPECIFY_ANY 0x3
#define EF_DKEK 0x108F
#define EF_PRKDFS 0x6040
#define EF_PUKDFS 0x6041
#define EF_CDFS 0x6042
#define EF_AODFS 0x6043
#define EF_DODFS 0x6044
#define EF_SKDFS 0x6045
#define EF_DEVOPS 0x100E
#define MAX_DEPTH 4
typedef struct file
{
const uint16_t fid;
const uint8_t parent; //entry number in the whole table!!
const uint8_t *name;
const uint8_t type;
const uint8_t ef_structure;
uint8_t *data; //should include 2 bytes len at begining
const uint8_t acl[7];
} __attribute__((packed)) file_t;
typedef struct file_chain
{
file_t *file;
struct file_chain *next;
} file_chain_t;
extern file_t *currentEF;
extern file_t *currentDF;
extern const file_t *selected_applet;
extern const file_t *MF;
extern const file_t *file_last;
extern const file_t *file_openpgp;
extern const file_t *file_sc_hsm;
extern bool card_terminated;
extern file_t *file_pin1;
extern file_t *file_retries_pin1;
extern file_t *file_sopin;
extern file_t *file_retries_sopin;
extern file_t *search_by_fid(const uint16_t fid, const file_t *parent, const uint8_t sp);
extern file_t *search_by_name(uint8_t *name, uint16_t namelen);
extern file_t *search_by_path(const uint8_t *pe_path, uint8_t pathlen, const file_t *parent);
extern bool authenticate_action(const file_t *ef, uint8_t op);
extern void process_fci(const file_t *pe);
extern void scan_flash();
extern void initialize_flash(bool);
extern file_t file_entries[];
extern uint8_t *file_read(const uint8_t *addr);
extern uint16_t file_read_uint16(const uint8_t *addr);
extern uint8_t file_read_uint8(const uint8_t *addr);
extern file_t *file_new(uint16_t);
file_t *get_parent(file_t *f);
extern uint16_t dynamic_files;
extern file_t dynamic_file[];
extern file_t *search_dynamic_file(uint16_t);
extern int delete_dynamic_file(file_t *f);
extern file_chain_t *add_file_to_chain(file_t *file, file_chain_t **chain);
extern file_t *search_file_chain(uint16_t fid, file_chain_t *chain);
extern bool isUserAuthenticated;
#endif

View File

@ -1,134 +0,0 @@
/*
* This file is part of the Pico HSM distribution (https://github.com/polhenarejos/pico-hsm).
* Copyright (c) 2022 Pol Henarejos.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdint.h>
#include <string.h>
#include "pico/stdlib.h"
#include "hardware/flash.h"
#include "hsm2040.h"
#include "tusb.h"
#include "file.h"
#include "sc_hsm.h"
/*
* ------------------------------------------------------
* | |
* | next_addr | prev_addr | fid | data (len + payload) |
* | |
* ------------------------------------------------------
*/
#define FLASH_TARGET_OFFSET (PICO_FLASH_SIZE_BYTES >> 1) // DATA starts at the mid of flash
#define FLASH_DATA_HEADER_SIZE (sizeof(uintptr_t)+sizeof(uint32_t))
#define FLASH_PERMANENT_REGION (4*FLASH_SECTOR_SIZE) // 4 sectors (16kb) of permanent memory
//To avoid possible future allocations, data region starts at the end of flash and goes upwards to the center region
const uintptr_t start_data_pool = (XIP_BASE + FLASH_TARGET_OFFSET);
const uintptr_t end_data_pool = (XIP_BASE + PICO_FLASH_SIZE_BYTES)-FLASH_DATA_HEADER_SIZE-FLASH_PERMANENT_REGION; //This is a fixed value. DO NOT CHANGE
#define FLASH_ADDR_DATA_STORAGE_START start_data_pool
extern int flash_program_block(uintptr_t addr, const uint8_t *data, size_t len);
extern int flash_program_halfword (uintptr_t addr, uint16_t data);
extern int flash_program_uintptr(uintptr_t, uintptr_t);
extern uintptr_t flash_read_uintptr(uintptr_t addr);
extern uint16_t flash_read_uint16(uintptr_t addr);
extern void low_flash_available();
uintptr_t allocate_free_addr(uint16_t size) {
if (size > FLASH_SECTOR_SIZE)
return 0x0; //ERROR
size_t real_size = size+sizeof(uint16_t)+sizeof(uintptr_t)+sizeof(uint16_t)+sizeof(uintptr_t); //len+len size+next address+fid+prev_addr size
uintptr_t next_base = 0x0;
for (uintptr_t base = end_data_pool; base >= start_data_pool; base = next_base) {
uintptr_t addr_alg = base & -FLASH_SECTOR_SIZE; //start address of sector
uintptr_t potential_addr = base-real_size;
next_base = flash_read_uintptr(base);
//printf("nb %x %x %x %x\r\n",base,next_base,addr_alg,potential_addr);
//printf("fid %x\r\n",flash_read_uint16(next_base+sizeof(uintptr_t)));
if (next_base == 0x0) { //we are at the end
//now we check if we fit in the current sector
if (addr_alg <= potential_addr) //it fits in the current sector
{
flash_program_uintptr(potential_addr, 0x0);
flash_program_uintptr(potential_addr+sizeof(uintptr_t), base);
flash_program_uintptr(base, potential_addr);
return potential_addr;
}
else if (addr_alg-FLASH_SECTOR_SIZE >= start_data_pool) { //check whether it fits in the next sector, so we take addr_aligned as the base
potential_addr = addr_alg-real_size;
flash_program_uintptr(potential_addr, 0x0);
flash_program_uintptr(potential_addr+sizeof(uintptr_t), base);
flash_program_uintptr(base, potential_addr);
return potential_addr;
}
return 0x0;
}
//we check if |base-(next_addr+size_next_addr)| > |base-potential_addr| only if fid != 1xxx (not size blocked)
else if (addr_alg <= potential_addr && base-(next_base+flash_read_uint16(next_base+sizeof(uintptr_t)+sizeof(uintptr_t)+sizeof(uint16_t))+2*sizeof(uint16_t)+2*sizeof(uintptr_t)) > base-potential_addr && flash_read_uint16(next_base+sizeof(uintptr_t)) & 0x1000 != 0x1000) {
flash_program_uintptr(potential_addr, next_base);
flash_program_uintptr(potential_addr+sizeof(uintptr_t), base);
flash_program_uintptr(base, potential_addr);
return potential_addr;
}
}
return 0x0; //probably never reached
}
int flash_clear_file(file_t *file) {
uintptr_t base_addr = (uintptr_t)(file->data-sizeof(uintptr_t)-sizeof(uint16_t)-sizeof(uintptr_t));
uintptr_t prev_addr = flash_read_uintptr(base_addr+sizeof(uintptr_t));
uintptr_t next_addr = flash_read_uintptr(base_addr);
//printf("nc %x->%x %x->%x\r\n",prev_addr,flash_read_uintptr(prev_addr),base_addr,next_addr);
flash_program_uintptr(prev_addr, next_addr);
flash_program_halfword((uintptr_t)file->data, 0);
if (next_addr > 0)
flash_program_uintptr(next_addr+sizeof(uintptr_t), prev_addr);
//printf("na %x->%x\r\n",prev_addr,flash_read_uintptr(prev_addr));
return HSM_OK;
}
int flash_write_data_to_file(file_t *file, const uint8_t *data, uint16_t len) {
if (!file)
return HSM_ERR_NULL_PARAM;
if (len > FLASH_SECTOR_SIZE)
return HSM_ERR_NO_MEMORY;
if (file->data) { //already in flash
uint16_t size_file_flash = flash_read_uint16((uintptr_t)file->data);
if (len <= size_file_flash) { //it fits, no need to move it
flash_program_halfword((uintptr_t)file->data, len);
if (data)
flash_program_block((uintptr_t)file->data+sizeof(uint16_t), data, len);
return HSM_OK;
}
else { //we clear the old file
flash_clear_file(file);
}
}
uintptr_t new_addr = allocate_free_addr(len);
//printf("na %x\r\n",new_addr);
if (new_addr == 0x0)
return HSM_ERR_NO_MEMORY;
file->data = (uint8_t *)new_addr+sizeof(uintptr_t)+sizeof(uint16_t)+sizeof(uintptr_t); //next addr+fid+prev addr
flash_program_halfword(new_addr+sizeof(uintptr_t)+sizeof(uintptr_t), file->fid);
flash_program_halfword((uintptr_t)file->data, len);
if (data)
flash_program_block((uintptr_t)file->data+sizeof(uint16_t), data, len);
return HSM_OK;
}

View File

@ -1,248 +0,0 @@
/*
* This file is part of the Pico HSM distribution (https://github.com/polhenarejos/pico-hsm).
* Copyright (c) 2022 Pol Henarejos.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include "pico/stdlib.h"
#include "hardware/flash.h"
#include "hardware/sync.h"
#include "pico/mutex.h"
#include "pico/sem.h"
#include "pico/multicore.h"
#include "hsm2040.h"
#include "sc_hsm.h"
#include <string.h>
#define TOTAL_FLASH_PAGES 4
typedef struct page_flash {
uint8_t page[FLASH_SECTOR_SIZE];
uintptr_t address;
bool ready;
bool erase;
size_t page_size; //this param is for easy erase. It allows to erase with a single call. IT DOES NOT APPLY TO WRITE
} page_flash_t;
static page_flash_t flash_pages[TOTAL_FLASH_PAGES];
static mutex_t mtx_flash;
static semaphore_t sem_wait;
static uint8_t ready_pages = 0;
bool flash_available = false;
static bool locked_out = false;
//this function has to be called from the core 0
void do_flash()
{
if (mutex_try_enter(&mtx_flash, NULL) == true) {
if (locked_out == true && flash_available == true && ready_pages > 0) {
//printf(" DO_FLASH AVAILABLE\r\n");
for (int r = 0; r < TOTAL_FLASH_PAGES; r++) {
if (flash_pages[r].ready == true) {
//printf("WRITTING %X\r\n",flash_pages[r].address-XIP_BASE);
while (multicore_lockout_start_timeout_us(1000) == false);
//printf("WRITTING %X\r\n",flash_pages[r].address-XIP_BASE);
uint32_t ints = save_and_disable_interrupts();
flash_range_erase(flash_pages[r].address-XIP_BASE, FLASH_SECTOR_SIZE);
flash_range_program(flash_pages[r].address-XIP_BASE, flash_pages[r].page, FLASH_SECTOR_SIZE);
restore_interrupts (ints);
while (multicore_lockout_end_timeout_us(1000) == false);
//printf("WRITEN %X !\r\n",flash_pages[r].address);
flash_pages[r].ready = false;
ready_pages--;
}
else if (flash_pages[r].erase == true) {
while (multicore_lockout_start_timeout_us(1000) == false);
//printf("WRITTING\r\n");
flash_range_erase(flash_pages[r].address-XIP_BASE, flash_pages[r].page_size ? ((int)(flash_pages[r].page_size/FLASH_SECTOR_SIZE))*FLASH_SECTOR_SIZE : FLASH_SECTOR_SIZE);
while (multicore_lockout_end_timeout_us(1000) == false);
flash_pages[r].erase = false;
ready_pages--;
}
}
flash_available = false;
if (ready_pages != 0) {
DEBUG_INFO("ERROR: DO FLASH DOES NOT HAVE ZERO PAGES");
}
}
mutex_exit(&mtx_flash);
}
sem_release(&sem_wait);
}
//this function has to be called from the core 0
void low_flash_init() {
mutex_init(&mtx_flash);
sem_init(&sem_wait, 0, 1);
memset(flash_pages, 0, sizeof(page_flash_t)*TOTAL_FLASH_PAGES);
}
void low_flash_init_core1() {
mutex_enter_blocking(&mtx_flash);
multicore_lockout_victim_init();
locked_out = true;
mutex_exit(&mtx_flash);
}
void wait_flash_finish() {
sem_acquire_blocking(&sem_wait); //blocks until released
//wake up
sem_acquire_blocking(&sem_wait); //decrease permits
}
void low_flash_available() {
mutex_enter_blocking(&mtx_flash);
flash_available = true;
mutex_exit(&mtx_flash);
}
page_flash_t *find_free_page(uintptr_t addr) {
uintptr_t addr_alg = addr & -FLASH_SECTOR_SIZE;
page_flash_t *p = NULL;
for (int r = 0; r < TOTAL_FLASH_PAGES; r++)
{
if ((!flash_pages[r].ready && !flash_pages[r].erase) || flash_pages[r].address == addr_alg) //first available
{
p = &flash_pages[r];
if (!flash_pages[r].ready && !flash_pages[r].erase)
{
memcpy(p->page, (uint8_t *)addr_alg, FLASH_SECTOR_SIZE);
ready_pages++;
p->address = addr_alg;
p->ready = true;
}
return p;
}
}
return NULL;
}
int flash_program_block(uintptr_t addr, const uint8_t *data, size_t len) {
uintptr_t addr_alg = addr & -FLASH_SECTOR_SIZE;
page_flash_t *p = NULL;
if (!data || len == 0)
return HSM_ERR_NULL_PARAM;
mutex_enter_blocking(&mtx_flash);
if (ready_pages == TOTAL_FLASH_PAGES) {
mutex_exit(&mtx_flash);
DEBUG_INFO("ERROR: ALL FLASH PAGES CACHED\r\n");
return HSM_ERR_NO_MEMORY;
}
if (!(p = find_free_page(addr)))
{
mutex_exit(&mtx_flash);
DEBUG_INFO("ERROR: FLASH CANNOT FIND A PAGE (rare error)\r\n");
return HSM_ERR_MEMORY_FATAL;
}
memcpy(&p->page[addr&(FLASH_SECTOR_SIZE-1)], data, len);
//printf("Flash: modified page %X with data %x at [%x] (top page %X)\r\n",addr_alg,data,addr&(FLASH_SECTOR_SIZE-1),addr);
mutex_exit(&mtx_flash);
return HSM_OK;
}
int flash_program_halfword (uintptr_t addr, uint16_t data) {
return flash_program_block(addr, (const uint8_t *)&data, sizeof(uint16_t));
}
int flash_program_word (uintptr_t addr, uint32_t data) {
return flash_program_block(addr, (const uint8_t *)&data, sizeof(uint32_t));
}
int flash_program_uintptr (uintptr_t addr, uintptr_t data) {
return flash_program_block(addr, (const uint8_t *)&data, sizeof(uintptr_t));
}
uint8_t *flash_read(uintptr_t addr) {
uintptr_t addr_alg = addr & -FLASH_SECTOR_SIZE;
mutex_enter_blocking(&mtx_flash);
if (ready_pages > 0) {
for (int r = 0; r < TOTAL_FLASH_PAGES; r++)
{
if (flash_pages[r].ready && flash_pages[r].address == addr_alg) {
uint8_t *v = &flash_pages[r].page[addr&(FLASH_SECTOR_SIZE-1)];
mutex_exit(&mtx_flash);
return v;
}
}
}
uint8_t *v = (uint8_t *)addr;
mutex_exit(&mtx_flash);
return v;
}
uintptr_t flash_read_uintptr(uintptr_t addr) {
uint8_t *p = flash_read(addr);
uintptr_t v = 0x0;
for (int i = 0; i < sizeof(uintptr_t); i++) {
v |= (uintptr_t)p[i]<<(8*i);
}
return v;
}
uint16_t flash_read_uint16(uintptr_t addr) {
uint8_t *p = flash_read(addr);
uint16_t v = 0x0;
for (int i = 0; i < sizeof(uint16_t); i++) {
v |= p[i]<<(8*i);
}
return v;
}
uint8_t flash_read_uint8(uintptr_t addr) {
return *flash_read(addr);
}
int flash_erase_page (uintptr_t addr, size_t page_size) {
uintptr_t addr_alg = addr & -FLASH_SECTOR_SIZE;
page_flash_t *p = NULL;
mutex_enter_blocking(&mtx_flash);
if (ready_pages == TOTAL_FLASH_PAGES) {
mutex_exit(&mtx_flash);
DEBUG_INFO("ERROR: ALL FLASH PAGES CACHED\r\n");
return HSM_ERR_NO_MEMORY;
}
if (!(p = find_free_page(addr))) {
DEBUG_INFO("ERROR: FLASH CANNOT FIND A PAGE (rare error)\r\n");
mutex_exit(&mtx_flash);
return HSM_ERR_MEMORY_FATAL;
}
p->erase = true;
p->ready = false;
p->page_size = page_size;
mutex_exit(&mtx_flash);
return HSM_OK;
}
bool flash_check_blank(const uint8_t *p_start, size_t size)
{
const uint8_t *p;
for (p = p_start; p < p_start + size; p++) {
if (*p != 0xff)
return false;
}
return true;
}

View File

@ -85,7 +85,7 @@ int aes_encrypt(const uint8_t *key, const uint8_t *iv, int key_size, int mode, u
memcpy(tmp_iv, iv, IV_SIZE);
int r = mbedtls_aes_setkey_enc(&aes, key, key_size);
if (r != 0)
return HSM_EXEC_ERROR;
return CCID_EXEC_ERROR;
if (mode == HSM_AES_MODE_CBC)
return mbedtls_aes_crypt_cbc(&aes, MBEDTLS_AES_ENCRYPT, len, tmp_iv, data, data);
return mbedtls_aes_crypt_cfb128(&aes, MBEDTLS_AES_ENCRYPT, len, &iv_offset, tmp_iv, data, data);
@ -101,7 +101,7 @@ int aes_decrypt(const uint8_t *key, const uint8_t *iv, int key_size, int mode, u
memcpy(tmp_iv, iv, IV_SIZE);
int r = mbedtls_aes_setkey_dec(&aes, key, key_size);
if (r != 0)
return HSM_EXEC_ERROR;
return CCID_EXEC_ERROR;
if (mode == HSM_AES_MODE_CBC)
return mbedtls_aes_crypt_cbc(&aes, MBEDTLS_AES_DECRYPT, len, tmp_iv, data, data);
r = mbedtls_aes_setkey_enc(&aes, key, key_size); //CFB requires set_enc instead set_dec

View File

@ -27,6 +27,7 @@
#include "mbedtls/cmac.h"
#include "mbedtls/rsa.h"
#include "mbedtls/ecdsa.h"
#include "files.h"
static uint8_t dkek[IV_SIZE+32];
static uint8_t tmp_dkek[32];
@ -35,15 +36,15 @@ extern uint8_t session_pin[32];
int load_dkek() {
if (has_session_pin == false)
return HSM_NO_LOGIN;
return CCID_NO_LOGIN;
file_t *tf = search_by_fid(EF_DKEK, NULL, SPECIFY_EF);
if (!tf)
return HSM_ERR_FILE_NOT_FOUND;
return CCID_ERR_FILE_NOT_FOUND;
memcpy(dkek, file_read(tf->data+sizeof(uint16_t)), IV_SIZE+32);
int ret = aes_decrypt_cfb_256(session_pin, dkek, dkek+IV_SIZE, 32);
if (ret != 0)
return HSM_EXEC_ERROR;
return HSM_OK;
return CCID_EXEC_ERROR;
return CCID_OK;
}
void release_dkek() {
@ -59,11 +60,11 @@ int store_dkek_key() {
aes_encrypt_cfb_256(session_pin, dkek, dkek+IV_SIZE, 32);
file_t *tf = search_by_fid(EF_DKEK, NULL, SPECIFY_EF);
if (!tf)
return HSM_ERR_FILE_NOT_FOUND;
return CCID_ERR_FILE_NOT_FOUND;
flash_write_data_to_file(tf, dkek, sizeof(dkek));
low_flash_available();
release_dkek();
return HSM_OK;
return CCID_OK;
}
int save_dkek_key(const uint8_t *key) {
@ -83,43 +84,43 @@ void import_dkek_share(const uint8_t *share) {
int dkek_kcv(uint8_t *kcv) { //kcv 8 bytes
uint8_t hsh[32];
int r = load_dkek();
if (r != HSM_OK)
if (r != CCID_OK)
return r;
hash256(dkek+IV_SIZE, 32, hsh);
release_dkek();
memcpy(kcv, hsh, 8);
return HSM_OK;
return CCID_OK;
}
int dkek_kenc(uint8_t *kenc) { //kenc 32 bytes
uint8_t buf[32+4];
int r = load_dkek();
if (r != HSM_OK)
if (r != CCID_OK)
return r;
memcpy(buf, dkek+IV_SIZE, 32);
release_dkek();
memcpy(buf+32, "\x0\x0\x0\x1", 4);
hash256(buf, sizeof(buf), kenc);
memset(buf, 0, sizeof(buf));
return HSM_OK;
return CCID_OK;
}
int dkek_kmac(uint8_t *kmac) { //kmac 32 bytes
uint8_t buf[32+4];
int r = load_dkek();
if (r != HSM_OK)
if (r != CCID_OK)
return r;
memcpy(buf, dkek+IV_SIZE, 32);
release_dkek();
memcpy(buf+32, "\x0\x0\x0\x2", 4);
hash256(buf, sizeof(buf), kmac);
memset(buf, 0, sizeof(buf));
return HSM_OK;
return CCID_OK;
}
int dkek_encrypt(uint8_t *data, size_t len) {
int r;
if ((r = load_dkek()) != HSM_OK)
if ((r = load_dkek()) != CCID_OK)
return r;
r = aes_encrypt_cfb_256(dkek+IV_SIZE, dkek, data, len);
release_dkek();
@ -128,7 +129,7 @@ int dkek_encrypt(uint8_t *data, size_t len) {
int dkek_decrypt(uint8_t *data, size_t len) {
int r;
if ((r = load_dkek()) != HSM_OK)
if ((r = load_dkek()) != CCID_OK)
return r;
r = aes_decrypt_cfb_256(dkek+IV_SIZE, dkek, data, len);
release_dkek();
@ -137,7 +138,7 @@ int dkek_decrypt(uint8_t *data, size_t len) {
int dkek_encode_key(void *key_ctx, int key_type, uint8_t *out, size_t *out_len) {
if (!(key_type & HSM_KEY_RSA) && !(key_type & HSM_KEY_EC) && !(key_type & HSM_KEY_AES))
return HSM_WRONG_DATA;
return CCID_WRONG_DATA;
uint8_t kb[8+2*4+2*4096/8+3+13]; //worst case: RSA-4096 (plus, 13 bytes padding)
memset(kb, 0, sizeof(kb));
@ -167,9 +168,9 @@ int dkek_encode_key(void *key_ctx, int key_type, uint8_t *out, size_t *out_len)
kb_len = 32;
if (kb_len != 16 && kb_len != 24 && kb_len != 32)
return HSM_WRONG_DATA;
return CCID_WRONG_DATA;
if (*out_len < 8+1+10+6+4+(2+32+14)+16)
return HSM_WRONG_LENGTH;
return CCID_WRONG_LENGTH;
put_uint16_t(kb_len, kb+8);
memcpy(kb+10, key_ctx, kb_len);
@ -182,7 +183,7 @@ int dkek_encode_key(void *key_ctx, int key_type, uint8_t *out, size_t *out_len)
}
else if (key_type & HSM_KEY_RSA) {
if (*out_len < 8+1+12+6+(8+2*4+2*4096/8+3+13)+16) //13 bytes pading
return HSM_WRONG_LENGTH;
return CCID_WRONG_LENGTH;
mbedtls_rsa_context *rsa = (mbedtls_rsa_context *)key_ctx;
kb_len = 0;
put_uint16_t(mbedtls_rsa_get_len(rsa)*8, kb+8+kb_len); kb_len += 2;
@ -199,7 +200,7 @@ int dkek_encode_key(void *key_ctx, int key_type, uint8_t *out, size_t *out_len)
}
else if (key_type & HSM_KEY_EC) {
if (*out_len < 8+1+12+6+(8+2*8+9*66+2+4)+16) //4 bytes pading
return HSM_WRONG_LENGTH;
return CCID_WRONG_LENGTH;
mbedtls_ecdsa_context *ecdsa = (mbedtls_ecdsa_context *)key_ctx;
kb_len = 0;
put_uint16_t(mbedtls_mpi_size(&ecdsa->grp.P)*8, kb+8+kb_len); kb_len += 2;
@ -265,7 +266,7 @@ int dkek_encode_key(void *key_ctx, int key_type, uint8_t *out, size_t *out_len)
kb[kb_len] = 0x80;
}
int r = aes_encrypt(kenc, NULL, 256, HSM_AES_MODE_CBC, kb, kb_len_pad);
if (r != HSM_OK)
if (r != CCID_OK)
return r;
memcpy(out+*out_len, kb, kb_len_pad);
@ -276,7 +277,7 @@ int dkek_encode_key(void *key_ctx, int key_type, uint8_t *out, size_t *out_len)
*out_len += 16;
if (r != 0)
return r;
return HSM_OK;
return CCID_OK;
}
int dkek_type_key(const uint8_t *in) {
@ -303,27 +304,27 @@ int dkek_decode_key(void *key_ctx, const uint8_t *in, size_t in_len, int *key_si
dkek_kenc(kenc);
if (memcmp(kcv, in, 8) != 0)
return HSM_WRONG_DKEK;
return CCID_WRONG_DKEK;
uint8_t signature[16];
int r = mbedtls_cipher_cmac(mbedtls_cipher_info_from_type(MBEDTLS_CIPHER_AES_256_ECB), kmac, 256, in, in_len-16, signature);
if (r != 0)
return HSM_WRONG_SIGNATURE;
return CCID_WRONG_SIGNATURE;
if (memcmp(signature, in+in_len-16, 16) != 0)
return HSM_WRONG_SIGNATURE;
return CCID_WRONG_SIGNATURE;
int key_type = in[8];
if (key_type != 5 && key_type != 6 && key_type != 12 && key_type != 15)
return HSM_WRONG_DATA;
return CCID_WRONG_DATA;
if ((key_type == 5 || key_type == 6) && memcmp(in+9, "\x00\x0A\x04\x00\x7F\x00\x07\x02\x02\x02\x01\x02", 12) != 0)
return HSM_WRONG_DATA;
return CCID_WRONG_DATA;
if (key_type == 12 && memcmp(in+9, "\x00\x0A\x04\x00\x7F\x00\x07\x02\x02\x02\x02\x03", 12) != 0)
return HSM_WRONG_DATA;
return CCID_WRONG_DATA;
if (key_type == 15 && memcmp(in+9, "\x00\x08\x60\x86\x48\x01\x65\x03\x04\x01", 10) != 0)
return HSM_WRONG_DATA;
return CCID_WRONG_DATA;
size_t ofs = 9;
@ -344,12 +345,12 @@ int dkek_decode_key(void *key_ctx, const uint8_t *in, size_t in_len, int *key_si
ofs += len+2;
if ((in_len-16-ofs) % 16 != 0)
return HSM_WRONG_PADDING;
return CCID_WRONG_PADDING;
uint8_t kb[8+2*4+2*4096/8+3+13]; //worst case: RSA-4096 (plus, 13 bytes padding)
memset(kb, 0, sizeof(kb));
memcpy(kb, in+ofs, in_len-16-ofs);
r = aes_decrypt(kenc, NULL, 256, HSM_AES_MODE_CBC, kb, in_len-16-ofs);
if (r != HSM_OK)
if (r != CCID_OK)
return r;
int key_size = get_uint16_t(kb, 8);
@ -364,14 +365,14 @@ int dkek_decode_key(void *key_ctx, const uint8_t *in, size_t in_len, int *key_si
r = mbedtls_mpi_read_binary(&rsa->D, kb+ofs, len); ofs += len;
if (r != 0) {
mbedtls_rsa_free(rsa);
return HSM_WRONG_DATA;
return CCID_WRONG_DATA;
}
len = get_uint16_t(kb, ofs); ofs += 2;
r = mbedtls_mpi_read_binary(&rsa->N, kb+ofs, len); ofs += len;
if (r != 0) {
mbedtls_rsa_free(rsa);
return HSM_WRONG_DATA;
return CCID_WRONG_DATA;
}
}
else if (key_type == 6) {
@ -385,7 +386,7 @@ int dkek_decode_key(void *key_ctx, const uint8_t *in, size_t in_len, int *key_si
r = mbedtls_mpi_read_binary(&rsa->P, kb+ofs, len); ofs += len;
if (r != 0) {
mbedtls_rsa_free(rsa);
return HSM_WRONG_DATA;
return CCID_WRONG_DATA;
}
//PQ
@ -395,7 +396,7 @@ int dkek_decode_key(void *key_ctx, const uint8_t *in, size_t in_len, int *key_si
r = mbedtls_mpi_read_binary(&rsa->Q, kb+ofs, len); ofs += len;
if (r != 0) {
mbedtls_rsa_free(rsa);
return HSM_WRONG_DATA;
return CCID_WRONG_DATA;
}
//N
len = get_uint16_t(kb, ofs); ofs += len+2;
@ -405,33 +406,33 @@ int dkek_decode_key(void *key_ctx, const uint8_t *in, size_t in_len, int *key_si
r = mbedtls_mpi_read_binary(&rsa->E, kb+ofs, len); ofs += len;
if (r != 0) {
mbedtls_rsa_free(rsa);
return HSM_WRONG_DATA;
return CCID_WRONG_DATA;
}
if (key_type == 5) {
r = mbedtls_rsa_import(rsa, &rsa->N, NULL, NULL, &rsa->D, &rsa->E);
if (r != 0) {
mbedtls_rsa_free(rsa);
return HSM_EXEC_ERROR;
return CCID_EXEC_ERROR;
}
}
else if (key_type == 6) {
r = mbedtls_rsa_import(rsa, NULL, &rsa->P, &rsa->Q, NULL, &rsa->E);
if (r != 0) {
mbedtls_rsa_free(rsa);
return HSM_EXEC_ERROR;
return CCID_EXEC_ERROR;
}
}
r = mbedtls_rsa_complete(rsa);
if (r != 0) {
mbedtls_rsa_free(rsa);
return HSM_EXEC_ERROR;
return CCID_EXEC_ERROR;
}
r = mbedtls_rsa_check_privkey(rsa);
if (r != 0) {
mbedtls_rsa_free(rsa);
return HSM_EXEC_ERROR;
return CCID_EXEC_ERROR;
}
}
else if (key_type == 12) {
@ -449,7 +450,7 @@ int dkek_decode_key(void *key_ctx, const uint8_t *in, size_t in_len, int *key_si
mbedtls_ecp_group_id ec_id = ec_get_curve_from_prime(kb+ofs, len);
if (ec_id == MBEDTLS_ECP_DP_NONE) {
mbedtls_ecdsa_free(ecdsa);
return HSM_WRONG_DATA;
return CCID_WRONG_DATA;
}
ofs += len;
@ -464,11 +465,11 @@ int dkek_decode_key(void *key_ctx, const uint8_t *in, size_t in_len, int *key_si
r = mbedtls_ecp_read_key(ec_id, ecdsa, kb+ofs, len);
if (r != 0) {
mbedtls_ecdsa_free(ecdsa);
return HSM_EXEC_ERROR;
return CCID_EXEC_ERROR;
}
}
else if (key_type == 15) {
memcpy(key_ctx, kb+ofs, key_size);
}
return HSM_OK;
return CCID_OK;
}

View File

@ -83,9 +83,9 @@ int sm_sign(uint8_t *in, size_t in_len, uint8_t *out) {
int sm_unwrap() {
uint8_t sm_indicator = (CLA(apdu) >> 2) & 0x3;
if (sm_indicator == 0)
return HSM_OK;
return CCID_OK;
int r = sm_verify();
if (r != HSM_OK)
if (r != CCID_OK)
return r;
int le = sm_get_le();
if (le >= 0)
@ -106,22 +106,22 @@ int sm_unwrap() {
}
}
if (!body)
return HSM_WRONG_DATA;
return CCID_WRONG_DATA;
if (is87 && *body++ != 0x1) {
return HSM_WRONG_PADDING;
return CCID_WRONG_PADDING;
}
sm_update_iv();
aes_decrypt(sm_kenc, sm_iv, 128, HSM_AES_MODE_CBC, body, body_size);
memmove(apdu.cmd_apdu_data, body, body_size);
apdu.cmd_apdu_data_len = sm_remove_padding(apdu.cmd_apdu_data, body_size);
DEBUG_PAYLOAD(apdu.cmd_apdu_data, apdu.cmd_apdu_data_len);
return HSM_OK;
return CCID_OK;
}
int sm_wrap() {
uint8_t sm_indicator = (CLA(apdu) >> 2) & 0x3;
if (sm_indicator == 0)
return HSM_OK;
return CCID_OK;
uint8_t input[1024];
size_t input_len = 0;
memset(input, 0, sizeof(input));
@ -176,7 +176,7 @@ int sm_wrap() {
res_APDU_size += 8;
if (apdu.expected_res_size > 0)
apdu.expected_res_size = res_APDU_size;
return HSM_OK;
return CCID_OK;
}
int sm_get_le() {
@ -210,7 +210,7 @@ int sm_verify() {
if (data_len % sm_blocksize)
data_len += sm_blocksize;
if (data_len+(add_header ? sm_blocksize : 0) > 1024)
return HSM_WRONG_LENGTH;
return CCID_WRONG_LENGTH;
mbedtls_mpi ssc;
mbedtls_mpi_init(&ssc);
mbedtls_mpi_add_int(&ssc, &sm_mSSC, 1);
@ -219,7 +219,7 @@ int sm_verify() {
input_len += sm_blocksize;
mbedtls_mpi_free(&ssc);
if (r != 0)
return HSM_EXEC_ERROR;
return CCID_EXEC_ERROR;
if (add_header) {
input[input_len++] = CLA(apdu);
input[input_len++] = INS(apdu);
@ -248,7 +248,7 @@ int sm_verify() {
}
}
if (!mac)
return HSM_WRONG_DATA;
return CCID_WRONG_DATA;
if (some_added) {
input[input_len++] = 0x80;
input_len += (sm_blocksize - (input_len%sm_blocksize));
@ -256,10 +256,10 @@ int sm_verify() {
uint8_t signature[16];
r = sm_sign(input, input_len, signature);
if (r != 0)
return HSM_EXEC_ERROR;
return CCID_EXEC_ERROR;
if (memcmp(signature, mac, mac_len) == 0)
return HSM_OK;
return HSM_VERIFICATION_FAILED;
return CCID_OK;
return CCID_VERIFICATION_FAILED;
}
int sm_remove_padding(const uint8_t *data, size_t data_len) {

View File

@ -20,7 +20,7 @@
#include <stdlib.h>
#include "pico/stdlib.h"
#include "hsm2040.h"
#include "ccid2040.h"
typedef enum MSE_protocol {
MSE_AES = 0,

60
src/hsm/files.c Normal file
View File

@ -0,0 +1,60 @@
/*
* This file is part of the Pico HSM distribution (https://github.com/polhenarejos/pico-hsm).
* Copyright (c) 2022 Pol Henarejos.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "files.h"
extern const uint8_t sc_hsm_aid[];
extern int parse_token_info(const file_t *f, int mode);
extern int parse_cvca(const file_t *f, int mode);
file_t file_entries[] = {
/* 0 */ { .fid = 0x3f00 , .parent = 0xff, .name = NULL, .type = FILE_TYPE_DF, .data = NULL, .ef_structure = 0, .acl = {0} }, // MF
/* 1 */ { .fid = 0x2f00 , .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.DIR
/* 2 */ { .fid = 0x2f01 , .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.ATR
/* 3 */ { .fid = 0x2f02 , .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF | FILE_DATA_FUNC,.data = (uint8_t *)parse_cvca, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.GDO
/* 4 */ { .fid = 0x2f03 , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF | FILE_DATA_FUNC,.data = (uint8_t *)parse_token_info, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.TokenInfo
/* 5 */ { .fid = 0x5015 , .parent = 0, .name = NULL, .type = FILE_TYPE_DF, .data = NULL, .ef_structure = 0, .acl = {0} }, //DF.PKCS15
/* 6 */ { .fid = 0x5031 , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.ODF
/* 7 */ { .fid = 0x5032 , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.TokenInfo
/* 8 */ { .fid = 0x5033 , .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.UnusedSpace
/* 9 */ { .fid = 0x1081 , .parent = 5, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff} }, //PIN (PIN1)
/* 10 */ { .fid = 0x1082 , .parent = 5, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff} }, //max retries PIN (PIN1)
/* 11 */ { .fid = 0x1083 , .parent = 5, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff} }, //retries PIN (PIN1)
/* 12 */ { .fid = 0x1088 , .parent = 5, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff} }, //PIN (SOPIN)
/* 13 */ { .fid = 0x1089 , .parent = 5, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff} }, //max retries PIN (SOPIN)
/* 14 */ { .fid = 0x108A , .parent = 5, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff} }, //retries PIN (SOPIN)
/* 15 */ { .fid = EF_DKEK , .parent = 5, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff} }, //DKEK
/* 16 */ { .fid = EF_DEVOPS , .parent = 5, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff} }, //Device options
/* 17 */ { .fid = EF_PRKDFS , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.PrKDFs
/* 18 */ { .fid = EF_PUKDFS , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.PuKDFs
/* 19 */ { .fid = EF_CDFS , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.CDFs
/* 20 */ { .fid = EF_AODFS , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.AODFs
/* 21 */ { .fid = EF_DODFS , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.DODFs
/* 22 */ { .fid = EF_SKDFS , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.SKDFs
///* 23 */ { .fid = 0x0000, .parent = 0, .name = openpgpcard_aid, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} },
/* 24 */ { .fid = 0x0000, .parent = 5, .name = sc_hsm_aid, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} },
/* 25 */ { .fid = 0x0000, .parent = 0xff, .name = NULL, .type = FILE_TYPE_UNKNOWN, .data = NULL, .ef_structure = 0, .acl = {0} } //end
};
const file_t *MF = &file_entries[0];
const file_t *file_last = &file_entries[sizeof(file_entries)/sizeof(file_t)-1];
const file_t *file_openpgp = &file_entries[sizeof(file_entries)/sizeof(file_t)-3];
const file_t *file_sc_hsm = &file_entries[sizeof(file_entries)/sizeof(file_t)-2];
file_t *file_pin1 = NULL;
file_t *file_retries_pin1 = NULL;
file_t *file_sopin = NULL;
file_t *file_retries_sopin = NULL;

View File

@ -15,15 +15,24 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _NEUG_H_
#define _NEUG_H_
#define NEUG_PRE_LOOP 32
#ifndef _FILES_H_
#define _FILES_H_
void neug_init(uint32_t *buf, uint8_t size);
uint32_t neug_get();
void neug_flush(void);
void neug_wait_full(void);
void neug_fini(void);
#include "file.h"
#define EF_DKEK 0x108F
#define EF_PRKDFS 0x6040
#define EF_PUKDFS 0x6041
#define EF_CDFS 0x6042
#define EF_AODFS 0x6043
#define EF_DODFS 0x6044
#define EF_SKDFS 0x6045
#define EF_DEVOPS 0x100E
extern file_t *file_pin1;
extern file_t *file_retries_pin1;
extern file_t *file_sopin;
extern file_t *file_retries_sopin;
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,178 +0,0 @@
/*
* This file is part of the Pico HSM distribution (https://github.com/polhenarejos/pico-hsm).
* Copyright (c) 2022 Pol Henarejos.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _HSM2040_H_
#define _HSM2040_H_
#include "ccid.h"
#include "tusb.h"
#include "file.h"
#include "pico/unique_id.h"
#include "pico/util/queue.h"
#define USB_REQ_CCID 0xA1
typedef struct app {
const uint8_t *aid;
int (*process_apdu)();
struct app* (*select_aid)();
int (*unload)();
} app_t;
extern int register_app(app_t * (*)());
extern const uint8_t historical_bytes[];
#define DEBUG_PAYLOAD(p,s) { \
printf("Payload %s (%d bytes):\r\n", #p,s);\
for (int i = 0; i < s; i += 16) {\
printf("%07Xh : ",i+p);\
for (int j = 0; j < 16; j++) {\
if (j < s-i) printf("%02X ",(p)[i+j]);\
else printf(" ");\
if (j == 7) printf(" ");\
} printf(": "); \
for (int j = 0; j < MIN(16,s-i); j++) {\
printf("%c",(p)[i+j] == 0x0a || (p)[i+j] == 0x0d ? '\\' : (p)[i+j]);\
if (j == 7) printf(" ");\
}\
printf("\r\n");\
} printf("\r\n"); \
}
struct apdu {
uint8_t seq;
/* command APDU */
uint8_t *cmd_apdu_head; /* CLS INS P1 P2 [ internal Lc ] */
uint8_t *cmd_apdu_data;
size_t cmd_apdu_data_len; /* Nc, calculated by Lc field */
size_t expected_res_size; /* Ne, calculated by Le field */
/* response APDU */
uint16_t sw;
uint16_t res_apdu_data_len;
uint8_t *res_apdu_data;
};
#define MAX_CMD_APDU_DATA_SIZE (24+4+512*4)
#define MAX_RES_APDU_DATA_SIZE (5+9+512*4)
#define CCID_MSG_HEADER_SIZE 10
#define USB_LL_BUF_SIZE 64
/* CCID thread */
#define EV_CARD_CHANGE 1
#define EV_TX_FINISHED 2 /* CCID Tx finished */
#define EV_EXEC_ACK_REQUIRED 4 /* OpenPGPcard Execution ACK required */
#define EV_EXEC_FINISHED 8 /* OpenPGPcard Execution finished */
#define EV_RX_DATA_READY 16 /* USB Rx data available */
#define EV_PRESS_BUTTON 32
/* SC HSM thread */
#define EV_MODIFY_CMD_AVAILABLE 1
#define EV_VERIFY_CMD_AVAILABLE 2
#define EV_CMD_AVAILABLE 4
#define EV_EXIT 8
#define EV_BUTTON_PRESSED 16
//Variables set by core1
extern queue_t *ccid_comm;
extern queue_t *card_comm;
enum ccid_state {
CCID_STATE_NOCARD, /* No card available */
CCID_STATE_START, /* Initial */
CCID_STATE_WAIT, /* Waiting APDU */
CCID_STATE_EXECUTE, /* Executing command */
CCID_STATE_ACK_REQUIRED_0, /* Ack required (executing)*/
CCID_STATE_ACK_REQUIRED_1, /* Waiting user's ACK (execution finished) */
CCID_STATE_EXITED, /* CCID Thread Terminated */
CCID_STATE_EXEC_REQUESTED, /* Exec requested */
};
#define CLA(a) a.cmd_apdu_head[0]
#define INS(a) a.cmd_apdu_head[1]
#define P1(a) a.cmd_apdu_head[2]
#define P2(a) a.cmd_apdu_head[3]
#define res_APDU apdu.res_apdu_data
#define res_APDU_size apdu.res_apdu_data_len
extern struct apdu apdu;
uint16_t set_res_sw (uint8_t sw1, uint8_t sw2);
static inline const uint16_t make_uint16_t(uint8_t b1, uint8_t b2) {
return (b1 << 8) | b2;
}
static inline const uint16_t get_uint16_t(const uint8_t *b, uint16_t offset) {
return make_uint16_t(b[offset], b[offset+1]);
}
static inline const void put_uint16_t(uint16_t n, uint8_t *b) {
*b++ = (n >> 8) & 0xff;
*b = n & 0xff;
}
#ifdef DEBUG
void stdout_init (void);
#define DEBUG_MORE 1
/*
* Debug functions in debug.c
*/
void put_byte (uint8_t b);
void put_byte_with_no_nl (uint8_t b);
void put_short (uint16_t x);
void put_word (uint32_t x);
void put_int (uint32_t x);
void put_string (const char *s);
void put_binary (const char *s, int len);
#define DEBUG_INFO(msg) put_string (msg)
#define DEBUG_WORD(w) put_word (w)
#define DEBUG_SHORT(h) put_short (h)
#define DEBUG_BYTE(b) put_byte (b)
#define DEBUG_BINARY(s,len) put_binary ((const char *)s,len)
#else
#define DEBUG_INFO(msg)
#define DEBUG_WORD(w)
#define DEBUG_SHORT(h)
#define DEBUG_BYTE(b)
#define DEBUG_BINARY(s,len)
#endif
extern int flash_write_data_to_file(file_t *file, const uint8_t *data, uint16_t len);
extern void low_flash_available();
extern int flash_clear_file(file_t *file);
extern pico_unique_board_id_t unique_id;
enum {
BLINK_NOT_MOUNTED = (250 << 16) | 250,
BLINK_MOUNTED = (250 << 16) | 250,
BLINK_SUSPENDED = (500 << 16) | 1000,
BLINK_PROCESSING = (50 << 16) | 50,
BLINK_ALWAYS_ON = UINT32_MAX,
BLINK_ALWAYS_OFF = 0
};
extern void led_set_blink(uint32_t mode);
#endif

View File

@ -16,7 +16,7 @@
*/
#include "sc_hsm.h"
#include "file.h"
#include "files.h"
#include "libopensc/card-sc-hsm.h"
#include "random.h"
#include "common.h"
@ -65,8 +65,85 @@ void __attribute__ ((constructor)) sc_hsm_ctor() {
register_app(sc_hsm_select_aid);
}
void init_sc_hsm() {
void scan_files() {
file_pin1 = search_by_fid(0x1081, NULL, SPECIFY_EF);
if (file_pin1) {
if (!file_pin1->data) {
TU_LOG1("PIN1 is empty. Initializing with default password\r\n");
const uint8_t empty[33] = { 0 };
flash_write_data_to_file(file_pin1, empty, sizeof(empty));
}
}
else {
TU_LOG1("FATAL ERROR: PIN1 not found in memory!\r\n");
}
file_sopin = search_by_fid(0x1088, NULL, SPECIFY_EF);
if (file_sopin) {
if (!file_sopin->data) {
TU_LOG1("SOPIN is empty. Initializing with default password\r\n");
const uint8_t empty[33] = { 0 };
flash_write_data_to_file(file_sopin, empty, sizeof(empty));
}
}
else {
TU_LOG1("FATAL ERROR: SOPIN not found in memory!\r\n");
}
file_retries_pin1 = search_by_fid(0x1083, NULL, SPECIFY_EF);
if (file_retries_pin1) {
if (!file_retries_pin1->data) {
TU_LOG1("Retries PIN1 is empty. Initializing with default retriesr\n");
const uint8_t retries = 3;
flash_write_data_to_file(file_retries_pin1, &retries, sizeof(uint8_t));
}
}
else {
TU_LOG1("FATAL ERROR: Retries PIN1 not found in memory!\r\n");
}
file_retries_sopin = search_by_fid(0x108A, NULL, SPECIFY_EF);
if (file_retries_sopin) {
if (!file_retries_sopin->data) {
TU_LOG1("Retries SOPIN is empty. Initializing with default retries\r\n");
const uint8_t retries = 15;
flash_write_data_to_file(file_retries_sopin, &retries, sizeof(uint8_t));
}
}
else {
TU_LOG1("FATAL ERROR: Retries SOPIN not found in memory!\r\n");
}
file_t *tf = NULL;
tf = search_by_fid(0x1082, NULL, SPECIFY_EF);
if (tf) {
if (!tf->data) {
TU_LOG1("Max retries PIN1 is empty. Initializing with default max retriesr\n");
const uint8_t retries = 3;
flash_write_data_to_file(tf, &retries, sizeof(uint8_t));
}
}
else {
TU_LOG1("FATAL ERROR: Max Retries PIN1 not found in memory!\r\n");
}
tf = search_by_fid(0x1089, NULL, SPECIFY_EF);
if (tf) {
if (!tf->data) {
TU_LOG1("Max Retries SOPIN is empty. Initializing with default max retries\r\n");
const uint8_t retries = 15;
flash_write_data_to_file(tf, &retries, sizeof(uint8_t));
}
}
else {
TU_LOG1("FATAL ERROR: Retries SOPIN not found in memory!\r\n");
}
low_flash_available();
}
void scan_all() {
scan_flash();
scan_files();
}
void init_sc_hsm() {
scan_all();
has_session_pin = has_session_sopin = false;
isUserAuthenticated = false;
cmd_select();
@ -76,7 +153,7 @@ int sc_hsm_unload() {
has_session_pin = has_session_sopin = false;
isUserAuthenticated = false;
sm_session_pin_len = 0;
return HSM_OK;
return CCID_OK;
}
void select_file(file_t *pe) {
@ -302,7 +379,7 @@ int cvc_prepare_signatures(sc_pkcs15_card_t *p15card, sc_cvc_t *cvc, size_t sig_
}
hash256(cvcbin, cvclen, hsh);
free(cvcbin);
return HSM_OK;
return CCID_OK;
}
int parse_token_info(const file_t *f, int mode) {
@ -446,14 +523,14 @@ static int cmd_read_binary()
int pin_reset_retries(const file_t *pin, bool force) {
if (!pin)
return HSM_ERR_NULL_PARAM;
return CCID_ERR_NULL_PARAM;
const file_t *max = search_by_fid(pin->fid+1, NULL, SPECIFY_EF);
const file_t *act = search_by_fid(pin->fid+2, NULL, SPECIFY_EF);
if (!max || !act)
return HSM_ERR_FILE_NOT_FOUND;
return CCID_ERR_FILE_NOT_FOUND;
uint8_t retries = file_read_uint8(act->data+2);
if (retries == 0 && force == false) //blocked
return HSM_ERR_BLOCKED;
return CCID_ERR_BLOCKED;
retries = file_read_uint8(max->data+2);
int r = flash_write_data_to_file((file_t *)act, &retries, sizeof(retries));
low_flash_available();
@ -462,22 +539,22 @@ int pin_reset_retries(const file_t *pin, bool force) {
int pin_wrong_retry(const file_t *pin) {
if (!pin)
return HSM_ERR_NULL_PARAM;
return CCID_ERR_NULL_PARAM;
const file_t *act = search_by_fid(pin->fid+2, NULL, SPECIFY_EF);
if (!act)
return HSM_ERR_FILE_NOT_FOUND;
return CCID_ERR_FILE_NOT_FOUND;
uint8_t retries = file_read_uint8(act->data+2);
if (retries > 0) {
retries -= 1;
int r = flash_write_data_to_file((file_t *)act, &retries, sizeof(retries));
if (r != HSM_OK)
if (r != CCID_OK)
return r;
low_flash_available();
if (retries == 0)
return HSM_ERR_BLOCKED;
return CCID_ERR_BLOCKED;
return retries;
}
return HSM_ERR_BLOCKED;
return CCID_ERR_BLOCKED;
}
int check_pin(const file_t *pin, const uint8_t *data, size_t len) {
@ -491,7 +568,7 @@ int check_pin(const file_t *pin, const uint8_t *data, size_t len) {
if (is_secured_apdu() && sm_session_pin_len > 0 && pin == file_pin1) {
if (len == sm_session_pin_len && memcmp(data, sm_session_pin, len) != 0) {
uint8_t retries;
if ((retries = pin_wrong_retry(pin)) < HSM_OK)
if ((retries = pin_wrong_retry(pin)) < CCID_OK)
return SW_PIN_BLOCKED();
return set_res_sw(0x63, 0xc0 | retries);
}
@ -503,15 +580,15 @@ int check_pin(const file_t *pin, const uint8_t *data, size_t len) {
return SW_CONDITIONS_NOT_SATISFIED();
if (memcmp(file_read(pin->data+3), dhash, sizeof(dhash)) != 0) {
uint8_t retries;
if ((retries = pin_wrong_retry(pin)) < HSM_OK)
if ((retries = pin_wrong_retry(pin)) < CCID_OK)
return SW_PIN_BLOCKED();
return set_res_sw(0x63, 0xc0 | retries);
}
}
int r = pin_reset_retries(pin, false);
if (r == HSM_ERR_BLOCKED)
if (r == CCID_ERR_BLOCKED)
return SW_PIN_BLOCKED();
if (r != HSM_OK)
if (r != CCID_OK)
return SW_MEMORY_FAILURE();
isUserAuthenticated = true;
hash_multi(data, len, session_pin);
@ -595,7 +672,7 @@ static int cmd_reset_retry() {
dhash[0] = newpin_len;
double_hash_pin(apdu.cmd_apdu_data+(apdu.cmd_apdu_data_len-newpin_len), newpin_len, dhash+1);
flash_write_data_to_file(file_pin1, dhash, sizeof(dhash));
if (pin_reset_retries(file_pin1, true) != HSM_OK)
if (pin_reset_retries(file_pin1, true) != CCID_OK)
return SW_MEMORY_FAILURE();
low_flash_available();
return SW_OK();
@ -616,7 +693,7 @@ static int cmd_reset_retry() {
if (apdu.cmd_apdu_data_len != 0)
return SW_WRONG_LENGTH();
}
if (pin_reset_retries(file_pin1, true) != HSM_OK)
if (pin_reset_retries(file_pin1, true) != CCID_OK)
return SW_MEMORY_FAILURE();
return SW_OK();
}
@ -643,7 +720,7 @@ int heapLeft() {
static int cmd_initialize() {
if (apdu.cmd_apdu_data_len > 0) {
initialize_flash(true);
scan_flash();
scan_all();
dkeks = current_dkeks = 0;
uint8_t tag = 0x0, *tag_data = NULL, *p = NULL;
size_t tag_len = 0;
@ -687,7 +764,7 @@ static int cmd_initialize() {
}
if (dkeks == 0) {
int r = save_dkek_key(random_bytes_get(32));
if (r != HSM_OK)
if (r != CCID_OK)
return SW_EXEC_ERROR();
}
else
@ -723,7 +800,7 @@ static int cmd_import_dkek() {
return SW_WRONG_LENGTH();
import_dkek_share(apdu.cmd_apdu_data);
if (++current_dkeks == dkeks) {
if (save_dkek_key(NULL) != HSM_OK)
if (save_dkek_key(NULL) != CCID_OK)
return SW_FILE_NOT_FOUND();
}
@ -765,14 +842,14 @@ int store_keys(void *key_ctx, int type, uint8_t key_id, sc_context_t *ctx) {
memcpy(kdata, key_ctx, key_size);
}
r = dkek_encrypt(kdata, key_size);
if (r != HSM_OK) {
if (r != CCID_OK) {
return r;
}
file_t *fpk = file_new((KEY_PREFIX << 8) | key_id);
if (!fpk)
return SW_MEMORY_FAILURE();
r = flash_write_data_to_file(fpk, kdata, key_size);
if (r != HSM_OK)
if (r != CCID_OK)
return r;
//add_file_to_chain(fpk, &ef_kf);
if (type == SC_PKCS15_TYPE_PRKEY_RSA || type == SC_PKCS15_TYPE_PRKEY_EC) {
@ -806,7 +883,7 @@ int store_keys(void *key_ctx, int type, uint8_t key_id, sc_context_t *ctx) {
r = flash_write_data_to_file(fpk, asn1bin, asn1len);
if (asn1bin)
free(asn1bin);
if (r != HSM_OK)
if (r != CCID_OK)
return r;
//add_file_to_chain(fpk, &ef_prkdf);
/*
@ -837,12 +914,12 @@ int store_keys(void *key_ctx, int type, uint8_t key_id, sc_context_t *ctx) {
fpk = file_new((EE_CERTIFICATE_PREFIX << 8) | key_id);
r = flash_write_data_to_file(fpk, asn1bin, asn1len);
free(asn1bin);
if (r != HSM_OK)
if (r != CCID_OK)
return r;
//add_file_to_chain(fpk, &ef_cdf);
*/
low_flash_available();
return HSM_OK;
return CCID_OK;
}
static int cmd_keypair_gen() {
@ -909,7 +986,7 @@ static int cmd_keypair_gen() {
uint8_t hsh[32];
ret = cvc_prepare_signatures(&p15card, &cvc, key_size/8, hsh);
if (ret != HSM_OK) {
if (ret != CCID_OK) {
sc_pkcs15emu_sc_hsm_free_cvc(&cvc);
mbedtls_rsa_free(&rsa);
free(ctx);
@ -925,7 +1002,7 @@ static int cmd_keypair_gen() {
return SW_EXEC_ERROR();
}
ret = store_keys(&rsa, SC_PKCS15_TYPE_PRKEY_RSA, key_id, ctx);
if (ret != HSM_OK) {
if (ret != CCID_OK) {
sc_pkcs15emu_sc_hsm_free_cvc(&cvc);
mbedtls_rsa_free(&rsa);
free(ctx);
@ -1034,7 +1111,7 @@ static int cmd_keypair_gen() {
uint8_t hsh[32];
ret = cvc_prepare_signatures(&p15card, &cvc, ecdsa.grp.pbits*2/8+9, hsh);
if (ret != HSM_OK) {
if (ret != CCID_OK) {
sc_pkcs15emu_sc_hsm_free_cvc(&cvc);
mbedtls_ecdsa_free(&ecdsa);
free(ctx);
@ -1051,7 +1128,7 @@ static int cmd_keypair_gen() {
}
ret = store_keys(&ecdsa, SC_PKCS15_TYPE_PRKEY_EC, key_id, ctx);
if (ret != HSM_OK) {
if (ret != CCID_OK) {
sc_pkcs15emu_sc_hsm_free_cvc(&cvc);
mbedtls_ecdsa_free(&ecdsa);
free(ctx);
@ -1148,7 +1225,7 @@ static int cmd_update_ef() {
}
if (offset == 0) {
int r = flash_write_data_to_file(ef, data, data_len);
if (r != HSM_OK)
if (r != CCID_OK)
return SW_MEMORY_FAILURE();
}
else {
@ -1159,7 +1236,7 @@ static int cmd_update_ef() {
memcpy(data_merge+offset, data, data_len);
int r = flash_write_data_to_file(ef, data_merge, offset+data_len);
free(data_merge);
if (r != HSM_OK)
if (r != CCID_OK)
return SW_MEMORY_FAILURE();
}
low_flash_available();
@ -1184,9 +1261,9 @@ static int cmd_delete_file() {
}
if (!authenticate_action(ef, ACL_OP_DELETE_SELF))
return SW_SECURITY_STATUS_NOT_SATISFIED();
if (flash_clear_file(ef) != HSM_OK)
if (flash_clear_file(ef) != CCID_OK)
return SW_EXEC_ERROR();
if (delete_dynamic_file(ef) != HSM_OK)
if (delete_dynamic_file(ef) != CCID_OK)
return SW_EXEC_ERROR();
low_flash_available();
return SW_OK();
@ -1205,12 +1282,12 @@ static int cmd_change_pin() {
uint16_t r = check_pin(file_pin1, apdu.cmd_apdu_data, pin_len);
if (r != 0x9000)
return r;
if (load_dkek() != HSM_OK) //loads the DKEK with old pin
if (load_dkek() != CCID_OK) //loads the DKEK with old pin
return SW_EXEC_ERROR();
//encrypt DKEK with new pin
hash_multi(apdu.cmd_apdu_data+pin_len, apdu.cmd_apdu_data_len-pin_len, session_pin);
has_session_pin = true;
if (store_dkek_key() != HSM_OK)
if (store_dkek_key() != CCID_OK)
return SW_EXEC_ERROR();
uint8_t dhash[33];
dhash[0] = apdu.cmd_apdu_data_len-pin_len;
@ -1248,7 +1325,7 @@ static int cmd_key_gen() {
sc_context_t *card_ctx = create_context();
r = store_keys(aes_key, aes_type, key_id, card_ctx);
free(card_ctx);
if (r != HSM_OK)
if (r != CCID_OK)
return SW_MEMORY_FAILURE();
low_flash_available();
return SW_OK();
@ -1286,7 +1363,7 @@ int load_private_key_rsa(mbedtls_rsa_context *ctx, file_t *fkey) {
mbedtls_rsa_free(ctx);
return SW_DATA_INVALID();
}
return HSM_OK;
return CCID_OK;
}
int load_private_key_ecdsa(mbedtls_ecdsa_context *ctx, file_t *fkey) {
@ -1295,15 +1372,15 @@ int load_private_key_ecdsa(mbedtls_ecdsa_context *ctx, file_t *fkey) {
uint8_t kdata[67]; //Worst case, 521 bit + 1byte
memcpy(kdata, file_read(fkey->data+2), key_size);
if (dkek_decrypt(kdata, key_size) != 0) {
return HSM_EXEC_ERROR;
return CCID_EXEC_ERROR;
}
mbedtls_ecp_group_id gid = kdata[0];
int r = mbedtls_ecp_read_key(gid, ctx, kdata+1, key_size-1);
if (r != 0) {
mbedtls_ecdsa_free(ctx);
return HSM_EXEC_ERROR;
return CCID_EXEC_ERROR;
}
return HSM_OK;
return CCID_OK;
}
static int cmd_signature() {
@ -1332,7 +1409,7 @@ static int cmd_signature() {
int r;
r = load_private_key_rsa(&ctx, fkey);
if (r != HSM_OK)
if (r != CCID_OK)
return SW_EXEC_ERROR();
const uint8_t *hash = apdu.cmd_apdu_data;
size_t hash_len = apdu.cmd_apdu_data_len;
@ -1428,7 +1505,7 @@ static int cmd_signature() {
md = MBEDTLS_MD_SHA256;
int r;
r = load_private_key_ecdsa(&ctx, fkey);
if (r != HSM_OK)
if (r != CCID_OK)
return SW_CONDITIONS_NOT_SATISFIED();
size_t olen = 0;
uint8_t buf[MBEDTLS_ECDSA_MAX_LEN];
@ -1463,7 +1540,7 @@ static int cmd_key_wrap() {
mbedtls_rsa_context ctx;
mbedtls_rsa_init(&ctx);
r = load_private_key_rsa(&ctx, ef);
if (r != HSM_OK) {
if (r != CCID_OK) {
mbedtls_rsa_free(&ctx);
return SW_EXEC_ERROR();
}
@ -1474,7 +1551,7 @@ static int cmd_key_wrap() {
mbedtls_ecdsa_context ctx;
mbedtls_ecdsa_init(&ctx);
r = load_private_key_ecdsa(&ctx, ef);
if (r != HSM_OK) {
if (r != CCID_OK) {
mbedtls_ecdsa_free(&ctx);
return SW_EXEC_ERROR();
}
@ -1497,7 +1574,7 @@ static int cmd_key_wrap() {
aes_type = HSM_KEY_AES_128;
r = dkek_encode_key(kdata, aes_type, res_APDU, &wrap_len);
}
if (r != HSM_OK)
if (r != CCID_OK)
return SW_EXEC_ERROR();
res_APDU_size = wrap_len;
return SW_OK();
@ -1516,7 +1593,7 @@ static int cmd_key_unwrap() {
mbedtls_rsa_context ctx;
mbedtls_rsa_init(&ctx);
r = dkek_decode_key(&ctx, apdu.cmd_apdu_data, apdu.cmd_apdu_data_len, NULL);
if (r != HSM_OK) {
if (r != CCID_OK) {
mbedtls_rsa_free(&ctx);
return SW_EXEC_ERROR();
}
@ -1524,7 +1601,7 @@ static int cmd_key_unwrap() {
r = store_keys(&ctx, SC_PKCS15_TYPE_PRKEY_RSA, key_id, card_ctx);
free(card_ctx);
mbedtls_rsa_free(&ctx);
if (r != HSM_OK) {
if (r != CCID_OK) {
return SW_EXEC_ERROR();
}
}
@ -1532,7 +1609,7 @@ static int cmd_key_unwrap() {
mbedtls_ecdsa_context ctx;
mbedtls_ecdsa_init(&ctx);
r = dkek_decode_key(&ctx, apdu.cmd_apdu_data, apdu.cmd_apdu_data_len, NULL);
if (r != HSM_OK) {
if (r != CCID_OK) {
mbedtls_ecdsa_free(&ctx);
return SW_EXEC_ERROR();
}
@ -1540,7 +1617,7 @@ static int cmd_key_unwrap() {
r = store_keys(&ctx, SC_PKCS15_TYPE_PRKEY_EC, key_id, card_ctx);
free(card_ctx);
mbedtls_ecdsa_free(&ctx);
if (r != HSM_OK) {
if (r != CCID_OK) {
return SW_EXEC_ERROR();
}
}
@ -1548,7 +1625,7 @@ static int cmd_key_unwrap() {
uint8_t aes_key[32];
int key_size = 0, aes_type;
r = dkek_decode_key(aes_key, apdu.cmd_apdu_data, apdu.cmd_apdu_data_len, &key_size);
if (r != HSM_OK) {
if (r != CCID_OK) {
return SW_EXEC_ERROR();
}
if (key_size == 32)
@ -1560,7 +1637,7 @@ static int cmd_key_unwrap() {
sc_context_t *card_ctx = create_context();
r = store_keys(aes_key, aes_type, key_id, card_ctx);
free(card_ctx);
if (r != HSM_OK) {
if (r != CCID_OK) {
return SW_EXEC_ERROR();
}
}
@ -1578,7 +1655,7 @@ static int cmd_decrypt_asym() {
mbedtls_rsa_context ctx;
mbedtls_rsa_init(&ctx);
int r = load_private_key_rsa(&ctx, ef);
if (r != HSM_OK)
if (r != CCID_OK)
return SW_EXEC_ERROR();
int key_size = file_read_uint16(ef->data);
if (apdu.cmd_apdu_data_len < key_size) //needs padding
@ -1747,7 +1824,7 @@ static int cmd_derive_asym() {
int r;
r = load_private_key_ecdsa(&ctx, fkey);
if (r != HSM_OK) {
if (r != CCID_OK) {
mbedtls_ecdsa_free(&ctx);
return SW_EXEC_ERROR();
}
@ -1778,7 +1855,7 @@ static int cmd_derive_asym() {
sc_context_t *card_ctx = create_context();
r = store_keys(&ctx, SC_PKCS15_TYPE_PRKEY_EC, dest_id, card_ctx);
free(card_ctx);
if (r != HSM_OK) {
if (r != CCID_OK) {
mbedtls_ecdsa_free(&ctx);
mbedtls_mpi_free(&a);
mbedtls_mpi_free(&nd);
@ -1935,7 +2012,7 @@ int cmd_general_authenticate() {
r = sm_sign(t, pubkey_len+16, res_APDU+res_APDU_size);
free(t);
if (r != HSM_OK)
if (r != CCID_OK)
return SW_EXEC_ERROR();
res_APDU_size += 8;
}

View File

@ -20,80 +20,10 @@
#include <stdlib.h>
#include "pico/stdlib.h"
#include "hsm2040.h"
#include "ccid2040.h"
extern const uint8_t sc_hsm_aid[];
#define SW_BYTES_REMAINING_00() set_res_sw (0x61, 0x00)
#define SW_WARNING_STATE_UNCHANGED() set_res_sw (0x62, 0x00)
#define SW_WARNING_CORRUPTED() set_res_sw (0x62, 0x81)
#define SW_WARNING_EOF() set_res_sw (0x62, 0x82)
#define SW_WARNING_EF_DEACTIVATED() set_res_sw (0x62, 0x83)
#define SW_WARNING_WRONG_FCI() set_res_sw (0x62, 0x84)
#define SW_WARNING_EF_TERMINATED() set_res_sw (0x62, 0x85)
#define SW_WARNING_NOINFO() set_res_sw (0x63, 0x00)
#define SW_WARNING_FILLUP() set_res_sw (0x63, 0x81)
#define SW_EXEC_ERROR() set_res_sw (0x64, 0x00)
#define SW_MEMORY_FAILURE() set_res_sw (0x65, 0x81)
#define SW_SECURE_MESSAGE_EXEC_ERROR() set_res_sw (0x66, 0x00)
#define SW_WRONG_LENGTH() set_res_sw (0x67, 0x00)
#define SW_WRONG_DATA() set_res_sw (0x67, 0x00)
#define SW_LOGICAL_CHANNEL_NOT_SUPPORTED() set_res_sw (0x68, 0x81)
#define SW_SECURE_MESSAGING_NOT_SUPPORTED() set_res_sw (0x68, 0x82)
#define SW_COMMAND_INCOMPATIBLE() set_res_sw (0x69, 0x81)
#define SW_SECURITY_STATUS_NOT_SATISFIED() set_res_sw (0x69, 0x82)
#define SW_PIN_BLOCKED() set_res_sw (0x69, 0x83)
#define SW_DATA_INVALID() set_res_sw (0x69, 0x84)
#define SW_CONDITIONS_NOT_SATISFIED() set_res_sw (0x69, 0x85)
#define SW_COMMAND_NOT_ALLOWED() set_res_sw (0x69, 0x86)
#define SW_SECURE_MESSAGING_MISSING_DO() set_res_sw (0x69, 0x87)
#define SW_SECURE_MESSAGING_INCORRECT_DO() set_res_sw (0x69, 0x88)
#define SW_APPLET_SELECT_FAILED() set_res_sw (0x69, 0x99)
#define SW_INCORRECT_PARAMS() set_res_sw (0x6A, 0x80)
#define SW_FUNC_NOT_SUPPORTED() set_res_sw (0x6A, 0x81)
#define SW_FILE_NOT_FOUND() set_res_sw (0x6A, 0x82)
#define SW_RECORD_NOT_FOUND() set_res_sw (0x6A, 0x83)
#define SW_FILE_FULL() set_res_sw (0x6A, 0x84)
#define SW_WRONG_NE() set_res_sw (0x6A, 0x85)
#define SW_INCORRECT_P1P2() set_res_sw (0x6A, 0x86)
#define SW_WRONG_NC() set_res_sw (0x6A, 0x87)
#define SW_REFERENCE_NOT_FOUND() set_res_sw (0x6A, 0x88)
#define SW_FILE_EXISTS() set_res_sw (0x6A, 0x89)
#define SW_WRONG_P1P2() set_res_sw (0x6B, 0x00)
#define SW_CORRECT_LENGTH_00() set_res_sw (0x6C, 0x00)
#define SW_INS_NOT_SUPPORTED() set_res_sw (0x6D, 0x00)
#define SW_CLA_NOT_SUPPORTED() set_res_sw (0x6E, 0x00)
#define SW_UNKNOWN() set_res_sw (0x6F, 0x00)
#define SW_OK() set_res_sw (0x90, 0x00)
#define HSM_OK 0
#define HSM_ERR_NO_MEMORY -1000
#define HSM_ERR_MEMORY_FATAL -1001
#define HSM_ERR_NULL_PARAM -1002
#define HSM_ERR_FILE_NOT_FOUND -1003
#define HSM_ERR_BLOCKED -1004
#define HSM_NO_LOGIN -1005
#define HSM_EXEC_ERROR -1006
#define HSM_WRONG_LENGTH -1007
#define HSM_WRONG_DATA -1008
#define HSM_WRONG_DKEK -1009
#define HSM_WRONG_SIGNATURE -1010
#define HSM_WRONG_PADDING -1011
#define HSM_VERIFICATION_FAILED -1012
#define ALGO_RSA_RAW 0x20 /* RSA signature with external padding */
#define ALGO_RSA_DECRYPT 0x21 /* RSA decrypt */

View File

@ -1,182 +0,0 @@
/*
* This file is part of the Pico HSM distribution (https://github.com/polhenarejos/pico-hsm).
* Copyright (c) 2022 Pol Henarejos.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//Part of the code is taken from GnuK (GPLv3)
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include "pico/stdlib.h"
#include "neug.h"
#include "hardware/structs/rosc.h"
#include "hardware/gpio.h"
#include "hardware/adc.h"
#include "bsp/board.h"
#include "pico/unique_id.h"
void adc_start() {
adc_init();
adc_gpio_init(27);
adc_select_input(1);
}
void adc_stop() {
}
static uint64_t random_word = 0xcbf29ce484222325;
static uint8_t ep_round = 0;
static void ep_init() {
random_word = 0xcbf29ce484222325;
ep_round = 0;
}
/* Here, we assume a little endian architecture. */
static int ep_process () {
if (ep_round == 0) {
ep_init();
}
uint64_t word = 0x0;
for (int n = 0; n < 64; n++) {
uint8_t bit1, bit2;
do
{
bit1 = rosc_hw->randombit&0xff;
//sleep_ms(1);
bit2 = rosc_hw->randombit&0xff;
} while(bit1 == bit2);
word = (word << 1) | bit1;
}
random_word ^= word^board_millis()^adc_read();
random_word *= 0x00000100000001B3;
if (++ep_round == 8) {
ep_round = 0;
return 2; //2 words
}
return 0;
}
static const uint32_t *ep_output() {
return (uint32_t *)&random_word;
}
struct rng_rb {
uint32_t *buf;
uint8_t head, tail;
uint8_t size;
unsigned int full :1;
unsigned int empty :1;
};
static void rb_init(struct rng_rb *rb, uint32_t *p, uint8_t size) {
rb->buf = p;
rb->size = size;
rb->head = rb->tail = 0;
rb->full = 0;
rb->empty = 1;
}
static void rb_add(struct rng_rb *rb, uint32_t v) {
rb->buf[rb->tail++] = v;
if (rb->tail == rb->size)
rb->tail = 0;
if (rb->tail == rb->head)
rb->full = 1;
rb->empty = 0;
}
static uint32_t rb_del(struct rng_rb *rb) {
uint32_t v = rb->buf[rb->head++];
if (rb->head == rb->size)
rb->head = 0;
if (rb->head == rb->tail)
rb->empty = 1;
rb->full = 0;
return v;
}
static struct rng_rb the_ring_buffer;
void *neug_task() {
struct rng_rb *rb = &the_ring_buffer;
int n;
if ((n = ep_process())) {
int i;
const uint32_t *vp;
vp = ep_output();
for (i = 0; i < n; i++) {
rb_add (rb, *vp++);
if (rb->full)
break;
}
}
return NULL;
}
void neug_init(uint32_t *buf, uint8_t size) {
pico_unique_board_id_t unique_id;
pico_get_unique_board_id(&unique_id);
const uint32_t *u = (const uint32_t *)unique_id.id;
struct rng_rb *rb = &the_ring_buffer;
int i;
rb_init(rb, buf, size);
adc_start();
ep_init();
}
void neug_flush(void) {
struct rng_rb *rb = &the_ring_buffer;
while (!rb->empty)
rb_del (rb);
}
uint32_t neug_get(int kick) {
struct rng_rb *rb = &the_ring_buffer;
uint32_t v;
while (rb->empty)
neug_task();
v = rb_del(rb);
return v;
}
void neug_wait_full(void) { //should be called only on core1
struct rng_rb *rb = &the_ring_buffer;
while (!rb->full) {
sleep_ms(1);
}
}
void neug_fini(void) {
neug_get(1);
}

View File

@ -1,109 +0,0 @@
/*
* This file is part of the Pico HSM distribution (https://github.com/polhenarejos/pico-hsm).
* Copyright (c) 2022 Pol Henarejos.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdint.h>
#include <string.h>
#include "neug.h"
#define RANDOM_BYTES_LENGTH 32
static uint32_t random_word[RANDOM_BYTES_LENGTH/sizeof (uint32_t)];
void random_init(void) {
int i;
neug_init(random_word, RANDOM_BYTES_LENGTH/sizeof (uint32_t));
for (i = 0; i < NEUG_PRE_LOOP; i++)
neug_get();
}
void random_fini(void) {
neug_fini ();
}
/*
* Return pointer to random 32-byte
*/
void random_bytes_free (const uint8_t *p);
#define MAX_RANDOM_BUFFER 1024
const uint8_t * random_bytes_get(size_t len) {
if (len > MAX_RANDOM_BUFFER)
return NULL;
static uint32_t return_word[MAX_RANDOM_BUFFER/sizeof(uint32_t)];
for (int ix = 0; ix < len; ix += RANDOM_BYTES_LENGTH) {
neug_wait_full();
memcpy(return_word+ix/sizeof(uint32_t), random_word, RANDOM_BYTES_LENGTH);
random_bytes_free((const uint8_t *)random_word);
}
return (const uint8_t *)return_word;
}
/*
* Free pointer to random 32-byte
*/
void random_bytes_free(const uint8_t *p) {
(void)p;
memset(random_word, 0, RANDOM_BYTES_LENGTH);
neug_flush();
}
/*
* Return 4-byte salt
*/
void random_get_salt(uint8_t *p) {
uint32_t rnd;
rnd = neug_get();
memcpy(p, &rnd, sizeof (uint32_t));
rnd = neug_get();
memcpy(p + sizeof (uint32_t), &rnd, sizeof (uint32_t));
}
/*
* Random byte iterator
*/
int random_gen(void *arg, unsigned char *out, size_t out_len) {
uint8_t *index_p = (uint8_t *)arg;
uint8_t index = index_p ? *index_p : 0;
size_t n;
while (out_len) {
neug_wait_full();
n = RANDOM_BYTES_LENGTH - index;
if (n > out_len)
n = out_len;
memcpy(out, ((unsigned char *)random_word) + index, n);
out += n;
out_len -= n;
index += n;
if (index >= RANDOM_BYTES_LENGTH) {
index = 0;
neug_flush();
}
}
if (index_p)
*index_p = index;
return 0;
}

View File

@ -1,38 +0,0 @@
/*
* This file is part of the Pico HSM distribution (https://github.com/polhenarejos/pico-hsm).
* Copyright (c) 2022 Pol Henarejos.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _RANDOM_H_
#define _RANDOM_H_
#include "stdlib.h"
#include "pico/stdlib.h"
void random_init (void);
void random_fini (void);
/* 32-byte random bytes */
const uint8_t *random_bytes_get (size_t);
void random_bytes_free (const uint8_t *p);
/* 8-byte salt */
void random_get_salt (uint8_t *p);
/* iterator returning a byta at a time */
int random_gen (void *arg, unsigned char *output, size_t output_len);
#endif

View File

@ -1,50 +0,0 @@
/*
* This file is part of the Pico HSM distribution (https://github.com/polhenarejos/pico-hsm).
* Copyright (c) 2022 Pol Henarejos.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _CCID_H_
#define _CCID_H_
#include "libopensc/ccid-types.h"
static const struct ccid_class_descriptor desc_ccid = {
.bLength = sizeof(struct ccid_class_descriptor),
.bDescriptorType = 0x21,
.bcdCCID = (0x0110),
.bMaxSlotIndex = 0,
.bVoltageSupport = 0x01, // 5.0V
.dwProtocols = (
0x01| // T=0
0x02), // T=1
.dwDefaultClock = (0xDFC),
.dwMaximumClock = (0xDFC),
.bNumClockSupport = 0,
.dwDataRate = (0x2580),
.dwMaxDataRate = (0x2580),
.bNumDataRatesSupported = 0,
.dwMaxIFSD = (0xFE), // IFSD is handled by the real reader driver
.dwSynchProtocols = (0),
.dwMechanical = (0),
.dwFeatures = 0x40840, //USB-ICC, short & extended APDU
.dwMaxCCIDMessageLength = 65544+10,
.bClassGetResponse = 0xFF,
.bclassEnvelope = 0xFF,
.wLcdLayout = 0x0,
.bPINSupport = 0x0,
.bMaxCCIDBusySlots = 0x01,
};
#endif

View File

@ -1,119 +0,0 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
#ifndef _TUSB_CONFIG_H_
#define _TUSB_CONFIG_H_
#ifdef __cplusplus
extern "C" {
#endif
//--------------------------------------------------------------------
// COMMON CONFIGURATION
//--------------------------------------------------------------------
// defined by board.mk
#ifndef CFG_TUSB_MCU
#error CFG_TUSB_MCU must be defined
#endif
// RHPort number used for device can be defined by board.mk, default to port 0
#ifndef BOARD_DEVICE_RHPORT_NUM
#define BOARD_DEVICE_RHPORT_NUM 0
#endif
// RHPort max operational speed can defined by board.mk
// Default to Highspeed for MCU with internal HighSpeed PHY (can be port specific), otherwise FullSpeed
#ifndef BOARD_DEVICE_RHPORT_SPEED
#if (CFG_TUSB_MCU == OPT_MCU_LPC18XX || CFG_TUSB_MCU == OPT_MCU_LPC43XX || CFG_TUSB_MCU == OPT_MCU_MIMXRT10XX || \
CFG_TUSB_MCU == OPT_MCU_NUC505 || CFG_TUSB_MCU == OPT_MCU_CXD56 || CFG_TUSB_MCU == OPT_MCU_SAMX7X)
#define BOARD_DEVICE_RHPORT_SPEED OPT_MODE_HIGH_SPEED
#else
#define BOARD_DEVICE_RHPORT_SPEED OPT_MODE_FULL_SPEED
#endif
#endif
// Device mode with rhport and speed defined by board.mk
#if BOARD_DEVICE_RHPORT_NUM == 0
#define CFG_TUSB_RHPORT0_MODE (OPT_MODE_DEVICE | BOARD_DEVICE_RHPORT_SPEED)
#elif BOARD_DEVICE_RHPORT_NUM == 1
#define CFG_TUSB_RHPORT1_MODE (OPT_MODE_DEVICE | BOARD_DEVICE_RHPORT_SPEED)
#else
#error "Incorrect RHPort configuration"
#endif
#ifndef CFG_TUSB_OS
#define CFG_TUSB_OS OPT_OS_PICO
#endif
// CFG_TUSB_DEBUG is defined by compiler in DEBUG build
// #define CFG_TUSB_DEBUG 0
/* USB DMA on some MCUs can only access a specific SRAM region with restriction on alignment.
* Tinyusb use follows macros to declare transferring memory so that they can be put
* into those specific section.
* e.g
* - CFG_TUSB_MEM SECTION : __attribute__ (( section(".usb_ram") ))
* - CFG_TUSB_MEM_ALIGN : __attribute__ ((aligned(4)))
*/
#ifndef CFG_TUSB_MEM_SECTION
#define CFG_TUSB_MEM_SECTION
#endif
#ifndef CFG_TUSB_MEM_ALIGN
#define CFG_TUSB_MEM_ALIGN __attribute__ ((aligned(4)))
#endif
//--------------------------------------------------------------------
// DEVICE CONFIGURATION
//--------------------------------------------------------------------
#ifndef CFG_TUD_ENDPOINT0_SIZE
#define CFG_TUD_ENDPOINT0_SIZE 64
#endif
//------------- CLASS -------------//
#define CFG_TUD_HID 0
#define CFG_TUD_CDC 0
#define CFG_TUD_MSC 0
#define CFG_TUD_MIDI 0
#define CFG_TUD_VENDOR 1
// HID buffer size Should be sufficient to hold ID (if any) + Data
#define CFG_TUD_HID_EP_BUFSIZE 16
#define CFG_TUD_VENDOR_RX_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64)
#define CFG_TUD_VENDOR_TX_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64)
#include "pico/types.h"
static inline uint16_t tu_u32_high16(uint32_t ui32) { return (uint16_t) (ui32 >> 16); }
static inline uint16_t tu_u32_low16 (uint32_t ui32) { return (uint16_t) (ui32 & 0x0000ffffu); }
#ifdef __cplusplus
}
#endif
#endif /* _TUSB_CONFIG_H_ */

View File

@ -1,209 +0,0 @@
/*
* This file is part of the Pico HSM distribution (https://github.com/polhenarejos/pico-hsm).
* Copyright (c) 2022 Pol Henarejos.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "tusb.h"
#include "usb_descriptors.h"
#include "ccid.h"
#include "pico/unique_id.h"
#include "version.h"
#ifndef USB_VID
#define USB_VID 0xFEFF
#endif
#ifndef USB_PID
#define USB_PID 0xFCFD
#endif
#define USB_BCD 0x0200
#define USB_CONFIG_ATT_ONE TU_BIT(7)
#define MAX_USB_POWER 1
//--------------------------------------------------------------------+
// Device Descriptors
//--------------------------------------------------------------------+
tusb_desc_device_t const desc_device =
{
.bLength = sizeof(tusb_desc_device_t),
.bDescriptorType = TUSB_DESC_DEVICE,
.bcdUSB = (USB_BCD),
.bDeviceClass = 0x00,
.bDeviceSubClass = 0,
.bDeviceProtocol = 0,
.bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
.idVendor = (USB_VID),
.idProduct = (USB_PID),
.bcdDevice = HSM_VERSION,
.iManufacturer = 1,
.iProduct = 2,
.iSerialNumber = 3,
.bNumConfigurations = 1
};
uint8_t const * tud_descriptor_device_cb(void)
{
return (uint8_t const *) &desc_device;
}
tusb_desc_interface_t const desc_interface =
{
.bLength = sizeof(tusb_desc_interface_t),
.bDescriptorType = TUSB_DESC_INTERFACE,
.bInterfaceNumber = 0,
.bAlternateSetting = 0,
.bNumEndpoints = 2,
.bInterfaceClass = TUSB_CLASS_SMART_CARD,
.bInterfaceSubClass = 0,
.bInterfaceProtocol = 0,
.iInterface = 5,
};
//--------------------------------------------------------------------+
// Configuration Descriptor
//--------------------------------------------------------------------+
tusb_desc_configuration_t const desc_config =
{
.bLength = sizeof(tusb_desc_configuration_t),
.bDescriptorType = TUSB_DESC_CONFIGURATION,
.wTotalLength = (sizeof(tusb_desc_configuration_t) + sizeof(tusb_desc_interface_t) + sizeof(struct ccid_class_descriptor) + 2*sizeof(tusb_desc_endpoint_t)),
.bNumInterfaces = 1,
.bConfigurationValue = 1,
.iConfiguration = 4,
.bmAttributes = USB_CONFIG_ATT_ONE | TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP,
.bMaxPower = TUSB_DESC_CONFIG_POWER_MA(MAX_USB_POWER+1),
};
tusb_desc_endpoint_t const desc_ep1 =
{
.bLength = sizeof(tusb_desc_endpoint_t),
.bDescriptorType = TUSB_DESC_ENDPOINT,
.bEndpointAddress = TUSB_DIR_IN_MASK | 1,
.bmAttributes.xfer = TUSB_XFER_BULK,
.wMaxPacketSize.size = (64),
.bInterval = 0
};
tusb_desc_endpoint_t const desc_ep2 =
{
.bLength = sizeof(tusb_desc_endpoint_t),
.bDescriptorType = TUSB_DESC_ENDPOINT,
.bEndpointAddress = 2,
.bmAttributes.xfer = TUSB_XFER_BULK,
.wMaxPacketSize.size = (64),
.bInterval = 0
};
static uint8_t desc_config_extended[sizeof(tusb_desc_configuration_t) + sizeof(tusb_desc_interface_t) + sizeof(struct ccid_class_descriptor) + 2*sizeof(tusb_desc_endpoint_t)];
uint8_t const * tud_descriptor_configuration_cb(uint8_t index)
{
(void) index; // for multiple configurations
static uint8_t initd = 0;
if (initd == 0)
{
uint8_t *p = desc_config_extended;
memcpy(p, &desc_config, sizeof(tusb_desc_configuration_t)); p += sizeof(tusb_desc_configuration_t);
memcpy(p, &desc_interface, sizeof(tusb_desc_interface_t)); p += sizeof(tusb_desc_interface_t);
memcpy(p, &desc_ccid, sizeof(struct ccid_class_descriptor)); p += sizeof(struct ccid_class_descriptor);
memcpy(p, &desc_ep1, sizeof(tusb_desc_endpoint_t)); p += sizeof(tusb_desc_endpoint_t);
memcpy(p, &desc_ep2, sizeof(tusb_desc_endpoint_t)); p += sizeof(tusb_desc_endpoint_t);
initd = 1;
}
return (const uint8_t *)desc_config_extended;
}
#define BOS_TOTAL_LEN (TUD_BOS_DESC_LEN)
#define MS_OS_20_DESC_LEN 0xB2
uint8_t const desc_bos[] =
{
// total length, number of device caps
TUD_BOS_DESCRIPTOR(BOS_TOTAL_LEN, 2)
};
uint8_t const * tud_descriptor_bos_cb(void)
{
return desc_bos;
}
//--------------------------------------------------------------------+
// String Descriptors
//--------------------------------------------------------------------+
// array of pointer to string descriptors
char const* string_desc_arr [] =
{
(const char[]) { 0x09, 0x04 }, // 0: is supported language is English (0x0409)
"Pol Henarejos", // 1: Manufacturer
"Pico HSM", // 2: Product
"11223344", // 3: Serials, should use chip ID
"Pico HSM Config", // 4: Vendor Interface
"Pico HSM Interface"
};
static uint16_t _desc_str[32];
uint16_t const* tud_descriptor_string_cb(uint8_t index, uint16_t langid)
{
(void) langid;
uint8_t chr_count;
if (index == 0) {
memcpy(&_desc_str[1], string_desc_arr[0], 2);
chr_count = 1;
}
else {
// Note: the 0xEE index string is a Microsoft OS 1.0 Descriptors.
// https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/microsoft-defined-usb-descriptors
if ( !(index < sizeof(string_desc_arr)/sizeof(string_desc_arr[0])) )
return NULL;
const char* str = string_desc_arr[index];
char unique_id_str[2 * PICO_UNIQUE_BOARD_ID_SIZE_BYTES + 1];
if (index == 3) {
pico_unique_board_id_t unique_id;
pico_get_unique_board_id(&unique_id);
pico_get_unique_board_id_string(unique_id_str, 2 * PICO_UNIQUE_BOARD_ID_SIZE_BYTES + 1);
str = unique_id_str;
}
chr_count = strlen(str);
if ( chr_count > 31 )
chr_count = 31;
// Convert ASCII string into UTF-16
for(uint8_t i=0; i<chr_count; i++) {
_desc_str[1+i] = str[i];
}
}
_desc_str[0] = (TUSB_DESC_STRING << 8 ) | (2*chr_count + 2);
return _desc_str;
}

View File

@ -1,29 +0,0 @@
/*
* This file is part of the Pico HSM distribution (https://github.com/polhenarejos/pico-hsm).
* Copyright (c) 2022 Pol Henarejos.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef USB_DESCRIPTORS_H_
#define USB_DESCRIPTORS_H_
enum
{
VENDOR_REQUEST_WEBUSB = 1,
VENDOR_REQUEST_MICROSOFT = 2
};
extern uint8_t const desc_ms_os_20[];
#endif /* USB_DESCRIPTORS_H_ */