Compare commits

..

No commits in common. "main" and "v3.0" have entirely different histories.
main ... v3.0

80 changed files with 2883 additions and 8426 deletions

3
.gitmodules vendored
View file

@ -1,6 +1,3 @@
[submodule "mbedtls"] [submodule "mbedtls"]
path = mbedtls path = mbedtls
url = https://github.com/ARMmbed/mbedtls url = https://github.com/ARMmbed/mbedtls
[submodule "tinycbor"]
path = tinycbor
url = https://github.com/intel/tinycbor.git

View file

@ -1,5 +1,5 @@
# #
# This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk). # This file is part of the Pico HSM SDK distribution (https://github.com/polhenarejos/pico-hsm-sdk).
# Copyright (c) 2022 Pol Henarejos. # Copyright (c) 2022 Pol Henarejos.
# #
# This program is free software: you can redistribute it and/or modify # This program is free software: you can redistribute it and/or modify
@ -15,88 +15,26 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
# #
cmake_minimum_required(VERSION 3.16) cmake_minimum_required(VERSION 3.13)
if(ESP_PLATFORM) include(pico_sdk_import.cmake)
set(EXTRA_COMPONENT_DIRS src)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
else()
if(NOT ENABLE_EMULATION)
set(PICO_USE_FASTEST_SUPPORTED_CLOCK 1)
include(pico_sdk_import.cmake)
endif()
project(picokey C CXX ASM) project(pico_hsm_sdk C CXX ASM)
set(CMAKE_C_STANDARD 11) set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD 17)
if(NOT DEFINED __FOR_CI) pico_sdk_init()
set(__FOR_CI 0)
endif()
if(__FOR_CI)
add_definitions(-D__FOR_CI)
endif()
add_executable(picokey) add_executable(pico_hsm_sdk_exe)
endif()
set(USB_ITF_CCID 1) include(pico_hsm_sdk.cmake)
set(USB_ITF_WCID 1)
include(cmake/version.cmake) target_compile_options(pico_hsm_sdk_exe PUBLIC
include(pico_keys_sdk_import.cmake) -Wall
if(NOT ESP_PLATFORM) -Werror
set(SOURCES ${PICO_KEYS_SOURCES})
endif()
set(SOURCES ${SOURCES}
${CMAKE_CURRENT_LIST_DIR}/src/fs/files.c
${CMAKE_CURRENT_LIST_DIR}/src/version.c
) )
SET_VERSION(ver_major ver_minor "${CMAKE_CURRENT_LIST_DIR}/src/pico_keys_version.h" 2) pico_add_extra_outputs(pico_hsm_sdk_exe)
if(ESP_PLATFORM)
project(picokey)
endif()
if(NOT ESP_PLATFORM)
target_sources(picokey PUBLIC ${SOURCES})
target_include_directories(picokey PUBLIC ${INCLUDES})
target_compile_options(picokey PUBLIC
-Wall
)
if(NOT MSVC)
target_compile_options(picokey PUBLIC
-Werror
)
endif()
if(ENABLE_EMULATION)
if(NOT MSVC)
target_compile_options(picokey PUBLIC
-fdata-sections
-ffunction-sections
)
endif()
if(APPLE)
target_link_options(picokey PUBLIC
-Wl,-dead_strip
)
elseif(MSVC)
target_compile_options(picokey PUBLIC
-WX
)
target_link_libraries(picokey PUBLIC wsock32 ws2_32 Bcrypt)
else()
target_link_options(picokey PUBLIC
-Wl,--gc-sections
)
endif(APPLE)
target_link_libraries(picokey PRIVATE pthread m)
else()
pico_add_extra_outputs(${CMAKE_PROJECT_NAME})
endif()
endif()
target_link_libraries(pico_hsm_sdk_exe PRIVATE pico_hsm_sdk pico_stdlib pico_multicore hardware_flash hardware_sync hardware_adc pico_unique_id hardware_rtc tinyusb_device tinyusb_board)

141
LICENSE
View file

@ -1,5 +1,5 @@
GNU AFFERO GENERAL PUBLIC LICENSE GNU GENERAL PUBLIC LICENSE
Version 3, 19 November 2007 Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/> Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies Everyone is permitted to copy and distribute verbatim copies
@ -7,15 +7,17 @@
Preamble Preamble
The GNU Affero General Public License is a free, copyleft license for The GNU General Public License is a free, copyleft license for
software and other kinds of works, specifically designed to ensure software and other kinds of works.
cooperation with the community in the case of network server software.
The licenses for most software and other practical works are designed The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast, to take away your freedom to share and change the works. By contrast,
our General Public Licenses are intended to guarantee your freedom to the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free share and change all versions of a program--to make sure it remains free
software for all its users. software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you price. Our General Public Licenses are designed to make sure that you
@ -24,34 +26,44 @@ them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things. free programs, and that you know you can do these things.
Developers that use our General Public Licenses protect your rights To protect your rights, we need to prevent others from denying you
with two steps: (1) assert copyright on the software, and (2) offer these rights or asking you to surrender the rights. Therefore, you have
you this License which gives you legal permission to copy, distribute certain responsibilities if you distribute copies of the software, or if
and/or modify the software. you modify it: responsibilities to respect the freedom of others.
A secondary benefit of defending all users' freedom is that For example, if you distribute copies of such a program, whether
improvements made in alternate versions of the program, if they gratis or for a fee, you must pass on to the recipients the same
receive widespread use, become available for other developers to freedoms that you received. You must make sure that they, too, receive
incorporate. Many developers of free software are heartened and or can get the source code. And you must show them these terms so they
encouraged by the resulting cooperation. However, in the case of know their rights.
software used on network servers, this result may fail to come about.
The GNU General Public License permits making a modified version and
letting the public access it on a server without ever releasing its
source code to the public.
The GNU Affero General Public License is designed specifically to Developers that use the GNU GPL protect your rights with two steps:
ensure that, in such cases, the modified source code becomes available (1) assert copyright on the software, and (2) offer you this License
to the community. It requires the operator of a network server to giving you legal permission to copy, distribute and/or modify it.
provide the source code of the modified version running there to the
users of that server. Therefore, public use of a modified version, on
a publicly accessible server, gives the public access to the source
code of the modified version.
An older license, called the Affero General Public License and For the developers' and authors' protection, the GPL clearly explains
published by Affero, was designed to accomplish similar goals. This is that there is no warranty for this free software. For both users' and
a different license, not a version of the Affero GPL, but Affero has authors' sake, the GPL requires that modified versions be marked as
released a new version of the Affero GPL which permits relicensing under changed, so that their problems will not be attributed erroneously to
this license. authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and The precise terms and conditions for copying, distribution and
modification follow. modification follow.
@ -60,7 +72,7 @@ modification follow.
0. Definitions. 0. Definitions.
"This License" refers to version 3 of the GNU Affero General Public License. "This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of "Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks. works, such as semiconductor masks.
@ -537,45 +549,35 @@ to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program. License would be to refrain entirely from conveying the Program.
13. Remote Network Interaction; Use with the GNU General Public License. 13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, if you modify the
Program, your modified version must prominently offer all users
interacting with it remotely through a computer network (if your version
supports such interaction) an opportunity to receive the Corresponding
Source of your version by providing access to the Corresponding Source
from a network server at no charge, through some standard or customary
means of facilitating copying of software. This Corresponding Source
shall include the Corresponding Source for any work covered by version 3
of the GNU General Public License that is incorporated pursuant to the
following paragraph.
Notwithstanding any other provision of this License, you have Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed permission to link or combine any covered work with a work licensed
under version 3 of the GNU General Public License into a single under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work, License will continue to apply to the part which is the covered work,
but the work with which it is combined will remain governed by version but the special requirements of the GNU Affero General Public License,
3 of the GNU General Public License. section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License. 14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of The Free Software Foundation may publish revised and/or new versions of
the GNU Affero General Public License from time to time. Such new versions the GNU General Public License from time to time. Such new versions will
will be similar in spirit to the present version, but may differ in detail to be similar in spirit to the present version, but may differ in detail to
address new problems or concerns. address new problems or concerns.
Each version is given a distinguishing version number. If the Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU Affero General Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the Foundation. If the Program does not specify a version number of the
GNU Affero General Public License, you may choose any version ever published GNU General Public License, you may choose any version ever published
by the Free Software Foundation. by the Free Software Foundation.
If the Program specifies that a proxy can decide which future If the Program specifies that a proxy can decide which future
versions of the GNU Affero General Public License can be used, that proxy's versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you public statement of acceptance of a version permanently authorizes you
to choose that version for the Program. to choose that version for the Program.
@ -633,29 +635,40 @@ the "copyright" line and a pointer to where the full notice is found.
Copyright (C) <year> <name of author> Copyright (C) <year> <name of author>
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU Affero General Public License You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. along with this program. If not, see <https://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail. Also add information on how to contact you by electronic and paper mail.
If your software can interact with users remotely through a computer If the program does terminal interaction, make it output a short
network, you should also make sure that it provides a way for users to notice like this when it starts in an interactive mode:
get its source. For example, if your program is a web application, its
interface could display a "Source" link that leads users to an archive <program> Copyright (C) <year> <name of author>
of the code. There are many ways you could offer source, and different This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
solutions will be better for different programs; see section 13 for the This is free software, and you are welcome to redistribute it
specific requirements. under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school, You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary. if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU AGPL, see For more information on this, and how to apply and follow the GNU GPL, see
<https://www.gnu.org/licenses/>. <https://www.gnu.org/licenses/>.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<https://www.gnu.org/licenses/why-not-lgpl.html>.

View file

@ -1,44 +0,0 @@
function(dict command dict )
if(command STREQUAL SET)
set(arg_key ${ARGV2})
set(arg_value ${ARGV3})
dict(_IDX ${dict} "${arg_key}" idx)
if(NOT idx STREQUAL -1)
list(REMOVE_AT ${dict} ${idx})
endif()
list(APPEND ${dict} "${arg_key}=${arg_value}")
set(${dict} "${${dict}}" PARENT_SCOPE)
elseif(command STREQUAL GET)
set(arg_key ${ARGV2})
set(arg_outvar ${ARGV3})
dict(_IDX ${dict} "${arg_key}" idx)
if(idx STREQUAL -1)
message(FATAL_ERROR "No key \"${arg_key}\" in dictionary")
endif()
list(GET ${dict} ${idx} kv)
string(REGEX REPLACE "^[^=]+=(.*)" "\\1" value "${kv}")
set(${arg_outvar} "${value}" PARENT_SCOPE)
elseif(command STREQUAL _IDX)
set(arg_key ${ARGV2})
set(arg_outvar ${ARGV3})
set(idx 0)
foreach(kv IN LISTS ${dict})
string(REGEX REPLACE "^([^=]+)=.*" "\\1" key "${kv}")
if(arg_key STREQUAL key)
set(${arg_outvar} "${idx}" PARENT_SCOPE)
return()
endif()
math(EXPR idx ${idx}+1)
endforeach()
set(${arg_outvar} "-1" PARENT_SCOPE)
else()
message(FATAL_ERROR "dict does not recognize sub-command ${command}")
endif()
endfunction()

View file

@ -1,54 +0,0 @@
macro(HEXCHAR2DEC VAR VAL)
if(${VAL} MATCHES "[0-9]")
SET(${VAR} ${VAL})
elseif(${VAL} MATCHES "[aA]")
SET(${VAR} 10)
elseif(${VAL} MATCHES "[bB]")
SET(${VAR} 11)
elseif(${VAL} MATCHES "[cC]")
SET(${VAR} 12)
elseif(${VAL} MATCHES "[dD]")
SET(${VAR} 13)
elseif(${VAL} MATCHES "[eE]")
SET(${VAR} 14)
elseif(${VAL} MATCHES "[fF]")
SET(${VAR} 15)
else()
MESSAGE(FATAL_ERROR "Invalid format for hexidecimal character")
endif()
endmacro(HEXCHAR2DEC)
macro(HEX2DEC VAR VAL)
SET(CURINDEX 0)
STRING(LENGTH "${VAL}" CURLENGTH)
SET(${VAR} 0)
while(CURINDEX LESS CURLENGTH)
STRING(SUBSTRING "${VAL}" ${CURINDEX} 1 CHAR)
HEXCHAR2DEC(CHAR ${CHAR})
MATH(EXPR POWAH "(1<<((${CURLENGTH}-${CURINDEX}-1)*4))")
MATH(EXPR CHAR "(${CHAR}*${POWAH})")
MATH(EXPR ${VAR} "${${VAR}}+${CHAR}")
MATH(EXPR CURINDEX "${CURINDEX}+1")
endwhile()
endmacro(HEX2DEC)
macro(SET_VERSION MAJOR MINOR FILE ROLLBACK)
file(READ ${FILE} ver)
string(REGEX MATCHALL "0x([0-9A-F])([0-9A-F])([0-9A-F])([0-9A-F])" _ ${ver})
string(CONCAT ver_major ${CMAKE_MATCH_1}${CMAKE_MATCH_2})
string(CONCAT ver_minor ${CMAKE_MATCH_3}${CMAKE_MATCH_4})
HEX2DEC(ver_major ${ver_major})
HEX2DEC(ver_minor ${ver_minor})
message(STATUS "Found version:\t\t ${ver_major}.${ver_minor}")
if(PICO_PLATFORM)
if (PICO_RP2350 AND SECURE_BOOT_PKEY)
message(STATUS "Setting rollback version:\t ${ROLLBACK}")
pico_set_binary_version(${CMAKE_PROJECT_NAME} MAJOR ${ver_major} MINOR ${ver_minor} ROLLBACK ${ROLLBACK})
else()
pico_set_binary_version(${CMAKE_PROJECT_NAME} MAJOR ${ver_major} MINOR ${ver_minor})
endif()
endif()
set(${MAJOR} ${ver_major})
set(${MINOR} ${ver_minor})
endmacro(SET_VERSION)

View file

@ -1,7 +0,0 @@
# Name, Type, SubType, Offset, Size, Flags
# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap
nvs, data, nvs, 0x9000, 0x6000
phy_init, data, phy, 0xf000, 0x1000
factory, app, factory, 0x10000, 1M,
part0, 0x40, 0x1, 0x200000, 1M,
1 # Name, Type, SubType, Offset, Size, Flags
2 # Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap
3 nvs, data, nvs, 0x9000, 0x6000
4 phy_init, data, phy, 0xf000, 0x1000
5 factory, app, factory, 0x10000, 1M,
6 part0, 0x40, 0x1, 0x200000, 1M,

File diff suppressed because it is too large Load diff

View file

@ -1,288 +0,0 @@
/*
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
* Copyright (c) 2022 Pol Henarejos.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "common.h"
#include "mbedtls/sha256.h"
#include "mbedtls/platform_util.h"
#include "mbedtls/error.h"
#include "pico/sha256.h"
#define SHA256_BLOCK_SIZE 64
static const uint32_t K[] = {
0x428A2F98, 0x71374491, 0xB5C0FBCF, 0xE9B5DBA5,
0x3956C25B, 0x59F111F1, 0x923F82A4, 0xAB1C5ED5,
0xD807AA98, 0x12835B01, 0x243185BE, 0x550C7DC3,
0x72BE5D74, 0x80DEB1FE, 0x9BDC06A7, 0xC19BF174,
0xE49B69C1, 0xEFBE4786, 0x0FC19DC6, 0x240CA1CC,
0x2DE92C6F, 0x4A7484AA, 0x5CB0A9DC, 0x76F988DA,
0x983E5152, 0xA831C66D, 0xB00327C8, 0xBF597FC7,
0xC6E00BF3, 0xD5A79147, 0x06CA6351, 0x14292967,
0x27B70A85, 0x2E1B2138, 0x4D2C6DFC, 0x53380D13,
0x650A7354, 0x766A0ABB, 0x81C2C92E, 0x92722C85,
0xA2BFE8A1, 0xA81A664B, 0xC24B8B70, 0xC76C51A3,
0xD192E819, 0xD6990624, 0xF40E3585, 0x106AA070,
0x19A4C116, 0x1E376C08, 0x2748774C, 0x34B0BCB5,
0x391C0CB3, 0x4ED8AA4A, 0x5B9CCA4F, 0x682E6FF3,
0x748F82EE, 0x78A5636F, 0x84C87814, 0x8CC70208,
0x90BEFFFA, 0xA4506CEB, 0xBEF9A3F7, 0xC67178F2,
};
#define SHR(x, n) (((x) & 0xFFFFFFFF) >> (n))
#define ROTR(x, n) (SHR(x, n) | ((x) << (32 - (n))))
#define S0(x) (ROTR(x, 7) ^ ROTR(x, 18) ^ SHR(x, 3))
#define S1(x) (ROTR(x, 17) ^ ROTR(x, 19) ^ SHR(x, 10))
#define S2(x) (ROTR(x, 2) ^ ROTR(x, 13) ^ ROTR(x, 22))
#define S3(x) (ROTR(x, 6) ^ ROTR(x, 11) ^ ROTR(x, 25))
#define F0(x, y, z) (((x) & (y)) | ((z) & ((x) | (y))))
#define F1(x, y, z) ((z) ^ ((x) & ((y) ^ (z))))
#define R(t) \
( \
local.W[t] = S1(local.W[(t) - 2]) + local.W[(t) - 7] + \
S0(local.W[(t) - 15]) + local.W[(t) - 16] \
)
#define P(a, b, c, d, e, f, g, h, x, K) \
do \
{ \
local.temp1 = (h) + S3(e) + F1((e), (f), (g)) + (K) + (x); \
local.temp2 = S2(a) + F0((a), (b), (c)); \
(d) += local.temp1; (h) = local.temp1 + local.temp2; \
} while (0)
void mbedtls_sha256_init(mbedtls_sha256_context *ctx) {
memset(ctx, 0, sizeof(mbedtls_sha256_context));
}
void mbedtls_sha256_free(mbedtls_sha256_context *ctx) {
if (ctx == NULL) {
return;
}
mbedtls_platform_zeroize(ctx, sizeof(mbedtls_sha256_context));
}
int mbedtls_sha256_starts(mbedtls_sha256_context *ctx, int is224) {
ctx->is224 = is224;
if (is224 == 1) {
ctx->total[0] = 0;
ctx->total[1] = 0;
ctx->state[0] = 0xC1059ED8;
ctx->state[1] = 0x367CD507;
ctx->state[2] = 0x3070DD17;
ctx->state[3] = 0xF70E5939;
ctx->state[4] = 0xFFC00B31;
ctx->state[5] = 0x68581511;
ctx->state[6] = 0x64F98FA7;
ctx->state[7] = 0xBEFA4FA4;
}
else {
return pico_sha256_start_blocking(&ctx->pico_state, SHA256_BIG_ENDIAN, true);
}
return 0;
}
static int mbedtls_internal_sha256_process_c(mbedtls_sha256_context *ctx, const unsigned char data[SHA256_BLOCK_SIZE]) {
struct {
uint32_t temp1, temp2, W[64];
uint32_t A[8];
} local;
unsigned int i;
for (i = 0; i < 8; i++) {
local.A[i] = ctx->state[i];
}
for (i = 0; i < 16; i++) {
local.W[i] = MBEDTLS_GET_UINT32_BE(data, 4 * i);
}
for (i = 0; i < 16; i += 8) {
P(local.A[0], local.A[1], local.A[2], local.A[3], local.A[4],
local.A[5], local.A[6], local.A[7], local.W[i+0], K[i+0]);
P(local.A[7], local.A[0], local.A[1], local.A[2], local.A[3],
local.A[4], local.A[5], local.A[6], local.W[i+1], K[i+1]);
P(local.A[6], local.A[7], local.A[0], local.A[1], local.A[2],
local.A[3], local.A[4], local.A[5], local.W[i+2], K[i+2]);
P(local.A[5], local.A[6], local.A[7], local.A[0], local.A[1],
local.A[2], local.A[3], local.A[4], local.W[i+3], K[i+3]);
P(local.A[4], local.A[5], local.A[6], local.A[7], local.A[0],
local.A[1], local.A[2], local.A[3], local.W[i+4], K[i+4]);
P(local.A[3], local.A[4], local.A[5], local.A[6], local.A[7],
local.A[0], local.A[1], local.A[2], local.W[i+5], K[i+5]);
P(local.A[2], local.A[3], local.A[4], local.A[5], local.A[6],
local.A[7], local.A[0], local.A[1], local.W[i+6], K[i+6]);
P(local.A[1], local.A[2], local.A[3], local.A[4], local.A[5],
local.A[6], local.A[7], local.A[0], local.W[i+7], K[i+7]);
}
for (i = 16; i < 64; i += 8) {
P(local.A[0], local.A[1], local.A[2], local.A[3], local.A[4],
local.A[5], local.A[6], local.A[7], R(i+0), K[i+0]);
P(local.A[7], local.A[0], local.A[1], local.A[2], local.A[3],
local.A[4], local.A[5], local.A[6], R(i+1), K[i+1]);
P(local.A[6], local.A[7], local.A[0], local.A[1], local.A[2],
local.A[3], local.A[4], local.A[5], R(i+2), K[i+2]);
P(local.A[5], local.A[6], local.A[7], local.A[0], local.A[1],
local.A[2], local.A[3], local.A[4], R(i+3), K[i+3]);
P(local.A[4], local.A[5], local.A[6], local.A[7], local.A[0],
local.A[1], local.A[2], local.A[3], R(i+4), K[i+4]);
P(local.A[3], local.A[4], local.A[5], local.A[6], local.A[7],
local.A[0], local.A[1], local.A[2], R(i+5), K[i+5]);
P(local.A[2], local.A[3], local.A[4], local.A[5], local.A[6],
local.A[7], local.A[0], local.A[1], R(i+6), K[i+6]);
P(local.A[1], local.A[2], local.A[3], local.A[4], local.A[5],
local.A[6], local.A[7], local.A[0], R(i+7), K[i+7]);
}
for (i = 0; i < 8; i++) {
ctx->state[i] += local.A[i];
}
/* Zeroise buffers and variables to clear sensitive data from memory. */
mbedtls_platform_zeroize(&local, sizeof(local));
return 0;
}
static size_t mbedtls_internal_sha256_process_many_c(mbedtls_sha256_context *ctx, const uint8_t *data, size_t len) {
size_t processed = 0;
while (len >= SHA256_BLOCK_SIZE) {
if (mbedtls_internal_sha256_process_c(ctx, data) != 0) {
return 0;
}
data += SHA256_BLOCK_SIZE;
len -= SHA256_BLOCK_SIZE;
processed += SHA256_BLOCK_SIZE;
}
return processed;
}
int mbedtls_sha256_update(mbedtls_sha256_context *ctx, const unsigned char *input, size_t ilen) {
if (ctx->is224 == 1) {
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
size_t fill;
uint32_t left;
if (ilen == 0) {
return 0;
}
left = ctx->total[0] & 0x3F;
fill = SHA256_BLOCK_SIZE - left;
ctx->total[0] += (uint32_t) ilen;
ctx->total[0] &= 0xFFFFFFFF;
if (ctx->total[0] < (uint32_t) ilen) {
ctx->total[1]++;
}
if (left && ilen >= fill) {
memcpy((void *) (ctx->buffer + left), input, fill);
if ((ret = mbedtls_internal_sha256_process_c(ctx, ctx->buffer)) != 0) {
return ret;
}
input += fill;
ilen -= fill;
left = 0;
}
while (ilen >= SHA256_BLOCK_SIZE) {
size_t processed = mbedtls_internal_sha256_process_many_c(ctx, input, ilen);
if (processed < SHA256_BLOCK_SIZE) {
return MBEDTLS_ERR_ERROR_GENERIC_ERROR;
}
input += processed;
ilen -= processed;
}
if (ilen > 0) {
memcpy((void *) (ctx->buffer + left), input, ilen);
}
}
else {
pico_sha256_update_blocking(&ctx->pico_state, (const uint8_t *)input, ilen);
}
return 0;
}
int mbedtls_sha256_finish(mbedtls_sha256_context *ctx, unsigned char *output) {
if (ctx->is224) {
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
uint32_t used;
uint32_t high, low;
used = ctx->total[0] & 0x3F;
ctx->buffer[used++] = 0x80;
if (used <= 56) {
memset(ctx->buffer + used, 0, 56 - used);
} else {
memset(ctx->buffer + used, 0, SHA256_BLOCK_SIZE - used);
if ((ret = mbedtls_internal_sha256_process_c(ctx, ctx->buffer)) != 0) {
goto exit;
}
memset(ctx->buffer, 0, 56);
}
high = (ctx->total[0] >> 29) | (ctx->total[1] << 3);
low = (ctx->total[0] << 3);
MBEDTLS_PUT_UINT32_BE(high, ctx->buffer, 56);
MBEDTLS_PUT_UINT32_BE(low, ctx->buffer, 60);
if ((ret = mbedtls_internal_sha256_process_c(ctx, ctx->buffer)) != 0) {
goto exit;
}
MBEDTLS_PUT_UINT32_BE(ctx->state[0], output, 0);
MBEDTLS_PUT_UINT32_BE(ctx->state[1], output, 4);
MBEDTLS_PUT_UINT32_BE(ctx->state[2], output, 8);
MBEDTLS_PUT_UINT32_BE(ctx->state[3], output, 12);
MBEDTLS_PUT_UINT32_BE(ctx->state[4], output, 16);
MBEDTLS_PUT_UINT32_BE(ctx->state[5], output, 20);
MBEDTLS_PUT_UINT32_BE(ctx->state[6], output, 24);
ret = 0;
exit:
mbedtls_sha256_free(ctx);
return ret;
}
else {
sha256_result_t result;
pico_sha256_finish(&ctx->pico_state, &result);
memcpy(output, result.bytes, 32);
}
return 0;
}

View file

@ -1,36 +0,0 @@
/*
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
* Copyright (c) 2022 Pol Henarejos.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef _SHA256_ALT_H_
#define _SHA256_ALT_H_
#include "pico_keys.h"
#include "pico/sha256.h"
typedef struct mbedtls_sha256_context {
pico_sha256_state_t MBEDTLS_PRIVATE(pico_state);
#if defined(MBEDTLS_SHA224_C)
unsigned char MBEDTLS_PRIVATE(buffer)[64]; /*!< The data block being processed. */
uint32_t MBEDTLS_PRIVATE(total)[2]; /*!< The number of Bytes processed. */
uint32_t MBEDTLS_PRIVATE(state)[8]; /*!< The intermediate digest state. */
int MBEDTLS_PRIVATE(is224); /*!< Determines which function to use:
0: Use SHA-256, or 1: Use SHA-224. */
#endif
}
mbedtls_sha256_context;
#endif /* _SHA256_ALT_H_ */

View file

@ -1,40 +0,0 @@
{
"version": [1, 0],
"unpartitioned": {
"families": ["absolute"],
"permissions": {
"secure": "rw",
"nonsecure": "rw",
"bootloader": "rw"
}
},
"partitions": [
{
"name": "Pico Keys Firmware",
"id": 0,
"start": 0,
"size": "1024K",
"families": ["rp2350-arm-s", "rp2350-riscv"],
"permissions": {
"secure": "rw",
"nonsecure": "rw",
"bootloader": "rw"
}
},
{
"name": "Pico Keys Data",
"id": 1,
"start": "1024K",
"size": "3072K",
"families": ["data"],
"permissions": {
"secure": "rw",
"nonsecure": "",
"bootloader": "r"
},
"link": ["owner", 0],
"ignored_during_arm_boot": true,
"ignored_during_riscv_boot": true
}
]
}

View file

@ -1,42 +0,0 @@
{
"boot_flags1": {
"key_valid": 1
},
"bootkey0": [
225,
209,
107,
167,
100,
171,
215,
18,
212,
239,
110,
62,
221,
116,
78,
213,
99,
140,
38,
11,
119,
28,
249,
129,
81,
17,
11,
175,
172,
155,
200,
113
],
"crit1": {
"secure_boot_enable": 1
}
}

@ -1 +1 @@
Subproject commit 107ea89daaefb9867ea9121002fbbdf926780e98 Subproject commit d65aeb37349ad1a50e0f6c9b694d4b5290d60e49

114
pico_hsm_sdk_import.cmake Normal file
View file

@ -0,0 +1,114 @@
#
# This file is part of the Pico HSM SDK distribution (https://github.com/polhenarejos/pico-hsm-sdk).
# 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/>.
#
if (NOT DEFINED USB_VID)
set(USB_VID 0xFEFF)
endif()
add_definitions(-DUSB_VID=${USB_VID})
if (NOT DEFINED USB_PID)
set(USB_PID 0xFCFD)
endif()
add_definitions(-DUSB_PID=${USB_PID})
if (NOT DEFINED DEBUG_APDU)
set(DEBUG_APDU 0)
endif()
if (NOT DEFINED HSM_DRIVER)
set(HSM_DRIVER "ccid")
endif()
add_definitions(-DDEBUG_APDU=${DEBUG_APDU})
configure_file(${CMAKE_CURRENT_LIST_DIR}/config/mbedtls_config.h ${CMAKE_CURRENT_LIST_DIR}/mbedtls/include/mbedtls COPYONLY)
message(STATUS "HSM driver: ${HSM_DRIVER}")
message(STATUS "USB VID/PID: ${USB_VID}:${USB_PID}")
configure_file(${CMAKE_CURRENT_LIST_DIR}/config/mbedtls_config.h ${CMAKE_CURRENT_LIST_DIR}/mbedtls/include/mbedtls COPYONLY)
if (NOT TARGET pico_hsm_sdk)
pico_add_impl_library(pico_hsm_sdk)
target_sources(pico_hsm_sdk INTERFACE
${CMAKE_CURRENT_LIST_DIR}/src/main.c
${CMAKE_CURRENT_LIST_DIR}/src/usb/usb.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/hwrng.c
${CMAKE_CURRENT_LIST_DIR}/src/eac.c
${CMAKE_CURRENT_LIST_DIR}/src/crypto_utils.c
${CMAKE_CURRENT_LIST_DIR}/src/asn1.c
${CMAKE_CURRENT_LIST_DIR}/src/apdu.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/aes.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/asn1parse.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/asn1write.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/bignum.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/cmac.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/cipher.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/cipher_wrap.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/constant_time.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/ecdsa.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/ecdh.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/ecp.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/ecp_curves.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/hkdf.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/md.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/md5.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/oid.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/platform_util.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/ripemd160.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/rsa.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/rsa_alt_helpers.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/sha1.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/sha256.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/sha512.c
)
if (${HSM_DRIVER} STREQUAL "ccid")
target_sources(pico_hsm_sdk INTERFACE
${CMAKE_CURRENT_LIST_DIR}/src/usb/ccid/usb_descriptors.c
${CMAKE_CURRENT_LIST_DIR}/src/usb/ccid/ccid.c
)
target_include_directories(pico_hsm_sdk INTERFACE
${CMAKE_CURRENT_LIST_DIR}/src/usb/ccid
)
elseif (${HSM_DRIVER} STREQUAL "hid")
target_sources(pico_hsm_sdk INTERFACE
${CMAKE_CURRENT_LIST_DIR}/src/usb/hid/hid.c
${CMAKE_CURRENT_LIST_DIR}/src/usb/hid/usb_descriptors.c
)
target_include_directories(pico_hsm_sdk INTERFACE
${CMAKE_CURRENT_LIST_DIR}/src/usb/hid
)
endif()
target_include_directories(pico_hsm_sdk INTERFACE
${CMAKE_CURRENT_LIST_DIR}/src
${CMAKE_CURRENT_LIST_DIR}/src/usb
${CMAKE_CURRENT_LIST_DIR}/src/fs
${CMAKE_CURRENT_LIST_DIR}/src/rng
${CMAKE_CURRENT_LIST_DIR}/mbedtls/include
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library
)
target_link_libraries(pico_hsm_sdk INTERFACE pico_stdlib pico_multicore hardware_flash hardware_sync hardware_adc pico_unique_id hardware_rtc tinyusb_device tinyusb_board)
endif()

View file

@ -1,472 +0,0 @@
#
# This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
# 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(pico-keys-sdk/cmake/version.cmake OPTIONAL)
option(VIDPID "Set specific VID/PID from a known platform {NitroHSM, NitroFIDO2, NitroStart, NitroPro, Nitro3, Yubikey5, YubikeyNeo, YubiHSM, Gnuk, GnuPG}" "None")
message(STATUS "VIDPID:\t\t\t '${VIDPID}'")
if(VIDPID STREQUAL "NitroHSM")
set(USB_VID 0x20A0)
set(USB_PID 0x4230)
elseif(VIDPID STREQUAL "NitroFIDO2")
set(USB_VID 0x20A0)
set(USB_PID 0x42B1)
elseif(VIDPID STREQUAL "NitroStart")
set(USB_VID 0x20A0)
set(USB_PID 0x4211)
elseif(VIDPID STREQUAL "NitroPro")
set(USB_VID 0x20A0)
set(USB_PID 0x4108)
elseif(VIDPID STREQUAL "Nitro3")
set(USB_VID 0x20A0)
set(USB_PID 0x42B2)
elseif(VIDPID STREQUAL "Yubikey5")
set(USB_VID 0x1050)
set(USB_PID 0x0407)
elseif(VIDPID STREQUAL "YubikeyNeo")
set(USB_VID 0x1050)
set(USB_PID 0x0116)
elseif(VIDPID STREQUAL "YubiHSM")
set(USB_VID 0x1050)
set(USB_PID 0x0030)
elseif(VIDPID STREQUAL "Gnuk")
set(USB_VID 0x234B)
set(USB_PID 0x0000)
elseif(VIDPID STREQUAL "GnuPG")
set(USB_VID 0x1209)
set(USB_PID 0x2440)
endif()
if(ESP_PLATFORM)
if(DEFINED CONFIG_TINYUSB_DESC_CUSTOM_VID)
set(USB_VID CONFIG_TINYUSB_DESC_CUSTOM_VID)
endif()
if(DEFINED CONFIG_TINYUSB_DESC_CUSTOM_PID)
set(USB_PID CONFIG_TINYUSB_DESC_CUSTOM_PID)
endif()
endif()
if(NOT DEFINED USB_VID)
set(USB_VID 0xFEFF)
endif()
add_definitions(-DUSB_VID=${USB_VID})
if(NOT DEFINED USB_PID)
set(USB_PID 0xFCFD)
endif()
add_definitions(-DUSB_PID=${USB_PID})
if(NOT DEFINED DEBUG_APDU)
set(DEBUG_APDU 0)
endif()
if(NOT DEFINED ENABLE_EMULATION)
set(ENABLE_EMULATION 0)
endif()
option(ENABLE_DELAYED_BOOT "Enable/disable delayed boot" OFF)
if(ENABLE_DELAYED_BOOT)
add_definitions(-DPICO_XOSC_STARTUP_DELAY_MULTIPLIER=64)
message(STATUS "Delayed boot:\t\t enabled")
else()
message(STATUS "Delayed boot:\t\t disabled")
endif(ENABLE_DELAYED_BOOT)
if(USB_ITF_HID)
add_definitions(-DUSB_ITF_HID=1)
message(STATUS "USB HID Interface:\t\t enabled")
endif(USB_ITF_HID)
if(USB_ITF_CCID)
add_definitions(-DUSB_ITF_CCID=1)
message(STATUS "USB CCID Interface:\t\t enabled")
if(USB_ITF_WCID)
add_definitions(-DUSB_ITF_WCID=1)
message(STATUS "USB WebCCID Interface:\t enabled")
endif(USB_ITF_WCID)
endif(USB_ITF_CCID)
add_definitions(-DDEBUG_APDU=${DEBUG_APDU})
if(NOT ESP_PLATFORM)
add_definitions(-DMBEDTLS_CONFIG_FILE="${CMAKE_CURRENT_LIST_DIR}/config/mbedtls_config.h")
else()
add_definitions(-DCFG_TUSB_CONFIG_FILE="${CMAKE_CURRENT_LIST_DIR}/src/usb/tusb_config.h")
endif()
message(STATUS "USB VID/PID:\t\t\t ${USB_VID}:${USB_PID}")
if(NOT ESP_PLATFORM)
set(NEED_UPDATE OFF)
option(ENABLE_EDDSA "Enable/disable EdDSA support" OFF)
if(ENABLE_EDDSA)
message(STATUS "EdDSA support:\t\t enabled")
else()
message(STATUS "EdDSA support:\t\t disabled")
endif(ENABLE_EDDSA)
set(MBEDTLS_PATH "${CMAKE_SOURCE_DIR}/pico-keys-sdk/mbedtls")
execute_process(
COMMAND git config --global --add safe.directory ${MBEDTLS_PATH}
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
OUTPUT_QUIET ERROR_QUIET
)
if(ENABLE_EDDSA)
set(MBEDTLS_ORIGIN "https://github.com/polhenarejos/mbedtls.git")
set(MBEDTLS_REF "mbedtls-3.6-eddsa")
execute_process(
COMMAND git -C ${MBEDTLS_PATH} symbolic-ref --quiet --short HEAD
OUTPUT_VARIABLE CURRENT_BRANCH
OUTPUT_STRIP_TRAILING_WHITESPACE
RESULT_VARIABLE BRANCH_ERR
)
message(STATUS "Current branch for mbedTLS: ${CURRENT_BRANCH}")
message(STATUS "Target branch for mbedTLS: ${MBEDTLS_REF}")
if(NOT BRANCH_ERR EQUAL 0 OR NOT "${CURRENT_BRANCH}" STREQUAL "${MBEDTLS_REF}")
set(NEED_UPDATE ON)
else()
set(NEED_UPDATE OFF)
endif()
add_definitions(-DMBEDTLS_ECP_DP_ED25519_ENABLED=1 -DMBEDTLS_ECP_DP_ED448_ENABLED=1 -DMBEDTLS_EDDSA_C=1 -DMBEDTLS_SHA3_C=1)
else()
set(MBEDTLS_ORIGIN "https://github.com/Mbed-TLS/mbedtls.git")
set(MBEDTLS_REF "v3.6.5")
execute_process(
COMMAND git -C ${MBEDTLS_PATH} describe --tags --exact-match
OUTPUT_VARIABLE CURRENT_TAG
OUTPUT_STRIP_TRAILING_WHITESPACE
RESULT_VARIABLE TAG_ERR
)
message(STATUS "Current tag for mbedTLS: ${CURRENT_TAG}")
message(STATUS "Target tag for mbedTLS: ${MBEDTLS_REF}")
if(NOT TAG_ERR EQUAL 0 OR NOT "${CURRENT_TAG}" STREQUAL "${MBEDTLS_REF}")
set(NEED_UPDATE ON)
else()
set(NEED_UPDATE OFF)
endif()
endif()
if(NEED_UPDATE)
message(STATUS "Updating mbedTLS source code...")
execute_process(
COMMAND git -C ${MBEDTLS_PATH} submodule update --init --recursive --remote pico-keys-sdk
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
OUTPUT_QUIET ERROR_QUIET
)
execute_process(
COMMAND git -C ${MBEDTLS_PATH} remote set-url origin ${MBEDTLS_ORIGIN}
OUTPUT_QUIET ERROR_QUIET
)
execute_process(
COMMAND git -C ${MBEDTLS_PATH} fetch origin +refs/heads/*:refs/remotes/origin/* --tags --force
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
OUTPUT_QUIET ERROR_QUIET
)
execute_process(
COMMAND rm -rf ${MBEDTLS_PATH}/framework
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
OUTPUT_QUIET ERROR_QUIET
)
if(ENABLE_EDDSA)
execute_process(
COMMAND git -C ${MBEDTLS_PATH} checkout -B ${MBEDTLS_REF} --track origin/${MBEDTLS_REF}
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
OUTPUT_QUIET ERROR_QUIET
)
else()
execute_process(
COMMAND git -C ${MBEDTLS_PATH} checkout ${MBEDTLS_REF}
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
OUTPUT_QUIET ERROR_QUIET
)
endif()
else()
message(STATUS "mbedTLS source code is up to date.")
endif()
endif(NOT ESP_PLATFORM)
set(MBEDTLS_SOURCES
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/aes.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/asn1parse.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/asn1write.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/bignum.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/bignum_core.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/ccm.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/cmac.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/cipher.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/cipher_wrap.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/constant_time.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/ecdsa.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/ecdh.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/ecp.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/ecp_curves.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/gcm.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/hkdf.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/md.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/md5.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/oid.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/pkcs5.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/platform_util.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/rsa.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/rsa_alt_helpers.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/sha1.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/sha256.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/sha512.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/chachapoly.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/chacha20.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/poly1305.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/ripemd160.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/des.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/x509write_crt.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/x509_create.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/x509write_csr.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/pk.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/pk_wrap.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/pkwrite.c
)
if (ENABLE_EDDSA)
set(MBEDTLS_SOURCES ${MBEDTLS_SOURCES}
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/eddsa.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/sha3.c
)
endif()
set(PICO_KEYS_SOURCES ${PICO_KEYS_SOURCES}
${CMAKE_CURRENT_LIST_DIR}/src/main.c
${CMAKE_CURRENT_LIST_DIR}/src/usb/usb.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/fs/otp.c
${CMAKE_CURRENT_LIST_DIR}/src/fs/phy.c
${CMAKE_CURRENT_LIST_DIR}/src/rng/random.c
${CMAKE_CURRENT_LIST_DIR}/src/rng/hwrng.c
${CMAKE_CURRENT_LIST_DIR}/src/eac.c
${CMAKE_CURRENT_LIST_DIR}/src/crypto_utils.c
${CMAKE_CURRENT_LIST_DIR}/src/asn1.c
${CMAKE_CURRENT_LIST_DIR}/src/apdu.c
${CMAKE_CURRENT_LIST_DIR}/src/rescue.c
${CMAKE_CURRENT_LIST_DIR}/src/led/led.c
)
if(ESP_PLATFORM)
set(PICO_KEYS_SOURCES ${PICO_KEYS_SOURCES} ${CMAKE_CURRENT_LIST_DIR}/src/led/led_neopixel.c)
else()
if (NOT ENABLE_EMULATION)
set(PICO_KEYS_SOURCES ${PICO_KEYS_SOURCES}
${CMAKE_CURRENT_LIST_DIR}/src/led/led_cyw43.c
${CMAKE_CURRENT_LIST_DIR}/src/led/led_pico.c
${CMAKE_CURRENT_LIST_DIR}/src/led/led_pimoroni.c
${CMAKE_CURRENT_LIST_DIR}/src/led/led_ws2812.c
)
endif()
endif()
## mbedTLS reports an stringop overflow for cmac.c
if(NOT ENABLE_EMULATION AND NOT APPLE)
set_source_files_properties(
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/cmac.c
PROPERTIES
COMPILE_FLAGS "-Wno-error=stringop-overflow= -Wno-stringop-overflow"
)
endif()
set(INCLUDES ${INCLUDES}
${CMAKE_CURRENT_LIST_DIR}/src
${CMAKE_CURRENT_LIST_DIR}/src/usb
${CMAKE_CURRENT_LIST_DIR}/src/fs
${CMAKE_CURRENT_LIST_DIR}/src/rng
${CMAKE_CURRENT_LIST_DIR}/src/led
${CMAKE_CURRENT_LIST_DIR}/mbedtls/include
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library
)
if(USB_ITF_HID)
set(MBEDTLS_SOURCES ${MBEDTLS_SOURCES}
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/x509write_crt.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/x509_create.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/x509write_csr.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/pk.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/pk_wrap.c
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/pkwrite.c
)
set(CBOR_SOURCES
${CMAKE_CURRENT_LIST_DIR}/tinycbor/src/cborencoder.c
${CMAKE_CURRENT_LIST_DIR}/tinycbor/src/cborparser.c
${CMAKE_CURRENT_LIST_DIR}/tinycbor/src/cborparser_dup_string.c
)
set(INCLUDES ${INCLUDES}
${CMAKE_CURRENT_LIST_DIR}/tinycbor/src
)
endif()
set(LIBRARIES
pico_stdlib
pico_multicore
pico_rand
pico_aon_timer
hardware_flash
pico_unique_id
tinyusb_device
tinyusb_board
hardware_pio
)
set(IS_CYW43 0)
if (PICO_PLATFORM)
file(READ ${PICO_SDK_PATH}/src/boards/include/boards/${PICO_BOARD}.h content)
string(REGEX MATCHALL "CYW43_WL_GPIO_LED_PIN" _ ${content})
if (CMAKE_MATCH_0)
message(STATUS "Found cyw43 LED:\t\t true")
set(LIBRARIES ${LIBRARIES} pico_cyw43_arch_none)
set(IS_CYW43 1)
endif()
endif()
function(add_impl_library target)
add_library(${target} INTERFACE)
string(TOUPPER ${target} TARGET_UPPER)
target_compile_definitions(${target} INTERFACE LIB_${TARGET_UPPER}=1)
endfunction()
if(USB_ITF_HID)
set(PICO_KEYS_SOURCES ${PICO_KEYS_SOURCES}
${CMAKE_CURRENT_LIST_DIR}/src/usb/hid/hid.c
)
set(INCLUDES ${INCLUDES}
${CMAKE_CURRENT_LIST_DIR}/src/usb/hid
)
endif()
if(USB_ITF_CCID)
set(PICO_KEYS_SOURCES ${PICO_KEYS_SOURCES}
${CMAKE_CURRENT_LIST_DIR}/src/usb/ccid/ccid.c
)
set(INCLUDES ${INCLUDES}
${CMAKE_CURRENT_LIST_DIR}/src/usb/ccid
)
endif()
if(NOT MSVC)
add_definitions("-fmacro-prefix-map=${CMAKE_CURRENT_LIST_DIR}/=")
endif()
if(MSVC)
set(PICO_KEYS_SOURCES ${PICO_KEYS_SOURCES}
${CMAKE_CURRENT_LIST_DIR}/src/fs/mman.c
)
endif()
if(ENABLE_EMULATION)
if(APPLE)
add_definitions("-Wno-deprecated-declarations")
endif()
add_definitions(-DENABLE_EMULATION)
set(PICO_KEYS_SOURCES ${PICO_KEYS_SOURCES}
${CMAKE_CURRENT_LIST_DIR}/src/usb/emulation/emulation.c
)
set(MBEDTLS_SOURCES ${MBEDTLS_SOURCES}
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/aesni.c
)
set(INCLUDES ${INCLUDES}
${CMAKE_CURRENT_LIST_DIR}/src/usb/emulation
)
else()
set(PICO_KEYS_SOURCES ${PICO_KEYS_SOURCES}
${CMAKE_CURRENT_LIST_DIR}/src/usb/usb_descriptors.c
)
endif()
set(EXTERNAL_SOURCES ${CBOR_SOURCES})
if(NOT ESP_PLATFORM)
set(EXTERNAL_SOURCES ${EXTERNAL_SOURCES} ${MBEDTLS_SOURCES})
endif()
if(MSVC)
set(
CMAKE_C_FLAGS
"${CMAKE_C_FLAGS} -wd4820 -wd4255 -wd5045 -wd4706 -wd4061 -wd5105 -wd4141 -wd4200"
)
add_compile_definitions(_CRT_SECURE_NO_WARNINGS
__STDC_WANT_SECURE_LIB__=0
_WIN32_WINNT_WIN10_TH2=0
_WIN32_WINNT_WIN10_RS1=0
_WIN32_WINNT_WIN10_RS2=0
_WIN32_WINNT_WIN10_RS3=0
_WIN32_WINNT_WIN10_RS4=0
_WIN32_WINNT_WIN10_RS5=0
_STRALIGN_USE_SECURE_CRT=0
NTDDI_WIN11_DT=0)
set_source_files_properties(
${EXTERNAL_SOURCES}
PROPERTIES
COMPILE_FLAGS " -W3 -wd4242 -wd4065"
)
endif()
if(PICO_PLATFORM)
pico_sdk_init()
endif()
if(PICO_RP2350)
pico_set_uf2_family(${CMAKE_PROJECT_NAME} "rp2350-arm-s")
pico_embed_pt_in_binary(${CMAKE_PROJECT_NAME} "${CMAKE_CURRENT_LIST_DIR}/config/rp2350/pt.json")
if (NOT IS_CYW43)
pico_set_binary_type(${CMAKE_PROJECT_NAME} copy_to_ram)
endif()
if (SECURE_BOOT_PKEY)
message(STATUS "Secure Boot Key ${SECURE_BOOT_PKEY}")
pico_sign_binary(${CMAKE_PROJECT_NAME} ${SECURE_BOOT_PKEY})
pico_hash_binary(${CMAKE_PROJECT_NAME})
endif()
target_link_libraries(${CMAKE_PROJECT_NAME} PRIVATE pico_bootrom)
set(INCLUDES ${INCLUDES}
${CMAKE_CURRENT_LIST_DIR}/config/rp2350/alt
)
set(PICO_KEYS_SOURCES ${PICO_KEYS_SOURCES}
${CMAKE_CURRENT_LIST_DIR}/config/rp2350/alt/sha256_alt.c
)
set(LIBRARIES ${LIBRARIES} pico_sha256)
endif()
set(INTERNAL_SOURCES ${PICO_KEYS_SOURCES})
set(PICO_KEYS_SOURCES ${PICO_KEYS_SOURCES} ${EXTERNAL_SOURCES})
if(NOT TARGET pico_keys_sdk)
if(PICO_PLATFORM)
pico_add_library(pico_keys_sdk)
target_link_libraries(${CMAKE_PROJECT_NAME} PRIVATE ${LIBRARIES})
else()
add_impl_library(pico_keys_sdk)
endif()
target_sources(pico_keys_sdk INTERFACE ${PICO_KEYS_SOURCES})
target_include_directories(pico_keys_sdk INTERFACE ${INCLUDES})
target_link_libraries(pico_keys_sdk INTERFACE ${LIBRARIES})
endif()

View file

@ -1,14 +0,0 @@
# This file was generated using idf.py save-defconfig. It can be edited manually.
# Espressif IoT Development Framework (ESP-IDF) Project Minimal Configuration
#
IGNORE_UNKNOWN_FILES_FOR_MANAGED_COMPONENTS=1
CONFIG_TINYUSB=y
CONFIG_PARTITION_TABLE_CUSTOM=y
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="config/esp32/partitions.csv"
CONFIG_PARTITION_TABLE_FILENAME="config/esp32/partitions.csv"
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
CONFIG_WL_SECTOR_SIZE_512=y
CONFIG_WL_SECTOR_MODE_PERF=y
COMPILER_OPTIMIZATION="Performance"

View file

@ -1,6 +0,0 @@
idf_component_register(
SRCS ${PICO_KEYS_SOURCES}
INCLUDE_DIRS . fs rng usb led ../tinycbor/src
REQUIRES bootloader_support esp_partition esp_tinyusb efuse mbedtls
)
idf_component_set_property(${COMPONENT_NAME} WHOLE_ARCHIVE ON)

View file

@ -1,174 +1,117 @@
/* /*
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk). * This file is part of the Pico HSM distribution (https://github.com/polhenarejos/pico-hsm).
* Copyright (c) 2022 Pol Henarejos. * Copyright (c) 2022 Pol Henarejos.
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3. * the Free Software Foundation, version 3.
* *
* This program is distributed in the hope that it will be useful, but * This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of * WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Affero General Public License for more details. * General Public License for more details.
* *
* You should have received a copy of the GNU Affero General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "apdu.h" #include "apdu.h"
#include "pico_keys.h" #include "hsm.h"
#include "usb.h" #include "usb.h"
#include <stdio.h> #include <stdio.h>
#ifdef ESP_PLATFORM
#include "esp_compat.h"
#endif
#ifdef ENABLE_EMULATION
#include "emulation.h"
#endif
uint8_t *rdata_gr = NULL; uint8_t *rdata_gr = NULL;
uint16_t rdata_bk = 0x0; uint16_t rdata_bk = 0x0;
extern uint32_t timeout; extern uint32_t timeout;
bool is_chaining = false;
uint8_t chain_buf[4096];
uint8_t *chain_ptr = NULL;
int process_apdu() { int process_apdu() {
led_set_mode(MODE_PROCESSING); led_set_blink(BLINK_PROCESSING);
if (CLA(apdu) & 0x10) { if (!current_app)
if (!is_chaining) { {
chain_ptr = chain_buf; if (INS(apdu) == 0xA4 && P1(apdu) == 0x04 && (P2(apdu) == 0x00 || P2(apdu) == 0x4)) { //select by AID
for (int a = 0; a < num_apps; a++) {
if ((current_app = apps[a].select_aid(&apps[a]))) {
return set_res_sw(0x90,0x00);
}
}
} }
if (chain_ptr - chain_buf + apdu.nc >= sizeof(chain_buf)) { return set_res_sw(0x6a, 0x82);
return SW_CLA_NOT_SUPPORTED();
}
memcpy(chain_ptr, apdu.data, apdu.nc);
chain_ptr += apdu.nc;
is_chaining = true;
return SW_OK();
} }
else { if (current_app->process_apdu)
if (is_chaining) {
memmove(apdu.data + (chain_ptr - chain_buf), apdu.data, apdu.nc);
memcpy(apdu.data, chain_buf, chain_ptr - chain_buf);
apdu.nc += (uint16_t)(chain_ptr - chain_buf);
is_chaining = false;
}
}
if (INS(apdu) == 0xA4 && P1(apdu) == 0x04 && (P2(apdu) == 0x00 || P2(apdu) == 0x4)) { //select by AID
if (select_app(apdu.data, apdu.nc) == PICOKEY_OK) {
return SW_OK();
}
return SW_FILE_NOT_FOUND();
}
if (current_app && current_app->process_apdu) {
return current_app->process_apdu(); return current_app->process_apdu();
} return set_res_sw(0x6D, 0x00);
return SW_FILE_NOT_FOUND();
} }
uint16_t apdu_process(uint8_t itf, const uint8_t *buffer, uint16_t buffer_size) { size_t apdu_process(const uint8_t *buffer, size_t buffer_size) {
apdu.header = (uint8_t *) buffer; apdu.header = (uint8_t *)buffer;
apdu.nc = apdu.ne = 0; apdu.nc = apdu.ne = 0;
if (buffer_size == 4) { if (buffer_size == 4) {
apdu.nc = apdu.ne = 0; apdu.nc = apdu.ne = 0;
if (apdu.ne == 0) { if (apdu.ne == 0)
apdu.ne = 256; apdu.ne = 256;
}
} }
else if (buffer_size == 5) { else if (buffer_size == 5) {
apdu.nc = 0; apdu.nc = 0;
apdu.ne = apdu.header[4]; apdu.ne = apdu.header[4];
if (apdu.ne == 0) { if (apdu.ne == 0)
apdu.ne = 256; apdu.ne = 256;
}
} }
else if (apdu.header[4] == 0x0 && buffer_size >= 7) { else if (apdu.header[4] == 0x0 && buffer_size >= 7) {
if (buffer_size == 7) { if (buffer_size == 7) {
apdu.ne = get_uint16_t_be(apdu.header + 5); apdu.ne = (apdu.header[5] << 8) | apdu.header[6];
if (apdu.ne == 0) { if (apdu.ne == 0)
apdu.ne = 65536; apdu.ne = 65536;
}
} }
else { else {
apdu.ne = 0; apdu.ne = 0;
apdu.nc = get_uint16_t_be(apdu.header + 5); apdu.nc = (apdu.header[5] << 8) | apdu.header[6];
apdu.data = apdu.header + 7; apdu.data = apdu.header+7;
if (apdu.nc + 7 + 2 == buffer_size) { if (apdu.nc+7+2 == buffer_size) {
apdu.ne = get_uint16_t_be(apdu.header + buffer_size - 2); apdu.ne = (apdu.header[buffer_size-2] << 8) | apdu.header[buffer_size-1];
if (apdu.ne == 0) { if (apdu.ne == 0)
apdu.ne = 65536; apdu.ne = 65536;
}
} }
} }
} }
else { else {
apdu.nc = apdu.header[4]; apdu.nc = apdu.header[4];
apdu.data = apdu.header + 5; apdu.data = apdu.header+5;
apdu.ne = 0; apdu.ne = 0;
if (apdu.nc + 5 + 1 == buffer_size) { if (apdu.nc+5+1 == buffer_size) {
apdu.ne = apdu.header[buffer_size - 1]; apdu.ne = apdu.header[buffer_size-1];
if (apdu.ne == 0) { if (apdu.ne == 0)
apdu.ne = 256; apdu.ne = 256;
}
} }
} }
//printf("apdu.nc %u, apdu.ne %u\n",apdu.nc,apdu.ne); //printf("apdu.nc %ld, apdu.ne %ld\r\n",apdu.nc,apdu.ne);
if (apdu.header[1] == 0xc0) { if (apdu.header[1] == 0xc0) {
//printf("apdu.ne %u, apdu.rlen %d, bk %x\n",apdu.ne,apdu.rlen,rdata_bk); //printf("apdu.ne %ld, apdu.rlen %d, bk %x\r\n",apdu.ne,apdu.rlen,rdata_bk);
timeout_stop(); timeout_stop();
rdata_gr[0] = rdata_bk >> 8; *(uint16_t *)rdata_gr = rdata_bk;
rdata_gr[1] = rdata_bk & 0xff;
if (apdu.rlen <= apdu.ne) { if (apdu.rlen <= apdu.ne) {
#ifndef ENABLE_EMULATION driver_exec_finished_cont(apdu.rlen+2, rdata_gr-usb_get_tx());
#ifdef USB_ITF_HID
if (itf == ITF_HID_CTAP) {
driver_exec_finished_cont_hid(itf, apdu.rlen + 2, (uint16_t)(rdata_gr - apdu.rdata));
}
#endif
#ifdef USB_ITF_CCID
if (itf == ITF_SC_CCID || itf == ITF_SC_WCID) {
driver_exec_finished_cont_ccid(itf, apdu.rlen + 2, (uint16_t)(rdata_gr - apdu.rdata));
}
#endif
#else
driver_exec_finished_cont_emul(itf, apdu.rlen + 2, (uint16_t)(rdata_gr - apdu.rdata));
#endif
//Prepare next RAPDU
apdu.sw = 0;
apdu.rlen = 0;
rdata_gr = apdu.rdata;
} }
else { else {
rdata_gr += apdu.ne; rdata_gr += apdu.ne;
rdata_bk = (rdata_gr[0] << 8) | rdata_gr[1]; rdata_bk = *rdata_gr;
rdata_gr[0] = 0x61; rdata_gr[0] = 0x61;
if (apdu.rlen - apdu.ne >= 256) { if (apdu.rlen - apdu.ne >= 256)
rdata_gr[1] = 0; rdata_gr[1] = 0;
} else
else { rdata_gr[1] = apdu.rlen - apdu.ne;
rdata_gr[1] = (uint8_t)(apdu.rlen - apdu.ne); driver_exec_finished_cont(apdu.ne+2, rdata_gr-apdu.ne-usb_get_tx());
} apdu.rlen -= apdu.ne;
#ifndef ENABLE_EMULATION
#ifdef USB_ITF_HID
if (itf == ITF_HID_CTAP) {
driver_exec_finished_cont_hid(itf, (uint16_t)(apdu.ne + 2), (uint16_t)(rdata_gr - apdu.ne - apdu.rdata));
}
#endif
#ifdef USB_ITF_CCID
if (itf == ITF_SC_CCID || itf == ITF_SC_WCID) {
driver_exec_finished_cont_ccid(itf, (uint16_t)(apdu.ne + 2), (uint16_t)(rdata_gr - apdu.ne - apdu.rdata));
}
#endif
#else
driver_exec_finished_cont_emul(itf, (uint16_t)(apdu.ne + 2), (uint16_t)(rdata_gr - apdu.ne - apdu.rdata));
#endif
apdu.rlen -= (uint16_t)apdu.ne;
} }
//Prepare next RAPDU
apdu.sw = 0;
apdu.rlen = 0;
usb_prepare_response();
return 0;
} }
else { else {
apdu.sw = 0; apdu.sw = 0;
apdu.rlen = 0; apdu.rlen = 0;
apdu.rdata = usb_prepare_response();
rdata_gr = apdu.rdata; rdata_gr = apdu.rdata;
return 1; return 1;
} }
@ -176,79 +119,35 @@ uint16_t apdu_process(uint8_t itf, const uint8_t *buffer, uint16_t buffer_size)
} }
uint16_t set_res_sw(uint8_t sw1, uint8_t sw2) { uint16_t set_res_sw(uint8_t sw1, uint8_t sw2) {
apdu.sw = make_uint16_t_be(sw1, sw2); apdu.sw = (sw1 << 8) | sw2;
if (sw1 != 0x90) { if (sw1 != 0x90)
res_APDU_size = 0; res_APDU_size = 0;
} return make_uint16_t(sw1, sw2);
return make_uint16_t_be(sw1, sw2);
}
void *apdu_thread(void *arg) {
(void)arg;
card_init_core1();
while (1) {
uint32_t m = 0;
queue_remove_blocking(&usb_to_card_q, &m);
uint32_t flag = m + 1;
queue_add_blocking(&card_to_usb_q, &flag);
if (m == EV_VERIFY_CMD_AVAILABLE || m == EV_MODIFY_CMD_AVAILABLE) {
set_res_sw(0x6f, 0x00);
goto done;
}
else if (m == EV_EXIT) {
break;
}
process_apdu();
done: ;
apdu_finish();
finished_data_size = apdu_next();
flag = EV_EXEC_FINISHED;
queue_add_blocking(&card_to_usb_q, &flag);
#ifdef ESP_PLATFORM
vTaskDelay(pdMS_TO_TICKS(10));
#endif
}
//printf("EXIT !!!!!!\n");
if (current_app && current_app->unload) {
current_app->unload();
current_app = NULL;
}
return NULL;
} }
void apdu_finish() { void apdu_finish() {
put_uint16_t_be(apdu.sw, apdu.rdata + apdu.rlen); apdu.rdata[apdu.rlen] = apdu.sw >> 8;
// timeout_stop(); apdu.rdata[apdu.rlen+1] = apdu.sw & 0xff;
#ifndef ENABLE_EMULATION timeout_stop();
/* It was fixed in the USB handling. Keep it just in case */ if ((apdu.rlen + 2 + 10) % 64 == 0)
//if ((apdu.rlen + 2 + 10) % 64 == 0) { // FIX for strange behaviour with PSCS and multiple of 64 { // FIX for strange behaviour with PSCS and multiple of 64
// apdu.ne = apdu.rlen - 2; apdu.ne = apdu.rlen - 2;
//} }
#endif
} }
uint16_t apdu_next() { size_t apdu_next() {
if (apdu.sw != 0) { if (apdu.rlen <= apdu.ne)
if (apdu.rlen <= apdu.ne) { return apdu.rlen + 2;
return apdu.rlen + 2; else {
} rdata_gr = apdu.rdata+apdu.ne;
else { rdata_bk = *(uint16_t *)rdata_gr;
rdata_gr = apdu.rdata + apdu.ne; rdata_gr[0] = 0x61;
rdata_bk = (rdata_gr[0] << 8) | rdata_gr[1]; if (apdu.rlen - apdu.ne >= 256)
rdata_gr[0] = 0x61; rdata_gr[1] = 0;
if (apdu.rlen - apdu.ne >= 256) { else
rdata_gr[1] = 0; rdata_gr[1] = apdu.rlen - apdu.ne;
} apdu.rlen -= apdu.ne;
else {
rdata_gr[1] = (uint8_t)(apdu.rlen - apdu.ne);
}
apdu.rlen -= (uint16_t)apdu.ne;
}
return (uint16_t)(apdu.ne + 2);
} }
return 0; return apdu.ne + 2;
} }

View file

@ -1,53 +1,61 @@
/* /*
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk). * This file is part of the Pico HSM distribution (https://github.com/polhenarejos/pico-hsm).
* Copyright (c) 2022 Pol Henarejos. * Copyright (c) 2022 Pol Henarejos.
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3. * the Free Software Foundation, version 3.
* *
* This program is distributed in the hope that it will be useful, but * This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of * WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Affero General Public License for more details. * General Public License for more details.
* *
* You should have received a copy of the GNU Affero General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef _APDU_H_ #ifndef _APDU_H_
#define _APDU_H_ #define _APDU_H_
#include <stdlib.h> #include <stdlib.h>
#if defined(PICO_PLATFORM)
#include "pico/stdlib.h" #include "pico/stdlib.h"
#endif
#include "compat.h"
#include <stdio.h>
#include <inttypes.h>
#include <stdbool.h>
typedef struct app { typedef struct app {
const uint8_t *aid; const uint8_t *aid;
int (*process_apdu)(); int (*process_apdu)();
int (*select_aid)(struct app *, uint8_t); struct app* (*select_aid)();
int (*unload)(); int (*unload)();
} app_t; } app_t;
extern bool app_exists(const uint8_t *aid, size_t aid_len); extern int register_app(app_t * (*)());
extern int register_app(int (*)(app_t *, uint8_t), const uint8_t *);
extern int select_app(const uint8_t *aid, size_t aid_len);
typedef struct cmd { #if defined(DEBUG_APDU) && DEBUG_APDU == 1
uint8_t ins; #define DEBUG_PAYLOAD(_p,_s) { \
int (*cmd_handler)(); printf("Payload %s (%d bytes):\r\n", #_p,_s);\
} cmd_t; for (int _i = 0; _i < _s; _i += 16) {\
printf("%07Xh : ",(unsigned int)(_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"); \
}
#else
#define DEBUG_PAYLOAD(_p,_s)
#endif
extern uint8_t num_apps; extern uint8_t num_apps;
extern app_t apps[16]; extern app_t apps[4];
extern app_t *current_app; extern app_t *current_app;
PACK(struct apdu { struct apdu {
uint8_t *header; uint8_t *header;
uint32_t nc; uint32_t nc;
uint32_t ne; uint32_t ne;
@ -55,24 +63,22 @@ PACK(struct apdu {
uint16_t sw; uint16_t sw;
uint8_t *rdata; uint8_t *rdata;
uint16_t rlen; uint16_t rlen;
} __packed;
});
#define CLA(a) a.header[0] #define CLA(a) a.header[0]
#define INS(a) a.header[1] #define INS(a) a.header[1]
#define P1(a) a.header[2] #define P1(a) a.header[2]
#define P2(a) a.header[3] #define P2(a) a.header[3]
#define res_APDU (apdu.rdata) #define res_APDU apdu.rdata
#define res_APDU_size (apdu.rlen) #define res_APDU_size apdu.rlen
extern struct apdu apdu; extern struct apdu apdu;
extern uint16_t set_res_sw(uint8_t sw1, uint8_t sw2); extern uint16_t set_res_sw (uint8_t sw1, uint8_t sw2);
extern int process_apdu(); extern int process_apdu();
extern uint16_t apdu_process(uint8_t, const uint8_t *buffer, uint16_t buffer_size); extern size_t apdu_process(const uint8_t *buffer, size_t buffer_size);
extern void apdu_finish(); extern void apdu_finish();
extern uint16_t apdu_next(); extern size_t apdu_next();
extern void *apdu_thread(void *);
#endif #endif

View file

@ -1,99 +1,62 @@
/* /*
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk). * This file is part of the Pico HSM SDK distribution (https://github.com/polhenarejos/pico-hsm-sdk).
* Copyright (c) 2022 Pol Henarejos. * Copyright (c) 2022 Pol Henarejos.
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3. * the Free Software Foundation, version 3.
* *
* This program is distributed in the hope that it will be useful, but * This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of * WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Affero General Public License for more details. * General Public License for more details.
* *
* You should have received a copy of the GNU Affero General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "pico_keys.h"
#include "asn1.h" #include "asn1.h"
int asn1_ctx_init(uint8_t *data, uint16_t len, asn1_ctx_t *ctx) { size_t asn1_len_tag(uint16_t tag, size_t len) {
if (!ctx) { size_t ret = 1+format_tlv_len(len, NULL)+len;
return PICOKEY_ERR_NULL_PARAM; if (tag > 0x00ff)
} return ret+1;
ctx->data = data;
ctx->len = len;
return PICOKEY_OK;
}
int asn1_ctx_clear(asn1_ctx_t *ctx) {
ctx->data = NULL;
ctx->len = 0;
return PICOKEY_OK;
}
uint16_t asn1_len(asn1_ctx_t *ctx) {
if (ctx->data && ctx->len > 0) {
return ctx->len;
}
return 0;
}
uint32_t asn1_get_uint(asn1_ctx_t *ctx) {
uint32_t d = ctx->data[0];
for (uint16_t lt = 1; lt < MIN(ctx->len, sizeof(uint32_t)); lt++) {
d <<= 8;
d |= ctx->data[lt];
}
return d;
}
uint16_t asn1_len_tag(uint16_t tag, uint16_t len) {
uint16_t ret = 1 + format_tlv_len(len, NULL) + len;
if (tag > 0x00ff) {
return ret + 1;
}
return ret; return ret;
} }
uint8_t format_tlv_len(uint16_t len, uint8_t *out) { int format_tlv_len(size_t len, uint8_t *out) {
if (len < 128) { if (len < 128) {
if (out) { if (out)
*out = (uint8_t)len; *out = len;
}
return 1; return 1;
} }
else if (len < 256) { else if (len < 256) {
if (out) { if (out) {
*out++ = 0x81; *out++ = 0x81;
*out++ = (uint8_t)len; *out++ = len;
} }
return 2; return 2;
} }
if (out) { else {
*out++ = 0x82; if (out) {
put_uint16_t_be(len, out); *out++ = 0x82;
*out++ = (len >> 8) & 0xff;
*out++ = len & 0xff;
}
return 3;
} }
return 3; return 0;
} }
int walk_tlv(const asn1_ctx_t *ctxi, int walk_tlv(const uint8_t *cdata, size_t cdata_len, uint8_t **p, uint16_t *tag, size_t *tag_len, uint8_t **data) {
uint8_t **p, if (!p)
uint16_t *tag,
uint16_t *tag_len,
uint8_t **data) {
if (!p) {
return 0; return 0;
} if (!*p)
if (!*p) { *p = (uint8_t *)cdata;
*p = (uint8_t *) ctxi->data; if (*p-cdata >= cdata_len)
}
if (*p - ctxi->data >= ctxi->len) {
return 0; return 0;
}
uint16_t tg = 0x0; uint16_t tg = 0x0;
uint16_t tgl = 0; size_t tgl = 0;
tg = *(*p)++; tg = *(*p)++;
if ((tg & 0x1f) == 0x1f) { if ((tg & 0x1f) == 0x1f) {
tg <<= 8; tg <<= 8;
@ -107,34 +70,22 @@ int walk_tlv(const asn1_ctx_t *ctxi,
else if (tgl == 0x81) { else if (tgl == 0x81) {
tgl = *(*p)++; tgl = *(*p)++;
} }
if (tag) { if (tag)
*tag = tg; *tag = tg;
} if (tag_len)
if (tag_len) {
*tag_len = tgl; *tag_len = tgl;
} if (data)
if (data) {
*data = *p; *data = *p;
} *p = *p+tgl;
*p = *p + tgl;
return 1; return 1;
} }
bool asn1_find_tag(const asn1_ctx_t *ctxi, bool asn1_find_tag(const uint8_t *data, size_t data_len, uint16_t itag, size_t *tag_len, uint8_t **tag_data) {
uint16_t itag,
asn1_ctx_t *ctxo) {
uint16_t tag = 0x0; uint16_t tag = 0x0;
uint8_t *p = NULL; uint8_t *p = NULL;
uint8_t *tdata = NULL; while (walk_tlv(data, data_len, &p, &tag, tag_len, tag_data)) {
uint16_t tlen = 0; if (itag == tag)
while (walk_tlv(ctxi, &p, &tag, &tlen, &tdata)) {
if (itag == tag) {
if (ctxo != NULL) {
ctxo->data = tdata;
ctxo->len = tlen;
}
return true; return true;
}
} }
return false; return false;
} }

View file

@ -1,50 +1,29 @@
/* /*
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk). * This file is part of the Pico HSM SDK distribution (https://github.com/polhenarejos/pico-hsm-sdk).
* Copyright (c) 2022 Pol Henarejos. * Copyright (c) 2022 Pol Henarejos.
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3. * the Free Software Foundation, version 3.
* *
* This program is distributed in the hope that it will be useful, but * This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of * WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Affero General Public License for more details. * General Public License for more details.
* *
* You should have received a copy of the GNU Affero General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef _ASN1_H_ #ifndef _ASN1_H_
#define _ASN1_H_ #define _ASN1_H_
#include <stdlib.h> #include <stdlib.h>
#if defined(PICO_PLATFORM)
#include "pico/stdlib.h" #include "pico/stdlib.h"
#else
#include <stdint.h>
#include <stdbool.h>
#endif
typedef struct asn1_ctx { extern int walk_tlv(const uint8_t *cdata, size_t cdata_len, uint8_t **p, uint16_t *tag, size_t *tag_len, uint8_t **data);
uint8_t *data; extern int format_tlv_len(size_t len, uint8_t *out);
uint16_t len; extern bool asn1_find_tag(const uint8_t *data, size_t data_len, uint16_t itag, size_t *tag_len, uint8_t **tag_data);
} asn1_ctx_t; extern size_t asn1_len_tag(uint16_t tag, size_t len);
extern int asn1_ctx_init(uint8_t *, uint16_t, asn1_ctx_t *);
extern int asn1_ctx_clear(asn1_ctx_t *ctx);
extern uint16_t asn1_len(asn1_ctx_t *ctx);
extern uint32_t asn1_get_uint(asn1_ctx_t *ctx);
extern int walk_tlv(const asn1_ctx_t *ctxi,
uint8_t **p,
uint16_t *tag,
uint16_t *tag_len,
uint8_t **data);
extern uint8_t format_tlv_len(uint16_t len, uint8_t *out);
extern bool asn1_find_tag(const asn1_ctx_t *ctxi,
uint16_t itag,
asn1_ctx_t *ctxo);
extern uint16_t asn1_len_tag(uint16_t tag, uint16_t len);
#endif #endif

View file

@ -1,35 +0,0 @@
/*
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
* Copyright (c) 2022 Pol Henarejos.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero 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
* Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef _BOARD_H_
#define _BOARD_H_
#ifdef _MSC_VER
#include <windows.h>
struct timezone;
extern int gettimeofday(struct timeval *tp, struct timezone *tzp);
#else
#include <sys/time.h>
#endif
static inline uint32_t board_millis() {
struct timeval start;
gettimeofday(&start, NULL);
return start.tv_sec * 1000 + start.tv_usec / 1000;
}
#endif // _BOARD_H_

View file

@ -1,69 +0,0 @@
/*
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
* Copyright (c) 2022 Pol Henarejos.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero 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
* Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef _COMPAT_H_
#define _COMPAT_H_
#ifdef _MSC_VER
#define PACK( __Declaration__ ) __pragma( pack(push, 1) ) __Declaration__ __pragma( pack(pop) )
#else
#define PACK( __Declaration__ ) __Declaration__ __attribute__((__packed__))
#endif
#ifdef __cplusplus
#define INITIALIZER(f) \
static void f(void); \
struct f##_t_ { f##_t_(void) { f(); } }; static f##_t_ f##_; \
static void f(void)
#elif defined(_MSC_VER)
#pragma section(".CRT$XCU",read)
#define INITIALIZER2_(f,p) \
static void f(void); \
__declspec(allocate(".CRT$XCU")) void (*f##_)(void) = f; \
__pragma(comment(linker,"/include:" p #f "_")) \
static void f(void)
#ifdef _WIN64
#define INITIALIZER(f) INITIALIZER2_(f,"")
#else
#define INITIALIZER(f) INITIALIZER2_(f,"_")
#endif
#else
#define INITIALIZER(f) \
static void f(void) __attribute__((constructor)); \
static void f(void)
#endif
#include <string.h>
#ifdef _MSC_VER
#ifndef HAVE_STRLCPY
static inline size_t strlcpy(char *dst, const char *src, size_t size)
{
size_t srclen = strlen(src);
if (size != 0) {
size_t copylen = (srclen >= size) ? size - 1 : srclen;
memcpy(dst, src, copylen);
dst[copylen] = '\0';
}
return srclen;
}
#endif
#endif
#endif // _COMPAT_H

View file

@ -1,226 +1,110 @@
/* /*
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk). * This file is part of the Pico HSM SDK distribution (https://github.com/polhenarejos/pico-hsm-sdk).
* Copyright (c) 2022 Pol Henarejos. * Copyright (c) 2022 Pol Henarejos.
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3. * the Free Software Foundation, version 3.
* *
* This program is distributed in the hope that it will be useful, but * This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of * WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Affero General Public License for more details. * General Public License for more details.
* *
* You should have received a copy of the GNU Affero General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#if defined(ESP_PLATFORM)
#include "esp_compat.h"
#elif defined(PICO_PLATFORM)
#include <pico/unique_id.h> #include <pico/unique_id.h>
#endif
#include "mbedtls/md.h" #include "mbedtls/md.h"
#include "mbedtls/sha256.h" #include "mbedtls/sha256.h"
#include "mbedtls/aes.h" #include "mbedtls/aes.h"
#include "mbedtls/hkdf.h"
#include "mbedtls/gcm.h"
#include "crypto_utils.h" #include "crypto_utils.h"
#include "pico_keys.h" #include "hsm.h"
#include "otp.h"
#include "random.h"
#include <stdio.h>
int ct_memcmp(const void *a, const void *b, size_t n) { void double_hash_pin(const uint8_t *pin, size_t len, uint8_t output[32]) {
const volatile uint8_t *x = (const volatile uint8_t *)a;
const volatile uint8_t *y = (const volatile uint8_t *)b;
uint8_t r = 0;
for (size_t i = 0; i < n; ++i) {
r |= x[i] ^ y[i];
}
return r;
}
static const mbedtls_md_info_t *SHA256(void) {
return mbedtls_md_info_from_type(MBEDTLS_MD_SHA256);
}
void derive_kbase(uint8_t kbase[32]) {
const uint8_t nootp_salt[] = "NO-OTP";
if (otp_key_1) {
mbedtls_hkdf(SHA256(), pico_serial_hash, sizeof(pico_serial_hash), otp_key_1, 32, (const uint8_t *)"DEVICE/ROOT", 12, kbase, 32);
}
else {
mbedtls_hkdf(SHA256(), nootp_salt, sizeof(nootp_salt)-1, pico_serial_hash, sizeof(pico_serial_hash), (const uint8_t *)"DEVICE/ROOT", 12, kbase, 32);
}
}
void derive_kver(const uint8_t *pin, size_t pin_len, uint8_t kver[32]) {
uint8_t kbase[32];
derive_kbase(kbase);
mbedtls_md_hmac(SHA256(), kbase, 32, pin, pin_len, kver);
mbedtls_platform_zeroize(kbase, sizeof(kbase));
}
void pin_derive_verifier(const uint8_t *pin, size_t pin_len, uint8_t verifier[32]) {
uint8_t kver[32];
derive_kver(pin, pin_len, kver);
mbedtls_hkdf(SHA256(), pico_serial_hash, sizeof(pico_serial_hash), kver, 32, (const uint8_t *)"PIN/VERIFY", 10, verifier, 32);
mbedtls_platform_zeroize(kver, sizeof(kver));
}
void pin_derive_session(const uint8_t *pin, size_t pin_len, uint8_t pin_token[32]) {
uint8_t kver[32];
derive_kver(pin, pin_len, kver);
mbedtls_hkdf(SHA256(), pico_serial_hash, sizeof(pico_serial_hash), kver, 32, (const uint8_t *)"PIN/TOKEN", 9, pin_token, 32);
mbedtls_platform_zeroize(kver, sizeof(kver));
}
void pin_derive_kenc(const uint8_t pin_token[32], uint8_t kenc[32]) {
mbedtls_hkdf(SHA256(), pico_serial_hash, sizeof(pico_serial_hash), pin_token, 32, (const uint8_t *)"PIN/ENC", 7, kenc, 32);
}
// ------------------------------------------------------------------
// Encrypt 32-byte device key using AES-256-GCM
// Output: [nonce|ciphertext|tag] = 12 + in_len + 16 = 60 bytes
// ------------------------------------------------------------------
int encrypt_with_aad(const uint8_t key[32], const uint8_t *in_buf, size_t in_len, uint8_t *out_buf) {
uint8_t *nonce = out_buf;
uint8_t *ct = out_buf + 12;
uint8_t *tag = out_buf + 12 + in_len;
random_gen(NULL, nonce, 12);
mbedtls_gcm_context gcm;
mbedtls_gcm_init(&gcm);
uint8_t kenc[32];
pin_derive_kenc(key, kenc);
int rc = mbedtls_gcm_setkey(&gcm, MBEDTLS_CIPHER_ID_AES, kenc, 256);
mbedtls_platform_zeroize(kenc, sizeof(kenc));
if (rc != 0) {
return rc;
}
rc = mbedtls_gcm_crypt_and_tag(&gcm, MBEDTLS_GCM_ENCRYPT, in_len, nonce, 12, pico_serial_hash, sizeof(pico_serial_hash), in_buf, ct, 16, tag);
mbedtls_gcm_free(&gcm);
return rc;
}
// ------------------------------------------------------------------
// Decrypt & verify 32-byte device key using AES-256-GCM
// Input: [nonce|ciphertext|tag] = in_len bytes
// Output: decrypted = in_len - 12 - 16 bytes
// ------------------------------------------------------------------
int decrypt_with_aad(const uint8_t key[32], const uint8_t *in_buf, size_t in_len, uint8_t *out_buf) {
const uint8_t *nonce = in_buf;
const uint8_t *ct = in_buf + 12;
const uint8_t *tag = in_buf + in_len - 16;
mbedtls_gcm_context gcm;
mbedtls_gcm_init(&gcm);
uint8_t kenc[32];
pin_derive_kenc(key, kenc);
int rc = mbedtls_gcm_setkey(&gcm, MBEDTLS_CIPHER_ID_AES, kenc, 256);
mbedtls_platform_zeroize(kenc, sizeof(kenc));
if (rc != 0) {
return rc;
}
rc = mbedtls_gcm_auth_decrypt(&gcm, in_len - 16 - 12, nonce, 12, pico_serial_hash, sizeof(pico_serial_hash), tag, 16, ct, out_buf);
mbedtls_gcm_free(&gcm);
return rc;
}
// Old functions, kept for compatibility. NOT SECURE, use the new ones above.
void double_hash_pin(const uint8_t *pin, uint16_t len, uint8_t output[32]) {
uint8_t o1[32]; uint8_t o1[32];
hash_multi(pin, len, o1); hash_multi(pin, len, o1);
for (size_t i = 0; i < sizeof(o1); i++) { for (int i = 0; i < sizeof(o1); i++)
o1[i] ^= pin[i % len]; o1[i] ^= pin[i%len];
}
hash_multi(o1, sizeof(o1), output); hash_multi(o1, sizeof(o1), output);
} }
void hash_multi(const uint8_t *input, size_t len, uint8_t output[32]) {
void hash_multi(const uint8_t *input, uint16_t len, uint8_t output[32]) {
mbedtls_sha256_context ctx; mbedtls_sha256_context ctx;
mbedtls_sha256_init(&ctx); mbedtls_sha256_init(&ctx);
uint16_t iters = 256; int iters = 256;
mbedtls_sha256_starts(&ctx, 0); pico_unique_board_id_t unique_id;
#ifndef ENABLE_EMULATION
mbedtls_sha256_update(&ctx, pico_serial.id, sizeof(pico_serial.id));
#endif
while (iters > len) { pico_get_unique_board_id(&unique_id);
mbedtls_sha256_update(&ctx, input, len);
mbedtls_sha256_starts (&ctx, 0);
mbedtls_sha256_update (&ctx, unique_id.id, sizeof(unique_id.id));
while (iters > len)
{
mbedtls_sha256_update (&ctx, input, len);
iters -= len; iters -= len;
} }
if (iters > 0) { // remaining iterations if (iters > 0) // remaining iterations
mbedtls_sha256_update(&ctx, input, iters); mbedtls_sha256_update (&ctx, input, iters);
} mbedtls_sha256_finish (&ctx, output);
mbedtls_sha256_finish(&ctx, output); mbedtls_sha256_free (&ctx);
mbedtls_sha256_free(&ctx);
} }
void hash256(const uint8_t *input, size_t len, uint8_t output[32]) { void hash256(const uint8_t *input, size_t len, uint8_t output[32]) {
mbedtls_sha256_context ctx; mbedtls_sha256_context ctx;
mbedtls_sha256_init(&ctx); mbedtls_sha256_init(&ctx);
mbedtls_sha256_starts(&ctx, 0); mbedtls_sha256_starts (&ctx, 0);
mbedtls_sha256_update(&ctx, input, len); mbedtls_sha256_update (&ctx, input, len);
mbedtls_sha256_finish(&ctx, output); mbedtls_sha256_finish (&ctx, output);
mbedtls_sha256_free(&ctx); mbedtls_sha256_free (&ctx);
} }
void generic_hash(mbedtls_md_type_t md, const uint8_t *input, size_t len, uint8_t *output) { void generic_hash(mbedtls_md_type_t md, const uint8_t *input, size_t len, uint8_t *output) {
mbedtls_md(mbedtls_md_info_from_type(md), input, len, output); mbedtls_md(mbedtls_md_info_from_type(md), input, len, output);
} }
int aes_encrypt(const uint8_t *key, const uint8_t *iv, uint16_t key_size, int mode, uint8_t *data, uint16_t len) { int aes_encrypt(const uint8_t *key, const uint8_t *iv, int key_size, int mode, uint8_t *data, int len) {
mbedtls_aes_context aes; mbedtls_aes_context aes;
mbedtls_aes_init(&aes); mbedtls_aes_init(&aes);
uint8_t tmp_iv[IV_SIZE]; uint8_t tmp_iv[IV_SIZE];
size_t iv_offset = 0; size_t iv_offset = 0;
memset(tmp_iv, 0, IV_SIZE); memset(tmp_iv, 0, IV_SIZE);
if (iv) { if (iv)
memcpy(tmp_iv, iv, IV_SIZE); memcpy(tmp_iv, iv, IV_SIZE);
}
int r = mbedtls_aes_setkey_enc(&aes, key, key_size); int r = mbedtls_aes_setkey_enc(&aes, key, key_size);
if (r != 0) { if (r != 0)
return PICOKEY_EXEC_ERROR; return CCID_EXEC_ERROR;
} if (mode == HSM_AES_MODE_CBC)
if (mode == PICO_KEYS_AES_MODE_CBC) {
return mbedtls_aes_crypt_cbc(&aes, MBEDTLS_AES_ENCRYPT, len, tmp_iv, data, data); 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); return mbedtls_aes_crypt_cfb128(&aes, MBEDTLS_AES_ENCRYPT, len, &iv_offset, tmp_iv, data, data);
} }
int aes_decrypt(const uint8_t *key, const uint8_t *iv, uint16_t key_size, int mode, uint8_t *data, uint16_t len) { int aes_decrypt(const uint8_t *key, const uint8_t *iv, int key_size, int mode, uint8_t *data, int len) {
mbedtls_aes_context aes; mbedtls_aes_context aes;
mbedtls_aes_init(&aes); mbedtls_aes_init(&aes);
uint8_t tmp_iv[IV_SIZE]; uint8_t tmp_iv[IV_SIZE];
size_t iv_offset = 0; size_t iv_offset = 0;
memset(tmp_iv, 0, IV_SIZE); memset(tmp_iv, 0, IV_SIZE);
if (iv) { if (iv)
memcpy(tmp_iv, iv, IV_SIZE); memcpy(tmp_iv, iv, IV_SIZE);
}
int r = mbedtls_aes_setkey_dec(&aes, key, key_size); int r = mbedtls_aes_setkey_dec(&aes, key, key_size);
if (r != 0) { if (r != 0)
return PICOKEY_EXEC_ERROR; return CCID_EXEC_ERROR;
} if (mode == HSM_AES_MODE_CBC)
if (mode == PICO_KEYS_AES_MODE_CBC) {
return mbedtls_aes_crypt_cbc(&aes, MBEDTLS_AES_DECRYPT, len, tmp_iv, data, data); 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 r = mbedtls_aes_setkey_enc(&aes, key, key_size); //CFB requires set_enc instead set_dec
return mbedtls_aes_crypt_cfb128(&aes, MBEDTLS_AES_DECRYPT, len, &iv_offset, tmp_iv, data, data); return mbedtls_aes_crypt_cfb128(&aes, MBEDTLS_AES_DECRYPT, len, &iv_offset, tmp_iv, data, data);
} }
int aes_encrypt_cfb_256(const uint8_t *key, const uint8_t *iv, uint8_t *data, uint16_t len) { int aes_encrypt_cfb_256(const uint8_t *key, const uint8_t *iv, uint8_t *data, int len) {
return aes_encrypt(key, iv, 256, PICO_KEYS_AES_MODE_CFB, data, len); return aes_encrypt(key, iv, 256, HSM_AES_MODE_CFB, data, len);
} }
int aes_decrypt_cfb_256(const uint8_t *key, const uint8_t *iv, uint8_t *data, uint16_t len) { int aes_decrypt_cfb_256(const uint8_t *key, const uint8_t *iv, uint8_t *data, int len) {
return aes_decrypt(key, iv, 256, PICO_KEYS_AES_MODE_CFB, data, len); return aes_decrypt(key, iv, 256, HSM_AES_MODE_CFB, data, len);
} }
struct lv_data { struct lv_data {
@ -233,40 +117,15 @@ struct ec_curve_mbed_id {
mbedtls_ecp_group_id id; mbedtls_ecp_group_id id;
}; };
struct ec_curve_mbed_id ec_curves_mbed[] = { struct ec_curve_mbed_id ec_curves_mbed[] = {
{ { (unsigned char *) { { (unsigned char *) "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFE\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 24}, MBEDTLS_ECP_DP_SECP192R1 },
"\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFE\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF", { { (unsigned char *) "\xFF\xFF\xFF\xFF\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 32}, MBEDTLS_ECP_DP_SECP256R1 },
24 }, MBEDTLS_ECP_DP_SECP192R1 }, { { (unsigned char *) "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFE\xFF\xFF\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF\xFF", 48}, MBEDTLS_ECP_DP_SECP384R1 },
{ { (unsigned char *) { { (unsigned char *) "\x01\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 66}, MBEDTLS_ECP_DP_SECP521R1 },
"\xFF\xFF\xFF\xFF\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF", { { (unsigned char *) "\xA9\xFB\x57\xDB\xA1\xEE\xA9\xBC\x3E\x66\x0A\x90\x9D\x83\x8D\x72\x6E\x3B\xF6\x23\xD5\x26\x20\x28\x20\x13\x48\x1D\x1F\x6E\x53\x77", 32}, MBEDTLS_ECP_DP_BP256R1 },
32 }, MBEDTLS_ECP_DP_SECP256R1 }, { { (unsigned char *) "\x8C\xB9\x1E\x82\xA3\x38\x6D\x28\x0F\x5D\x6F\x7E\x50\xE6\x41\xDF\x15\x2F\x71\x09\xED\x54\x56\xB4\x12\xB1\xDA\x19\x7F\xB7\x11\x23\xAC\xD3\xA7\x29\x90\x1D\x1A\x71\x87\x47\x00\x13\x31\x07\xEC\x53", 48}, MBEDTLS_ECP_DP_BP384R1 },
{ { (unsigned char *) { { (unsigned char *) "\xAA\xDD\x9D\xB8\xDB\xE9\xC4\x8B\x3F\xD4\xE6\xAE\x33\xC9\xFC\x07\xCB\x30\x8D\xB3\xB3\xC9\xD2\x0E\xD6\x63\x9C\xCA\x70\x33\x08\x71\x7D\x4D\x9B\x00\x9B\xC6\x68\x42\xAE\xCD\xA1\x2A\xE6\xA3\x80\xE6\x28\x81\xFF\x2F\x2D\x82\xC6\x85\x28\xAA\x60\x56\x58\x3A\x48\xF3", 64}, MBEDTLS_ECP_DP_BP512R1 },
"\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFE\xFF\xFF\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF\xFF", { { (unsigned char *) "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFE\xFF\xFF\xEE\x37", 24}, MBEDTLS_ECP_DP_SECP192K1 },
48 }, MBEDTLS_ECP_DP_SECP384R1 }, { { (unsigned char *) "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFE\xFF\xFF\xFC\x2F", 32}, MBEDTLS_ECP_DP_SECP256K1 },
{ { (unsigned char *)
"\x01\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF",
66 }, MBEDTLS_ECP_DP_SECP521R1 },
{ { (unsigned char *)
"\xA9\xFB\x57\xDB\xA1\xEE\xA9\xBC\x3E\x66\x0A\x90\x9D\x83\x8D\x72\x6E\x3B\xF6\x23\xD5\x26\x20\x28\x20\x13\x48\x1D\x1F\x6E\x53\x77",
32 }, MBEDTLS_ECP_DP_BP256R1 },
{ { (unsigned char *)
"\x8C\xB9\x1E\x82\xA3\x38\x6D\x28\x0F\x5D\x6F\x7E\x50\xE6\x41\xDF\x15\x2F\x71\x09\xED\x54\x56\xB4\x12\xB1\xDA\x19\x7F\xB7\x11\x23\xAC\xD3\xA7\x29\x90\x1D\x1A\x71\x87\x47\x00\x13\x31\x07\xEC\x53",
48 }, MBEDTLS_ECP_DP_BP384R1 },
{ { (unsigned char *)
"\xAA\xDD\x9D\xB8\xDB\xE9\xC4\x8B\x3F\xD4\xE6\xAE\x33\xC9\xFC\x07\xCB\x30\x8D\xB3\xB3\xC9\xD2\x0E\xD6\x63\x9C\xCA\x70\x33\x08\x71\x7D\x4D\x9B\x00\x9B\xC6\x68\x42\xAE\xCD\xA1\x2A\xE6\xA3\x80\xE6\x28\x81\xFF\x2F\x2D\x82\xC6\x85\x28\xAA\x60\x56\x58\x3A\x48\xF3",
64 }, MBEDTLS_ECP_DP_BP512R1 },
{ { (unsigned char *)
"\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFE\xFF\xFF\xEE\x37",
24 }, MBEDTLS_ECP_DP_SECP192K1 },
{ { (unsigned char *)
"\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFE\xFF\xFF\xFC\x2F",
32 }, MBEDTLS_ECP_DP_SECP256K1 },
{ { (unsigned char *)
"\x7f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xed",
32 }, MBEDTLS_ECP_DP_CURVE25519 },
{ { (unsigned char *)
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff",
56 }, MBEDTLS_ECP_DP_CURVE448 },
{ { NULL, 0 }, MBEDTLS_ECP_DP_NONE } { { NULL, 0 }, MBEDTLS_ECP_DP_NONE }
}; };

View file

@ -1,60 +1,48 @@
/* /*
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk). * This file is part of the Pico HSM SDK distribution (https://github.com/polhenarejos/pico-hsm-sdk).
* Copyright (c) 2022 Pol Henarejos. * Copyright (c) 2022 Pol Henarejos.
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3. * the Free Software Foundation, version 3.
* *
* This program is distributed in the hope that it will be useful, but * This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of * WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Affero General Public License for more details. * General Public License for more details.
* *
* You should have received a copy of the GNU Affero General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef _CRYPTO_UTILS_H_ #ifndef _CRYPTO_UTILS_H_
#define _CRYPTO_UTILS_H_ #define _CRYPTO_UTILS_H_
#include "stdlib.h"
#include "pico/stdlib.h"
#include "mbedtls/ecp.h" #include "mbedtls/ecp.h"
#include "mbedtls/md.h" #include "mbedtls/md.h"
#define PICO_KEYS_KEY_RSA 0x000f // It is a mask #define HSM_KEY_RSA 0x1
#define PICO_KEYS_KEY_RSA_1K 0x0001 #define HSM_KEY_EC 0x10
#define PICO_KEYS_KEY_RSA_2K 0x0002 #define HSM_KEY_AES 0x100
#define PICO_KEYS_KEY_RSA_3K 0x0004 #define HSM_KEY_AES_128 0x300
#define PICO_KEYS_KEY_RSA_4k 0x0008 #define HSM_KEY_AES_192 0x500
#define PICO_KEYS_KEY_EC 0x0010 #define HSM_KEY_AES_256 0x900
#define PICO_KEYS_KEY_AES 0x0f00 // It is a mask
#define PICO_KEYS_KEY_AES_128 0x0100
#define PICO_KEYS_KEY_AES_192 0x0200
#define PICO_KEYS_KEY_AES_256 0x0400
#define PICO_KEYS_KEY_AES_512 0x0800 /* For AES XTS */
#define PICO_KEYS_AES_MODE_CBC 1 #define HSM_AES_MODE_CBC 1
#define PICO_KEYS_AES_MODE_CFB 2 #define HSM_AES_MODE_CFB 2
#define IV_SIZE 16 #define IV_SIZE 16
extern int ct_memcmp(const void *a, const void *b, size_t n); extern void double_hash_pin(const uint8_t *pin, size_t len, uint8_t output[32]);
// Newer and safe functions extern void hash_multi(const uint8_t *input, size_t len, uint8_t output[32]);
extern void derive_kbase(uint8_t kbase[32]);
extern void derive_kver(const uint8_t *pin, size_t pin_len, uint8_t kver[32]);
extern void pin_derive_kenc(const uint8_t pin_token[32], uint8_t kenc[32]);
extern void pin_derive_session(const uint8_t *pin, size_t pin_len, uint8_t pin_token[32]);
extern void pin_derive_verifier(const uint8_t *pin, size_t pin_len, uint8_t verifier[32]);
extern int encrypt_with_aad(const uint8_t key[32], const uint8_t *in_buf, size_t in_len, uint8_t *out_buf);
extern int decrypt_with_aad(const uint8_t key[32], const uint8_t *in_buf, size_t in_len, uint8_t *out_buf);
extern void double_hash_pin(const uint8_t *pin, uint16_t len, uint8_t output[32]);
extern void hash_multi(const uint8_t *input, uint16_t len, uint8_t output[32]);
extern void hash256(const uint8_t *input, size_t len, uint8_t output[32]); extern void hash256(const uint8_t *input, size_t len, uint8_t output[32]);
extern void generic_hash(mbedtls_md_type_t md, const uint8_t *input, size_t len, uint8_t *output); extern void generic_hash(mbedtls_md_type_t md, const uint8_t *input, size_t len, uint8_t *output);
extern int aes_encrypt(const uint8_t *key, const uint8_t *iv, uint16_t key_size, int mode, uint8_t *data, uint16_t len); extern int aes_encrypt(const uint8_t *key, const uint8_t *iv, int key_size, int mode, uint8_t *data, int len);
extern int aes_decrypt(const uint8_t *key, const uint8_t *iv, uint16_t key_size, int mode, uint8_t *data, uint16_t len); extern int aes_decrypt(const uint8_t *key, const uint8_t *iv, int key_size, int mode, uint8_t *data, int len);
extern int aes_encrypt_cfb_256(const uint8_t *key, const uint8_t *iv, uint8_t *data, uint16_t len); extern int aes_encrypt_cfb_256(const uint8_t *key, const uint8_t *iv, uint8_t *data, int len);
extern int aes_decrypt_cfb_256(const uint8_t *key, const uint8_t *iv, uint8_t *data, uint16_t len); extern int aes_decrypt_cfb_256(const uint8_t *key, const uint8_t *iv, uint8_t *data, int len);
extern mbedtls_ecp_group_id ec_get_curve_from_prime(const uint8_t *prime, size_t prime_len); extern mbedtls_ecp_group_id ec_get_curve_from_prime(const uint8_t *prime, size_t prime_len);
#endif #endif

View file

@ -1,54 +0,0 @@
/*
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
* Copyright (c) 2022 Pol Henarejos.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero 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
* Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef _DEBUG_H_
#define _DEBUG_H_
#if defined(DEBUG_APDU) && DEBUG_APDU == 1
#define DEBUG_PAYLOAD(_p, _s) { \
printf("Payload %s (%zu bytes) [%s:%d]:\n", #_p, (size_t)(_s), __FILE__, __LINE__); \
for (size_t _i = 0; _i < (size_t)(_s); _i += 16) { \
printf("%" PRIxPTR "h : ", (uintptr_t) (_i + _p)); \
for (size_t _j = 0; _j < 16; _j++) { \
if (_j < (size_t)(_s) - _i) printf("%02X ", (_p)[_i + _j]); \
else printf(" "); \
if (_j == 7) printf(" "); \
} printf(": "); \
for (size_t _j = 0; _j < 16; _j++) { \
if (_j < (size_t)(_s) - _i && (_p)[_i + _j] > 32 && (_p)[_i + _j] != 127 && (_p)[_i + _j] < 176) printf("%c", (_p)[_i + _j]); \
else printf(" "); \
if (_j == 7) printf(" "); \
} \
printf("\n"); \
} printf("\n"); \
}
#define DEBUG_DATA(_p, _s) { \
printf("Data %s (%zu bytes) [%s:%d]:\n", #_p, (size_t)(_s), __FILE__, __LINE__); \
char *_tmp = (char *) calloc(2 * (_s) + 1, sizeof(char)); \
for (size_t _i = 0; _i < (size_t)(_s); _i++) { \
sprintf(&_tmp[2 * _i], "%02X", (_p)[_i]); \
} \
printf("%s\n", _tmp); \
free(_tmp); \
}
#else
#define DEBUG_PAYLOAD(_p, _s)
#define DEBUG_DATA(_p, _s)
#endif
#endif // _DEBUG_H_

232
src/eac.c
View file

@ -1,18 +1,18 @@
/* /*
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk). * This file is part of the Pico HSM SDK distribution (https://github.com/polhenarejos/pico-hsm-sdk).
* Copyright (c) 2022 Pol Henarejos. * Copyright (c) 2022 Pol Henarejos.
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3. * the Free Software Foundation, version 3.
* *
* This program is distributed in the hope that it will be useful, but * This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of * WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Affero General Public License for more details. * General Public License for more details.
* *
* You should have received a copy of the GNU Affero General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "eac.h" #include "eac.h"
@ -22,44 +22,37 @@
#include "asn1.h" #include "asn1.h"
#include "apdu.h" #include "apdu.h"
static uint8_t sm_nonce[8]; static uint8_t nonce[8];
static uint8_t sm_kmac[16]; static uint8_t sm_kmac[16];
static uint8_t sm_kenc[16]; static uint8_t sm_kenc[16];
static MSE_protocol sm_protocol = MSE_NONE; static MSE_protocol sm_protocol = MSE_NONE;
static mbedtls_mpi sm_mSSC; static mbedtls_mpi sm_mSSC;
static uint8_t sm_blocksize = 0; static uint8_t sm_blocksize = 0;
static uint8_t sm_iv[16]; static uint8_t sm_iv[16];
uint16_t sm_session_pin_len = 0; size_t sm_session_pin_len = 0;
uint8_t sm_session_pin[16]; uint8_t sm_session_pin[16];
bool is_secured_apdu() { bool is_secured_apdu() {
return CLA(apdu) & 0xC; return (CLA(apdu) & 0xC);
} }
void sm_derive_key(const uint8_t *input, void sm_derive_key(const uint8_t *input, size_t input_len, uint8_t counter, const uint8_t *nonce, size_t nonce_len, uint8_t *out) {
size_t input_len, uint8_t *b = (uint8_t *)calloc(1, input_len+nonce_len+4);
uint8_t counter, if (input)
const uint8_t *nonce,
size_t nonce_len,
uint8_t *out) {
uint8_t *b = (uint8_t *) calloc(1, input_len + nonce_len + 4);
if (input) {
memcpy(b, input, input_len); memcpy(b, input, input_len);
} if (nonce)
if (nonce) { memcpy(b+input_len, nonce, nonce_len);
memcpy(b + input_len, nonce, nonce_len); b[input_len+nonce_len+3] = counter;
}
b[input_len + nonce_len + 3] = counter;
uint8_t digest[20]; uint8_t digest[20];
generic_hash(MBEDTLS_MD_SHA1, b, input_len + nonce_len + 4, digest); generic_hash(MBEDTLS_MD_SHA1, b, input_len+nonce_len+4, digest);
memcpy(out, digest, 16); memcpy(out, digest, 16);
free(b); free(b);
} }
void sm_derive_all_keys(const uint8_t *derived, size_t derived_len) { void sm_derive_all_keys(const uint8_t *derived, size_t derived_len) {
memcpy(sm_nonce, random_bytes_get(8), 8); memcpy(nonce, random_bytes_get(8), 8);
sm_derive_key(derived, derived_len, 1, sm_nonce, sizeof(sm_nonce), sm_kenc); sm_derive_key(derived, derived_len, 1, nonce, sizeof(nonce), sm_kenc);
sm_derive_key(derived, derived_len, 2, sm_nonce, sizeof(sm_nonce), sm_kmac); sm_derive_key(derived, derived_len, 2, nonce, sizeof(nonce), sm_kmac);
mbedtls_mpi_init(&sm_mSSC); mbedtls_mpi_init(&sm_mSSC);
mbedtls_mpi_grow(&sm_mSSC, sm_blocksize); mbedtls_mpi_grow(&sm_mSSC, sm_blocksize);
mbedtls_mpi_lset(&sm_mSSC, 0); mbedtls_mpi_lset(&sm_mSSC, 0);
@ -69,12 +62,10 @@ void sm_derive_all_keys(const uint8_t *derived, size_t derived_len) {
void sm_set_protocol(MSE_protocol proto) { void sm_set_protocol(MSE_protocol proto) {
sm_protocol = proto; sm_protocol = proto;
if (proto == MSE_AES) { if (proto == MSE_AES)
sm_blocksize = 16; sm_blocksize = 16;
} else if (proto == MSE_3DES)
else if (proto == MSE_3DES) {
sm_blocksize = 8; sm_blocksize = 8;
}
} }
MSE_protocol sm_get_protocol() { MSE_protocol sm_get_protocol() {
@ -82,39 +73,30 @@ MSE_protocol sm_get_protocol() {
} }
uint8_t *sm_get_nonce() { uint8_t *sm_get_nonce() {
return sm_nonce; return nonce;
} }
int sm_sign(uint8_t *in, size_t in_len, uint8_t *out) { int sm_sign(uint8_t *in, size_t in_len, uint8_t *out) {
return mbedtls_cipher_cmac(mbedtls_cipher_info_from_type(MBEDTLS_CIPHER_AES_128_ECB), return mbedtls_cipher_cmac(mbedtls_cipher_info_from_type(MBEDTLS_CIPHER_AES_128_ECB), sm_kmac, 128, in, in_len, out);
sm_kmac,
128,
in,
in_len,
out);
} }
int sm_unwrap() { int sm_unwrap() {
uint8_t sm_indicator = (CLA(apdu) >> 2) & 0x3; uint8_t sm_indicator = (CLA(apdu) >> 2) & 0x3;
if (sm_indicator == 0) { if (sm_indicator == 0)
return PICOKEY_OK; return CCID_OK;
}
int r = sm_verify(); int r = sm_verify();
if (r != PICOKEY_OK) { if (r != CCID_OK)
return r; return r;
} int le = sm_get_le();
apdu.ne = sm_get_le(); if (le >= 0)
apdu.ne = le;
uint8_t *body = NULL; uint8_t *body = NULL;
uint16_t body_size = 0; size_t body_size = 0;
bool is87 = false; bool is87 = false;
uint16_t tag = 0x0; uint16_t tag = 0x0;
uint8_t *tag_data = NULL, *p = NULL; uint8_t *tag_data = NULL, *p = NULL;
uint16_t tag_len = 0; size_t tag_len = 0;
asn1_ctx_t ctxi; while (walk_tlv(apdu.data, apdu.nc, &p, &tag, &tag_len, &tag_data)) {
asn1_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi);
while (walk_tlv(&ctxi, &p, &tag, &tag_len, &tag_data))
{
if (tag == 0x87 || tag == 0x85) { if (tag == 0x87 || tag == 0x85) {
body = tag_data; body = tag_data;
body_size = tag_len; body_size = tag_len;
@ -124,27 +106,24 @@ int sm_unwrap() {
} }
} }
} }
if (!body) { if (!body)
apdu.nc = 0; return CCID_WRONG_DATA;
return PICOKEY_OK;
}
if (is87 && *body++ != 0x1) { if (is87 && *body++ != 0x1) {
return PICOKEY_WRONG_PADDING; return CCID_WRONG_PADDING;
} }
sm_update_iv(); sm_update_iv();
aes_decrypt(sm_kenc, sm_iv, 128, PICO_KEYS_AES_MODE_CBC, body, body_size); aes_decrypt(sm_kenc, sm_iv, 128, HSM_AES_MODE_CBC, body, body_size);
memmove(apdu.data, body, body_size); memmove(apdu.data, body, body_size);
apdu.nc = sm_remove_padding(apdu.data, body_size); apdu.nc = sm_remove_padding(apdu.data, body_size);
DEBUG_PAYLOAD(apdu.data, (int) apdu.nc); DEBUG_PAYLOAD(apdu.data, (int)apdu.nc);
return PICOKEY_OK; return CCID_OK;
} }
int sm_wrap() { int sm_wrap() {
uint8_t sm_indicator = (CLA(apdu) >> 2) & 0x3; uint8_t sm_indicator = (CLA(apdu) >> 2) & 0x3;
if (sm_indicator == 0) { if (sm_indicator == 0)
return PICOKEY_OK; return CCID_OK;
} uint8_t input[1024];
uint8_t input[2048];
size_t input_len = 0; size_t input_len = 0;
memset(input, 0, sizeof(input)); memset(input, 0, sizeof(input));
mbedtls_mpi ssc; mbedtls_mpi ssc;
@ -152,98 +131,90 @@ int sm_wrap() {
mbedtls_mpi_add_int(&ssc, &sm_mSSC, 1); mbedtls_mpi_add_int(&ssc, &sm_mSSC, 1);
mbedtls_mpi_copy(&sm_mSSC, &ssc); mbedtls_mpi_copy(&sm_mSSC, &ssc);
int r = mbedtls_mpi_write_binary(&ssc, input, sm_blocksize); int r = mbedtls_mpi_write_binary(&ssc, input, sm_blocksize);
if (r != 0) { if (r != 0)
return PICOKEY_EXEC_ERROR; return CCID_EXEC_ERROR;
}
input_len += sm_blocksize; input_len += sm_blocksize;
mbedtls_mpi_free(&ssc); mbedtls_mpi_free(&ssc);
if (res_APDU_size > 0) { if (res_APDU_size > 0) {
res_APDU[res_APDU_size++] = 0x80; res_APDU[res_APDU_size++] = 0x80;
memset(res_APDU + res_APDU_size, 0, (sm_blocksize - (res_APDU_size % sm_blocksize))); memset(res_APDU+res_APDU_size, 0, (sm_blocksize - (res_APDU_size%sm_blocksize)));
res_APDU_size += (sm_blocksize - (res_APDU_size % sm_blocksize)); res_APDU_size += (sm_blocksize - (res_APDU_size%sm_blocksize));
DEBUG_PAYLOAD(res_APDU, res_APDU_size); DEBUG_PAYLOAD(res_APDU, res_APDU_size);
sm_update_iv(); sm_update_iv();
aes_encrypt(sm_kenc, sm_iv, 128, PICO_KEYS_AES_MODE_CBC, res_APDU, res_APDU_size); aes_encrypt(sm_kenc, sm_iv, 128, HSM_AES_MODE_CBC, res_APDU, res_APDU_size);
memmove(res_APDU + 1, res_APDU, res_APDU_size); memmove(res_APDU+1, res_APDU, res_APDU_size);
res_APDU[0] = 0x1; res_APDU[0] = 0x1;
res_APDU_size++; res_APDU_size++;
if (res_APDU_size < 128) { if (res_APDU_size < 128) {
memmove(res_APDU + 2, res_APDU, res_APDU_size); memmove(res_APDU+2, res_APDU, res_APDU_size);
res_APDU[1] = (uint8_t)res_APDU_size; res_APDU[1] = res_APDU_size;
res_APDU_size += 2; res_APDU_size += 2;
} }
else if (res_APDU_size < 256) { else if (res_APDU_size < 256) {
memmove(res_APDU + 3, res_APDU, res_APDU_size); memmove(res_APDU+3, res_APDU, res_APDU_size);
res_APDU[1] = 0x81; res_APDU[1] = 0x81;
res_APDU[2] = (uint8_t)res_APDU_size; res_APDU[2] = res_APDU_size;
res_APDU_size += 3; res_APDU_size += 3;
} }
else { else {
memmove(res_APDU + 4, res_APDU, res_APDU_size); memmove(res_APDU+4, res_APDU, res_APDU_size);
res_APDU[1] = 0x82; res_APDU[1] = 0x82;
put_uint16_t_be(res_APDU_size, res_APDU + 2); res_APDU[2] = res_APDU_size >> 8;
res_APDU[3] = res_APDU_size & 0xff;
res_APDU_size += 4; res_APDU_size += 4;
} }
res_APDU[0] = 0x87; res_APDU[0] = 0x87;
} }
res_APDU[res_APDU_size++] = 0x99; res_APDU[res_APDU_size++] = 0x99;
res_APDU[res_APDU_size++] = 2; res_APDU[res_APDU_size++] = 2;
put_uint16_t_be(apdu.sw, res_APDU + res_APDU_size); res_APDU[res_APDU_size++] = apdu.sw >> 8;
res_APDU_size += 2; res_APDU[res_APDU_size++] = apdu.sw & 0xff;
memcpy(input + input_len, res_APDU, res_APDU_size); memcpy(input+input_len, res_APDU, res_APDU_size);
input_len += res_APDU_size; input_len += res_APDU_size;
input[input_len++] = 0x80; input[input_len++] = 0x80;
input_len += (sm_blocksize - (input_len % sm_blocksize)); input_len += (sm_blocksize - (input_len%sm_blocksize));
r = sm_sign(input, input_len, res_APDU + res_APDU_size + 2); r = sm_sign(input, input_len, res_APDU+res_APDU_size+2);
res_APDU[res_APDU_size++] = 0x8E; res_APDU[res_APDU_size++] = 0x8E;
res_APDU[res_APDU_size++] = 8; res_APDU[res_APDU_size++] = 8;
res_APDU_size += 8; res_APDU_size += 8;
if (apdu.ne > 0) { if (apdu.ne > 0)
apdu.ne = res_APDU_size; apdu.ne = res_APDU_size;
} return CCID_OK;
set_res_sw(0x90, 0x00);
return PICOKEY_OK;
} }
uint16_t sm_get_le() { int sm_get_le() {
uint16_t tag = 0x0; uint16_t tag = 0x0;
uint8_t *tag_data = NULL, *p = NULL; uint8_t *tag_data = NULL, *p = NULL;
uint16_t tag_len = 0; size_t tag_len = 0;
asn1_ctx_t ctxi; while (walk_tlv(apdu.data, apdu.nc, &p, &tag, &tag_len, &tag_data)) {
asn1_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi);
while (walk_tlv(&ctxi, &p, &tag, &tag_len, &tag_data)) {
if (tag == 0x97) { if (tag == 0x97) {
uint16_t le = 0; uint32_t le = 0;
for (uint16_t t = 1; t <= tag_len; t++) { for (int t = 1; t <= tag_len; t++)
le |= (*tag_data++) << (tag_len - t) * 8; le |= (*tag_data++) << (tag_len-t);
}
return le; return le;
} }
} }
return 0; return -1;
} }
void sm_update_iv() { void sm_update_iv() {
uint8_t tmp_iv[16], sc_counter[16]; uint8_t tmp_iv[16], sc_counter[16];
memset(tmp_iv, 0, sizeof(tmp_iv)); //IV is always 0 for encryption of IV based on counter memset(tmp_iv, 0, sizeof(tmp_iv)); //IV is always 0 for encryption of IV based on counter
mbedtls_mpi_write_binary(&sm_mSSC, sc_counter, sizeof(sc_counter)); mbedtls_mpi_write_binary(&sm_mSSC, sc_counter, sizeof(sc_counter));
aes_encrypt(sm_kenc, tmp_iv, 128, PICO_KEYS_AES_MODE_CBC, sc_counter, sizeof(sc_counter)); aes_encrypt(sm_kenc, tmp_iv, 128, HSM_AES_MODE_CBC, sc_counter, sizeof(sc_counter));
memcpy(sm_iv, sc_counter, sizeof(sc_counter)); memcpy(sm_iv, sc_counter, sizeof(sc_counter));
} }
int sm_verify() { int sm_verify() {
uint8_t input[2048]; uint8_t input[1024];
memset(input, 0, sizeof(input)); memset(input, 0, sizeof(input));
uint16_t input_len = 0; int input_len = 0, r = 0;
int r = 0;
bool add_header = (CLA(apdu) & 0xC) == 0xC; bool add_header = (CLA(apdu) & 0xC) == 0xC;
size_t data_len = (size_t)(apdu.nc / sm_blocksize) * sm_blocksize; int data_len = (int)(apdu.nc/sm_blocksize)*sm_blocksize;
if (data_len % sm_blocksize) { if (data_len % sm_blocksize)
data_len += sm_blocksize; data_len += sm_blocksize;
} if (data_len+(add_header ? sm_blocksize : 0) > 1024)
if (data_len + (add_header ? sm_blocksize : 0) > sizeof(input)) { return CCID_WRONG_LENGTH;
return PICOKEY_WRONG_LENGTH;
}
mbedtls_mpi ssc; mbedtls_mpi ssc;
mbedtls_mpi_init(&ssc); mbedtls_mpi_init(&ssc);
mbedtls_mpi_add_int(&ssc, &sm_mSSC, 1); mbedtls_mpi_add_int(&ssc, &sm_mSSC, 1);
@ -251,31 +222,28 @@ int sm_verify() {
r = mbedtls_mpi_write_binary(&ssc, input, sm_blocksize); r = mbedtls_mpi_write_binary(&ssc, input, sm_blocksize);
input_len += sm_blocksize; input_len += sm_blocksize;
mbedtls_mpi_free(&ssc); mbedtls_mpi_free(&ssc);
if (r != 0) { if (r != 0)
return PICOKEY_EXEC_ERROR; return CCID_EXEC_ERROR;
}
if (add_header) { if (add_header) {
input[input_len++] = CLA(apdu); input[input_len++] = CLA(apdu);
input[input_len++] = INS(apdu); input[input_len++] = INS(apdu);
input[input_len++] = P1(apdu); input[input_len++] = P1(apdu);
input[input_len++] = P2(apdu); input[input_len++] = P2(apdu);
input[input_len++] = 0x80; input[input_len++] = 0x80;
input_len += sm_blocksize - 5; input_len += sm_blocksize-5;
} }
bool some_added = false; bool some_added = false;
const uint8_t *mac = NULL; const uint8_t *mac = NULL;
uint16_t mac_len = 0; size_t mac_len = 0;
uint16_t tag = 0x0; uint16_t tag = 0x0;
uint8_t *tag_data = NULL, *p = NULL; uint8_t *tag_data = NULL, *p = NULL;
uint16_t tag_len = 0; size_t tag_len = 0;
asn1_ctx_t ctxi; while (walk_tlv(apdu.data, apdu.nc, &p, &tag, &tag_len, &tag_data)) {
asn1_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi);
while (walk_tlv(&ctxi, &p, &tag, &tag_len, &tag_data)) {
if (tag & 0x1) { if (tag & 0x1) {
input[input_len++] = (uint8_t)tag; input[input_len++] = tag;
uint8_t tlen = format_tlv_len(tag_len, input + input_len); int tlen = format_tlv_len(tag_len, input+input_len);
input_len += tlen; input_len += tlen;
memcpy(input + input_len, tag_data, tag_len); memcpy(input+input_len, tag_data, tag_len);
input_len += tag_len; input_len += tag_len;
some_added = true; some_added = true;
} }
@ -284,31 +252,25 @@ int sm_verify() {
mac_len = tag_len; mac_len = tag_len;
} }
} }
if (!mac) { if (!mac)
return PICOKEY_WRONG_DATA; return CCID_WRONG_DATA;
}
if (some_added) { if (some_added) {
input[input_len++] = 0x80; input[input_len++] = 0x80;
input_len += (sm_blocksize - (input_len % sm_blocksize)); input_len += (sm_blocksize - (input_len%sm_blocksize));
} }
uint8_t signature[16]; uint8_t signature[16];
r = sm_sign(input, input_len, signature); r = sm_sign(input, input_len, signature);
if (r != 0) { if (r != 0)
return PICOKEY_EXEC_ERROR; return CCID_EXEC_ERROR;
} if (memcmp(signature, mac, mac_len) == 0)
if (memcmp(signature, mac, mac_len) == 0) { return CCID_OK;
return PICOKEY_OK; return CCID_VERIFICATION_FAILED;
}
return PICOKEY_VERIFICATION_FAILED;
} }
uint16_t sm_remove_padding(const uint8_t *data, uint16_t data_len) { int sm_remove_padding(const uint8_t *data, size_t data_len) {
int32_t i = data_len - 1; int i = data_len-1;
for (; i >= 0 && data[i] == 0; i--) { for (; i >= 0 && data[i] == 0; i--);
; if (i < 0 || data[i] != 0x80)
} return -1;
if (i < 0 || data[i] != 0x80) { return i;
return 0;
}
return (uint16_t)i;
} }

View file

@ -1,30 +1,32 @@
/* /*
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk). * This file is part of the Pico HSM SDK distribution (https://github.com/polhenarejos/pico-hsm-sdk).
* Copyright (c) 2022 Pol Henarejos. * Copyright (c) 2022 Pol Henarejos.
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3. * the Free Software Foundation, version 3.
* *
* This program is distributed in the hope that it will be useful, but * This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of * WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Affero General Public License for more details. * General Public License for more details.
* *
* You should have received a copy of the GNU Affero General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef _EAC_H_ #ifndef _EAC_H_
#define _EAC_H_ #define _EAC_H_
#include "pico_keys.h" #include <stdlib.h>
#include "pico/stdlib.h"
#include "hsm.h"
typedef enum MSE_protocol { typedef enum MSE_protocol {
MSE_AES = 0, MSE_AES = 0,
MSE_3DES, MSE_3DES,
MSE_NONE MSE_NONE
} MSE_protocol; }MSE_protocol;
extern void sm_derive_all_keys(const uint8_t *input, size_t input_len); extern void sm_derive_all_keys(const uint8_t *input, size_t input_len);
extern void sm_set_protocol(MSE_protocol proto); extern void sm_set_protocol(MSE_protocol proto);
@ -33,12 +35,12 @@ extern uint8_t *sm_get_nonce();
extern int sm_sign(uint8_t *in, size_t in_len, uint8_t *out); extern int sm_sign(uint8_t *in, size_t in_len, uint8_t *out);
int sm_verify(); int sm_verify();
void sm_update_iv(); void sm_update_iv();
uint16_t sm_get_le(); int sm_get_le();
extern int sm_unwrap(); extern int sm_unwrap();
uint16_t sm_remove_padding(const uint8_t *data, uint16_t data_len); int sm_remove_padding(const uint8_t *data, size_t data_len);
extern int sm_wrap(); extern int sm_wrap();
extern bool is_secured_apdu(); extern bool is_secured_apdu();
extern uint8_t sm_session_pin[16]; extern uint8_t sm_session_pin[16];
extern uint16_t sm_session_pin_len; extern size_t sm_session_pin_len;
#endif #endif

View file

@ -1,66 +0,0 @@
/*
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
* Copyright (c) 2022 Pol Henarejos.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero 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
* Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef __ESP_COMPAT_H_
#define __ESP_COMPAT_H_
#ifdef ESP_PLATFORM
#include "freertos/FreeRTOS.h"
#include "freertos/queue.h"
typedef QueueHandle_t queue_t;
#define queue_init(a,b,c) do { *(a) = xQueueCreate(c, b); } while(0)
#define queue_add_blocking(a,b) xQueueSend(*(a), b, portMAX_DELAY)
#define queue_remove_blocking(a,b) xQueueReceive(*(a), b, portMAX_DELAY)
#define queue_try_add(a,b) xQueueSend(*(a), b, 0)
#define queue_is_empty(a) (uxQueueMessagesWaiting(*(a)) == 0)
#define queue_try_remove(a,b) xQueueReceive(*(a), b, 0)
extern TaskHandle_t hcore0, hcore1;
#ifdef CONFIG_IDF_TARGET_ESP32S3
#define ESP32_CORE0 0
#define ESP32_CORE1 1
#else
#define ESP32_CORE0 tskNO_AFFINITY
#define ESP32_CORE1 tskNO_AFFINITY
#endif
static inline void task_wrapper(void *arg) {
void* (*func)(void*) = (void* (*)(void*))arg;
func(NULL);
vTaskDelete(NULL);
}
#define multicore_launch_func_core1(func) xTaskCreatePinnedToCore(task_wrapper, "core1", 4096*ITF_TOTAL*2, (void *)func, CONFIG_TINYUSB_TASK_PRIORITY - 2, &hcore1, ESP32_CORE1)
#define multicore_reset_core1() do { if (hcore1) { eTaskState e = eTaskGetState(hcore1); if (e <= eSuspended) { vTaskDelete(hcore1); }} }while(0)
#define sleep_ms(a) vTaskDelay(a / portTICK_PERIOD_MS)
static inline uint32_t board_millis(void) {
return ( ( ((uint64_t) xTaskGetTickCount()) * 1000) / configTICK_RATE_HZ );
}
typedef SemaphoreHandle_t mutex_t;
typedef SemaphoreHandle_t semaphore_t;
#define mutex_init(a) do { *(a) = xSemaphoreCreateMutex();} while(0)
#define mutex_try_enter(a,b) xSemaphoreTake(*(a), 0)
#define mutex_enter_blocking(a) xSemaphoreTake(*(a), portMAX_DELAY)
#define mutex_exit(a) xSemaphoreGive(*(a))
#define sem_init(a,b,c) do { *(a) = xSemaphoreCreateCounting(c, b); } while(0)
#define sem_release(a) xSemaphoreGive(*(a))
#define sem_acquire_blocking(a) xSemaphoreTake(*(a), portMAX_DELAY)
#define multicore_lockout_victim_init() (void)0
static inline bool multicore_lockout_start_timeout_us(int a) { if (hcore1) { vTaskSuspend(hcore1); } return true; }
static inline bool multicore_lockout_end_timeout_us(int a) { if (hcore1) { vTaskResume(hcore1); } return true; }
#endif
#endif

View file

@ -1,22 +1,22 @@
/* /*
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk). * This file is part of the Pico HSM SDK distribution (https://github.com/polhenarejos/pico-hsm-sdk).
* Copyright (c) 2022 Pol Henarejos. * Copyright (c) 2022 Pol Henarejos.
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3. * the Free Software Foundation, version 3.
* *
* This program is distributed in the hope that it will be useful, but * This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of * WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Affero General Public License for more details. * General Public License for more details.
* *
* You should have received a copy of the GNU Affero General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "file.h" #include "file.h"
#include "pico_keys.h" #include "hsm.h"
#include <string.h> #include <string.h>
#include <stdio.h> #include <stdio.h>
#include "asn1.h" #include "asn1.h"
@ -27,19 +27,17 @@ extern const uintptr_t start_data_pool;
extern const uintptr_t end_rom_pool; extern const uintptr_t end_rom_pool;
extern const uintptr_t start_rom_pool; extern const uintptr_t start_rom_pool;
extern int flash_write_data_to_file(file_t *file, const uint8_t *data, uint16_t len); extern int flash_write_data_to_file(file_t *file, const uint8_t *data, uint16_t len);
extern int flash_write_data_to_file_offset(file_t *file, const uint8_t *data, uint16_t len, uint16_t offset);
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 int flash_program_block(uintptr_t addr, const uint8_t *data, size_t len);
extern uintptr_t flash_read_uintptr(uintptr_t addr); extern uintptr_t flash_read_uintptr(uintptr_t addr);
extern uint16_t flash_read_uint16(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_uint8(uintptr_t addr);
extern uint8_t *flash_read(uintptr_t addr); extern uint8_t *flash_read(uintptr_t addr);
extern int flash_clear_file(file_t *ef);
extern void low_flash_available(); extern void low_flash_available();
#ifndef ENABLE_EMULATION
file_t sef_phy = {.fid = EF_PHY, .parent = 5, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH | FILE_PERSISTENT, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff}};
file_t *ef_phy = &sef_phy;
#endif
//puts FCI in the RAPDU //puts FCI in the RAPDU
void process_fci(const file_t *pe, int fmd) { void process_fci(const file_t *pe, int fmd) {
res_APDU_size = 0; res_APDU_size = 0;
@ -55,73 +53,67 @@ void process_fci(const file_t *pe, int fmd) {
res_APDU[res_APDU_size++] = 2; res_APDU[res_APDU_size++] = 2;
if (pe->data) { if (pe->data) {
if ((pe->type & FILE_DATA_FUNC) == FILE_DATA_FUNC) { if ((pe->type & FILE_DATA_FUNC) == FILE_DATA_FUNC) {
uint16_t len = (uint16_t)((int (*)(const file_t *, int))(pe->data))(pe, 0); uint16_t len = ((int (*)(const file_t *, int))(pe->data))(pe, 0);
res_APDU_size += put_uint16_t_be(len, res_APDU + res_APDU_size); res_APDU[res_APDU_size++] = (len >> 8) & 0xff;
res_APDU[res_APDU_size++] = len & 0xff;
} }
else { else {
uint16_t v = file_get_size(pe); res_APDU[res_APDU_size++] = pe->data[1];
res_APDU_size += put_uint16_t_be(v, res_APDU + res_APDU_size); res_APDU[res_APDU_size++] = pe->data[0];
} }
} }
else { else {
memset(res_APDU + res_APDU_size, 0, 2); memset(res_APDU+res_APDU_size, 0, 2);
res_APDU_size += 2; res_APDU_size += 2;
} }
res_APDU[res_APDU_size++] = 0x82; res_APDU[res_APDU_size++] = 0x82;
res_APDU[res_APDU_size++] = 1; res_APDU[res_APDU_size++] = 1;
res_APDU[res_APDU_size] = 0; res_APDU[res_APDU_size] = 0;
if (pe->type & FILE_TYPE_INTERNAL_EF) { if (pe->type == FILE_TYPE_INTERNAL_EF)
res_APDU[res_APDU_size++] |= 0x08; res_APDU[res_APDU_size++] |= 0x08;
} else if (pe->type == FILE_TYPE_WORKING_EF)
else if (pe->type & FILE_TYPE_WORKING_EF) {
res_APDU[res_APDU_size++] |= pe->ef_structure & 0x7; res_APDU[res_APDU_size++] |= pe->ef_structure & 0x7;
} else if (pe->type == FILE_TYPE_DF)
else if (pe->type & FILE_TYPE_DF) {
res_APDU[res_APDU_size++] |= 0x38; res_APDU[res_APDU_size++] |= 0x38;
}
else {
res_APDU_size++;
}
res_APDU[res_APDU_size++] = 0x83; res_APDU[res_APDU_size++] = 0x83;
res_APDU[res_APDU_size++] = 2; res_APDU[res_APDU_size++] = 2;
res_APDU_size += put_uint16_t_be(pe->fid, res_APDU + res_APDU_size); put_uint16_t(pe->fid, res_APDU+res_APDU_size);
res_APDU_size += 2;
if (pe->name) { if (pe->name) {
res_APDU[res_APDU_size++] = 0x84; res_APDU[res_APDU_size++] = 0x84;
res_APDU[res_APDU_size++] = MIN(pe->name[0], 16); res_APDU[res_APDU_size++] = MIN(pe->name[0],16);
memcpy(res_APDU + res_APDU_size, pe->name + 2, MIN(pe->name[0], 16)); memcpy(res_APDU+res_APDU_size, pe->name+2, MIN(pe->name[0],16));
res_APDU_size += MIN(pe->name[0], 16); res_APDU_size += MIN(pe->name[0],16);
} }
memcpy(res_APDU + res_APDU_size, "\x8A\x01\x05", 3); //life-cycle (5 -> activated) memcpy(res_APDU+res_APDU_size, "\x8A\x01\x05", 3); //life-cycle (5 -> activated)
res_APDU_size += 3; res_APDU_size += 3;
uint8_t *meta_data = NULL; uint8_t *meta_data = NULL;
uint16_t meta_size = meta_find(pe->fid, &meta_data); uint8_t meta_size = meta_find(pe->fid, &meta_data);
if (meta_size > 0 && meta_data != NULL) { if (meta_size > 0 && meta_data != NULL) {
res_APDU[res_APDU_size++] = 0xA5; res_APDU[res_APDU_size++] = 0xA5;
res_APDU[res_APDU_size++] = 0x81; res_APDU[res_APDU_size++] = 0x81;
res_APDU[res_APDU_size++] = (uint8_t )meta_size; res_APDU[res_APDU_size++] = meta_size;
memcpy(res_APDU + res_APDU_size, meta_data, meta_size); memcpy(res_APDU+res_APDU_size,meta_data,meta_size);
res_APDU_size += meta_size; res_APDU_size += meta_size;
} }
res_APDU[1] = (uint8_t)res_APDU_size - 2; res_APDU[1] = res_APDU_size-2;
if (fmd) { if (fmd)
res_APDU[3] = (uint8_t )res_APDU_size - 4; res_APDU[3] = res_APDU_size-4;
}
} }
#define MAX_DYNAMIC_FILES 128
uint16_t dynamic_files = 0; uint16_t dynamic_files = 0;
file_t dynamic_file[MAX_DYNAMIC_FILES]; file_t dynamic_file[MAX_DYNAMIC_FILES];
bool card_terminated = false; bool card_terminated = false;
bool is_parent(const file_t *child, const file_t *parent) { bool is_parent(const file_t *child, const file_t *parent) {
if (child == parent) { if (child == parent)
return true; return true;
} if (child == MF)
if (child == MF) {
return false; return false;
}
return is_parent(&file_entries[child->parent], parent); return is_parent(&file_entries[child->parent], parent);
} }
@ -131,7 +123,7 @@ file_t *get_parent(file_t *f) {
file_t *search_by_name(uint8_t *name, uint16_t namelen) { file_t *search_by_name(uint8_t *name, uint16_t namelen) {
for (file_t *p = file_entries; p != file_last; p++) { for (file_t *p = file_entries; p != file_last; p++) {
if (p->name && *p->name == apdu.nc && memcmp(p->name + 1, name, namelen) == 0) { if (p->name && *p->name == apdu.nc && memcmp(p->name+1, name, namelen) == 0) {
return p; return p;
} }
} }
@ -139,65 +131,47 @@ file_t *search_by_name(uint8_t *name, uint16_t namelen) {
} }
file_t *search_by_fid(const uint16_t fid, const file_t *parent, const uint8_t sp) { file_t *search_by_fid(const uint16_t fid, const file_t *parent, const uint8_t sp) {
#ifndef ENABLE_EMULATION
if (fid == EF_PHY) {
return ef_phy;
}
#endif
for (file_t *p = file_entries; p != file_last; p++) { for (file_t *p = file_entries; p != file_last; p++) {
if (p->fid != 0x0000 && p->fid == fid) { if (p->fid != 0x0000 && p->fid == fid) {
if (!parent || (parent && is_parent(p, parent))) { if (!parent || (parent && is_parent(p, parent))) {
if (!sp || sp == SPECIFY_ANY || if (!sp || sp == SPECIFY_ANY || (((sp & SPECIFY_EF) && (p->type & FILE_TYPE_INTERNAL_EF)) || ((sp & SPECIFY_DF) && p->type == FILE_TYPE_DF)))
(((sp & SPECIFY_EF) && (p->type & (FILE_TYPE_INTERNAL_EF|FILE_TYPE_WORKING_EF))) ||
((sp & SPECIFY_DF) && p->type == FILE_TYPE_DF))) {
return p; return p;
}
} }
} }
} }
return NULL; return NULL;
} }
file_t *search_file(const uint16_t fid) {
file_t *ef = search_by_fid(fid, NULL, SPECIFY_EF);
if (ef) {
return ef;
}
return search_dynamic_file(fid);
}
uint8_t make_path_buf(const file_t *pe, uint8_t *buf, uint8_t buflen, const file_t *top) { uint8_t make_path_buf(const file_t *pe, uint8_t *buf, uint8_t buflen, const file_t *top) {
if (!buflen) { if (!buflen)
return 0; return 0;
} if (pe == top) //MF or relative DF
if (pe == top) { //MF or relative DF
return 0; return 0;
} put_uint16_t(pe->fid, buf);
put_uint16_t_be(pe->fid, buf); return make_path_buf(&file_entries[pe->parent], buf+2, buflen-2, top)+2;
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 make_path(const file_t *pe, const file_t *top, uint8_t *path) {
uint8_t buf[MAX_DEPTH * 2], *p = path; uint8_t buf[MAX_DEPTH*2], *p = path;
put_uint16_t_be(pe->fid, buf); put_uint16_t(pe->fid, buf);
uint8_t depth = make_path_buf(&file_entries[pe->parent], buf + 2, sizeof(buf) - 2, top) + 2; 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) { for (int d = depth-2; d >= 0; d -= 2) {
memcpy(p, buf + d, 2); memcpy(p, buf+d, 2);
p += 2; p += 2;
} }
return depth; return depth;
} }
file_t *search_by_path(const uint8_t *pe_path, uint8_t pathlen, const file_t *parent) { file_t *search_by_path(const uint8_t *pe_path, uint8_t pathlen, const file_t *parent) {
uint8_t path[MAX_DEPTH * 2]; uint8_t path[MAX_DEPTH*2];
if (pathlen > sizeof(path)) { if (pathlen > sizeof(path)) {
return NULL; return NULL;
} }
for (file_t *p = file_entries; p != file_last; p++) { for (file_t *p = file_entries; p != file_last; p++) {
uint8_t depth = make_path(p, parent, path); uint8_t depth = make_path(p, parent, path);
if (pathlen == depth && memcmp(path, pe_path, depth) == 0) { if (pathlen == depth && memcmp(path, pe_path, depth) == 0)
return p; return p;
}
} }
return NULL; return NULL;
} }
@ -209,14 +183,12 @@ bool isUserAuthenticated = false;
bool authenticate_action(const file_t *ef, uint8_t op) { bool authenticate_action(const file_t *ef, uint8_t op) {
uint8_t acl = ef->acl[op]; uint8_t acl = ef->acl[op];
if (acl == 0x0) { if (acl == 0x0)
return true; return true;
} else if (acl == 0xff)
else if (acl == 0xff) {
return false; return false;
}
else if (acl == 0x90 || (acl & 0x9F) == 0x10) { else if (acl == 0x90 || (acl & 0x9F) == 0x10) {
// PIN required. // PIN required.
if (isUserAuthenticated) { if (isUserAuthenticated) {
return true; return true;
} }
@ -234,133 +206,101 @@ void initialize_flash(bool hard) {
low_flash_available(); low_flash_available();
} }
for (file_t *f = file_entries; f != file_last; f++) { for (file_t *f = file_entries; f != file_last; f++) {
if ((f->type & FILE_DATA_FLASH) == FILE_DATA_FLASH) { if ((f->type & FILE_DATA_FLASH) == FILE_DATA_FLASH)
f->data = NULL; f->data = NULL;
}
} }
dynamic_files = 0; dynamic_files = 0;
} }
extern uintptr_t last_base; void scan_region(bool persistent) {
extern uint32_t num_files;
void scan_region(bool persistent)
{
uintptr_t endp = end_data_pool, startp = start_data_pool; uintptr_t endp = end_data_pool, startp = start_data_pool;
if (persistent) { if (persistent) {
endp = end_rom_pool; endp = end_rom_pool;
startp = start_rom_pool; startp = start_rom_pool;
} }
else {
last_base = endp;
num_files = 0;
}
for (uintptr_t base = flash_read_uintptr(endp); base >= startp; base = flash_read_uintptr(base)) { for (uintptr_t base = flash_read_uintptr(endp); base >= startp; base = flash_read_uintptr(base)) {
if (base == 0x0) { //all is empty if (base == 0x0) //all is empty
break; break;
}
uint16_t fid = flash_read_uint16(base + sizeof(uintptr_t) + sizeof(uintptr_t)); uint16_t fid = flash_read_uint16(base+sizeof(uintptr_t)+sizeof(uintptr_t));
printf("[%x] scan fid %x, len %d\n", (unsigned int) base, fid, flash_read_uint16(base + sizeof(uintptr_t) + sizeof(uintptr_t) + sizeof(uint16_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); file_t *file = (file_t *)search_by_fid(fid, NULL, SPECIFY_EF);
if (!file) { if (!file) {
file = file_new(fid); file = file_new(fid);
} }
if (file) { if (file)
file->data = (uint8_t *) (base + sizeof(uintptr_t) + sizeof(uintptr_t) + sizeof(uint16_t)); file->data = (uint8_t *)(base+sizeof(uintptr_t)+sizeof(uintptr_t)+sizeof(uint16_t));
}
if (!persistent) {
num_files++;
}
if (flash_read_uintptr(base) == 0x0) { if (flash_read_uintptr(base) == 0x0) {
if (base < last_base) {
last_base = base;
}
break; break;
} }
} }
} }
void wait_flash_finish();
void scan_flash() { void scan_flash() {
initialize_flash(false); //soft initialization initialize_flash(false); //soft initialization
uint32_t r1 = (uint32_t)(*(uintptr_t *) flash_read(end_rom_pool)), r2 = (uint32_t)(*(uintptr_t *) flash_read(end_rom_pool + sizeof(uintptr_t))); if (*(uintptr_t *)end_data_pool == 0xffffffff && *(uintptr_t *)(end_data_pool+sizeof(uintptr_t)) == 0xffffffff)
if ((r1 == 0xffffffff || r1 == 0xefefefef) && (r2 == 0xffffffff || r2 == 0xefefefef)) { {
printf("First initialization (or corrupted!)\n"); printf("First initialization (or corrupted!)\r\n");
uint8_t empty[sizeof(uintptr_t) * 2 + sizeof(uint32_t)]; uint8_t empty[sizeof(uintptr_t)*2+sizeof(uint32_t)];
memset(empty, 0, sizeof(empty)); memset(empty, 0, sizeof(empty));
flash_program_block(end_data_pool, empty, sizeof(empty)); flash_program_block(end_data_pool, empty, sizeof(empty));
flash_program_block(end_rom_pool, empty, sizeof(empty)); flash_program_block(end_rom_pool, empty, sizeof(empty));
//low_flash_available(); //low_flash_available();
//wait_flash_finish(); //wait_flash_finish();
} }
printf("SCAN\n"); printf("SCAN\r\n");
scan_region(true); scan_region(true);
scan_region(false); scan_region(false);
} }
uint8_t *file_read(const uint8_t *addr) { uint8_t *file_read(const uint8_t *addr) {
return flash_read((uintptr_t) addr); return flash_read((uintptr_t)addr);
} }
uint16_t file_read_uint16(const uint8_t *addr) { uint16_t file_read_uint16(const uint8_t *addr) {
return flash_read_uint16((uintptr_t) addr); return flash_read_uint16((uintptr_t)addr);
} }
uint8_t file_read_uint8_offset(const file_t *ef, const uint16_t offset) { uint8_t file_read_uint8(const uint8_t *addr) {
return flash_read_uint8((uintptr_t) (file_get_data(ef) + offset)); return flash_read_uint8((uintptr_t)addr);
}
uint8_t file_read_uint8(const file_t *ef) {
return file_read_uint8_offset(ef, 0);
} }
uint8_t *file_get_data(const file_t *tf) { uint8_t *file_get_data(const file_t *tf) {
if (!tf || !tf->data) { if (!tf || !tf->data)
return NULL; return NULL;
} return file_read(tf->data+sizeof(uint16_t));
return file_read(tf->data + sizeof(uint16_t));
} }
uint16_t file_get_size(const file_t *tf) { uint16_t file_get_size(const file_t *tf) {
if (!tf || !tf->data) { if (!tf || !tf->data)
return 0; return 0;
}
return file_read_uint16(tf->data); return file_read_uint16(tf->data);
} }
int file_put_data(file_t *file, const uint8_t *data, uint16_t len) {
return flash_write_data_to_file(file, data, len);
}
file_t *search_dynamic_file(uint16_t fid) { file_t *search_dynamic_file(uint16_t fid) {
for (int i = 0; i < dynamic_files; i++) { for (int i = 0; i < dynamic_files; i++) {
if (dynamic_file[i].fid == fid) { if (dynamic_file[i].fid == fid)
return &dynamic_file[i]; return &dynamic_file[i];
}
} }
return NULL; return NULL;
} }
int delete_dynamic_file(file_t *f) { int delete_dynamic_file(file_t *f) {
if (f == NULL) {
return PICOKEY_ERR_FILE_NOT_FOUND;
}
for (int i = 0; i < dynamic_files; i++) { for (int i = 0; i < dynamic_files; i++) {
if (dynamic_file[i].fid == f->fid) { if (dynamic_file[i].fid == f->fid) {
for (int j = i + 1; j < dynamic_files; j++) { for (int j = i+1; j < dynamic_files; j++)
memcpy(&dynamic_file[j - 1], &dynamic_file[j], sizeof(file_t)); memcpy(&dynamic_file[j-1], &dynamic_file[j], sizeof(file_t));
}
dynamic_files--; dynamic_files--;
return PICOKEY_OK; return CCID_OK;
} }
} }
return PICOKEY_ERR_FILE_NOT_FOUND; return CCID_ERR_FILE_NOT_FOUND;
} }
file_t *file_new(uint16_t fid) { file_t *file_new(uint16_t fid) {
file_t *f; file_t *f;
if ((f = search_file(fid))) { if ((f = search_dynamic_file(fid)) || (f = search_by_fid(fid, NULL, SPECIFY_EF)))
return f; return f;
} if (dynamic_files == MAX_DYNAMIC_FILES)
if (dynamic_files == MAX_DYNAMIC_FILES) {
return NULL; return NULL;
}
f = &dynamic_file[dynamic_files]; f = &dynamic_file[dynamic_files];
dynamic_files++; dynamic_files++;
file_t file = { file_t file = {
@ -370,166 +310,120 @@ file_t *file_new(uint16_t fid) {
.type = FILE_TYPE_WORKING_EF, .type = FILE_TYPE_WORKING_EF,
.ef_structure = FILE_EF_TRANSPARENT, .ef_structure = FILE_EF_TRANSPARENT,
.data = NULL, .data = NULL,
.acl = { 0 } .acl = {0}
}; };
memcpy(f, &file, sizeof(file_t)); memcpy(f, &file, sizeof(file_t));
//memset((uint8_t *)f->acl, 0x90, sizeof(f->acl)); //memset((uint8_t *)f->acl, 0x90, sizeof(f->acl));
return f; return f;
} }
uint16_t meta_find(uint16_t fid, uint8_t **out) { int meta_find(uint16_t fid, uint8_t **out) {
file_t *ef = search_file(EF_META); file_t *ef = search_by_fid(EF_META, NULL, SPECIFY_EF);
if (!ef) { if (!ef)
return 0; return CCID_ERR_FILE_NOT_FOUND;
}
uint16_t tag = 0x0; uint16_t tag = 0x0;
uint8_t *tag_data = NULL, *p = NULL; uint8_t *tag_data = NULL, *p = NULL, *data = file_get_data(ef);
uint16_t tag_len = 0; size_t tag_len = 0, data_len = file_get_size(ef);
asn1_ctx_t ctxi; while (walk_tlv(data, data_len, &p, &tag, &tag_len, &tag_data)) {
asn1_ctx_init(file_get_data(ef), file_get_size(ef), &ctxi); if (tag_len < 2)
while (walk_tlv(&ctxi, &p, &tag, &tag_len, &tag_data)) {
if (tag_len < 2) {
continue; continue;
} uint16_t cfid = (tag_data[0] << 8 | tag_data[1]);
uint16_t cfid = get_uint16_t_be(tag_data);
if (cfid == fid) { if (cfid == fid) {
if (out) { if (out)
*out = tag_data + 2; *out = tag_data+2;
} return tag_len-2;
return tag_len - 2;
} }
} }
return 0; return 0;
} }
int meta_delete(uint16_t fid) { int meta_delete(uint16_t fid) {
file_t *ef = search_file(EF_META); file_t *ef = search_by_fid(EF_META, NULL, SPECIFY_EF);
if (!ef) { if (!ef)
return PICOKEY_ERR_FILE_NOT_FOUND; return CCID_ERR_FILE_NOT_FOUND;
}
uint16_t tag = 0x0; uint16_t tag = 0x0;
uint8_t *tag_data = NULL, *p = NULL; uint8_t *tag_data = NULL, *p = NULL, *data = file_get_data(ef);
uint16_t tag_len = 0; size_t tag_len = 0, data_len = file_get_size(ef);
uint8_t *fdata = NULL; uint8_t *fdata = NULL;
asn1_ctx_t ctxi; while (walk_tlv(data, data_len, &p, &tag, &tag_len, &tag_data)) {
asn1_ctx_init(file_get_data(ef), file_get_size(ef), &ctxi); uint8_t *tpos = p-tag_len-format_tlv_len(tag_len, NULL)-1;
while (walk_tlv(&ctxi, &p, &tag, &tag_len, &tag_data)) { if (tag_len < 2)
uint8_t *tpos = p - tag_len - format_tlv_len(tag_len, NULL) - 1;
if (tag_len < 2) {
continue; continue;
} uint16_t cfid = (tag_data[0] << 8 | tag_data[1]);
uint16_t cfid = get_uint16_t_be(tag_data);
if (cfid == fid) { if (cfid == fid) {
uint16_t new_len = ctxi.len - 1 - tag_len - format_tlv_len(tag_len, NULL); size_t new_len = data_len-1-tag_len-format_tlv_len(tag_len, NULL);
if (new_len == 0) { fdata = (uint8_t *)calloc(1, new_len);
flash_clear_file(ef); if (tpos > data) {
memcpy(fdata, data, tpos-data);
} }
else { if (data+data_len > p) {
fdata = (uint8_t *) calloc(1, new_len); memcpy(fdata+(tpos-data), p, data+data_len-p);
if (tpos > ctxi.data) {
memcpy(fdata, ctxi.data, tpos - ctxi.data);
}
if (ctxi.data + ctxi.len > p) {
memcpy(fdata + (tpos - ctxi.data), p, ctxi.data + ctxi.len - p);
}
int r = file_put_data(ef, fdata, new_len);
free(fdata);
if (r != PICOKEY_OK) {
return PICOKEY_EXEC_ERROR;
}
} }
int r = flash_write_data_to_file(ef, fdata, new_len);
free(fdata);
if (r != CCID_OK)
return CCID_EXEC_ERROR;
low_flash_available(); low_flash_available();
break; break;
} }
} }
return PICOKEY_OK; return CCID_OK;
} }
int meta_add(uint16_t fid, const uint8_t *data, uint16_t len) { int meta_add(uint16_t fid, const uint8_t *data, uint16_t len) {
int r; int r;
file_t *ef = search_file(EF_META); file_t *ef = search_by_fid(EF_META, NULL, SPECIFY_EF);
if (!ef) { if (!ef)
return PICOKEY_ERR_FILE_NOT_FOUND; return CCID_ERR_FILE_NOT_FOUND;
}
uint16_t ef_size = file_get_size(ef); uint16_t ef_size = file_get_size(ef);
uint8_t *fdata = (uint8_t *) calloc(1, ef_size); uint8_t *fdata = (uint8_t *)calloc(1, ef_size);
memcpy(fdata, file_get_data(ef), ef_size); memcpy(fdata, file_get_data(ef), ef_size);
uint16_t tag = 0x0; uint16_t tag = 0x0;
uint8_t *tag_data = NULL, *p = NULL; uint8_t *tag_data = NULL, *p = NULL;
uint16_t tag_len = 0; size_t tag_len = 0;
asn1_ctx_t ctxi; while (walk_tlv(fdata, ef_size, &p, &tag, &tag_len, &tag_data)) {
asn1_ctx_init(fdata, ef_size, &ctxi); if (tag_len < 2)
while (walk_tlv(&ctxi, &p, &tag, &tag_len, &tag_data)) {
if (tag_len < 2) {
continue; continue;
} uint16_t cfid = (tag_data[0] << 8 | tag_data[1]);
uint16_t cfid = get_uint16_t_be(tag_data);
if (cfid == fid) { if (cfid == fid) {
if (tag_len - 2 == len) { //an update if (tag_len-2 == len) { //an update
memcpy(p - tag_len + 2, data, len); memcpy(p-tag_len+2, data, len);
r = file_put_data(ef, fdata, ef_size); r = flash_write_data_to_file(ef, fdata, ef_size);
free(fdata); free(fdata);
if (r != PICOKEY_OK) { if (r != CCID_OK)
return PICOKEY_EXEC_ERROR; return CCID_EXEC_ERROR;
} return CCID_OK;
return PICOKEY_OK;
} }
else { //needs reallocation else { //needs reallocation
uint8_t *tpos = p - asn1_len_tag(tag, tag_len); uint8_t *tpos = p-asn1_len_tag(tag, tag_len);
memmove(tpos, p, fdata + ef_size - p); memmove(tpos, p, fdata+ef_size-p);
tpos += fdata + ef_size - p; tpos += fdata+ef_size-p;
volatile uintptr_t meta_offset = tpos - fdata; uintptr_t meta_offset = tpos-fdata;
ef_size += len - (tag_len - 2); ef_size += len - (tag_len-2);
if (len > tag_len - 2) { if (len > tag_len-2)
uint8_t *fdata_new = (uint8_t *) realloc(fdata, ef_size); fdata = (uint8_t *)realloc(fdata, ef_size);
if (fdata_new != NULL) { uint8_t *f = fdata+meta_offset;
fdata = fdata_new; *f++ = fid & 0xff;
} f += format_tlv_len(len+2, f);
else { *f++ = fid >> 8;
free(fdata);
return PICOKEY_ERR_MEMORY_FATAL;
}
}
uint8_t *f = fdata + meta_offset;
*f++ = fid & 0xff; *f++ = fid & 0xff;
f += format_tlv_len(len + 2, f);
f += put_uint16_t_be(fid, f);
memcpy(f, data, len); memcpy(f, data, len);
r = file_put_data(ef, fdata, ef_size); r = flash_write_data_to_file(ef, fdata, ef_size);
free(fdata); free(fdata);
if (r != PICOKEY_OK) { if (r != CCID_OK)
return PICOKEY_EXEC_ERROR; return CCID_EXEC_ERROR;
} return CCID_OK;
return PICOKEY_OK;
} }
} }
} }
fdata = (uint8_t *) realloc(fdata, ef_size + asn1_len_tag(fid & 0x1f, len + 2)); fdata = (uint8_t *)realloc(fdata, ef_size+asn1_len_tag(fid & 0x1f, len+2));
uint8_t *f = fdata + ef_size; uint8_t *f = fdata+ef_size;
*f++ = fid & 0x1f; *f++ = fid & 0x1f;
f += format_tlv_len(len + 2, f); f += format_tlv_len(len+2, f);
f += put_uint16_t_be(fid, f); *f++ = fid >> 8;
*f++ = fid & 0xff;
memcpy(f, data, len); memcpy(f, data, len);
r = file_put_data(ef, fdata, ef_size + (uint16_t)asn1_len_tag(fid & 0x1f, len + 2)); r = flash_write_data_to_file(ef, fdata, ef_size+asn1_len_tag(fid & 0x1f, len+2));
free(fdata); free(fdata);
if (r != PICOKEY_OK) { if (r != CCID_OK)
return PICOKEY_EXEC_ERROR; return CCID_EXEC_ERROR;
} return CCID_OK;
return PICOKEY_OK;
} }
bool file_has_data(file_t *f) {
return f != NULL && f->data != NULL && file_get_size(f) > 0;
}
int delete_file(file_t *ef) {
if (ef == NULL) {
return PICOKEY_OK;
}
meta_delete(ef->fid);
if (flash_clear_file(ef) != PICOKEY_OK) {
return PICOKEY_EXEC_ERROR;
}
if (delete_dynamic_file(ef) != PICOKEY_OK) {
return PICOKEY_EXEC_ERROR;
}
low_flash_available();
return PICOKEY_OK;
}

View file

@ -1,36 +1,30 @@
/* /*
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk). * This file is part of the Pico HSM SDK distribution (https://github.com/polhenarejos/pico-hsm-sdk).
* Copyright (c) 2022 Pol Henarejos. * Copyright (c) 2022 Pol Henarejos.
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3. * the Free Software Foundation, version 3.
* *
* This program is distributed in the hope that it will be useful, but * This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of * WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Affero General Public License for more details. * General Public License for more details.
* *
* You should have received a copy of the GNU Affero General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef _FILE_H_ #ifndef _FILE_H_
#define _FILE_H_ #define _FILE_H_
#include <stdlib.h> #include <stdlib.h>
#if defined(PICO_PLATFORM)
#include "pico/stdlib.h" #include "pico/stdlib.h"
#else
#include <stdbool.h>
#include <stdint.h>
#endif
#include "compat.h"
#include "phy.h"
#define FILE_TYPE_NOT_KNOWN 0x00 #define FILE_TYPE_UNKNOWN 0x00
#define FILE_TYPE_DF 0x04 #define FILE_TYPE_DF 0x04
#define FILE_TYPE_INTERNAL_EF 0x02 #define FILE_TYPE_INTERNAL_EF 0x03
#define FILE_TYPE_WORKING_EF 0x01 #define FILE_TYPE_WORKING_EF 0x01
#define FILE_TYPE_BSO 0x10 #define FILE_TYPE_BSO 0x10
#define FILE_PERSISTENT 0x20 #define FILE_PERSISTENT 0x20
@ -69,31 +63,16 @@
#define MAX_DEPTH 4 #define MAX_DEPTH 4
#define MAX_DYNAMIC_FILES 256 typedef struct file
{
#ifdef _MSC_VER
__pragma( pack(push, 1) )
#endif
typedef struct file {
const uint8_t *name;
uint8_t *data; //should include 2 bytes len at begining
const uint16_t fid; const uint16_t fid;
const uint8_t acl[7]; const uint8_t parent; //entry number in the whole table!!
const uint8_t parent; //entry number in the whole table!! const uint8_t *name;
const uint8_t type; const uint8_t type;
const uint8_t ef_structure; const uint8_t ef_structure;
#ifdef ENABLE_EMULATION uint8_t *data; //should include 2 bytes len at begining
uint32_t _padding; const uint8_t acl[7];
#endif } __attribute__((packed)) file_t;
}
#ifdef _MSC_VER
__pragma( pack(pop) )
#else
__attribute__ ((packed))
#endif
file_t;
extern bool file_has_data(file_t *);
extern file_t *currentEF; extern file_t *currentEF;
extern file_t *currentDF; extern file_t *currentDF;
@ -110,7 +89,6 @@ extern file_t *file_sopin;
extern file_t *file_retries_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_fid(const uint16_t fid, const file_t *parent, const uint8_t sp);
extern file_t *search_file(const uint16_t fid);
extern file_t *search_by_name(uint8_t *name, uint16_t namelen); extern file_t *search_by_name(uint8_t *name, uint16_t namelen);
extern file_t *search_by_path(const uint8_t *pe_path, uint8_t pathlen, const file_t *parent); extern file_t *search_by_path(const uint8_t *pe_path, uint8_t pathlen, const file_t *parent);
extern bool authenticate_action(const file_t *ef, uint8_t op); extern bool authenticate_action(const file_t *ef, uint8_t op);
@ -122,11 +100,9 @@ extern file_t file_entries[];
extern uint8_t *file_read(const uint8_t *addr); extern uint8_t *file_read(const uint8_t *addr);
extern uint16_t file_read_uint16(const uint8_t *addr); extern uint16_t file_read_uint16(const uint8_t *addr);
extern uint8_t file_read_uint8(const file_t *ef); extern uint8_t file_read_uint8(const uint8_t *addr);
extern uint8_t file_read_uint8_offset(const file_t *ef, const uint16_t offset);
extern uint8_t *file_get_data(const file_t *tf); extern uint8_t *file_get_data(const file_t *tf);
extern uint16_t file_get_size(const file_t *tf); extern uint16_t file_get_size(const file_t *tf);
extern int file_put_data(file_t *file, const uint8_t *data, uint16_t len);
extern file_t *file_new(uint16_t); extern file_t *file_new(uint16_t);
file_t *get_parent(file_t *f); file_t *get_parent(file_t *f);
@ -137,19 +113,9 @@ extern int delete_dynamic_file(file_t *f);
extern bool isUserAuthenticated; extern bool isUserAuthenticated;
extern uint16_t meta_find(uint16_t, uint8_t **out); extern int meta_find(uint16_t, uint8_t **out);
extern int meta_delete(uint16_t fid); extern int meta_delete(uint16_t fid);
extern int meta_add(uint16_t fid, const uint8_t *data, uint16_t len); extern int meta_add(uint16_t fid, const uint8_t *data, uint16_t len);
extern int delete_file(file_t *ef);
extern uint32_t flash_free_space();
extern uint32_t flash_used_space();
extern uint32_t flash_total_space();
extern uint32_t flash_num_files();
extern uint32_t flash_size();
#ifndef ENABLE_EMULATION
extern file_t *ef_phy;
#endif #endif
#endif // _FILE_H_

View file

@ -1,28 +0,0 @@
/*
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
* Copyright (c) 2022 Pol Henarejos.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero 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
* Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "file.h"
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 = 0x0000, .parent = 0xff, .name = NULL, .type = FILE_TYPE_NOT_KNOWN, .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];

View file

@ -1,40 +1,28 @@
/* /*
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk). * This file is part of the Pico HSM SDK distribution (https://github.com/polhenarejos/pico-hsm-sdk).
* Copyright (c) 2022 Pol Henarejos. * Copyright (c) 2022 Pol Henarejos.
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3. * the Free Software Foundation, version 3.
* *
* This program is distributed in the hope that it will be useful, but * This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of * WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Affero General Public License for more details. * General Public License for more details.
* *
* You should have received a copy of the GNU Affero General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <stdint.h> #include <stdint.h>
#include <string.h> #include <string.h>
#include "pico_keys.h"
#if !defined(PICO_PLATFORM)
#define XIP_BASE 0
#define FLASH_SECTOR_SIZE 4096
#ifdef ESP_PLATFORM
uint32_t FLASH_SIZE_BYTES = (1 * 1024 * 1024);
#else
#define FLASH_SIZE_BYTES (8 * 1024 * 1024)
#endif
#else
uint32_t FLASH_SIZE_BYTES = (2 * 1024 * 1024);
#include "pico/stdlib.h" #include "pico/stdlib.h"
#include "hardware/flash.h" #include "hardware/flash.h"
#endif #include "hsm.h"
#include "file.h" #include "file.h"
#include <stdio.h>
/* /*
* ------------------------------------------------------ * ------------------------------------------------------
@ -43,40 +31,29 @@ uint32_t FLASH_SIZE_BYTES = (2 * 1024 * 1024);
* | | * | |
* ------------------------------------------------------ * ------------------------------------------------------
*/ */
#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_DATA_HEADER_SIZE (sizeof(uintptr_t)+sizeof(uint32_t))
#define FLASH_PERMANENT_REGION (4 * FLASH_SECTOR_SIZE) // 4 sectors (16kb) of permanent memory #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 //To avoid possible future allocations, data region starts at the end of flash and goes upwards to the center region
uintptr_t end_flash, end_rom_pool, start_rom_pool, end_data_pool, start_data_pool;
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-FLASH_DATA_HEADER_SIZE-4; //This is a fixed value. DO NOT CHANGE
const uintptr_t end_rom_pool = (XIP_BASE + PICO_FLASH_SIZE_BYTES)-FLASH_DATA_HEADER_SIZE-4; //This is a fixed value. DO NOT CHANGE
const uintptr_t start_rom_pool = (XIP_BASE + PICO_FLASH_SIZE_BYTES)-FLASH_DATA_HEADER_SIZE-FLASH_PERMANENT_REGION; //This is a fixed value. DO NOT CHANGE
extern int flash_program_block(uintptr_t addr, const uint8_t *data, size_t len); extern int flash_program_block(uintptr_t addr, const uint8_t *data, size_t len);
extern int flash_program_halfword(uintptr_t addr, uint16_t data); extern int flash_program_halfword (uintptr_t addr, uint16_t data);
extern int flash_program_uintptr(uintptr_t, uintptr_t); extern int flash_program_uintptr(uintptr_t, uintptr_t);
extern uintptr_t flash_read_uintptr(uintptr_t addr); extern uintptr_t flash_read_uintptr(uintptr_t addr);
extern uint16_t flash_read_uint16(uintptr_t addr); extern uint16_t flash_read_uint16(uintptr_t addr);
extern uint8_t *flash_read(uintptr_t addr);
extern void low_flash_available(); extern void low_flash_available();
uintptr_t last_base;
uint32_t num_files = 0;
void flash_set_bounds(uintptr_t start, uintptr_t end) {
end_flash = end;
end_rom_pool = end_flash - FLASH_DATA_HEADER_SIZE - 4;
start_rom_pool = end_rom_pool - FLASH_PERMANENT_REGION;
end_data_pool = start_rom_pool - FLASH_DATA_HEADER_SIZE;
start_data_pool = start;
last_base = end_data_pool;
}
uintptr_t allocate_free_addr(uint16_t size, bool persistent) { uintptr_t allocate_free_addr(uint16_t size, bool persistent) {
if (size > FLASH_SECTOR_SIZE) { if (size > FLASH_SECTOR_SIZE)
return 0x0; //ERROR 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
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, endp = end_data_pool, startp = start_data_pool; uintptr_t next_base = 0x0, endp = end_data_pool, startp = start_data_pool;
if (persistent) { if (persistent) {
endp = end_rom_pool; endp = end_rom_pool;
@ -84,34 +61,32 @@ uintptr_t allocate_free_addr(uint16_t size, bool persistent) {
} }
for (uintptr_t base = endp; base >= startp; base = next_base) { for (uintptr_t base = endp; base >= startp; base = next_base) {
uintptr_t addr_alg = base & -FLASH_SECTOR_SIZE; //start address of sector uintptr_t addr_alg = base & -FLASH_SECTOR_SIZE; //start address of sector
uintptr_t potential_addr = base - real_size; uintptr_t potential_addr = base-real_size;
next_base = flash_read_uintptr(base); next_base = flash_read_uintptr(base);
//printf("nb %x %x %x %x\n",base,next_base,addr_alg,potential_addr); //printf("nb %x %x %x %x\r\n",base,next_base,addr_alg,potential_addr);
//printf("fid %x\n",flash_read_uint16(next_base+sizeof(uintptr_t))); //printf("fid %x\r\n",flash_read_uint16(next_base+sizeof(uintptr_t)));
if (next_base == 0x0) { //we are at the end if (next_base == 0x0) { //we are at the end
//now we check if we fit in the current sector //now we check if we fit in the current sector
if (addr_alg <= potential_addr) { //it fits 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, 0x0);
flash_program_uintptr(potential_addr + sizeof(uintptr_t), base); flash_program_uintptr(potential_addr+sizeof(uintptr_t), base);
flash_program_uintptr(base, potential_addr); flash_program_uintptr(base, potential_addr);
return potential_addr; return potential_addr;
} }
else if (addr_alg - FLASH_SECTOR_SIZE >= startp) { //check whether it fits in the next sector, so we take addr_aligned as the base else if (addr_alg-FLASH_SECTOR_SIZE >= startp) { //check whether it fits in the next sector, so we take addr_aligned as the base
potential_addr = addr_alg - real_size; potential_addr = addr_alg-real_size;
flash_program_uintptr(potential_addr, 0x0); flash_program_uintptr(potential_addr, 0x0);
flash_program_uintptr(potential_addr + sizeof(uintptr_t), base); flash_program_uintptr(potential_addr+sizeof(uintptr_t), base);
flash_program_uintptr(base, potential_addr); flash_program_uintptr(base, potential_addr);
return potential_addr; return potential_addr;
} }
return 0x0; return 0x0;
} }
//we check if |base-(next_addr+size_next_addr)| > |base-potential_addr| only if fid != 1xxx (not size blocked) //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 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) {
&& 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 + 2 * sizeof(uintptr_t)) & 0x1000) != 0x1000) {
flash_program_uintptr(potential_addr, next_base); flash_program_uintptr(potential_addr, next_base);
flash_program_uintptr(next_base + sizeof(uintptr_t), potential_addr); flash_program_uintptr(potential_addr+sizeof(uintptr_t), base);
flash_program_uintptr(potential_addr + sizeof(uintptr_t), base);
flash_program_uintptr(base, potential_addr); flash_program_uintptr(base, potential_addr);
return potential_addr; return potential_addr;
} }
@ -120,96 +95,57 @@ uintptr_t allocate_free_addr(uint16_t size, bool persistent) {
} }
int flash_clear_file(file_t *file) { int flash_clear_file(file_t *file) {
if (file == NULL || file->data == NULL) { uintptr_t base_addr = (uintptr_t)(file->data-sizeof(uintptr_t)-sizeof(uint16_t)-sizeof(uintptr_t));
return PICOKEY_OK; uintptr_t prev_addr = flash_read_uintptr(base_addr+sizeof(uintptr_t));
}
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); uintptr_t next_addr = flash_read_uintptr(base_addr);
//printf("nc %lx->%lx %lx->%lx\n",prev_addr,flash_read_uintptr(prev_addr),base_addr,next_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_uintptr(prev_addr, next_addr);
flash_program_halfword((uintptr_t) file->data, 0); flash_program_halfword((uintptr_t)file->data, 0);
if (next_addr > 0) { if (next_addr > 0)
flash_program_uintptr(next_addr + sizeof(uintptr_t), prev_addr); flash_program_uintptr(next_addr+sizeof(uintptr_t), prev_addr);
} //printf("na %x->%x\r\n",prev_addr,flash_read_uintptr(prev_addr));
flash_program_uintptr(base_addr, 0); return CCID_OK;
flash_program_uintptr(base_addr + sizeof(uintptr_t), 0);
file->data = NULL;
num_files--;
//printf("na %lx->%lx\n",prev_addr,flash_read_uintptr(prev_addr));
return PICOKEY_OK;
} }
int flash_write_data_to_file_offset(file_t *file, const uint8_t *data, uint16_t len, uint16_t offset) { int flash_write_data_to_file_offset(file_t *file, const uint8_t *data, uint16_t len, uint16_t offset) {
if (!file) { if (!file)
return PICOKEY_ERR_NULL_PARAM; return CCID_ERR_NULL_PARAM;
} uint16_t size_file_flash = file->data ? flash_read_uint16((uintptr_t)file->data) : 0;
uint16_t size_file_flash = file->data ? flash_read_uint16((uintptr_t) file->data) : 0;
uint8_t *old_data = NULL; uint8_t *old_data = NULL;
if (offset + len > FLASH_SECTOR_SIZE || offset > size_file_flash) { if (offset+len > FLASH_SECTOR_SIZE || offset > size_file_flash)
return PICOKEY_ERR_NO_MEMORY; return CCID_ERR_NO_MEMORY;
}
if (file->data) { //already in flash if (file->data) { //already in flash
if (offset + len <= size_file_flash) { //it fits, no need to move it if (offset+len <= size_file_flash) { //it fits, no need to move it
flash_program_halfword((uintptr_t) file->data, offset + len); flash_program_halfword((uintptr_t)file->data, offset+len);
if (data) { if (data)
flash_program_block((uintptr_t) file->data + sizeof(uint16_t) + offset, data, len); flash_program_block((uintptr_t)file->data+sizeof(uint16_t)+offset, data, len);
} return CCID_OK;
return PICOKEY_OK;
} }
else { //we clear the old file else { //we clear the old file
flash_clear_file(file); flash_clear_file(file);
if (offset > 0) { if (offset > 0) {
old_data = (uint8_t *) calloc(1, offset + len); old_data = (uint8_t *)calloc(1, offset+len);
memcpy(old_data, flash_read((uintptr_t) (file->data + sizeof(uint16_t))), offset); memcpy(old_data, file->data+sizeof(uint16_t), offset);
memcpy(old_data + offset, data, len); memcpy(old_data+offset, data, len);
len = offset + len; len = offset+len;
data = old_data; data = old_data;
} }
} }
} }
uintptr_t new_addr = allocate_free_addr(len, (file->type & FILE_PERSISTENT) == FILE_PERSISTENT); uintptr_t new_addr = allocate_free_addr(len, (file->type & FILE_PERSISTENT) == FILE_PERSISTENT);
//printf("na %x\n",new_addr); //printf("na %x\r\n",new_addr);
if (new_addr == 0x0) { if (new_addr == 0x0)
return PICOKEY_ERR_NO_MEMORY; return CCID_ERR_NO_MEMORY;
} file->data = (uint8_t *)new_addr+sizeof(uintptr_t)+sizeof(uint16_t)+sizeof(uintptr_t); //next addr+fid+prev addr
if (new_addr < last_base) { flash_program_halfword(new_addr+sizeof(uintptr_t)+sizeof(uintptr_t), file->fid);
last_base = new_addr; flash_program_halfword((uintptr_t)file->data, len);
} if (data)
file->data = (uint8_t *) new_addr + sizeof(uintptr_t) + sizeof(uint16_t) + sizeof(uintptr_t); //next addr+fid+prev addr flash_program_block((uintptr_t)file->data+sizeof(uint16_t), data, len);
flash_program_halfword(new_addr + sizeof(uintptr_t) + sizeof(uintptr_t), file->fid); if (old_data)
flash_program_halfword((uintptr_t) file->data, len);
if (data) {
flash_program_block((uintptr_t) file->data + sizeof(uint16_t), data, len);
}
if (old_data) {
free(old_data); free(old_data);
} return CCID_OK;
num_files++;
return PICOKEY_OK;
} }
int flash_write_data_to_file(file_t *file, const uint8_t *data, uint16_t len) { int flash_write_data_to_file(file_t *file, const uint8_t *data, uint16_t len) {
return flash_write_data_to_file_offset(file, data, len, 0); return flash_write_data_to_file_offset(file, data, len, 0);
} }
uint32_t flash_free_space() {
return (uint32_t)(last_base - start_data_pool);
}
uint32_t flash_used_space() {
return (uint32_t)(end_data_pool - last_base);
}
uint32_t flash_total_space() {
return (uint32_t)(end_data_pool - start_data_pool);
}
uint32_t flash_num_files() {
return num_files;
}
uint32_t flash_size() {
return FLASH_SIZE_BYTES;
}

View file

@ -1,18 +1,18 @@
/* /*
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk). * This file is part of the Pico HSM SDK distribution (https://github.com/polhenarejos/pico-hsm-sdk).
* Copyright (c) 2022 Pol Henarejos. * Copyright (c) 2022 Pol Henarejos.
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3. * the Free Software Foundation, version 3.
* *
* This program is distributed in the hope that it will be useful, but * This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of * WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Affero General Public License for more details. * General Public License for more details.
* *
* You should have received a copy of the GNU Affero General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
@ -20,62 +20,16 @@
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include "pico_keys.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 "hsm.h"
#include <string.h> #include <string.h>
#ifdef PICO_PLATFORM
#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 "pico/bootrom.h"
#include "boot/picobin.h"
#else
#ifdef ESP_PLATFORM
#include "esp_compat.h"
#include "esp_partition.h"
const esp_partition_t *part0;
#define save_and_disable_interrupts() 1
#define flash_range_erase(a,b) esp_partition_erase_range(part0, a, b)
#define flash_range_program(a,b,c) esp_partition_write(part0, a, b, c);
#define restore_interrupts(a) (void)a
#else
#ifdef _MSC_VER
#include <windows.h>
#include <io.h>
#define O_RDWR _O_RDWR
#define O_CREAT _O_CREAT
#define open _open
#define write _write
#define mode_t unsigned short
#define lseek _lseek
#include "mman.h"
#else
#include <unistd.h>
#include <sys/mman.h>
#endif
#include "queue.h"
#endif
#define FLASH_SECTOR_SIZE 4096
#define XIP_BASE 0
int fd_map = 0;
uint8_t *map = NULL;
#include <fcntl.h>
#endif
#if defined(PICO_PLATFORM) || defined(ESP_PLATFORM)
extern uint32_t FLASH_SIZE_BYTES;
#else
#define FLASH_SIZE_BYTES (8 * 1024 * 1024)
#endif
#define TOTAL_FLASH_PAGES 6 #define TOTAL_FLASH_PAGES 4
#define FLASH_LOCKOUT_RETRIES 5
extern void flash_set_bounds(uintptr_t start, uintptr_t end);
extern const uintptr_t start_data_pool;
extern const uintptr_t end_rom_pool;
typedef struct page_flash { typedef struct page_flash {
uint8_t page[FLASH_SECTOR_SIZE]; uint8_t page[FLASH_SECTOR_SIZE];
@ -88,135 +42,59 @@ typedef struct page_flash {
static page_flash_t flash_pages[TOTAL_FLASH_PAGES]; static page_flash_t flash_pages[TOTAL_FLASH_PAGES];
static mutex_t mtx_flash; static mutex_t mtx_flash;
static semaphore_t sem_flash; static semaphore_t sem_wait;
#ifndef ENABLE_EMULATION
static bool locked_out = false;
#else
static bool locked_out = true;
#endif
static uint8_t ready_pages = 0; static uint8_t ready_pages = 0;
bool flash_available = false; bool flash_available = false;
static bool locked_out = false;
//this function has to be called from the core 0 //this function has to be called from the core 0
void do_flash() { void do_flash()
{
if (mutex_try_enter(&mtx_flash, NULL) == true) { if (mutex_try_enter(&mtx_flash, NULL) == true) {
if (locked_out == true && flash_available == true && ready_pages > 0) { if (locked_out == true && flash_available == true && ready_pages > 0) {
//printf(" DO_FLASH AVAILABLE\n"); //printf(" DO_FLASH AVAILABLE\r\n");
for (int r = 0; r < TOTAL_FLASH_PAGES; r++) { for (int r = 0; r < TOTAL_FLASH_PAGES; r++) {
if (flash_pages[r].ready == true) { if (flash_pages[r].ready == true) {
#if defined(PICO_PLATFORM) || defined(ESP_PLATFORM) //printf("WRITTING %X\r\n",flash_pages[r].address-XIP_BASE);
//printf("WRITTING %X\n",flash_pages[r].address-XIP_BASE); while (multicore_lockout_start_timeout_us(1000) == false);
for (int retries = 0; retries < FLASH_LOCKOUT_RETRIES && multicore_lockout_start_timeout_us(1000) == false; retries++) { //printf("WRITTING %X\r\n",flash_pages[r].address-XIP_BASE);
}
//printf("WRITTING %X\n",flash_pages[r].address-XIP_BASE);
uint32_t ints = save_and_disable_interrupts(); uint32_t ints = save_and_disable_interrupts();
flash_range_erase(flash_pages[r].address - XIP_BASE, FLASH_SECTOR_SIZE); 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); flash_range_program(flash_pages[r].address-XIP_BASE, flash_pages[r].page, FLASH_SECTOR_SIZE);
restore_interrupts(ints); restore_interrupts (ints);
for (int retries = 0; retries < FLASH_LOCKOUT_RETRIES && multicore_lockout_end_timeout_us(1000) == false; retries++) { while (multicore_lockout_end_timeout_us(1000) == false);
} //printf("WRITEN %X !\r\n",flash_pages[r].address);
//printf("WRITEN %X !\n",flash_pages[r].address);
#else
memcpy(map + flash_pages[r].address, flash_pages[r].page, FLASH_SECTOR_SIZE);
#endif
flash_pages[r].ready = false; flash_pages[r].ready = false;
ready_pages--; ready_pages--;
} }
else if (flash_pages[r].erase == true) { else if (flash_pages[r].erase == true) {
#if defined(PICO_PLATFORM) || defined(ESP_PLATFORM) while (multicore_lockout_start_timeout_us(1000) == false);
for (int retries = 0; retries < FLASH_LOCKOUT_RETRIES && multicore_lockout_start_timeout_us(1000) == false; retries++) { //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);
//printf("WRITTING\n"); while (multicore_lockout_end_timeout_us(1000) == false);
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);
for (int retries = 0; retries < FLASH_LOCKOUT_RETRIES && multicore_lockout_end_timeout_us(1000) == false; retries++) {
}
#else
memset(map + flash_pages[r].address, 0, FLASH_SECTOR_SIZE);
#endif
flash_pages[r].erase = false; flash_pages[r].erase = false;
ready_pages--; ready_pages--;
} }
} }
#if !defined(PICO_PLATFORM) && !defined(ESP_PLATFORM) flash_available = false;
msync(map, FLASH_SIZE_BYTES, MS_SYNC);
#endif
if (ready_pages != 0) { if (ready_pages != 0) {
printf("ERROR: DO FLASH DOES NOT HAVE ZERO PAGES\n"); printf("ERROR: DO FLASH DOES NOT HAVE ZERO PAGES\n");
} }
} }
flash_available = false;
#ifdef ESP_PLATFORM
esp_partition_munmap(fd_map);
esp_partition_mmap(part0, 0, part0->size, ESP_PARTITION_MMAP_DATA, (const void **)&map, (esp_partition_mmap_handle_t *)&fd_map);
#endif
mutex_exit(&mtx_flash); mutex_exit(&mtx_flash);
} }
sem_release(&sem_flash); sem_release(&sem_wait);
} }
//this function has to be called from the core 0 //this function has to be called from the core 0
void low_flash_init() { void low_flash_init() {
memset(flash_pages, 0, sizeof(page_flash_t) * TOTAL_FLASH_PAGES);
mutex_init(&mtx_flash); mutex_init(&mtx_flash);
sem_init(&sem_flash, 0, 1); sem_init(&sem_wait, 0, 1);
memset(flash_pages, 0, sizeof(page_flash_t)*TOTAL_FLASH_PAGES);
uint32_t data_start_addr;
uint32_t data_end_addr;
#if defined(ESP_PLATFORM)
part0 = esp_partition_find_first(0x40, 0x1, "part0");
esp_partition_mmap(part0, 0, part0->size, ESP_PARTITION_MMAP_DATA, (const void **)&map, (esp_partition_mmap_handle_t *)&fd_map);
data_start_addr = 0;
data_end_addr = part0->size;
FLASH_SIZE_BYTES = part0->size;
#elif defined(PICO_PLATFORM)
uint8_t txbuf[6] = {0x9f};
uint8_t rxbuf[6] = {0};
flash_do_cmd(txbuf, rxbuf, 4);
FLASH_SIZE_BYTES = (1 << rxbuf[3]);
#ifdef PICO_RP2350
__attribute__((aligned(4))) uint8_t workarea[4 * 1024];
int rc = rom_load_partition_table(workarea, sizeof(workarea), false);
if (rc) {
reset_usb_boot(0, 0);
}
uint8_t boot_partition = 1;
rc = rom_get_partition_table_info((uint32_t*)workarea, 0x8, PT_INFO_PARTITION_LOCATION_AND_FLAGS | PT_INFO_SINGLE_PARTITION | (boot_partition << 24));
if (rc != 3) {
data_start_addr = (FLASH_SIZE_BYTES >> 1);
data_end_addr = FLASH_SIZE_BYTES;
} else {
uint16_t first_sector_number = (((uint32_t*)workarea)[1] & PICOBIN_PARTITION_LOCATION_FIRST_SECTOR_BITS) >> PICOBIN_PARTITION_LOCATION_FIRST_SECTOR_LSB;
uint16_t last_sector_number = (((uint32_t*)workarea)[1] & PICOBIN_PARTITION_LOCATION_LAST_SECTOR_BITS) >> PICOBIN_PARTITION_LOCATION_LAST_SECTOR_LSB;
data_start_addr = first_sector_number * FLASH_SECTOR_SIZE;
data_end_addr = (last_sector_number + 1) * FLASH_SECTOR_SIZE;
if (data_end_addr > FLASH_SIZE_BYTES) {
data_end_addr = FLASH_SIZE_BYTES;
}
}
data_end_addr -= 2 * FLASH_SECTOR_SIZE;
#else
data_start_addr = (FLASH_SIZE_BYTES >> 1);
data_end_addr = FLASH_SIZE_BYTES;
#endif
data_start_addr += XIP_BASE;
data_end_addr += XIP_BASE;
#else
fd_map = open("memory.flash", O_RDWR | O_CREAT, (mode_t) 0600);
lseek(fd_map, FLASH_SIZE_BYTES - 1, SEEK_SET);
write(fd_map, "", 1);
map = mmap(0, FLASH_SIZE_BYTES, PROT_READ | PROT_WRITE, MAP_SHARED, fd_map, 0);
data_start_addr = 0;
data_end_addr = FLASH_SIZE_BYTES;
#endif
flash_set_bounds(data_start_addr, data_end_addr);
} }
void low_flash_init_core1() { void low_flash_init_core1() {
@ -227,9 +105,9 @@ void low_flash_init_core1() {
} }
void wait_flash_finish() { void wait_flash_finish() {
sem_acquire_blocking(&sem_flash); //blocks until released sem_acquire_blocking(&sem_wait); //blocks until released
//wake up //wake up
sem_acquire_blocking(&sem_flash); //decrease permits sem_acquire_blocking(&sem_wait); //decrease permits
} }
void low_flash_available() { void low_flash_available() {
@ -241,16 +119,14 @@ void low_flash_available() {
page_flash_t *find_free_page(uintptr_t addr) { page_flash_t *find_free_page(uintptr_t addr) {
uintptr_t addr_alg = addr & -FLASH_SECTOR_SIZE; uintptr_t addr_alg = addr & -FLASH_SECTOR_SIZE;
page_flash_t *p = NULL; page_flash_t *p = NULL;
for (int r = 0; r < TOTAL_FLASH_PAGES; r++) { 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 if ((!flash_pages[r].ready && !flash_pages[r].erase) || flash_pages[r].address == addr_alg) //first available
{
p = &flash_pages[r]; p = &flash_pages[r];
if (!flash_pages[r].ready && !flash_pages[r].erase) { if (!flash_pages[r].ready && !flash_pages[r].erase)
#ifdef PICO_PLATFORM {
memcpy(p->page, (uint8_t *) addr_alg, FLASH_SECTOR_SIZE); memcpy(p->page, (uint8_t *)addr_alg, FLASH_SECTOR_SIZE);
#else
memcpy(p->page, (addr >= start_data_pool && addr <= end_rom_pool + sizeof(uintptr_t)) ? (uint8_t *) (map + addr_alg) : (uint8_t *) addr_alg, FLASH_SECTOR_SIZE);
#endif
ready_pages++; ready_pages++;
p->address = addr_alg; p->address = addr_alg;
p->ready = true; p->ready = true;
@ -264,74 +140,70 @@ page_flash_t *find_free_page(uintptr_t addr) {
int flash_program_block(uintptr_t addr, const uint8_t *data, size_t len) { int flash_program_block(uintptr_t addr, const uint8_t *data, size_t len) {
page_flash_t *p = NULL; page_flash_t *p = NULL;
if (!data || len == 0) { if (!data || len == 0)
return PICOKEY_ERR_NULL_PARAM; return CCID_ERR_NULL_PARAM;
}
mutex_enter_blocking(&mtx_flash); mutex_enter_blocking(&mtx_flash);
if (ready_pages == TOTAL_FLASH_PAGES) { if (ready_pages == TOTAL_FLASH_PAGES) {
mutex_exit(&mtx_flash); mutex_exit(&mtx_flash);
printf("ERROR: ALL FLASH PAGES CACHED\n"); printf("ERROR: ALL FLASH PAGES CACHED\r\n");
return PICOKEY_ERR_NO_MEMORY; return CCID_ERR_NO_MEMORY;
} }
if (!(p = find_free_page(addr))) { if (!(p = find_free_page(addr)))
{
mutex_exit(&mtx_flash); mutex_exit(&mtx_flash);
printf("ERROR: FLASH CANNOT FIND A PAGE (rare error)\n"); printf("ERROR: FLASH CANNOT FIND A PAGE (rare error)\r\n");
return PICOKEY_ERR_MEMORY_FATAL; return CCID_ERR_MEMORY_FATAL;
} }
memcpy(&p->page[addr & (FLASH_SECTOR_SIZE - 1)], data, len); memcpy(&p->page[addr&(FLASH_SECTOR_SIZE-1)], data, len);
//printf("Flash: modified page %X with data %x at [%x]\n",(uintptr_t)addr,(uintptr_t)data,addr&(FLASH_SECTOR_SIZE-1)); //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); mutex_exit(&mtx_flash);
return PICOKEY_OK; return CCID_OK;
} }
int flash_program_halfword(uintptr_t addr, uint16_t data) { int flash_program_halfword (uintptr_t addr, uint16_t data) {
return flash_program_block(addr, (const uint8_t *) &data, sizeof(uint16_t)); return flash_program_block(addr, (const uint8_t *)&data, sizeof(uint16_t));
} }
int flash_program_word(uintptr_t addr, uint32_t data) { int flash_program_word (uintptr_t addr, uint32_t data) {
return flash_program_block(addr, (const uint8_t *) &data, sizeof(uint32_t)); return flash_program_block(addr, (const uint8_t *)&data, sizeof(uint32_t));
} }
int flash_program_uintptr(uintptr_t addr, uintptr_t data) { int flash_program_uintptr (uintptr_t addr, uintptr_t data) {
return flash_program_block(addr, (const uint8_t *) &data, sizeof(uintptr_t)); return flash_program_block(addr, (const uint8_t *)&data, sizeof(uintptr_t));
} }
uint8_t *flash_read(uintptr_t addr) { uint8_t *flash_read(uintptr_t addr) {
uintptr_t addr_alg = addr & -FLASH_SECTOR_SIZE; uintptr_t addr_alg = addr & -FLASH_SECTOR_SIZE;
mutex_enter_blocking(&mtx_flash); mutex_enter_blocking(&mtx_flash);
if (ready_pages > 0) { if (ready_pages > 0) {
for (int r = 0; r < TOTAL_FLASH_PAGES; r++) { for (int r = 0; r < TOTAL_FLASH_PAGES; r++)
{
if (flash_pages[r].ready && flash_pages[r].address == addr_alg) { if (flash_pages[r].ready && flash_pages[r].address == addr_alg) {
uint8_t *v = &flash_pages[r].page[addr & (FLASH_SECTOR_SIZE - 1)]; uint8_t *v = &flash_pages[r].page[addr&(FLASH_SECTOR_SIZE-1)];
mutex_exit(&mtx_flash); mutex_exit(&mtx_flash);
return v; return v;
} }
} }
} }
uint8_t *v = (uint8_t *) addr; uint8_t *v = (uint8_t *)addr;
mutex_exit(&mtx_flash); mutex_exit(&mtx_flash);
#if !defined(PICO_PLATFORM)
if (addr >= start_data_pool && addr <= end_rom_pool + sizeof(uintptr_t)) {
v += (uintptr_t) map;
}
#endif
return v; return v;
} }
uintptr_t flash_read_uintptr(uintptr_t addr) { uintptr_t flash_read_uintptr(uintptr_t addr) {
uint8_t *p = flash_read(addr); uint8_t *p = flash_read(addr);
uintptr_t v = 0x0; uintptr_t v = 0x0;
for (size_t i = 0; i < sizeof(uintptr_t); i++) { for (int i = 0; i < sizeof(uintptr_t); i++) {
v |= (uintptr_t) p[i] << (8 * i); v |= (uintptr_t)p[i]<<(8*i);
} }
return v; return v;
} }
uint16_t flash_read_uint16(uintptr_t addr) { uint16_t flash_read_uint16(uintptr_t addr) {
uint8_t *p = flash_read(addr); uint8_t *p = flash_read(addr);
uint16_t v = 0x0; uint16_t v = 0x0;
for (size_t i = 0; i < sizeof(uint16_t); i++) { for (int i = 0; i < sizeof(uint16_t); i++) {
v |= p[i] << (8 * i); v |= p[i]<<(8*i);
} }
return v; return v;
} }
@ -339,35 +211,35 @@ uint8_t flash_read_uint8(uintptr_t addr) {
return *flash_read(addr); return *flash_read(addr);
} }
int flash_erase_page(uintptr_t addr, size_t page_size) { int flash_erase_page (uintptr_t addr, size_t page_size) {
page_flash_t *p = NULL; page_flash_t *p = NULL;
mutex_enter_blocking(&mtx_flash); mutex_enter_blocking(&mtx_flash);
if (ready_pages == TOTAL_FLASH_PAGES) { if (ready_pages == TOTAL_FLASH_PAGES) {
mutex_exit(&mtx_flash); mutex_exit(&mtx_flash);
printf("ERROR: ALL FLASH PAGES CACHED\n"); printf("ERROR: ALL FLASH PAGES CACHED\r\n");
return PICOKEY_ERR_NO_MEMORY; return CCID_ERR_NO_MEMORY;
} }
if (!(p = find_free_page(addr))) { if (!(p = find_free_page(addr))) {
printf("ERROR: FLASH CANNOT FIND A PAGE (rare error)\n"); printf("ERROR: FLASH CANNOT FIND A PAGE (rare error)\r\n");
mutex_exit(&mtx_flash); mutex_exit(&mtx_flash);
return PICOKEY_ERR_MEMORY_FATAL; return CCID_ERR_MEMORY_FATAL;
} }
p->erase = true; p->erase = true;
p->ready = false; p->ready = false;
p->page_size = page_size; p->page_size = page_size;
mutex_exit(&mtx_flash); mutex_exit(&mtx_flash);
return PICOKEY_OK; return CCID_OK;
} }
bool flash_check_blank(const uint8_t *p_start, size_t size) { bool flash_check_blank(const uint8_t *p_start, size_t size)
{
const uint8_t *p; const uint8_t *p;
for (p = p_start; p < p_start + size; p++) { for (p = p_start; p < p_start + size; p++) {
if (*p != 0xff) { if (*p != 0xff)
return false; return false;
}
} }
return true; return true;
} }

View file

@ -1,201 +0,0 @@
/*
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
* Copyright (c) 2022 Pol Henarejos.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero 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
* Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include <windows.h>
#include <errno.h>
#include <io.h>
#include "mman.h"
#ifndef FILE_MAP_EXECUTE
#define FILE_MAP_EXECUTE 0x0020
#endif /* FILE_MAP_EXECUTE */
static int __map_mman_error(const DWORD err, const int deferr)
{
(void)deferr;
if (err == 0)
return 0;
//TODO: implement
return err;
}
static DWORD __map_mmap_prot_page(const int prot)
{
DWORD protect = 0;
if (prot == PROT_NONE)
return protect;
if ((prot & PROT_EXEC) != 0)
{
protect = ((prot & PROT_WRITE) != 0) ?
PAGE_EXECUTE_READWRITE : PAGE_EXECUTE_READ;
}
else
{
protect = ((prot & PROT_WRITE) != 0) ?
PAGE_READWRITE : PAGE_READONLY;
}
return protect;
}
static DWORD __map_mmap_prot_file(const int prot)
{
DWORD desiredAccess = 0;
if (prot == PROT_NONE)
return desiredAccess;
if ((prot & PROT_READ) != 0)
desiredAccess |= FILE_MAP_READ;
if ((prot & PROT_WRITE) != 0)
desiredAccess |= FILE_MAP_WRITE;
if ((prot & PROT_EXEC) != 0)
desiredAccess |= FILE_MAP_EXECUTE;
return desiredAccess;
}
void* mmap(void* addr, size_t len, int prot, int flags, int fildes, off_t off)
{
(void)addr;
HANDLE fm, h;
void* map = MAP_FAILED;
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable: 4293)
#endif
const DWORD dwFileOffsetLow = (sizeof(off_t) <= sizeof(DWORD)) ?
(DWORD)off : (DWORD)(off & 0xFFFFFFFFL);
const DWORD dwFileOffsetHigh = (sizeof(off_t) <= sizeof(DWORD)) ?
(DWORD)0 : (DWORD)((off >> 32) & 0xFFFFFFFFL);
const DWORD protect = __map_mmap_prot_page(prot);
const DWORD desiredAccess = __map_mmap_prot_file(prot);
const off_t maxSize = off + (off_t)len;
const DWORD dwMaxSizeLow = (sizeof(off_t) <= sizeof(DWORD)) ?
(DWORD)maxSize : (DWORD)(maxSize & 0xFFFFFFFFL);
const DWORD dwMaxSizeHigh = (sizeof(off_t) <= sizeof(DWORD)) ?
(DWORD)0 : (DWORD)((maxSize >> 32) & 0xFFFFFFFFL);
#ifdef _MSC_VER
#pragma warning(pop)
#endif
errno = 0;
if (len == 0
/* Unsupported flag combinations */
|| (flags & MAP_FIXED) != 0
/* Usupported protection combinations */
|| prot == PROT_EXEC)
{
errno = EINVAL;
return MAP_FAILED;
}
h = ((flags & MAP_ANONYMOUS) == 0) ?
(HANDLE)_get_osfhandle(fildes) : INVALID_HANDLE_VALUE;
if ((flags & MAP_ANONYMOUS) == 0 && h == INVALID_HANDLE_VALUE)
{
errno = EBADF;
return MAP_FAILED;
}
fm = CreateFileMapping(h, NULL, protect, dwMaxSizeHigh, dwMaxSizeLow, NULL);
if (fm == NULL)
{
errno = __map_mman_error(GetLastError(), EPERM);
return MAP_FAILED;
}
map = MapViewOfFile(fm, desiredAccess, dwFileOffsetHigh, dwFileOffsetLow, len);
CloseHandle(fm);
if (map == NULL)
{
errno = __map_mman_error(GetLastError(), EPERM);
return MAP_FAILED;
}
return map;
}
int munmap(void* addr, size_t len)
{
(void)len;
if (UnmapViewOfFile(addr))
return 0;
errno = __map_mman_error(GetLastError(), EPERM);
return -1;
}
int mprotect(void* addr, size_t len, int prot)
{
DWORD newProtect = __map_mmap_prot_page(prot);
DWORD oldProtect = 0;
if (VirtualProtect(addr, len, newProtect, &oldProtect))
return 0;
errno = __map_mman_error(GetLastError(), EPERM);
return -1;
}
int msync(void* addr, size_t len, int flags)
{
(void)flags;
if (FlushViewOfFile(addr, len))
return 0;
errno = __map_mman_error(GetLastError(), EPERM);
return -1;
}
int mlock(const void* addr, size_t len)
{
if (VirtualLock((LPVOID)addr, len))
return 0;
errno = __map_mman_error(GetLastError(), EPERM);
return -1;
}
int munlock(const void* addr, size_t len)
{
if (VirtualUnlock((LPVOID)addr, len))
return 0;
errno = __map_mman_error(GetLastError(), EPERM);
return -1;
}

View file

@ -1,68 +0,0 @@
/*
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
* Copyright (c) 2022 Pol Henarejos.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero 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
* Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef _SYS_MMAN_H_
#define _SYS_MMAN_H_
#ifndef _WIN32_WINNT // Allow use of features specific to Windows XP or later.
#define _WIN32_WINNT 0x0501 // Change this to the appropriate value to target other versions of Windows.
#endif
/* All the headers include this file. */
#ifndef _MSC_VER
#include <_mingw.h>
#endif
#include <sys/types.h>
#ifdef __cplusplus
extern "C" {
#endif
#define PROT_NONE 0
#define PROT_READ 1
#define PROT_WRITE 2
#define PROT_EXEC 4
#define MAP_FILE 0
#define MAP_SHARED 1
#define MAP_PRIVATE 2
#define MAP_TYPE 0xf
#define MAP_FIXED 0x10
#define MAP_ANONYMOUS 0x20
#define MAP_ANON MAP_ANONYMOUS
#define MAP_FAILED ((void *)-1)
/* Flags for msync. */
#define MS_ASYNC 1
#define MS_SYNC 2
#define MS_INVALIDATE 4
void* mmap(void* addr, size_t len, int prot, int flags, int fildes, off_t off);
int munmap(void* addr, size_t len);
int mprotect(void* addr, size_t len, int prot);
int msync(void* addr, size_t len, int flags);
int mlock(const void* addr, size_t len);
int munlock(const void* addr, size_t len);
#ifdef __cplusplus
};
#endif
#endif /* _SYS_MMAN_H_ */

View file

@ -1,361 +0,0 @@
/*
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
* Copyright (c) 2022 Pol Henarejos.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero 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
* Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "file.h"
#include "pico_keys.h"
#include <stdio.h>
#include "otp.h"
#ifdef PICO_RP2350
#include "pico/bootrom.h"
#include "hardware/structs/otp.h"
#include "hardware/regs/otp_data.h"
#endif
#include "random.h"
#include "mbedtls/ecdsa.h"
#include <stdalign.h>
#ifdef PICO_RP2350
static bool is_empty_buffer(const uint8_t *buffer, uint16_t buffer_len) {
for (int i = 0; i < buffer_len; i++) {
if (buffer[i] != 0x00) {
return false;
}
}
return true;
}
static int otp_write_data_mode(uint16_t row, const uint8_t *data, uint16_t len, bool is_ecc) {
otp_cmd_t cmd = { .flags = row | (is_ecc ? OTP_CMD_ECC_BITS : 0) | OTP_CMD_WRITE_BITS };
uint32_t ret = rom_func_otp_access((uint8_t *)data, len, cmd);
if (ret) {
printf("OTP Write failed with error: %ld\n", ret);
}
return ret;
}
int otp_write_data(uint16_t row, const uint8_t *data, uint16_t len) {
return otp_write_data_mode(row, data, len, true);
}
int otp_write_data_raw(uint16_t row, const uint8_t *data, uint16_t len) {
return otp_write_data_mode(row, data, len, false);
}
const uint8_t* otp_buffer(uint16_t row) {
volatile uint32_t *p = ((uint32_t *)(OTP_DATA_BASE + (row*2)));
return (const uint8_t *)p;
}
const uint8_t* otp_buffer_raw(uint16_t row) {
volatile uint32_t *p = ((uint32_t *)(OTP_DATA_RAW_BASE + (row*4)));
return (const uint8_t *)p;
}
bool is_empty_otp_buffer(uint16_t row, uint16_t len) {
return is_empty_buffer(otp_buffer_raw(row), len * 2);
}
static bool is_otp_locked_page(uint8_t page) {
volatile uint32_t *p = ((uint32_t *)(OTP_DATA_BASE + ((OTP_DATA_PAGE0_LOCK0_ROW + page*2)*2)));
return ((p[0] & 0xFFFF0000) == 0x3C3C0000 && (p[1] & 0xFF) == 0x3C);
}
static void otp_lock_page(uint8_t page) {
if (!is_otp_locked_page(page)) {
alignas(4) uint32_t value = 0x3c3c3c;
otp_write_data_raw(OTP_DATA_PAGE0_LOCK0_ROW + page*2 + 1, (uint8_t *)&value, sizeof(value));
}
otp_hw->sw_lock[page] = 0b1100;
}
#endif
#ifdef ESP_PLATFORM
uint8_t _otp_key_1[32] = {0};
uint8_t _otp_key_2[32] = {0};
esp_err_t read_key_from_efuse(esp_efuse_block_t block, uint8_t *key, size_t key_len) {
const esp_efuse_desc_t **key_desc = esp_efuse_get_key(block);
if (!key_desc) {
return ESP_FAIL;
}
return esp_efuse_read_field_blob(key_desc, key, key_len * 8);
}
#endif
const uint8_t *otp_key_1 = NULL;
const uint8_t *otp_key_2 = NULL;
#ifdef PICO_RP2350
typedef int otp_ret_t;
#define OTP_WRITE(ROW, DATA, LEN) otp_write_data(ROW, DATA, LEN)
#define OTP_READ(ROW, PTR) do { PTR = otp_buffer(ROW); } while(0)
#define OTP_EMTPY(ROW, LEN) is_empty_otp_buffer(ROW, LEN)
#elif defined(ESP_PLATFORM)
typedef esp_err_t otp_ret_t;
#define OTP_WRITE(ROW, DATA, LEN) esp_efuse_write_key(ROW, ESP_EFUSE_KEY_PURPOSE_USER, DATA, LEN)
#define OTP_READ(ROW, PTR) do { \
esp_err_t ret = read_key_from_efuse(ROW, _##PTR, sizeof(_##PTR)); \
if (ret != ESP_OK) { printf("Error reading OTP key 1 [%d]\n", ret); } \
PTR = _##PTR; } while(0)
#define OTP_EMTPY(ROW, LEN) esp_efuse_key_block_unused(ROW)
#endif
#ifndef SECURE_BOOT_BOOTKEY_INDEX
#define SECURE_BOOT_BOOTKEY_INDEX 0
#endif
bool otp_is_secure_boot_enabled(uint8_t *bootkey) {
#ifdef PICO_RP2350
const uint8_t *crit1 = otp_buffer(OTP_DATA_CRIT1_ROW);
if ((crit1[0] & (1 << OTP_DATA_CRIT1_SECURE_BOOT_ENABLE_LSB)) == 0) {
return false;
}
alignas(2) uint8_t BOOTKEY[] = "\xe1\xd1\x6b\xa7\x64\xab\xd7\x12\xd4\xef\x6e\x3e\xdd\x74\x4e\xd5\x63\x8c\x26\xb\x77\x1c\xf9\x81\x51\x11\xb\xaf\xac\x9b\xc8\x71";
uint8_t bootkey_idx = 0;
for (; bootkey_idx < 6; bootkey_idx++) {
const uint8_t *bootkey_row = otp_buffer(OTP_DATA_BOOTKEY0_0_ROW + 0x10 * bootkey_idx);
if (memcmp(bootkey_row, BOOTKEY, sizeof(BOOTKEY)) == 0) {
break;
}
}
if (bootkey_idx == 6) {
return false;
}
const uint8_t *boot_flags1 = otp_buffer(OTP_DATA_BOOT_FLAGS1_ROW);
if ((boot_flags1[0] & (1 << (bootkey_idx + OTP_DATA_BOOT_FLAGS1_KEY_VALID_LSB))) == 0) {
return false;
}
if (bootkey) {
*bootkey = bootkey_idx;
}
return true;
#elif defined(ESP_PLATFORM)
// TODO: Implement secure boot check for ESP32-S3
#endif
return false;
}
bool otp_is_secure_boot_locked() {
uint8_t bootkey_idx = 0xFF;
if (otp_is_secure_boot_enabled(&bootkey_idx) == false) {
return false;
}
#ifdef PICO_RP2350
const uint8_t *boot_flags1 = otp_buffer_raw(OTP_DATA_BOOT_FLAGS1_ROW);
if ((boot_flags1[1] & ((OTP_DATA_BOOT_FLAGS1_KEY_INVALID_BITS >> OTP_DATA_BOOT_FLAGS1_KEY_INVALID_LSB) & (~(1 << bootkey_idx)))) != ((OTP_DATA_BOOT_FLAGS1_KEY_INVALID_BITS >> OTP_DATA_BOOT_FLAGS1_KEY_INVALID_LSB) & (~(1 << bootkey_idx)))) {
return false;
}
const uint8_t *crit1 = otp_buffer_raw(OTP_DATA_CRIT1_ROW);
if ((crit1[0] & (1 << OTP_DATA_CRIT1_DEBUG_DISABLE_LSB)) == 0
|| (crit1[0] & (1 << OTP_DATA_CRIT1_GLITCH_DETECTOR_ENABLE_LSB)) == 0
|| ((crit1[0] & (3 << OTP_DATA_CRIT1_GLITCH_DETECTOR_SENS_LSB)) != (3 << OTP_DATA_CRIT1_GLITCH_DETECTOR_SENS_LSB))) {
return false;
}
return bootkey_idx != 0xFF;
#elif defined(ESP_PLATFORM)
// TODO: Implement secure boot lock check for ESP32-S3
#endif
return false;
}
int otp_enable_secure_boot(uint8_t bootkey, bool secure_lock) {
int ret = 0;
#ifdef PICO_RP2350
alignas(2) uint8_t BOOTKEY[] = "\xe1\xd1\x6b\xa7\x64\xab\xd7\x12\xd4\xef\x6e\x3e\xdd\x74\x4e\xd5\x63\x8c\x26\xb\x77\x1c\xf9\x81\x51\x11\xb\xaf\xac\x9b\xc8\x71";
if (is_empty_otp_buffer(OTP_DATA_BOOTKEY0_0_ROW + 0x10*bootkey, 32)) {
PICOKEY_CHECK(otp_write_data(OTP_DATA_BOOTKEY0_0_ROW + 0x10*bootkey, BOOTKEY, sizeof(BOOTKEY)));
}
const uint8_t *boot_flags1 = otp_buffer_raw(OTP_DATA_BOOT_FLAGS1_ROW);
alignas(4) uint8_t flagsb1[] = { boot_flags1[0] | (1 << (bootkey + OTP_DATA_BOOT_FLAGS1_KEY_VALID_LSB)), boot_flags1[1], boot_flags1[2], 0x00 };
if (secure_lock) {
flagsb1[1] |= ((OTP_DATA_BOOT_FLAGS1_KEY_INVALID_BITS >> OTP_DATA_BOOT_FLAGS1_KEY_INVALID_LSB) & (~(1 << bootkey)));
}
PICOKEY_CHECK(otp_write_data_raw(OTP_DATA_BOOT_FLAGS1_ROW, flagsb1, sizeof(flagsb1)));
PICOKEY_CHECK(otp_write_data_raw(OTP_DATA_BOOT_FLAGS1_R1_ROW, flagsb1, sizeof(flagsb1)));
PICOKEY_CHECK(otp_write_data_raw(OTP_DATA_BOOT_FLAGS1_R2_ROW, flagsb1, sizeof(flagsb1)));
const uint8_t *crit1 = otp_buffer_raw(OTP_DATA_CRIT1_ROW);
alignas(4) uint8_t flagsc1[] = { crit1[0] | (1 << OTP_DATA_CRIT1_SECURE_BOOT_ENABLE_LSB), crit1[1], crit1[2], 0x00 };
if (secure_lock) {
flagsc1[0] |= (1 << OTP_DATA_CRIT1_DEBUG_DISABLE_LSB);
flagsc1[0] |= (1 << OTP_DATA_CRIT1_GLITCH_DETECTOR_ENABLE_LSB);
flagsc1[0] |= (3 << OTP_DATA_CRIT1_GLITCH_DETECTOR_SENS_LSB);
}
PICOKEY_CHECK(otp_write_data_raw(OTP_DATA_CRIT1_ROW, flagsc1, sizeof(flagsc1)));
PICOKEY_CHECK(otp_write_data_raw(OTP_DATA_CRIT1_R1_ROW, flagsc1, sizeof(flagsc1)));
PICOKEY_CHECK(otp_write_data_raw(OTP_DATA_CRIT1_R2_ROW, flagsc1, sizeof(flagsc1)));
PICOKEY_CHECK(otp_write_data_raw(OTP_DATA_CRIT1_R3_ROW, flagsc1, sizeof(flagsc1)));
PICOKEY_CHECK(otp_write_data_raw(OTP_DATA_CRIT1_R4_ROW, flagsc1, sizeof(flagsc1)));
PICOKEY_CHECK(otp_write_data_raw(OTP_DATA_CRIT1_R5_ROW, flagsc1, sizeof(flagsc1)));
PICOKEY_CHECK(otp_write_data_raw(OTP_DATA_CRIT1_R6_ROW, flagsc1, sizeof(flagsc1)));
PICOKEY_CHECK(otp_write_data_raw(OTP_DATA_CRIT1_R7_ROW, flagsc1, sizeof(flagsc1)));
if (secure_lock) {
const uint8_t *page1 = otp_buffer_raw(OTP_DATA_PAGE1_LOCK1_ROW);
uint8_t page1v = page1[0] | (OTP_DATA_PAGE1_LOCK1_LOCK_BL_VALUE_READ_ONLY << OTP_DATA_PAGE1_LOCK1_LOCK_BL_LSB);
alignas(4) uint8_t flagsp1[] = { page1v, page1v, page1v, 0x00 };
PICOKEY_CHECK(otp_write_data_raw(OTP_DATA_PAGE1_LOCK1_ROW, flagsp1, sizeof(flagsp1)));
const uint8_t *page2 = otp_buffer_raw(OTP_DATA_PAGE2_LOCK1_ROW);
uint8_t page2v = page2[0] | (OTP_DATA_PAGE2_LOCK1_LOCK_BL_VALUE_READ_ONLY << OTP_DATA_PAGE2_LOCK1_LOCK_BL_LSB);
alignas(4) uint8_t flagsp2[] = { page2v, page2v, page2v, 0x00 };
PICOKEY_CHECK(otp_write_data_raw(OTP_DATA_PAGE2_LOCK1_ROW, flagsp2, sizeof(flagsp2)));
}
#elif defined(ESP_PLATFORM)
// TODO: Implement secure boot for ESP32-S3
#else
(void)bootkey;
(void)secure_lock;
#endif // PICO_RP2350
goto err;
err:
if (ret != PICOKEY_OK) {
return ret;
}
return PICOKEY_OK;
}
#ifdef PICO_RP2350
static void otp_invalidate_key(uint16_t row, uint16_t len) {
if (!is_empty_otp_buffer(row, len)) {
uint8_t *inval = (uint8_t *)calloc(len * 2, sizeof(uint8_t));
if (inval) {
memset(inval, 0xFF, len * 2);
otp_write_data_raw(row, inval, len * 2);
free(inval);
}
}
}
static otp_ret_t otp_chaff(uint16_t row, uint16_t len) {
const uint8_t *raw = otp_buffer_raw(row);
uint8_t *chaff = (uint8_t *)calloc(len * 2, sizeof(uint8_t));
if (chaff) {
memcpy(chaff, raw, len * 2);
for (int i = 0; i < len * 2; i++) {
chaff[i] ^= 0xFF;
}
otp_ret_t ret = otp_write_data_raw(row + 32, chaff, len * 2);
free(chaff);
return ret;
}
return BOOTROM_ERROR_INVALID_STATE;
}
static otp_ret_t otp_migrate_key(uint16_t new_row, uint16_t old_row, uint16_t len) {
if (is_empty_otp_buffer(new_row, len) && !is_empty_otp_buffer(old_row, len)) {
const uint8_t *key = otp_buffer(old_row);
uint8_t *new_key = (uint8_t *)calloc(len, sizeof(uint8_t));
if (new_key) {
memcpy(new_key, key, len);
otp_ret_t ret = otp_write_data(new_row, new_key, len);
if (ret == BOOTROM_OK) {
otp_chaff(new_row, len);
otp_invalidate_key(old_row, 32);
}
free(new_key);
return ret;
}
}
return BOOTROM_ERROR_INVALID_STATE;
}
void otp_migrate_chaff() {
otp_migrate_key(OTP_MKEK_ROW, OTP_OLD_MKEK_ROW, 32);
otp_migrate_key(OTP_DEVK_ROW, OTP_OLD_DEVK_ROW, 32);
otp_lock_page(OTP_MKEK_ROW >> 6);
}
#endif
void init_otp_files() {
#ifdef PICO_RP2350
otp_migrate_chaff();
#endif
#if defined(PICO_RP2350) || defined(ESP_PLATFORM)
otp_ret_t ret = 0;
uint16_t write_otp[2] = {0xFFFF, 0xFFFF};
if (OTP_EMTPY(OTP_KEY_1, 32)) {
uint8_t mkek[32] = {0};
random_gen(NULL, mkek, sizeof(mkek));
ret = OTP_WRITE(OTP_KEY_1, mkek, sizeof(mkek));
if (ret != 0) {
printf("Error writing OTP key 1 [%d]\n", ret);
}
#ifdef PICO_RP2350
otp_chaff(OTP_KEY_1, 32);
#endif
write_otp[0] = OTP_KEY_1;
}
OTP_READ(OTP_KEY_1, otp_key_1);
if (OTP_EMTPY(OTP_KEY_2, 32)) {
mbedtls_ecdsa_context ecdsa;
size_t olen = 0;
uint8_t pkey[MBEDTLS_ECP_MAX_BYTES];
while (olen != 32) {
mbedtls_ecdsa_init(&ecdsa);
mbedtls_ecp_group_id ec_id = MBEDTLS_ECP_DP_SECP256K1;
mbedtls_ecdsa_genkey(&ecdsa, ec_id, random_gen, NULL);
mbedtls_ecp_write_key_ext(&ecdsa, &olen, pkey, sizeof(pkey));
mbedtls_ecdsa_free(&ecdsa);
}
ret = OTP_WRITE(OTP_KEY_2, pkey, olen);
if (ret != 0) {
printf("Error writing OTP key 2 [%d]\n", ret);
}
mbedtls_platform_zeroize(pkey, sizeof(pkey));
#ifdef PICO_RP2350
otp_chaff(OTP_KEY_2, 32);
#endif
write_otp[1] = OTP_KEY_2;
}
OTP_READ(OTP_KEY_2, otp_key_2);
for (int i = 0; i < sizeof(write_otp)/sizeof(uint16_t); i++) {
if (write_otp[i] != 0xFFFF) {
#if defined(PICO_RP2350)
otp_lock_page(write_otp[i] >> 6);
#elif defined(ESP_PLATFORM)
ret = esp_efuse_set_key_dis_write(write_otp[i]);
if (ret != ESP_OK) {
printf("Error setting OTP key %d to read only [%d]\n", i, ret);
}
ret = esp_efuse_set_keypurpose_dis_write(write_otp[i]);
if (ret != ESP_OK) {
printf("Error setting OTP key %d purpose to read only [%d]\n", i, ret);
}
#endif
}
}
#elif defined(ENABLE_EMULATION)
static uint8_t _otp1[32] = {0}, _otp2[32] = {0};
memset(_otp1, 0xAC, sizeof(_otp1));
memset(_otp2, 0xBE, sizeof(_otp2));
otp_key_1 = _otp1;
otp_key_2 = _otp2;
#endif
}

View file

@ -1,56 +0,0 @@
/*
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
* Copyright (c) 2022 Pol Henarejos.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero 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
* Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef _OTP_H_
#define _OTP_H_
#ifdef PICO_RP2350
#define OTP_OLD_MKEK_ROW 0xEF0
#define OTP_OLD_DEVK_ROW 0xED0
#define OTP_MKEK_ROW 0xE90
#define OTP_DEVK_ROW 0xE80
#define OTP_KEY_1 OTP_MKEK_ROW
#define OTP_KEY_2 OTP_DEVK_ROW
extern const uint8_t* otp_buffer(uint16_t row);
extern const uint8_t* otp_buffer_raw(uint16_t row);
extern bool is_empty_otp_buffer(uint16_t row, uint16_t len);
extern int otp_write_data(uint16_t row, const uint8_t *data, uint16_t len);
extern int otp_write_data_raw(uint16_t row, const uint8_t *data, uint16_t len);
#elif defined(ESP_PLATFORM)
#include "esp_efuse.h"
#define OTP_KEY_1 EFUSE_BLK_KEY3
#define OTP_KEY_2 EFUSE_BLK_KEY4
#endif
extern int otp_enable_secure_boot(uint8_t bootkey, bool secure_lock);
extern void init_otp_files();
extern const uint8_t *otp_key_1;
extern const uint8_t *otp_key_2;
extern bool otp_is_secure_boot_enabled(uint8_t *bootkey);
extern bool otp_is_secure_boot_locked();
#endif // _OTP_H_

View file

@ -1,191 +0,0 @@
/*
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
* Copyright (c) 2022 Pol Henarejos.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero 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
* Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "pico_keys.h"
#include "file.h"
#include "otp.h"
#ifndef ENABLE_EMULATION
phy_data_t phy_data;
int phy_serialize_data(const phy_data_t *phy, uint8_t *data, uint16_t *len) {
if (!phy || !data || !len) {
return PICOKEY_ERR_NULL_PARAM;
}
uint8_t *p = data;
if (phy->vidpid_present) {
*p++ = PHY_VIDPID;
*p++ = 4;
*p++ = phy->vidpid[1];
*p++ = phy->vidpid[0];
*p++ = phy->vidpid[3];
*p++ = phy->vidpid[2];
}
if (phy->led_gpio_present) {
*p++ = PHY_LED_GPIO;
*p++ = 1;
*p++ = phy->led_gpio;
}
if (phy->led_brightness_present) {
*p++ = PHY_LED_BTNESS;
*p++ = 1;
*p++ = phy->led_brightness;
}
*p++ = PHY_OPTS;
*p++ = 2;
p += put_uint16_t_be(phy->opts, p);
if (phy->up_btn_present) {
*p++ = PHY_UP_BTN;
*p++ = 1;
*p++ = phy->up_btn;
}
if (phy->usb_product_present) {
*p++ = PHY_USB_PRODUCT;
*p++ = (uint8_t)strlen(phy->usb_product) + 1;
strcpy((char *)p, phy->usb_product);
p += strlen(phy->usb_product);
*p++ = '\0';
}
if (phy->enabled_curves_present) {
*p++ = PHY_ENABLED_CURVES;
*p++ = 4;
p += put_uint32_t_be(phy->enabled_curves, p);
}
if (phy->enabled_usb_itf_present) {
*p++ = PHY_ENABLED_USB_ITF;
*p++ = 1;
*p++ = phy->enabled_usb_itf;
}
if (phy->led_driver_present) {
*p++ = PHY_LED_DRIVER;
*p++ = 1;
*p++ = phy->led_driver;
}
*len = (uint8_t)(p - data);
return PICOKEY_OK;
}
int phy_unserialize_data(const uint8_t *data, uint16_t len, phy_data_t *phy) {
if (!phy || !data || !len) {
return PICOKEY_ERR_NULL_PARAM;
}
const uint8_t *p = data;
uint8_t tag, tlen;
while (p < data + len) {
tag = *p++;
tlen = *p++;
switch (tag) {
case PHY_VIDPID:
if (tlen == 4) {
memcpy(phy->vidpid, p, 4);
phy->vidpid[1] = *p++;
phy->vidpid[0] = *p++;
phy->vidpid[3] = *p++;
phy->vidpid[2] = *p++;
phy->vidpid_present = true;
}
break;
case PHY_LED_GPIO:
if (tlen == 1) {
phy->led_gpio = *p++;
phy->led_gpio_present = true;
}
break;
case PHY_LED_BTNESS:
if (tlen == 1) {
phy->led_brightness = *p++;
phy->led_brightness_present = true;
}
break;
case PHY_OPTS:
if (tlen == 2) {
phy->opts = get_uint16_t_be(p);
p += 2;
}
break;
case PHY_UP_BTN:
if (tlen == 1) {
phy->up_btn = *p++;
phy->up_btn_present = true;
}
break;
case PHY_USB_PRODUCT:
if (tlen > 0 && tlen <= sizeof(phy->usb_product)) {
memset(phy->usb_product, 0, sizeof(phy->usb_product));
strlcpy(phy->usb_product, (const char *)p, sizeof(phy->usb_product));
phy->usb_product_present = true;
p += strlen(phy->usb_product) + 1;
}
break;
case PHY_ENABLED_CURVES:
if (tlen == 4) {
phy->enabled_curves = get_uint32_t_be(p);
p += 4;
phy->enabled_curves_present = true;
}
break;
case PHY_ENABLED_USB_ITF:
if (tlen == 1) {
phy->enabled_usb_itf = *p++;
phy->enabled_usb_itf_present = true;
}
break;
case PHY_LED_DRIVER:
if (tlen == 1) {
phy->led_driver = *p++;
phy->led_driver_present = true;
}
break;
default:
p += tlen;
break;
}
}
if (!phy_data.enabled_usb_itf_present) {
phy_data.enabled_usb_itf = PHY_USB_ITF_CCID | PHY_USB_ITF_WCID | PHY_USB_ITF_HID | PHY_USB_ITF_KB;
phy_data.enabled_usb_itf_present = true;
}
return PICOKEY_OK;
}
int phy_init() {
memset(&phy_data, 0, sizeof(phy_data_t));
return phy_load();
}
int phy_save() {
uint8_t tmp[PHY_MAX_SIZE] = {0};
uint16_t tmp_len = 0;
int ret = phy_serialize_data(&phy_data, tmp, &tmp_len);
if (ret != PICOKEY_OK) {
return ret;
}
file_put_data(ef_phy, tmp, tmp_len);
low_flash_available();
return PICOKEY_OK;
}
int phy_load() {
if (file_has_data(ef_phy)) {
return phy_unserialize_data(file_get_data(ef_phy), file_get_size(ef_phy), &phy_data);
}
return PICOKEY_OK;
}
#endif

View file

@ -1,113 +0,0 @@
/*
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
* Copyright (c) 2022 Pol Henarejos.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero 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
* Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef _PHY_H_
#define _PHY_H_
#define EF_PHY 0xE020
#define PHY_VIDPID 0x0
#define PHY_LED_GPIO 0x4
#define PHY_LED_BTNESS 0x5
#define PHY_OPTS 0x6
#define PHY_UP_BTN 0x8
#define PHY_USB_PRODUCT 0x9
#define PHY_ENABLED_CURVES 0xA
#define PHY_ENABLED_USB_ITF 0xB
#define PHY_LED_DRIVER 0xC
#define PHY_OPT_WCID 0x1
#define PHY_OPT_DIMM 0x2
#define PHY_OPT_DISABLE_POWER_RESET 0x4
#define PHY_OPT_LED_STEADY 0x8
#define PHY_CURVE_SECP256R1 0x1
#define PHY_CURVE_SECP384R1 0x2
#define PHY_CURVE_SECP521R1 0x4
#define PHY_CURVE_SECP256K1 0x8
#define PHY_CURVE_BP256R1 0x10
#define PHY_CURVE_BP384R1 0x20
#define PHY_CURVE_BP512R1 0x40
#define PHY_CURVE_ED25519 0x80
#define PHY_CURVE_ED448 0x100
#define PHY_CURVE_CURVE25519 0x200
#define PHY_CURVE_CURVE448 0x400
#define PHY_USB_ITF_CCID 0x1
#define PHY_USB_ITF_WCID 0x2
#define PHY_USB_ITF_HID 0x4
#define PHY_USB_ITF_KB 0x8
#define PHY_LED_DRIVER_PICO 0x1
#define PHY_LED_DRIVER_PIMORONI 0x2
#define PHY_LED_DRIVER_WS2812 0x3
#ifdef CYW43_WL_GPIO_LED_PIN
#define PHY_LED_DRIVER_CYW43 0x4
#endif
#ifdef ESP_PLATFORM
#define PHY_LED_DRIVER_NEOPIXEL 0x5
#endif
#define PHY_LED_DRIVER_NONE 0xFF
#include <stdint.h>
#include <stdbool.h>
typedef struct phy_data {
union {
struct {
uint16_t vid;
uint16_t pid;
};
uint8_t vidpid[4];
};
uint32_t enabled_curves;
char usb_product[32];
uint16_t opts;
uint8_t led_gpio;
uint8_t led_brightness;
uint8_t up_btn;
uint8_t enabled_usb_itf;
uint8_t led_driver;
bool vidpid_present;
bool led_gpio_present;
bool led_brightness_present;
bool up_btn_present;
bool usb_product_present;
bool enabled_curves_present;
bool enabled_usb_itf_present;
bool led_driver_present;
} phy_data_t;
#define PHY_MAX_SIZE ((2+4)+(2+4)+(2+32)+(2+2)+(2+1)+(2+1)+(2+1)+(2+1)+(2+1))
#ifndef ENABLE_EMULATION
extern int phy_serialize_data(const phy_data_t *phy, uint8_t *data, uint16_t *len);
extern int phy_unserialize_data(const uint8_t *data, uint16_t len, phy_data_t *phy);
extern int phy_init();
extern int phy_save();
extern int phy_load();
extern phy_data_t phy_data;
#endif
#endif // _PHY_H_

135
src/hsm.h Normal file
View file

@ -0,0 +1,135 @@
/*
* This file is part of the Pico HSM SDK distribution (https://github.com/polhenarejos/pico-hsm-sdk).
* 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 _HSM_H_
#define _HSM_H_
#include "file.h"
#include "pico/unique_id.h"
#include <string.h>
extern int driver_init();
extern void driver_task();
extern bool wait_button();
extern void low_flash_init_core1();
extern int driver_write(const uint8_t *, size_t);
extern size_t driver_read(uint8_t *, size_t);
extern size_t usb_rx(const uint8_t *buffer, size_t len);
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;
}
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);
#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 CCID_OK 0
#define CCID_ERR_NO_MEMORY -1000
#define CCID_ERR_MEMORY_FATAL -1001
#define CCID_ERR_NULL_PARAM -1002
#define CCID_ERR_FILE_NOT_FOUND -1003
#define CCID_ERR_BLOCKED -1004
#define CCID_NO_LOGIN -1005
#define CCID_EXEC_ERROR -1006
#define CCID_WRONG_LENGTH -1007
#define CCID_WRONG_DATA -1008
#define CCID_WRONG_DKEK -1009
#define CCID_WRONG_SIGNATURE -1010
#define CCID_WRONG_PADDING -1011
#define CCID_VERIFICATION_FAILED -1012
#endif

27
src/hsm_version.h Normal file
View file

@ -0,0 +1,27 @@
/*
* This file is part of the Pico HSM SDK distribution (https://github.com/polhenarejos/pico-hsm-sdk).
* 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 __VERSION_H_
#define __VERSION_H_
#define HSM_SDK_VERSION 0x0300
#define HSM_SDK_VERSION_MAJOR ((HSM_SDK_VERSION >> 8) & 0xff)
#define HSM_SDK_VERSION_MINOR (HSM_SDK_VERSION & 0xff)
#endif

View file

@ -1,5 +0,0 @@
## IDF Component Manager Manifest File
dependencies:
espressif/esp_tinyusb: "^1.7.6"
#espressif/tinyusb: "^0.15.0"
zorxx/neopixel: "^1.0.4"

View file

@ -1,176 +0,0 @@
/*
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
* Copyright (c) 2022 Pol Henarejos.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero 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
* Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <stdlib.h>
#include "pico_keys.h"
#ifdef PICO_PLATFORM
#include "bsp/board.h"
#elif defined(ESP_PLATFORM)
#include "driver/gpio.h"
#include "esp_compat.h"
#elif defined(ENABLE_EMULATION)
#include "emulation.h"
#endif
led_driver_t *led_driver = NULL;
static uint32_t led_mode = MODE_NOT_MOUNTED;
void led_set_mode(uint32_t mode) {
led_mode = mode;
}
uint32_t led_get_mode() {
return led_mode;
}
void led_blinking_task() {
#if defined(PICO_PLATFORM) || defined(ESP_PLATFORM)
static uint32_t start_ms = 0;
static uint32_t stop_ms = 0;
static uint32_t last_led_update_ms = 0;
static uint8_t led_state = false;
uint8_t state = led_state;
#ifdef PICO_DEFAULT_LED_PIN_INVERTED
state = !state;
#endif
uint32_t led_brightness = (led_mode & LED_BTNESS_MASK) >> LED_BTNESS_SHIFT;
uint32_t led_color = (led_mode & LED_COLOR_MASK) >> LED_COLOR_SHIFT;
uint32_t led_off = (led_mode & LED_OFF_MASK) >> LED_OFF_SHIFT;
uint32_t led_on = (led_mode & LED_ON_MASK) >> LED_ON_SHIFT;
float progress = 0;
if (stop_ms > start_ms) {
progress = (float)(board_millis() - start_ms) / (stop_ms - start_ms);
}
if (!state) {
progress = 1. - progress;
}
if (phy_data.opts & PHY_OPT_LED_STEADY) {
progress = 1;
}
// limit the frequency of LED status updates
if (board_millis() - last_led_update_ms > 2) {
led_driver->set_color(led_color, led_brightness, progress);
last_led_update_ms = board_millis();
}
if (board_millis() >= stop_ms){
start_ms = stop_ms;
led_state ^= 1; // toggle
stop_ms = start_ms + (led_state ? led_on : led_off);
}
#endif
}
void led_off_all() {
#if defined(PICO_PLATFORM) || defined(ESP_PLATFORM)
led_driver->set_color(LED_COLOR_OFF, 0, 0);
#endif
}
extern led_driver_t led_driver_pico;
extern led_driver_t led_driver_cyw43;
extern led_driver_t led_driver_ws2812;
extern led_driver_t led_driver_neopixel;
extern led_driver_t led_driver_pimoroni;
void led_driver_init_dummy() {
// Do nothing
}
void led_driver_color_dummy(uint8_t color, uint32_t led_brightness, float progress) {
(void)color;
(void)led_brightness;
(void)progress;
// Do nothing
}
led_driver_t led_driver_dummy = {
.init = led_driver_init_dummy,
.set_color = led_driver_color_dummy,
};
void led_init() {
led_driver = &led_driver_dummy;
#if defined(PICO_PLATFORM) || defined(ESP_PLATFORM)
// Guess default driver
#if defined(PIMORONI_TINY2040) || defined(PIMORONI_TINY2350)
led_driver = &led_driver_pimoroni;
phy_data.led_driver = phy_data.led_driver_present ? phy_data.led_driver : PHY_LED_DRIVER_PIMORONI;
#elif defined(CYW43_WL_GPIO_LED_PIN)
led_driver = &led_driver_cyw43;
phy_data.led_driver = phy_data.led_driver_present ? phy_data.led_driver : PHY_LED_DRIVER_CYW43;
phy_data.led_gpio = phy_data.led_gpio_present ? phy_data.led_gpio : CYW43_WL_GPIO_LED_PIN;
#elif defined(PICO_DEFAULT_WS2812_PIN)
led_driver = &led_driver_ws2812;
phy_data.led_driver = phy_data.led_driver_present ? phy_data.led_driver : PHY_LED_DRIVER_WS2812;
phy_data.led_gpio = phy_data.led_gpio_present ? phy_data.led_gpio : PICO_DEFAULT_WS2812_PIN;
#elif defined(ESP_PLATFORM)
#if defined(CONFIG_IDF_TARGET_ESP32S3)
#define NEOPIXEL_PIN GPIO_NUM_48
#elif defined(CONFIG_IDF_TARGET_ESP32S2)
#define NEOPIXEL_PIN GPIO_NUM_15
#elif defined(CONFIG_IDF_TARGET_ESP32C6)
#define NEOPIXEL_PIN GPIO_NUM_8
#else
#define NEOPIXEL_PIN GPIO_NUM_27
#endif
led_driver = &led_driver_neopixel;
phy_data.led_driver = phy_data.led_driver_present ? phy_data.led_driver : PHY_LED_DRIVER_NEOPIXEL;
phy_data.led_gpio = phy_data.led_gpio_present ? phy_data.led_gpio : NEOPIXEL_PIN;
#elif defined(PICO_DEFAULT_LED_PIN)
led_driver = &led_driver_pico;
phy_data.led_driver = phy_data.led_driver_present ? phy_data.led_driver : PHY_LED_DRIVER_PICO;
phy_data.led_gpio = phy_data.led_gpio_present ? phy_data.led_gpio : PICO_DEFAULT_LED_PIN;
#endif
if (phy_data.led_driver_present) {
switch (phy_data.led_driver) {
#ifdef ESP_PLATFORM
case PHY_LED_DRIVER_NEOPIXEL:
led_driver = &led_driver_neopixel;
break;
#else
case PHY_LED_DRIVER_PICO:
led_driver = &led_driver_pico;
break;
#ifdef CYW43_WL_GPIO_LED_PIN
case PHY_LED_DRIVER_CYW43:
led_driver = &led_driver_cyw43;
break;
#endif
case PHY_LED_DRIVER_WS2812:
led_driver = &led_driver_ws2812;
break;
case PHY_LED_DRIVER_PIMORONI:
led_driver = &led_driver_pimoroni;
break;
#endif
default:
break;
}
}
phy_data.led_driver_present = true;
phy_data.led_gpio_present = true;
led_driver->init();
led_set_mode(MODE_NOT_MOUNTED);
#endif
}

View file

@ -1,77 +0,0 @@
/*
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
* Copyright (c) 2022 Pol Henarejos.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero 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
* Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef _LED_H_
#define _LED_H_
#include <stdint.h>
enum {
LED_COLOR_OFF = 0,
LED_COLOR_RED,
LED_COLOR_GREEN,
LED_COLOR_BLUE,
LED_COLOR_YELLOW,
LED_COLOR_MAGENTA,
LED_COLOR_CYAN,
LED_COLOR_WHITE
};
#define LED_OFF_BITS 12
#define LED_OFF_SHIFT 0
#define LED_OFF_MASK (((1 << LED_OFF_BITS) - 1) << LED_OFF_SHIFT)
#define LED_ON_BITS 12
#define LED_ON_SHIFT LED_OFF_BITS
#define LED_ON_MASK (((1 << LED_ON_BITS) - 1) << LED_ON_SHIFT)
#define LED_COLOR_BITS 3
#define LED_COLOR_SHIFT (LED_ON_BITS + LED_OFF_BITS)
#define LED_COLOR_MASK (((1 << LED_COLOR_BITS) - 1) << LED_COLOR_SHIFT)
#define LED_BTNESS_BITS 4
#define LED_BTNESS_SHIFT (LED_ON_BITS + LED_OFF_BITS + LED_COLOR_BITS)
#define LED_BTNESS_MASK (((1 << LED_BTNESS_BITS) - 1 ) << LED_BTNESS_SHIFT)
#define MAX_BTNESS ((1 << LED_BTNESS_BITS) - 1)
#define HALF_BTNESS ((1 << (LED_BTNESS_BITS - 1)) - 1)
// steady on
#define LED_ON_NO_BLINK ((1000 << LED_ON_SHIFT) | (0 << LED_OFF_SHIFT))
enum {
MODE_NOT_MOUNTED = (MAX_BTNESS << LED_BTNESS_SHIFT) | (LED_COLOR_RED << LED_COLOR_SHIFT) | (500 << LED_ON_SHIFT) | (500 << LED_OFF_SHIFT),
MODE_MOUNTED = (MAX_BTNESS << LED_BTNESS_SHIFT) | (LED_COLOR_GREEN << LED_COLOR_SHIFT) | (500 << LED_ON_SHIFT) | (500 << LED_OFF_SHIFT),
MODE_SUSPENDED = (MAX_BTNESS << LED_BTNESS_SHIFT) | (LED_COLOR_BLUE << LED_COLOR_SHIFT) | (1000 << LED_ON_SHIFT) | (2000 << LED_OFF_SHIFT),
MODE_PROCESSING = (MAX_BTNESS << LED_BTNESS_SHIFT) | (LED_COLOR_GREEN << LED_COLOR_SHIFT) | (50 << LED_ON_SHIFT) | (50 << LED_OFF_SHIFT),
MODE_BUTTON = (MAX_BTNESS << LED_BTNESS_SHIFT) | (LED_COLOR_YELLOW << LED_COLOR_SHIFT) | (1000 << LED_ON_SHIFT) | (100 << LED_OFF_SHIFT),
MODE_ALWAYS_ON = UINT32_MAX,
MODE_ALWAYS_OFF = 0
};
extern void led_set_mode(uint32_t mode);
extern uint32_t led_get_mode();
extern void led_blinking_task();
extern void led_off_all();
extern void led_init();
typedef struct {
void (*init)();
void (*set_color)(uint8_t color, uint32_t led_brightness, float progress);
} led_driver_t;
extern led_driver_t *led_driver;
#endif // _LED_H_

View file

@ -1,42 +0,0 @@
/*
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
* Copyright (c) 2022 Pol Henarejos.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero 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
* Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "pico_keys.h"
#ifdef CYW43_WL_GPIO_LED_PIN
#include "pico/cyw43_arch.h"
void led_driver_init_cyw43() {
cyw43_arch_init();
}
void led_driver_color_cyw43(uint8_t color, uint32_t led_brightness, float progress) {
(void)led_brightness;
uint8_t gpio = CYW43_WL_GPIO_LED_PIN;
if (phy_data.led_gpio_present) {
gpio = phy_data.led_gpio;
}
cyw43_arch_gpio_put(gpio, progress >= 0.5);
}
led_driver_t led_driver_cyw43 = {
.init = led_driver_init_cyw43,
.set_color = led_driver_color_cyw43,
};
#endif

View file

@ -1,80 +0,0 @@
/*
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
* Copyright (c) 2022 Pol Henarejos.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero 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
* Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "pico_keys.h"
#ifdef ESP_PLATFORM
#include "driver/gpio.h"
#include "neopixel.h"
tNeopixelContext neopixel = NULL;
tNeopixel pixel[] = {
{ 0, NP_RGB(0, 0, 0) }, /* off */
{ 0, NP_RGB(255, 0, 0) }, /* red */
{ 0, NP_RGB(0, 255, 0) }, /* green */
{ 0, NP_RGB(0, 0, 255) }, /* blue */
{ 0, NP_RGB(255, 255, 0) }, /* yellow */
{ 0, NP_RGB(255, 0, 255) }, /* magenta */
{ 0, NP_RGB(0, 255, 255) }, /* cyan */
{ 0, NP_RGB(255, 255, 255) }, /* white */
};
#if defined(CONFIG_IDF_TARGET_ESP32S3)
#define NEOPIXEL_PIN GPIO_NUM_48
#elif defined(CONFIG_IDF_TARGET_ESP32S2)
#define NEOPIXEL_PIN GPIO_NUM_15
#elif defined(CONFIG_IDF_TARGET_ESP32C6)
#define NEOPIXEL_PIN GPIO_NUM_8
#else
#define NEOPIXEL_PIN GPIO_NUM_27
#endif
void led_driver_init_neopixel() {
uint8_t gpio = NEOPIXEL_PIN;
if (phy_data.led_gpio_present) {
gpio = phy_data.led_gpio;
}
neopixel = neopixel_Init(1, gpio);
}
void led_driver_color_neopixel(uint8_t color, uint32_t led_brightness, float progress) {
static tNeopixel spx = {.index = 0, .rgb = 0};
if (!(phy_data.opts & PHY_OPT_DIMM)) {
progress = progress >= 0.5 ? 1 : 0;
}
uint32_t led_phy_btness = phy_data.led_brightness_present ? phy_data.led_brightness : MAX_BTNESS;
float brightness = ((float)led_brightness / MAX_BTNESS) * ((float)led_phy_btness / MAX_BTNESS) * progress;
uint32_t pixel_color = pixel[color].rgb;
uint8_t r = (pixel_color >> 16) & 0xFF;
uint8_t g = (pixel_color >> 8) & 0xFF;
uint8_t b = (pixel_color) & 0xFF;
r = (uint8_t)(r * brightness);
g = (uint8_t)(g * brightness);
b = (uint8_t)(b * brightness);
spx.rgb = NP_RGB(r, g, b);
neopixel_SetPixel(neopixel, &spx, 1);
}
led_driver_t led_driver_neopixel = {
.init = led_driver_init_neopixel,
.set_color = led_driver_color_neopixel,
};
#endif

View file

@ -1,45 +0,0 @@
/*
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
* Copyright (c) 2022 Pol Henarejos.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero 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
* Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "pico_keys.h"
#ifdef PICO_DEFAULT_LED_PIN
static uint8_t gpio = PICO_DEFAULT_LED_PIN;
#else
static uint8_t gpio = 0;
#endif
#ifdef PICO_PLATFORM
void led_driver_init_pico() {
if (phy_data.led_gpio_present) {
gpio = phy_data.led_gpio;
}
gpio_init(gpio);
gpio_set_dir(gpio, GPIO_OUT);
}
void led_driver_color_pico(uint8_t color, uint32_t led_brightness, float progress) {
(void)led_brightness;
gpio_put(gpio, progress >= 0.5);
}
led_driver_t led_driver_pico = {
.init = led_driver_init_pico,
.set_color = led_driver_color_pico,
};
#endif

View file

@ -1,64 +0,0 @@
/*
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
* Copyright (c) 2022 Pol Henarejos.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero 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
* Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "pico_keys.h"
#ifdef PICO_PLATFORM
#ifdef PICO_DEFAULT_LED_PIN
static uint8_t gpio = PICO_DEFAULT_LED_PIN;
#else
static uint8_t gpio = 0;
#endif
uint8_t pixel[][3] = {
{1, 1, 1}, // 0: off
{0, 1, 1}, // 1: red
{1, 0, 1}, // 2: green
{1, 1, 0}, // 3: blue
{0, 0, 1}, // 4: yellow
{0, 1, 0}, // 5: magenta
{1, 0, 0}, // 6: cyan
{0, 0, 0} // 7: white
};
void led_driver_init_pimoroni() {
if (phy_data.led_gpio_present) {
gpio = phy_data.led_gpio;
}
gpio_init(gpio-1);
gpio_set_dir(gpio-1, GPIO_OUT);
gpio_init(gpio);
gpio_set_dir(gpio, GPIO_OUT);
gpio_init(gpio+1);
gpio_set_dir(gpio+1, GPIO_OUT);
}
void led_driver_color_pimoroni(uint8_t color, uint32_t led_brightness, float progress) {
if (progress < 0.5) {
color = LED_COLOR_OFF;
}
gpio_put(gpio-1, pixel[color][0]);
gpio_put(gpio, pixel[color][1]);
gpio_put(gpio+1, pixel[color][2]);
}
led_driver_t led_driver_pimoroni = {
.init = led_driver_init_pimoroni,
.set_color = led_driver_color_pimoroni,
};
#endif

View file

@ -1,138 +0,0 @@
/*
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
* Copyright (c) 2022 Pol Henarejos.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero 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
* Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "pico_keys.h"
#ifdef PICO_PLATFORM
#include "hardware/pio.h"
#include "hardware/clocks.h"
#define ws2812_wrap_target 0
#define ws2812_wrap 3
#define ws2812_pio_version 0
#define ws2812_T1 3
#define ws2812_T2 3
#define ws2812_T3 4
static const uint16_t ws2812_program_instructions[] = {
// .wrap_target
0x6321, // 0: out x, 1 side 0 [3]
0x1223, // 1: jmp !x, 3 side 1 [2]
0x1200, // 2: jmp 0 side 1 [2]
0xa242, // 3: nop side 0 [2]
// .wrap
};
static const struct pio_program ws2812_program = {
.instructions = ws2812_program_instructions,
.length = 4,
.origin = -1,
.pio_version = ws2812_pio_version,
#if PICO_PIO_VERSION > 0
.used_gpio_ranges = 0x0
#endif
};
static inline pio_sm_config ws2812_program_get_default_config(uint offset) {
pio_sm_config c = pio_get_default_sm_config();
sm_config_set_wrap(&c, offset + ws2812_wrap_target, offset + ws2812_wrap);
sm_config_set_sideset(&c, 1, false, false);
return c;
}
static inline void ws2812_program_init(PIO pio, uint sm, uint offset, uint pin, float freq, bool rgbw) {
pio_gpio_init(pio, pin);
pio_sm_set_consecutive_pindirs(pio, sm, pin, 1, true);
pio_sm_config c = ws2812_program_get_default_config(offset);
sm_config_set_sideset_pins(&c, pin);
sm_config_set_out_shift(&c, false, true, rgbw ? 32 : 24);
sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_TX);
int cycles_per_bit = ws2812_T1 + ws2812_T2 + ws2812_T3;
float div = clock_get_hz(clk_sys) / (freq * cycles_per_bit);
sm_config_set_clkdiv(&c, div);
pio_sm_init(pio, sm, offset, &c);
pio_sm_set_enabled(pio, sm, true);
}
void led_driver_init_ws2812() {
PIO pio = pio0;
int sm = 0;
uint offset = pio_add_program(pio, &ws2812_program);
uint8_t gpio = 0;
#ifdef PICO_DEFAULT_WS2812_PIN
gpio = PICO_DEFAULT_WS2812_PIN;
#endif
if (phy_data.led_gpio_present) {
gpio = phy_data.led_gpio;
}
ws2812_program_init(pio, sm, offset, gpio, 800000, false);
}
struct urgb_color {
uint8_t r;
uint8_t g;
uint8_t b;
};
static struct urgb_color urgb_color_table[] = {
{0x00, 0x00, 0x00}, // 0: off LED_COLOR_OFF
{0xff, 0x00, 0x00}, // 1: red LED_COLOR_RED
{0x00, 0xff, 0x00}, // 2: green LED_COLOR_GREEN
{0x00, 0x00, 0xff}, // 3: blue LED_COLOR_BLUE
{0xff, 0xff, 0x00}, // 4: yellow LED_COLOR_YELLOW
{0xff, 0x00, 0xff}, // 5: magenta LED_COLOR_MAGENTA
{0x00, 0xff, 0xff}, // 6: cyan LED_COLOR_CYAN
{0xff, 0xff, 0xff} // 7: white LED_COLOR_WHITE
};
static inline uint32_t urgb_u32(uint8_t r, uint8_t g, uint8_t b) {
return ((uint32_t) (r) << 8) | // For GRB data ordering WS2812
((uint32_t) (g) << 16) |
(uint32_t) (b);
#if 0 // TODO: How to adapt WS2812 with different data ordering ?
return ((uint32_t)(r) << 16) | // For RGB data ordering WS2812
((uint32_t)(g) << 8) |
(uint32_t)(b);
#endif
}
static inline void ws2812_put_pixel(uint32_t u32_pixel) {
pio_sm_put_blocking(pio0, 0, u32_pixel << 8u);
}
void led_driver_color_ws2812(uint8_t color, uint32_t led_brightness, float progress) {
if (!(phy_data.opts & PHY_OPT_DIMM)) {
progress = progress >= 0.5 ? 1 : 0;
}
uint32_t led_phy_btness = phy_data.led_brightness_present ? phy_data.led_brightness : MAX_BTNESS;
float brightness = ((float)led_brightness / MAX_BTNESS) * ((float)led_phy_btness / MAX_BTNESS) * progress;
struct urgb_color pixel_color = urgb_color_table[color];
pixel_color.r = (uint8_t)(pixel_color.r * brightness);
pixel_color.g = (uint8_t)(pixel_color.g * brightness);
pixel_color.b = (uint8_t)(pixel_color.b * brightness);
ws2812_put_pixel(urgb_u32(pixel_color.r, pixel_color.g, pixel_color.b));
}
led_driver_t led_driver_ws2812 = {
.init = led_driver_init_ws2812,
.set_color = led_driver_color_ws2812,
};
#endif

View file

@ -1,225 +1,87 @@
/* /*
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk). * This file is part of the Pico HSM SDK distribution (https://github.com/polhenarejos/pico-hsm-sdk).
* Copyright (c) 2022 Pol Henarejos. * Copyright (c) 2022 Pol Henarejos.
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3. * the Free Software Foundation, version 3.
* *
* This program is distributed in the hope that it will be useful, but * This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of * WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Affero General Public License for more details. * General Public License for more details.
* *
* You should have received a copy of the GNU Affero General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <stdio.h> #include <stdio.h>
#include <stdlib.h>
#include "pico_keys.h"
#if !defined(ENABLE_EMULATION) // Pico
#include "tusb.h"
#endif
#if defined(ENABLE_EMULATION)
#include "emulation.h"
#elif defined(ESP_PLATFORM)
#include "driver/gpio.h"
#include "rom/gpio.h"
#include "tinyusb.h"
#include "esp_efuse.h"
#define BOOT_PIN GPIO_NUM_0
#elif defined(PICO_PLATFORM)
#include "pico/stdlib.h" #include "pico/stdlib.h"
#include "bsp/board.h"
#include "pico/aon_timer.h"
#include "hardware/gpio.h"
#include "hardware/sync.h"
#include "hardware/structs/ioqspi.h"
#include "hardware/structs/sio.h"
#endif
// For memcpy
#include <string.h>
// Include descriptor struct definitions
//#include "usb_common.h"
// USB register definitions from pico-sdk
#include "hardware/regs/usb.h"
// USB hardware struct definitions from pico-sdk
#include "hardware/structs/usb.h"
// For interrupt enable and numbers
#include "hardware/irq.h"
// For resetting the USB controller
#include "hardware/resets.h"
#include "pico/multicore.h"
#include "random.h" #include "random.h"
#include "hsm.h"
#include "apdu.h" #include "apdu.h"
#include "usb.h" #include "usb.h"
#include "mbedtls/sha256.h" #include "hardware/rtc.h"
#include "bsp/board.h"
extern void do_flash(); extern void do_flash();
extern void low_flash_init(); extern void low_flash_init();
extern void init_otp_files();
app_t apps[16]; app_t apps[4];
uint8_t num_apps = 0; uint8_t num_apps = 0;
app_t *current_app = NULL; app_t *current_app = NULL;
const uint8_t *ccid_atr = NULL; int register_app(app_t * (*select_aid)()) {
if (num_apps < sizeof(apps)/sizeof(app_t)) {
bool app_exists(const uint8_t *aid, size_t aid_len) {
for (int a = 0; a < num_apps; a++) {
if (aid_len >= apps[a].aid[0] && !memcmp(apps[a].aid + 1, aid, apps[a].aid[0])) {
return true;
}
}
return false;
}
int register_app(int (*select_aid)(app_t *, uint8_t), const uint8_t *aid) {
if (app_exists(aid + 1, aid[0])) {
return 1;
}
if (num_apps < sizeof(apps) / sizeof(app_t)) {
apps[num_apps].select_aid = select_aid; apps[num_apps].select_aid = select_aid;
apps[num_apps].aid = aid;
num_apps++; num_apps++;
return 1; return 1;
} }
return 0; return 0;
} }
int select_app(const uint8_t *aid, size_t aid_len) { static uint32_t blink_interval_ms = BLINK_NOT_MOUNTED;
if (current_app && current_app->aid && (current_app->aid + 1 == aid || (aid_len >= current_app->aid[0] && !memcmp(current_app->aid + 1, aid, current_app->aid[0])))) {
current_app->select_aid(current_app, 0);
return PICOKEY_OK;
}
for (int a = 0; a < num_apps; a++) {
if (aid_len >= apps[a].aid[0] && !memcmp(apps[a].aid + 1, aid, apps[a].aid[0])) {
if (current_app) {
if (current_app->aid && aid_len >= current_app->aid[0] && !memcmp(current_app->aid + 1, aid, current_app->aid[0])) {
current_app->select_aid(current_app, 1);
return PICOKEY_OK;
}
if (current_app->unload) {
current_app->unload();
}
}
current_app = &apps[a];
if (current_app->select_aid(current_app, 1) == PICOKEY_OK) {
return PICOKEY_OK;
}
}
}
return PICOKEY_ERR_FILE_NOT_FOUND;
}
int (*button_pressed_cb)(uint8_t) = NULL; void led_set_blink(uint32_t mode) {
blink_interval_ms = mode;
}
void execute_tasks(); void execute_tasks();
static bool req_button_pending = false;
bool is_req_button_pending() {
return req_button_pending;
}
bool cancel_button = false;
#ifdef _MSC_VER
#include <windows.h>
struct timezone
{
__int32 tz_minuteswest; /* minutes W of Greenwich */
bool tz_dsttime; /* type of dst correction */
};
int gettimeofday(struct timeval* tp, struct timezone* tzp)
{
(void)tzp;
// Note: some broken versions only have 8 trailing zero's, the correct epoch has 9 trailing zero's
// This magic number is the number of 100 nanosecond intervals since January 1, 1601 (UTC)
// until 00:00:00 January 1, 1970
static const uint64_t EPOCH = ((uint64_t)116444736000000000ULL);
SYSTEMTIME system_time;
FILETIME file_time;
uint64_t time;
GetSystemTime(&system_time);
SystemTimeToFileTime(&system_time, &file_time);
time = ((uint64_t)file_time.dwLowDateTime);
time += ((uint64_t)file_time.dwHighDateTime) << 32;
tp->tv_sec = (long)((time - EPOCH) / 10000000L);
tp->tv_usec = (long)(system_time.wMilliseconds * 1000);
return 0;
}
#endif
#if !defined(ENABLE_EMULATION)
#ifdef ESP_PLATFORM
bool picok_board_button_read() {
int boot_state = gpio_get_level(BOOT_PIN);
return boot_state == 0;
}
#elif defined(PICO_PLATFORM)
bool __no_inline_not_in_flash_func(picok_get_bootsel_button)() {
const uint CS_PIN_INDEX = 1;
// Must disable interrupts, as interrupt handlers may be in flash, and we
// are about to temporarily disable flash access!
uint32_t flags = save_and_disable_interrupts();
// Set chip select to Hi-Z
hw_write_masked(&ioqspi_hw->io[CS_PIN_INDEX].ctrl,
GPIO_OVERRIDE_LOW << IO_QSPI_GPIO_QSPI_SS_CTRL_OEOVER_LSB,
IO_QSPI_GPIO_QSPI_SS_CTRL_OEOVER_BITS);
// Note we can't call into any sleep functions in flash right now
for (volatile int i = 0; i < 1000; ++i);
// The HI GPIO registers in SIO can observe and control the 6 QSPI pins.
// Note the button pulls the pin *low* when pressed.
#if PICO_RP2040
#define CS_BIT (1u << 1)
#else
#define CS_BIT SIO_GPIO_HI_IN_QSPI_CSN_BITS
#endif
bool button_state = !(sio_hw->gpio_hi_in & CS_BIT);
// Need to restore the state of chip select, else we are going to have a
// bad time when we return to code in flash!
hw_write_masked(&ioqspi_hw->io[CS_PIN_INDEX].ctrl,
GPIO_OVERRIDE_NORMAL << IO_QSPI_GPIO_QSPI_SS_CTRL_OEOVER_LSB,
IO_QSPI_GPIO_QSPI_SS_CTRL_OEOVER_BITS);
restore_interrupts(flags);
return button_state;
}
bool picok_board_button_read(void) {
return picok_get_bootsel_button();
}
#else
bool picok_board_button_read(void) {
return true; // always unpressed
}
#endif
bool button_pressed_state = false;
uint32_t button_pressed_time = 0;
uint8_t button_press = 0;
bool wait_button() { bool wait_button() {
uint32_t button_timeout = 15000;
if (phy_data.up_btn_present) {
button_timeout = phy_data.up_btn * 1000;
if (button_timeout == 0) {
return false;
}
}
uint32_t start_button = board_millis(); uint32_t start_button = board_millis();
bool timeout = false; bool timeout = false;
cancel_button = false; led_set_blink((1000 << 16) | 100);
uint32_t led_mode = led_get_mode();
led_set_mode(MODE_BUTTON); while (board_button_read() == false) {
req_button_pending = true;
while (picok_board_button_read() == false && cancel_button == false) {
execute_tasks(); execute_tasks();
//sleep_ms(10); //sleep_ms(10);
if (start_button + button_timeout < board_millis()) { /* timeout */ if (start_button + 15000 < board_millis()) { /* timeout */
timeout = true; timeout = true;
break; break;
} }
} }
if (!timeout) { if (!timeout) {
while (picok_board_button_read() == true && cancel_button == false) { while (board_button_read() == true) {
execute_tasks(); execute_tasks();
//sleep_ms(10); //sleep_ms(10);
if (start_button + 15000 < board_millis()) { /* timeout */ if (start_button + 15000 < board_millis()) { /* timeout */
@ -228,144 +90,110 @@ bool wait_button() {
} }
} }
} }
led_set_mode(led_mode); led_set_blink(BLINK_PROCESSING);
req_button_pending = false; return timeout;
return timeout || cancel_button;
} }
#endif
struct apdu apdu; struct apdu apdu;
void init_rtc() { void led_blinking_task() {
#ifdef PICO_PLATFORM #ifdef PICO_DEFAULT_LED_PIN
struct timespec tv = {0}; static uint32_t start_ms = 0;
tv.tv_sec = 1577836800; // 2020-01-01 static uint8_t led_state = false;
aon_timer_start(&tv); static uint8_t led_color = PICO_DEFAULT_LED_PIN;
#ifdef PICO_DEFAULT_LED_PIN_INVERTED
uint32_t interval = !led_state ? blink_interval_ms & 0xffff : blink_interval_ms >> 16;
#else
uint32_t interval = led_state ? blink_interval_ms & 0xffff : blink_interval_ms >> 16;
#endif #endif
// Blink every interval ms
if (board_millis() - start_ms < interval)
return; // not enough time
start_ms += interval;
gpio_put(led_color, led_state);
led_state ^= 1; // toggle
#endif
}
void led_off_all() {
#ifdef PIMORONI_TINY2040
gpio_put(TINY2040_LED_R_PIN, 1);
gpio_put(TINY2040_LED_G_PIN, 1);
gpio_put(TINY2040_LED_B_PIN, 1);
#else
#ifdef PICO_DEFAULT_LED_PIN
gpio_put(PICO_DEFAULT_LED_PIN, 0);
#endif
#endif
}
void init_rtc() {
rtc_init();
datetime_t dt = {
.year = 2020,
.month = 1,
.day = 1,
.dotw = 3, // 0 is Sunday, so 5 is Friday
.hour = 00,
.min = 00,
.sec = 00
};
rtc_set_datetime(&dt);
} }
extern void neug_task(); extern void neug_task();
extern void usb_task();
void execute_tasks() pico_unique_board_id_t unique_id;
{
#if !defined(ENABLE_EMULATION) && !defined(ESP_PLATFORM) void execute_tasks() {
tud_task(); // tinyusb device task
#endif
usb_task(); usb_task();
tud_task(); // tinyusb device task
led_blinking_task(); led_blinking_task();
} }
void core0_loop() { int main(void) {
usb_init();
board_init();
stdio_init_all();
#ifdef PIMORONI_TINY2040
gpio_init(TINY2040_LED_R_PIN);
gpio_set_dir(TINY2040_LED_R_PIN, GPIO_OUT);
gpio_init(TINY2040_LED_G_PIN);
gpio_set_dir(TINY2040_LED_G_PIN, GPIO_OUT);
gpio_init(TINY2040_LED_B_PIN);
gpio_set_dir(TINY2040_LED_B_PIN, GPIO_OUT);
#else
#ifdef PICO_DEFAULT_LED_PIN
gpio_init(PICO_DEFAULT_LED_PIN);
gpio_set_dir(PICO_DEFAULT_LED_PIN, GPIO_OUT);
#endif
#endif
led_off_all();
tusb_init();
//prepare_ccid();
random_init();
low_flash_init();
init_rtc();
//ccid_prepare_receive(&ccid);
while (1) { while (1) {
execute_tasks(); execute_tasks();
neug_task(); neug_task();
do_flash(); do_flash();
#ifndef ENABLE_EMULATION
if (button_pressed_cb && board_millis() > 1000 && !is_busy()) { // wait 1 second to boot up
bool current_button_state = picok_board_button_read();
if (current_button_state != button_pressed_state) {
if (current_button_state == false) { // unpressed
if (button_pressed_time == 0 || button_pressed_time + 1000 > board_millis()) {
button_press++;
}
button_pressed_time = board_millis();
}
button_pressed_state = current_button_state;
}
if (button_pressed_time > 0 && button_press > 0 && button_pressed_time + 1000 < board_millis() && button_pressed_state == false) {
if (button_pressed_cb != NULL) {
(*button_pressed_cb)(button_press);
}
button_pressed_time = button_press = 0;
}
}
#endif
#ifdef ESP_PLATFORM
vTaskDelay(pdMS_TO_TICKS(10));
#endif
} }
}
char pico_serial_str[2 * PICO_UNIQUE_BOARD_ID_SIZE_BYTES + 1];
uint8_t pico_serial_hash[32];
pico_unique_board_id_t pico_serial;
#ifdef ESP_PLATFORM
#define pico_get_unique_board_id(a) do { uint32_t value; esp_efuse_read_block(EFUSE_BLK1, &value, 0, 32); memcpy((uint8_t *)(a), &value, sizeof(uint32_t)); esp_efuse_read_block(EFUSE_BLK1, &value, 32, 32); memcpy((uint8_t *)(a)+4, &value, sizeof(uint32_t)); } while(0)
extern tinyusb_config_t tusb_cfg;
extern const uint8_t desc_config[];
TaskHandle_t hcore0 = NULL, hcore1 = NULL;
int app_main() {
#else
#ifndef PICO_PLATFORM
#define pico_get_unique_board_id(a) memset(a, 0, sizeof(*(a)))
#endif
int main(void) {
#endif
pico_get_unique_board_id(&pico_serial);
memset(pico_serial_str, 0, sizeof(pico_serial_str));
for (size_t i = 0; i < sizeof(pico_serial); i++) {
snprintf(&pico_serial_str[2 * i], 3, "%02X", pico_serial.id[i]);
}
mbedtls_sha256(pico_serial.id, sizeof(pico_serial.id), pico_serial_hash, false);
#ifndef ENABLE_EMULATION
#ifdef PICO_PLATFORM
board_init();
stdio_init_all();
#endif
#else
emul_init("127.0.0.1", 35963);
#endif
random_init();
init_otp_files();
low_flash_init();
scan_flash();
init_rtc();
#ifndef ENABLE_EMULATION
phy_init();
#endif
led_init();
usb_init();
#ifndef ENABLE_EMULATION
#ifdef ESP_PLATFORM
gpio_pad_select_gpio(BOOT_PIN);
gpio_set_direction(BOOT_PIN, GPIO_MODE_INPUT);
gpio_pulldown_dis(BOOT_PIN);
tusb_cfg.string_descriptor[3] = pico_serial_str;
if (phy_data.usb_product_present) {
tusb_cfg.string_descriptor[2] = phy_data.usb_product;
}
static char tmps[4][32];
for (int i = 4; i < tusb_cfg.string_descriptor_count; i++) {
strlcpy(tmps[i-4], tusb_cfg.string_descriptor[2], sizeof(tmps[0]));
strlcat(tmps[i-4], " ", sizeof(tmps[0]));
strlcat(tmps[i-4], tusb_cfg.string_descriptor[i], sizeof(tmps[0]));
tusb_cfg.string_descriptor[i] = tmps[i-4];
}
tusb_cfg.configuration_descriptor = desc_config;
tinyusb_driver_install(&tusb_cfg);
#else
tusb_init();
#endif
#endif
#ifdef ESP_PLATFORM
xTaskCreatePinnedToCore(core0_loop, "core0", 4096*ITF_TOTAL*2, NULL, CONFIG_TINYUSB_TASK_PRIORITY - 1, &hcore0, ESP32_CORE0);
#else
core0_loop();
#endif
return 0; return 0;
} }

View file

@ -1,243 +0,0 @@
/*
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
* Copyright (c) 2022 Pol Henarejos.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero 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
* Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef _PICO_KEYS_H_
#define _PICO_KEYS_H_
#if defined(PICO_RP2040) || defined(PICO_RP2350)
#define PICO_PLATFORM
#endif
#include "file.h"
#include "led/led.h"
#include <stdint.h>
#if !defined(MIN)
#if defined(_MSC_VER)
#define MIN(a,b) (((a)<(b))?(a):(b))
#else
#define MIN(a, b) \
({ __typeof__ (a) _a = (a); \
__typeof__ (b) _b = (b); \
_a < _b ? _a : _b; })
#endif
#endif
#if !defined(MAX)
#if defined(_MSC_VER)
#define MAX(a,b) (((a)>(b))?(a):(b))
#else
#define MAX(a, b) \
({ __typeof__ (a) _a = (a); \
__typeof__ (b) _b = (b); \
_a > _b ? _a : _b; })
#endif
#endif
#if defined(PICO_PLATFORM)
#include "pico/unique_id.h"
#endif
#include <string.h>
#include "debug.h"
#if defined(ENABLE_EMULATION)
#include <stdbool.h>
#elif defined(ESP_PLATFORM)
#include "esp_compat.h"
#elif defined(PICO_PLATFORM)
#include "pico/util/queue.h"
#endif
extern bool wait_button();
extern void low_flash_init_core1();
static inline uint16_t make_uint16_t_be(uint8_t b1, uint8_t b2) {
return (b1 << 8) | b2;
}
static inline uint16_t make_uint16_t_le(uint8_t b1, uint8_t b2) {
return (b2 << 8) | b1;
}
static inline uint16_t get_uint16_t_be(const uint8_t *b) {
return make_uint16_t_be(b[0], b[1]);
}
static inline uint16_t get_uint16_t_le(const uint8_t *b) {
return make_uint16_t_le(b[0], b[1]);
}
static inline uint8_t put_uint16_t_be(uint16_t n, uint8_t *b) {
*b++ = (n >> 8) & 0xff;
*b = n & 0xff;
return 2;
}
static inline uint8_t put_uint16_t_le(uint16_t n, uint8_t *b) {
*b++ = n & 0xff;
*b = (n >> 8) & 0xff;
return 2;
}
static inline uint32_t make_uint32_t_be(uint8_t b1, uint8_t b2, uint8_t b3, uint8_t b4) {
return (b1 << 24) | (b2 << 16) | (b3 << 8) | b4;
}
static inline uint32_t make_uint32_t_le(uint8_t b1, uint8_t b2, uint8_t b3, uint8_t b4) {
return (b4 << 24) | (b3 << 16) | (b2 << 8) | b1;
}
static inline uint32_t get_uint32_t_be(const uint8_t *b) {
return make_uint32_t_be(b[0], b[1], b[2], b[3]);
}
static inline uint32_t get_uint32_t_le(const uint8_t *b) {
return make_uint32_t_le(b[0], b[1], b[2], b[3]);
}
static inline uint32_t put_uint32_t_be(uint32_t n, uint8_t *b) {
*b++ = (n >> 24) & 0xff;
*b++ = (n >> 16) & 0xff;
*b++ = (n >> 8) & 0xff;
*b = n & 0xff;
return 4;
}
static inline uint32_t put_uint32_t_le(uint32_t n, uint8_t *b) {
*b++ = n & 0xff;
*b++ = (n >> 8) & 0xff;
*b++ = (n >> 16) & 0xff;
*b = (n >> 24) & 0xff;
return 4;
}
static inline uint64_t make_uint64_t_be(uint8_t b1, uint8_t b2, uint8_t b3, uint8_t b4, uint8_t b5, uint8_t b6, uint8_t b7, uint8_t b8) {
return ((uint64_t) b1 << 56) | ((uint64_t) b2 << 48) | ((uint64_t) b3 << 40) | ((uint64_t) b4 << 32) | ((uint64_t) b5 << 24) | ((uint64_t) b6 << 16) | ((uint64_t) b7 << 8) | b8;
}
static inline uint64_t make_uint64_t_le(uint8_t b1, uint8_t b2, uint8_t b3, uint8_t b4, uint8_t b5, uint8_t b6, uint8_t b7, uint8_t b8) {
return ((uint64_t) b8 << 56) | ((uint64_t) b7 << 48) | ((uint64_t) b6 << 40) | ((uint64_t) b5 << 32) | ((uint64_t) b4 << 24) | ((uint64_t) b3 << 16) | ((uint64_t) b2 << 8) | b1;
}
static inline uint64_t get_uint64_t_be(const uint8_t *b) {
return make_uint64_t_be(b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]);
}
static inline uint64_t get_uint64_t_le(const uint8_t *b) {
return make_uint64_t_le(b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]);
}
static inline uint32_t put_uint64_t_be(uint64_t n, uint8_t *b) {
*b++ = (n >> 56) & 0xff;
*b++ = (n >> 48) & 0xff;
*b++ = (n >> 40) & 0xff;
*b++ = (n >> 32) & 0xff;
*b++ = (n >> 24) & 0xff;
*b++ = (n >> 16) & 0xff;
*b++ = (n >> 8) & 0xff;
*b = n & 0xff;
return 8;
}
static inline uint32_t put_uint64_t_le(uint64_t n, uint8_t *b) {
*b++ = n & 0xff;
*b++ = (n >> 8) & 0xff;
*b++ = (n >> 16) & 0xff;
*b++ = (n >> 24) & 0xff;
*b++ = (n >> 32) & 0xff;
*b++ = (n >> 40) & 0xff;
*b++ = (n >> 48) & 0xff;
*b = (n >> 56) & 0xff;
return 8;
}
extern void low_flash_available();
extern int flash_clear_file(file_t *file);
extern int (*button_pressed_cb)(uint8_t);
extern bool is_req_button_pending();
#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 PICOKEY_OK 0
#define PICOKEY_ERR_NO_MEMORY -1000
#define PICOKEY_ERR_MEMORY_FATAL -1001
#define PICOKEY_ERR_NULL_PARAM -1002
#define PICOKEY_ERR_FILE_NOT_FOUND -1003
#define PICOKEY_ERR_BLOCKED -1004
#define PICOKEY_NO_LOGIN -1005
#define PICOKEY_EXEC_ERROR -1006
#define PICOKEY_WRONG_LENGTH -1007
#define PICOKEY_WRONG_DATA -1008
#define PICOKEY_WRONG_DKEK -1009
#define PICOKEY_WRONG_SIGNATURE -1010
#define PICOKEY_WRONG_PADDING -1011
#define PICOKEY_VERIFICATION_FAILED -1012
#define PICOKEY_CHECK(x) do { ret = (x); if (ret != PICOKEY_OK) goto err; } while (0)
#if !defined (PICO_PLATFORM)
#define PICO_UNIQUE_BOARD_ID_SIZE_BYTES 8
typedef struct { uint8_t id[PICO_UNIQUE_BOARD_ID_SIZE_BYTES]; } pico_unique_board_id_t;
#endif
extern pico_unique_board_id_t pico_serial;
extern char pico_serial_str[2 * PICO_UNIQUE_BOARD_ID_SIZE_BYTES + 1];
extern uint8_t pico_serial_hash[32];
#if defined(PICO_PLATFORM)
#define multicore_launch_func_core1(a) multicore_launch_core1((void (*) (void))a)
#endif
#endif

View file

@ -1,26 +0,0 @@
/*
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
* Copyright (c) 2022 Pol Henarejos.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero 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
* Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef __VERSION_H_
#define __VERSION_H_
#define PICO_KEYS_SDK_VERSION 0x0800
#define PICO_KEYS_SDK_VERSION_MAJOR ((PICO_KEYS_SDK_VERSION >> 8) & 0xff)
#define PICO_KEYS_SDK_VERSION_MINOR (PICO_KEYS_SDK_VERSION & 0xff)
#endif

View file

@ -1,113 +0,0 @@
/*
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
* Copyright (c) 2022 Pol Henarejos.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero 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
* Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifdef _MSC_VER
#ifndef _PTHREAD_H_
#define _PTHREAD_H_
#include <windows.h>
#include <stdint.h>
typedef HANDLE pthread_t;
typedef CRITICAL_SECTION pthread_mutex_t;
typedef struct {
CONDITION_VARIABLE cond;
} pthread_cond_t;
// Mutex
static inline int pthread_mutex_init(pthread_mutex_t *m, void *a) {
(void)a;
InitializeCriticalSection(m);
return 0;
}
static inline int pthread_mutex_lock(pthread_mutex_t *m) {
EnterCriticalSection(m);
return 0;
}
static inline int pthread_mutex_unlock(pthread_mutex_t *m) {
LeaveCriticalSection(m);
return 0;
}
static inline int pthread_mutex_destroy(pthread_mutex_t *m) {
DeleteCriticalSection(m);
return 0;
}
// Thread
static DWORD WINAPI thread_entry(LPVOID param) {
void **args = (void **)param;
void *(*fn)(void *) = (void *(*)(void *))(uintptr_t)args[0];
void *arg = args[1];
fn(arg);
free(param);
return 0;
}
static inline int pthread_create(pthread_t *t, void *a, void *(*fn)(void *), void *arg) {
(void)a;
void **params = malloc(2 * sizeof(void *));
if (!params) return -1;
params[0] = (void *)(uintptr_t)fn;
params[1] = arg;
*t = CreateThread(NULL, 0, thread_entry, params, 0, NULL);
return *t ? 0 : -1;
}
static inline int pthread_join(pthread_t t, void **ret) {
WaitForSingleObject(t, INFINITE);
CloseHandle(t);
if (ret) *ret = NULL;
return 0;
}
// Condition variable
static inline int pthread_cond_init(pthread_cond_t *c, void *a) {
(void)a;
InitializeConditionVariable(&c->cond);
return 0;
}
static inline int pthread_cond_destroy(pthread_cond_t *c) {
(void)c;
return 0;
}
static inline int pthread_cond_wait(pthread_cond_t *c, pthread_mutex_t *m) {
SleepConditionVariableCS(&c->cond, m, INFINITE);
return 0;
}
static inline int pthread_cond_signal(pthread_cond_t *c) {
WakeConditionVariable(&c->cond);
return 0;
}
static inline int pthread_cond_broadcast(pthread_cond_t *c) {
WakeAllConditionVariable(&c->cond);
return 0;
}
static inline int pthread_mutex_trylock(pthread_mutex_t *m){
return TryEnterCriticalSection(m) ? 0 : EBUSY;
}
#endif // _PTHREAD_H_
#endif // _MSC_VER

View file

@ -1,132 +0,0 @@
/*
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
* Copyright (c) 2022 Pol Henarejos.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero 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
* Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef QUEUE_H
#define QUEUE_H
#ifdef _MSC_VER
#include "pthread_win32.h"
#include "semaphore_win32.h"
#else
#include <pthread.h>
#include <semaphore.h>
#endif
#include <stdbool.h>
typedef struct {
pthread_mutex_t mtx;
pthread_cond_t cnd;
size_t size_elem;
size_t num_elem;
size_t max_elem;
uint8_t buf[1024];
bool is_init;
} queue_t;
static inline void queue_free(queue_t *a) {
pthread_mutex_destroy(&a->mtx);
pthread_cond_destroy(&a->cnd);
a->is_init = false;
}
static inline void queue_init(queue_t *a, size_t size_elem, size_t max_elem) {
if (a->is_init) {
queue_free(a);
}
pthread_mutex_init(&a->mtx, NULL);
pthread_cond_init(&a->cnd, NULL);
a->size_elem = size_elem;
a->max_elem = max_elem;
a->num_elem = 0;
a->is_init = true;
}
static inline void queue_add_blocking(queue_t *a, const void *b) {
pthread_mutex_lock(&a->mtx);
while (a->num_elem == a->max_elem) {
pthread_cond_wait(&a->cnd, &a->mtx);
}
memcpy(a->buf + a->num_elem * a->size_elem, b, a->size_elem);
a->num_elem++;
pthread_cond_signal(&a->cnd);
pthread_mutex_unlock(&a->mtx);
}
static inline void queue_remove_blocking(queue_t *a, void *b) {
pthread_mutex_lock(&a->mtx);
while (a->num_elem == 0) {
pthread_cond_wait(&a->cnd, &a->mtx);
}
memcpy(b, a->buf, a->size_elem);
memmove(a->buf, a->buf + a->size_elem, a->size_elem * (a->num_elem - 1));
a->num_elem--;
pthread_cond_signal(&a->cnd);
pthread_mutex_unlock(&a->mtx);
}
static inline int queue_try_add(queue_t *a, const void *b) {
pthread_mutex_lock(&a->mtx);
if (a->num_elem == a->max_elem) {
pthread_mutex_unlock(&a->mtx);
return 0;
}
memcpy(a->buf + a->num_elem * a->size_elem, b, a->size_elem);
a->num_elem++;
pthread_cond_signal(&a->cnd);
pthread_mutex_unlock(&a->mtx);
return 1;
}
static inline int queue_try_remove(queue_t *a, void *b) {
pthread_mutex_lock(&a->mtx);
if (a->num_elem == 0) {
pthread_mutex_unlock(&a->mtx);
return 0;
}
memcpy(b, a->buf, a->size_elem);
memmove(a->buf, a->buf + a->size_elem, a->size_elem * (a->num_elem - 1));
a->num_elem--;
pthread_cond_signal(&a->cnd);
pthread_mutex_unlock(&a->mtx);
return 1;
}
static inline int queue_is_empty(queue_t *a) {
pthread_mutex_lock(&a->mtx);
bool ret = a->num_elem == 0;
pthread_mutex_unlock(&a->mtx);
return ret;
}
static inline int queue_is_full(queue_t *a) {
pthread_mutex_lock(&a->mtx);
bool ret = a->num_elem == a->max_elem;
pthread_mutex_unlock(&a->mtx);
return ret;
}
static inline void queue_clear(queue_t *a) {
pthread_mutex_lock(&a->mtx);
a->num_elem = 0;
pthread_mutex_unlock(&a->mtx);
}
extern pthread_t hcore0, hcore1;
#define multicore_launch_func_core1(a) pthread_create(&hcore1, NULL, (void *(*) (void *))a, NULL)
#define multicore_reset_core1()
typedef pthread_mutex_t mutex_t;
typedef sem_t semaphore_t;
#define mutex_init(a) pthread_mutex_init(a, NULL)
#define mutex_try_enter(a,b) (pthread_mutex_trylock(a) == 0)
#define mutex_enter_blocking(a) pthread_mutex_lock(a)
#define mutex_exit(a) pthread_mutex_unlock(a)
#define sem_release(a) sem_post(a)
#define sem_acquire_blocking(a) sem_wait(a)
#define multicore_lockout_victim_init() (void)0
#endif // QUEUE_H

View file

@ -1,284 +0,0 @@
/*
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
* Copyright (c) 2022 Pol Henarejos.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero 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
* Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "pico_keys.h"
#include "apdu.h"
#include "pico_keys_version.h"
#include "otp.h"
#ifdef PICO_PLATFORM
#include "pico/bootrom.h"
#include "hardware/watchdog.h"
#endif
#include "mbedtls/ecdsa.h"
#include "mbedtls/sha256.h"
#include "random.h"
int rescue_process_apdu();
int rescue_unload();
const uint8_t rescue_aid[] = {
8,
0xA0, 0x58, 0x3F, 0xC1, 0x9B, 0x7E, 0x4F, 0x21
};
#ifdef PICO_RP2350
#define PICO_MCU 1
#elif defined(ESP_PLATFORM)
#define PICO_MCU 2
#elif defined(ENABLE_EMULATION)
#define PICO_MCU 3
#else
#define PICO_MCU 0
#endif
extern uint8_t PICO_PRODUCT;
extern uint8_t PICO_VERSION_MAJOR;
extern uint8_t PICO_VERSION_MINOR;
int rescue_select(app_t *a, uint8_t force) {
a->process_apdu = rescue_process_apdu;
a->unload = rescue_unload;
res_APDU_size = 0;
res_APDU[res_APDU_size++] = PICO_MCU;
res_APDU[res_APDU_size++] = PICO_PRODUCT;
res_APDU[res_APDU_size++] = PICO_VERSION_MAJOR;
res_APDU[res_APDU_size++] = PICO_VERSION_MINOR;
memcpy(res_APDU + res_APDU_size, pico_serial.id, sizeof(pico_serial.id));
res_APDU_size += sizeof(pico_serial.id);
apdu.ne = res_APDU_size;
if (force) {
scan_flash();
}
return PICOKEY_OK;
}
INITIALIZER ( rescue_ctor ) {
register_app(rescue_select, rescue_aid);
}
int rescue_unload() {
return PICOKEY_OK;
}
int cmd_keydev_sign() {
uint8_t p1 = P1(apdu);
if (p1 == 0x01) {
if (apdu.nc != 32) {
return SW_WRONG_LENGTH();
}
if (!otp_key_2) {
return SW_INS_NOT_SUPPORTED();
}
mbedtls_ecdsa_context ecdsa;
mbedtls_ecdsa_init(&ecdsa);
int ret = mbedtls_ecp_read_key(MBEDTLS_ECP_DP_SECP256K1, &ecdsa, otp_key_2, 32);
if (ret != 0) {
mbedtls_ecdsa_free(&ecdsa);
return SW_EXEC_ERROR();
}
uint16_t key_size = 2 * (int)((mbedtls_ecp_curve_info_from_grp_id(MBEDTLS_ECP_DP_SECP256K1)->bit_size + 7) / 8);
mbedtls_mpi r, s;
mbedtls_mpi_init(&r);
mbedtls_mpi_init(&s);
ret = mbedtls_ecdsa_sign(&ecdsa.MBEDTLS_PRIVATE(grp), &r, &s, &ecdsa.MBEDTLS_PRIVATE(d), apdu.data, apdu.nc, random_gen, NULL);
if (ret != 0) {
mbedtls_ecdsa_free(&ecdsa);
mbedtls_mpi_free(&r);
mbedtls_mpi_free(&s);
return SW_EXEC_ERROR();
}
mbedtls_mpi_write_binary(&r, res_APDU, key_size / 2); res_APDU_size = key_size / 2;
mbedtls_mpi_write_binary(&s, res_APDU + res_APDU_size, key_size / 2); res_APDU_size += key_size / 2;
mbedtls_ecdsa_free(&ecdsa);
mbedtls_mpi_free(&r);
mbedtls_mpi_free(&s);
}
else if (p1 == 0x02) {
// Return public key
if (!otp_key_2) {
return SW_INS_NOT_SUPPORTED();
}
if (apdu.nc != 0) {
return SW_WRONG_LENGTH();
}
mbedtls_ecp_keypair ecp;
mbedtls_ecp_keypair_init(&ecp);
int ret = mbedtls_ecp_read_key(MBEDTLS_ECP_DP_SECP256K1, &ecp, otp_key_2, 32);
if (ret != 0) {
mbedtls_ecp_keypair_free(&ecp);
return SW_EXEC_ERROR();
}
ret = mbedtls_ecp_mul(&ecp.MBEDTLS_PRIVATE(grp), &ecp.MBEDTLS_PRIVATE(Q), &ecp.MBEDTLS_PRIVATE(d), &ecp.MBEDTLS_PRIVATE(grp).G, random_gen, NULL);
if (ret != 0) {
mbedtls_ecp_keypair_free(&ecp);
return SW_EXEC_ERROR();
}
size_t olen = 0;
ret = mbedtls_ecp_point_write_binary(&ecp.MBEDTLS_PRIVATE(grp), &ecp.MBEDTLS_PRIVATE(Q), MBEDTLS_ECP_PF_UNCOMPRESSED, &olen, res_APDU, 4096);
if (ret != 0) {
mbedtls_ecp_keypair_free(&ecp);
return SW_EXEC_ERROR();
}
res_APDU_size = (uint16_t)olen;
mbedtls_ecp_keypair_free(&ecp);
}
else if (p1 == 0x03) {
// Upload device attestation certificate
if (apdu.nc == 0) {
return SW_WRONG_LENGTH();
}
file_t *ef_devcert = file_new(0x2F02); // EF_DEVCERT
if (!ef_devcert) {
return SW_FILE_NOT_FOUND();
}
file_put_data(ef_devcert, apdu.data, (uint16_t)apdu.nc);
res_APDU_size = 0;
low_flash_available();
}
else {
return SW_INCORRECT_P1P2();
}
return SW_OK();
}
int cmd_write() {
if (apdu.nc < 2) {
return SW_WRONG_LENGTH();
}
if (P1(apdu) == 0x1) { // PHY
#ifndef ENABLE_EMULATION
int ret = phy_unserialize_data(apdu.data, (uint16_t)apdu.nc, &phy_data);
if (ret == PICOKEY_OK) {
if (phy_save() != PICOKEY_OK) {
return SW_EXEC_ERROR();
}
}
#endif
}
return SW_OK();
}
int cmd_read() {
if (apdu.nc != 0) {
return SW_WRONG_LENGTH();
}
uint8_t p1 = P1(apdu);
if (p1 == 0x1) { // PHY
#ifndef ENABLE_EMULATION
uint16_t len = 0;
int ret = phy_serialize_data(&phy_data, apdu.rdata, &len);
if (ret != PICOKEY_OK) {
return SW_EXEC_ERROR();
}
res_APDU_size = len;
#endif
}
else if (p1 == 0x2) { // FLASH INFO
res_APDU_size = 0;
uint32_t free = flash_free_space(), total = flash_total_space(), used = flash_used_space(), nfiles = flash_num_files(), size = flash_size();
res_APDU_size += put_uint32_t_be(free, res_APDU + res_APDU_size);
res_APDU_size += put_uint32_t_be(used, res_APDU + res_APDU_size);
res_APDU_size += put_uint32_t_be(total, res_APDU + res_APDU_size);
res_APDU_size += put_uint32_t_be(nfiles, res_APDU + res_APDU_size);
res_APDU_size += put_uint32_t_be(size, res_APDU + res_APDU_size);
}
else if (p1 == 0x3) { // OTP SECURE BOOT STATUS
res_APDU_size = 0;
uint8_t bootkey = 0xFF;
bool enabled = otp_is_secure_boot_enabled(&bootkey);
bool locked = otp_is_secure_boot_locked();
res_APDU[res_APDU_size++] = enabled ? 0x1 : 0x0;
res_APDU[res_APDU_size++] = locked ? 0x1 : 0x0;
res_APDU[res_APDU_size++] = bootkey;
}
return SW_OK();
}
#if defined(PICO_RP2350) || defined(ESP_PLATFORM)
int cmd_secure() {
if (apdu.nc != 0) {
return SW_WRONG_LENGTH();
}
uint8_t bootkey = P1(apdu);
bool secure_lock = P2(apdu) == 0x1;
int ret = otp_enable_secure_boot(bootkey, secure_lock);
if (ret != 0) {
return SW_EXEC_ERROR();
}
return SW_OK();
}
#endif
#ifdef PICO_PLATFORM
int cmd_reboot_bootsel() {
if (apdu.nc != 0) {
return SW_WRONG_LENGTH();
}
if (P1(apdu) == 0x1) {
// Reboot to BOOTSEL
reset_usb_boot(0, 0);
}
else if (P1(apdu) == 0x0) {
// Reboot to normal mode
watchdog_reboot(0, 0, 100);
}
else {
return SW_INCORRECT_P1P2();
}
return SW_OK();
}
#endif
#define INS_KEYDEV_SIGN 0x10
#define INS_WRITE 0x1C
#define INS_SECURE 0x1D
#define INS_READ 0x1E
#define INS_REBOOT_BOOTSEL 0x1F
static const cmd_t cmds[] = {
{ INS_KEYDEV_SIGN, cmd_keydev_sign },
{ INS_WRITE, cmd_write },
#if defined(PICO_RP2350) || defined(ESP_PLATFORM)
{ INS_SECURE, cmd_secure },
#endif
{ INS_READ, cmd_read },
#ifdef PICO_PLATFORM
{ INS_REBOOT_BOOTSEL, cmd_reboot_bootsel },
#endif
{ 0x00, 0x0 }
};
int rescue_process_apdu() {
if (CLA(apdu) != 0x80) {
return SW_CLA_NOT_SUPPORTED();
}
for (const cmd_t *cmd = cmds; cmd->ins != 0x00; cmd++) {
if (cmd->ins == INS(apdu)) {
int r = cmd->cmd_handler();
return r;
}
}
return SW_INS_NOT_SUPPORTED();
}

View file

@ -1,46 +1,44 @@
/* /*
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk). * This file is part of the Pico HSM SDK distribution (https://github.com/polhenarejos/pico-hsm-sdk).
* Copyright (c) 2022 Pol Henarejos. * Copyright (c) 2022 Pol Henarejos.
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3. * the Free Software Foundation, version 3.
* *
* This program is distributed in the hope that it will be useful, but * This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of * WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Affero General Public License for more details. * General Public License for more details.
* *
* You should have received a copy of the GNU Affero General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <stdint.h> #include <stdint.h>
#include <string.h> #include <string.h>
#include <stdio.h> #include <stdio.h>
#if defined(PICO_PLATFORM)
#include "pico/stdlib.h" #include "pico/stdlib.h"
#include "hwrng.h"
#include "bsp/board.h"
#include "pico/rand.h"
#elif defined(ESP_PLATFORM)
#include "bootloader_random.h"
#include "esp_random.h"
#include "esp_compat.h"
#else
#include <stdbool.h>
#include <stdlib.h>
#include <time.h>
#include "board.h"
#endif
void hwrng_start() { #include "hwrng.h"
#if defined(ENABLE_EMULATION) #include "hardware/structs/rosc.h"
srand(time(0)); #include "hardware/gpio.h"
#elif defined(ESP_PLATFORM) #include "hardware/adc.h"
bootloader_random_enable(); #include "pico/unique_id.h"
#endif
#include "pico/time.h"
static inline uint32_t board_millis(void)
{
return to_ms_since_boot(get_absolute_time());
}
void adc_start() {
adc_init();
adc_gpio_init(27);
adc_select_input(1);
}
void adc_stop() {
} }
static uint64_t random_word = 0xcbf29ce484222325; static uint64_t random_word = 0xcbf29ce484222325;
@ -52,22 +50,22 @@ static void ep_init() {
} }
/* Here, we assume a little endian architecture. */ /* Here, we assume a little endian architecture. */
static int ep_process() { static int ep_process () {
if (ep_round == 0) { if (ep_round == 0) {
ep_init(); ep_init();
} }
uint64_t word = 0x0; uint64_t word = 0x0;
for (int n = 0; n < 64; n++) {
#if defined(PICO_PLATFORM) uint8_t bit1, bit2;
word = get_rand_64(); do
#elif defined(ESP_PLATFORM) {
esp_fill_random((uint8_t *)&word, sizeof(word)); bit1 = rosc_hw->randombit&0xff;
#else //sleep_ms(1);
word = rand(); bit2 = rosc_hw->randombit&0xff;
word <<= 32; } while(bit1 == bit2);
word |= rand(); word = (word << 1) | bit1;
#endif }
random_word ^= word ^ board_millis(); random_word ^= word^board_millis()^adc_read();
random_word *= 0x00000100000001B3; random_word *= 0x00000100000001B3;
if (++ep_round == 8) { if (++ep_round == 8) {
ep_round = 0; ep_round = 0;
@ -76,12 +74,16 @@ static int ep_process() {
return 0; return 0;
} }
static const uint32_t *ep_output() {
return (uint32_t *)&random_word;
}
struct rng_rb { struct rng_rb {
uint32_t *buf; uint32_t *buf;
uint8_t head, tail; uint8_t head, tail;
uint8_t size; uint8_t size;
unsigned int full : 1; unsigned int full :1;
unsigned int empty : 1; unsigned int empty :1;
}; };
static void rb_init(struct rng_rb *rb, uint32_t *p, uint8_t size) { static void rb_init(struct rng_rb *rb, uint32_t *p, uint8_t size) {
@ -94,24 +96,20 @@ static void rb_init(struct rng_rb *rb, uint32_t *p, uint8_t size) {
static void rb_add(struct rng_rb *rb, uint32_t v) { static void rb_add(struct rng_rb *rb, uint32_t v) {
rb->buf[rb->tail++] = v; rb->buf[rb->tail++] = v;
if (rb->tail == rb->size) { if (rb->tail == rb->size)
rb->tail = 0; rb->tail = 0;
} if (rb->tail == rb->head)
if (rb->tail == rb->head) {
rb->full = 1; rb->full = 1;
}
rb->empty = 0; rb->empty = 0;
} }
static uint32_t rb_del(struct rng_rb *rb) { static uint32_t rb_del(struct rng_rb *rb) {
uint32_t v = rb->buf[rb->head++]; uint32_t v = rb->buf[rb->head++];
if (rb->head == rb->size) { if (rb->head == rb->size)
rb->head = 0; rb->head = 0;
} if (rb->head == rb->tail)
if (rb->head == rb->tail) {
rb->empty = 1; rb->empty = 1;
}
rb->full = 0; rb->full = 0;
return v; return v;
@ -125,25 +123,29 @@ void *neug_task() {
int n; int n;
if ((n = ep_process())) { if ((n = ep_process())) {
int i; int i;
const uint32_t *vp = (const uint32_t *) &random_word; const uint32_t *vp;
vp = ep_output();
for (i = 0; i < n; i++) {
rb_add (rb, *vp++);
if (rb->full)
break;
}
}
for (i = 0; i < n; i++) {
rb_add(rb, *vp++);
if (rb->full) {
break;
}
}
}
return NULL; return NULL;
} }
void neug_init(uint32_t *buf, uint8_t size) { void neug_init(uint32_t *buf, uint8_t size) {
pico_unique_board_id_t unique_id;
pico_get_unique_board_id(&unique_id);
struct rng_rb *rb = &the_ring_buffer; struct rng_rb *rb = &the_ring_buffer;
rb_init(rb, buf, size); rb_init(rb, buf, size);
hwrng_start(); adc_start();
ep_init(); ep_init();
} }
@ -151,37 +153,30 @@ void neug_init(uint32_t *buf, uint8_t size) {
void neug_flush(void) { void neug_flush(void) {
struct rng_rb *rb = &the_ring_buffer; struct rng_rb *rb = &the_ring_buffer;
while (!rb->empty) { while (!rb->empty)
rb_del(rb); rb_del (rb);
}
} }
uint32_t neug_get() { uint32_t neug_get() {
struct rng_rb *rb = &the_ring_buffer; struct rng_rb *rb = &the_ring_buffer;
uint32_t v; uint32_t v;
while (rb->empty) { while (rb->empty)
neug_task(); neug_task();
}
v = rb_del(rb); v = rb_del(rb);
return v; return v;
} }
void neug_wait_full() { void neug_wait_full(void) { //should be called only on core1
struct rng_rb *rb = &the_ring_buffer; struct rng_rb *rb = &the_ring_buffer;
#ifdef ESP_PLATFORM
uint8_t core = xTaskGetCurrentTaskHandle() == hcore1 ? 1 : 0;
#elif defined(PICO_PLATFORM)
uint core = get_core_num();
#endif
while (!rb->full) { while (!rb->full) {
#if defined(PICO_PLATFORM) || defined(ESP_PLATFORM) sleep_ms(1);
if (core == 1) {
sleep_ms(1);
}
else
#endif
neug_task();
} }
} }
void neug_fini(void) {
neug_get();
}

View file

@ -1,18 +1,18 @@
/* /*
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk). * This file is part of the Pico HSM SDK distribution (https://github.com/polhenarejos/pico-hsm-sdk).
* Copyright (c) 2022 Pol Henarejos. * Copyright (c) 2022 Pol Henarejos.
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3. * the Free Software Foundation, version 3.
* *
* This program is distributed in the hope that it will be useful, but * This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of * WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Affero General Public License for more details. * General Public License for more details.
* *
* You should have received a copy of the GNU Affero General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef _NEUG_H_ #ifndef _NEUG_H_
@ -20,14 +20,10 @@
#define NEUG_PRE_LOOP 32 #define NEUG_PRE_LOOP 32
#include <stdlib.h>
#if defined(PICO_PLATFORM)
#include "pico/stdlib.h"
#endif
void neug_init(uint32_t *buf, uint8_t size); void neug_init(uint32_t *buf, uint8_t size);
uint32_t neug_get(); uint32_t neug_get();
void neug_flush(void); void neug_flush(void);
void neug_wait_full(); void neug_wait_full(void);
void neug_fini(void);
#endif #endif

View file

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

View file

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

View file

@ -1,47 +0,0 @@
/*
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
* Copyright (c) 2022 Pol Henarejos.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero 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
* Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifdef _MSC_VER
#ifndef _SEMAPHORE_H_
#define _SEMAPHORE_H_
#include <windows.h>
typedef struct {
HANDLE handle;
} sem_t;
static inline int sem_init(sem_t *sem, int pshared, unsigned int value) {
(void)pshared;
sem->handle = CreateSemaphore(NULL, value, 0x7FFFFFFF, NULL);
return sem->handle ? 0 : -1;
}
static inline int sem_wait(sem_t *sem) {
return WaitForSingleObject(sem->handle, INFINITE) == WAIT_OBJECT_0 ? 0 : -1;
}
static inline int sem_post(sem_t *sem) {
return ReleaseSemaphore(sem->handle, 1, NULL) ? 0 : -1;
}
static inline int sem_destroy(sem_t *sem) {
return CloseHandle(sem->handle) ? 0 : -1;
}
#endif // _SEMAPHORE_H_
#endif // _MSC_VER

View file

@ -1,71 +1,84 @@
/* /*
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk). * This file is part of the Pico HSM SDK distribution (https://github.com/polhenarejos/pico-hsm-sdk).
* Copyright (c) 2022 Pol Henarejos. * Copyright (c) 2022 Pol Henarejos.
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3. * the Free Software Foundation, version 3.
* *
* This program is distributed in the hope that it will be useful, but * This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of * WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Affero General Public License for more details. * General Public License for more details.
* *
* You should have received a copy of the GNU Affero General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <stdio.h>
// Pico
#include "pico/stdlib.h"
// For memcpy
#include <string.h>
// Include descriptor struct definitions
//#include "usb_common.h"
// USB register definitions from pico-sdk
#include "hardware/regs/usb.h"
// USB hardware struct definitions from pico-sdk
#include "hardware/structs/usb.h"
// For interrupt enable and numbers
#include "hardware/irq.h"
// For resetting the USB controller
#include "hardware/resets.h"
#include "random.h" #include "random.h"
#include "pico_keys.h" #include "hsm.h"
#ifdef PICO_PLATFORM #include "hardware/rtc.h"
#include "bsp/board.h"
#endif
#ifndef ENABLE_EMULATION
#include "tusb.h" #include "tusb.h"
#include "device/usbd_pvt.h"
#else
#include "emulation.h"
#endif
#include "ccid.h" #include "ccid.h"
#include "device/usbd_pvt.h"
#include "usb_descriptors.h" #include "usb_descriptors.h"
#include "apdu.h" #include "apdu.h"
#include "usb.h" #include "usb.h"
const uint8_t *ccid_atr = NULL;
#if MAX_RES_APDU_DATA_SIZE > MAX_CMD_APDU_DATA_SIZE #if MAX_RES_APDU_DATA_SIZE > MAX_CMD_APDU_DATA_SIZE
#define USB_BUF_SIZE (MAX_RES_APDU_DATA_SIZE + 20 + 9) #define USB_BUF_SIZE (MAX_RES_APDU_DATA_SIZE+20+9)
#else #else
#define USB_BUF_SIZE (MAX_CMD_APDU_DATA_SIZE + 20 + 9) #define USB_BUF_SIZE (MAX_CMD_APDU_DATA_SIZE+20+9)
#endif #endif
#define CCID_SET_PARAMS 0x61 /* non-ICCD command */ #define CCID_SET_PARAMS 0x61 /* non-ICCD command */
#define CCID_POWER_ON 0x62 #define CCID_POWER_ON 0x62
#define CCID_POWER_OFF 0x63 #define CCID_POWER_OFF 0x63
#define CCID_SLOT_STATUS 0x65 /* non-ICCD command */ #define CCID_SLOT_STATUS 0x65 /* non-ICCD command */
#define CCID_SECURE 0x69 /* non-ICCD command */ #define CCID_SECURE 0x69 /* non-ICCD command */
#define CCID_GET_PARAMS 0x6C /* non-ICCD command */ #define CCID_GET_PARAMS 0x6C /* non-ICCD command */
#define CCID_RESET_PARAMS 0x6D /* non-ICCD command */ #define CCID_RESET_PARAMS 0x6D /* non-ICCD command */
#define CCID_XFR_BLOCK 0x6F #define CCID_XFR_BLOCK 0x6F
#define CCID_DATA_BLOCK_RET 0x80 #define CCID_DATA_BLOCK_RET 0x80
#define CCID_SLOT_STATUS_RET 0x81 /* non-ICCD result */ #define CCID_SLOT_STATUS_RET 0x81 /* non-ICCD result */
#define CCID_PARAMS_RET 0x82 /* non-ICCD result */ #define CCID_PARAMS_RET 0x82 /* non-ICCD result */
#define CCID_SETDATARATEANDCLOCKFREQUENCY 0x73
#define CCID_SETDATARATEANDCLOCKFREQUENCY_RET 0x84
#define CCID_MSG_SEQ_OFFSET 6 #define CCID_MSG_SEQ_OFFSET 6
#define CCID_MSG_STATUS_OFFSET 7 #define CCID_MSG_STATUS_OFFSET 7
#define CCID_MSG_ERROR_OFFSET 8 #define CCID_MSG_ERROR_OFFSET 8
#define CCID_MSG_CHAIN_OFFSET 9 #define CCID_MSG_CHAIN_OFFSET 9
#define CCID_MSG_DATA_OFFSET 10 /* == CCID_MSG_HEADER_SIZE */ #define CCID_MSG_DATA_OFFSET 10 /* == CCID_MSG_HEADER_SIZE */
#define CCID_MAX_MSG_DATA_SIZE USB_BUF_SIZE #define CCID_MAX_MSG_DATA_SIZE USB_BUF_SIZE
#define CCID_STATUS_RUN 0x00 #define CCID_STATUS_RUN 0x00
#define CCID_STATUS_PRESENT 0x01 #define CCID_STATUS_PRESENT 0x01
#define CCID_STATUS_NOTPRESENT 0x02 #define CCID_STATUS_NOTPRESENT 0x02
#define CCID_CMD_STATUS_OK 0x00 #define CCID_CMD_STATUS_OK 0x00
#define CCID_CMD_STATUS_ERROR 0x40 #define CCID_CMD_STATUS_ERROR 0x40
#define CCID_CMD_STATUS_TIMEEXT 0x80 #define CCID_CMD_STATUS_TIMEEXT 0x80
#define CCID_ERROR_XFR_OVERRUN 0xFC #define CCID_ERROR_XFR_OVERRUN 0xFC
/* /*
* Since command-byte is at offset 0, * Since command-byte is at offset 0,
@ -78,8 +91,7 @@
#define CCID_THREAD_TERMINATED 0xffff #define CCID_THREAD_TERMINATED 0xffff
#define CCID_ACK_TIMEOUT 0x6600 #define CCID_ACK_TIMEOUT 0x6600
PACK( struct ccid_header {
typedef struct {
uint8_t bMessageType; uint8_t bMessageType;
uint32_t dwLength; uint32_t dwLength;
uint8_t bSlot; uint8_t bSlot;
@ -87,307 +99,185 @@ typedef struct {
uint8_t abRFU0; uint8_t abRFU0;
uint16_t abRFU1; uint16_t abRFU1;
uint8_t apdu; //Actually it is an array uint8_t apdu; //Actually it is an array
}) ccid_header_t; } __packed;
uint8_t ccid_status = 1; uint8_t ccid_status = 1;
#ifndef ENABLE_EMULATION
static uint8_t itf_num; static uint8_t itf_num;
#endif
static usb_buffer_t *ccid_rx = NULL, *ccid_tx = NULL; void ccid_write_offset(uint16_t size, uint16_t offset) {
if (*usb_get_tx()+offset != 0x81)
int driver_process_usb_packet_ccid(uint8_t itf, uint16_t rx_read); DEBUG_PAYLOAD(usb_get_tx()+offset,size+10);
usb_write_offset(size+10, offset);
void ccid_write_offset(uint8_t itf, uint16_t size, uint16_t offset) {
ccid_tx[itf].w_ptr += size + offset;
ccid_tx[itf].r_ptr += offset;
} }
void ccid_write(uint8_t itf, uint16_t size) { void ccid_write(uint16_t size) {
ccid_write_offset(itf, size, 0); ccid_write_offset(size, 0);
} }
ccid_header_t **ccid_response = NULL; struct ccid_header *ccid_response;
ccid_header_t **ccid_resp_fast = NULL; struct ccid_header *ccid_header;
ccid_header_t **ccid_header = NULL;
uint8_t sc_itf_to_usb_itf(uint8_t itf) { int driver_init() {
if (itf == ITF_SC_CCID) { ccid_header = (struct ccid_header *)usb_get_rx();
return ITF_CCID; apdu.header = &ccid_header->apdu;
}
else if (itf == ITF_SC_WCID) { ccid_response = (struct ccid_header *)usb_get_tx();
return ITF_WCID; apdu.rdata = &ccid_response->apdu;
}
return itf; return CCID_OK;
} }
void ccid_init_buffers() { void tud_vendor_rx_cb(uint8_t itf) {
if (ITF_SC_TOTAL == 0) { (void) itf;
return;
} uint32_t len = tud_vendor_available();
if (ccid_rx == NULL) { usb_rx(NULL, len);
ccid_rx = (usb_buffer_t *)calloc(ITF_SC_TOTAL, sizeof(usb_buffer_t));
}
if (ccid_tx == NULL) {
ccid_tx = (usb_buffer_t *)calloc(ITF_SC_TOTAL, sizeof(usb_buffer_t));
}
if (ccid_header == NULL) {
ccid_header = (ccid_header_t **)calloc(ITF_SC_TOTAL, sizeof(ccid_header_t *));
}
if (ccid_response == NULL) {
ccid_response = (ccid_header_t **)calloc(ITF_SC_TOTAL, sizeof(ccid_header_t *));
}
if (ccid_resp_fast == NULL) {
ccid_resp_fast = (ccid_header_t **)calloc(ITF_SC_TOTAL, sizeof(ccid_header_t *));
}
} }
int driver_init_ccid(uint8_t itf) { void tud_vendor_tx_cb(uint8_t itf, uint32_t sent_bytes) {
ccid_header[itf] = (ccid_header_t *) (ccid_rx[itf].buffer + ccid_rx[itf].r_ptr); printf("written %ld\n",sent_bytes);
ccid_resp_fast[itf] = (ccid_header_t *) (ccid_tx[itf].buffer + sizeof(ccid_tx[itf].buffer) - 64); usb_write_flush();
// apdu.header = &ccid_header->apdu;
ccid_response[itf] = (ccid_header_t *) (ccid_tx[itf].buffer + ccid_tx[itf].w_ptr);
usb_set_timeout_counter(sc_itf_to_usb_itf(itf), 1500);
//ccid_tx[itf].w_ptr = ccid_tx[itf].r_ptr = 0;
return PICOKEY_OK;
} }
void tud_vendor_rx_cb(uint8_t itf, const uint8_t *buffer, uint16_t bufsize) { int driver_write(const uint8_t *buffer, size_t buffer_size) {
uint32_t len = tud_vendor_n_available(itf); return tud_vendor_write(buffer, buffer_size);
do {
uint16_t tlen = 0;
if (len > 0xFFFF) {
tlen = 0xFFFF;
}
else {
tlen = (uint16_t)len;
}
tlen = (uint16_t)tud_vendor_n_read(itf, ccid_rx[itf].buffer + ccid_rx[itf].w_ptr, tlen);
ccid_rx[itf].w_ptr += tlen;
driver_process_usb_packet_ccid(itf, tlen);
len -= tlen;
} while (len > 0);
} }
int driver_write_ccid(uint8_t itf, const uint8_t *tx_buffer, uint16_t buffer_size) { size_t driver_read(uint8_t *buffer, size_t buffer_size) {
if (*tx_buffer != 0x81) { return tud_vendor_read(buffer, buffer_size);
DEBUG_PAYLOAD(tx_buffer, buffer_size);
}
int r = tud_vendor_n_write(itf, tx_buffer, buffer_size);
if (r > 0) {
tud_vendor_n_flush(itf);
ccid_tx[itf].r_ptr += (uint16_t)buffer_size;
if (ccid_tx[itf].r_ptr >= ccid_tx[itf].w_ptr) {
ccid_tx[itf].r_ptr = ccid_tx[itf].w_ptr = 0;
}
}
#ifdef ENABLE_EMULATION
tud_vendor_tx_cb(itf, r);
#endif
return r;
} }
int ccid_write_fast(uint8_t itf, const uint8_t *buffer, uint16_t buffer_size) { int driver_process_usb_packet(uint16_t rx_read) {
return driver_write_ccid(itf, buffer, buffer_size); if (rx_read >= 10)
} {
//printf("%d %d %x\r\n",tccid->dwLength,rx_read-10,tccid->bMessageType);
int driver_process_usb_packet_ccid(uint8_t itf, uint16_t rx_read) { if (ccid_header->dwLength <= rx_read-10) {
(void) rx_read;
if (ccid_rx[itf].w_ptr - ccid_rx[itf].r_ptr >= 10) {
driver_init_ccid(itf);
//printf("ccid_process %ld %d %x %x %d\n",ccid_header[itf]->dwLength,rx_read-10,ccid_header[itf]->bMessageType,ccid_header[itf]->bSeq,ccid_rx[itf].w_ptr - ccid_rx[itf].r_ptr - 10);
if (ccid_header[itf]->dwLength <= (uint32_t)(ccid_rx[itf].w_ptr - ccid_rx[itf].r_ptr - 10)){
ccid_rx[itf].r_ptr += (uint16_t)(ccid_header[itf]->dwLength + 10);
if (ccid_rx[itf].r_ptr >= ccid_rx[itf].w_ptr) {
ccid_rx[itf].r_ptr = ccid_rx[itf].w_ptr = 0;
}
size_t apdu_sent = 0; size_t apdu_sent = 0;
if (ccid_header[itf]->bMessageType != CCID_SLOT_STATUS) { if (ccid_header->bMessageType != 0x65)
DEBUG_PAYLOAD((uint8_t *)ccid_header[itf], ccid_header[itf]->dwLength + 10); DEBUG_PAYLOAD(usb_get_rx(),usb_read_available());
if (ccid_header->bMessageType == 0x65) {
ccid_response->bMessageType = CCID_SLOT_STATUS_RET;
ccid_response->dwLength = 0;
ccid_response->bSlot = 0;
ccid_response->bSeq = ccid_header->bSeq;
ccid_response->abRFU0 = ccid_status;
ccid_response->abRFU1 = 0;
ccid_write(0);
} }
if (ccid_header[itf]->bMessageType == CCID_SLOT_STATUS) { else if (ccid_header->bMessageType == 0x62) {
ccid_resp_fast[itf]->bMessageType = CCID_SLOT_STATUS_RET;
ccid_resp_fast[itf]->dwLength = 0;
ccid_resp_fast[itf]->bSlot = 0;
ccid_resp_fast[itf]->bSeq = ccid_header[itf]->bSeq;
ccid_resp_fast[itf]->abRFU0 = ccid_status;
ccid_resp_fast[itf]->abRFU1 = 0;
ccid_write_fast(itf, (const uint8_t *)ccid_resp_fast[itf], 10);
}
else if (ccid_header[itf]->bMessageType == CCID_POWER_ON) {
size_t size_atr = (ccid_atr ? ccid_atr[0] : 0); size_t size_atr = (ccid_atr ? ccid_atr[0] : 0);
ccid_resp_fast[itf]->bMessageType = CCID_DATA_BLOCK_RET; ccid_response->bMessageType = 0x80;
ccid_resp_fast[itf]->dwLength = (uint32_t)size_atr; ccid_response->dwLength = size_atr;
ccid_resp_fast[itf]->bSlot = 0; ccid_response->bSlot = 0;
ccid_resp_fast[itf]->bSeq = ccid_header[itf]->bSeq; ccid_response->bSeq = ccid_header->bSeq;
ccid_resp_fast[itf]->abRFU0 = 0; ccid_response->abRFU0 = 0;
ccid_resp_fast[itf]->abRFU1 = 0; ccid_response->abRFU1 = 0;
//printf("1 %x %x %x || %x %x %x\n",ccid_resp_fast->apdu,apdu.rdata,ccid_resp_fast,ccid_header,ccid_header->apdu,apdu.data); //printf("1 %x %x %x || %x %x %x\r\n",ccid_response->apdu,apdu.rdata,ccid_response,ccid_header,ccid_header->apdu,apdu.data);
memcpy(&ccid_resp_fast[itf]->apdu, ccid_atr + 1, size_atr); memcpy(apdu.rdata, ccid_atr+1, size_atr);
if (ccid_status == 1) { card_start();
//card_start(apdu_thread);
}
ccid_status = 0; ccid_status = 0;
ccid_write_fast(itf, (const uint8_t *)ccid_resp_fast[itf], (uint16_t)(size_atr + 10)); ccid_write(size_atr);
led_set_mode(MODE_MOUNTED);
} }
else if (ccid_header[itf]->bMessageType == CCID_POWER_OFF) { else if (ccid_header->bMessageType == 0x63) {
if (ccid_status == 0) {
//card_exit(0);
}
ccid_status = 1; ccid_status = 1;
ccid_resp_fast[itf]->bMessageType = CCID_SLOT_STATUS_RET; ccid_response->bMessageType = CCID_SLOT_STATUS_RET;
ccid_resp_fast[itf]->dwLength = 0; ccid_response->dwLength = 0;
ccid_resp_fast[itf]->bSlot = 0; ccid_response->bSlot = 0;
ccid_resp_fast[itf]->bSeq = ccid_header[itf]->bSeq; ccid_response->bSeq = ccid_header->bSeq;
ccid_resp_fast[itf]->abRFU0 = ccid_status; ccid_response->abRFU0 = ccid_status;
ccid_resp_fast[itf]->abRFU1 = 0; ccid_response->abRFU1 = 0;
ccid_write_fast(itf, (const uint8_t *)ccid_resp_fast[itf], 10); card_exit();
ccid_write(0);
led_set_mode(MODE_SUSPENDED);
} }
else if (ccid_header[itf]->bMessageType == CCID_SET_PARAMS || else if (ccid_header->bMessageType == 0x6F) {
ccid_header[itf]->bMessageType == CCID_GET_PARAMS || apdu_sent = apdu_process(&ccid_header->apdu, ccid_header->dwLength);
ccid_header[itf]->bMessageType == CCID_RESET_PARAMS) {
/* Values from gnuk. Not specified in ICCD spec. */
const uint8_t params[] = {
0x11, /* bmFindexDindex */
0x10, /* bmTCCKST1 */
0xFE, /* bGuardTimeT1 */
0x55, /* bmWaitingIntegersT1 */
0x03, /* bClockStop */
0xFE, /* bIFSC */
0 /* bNadValue */
};
ccid_resp_fast[itf]->bMessageType = CCID_PARAMS_RET;
ccid_resp_fast[itf]->dwLength = sizeof(params);
ccid_resp_fast[itf]->bSlot = 0;
ccid_resp_fast[itf]->bSeq = ccid_header[itf]->bSeq;
ccid_resp_fast[itf]->abRFU0 = ccid_status;
ccid_resp_fast[itf]->abRFU1 = 0x0100;
memcpy(&ccid_resp_fast[itf]->apdu, params, sizeof(params));
ccid_write_fast(itf, (const uint8_t *)ccid_resp_fast[itf], sizeof(params) + 10);
} }
else if (ccid_header[itf]->bMessageType == CCID_SETDATARATEANDCLOCKFREQUENCY) { usb_clear_rx();
ccid_resp_fast[itf]->bMessageType = CCID_SETDATARATEANDCLOCKFREQUENCY_RET; return apdu_sent;
ccid_resp_fast[itf]->dwLength = 8;
ccid_resp_fast[itf]->bSlot = 0;
ccid_resp_fast[itf]->bSeq = ccid_header[itf]->bSeq;
ccid_resp_fast[itf]->abRFU0 = ccid_status;
ccid_resp_fast[itf]->abRFU1 = 0;
memset(&ccid_resp_fast[itf]->apdu, 0, 8);
ccid_write_fast(itf, (const uint8_t *)ccid_resp_fast[itf], 18);
}
else if (ccid_header[itf]->bMessageType == CCID_XFR_BLOCK) {
apdu.rdata = &ccid_response[itf]->apdu;
apdu_sent = apdu_process(itf, &ccid_header[itf]->apdu, (uint16_t)ccid_header[itf]->dwLength);
#ifndef ENABLE_EMULATION
if (apdu_sent > 0) {
card_start(sc_itf_to_usb_itf(itf), apdu_thread);
usb_send_event(EV_CMD_AVAILABLE);
}
#endif
}
return (uint16_t)apdu_sent;
} }
} }
/*
if (usb_read_available() && c->epo->ready) {
if ()
uint32_t count = usb_read(endp1_rx_buf, sizeof(endp1_rx_buf));
//if (endp1_rx_buf[0] != 0x65)
DEBUG_PAYLOAD(endp1_rx_buf, count);
//DEBUG_PAYLOAD(endp1_rx_buf, count);
ccid_rx_ready(count);
}
*/
return 0; return 0;
} }
void driver_exec_timeout_ccid(uint8_t itf) { bool driver_mounted() {
ccid_resp_fast[itf]->bMessageType = CCID_DATA_BLOCK_RET; return tud_vendor_mounted();
ccid_resp_fast[itf]->dwLength = 0;
ccid_resp_fast[itf]->bSlot = 0;
ccid_resp_fast[itf]->bSeq = ccid_header[itf]->bSeq;
ccid_resp_fast[itf]->abRFU0 = CCID_CMD_STATUS_TIMEEXT;
ccid_resp_fast[itf]->abRFU1 = 0;
ccid_write_fast(itf, (const uint8_t *)ccid_resp_fast[itf], 10);
} }
void driver_exec_finished_ccid(uint8_t itf, uint16_t size_next) { void driver_exec_timeout() {
driver_exec_finished_cont_ccid(itf, size_next, 0); ccid_response->bMessageType = CCID_DATA_BLOCK_RET;
ccid_response->dwLength = 0;
ccid_response->bSlot = 0;
ccid_response->bSeq = ccid_header->bSeq;
ccid_response->abRFU0 = CCID_CMD_STATUS_TIMEEXT;
ccid_response->abRFU1 = 0;
ccid_write(0);
} }
void driver_exec_finished_cont_ccid(uint8_t itf, uint16_t size_next, uint16_t offset) { void driver_exec_finished(size_t size_next) {
ccid_response[itf] = (ccid_header_t *) (ccid_tx[itf].buffer + ccid_tx[itf].w_ptr + offset); ccid_response->bMessageType = CCID_DATA_BLOCK_RET;
ccid_response[itf]->bMessageType = CCID_DATA_BLOCK_RET; ccid_response->dwLength = size_next;
ccid_response[itf]->dwLength = size_next; ccid_response->bSlot = 0;
ccid_response[itf]->bSlot = 0; ccid_response->bSeq = ccid_header->bSeq;
ccid_response[itf]->bSeq = ccid_header[itf]->bSeq; ccid_response->abRFU0 = ccid_status;
ccid_response[itf]->abRFU0 = ccid_status; ccid_response->abRFU1 = 0;
ccid_response[itf]->abRFU1 = 0; ccid_write(size_next);
ccid_write_offset(itf, size_next+10, offset);
} }
void ccid_task() { void driver_exec_finished_cont(size_t size_next, size_t offset) {
for (int itf = 0; itf < ITF_SC_TOTAL; itf++) {
int status = card_status(sc_itf_to_usb_itf(itf));
if (status == PICOKEY_OK) {
driver_exec_finished_ccid(itf, finished_data_size);
}
else if (status == PICOKEY_ERR_BLOCKED) {
driver_exec_timeout_ccid(itf);
}
if (ccid_tx[itf].w_ptr > ccid_tx[itf].r_ptr) {
if (driver_write_ccid(itf, ccid_tx[itf].buffer + ccid_tx[itf].r_ptr, ccid_tx[itf].w_ptr - ccid_tx[itf].r_ptr) > 0) {
} ccid_response = (struct ccid_header *)(usb_get_tx()+offset-10);
} ccid_response->bMessageType = CCID_DATA_BLOCK_RET;
} ccid_response->dwLength = size_next;
ccid_response->bSlot = 0;
ccid_response->bSeq = ccid_header->bSeq;
ccid_response->abRFU0 = ccid_status;
ccid_response->abRFU1 = 0;
ccid_write_offset(size_next, offset-10);
} }
void ccid_init() { uint8_t *driver_prepare_response() {
ccid_init_buffers(); ccid_response = (struct ccid_header *)usb_get_tx();
return &ccid_response->apdu;
} }
#define USB_CONFIG_ATT_ONE TU_BIT(7)
#ifndef ENABLE_EMULATION #define MAX_USB_POWER 1
void tud_vendor_tx_cb(uint8_t itf, uint32_t sent_bytes) {
(void) sent_bytes;
tud_vendor_n_write_flush(itf);
}
static void ccid_init_cb(void) { static void ccid_init_cb(void) {
TU_LOG1("-------- CCID INIT\r\n");
vendord_init(); vendord_init();
//ccid_notify_slot_change(c);
} }
static void ccid_reset_cb(uint8_t rhport) { static void ccid_reset_cb(uint8_t rhport) {
TU_LOG1("-------- CCID RESET\r\n");
itf_num = 0; itf_num = 0;
vendord_reset(rhport); vendord_reset(rhport);
} }
static uint16_t ccid_open(uint8_t rhport, tusb_desc_interface_t const *itf_desc, uint16_t max_len) { static uint16_t ccid_open(uint8_t rhport, tusb_desc_interface_t const *itf_desc, uint16_t max_len) {
uint8_t *itf_vendor = (uint8_t *) malloc(sizeof(uint8_t) * max_len); uint8_t *itf_vendor = (uint8_t *)malloc(sizeof(uint8_t)*max_len);
TU_VERIFY( itf_desc->bInterfaceClass == TUSB_CLASS_SMART_CARD && itf_desc->bInterfaceSubClass == 0 && itf_desc->bInterfaceProtocol == 0, 0); TU_LOG1("-------- CCID OPEN\r\n");
TU_VERIFY(itf_desc->bInterfaceClass == TUSB_CLASS_SMART_CARD && itf_desc->bInterfaceSubClass == 0 && itf_desc->bInterfaceProtocol == 0, 0);
//vendord_open expects a CLASS_VENDOR interface class //vendord_open expects a CLASS_VENDOR interface class
uint16_t const drv_len = sizeof(tusb_desc_interface_t) + sizeof(struct ccid_class_descriptor) + TUSB_SMARTCARD_CCID_EPS * sizeof(tusb_desc_endpoint_t); memcpy(itf_vendor, itf_desc, sizeof(uint8_t)*max_len);
memcpy(itf_vendor, itf_desc, sizeof(uint8_t) * max_len); ((tusb_desc_interface_t *)itf_vendor)->bInterfaceClass = TUSB_CLASS_VENDOR_SPECIFIC;
((tusb_desc_interface_t *) itf_vendor)->bInterfaceClass = TUSB_CLASS_VENDOR_SPECIFIC;
#if TUSB_SMARTCARD_CCID_EPS == 3
((tusb_desc_interface_t *) itf_vendor)->bNumEndpoints -= 1;
vendord_open(rhport, (tusb_desc_interface_t *)itf_vendor, max_len - sizeof(tusb_desc_endpoint_t));
tusb_desc_endpoint_t const *desc_ep = (tusb_desc_endpoint_t const *)((uint8_t *)itf_desc + drv_len - sizeof(tusb_desc_endpoint_t));
TU_ASSERT(usbd_edpt_open(rhport, desc_ep), 0);
uint8_t msg[] = { 0x50, 0x03 };
#if defined(PICO_PLATFORM) || defined(ESP_PLATFORM)
usbd_edpt_xfer(rhport, desc_ep->bEndpointAddress, msg, sizeof(msg));
#else
usbd_edpt_xfer(rhport, desc_ep->bEndpointAddress, msg, sizeof(msg), sizeof(msg));
#endif
#else
vendord_open(rhport, (tusb_desc_interface_t *)itf_vendor, max_len); vendord_open(rhport, (tusb_desc_interface_t *)itf_vendor, max_len);
#endif
free(itf_vendor); free(itf_vendor);
uint16_t const drv_len = sizeof(tusb_desc_interface_t) + sizeof(struct ccid_class_descriptor) + 2*sizeof(tusb_desc_endpoint_t);
TU_VERIFY(max_len >= drv_len, 0); TU_VERIFY(max_len >= drv_len, 0);
itf_num = itf_desc->bInterfaceNumber; itf_num = itf_desc->bInterfaceNumber;
@ -395,55 +285,45 @@ static uint16_t ccid_open(uint8_t rhport, tusb_desc_interface_t const *itf_desc,
} }
// Support for parameterized reset via vendor interface control request // Support for parameterized reset via vendor interface control request
static bool ccid_control_xfer_cb(uint8_t __unused rhport, static bool ccid_control_xfer_cb(uint8_t __unused rhport, uint8_t stage, tusb_control_request_t const * request) {
uint8_t stage,
tusb_control_request_t const *request) {
// nothing to do with DATA & ACK stage // nothing to do with DATA & ACK stage
TU_LOG2("-------- CCID CTRL XFER\n"); TU_LOG2("-------- CCID CTRL XFER\r\n");
if (stage != CONTROL_STAGE_SETUP) { if (stage != CONTROL_STAGE_SETUP) return true;
return true;
}
if (request->wIndex == itf_num) { if (request->wIndex == itf_num)
TU_LOG2("-------- bmRequestType %x, bRequest %x, wValue %x, wLength %x\n", {
request->bmRequestType, TU_LOG2("-------- bmRequestType %x, bRequest %x, wValue %x, wLength %x\r\n",request->bmRequestType,request->bRequest, request->wValue, request->wLength);
request->bRequest,
request->wValue,
request->wLength);
/* /*
#if PICO_STDIO_USB_RESET_INTERFACE_SUPPORT_RESET_TO_BOOTSEL #if PICO_STDIO_USB_RESET_INTERFACE_SUPPORT_RESET_TO_BOOTSEL
if (request->bRequest == RESET_REQUEST_BOOTSEL) { if (request->bRequest == RESET_REQUEST_BOOTSEL) {
#ifdef PICO_STDIO_USB_RESET_BOOTSEL_ACTIVITY_LED #ifdef PICO_STDIO_USB_RESET_BOOTSEL_ACTIVITY_LED
uint gpio_mask = 1u << PICO_STDIO_USB_RESET_BOOTSEL_ACTIVITY_LED; uint gpio_mask = 1u << PICO_STDIO_USB_RESET_BOOTSEL_ACTIVITY_LED;
#else #else
uint gpio_mask = 0u; uint gpio_mask = 0u;
#endif #endif
#if !PICO_STDIO_USB_RESET_BOOTSEL_FIXED_ACTIVITY_LED #if !PICO_STDIO_USB_RESET_BOOTSEL_FIXED_ACTIVITY_LED
if (request->wValue & 0x100) { if (request->wValue & 0x100) {
gpio_mask = 1u << (request->wValue >> 9u); gpio_mask = 1u << (request->wValue >> 9u);
} }
#endif #endif
reset_usb_boot(gpio_mask, (request->wValue & 0x7f) | PICO_STDIO_USB_RESET_BOOTSEL_INTERFACE_DISABLE_MASK); reset_usb_boot(gpio_mask, (request->wValue & 0x7f) | PICO_STDIO_USB_RESET_BOOTSEL_INTERFACE_DISABLE_MASK);
// does not return, otherwise we'd return true // does not return, otherwise we'd return true
} }
#endif #endif
#if PICO_STDIO_USB_RESET_INTERFACE_SUPPORT_RESET_TO_FLASH_BOOT #if PICO_STDIO_USB_RESET_INTERFACE_SUPPORT_RESET_TO_FLASH_BOOT
if (request->bRequest == RESET_REQUEST_FLASH) { if (request->bRequest == RESET_REQUEST_FLASH) {
watchdog_reboot(0, 0, PICO_STDIO_USB_RESET_RESET_TO_FLASH_DELAY_MS); watchdog_reboot(0, 0, PICO_STDIO_USB_RESET_RESET_TO_FLASH_DELAY_MS);
return true; return true;
} }
#endif #endif
*/ */
return true; return true;
} }
return false; return false;
} }
static bool ccid_xfer_cb(uint8_t rhport, static bool ccid_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) {
uint8_t ep_addr, //printf("------ CALLED XFER_CB\r\n");
xfer_result_t result,
uint32_t xferred_bytes) {
//printf("------ CALLED XFER_CB\n");
return vendord_xfer_cb(rhport, ep_addr, result, xferred_bytes); return vendord_xfer_cb(rhport, ep_addr, result, xferred_bytes);
//return true; //return true;
} }
@ -465,4 +345,3 @@ usbd_class_driver_t const *usbd_app_driver_get_cb(uint8_t *driver_count) {
*driver_count = 1; *driver_count = 1;
return &ccid_driver; return &ccid_driver;
} }
#endif

View file

@ -1,18 +1,18 @@
/* /*
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk). * This file is part of the Pico HSM SDK distribution (https://github.com/polhenarejos/pico-hsm-sdk).
* Copyright (c) 2022 Pol Henarejos. * Copyright (c) 2022 Pol Henarejos.
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3. * the Free Software Foundation, version 3.
* *
* This program is distributed in the hope that it will be useful, but * This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of * WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Affero General Public License for more details. * General Public License for more details.
* *
* You should have received a copy of the GNU Affero General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef _CCID_H_ #ifndef _CCID_H_
@ -20,24 +20,30 @@
extern const uint8_t historical_bytes[]; extern const uint8_t historical_bytes[];
#define MAX_CMD_APDU_DATA_SIZE (24 + 4 + 512 * 4) #define MAX_CMD_APDU_DATA_SIZE (24+4+512*4)
#define MAX_RES_APDU_DATA_SIZE (5 + 9 + 512 * 4) #define MAX_RES_APDU_DATA_SIZE (5+9+512*4)
#define CCID_MSG_HEADER_SIZE 10 #define CCID_MSG_HEADER_SIZE 10
#define USB_LL_BUF_SIZE 64 #define USB_LL_BUF_SIZE 64
enum ccid_state { enum ccid_state {
CCID_STATE_NOCARD, /* No card available */ CCID_STATE_NOCARD, /* No card available */
CCID_STATE_START, /* Initial */ CCID_STATE_START, /* Initial */
CCID_STATE_WAIT, /* Waiting APDU */ CCID_STATE_WAIT, /* Waiting APDU */
CCID_STATE_EXECUTE, /* Executing command */ CCID_STATE_EXECUTE, /* Executing command */
CCID_STATE_ACK_REQUIRED_0, /* Ack required (executing)*/ CCID_STATE_ACK_REQUIRED_0, /* Ack required (executing)*/
CCID_STATE_ACK_REQUIRED_1, /* Waiting user's ACK (execution finished) */ CCID_STATE_ACK_REQUIRED_1, /* Waiting user's ACK (execution finished) */
CCID_STATE_EXITED, /* CCID Thread Terminated */ CCID_STATE_EXITED, /* CCID Thread Terminated */
CCID_STATE_EXEC_REQUESTED, /* Exec requested */ CCID_STATE_EXEC_REQUESTED, /* Exec requested */
}; };
extern const uint8_t *ccid_atr; extern const uint8_t *ccid_atr;
extern uint8_t *usb_get_rx();
extern uint8_t *usb_get_tx();
extern uint32_t usb_write_offset(uint16_t len, uint16_t offset);
extern uint16_t usb_read_available();
extern void usb_clear_rx();
extern uint32_t usb_write_flush();
#endif //_CCID_H_ #endif //_CCID_H_

119
src/usb/ccid/tusb_config.h Normal file
View file

@ -0,0 +1,119 @@
/*
* 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

@ -133,29 +133,29 @@ struct usb_endpoint_descriptor_long {
struct ccid_class_descriptor { struct ccid_class_descriptor {
uint8_t bLength; uint8_t bLength;
uint8_t bDescriptorType; uint8_t bDescriptorType;
uint16_t bcdCCID; uint16_t bcdCCID;
uint8_t bMaxSlotIndex; uint8_t bMaxSlotIndex;
uint8_t bVoltageSupport; uint8_t bVoltageSupport;
uint32_t dwProtocols; uint32_t dwProtocols;
uint32_t dwDefaultClock; uint32_t dwDefaultClock;
uint32_t dwMaximumClock; uint32_t dwMaximumClock;
uint8_t bNumClockSupport; uint8_t bNumClockSupport;
uint32_t dwDataRate; uint32_t dwDataRate;
uint32_t dwMaxDataRate; uint32_t dwMaxDataRate;
uint8_t bNumDataRatesSupported; uint8_t bNumDataRatesSupported;
uint32_t dwMaxIFSD; uint32_t dwMaxIFSD;
uint32_t dwSynchProtocols; uint32_t dwSynchProtocols;
uint32_t dwMechanical; uint32_t dwMechanical;
uint32_t dwFeatures; uint32_t dwFeatures;
uint32_t dwMaxCCIDMessageLength; uint32_t dwMaxCCIDMessageLength;
uint8_t bClassGetResponse; uint8_t bClassGetResponse;
uint8_t bclassEnvelope; uint8_t bclassEnvelope;
uint16_t wLcdLayout; uint16_t wLcdLayout;
uint8_t bPINSupport; uint8_t bPINSupport;
uint8_t bMaxCCIDBusySlots; uint8_t bMaxCCIDBusySlots;
} __attribute__((__packed__)); } __attribute__ ((__packed__));
static const struct ccid_class_descriptor ccid_desc = { static const struct ccid_class_descriptor ccid_desc = {
.bLength = sizeof(struct ccid_class_descriptor), .bLength = sizeof(struct ccid_class_descriptor),
@ -164,8 +164,8 @@ static const struct ccid_class_descriptor ccid_desc = {
.bMaxSlotIndex = 0, .bMaxSlotIndex = 0,
.bVoltageSupport = 0x01, // 5.0V .bVoltageSupport = 0x01, // 5.0V
.dwProtocols = ( .dwProtocols = (
0x01 | // T=0 0x01| // T=0
0x02), // T=1 0x02), // T=1
.dwDefaultClock = (0xDFC), .dwDefaultClock = (0xDFC),
.dwMaximumClock = (0xDFC), .dwMaximumClock = (0xDFC),
.bNumClockSupport = 0, .bNumClockSupport = 0,
@ -176,7 +176,7 @@ static const struct ccid_class_descriptor ccid_desc = {
.dwSynchProtocols = (0), .dwSynchProtocols = (0),
.dwMechanical = (0), .dwMechanical = (0),
.dwFeatures = 0x40840, //USB-ICC, short & extended APDU .dwFeatures = 0x40840, //USB-ICC, short & extended APDU
.dwMaxCCIDMessageLength = 65544 + 10, .dwMaxCCIDMessageLength = 65544+10,
.bClassGetResponse = 0xFF, .bClassGetResponse = 0xFF,
.bclassEnvelope = 0xFF, .bclassEnvelope = 0xFF,
.wLcdLayout = 0x0, .wLcdLayout = 0x0,
@ -219,90 +219,90 @@ struct usb_device_configuration {
// EP0 IN and OUT // EP0 IN and OUT
static const struct usb_endpoint_descriptor ep0_out = { static const struct usb_endpoint_descriptor ep0_out = {
.bLength = sizeof(struct usb_endpoint_descriptor), .bLength = sizeof(struct usb_endpoint_descriptor),
.bDescriptorType = USB_DT_ENDPOINT, .bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = EP0_OUT_ADDR, // EP number 0, OUT from host (rx to device) .bEndpointAddress = EP0_OUT_ADDR, // EP number 0, OUT from host (rx to device)
.bmAttributes = USB_TRANSFER_TYPE_CONTROL, .bmAttributes = USB_TRANSFER_TYPE_CONTROL,
.wMaxPacketSize = 64, .wMaxPacketSize = 64,
.bInterval = 0 .bInterval = 0
}; };
static const struct usb_endpoint_descriptor ep0_in = { static const struct usb_endpoint_descriptor ep0_in = {
.bLength = sizeof(struct usb_endpoint_descriptor), .bLength = sizeof(struct usb_endpoint_descriptor),
.bDescriptorType = USB_DT_ENDPOINT, .bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = EP0_IN_ADDR, // EP number 0, OUT from host (rx to device) .bEndpointAddress = EP0_IN_ADDR, // EP number 0, OUT from host (rx to device)
.bmAttributes = USB_TRANSFER_TYPE_CONTROL, .bmAttributes = USB_TRANSFER_TYPE_CONTROL,
.wMaxPacketSize = 64, .wMaxPacketSize = 64,
.bInterval = 0 .bInterval = 0
}; };
// Descriptors // Descriptors
static const struct usb_device_descriptor device_descriptor = { static const struct usb_device_descriptor device_descriptor = {
.bLength = sizeof(struct usb_device_descriptor), .bLength = sizeof(struct usb_device_descriptor),
.bDescriptorType = USB_DT_DEVICE, .bDescriptorType = USB_DT_DEVICE,
.bcdUSB = 0x0200, // USB 1.1 device .bcdUSB = 0x0200, // USB 1.1 device
.bDeviceClass = 0, // Specified in interface descriptor .bDeviceClass = 0, // Specified in interface descriptor
.bDeviceSubClass = 0, // No subclass .bDeviceSubClass = 0, // No subclass
.bDeviceProtocol = 0, // No protocol .bDeviceProtocol = 0, // No protocol
.bMaxPacketSize0 = 64, // Max packet size for ep0 .bMaxPacketSize0 = 64, // Max packet size for ep0
.idVendor = 0x20a0, // Your vendor id .idVendor = 0x20a0, // Your vendor id
.idProduct = 0x4230, // Your product ID .idProduct = 0x4230, // Your product ID
.bcdDevice = 0x0101, // No device revision number .bcdDevice = 0x0101, // No device revision number
.iManufacturer = 1, // Manufacturer string index .iManufacturer = 1, // Manufacturer string index
.iProduct = 2, // Product string index .iProduct = 2, // Product string index
.iSerialNumber = 3, // No serial number .iSerialNumber = 3, // No serial number
.bNumConfigurations = 1 // One configuration .bNumConfigurations = 1 // One configuration
}; };
static const struct usb_interface_descriptor interface_descriptor = { static const struct usb_interface_descriptor interface_descriptor = {
.bLength = sizeof(struct usb_interface_descriptor), .bLength = sizeof(struct usb_interface_descriptor),
.bDescriptorType = USB_DT_INTERFACE, .bDescriptorType = USB_DT_INTERFACE,
.bInterfaceNumber = 0, .bInterfaceNumber = 0,
.bAlternateSetting = 0, .bAlternateSetting = 0,
.bNumEndpoints = 2, // Interface has 2 endpoints .bNumEndpoints = 2, // Interface has 2 endpoints
.bInterfaceClass = 0x0b, // Vendor specific endpoint .bInterfaceClass = 0x0b, // Vendor specific endpoint
.bInterfaceSubClass = 0, .bInterfaceSubClass = 0,
.bInterfaceProtocol = 0, .bInterfaceProtocol = 0,
.iInterface = 5 .iInterface = 5
}; };
static const struct usb_endpoint_descriptor ep1_out = { static const struct usb_endpoint_descriptor ep1_out = {
.bLength = sizeof(struct usb_endpoint_descriptor), .bLength = sizeof(struct usb_endpoint_descriptor),
.bDescriptorType = USB_DT_ENDPOINT, .bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = EP1_OUT_ADDR, // EP number 1, OUT from host (rx to device) .bEndpointAddress = EP1_OUT_ADDR, // EP number 1, OUT from host (rx to device)
.bmAttributes = USB_TRANSFER_TYPE_BULK, .bmAttributes = USB_TRANSFER_TYPE_BULK,
.wMaxPacketSize = 64, .wMaxPacketSize = 64,
.bInterval = 0 .bInterval = 0
}; };
static const struct usb_endpoint_descriptor ep2_in = { static const struct usb_endpoint_descriptor ep2_in = {
.bLength = sizeof(struct usb_endpoint_descriptor), .bLength = sizeof(struct usb_endpoint_descriptor),
.bDescriptorType = USB_DT_ENDPOINT, .bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = EP2_IN_ADDR, // EP number 2, IN from host (tx from device) .bEndpointAddress = EP2_IN_ADDR, // EP number 2, IN from host (tx from device)
.bmAttributes = USB_TRANSFER_TYPE_BULK, .bmAttributes = USB_TRANSFER_TYPE_BULK,
.wMaxPacketSize = 64, .wMaxPacketSize = 64,
.bInterval = 0 .bInterval = 0
}; };
static const struct usb_configuration_descriptor config_descriptor = { static const struct usb_configuration_descriptor config_descriptor = {
.bLength = sizeof(struct usb_configuration_descriptor), .bLength = sizeof(struct usb_configuration_descriptor),
.bDescriptorType = USB_DT_CONFIG, .bDescriptorType = USB_DT_CONFIG,
.wTotalLength = (sizeof(config_descriptor) + .wTotalLength = (sizeof(config_descriptor) +
sizeof(interface_descriptor) + sizeof(interface_descriptor) +
sizeof(ccid_desc) + sizeof(ccid_desc) +
sizeof(ep1_out) + sizeof(ep1_out) +
sizeof(ep2_in)), sizeof(ep2_in)),
.bNumInterfaces = 1, .bNumInterfaces = 1,
.bConfigurationValue = 1, // Configuration 1 .bConfigurationValue = 1, // Configuration 1
.iConfiguration = 4, // No string .iConfiguration = 4, // No string
.bmAttributes = 0xa0, // attributes: self powered, no remote wakeup .bmAttributes = 0xa0, // attributes: self powered, no remote wakeup
.bMaxPower = 0x32 // 100ma .bMaxPower = 0x32 // 100ma
}; };
static const unsigned char lang_descriptor[] = { static const unsigned char lang_descriptor[] = {
4, // bLength 4, // bLength
0x03, // bDescriptorType == String Descriptor 0x03, // bDescriptorType == String Descriptor
0x09, 0x04 // language id = us english 0x09, 0x04 // language id = us english
}; };
@ -322,3 +322,4 @@ extern bool usb_write_available();
extern uint32_t usb_write_flush(); extern uint32_t usb_write_flush();
#endif #endif

View file

@ -0,0 +1,233 @@
/*
* This file is part of the Pico HSM SDK distribution (https://github.com/polhenarejos/pico-hsm-sdk).
* 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 "pico/unique_id.h"
#include "hsm_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
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,
};
//--------------------------------------------------------------------+
// 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_SDK_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

@ -0,0 +1,46 @@
/*
* This file is part of the Pico HSM SDK distribution (https://github.com/polhenarejos/pico-hsm-sdk).
* 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_
struct ccid_class_descriptor {
uint8_t bLength;
uint8_t bDescriptorType;
uint16_t bcdCCID;
uint8_t bMaxSlotIndex;
uint8_t bVoltageSupport;
uint32_t dwProtocols;
uint32_t dwDefaultClock;
uint32_t dwMaximumClock;
uint8_t bNumClockSupport;
uint32_t dwDataRate;
uint32_t dwMaxDataRate;
uint8_t bNumDataRatesSupported;
uint32_t dwMaxIFSD;
uint32_t dwSynchProtocols;
uint32_t dwMechanical;
uint32_t dwFeatures;
uint32_t dwMaxCCIDMessageLength;
uint8_t bClassGetResponse;
uint8_t bclassEnvelope;
uint16_t wLcdLayout;
uint8_t bPINSupport;
uint8_t bMaxCCIDBusySlots;
} __attribute__ ((__packed__));
#endif /* USB_DESCRIPTORS_H_ */

View file

@ -1,343 +0,0 @@
/*
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
* Copyright (c) 2022 Pol Henarejos.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero 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
* Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "pico_keys.h"
#include "emulation.h"
#include <stdio.h>
#ifndef _MSC_VER
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <poll.h>
#include <netinet/tcp.h>
typedef int socket_t;
#include <fcntl.h>
#define INVALID_SOCKET (-1)
#define SOCKET_ERROR (-1)
#else
#include <ws2tcpip.h>
#define O_NONBLOCK _O_NONBLOCK
#define close closesocket
typedef SOCKET socket_t;
typedef int socklen_t;
#define msleep Sleep
#pragma comment(lib, "Ws2_32.lib")
#endif
#include <stdlib.h>
#include <errno.h>
#include <time.h>
#include "apdu.h"
#include "usb.h"
#include "ccid/ccid.h"
#include "hid/ctap_hid.h"
socket_t ccid_sock = 0;
socket_t hid_server_sock = 0;
socket_t hid_client_sock = INVALID_SOCKET;
extern uint8_t thread_type;
extern const uint8_t *cbor_data;
extern size_t cbor_len;
extern uint8_t cmd;
uint8_t emul_rx[USB_BUFFER_SIZE], emul_tx[USB_BUFFER_SIZE];
uint16_t emul_rx_size = 0, emul_tx_size = 0;
extern int cbor_parse(uint8_t cmd, const uint8_t *data, size_t len);
pthread_t hcore0, hcore1;
#ifndef _MSC_VER
int msleep(long msec) {
struct timespec ts;
int res;
if (msec < 0) {
errno = EINVAL;
return -1;
}
ts.tv_sec = msec / 1000;
ts.tv_nsec = (msec % 1000) * 1000000;
do {
res = nanosleep(&ts, &ts);
} while (res && errno == EINTR);
return res;
}
#endif
int emul_init(char *host, uint16_t port) {
struct sockaddr_in serv_addr;
fprintf(stderr, "\n Starting emulation envionrment\n");
#ifdef _MSC_VER
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
printf("winsock initialization failure\n");
}
#endif
if ((ccid_sock = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
perror("socket");
return -1;
}
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(port);
// Convert IPv4 and IPv6 addresses from text to binary
// form
if (inet_pton(AF_INET, host, &serv_addr.sin_addr) <= 0) {
perror("inet_pton");
close(ccid_sock);
return -1;
}
if (connect(ccid_sock, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) {
perror("connect");
close(ccid_sock);
return -1;
}
#ifdef _MSC_VER
unsigned long on = 1;
if (0 != ioctlsocket(ccid_sock, FIONBIO, &on)) {
perror("ioctlsocket FIONBIO");
}
#else
int x = fcntl(ccid_sock, F_GETFL, 0);
fcntl(ccid_sock, F_SETFL, x | O_NONBLOCK);
int flag = 1;
setsockopt(ccid_sock, IPPROTO_TCP, TCP_NODELAY, (char *)&flag, sizeof(int));
#endif
// HID server
socklen_t yes = 1;
uint16_t hid_port = port - 1;
struct sockaddr_in server_sockaddr;
if ((hid_server_sock = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
perror("socket");
return -1;
}
if (setsockopt(hid_server_sock, SOL_SOCKET, SO_REUSEADDR, (void *) &yes, sizeof yes) != 0) {
perror("setsockopt");
close(hid_server_sock);
return 1;
}
#if defined(HAVE_DECL_SO_NOSIGPIPE)
if (setsockopt(hid_server_sock, SOL_SOCKET, SO_NOSIGPIPE, (void *) &yes, sizeof yes) != 0) {
perror("setsockopt");
close(hid_server_sock);
return 1;
}
#endif
memset(&server_sockaddr, 0, sizeof server_sockaddr);
server_sockaddr.sin_family = PF_INET;
server_sockaddr.sin_port = htons(hid_port);
server_sockaddr.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind(hid_server_sock, (struct sockaddr *) &server_sockaddr,
sizeof server_sockaddr) != 0) {
perror("bind");
close(hid_server_sock);
return 1;
}
if (listen(hid_server_sock, 0) != 0) {
perror("listen");
close(hid_server_sock);
return 1;
}
return 0;
}
socket_t get_sock_itf(uint8_t itf) {
#ifdef USB_ITF_CCID
if (itf == ITF_CCID) {
return ccid_sock;
}
#endif
#ifdef USB_ITF_HID
if (itf == ITF_HID) {
return hid_client_sock;
}
#endif
return INVALID_SOCKET;
}
uint32_t tud_vendor_n_write(uint8_t itf, const uint8_t *buffer, uint32_t n) {
uint16_t ret = driver_write_emul(ITF_CCID, buffer, (uint16_t)n);
tud_vendor_tx_cb(itf, ret);
return ret;
}
#ifdef USB_ITF_HID
bool tud_hid_n_report(uint8_t itf, uint8_t report_id, const uint8_t *buffer, uint32_t n) {
(void) itf;
(void) report_id;
uint16_t ret = driver_write_emul(ITF_HID, buffer, (uint16_t)n);
return ret > 0;
}
#endif
uint16_t driver_write_emul(uint8_t itf, const uint8_t *buffer, uint16_t buffer_size) {
uint16_t size = htons(buffer_size);
socket_t sock = get_sock_itf(itf);
// DEBUG_PAYLOAD(buffer,buffer_size);
int ret = 0;
do {
ret = send(sock, (const char *)&size, sizeof(size), 0);
if (ret == SOCKET_ERROR) {
msleep(10);
}
} while (ret <= 0);
do {
ret = send(sock, (const char *)buffer, buffer_size, 0);
if (ret == SOCKET_ERROR) {
msleep(10);
}
} while (ret <= 0);
emul_tx_size = buffer_size;
return buffer_size;
}
void driver_exec_finished_cont_emul(uint8_t itf, uint16_t size_next, uint16_t offset) {
#ifdef USB_ITF_HID
if (itf == ITF_HID) {
driver_exec_finished_cont_hid(itf, size_next, offset);
}
#endif
#ifdef USB_ITF_CCID
if (itf == ITF_CCID) {
driver_write_emul(itf, emul_tx + offset, size_next);
}
#endif
}
uint16_t emul_read(uint8_t itf) {
/* First we look for a client */
#ifdef USB_ITF_HID
if (itf == ITF_HID) {
struct sockaddr_in client_sockaddr;
socklen_t client_socklen = sizeof client_sockaddr;
int timeout;
struct pollfd pfd;
pfd.fd = hid_server_sock;
pfd.events = POLLIN;
pfd.revents = 0;
timeout = (0 * 1000 + 1000 / 1000);
if (poll(&pfd, 1, timeout) == -1) {
return 0;
}
if (pfd.revents & POLLIN) {
if (hid_client_sock > 0) {
close(hid_client_sock);
}
hid_client_sock = accept(hid_server_sock, (struct sockaddr *) &client_sockaddr, &client_socklen);
if (hid_client_sock != INVALID_SOCKET) {
printf("hid_client connected! %d\n", hid_client_sock);
}
}
/*if (send_buffer_size > 0) {
last_write_result[itf] = WRITE_PENDING;
tud_hid_report_complete_cb(ITF_HID, complete_report, complete_len);
}*/
}
#endif
socket_t sock = get_sock_itf(itf);
//printf("get_sockt itf %d - %d\n", itf, sock);
uint16_t len = 0;
fd_set input;
FD_ZERO(&input);
#ifdef _WIN32
__pragma(warning(push))
__pragma(warning(disable:4548))
#endif
FD_SET(sock, &input);
#ifdef _WIN32
__pragma(warning(pop))
#endif
struct timeval timeout;
int valread = 0;
timeout.tv_sec = 0;
timeout.tv_usec = 0 * 1000;
int n = select((int)(sock + 1), &input, NULL, NULL, &timeout);
if (n == -1) {
//printf("read wrong [itf:%d]\n", itf);
//something wrong
}
else if (n == 0) {
//printf("read timeout [itf:%d]\n", itf);
}
if (FD_ISSET(sock, &input)) {
valread = recv(sock, (char *)&len, sizeof(len), 0);
len = ntohs(len);
if (len > 0) {
while (true) {
valread = recv(sock, (char *)emul_rx + emul_rx_size, len, 0);
if (valread > 0) {
if (len == 1) {
uint8_t c = emul_rx[0];
if (c == 4) {
driver_write_emul(itf, ccid_atr ? ccid_atr + 1 : NULL, ccid_atr ? ccid_atr[0] : 0);
}
}
#ifdef USB_ITF_CCID
else if (itf == ITF_CCID) {
uint16_t sent = 0;
DEBUG_PAYLOAD(emul_rx, len);
apdu.rdata = emul_tx;
if ((sent = apdu_process(itf, emul_rx, len)) > 0) {
process_apdu();
apdu_finish();
}
if (sent > 0) {
uint16_t ret = apdu_next();
DEBUG_PAYLOAD(apdu.rdata, ret);
driver_write_emul(itf, apdu.rdata, ret);
}
}
#endif
else {
emul_rx_size += valread;
}
return (uint16_t)emul_rx_size;
}
msleep(10);
}
}
}
//else
// printf("no input for sock %d - %d\n", itf, sock);
return emul_rx_size;
}
void emul_task() {
#ifdef USB_ITF_CCID
emul_read(ITF_CCID);
#endif
#ifdef USB_ITF_HID
emul_read(ITF_HID);
#endif
}

View file

@ -1,65 +0,0 @@
/*
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
* Copyright (c) 2022 Pol Henarejos.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero 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
* Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef _EMULATION_H_
#define _EMULATION_H_
#include <stdint.h>
#include <string.h>
#include "queue.h"
#include "board.h"
#include <stdbool.h>
#define USB_BUFFER_SIZE 2048
extern int emul_init(char *host, uint16_t port);
extern uint8_t emul_rx[USB_BUFFER_SIZE];
extern uint16_t emul_rx_size, emul_tx_size;
extern uint16_t driver_write_emul(uint8_t itf, const uint8_t *buffer, uint16_t buffer_size);
extern uint16_t emul_read(uint8_t itf);
#ifdef USB_ITF_HID
typedef uint8_t hid_report_type_t;
#endif
#ifdef USB_ITF_CCID
static inline uint32_t tud_vendor_n_available(uint8_t itf) {
(void) itf;
return emul_rx_size;
}
static inline uint32_t tud_vendor_n_read(uint8_t itf, uint8_t *buffer, uint32_t n) {
(void) itf;
if (n > emul_rx_size) {
n = emul_rx_size;
}
memcpy(buffer, emul_rx, n);
emul_rx_size = 0;
return n;
}
extern void tud_vendor_tx_cb(uint8_t itf, uint32_t sent_bytes);
extern uint32_t tud_vendor_n_write(uint8_t itf, const uint8_t *buffer, uint32_t n);
static inline uint32_t tud_vendor_n_flush(uint8_t itf) {
(void) itf;
return emul_tx_size;
}
#endif
#ifdef USB_ITF_HID
extern void tud_hid_report_complete_cb(uint8_t instance, uint8_t const *report, uint16_t len);
extern bool tud_hid_n_report(uint8_t itf, uint8_t report_id, const uint8_t *buffer, uint32_t n);
#endif
#endif // _EMULATION_H_

View file

@ -1,168 +0,0 @@
/*
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
* Copyright (c) 2022 Pol Henarejos.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero 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
* Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef _CTAP_HID_H_
#define _CTAP_HID_H_
#include <stdint.h>
#include <stdlib.h>
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
#include "usb.h"
// Size of HID reports
#define HID_RPT_SIZE 64 // Default size of raw HID report
// Frame layout - command- and continuation frames
#define CID_BROADCAST 0xffffffff // Broadcast channel id
#define TYPE_MASK 0x80 // Frame type mask
#define TYPE_INIT 0x80 // Initial frame identifier
#define TYPE_CONT 0x00 // Continuation frame identifier
PACK(
typedef struct {
uint32_t cid; // Channel identifier
union {
uint8_t type; // Frame type - b7 defines type
struct {
uint8_t cmd; // Command - b7 set
uint8_t bcnth; // Message byte count - high part
uint8_t bcntl; // Message byte count - low part
uint8_t data[HID_RPT_SIZE - 7]; // Data payload
} init;
struct {
uint8_t seq; // Sequence number - b7 cleared
uint8_t data[HID_RPT_SIZE - 5]; // Data payload
} cont;
};
}) CTAPHID_FRAME;
extern CTAPHID_FRAME *ctap_req, *ctap_resp;
#define FRAME_TYPE(f) ((f)->type & TYPE_MASK)
#define FRAME_CMD(f) ((f)->init.cmd & ~TYPE_MASK)
#define MSG_LEN(f) ((f)->init.bcnth * 256 + (f)->init.bcntl)
#define FRAME_SEQ(f) ((f)->cont.seq & ~TYPE_MASK)
// HID usage- and usage-page definitions
#define FIDO_USAGE_PAGE 0xf1d0 // FIDO alliance HID usage page
#define FIDO_USAGE_CTAPHID 0x01 // CTAPHID usage for top-level collection
#define FIDO_USAGE_DATA_IN 0x20 // Raw IN data report
#define FIDO_USAGE_DATA_OUT 0x21 // Raw OUT data report
// General constants
#define CTAPHID_IF_VERSION 2 // Current interface implementation version
#define CTAPHID_TRANS_TIMEOUT 3000 // Default message timeout in ms
// CTAPHID native commands
#define CTAPHID_PING (TYPE_INIT | 0x01) // Echo data through local processor only
#define CTAPHID_MSG (TYPE_INIT | 0x03) // Send CTAP message frame
#define CTAPHID_LOCK (TYPE_INIT | 0x04) // Send lock channel command
#define CTAPHID_INIT (TYPE_INIT | 0x06) // Channel initialization
#define CTAPHID_WINK (TYPE_INIT | 0x08) // Send device identification wink
#define CTAPHID_CBOR (TYPE_INIT | 0x10) // CBOR
#define CTAPHID_CANCEL (TYPE_INIT | 0x11) // Cancel any request
#define CTAPHID_KEEPALIVE (TYPE_INIT | 0x3B) // Keepalive command
#define CTAPHID_SYNC (TYPE_INIT | 0x3C) // Protocol resync command
#define CTAPHID_ERROR (TYPE_INIT | 0x3F) // Error response
#define CTAPHID_UPDATE (TYPE_INIT | 0x51)
#define CTAPHID_REBOOT (TYPE_INIT | 0x53)
#define CTAPHID_RNG (TYPE_INIT | 0x60)
#define CTAPHID_VERSION (TYPE_INIT | 0x61)
#define CTAPHID_UUID (TYPE_INIT | 0x62)
#define CTAPHID_LOCKED (TYPE_INIT | 0x63)
#define CTAPHID_OTP (TYPE_INIT | 0x70)
#define CTAPHID_PROVISIONER (TYPE_INIT | 0x71)
#define CTAPHID_ADMIN (TYPE_INIT | 0x72)
#define CTAPHID_VENDOR_FIRST (TYPE_INIT | 0x40) // First vendor defined command
#define CTAPHID_VENDOR_LAST (TYPE_INIT | 0x7F) // Last vendor defined command
// CTAP_KEEPALIVE command defines
#define KEEPALIVE_STATUS_PROCESSING 0x1
#define KEEPALIVE_STATUS_UPNEEDED 0x2
// CTAPHID_INIT command defines
#define INIT_NONCE_SIZE 8 // Size of channel initialization challenge
#define CAPFLAG_WINK 0x01 // Device supports WINK command
#define CAPFLAG_CBOR 0x04 // Device supports CBOR command
PACK(
typedef struct {
uint8_t nonce[INIT_NONCE_SIZE]; // Client application nonce
}) CTAPHID_INIT_REQ;
PACK(
typedef struct {
uint8_t nonce[INIT_NONCE_SIZE]; // Client application nonce
uint32_t cid; // Channel identifier
uint8_t versionInterface; // Interface version
uint8_t versionMajor; // Major version number
uint8_t versionMinor; // Minor version number
uint8_t versionBuild; // Build version number
uint8_t capFlags; // Capabilities flags
}) CTAPHID_INIT_RESP;
// CTAPHID_SYNC command defines
typedef struct {
uint8_t nonce; // Client application nonce
} CTAPHID_SYNC_REQ;
typedef struct {
uint8_t nonce; // Client application nonce
} CTAPHID_SYNC_RESP;
// Low-level error codes. Return as negatives.
#define CTAP_MAX_PACKET_SIZE (64 - 7 + 128 * (64 - 5))
#define CTAP_MAX_CBOR_PAYLOAD (USB_BUFFER_SIZE - 64 - 7 - 1)
#define CTAP1_ERR_NONE 0x00 // No error
#define CTAP1_ERR_INVALID_CMD 0x01 // Invalid command
#define CTAP1_ERR_INVALID_PARAMETER 0x02 // Invalid parameter
#define CTAP1_ERR_INVALID_LEN 0x03 // Invalid message length
#define CTAP1_ERR_INVALID_SEQ 0x04 // Invalid message sequencing
#define CTAP1_ERR_MSG_TIMEOUT 0x05 // Message has timed out
#define CTAP1_ERR_CHANNEL_BUSY 0x06 // Channel busy
#define CTAP1_ERR_LOCK_REQUIRED 0x0a // Command requires channel lock
#define CTAP1_ERR_INVALID_CHANNEL 0x0b // CID not valid
#define CTAP1_ERR_OTHER 0x7f // Other unspecified error
extern void add_keyboard_buffer(const uint8_t *, size_t, bool);
extern void append_keyboard_buffer(const uint8_t *data, size_t data_len);
extern bool is_nk;
#ifdef __cplusplus
}
#endif
#endif // _CTAP_HID_H_

View file

@ -1,647 +1,141 @@
/* /*
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk). * This file is part of the Pico HSM SDK distribution (https://github.com/polhenarejos/pico-hsm-sdk).
* Copyright (c) 2022 Pol Henarejos. * Copyright (c) 2022 Pol Henarejos.
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3. * the Free Software Foundation, version 3.
* *
* This program is distributed in the hope that it will be useful, but * This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of * WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Affero General Public License for more details. * General Public License for more details.
* *
* You should have received a copy of the GNU Affero General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "pico_keys.h"
#ifndef ENABLE_EMULATION
#include "tusb.h" #include "tusb.h"
#if defined(PICO_PLATFORM) #include "u2f_hid.h"
#include "bsp/board.h" #include "hsm.h"
#elif defined(ESP_PLATFORM) #include "hsm_version.h"
static portMUX_TYPE mutex = portMUX_INITIALIZER_UNLOCKED;
#endif
#else
#include "emulation.h"
#endif
#include "ctap_hid.h"
#include "pico_keys_version.h"
#include "apdu.h" #include "apdu.h"
#include "usb.h" #include "usb.h"
extern void init_fido(); static bool mounted = false;
bool is_nk = false;
uint8_t (*get_version_major)() = NULL;
uint8_t (*get_version_minor)() = NULL;
static usb_buffer_t *hid_rx = NULL, *hid_tx = NULL; void tud_mount_cb()
{
PACK( mounted = true;
typedef struct msg_packet {
uint16_t len;
uint16_t current_len;
uint8_t data[CTAP_MAX_PACKET_SIZE];
}) msg_packet_t;
msg_packet_t msg_packet = { 0 };
static uint16_t *send_buffer_size = NULL;
static write_status_t *last_write_result = NULL;
CTAPHID_FRAME *ctap_req = NULL, *ctap_resp = NULL;
void send_keepalive();
int driver_process_usb_packet_hid(uint16_t read);
int driver_write_hid(uint8_t itf, const uint8_t *buffer, uint16_t buffer_size);
int driver_process_usb_nopacket_hid();
void hid_init() {
if (ITF_HID_TOTAL == 0) {
return;
}
if (send_buffer_size == NULL) {
send_buffer_size = (uint16_t *)calloc(ITF_HID_TOTAL, sizeof(uint16_t));
}
if (last_write_result == NULL) {
last_write_result = (write_status_t *)calloc(ITF_HID_TOTAL, sizeof(write_status_t));
}
if (hid_rx == NULL) {
hid_rx = (usb_buffer_t *)calloc(ITF_HID_TOTAL, sizeof(usb_buffer_t));
}
if (hid_tx == NULL) {
hid_tx = (usb_buffer_t *)calloc(ITF_HID_TOTAL, sizeof(usb_buffer_t));
}
} }
int driver_init_hid() { bool driver_mounted() {
#ifndef ENABLE_EMULATION return mounted;
static bool _init = false; }
if (_init == false) {
tud_init(BOARD_TUD_RHPORT);
_init = true;
}
#endif
ctap_req = (CTAPHID_FRAME *) (hid_rx[ITF_HID_CTAP].buffer + hid_rx[ITF_HID_CTAP].r_ptr);
apdu.header = ctap_req->init.data;
ctap_resp = (CTAPHID_FRAME *) (hid_tx[ITF_HID_CTAP].buffer); U2FHID_FRAME *u2f_req, *u2f_resp;
apdu.rdata = ctap_resp->init.data;
memset(ctap_resp, 0, sizeof(CTAPHID_FRAME));
usb_set_timeout_counter(ITF_HID, 200); int driver_init() {
tud_init(BOARD_TUD_RHPORT);
u2f_req = (U2FHID_FRAME *)usb_get_rx();
apdu.header = u2f_req->init.data;
is_nk = false; u2f_resp = (U2FHID_FRAME *)usb_get_tx();
apdu.rdata = u2f_resp->init.data;
hid_tx[ITF_HID_CTAP].w_ptr = hid_tx[ITF_HID_CTAP].r_ptr = 0;
send_buffer_size[ITF_HID_CTAP] = 0;
return 0; return 0;
} }
void driver_task() {
uint16_t *get_send_buffer_size(uint8_t itf) { tud_task(); // tinyusb device task
return &send_buffer_size[itf];
} }
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
// USB HID // USB HID
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
uint16_t (*hid_get_report_cb)(uint8_t, uint8_t, hid_report_type_t, uint8_t *, uint16_t) = NULL;
// Invoked when received GET_REPORT control request // Invoked when received GET_REPORT control request
// Application must fill buffer report's content and return its length. // Application must fill buffer report's content and return its length.
// Return zero will cause the stack to STALL request // Return zero will cause the stack to STALL request
uint16_t tud_hid_get_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t* buffer, uint16_t reqlen)
{
// TODO not Implemented
(void) itf;
(void) report_id;
(void) report_type;
(void) buffer;
(void) reqlen;
printf("get_report\n");
DEBUG_PAYLOAD(buffer, reqlen);
uint16_t tud_hid_get_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen) { return 0;
// TODO not Implemented
(void) itf;
(void) report_id;
(void) report_type;
(void) buffer;
(void) reqlen;
printf("get_report %d %d %d\n", itf, report_id, report_type);
memset(buffer, 0, reqlen);
DEBUG_PAYLOAD(buffer, reqlen);
if (hid_get_report_cb) {
hid_get_report_cb(itf, report_id, report_type, buffer, reqlen);
}
return reqlen;
} }
uint32_t hid_write_offset(uint16_t size, uint16_t offset) { int driver_write(const uint8_t *buffer, size_t buffer_size) {
if (hid_tx[ITF_HID_CTAP].buffer[offset] != 0x81) { return tud_hid_report(0, buffer, buffer_size);
DEBUG_PAYLOAD(&hid_tx[ITF_HID_CTAP].buffer[offset], size);
}
hid_tx[ITF_HID_CTAP].w_ptr += size + offset;
hid_tx[ITF_HID_CTAP].r_ptr += offset;
return size;
} }
uint32_t hid_write(uint16_t size) { size_t driver_read(uint8_t *buffer, size_t buffer_size) {
return hid_write_offset(size, 0); return 0;
} }
#ifndef ENABLE_EMULATION
static uint8_t keyboard_buffer[256];
static uint8_t keyboard_buffer_len = 0;
static const uint8_t conv_table[128][2] = { HID_ASCII_TO_KEYCODE };
static uint8_t keyboard_w = 0;
static bool sent_key = false;
static bool keyboard_encode = false;
void add_keyboard_buffer(const uint8_t *data, size_t data_len, bool encode) {
keyboard_buffer_len = (uint8_t)MIN(sizeof(keyboard_buffer), data_len);
memcpy(keyboard_buffer, data, keyboard_buffer_len);
keyboard_encode = encode;
}
void append_keyboard_buffer(const uint8_t *data, size_t data_len) {
if (keyboard_buffer_len + data_len < sizeof(keyboard_buffer)) {
memcpy(keyboard_buffer + keyboard_buffer_len, data, MIN(sizeof(keyboard_buffer) - keyboard_buffer_len, data_len));
keyboard_buffer_len += (uint8_t)MIN(sizeof(keyboard_buffer) - keyboard_buffer_len, data_len);
}
}
static void send_hid_report(uint8_t report_id) {
if (!tud_hid_ready()) {
return;
}
switch (report_id) {
case REPORT_ID_KEYBOARD: {
if (keyboard_w < keyboard_buffer_len) {
if (sent_key == false) {
uint8_t keycode[6] = { 0 };
uint8_t modifier = 0;
uint8_t chr = keyboard_buffer[keyboard_w];
if (keyboard_encode) {
if (conv_table[chr][0]) {
modifier = KEYBOARD_MODIFIER_LEFTSHIFT;
}
keycode[0] = conv_table[chr][1];
}
else {
if (chr & 0x80) {
modifier = KEYBOARD_MODIFIER_LEFTSHIFT;
}
keycode[0] = chr & 0x7f;
}
if (tud_hid_n_keyboard_report(ITF_HID_KB, REPORT_ID_KEYBOARD, modifier, keycode) == true) {
sent_key = true;
}
}
else {
if (tud_hid_n_keyboard_report(ITF_HID_KB, REPORT_ID_KEYBOARD, 0, NULL) == true) {
keyboard_w++;
sent_key = false;
}
}
}
else if (keyboard_w == keyboard_buffer_len && keyboard_buffer_len > 0) {
keyboard_w = keyboard_buffer_len = 0;
}
}
break;
default: break;
}
}
#endif
void tud_hid_report_complete_cb(uint8_t instance, uint8_t const *report, uint16_t len) {
//printf("report_complete %d %d %d\n", instance, len, send_buffer_size[instance]);
if (instance == ITF_HID_CTAP && len > 0) {
#ifdef ESP_PLATFORM
taskENTER_CRITICAL(&mutex);
#endif
CTAPHID_FRAME *req = (CTAPHID_FRAME *) report;
if (last_write_result[instance] == WRITE_PENDING) {
last_write_result[instance] = WRITE_SUCCESS;
if (FRAME_TYPE(req) == TYPE_INIT) {
if (req->init.cmd != CTAPHID_KEEPALIVE) {
send_buffer_size[instance] -= MIN(64 - 7, send_buffer_size[instance]);
}
}
else {
send_buffer_size[instance] -= MIN(64 - 5, send_buffer_size[instance]);
}
}
if (last_write_result[instance] == WRITE_SUCCESS) {
if (FRAME_TYPE(req) != TYPE_INIT || req->init.cmd != CTAPHID_KEEPALIVE) {
if (send_buffer_size[instance] > 0) {
ctap_resp = (CTAPHID_FRAME *) ((uint8_t *) ctap_resp + 64 - 5);
uint8_t seq = FRAME_TYPE(req) == TYPE_INIT ? 0 : FRAME_SEQ(req) + 1;
ctap_resp->cid = req->cid;
ctap_resp->cont.seq = seq;
hid_tx[ITF_HID_CTAP].r_ptr += 64 - 5;
}
else {
hid_tx[ITF_HID_CTAP].r_ptr += 64;
}
}
}
if (hid_tx[ITF_HID_CTAP].r_ptr >= hid_tx[ITF_HID_CTAP].w_ptr) {
hid_tx[ITF_HID_CTAP].r_ptr = hid_tx[ITF_HID_CTAP].w_ptr = 0;
}
#ifdef ESP_PLATFORM
taskEXIT_CRITICAL(&mutex);
#endif
}
}
int driver_write_hid(uint8_t itf, const uint8_t *buffer, uint16_t buffer_size) {
if (last_write_result[itf] == WRITE_PENDING) {
return 0;
}
bool r = tud_hid_n_report(itf, 0, buffer, buffer_size);
last_write_result[itf] = r ? WRITE_PENDING : WRITE_FAILED;
if (last_write_result[itf] == WRITE_FAILED) {
return 0;
}
#ifdef ENABLE_EMULATION
tud_hid_report_complete_cb(ITF_HID_CTAP, buffer, buffer_size);
#endif
return MIN(64, buffer_size);
}
int (*hid_set_report_cb)(uint8_t, uint8_t, hid_report_type_t, uint8_t const *, uint16_t) = NULL;
// Invoked when received SET_REPORT control request or // Invoked when received SET_REPORT control request or
// received data on OUT endpoint ( Report ID = 0, Type = 0 ) // received data on OUT endpoint ( Report ID = 0, Type = 0 )
void tud_hid_set_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t const* buffer, uint16_t bufsize)
void tud_hid_set_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize) { {
// This example doesn't use multiple report and report ID // This example doesn't use multiple report and report ID
(void) itf; (void) itf;
(void) report_id; (void) report_id;
(void) report_type; (void) report_type;
printf("set_report %d %d %d\n", itf, report_id, report_type); printf("set report\n");
if (!hid_set_report_cb || hid_set_report_cb(itf, report_id, report_type, buffer, bufsize) == 0) { usb_rx(buffer, bufsize);
//usb_rx(itf, buffer, bufsize);
if (itf == ITF_HID_CTAP) {
memcpy(hid_rx[itf].buffer + hid_rx[itf].w_ptr, buffer, bufsize);
hid_rx[itf].w_ptr += bufsize;
int proc_pkt = driver_process_usb_packet_hid(64);
if (proc_pkt == 0) {
driver_process_usb_nopacket_hid();
}
}
}
} }
uint32_t last_cmd_time = 0, last_packet_time = 0; void hid_write_offset(uint16_t size, uint16_t offset) {
int ctap_error(uint8_t error) { if (*usb_get_tx() != 0x81)
memset((uint8_t *)ctap_resp, 0, sizeof(CTAPHID_FRAME)); DEBUG_PAYLOAD(usb_get_tx()+offset,size+10);
ctap_resp->cid = ctap_req->cid; usb_write_offset(size, offset);
ctap_resp->init.cmd = CTAPHID_ERROR;
ctap_resp->init.bcntl = 1;
ctap_resp->init.data[0] = error;
hid_write(64);
last_packet_time = 0;
return 0;
} }
uint8_t last_cmd = 0; void hid_write(uint16_t size) {
uint8_t last_seq = 0; hid_write_offset(size, 0);
CTAPHID_FRAME last_req = { 0 };
uint32_t lock = 0;
uint8_t thread_type = 0; //1 is APDU, 2 is CBOR
extern bool cancel_button;
extern int cbor_process(uint8_t last_cmd, const uint8_t *data, size_t len);
int driver_process_usb_nopacket_hid() {
if (last_packet_time > 0 && last_packet_time + 500 < board_millis()) {
ctap_error(CTAP1_ERR_MSG_TIMEOUT);
last_packet_time = 0;
msg_packet.len = msg_packet.current_len = 0;
}
return 0;
} }
extern const uint8_t fido_aid[], u2f_aid[], oath_aid[]; int driver_process_usb_packet(uint16_t read) {
extern void *cbor_thread(void *); if (read >= 10)
{
int driver_process_usb_packet_hid(uint16_t read) { if (FRAME_TYPE(u2f_req) == TYPE_INIT) {
int apdu_sent = 0; printf("command %x\n", FRAME_CMD(u2f_req));
if (read >= 5) { printf("len %d\n", MSG_LEN(u2f_req));
driver_init_hid(); DEBUG_PAYLOAD(u2f_req->init.data, MSG_LEN(u2f_req));
hid_rx[ITF_HID_CTAP].r_ptr += 64;
if (hid_rx[ITF_HID_CTAP].r_ptr >= hid_rx[ITF_HID_CTAP].w_ptr) {
hid_rx[ITF_HID_CTAP].r_ptr = hid_rx[ITF_HID_CTAP].w_ptr = 0;
} }
last_packet_time = board_millis(); if (u2f_req->init.cmd == U2FHID_INIT) {
DEBUG_PAYLOAD((uint8_t *)ctap_req, 64); U2FHID_INIT_REQ *req = (U2FHID_INIT_REQ *)u2f_req->init.data;
if (ctap_req->cid == 0x0 || U2FHID_INIT_RESP *resp = (U2FHID_INIT_RESP *)u2f_resp->init.data;
(ctap_req->cid == CID_BROADCAST && (FRAME_TYPE(ctap_req) != TYPE_INIT || ctap_req->init.cmd != CTAPHID_INIT))) {
return ctap_error(CTAP1_ERR_INVALID_CHANNEL);
}
if (board_millis() < lock && ctap_req->cid != last_req.cid &&
last_cmd_time + 100 > board_millis()) {
return ctap_error(CTAP1_ERR_CHANNEL_BUSY);
}
if (FRAME_TYPE(ctap_req) == TYPE_INIT) {
if (MSG_LEN(ctap_req) > CTAP_MAX_PACKET_SIZE) {
return ctap_error(CTAP1_ERR_INVALID_LEN);
}
if (msg_packet.len > 0 && last_cmd_time + 100 > board_millis() &&
ctap_req->init.cmd != CTAPHID_INIT) {
if (last_req.cid != ctap_req->cid) { //We are in a transaction
return ctap_error(CTAP1_ERR_CHANNEL_BUSY);
}
else {
return ctap_error(CTAP1_ERR_INVALID_SEQ);
}
}
printf("command %x\n", FRAME_CMD(ctap_req));
printf("len %d\n", MSG_LEN(ctap_req));
msg_packet.len = msg_packet.current_len = 0;
if (MSG_LEN(ctap_req) > 64 - 7) {
msg_packet.len = MSG_LEN(ctap_req);
memcpy(msg_packet.data + msg_packet.current_len, ctap_req->init.data, 64 - 7);
msg_packet.current_len += 64 - 7;
}
memcpy(&last_req, ctap_req, sizeof(CTAPHID_FRAME));
last_cmd = ctap_req->init.cmd;
last_seq = 0;
last_cmd_time = board_millis();
}
else {
if (msg_packet.len == 0) { //Received a cont with a prior init pkt
return 0;
}
if (last_seq != ctap_req->cont.seq) {
return ctap_error(CTAP1_ERR_INVALID_SEQ);
}
if (last_req.cid == ctap_req->cid) {
memcpy(msg_packet.data + msg_packet.current_len, ctap_req->cont.data,
MIN(64 - 5, msg_packet.len - msg_packet.current_len));
msg_packet.current_len += MIN(64 - 5, msg_packet.len - msg_packet.current_len);
memcpy(&last_req, ctap_req, sizeof(CTAPHID_FRAME));
last_seq++;
}
else if (last_cmd_time + 100 > board_millis()) {
return ctap_error(CTAP1_ERR_CHANNEL_BUSY);
}
}
if (ctap_req->init.cmd == CTAPHID_INIT) {
card_exit();
hid_tx[ITF_HID_CTAP].r_ptr = hid_tx[ITF_HID_CTAP].w_ptr = 0;
init_fido();
CTAPHID_INIT_REQ *req = (CTAPHID_INIT_REQ *) ctap_req->init.data;
CTAPHID_INIT_RESP *resp = (CTAPHID_INIT_RESP *) ctap_resp->init.data;
memcpy(resp->nonce, req->nonce, sizeof(resp->nonce)); memcpy(resp->nonce, req->nonce, sizeof(resp->nonce));
resp->cid = 0x01000000; resp->cid = 0x01000000;
resp->versionInterface = CTAPHID_IF_VERSION; resp->versionInterface = U2FHID_IF_VERSION;
resp->versionMajor = get_version_major ? get_version_major() : PICO_KEYS_SDK_VERSION_MAJOR; resp->versionMajor = HSM_SDK_VERSION_MAJOR;
resp->versionMinor = get_version_minor ? get_version_minor() : PICO_KEYS_SDK_VERSION_MINOR; resp->versionMinor = HSM_SDK_VERSION_MINOR;
resp->capFlags = CAPFLAG_WINK | CAPFLAG_CBOR; resp->capFlags = CAPFLAG_WINK;
ctap_resp->cid = ctap_req->cid; u2f_resp->cid = CID_BROADCAST;
ctap_resp->init.cmd = CTAPHID_INIT; u2f_resp->init.cmd = U2FHID_INIT;
ctap_resp->init.bcntl = 17; u2f_resp->init.bcntl = 17;
ctap_resp->init.bcnth = 0; u2f_resp->init.bcnth = 0;
driver_write_hid(ITF_HID_CTAP, (const uint8_t *)ctap_resp, 64); hid_write(64);
msg_packet.len = msg_packet.current_len = 0; DEBUG_PAYLOAD((uint8_t *)u2f_resp, u2f_resp->init.bcntl+7);
last_packet_time = 0;
}
else if (ctap_req->init.cmd == CTAPHID_WINK) {
if (MSG_LEN(ctap_req) != 0) {
return ctap_error(CTAP1_ERR_INVALID_LEN);
}
last_packet_time = 0;
memcpy(ctap_resp, ctap_req, sizeof(CTAPHID_FRAME));
#if defined(PICO_PLATFORM) || defined(ESP_PLATFORM)
sleep_ms(1000); //For blinking the device during 1 seg
#endif
driver_write_hid(ITF_HID_CTAP, (const uint8_t *)ctap_resp, 64);
msg_packet.len = msg_packet.current_len = 0;
}
else if ((last_cmd == CTAPHID_PING || last_cmd == CTAPHID_SYNC) &&
(msg_packet.len == 0 ||
(msg_packet.len == msg_packet.current_len && msg_packet.len > 0))) {
if (msg_packet.current_len == msg_packet.len && msg_packet.len > 0) {
memcpy(ctap_resp->init.data, msg_packet.data, msg_packet.len);
driver_exec_finished_hid(msg_packet.len);
}
else {
memcpy(ctap_resp->init.data, ctap_req->init.data, MSG_LEN(ctap_req));
ctap_resp->cid = ctap_req->cid;
ctap_resp->init.cmd = last_cmd;
ctap_resp->init.bcnth = MSG_LEN(ctap_req) >> 8;
ctap_resp->init.bcntl = MSG_LEN(ctap_req) & 0xff;
driver_write_hid(ITF_HID_CTAP, (const uint8_t *)ctap_resp, 64);
}
msg_packet.len = msg_packet.current_len = 0;
last_packet_time = 0;
}
else if (ctap_req->init.cmd == CTAPHID_LOCK) {
if (MSG_LEN(ctap_req) != 1) {
return ctap_error(CTAP1_ERR_INVALID_LEN);
}
if (ctap_req->init.data[0] > 10) {
return ctap_error(CTAP1_ERR_INVALID_PARAMETER);
}
lock = board_millis() + ctap_req->init.data[0] * 1000;
ctap_resp->cid = ctap_req->cid;
ctap_resp->init.cmd = ctap_req->init.cmd;
driver_write_hid(ITF_HID_CTAP, (const uint8_t *)ctap_resp, 64);
msg_packet.len = msg_packet.current_len = 0;
last_packet_time = 0;
}
else if (ctap_req->init.cmd == CTAPHID_UUID) {
ctap_resp->cid = ctap_req->cid;
ctap_resp->init.cmd = ctap_req->init.cmd;
memcpy(ctap_resp->init.data, pico_serial.id, sizeof(pico_serial.id));
ctap_resp->init.bcntl = 16;
driver_write_hid(ITF_HID_CTAP, (const uint8_t *)ctap_resp, 64);
msg_packet.len = msg_packet.current_len = 0;
last_packet_time = 0;
}
else if (ctap_req->init.cmd == CTAPHID_VERSION) {
ctap_resp->cid = ctap_req->cid;
ctap_resp->init.cmd = ctap_req->init.cmd;
ctap_resp->init.data[0] = PICO_KEYS_SDK_VERSION_MAJOR;
ctap_resp->init.data[1] = PICO_KEYS_SDK_VERSION_MINOR;
ctap_resp->init.bcntl = 4;
driver_write_hid(ITF_HID_CTAP, (const uint8_t *)ctap_resp, 64);
msg_packet.len = msg_packet.current_len = 0;
last_packet_time = 0;
}
else if (ctap_req->init.cmd == CTAPHID_ADMIN) {
ctap_resp->cid = ctap_req->cid;
ctap_resp->init.cmd = ctap_req->init.cmd;
if (ctap_req->init.data[0] == 0x80) { // Status
memcpy(ctap_resp->init.data, "\x00\xff\xff\xff\x00", 5);
ctap_resp->init.bcntl = 5;
}
driver_write_hid(ITF_HID_CTAP, (const uint8_t *)ctap_resp, 64);
msg_packet.len = msg_packet.current_len = 0;
last_packet_time = 0;
}
else if ((last_cmd == CTAPHID_MSG || last_cmd == CTAPHID_OTP) &&
(msg_packet.len == 0 ||
(msg_packet.len == msg_packet.current_len && msg_packet.len > 0))) {
if (last_cmd == CTAPHID_OTP) {
is_nk = true;
#ifdef ENABLE_OATH_APP
select_app(oath_aid + 1, oath_aid[0]);
#endif
}
else {
select_app(u2f_aid + 1, u2f_aid[0]);
}
thread_type = 1;
if (msg_packet.current_len == msg_packet.len && msg_packet.len > 0) {
apdu_sent = apdu_process(ITF_HID_CTAP, msg_packet.data, msg_packet.len);
}
else {
apdu_sent = apdu_process(ITF_HID_CTAP, ctap_req->init.data, MSG_LEN(ctap_req));
}
DEBUG_PAYLOAD(apdu.data, (int) apdu.nc);
msg_packet.len = msg_packet.current_len = 0;
last_packet_time = 0;
}
else if ((last_cmd == CTAPHID_CBOR || last_cmd >= CTAPHID_VENDOR_FIRST) &&
(msg_packet.len == 0 || (msg_packet.len == msg_packet.current_len && msg_packet.len > 0))) {
thread_type = 2;
select_app(fido_aid + 1, fido_aid[0]);
if (msg_packet.current_len == msg_packet.len && msg_packet.len > 0) {
apdu_sent = cbor_process(last_cmd, msg_packet.data, msg_packet.len);
}
else {
apdu_sent = cbor_process(last_cmd, ctap_req->init.data, MSG_LEN(ctap_req));
}
msg_packet.len = msg_packet.current_len = 0;
last_packet_time = 0;
if (apdu_sent < 0) {
return ctap_error((uint8_t)(-apdu_sent));
}
send_keepalive();
}
else if (ctap_req->init.cmd == CTAPHID_CANCEL) {
ctap_error(0x2D);
msg_packet.len = msg_packet.current_len = 0;
last_packet_time = 0;
cancel_button = true;
hid_tx[ITF_HID_CTAP].r_ptr = hid_tx[ITF_HID_CTAP].w_ptr = 0;
}
else {
if (msg_packet.len == 0) {
return ctap_error(CTAP1_ERR_INVALID_CMD);
}
} }
// echo back anything we received from host // echo back anything we received from host
//tud_hid_report(0, buffer, bufsize); //tud_hid_report(0, buffer, bufsize);
//printf("END\n"); printf("END\n");
if (apdu_sent > 0) { usb_clear_rx();
if (apdu_sent == 1) {
card_start(ITF_HID, apdu_thread);
}
else if (apdu_sent == 2) {
card_start(ITF_HID, cbor_thread);
}
usb_send_event(EV_CMD_AVAILABLE);
}
} }
return apdu_sent; return 0;
} }
void send_keepalive() { void driver_exec_timeout() {
if (thread_type == 1) {
return;
}
CTAPHID_FRAME *resp = (CTAPHID_FRAME *) (hid_tx[ITF_HID_CTAP].buffer + sizeof(hid_tx[ITF_HID_CTAP].buffer) - 64);
//memset(ctap_resp, 0, sizeof(CTAPHID_FRAME));
resp->cid = ctap_req->cid;
resp->init.cmd = CTAPHID_KEEPALIVE;
resp->init.bcntl = 1;
resp->init.data[0] = is_req_button_pending() ? 2 : 1;
//send_buffer_size[ITF_HID_CTAP] = 0;
driver_write_hid(ITF_HID_CTAP, (const uint8_t *)resp, 64);
} }
void driver_exec_finished_hid(uint16_t size_next) { void driver_exec_finished(size_t size_next) {
if (size_next > 0) {
if (thread_type == 2 && apdu.sw != 0) {
ctap_error(apdu.sw & 0xff);
}
else {
if (is_nk) {
memmove(apdu.rdata + 2, apdu.rdata, size_next - 2);
put_uint16_t_be(apdu.sw, apdu.rdata);
}
driver_exec_finished_cont_hid(ITF_HID_CTAP, size_next, 7);
}
}
apdu.sw = 0;
}
void driver_exec_finished_cont_hid(uint8_t itf, uint16_t size_next, uint16_t offset) {
offset -= 7;
ctap_resp = (CTAPHID_FRAME *) (hid_tx[itf].buffer + offset);
ctap_resp->cid = ctap_req->cid;
ctap_resp->init.bcnth = size_next >> 8;
ctap_resp->init.bcntl = size_next & 0xff;
send_buffer_size[itf] = size_next;
ctap_resp->init.cmd = last_cmd;
if (hid_write_offset(size_next+7, offset) > 0) {
//ctap_resp = (CTAPHID_FRAME *) ((uint8_t *) ctap_resp + 64 - 5);
//send_buffer_size[ITF_HID_CTAP] -= MIN(64 - 7, send_buffer_size[ITF_HID_CTAP]);
}
}
void hid_task() {
#ifdef ENABLE_EMULATION
uint16_t rx_len = emul_read(ITF_HID);
if (rx_len) {
uint16_t rptr = 0;
while (rx_len > 0) {
tud_hid_set_report_cb(ITF_HID, 0, 0, emul_rx + rptr, 64);
rx_len -= 64;
rptr += 64;
}
emul_rx_size = 0;
}
#endif
int proc_pkt = 0;
if (hid_rx[ITF_HID_CTAP].w_ptr - hid_rx[ITF_HID_CTAP].r_ptr >= 64) {
//proc_pkt = driver_process_usb_packet_hid(64);
}
if (proc_pkt == 0) {
driver_process_usb_nopacket_hid();
}
int status = card_status(ITF_HID);
if (status == PICOKEY_OK) {
driver_exec_finished_hid(finished_data_size);
}
else if (status == PICOKEY_ERR_BLOCKED) {
send_keepalive();
}
if (hid_tx[ITF_HID_CTAP].w_ptr > hid_tx[ITF_HID_CTAP].r_ptr && last_write_result[ITF_HID_CTAP] != WRITE_PENDING) {
if (driver_write_hid(ITF_HID_CTAP, hid_tx[ITF_HID_CTAP].buffer + hid_tx[ITF_HID_CTAP].r_ptr, 64) > 0) {
}
}
#ifndef ENABLE_EMULATION
/* Keyboard ITF */
// Poll every 10ms
const uint32_t interval_ms = 10;
static uint32_t start_ms = 0;
if (board_millis() - start_ms < interval_ms) {
return;
}
start_ms += interval_ms;
// Remote wakeup
if (tud_suspended() && keyboard_buffer_len > 0) {
tud_remote_wakeup();
}
else {
send_hid_report(REPORT_ID_KEYBOARD);
}
#endif
} }

View file

@ -27,7 +27,7 @@
#define _TUSB_CONFIG_H_ #define _TUSB_CONFIG_H_
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
@ -45,7 +45,7 @@ extern "C" {
#endif #endif
//-------------------------------------------------------------------- //--------------------------------------------------------------------
// Common Configuration // COMMON CONFIGURATION
//-------------------------------------------------------------------- //--------------------------------------------------------------------
// defined by compiler flags for flexibility // defined by compiler flags for flexibility
@ -53,23 +53,19 @@ extern "C" {
#error CFG_TUSB_MCU must be defined #error CFG_TUSB_MCU must be defined
#endif #endif
#ifndef CFG_TUSB_OS #if CFG_TUSB_MCU == OPT_MCU_LPC18XX || CFG_TUSB_MCU == OPT_MCU_LPC43XX || CFG_TUSB_MCU == OPT_MCU_MIMXRT10XX || \
#if CFG_TUSB_MCU == OPT_MCU_RP2040 CFG_TUSB_MCU == OPT_MCU_NUC505 || CFG_TUSB_MCU == OPT_MCU_CXD56
#define CFG_TUSB_OS OPT_OS_PICO #define CFG_TUSB_RHPORT0_MODE (OPT_MODE_DEVICE | OPT_MODE_HIGH_SPEED)
#elif CFG_TUSB_MCU == OPT_MCU_ESP32S2 || CFG_TUSB_MCU == OPT_MCU_ESP32S3 #else
#define CFG_TUSB_OS OPT_OS_FREERTOS #define CFG_TUSB_RHPORT0_MODE OPT_MODE_DEVICE
#elif CFG_TUSB_MCU == OPT_MCU_NONE
#define CFG_TUSB_OS OPT_OS_NONE
#define TUP_DCD_ENDPOINT_MAX 16
#endif
#endif #endif
#ifndef CFG_TUSB_RHPORT0_MODE #ifndef CFG_TUSB_OS
#define CFG_TUSB_RHPORT0_MODE (OPT_MODE_DEVICE | OPT_MODE_FULL_SPEED) #define CFG_TUSB_OS OPT_OS_PICO
#endif #endif
#ifndef CFG_TUSB_DEBUG #ifndef CFG_TUSB_DEBUG
#define CFG_TUSB_DEBUG 0 #define CFG_TUSB_DEBUG 1
#endif #endif
// Enable Device stack // Enable Device stack
@ -90,11 +86,7 @@ extern "C" {
#endif #endif
#ifndef CFG_TUSB_MEM_ALIGN #ifndef CFG_TUSB_MEM_ALIGN
#ifdef _MSC_VER #define CFG_TUSB_MEM_ALIGN __attribute__ ((aligned(4)))
#define CFG_TUSB_MEM_ALIGN __declspec(align(4))
#else
#define CFG_TUSB_MEM_ALIGN __attribute__((aligned(4)))
#endif
#endif #endif
//-------------------------------------------------------------------- //--------------------------------------------------------------------
@ -105,35 +97,19 @@ extern "C" {
#define CFG_TUD_ENDPOINT0_SIZE 64 #define CFG_TUD_ENDPOINT0_SIZE 64
#endif #endif
#define CFG_TUD_VENDOR_RX_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64)
#define CFG_TUD_VENDOR_TX_BUFSIZE 2048
//------------- CLASS -------------// //------------- CLASS -------------//
#define CFG_TUD_CDC 0 #define CFG_TUD_CDC 0
#define CFG_TUD_MSC 0 #define CFG_TUD_MSC 0
#ifdef USB_ITF_HID #define CFG_TUD_HID 1
#define CFG_TUD_HID 2
#else
#define CFG_TUD_HID 0
#endif
#define CFG_TUD_MIDI 0 #define CFG_TUD_MIDI 0
#ifdef USB_ITF_CCID
#define CFG_TUD_VENDOR 2
#else
#define CFG_TUD_VENDOR 0 #define CFG_TUD_VENDOR 0
#endif
// HID buffer size Should be sufficient to hold ID (if any) + Data // HID buffer size Should be sufficient to hold ID (if any) + Data
#define CFG_TUD_HID_EP_BUFSIZE 64 #define CFG_TUD_HID_EP_BUFSIZE 64
// CDC FIFO size of TX and RX
#define CFG_TUD_CDC_RX_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64)
#define CFG_TUD_CDC_TX_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64)
// CDC Endpoint transfer buffer size, more is faster
#define CFG_TUD_CDC_EP_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64)
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
#endif /* _TUSB_CONFIG_H_ */ #endif /* _TUSB_CONFIG_H_ */

107
src/usb/hid/u2f.h Normal file
View file

@ -0,0 +1,107 @@
// Common U2F raw message format header - Review Draft
// 2014-10-08
// Editor: Jakob Ehrensvard, Yubico, jakob@yubico.com
#ifndef __U2F_H_INCLUDED__
#define __U2F_H_INCLUDED__
#ifdef _MSC_VER // Windows
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
typedef unsigned long int uint64_t;
#else
#include <stdint.h>
#endif
#ifdef __cplusplus
extern "C" {
#endif
// General constants
#define U2F_EC_KEY_SIZE 32 // EC key size in bytes
#define U2F_EC_POINT_SIZE ((U2F_EC_KEY_SIZE * 2) + 1) // Size of EC point
#define U2F_MAX_KH_SIZE 128 // Max size of key handle
#define U2F_MAX_ATT_CERT_SIZE 2048 // Max size of attestation certificate
#define U2F_MAX_EC_SIG_SIZE 72 // Max size of DER coded EC signature
#define U2F_CTR_SIZE 4 // Size of counter field
#define U2F_APPID_SIZE 32 // Size of application id
#define U2F_CHAL_SIZE 32 // Size of challenge
#define ENC_SIZE(x) ((x + 7) & 0xfff8)
// EC (uncompressed) point
#define U2F_POINT_UNCOMPRESSED 0x04 // Uncompressed point format
typedef struct {
uint8_t pointFormat; // Point type
uint8_t x[U2F_EC_KEY_SIZE]; // X-value
uint8_t y[U2F_EC_KEY_SIZE]; // Y-value
} U2F_EC_POINT;
// U2F native commands
#define U2F_REGISTER 0x01 // Registration command
#define U2F_AUTHENTICATE 0x02 // Authenticate/sign command
#define U2F_VERSION 0x03 // Read version string command
#define U2F_VENDOR_FIRST 0x40 // First vendor defined command
#define U2F_VENDOR_LAST 0xbf // Last vendor defined command
// U2F_CMD_REGISTER command defines
#define U2F_REGISTER_ID 0x05 // Version 2 registration identifier
#define U2F_REGISTER_HASH_ID 0x00 // Version 2 hash identintifier
typedef struct {
uint8_t chal[U2F_CHAL_SIZE]; // Challenge
uint8_t appId[U2F_APPID_SIZE]; // Application id
} U2F_REGISTER_REQ;
typedef struct {
uint8_t registerId; // Registration identifier (U2F_REGISTER_ID_V2)
U2F_EC_POINT pubKey; // Generated public key
uint8_t keyHandleLen; // Length of key handle
uint8_t keyHandleCertSig[
U2F_MAX_KH_SIZE + // Key handle
U2F_MAX_ATT_CERT_SIZE + // Attestation certificate
U2F_MAX_EC_SIG_SIZE]; // Registration signature
} U2F_REGISTER_RESP;
// U2F_CMD_AUTHENTICATE command defines
// Authentication control byte
#define U2F_AUTH_ENFORCE 0x03 // Enforce user presence and sign
#define U2F_AUTH_CHECK_ONLY 0x07 // Check only
#define U2F_AUTH_FLAG_TUP 0x01 // Test of user presence set
typedef struct {
uint8_t chal[U2F_CHAL_SIZE]; // Challenge
uint8_t appId[U2F_APPID_SIZE]; // Application id
uint8_t keyHandleLen; // Length of key handle
uint8_t keyHandle[U2F_MAX_KH_SIZE]; // Key handle
} U2F_AUTHENTICATE_REQ;
typedef struct {
uint8_t flags; // U2F_AUTH_FLAG_ values
uint8_t ctr[U2F_CTR_SIZE]; // Counter field (big-endian)
uint8_t sig[U2F_MAX_EC_SIG_SIZE]; // Signature
} U2F_AUTHENTICATE_RESP;
// Command status responses
#define U2F_SW_NO_ERROR 0x9000 // SW_NO_ERROR
#define U2F_SW_WRONG_DATA 0x6A80 // SW_WRONG_DATA
#define U2F_SW_CONDITIONS_NOT_SATISFIED 0x6985 // SW_CONDITIONS_NOT_SATISFIED
#define U2F_SW_COMMAND_NOT_ALLOWED 0x6986 // SW_COMMAND_NOT_ALLOWED
#define U2F_SW_INS_NOT_SUPPORTED 0x6D00 // SW_INS_NOT_SUPPORTED
#ifdef __cplusplus
}
#endif
#endif // __U2F_H_INCLUDED__

127
src/usb/hid/u2f_hid.h Normal file
View file

@ -0,0 +1,127 @@
// Common U2F HID transport header - Review Draft
// 2014-10-08
// Editor: Jakob Ehrensvard, Yubico, jakob@yubico.com
#ifndef __U2FHID_H_INCLUDED__
#define __U2FHID_H_INCLUDED__
#ifdef _MSC_VER // Windows
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
typedef unsigned long int uint64_t;
#else
#include <stdint.h>
#endif
#ifdef __cplusplus
extern "C" {
#endif
// Size of HID reports
#define HID_RPT_SIZE 64 // Default size of raw HID report
// Frame layout - command- and continuation frames
#define CID_BROADCAST 0xffffffff // Broadcast channel id
#define TYPE_MASK 0x80 // Frame type mask
#define TYPE_INIT 0x80 // Initial frame identifier
#define TYPE_CONT 0x00 // Continuation frame identifier
typedef struct {
uint32_t cid; // Channel identifier
union {
uint8_t type; // Frame type - b7 defines type
struct {
uint8_t cmd; // Command - b7 set
uint8_t bcnth; // Message byte count - high part
uint8_t bcntl; // Message byte count - low part
uint8_t data[HID_RPT_SIZE - 7]; // Data payload
} init;
struct {
uint8_t seq; // Sequence number - b7 cleared
uint8_t data[HID_RPT_SIZE - 5]; // Data payload
} cont;
};
}__packed U2FHID_FRAME;
#define FRAME_TYPE(f) ((f)->type & TYPE_MASK)
#define FRAME_CMD(f) ((f)->init.cmd & ~TYPE_MASK)
#define MSG_LEN(f) ((f)->init.bcnth*256 + (f)->init.bcntl)
#define FRAME_SEQ(f) ((f)->cont.seq & ~TYPE_MASK)
// HID usage- and usage-page definitions
#define FIDO_USAGE_PAGE 0xf1d0 // FIDO alliance HID usage page
#define FIDO_USAGE_U2FHID 0x01 // U2FHID usage for top-level collection
#define FIDO_USAGE_DATA_IN 0x20 // Raw IN data report
#define FIDO_USAGE_DATA_OUT 0x21 // Raw OUT data report
// General constants
#define U2FHID_IF_VERSION 2 // Current interface implementation version
#define U2FHID_TRANS_TIMEOUT 3000 // Default message timeout in ms
// U2FHID native commands
#define U2FHID_PING (TYPE_INIT | 0x01) // Echo data through local processor only
#define U2FHID_MSG (TYPE_INIT | 0x03) // Send U2F message frame
#define U2FHID_LOCK (TYPE_INIT | 0x04) // Send lock channel command
#define U2FHID_INIT (TYPE_INIT | 0x06) // Channel initialization
#define U2FHID_WINK (TYPE_INIT | 0x08) // Send device identification wink
#define U2FHID_SYNC (TYPE_INIT | 0x3c) // Protocol resync command
#define U2FHID_ERROR (TYPE_INIT | 0x3f) // Error response
#define U2FHID_VENDOR_FIRST (TYPE_INIT | 0x40) // First vendor defined command
#define U2FHID_VENDOR_LAST (TYPE_INIT | 0x7f) // Last vendor defined command
// U2FHID_INIT command defines
#define INIT_NONCE_SIZE 8 // Size of channel initialization challenge
#define CAPFLAG_WINK 0x01 // Device supports WINK command
typedef struct {
uint8_t nonce[INIT_NONCE_SIZE]; // Client application nonce
}__packed U2FHID_INIT_REQ;
typedef struct {
uint8_t nonce[INIT_NONCE_SIZE]; // Client application nonce
uint32_t cid; // Channel identifier
uint8_t versionInterface; // Interface version
uint8_t versionMajor; // Major version number
uint8_t versionMinor; // Minor version number
uint8_t versionBuild; // Build version number
uint8_t capFlags; // Capabilities flags
}__packed U2FHID_INIT_RESP;
// U2FHID_SYNC command defines
typedef struct {
uint8_t nonce; // Client application nonce
} U2FHID_SYNC_REQ;
typedef struct {
uint8_t nonce; // Client application nonce
} U2FHID_SYNC_RESP;
// Low-level error codes. Return as negatives.
#define ERR_NONE 0x00 // No error
#define ERR_INVALID_CMD 0x01 // Invalid command
#define ERR_INVALID_PAR 0x02 // Invalid parameter
#define ERR_INVALID_LEN 0x03 // Invalid message length
#define ERR_INVALID_SEQ 0x04 // Invalid message sequencing
#define ERR_MSG_TIMEOUT 0x05 // Message has timed out
#define ERR_CHANNEL_BUSY 0x06 // Channel busy
#define ERR_LOCK_REQUIRED 0x0a // Command requires channel lock
#define ERR_SYNC_FAIL 0x0b // SYNC command failed
#define ERR_OTHER 0x7f // Other unspecified error
#ifdef __cplusplus
}
#endif
#endif // __U2FHID_H_INCLUDED__

View file

@ -0,0 +1,192 @@
/*
* 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.
*
*/
#include "tusb.h"
#include "u2f_hid.h"
/* A combination of interfaces must have a unique product id, since PC will save device driver after the first plug.
* Same VID/PID with different interface e.g MSC (first), then CDC (later) will possibly cause system error on PC.
*
* Auto ProductID layout's Bitmap:
* [MSB] HID | MSC | CDC [LSB]
*/
//--------------------------------------------------------------------+
// Device Descriptors
//--------------------------------------------------------------------+
tusb_desc_device_t const desc_device =
{
.bLength = sizeof(tusb_desc_device_t),
.bDescriptorType = TUSB_DESC_DEVICE,
.bcdUSB = 0x0200,
.bDeviceClass = 0x00,
.bDeviceSubClass = 0x00,
.bDeviceProtocol = 0x00,
.bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
.idVendor = 0xCafe,
.idProduct = 0x4231,
.bcdDevice = 0x0100,
.iManufacturer = 0x01,
.iProduct = 0x02,
.iSerialNumber = 0x03,
.bNumConfigurations = 0x01
};
// Invoked when received GET DEVICE DESCRIPTOR
// Application return pointer to descriptor
uint8_t const * tud_descriptor_device_cb(void)
{
return (uint8_t const *) &desc_device;
}
//--------------------------------------------------------------------+
// HID Report Descriptor
//--------------------------------------------------------------------+
#define TUD_HID_REPORT_DESC_U2F(report_size, ...) \
HID_USAGE_PAGE_N ( FIDO_USAGE_PAGE, 2 ),\
HID_USAGE ( FIDO_USAGE_U2FHID ),\
HID_COLLECTION ( HID_COLLECTION_APPLICATION ),\
/* Report ID if any */\
__VA_ARGS__ \
/* Input */ \
HID_USAGE ( FIDO_USAGE_DATA_IN ),\
HID_LOGICAL_MIN ( 0x00 ),\
HID_LOGICAL_MAX_N ( 0xff, 2 ),\
HID_REPORT_SIZE ( 8 ),\
HID_REPORT_COUNT( report_size ),\
HID_INPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ),\
/* Output */ \
HID_USAGE ( FIDO_USAGE_DATA_OUT ),\
HID_LOGICAL_MIN ( 0x00 ),\
HID_LOGICAL_MAX_N ( 0xff, 2 ),\
HID_REPORT_SIZE ( 8 ),\
HID_REPORT_COUNT( report_size ),\
HID_OUTPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ),\
HID_COLLECTION_END \
uint8_t const desc_hid_report[] =
{
TUD_HID_REPORT_DESC_U2F(CFG_TUD_HID_EP_BUFSIZE)
};
// Invoked when received GET HID REPORT DESCRIPTOR
// Application return pointer to descriptor
// Descriptor contents must exist long enough for transfer to complete
uint8_t const * tud_hid_descriptor_report_cb(uint8_t itf)
{
printf("report_cb %d\n", itf);
return desc_hid_report;
}
//--------------------------------------------------------------------+
// Configuration Descriptor
//--------------------------------------------------------------------+
enum
{
ITF_NUM_HID,
ITF_NUM_TOTAL
};
#define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_HID_INOUT_DESC_LEN)
#define EPNUM_HID 0x01
uint8_t const desc_configuration[] =
{
// Config number, interface count, string index, total length, attribute, power in mA
TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100),
// Interface number, string index, protocol, report descriptor len, EP In & Out address, size & polling interval
TUD_HID_INOUT_DESCRIPTOR(ITF_NUM_HID, 0, HID_ITF_PROTOCOL_NONE, sizeof(desc_hid_report), EPNUM_HID, 0x80 | EPNUM_HID, CFG_TUD_HID_EP_BUFSIZE, 10)
};
// Invoked when received GET CONFIGURATION DESCRIPTOR
// Application return pointer to descriptor
// Descriptor contents must exist long enough for transfer to complete
uint8_t const * tud_descriptor_configuration_cb(uint8_t index)
{
(void) index; // for multiple configurations
return desc_configuration;
}
//--------------------------------------------------------------------+
// String Descriptors
//--------------------------------------------------------------------+
// array of pointer to string descriptors
char const* string_desc_arr [] =
{
(const char[]) { 0x09, 0x04 }, // 0: is supported language is English (0x0409)
"TinyUSB", // 1: Manufacturer
"TinyUSB Device", // 2: Product
"123456", // 3: Serials, should use chip ID
};
static uint16_t _desc_str[32];
// Invoked when received GET STRING DESCRIPTOR request
// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete
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];
// Cap at max char
chr_count = (uint8_t) 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];
}
}
// first byte is length (including header), second byte is string type
_desc_str[0] = (uint16_t) ((TUSB_DESC_STRING << 8 ) | (2*chr_count + 2));
return _desc_str;
}

View file

@ -1,149 +1,276 @@
/* /*
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk). * This file is part of the Pico HSM SDK distribution (https://github.com/polhenarejos/pico-hsm-sdk).
* Copyright (c) 2022 Pol Henarejos. * Copyright (c) 2022 Pol Henarejos.
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3. * the Free Software Foundation, version 3.
* *
* This program is distributed in the hope that it will be useful, but * This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of * WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Affero General Public License for more details. * General Public License for more details.
* *
* You should have received a copy of the GNU Affero General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "pico/unique_id.h"
#include <stdio.h> #include <stdio.h>
#include "pico_keys.h"
#if defined(PICO_PLATFORM) // Pico
#include "pico/stdlib.h" #include "pico/stdlib.h"
#include "pico/multicore.h" #include "pico/multicore.h"
#include "bsp/board.h" #include "tusb.h"
#endif #include "hsm.h"
#include "usb.h" #include "usb.h"
#include "apdu.h" #include "apdu.h"
#ifndef ENABLE_EMULATION
#include "tusb.h" #include "bsp/board.h"
#else
#include "emulation.h"
#endif
// For memcpy // For memcpy
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
// Device specific functions // Device specific functions
static uint32_t *timeout_counter = NULL; static uint8_t rx_buffer[4096], tx_buffer[4096];
static uint8_t card_locked_itf = 0; // no locked static uint16_t w_offset = 0, r_offset = 0;
static void *(*card_locked_func)(void *) = NULL; static uint16_t w_len = 0, tx_r_offset = 0;
#ifndef ENABLE_EMULATION
static mutex_t mutex;
extern void usb_desc_setup();
#endif
#if !defined(PICO_PLATFORM) && !defined(ENABLE_EMULATION) && !defined(ESP_PLATFORM)
#ifdef _MSC_VER
#include "pthread_win32.h"
#endif
pthread_t hcore0, hcore1;
#endif
#ifdef USB_ITF_HID uint32_t usb_write_offset(uint16_t len, uint16_t offset) {
uint8_t ITF_HID_CTAP = ITF_INVALID, ITF_HID_KB = ITF_INVALID; uint8_t pkt_max = 64;
uint8_t ITF_HID = ITF_INVALID, ITF_KEYBOARD = ITF_INVALID; if (len > sizeof(tx_buffer))
uint8_t ITF_HID_TOTAL = 0; len = sizeof(tx_buffer);
extern void hid_init(); w_len = len;
#endif tx_r_offset = offset;
driver_write(tx_buffer+offset, MIN(len, pkt_max));
#ifdef USB_ITF_CCID w_len -= MIN(len, pkt_max);
uint8_t ITF_SC_CCID = ITF_INVALID, ITF_SC_WCID = ITF_INVALID; tx_r_offset += MIN(len, pkt_max);
uint8_t ITF_CCID = ITF_INVALID, ITF_WCID = ITF_INVALID; return MIN(w_len, pkt_max);
uint8_t ITF_SC_TOTAL = 0;
extern void ccid_init();
#endif
uint8_t ITF_TOTAL = 0;
void usb_set_timeout_counter(uint8_t itf, uint32_t v) {
timeout_counter[itf] = v;
} }
queue_t usb_to_card_q = {0}; size_t usb_rx(const uint8_t *buffer, size_t len) {
queue_t card_to_usb_q = {0}; uint16_t size = MIN(sizeof(rx_buffer) - w_offset, len);
if (size > 0) {
#ifndef ENABLE_EMULATION if (buffer == NULL)
extern tusb_desc_device_t desc_device; size = driver_read(rx_buffer + w_offset, size);
#endif else
void usb_init() { memcpy(rx_buffer + w_offset, buffer, size);
#ifndef ENABLE_EMULATION w_offset += size;
if (phy_data.vidpid_present) {
desc_device.idVendor = phy_data.vid;
desc_device.idProduct = phy_data.pid;
} }
else { return size;
phy_data.vid = desc_device.idVendor;
phy_data.pid = desc_device.idProduct;
phy_data.vidpid_present = true;
}
mutex_init(&mutex);
#endif
queue_init(&card_to_usb_q, sizeof(uint32_t), 64);
queue_init(&usb_to_card_q, sizeof(uint32_t), 64);
uint8_t enabled_usb_itf = PHY_USB_ITF_CCID | PHY_USB_ITF_WCID | PHY_USB_ITF_HID | PHY_USB_ITF_KB;
#ifndef ENABLE_EMULATION
if (phy_data.enabled_usb_itf_present) {
enabled_usb_itf = phy_data.enabled_usb_itf;
}
#endif
#ifdef USB_ITF_HID
ITF_HID_TOTAL = 0;
#endif
#ifdef USB_ITF_CCID
ITF_SC_TOTAL = 0;
#endif
ITF_TOTAL = 0;
#ifdef USB_ITF_HID
if (enabled_usb_itf & PHY_USB_ITF_HID) {
ITF_HID_CTAP = ITF_HID_TOTAL++;
ITF_HID = ITF_TOTAL++;
}
if (enabled_usb_itf & PHY_USB_ITF_KB) {
ITF_HID_KB = ITF_HID_TOTAL++;
ITF_KEYBOARD = ITF_TOTAL++;
}
#endif
#ifdef USB_ITF_CCID
if (enabled_usb_itf & PHY_USB_ITF_CCID) {
ITF_SC_CCID = ITF_SC_TOTAL++;
ITF_CCID = ITF_TOTAL++;
}
if (enabled_usb_itf & PHY_USB_ITF_WCID) {
ITF_SC_WCID = ITF_SC_TOTAL++;
ITF_WCID = ITF_TOTAL++;
}
#endif
card_locked_itf = ITF_TOTAL;
if (timeout_counter == NULL) {
timeout_counter = (uint32_t *)calloc(ITF_TOTAL, sizeof(uint32_t));
}
#ifdef USB_ITF_HID
if (ITF_HID_TOTAL > 0) {
hid_init();
}
#endif
#ifdef USB_ITF_CCID
if (ITF_SC_TOTAL > 0) {
ccid_init();
}
#endif
#ifdef ESP_PLATFORM
usb_desc_setup();
#endif
} }
uint32_t usb_write_flush() {
if (w_len > 0) {
driver_write(tx_buffer+tx_r_offset, MIN(w_len, 64));
tx_r_offset += MIN(w_len, 64);
w_len -= MIN(w_len, 64);
}
return w_len;
}
uint32_t usb_write(uint16_t len) {
return usb_write_offset(len, 0);
}
uint16_t usb_read_available() {
return w_offset - r_offset;
}
uint16_t usb_write_available() {
return w_len > 0;
}
uint8_t *usb_get_rx() {
return rx_buffer;
}
uint8_t *usb_get_tx() {
return tx_buffer;
}
void usb_clear_rx() {
w_offset = r_offset = 0;
}
uint16_t usb_read(uint8_t *buffer, size_t buffer_size) {
uint16_t size = MIN(buffer_size, w_offset-r_offset);
if (size > 0) {
memcpy(buffer, rx_buffer+r_offset, size);
r_offset += size;
if (r_offset == w_offset) {
r_offset = w_offset = 0;
}
return size;
}
return 0;
}
#ifndef USB_VID
#define USB_VID 0xFEFF
#endif
#ifndef USB_PID
#define USB_PID 0xFCFD
#endif
#define USB_BCD 0x0200
uint32_t timeout = 0; uint32_t timeout = 0;
queue_t usb_to_card_q;
queue_t card_to_usb_q;
void usb_init() {
queue_init(&card_to_usb_q, sizeof(uint32_t), 64);
queue_init(&usb_to_card_q, sizeof(uint32_t), 64);
driver_init();
}
static int usb_event_handle() {
uint16_t rx_read = usb_read_available();
if (driver_process_usb_packet(rx_read) > 0) {
uint32_t flag = EV_CMD_AVAILABLE;
queue_add_blocking(&usb_to_card_q, &flag);
timeout_start();
}
return 0;
}
static void card_init_core1(void) {
//gpg_data_scan (flash_do_start, flash_do_end);
low_flash_init_core1();
}
void card_thread() {
card_init_core1();
while (1) {
uint32_t m;
queue_remove_blocking(&usb_to_card_q, &m);
if (m == EV_VERIFY_CMD_AVAILABLE || m == EV_MODIFY_CMD_AVAILABLE)
{
set_res_sw (0x6f, 0x00);
goto done;
}
else if (m == EV_EXIT) {
if (current_app && current_app->unload) {
current_app->unload();
}
break;
}
process_apdu();
done:;
uint32_t flag = EV_EXEC_FINISHED;
queue_add_blocking(&card_to_usb_q, &flag);
}
//printf("EXIT !!!!!!\r\n");
if (current_app && current_app->unload)
current_app->unload();
}
void card_thread();
void card_start()
{
multicore_reset_core1();
multicore_launch_core1(card_thread);
led_set_blink(BLINK_MOUNTED);
}
void card_exit() {
uint32_t flag = EV_EXIT;
queue_try_add(&usb_to_card_q, &flag);
led_set_blink(BLINK_SUSPENDED);
}
void usb_task() {
if (driver_mounted()) {
if (usb_event_handle() != 0) {
}
usb_write_flush();
uint32_t m = 0x0;
bool has_m = queue_try_remove(&card_to_usb_q, &m);
//if (m != 0)
// printf("\r\n ------ M = %lu\r\n",m);
if (has_m) {
if (m == EV_EXEC_FINISHED) {
apdu_finish();
size_t size_next = apdu_next();
driver_exec_finished(size_next);
led_set_blink(BLINK_MOUNTED);
}
else if (m == EV_PRESS_BUTTON) {
uint32_t flag = wait_button() ? EV_BUTTON_TIMEOUT : EV_BUTTON_PRESSED;
queue_try_add(&usb_to_card_q, &flag);
}
/*
if (m == EV_RX_DATA_READY) {
c->ccid_state = ccid_handle_data(c);
timeout = 0;
c->timeout_cnt = 0;
}
else if (m == EV_EXEC_FINISHED) {
if (c->ccid_state == CCID_STATE_EXECUTE) {
exec_done:
if (c->a->sw == CCID_THREAD_TERMINATED) {
c->sw1sw2[0] = 0x90;
c->sw1sw2[1] = 0x00;
c->state = APDU_STATE_RESULT;
ccid_send_data_block(c);
c->ccid_state = CCID_STATE_EXITED;
c->application = 0;
return;
}
c->a->cmd_apdu_data_len = 0;
c->sw1sw2[0] = c->a->sw >> 8;
c->sw1sw2[1] = c->a->sw & 0xff;
if (c->a->res_apdu_data_len <= c->a->expected_res_size) {
c->state = APDU_STATE_RESULT;
ccid_send_data_block(c);
c->ccid_state = CCID_STATE_WAIT;
}
else {
c->state = APDU_STATE_RESULT_GET_RESPONSE;
c->p = c->a->res_apdu_data;
c->len = c->a->res_apdu_data_len;
ccid_send_data_block_gr(c, c->a->expected_res_size);
c->ccid_state = CCID_STATE_WAIT;
}
}
else {
DEBUG_INFO ("ERR05\r\n");
}
led_set_blink(BLINK_MOUNTED);
}
else if (m == EV_TX_FINISHED){
if (c->state == APDU_STATE_RESULT)
ccid_reset(c);
else
c->tx_busy = 0;
if (c->state == APDU_STATE_WAIT_COMMAND || c->state == APDU_STATE_COMMAND_CHAINING || c->state == APDU_STATE_RESULT_GET_RESPONSE)
ccid_prepare_receive(c);
}
*/
}
else {
if (timeout > 0) {
if (timeout + 1500 < board_millis()) {
driver_exec_timeout();
timeout = board_millis();
}
}
}
}
}
void timeout_stop() { void timeout_stop() {
timeout = 0; timeout = 0;
} }
@ -152,134 +279,6 @@ void timeout_start() {
timeout = board_millis(); timeout = board_millis();
} }
bool is_busy() { uint8_t *usb_prepare_response() {
return timeout > 0; return driver_prepare_response();
} }
void usb_send_event(uint32_t flag) {
#ifndef ENABLE_EMULATION
mutex_enter_blocking(&mutex);
#endif
queue_add_blocking(&usb_to_card_q, &flag);
if (flag == EV_CMD_AVAILABLE) {
timeout_start();
}
uint32_t m;
queue_remove_blocking(&card_to_usb_q , &m);
#ifndef ENABLE_EMULATION
mutex_exit(&mutex);
#endif
}
extern void low_flash_init();
void card_init_core1() {
low_flash_init_core1();
}
uint16_t finished_data_size = 0;
void card_start(uint8_t itf, void *(*func)(void *)) {
timeout_start();
if (card_locked_itf != itf || card_locked_func != func) {
if (card_locked_itf != ITF_TOTAL || card_locked_func != NULL) {
card_exit();
}
if (func) {
multicore_reset_core1();
multicore_launch_func_core1(func);
}
led_set_mode(MODE_MOUNTED);
card_locked_itf = itf;
card_locked_func = func;
}
}
void card_exit() {
if (card_locked_itf != ITF_TOTAL || card_locked_func != NULL) {
usb_send_event(EV_EXIT);
uint32_t m;
while (queue_is_empty(&usb_to_card_q) == false) {
if (queue_try_remove(&usb_to_card_q, &m) == false) {
break;
}
}
while (queue_is_empty(&card_to_usb_q) == false) {
#ifndef ENABLE_EMULATION
mutex_enter_blocking(&mutex);
#endif
if (queue_try_remove(&card_to_usb_q, &m) == false) {
break;
}
#ifndef ENABLE_EMULATION
mutex_exit(&mutex);
#endif
}
led_set_mode(MODE_SUSPENDED);
#ifdef ESP_PLATFORM
hcore1 = NULL;
#endif
}
card_locked_itf = ITF_TOTAL;
card_locked_func = NULL;
}
extern void hid_task();
extern void ccid_task();
extern void emul_task();
void usb_task() {
#ifdef USB_ITF_HID
hid_task();
#endif
#ifdef ENABLE_EMULATION
emul_task();
#else
#ifdef USB_ITF_CCID
ccid_task();
#endif
#endif
}
int card_status(uint8_t itf) {
if (card_locked_itf == itf) {
uint32_t m = 0x0;
#ifndef ENABLE_EMULATION
mutex_enter_blocking(&mutex);
#endif
bool has_m = queue_try_remove(&card_to_usb_q, &m);
#ifndef ENABLE_EMULATION
mutex_exit(&mutex);
#endif
//if (m != 0)
// printf("\n ------ M = %lu\n",m);
if (has_m) {
if (m == EV_EXEC_FINISHED) {
timeout_stop();
led_set_mode(MODE_MOUNTED);
return PICOKEY_OK;
}
#ifndef ENABLE_EMULATION
else if (m == EV_PRESS_BUTTON) {
uint32_t flag = wait_button() ? EV_BUTTON_TIMEOUT : EV_BUTTON_PRESSED;
queue_try_add(&usb_to_card_q, &flag);
}
#endif
return PICOKEY_ERR_FILE_NOT_FOUND;
}
else {
if (timeout > 0) {
if (timeout + timeout_counter[itf] < board_millis()) {
timeout = board_millis();
return PICOKEY_ERR_BLOCKED;
}
}
}
}
return PICOKEY_ERR_FILE_NOT_FOUND;
}
#ifndef USB_ITF_CCID
#include "device/usbd_pvt.h"
usbd_class_driver_t const *usbd_app_driver_get_cb(uint8_t *driver_count) {
*driver_count = 0;
return NULL;
}
#endif

View file

@ -1,35 +1,24 @@
/* /*
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk). * This file is part of the Pico HSM distribution (https://github.com/polhenarejos/pico-hsm).
* Copyright (c) 2022 Pol Henarejos. * Copyright (c) 2022 Pol Henarejos.
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3. * the Free Software Foundation, version 3.
* *
* This program is distributed in the hope that it will be useful, but * This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of * WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Affero General Public License for more details. * General Public License for more details.
* *
* You should have received a copy of the GNU Affero General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef _USB_H_ #ifndef _USB_H_
#define _USB_H_ #define _USB_H_
#if defined(ENABLE_EMULATION)
#include "emulation.h"
#elif defined(ESP_PLATFORM)
#include "esp_compat.h"
#elif defined(PICO_PLATFORM)
#include "pico/util/queue.h" #include "pico/util/queue.h"
#else
#include "queue.h"
#include "board.h"
#endif
#include "compat.h"
/* USB thread */ /* USB thread */
#define EV_CARD_CHANGE 1 #define EV_CARD_CHANGE 1
@ -47,79 +36,24 @@
#define EV_BUTTON_TIMEOUT 16 #define EV_BUTTON_TIMEOUT 16
#define EV_BUTTON_PRESSED 32 #define EV_BUTTON_PRESSED 32
enum { ITF_INVALID = 0xFF };
#ifdef USB_ITF_HID
extern uint8_t ITF_HID_CTAP, ITF_HID_KB;
extern uint8_t ITF_HID, ITF_KEYBOARD;
extern uint8_t ITF_HID_TOTAL;
#endif
#ifdef USB_ITF_CCID
extern uint8_t ITF_SC_CCID, ITF_SC_WCID;
extern uint8_t ITF_CCID, ITF_WCID;
extern uint8_t ITF_SC_TOTAL;
#endif
extern uint8_t ITF_TOTAL;
enum {
REPORT_ID_KEYBOARD = 0,
REPORT_ID_COUNT
};
#if defined(ESP_PLATFORM) && defined(USB_ITF_HID) && defined(USB_ITF_CCID)
#define TUSB_SMARTCARD_CCID_EPS 2
#else
#define TUSB_SMARTCARD_CCID_EPS 3
#endif
extern void usb_task(); extern void usb_task();
extern queue_t usb_to_card_q; extern queue_t usb_to_card_q;
extern queue_t card_to_usb_q; extern queue_t card_to_usb_q;
extern int driver_process_usb_packet(uint16_t rx_read);
extern void driver_exec_finished(size_t size_next);
extern void driver_exec_finished_cont(size_t size_next, size_t offset);
extern void driver_exec_timeout();
extern bool driver_mounted();
extern uint8_t *driver_prepare_response();
extern void card_start(uint8_t, void *(*func)(void *)); extern void card_start();
extern void card_exit(); extern void card_exit();
extern int card_status(uint8_t itf);
extern void usb_init(); extern void usb_init();
extern uint8_t *usb_prepare_response();
extern uint16_t finished_data_size;
extern void usb_set_timeout_counter(uint8_t itf, uint32_t v);
extern void card_init_core1();
extern void usb_send_event(uint32_t flag);
extern void timeout_stop(); extern void timeout_stop();
extern void timeout_start(); extern void timeout_start();
extern bool is_busy(); extern uint8_t *usb_get_rx();
extern uint8_t *usb_get_tx();
#ifdef USB_ITF_HID extern uint32_t usb_write_offset(uint16_t len, uint16_t offset);
extern void driver_exec_finished_hid(uint16_t size_next); extern void usb_clear_rx();
extern void driver_exec_finished_cont_hid(uint8_t itf, uint16_t size_next, uint16_t offset);
#endif
#ifdef USB_ITF_CCID
extern void driver_exec_finished_ccid(uint8_t itf, uint16_t size_next);
extern void driver_exec_finished_cont_ccid(uint8_t itf, uint16_t size_next, uint16_t offset);
#endif
#ifdef ENABLE_EMULATION
extern void driver_exec_finished_emul(uint8_t itf, uint16_t size_next);
extern void driver_exec_finished_cont_emul(uint8_t itf, uint16_t size_next, uint16_t offset);
#endif
#define USB_BUFFER_SIZE 2048
PACK(
typedef struct {
uint8_t buffer[USB_BUFFER_SIZE];
uint16_t r_ptr;
uint16_t w_ptr;
}) usb_buffer_t;
typedef enum {
WRITE_UNKNOWN = 0,
WRITE_PENDING,
WRITE_FAILED,
WRITE_SUCCESS,
} write_status_t;
#endif #endif

View file

@ -1,395 +0,0 @@
/*
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
* Copyright (c) 2022 Pol Henarejos.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero 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
* Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "pico_keys.h"
#include "tusb.h"
#include "usb_descriptors.h"
#if defined(PICO_PLATFORM)
#include "pico/unique_id.h"
#endif
#ifdef ESP_PLATFORM
#include "tinyusb.h"
#endif
#include "pico_keys_version.h"
#include "usb.h"
#ifndef USB_VID
#define USB_VID 0xFEFF
#endif
#ifndef USB_PID
#define USB_PID 0xFCFD
#endif
#if defined(PICO_PLATFORM) || defined(ESP_PLATFORM)
#define USB_BCD 0x0210
#else
#define USB_BCD 0x0110
#endif
#define USB_CONFIG_ATT_ONE TU_BIT(7)
#define MAX_USB_POWER 2
//--------------------------------------------------------------------+
// Device Descriptors
//--------------------------------------------------------------------+
tusb_desc_device_t 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 = PICO_KEYS_SDK_VERSION,
.iManufacturer = 1,
.iProduct = 2,
.iSerialNumber = 3,
.bNumConfigurations = 1
};
#ifndef ESP_PLATFORM
uint8_t const *tud_descriptor_device_cb(void) {
return (uint8_t const *) &desc_device;
}
#endif
//--------------------------------------------------------------------+
// Configuration Descriptor
//--------------------------------------------------------------------+
#define TUD_INTERFACE_DESC_LEN 9
#define TUD_ENDPOINT_DESC_LEN 7
#define TUSB_SMARTCARD_LEN 54
#define TUSB_WSMARTCARD_LEN 53
#define TUSB_SMARTCARD_CCID_DESC_LEN (TUD_INTERFACE_DESC_LEN + TUSB_SMARTCARD_LEN + TUSB_SMARTCARD_CCID_EPS * TUD_ENDPOINT_DESC_LEN)
#define TUSB_SMARTCARD_WCID_DESC_LEN (TUD_INTERFACE_DESC_LEN + TUSB_WSMARTCARD_LEN + 2 * TUD_ENDPOINT_DESC_LEN)
uint16_t TUSB_DESC_TOTAL_LEN = TUD_CONFIG_DESC_LEN;
enum {
MAX_TUSB_DESC_TOTAL_LEN = (TUD_CONFIG_DESC_LEN
#ifdef USB_ITF_HID
+ TUD_HID_INOUT_DESC_LEN + TUD_HID_DESC_LEN
#endif
#ifdef USB_ITF_CCID
+ TUSB_SMARTCARD_CCID_DESC_LEN + TUSB_SMARTCARD_WCID_DESC_LEN
#endif
)
};
#ifdef USB_ITF_HID
uint8_t const desc_hid_report[] = {
TUD_HID_REPORT_DESC_FIDO_U2F(CFG_TUD_HID_EP_BUFSIZE)
};
uint8_t const desc_hid_report_kb[] = {
TUD_HID_REPORT_DESC_KEYBOARD(HID_USAGE_PAGE(HID_USAGE_DESKTOP_KEYBOARD), HID_USAGE_MIN(0), HID_USAGE_MAX_N(255,2), HID_LOGICAL_MIN(0), HID_LOGICAL_MAX_N(255, 2), HID_REPORT_COUNT(8), HID_REPORT_SIZE(8), HID_FEATURE( HID_DATA | HID_VARIABLE | HID_ABSOLUTE),)
};
#endif
enum {
EPNUM_DUMMY = 0,
#ifdef USB_ITF_CCID
EPNUM_CCID,
#if TUSB_SMARTCARD_CCID_EPS == 3
EPNUM_CCID_INT,
#endif
EPNUM_WCID,
#endif
#ifdef USB_ITF_HID
EPNUM_HID,
EPNUM_HID_KB,
#endif
EPNUM_TOTAL
};
#ifdef USB_ITF_CCID
#define TUD_SMARTCARD_DESCRIPTOR_WEB(_itf, _strix, _epout, _epin, _epsize) \
9, TUSB_DESC_INTERFACE, _itf, 0, 2, 0xFF, 0, 0, _strix, \
TUSB_WSMARTCARD_LEN, 0x21, U16_TO_U8S_LE(0x0110), 0, 0x1, U32_TO_U8S_LE(0x01|0x2), U32_TO_U8S_LE(0xDFC), U32_TO_U8S_LE(0xDFC), 0, U32_TO_U8S_LE(0x2580), U32_TO_U8S_LE(0x2580), 0, U32_TO_U8S_LE(0xFE), U32_TO_U8S_LE(0), U32_TO_U8S_LE(0), U32_TO_U8S_LE(0x40840), U32_TO_U8S_LE(USB_BUFFER_SIZE), 0xFF, 0xFF, U16_TO_U8S_LE(0x0), 0, \
7, TUSB_DESC_ENDPOINT, _epout, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0, \
7, TUSB_DESC_ENDPOINT, _epin, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0
#define TUD_SMARTCARD_DESCRIPTOR_2EP(_itf, _strix, _epout, _epin, _epsize) \
9, TUSB_DESC_INTERFACE, _itf, 0, TUSB_SMARTCARD_CCID_EPS, TUSB_CLASS_SMART_CARD, 0, 0, _strix, \
TUSB_SMARTCARD_LEN, 0x21, U16_TO_U8S_LE(0x0110), 0, 0x1, U32_TO_U8S_LE(0x01|0x2), U32_TO_U8S_LE(0xDFC), U32_TO_U8S_LE(0xDFC), 0, U32_TO_U8S_LE(0x2580), U32_TO_U8S_LE(0x2580), 0, U32_TO_U8S_LE(0xFE), U32_TO_U8S_LE(0), U32_TO_U8S_LE(0), U32_TO_U8S_LE(0x40840), U32_TO_U8S_LE(USB_BUFFER_SIZE), 0xFF, 0xFF, U16_TO_U8S_LE(0x0), 0, 0x1, \
7, TUSB_DESC_ENDPOINT, _epout, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0, \
7, TUSB_DESC_ENDPOINT, _epin, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0
#if TUSB_SMARTCARD_CCID_EPS == 3
#define TUD_SMARTCARD_DESCRIPTOR(_itf, _strix, _epout, _epin, _epint, _epsize) \
TUD_SMARTCARD_DESCRIPTOR_2EP(_itf, _strix, _epout, _epin, _epsize), \
7, TUSB_DESC_ENDPOINT, _epint, TUSB_XFER_INTERRUPT, U16_TO_U8S_LE(_epsize), 10
#else
#define TUD_SMARTCARD_DESCRIPTOR(_itf, _strix, _epout, _epin, _epint, _epsize) \
TUD_SMARTCARD_DESCRIPTOR_2EP(_itf, _strix, _epout, _epin, _epsize)
#endif
#endif
uint8_t desc_config[MAX_TUSB_DESC_TOTAL_LEN] = {
TUD_CONFIG_DESCRIPTOR(1, 0, 4, 0, USB_CONFIG_ATT_ONE | TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, MAX_USB_POWER)
};
#ifdef USB_ITF_HID
uint8_t const *tud_hid_descriptor_report_cb(uint8_t itf) {
printf("report_cb %d\n", itf);
if (itf == ITF_HID_CTAP) {
return desc_hid_report;
}
else if (itf == ITF_HID_KB) {
return desc_hid_report_kb;
}
return NULL;
}
#endif
void usb_desc_setup() {
desc_config[4] = ITF_TOTAL;
TUSB_DESC_TOTAL_LEN = TUD_CONFIG_DESC_LEN;
uint8_t *p = desc_config + TUD_CONFIG_DESC_LEN;
#ifdef USB_ITF_HID
if (ITF_HID != ITF_INVALID) {
TUSB_DESC_TOTAL_LEN += TUD_HID_INOUT_DESC_LEN;
const uint8_t desc[] = { TUD_HID_INOUT_DESCRIPTOR(ITF_HID, ITF_HID + 5, HID_ITF_PROTOCOL_NONE, sizeof(desc_hid_report), EPNUM_HID, (uint8_t)TUSB_DIR_IN_MASK | EPNUM_HID, CFG_TUD_HID_EP_BUFSIZE, 10) };
memcpy(p, desc, sizeof(desc));
p += sizeof(desc);
}
if (ITF_KEYBOARD != ITF_INVALID) {
TUSB_DESC_TOTAL_LEN += TUD_HID_DESC_LEN;
const uint8_t desc_kb[] = { TUD_HID_DESCRIPTOR(ITF_KEYBOARD, ITF_KEYBOARD + 5, HID_ITF_PROTOCOL_NONE, sizeof(desc_hid_report_kb), (uint8_t)TUSB_DIR_IN_MASK | EPNUM_HID_KB, 16, 5) };
memcpy(p, desc_kb, sizeof(desc_kb));
p += sizeof(desc_kb);
}
#endif
#ifdef USB_ITF_CCID
if (ITF_CCID != ITF_INVALID) {
TUSB_DESC_TOTAL_LEN += TUSB_SMARTCARD_CCID_DESC_LEN;
const uint8_t desc_ccid[] = { TUD_SMARTCARD_DESCRIPTOR(ITF_CCID, ITF_CCID + 5, EPNUM_CCID, TUSB_DIR_IN_MASK | EPNUM_CCID, TUSB_DIR_IN_MASK | EPNUM_CCID_INT, 64) };
memcpy(p, desc_ccid, sizeof(desc_ccid));
p += sizeof(desc_ccid);
}
if (ITF_WCID != ITF_INVALID) {
TUSB_DESC_TOTAL_LEN += TUSB_SMARTCARD_WCID_DESC_LEN;
const uint8_t desc_wcid[] = { TUD_SMARTCARD_DESCRIPTOR_WEB(ITF_WCID, ITF_WCID + 5, EPNUM_WCID, TUSB_DIR_IN_MASK | EPNUM_WCID, 64) };
memcpy(p, desc_wcid, sizeof(desc_wcid));
p += sizeof(desc_wcid);
}
#endif
desc_config[2] = TUSB_DESC_TOTAL_LEN & 0xFF;
desc_config[3] = TUSB_DESC_TOTAL_LEN >> 8;
}
#ifndef ESP_PLATFORM
uint8_t const *tud_descriptor_configuration_cb(uint8_t index) {
(void) index; // for multiple configurations
usb_desc_setup();
return desc_config;
}
#endif
#ifdef USB_ITF_WCID
#define BOS_TOTAL_LEN (TUD_BOS_DESC_LEN + TUD_BOS_WEBUSB_DESC_LEN + TUD_BOS_MICROSOFT_OS_DESC_LEN)
#define MS_OS_20_DESC_LEN 0xB2
enum
{
VENDOR_REQUEST_WEBUSB = 1,
VENDOR_REQUEST_MICROSOFT = 2
};
#define URL "www.picokeys.com"
static bool web_serial_connected = false;
const tusb_desc_webusb_url_t desc_url =
{
.bLength = 3 + sizeof(URL) - 1,
.bDescriptorType = 3, // WEBUSB URL type
.bScheme = 1, // 0: http, 1: https
.url = URL
};
#define BOS_TOTAL_LEN (TUD_BOS_DESC_LEN + TUD_BOS_WEBUSB_DESC_LEN + TUD_BOS_MICROSOFT_OS_DESC_LEN)
#define MS_OS_20_DESC_LEN 0xB2
uint8_t desc_ms_os_20[] = {
// Set header: length, type, windows version, total length
U16_TO_U8S_LE(0x000A), U16_TO_U8S_LE(MS_OS_20_SET_HEADER_DESCRIPTOR), U32_TO_U8S_LE(0x06030000), U16_TO_U8S_LE(MS_OS_20_DESC_LEN),
// Configuration subset header: length, type, configuration index, reserved, configuration total length
U16_TO_U8S_LE(0x0008), U16_TO_U8S_LE(MS_OS_20_SUBSET_HEADER_CONFIGURATION), 0, 0, U16_TO_U8S_LE(MS_OS_20_DESC_LEN-0x0A),
// Function Subset header: length, type, first interface, reserved, subset length
U16_TO_U8S_LE(0x0008), U16_TO_U8S_LE(MS_OS_20_SUBSET_HEADER_FUNCTION), 0/*ITF_WCID*/, 0, U16_TO_U8S_LE(MS_OS_20_DESC_LEN-0x0A-0x08),
// MS OS 2.0 Compatible ID descriptor: length, type, compatible ID, sub compatible ID
U16_TO_U8S_LE(0x0014), U16_TO_U8S_LE(MS_OS_20_FEATURE_COMPATBLE_ID), 'W', 'I', 'N', 'U', 'S', 'B', 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // sub-compatible
// MS OS 2.0 Registry property descriptor: length, type
U16_TO_U8S_LE(MS_OS_20_DESC_LEN-0x0A-0x08-0x08-0x14), U16_TO_U8S_LE(MS_OS_20_FEATURE_REG_PROPERTY),
U16_TO_U8S_LE(0x0007), U16_TO_U8S_LE(0x002A), // wPropertyDataType, wPropertyNameLength and PropertyName "DeviceInterfaceGUIDs\0" in UTF-16
'D', 0x00, 'e', 0x00, 'v', 0x00, 'i', 0x00, 'c', 0x00, 'e', 0x00, 'I', 0x00, 'n', 0x00, 't', 0x00, 'e', 0x00,
'r', 0x00, 'f', 0x00, 'a', 0x00, 'c', 0x00, 'e', 0x00, 'G', 0x00, 'U', 0x00, 'I', 0x00, 'D', 0x00, 's', 0x00, 0x00, 0x00,
U16_TO_U8S_LE(0x0050), // wPropertyDataLength
//bPropertyData: “{975F44D9-0D08-43FD-8B3E-127CA8AFFF9D}”.
'{', 0x00, '9', 0x00, '7', 0x00, '5', 0x00, 'F', 0x00, '4', 0x00, '4', 0x00, 'D', 0x00, '9', 0x00, '-', 0x00,
'0', 0x00, 'D', 0x00, '0', 0x00, '8', 0x00, '-', 0x00, '4', 0x00, '3', 0x00, 'F', 0x00, 'D', 0x00, '-', 0x00,
'8', 0x00, 'B', 0x00, '3', 0x00, 'E', 0x00, '-', 0x00, '1', 0x00, '2', 0x00, '7', 0x00, 'C', 0x00, 'A', 0x00,
'8', 0x00, 'A', 0x00, 'F', 0x00, 'F', 0x00, 'F', 0x00, '9', 0x00, 'D', 0x00, '}', 0x00, 0x00, 0x00, 0x00, 0x00
};
bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request) {
// nothing to with DATA & ACK stage
if (stage != CONTROL_STAGE_SETUP)
return true;
switch (request->bmRequestType_bit.type) {
case TUSB_REQ_TYPE_VENDOR:
switch (request->bRequest) {
case VENDOR_REQUEST_WEBUSB:
return tud_control_xfer(rhport, request, (void*)(uintptr_t) &desc_url, desc_url.bLength);
case VENDOR_REQUEST_MICROSOFT:
if (request->wIndex == 7) {
// Get Microsoft OS 2.0 compatible descriptor
uint16_t total_len;
desc_ms_os_20[22] = ITF_WCID;
memcpy(&total_len, desc_ms_os_20+8, 2);
return tud_control_xfer(rhport, request, (void*)(uintptr_t) desc_ms_os_20, total_len);
}
else {
return false;
}
default:
break;
}
break;
case TUSB_REQ_TYPE_CLASS:
if (request->bRequest == 0x22) {
web_serial_connected = (request->wValue != 0);
if (web_serial_connected) {
printf("\nWebUSB interface connected\n");
}
return tud_control_status(rhport, request);
}
break;
default:
break;
}
// stall unknown request
return false;
}
uint8_t const desc_bos[] = {
// total length, number of device caps
TUD_BOS_DESCRIPTOR(BOS_TOTAL_LEN, 2),
// Vendor Code, iLandingPage
TUD_BOS_WEBUSB_DESCRIPTOR(VENDOR_REQUEST_WEBUSB, 1),
// Microsoft OS 2.0 descriptor
TUD_BOS_MS_OS_20_DESCRIPTOR(MS_OS_20_DESC_LEN, VENDOR_REQUEST_MICROSOFT)
};
uint8_t const *tud_descriptor_bos_cb(void) {
return desc_bos;
}
#endif
//--------------------------------------------------------------------+
// 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 Key", // 2: Product
"11223344", // 3: Serials, should use chip ID
"Config" // 4: Vendor Interface
#ifdef USB_ITF_HID
, "HID Interface"
, "HID Keyboard Interface"
#endif
#ifdef USB_ITF_CCID
, "CCID OTP FIDO Interface"
, "WebCCID Interface"
#endif
};
#ifdef ESP_PLATFORM
tinyusb_config_t tusb_cfg = {
.device_descriptor = &desc_device,
.string_descriptor = string_desc_arr,
.string_descriptor_count = (sizeof(string_desc_arr) / sizeof(string_desc_arr[0])) > 8 ? 8 : (sizeof(string_desc_arr) / sizeof(string_desc_arr[0])),
.external_phy = false,
.configuration_descriptor = desc_config,
};
#else
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 = 0;
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];
if (index == 3) {
str = pico_serial_str;
}
else if (index == 2) {
if (phy_data.usb_product_present) {
str = phy_data.usb_product;
}
}
uint8_t buff_avail = sizeof(_desc_str) / sizeof(_desc_str[0]) - 1;
if (index >= 4) {
const char *product = phy_data.usb_product_present ? phy_data.usb_product : string_desc_arr[2];
uint8_t len = (uint8_t)MIN(strlen(product), buff_avail);
for (size_t ix = 0; ix < len; chr_count++, ix++) {
_desc_str[1 + chr_count] = product[ix];
}
buff_avail -= len;
if (buff_avail > 0) {
_desc_str[1 + chr_count++] = ' ';
buff_avail--;
}
}
for (size_t ix = 0; ix < MIN(strlen(str), buff_avail); chr_count++, ix++) {
_desc_str[1 + chr_count] = str[ix];
}
}
_desc_str[0] = (TUSB_DESC_STRING << 8) | (2 * chr_count + 2);
return _desc_str;
}
#endif

View file

@ -1,49 +0,0 @@
/*
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
* Copyright (c) 2022 Pol Henarejos.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero 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
* Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef USB_DESCRIPTORS_H_
#define USB_DESCRIPTORS_H_
#include "compat.h"
PACK(
struct ccid_class_descriptor {
uint8_t bLength;
uint8_t bDescriptorType;
uint16_t bcdCCID;
uint8_t bMaxSlotIndex;
uint8_t bVoltageSupport;
uint32_t dwProtocols;
uint32_t dwDefaultClock;
uint32_t dwMaximumClock;
uint8_t bNumClockSupport;
uint32_t dwDataRate;
uint32_t dwMaxDataRate;
uint8_t bNumDataRatesSupported;
uint32_t dwMaxIFSD;
uint32_t dwSynchProtocols;
uint32_t dwMechanical;
uint32_t dwFeatures;
uint32_t dwMaxCCIDMessageLength;
uint8_t bClassGetResponse;
uint8_t bclassEnvelope;
uint16_t wLcdLayout;
uint8_t bPINSupport;
uint8_t bMaxCCIDBusySlots;
});
#endif /* USB_DESCRIPTORS_H_ */

View file

@ -1,23 +0,0 @@
/*
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
* Copyright (c) 2022 Pol Henarejos.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero 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
* Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "pico_keys.h"
#include "pico_keys_version.h"
const uint8_t PICO_PRODUCT = 0;
const uint8_t PICO_VERSION_MAJOR = PICO_KEYS_SDK_VERSION_MAJOR;
const uint8_t PICO_VERSION_MINOR = PICO_KEYS_SDK_VERSION_MINOR;

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