Compare commits
142 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
239e01c3f8 | ||
|
|
4a57698173 | ||
|
|
468051288c | ||
|
|
565ea12d88 | ||
|
|
1c7ef50568 | ||
|
|
878eae9787 | ||
|
|
24b1d6807b | ||
|
|
6bc081a1e1 | ||
|
|
afb16fff65 | ||
|
|
cf81a82645 | ||
|
|
dc820a60ae | ||
|
|
c57cc139f6 | ||
|
|
79426f35cd | ||
|
|
502a7ba81c | ||
|
|
deef209687 | ||
|
|
bb09f212d2 | ||
|
|
cfd86df45e | ||
|
|
d16c9b2324 | ||
|
|
f1630023c7 | ||
|
|
d41a488eda | ||
|
|
375a18ebac | ||
|
|
20216ac4ba | ||
|
|
d27d8b0c5b | ||
|
|
a619527482 | ||
|
|
85ff92c4de | ||
|
|
b1121718db | ||
|
|
2905dcc8c0 | ||
|
|
c9855f7214 | ||
|
|
853b8f29a2 | ||
|
|
d5378ffa41 | ||
|
|
4400eba974 | ||
|
|
0cc656c6c0 | ||
|
|
c9b32ab5d0 | ||
|
|
f9ffd39661 | ||
|
|
bfc12d6856 | ||
|
|
11874b52de | ||
|
|
b4e928588e | ||
|
|
33a2222cd8 | ||
|
|
923e05a36c | ||
|
|
b5cc4d6fd7 | ||
|
|
25291f978f | ||
|
|
ad66170379 | ||
|
|
86e38419ac | ||
|
|
1a5e6a7edc | ||
|
|
7cf166d615 | ||
|
|
413c3e0208 | ||
|
|
7410498df1 | ||
|
|
7aee18110e | ||
|
|
7aca7b323a | ||
|
|
4651a0e224 | ||
|
|
d018e3b9b9 | ||
|
|
1c272842a7 | ||
|
|
0141e0ab4e | ||
|
|
e7d8695394 | ||
|
|
6876edea5a | ||
|
|
2e655d6341 | ||
|
|
2f4cca19c4 | ||
|
|
5eb74d8ca3 | ||
|
|
7b0d5a6700 | ||
|
|
427260663f | ||
|
|
047a443536 | ||
|
|
7a9ee8145d | ||
|
|
2535d0e537 | ||
|
|
6fe7d7991b | ||
|
|
d061958f90 | ||
|
|
3112200eb6 | ||
|
|
69a406832d | ||
|
|
cd4ceb0a61 | ||
|
|
450ec5dec1 | ||
|
|
c7abd1a067 | ||
|
|
c6d87756ab | ||
|
|
0916489388 | ||
|
|
b1e83c92e9 | ||
|
|
d01e06aa11 | ||
|
|
464107b13f | ||
|
|
e431b25fc1 | ||
|
|
e4ed917c1c | ||
|
|
ade3e6d2fb | ||
|
|
d12d18261f | ||
|
|
525b4439c9 | ||
|
|
43ec92ddc5 | ||
|
|
74127a038f | ||
|
|
a01bd39f21 | ||
|
|
9c707df93b | ||
|
|
4bdb189f10 | ||
|
|
c2a474df98 | ||
|
|
483dc5e953 | ||
|
|
f490f073b0 | ||
|
|
2eab8eba09 | ||
|
|
783c901567 | ||
|
|
90d1fa0f9b | ||
|
|
96b791b3b9 | ||
|
|
78d71a6d9c | ||
|
|
0a2740fbab | ||
|
|
3192e928ff | ||
|
|
ae1e2ac111 | ||
|
|
d87073f4cc | ||
|
|
36a8f78313 | ||
|
|
0628d5015c | ||
|
|
daf0f98660 | ||
|
|
1f06c44a89 | ||
|
|
ab1490a50b | ||
|
|
23f53a6095 | ||
|
|
920cf3a1c5 | ||
|
|
74f2a80fb4 | ||
|
|
29361fa110 | ||
|
|
679486d38c | ||
|
|
8988d1cf15 | ||
|
|
693c890663 | ||
|
|
591b02804e | ||
|
|
37c3028b1c | ||
|
|
2cedf65f1a | ||
|
|
c31e4f8c2b | ||
|
|
c756e756b6 | ||
|
|
73bc2ede6b | ||
|
|
dcae71a4e8 | ||
|
|
71a5a456c5 | ||
|
|
e1f88acb17 | ||
|
|
5a2ec221b7 | ||
|
|
a018699283 | ||
|
|
0a10fa4fbb | ||
|
|
c609cec441 | ||
|
|
587ead4ad9 | ||
|
|
e3d809ae7f | ||
|
|
4f142d1b93 | ||
|
|
1f7e7aa14c | ||
|
|
a4baa99fce | ||
|
|
df020efa46 | ||
|
|
c31dd26e22 | ||
|
|
6d22fc20d4 | ||
|
|
3d74952c41 | ||
|
|
51f574f9f6 | ||
|
|
1c6fb98350 | ||
|
|
f1c0b12f5c | ||
|
|
213b675b9f | ||
|
|
b701f639ac | ||
|
|
4a0144ed2a | ||
|
|
9be78aade6 | ||
|
|
b7ee325d4f | ||
|
|
3e89e8f835 | ||
|
|
70f71e742e | ||
|
|
7988083d6b |
2
.gitmodules
vendored
2
.gitmodules
vendored
@@ -1,6 +1,6 @@
|
|||||||
[submodule "OpenSC"]
|
[submodule "OpenSC"]
|
||||||
path = OpenSC
|
path = OpenSC
|
||||||
url = https://github.com/OpenSC/OpenSC
|
url = https://github.com/polhenarejos/OpenSC
|
||||||
[submodule "mbedtls"]
|
[submodule "mbedtls"]
|
||||||
path = mbedtls
|
path = mbedtls
|
||||||
url = https://github.com/ARMmbed/mbedtls
|
url = https://github.com/ARMmbed/mbedtls
|
||||||
|
|||||||
@@ -1,15 +1,32 @@
|
|||||||
|
#
|
||||||
|
# This file is part of the Pico HSM distribution (https://github.com/polhenarejos/pico-hsm).
|
||||||
|
# Copyright (c) 2022 Pol Henarejos.
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, version 3.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful, but
|
||||||
|
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
# General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
|
||||||
cmake_minimum_required(VERSION 3.13)
|
cmake_minimum_required(VERSION 3.13)
|
||||||
|
|
||||||
include(pico_sdk_import.cmake)
|
include(pico_sdk_import.cmake)
|
||||||
|
|
||||||
project(hsm2040 C CXX ASM)
|
project(pico_hsm C CXX ASM)
|
||||||
|
|
||||||
set(CMAKE_C_STANDARD 11)
|
set(CMAKE_C_STANDARD 11)
|
||||||
set(CMAKE_CXX_STANDARD 17)
|
set(CMAKE_CXX_STANDARD 17)
|
||||||
|
|
||||||
pico_sdk_init()
|
pico_sdk_init()
|
||||||
|
|
||||||
add_executable(hsm2040)
|
add_executable(pico_hsm)
|
||||||
|
|
||||||
if (NOT DEFINED USB_VID)
|
if (NOT DEFINED USB_VID)
|
||||||
set(USB_VID 0xFEFF)
|
set(USB_VID 0xFEFF)
|
||||||
@@ -25,24 +42,18 @@ set_source_files_properties(
|
|||||||
PROPERTIES COMPILE_DEFINITIONS "PACKAGE_VERSION=\"0.22.0\";OPENSC_CONF_PATH=\".\""
|
PROPERTIES COMPILE_DEFINITIONS "PACKAGE_VERSION=\"0.22.0\";OPENSC_CONF_PATH=\".\""
|
||||||
)
|
)
|
||||||
|
|
||||||
target_sources(hsm2040 PUBLIC
|
target_sources(pico_hsm PUBLIC
|
||||||
${CMAKE_CURRENT_LIST_DIR}/hsm2040.c
|
${CMAKE_CURRENT_LIST_DIR}/src/hsm/hsm2040.c
|
||||||
${CMAKE_CURRENT_LIST_DIR}/usb_descriptors.c
|
${CMAKE_CURRENT_LIST_DIR}/src/hsm/sc_hsm.c
|
||||||
${CMAKE_CURRENT_LIST_DIR}/openpgp.c
|
${CMAKE_CURRENT_LIST_DIR}/src/usb/usb_descriptors.c
|
||||||
${CMAKE_CURRENT_LIST_DIR}/debug.c
|
${CMAKE_CURRENT_LIST_DIR}/src/fs/file.c
|
||||||
${CMAKE_CURRENT_LIST_DIR}/openpgp-do.c
|
${CMAKE_CURRENT_LIST_DIR}/src/fs/flash.c
|
||||||
${CMAKE_CURRENT_LIST_DIR}/ac.c
|
${CMAKE_CURRENT_LIST_DIR}/src/fs/low_flash.c
|
||||||
${CMAKE_CURRENT_LIST_DIR}/file.c
|
${CMAKE_CURRENT_LIST_DIR}/src/rng/random.c
|
||||||
${CMAKE_CURRENT_LIST_DIR}/flash.c
|
${CMAKE_CURRENT_LIST_DIR}/src/rng/neug.c
|
||||||
${CMAKE_CURRENT_LIST_DIR}/flash_openpgp.c
|
${CMAKE_CURRENT_LIST_DIR}/src/hsm/crypto_utils.c
|
||||||
${CMAKE_CURRENT_LIST_DIR}/low_flash.c
|
${CMAKE_CURRENT_LIST_DIR}/src/hsm/dkek.c
|
||||||
${CMAKE_CURRENT_LIST_DIR}/call-rsa.c
|
|
||||||
${CMAKE_CURRENT_LIST_DIR}/call-ec_p256k1.c
|
|
||||||
${CMAKE_CURRENT_LIST_DIR}/ecc-ed25519.c
|
|
||||||
${CMAKE_CURRENT_LIST_DIR}/ecc-ed448.c
|
|
||||||
${CMAKE_CURRENT_LIST_DIR}/random.c
|
|
||||||
${CMAKE_CURRENT_LIST_DIR}/ecc-mont.c
|
|
||||||
${CMAKE_CURRENT_LIST_DIR}/ecc-x448.c
|
|
||||||
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/sha256.c
|
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/sha256.c
|
||||||
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/aes.c
|
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/aes.c
|
||||||
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/sha512.c
|
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/sha512.c
|
||||||
@@ -61,17 +72,21 @@ target_sources(hsm2040 PUBLIC
|
|||||||
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/md5.c
|
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/md5.c
|
||||||
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/ripemd160.c
|
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/ripemd160.c
|
||||||
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/sha1.c
|
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/sha1.c
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/ecdh.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/chachapoly.c
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/camellia.c
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/chacha20.c
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/aria.c
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/poly1305.c
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/gcm.c
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/ccm.c
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/des.c
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/nist_kw.c
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/hkdf.c
|
||||||
|
|
||||||
${CMAKE_CURRENT_LIST_DIR}/shake256.c
|
|
||||||
${CMAKE_CURRENT_LIST_DIR}/neug.c
|
|
||||||
${CMAKE_CURRENT_LIST_DIR}/ec_p256k1.c
|
|
||||||
${CMAKE_CURRENT_LIST_DIR}/bn.c
|
|
||||||
${CMAKE_CURRENT_LIST_DIR}/mod.c
|
|
||||||
${CMAKE_CURRENT_LIST_DIR}/jpc_p256k1.c
|
|
||||||
${CMAKE_CURRENT_LIST_DIR}/modp256k1.c
|
|
||||||
${CMAKE_CURRENT_LIST_DIR}/p448.c
|
|
||||||
${CMAKE_CURRENT_LIST_DIR}/mod25638.c
|
|
||||||
${CMAKE_CURRENT_LIST_DIR}/sc_hsm.c
|
|
||||||
${CMAKE_CURRENT_LIST_DIR}/OpenSC/src/libopensc/pkcs15.c
|
${CMAKE_CURRENT_LIST_DIR}/OpenSC/src/libopensc/pkcs15.c
|
||||||
${CMAKE_CURRENT_LIST_DIR}/OpenSC/src/libopensc/pkcs15-prkey.c
|
${CMAKE_CURRENT_LIST_DIR}/OpenSC/src/libopensc/pkcs15-prkey.c
|
||||||
${CMAKE_CURRENT_LIST_DIR}/OpenSC/src/libopensc/pkcs15-algo.c
|
${CMAKE_CURRENT_LIST_DIR}/OpenSC/src/libopensc/pkcs15-algo.c
|
||||||
@@ -90,18 +105,21 @@ target_sources(hsm2040 PUBLIC
|
|||||||
${CMAKE_CURRENT_LIST_DIR}/OpenSC/src/libopensc/padding.c
|
${CMAKE_CURRENT_LIST_DIR}/OpenSC/src/libopensc/padding.c
|
||||||
)
|
)
|
||||||
|
|
||||||
target_include_directories(hsm2040 PUBLIC
|
target_include_directories(pico_hsm PUBLIC
|
||||||
${CMAKE_CURRENT_LIST_DIR}
|
${CMAKE_CURRENT_LIST_DIR}/src/fs
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/src/hsm
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/src/rng
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/src/usb
|
||||||
${CMAKE_CURRENT_LIST_DIR}/opensc/src
|
${CMAKE_CURRENT_LIST_DIR}/opensc/src
|
||||||
${CMAKE_CURRENT_LIST_DIR}/mbedtls/include
|
${CMAKE_CURRENT_LIST_DIR}/mbedtls/include
|
||||||
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library
|
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library
|
||||||
)
|
)
|
||||||
|
|
||||||
pico_add_extra_outputs(hsm2040)
|
pico_add_extra_outputs(pico_hsm)
|
||||||
|
|
||||||
#target_compile_definitions(hsm2040 PRIVATE MBEDTLS_ECDSA_DETERMINISTIC=1)
|
#target_compile_definitions(pico_hsm PRIVATE MBEDTLS_ECDSA_DETERMINISTIC=1)
|
||||||
|
|
||||||
target_link_libraries(hsm2040 PRIVATE pico_stdlib tinyusb_device tinyusb_board pico_multicore hardware_flash hardware_sync hardware_adc pico_unique_id)
|
target_link_libraries(pico_hsm PRIVATE pico_stdlib tinyusb_device tinyusb_board pico_multicore hardware_flash hardware_sync hardware_adc pico_unique_id hardware_rtc)
|
||||||
|
|
||||||
#
|
#
|
||||||
#project(flash_nuke C CXX ASM)
|
#project(flash_nuke C CXX ASM)
|
||||||
|
|||||||
674
LICENSE
Normal file
674
LICENSE
Normal file
@@ -0,0 +1,674 @@
|
|||||||
|
GNU GENERAL PUBLIC LICENSE
|
||||||
|
Version 3, 29 June 2007
|
||||||
|
|
||||||
|
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||||
|
Everyone is permitted to copy and distribute verbatim copies
|
||||||
|
of this license document, but changing it is not allowed.
|
||||||
|
|
||||||
|
Preamble
|
||||||
|
|
||||||
|
The GNU General Public License is a free, copyleft license for
|
||||||
|
software and other kinds of works.
|
||||||
|
|
||||||
|
The licenses for most software and other practical works are designed
|
||||||
|
to take away your freedom to share and change the works. By contrast,
|
||||||
|
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
|
||||||
|
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
|
||||||
|
price. Our General Public Licenses are designed to make sure that you
|
||||||
|
have the freedom to distribute copies of free software (and charge for
|
||||||
|
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
|
||||||
|
free programs, and that you know you can do these things.
|
||||||
|
|
||||||
|
To protect your rights, we need to prevent others from denying you
|
||||||
|
these rights or asking you to surrender the rights. Therefore, you have
|
||||||
|
certain responsibilities if you distribute copies of the software, or if
|
||||||
|
you modify it: responsibilities to respect the freedom of others.
|
||||||
|
|
||||||
|
For example, if you distribute copies of such a program, whether
|
||||||
|
gratis or for a fee, you must pass on to the recipients the same
|
||||||
|
freedoms that you received. You must make sure that they, too, receive
|
||||||
|
or can get the source code. And you must show them these terms so they
|
||||||
|
know their rights.
|
||||||
|
|
||||||
|
Developers that use the GNU GPL protect your rights with two steps:
|
||||||
|
(1) assert copyright on the software, and (2) offer you this License
|
||||||
|
giving you legal permission to copy, distribute and/or modify it.
|
||||||
|
|
||||||
|
For the developers' and authors' protection, the GPL clearly explains
|
||||||
|
that there is no warranty for this free software. For both users' and
|
||||||
|
authors' sake, the GPL requires that modified versions be marked as
|
||||||
|
changed, so that their problems will not be attributed erroneously to
|
||||||
|
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
|
||||||
|
modification follow.
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
0. Definitions.
|
||||||
|
|
||||||
|
"This License" refers to version 3 of the GNU General Public License.
|
||||||
|
|
||||||
|
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||||
|
works, such as semiconductor masks.
|
||||||
|
|
||||||
|
"The Program" refers to any copyrightable work licensed under this
|
||||||
|
License. Each licensee is addressed as "you". "Licensees" and
|
||||||
|
"recipients" may be individuals or organizations.
|
||||||
|
|
||||||
|
To "modify" a work means to copy from or adapt all or part of the work
|
||||||
|
in a fashion requiring copyright permission, other than the making of an
|
||||||
|
exact copy. The resulting work is called a "modified version" of the
|
||||||
|
earlier work or a work "based on" the earlier work.
|
||||||
|
|
||||||
|
A "covered work" means either the unmodified Program or a work based
|
||||||
|
on the Program.
|
||||||
|
|
||||||
|
To "propagate" a work means to do anything with it that, without
|
||||||
|
permission, would make you directly or secondarily liable for
|
||||||
|
infringement under applicable copyright law, except executing it on a
|
||||||
|
computer or modifying a private copy. Propagation includes copying,
|
||||||
|
distribution (with or without modification), making available to the
|
||||||
|
public, and in some countries other activities as well.
|
||||||
|
|
||||||
|
To "convey" a work means any kind of propagation that enables other
|
||||||
|
parties to make or receive copies. Mere interaction with a user through
|
||||||
|
a computer network, with no transfer of a copy, is not conveying.
|
||||||
|
|
||||||
|
An interactive user interface displays "Appropriate Legal Notices"
|
||||||
|
to the extent that it includes a convenient and prominently visible
|
||||||
|
feature that (1) displays an appropriate copyright notice, and (2)
|
||||||
|
tells the user that there is no warranty for the work (except to the
|
||||||
|
extent that warranties are provided), that licensees may convey the
|
||||||
|
work under this License, and how to view a copy of this License. If
|
||||||
|
the interface presents a list of user commands or options, such as a
|
||||||
|
menu, a prominent item in the list meets this criterion.
|
||||||
|
|
||||||
|
1. Source Code.
|
||||||
|
|
||||||
|
The "source code" for a work means the preferred form of the work
|
||||||
|
for making modifications to it. "Object code" means any non-source
|
||||||
|
form of a work.
|
||||||
|
|
||||||
|
A "Standard Interface" means an interface that either is an official
|
||||||
|
standard defined by a recognized standards body, or, in the case of
|
||||||
|
interfaces specified for a particular programming language, one that
|
||||||
|
is widely used among developers working in that language.
|
||||||
|
|
||||||
|
The "System Libraries" of an executable work include anything, other
|
||||||
|
than the work as a whole, that (a) is included in the normal form of
|
||||||
|
packaging a Major Component, but which is not part of that Major
|
||||||
|
Component, and (b) serves only to enable use of the work with that
|
||||||
|
Major Component, or to implement a Standard Interface for which an
|
||||||
|
implementation is available to the public in source code form. A
|
||||||
|
"Major Component", in this context, means a major essential component
|
||||||
|
(kernel, window system, and so on) of the specific operating system
|
||||||
|
(if any) on which the executable work runs, or a compiler used to
|
||||||
|
produce the work, or an object code interpreter used to run it.
|
||||||
|
|
||||||
|
The "Corresponding Source" for a work in object code form means all
|
||||||
|
the source code needed to generate, install, and (for an executable
|
||||||
|
work) run the object code and to modify the work, including scripts to
|
||||||
|
control those activities. However, it does not include the work's
|
||||||
|
System Libraries, or general-purpose tools or generally available free
|
||||||
|
programs which are used unmodified in performing those activities but
|
||||||
|
which are not part of the work. For example, Corresponding Source
|
||||||
|
includes interface definition files associated with source files for
|
||||||
|
the work, and the source code for shared libraries and dynamically
|
||||||
|
linked subprograms that the work is specifically designed to require,
|
||||||
|
such as by intimate data communication or control flow between those
|
||||||
|
subprograms and other parts of the work.
|
||||||
|
|
||||||
|
The Corresponding Source need not include anything that users
|
||||||
|
can regenerate automatically from other parts of the Corresponding
|
||||||
|
Source.
|
||||||
|
|
||||||
|
The Corresponding Source for a work in source code form is that
|
||||||
|
same work.
|
||||||
|
|
||||||
|
2. Basic Permissions.
|
||||||
|
|
||||||
|
All rights granted under this License are granted for the term of
|
||||||
|
copyright on the Program, and are irrevocable provided the stated
|
||||||
|
conditions are met. This License explicitly affirms your unlimited
|
||||||
|
permission to run the unmodified Program. The output from running a
|
||||||
|
covered work is covered by this License only if the output, given its
|
||||||
|
content, constitutes a covered work. This License acknowledges your
|
||||||
|
rights of fair use or other equivalent, as provided by copyright law.
|
||||||
|
|
||||||
|
You may make, run and propagate covered works that you do not
|
||||||
|
convey, without conditions so long as your license otherwise remains
|
||||||
|
in force. You may convey covered works to others for the sole purpose
|
||||||
|
of having them make modifications exclusively for you, or provide you
|
||||||
|
with facilities for running those works, provided that you comply with
|
||||||
|
the terms of this License in conveying all material for which you do
|
||||||
|
not control copyright. Those thus making or running the covered works
|
||||||
|
for you must do so exclusively on your behalf, under your direction
|
||||||
|
and control, on terms that prohibit them from making any copies of
|
||||||
|
your copyrighted material outside their relationship with you.
|
||||||
|
|
||||||
|
Conveying under any other circumstances is permitted solely under
|
||||||
|
the conditions stated below. Sublicensing is not allowed; section 10
|
||||||
|
makes it unnecessary.
|
||||||
|
|
||||||
|
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||||
|
|
||||||
|
No covered work shall be deemed part of an effective technological
|
||||||
|
measure under any applicable law fulfilling obligations under article
|
||||||
|
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||||
|
similar laws prohibiting or restricting circumvention of such
|
||||||
|
measures.
|
||||||
|
|
||||||
|
When you convey a covered work, you waive any legal power to forbid
|
||||||
|
circumvention of technological measures to the extent such circumvention
|
||||||
|
is effected by exercising rights under this License with respect to
|
||||||
|
the covered work, and you disclaim any intention to limit operation or
|
||||||
|
modification of the work as a means of enforcing, against the work's
|
||||||
|
users, your or third parties' legal rights to forbid circumvention of
|
||||||
|
technological measures.
|
||||||
|
|
||||||
|
4. Conveying Verbatim Copies.
|
||||||
|
|
||||||
|
You may convey verbatim copies of the Program's source code as you
|
||||||
|
receive it, in any medium, provided that you conspicuously and
|
||||||
|
appropriately publish on each copy an appropriate copyright notice;
|
||||||
|
keep intact all notices stating that this License and any
|
||||||
|
non-permissive terms added in accord with section 7 apply to the code;
|
||||||
|
keep intact all notices of the absence of any warranty; and give all
|
||||||
|
recipients a copy of this License along with the Program.
|
||||||
|
|
||||||
|
You may charge any price or no price for each copy that you convey,
|
||||||
|
and you may offer support or warranty protection for a fee.
|
||||||
|
|
||||||
|
5. Conveying Modified Source Versions.
|
||||||
|
|
||||||
|
You may convey a work based on the Program, or the modifications to
|
||||||
|
produce it from the Program, in the form of source code under the
|
||||||
|
terms of section 4, provided that you also meet all of these conditions:
|
||||||
|
|
||||||
|
a) The work must carry prominent notices stating that you modified
|
||||||
|
it, and giving a relevant date.
|
||||||
|
|
||||||
|
b) The work must carry prominent notices stating that it is
|
||||||
|
released under this License and any conditions added under section
|
||||||
|
7. This requirement modifies the requirement in section 4 to
|
||||||
|
"keep intact all notices".
|
||||||
|
|
||||||
|
c) You must license the entire work, as a whole, under this
|
||||||
|
License to anyone who comes into possession of a copy. This
|
||||||
|
License will therefore apply, along with any applicable section 7
|
||||||
|
additional terms, to the whole of the work, and all its parts,
|
||||||
|
regardless of how they are packaged. This License gives no
|
||||||
|
permission to license the work in any other way, but it does not
|
||||||
|
invalidate such permission if you have separately received it.
|
||||||
|
|
||||||
|
d) If the work has interactive user interfaces, each must display
|
||||||
|
Appropriate Legal Notices; however, if the Program has interactive
|
||||||
|
interfaces that do not display Appropriate Legal Notices, your
|
||||||
|
work need not make them do so.
|
||||||
|
|
||||||
|
A compilation of a covered work with other separate and independent
|
||||||
|
works, which are not by their nature extensions of the covered work,
|
||||||
|
and which are not combined with it such as to form a larger program,
|
||||||
|
in or on a volume of a storage or distribution medium, is called an
|
||||||
|
"aggregate" if the compilation and its resulting copyright are not
|
||||||
|
used to limit the access or legal rights of the compilation's users
|
||||||
|
beyond what the individual works permit. Inclusion of a covered work
|
||||||
|
in an aggregate does not cause this License to apply to the other
|
||||||
|
parts of the aggregate.
|
||||||
|
|
||||||
|
6. Conveying Non-Source Forms.
|
||||||
|
|
||||||
|
You may convey a covered work in object code form under the terms
|
||||||
|
of sections 4 and 5, provided that you also convey the
|
||||||
|
machine-readable Corresponding Source under the terms of this License,
|
||||||
|
in one of these ways:
|
||||||
|
|
||||||
|
a) Convey the object code in, or embodied in, a physical product
|
||||||
|
(including a physical distribution medium), accompanied by the
|
||||||
|
Corresponding Source fixed on a durable physical medium
|
||||||
|
customarily used for software interchange.
|
||||||
|
|
||||||
|
b) Convey the object code in, or embodied in, a physical product
|
||||||
|
(including a physical distribution medium), accompanied by a
|
||||||
|
written offer, valid for at least three years and valid for as
|
||||||
|
long as you offer spare parts or customer support for that product
|
||||||
|
model, to give anyone who possesses the object code either (1) a
|
||||||
|
copy of the Corresponding Source for all the software in the
|
||||||
|
product that is covered by this License, on a durable physical
|
||||||
|
medium customarily used for software interchange, for a price no
|
||||||
|
more than your reasonable cost of physically performing this
|
||||||
|
conveying of source, or (2) access to copy the
|
||||||
|
Corresponding Source from a network server at no charge.
|
||||||
|
|
||||||
|
c) Convey individual copies of the object code with a copy of the
|
||||||
|
written offer to provide the Corresponding Source. This
|
||||||
|
alternative is allowed only occasionally and noncommercially, and
|
||||||
|
only if you received the object code with such an offer, in accord
|
||||||
|
with subsection 6b.
|
||||||
|
|
||||||
|
d) Convey the object code by offering access from a designated
|
||||||
|
place (gratis or for a charge), and offer equivalent access to the
|
||||||
|
Corresponding Source in the same way through the same place at no
|
||||||
|
further charge. You need not require recipients to copy the
|
||||||
|
Corresponding Source along with the object code. If the place to
|
||||||
|
copy the object code is a network server, the Corresponding Source
|
||||||
|
may be on a different server (operated by you or a third party)
|
||||||
|
that supports equivalent copying facilities, provided you maintain
|
||||||
|
clear directions next to the object code saying where to find the
|
||||||
|
Corresponding Source. Regardless of what server hosts the
|
||||||
|
Corresponding Source, you remain obligated to ensure that it is
|
||||||
|
available for as long as needed to satisfy these requirements.
|
||||||
|
|
||||||
|
e) Convey the object code using peer-to-peer transmission, provided
|
||||||
|
you inform other peers where the object code and Corresponding
|
||||||
|
Source of the work are being offered to the general public at no
|
||||||
|
charge under subsection 6d.
|
||||||
|
|
||||||
|
A separable portion of the object code, whose source code is excluded
|
||||||
|
from the Corresponding Source as a System Library, need not be
|
||||||
|
included in conveying the object code work.
|
||||||
|
|
||||||
|
A "User Product" is either (1) a "consumer product", which means any
|
||||||
|
tangible personal property which is normally used for personal, family,
|
||||||
|
or household purposes, or (2) anything designed or sold for incorporation
|
||||||
|
into a dwelling. In determining whether a product is a consumer product,
|
||||||
|
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||||
|
product received by a particular user, "normally used" refers to a
|
||||||
|
typical or common use of that class of product, regardless of the status
|
||||||
|
of the particular user or of the way in which the particular user
|
||||||
|
actually uses, or expects or is expected to use, the product. A product
|
||||||
|
is a consumer product regardless of whether the product has substantial
|
||||||
|
commercial, industrial or non-consumer uses, unless such uses represent
|
||||||
|
the only significant mode of use of the product.
|
||||||
|
|
||||||
|
"Installation Information" for a User Product means any methods,
|
||||||
|
procedures, authorization keys, or other information required to install
|
||||||
|
and execute modified versions of a covered work in that User Product from
|
||||||
|
a modified version of its Corresponding Source. The information must
|
||||||
|
suffice to ensure that the continued functioning of the modified object
|
||||||
|
code is in no case prevented or interfered with solely because
|
||||||
|
modification has been made.
|
||||||
|
|
||||||
|
If you convey an object code work under this section in, or with, or
|
||||||
|
specifically for use in, a User Product, and the conveying occurs as
|
||||||
|
part of a transaction in which the right of possession and use of the
|
||||||
|
User Product is transferred to the recipient in perpetuity or for a
|
||||||
|
fixed term (regardless of how the transaction is characterized), the
|
||||||
|
Corresponding Source conveyed under this section must be accompanied
|
||||||
|
by the Installation Information. But this requirement does not apply
|
||||||
|
if neither you nor any third party retains the ability to install
|
||||||
|
modified object code on the User Product (for example, the work has
|
||||||
|
been installed in ROM).
|
||||||
|
|
||||||
|
The requirement to provide Installation Information does not include a
|
||||||
|
requirement to continue to provide support service, warranty, or updates
|
||||||
|
for a work that has been modified or installed by the recipient, or for
|
||||||
|
the User Product in which it has been modified or installed. Access to a
|
||||||
|
network may be denied when the modification itself materially and
|
||||||
|
adversely affects the operation of the network or violates the rules and
|
||||||
|
protocols for communication across the network.
|
||||||
|
|
||||||
|
Corresponding Source conveyed, and Installation Information provided,
|
||||||
|
in accord with this section must be in a format that is publicly
|
||||||
|
documented (and with an implementation available to the public in
|
||||||
|
source code form), and must require no special password or key for
|
||||||
|
unpacking, reading or copying.
|
||||||
|
|
||||||
|
7. Additional Terms.
|
||||||
|
|
||||||
|
"Additional permissions" are terms that supplement the terms of this
|
||||||
|
License by making exceptions from one or more of its conditions.
|
||||||
|
Additional permissions that are applicable to the entire Program shall
|
||||||
|
be treated as though they were included in this License, to the extent
|
||||||
|
that they are valid under applicable law. If additional permissions
|
||||||
|
apply only to part of the Program, that part may be used separately
|
||||||
|
under those permissions, but the entire Program remains governed by
|
||||||
|
this License without regard to the additional permissions.
|
||||||
|
|
||||||
|
When you convey a copy of a covered work, you may at your option
|
||||||
|
remove any additional permissions from that copy, or from any part of
|
||||||
|
it. (Additional permissions may be written to require their own
|
||||||
|
removal in certain cases when you modify the work.) You may place
|
||||||
|
additional permissions on material, added by you to a covered work,
|
||||||
|
for which you have or can give appropriate copyright permission.
|
||||||
|
|
||||||
|
Notwithstanding any other provision of this License, for material you
|
||||||
|
add to a covered work, you may (if authorized by the copyright holders of
|
||||||
|
that material) supplement the terms of this License with terms:
|
||||||
|
|
||||||
|
a) Disclaiming warranty or limiting liability differently from the
|
||||||
|
terms of sections 15 and 16 of this License; or
|
||||||
|
|
||||||
|
b) Requiring preservation of specified reasonable legal notices or
|
||||||
|
author attributions in that material or in the Appropriate Legal
|
||||||
|
Notices displayed by works containing it; or
|
||||||
|
|
||||||
|
c) Prohibiting misrepresentation of the origin of that material, or
|
||||||
|
requiring that modified versions of such material be marked in
|
||||||
|
reasonable ways as different from the original version; or
|
||||||
|
|
||||||
|
d) Limiting the use for publicity purposes of names of licensors or
|
||||||
|
authors of the material; or
|
||||||
|
|
||||||
|
e) Declining to grant rights under trademark law for use of some
|
||||||
|
trade names, trademarks, or service marks; or
|
||||||
|
|
||||||
|
f) Requiring indemnification of licensors and authors of that
|
||||||
|
material by anyone who conveys the material (or modified versions of
|
||||||
|
it) with contractual assumptions of liability to the recipient, for
|
||||||
|
any liability that these contractual assumptions directly impose on
|
||||||
|
those licensors and authors.
|
||||||
|
|
||||||
|
All other non-permissive additional terms are considered "further
|
||||||
|
restrictions" within the meaning of section 10. If the Program as you
|
||||||
|
received it, or any part of it, contains a notice stating that it is
|
||||||
|
governed by this License along with a term that is a further
|
||||||
|
restriction, you may remove that term. If a license document contains
|
||||||
|
a further restriction but permits relicensing or conveying under this
|
||||||
|
License, you may add to a covered work material governed by the terms
|
||||||
|
of that license document, provided that the further restriction does
|
||||||
|
not survive such relicensing or conveying.
|
||||||
|
|
||||||
|
If you add terms to a covered work in accord with this section, you
|
||||||
|
must place, in the relevant source files, a statement of the
|
||||||
|
additional terms that apply to those files, or a notice indicating
|
||||||
|
where to find the applicable terms.
|
||||||
|
|
||||||
|
Additional terms, permissive or non-permissive, may be stated in the
|
||||||
|
form of a separately written license, or stated as exceptions;
|
||||||
|
the above requirements apply either way.
|
||||||
|
|
||||||
|
8. Termination.
|
||||||
|
|
||||||
|
You may not propagate or modify a covered work except as expressly
|
||||||
|
provided under this License. Any attempt otherwise to propagate or
|
||||||
|
modify it is void, and will automatically terminate your rights under
|
||||||
|
this License (including any patent licenses granted under the third
|
||||||
|
paragraph of section 11).
|
||||||
|
|
||||||
|
However, if you cease all violation of this License, then your
|
||||||
|
license from a particular copyright holder is reinstated (a)
|
||||||
|
provisionally, unless and until the copyright holder explicitly and
|
||||||
|
finally terminates your license, and (b) permanently, if the copyright
|
||||||
|
holder fails to notify you of the violation by some reasonable means
|
||||||
|
prior to 60 days after the cessation.
|
||||||
|
|
||||||
|
Moreover, your license from a particular copyright holder is
|
||||||
|
reinstated permanently if the copyright holder notifies you of the
|
||||||
|
violation by some reasonable means, this is the first time you have
|
||||||
|
received notice of violation of this License (for any work) from that
|
||||||
|
copyright holder, and you cure the violation prior to 30 days after
|
||||||
|
your receipt of the notice.
|
||||||
|
|
||||||
|
Termination of your rights under this section does not terminate the
|
||||||
|
licenses of parties who have received copies or rights from you under
|
||||||
|
this License. If your rights have been terminated and not permanently
|
||||||
|
reinstated, you do not qualify to receive new licenses for the same
|
||||||
|
material under section 10.
|
||||||
|
|
||||||
|
9. Acceptance Not Required for Having Copies.
|
||||||
|
|
||||||
|
You are not required to accept this License in order to receive or
|
||||||
|
run a copy of the Program. Ancillary propagation of a covered work
|
||||||
|
occurring solely as a consequence of using peer-to-peer transmission
|
||||||
|
to receive a copy likewise does not require acceptance. However,
|
||||||
|
nothing other than this License grants you permission to propagate or
|
||||||
|
modify any covered work. These actions infringe copyright if you do
|
||||||
|
not accept this License. Therefore, by modifying or propagating a
|
||||||
|
covered work, you indicate your acceptance of this License to do so.
|
||||||
|
|
||||||
|
10. Automatic Licensing of Downstream Recipients.
|
||||||
|
|
||||||
|
Each time you convey a covered work, the recipient automatically
|
||||||
|
receives a license from the original licensors, to run, modify and
|
||||||
|
propagate that work, subject to this License. You are not responsible
|
||||||
|
for enforcing compliance by third parties with this License.
|
||||||
|
|
||||||
|
An "entity transaction" is a transaction transferring control of an
|
||||||
|
organization, or substantially all assets of one, or subdividing an
|
||||||
|
organization, or merging organizations. If propagation of a covered
|
||||||
|
work results from an entity transaction, each party to that
|
||||||
|
transaction who receives a copy of the work also receives whatever
|
||||||
|
licenses to the work the party's predecessor in interest had or could
|
||||||
|
give under the previous paragraph, plus a right to possession of the
|
||||||
|
Corresponding Source of the work from the predecessor in interest, if
|
||||||
|
the predecessor has it or can get it with reasonable efforts.
|
||||||
|
|
||||||
|
You may not impose any further restrictions on the exercise of the
|
||||||
|
rights granted or affirmed under this License. For example, you may
|
||||||
|
not impose a license fee, royalty, or other charge for exercise of
|
||||||
|
rights granted under this License, and you may not initiate litigation
|
||||||
|
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||||
|
any patent claim is infringed by making, using, selling, offering for
|
||||||
|
sale, or importing the Program or any portion of it.
|
||||||
|
|
||||||
|
11. Patents.
|
||||||
|
|
||||||
|
A "contributor" is a copyright holder who authorizes use under this
|
||||||
|
License of the Program or a work on which the Program is based. The
|
||||||
|
work thus licensed is called the contributor's "contributor version".
|
||||||
|
|
||||||
|
A contributor's "essential patent claims" are all patent claims
|
||||||
|
owned or controlled by the contributor, whether already acquired or
|
||||||
|
hereafter acquired, that would be infringed by some manner, permitted
|
||||||
|
by this License, of making, using, or selling its contributor version,
|
||||||
|
but do not include claims that would be infringed only as a
|
||||||
|
consequence of further modification of the contributor version. For
|
||||||
|
purposes of this definition, "control" includes the right to grant
|
||||||
|
patent sublicenses in a manner consistent with the requirements of
|
||||||
|
this License.
|
||||||
|
|
||||||
|
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||||
|
patent license under the contributor's essential patent claims, to
|
||||||
|
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||||
|
propagate the contents of its contributor version.
|
||||||
|
|
||||||
|
In the following three paragraphs, a "patent license" is any express
|
||||||
|
agreement or commitment, however denominated, not to enforce a patent
|
||||||
|
(such as an express permission to practice a patent or covenant not to
|
||||||
|
sue for patent infringement). To "grant" such a patent license to a
|
||||||
|
party means to make such an agreement or commitment not to enforce a
|
||||||
|
patent against the party.
|
||||||
|
|
||||||
|
If you convey a covered work, knowingly relying on a patent license,
|
||||||
|
and the Corresponding Source of the work is not available for anyone
|
||||||
|
to copy, free of charge and under the terms of this License, through a
|
||||||
|
publicly available network server or other readily accessible means,
|
||||||
|
then you must either (1) cause the Corresponding Source to be so
|
||||||
|
available, or (2) arrange to deprive yourself of the benefit of the
|
||||||
|
patent license for this particular work, or (3) arrange, in a manner
|
||||||
|
consistent with the requirements of this License, to extend the patent
|
||||||
|
license to downstream recipients. "Knowingly relying" means you have
|
||||||
|
actual knowledge that, but for the patent license, your conveying the
|
||||||
|
covered work in a country, or your recipient's use of the covered work
|
||||||
|
in a country, would infringe one or more identifiable patents in that
|
||||||
|
country that you have reason to believe are valid.
|
||||||
|
|
||||||
|
If, pursuant to or in connection with a single transaction or
|
||||||
|
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||||
|
covered work, and grant a patent license to some of the parties
|
||||||
|
receiving the covered work authorizing them to use, propagate, modify
|
||||||
|
or convey a specific copy of the covered work, then the patent license
|
||||||
|
you grant is automatically extended to all recipients of the covered
|
||||||
|
work and works based on it.
|
||||||
|
|
||||||
|
A patent license is "discriminatory" if it does not include within
|
||||||
|
the scope of its coverage, prohibits the exercise of, or is
|
||||||
|
conditioned on the non-exercise of one or more of the rights that are
|
||||||
|
specifically granted under this License. You may not convey a covered
|
||||||
|
work if you are a party to an arrangement with a third party that is
|
||||||
|
in the business of distributing software, under which you make payment
|
||||||
|
to the third party based on the extent of your activity of conveying
|
||||||
|
the work, and under which the third party grants, to any of the
|
||||||
|
parties who would receive the covered work from you, a discriminatory
|
||||||
|
patent license (a) in connection with copies of the covered work
|
||||||
|
conveyed by you (or copies made from those copies), or (b) primarily
|
||||||
|
for and in connection with specific products or compilations that
|
||||||
|
contain the covered work, unless you entered into that arrangement,
|
||||||
|
or that patent license was granted, prior to 28 March 2007.
|
||||||
|
|
||||||
|
Nothing in this License shall be construed as excluding or limiting
|
||||||
|
any implied license or other defenses to infringement that may
|
||||||
|
otherwise be available to you under applicable patent law.
|
||||||
|
|
||||||
|
12. No Surrender of Others' Freedom.
|
||||||
|
|
||||||
|
If conditions are imposed on you (whether by court order, agreement or
|
||||||
|
otherwise) that contradict the conditions of this License, they do not
|
||||||
|
excuse you from the conditions of this License. If you cannot convey a
|
||||||
|
covered work so as to satisfy simultaneously your obligations under this
|
||||||
|
License and any other pertinent obligations, then as a consequence you may
|
||||||
|
not convey it at all. For example, if you agree to terms that obligate you
|
||||||
|
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
|
||||||
|
License would be to refrain entirely from conveying the Program.
|
||||||
|
|
||||||
|
13. Use with the GNU Affero General Public License.
|
||||||
|
|
||||||
|
Notwithstanding any other provision of this License, you have
|
||||||
|
permission to link or combine any covered work with a work licensed
|
||||||
|
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
|
||||||
|
License will continue to apply to the part which is the covered work,
|
||||||
|
but the special requirements of the GNU Affero General Public License,
|
||||||
|
section 13, concerning interaction through a network will apply to the
|
||||||
|
combination as such.
|
||||||
|
|
||||||
|
14. Revised Versions of this License.
|
||||||
|
|
||||||
|
The Free Software Foundation may publish revised and/or new versions of
|
||||||
|
the GNU General Public License from time to time. Such new versions will
|
||||||
|
be similar in spirit to the present version, but may differ in detail to
|
||||||
|
address new problems or concerns.
|
||||||
|
|
||||||
|
Each version is given a distinguishing version number. If the
|
||||||
|
Program specifies that a certain numbered version of the GNU General
|
||||||
|
Public License "or any later version" applies to it, you have the
|
||||||
|
option of following the terms and conditions either of that numbered
|
||||||
|
version or of any later version published by the Free Software
|
||||||
|
Foundation. If the Program does not specify a version number of the
|
||||||
|
GNU General Public License, you may choose any version ever published
|
||||||
|
by the Free Software Foundation.
|
||||||
|
|
||||||
|
If the Program specifies that a proxy can decide which future
|
||||||
|
versions of the GNU General Public License can be used, that proxy's
|
||||||
|
public statement of acceptance of a version permanently authorizes you
|
||||||
|
to choose that version for the Program.
|
||||||
|
|
||||||
|
Later license versions may give you additional or different
|
||||||
|
permissions. However, no additional obligations are imposed on any
|
||||||
|
author or copyright holder as a result of your choosing to follow a
|
||||||
|
later version.
|
||||||
|
|
||||||
|
15. Disclaimer of Warranty.
|
||||||
|
|
||||||
|
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||||
|
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||||
|
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||||
|
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||||
|
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||||
|
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||||
|
|
||||||
|
16. Limitation of Liability.
|
||||||
|
|
||||||
|
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||||
|
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||||
|
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||||
|
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||||
|
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||||
|
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||||
|
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||||
|
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||||
|
SUCH DAMAGES.
|
||||||
|
|
||||||
|
17. Interpretation of Sections 15 and 16.
|
||||||
|
|
||||||
|
If the disclaimer of warranty and limitation of liability provided
|
||||||
|
above cannot be given local legal effect according to their terms,
|
||||||
|
reviewing courts shall apply local law that most closely approximates
|
||||||
|
an absolute waiver of all civil liability in connection with the
|
||||||
|
Program, unless a warranty or assumption of liability accompanies a
|
||||||
|
copy of the Program in return for a fee.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
How to Apply These Terms to Your New Programs
|
||||||
|
|
||||||
|
If you develop a new program, and you want it to be of the greatest
|
||||||
|
possible use to the public, the best way to achieve this is to make it
|
||||||
|
free software which everyone can redistribute and change under these terms.
|
||||||
|
|
||||||
|
To do so, attach the following notices to the program. It is safest
|
||||||
|
to attach them to the start of each source file to most effectively
|
||||||
|
state the exclusion of warranty; and each file should have at least
|
||||||
|
the "copyright" line and a pointer to where the full notice is found.
|
||||||
|
|
||||||
|
<one line to give the program's name and a brief idea of what it does.>
|
||||||
|
Copyright (C) <year> <name of author>
|
||||||
|
|
||||||
|
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, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
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 <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
Also add information on how to contact you by electronic and paper mail.
|
||||||
|
|
||||||
|
If the program does terminal interaction, make it output a short
|
||||||
|
notice like this when it starts in an interactive mode:
|
||||||
|
|
||||||
|
<program> Copyright (C) <year> <name of author>
|
||||||
|
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||||
|
This is free software, and you are welcome to redistribute it
|
||||||
|
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,
|
||||||
|
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 GPL, see
|
||||||
|
<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>.
|
||||||
166
README.md
Normal file
166
README.md
Normal file
@@ -0,0 +1,166 @@
|
|||||||
|
# Raspberry Pico HSM
|
||||||
|
This is a project to create a Hardware Security Module (HSM) with a Raspberry Pico. It converts your Pico board into a HSM which is able to generate and store private keys, encrypt or decrypt with AES or signing data without to disclose the private key. In detail, the private key never leaves the board and it cannot be retrieved as it is encrypted in the flash memory.
|
||||||
|
|
||||||
|
## Capabilities
|
||||||
|
- Key generation and encrypted storage.
|
||||||
|
- RSA key generation from 1024 to 4096 bits.
|
||||||
|
- ECDSA key generation from 192 to 521 bits.
|
||||||
|
- ECC curves secp192r1, secp256r1, secp384r1, secp521r1, brainpoolP256r1, brainpoolP384r1, brainpoolP512r1, secp192k1 (insecure), secp256k1.
|
||||||
|
- SHA1, SHA224, SHA256, SHA384, SHA512 digests.
|
||||||
|
- RSA-PSS, RSA-PKCS and raw RSA signature.
|
||||||
|
- ECDSA raw and hash signature.
|
||||||
|
- ECDH key derivation.
|
||||||
|
- EC private key derivation.[^1]
|
||||||
|
- RSA-OEP and RSA-X-509 decryption.
|
||||||
|
- AES key generation of 128, 192 and 256 bits.
|
||||||
|
- AES-CBC encryption/decryption.
|
||||||
|
- AES-CMAC authentication.[^1]
|
||||||
|
- AES secret key derivation.[^1]
|
||||||
|
- PIN authorization.
|
||||||
|
- PKCS11 compliant interface.
|
||||||
|
- HRNG (hardware random number generator).
|
||||||
|
- Device Key Encryption Key (DKEK) shares.
|
||||||
|
- DKEK n-of-m threshold scheme.
|
||||||
|
- USB/CCID support with OpenSC, openssl, etc.
|
||||||
|
- Extended APDU support.
|
||||||
|
- Private keys and certificates import from WKY or PKCS#12 files.[^2][^3]
|
||||||
|
- Transport PIN for provisioning and forcing to set a new PIN.[^2]
|
||||||
|
- Press-to-confirm button optional feature to authorize operations with private/secret keys.
|
||||||
|
- Store and retrieve binary data.
|
||||||
|
- Real time clock with external datetime setting and getting.
|
||||||
|
|
||||||
|
[^1]: PKCS11 modules (`pkcs11-tool` and `sc-tool`) do not support CMAC and key derivation. It must be processed through raw APDU command (`opensc-tool -s`).
|
||||||
|
[^2]: Available via SCS3 tool. See [SCS3](/doc/rsa_4096.md "SCS3") for more information.
|
||||||
|
[^3]: Imports are available only if the Pico HSM is previously initialized with a DKEK and the DKEK shares are available during the import process.
|
||||||
|
|
||||||
|
## Security considerations
|
||||||
|
All secret keys (asymmetric and symmetric) are stored encrypted in the flash memory of the Raspberry Pico. DKEK is used as a 256 bit AES key to protect private and secret keys. Keys are never stored in RAM except for signature and decryption operations and only during the process. All keys (including DKEK) are loaded and cleared every time to avoid potential security flaws.
|
||||||
|
|
||||||
|
At the same time, DKEK is encrypted with doubled salted and hashed PIN. Also, the PIN is hashed in memory during the session. Hence, PIN is never stored in plain text neither in flash nor in memory. Note that PIN is conveyed from the host to the HSM in plain text if no secure channel is provided.
|
||||||
|
|
||||||
|
If the Pico is stolen the contents of private and secret keys cannot be read without the PIN, even if the flash memory is dumped.
|
||||||
|
|
||||||
|
## Download
|
||||||
|
Please, go to the Release page and download the UF2 file for your board.
|
||||||
|
|
||||||
|
Note that UF2 files are shiped with a dummy VID/PID to avoid license issues (FEFF:FCFD). If you are planning to use it with OpenSC or similar, you should modify Info.plist of CCID driver to add these VID/PID or use the VID/PID patcher as follows:
|
||||||
|
`./patch_vidpid.sh VID:PID input_hsm_file.uf2 output_hsm_file.uf2`
|
||||||
|
|
||||||
|
You can use whatever VID/PID (i.e., 234b:0000 from FISJ), but remember that you are not authorized to distribute the binary with a VID/PID that you do not own.
|
||||||
|
|
||||||
|
## Build
|
||||||
|
Before building, ensure you have installed the toolchain for the Pico and the Pico SDK is properly located in your drive.
|
||||||
|
|
||||||
|
```
|
||||||
|
git clone https://github.com/polhenarejos/pico-hsm
|
||||||
|
cd pico-hsm
|
||||||
|
mkdir build
|
||||||
|
cd build
|
||||||
|
PICO_SDK_PATH=/path/to/pico-sdk cmake .. -DPICO_BOARD=board_type -DUSB_VID=0x1234 -DUSB_PID=0x5678
|
||||||
|
make
|
||||||
|
```
|
||||||
|
Note that `PICO_BOARD`, `USB_VID` and `USB_PID` are optional. If not provided, `pico` board and VID/PID `FEFF:FCFD` will be used.
|
||||||
|
|
||||||
|
After `make` ends, the binary file `pico_hsm.uf2` will be generated. Put your pico board into loading mode, by pushing `BOOTSEL` button while pluging on, and copy the UF2 to the new fresh usb mass storage Pico device. Once copied, the pico mass storage will be disconnected automatically and the pico board will reset with the new firmware. A blinking led will indicate the device is ready to work.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
The firmware uploaded to the Pico contains a reader and a virtual smart card. It is like having a physical reader with an inserted SIM card.
|
||||||
|
We recommend the use of [OpenSC](http://github.com/opensc/opensc/ "OpenSC") to communicate with the reader. If it is not installed, you can download and build it or install the binaries for your system. The first command is to ensure that the Pico is detected as a HSM:
|
||||||
|
```
|
||||||
|
opensc-tool -an
|
||||||
|
````
|
||||||
|
It should return a text like the following:
|
||||||
|
```
|
||||||
|
Using reader with a card: Free Software Initiative of Japan Gnuk
|
||||||
|
3b:fe:18:00:00:81:31:fe:45:80:31:81:54:48:53:4d:31:73:80:21:40:81:07:fa
|
||||||
|
SmartCard-HSM
|
||||||
|
```
|
||||||
|
The name of the reader may vary if you modified the VID/PID.
|
||||||
|
|
||||||
|
For initialization and asymmetric operations, check [doc/usage.md](/doc/usage.md).
|
||||||
|
|
||||||
|
For signing and verification operations, check [doc/sign-verify.md](/doc/sign-verify.md).
|
||||||
|
|
||||||
|
For asymmetric encryption and decryption, check [doc/asymmetric-ciphering.md](/doc/asymmetric-ciphering.md).
|
||||||
|
|
||||||
|
For backup, restore and DKEK share management, check [doc/backup-and-restore.md](/doc/backup-and-restore.md).
|
||||||
|
|
||||||
|
For AES key generation, encryption and decryption, check [doc/aes.md](/doc/aes.md).
|
||||||
|
|
||||||
|
For 4096 bits RSA support, check [doc/rsa_4096_support.md](/doc/rsa_4096.md).
|
||||||
|
|
||||||
|
For storing and retrieving arbitrary data, check [doc/store_data.md](/doc/store_data.md).
|
||||||
|
|
||||||
|
For extra options, such as set/get real datetime or enable/disable press-to-confirm button, check [doc/extra_command.md](/doc/extra_command.md).
|
||||||
|
|
||||||
|
## Operation time
|
||||||
|
### Keypair generation
|
||||||
|
Generating EC keys is almost instant. RSA keypair generation takes some time, specially for `3072` and `4096` bits.
|
||||||
|
|
||||||
|
| RSA key length (bits) | Average time (seconds) |
|
||||||
|
| :---: | :---: |
|
||||||
|
| 1024 | 16 |
|
||||||
|
| 2048 | 124 |
|
||||||
|
| 3072 | 600 |
|
||||||
|
| 4096 | ~1000 |
|
||||||
|
|
||||||
|
### Signature and decrypt
|
||||||
|
| RSA key length (bits) | Average time (seconds) |
|
||||||
|
| :---: | :---: |
|
||||||
|
| 1024 | 1 |
|
||||||
|
| 2048 | 3 |
|
||||||
|
| 3072 | 7 |
|
||||||
|
| 4096 | 15 |
|
||||||
|
|
||||||
|
## Press-to-confirm button
|
||||||
|
Raspberry Pico comes with the BOOTSEL button to load the firmware. When this firmware is running, the button can be used for other purposes. Pico HSM uses this button to confirm private/secret operations. This feature is optional and it shall be enabled. For more information, see [doc/extra_command.md](/doc/extra_command.md).
|
||||||
|
|
||||||
|
With this feature enabled, everytime that a private/secret key is loaded, the Pico HSM awaits for the user confirmation by pressing the BOOTSEL button. The Led of the Pico HSM will remain almost illuminated, turning off quickly once a second, indicating that the user must press the button to confirm the operation. Otherwise, the Pico HSM waits indefinitely. See [Led blink](#press-to-confirm) for a picture of the blinking sequence. When in this mode, the Pico HSM sends periodic timeout commands to the host to do not trigger the timeout operation.
|
||||||
|
|
||||||
|
This feature is an extra layer of security, as it requires the user intervention to sign or decrypt and it ensures that any application will use the Pico HSM without user awareness. However, it is not recommended for servers or other environments where operations are authomatized, since it requires a physical access to the Pico HSM to push the button.
|
||||||
|
|
||||||
|
## Led blink
|
||||||
|
Pico HSM uses the led to indicate the current status. Four states are available:
|
||||||
|
### Press to confirm
|
||||||
|
The Led is almost on all the time. It goes off for 100 miliseconds every second.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
### Idle mode
|
||||||
|
In idle mode, the Pico HSM goes to sleep. It waits for a command and it is awaken by the driver. The Led is almost off all the time. It goes on for 500 milliseconds every second.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
### Active mode
|
||||||
|
In active mode, the Pico HSM is awaken and ready to receive a command. It blinks four times in a second.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
### Processing
|
||||||
|
While processing, the Pico HSM is busy and cannot receive additional commands until the current is processed. In this state, the Led blinks 20 times in a second.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## Driver
|
||||||
|
|
||||||
|
Pico HSM uses the `sc-hsm` driver provided by [OpenSC](https://github.com/OpenSC/OpenSC/ "OpenSC") or the `sc-hsm-embedded` driver provided by [CardContact](https://github.com/CardContact/sc-hsm-embedded "CardContact"). This driver utilizes the standardized PKCS#11 interface to communicate with the user and it can be used with many engines that accept PKCS#11 interface, such as OpenSSL, P11 library or pkcs11-tool.
|
||||||
|
|
||||||
|
Pico HSM relies on PKCS#15 structure to store and manipulate the internal files (PINs, private keys, certificates, etc.) and directories. Therefore, it accepts the commands from `pkcs15-tool`. For instance, `pkcs15-tool -D` will list all elements stored in the Pico HSM.
|
||||||
|
|
||||||
|
The way to communicate is exactly the same as with other cards, such as OpenPGP or similar.
|
||||||
|
|
||||||
|
For an advanced usage, see the docs and examples.
|
||||||
|
|
||||||
|
Pico HSM also supports SCS3 tool. See [SCS3](/doc/rsa_4096.md "SCS3") for more information.
|
||||||
|
|
||||||
|
### Important
|
||||||
|
OpenSC relies on PCSC driver, which reads a list (`Info.plist`) that contains a pair of VID/PID of supported readers. In order to be detectable, you must patch the UF2 binary (if you just downloaded from the [Release section](https://github.com/polhenarejos/pico-hsm/releases "Release section")) or configure the project with the proper VID/PID with `USB_VID` and `USB_PID` parameters in `CMake` (see [Build section](#build "Build section")). Note that you cannot distribute the patched/compiled binary if you do not own the VID/PID or have an explicit authorization.
|
||||||
|
|
||||||
|
## Credits
|
||||||
|
Pico HSM uses the following libraries or portion of code:
|
||||||
|
- OpenSC for ASN1 manipulation.
|
||||||
|
- mbedTLS for cryptographic operations.
|
||||||
|
- gnuk for low level CCID procedures and OpenPGP support.
|
||||||
|
- TinyUSB for low level USB procedures.
|
||||||
|
|
||||||
|
In the case of gnuk, it is intended to work with STM32 processor and its family. Part of the code of CCID procedures are ported and adapted to run with Pico.
|
||||||
21
build_pico_hsm.sh
Executable file
21
build_pico_hsm.sh
Executable file
@@ -0,0 +1,21 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
VERSION_MAJOR="1"
|
||||||
|
VERSION_MINOR="12"
|
||||||
|
|
||||||
|
rm -rf release/*
|
||||||
|
cd build_release
|
||||||
|
|
||||||
|
for board in adafruit_feather_rp2040 adafruit_itsybitsy_rp2040 adafruit_qtpy_rp2040 adafruit_trinkey_qt2040 arduino_nano_rp2040_connect melopero_shake_rp2040 pimoroni_interstate75 pimoroni_keybow2040 pimoroni_pga2040 pimoroni_picolipo_4mb pimoroni_picolipo_16mb pimoroni_picosystem pimoroni_plasma2040 pimoroni_tiny2040 pybstick26_rp2040 sparkfun_micromod sparkfun_promicro sparkfun_thingplus vgaboard waveshare_rp2040_lcd_0.96 waveshare_rp2040_plus_4mb waveshare_rp2040_plus_16mb waveshare_rp2040_zero
|
||||||
|
do
|
||||||
|
rm -rf *
|
||||||
|
PICO_SDK_PATH=~/Devel/pico/pico-sdk cmake .. -DPICO_BOARD=$board
|
||||||
|
make -kj20
|
||||||
|
mv pico_hsm.uf2 ../release/pico_hsm_$board-$VERSION_MAJOR.$VERSION_MINOR.uf2
|
||||||
|
|
||||||
|
done
|
||||||
|
|
||||||
|
rm -rf *
|
||||||
|
PICO_SDK_PATH=~/Devel/pico/pico-sdk cmake ..
|
||||||
|
make -kj20
|
||||||
|
mv pico_hsm.uf2 ../release/pico_hsm_pico_generic-$VERSION_MAJOR.$VERSION_MINOR.uf2
|
||||||
273
ccid-types.h
273
ccid-types.h
@@ -1,273 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2009-2015 Frank Morgner
|
|
||||||
*
|
|
||||||
* This library is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
|
||||||
* License as published by the Free Software Foundation; either
|
|
||||||
* version 2.1 of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This library 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
|
|
||||||
* Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
|
||||||
* License along with this library; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
*/
|
|
||||||
/**
|
|
||||||
* @file
|
|
||||||
*/
|
|
||||||
#ifndef _CCID_TYPES_H
|
|
||||||
#define _CCID_TYPES_H
|
|
||||||
|
|
||||||
#include "pico/types.h"
|
|
||||||
#include "hardware/structs/usb.h"
|
|
||||||
|
|
||||||
#define USB_REQ_CCID 0xA1
|
|
||||||
|
|
||||||
#define CCID_CONTROL_ABORT 0x01
|
|
||||||
#define CCID_CONTROL_GET_CLOCK_FREQUENCIES 0x02
|
|
||||||
#define CCID_CONTROL_GET_DATA_RATES 0x03
|
|
||||||
|
|
||||||
#define CCID_OPERATION_VERIFY 0x00;
|
|
||||||
#define CCID_OPERATION_MODIFY 0x01;
|
|
||||||
#define CCID_ENTRY_VALIDATE 0x02
|
|
||||||
|
|
||||||
#define CCID_BERROR_CMD_ABORTED 0xff /** Host aborted the current activity */
|
|
||||||
#define CCID_BERROR_ICC_MUTE 0xfe /** CCID timed out while talking to the ICC */
|
|
||||||
#define CCID_BERROR_XFR_PARITY_ERROR 0xfd /** Parity error while talking to the ICC */
|
|
||||||
#define CCID_BERROR_XFR_OVERRUN 0xfc /** Overrun error while talking to the ICC */
|
|
||||||
#define CCID_BERROR_HW_ERROR 0xfb /** An all inclusive hardware error occurred */
|
|
||||||
#define CCID_BERROR_BAD_ATR_TS 0xf
|
|
||||||
#define CCID_BERROR_BAD_ATR_TCK 0xf
|
|
||||||
#define CCID_BERROR_ICC_PROTOCOL_NOT_SUPPORTED 0xf6
|
|
||||||
#define CCID_BERROR_ICC_CLASS_NOT_SUPPORTED 0xf5
|
|
||||||
#define CCID_BERROR_PROCEDURE_BYTE_CONFLICT 0xf4
|
|
||||||
#define CCID_BERROR_DEACTIVATED_PROTOCOL 0xf3
|
|
||||||
#define CCID_BERROR_BUSY_WITH_AUTO_SEQUENCE 0xf2 /** Automatic Sequence Ongoing */
|
|
||||||
#define CCID_BERROR_PIN_TIMEOUT 0xf0
|
|
||||||
#define CCID_BERROR_PIN_CANCELLED 0xef
|
|
||||||
#define CCID_BERROR_CMD_SLOT_BUSY 0xe0 /** A second command was sent to a slot which was already processing a command. */
|
|
||||||
#define CCID_BERROR_CMD_NOT_SUPPORTED 0x00
|
|
||||||
#define CCID_BERROR_OK 0x00
|
|
||||||
|
|
||||||
#define CCID_BSTATUS_OK_ACTIVE 0x00 /** No error. An ICC is present and active */
|
|
||||||
#define CCID_BSTATUS_OK_INACTIVE 0x01 /** No error. ICC is present and inactive */
|
|
||||||
#define CCID_BSTATUS_OK_NOICC 0x02 /** No error. No ICC is present */
|
|
||||||
#define CCID_BSTATUS_ERROR_ACTIVE 0x40 /** Failed. An ICC is present and active */
|
|
||||||
#define CCID_BSTATUS_ERROR_INACTIVE 0x41 /** Failed. ICC is present and inactive */
|
|
||||||
#define CCID_BSTATUS_ERROR_NOICC 0x42 /** Failed. No ICC is present */
|
|
||||||
|
|
||||||
#define CCID_WLEVEL_DIRECT __constant_cpu_to_le16(0) /** APDU begins and ends with this command */
|
|
||||||
#define CCID_WLEVEL_CHAIN_NEXT_XFRBLOCK __constant_cpu_to_le16(1) /** APDU begins with this command, and continue in the next PC_to_RDR_XfrBlock */
|
|
||||||
#define CCID_WLEVEL_CHAIN_END __constant_cpu_to_le16(2) /** abData field continues a command APDU and ends the APDU command */
|
|
||||||
#define CCID_WLEVEL_CHAIN_CONTINUE __constant_cpu_to_le16(3) /** abData field continues a command APDU and another block is to follow */
|
|
||||||
#define CCID_WLEVEL_RESPONSE_IN_DATABLOCK __constant_cpu_to_le16(0x10) /** empty abData field, continuation of response APDU is expected in the next RDR_to_PC_DataBlock */
|
|
||||||
|
|
||||||
#define CCID_PIN_ENCODING_BIN 0x00
|
|
||||||
#define CCID_PIN_ENCODING_BCD 0x01
|
|
||||||
#define CCID_PIN_ENCODING_ASCII 0x02
|
|
||||||
#define CCID_PIN_UNITS_BYTES 0x80
|
|
||||||
#define CCID_PIN_JUSTIFY_RIGHT 0x04
|
|
||||||
#define CCID_PIN_CONFIRM_NEW 0x01
|
|
||||||
#define CCID_PIN_INSERT_OLD 0x02
|
|
||||||
#define CCID_PIN_NO_MSG 0x00
|
|
||||||
#define CCID_PIN_MSG1 0x01
|
|
||||||
#define CCID_PIN_MSG2 0x02
|
|
||||||
#define CCID_PIN_MSG_REF 0x03
|
|
||||||
#define CCID_PIN_MSG_DEFAULT 0xff
|
|
||||||
|
|
||||||
#define CCID_SLOTS_UNCHANGED 0x00
|
|
||||||
#define CCID_SLOT1_CARD_PRESENT 0x01
|
|
||||||
#define CCID_SLOT1_CHANGED 0x02
|
|
||||||
#define CCID_SLOT2_CARD_PRESENT 0x04
|
|
||||||
#define CCID_SLOT2_CHANGED 0x08
|
|
||||||
#define CCID_SLOT3_CARD_PRESENT 0x10
|
|
||||||
#define CCID_SLOT3_CHANGED 0x20
|
|
||||||
#define CCID_SLOT4_CARD_PRESENT 0x40
|
|
||||||
#define CCID_SLOT4_CHANGED 0x80
|
|
||||||
|
|
||||||
#define CCID_EXT_APDU_MAX (4 + 3 + 0xffff + 3)
|
|
||||||
#define CCID_SHORT_APDU_MAX (4 + 1 + 0xff + 1)
|
|
||||||
|
|
||||||
typedef struct TU_ATTR_PACKED {
|
|
||||||
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;
|
|
||||||
} class_desc_ccid_t;
|
|
||||||
|
|
||||||
struct abProtocolDataStructure_T0 {
|
|
||||||
uint8_t bmFindexDindex;
|
|
||||||
uint8_t bmTCCKST0;
|
|
||||||
uint8_t bGuardTimeT0;
|
|
||||||
uint8_t bWaitingIntegerT0;
|
|
||||||
uint8_t bClockStop;
|
|
||||||
} __packed;
|
|
||||||
|
|
||||||
struct abProtocolDataStructure_T1 {
|
|
||||||
uint8_t bmFindexDindex;
|
|
||||||
uint8_t bmTCCKST1;
|
|
||||||
uint8_t bGuardTimeT1;
|
|
||||||
uint8_t bWaitingIntegersT1;
|
|
||||||
uint8_t bClockStop;
|
|
||||||
uint8_t bIFSC;
|
|
||||||
uint8_t bNadValue;
|
|
||||||
} __packed;
|
|
||||||
|
|
||||||
struct abPINDataStucture_Verification {
|
|
||||||
uint8_t bTimeOut;
|
|
||||||
uint8_t bmFormatString;
|
|
||||||
uint8_t bmPINBlockString;
|
|
||||||
uint8_t bmPINLengthFormat;
|
|
||||||
uint16_t wPINMaxExtraDigit;
|
|
||||||
uint8_t bEntryValidationCondition;
|
|
||||||
uint8_t bNumberMessage;
|
|
||||||
uint16_t wLangId;
|
|
||||||
uint8_t bMsgIndex;
|
|
||||||
uint8_t bTeoPrologue1;
|
|
||||||
uint16_t bTeoPrologue2;
|
|
||||||
} __packed;
|
|
||||||
|
|
||||||
struct abPINDataStucture_Modification {
|
|
||||||
uint8_t bTimeOut;
|
|
||||||
uint8_t bmFormatString;
|
|
||||||
uint8_t bmPINBlockString;
|
|
||||||
uint8_t bmPINLengthFormat;
|
|
||||||
uint8_t bInsertionOffsetOld;
|
|
||||||
uint8_t bInsertionOffsetNew;
|
|
||||||
uint16_t wPINMaxExtraDigit;
|
|
||||||
uint8_t bConfirmPIN;
|
|
||||||
uint8_t bEntryValidationCondition;
|
|
||||||
uint8_t bNumberMessage;
|
|
||||||
uint16_t wLangId;
|
|
||||||
uint8_t bMsgIndex1;
|
|
||||||
} __packed;
|
|
||||||
|
|
||||||
struct PC_to_RDR_XfrBlock {
|
|
||||||
uint8_t bMessageType;
|
|
||||||
uint32_t dwLength;
|
|
||||||
uint8_t bSlot;
|
|
||||||
uint8_t bSeq;
|
|
||||||
uint8_t bBWI;
|
|
||||||
uint16_t wLevelParameter;
|
|
||||||
} __packed;
|
|
||||||
|
|
||||||
struct PC_to_RDR_IccPowerOff {
|
|
||||||
uint8_t bMessageType;
|
|
||||||
uint32_t dwLength;
|
|
||||||
uint8_t bSlot;
|
|
||||||
uint8_t bSeq;
|
|
||||||
uint8_t abRFU1;
|
|
||||||
uint16_t abRFU2;
|
|
||||||
} __packed;
|
|
||||||
|
|
||||||
struct PC_to_RDR_GetSlotStatus {
|
|
||||||
uint8_t bMessageType;
|
|
||||||
uint32_t dwLength;
|
|
||||||
uint8_t bSlot;
|
|
||||||
uint8_t bSeq;
|
|
||||||
uint8_t abRFU1;
|
|
||||||
uint16_t abRFU2;
|
|
||||||
} __packed;
|
|
||||||
|
|
||||||
struct PC_to_RDR_GetParameters {
|
|
||||||
uint8_t bMessageType;
|
|
||||||
uint32_t dwLength;
|
|
||||||
uint8_t bSlot;
|
|
||||||
uint8_t bSeq;
|
|
||||||
uint8_t abRFU1;
|
|
||||||
uint16_t abRFU2;
|
|
||||||
} __packed;
|
|
||||||
|
|
||||||
struct PC_to_RDR_ResetParameters {
|
|
||||||
uint8_t bMessageType;
|
|
||||||
uint32_t dwLength;
|
|
||||||
uint8_t bSlot;
|
|
||||||
uint8_t bSeq;
|
|
||||||
uint8_t abRFU1;
|
|
||||||
uint16_t abRFU2;
|
|
||||||
} __packed;
|
|
||||||
|
|
||||||
struct PC_to_RDR_SetParameters {
|
|
||||||
uint8_t bMessageType;
|
|
||||||
uint32_t dwLength;
|
|
||||||
uint8_t bSlot;
|
|
||||||
uint8_t bSeq;
|
|
||||||
uint8_t bProtocolNum;
|
|
||||||
uint16_t abRFU;
|
|
||||||
} __packed;
|
|
||||||
|
|
||||||
struct PC_to_RDR_Secure {
|
|
||||||
uint8_t bMessageType;
|
|
||||||
uint32_t dwLength;
|
|
||||||
uint8_t bSlot;
|
|
||||||
uint8_t bSeq;
|
|
||||||
uint8_t bBWI;
|
|
||||||
uint16_t wLevelParameter;
|
|
||||||
} __packed;
|
|
||||||
|
|
||||||
struct PC_to_RDR_IccPowerOn {
|
|
||||||
uint8_t bMessageType;
|
|
||||||
uint32_t dwLength;
|
|
||||||
uint8_t bSlot;
|
|
||||||
uint8_t bSeq;
|
|
||||||
uint8_t bPowerSelect;
|
|
||||||
uint16_t abRFU;
|
|
||||||
} __packed;
|
|
||||||
|
|
||||||
struct RDR_to_PC_SlotStatus {
|
|
||||||
uint8_t bMessageType;
|
|
||||||
uint32_t dwLength;
|
|
||||||
uint8_t bSlot;
|
|
||||||
uint8_t bSeq;
|
|
||||||
uint8_t bStatus;
|
|
||||||
uint8_t bError;
|
|
||||||
uint8_t bClockStatus;
|
|
||||||
} __packed;
|
|
||||||
|
|
||||||
struct RDR_to_PC_DataBlock {
|
|
||||||
uint8_t bMessageType;
|
|
||||||
uint32_t dwLength;
|
|
||||||
uint8_t bSlot;
|
|
||||||
uint8_t bSeq;
|
|
||||||
uint8_t bStatus;
|
|
||||||
uint8_t bError;
|
|
||||||
uint8_t bChainParameter;
|
|
||||||
} __packed;
|
|
||||||
|
|
||||||
struct RDR_to_PC_Parameters {
|
|
||||||
uint8_t bMessageType;
|
|
||||||
uint32_t dwLength;
|
|
||||||
uint8_t bSlot;
|
|
||||||
uint8_t bSeq;
|
|
||||||
uint8_t bStatus;
|
|
||||||
uint8_t bError;
|
|
||||||
uint8_t bProtocolNum;
|
|
||||||
} __packed;
|
|
||||||
|
|
||||||
struct RDR_to_PC_NotifySlotChange {
|
|
||||||
uint8_t bMessageType;
|
|
||||||
uint8_t bmSlotICCState; /* we support 1 slots, so we need 2*1 bits = 1 byte */
|
|
||||||
} __packed;
|
|
||||||
|
|
||||||
#endif
|
|
||||||
54
ccid.h
54
ccid.h
@@ -1,54 +0,0 @@
|
|||||||
#ifndef _CCID_H_
|
|
||||||
#define _CCID_H_
|
|
||||||
|
|
||||||
#include "ccid-types.h"
|
|
||||||
|
|
||||||
static const class_desc_ccid_t desc_ccid = {
|
|
||||||
.bLength = sizeof (class_desc_ccid_t),
|
|
||||||
.bDescriptorType = 0x21,
|
|
||||||
.bcdCCID = (0x0110),
|
|
||||||
.bMaxSlotIndex = 0,
|
|
||||||
.bVoltageSupport = 0x01, // 5.0V
|
|
||||||
.dwProtocols = (
|
|
||||||
0x01| // T=0
|
|
||||||
0x02), // T=1
|
|
||||||
.dwDefaultClock = (0xDFC),
|
|
||||||
.dwMaximumClock = (0xDFC),
|
|
||||||
.bNumClockSupport = 1,
|
|
||||||
.dwDataRate = (0x2580),
|
|
||||||
.dwMaxDataRate = (0x2580),
|
|
||||||
.bNumDataRatesSupported = 1,
|
|
||||||
.dwMaxIFSD = (0xFF), // IFSD is handled by the real reader driver
|
|
||||||
.dwSynchProtocols = (0),
|
|
||||||
.dwMechanical = (0),
|
|
||||||
.dwFeatures = (
|
|
||||||
0x00000002| // Automatic parameter configuration based on ATR data
|
|
||||||
0x00000004| // Automatic activation of ICC on inserting
|
|
||||||
0x00000008| // Automatic ICC voltage selection
|
|
||||||
0x00000010| // Automatic ICC clock frequency change
|
|
||||||
0x00000020| // Automatic baud rate change
|
|
||||||
0x00000040| // Automatic parameters negotiation
|
|
||||||
0x00000080| // Automatic PPS
|
|
||||||
0x00000400| // Automatic IFSD exchange as first exchange
|
|
||||||
0x00040000| // Short and Extended APDU level exchange with CCID
|
|
||||||
0x00100000), // USB Wake up signaling supported
|
|
||||||
.dwMaxCCIDMessageLength = (CCID_EXT_APDU_MAX),
|
|
||||||
.bClassGetResponse = 0xFF,
|
|
||||||
.bclassEnvelope = 0xFF,
|
|
||||||
.wLcdLayout = 0x0,
|
|
||||||
/*
|
|
||||||
(
|
|
||||||
0xFF00| // Number of lines for the LCD display
|
|
||||||
0x00FF), // Number of characters per line
|
|
||||||
*/
|
|
||||||
.bPINSupport = 0x0,
|
|
||||||
/*
|
|
||||||
0x1| // PIN Verification supported
|
|
||||||
0x2| // PIN Modification supported
|
|
||||||
0x10| // PIN PACE Capabilities supported
|
|
||||||
0x20, // PIN PACE Verification supported
|
|
||||||
*/
|
|
||||||
.bMaxCCIDBusySlots = 0x01,
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
401
common.h
401
common.h
@@ -1,401 +0,0 @@
|
|||||||
/**
|
|
||||||
* \file common.h
|
|
||||||
*
|
|
||||||
* \brief Utility macros for internal use in the library
|
|
||||||
*/
|
|
||||||
/*
|
|
||||||
* Copyright The Mbed TLS Contributors
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
||||||
* not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef MBEDTLS_LIBRARY_COMMON_H
|
|
||||||
#define MBEDTLS_LIBRARY_COMMON_H
|
|
||||||
|
|
||||||
#include "mbedtls/build_info.h"
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
/** Helper to define a function as static except when building invasive tests.
|
|
||||||
*
|
|
||||||
* If a function is only used inside its own source file and should be
|
|
||||||
* declared `static` to allow the compiler to optimize for code size,
|
|
||||||
* but that function has unit tests, define it with
|
|
||||||
* ```
|
|
||||||
* MBEDTLS_STATIC_TESTABLE int mbedtls_foo(...) { ... }
|
|
||||||
* ```
|
|
||||||
* and declare it in a header in the `library/` directory with
|
|
||||||
* ```
|
|
||||||
* #if defined(MBEDTLS_TEST_HOOKS)
|
|
||||||
* int mbedtls_foo(...);
|
|
||||||
* #endif
|
|
||||||
* ```
|
|
||||||
*/
|
|
||||||
#if defined(MBEDTLS_TEST_HOOKS)
|
|
||||||
#define MBEDTLS_STATIC_TESTABLE
|
|
||||||
#else
|
|
||||||
#define MBEDTLS_STATIC_TESTABLE static
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(MBEDTLS_TEST_HOOKS)
|
|
||||||
extern void (*mbedtls_test_hook_test_fail)( const char * test, int line, const char * file );
|
|
||||||
#define MBEDTLS_TEST_HOOK_TEST_ASSERT( TEST ) \
|
|
||||||
do { \
|
|
||||||
if( ( ! ( TEST ) ) && ( ( *mbedtls_test_hook_test_fail ) != NULL ) ) \
|
|
||||||
{ \
|
|
||||||
( *mbedtls_test_hook_test_fail )( #TEST, __LINE__, __FILE__ ); \
|
|
||||||
} \
|
|
||||||
} while( 0 )
|
|
||||||
#else
|
|
||||||
#define MBEDTLS_TEST_HOOK_TEST_ASSERT( TEST )
|
|
||||||
#endif /* defined(MBEDTLS_TEST_HOOKS) */
|
|
||||||
|
|
||||||
/** Allow library to access its structs' private members.
|
|
||||||
*
|
|
||||||
* Although structs defined in header files are publicly available,
|
|
||||||
* their members are private and should not be accessed by the user.
|
|
||||||
*/
|
|
||||||
#define MBEDTLS_ALLOW_PRIVATE_ACCESS
|
|
||||||
|
|
||||||
/** Byte Reading Macros
|
|
||||||
*
|
|
||||||
* Given a multi-byte integer \p x, MBEDTLS_BYTE_n retrieves the n-th
|
|
||||||
* byte from x, where byte 0 is the least significant byte.
|
|
||||||
*/
|
|
||||||
#define MBEDTLS_BYTE_0( x ) ( (uint8_t) ( ( x ) & 0xff ) )
|
|
||||||
#define MBEDTLS_BYTE_1( x ) ( (uint8_t) ( ( ( x ) >> 8 ) & 0xff ) )
|
|
||||||
#define MBEDTLS_BYTE_2( x ) ( (uint8_t) ( ( ( x ) >> 16 ) & 0xff ) )
|
|
||||||
#define MBEDTLS_BYTE_3( x ) ( (uint8_t) ( ( ( x ) >> 24 ) & 0xff ) )
|
|
||||||
#define MBEDTLS_BYTE_4( x ) ( (uint8_t) ( ( ( x ) >> 32 ) & 0xff ) )
|
|
||||||
#define MBEDTLS_BYTE_5( x ) ( (uint8_t) ( ( ( x ) >> 40 ) & 0xff ) )
|
|
||||||
#define MBEDTLS_BYTE_6( x ) ( (uint8_t) ( ( ( x ) >> 48 ) & 0xff ) )
|
|
||||||
#define MBEDTLS_BYTE_7( x ) ( (uint8_t) ( ( ( x ) >> 56 ) & 0xff ) )
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the unsigned 32 bits integer corresponding to four bytes in
|
|
||||||
* big-endian order (MSB first).
|
|
||||||
*
|
|
||||||
* \param data Base address of the memory to get the four bytes from.
|
|
||||||
* \param offset Offset from \p data of the first and most significant
|
|
||||||
* byte of the four bytes to build the 32 bits unsigned
|
|
||||||
* integer from.
|
|
||||||
*/
|
|
||||||
#ifndef MBEDTLS_GET_UINT32_BE
|
|
||||||
#define MBEDTLS_GET_UINT32_BE( data , offset ) \
|
|
||||||
( \
|
|
||||||
( (uint32_t) ( data )[( offset ) ] << 24 ) \
|
|
||||||
| ( (uint32_t) ( data )[( offset ) + 1] << 16 ) \
|
|
||||||
| ( (uint32_t) ( data )[( offset ) + 2] << 8 ) \
|
|
||||||
| ( (uint32_t) ( data )[( offset ) + 3] ) \
|
|
||||||
)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Put in memory a 32 bits unsigned integer in big-endian order.
|
|
||||||
*
|
|
||||||
* \param n 32 bits unsigned integer to put in memory.
|
|
||||||
* \param data Base address of the memory where to put the 32
|
|
||||||
* bits unsigned integer in.
|
|
||||||
* \param offset Offset from \p data where to put the most significant
|
|
||||||
* byte of the 32 bits unsigned integer \p n.
|
|
||||||
*/
|
|
||||||
#ifndef MBEDTLS_PUT_UINT32_BE
|
|
||||||
#define MBEDTLS_PUT_UINT32_BE( n, data, offset ) \
|
|
||||||
{ \
|
|
||||||
( data )[( offset ) ] = MBEDTLS_BYTE_3( n ); \
|
|
||||||
( data )[( offset ) + 1] = MBEDTLS_BYTE_2( n ); \
|
|
||||||
( data )[( offset ) + 2] = MBEDTLS_BYTE_1( n ); \
|
|
||||||
( data )[( offset ) + 3] = MBEDTLS_BYTE_0( n ); \
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the unsigned 32 bits integer corresponding to four bytes in
|
|
||||||
* little-endian order (LSB first).
|
|
||||||
*
|
|
||||||
* \param data Base address of the memory to get the four bytes from.
|
|
||||||
* \param offset Offset from \p data of the first and least significant
|
|
||||||
* byte of the four bytes to build the 32 bits unsigned
|
|
||||||
* integer from.
|
|
||||||
*/
|
|
||||||
#ifndef MBEDTLS_GET_UINT32_LE
|
|
||||||
#define MBEDTLS_GET_UINT32_LE( data, offset ) \
|
|
||||||
( \
|
|
||||||
( (uint32_t) ( data )[( offset ) ] ) \
|
|
||||||
| ( (uint32_t) ( data )[( offset ) + 1] << 8 ) \
|
|
||||||
| ( (uint32_t) ( data )[( offset ) + 2] << 16 ) \
|
|
||||||
| ( (uint32_t) ( data )[( offset ) + 3] << 24 ) \
|
|
||||||
)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Put in memory a 32 bits unsigned integer in little-endian order.
|
|
||||||
*
|
|
||||||
* \param n 32 bits unsigned integer to put in memory.
|
|
||||||
* \param data Base address of the memory where to put the 32
|
|
||||||
* bits unsigned integer in.
|
|
||||||
* \param offset Offset from \p data where to put the least significant
|
|
||||||
* byte of the 32 bits unsigned integer \p n.
|
|
||||||
*/
|
|
||||||
#ifndef MBEDTLS_PUT_UINT32_LE
|
|
||||||
#define MBEDTLS_PUT_UINT32_LE( n, data, offset ) \
|
|
||||||
{ \
|
|
||||||
( data )[( offset ) ] = MBEDTLS_BYTE_0( n ); \
|
|
||||||
( data )[( offset ) + 1] = MBEDTLS_BYTE_1( n ); \
|
|
||||||
( data )[( offset ) + 2] = MBEDTLS_BYTE_2( n ); \
|
|
||||||
( data )[( offset ) + 3] = MBEDTLS_BYTE_3( n ); \
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the unsigned 16 bits integer corresponding to two bytes in
|
|
||||||
* little-endian order (LSB first).
|
|
||||||
*
|
|
||||||
* \param data Base address of the memory to get the two bytes from.
|
|
||||||
* \param offset Offset from \p data of the first and least significant
|
|
||||||
* byte of the two bytes to build the 16 bits unsigned
|
|
||||||
* integer from.
|
|
||||||
*/
|
|
||||||
#ifndef MBEDTLS_GET_UINT16_LE
|
|
||||||
#define MBEDTLS_GET_UINT16_LE( data, offset ) \
|
|
||||||
( \
|
|
||||||
( (uint16_t) ( data )[( offset ) ] ) \
|
|
||||||
| ( (uint16_t) ( data )[( offset ) + 1] << 8 ) \
|
|
||||||
)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Put in memory a 16 bits unsigned integer in little-endian order.
|
|
||||||
*
|
|
||||||
* \param n 16 bits unsigned integer to put in memory.
|
|
||||||
* \param data Base address of the memory where to put the 16
|
|
||||||
* bits unsigned integer in.
|
|
||||||
* \param offset Offset from \p data where to put the least significant
|
|
||||||
* byte of the 16 bits unsigned integer \p n.
|
|
||||||
*/
|
|
||||||
#ifndef MBEDTLS_PUT_UINT16_LE
|
|
||||||
#define MBEDTLS_PUT_UINT16_LE( n, data, offset ) \
|
|
||||||
{ \
|
|
||||||
( data )[( offset ) ] = MBEDTLS_BYTE_0( n ); \
|
|
||||||
( data )[( offset ) + 1] = MBEDTLS_BYTE_1( n ); \
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the unsigned 16 bits integer corresponding to two bytes in
|
|
||||||
* big-endian order (MSB first).
|
|
||||||
*
|
|
||||||
* \param data Base address of the memory to get the two bytes from.
|
|
||||||
* \param offset Offset from \p data of the first and most significant
|
|
||||||
* byte of the two bytes to build the 16 bits unsigned
|
|
||||||
* integer from.
|
|
||||||
*/
|
|
||||||
#ifndef MBEDTLS_GET_UINT16_BE
|
|
||||||
#define MBEDTLS_GET_UINT16_BE( data, offset ) \
|
|
||||||
( \
|
|
||||||
( (uint16_t) ( data )[( offset ) ] << 8 ) \
|
|
||||||
| ( (uint16_t) ( data )[( offset ) + 1] ) \
|
|
||||||
)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Put in memory a 16 bits unsigned integer in big-endian order.
|
|
||||||
*
|
|
||||||
* \param n 16 bits unsigned integer to put in memory.
|
|
||||||
* \param data Base address of the memory where to put the 16
|
|
||||||
* bits unsigned integer in.
|
|
||||||
* \param offset Offset from \p data where to put the most significant
|
|
||||||
* byte of the 16 bits unsigned integer \p n.
|
|
||||||
*/
|
|
||||||
#ifndef MBEDTLS_PUT_UINT16_BE
|
|
||||||
#define MBEDTLS_PUT_UINT16_BE( n, data, offset ) \
|
|
||||||
{ \
|
|
||||||
( data )[( offset ) ] = MBEDTLS_BYTE_1( n ); \
|
|
||||||
( data )[( offset ) + 1] = MBEDTLS_BYTE_0( n ); \
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the unsigned 24 bits integer corresponding to three bytes in
|
|
||||||
* big-endian order (MSB first).
|
|
||||||
*
|
|
||||||
* \param data Base address of the memory to get the three bytes from.
|
|
||||||
* \param offset Offset from \p data of the first and most significant
|
|
||||||
* byte of the three bytes to build the 24 bits unsigned
|
|
||||||
* integer from.
|
|
||||||
*/
|
|
||||||
#ifndef MBEDTLS_GET_UINT24_BE
|
|
||||||
#define MBEDTLS_GET_UINT24_BE( data , offset ) \
|
|
||||||
( \
|
|
||||||
( (uint32_t) ( data )[( offset ) ] << 16 ) \
|
|
||||||
| ( (uint32_t) ( data )[( offset ) + 1] << 8 ) \
|
|
||||||
| ( (uint32_t) ( data )[( offset ) + 2] ) \
|
|
||||||
)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Put in memory a 24 bits unsigned integer in big-endian order.
|
|
||||||
*
|
|
||||||
* \param n 24 bits unsigned integer to put in memory.
|
|
||||||
* \param data Base address of the memory where to put the 24
|
|
||||||
* bits unsigned integer in.
|
|
||||||
* \param offset Offset from \p data where to put the most significant
|
|
||||||
* byte of the 24 bits unsigned integer \p n.
|
|
||||||
*/
|
|
||||||
#ifndef MBEDTLS_PUT_UINT24_BE
|
|
||||||
#define MBEDTLS_PUT_UINT24_BE( n, data, offset ) \
|
|
||||||
{ \
|
|
||||||
( data )[( offset ) ] = MBEDTLS_BYTE_2( n ); \
|
|
||||||
( data )[( offset ) + 1] = MBEDTLS_BYTE_1( n ); \
|
|
||||||
( data )[( offset ) + 2] = MBEDTLS_BYTE_0( n ); \
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the unsigned 24 bits integer corresponding to three bytes in
|
|
||||||
* little-endian order (LSB first).
|
|
||||||
*
|
|
||||||
* \param data Base address of the memory to get the three bytes from.
|
|
||||||
* \param offset Offset from \p data of the first and least significant
|
|
||||||
* byte of the three bytes to build the 24 bits unsigned
|
|
||||||
* integer from.
|
|
||||||
*/
|
|
||||||
#ifndef MBEDTLS_GET_UINT24_LE
|
|
||||||
#define MBEDTLS_GET_UINT24_LE( data, offset ) \
|
|
||||||
( \
|
|
||||||
( (uint32_t) ( data )[( offset ) ] ) \
|
|
||||||
| ( (uint32_t) ( data )[( offset ) + 1] << 8 ) \
|
|
||||||
| ( (uint32_t) ( data )[( offset ) + 2] << 16 ) \
|
|
||||||
)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Put in memory a 24 bits unsigned integer in little-endian order.
|
|
||||||
*
|
|
||||||
* \param n 24 bits unsigned integer to put in memory.
|
|
||||||
* \param data Base address of the memory where to put the 24
|
|
||||||
* bits unsigned integer in.
|
|
||||||
* \param offset Offset from \p data where to put the least significant
|
|
||||||
* byte of the 24 bits unsigned integer \p n.
|
|
||||||
*/
|
|
||||||
#ifndef MBEDTLS_PUT_UINT24_LE
|
|
||||||
#define MBEDTLS_PUT_UINT24_LE( n, data, offset ) \
|
|
||||||
{ \
|
|
||||||
( data )[( offset ) ] = MBEDTLS_BYTE_0( n ); \
|
|
||||||
( data )[( offset ) + 1] = MBEDTLS_BYTE_1( n ); \
|
|
||||||
( data )[( offset ) + 2] = MBEDTLS_BYTE_2( n ); \
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the unsigned 64 bits integer corresponding to eight bytes in
|
|
||||||
* big-endian order (MSB first).
|
|
||||||
*
|
|
||||||
* \param data Base address of the memory to get the eight bytes from.
|
|
||||||
* \param offset Offset from \p data of the first and most significant
|
|
||||||
* byte of the eight bytes to build the 64 bits unsigned
|
|
||||||
* integer from.
|
|
||||||
*/
|
|
||||||
#ifndef MBEDTLS_GET_UINT64_BE
|
|
||||||
#define MBEDTLS_GET_UINT64_BE( data, offset ) \
|
|
||||||
( \
|
|
||||||
( (uint64_t) ( data )[( offset ) ] << 56 ) \
|
|
||||||
| ( (uint64_t) ( data )[( offset ) + 1] << 48 ) \
|
|
||||||
| ( (uint64_t) ( data )[( offset ) + 2] << 40 ) \
|
|
||||||
| ( (uint64_t) ( data )[( offset ) + 3] << 32 ) \
|
|
||||||
| ( (uint64_t) ( data )[( offset ) + 4] << 24 ) \
|
|
||||||
| ( (uint64_t) ( data )[( offset ) + 5] << 16 ) \
|
|
||||||
| ( (uint64_t) ( data )[( offset ) + 6] << 8 ) \
|
|
||||||
| ( (uint64_t) ( data )[( offset ) + 7] ) \
|
|
||||||
)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Put in memory a 64 bits unsigned integer in big-endian order.
|
|
||||||
*
|
|
||||||
* \param n 64 bits unsigned integer to put in memory.
|
|
||||||
* \param data Base address of the memory where to put the 64
|
|
||||||
* bits unsigned integer in.
|
|
||||||
* \param offset Offset from \p data where to put the most significant
|
|
||||||
* byte of the 64 bits unsigned integer \p n.
|
|
||||||
*/
|
|
||||||
#ifndef MBEDTLS_PUT_UINT64_BE
|
|
||||||
#define MBEDTLS_PUT_UINT64_BE( n, data, offset ) \
|
|
||||||
{ \
|
|
||||||
( data )[( offset ) ] = MBEDTLS_BYTE_7( n ); \
|
|
||||||
( data )[( offset ) + 1] = MBEDTLS_BYTE_6( n ); \
|
|
||||||
( data )[( offset ) + 2] = MBEDTLS_BYTE_5( n ); \
|
|
||||||
( data )[( offset ) + 3] = MBEDTLS_BYTE_4( n ); \
|
|
||||||
( data )[( offset ) + 4] = MBEDTLS_BYTE_3( n ); \
|
|
||||||
( data )[( offset ) + 5] = MBEDTLS_BYTE_2( n ); \
|
|
||||||
( data )[( offset ) + 6] = MBEDTLS_BYTE_1( n ); \
|
|
||||||
( data )[( offset ) + 7] = MBEDTLS_BYTE_0( n ); \
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the unsigned 64 bits integer corresponding to eight bytes in
|
|
||||||
* little-endian order (LSB first).
|
|
||||||
*
|
|
||||||
* \param data Base address of the memory to get the eight bytes from.
|
|
||||||
* \param offset Offset from \p data of the first and least significant
|
|
||||||
* byte of the eight bytes to build the 64 bits unsigned
|
|
||||||
* integer from.
|
|
||||||
*/
|
|
||||||
#ifndef MBEDTLS_GET_UINT64_LE
|
|
||||||
#define MBEDTLS_GET_UINT64_LE( data, offset ) \
|
|
||||||
( \
|
|
||||||
( (uint64_t) ( data )[( offset ) + 7] << 56 ) \
|
|
||||||
| ( (uint64_t) ( data )[( offset ) + 6] << 48 ) \
|
|
||||||
| ( (uint64_t) ( data )[( offset ) + 5] << 40 ) \
|
|
||||||
| ( (uint64_t) ( data )[( offset ) + 4] << 32 ) \
|
|
||||||
| ( (uint64_t) ( data )[( offset ) + 3] << 24 ) \
|
|
||||||
| ( (uint64_t) ( data )[( offset ) + 2] << 16 ) \
|
|
||||||
| ( (uint64_t) ( data )[( offset ) + 1] << 8 ) \
|
|
||||||
| ( (uint64_t) ( data )[( offset ) ] ) \
|
|
||||||
)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Put in memory a 64 bits unsigned integer in little-endian order.
|
|
||||||
*
|
|
||||||
* \param n 64 bits unsigned integer to put in memory.
|
|
||||||
* \param data Base address of the memory where to put the 64
|
|
||||||
* bits unsigned integer in.
|
|
||||||
* \param offset Offset from \p data where to put the least significant
|
|
||||||
* byte of the 64 bits unsigned integer \p n.
|
|
||||||
*/
|
|
||||||
#ifndef MBEDTLS_PUT_UINT64_LE
|
|
||||||
#define MBEDTLS_PUT_UINT64_LE( n, data, offset ) \
|
|
||||||
{ \
|
|
||||||
( data )[( offset ) ] = MBEDTLS_BYTE_0( n ); \
|
|
||||||
( data )[( offset ) + 1] = MBEDTLS_BYTE_1( n ); \
|
|
||||||
( data )[( offset ) + 2] = MBEDTLS_BYTE_2( n ); \
|
|
||||||
( data )[( offset ) + 3] = MBEDTLS_BYTE_3( n ); \
|
|
||||||
( data )[( offset ) + 4] = MBEDTLS_BYTE_4( n ); \
|
|
||||||
( data )[( offset ) + 5] = MBEDTLS_BYTE_5( n ); \
|
|
||||||
( data )[( offset ) + 6] = MBEDTLS_BYTE_6( n ); \
|
|
||||||
( data )[( offset ) + 7] = MBEDTLS_BYTE_7( n ); \
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Fix MSVC C99 compatible issue
|
|
||||||
* MSVC support __func__ from visual studio 2015( 1900 )
|
|
||||||
* Use MSVC predefine macro to avoid name check fail.
|
|
||||||
*/
|
|
||||||
#if (defined(_MSC_VER) && ( _MSC_VER <= 1900 ))
|
|
||||||
#define /*no-check-names*/ __func__ __FUNCTION__
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* MBEDTLS_LIBRARY_COMMON_H */
|
|
||||||
58
doc/aes.md
Normal file
58
doc/aes.md
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
# AES
|
||||||
|
The Pico HSM supports AES secret key generation and CBC encryption/decryption. However, OpenSC does not provide AES support for sc-hsm driver. Instead, the `sc-hsm-embedded` module is used.
|
||||||
|
|
||||||
|
First, we setup the tool:
|
||||||
|
|
||||||
|
```
|
||||||
|
alias sc-tool=pkcs11-tool --module /path/to/libsc-hsm-pkcs11.so
|
||||||
|
```
|
||||||
|
|
||||||
|
## Secret key generation
|
||||||
|
Pico HSM supports AES keys with 128, 192 and 256 bits. To generate a secret 256 bits AES key:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ sc-tool -l --pin 648219 --keygen --key-type AES:32 --id 12 --label "AES32"
|
||||||
|
Using slot 0 with a present token (0x1)
|
||||||
|
Key generated:
|
||||||
|
Secret Key Object; AES length 32
|
||||||
|
label: AES32
|
||||||
|
ID: 12
|
||||||
|
Usage: encrypt, decrypt
|
||||||
|
Access: sensitive, always sensitive, never extractable, local
|
||||||
|
```
|
||||||
|
|
||||||
|
For 128 bits, use the `--key-type aes:16`, for 192 bits, `aes:24`, and for 256 bits, `aes:32`.
|
||||||
|
|
||||||
|
For lack of AES support in AES, `pkcs15-tool -D` does not list AES keys. Instead, they can be listed with:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ sc-tool -l --pin 648219 --list-object --type secrkey
|
||||||
|
Using slot 0 with a present token (0x1)
|
||||||
|
Secret Key Object; AES length 32
|
||||||
|
label: AES32
|
||||||
|
ID: 12
|
||||||
|
Usage: encrypt, decrypt
|
||||||
|
Access: sensitive, always sensitive, never extractable, local
|
||||||
|
```
|
||||||
|
|
||||||
|
## Encryption and decryption
|
||||||
|
Once a secret AES key is generated, a content can be encrypted and decrypted symmetrically:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ echo "This is a text." | sc-tool -l --pin 648219 --encrypt --id 12 --mechanism aes-cbc > crypted.aes
|
||||||
|
````
|
||||||
|
|
||||||
|
The file `crypted.aes` contains the ciphered string with the AES key generated previously.
|
||||||
|
|
||||||
|
To decrypt the message, the inverse operation:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ cat crypted.aes | sc-tool -l --pin 648219 --decrypt --id 12 --mechanism aes-cbc
|
||||||
|
Using slot 0 with a present token (0x1)
|
||||||
|
Using decrypt algorithm AES-CBC
|
||||||
|
|
||||||
|
This is a text.
|
||||||
|
```
|
||||||
|
|
||||||
|
AES-CBC it is a block operation and it requires an input size multiple of 16 bytes. Thus, for a trivial data, a padding operation has to be performed beforehand.
|
||||||
|
|
||||||
111
doc/asymmetric-ciphering.md
Normal file
111
doc/asymmetric-ciphering.md
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
# Asymmetric encryption and decryption
|
||||||
|
|
||||||
|
Pico HSM supports in place decryption with the following algorithms:
|
||||||
|
* RSA-PKCS
|
||||||
|
* RSA-X-509
|
||||||
|
* RSA-PKCS-OAEP
|
||||||
|
* ECDH-DERIVE
|
||||||
|
|
||||||
|
First, we generate the data:
|
||||||
|
```
|
||||||
|
$ echo "This is a test string. Be safe, be secure." > data
|
||||||
|
```
|
||||||
|
|
||||||
|
Obtain the public key and convert it to PEM format:
|
||||||
|
```
|
||||||
|
$ pkcs11-tool --read-object --pin 648219 --id 1 --type pubkey > 1.der
|
||||||
|
$ openssl rsa -inform DER -outform PEM -in 1.der -pubin > 1.pub
|
||||||
|
```
|
||||||
|
|
||||||
|
At this moment, you are able to verify with the public key in `1.pub`. The signature is computed inside the Pico HSM with the private key. It never leaves the device.
|
||||||
|
|
||||||
|
## RSA-PKCS
|
||||||
|
This algorithm uses the PKCSv1.5 padding. It is considered deprecated and insecure.
|
||||||
|
First, we encrypt the data with the public key:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ openssl rsautl -encrypt -inkey 1.pub -in data -pubin -out data.crypt
|
||||||
|
```
|
||||||
|
|
||||||
|
Then, we decrypt with the private key inside the Pico HSM:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ pkcs11-tool --id 1 --pin 648219 --decrypt --mechanism RSA-PKCS -i data.crypt
|
||||||
|
Using slot 0 with a present token (0x0)
|
||||||
|
Using decrypt algorithm RSA-PKCS
|
||||||
|
This is a test string. Be safe, be secure.
|
||||||
|
```
|
||||||
|
|
||||||
|
## RSA-X-509
|
||||||
|
In this algorithm, the data must be padded with a length equal to the size of private key (128, 256, 512 bytes for RSA-1024, RSA-2048 and RSA-4096, respectively).
|
||||||
|
|
||||||
|
First, we pad the data. The original data file occupies 29 bytes. Thus, for a 2048 bits key, a padding of 227 bytes is needed:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ cp data data_pad
|
||||||
|
$ dd if=/dev/zero bs=1 count=227 >> data_pad
|
||||||
|
```
|
||||||
|
|
||||||
|
we encrypt the data with the public key:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ openssl rsautl -encrypt -inkey 1.pub -in data_pad -pubin -out data.crypt -raw
|
||||||
|
```
|
||||||
|
|
||||||
|
Then, we decrypt with the private key inside the Pico HSM:
|
||||||
|
```
|
||||||
|
$ cat data.crypt|pkcs11-tool --id 4 --pin 648219 --decrypt --mechanism RSA-X-509
|
||||||
|
Using slot 0 with a present token (0x0)
|
||||||
|
Using decrypt algorithm RSA-X-509
|
||||||
|
This is a test string. Be safe, be secure.
|
||||||
|
```
|
||||||
|
|
||||||
|
## RSA-PKCS-OAEP
|
||||||
|
This algorithm is defined as PKCSv2.1 and it includes a padding mechanism to avoid garbage. Currently it only supports SHA256.
|
||||||
|
|
||||||
|
To encrypt the data:
|
||||||
|
```
|
||||||
|
$ openssl pkeyutl -encrypt -inkey 1.pub -pubin -pkeyopt rsa_padding_mode:oaep -pkeyopt rsa_oaep_md:sha256 -pkeyopt rsa_mgf1_md:sha256 -in data -out data.crypt
|
||||||
|
```
|
||||||
|
|
||||||
|
To decrypt with the private key inside the Pico HSM:
|
||||||
|
```
|
||||||
|
$ pkcs11-tool --id 1 --pin 648219 --decrypt --mechanism RSA-PKCS-OAEP -i data.crypt
|
||||||
|
Using slot 0 with a present token (0x0)
|
||||||
|
Using decrypt algorithm RSA-PKCS-OAEP
|
||||||
|
OAEP parameters: hashAlg=SHA256, mgf=MGF1-SHA256, source_type=0, source_ptr=0x0, source_len=0
|
||||||
|
This is a test string. Be safe, be secure.
|
||||||
|
```
|
||||||
|
|
||||||
|
## ECDH-DERIVE
|
||||||
|
ECC keys do not allow ciphering operations. Instead, the ECDH scheme provides a mechanism to exchange a shared symmetric key without transmitting it to the remote part. The shared key is composed by multiplying the local private key and the remote public key.
|
||||||
|
|
||||||
|
First, we create the remote part, Bob, by generating an ECC keypair and getting the public key:
|
||||||
|
```
|
||||||
|
$ openssl ecparam -genkey -name prime192v1 > bob.pem
|
||||||
|
$ openssl ec -in bob.pem -pubout -outform DER > bob.der
|
||||||
|
```
|
||||||
|
|
||||||
|
We derive the shared key by giving the Bob's public key to the Pico HSM:
|
||||||
|
```
|
||||||
|
$ pkcs11-tool --pin 648219 --id 11 --derive -i bob.der -o mine-bob.der
|
||||||
|
```
|
||||||
|
|
||||||
|
We compute the other shared key, with Bob's private key and our public key:
|
||||||
|
```
|
||||||
|
$ openssl pkeyutl -derive -out bob-mine.der -inkey bob.pem -peerkey 11.pub
|
||||||
|
```
|
||||||
|
|
||||||
|
Finally, we compare both shared keys:
|
||||||
|
```
|
||||||
|
$ cmp bob-mine.der mine-bob.der
|
||||||
|
```
|
||||||
|
No output is displayed if both are equal.
|
||||||
|
|
||||||
|
You can also view the contents of both keys:
|
||||||
|
```
|
||||||
|
$ xxd -p bob-mine.der
|
||||||
|
9874558aefa9d92cc051e5da6d1753987e5314925d6d78bf
|
||||||
|
$ xxd -p mine-bob.der
|
||||||
|
9874558aefa9d92cc051e5da6d1753987e5314925d6d78bf
|
||||||
|
```
|
||||||
218
doc/backup-and-restore.md
Normal file
218
doc/backup-and-restore.md
Normal file
@@ -0,0 +1,218 @@
|
|||||||
|
# Backup and restore
|
||||||
|
Pico HSM supports secure backup and restore. This mechanism is used to export a private key securely and restore it into another Pico HSM or the same device. The exported key is encrypted with the Device Key Encryption Key (DKEK), an AES 256 bits key that is stored safely during the initialization.
|
||||||
|
|
||||||
|
## Initialization
|
||||||
|
|
||||||
|
It is highly recommended to initialize the Pico HSM with a known DKEK. You have multiple options:
|
||||||
|
* No DKEK (be careful!)
|
||||||
|
* Single DKEK share: the DKEK is stored safely with a passphrase outside the device and kept by one custodian. If the custodian looses the DKEK share or an attacker gets the share and the passphrase, the Pico HSM and all its contents will be compromised.
|
||||||
|
* Multiple DKEK shares: the DKEK is created from multiple portions of the original DKEK, kept by multiple custodians. For instance, a DKEK with 3 shares implies that the device cannot be fully initialized until all 3 custodians load their portion into the device. The order is irrelevant.
|
||||||
|
* DKEK n-of-m threshold scheme: the DKEK is created with at minimum of n of m portions. It adds more flexibility, as it does not require the availability of all custodians. For instance, an scheme of 3-of-5 implies that the DKEK can be created with the portions of 3 custodians of 5 in total. The order is irrelevant.
|
||||||
|
|
||||||
|
### No DKEK
|
||||||
|
If no DKEK is provided during the initialization, the Pico HSM will generate one randomly. Note that in this case, despite you still can export a private key but **you cannot import it into another Pico HSM**, since you do not know the DKEK. Furthermore, if you initialize again the device, another DKEK will be stored and the backups will not be restored, as they were encrypted with another DKEK.
|
||||||
|
|
||||||
|
Note that, even no DKEK is provided, the Pico HSM generates a DKEK internally but it is never exported for obvious reasons.
|
||||||
|
|
||||||
|
### Single DKEK
|
||||||
|
Before initializing the device, a DKEK is created with:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ sc-hsm-tool --create-dkek-share dkek.pbe
|
||||||
|
Using reader with a card: Free Software Initiative of Japan Gnuk
|
||||||
|
|
||||||
|
The DKEK share will be enciphered using a key derived from a user supplied password.
|
||||||
|
The security of the DKEK share relies on a well chosen and sufficiently long password.
|
||||||
|
The recommended length is more than 10 characters, which are mixed letters, numbers and
|
||||||
|
symbols.
|
||||||
|
|
||||||
|
Please keep the generated DKEK share file in a safe location. We also recommend to keep a
|
||||||
|
paper printout, in case the electronic version becomes unavailable. A printable version
|
||||||
|
of the file can be generated using "openssl base64 -in <filename>".
|
||||||
|
Enter password to encrypt DKEK share :
|
||||||
|
|
||||||
|
Please retype password to confirm :
|
||||||
|
|
||||||
|
Enciphering DKEK share, please wait...
|
||||||
|
DKEK share created and saved to dkek.pbe
|
||||||
|
```
|
||||||
|
|
||||||
|
The generated file `dkek.pbe` contains the DKEK. Technically, it contains a share. But if a device is initialized with one share, it is equivalent to contain the full DKEK.
|
||||||
|
|
||||||
|
Keep these file in a safe place. If this file is lost, you can export the private keys but you will not be able to import into another device or in the same device if it is initialized again.
|
||||||
|
|
||||||
|
To initialize the device with a single share:
|
||||||
|
|
||||||
|
```
|
||||||
|
sc-hsm-tool --initialize --so-pin 3537363231383830 --pin 648219 --dkek-shares 1
|
||||||
|
```
|
||||||
|
|
||||||
|
At this moment, the Pico HSM expects the DKEK. It is loaded with the following command:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ sc-hsm-tool --import-dkek-share dkek.pbe
|
||||||
|
Using reader with a card: Free Software Initiative of Japan Gnuk
|
||||||
|
Enter password to decrypt DKEK share :
|
||||||
|
|
||||||
|
Deciphering DKEK share, please wait...
|
||||||
|
DKEK share imported
|
||||||
|
DKEK shares : 1
|
||||||
|
DKEK key check value : 4B7DA256ACD4EF62
|
||||||
|
```
|
||||||
|
|
||||||
|
The Pico HSM is fully operative and you are ready to generate, export and import keys.
|
||||||
|
|
||||||
|
### Multiple DKEK
|
||||||
|
The process is similar with the [Single DKEK](#single-dkek), but it is repeated with multiple DKEK:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ sc-hsm-tool --create-dkek-share dkek-share-1.pbe
|
||||||
|
$ sc-hsm-tool --create-dkek-share dkek-share-2.pbe
|
||||||
|
$ sc-hsm-tool --create-dkek-share dkek-share-3.pbe
|
||||||
|
```
|
||||||
|
|
||||||
|
The device is then initialized with 3 DKEK shares:
|
||||||
|
|
||||||
|
```
|
||||||
|
sc-hsm-tool --initialize --so-pin 3537363231383830 --pin 648219 --dkek-shares 3
|
||||||
|
```
|
||||||
|
|
||||||
|
And finally, all are imported one after the other, without special order:
|
||||||
|
```
|
||||||
|
$ sc-hsm-tool --import-dkek-share dkek-share-1.pbe
|
||||||
|
Using reader with a card: Free Software Initiative of Japan Gnuk
|
||||||
|
Enter password to decrypt DKEK share :
|
||||||
|
|
||||||
|
Deciphering DKEK share, please wait...
|
||||||
|
DKEK share imported
|
||||||
|
DKEK shares : 3
|
||||||
|
DKEK import pending, 2 share(s) still missing
|
||||||
|
|
||||||
|
$ sc-hsm-tool --import-dkek-share dkek-share-2.pbe
|
||||||
|
Using reader with a card: Free Software Initiative of Japan Gnuk
|
||||||
|
Enter password to decrypt DKEK share :
|
||||||
|
|
||||||
|
Deciphering DKEK share, please wait...
|
||||||
|
DKEK share imported
|
||||||
|
DKEK shares : 3
|
||||||
|
DKEK import pending, 1 share(s) still missing
|
||||||
|
|
||||||
|
$ sc-hsm-tool --import-dkek-share dkek-share-1.pbe
|
||||||
|
Using reader with a card: Free Software Initiative of Japan Gnuk
|
||||||
|
Enter password to decrypt DKEK share :
|
||||||
|
|
||||||
|
Deciphering DKEK share, please wait...
|
||||||
|
DKEK share imported
|
||||||
|
DKEK shares : 1
|
||||||
|
DKEK key check value : 4B7DA256ACD4EF62
|
||||||
|
```
|
||||||
|
|
||||||
|
### DKEK n-of-m threshold scheme
|
||||||
|
This scheme provides an extra level of flexiblity, as not all custodians are necessary to import the DKEK share. For instance, with the previous schemes, if a custodian gets unavailable, the initialization will block until the missing custodian can got to finalize the initialization.
|
||||||
|
|
||||||
|
With n-of-m threshold scheme, it flexibilizes the number of required custodians to reduce failure points. If a share is lost, the DKEK can still be recovered without major implications.
|
||||||
|
|
||||||
|
This scheme is not a replacement of DKEK shares. Instead, it splits the DKEK share encryption password amongst the n-of-m threshold scheme. For instance, if you define 2 shares and a scheme of 3-of-5 threshold for each share, it will imply 10 different custodians, where 6 are necessary to load both shares. You can also mix one share with traditional passphrase and the other with the n-of-m threshold scheme.
|
||||||
|
|
||||||
|
To generate a DKEK share with a 3-of-5 threshold scheme:
|
||||||
|
|
||||||
|
```
|
||||||
|
sc-hsm-tool --create-dkek-share dkek-share-1.pbe --pwd-shares-threshold 3 --pwd-shares-total 5
|
||||||
|
Using reader with a card:Free Software Initiative of Japan Gnuk
|
||||||
|
|
||||||
|
The DKEK will be enciphered using a randomly generated 64 bit password.
|
||||||
|
This password is split using a (3-of-5) threshold scheme.
|
||||||
|
|
||||||
|
Please keep the generated and encrypted DKEK file in a safe location. We also recommend
|
||||||
|
to keep a paper printout, in case the electronic version becomes unavailable. A printable version
|
||||||
|
of the file can be generated using "openssl base64 -in <filename>".
|
||||||
|
|
||||||
|
|
||||||
|
Press <enter> to continue
|
||||||
|
```
|
||||||
|
After enter, it will display 5 screens with the following information:
|
||||||
|
|
||||||
|
```
|
||||||
|
Share 1 of 5
|
||||||
|
|
||||||
|
|
||||||
|
Prime : f5:56:46:c9:a5:a1:01:87
|
||||||
|
Share ID : 1
|
||||||
|
Share value : 99:64:68:65:d8:8d:c0:5f
|
||||||
|
|
||||||
|
|
||||||
|
Please note ALL values above and press <enter> when finished
|
||||||
|
```
|
||||||
|
|
||||||
|
The `Prime` value is the same for all custodians. Only the first custodian is required to introduce it. Nevertheless, it is recommended that all custodians keep also the `Prime` value.
|
||||||
|
|
||||||
|
To import the DKEK share encrypted with this scheme:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ sc-hsm-tool --import-dkek-share dkek-share-1.pbe --pwd-shares-total 3
|
||||||
|
Using reader with a card: Free Software Initiative of Japan Gnuk
|
||||||
|
|
||||||
|
Deciphering the DKEK for import into the SmartCard-HSM requires 3 key custodians
|
||||||
|
to present their share. Only the first key custodian needs to enter the public prime.
|
||||||
|
Please remember to present the share id as well as the share value.
|
||||||
|
|
||||||
|
Please enter prime: f5:56:46:c9:a5:a1:01:87
|
||||||
|
```
|
||||||
|
|
||||||
|
Then, all custodians introduce the `Share ID` and `Share value`:
|
||||||
|
|
||||||
|
```
|
||||||
|
Share 1 of 3
|
||||||
|
|
||||||
|
Please enter share ID: 1
|
||||||
|
Please enter share value: 99:64:68:65:d8:8d:c0:5f
|
||||||
|
```
|
||||||
|
|
||||||
|
After the 3 custodians introduce the share values, the share is successfully loaded.
|
||||||
|
|
||||||
|
## Backup
|
||||||
|
Once the Pico HSM is fully initialized, the device is ready to generate private keys and export them. To wrap a key and export them, the `Key Reference` field is necessary. To obtain it, you can list the objects with the `pkcs15-tool`:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ pkcs15-tool -D
|
||||||
|
Using reader with a card: Free Software Initiative of Japan Gnuk
|
||||||
|
...
|
||||||
|
Private RSA Key [Certificate]
|
||||||
|
Object Flags : [0x03], private, modifiable
|
||||||
|
Usage : [0x2E], decrypt, sign, signRecover, unwrap
|
||||||
|
Access Flags : [0x1D], sensitive, alwaysSensitive, neverExtract, local
|
||||||
|
Algo_refs : 0
|
||||||
|
ModLength : 2048
|
||||||
|
Key ref : 1 (0x01)
|
||||||
|
Native : yes
|
||||||
|
Auth ID : 01
|
||||||
|
ID : 01
|
||||||
|
MD:guid : 748d16af-097a-cd84-2d62-92048f30f21d
|
||||||
|
...
|
||||||
|
```
|
||||||
|
|
||||||
|
Note that `Key ref` and `ID` may be different. Whilst different keys may share the same `ID` (highly discouraged), the `Key ref` is a value internally computed and unique.
|
||||||
|
|
||||||
|
To export and wrap the private key:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ sc-hsm-tool --wrap-key wrap-key.bin --key-reference 1 --pin 648219
|
||||||
|
```
|
||||||
|
|
||||||
|
A file named `wrap-key.bin` is created with the private key encrypted securely with the DKEK.
|
||||||
|
|
||||||
|
## Restore
|
||||||
|
To restore the wraped key, a device initialized with the same DKEK is mandatory.
|
||||||
|
|
||||||
|
To unwrap the key:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ sc-hsm-tool --unwrap-key wrap-key.bin --key-reference 10 --pin 648219
|
||||||
|
Using reader with a card: Free Software Initiative of Japan Gnuk
|
||||||
|
Wrapped key contains:
|
||||||
|
Key blob
|
||||||
|
Private Key Description (PRKD)
|
||||||
|
Certificate
|
||||||
|
Key successfully imported
|
||||||
|
```
|
||||||
|
Now, the key is restored in the device with the same `ID` as the original and with the specified `Key ref`.
|
||||||
86
doc/extra_command.md
Normal file
86
doc/extra_command.md
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
# Extra command
|
||||||
|
|
||||||
|
Pico HSM supports a customized extra command to use with different options. Since the drivers in the market do not support the following features, a raw APDU command shall be sent.
|
||||||
|
|
||||||
|
To send a raw APDU command, `opensc-tool -s <APDU>` can be used. The `APDU` parameter is a string of hexadecimal numbers and it takes the following form:
|
||||||
|
```
|
||||||
|
8054XX00YYZZZZRR
|
||||||
|
```
|
||||||
|
|
||||||
|
It composed by the following fields:
|
||||||
|
- `80` to indicate that it is a custom vendor type command.
|
||||||
|
- `54` is the `INS` custom command.
|
||||||
|
- `XX` is the command to execute. It varies depending on the targeted command.
|
||||||
|
- `00` is the parameter of the command. At this moment, no commands support parameters.
|
||||||
|
- `YY` is the length of the data. If no data is provided, this field is absent.
|
||||||
|
- `ZZZZ` is the data to be sent. Optional. The length is variable.
|
||||||
|
- `RR` is the length of the expected response. If no response is expected, this field is absent.
|
||||||
|
|
||||||
|
## Real time clock and datetime
|
||||||
|
Pico HSM has an internal real time clock (RTC) which can track precisely the date and the time. However, when it is reset or powered down, the Pico HSM is reset to the initial datetime: 2020 January 1, 00:00:00.
|
||||||
|
|
||||||
|
### Getting the datetime
|
||||||
|
To obtain the current datetime (referenced to 00:00:00 2020/01/01), the `XX` parameter must be set to `0A`. There is no data and, thus, `YY` and `ZZZZ` are absent. The expected response is 8 bytes length.
|
||||||
|
|
||||||
|
For example, to obtain the current datetime:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ opensc-tool -s 80540A0008
|
||||||
|
Using reader with a card: Free Software Initiative of Japan Gnuk
|
||||||
|
Sending: 80 54 0A 00 08
|
||||||
|
Received (SW1=0x90, SW2=0x00):
|
||||||
|
07 E6 04 06 03 13 29 1E ......).
|
||||||
|
```
|
||||||
|
|
||||||
|
The response is composed by 8 bytes:
|
||||||
|
- The first two bytes are the current year, MSB first. Hence, `07E6h` equals to `2022`.
|
||||||
|
- 1 byte for the current month, `01h` is January and `0Ch` is December.
|
||||||
|
- 1 byte for the current day, from `01h` (1) to `1Fh` (31).
|
||||||
|
- 1 byte for the day of the week, `00h` is Sunday, `01h` is Monday, etc.
|
||||||
|
- 1 byte for the hours, from `00h` (0) to `17h` (23).
|
||||||
|
- 1 byte for the minutes, from `00h` (0) to `3Bh` (59).
|
||||||
|
- 1 byte for the seconds, from `00h` (0) to `3Bh` (59).
|
||||||
|
|
||||||
|
If the command is correctly received, `SW1=0x90` and `SW2=0x00`. Other values mean that an error has ocurred.
|
||||||
|
|
||||||
|
### Setting the datetime
|
||||||
|
To set the reference datetime, a datetime string must be provided. For example:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ opensc-tool -s 80540A000807E6040603132917
|
||||||
|
Using reader with a card: Free Software Initiative of Japan Gnuk
|
||||||
|
Sending: 80 54 0A 00 08 07 E6 04 06 03 13 29 17
|
||||||
|
Received (SW1=0x90, SW2=0x00)
|
||||||
|
```
|
||||||
|
|
||||||
|
will set the reference datetime to `Wednesday, 2022 April 6th, 19:41:23`.
|
||||||
|
|
||||||
|
## Dynamic options
|
||||||
|
Pico HSM support initialize options, such as setting Transport PIN or reset retry counter options. However, once it is initialized, these options cannot be modified anymore, without a new initialization (loosing all stored keys). Pico HSM offers the chance to define a set of dynamic options that can be enabled/disabled dynamically without initializing the device at every moment.
|
||||||
|
|
||||||
|
To specify a set of options, the `XX` parameter shall be set to `06`. The data parameter shall be 1 byte, where the options are combined with the or operand `|`. The length `YY` shall be set to `01`.
|
||||||
|
|
||||||
|
### Press-to-confirm button
|
||||||
|
Press-to-confirm button offers an extra security layer by requiring the user confirmation everytime that a private/secret key is loaded. This avoids ghost applications thay may perform hidden opperations without noticing the user, such as signing or decrypting. Pico HSM will inform the user that is awaiting for a confirmation by making almost a fixed Led blink.
|
||||||
|
|
||||||
|
This feature is disabled by default but can be enabled rapidly by setting the LSB bit to 1:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ opensc-tool -s 805406000101
|
||||||
|
Using reader with a card: Free Software Initiative of Japan Gnuk
|
||||||
|
Sending: 80 54 06 00 01 01
|
||||||
|
Received (SW1=0x90, SW2=0x00)
|
||||||
|
```
|
||||||
|
|
||||||
|
At this moment, when a private/secret key is loaded, the Pico HSM will wait for the pressed BOOTSEL button to confirm the operation.
|
||||||
|
|
||||||
|
To disable, the LSB bit must be set to 0:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ opensc-tool -s 805406000100
|
||||||
|
Using reader with a card: Free Software Initiative of Japan Gnuk
|
||||||
|
Sending: 80 54 06 00 01 00
|
||||||
|
Received (SW1=0x90, SW2=0x00)
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
49
doc/rsa_4096.md
Normal file
49
doc/rsa_4096.md
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
# RSA 4096 support
|
||||||
|
|
||||||
|
Generating 4096 bits key in the Pico HSM is highly expensive. It may take minutes or hours to finish the generation. Therefore, it is extremely recommendable to generate the key in the host and import it into the Pico HSM.
|
||||||
|
|
||||||
|
## SCS3 tool
|
||||||
|
|
||||||
|
Unfortunately, there is no pkcs11 tool or equivalent capable to perform the import. Since it uses the SC-HSM driver, it also supports the communication with the [SCS3 tool](https://www.openscdp.org/scsh3/ "SCS3 tool"). It can be downloaded from [here](https://www.openscdp.org/scsh3/download.html "here").
|
||||||
|
|
||||||
|
However, SCS3 only works with those HSM manufactured by CardContact. The check is performed by means of trust store against the manufacturing certificates. For obvious reasons, these certificates can only be signed with the private keys of the Certificate Authorities listed in the trust store.
|
||||||
|
|
||||||
|
Pico HSM is shipped with its own CA certificates. To load this certificate onto the trust store of SCS3, the following line has to be appended to `SmartCardHSM.rootCerts` variable, near line `235` in the file `scs3/scsh/sc-hsm/SmartCardHSM.js`.
|
||||||
|
|
||||||
|
```
|
||||||
|
ESCVCAHSM00001: new CVC(new ByteString("7F218201657F4E82012D5F290100420E45534356434148534D30303030317F4981DD060A04007F000702020202038118FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF8218FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFC831864210519E59C80E70FA7E9AB72243049FEB8DEECC146B9B1843104188DA80EB03090F67CBF20EB43A18800F4FF0AFD82FF101207192B95FFC8DA78631011ED6B24CDD573F977A11E7948118518FFFFFFFFFFFFFFFFFFFFFFFF99DEF836146BC9B1B4D22831863104088FCDFCCE87EDD285920615E651D76452D857ECBB408C327ADB48A2A514C1C9BD77CC9783607A741493A742744AD1738701015F200E45534356434148534D30303030317F4C12060904007F0007030102025305C0000000045F25060202000302065F24060300010203015F37307297777664B60C57A2C45E7BFD12E520143EDE9038BFB302739106F2730D760665D74649910C519089848D4FB6E51340", HEX))
|
||||||
|
```
|
||||||
|
|
||||||
|
Therefore, the whole variable becomes:
|
||||||
|
|
||||||
|
```
|
||||||
|
SmartCardHSM.rootCerts = {
|
||||||
|
DESRCACC100001: new CVC(new ByteString("7F218201B47F4E82016C5F290100420E44455352434143433130303030317F4982011D060A04007F000702020202038120A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E537782207D5A0975FC2C3057EEF67530417AFFE7FB8055C126DC5C6CE94A4B44F330B5D9832026DC5C6CE94A4B44F330B5D9BBD77CBF958416295CF7E1CE6BCCDC18FF8C07B68441048BD2AEB9CB7E57CB2C4B482FFC81B7AFB9DE27E1E3BD23C23A4453BD9ACE3262547EF835C3DAC4FD97F8461A14611DC9C27745132DED8E545C1D54C72F0469978520A9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A78641046D025A8026CDBA245F10DF1B72E9880FFF746DAB40A43A3D5C6BEBF27707C30F6DEA72430EE3287B0665C1EAA6EAA4FA26C46303001983F82BD1AA31E03DA0628701015F200E44455352434143433130303030317F4C10060B2B0601040181C31F0301015301C05F25060102010100095F24060302010100085F37409DBB382B1711D2BAACB0C623D40C6267D0B52BA455C01F56333DC9554810B9B2878DAF9EC3ADA19C7B065D780D6C9C3C2ECEDFD78DEB18AF40778ADF89E861CA", HEX)),
|
||||||
|
UTSRCACC100001: new CVC(new ByteString("7F218201B47F4E82016C5F290100420E55545352434143433130303030317F4982011D060A04007F000702020202038120A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E537782207D5A0975FC2C3057EEF67530417AFFE7FB8055C126DC5C6CE94A4B44F330B5D9832026DC5C6CE94A4B44F330B5D9BBD77CBF958416295CF7E1CE6BCCDC18FF8C07B68441048BD2AEB9CB7E57CB2C4B482FFC81B7AFB9DE27E1E3BD23C23A4453BD9ACE3262547EF835C3DAC4FD97F8461A14611DC9C27745132DED8E545C1D54C72F0469978520A9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A7864104A041FEB2FD116B2AD19CA6B7EACD71C9892F941BB88D67DCEEC92501F070011957E22122BA6C2CF5FF02936F482E35A6129CCBBA8E9383836D3106879C408EF08701015F200E55545352434143433130303030317F4C10060B2B0601040181C31F0301015301C05F25060102010100095F24060302010100085F3740914DD0FA00615C44048D1467435400423A4AD1BD37FD98D6DE84FD8037489582325C72956D4FDFABC6EDBA48184A754F37F1BE5142DD1C27D66569308CE19AAF", HEX)),
|
||||||
|
ESCVCAHSM00001: new CVC(new ByteString("7F218201657F4E82012D5F290100420E45534356434148534D30303030317F4981DD060A04007F000702020202038118FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF8218FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFC831864210519E59C80E70FA7E9AB72243049FEB8DEECC146B9B1843104188DA80EB03090F67CBF20EB43A18800F4FF0AFD82FF101207192B95FFC8DA78631011ED6B24CDD573F977A11E7948118518FFFFFFFFFFFFFFFFFFFFFFFF99DEF836146BC9B1B4D22831863104088FCDFCCE87EDD285920615E651D76452D857ECBB408C327ADB48A2A514C1C9BD77CC9783607A741493A742744AD1738701015F200E45534356434148534D30303030317F4C12060904007F0007030102025305C0000000045F25060202000302065F24060300010203015F37307297777664B60C57A2C45E7BFD12E520143EDE9038BFB302739106F2730D760665D74649910C519089848D4FB6E51340", HEX))
|
||||||
|
}
|
||||||
|
````
|
||||||
|
|
||||||
|
After this ammendment, the KeyManager can be invoked (CTRL+M) and it will output something similar to:
|
||||||
|
```
|
||||||
|
>load("keymanager/keymanager.js");
|
||||||
|
|
||||||
|
SmartCard-HSM Version 1.6 on JCOP Free memory 217104 byte
|
||||||
|
Issuer Certificate : CVC id-AT DV (official domestic) CAR=ESCVCAHSM00001 CHR=ESDVCAHSM00001 CED=27 / de març / 2022 CXD=31 / de desembre / 2025
|
||||||
|
Device Certificate : CVC id-AT Terminal CAR=ESDVCAHSM00001 CHR=ESTERMHSM00001 CED=27 / de març / 2022 CXD=31 / de desembre / 2023
|
||||||
|
Default Key Domain : 0F89B400975EDD2D425ABF85F2FBD318779B3D85475E65D4
|
||||||
|
-------------------------------------------------------------------
|
||||||
|
Please right-click on nodes in the outline to see possible actions.
|
||||||
|
For most operations you will need to authenticate first using a
|
||||||
|
mechanism from the User PIN context menu.
|
||||||
|
>
|
||||||
|
```
|
||||||
|
|
||||||
|
The SCS3 tool is ready to import private keys and certificates, wraped in WKY files or in PKCS#12 format. Also, all stored keys can be exported, combined with their respective certificates. Note that the user has to be previously logged in.
|
||||||
|
|
||||||
|
## DKEK requirement
|
||||||
|
|
||||||
|
In order to perform the import, private keys must be wrapped with the same DKEK present in the Pico HSM. Thus, the Pico HSM must be previously initialized with at minimum of 1 DKEK share. This share will be used to wrap the private key before import.
|
||||||
|
|
||||||
|
Note that the DKEK share shall be available before the import. In this way, all custodians must be present during the import process, since they will have to introduce their respective DKEK.
|
||||||
|
|
||||||
153
doc/sign-verify.md
Normal file
153
doc/sign-verify.md
Normal file
@@ -0,0 +1,153 @@
|
|||||||
|
# Sign and verify
|
||||||
|
|
||||||
|
Pico HSM supports in place signature of arbitrary data. It supports the following algorithms:
|
||||||
|
* RSA-PKCS
|
||||||
|
* RSA-X-509
|
||||||
|
* SHA1-RSA-PKCS
|
||||||
|
* SHA256-RSA-PKCS
|
||||||
|
* SHA224-RSA-PKCS
|
||||||
|
* SHA384-RSA-PKCS
|
||||||
|
* SHA512-RSA-PKCS
|
||||||
|
* RSA-PKCS-PSS
|
||||||
|
* SHA1-RSA-PKCS-PSS
|
||||||
|
* SHA256-RSA-PKCS-PSS
|
||||||
|
* SHA224-RSA-PKCS-PSS
|
||||||
|
* SHA384-RSA-PKCS-PSS
|
||||||
|
* SHA512-RSA-PKCS-PSS
|
||||||
|
* SHA1-ECDSA
|
||||||
|
* SHA224-ECDSA
|
||||||
|
* SHA256-ECDSA
|
||||||
|
|
||||||
|
First, we generate the data:
|
||||||
|
```
|
||||||
|
$ echo "This is a test string. Be safe, be secure." > data
|
||||||
|
```
|
||||||
|
|
||||||
|
Obtain the public key and convert it to PEM format:
|
||||||
|
```
|
||||||
|
$ pkcs11-tool --read-object --pin 648219 --id 1 --type pubkey > 1.der
|
||||||
|
$ openssl rsa -inform DER -outform PEM -in 1.der -pubin > 1.pub
|
||||||
|
```
|
||||||
|
|
||||||
|
At this moment, you are able to verify with the public key in `1.pub`. The signature is computed inside the Pico HSM with the private key. It never leaves the device.
|
||||||
|
|
||||||
|
## RSA-PKCS
|
||||||
|
This algorithm is used to sign raw data.
|
||||||
|
|
||||||
|
To sign the data:
|
||||||
|
```
|
||||||
|
$ pkcs11-tool --id 1 --sign --pin 648219 --mechanism RSA-PKCS -i data -o data.sig
|
||||||
|
```
|
||||||
|
|
||||||
|
To verify the signature:
|
||||||
|
```
|
||||||
|
$ openssl pkeyutl -verify -pubin -inkey 1.pub -in data -sigfile data.sig
|
||||||
|
Signature Verified Successfully
|
||||||
|
```
|
||||||
|
|
||||||
|
## SHA1-RSA-PKCS
|
||||||
|
This algorithm is used to sign digests computed outside. It supports SHA1, SHA224, SHA256, SHA384 and SHA512.
|
||||||
|
|
||||||
|
First, we generate a file with the digest:
|
||||||
|
```
|
||||||
|
openssl dgst -sha1 -binary -out data.sha1 data
|
||||||
|
```
|
||||||
|
|
||||||
|
To sign the data:
|
||||||
|
```
|
||||||
|
$ pkcs11-tool --id 1 --sign --pin 648219 --mechanism SHA1-RSA-PKCS -i data -o data.sig
|
||||||
|
```
|
||||||
|
|
||||||
|
To verify the signature:
|
||||||
|
```
|
||||||
|
$ openssl pkeyutl -verify -in data.sha1 -sigfile data.sig -pubin -inkey 1.pub -pkeyopt digest:sha1
|
||||||
|
Signature Verified Successfully
|
||||||
|
```
|
||||||
|
|
||||||
|
## RSA-X-509
|
||||||
|
This algorithm is used for signing raw data. In this algorithm, the data must be padded with a length equal to the size of private key (128, 256, 512 bytes for RSA-1024, RSA-2048 and RSA-4096, respectively).
|
||||||
|
|
||||||
|
First, we pad the data. The original data file occupies 29 bytes. Thus, for a 2048 bits key, a padding of 227 bytes is needed:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ cp data data_pad
|
||||||
|
$ dd if=/dev/zero bs=1 count=227 >> data_pad
|
||||||
|
```
|
||||||
|
|
||||||
|
To sign the data:
|
||||||
|
```
|
||||||
|
$ pkcs11-tool --id 1 --sign --pin 648219 --mechanism RSA-X-509 -i data_pad -o data.sig
|
||||||
|
```
|
||||||
|
|
||||||
|
To verify the signature:
|
||||||
|
```
|
||||||
|
$ openssl rsautl -verify -inkey 1.pub -in data.sig -pubin -raw
|
||||||
|
This is a test string. Be safe, be secure.
|
||||||
|
```
|
||||||
|
|
||||||
|
## RSA-PKCS-PSS
|
||||||
|
This algorithm uses the RSA-PKCS with PSS salt to randomize the signature. Pico HSM does not support arbitrary salt lengths. Instead, it always uses the maximum salt length (the hash length). It uses the hash as the input.
|
||||||
|
|
||||||
|
To sign the data:
|
||||||
|
```
|
||||||
|
$ pkcs11-tool --id 1 --sign --pin 648219 --mechanism RSA-PKCS-PSS -i data.sha1 -o data.sig
|
||||||
|
```
|
||||||
|
|
||||||
|
To verify the signature:
|
||||||
|
```
|
||||||
|
$ openssl pkeyutl -verify -in data.sha1 -sigfile data.sig -pubin -inkey 1.pub -pkeyopt rsa_padding_mode:pss -pkeyopt rsa_pss_saltlen:-1 -pkeyopt digest:sha1
|
||||||
|
Signature Verified Successfully
|
||||||
|
```
|
||||||
|
|
||||||
|
## SHA1-RSA-PKCS-PSS
|
||||||
|
This algorithm takes the file as the input and sends its hash for signing with the random salt.
|
||||||
|
|
||||||
|
To sign the data:
|
||||||
|
```
|
||||||
|
$ pkcs11-tool --id 1 --sign --pin 648219 --mechanism SHA1-RSA-PKCS-PSS -i data -o data.sig
|
||||||
|
```
|
||||||
|
|
||||||
|
To verify the signature:
|
||||||
|
```
|
||||||
|
$ openssl pkeyutl -verify -in data.sha1 -sigfile data.sig -pubin -inkey 1.pub -pkeyopt rsa_padding_mode:pss -pkeyopt rsa_pss_saltlen:-1
|
||||||
|
Signature Verified Successfully
|
||||||
|
```
|
||||||
|
|
||||||
|
## ECDSA
|
||||||
|
This is a raw ECDSA signature, which is usually used to sign a hashed message. `pkcs11-tool` has the limit of the maximum supported length, which is the length in bytes of the ECC curve. For a 192 bits curve, it only supports hashed messages with SHA1 (20 bytes < 24 bytes). To support SHA256 hashed messages, a minimum of ECC curve of 256 bits is required. `sc-hsm-embedded` driver and `sc-tool` do not have this constraint and can be used with arbitrary data.
|
||||||
|
|
||||||
|
To sign the data:
|
||||||
|
```
|
||||||
|
$ pkcs11-tool --id 11 --sign --pin 648219 --mechanism ECDSA -i data.sha1 -o data.sig --signature-format openssl
|
||||||
|
Using slot 0 with a present token (0x0)
|
||||||
|
Using signature algorithm ECDSA
|
||||||
|
```
|
||||||
|
|
||||||
|
To verify the signature:
|
||||||
|
```
|
||||||
|
$ openssl pkeyutl -verify -pubin -inkey 11.pub -in data.sha1 -sigfile data.sig
|
||||||
|
Signature Verified Successfully
|
||||||
|
```
|
||||||
|
|
||||||
|
To sign raw data, use `sc-tool` of `sc-hsm-embedded` driver instead of `pkcs11-tool`.
|
||||||
|
|
||||||
|
## SHA1-ECDSA
|
||||||
|
For ECDSA signature, we employ a ECC key with the id `--id 11`. The signature is quite similar as with RSA.
|
||||||
|
|
||||||
|
To sign the data:
|
||||||
|
```
|
||||||
|
$ pkcs11-tool --id 11 --sign --pin 648219 --mechanism ECDSA-SHA1 -i data -o data.sig --signature-format openssl
|
||||||
|
Using slot 0 with a present token (0x0)
|
||||||
|
Using signature algorithm ECDSA-SHA256
|
||||||
|
```
|
||||||
|
|
||||||
|
The signature is verified with the hash:
|
||||||
|
```
|
||||||
|
$ openssl pkeyutl -verify -pubin -inkey 11.pub -in data.sha1 -sigfile data.sig
|
||||||
|
Signature Verified Successfully
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
117
doc/store_data.md
Normal file
117
doc/store_data.md
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
# Store binary data
|
||||||
|
Pico HSM has a internal flash which can store binary data. With this approach, you can save different files, encrypt into the Pico HSM and retrieve them after.
|
||||||
|
|
||||||
|
## Maximum size
|
||||||
|
Due to internal constraints with the flash components, the maximum file size is `4096` bytes. This mechanism is mainly used to store small files, such as keys in plain text, certificates, credentials, etc.
|
||||||
|
|
||||||
|
## Store a file
|
||||||
|
Before writting a file into the Pico HSM, we generate the data file with the following text:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ echo 'Pico HSM is awesome!' > test
|
||||||
|
```
|
||||||
|
|
||||||
|
Then, we can store the data file with the following command:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ pkcs11-tool --pin 648219 --write-object test --type data --id 1 --label 'test1'
|
||||||
|
Using slot 0 with a present token (0x0)
|
||||||
|
Created Data Object:
|
||||||
|
Data object 1236368320
|
||||||
|
label: 'test1'
|
||||||
|
application: 'test1'
|
||||||
|
app_id: <empty>
|
||||||
|
flags: modifiable
|
||||||
|
```
|
||||||
|
|
||||||
|
This file can also be protected with the PIN. In this case, use the previous command with the `--private` flag:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ pkcs11-tool --pin 648219 --write-object test --type data --id 2 --label 'test2' --private
|
||||||
|
Using slot 0 with a present token (0x0)
|
||||||
|
Created Data Object:
|
||||||
|
Data object 1329612320
|
||||||
|
label: 'test2'
|
||||||
|
application: 'test2'
|
||||||
|
app_id: <empty>
|
||||||
|
flags: modifiable private
|
||||||
|
```
|
||||||
|
|
||||||
|
Always provide a unique `--label`, as it will be used to index and reference the file for retrieving.
|
||||||
|
|
||||||
|
## Retrieve a file
|
||||||
|
To view the stored file, we can use the following command with the same label we employed:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ pkcs11-tool --read-object --type data --label 'test1'
|
||||||
|
Using slot 0 with a present token (0x0)
|
||||||
|
Pico HSM is awesome!
|
||||||
|
```
|
||||||
|
|
||||||
|
Note that if the `--private` flag is not provided during the writting stage, the file can be accessed without the PIN.
|
||||||
|
|
||||||
|
To retrieve a private file with the PIN:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ pkcs11-tool --read-object --type data --label 'test2' --pin 648219
|
||||||
|
Using slot 0 with a present token (0x0)
|
||||||
|
Pico HSM is awesome!
|
||||||
|
```
|
||||||
|
|
||||||
|
## Using `pkcs15-tool`
|
||||||
|
PKCS15 tool can be used to list the stored files. For instance:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ pkcs15-tool -D
|
||||||
|
Using reader with a card: Free Software Initiative of Japan Gnuk
|
||||||
|
PKCS#15 Card [Pico-HSM]:
|
||||||
|
Version : 1
|
||||||
|
Serial number : ESTERMHSM
|
||||||
|
Manufacturer ID: Pol Henarejos
|
||||||
|
Flags : PRN generation, EID compliant
|
||||||
|
|
||||||
|
|
||||||
|
PIN [UserPIN]
|
||||||
|
Object Flags : [0x03], private, modifiable
|
||||||
|
Auth ID : 02
|
||||||
|
ID : 01
|
||||||
|
Flags : [0x812], local, initialized, exchangeRefData
|
||||||
|
Length : min_len:6, max_len:15, stored_len:0
|
||||||
|
Pad char : 0x00
|
||||||
|
Reference : 129 (0x81)
|
||||||
|
Type : ascii-numeric
|
||||||
|
Path : e82b0601040181c31f0201::
|
||||||
|
Tries left : 3
|
||||||
|
|
||||||
|
PIN [SOPIN]
|
||||||
|
Object Flags : [0x01], private
|
||||||
|
ID : 02
|
||||||
|
Flags : [0x9A], local, unblock-disabled, initialized, soPin
|
||||||
|
Length : min_len:16, max_len:16, stored_len:0
|
||||||
|
Pad char : 0x00
|
||||||
|
Reference : 136 (0x88)
|
||||||
|
Type : bcd
|
||||||
|
Path : e82b0601040181c31f0201::
|
||||||
|
Tries left : 15
|
||||||
|
|
||||||
|
Data object 'test1'
|
||||||
|
applicationName: test1
|
||||||
|
Path: e82b0601040181c31f0201::cf00
|
||||||
|
Data (21 bytes): 5069636F2048534D20697320617765736F6D65210A
|
||||||
|
|
||||||
|
Data object 'test2'
|
||||||
|
applicationName: test2
|
||||||
|
Path: e82b0601040181c31f0201::cd01
|
||||||
|
Auth ID: 01
|
||||||
|
```
|
||||||
|
|
||||||
|
As expected, the public file is displayed (in hexadecimal string). The private file contains the `Auth ID` flag and it is not displayed.
|
||||||
|
|
||||||
|
## Delete a file
|
||||||
|
A stored file can be deleted with the following command:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ pkcs11-tool --login --pin 648219 --delete-object --type data --application-label test1
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
220
doc/usage.md
Normal file
220
doc/usage.md
Normal file
@@ -0,0 +1,220 @@
|
|||||||
|
# Usage
|
||||||
|
|
||||||
|
## Tools
|
||||||
|
We use multiple tools and PKCS#11 drivers and modules, depending on the purpose.
|
||||||
|
* **pkcs11-tool**: from OpenSC. It interfaces with the HSM via PKCS#11 interface. It supports different drivers and modules.
|
||||||
|
* **sc-tool**: an alias of pkcs11-tool with the sc-hsm-embedded module. It is mainly used for AES management and it is defined as:
|
||||||
|
```
|
||||||
|
$ alias sc-tool=pkcs11-tool --module /path/to/libsc-hsm-pkcs11.so
|
||||||
|
```
|
||||||
|
* **openssl**: it used for certificate and X509 generation and management. It uses the pkcs11 engine. To configure the pkcs11 engine, add the following lines at the begining of `/etc/openssl.cnf` file[^1]:
|
||||||
|
```
|
||||||
|
openssl_conf = openssl_init
|
||||||
|
[openssl_init]
|
||||||
|
engines=engine_section
|
||||||
|
[engine_section]
|
||||||
|
pkcs11 = pkcs11_section
|
||||||
|
[pkcs11_section]
|
||||||
|
engine_id = pkcs11
|
||||||
|
dynamic_path = /path/to/ENGINESDIR/pkcs11.so
|
||||||
|
MODULE_PATH = /usr/local/lib/opensc-pkcs11.so
|
||||||
|
init=0
|
||||||
|
PIN=648219
|
||||||
|
```
|
||||||
|
`opensc-pkcs11.so` can be replaced by `libsc-hsm-pkcs11.so` if desired.
|
||||||
|
* **sc-hsm-tool**: from OpenSC. Used to initialize the device.
|
||||||
|
* **opensc-tool**: from OpenSC. Used to list and detect the reader with the HSM.
|
||||||
|
|
||||||
|
[^1]: `openssl version -a` will return the `OPENSSLDIR`, which contains `openssl.cnf` file and `ENGINESDIR`, which contains the p11 engine.
|
||||||
|
|
||||||
|
## Initialization
|
||||||
|
The first step is to initialize the HSM:
|
||||||
|
```
|
||||||
|
$ sc-hsm-tool --initialize --so-pin 3537363231383830 --pin 648219
|
||||||
|
```
|
||||||
|
The PIN number is used to manage all private keys in the device. It supports three attemps. After the third PIN failure, it gets blocked.
|
||||||
|
The PIN accepts from 6 to 16 characters.
|
||||||
|
|
||||||
|
The SO-PIN is used to unblock the PIN. It accepts 15 attemps. After 15 failed attempts, the device will be completely blocked and will be necessary to initialize again, erasing all private keys and losing the access. Therefore, keep the SO-PIN in a safe place.
|
||||||
|
The SO-PIN is always 16 hexadecimal characters.
|
||||||
|
|
||||||
|
## PIN and SO-PIN management
|
||||||
|
To change the SO-PIN:
|
||||||
|
```
|
||||||
|
$ pkcs11-tool --login --login-type so --so-pin 3537363231383830 --change-pin --new-pin 0123456789012345
|
||||||
|
```
|
||||||
|
|
||||||
|
To change the PIN:
|
||||||
|
```
|
||||||
|
$ pkcs11-tool --login --pin 648219 --change-pin --new-pin 123456
|
||||||
|
```
|
||||||
|
|
||||||
|
To unblock the PIN:
|
||||||
|
```
|
||||||
|
$ pkcs11-tool --login --login-type so --so-pin=3537363231383830 --init-pin --new-pin=648219
|
||||||
|
```
|
||||||
|
|
||||||
|
## Keypair generation
|
||||||
|
Pico HSM accepts internal keypair generation with RSA scheme. It generates a pair of private and public keys and stores both internally encrypted with a 256 bits AES key. The private key never leaves the device. It may be exported with wrap command but it will be encrypted with a passphrase and the AES key.
|
||||||
|
|
||||||
|
To generate a RSA 2048 bits, use the following command:
|
||||||
|
```
|
||||||
|
$ pkcs11-tool -l --pin 648219 --keypairgen --key-type rsa:2048 --id 1 --label "RSA2K"
|
||||||
|
Using slot 0 with a present token (0x0)
|
||||||
|
Key pair generated:
|
||||||
|
Private Key Object; RSA
|
||||||
|
label: RSA2K
|
||||||
|
ID: 1
|
||||||
|
Usage: decrypt, sign
|
||||||
|
Access: none
|
||||||
|
Public Key Object; RSA 2048 bits
|
||||||
|
label: RSA2K
|
||||||
|
ID: 1
|
||||||
|
Usage: encrypt, verify
|
||||||
|
Access: none
|
||||||
|
```
|
||||||
|
The ID parameter is an internal hexadecimal number for easy identification. The label is a string that also identifies the key. Despite it allows to store multiple keys with the same ID and/or same label, internally are stored with a unique index (the key reference). In any case, do not reuse the same ID/label to avoid future conflicts. Furthermore, it is highly recommended to use always the `--id` parameter, as it can be later referenced easily.
|
||||||
|
|
||||||
|
Pico HSM accepts RSA of 1024 (`rsa:1024`), 2048 (`rsa:2048`) and 4096 bits (`rsa:4096`).
|
||||||
|
|
||||||
|
**Caution**: RSA 2048 bits may take more than 20 seconds. RSA 4096 bits may take more than 20 minutes. The Pico HSM will work as normally and neither the HSM nor the host will block. But, in the meantime, the Pico HSM will not accept any command.
|
||||||
|
An alternative is to generate the private key locally and import it to the HSM. This approach, however, is less secure as it does not use a True RNG or HRNG like Pico HSM. Use this approach if you have plugged a TRNG or you are not worried about obtaining the highest entropy.
|
||||||
|
|
||||||
|
Pico HSM also accepts ECDSA keypairs:
|
||||||
|
* secp192r1 (prime192v1)
|
||||||
|
* secp256r1 (prime256v1)
|
||||||
|
* secp384r1 (prime384v1)
|
||||||
|
* secp521r1 (prime521v1)
|
||||||
|
* brainpoolP256r1
|
||||||
|
* brainpoolP384r1
|
||||||
|
* brainpoolP512r1
|
||||||
|
* secp192k1
|
||||||
|
* secp256k1
|
||||||
|
|
||||||
|
To use ECC keys, use the above command with the `--key-type` parameter with `EC:secp192r1`, `EC:secp256r1`, `EC:secp384r1`, `EC:secp521r1`, `EC:brainpoolP256r1`, `EC:brainpoolP384r1`, `EC:brainpoolP512r1`, `EC:secp192k1` and `EC:secp256r1`.
|
||||||
|
|
||||||
|
## Delete keys
|
||||||
|
To delete the previous generated key:
|
||||||
|
```
|
||||||
|
pkcs11-tool -l --pin 648219 --delete-object --type privkey --id 1
|
||||||
|
```
|
||||||
|
|
||||||
|
## Generate a certificate and sign it
|
||||||
|
Secret keys stored in the Pico HSM and can be used to sign data without leaving the device. To generate a certificate request and sign it with the private key stored in the device, use the following command:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ openssl req -engine pkcs11 -new -key 0:1 -keyform engine -out cert.pem -text -x509 -days 365
|
||||||
|
```
|
||||||
|
|
||||||
|
The key is specified in the form of `slotid:keyid`. For Pico HSM, `slotid` is always `0` and the `keyid` is the id of the key specified with the key generation.
|
||||||
|
The `openssl.cnf` used by `openssl` command shall contain the blocks configured in [Tools section](#tools). The output will depend on your configuration, but for default configuration files it will prompt you something like this:
|
||||||
|
|
||||||
|
```
|
||||||
|
engine "pkcs11" set.
|
||||||
|
You are about to be asked to enter information that will be incorporated
|
||||||
|
into your certificate request.
|
||||||
|
What you are about to enter is what is called a Distinguished Name or a DN.
|
||||||
|
There are quite a few fields but you can leave some blank
|
||||||
|
For some fields there will be a default value,
|
||||||
|
If you enter '.', the field will be left blank.
|
||||||
|
-----
|
||||||
|
Country Name (2 letter code) [AU]:ES
|
||||||
|
State or Province Name (full name) [Some-State]:
|
||||||
|
Locality Name (eg, city) []:
|
||||||
|
Organization Name (eg, company) [Internet Widgits Pty Ltd]:
|
||||||
|
Organizational Unit Name (eg, section) []:
|
||||||
|
Common Name (e.g. server FQDN or YOUR name) []:patata.com
|
||||||
|
Email Address []:
|
||||||
|
```
|
||||||
|
|
||||||
|
The command terminates with success silently. Thus, if no additional output/errors are displayed, the certificate is properly generated and signed. You can check this with:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ openssl x509 -in cert.pem -noout -text
|
||||||
|
Certificate:
|
||||||
|
Data:
|
||||||
|
Version: 3 (0x2)
|
||||||
|
Serial Number:
|
||||||
|
01:3f:b4:5a:ac:7c:1a:e7:bc:37:e0:aa:f9:31:f4:68:90:08:fc:3d
|
||||||
|
Signature Algorithm: sha256WithRSAEncryption
|
||||||
|
Issuer: C = ES, ST = Some-State, O = Internet Widgits Pty Ltd, CN = patata.com
|
||||||
|
Validity
|
||||||
|
Not Before: Mar 13 17:58:00 2022 GMT
|
||||||
|
Not After : Feb 29 17:58:00 2032 GMT
|
||||||
|
Subject: C = ES, ST = Some-State, O = Internet Widgits Pty Ltd, CN = patata.com
|
||||||
|
Subject Public Key Info:
|
||||||
|
Public Key Algorithm: rsaEncryption
|
||||||
|
RSA Public-Key: (1024 bit)
|
||||||
|
Modulus:
|
||||||
|
00:91:85:89:5d:e0:fa:f3:2b:9e:85:75:c9:92:7d:
|
||||||
|
c5:18:16:c0:15:1b:4d:7e:af:1a:8c:ff:2e:39:74:
|
||||||
|
bb:b7:af:b4:ca:24:9d:80:c8:53:51:82:b5:c5:77:
|
||||||
|
0d:56:0a:08:99:84:8d:7a:28:6d:8e:c6:32:40:b0:
|
||||||
|
62:d6:e5:e6:28:35:08:32:d7:f7:d6:eb:10:a8:81:
|
||||||
|
43:9e:7c:51:b2:52:16:d2:fd:05:df:c3:dd:ee:c4:
|
||||||
|
dd:43:db:ca:ed:6f:10:ab:d4:59:dc:3a:2d:80:4b:
|
||||||
|
2c:37:75:14:df:62:e0:7a:b3:62:5b:80:5f:c5:9b:
|
||||||
|
a0:30:b2:ec:d3:d6:0d:58:f3
|
||||||
|
Exponent: 65537 (0x10001)
|
||||||
|
X509v3 extensions:
|
||||||
|
X509v3 Subject Key Identifier:
|
||||||
|
98:07:DA:13:B0:8E:A0:5C:97:83:68:FE:4A:25:8D:50:C4:DC:16:FA
|
||||||
|
X509v3 Authority Key Identifier:
|
||||||
|
keyid:98:07:DA:13:B0:8E:A0:5C:97:83:68:FE:4A:25:8D:50:C4:DC:16:FA
|
||||||
|
|
||||||
|
X509v3 Basic Constraints: critical
|
||||||
|
CA:TRUE
|
||||||
|
Signature Algorithm: sha256WithRSAEncryption
|
||||||
|
56:bc:32:c6:dc:4a:af:64:4e:27:1c:52:e2:9d:8a:d7:b9:e0:
|
||||||
|
7f:f0:3a:97:08:9a:5d:64:86:88:df:2f:c5:5d:ab:ae:00:ce:
|
||||||
|
db:13:fc:a0:a7:b3:13:4a:0b:2f:1d:9c:64:95:58:94:52:93:
|
||||||
|
81:18:32:a5:9d:5f:be:bd:b9:47:4d:67:b7:91:e6:10:a2:12:
|
||||||
|
3b:96:d3:8b:4d:1c:ef:12:81:63:97:85:9a:4c:04:d1:4c:da:
|
||||||
|
99:2b:b2:82:66:c1:06:a7:2c:62:af:e2:e4:93:42:36:66:8d:
|
||||||
|
c5:3f:e1:ec:5f:9a:f8:5f:b3:6a:8f:0e:12:5d:c9:46:38:ea:
|
||||||
|
0b:08
|
||||||
|
```
|
||||||
|
|
||||||
|
The resulting file `cert.pem` contains the signed certificate in PEM format. Convert it into DER format and load it into the Pico HSM:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ openssl x509 -in cert.pem -out cert.der -outform der
|
||||||
|
$ pkcs11-tool -l --pin 648219 --write-object cert.der --type cert --id 1
|
||||||
|
Using slot 0 with a present token (0x0)
|
||||||
|
Created certificate:
|
||||||
|
Certificate Object; type = X.509 cert
|
||||||
|
label: Certificate
|
||||||
|
subject: DN: C=ES, ST=Some-State, O=Internet Widgits Pty Ltd, CN=patata.com
|
||||||
|
ID: 01
|
||||||
|
```
|
||||||
|
|
||||||
|
## Generate random numbers
|
||||||
|
|
||||||
|
To generate random numbers:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ pkcs11-tool -l --pin 648219 --generate-random 64 | xxd -c 64 -p
|
||||||
|
Using slot 0 with a present token (0x0)
|
||||||
|
773ec49733435915f5cf056497d97d2b1e6a4af23e2851eb2adf75af40db6677115c401aa26d46677184f4cf878da6289cf3ff1a5192711377b869adbc7f2b6b
|
||||||
|
```
|
||||||
|
|
||||||
|
It supports up to $1024$ random bytes in a single call.
|
||||||
|
|
||||||
|
## Signing and verification
|
||||||
|
|
||||||
|
For signing and verification operations, check [doc/sign-verify.md](/doc/sign-verify.md).
|
||||||
|
|
||||||
|
## Asymmetric encryption and decryption
|
||||||
|
|
||||||
|
For asymmetric encryption and decryption, check [doc/asymmetric-ciphering.md](/doc/asymmetric-ciphering.md).
|
||||||
|
|
||||||
|
## Backup and restore
|
||||||
|
|
||||||
|
For backup, restore and DKEK share management, check [doc/backup-and-restore.md](/doc/backup-and-restore.md).
|
||||||
|
|
||||||
|
## AES operations
|
||||||
|
|
||||||
|
For AES key generation, encryption and decryption, check [doc/aes.md](/doc/aes.md).
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
82
md_wrap.h
82
md_wrap.h
@@ -1,82 +0,0 @@
|
|||||||
/**
|
|
||||||
* \file md_wrap.h
|
|
||||||
*
|
|
||||||
* \brief Message digest wrappers.
|
|
||||||
*
|
|
||||||
* \warning This in an internal header. Do not include directly.
|
|
||||||
*
|
|
||||||
* \author Adriaan de Jong <dejong@fox-it.com>
|
|
||||||
*/
|
|
||||||
/*
|
|
||||||
* Copyright The Mbed TLS Contributors
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
||||||
* not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
#ifndef MBEDTLS_MD_WRAP_H
|
|
||||||
#define MBEDTLS_MD_WRAP_H
|
|
||||||
|
|
||||||
#include "mbedtls/build_info.h"
|
|
||||||
|
|
||||||
#include "mbedtls/md.h"
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Message digest information.
|
|
||||||
* Allows message digest functions to be called in a generic way.
|
|
||||||
*/
|
|
||||||
struct mbedtls_md_info_t
|
|
||||||
{
|
|
||||||
/** Name of the message digest */
|
|
||||||
const char * name;
|
|
||||||
|
|
||||||
/** Digest identifier */
|
|
||||||
mbedtls_md_type_t type;
|
|
||||||
|
|
||||||
/** Output length of the digest function in bytes */
|
|
||||||
unsigned char size;
|
|
||||||
|
|
||||||
/** Block length of the digest function in bytes */
|
|
||||||
unsigned char block_size;
|
|
||||||
};
|
|
||||||
|
|
||||||
#if defined(MBEDTLS_MD5_C)
|
|
||||||
extern const mbedtls_md_info_t mbedtls_md5_info;
|
|
||||||
#endif
|
|
||||||
#if defined(MBEDTLS_RIPEMD160_C)
|
|
||||||
extern const mbedtls_md_info_t mbedtls_ripemd160_info;
|
|
||||||
#endif
|
|
||||||
#if defined(MBEDTLS_SHA1_C)
|
|
||||||
extern const mbedtls_md_info_t mbedtls_sha1_info;
|
|
||||||
#endif
|
|
||||||
#if defined(MBEDTLS_SHA224_C)
|
|
||||||
extern const mbedtls_md_info_t mbedtls_sha224_info;
|
|
||||||
#endif
|
|
||||||
#if defined(MBEDTLS_SHA256_C)
|
|
||||||
extern const mbedtls_md_info_t mbedtls_sha256_info;
|
|
||||||
#endif
|
|
||||||
#if defined(MBEDTLS_SHA384_C)
|
|
||||||
extern const mbedtls_md_info_t mbedtls_sha384_info;
|
|
||||||
#endif
|
|
||||||
#if defined(MBEDTLS_SHA512_C)
|
|
||||||
extern const mbedtls_md_info_t mbedtls_sha512_info;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* MBEDTLS_MD_WRAP_H */
|
|
||||||
279
neug.c
279
neug.c
@@ -1,279 +0,0 @@
|
|||||||
/*
|
|
||||||
* neug.c - true random number generation
|
|
||||||
*
|
|
||||||
* Copyright (C) 2011, 2012, 2013, 2016, 2017, 2018
|
|
||||||
* Free Software Initiative of Japan
|
|
||||||
* Author: NIIBE Yutaka <gniibe@fsij.org>
|
|
||||||
*
|
|
||||||
* This file is a part of NeuG, a True Random Number Generator
|
|
||||||
* implementation based on quantization error of ADC (for STM32F103).
|
|
||||||
*
|
|
||||||
* NeuG is free software: you can redistribute it and/or modify it
|
|
||||||
* under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* NeuG is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
||||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
|
||||||
* License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include "pico/stdlib.h"
|
|
||||||
//#include <chopstx.h>
|
|
||||||
|
|
||||||
#include "sys.h"
|
|
||||||
#include "neug.h"
|
|
||||||
//#include "adc.h"
|
|
||||||
#include "gnuk.h"
|
|
||||||
#include "hardware/structs/rosc.h"
|
|
||||||
#include "hardware/gpio.h"
|
|
||||||
#include "hardware/adc.h"
|
|
||||||
#include "bsp/board.h"
|
|
||||||
|
|
||||||
void adc_start ()
|
|
||||||
{
|
|
||||||
adc_init();
|
|
||||||
adc_gpio_init(27);
|
|
||||||
adc_select_input(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
adc_stop (void)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint64_t random_word = 0xcbf29ce484222325;
|
|
||||||
static uint8_t ep_round = 0;
|
|
||||||
|
|
||||||
static void ep_init (int mode)
|
|
||||||
{
|
|
||||||
random_word = 0xcbf29ce484222325;
|
|
||||||
ep_round = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Here, we assume a little endian architecture. */
|
|
||||||
static int ep_process (int mode)
|
|
||||||
{
|
|
||||||
if (ep_round == 0)
|
|
||||||
{
|
|
||||||
ep_init(mode);
|
|
||||||
}
|
|
||||||
uint64_t word = 0x0;
|
|
||||||
for (int n = 0; n < 64; n++) {
|
|
||||||
uint8_t bit1, bit2;
|
|
||||||
do
|
|
||||||
{
|
|
||||||
bit1 = rosc_hw->randombit&0xff;
|
|
||||||
//sleep_ms(1);
|
|
||||||
bit2 = rosc_hw->randombit&0xff;
|
|
||||||
} while(bit1 == bit2);
|
|
||||||
word = (word << 1) | bit1;
|
|
||||||
}
|
|
||||||
random_word ^= word^board_millis()^adc_read();
|
|
||||||
random_word *= 0x00000100000001B3;
|
|
||||||
if (++ep_round == 8)
|
|
||||||
{
|
|
||||||
ep_round = 0;
|
|
||||||
return 2; //2 words
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const uint32_t *ep_output (int mode)
|
|
||||||
{
|
|
||||||
(void) mode;
|
|
||||||
return (uint32_t *)&random_word;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Ring buffer, filled by generator, consumed by neug_get routine.
|
|
||||||
*/
|
|
||||||
struct rng_rb {
|
|
||||||
uint32_t *buf;
|
|
||||||
//chopstx_mutex_t m;
|
|
||||||
//chopstx_cond_t data_available;
|
|
||||||
//chopstx_cond_t space_available;
|
|
||||||
uint8_t head, tail;
|
|
||||||
uint8_t size;
|
|
||||||
unsigned int full :1;
|
|
||||||
unsigned int empty :1;
|
|
||||||
};
|
|
||||||
|
|
||||||
static void rb_init (struct rng_rb *rb, uint32_t *p, uint8_t size)
|
|
||||||
{
|
|
||||||
rb->buf = p;
|
|
||||||
rb->size = size;
|
|
||||||
//chopstx_mutex_init (&rb->m);
|
|
||||||
//chopstx_cond_init (&rb->data_available);
|
|
||||||
//chopstx_cond_init (&rb->space_available);
|
|
||||||
rb->head = rb->tail = 0;
|
|
||||||
rb->full = 0;
|
|
||||||
rb->empty = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void rb_add (struct rng_rb *rb, uint32_t v)
|
|
||||||
{
|
|
||||||
rb->buf[rb->tail++] = v;
|
|
||||||
if (rb->tail == rb->size)
|
|
||||||
rb->tail = 0;
|
|
||||||
if (rb->tail == rb->head)
|
|
||||||
rb->full = 1;
|
|
||||||
rb->empty = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint32_t rb_del (struct rng_rb *rb)
|
|
||||||
{
|
|
||||||
uint32_t v = rb->buf[rb->head++];
|
|
||||||
|
|
||||||
if (rb->head == rb->size)
|
|
||||||
rb->head = 0;
|
|
||||||
if (rb->head == rb->tail)
|
|
||||||
rb->empty = 1;
|
|
||||||
rb->full = 0;
|
|
||||||
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t neug_mode;
|
|
||||||
static int rng_should_terminate;
|
|
||||||
|
|
||||||
static struct rng_rb the_ring_buffer;
|
|
||||||
//static chopstx_t rng_thread;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Random number generation thread.
|
|
||||||
*/
|
|
||||||
void *neug_task ()
|
|
||||||
{
|
|
||||||
struct rng_rb *rb = &the_ring_buffer;
|
|
||||||
int mode = neug_mode;
|
|
||||||
|
|
||||||
rng_should_terminate = 0;
|
|
||||||
//chopstx_mutex_init (&mode_mtx);
|
|
||||||
//chopstx_cond_init (&mode_cond);
|
|
||||||
|
|
||||||
//while (!rng_should_terminate)
|
|
||||||
{
|
|
||||||
int n;
|
|
||||||
|
|
||||||
if ((n = ep_process (mode)))
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
const uint32_t *vp;
|
|
||||||
|
|
||||||
vp = ep_output (mode);
|
|
||||||
|
|
||||||
//chopstx_mutex_lock (&rb->m);
|
|
||||||
//while (rb->full)
|
|
||||||
//chopstx_cond_wait (&rb->space_available, &rb->m);
|
|
||||||
|
|
||||||
for (i = 0; i < n; i++)
|
|
||||||
{
|
|
||||||
rb_add (rb, *vp++);
|
|
||||||
if (rb->full)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
//chopstx_cond_signal (&rb->data_available);
|
|
||||||
//chopstx_mutex_unlock (&rb->m);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//adc_stop ();
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Initialize NeuG.
|
|
||||||
*/
|
|
||||||
void neug_init (uint32_t *buf, uint8_t size)
|
|
||||||
{
|
|
||||||
const uint32_t *u = (const uint32_t *)unique_device_id ();
|
|
||||||
struct rng_rb *rb = &the_ring_buffer;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This initialization ensures that it generates different sequence
|
|
||||||
* even if all physical conditions are same.
|
|
||||||
*/
|
|
||||||
|
|
||||||
neug_mode = NEUG_MODE_CONDITIONED;
|
|
||||||
rb_init (rb, buf, size);
|
|
||||||
|
|
||||||
/* Enable ADCs */
|
|
||||||
adc_start ();
|
|
||||||
|
|
||||||
ep_init (neug_mode);
|
|
||||||
|
|
||||||
//rng_thread = chopstx_create (PRIO_RNG, STACK_ADDR_RNG, STACK_SIZE_RNG,
|
|
||||||
// rng, rb);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @breif Flush random bytes.
|
|
||||||
*/
|
|
||||||
void neug_flush (void)
|
|
||||||
{
|
|
||||||
struct rng_rb *rb = &the_ring_buffer;
|
|
||||||
|
|
||||||
//chopstx_mutex_lock (&rb->m);
|
|
||||||
while (!rb->empty)
|
|
||||||
rb_del (rb);
|
|
||||||
//chopstx_cond_signal (&rb->space_available);
|
|
||||||
//chopstx_mutex_unlock (&rb->m);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Get random word (32-bit) from NeuG.
|
|
||||||
* @detail With NEUG_KICK_FILLING, it wakes up RNG thread.
|
|
||||||
* With NEUG_NO_KICK, it doesn't wake up RNG thread automatically,
|
|
||||||
* it is needed to call neug_kick_filling later.
|
|
||||||
*/
|
|
||||||
uint32_t neug_get (int kick)
|
|
||||||
{
|
|
||||||
struct rng_rb *rb = &the_ring_buffer;
|
|
||||||
uint32_t v;
|
|
||||||
|
|
||||||
//chopstx_mutex_lock (&rb->m);
|
|
||||||
while (rb->empty)
|
|
||||||
neug_task(); //chopstx_cond_wait (&rb->data_available, &rb->m);
|
|
||||||
v = rb_del (rb);
|
|
||||||
//if (kick)
|
|
||||||
//chopstx_cond_signal (&rb->space_available);
|
|
||||||
//chopstx_mutex_unlock (&rb->m);
|
|
||||||
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
|
|
||||||
void neug_wait_full (void) //should be called only on core1
|
|
||||||
{
|
|
||||||
struct rng_rb *rb = &the_ring_buffer;
|
|
||||||
|
|
||||||
//chopstx_mutex_lock (&rb->m);
|
|
||||||
while (!rb->full) {
|
|
||||||
//neug_task(); //chopstx_cond_wait (&rb->data_available, &rb->m);
|
|
||||||
sleep_ms(1);
|
|
||||||
}
|
|
||||||
//chopstx_mutex_unlock (&rb->m);
|
|
||||||
}
|
|
||||||
|
|
||||||
void neug_fini (void)
|
|
||||||
{
|
|
||||||
rng_should_terminate = 1;
|
|
||||||
neug_get (1);
|
|
||||||
//chopstx_join (rng_thread, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
14
neug.h
14
neug.h
@@ -1,14 +0,0 @@
|
|||||||
#define NEUG_NO_KICK 0
|
|
||||||
#define NEUG_KICK_FILLING 1
|
|
||||||
|
|
||||||
#define NEUG_PRE_LOOP 32
|
|
||||||
|
|
||||||
#define NEUG_MODE_CONDITIONED 0 /* Conditioned data. */
|
|
||||||
#define NEUG_MODE_RAW 1 /* CRC-32 filtered sample data. */
|
|
||||||
#define NEUG_MODE_RAW_DATA 2 /* Sample data directly. */
|
|
||||||
|
|
||||||
void neug_init (uint32_t *buf, uint8_t size);
|
|
||||||
uint32_t neug_get (int kick);
|
|
||||||
void neug_flush (void);
|
|
||||||
void neug_wait_full (void);
|
|
||||||
void neug_fini (void);
|
|
||||||
120
padlock.h
120
padlock.h
@@ -1,120 +0,0 @@
|
|||||||
/**
|
|
||||||
* \file padlock.h
|
|
||||||
*
|
|
||||||
* \brief VIA PadLock ACE for HW encryption/decryption supported by some
|
|
||||||
* processors
|
|
||||||
*
|
|
||||||
* \warning These functions are only for internal use by other library
|
|
||||||
* functions; you must not call them directly.
|
|
||||||
*/
|
|
||||||
/*
|
|
||||||
* Copyright The Mbed TLS Contributors
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
||||||
* not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
#ifndef MBEDTLS_PADLOCK_H
|
|
||||||
#define MBEDTLS_PADLOCK_H
|
|
||||||
|
|
||||||
#include "mbedtls/build_info.h"
|
|
||||||
|
|
||||||
#include "mbedtls/aes.h"
|
|
||||||
|
|
||||||
#define MBEDTLS_ERR_PADLOCK_DATA_MISALIGNED -0x0030 /**< Input data should be aligned. */
|
|
||||||
|
|
||||||
#if defined(__has_feature)
|
|
||||||
#if __has_feature(address_sanitizer)
|
|
||||||
#define MBEDTLS_HAVE_ASAN
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Some versions of ASan result in errors about not enough registers */
|
|
||||||
#if defined(MBEDTLS_HAVE_ASM) && defined(__GNUC__) && defined(__i386__) && \
|
|
||||||
!defined(MBEDTLS_HAVE_ASAN)
|
|
||||||
|
|
||||||
#ifndef MBEDTLS_HAVE_X86
|
|
||||||
#define MBEDTLS_HAVE_X86
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
#define MBEDTLS_PADLOCK_RNG 0x000C
|
|
||||||
#define MBEDTLS_PADLOCK_ACE 0x00C0
|
|
||||||
#define MBEDTLS_PADLOCK_PHE 0x0C00
|
|
||||||
#define MBEDTLS_PADLOCK_PMM 0x3000
|
|
||||||
|
|
||||||
#define MBEDTLS_PADLOCK_ALIGN16(x) (uint32_t *) (16 + ((int32_t) (x) & ~15))
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Internal PadLock detection routine
|
|
||||||
*
|
|
||||||
* \note This function is only for internal use by other library
|
|
||||||
* functions; you must not call it directly.
|
|
||||||
*
|
|
||||||
* \param feature The feature to detect
|
|
||||||
*
|
|
||||||
* \return non-zero if CPU has support for the feature, 0 otherwise
|
|
||||||
*/
|
|
||||||
int mbedtls_padlock_has_support( int feature );
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Internal PadLock AES-ECB block en(de)cryption
|
|
||||||
*
|
|
||||||
* \note This function is only for internal use by other library
|
|
||||||
* functions; you must not call it directly.
|
|
||||||
*
|
|
||||||
* \param ctx AES context
|
|
||||||
* \param mode MBEDTLS_AES_ENCRYPT or MBEDTLS_AES_DECRYPT
|
|
||||||
* \param input 16-byte input block
|
|
||||||
* \param output 16-byte output block
|
|
||||||
*
|
|
||||||
* \return 0 if success, 1 if operation failed
|
|
||||||
*/
|
|
||||||
int mbedtls_padlock_xcryptecb( mbedtls_aes_context *ctx,
|
|
||||||
int mode,
|
|
||||||
const unsigned char input[16],
|
|
||||||
unsigned char output[16] );
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Internal PadLock AES-CBC buffer en(de)cryption
|
|
||||||
*
|
|
||||||
* \note This function is only for internal use by other library
|
|
||||||
* functions; you must not call it directly.
|
|
||||||
*
|
|
||||||
* \param ctx AES context
|
|
||||||
* \param mode MBEDTLS_AES_ENCRYPT or MBEDTLS_AES_DECRYPT
|
|
||||||
* \param length length of the input data
|
|
||||||
* \param iv initialization vector (updated after use)
|
|
||||||
* \param input buffer holding the input data
|
|
||||||
* \param output buffer holding the output data
|
|
||||||
*
|
|
||||||
* \return 0 if success, 1 if operation failed
|
|
||||||
*/
|
|
||||||
int mbedtls_padlock_xcryptcbc( mbedtls_aes_context *ctx,
|
|
||||||
int mode,
|
|
||||||
size_t length,
|
|
||||||
unsigned char iv[16],
|
|
||||||
const unsigned char *input,
|
|
||||||
unsigned char *output );
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* HAVE_X86 */
|
|
||||||
|
|
||||||
#endif /* padlock.h */
|
|
||||||
@@ -1,7 +1,27 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
|
#
|
||||||
|
# This file is part of the Pico HSM distribution (https://github.com/polhenarejos/pico-hsm).
|
||||||
|
# Copyright (c) 2022 Pol Henarejos.
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, version 3.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful, but
|
||||||
|
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
# General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
|
||||||
|
VERSION_MAJOR="1"
|
||||||
|
VERSION_MINOR="0C"
|
||||||
|
|
||||||
echo "----------------------------"
|
echo "----------------------------"
|
||||||
echo "VID/PID patcher for HSM 2040"
|
echo "VID/PID patcher for Pico HSM"
|
||||||
echo "----------------------------"
|
echo "----------------------------"
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
@@ -64,13 +84,10 @@ if [ "$UF2_FILE_IF" != "$UF2_FILE_OF" ]; then
|
|||||||
cp -R $UF2_FILE_IF $UF2_FILE_OF
|
cp -R $UF2_FILE_IF $UF2_FILE_OF
|
||||||
fi
|
fi
|
||||||
|
|
||||||
BASE_ADDRESS=`xxd "$UF2_FILE_IF" | grep "fffe fdfc 0103 0102 0301" | cut -d " " -f1`
|
|
||||||
ADDRESS="0x${BASE_ADDRESS%?}"
|
|
||||||
|
|
||||||
LITTLE_VID="\x${VID:2:2}\x${VID:0:2}"
|
LITTLE_VID="\x${VID:2:2}\x${VID:0:2}"
|
||||||
LITTLE_PID="\x${PID:2:2}\x${PID:0:2}"
|
LITTLE_PID="\x${PID:2:2}\x${PID:0:2}"
|
||||||
|
|
||||||
printf "$LITTLE_VID$LITTLE_PID" | dd of="$UF2_FILE_OF" bs=1 seek=$(($ADDRESS)) conv=notrunc 2> /dev/null
|
perl -pi -e "s/\xff\xfe\xfd\xfc\x$VERSION_MINOR\x$VERSION_MAJOR\x01\x02\x03\x01/$LITTLE_VID$LITTLE_PID\x$VERSION_MINOR\x$VERSION_MAJOR\x01\x02\x03\x01/" $UF2_FILE_OF
|
||||||
|
|
||||||
echo "Done!"
|
echo "Done!"
|
||||||
echo ""
|
echo ""
|
||||||
|
|||||||
121
random.c
121
random.c
@@ -1,121 +0,0 @@
|
|||||||
/*
|
|
||||||
* random.c -- get random bytes
|
|
||||||
*
|
|
||||||
* Copyright (C) 2010, 2011, 2012, 2013, 2015
|
|
||||||
* Free Software Initiative of Japan
|
|
||||||
* Author: NIIBE Yutaka <gniibe@fsij.org>
|
|
||||||
*
|
|
||||||
* This file is a part of Gnuk, a GnuPG USB Token implementation.
|
|
||||||
*
|
|
||||||
* Gnuk is free software: you can redistribute it and/or modify it
|
|
||||||
* under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* Gnuk is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
||||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
|
||||||
* License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include "gnuk.h"
|
|
||||||
#include "neug.h"
|
|
||||||
|
|
||||||
#define RANDOM_BYTES_LENGTH 32
|
|
||||||
static uint32_t random_word[RANDOM_BYTES_LENGTH/sizeof (uint32_t)];
|
|
||||||
|
|
||||||
void random_init (void)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
neug_init (random_word, RANDOM_BYTES_LENGTH/sizeof (uint32_t));
|
|
||||||
|
|
||||||
for (i = 0; i < NEUG_PRE_LOOP; i++)
|
|
||||||
neug_get (NEUG_KICK_FILLING);
|
|
||||||
}
|
|
||||||
|
|
||||||
void random_fini (void)
|
|
||||||
{
|
|
||||||
neug_fini ();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Return pointer to random 32-byte
|
|
||||||
*/
|
|
||||||
void random_bytes_free (const uint8_t *p);
|
|
||||||
const uint8_t * random_bytes_get (size_t len)
|
|
||||||
{
|
|
||||||
static uint32_t return_word[512/sizeof(uint32_t)];
|
|
||||||
for (int ix = 0; ix < len; ix += RANDOM_BYTES_LENGTH) {
|
|
||||||
neug_wait_full ();
|
|
||||||
memcpy(return_word+ix/sizeof(uint32_t), random_word, RANDOM_BYTES_LENGTH);
|
|
||||||
random_bytes_free((const uint8_t *)random_word);
|
|
||||||
}
|
|
||||||
return (const uint8_t *)return_word;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Free pointer to random 32-byte
|
|
||||||
*/
|
|
||||||
void random_bytes_free (const uint8_t *p)
|
|
||||||
{
|
|
||||||
(void)p;
|
|
||||||
memset (random_word, 0, RANDOM_BYTES_LENGTH);
|
|
||||||
neug_flush ();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Return 4-byte salt
|
|
||||||
*/
|
|
||||||
void random_get_salt (uint8_t *p)
|
|
||||||
{
|
|
||||||
uint32_t rnd;
|
|
||||||
|
|
||||||
rnd = neug_get (NEUG_KICK_FILLING);
|
|
||||||
memcpy (p, &rnd, sizeof (uint32_t));
|
|
||||||
rnd = neug_get (NEUG_KICK_FILLING);
|
|
||||||
memcpy (p + sizeof (uint32_t), &rnd, sizeof (uint32_t));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Random byte iterator
|
|
||||||
*/
|
|
||||||
int random_gen (void *arg, unsigned char *out, size_t out_len)
|
|
||||||
{
|
|
||||||
uint8_t *index_p = (uint8_t *)arg;
|
|
||||||
uint8_t index = index_p ? *index_p : 0;
|
|
||||||
size_t n;
|
|
||||||
|
|
||||||
while (out_len)
|
|
||||||
{
|
|
||||||
neug_wait_full ();
|
|
||||||
|
|
||||||
n = RANDOM_BYTES_LENGTH - index;
|
|
||||||
if (n > out_len)
|
|
||||||
n = out_len;
|
|
||||||
|
|
||||||
memcpy (out, ((unsigned char *)random_word) + index, n);
|
|
||||||
out += n;
|
|
||||||
out_len -= n;
|
|
||||||
index += n;
|
|
||||||
|
|
||||||
if (index >= RANDOM_BYTES_LENGTH)
|
|
||||||
{
|
|
||||||
index = 0;
|
|
||||||
neug_flush ();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (index_p)
|
|
||||||
*index_p = index;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
12
random.h
12
random.h
@@ -1,12 +0,0 @@
|
|||||||
void random_init (void);
|
|
||||||
void random_fini (void);
|
|
||||||
|
|
||||||
/* 32-byte random bytes */
|
|
||||||
const uint8_t *random_bytes_get (size_t);
|
|
||||||
void random_bytes_free (const uint8_t *p);
|
|
||||||
|
|
||||||
/* 8-byte salt */
|
|
||||||
void random_get_salt (uint8_t *p);
|
|
||||||
|
|
||||||
/* iterator returning a byta at a time */
|
|
||||||
int random_gen (void *arg, unsigned char *output, size_t output_len);
|
|
||||||
@@ -1,5 +1,21 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the Pico HSM distribution (https://github.com/polhenarejos/pico-hsm).
|
||||||
|
* Copyright (c) 2022 Pol Henarejos.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
#include "file.h"
|
#include "file.h"
|
||||||
#include "gnuk.h"
|
|
||||||
#include "tusb.h"
|
#include "tusb.h"
|
||||||
#include "hsm2040.h"
|
#include "hsm2040.h"
|
||||||
#include "sc_hsm.h"
|
#include "sc_hsm.h"
|
||||||
@@ -62,55 +78,15 @@ void process_fci(const file_t *pe) {
|
|||||||
res_APDU[1] = res_APDU_size-2;
|
res_APDU[1] = res_APDU_size-2;
|
||||||
}
|
}
|
||||||
|
|
||||||
const uint8_t cvca[] = {
|
|
||||||
0x6A, 0x01,
|
|
||||||
0x7f, 0x21, 0x82, 0x01, 0x65, 0x7f, 0x4e, 0x82, 0x01, 0x2d, 0x5f,
|
|
||||||
0x29, 0x01, 0x00, 0x42, 0x0e, 0x45, 0x53, 0x48, 0x53, 0x4d, 0x43,
|
|
||||||
0x56, 0x43, 0x41, 0x32, 0x30, 0x34, 0x30, 0x31, 0x7f, 0x49, 0x81,
|
|
||||||
0xdd, 0x06, 0x0a, 0x04, 0x00, 0x7f, 0x00, 0x07, 0x02, 0x02, 0x02,
|
|
||||||
0x02, 0x03, 0x81, 0x18, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x82, 0x18, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x83,
|
|
||||||
0x18, 0x64, 0x21, 0x05, 0x19, 0xe5, 0x9c, 0x80, 0xe7, 0x0f, 0xa7,
|
|
||||||
0xe9, 0xab, 0x72, 0x24, 0x30, 0x49, 0xfe, 0xb8, 0xde, 0xec, 0xc1,
|
|
||||||
0x46, 0xb9, 0xb1, 0x84, 0x31, 0x04, 0x18, 0x8d, 0xa8, 0x0e, 0xb0,
|
|
||||||
0x30, 0x90, 0xf6, 0x7c, 0xbf, 0x20, 0xeb, 0x43, 0xa1, 0x88, 0x00,
|
|
||||||
0xf4, 0xff, 0x0a, 0xfd, 0x82, 0xff, 0x10, 0x12, 0x07, 0x19, 0x2b,
|
|
||||||
0x95, 0xff, 0xc8, 0xda, 0x78, 0x63, 0x10, 0x11, 0xed, 0x6b, 0x24,
|
|
||||||
0xcd, 0xd5, 0x73, 0xf9, 0x77, 0xa1, 0x1e, 0x79, 0x48, 0x11, 0x85,
|
|
||||||
0x18, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0xff, 0x99, 0xde, 0xf8, 0x36, 0x14, 0x6b, 0xc9, 0xb1, 0xb4,
|
|
||||||
0xd2, 0x28, 0x31, 0x86, 0x31, 0x04, 0x4d, 0x28, 0x34, 0x67, 0xb5,
|
|
||||||
0x43, 0xfd, 0x84, 0x22, 0x09, 0xbd, 0xd2, 0xd6, 0x26, 0x27, 0x2d,
|
|
||||||
0x53, 0xa7, 0xdf, 0x52, 0x8f, 0xc2, 0xde, 0x7c, 0x9a, 0xcd, 0x1f,
|
|
||||||
0xf2, 0x10, 0x42, 0x7c, 0x13, 0x44, 0x03, 0xb0, 0xa5, 0xdf, 0x8a,
|
|
||||||
0xd4, 0x59, 0xd1, 0x86, 0x4b, 0xde, 0x33, 0xb1, 0x60, 0x17, 0x87,
|
|
||||||
0x01, 0x01, 0x5f, 0x20, 0x0e, 0x45, 0x53, 0x48, 0x53, 0x4d, 0x43,
|
|
||||||
0x56, 0x43, 0x41, 0x32, 0x30, 0x34, 0x30, 0x31, 0x7f, 0x4c, 0x12,
|
|
||||||
0x06, 0x09, 0x04, 0x00, 0x7f, 0x00, 0x07, 0x03, 0x01, 0x02, 0x02,
|
|
||||||
0x53, 0x05, 0xc0, 0x00, 0x00, 0x00, 0x04, 0x5f, 0x25, 0x06, 0x02,
|
|
||||||
0x02, 0x00, 0x02, 0x01, 0x09, 0x5f, 0x24, 0x06, 0x03, 0x00, 0x01,
|
|
||||||
0x02, 0x03, 0x01, 0x5f, 0x37, 0x30, 0x26, 0x2d, 0x6f, 0xa6, 0xd0,
|
|
||||||
0x52, 0x01, 0xf1, 0x41, 0x1e, 0xe9, 0x33, 0x29, 0x19, 0x42, 0x42,
|
|
||||||
0x9b, 0xb0, 0xeb, 0xf7, 0x46, 0x20, 0xcb, 0x81, 0xfe, 0xda, 0xd7,
|
|
||||||
0xab, 0x2b, 0xdc, 0xa7, 0x38, 0xf4, 0xc8, 0xec, 0x4c, 0x66, 0xb4,
|
|
||||||
0x0a, 0x2d, 0x16, 0xfb, 0xf3, 0x79, 0xe9, 0x93, 0xc8, 0x25
|
|
||||||
};
|
|
||||||
const uint8_t token_info[] = {
|
|
||||||
0x28, 0x00, //litle endian
|
|
||||||
0x30, 0x26, 0x2, 0x1, 0x1, 0x4, 0x4, 0xd, 0x0, 0x0, 0x0, 0xc, 0xd, 0x50, 0x6f, 0x6c, 0x20, 0x48, 0x65, 0x6e, 0x61, 0x72, 0x65, 0x6a, 0x6f, 0x73, 0x80, 0x8, 0x48, 0x53, 0x4d, 0x20, 0x32, 0x30, 0x34, 0x30, 0x3, 0x2, 0x4, 0xf0
|
|
||||||
};
|
|
||||||
|
|
||||||
extern const uint8_t sc_hsm_aid[];
|
extern const uint8_t sc_hsm_aid[];
|
||||||
extern int parse_token_info(const file_t *f, int mode);
|
extern int parse_token_info(const file_t *f, int mode);
|
||||||
|
extern int parse_cvca(const file_t *f, int mode);
|
||||||
|
|
||||||
file_t file_entries[] = {
|
file_t file_entries[] = {
|
||||||
/* 0 */ { .fid = 0x3f00 , .parent = 0xff, .name = NULL, .type = FILE_TYPE_DF, .data = NULL, .ef_structure = 0, .acl = {0} }, // MF
|
/* 0 */ { .fid = 0x3f00 , .parent = 0xff, .name = NULL, .type = FILE_TYPE_DF, .data = NULL, .ef_structure = 0, .acl = {0} }, // MF
|
||||||
/* 1 */ { .fid = 0x2f00 , .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.DIR
|
/* 1 */ { .fid = 0x2f00 , .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.DIR
|
||||||
/* 2 */ { .fid = 0x2f01 , .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.ATR
|
/* 2 */ { .fid = 0x2f01 , .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.ATR
|
||||||
/* 3 */ { .fid = 0x2f02 , .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF,.data = (uint8_t *)cvca, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.GDO
|
/* 3 */ { .fid = 0x2f02 , .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF | FILE_DATA_FUNC,.data = (uint8_t *)parse_cvca, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.GDO
|
||||||
/* 4 */ { .fid = 0x2f03 , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF | FILE_DATA_FUNC,.data = (uint8_t *)parse_token_info, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.TokenInfo
|
/* 4 */ { .fid = 0x2f03 , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF | FILE_DATA_FUNC,.data = (uint8_t *)parse_token_info, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.TokenInfo
|
||||||
/* 5 */ { .fid = 0x5015 , .parent = 0, .name = NULL, .type = FILE_TYPE_DF, .data = NULL, .ef_structure = 0, .acl = {0} }, //DF.PKCS15
|
/* 5 */ { .fid = 0x5015 , .parent = 0, .name = NULL, .type = FILE_TYPE_DF, .data = NULL, .ef_structure = 0, .acl = {0} }, //DF.PKCS15
|
||||||
/* 6 */ { .fid = 0x5031 , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.ODF
|
/* 6 */ { .fid = 0x5031 , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.ODF
|
||||||
@@ -123,15 +99,16 @@ file_t file_entries[] = {
|
|||||||
/* 13 */ { .fid = 0x1089 , .parent = 5, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff} }, //max retries PIN (SOPIN)
|
/* 13 */ { .fid = 0x1089 , .parent = 5, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff} }, //max retries PIN (SOPIN)
|
||||||
/* 14 */ { .fid = 0x108A , .parent = 5, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff} }, //retries PIN (SOPIN)
|
/* 14 */ { .fid = 0x108A , .parent = 5, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff} }, //retries PIN (SOPIN)
|
||||||
/* 15 */ { .fid = EF_DKEK , .parent = 5, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff} }, //DKEK
|
/* 15 */ { .fid = EF_DKEK , .parent = 5, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff} }, //DKEK
|
||||||
/* 16 */ { .fid = EF_PRKDFS , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.PrKDFs
|
/* 16 */ { .fid = EF_DEVOPS , .parent = 5, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff} }, //Device options
|
||||||
/* 17 */ { .fid = EF_PUKDFS , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.PuKDFs
|
/* 17 */ { .fid = EF_PRKDFS , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.PrKDFs
|
||||||
/* 18 */ { .fid = EF_CDFS , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.CDFs
|
/* 18 */ { .fid = EF_PUKDFS , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.PuKDFs
|
||||||
/* 19 */ { .fid = EF_AODFS , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.AODFs
|
/* 19 */ { .fid = EF_CDFS , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.CDFs
|
||||||
/* 20 */ { .fid = EF_DODFS , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.DODFs
|
/* 20 */ { .fid = EF_AODFS , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.AODFs
|
||||||
/* 21 */ { .fid = EF_SKDFS , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.SKDFs
|
/* 21 */ { .fid = EF_DODFS , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.DODFs
|
||||||
///* 22 */ { .fid = 0x0000, .parent = 0, .name = openpgpcard_aid, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} },
|
/* 22 */ { .fid = EF_SKDFS , .parent = 5, .name = NULL, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} }, //EF.SKDFs
|
||||||
/* 23 */ { .fid = 0x0000, .parent = 5, .name = sc_hsm_aid, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} },
|
///* 23 */ { .fid = 0x0000, .parent = 0, .name = openpgpcard_aid, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} },
|
||||||
/* 24 */ { .fid = 0x0000, .parent = 0xff, .name = NULL, .type = FILE_TYPE_UNKNOWN, .data = NULL, .ef_structure = 0, .acl = {0} } //end
|
/* 24 */ { .fid = 0x0000, .parent = 5, .name = sc_hsm_aid, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} },
|
||||||
|
/* 25 */ { .fid = 0x0000, .parent = 0xff, .name = NULL, .type = FILE_TYPE_UNKNOWN, .data = NULL, .ef_structure = 0, .acl = {0} } //end
|
||||||
};
|
};
|
||||||
|
|
||||||
const file_t *MF = &file_entries[0];
|
const file_t *MF = &file_entries[0];
|
||||||
@@ -280,29 +257,18 @@ void scan_flash() {
|
|||||||
if (base == 0x0) //all is empty
|
if (base == 0x0) //all is empty
|
||||||
break;
|
break;
|
||||||
|
|
||||||
uint16_t fid = flash_read_uint16(base+sizeof(uintptr_t));
|
uint16_t fid = flash_read_uint16(base+sizeof(uintptr_t)+sizeof(uintptr_t));
|
||||||
printf("scan fid %x\r\n",fid);
|
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 ((fid & 0xff00) == (KEY_PREFIX << 8)) {
|
uint8_t pfx = fid >> 8;
|
||||||
//add_file_to_chain(file, &ef_kf);
|
if (pfx != KEY_PREFIX && pfx != PRKD_PREFIX && pfx != CD_PREFIX && pfx != EE_CERTIFICATE_PREFIX && pfx != DCOD_PREFIX && pfx != PROT_DATA_PREFIX && pfx != DATA_PREFIX) {
|
||||||
}
|
|
||||||
else if ((fid & 0xff00) == (PRKD_PREFIX << 8)) {
|
|
||||||
//add_file_to_chain(file, &ef_prkdf);
|
|
||||||
}
|
|
||||||
else if ((fid & 0xff00) == (CD_PREFIX << 8)) {
|
|
||||||
//add_file_to_chain(file, &ef_cdf);
|
|
||||||
}
|
|
||||||
else if ((fid & 0xff00) == (EE_CERTIFICATE_PREFIX << 8)) {
|
|
||||||
//add_file_to_chain(file, &ef_pukdf);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
TU_LOG1("SCAN FOUND ORPHAN FILE: %x\r\n",fid);
|
TU_LOG1("SCAN FOUND ORPHAN FILE: %x\r\n",fid);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
file->data = (uint8_t *)(base+sizeof(uintptr_t)+sizeof(uint16_t));
|
file->data = (uint8_t *)(base+sizeof(uintptr_t)+sizeof(uintptr_t)+sizeof(uint16_t));
|
||||||
if (flash_read_uintptr(base) == 0x0) {
|
if (flash_read_uintptr(base) == 0x0) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -1,3 +1,21 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the Pico HSM distribution (https://github.com/polhenarejos/pico-hsm).
|
||||||
|
* Copyright (c) 2022 Pol Henarejos.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
#ifndef _FILE_H_
|
#ifndef _FILE_H_
|
||||||
#define _FILE_H_
|
#define _FILE_H_
|
||||||
|
|
||||||
@@ -42,6 +60,7 @@
|
|||||||
#define EF_AODFS 0x6043
|
#define EF_AODFS 0x6043
|
||||||
#define EF_DODFS 0x6044
|
#define EF_DODFS 0x6044
|
||||||
#define EF_SKDFS 0x6045
|
#define EF_SKDFS 0x6045
|
||||||
|
#define EF_DEVOPS 0x100E
|
||||||
|
|
||||||
#define MAX_DEPTH 4
|
#define MAX_DEPTH 4
|
||||||
|
|
||||||
@@ -1,43 +1,24 @@
|
|||||||
/*
|
/*
|
||||||
* flash.c -- Data Objects (DO) and GPG Key handling on Flash ROM
|
* This file is part of the Pico HSM distribution (https://github.com/polhenarejos/pico-hsm).
|
||||||
|
* Copyright (c) 2022 Pol Henarejos.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* Free Software Initiative of Japan
|
* it under the terms of the GNU General Public License as published by
|
||||||
* Author: NIIBE Yutaka <gniibe@fsij.org>
|
* the Free Software Foundation, version 3.
|
||||||
*
|
*
|
||||||
* This file is a part of Gnuk, a GnuPG USB Token implementation.
|
* This program is distributed in the hope that it will be useful, but
|
||||||
*
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* Gnuk is free software: you can redistribute it and/or modify it
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* under the terms of the GNU General Public License as published by
|
* General Public License for more details.
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* Gnuk is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
||||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
|
||||||
* License for more details.
|
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
|
||||||
* We assume single DO size is less than 256.
|
|
||||||
*
|
|
||||||
* NOTE: "Card holder certificate" (which size is larger than 256) is
|
|
||||||
* not put into data pool, but is implemented by its own flash
|
|
||||||
* page(s).
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
|
|
||||||
#include "sys.h"
|
|
||||||
#include "gnuk.h"
|
|
||||||
|
|
||||||
#include "pico/stdlib.h"
|
#include "pico/stdlib.h"
|
||||||
#include "hardware/flash.h"
|
#include "hardware/flash.h"
|
||||||
#include "hsm2040.h"
|
#include "hsm2040.h"
|
||||||
@@ -45,10 +26,17 @@
|
|||||||
#include "file.h"
|
#include "file.h"
|
||||||
#include "sc_hsm.h"
|
#include "sc_hsm.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ------------------------------------------------------
|
||||||
|
* | |
|
||||||
|
* | next_addr | prev_addr | fid | data (len + payload) |
|
||||||
|
* | |
|
||||||
|
* ------------------------------------------------------
|
||||||
|
*/
|
||||||
#define FLASH_TARGET_OFFSET (PICO_FLASH_SIZE_BYTES >> 1) // DATA starts at the mid of flash
|
#define FLASH_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))
|
||||||
|
|
||||||
//To avoid possible future allocations, data region starts at the begining 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
|
||||||
|
|
||||||
const uintptr_t start_data_pool = (XIP_BASE + FLASH_TARGET_OFFSET);
|
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; //This is a fixed value. DO NOT CHANGE
|
const uintptr_t end_data_pool = (XIP_BASE + PICO_FLASH_SIZE_BYTES)-FLASH_DATA_HEADER_SIZE; //This is a fixed value. DO NOT CHANGE
|
||||||
@@ -62,33 +50,10 @@ extern uint16_t flash_read_uint16(uintptr_t addr);
|
|||||||
|
|
||||||
extern void low_flash_available();
|
extern void low_flash_available();
|
||||||
|
|
||||||
/*
|
|
||||||
* Flash data pool managenent
|
|
||||||
*
|
|
||||||
* Flash data pool consists of two parts:
|
|
||||||
* 2-byte header
|
|
||||||
* contents
|
|
||||||
*
|
|
||||||
* Flash data pool objects:
|
|
||||||
* Data Object (DO) (of smart card)
|
|
||||||
* Internal objects:
|
|
||||||
* NONE (0x0000)
|
|
||||||
* 123-counter
|
|
||||||
* 14-bit counter
|
|
||||||
* bool object
|
|
||||||
* small enum
|
|
||||||
*
|
|
||||||
* Format of a Data Object:
|
|
||||||
* NR: 8-bit tag_number
|
|
||||||
* LEN: 8-bit length
|
|
||||||
* DATA: data * LEN
|
|
||||||
* PAD: optional byte for 16-bit alignment
|
|
||||||
*/
|
|
||||||
|
|
||||||
uintptr_t allocate_free_addr(uint16_t size) {
|
uintptr_t allocate_free_addr(uint16_t size) {
|
||||||
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); //len+len size+next address+fid
|
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;
|
uintptr_t next_base = 0x0;
|
||||||
for (uintptr_t base = end_data_pool; base >= start_data_pool; base = next_base) {
|
for (uintptr_t base = end_data_pool; base >= start_data_pool; base = next_base) {
|
||||||
uintptr_t addr_alg = base & -FLASH_SECTOR_SIZE; //start address of sector
|
uintptr_t addr_alg = base & -FLASH_SECTOR_SIZE; //start address of sector
|
||||||
@@ -101,20 +66,23 @@ uintptr_t allocate_free_addr(uint16_t size) {
|
|||||||
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(base, potential_addr);
|
flash_program_uintptr(base, potential_addr);
|
||||||
return potential_addr;
|
return potential_addr;
|
||||||
}
|
}
|
||||||
else if (addr_alg-FLASH_SECTOR_SIZE >= start_data_pool) { //check whether it fits in the next sector, so we take addr_aligned as the base
|
else if (addr_alg-FLASH_SECTOR_SIZE >= start_data_pool) { //check whether it fits in the next sector, so we take addr_aligned as the base
|
||||||
potential_addr = addr_alg-real_size;
|
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(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 && base-(next_base+flash_read_uint16(next_base+sizeof(uintptr_t)+sizeof(uint16_t))+2*sizeof(uint16_t)) > base-potential_addr && flash_read_uint16(next_base+sizeof(uintptr_t)) & 0x1000 != 0x1000) {
|
else if (addr_alg <= potential_addr && base-(next_base+flash_read_uint16(next_base+sizeof(uintptr_t)+sizeof(uintptr_t)+sizeof(uint16_t))+2*sizeof(uint16_t)+2*sizeof(uintptr_t)) > base-potential_addr && flash_read_uint16(next_base+sizeof(uintptr_t)) & 0x1000 != 0x1000) {
|
||||||
flash_program_uintptr(potential_addr, next_base);
|
flash_program_uintptr(potential_addr, next_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;
|
||||||
}
|
}
|
||||||
@@ -123,13 +91,16 @@ uintptr_t allocate_free_addr(uint16_t size) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int flash_clear_file(file_t *file) {
|
int flash_clear_file(file_t *file) {
|
||||||
uintptr_t prev_addr = (uintptr_t)(file->data+flash_read_uint16((uintptr_t)file->data)+sizeof(uint16_t));
|
uintptr_t base_addr = (uintptr_t)(file->data-sizeof(uintptr_t)-sizeof(uint16_t)-sizeof(uintptr_t));
|
||||||
uintptr_t base_addr = (uintptr_t)(file->data-sizeof(uintptr_t)-sizeof(uint16_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 %x %x %x\r\n",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);
|
||||||
return 0;
|
if (next_addr > 0)
|
||||||
|
flash_program_uintptr(next_addr+sizeof(uintptr_t), prev_addr);
|
||||||
|
//printf("na %x->%x\r\n",prev_addr,flash_read_uintptr(prev_addr));
|
||||||
|
return HSM_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int flash_write_data_to_file(file_t *file, const uint8_t *data, uint16_t len) {
|
int flash_write_data_to_file(file_t *file, const uint8_t *data, uint16_t len) {
|
||||||
@@ -153,8 +124,8 @@ int flash_write_data_to_file(file_t *file, const uint8_t *data, uint16_t len) {
|
|||||||
//printf("na %x\r\n",new_addr);
|
//printf("na %x\r\n",new_addr);
|
||||||
if (new_addr == 0x0)
|
if (new_addr == 0x0)
|
||||||
return HSM_ERR_NO_MEMORY;
|
return HSM_ERR_NO_MEMORY;
|
||||||
file->data = (uint8_t *)new_addr+sizeof(uintptr_t)+sizeof(uint16_t); //next addr+fid
|
file->data = (uint8_t *)new_addr+sizeof(uintptr_t)+sizeof(uint16_t)+sizeof(uintptr_t); //next addr+fid+prev addr
|
||||||
flash_program_halfword(new_addr+sizeof(uintptr_t), file->fid);
|
flash_program_halfword(new_addr+sizeof(uintptr_t)+sizeof(uintptr_t), file->fid);
|
||||||
flash_program_halfword((uintptr_t)file->data, len);
|
flash_program_halfword((uintptr_t)file->data, len);
|
||||||
if (data)
|
if (data)
|
||||||
flash_program_block((uintptr_t)file->data+sizeof(uint16_t), data, len);
|
flash_program_block((uintptr_t)file->data+sizeof(uint16_t), data, len);
|
||||||
@@ -1,3 +1,21 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the Pico HSM distribution (https://github.com/polhenarejos/pico-hsm).
|
||||||
|
* Copyright (c) 2022 Pol Henarejos.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
@@ -8,7 +26,6 @@
|
|||||||
#include "pico/mutex.h"
|
#include "pico/mutex.h"
|
||||||
#include "pico/sem.h"
|
#include "pico/sem.h"
|
||||||
#include "pico/multicore.h"
|
#include "pico/multicore.h"
|
||||||
#include "gnuk.h"
|
|
||||||
#include "hsm2040.h"
|
#include "hsm2040.h"
|
||||||
#include "sc_hsm.h"
|
#include "sc_hsm.h"
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@@ -37,15 +54,11 @@ 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\r\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)
|
|
||||||
{
|
|
||||||
//printf("WRITTING %X\r\n",flash_pages[r].address-XIP_BASE);
|
//printf("WRITTING %X\r\n",flash_pages[r].address-XIP_BASE);
|
||||||
while (multicore_lockout_start_timeout_us(1000) == false);
|
while (multicore_lockout_start_timeout_us(1000) == false);
|
||||||
//printf("WRITTING %X\r\n",flash_pages[r].address-XIP_BASE);
|
//printf("WRITTING %X\r\n",flash_pages[r].address-XIP_BASE);
|
||||||
@@ -59,8 +72,7 @@ void do_flash()
|
|||||||
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) {
|
||||||
{
|
|
||||||
while (multicore_lockout_start_timeout_us(1000) == false);
|
while (multicore_lockout_start_timeout_us(1000) == false);
|
||||||
//printf("WRITTING\r\n");
|
//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);
|
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);
|
||||||
@@ -80,8 +92,7 @@ void do_flash()
|
|||||||
}
|
}
|
||||||
|
|
||||||
//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() {
|
||||||
{
|
|
||||||
mutex_init(&mtx_flash);
|
mutex_init(&mtx_flash);
|
||||||
sem_init(&sem_wait, 0, 1);
|
sem_init(&sem_wait, 0, 1);
|
||||||
memset(flash_pages, 0, sizeof(page_flash_t)*TOTAL_FLASH_PAGES);
|
memset(flash_pages, 0, sizeof(page_flash_t)*TOTAL_FLASH_PAGES);
|
||||||
@@ -100,8 +111,7 @@ void wait_flash_finish() {
|
|||||||
sem_acquire_blocking(&sem_wait); //decrease permits
|
sem_acquire_blocking(&sem_wait); //decrease permits
|
||||||
}
|
}
|
||||||
|
|
||||||
void low_flash_available()
|
void low_flash_available() {
|
||||||
{
|
|
||||||
mutex_enter_blocking(&mtx_flash);
|
mutex_enter_blocking(&mtx_flash);
|
||||||
flash_available = true;
|
flash_available = true;
|
||||||
mutex_exit(&mtx_flash);
|
mutex_exit(&mtx_flash);
|
||||||
@@ -153,18 +163,15 @@ int flash_program_block(uintptr_t addr, const uint8_t *data, size_t len) {
|
|||||||
return HSM_OK;
|
return HSM_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));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -206,8 +213,7 @@ 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) {
|
||||||
{
|
|
||||||
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;
|
||||||
|
|
||||||
@@ -217,8 +223,7 @@ int flash_erase_page (uintptr_t addr, size_t page_size)
|
|||||||
DEBUG_INFO("ERROR: ALL FLASH PAGES CACHED\r\n");
|
DEBUG_INFO("ERROR: ALL FLASH PAGES CACHED\r\n");
|
||||||
return HSM_ERR_NO_MEMORY;
|
return HSM_ERR_NO_MEMORY;
|
||||||
}
|
}
|
||||||
if (!(p = find_free_page(addr)))
|
if (!(p = find_free_page(addr))) {
|
||||||
{
|
|
||||||
DEBUG_INFO("ERROR: FLASH CANNOT FIND A PAGE (rare error)\r\n");
|
DEBUG_INFO("ERROR: FLASH CANNOT FIND A PAGE (rare error)\r\n");
|
||||||
mutex_exit(&mtx_flash);
|
mutex_exit(&mtx_flash);
|
||||||
return HSM_ERR_MEMORY_FATAL;
|
return HSM_ERR_MEMORY_FATAL;
|
||||||
@@ -231,13 +236,13 @@ int flash_erase_page (uintptr_t addr, size_t page_size)
|
|||||||
return HSM_OK;
|
return HSM_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;
|
||||||
}
|
}
|
||||||
142
src/hsm/crypto_utils.c
Normal file
142
src/hsm/crypto_utils.c
Normal file
@@ -0,0 +1,142 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the Pico HSM distribution (https://github.com/polhenarejos/pico-hsm).
|
||||||
|
* Copyright (c) 2022 Pol Henarejos.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <pico/unique_id.h>
|
||||||
|
#include "mbedtls/md.h"
|
||||||
|
#include "mbedtls/sha256.h"
|
||||||
|
#include "mbedtls/aes.h"
|
||||||
|
#include "crypto_utils.h"
|
||||||
|
#include "sc_hsm.h"
|
||||||
|
#include "libopensc/card-sc-hsm.h"
|
||||||
|
|
||||||
|
void double_hash_pin(const uint8_t *pin, size_t len, uint8_t output[32]) {
|
||||||
|
uint8_t o1[32];
|
||||||
|
hash_multi(pin, len, o1);
|
||||||
|
for (int i = 0; i < sizeof(o1); i++)
|
||||||
|
o1[i] ^= pin[i%len];
|
||||||
|
hash_multi(o1, sizeof(o1), output);
|
||||||
|
}
|
||||||
|
|
||||||
|
void hash_multi(const uint8_t *input, size_t len, uint8_t output[32]) {
|
||||||
|
mbedtls_sha256_context ctx;
|
||||||
|
mbedtls_sha256_init(&ctx);
|
||||||
|
int iters = 256;
|
||||||
|
pico_unique_board_id_t unique_id;
|
||||||
|
|
||||||
|
pico_get_unique_board_id(&unique_id);
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
if (iters > 0) // remaining iterations
|
||||||
|
mbedtls_sha256_update (&ctx, input, iters);
|
||||||
|
mbedtls_sha256_finish (&ctx, output);
|
||||||
|
mbedtls_sha256_free (&ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
void hash256(const uint8_t *input, size_t len, uint8_t output[32]) {
|
||||||
|
mbedtls_sha256_context ctx;
|
||||||
|
mbedtls_sha256_init(&ctx);
|
||||||
|
|
||||||
|
mbedtls_sha256_starts (&ctx, 0);
|
||||||
|
mbedtls_sha256_update (&ctx, input, len);
|
||||||
|
|
||||||
|
mbedtls_sha256_finish (&ctx, output);
|
||||||
|
mbedtls_sha256_free (&ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
void generic_hash(mbedtls_md_type_t md, const uint8_t *input, size_t len, uint8_t *output) {
|
||||||
|
mbedtls_md_context_t ctx;
|
||||||
|
mbedtls_md_init(&ctx);
|
||||||
|
const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type(md);
|
||||||
|
mbedtls_md_setup(&ctx, md_info, 0);
|
||||||
|
mbedtls_md_starts(&ctx);
|
||||||
|
mbedtls_md_update(&ctx, input, len);
|
||||||
|
mbedtls_md_finish(&ctx, output);
|
||||||
|
mbedtls_md_free(&ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
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_init(&aes);
|
||||||
|
uint8_t tmp_iv[IV_SIZE];
|
||||||
|
size_t iv_offset = 0;
|
||||||
|
memset(tmp_iv, 0, IV_SIZE);
|
||||||
|
if (iv)
|
||||||
|
memcpy(tmp_iv, iv, IV_SIZE);
|
||||||
|
int r = mbedtls_aes_setkey_enc(&aes, key, key_size);
|
||||||
|
if (r != 0)
|
||||||
|
return HSM_EXEC_ERROR;
|
||||||
|
if (mode == HSM_AES_MODE_CBC)
|
||||||
|
return mbedtls_aes_crypt_cbc(&aes, MBEDTLS_AES_ENCRYPT, len, tmp_iv, data, data);
|
||||||
|
return mbedtls_aes_crypt_cfb128(&aes, MBEDTLS_AES_ENCRYPT, len, &iv_offset, tmp_iv, data, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
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_init(&aes);
|
||||||
|
uint8_t tmp_iv[IV_SIZE];
|
||||||
|
size_t iv_offset = 0;
|
||||||
|
memset(tmp_iv, 0, IV_SIZE);
|
||||||
|
if (iv)
|
||||||
|
memcpy(tmp_iv, iv, IV_SIZE);
|
||||||
|
int r = mbedtls_aes_setkey_dec(&aes, key, key_size);
|
||||||
|
if (r != 0)
|
||||||
|
return HSM_EXEC_ERROR;
|
||||||
|
if (mode == HSM_AES_MODE_CBC)
|
||||||
|
return mbedtls_aes_crypt_cbc(&aes, MBEDTLS_AES_DECRYPT, len, tmp_iv, data, data);
|
||||||
|
r = mbedtls_aes_setkey_enc(&aes, key, key_size); //CFB requires set_enc instead set_dec
|
||||||
|
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, int 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, int len) {
|
||||||
|
return aes_decrypt(key, iv, 256, HSM_AES_MODE_CFB, data, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ec_curve_mbed_id {
|
||||||
|
struct sc_lv_data curve;
|
||||||
|
mbedtls_ecp_group_id id;
|
||||||
|
};
|
||||||
|
struct ec_curve_mbed_id ec_curves_mbed[] = {
|
||||||
|
{ { (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 },
|
||||||
|
{ { (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 },
|
||||||
|
{ { (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 *) "\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 },
|
||||||
|
{ { NULL, 0 }, MBEDTLS_ECP_DP_NONE }
|
||||||
|
};
|
||||||
|
|
||||||
|
mbedtls_ecp_group_id ec_get_curve_from_prime(const uint8_t *prime, size_t prime_len) {
|
||||||
|
for (struct ec_curve_mbed_id *ec = ec_curves_mbed; ec->id != MBEDTLS_ECP_DP_NONE; ec++) {
|
||||||
|
if (prime_len == ec->curve.len && memcmp(prime, ec->curve.value, prime_len) == 0) {
|
||||||
|
return ec->id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return MBEDTLS_ECP_DP_NONE;
|
||||||
|
}
|
||||||
46
src/hsm/crypto_utils.h
Normal file
46
src/hsm/crypto_utils.h
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the Pico HSM distribution (https://github.com/polhenarejos/pico-hsm).
|
||||||
|
* Copyright (c) 2022 Pol Henarejos.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _CRYPTO_UTILS_H_
|
||||||
|
#define _CRYPTO_UTILS_H_
|
||||||
|
|
||||||
|
#include "stdlib.h"
|
||||||
|
#include "pico/stdlib.h"
|
||||||
|
#include "mbedtls/ecp.h"
|
||||||
|
#include "mbedtls/md.h"
|
||||||
|
|
||||||
|
#define HSM_KEY_RSA 0x1
|
||||||
|
#define HSM_KEY_EC 0x10
|
||||||
|
#define HSM_KEY_AES 0x100
|
||||||
|
#define HSM_KEY_AES_128 0x300
|
||||||
|
#define HSM_KEY_AES_192 0x500
|
||||||
|
#define HSM_KEY_AES_256 0x900
|
||||||
|
|
||||||
|
#define HSM_AES_MODE_CBC 1
|
||||||
|
#define HSM_AES_MODE_CFB 2
|
||||||
|
|
||||||
|
extern void double_hash_pin(const uint8_t *pin, size_t len, uint8_t output[32]);
|
||||||
|
extern void hash_multi(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 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, 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, int 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);
|
||||||
|
|
||||||
|
#endif
|
||||||
41
src/hsm/cvcerts.h
Normal file
41
src/hsm/cvcerts.h
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
#ifndef CVCERTS_H_
|
||||||
|
#define CVCERTS_H_
|
||||||
|
|
||||||
|
static const unsigned char termca[] = {
|
||||||
|
0xfa, 0x00,
|
||||||
|
0x7f,0x21,0x81,0xf6,0x7f,0x4e,0x81,0xbf,0x5f,0x29,0x01,0x00,0x42,0x0e,0x45,0x53,
|
||||||
|
0x44,0x56,0x43,0x41,0x48,0x53,0x4d,0x30,0x30,0x30,0x30,0x31,0x7f,0x49,0x3f,0x06,
|
||||||
|
0x0a,0x04,0x00,0x7f,0x00,0x07,0x02,0x02,0x02,0x02,0x03,0x86,0x31,0x04,0x0f,0x89,
|
||||||
|
0xb4,0x00,0x97,0x5e,0xdd,0x2d,0x42,0x5a,0xbf,0x85,0xf2,0xfb,0xd3,0x18,0x77,0x9b,
|
||||||
|
0x3d,0x85,0x47,0x5e,0x65,0xd4,0xd8,0x58,0x69,0xd3,0x04,0x14,0xb7,0x1f,0x16,0x1e,
|
||||||
|
0xb0,0x40,0xd9,0xf7,0xa7,0xe3,0x73,0xa3,0x15,0xc7,0xd9,0x9a,0x51,0xf5,0x5f,0x20,
|
||||||
|
0x0e,0x45,0x53,0x54,0x45,0x52,0x4d,0x48,0x53,0x4d,0x30,0x30,0x30,0x30,0x31,0x7f,
|
||||||
|
0x4c,0x12,0x06,0x09,0x04,0x00,0x7f,0x00,0x07,0x03,0x01,0x02,0x02,0x53,0x05,0x00,
|
||||||
|
0x00,0x00,0x00,0x04,0x5f,0x25,0x06,0x02,0x02,0x00,0x03,0x02,0x07,0x5f,0x24,0x06,
|
||||||
|
0x02,0x03,0x01,0x02,0x03,0x01,0x65,0x2f,0x73,0x2d,0x06,0x09,0x04,0x00,0x7f,0x00,
|
||||||
|
0x07,0x03,0x01,0x03,0x01,0x80,0x20,0x68,0x53,0x30,0xc7,0x9a,0x47,0xad,0xfd,0x37,
|
||||||
|
0xaa,0xe8,0x53,0xf4,0xbd,0x77,0x3a,0x40,0x89,0x3a,0x79,0x7e,0x3c,0x27,0x18,0x3b,
|
||||||
|
0x39,0x67,0xdf,0x8d,0x4f,0xe5,0x99,0x5f,0x37,0x30,0x10,0xff,0x17,0x96,0x0d,0x93,
|
||||||
|
0x07,0xc0,0x69,0x8e,0x3a,0xa0,0x44,0x69,0x70,0x88,0xe6,0x9c,0xb4,0xd3,0x16,0x9a,
|
||||||
|
0x22,0x4e,0x5c,0x77,0xa9,0xe7,0x83,0x75,0x9a,0xd2,0x7e,0x92,0xf2,0x04,0x93,0xb1,
|
||||||
|
0xe9,0xc9,0xe5,0x10,0xc9,0x94,0xff,0x9d,0xe2,0x00
|
||||||
|
};
|
||||||
|
|
||||||
|
static const unsigned char dica[] = {
|
||||||
|
0xc9, 0x00,
|
||||||
|
0x7f,0x21,0x81,0xc5,0x7f,0x4e,0x81,0x8e,0x5f,0x29,0x01,0x00,0x42,0x0e,0x45,0x53,
|
||||||
|
0x43,0x56,0x43,0x41,0x48,0x53,0x4d,0x30,0x30,0x30,0x30,0x31,0x7f,0x49,0x3f,0x06,
|
||||||
|
0x0a,0x04,0x00,0x7f,0x00,0x07,0x02,0x02,0x02,0x02,0x03,0x86,0x31,0x04,0x93,0x7e,
|
||||||
|
0xdf,0xf1,0xa6,0xd2,0x40,0x7e,0xb4,0x71,0xb2,0x97,0x50,0xdb,0x7e,0xe1,0x70,0xfb,
|
||||||
|
0x6c,0xcd,0x06,0x47,0x2a,0x3e,0x9c,0x8d,0x59,0x56,0x57,0xbe,0x11,0x11,0x0a,0x08,
|
||||||
|
0x81,0x54,0xed,0x22,0xc0,0x83,0xac,0xa1,0x2e,0x39,0x7b,0xd4,0x65,0x1f,0x5f,0x20,
|
||||||
|
0x0e,0x45,0x53,0x44,0x56,0x43,0x41,0x48,0x53,0x4d,0x30,0x30,0x30,0x30,0x31,0x7f,
|
||||||
|
0x4c,0x12,0x06,0x09,0x04,0x00,0x7f,0x00,0x07,0x03,0x01,0x02,0x02,0x53,0x05,0x80,
|
||||||
|
0x00,0x00,0x00,0x04,0x5f,0x25,0x06,0x02,0x02,0x00,0x03,0x02,0x07,0x5f,0x24,0x06,
|
||||||
|
0x02,0x05,0x01,0x02,0x03,0x01,0x5f,0x37,0x30,0x8b,0xb2,0x01,0xb6,0x24,0xfe,0xe5,
|
||||||
|
0x4e,0x65,0x3a,0x02,0xa2,0xb2,0x27,0x2d,0x3d,0xb4,0xb0,0xc9,0xdd,0xbf,0x10,0x6d,
|
||||||
|
0x99,0x49,0x46,0xd6,0xd0,0x72,0xc1,0xf3,0x4c,0xab,0x4f,0x32,0x14,0x7c,0xb0,0x99,
|
||||||
|
0xb7,0x33,0x70,0xd6,0x00,0xff,0x73,0x0c,0x5d
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
474
src/hsm/dkek.c
Normal file
474
src/hsm/dkek.c
Normal file
@@ -0,0 +1,474 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the Pico HSM distribution (https://github.com/polhenarejos/pico-hsm).
|
||||||
|
* Copyright (c) 2022 Pol Henarejos.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include "common.h"
|
||||||
|
#include "stdlib.h"
|
||||||
|
#include "pico/stdlib.h"
|
||||||
|
#include "dkek.h"
|
||||||
|
#include "crypto_utils.h"
|
||||||
|
#include "random.h"
|
||||||
|
#include "sc_hsm.h"
|
||||||
|
#include "mbedtls/md.h"
|
||||||
|
#include "mbedtls/cmac.h"
|
||||||
|
#include "mbedtls/rsa.h"
|
||||||
|
#include "mbedtls/ecdsa.h"
|
||||||
|
|
||||||
|
static uint8_t dkek[IV_SIZE+32];
|
||||||
|
static uint8_t tmp_dkek[32];
|
||||||
|
extern bool has_session_pin;
|
||||||
|
extern uint8_t session_pin[32];
|
||||||
|
|
||||||
|
int load_dkek() {
|
||||||
|
if (has_session_pin == false)
|
||||||
|
return HSM_NO_LOGIN;
|
||||||
|
file_t *tf = search_by_fid(EF_DKEK, NULL, SPECIFY_EF);
|
||||||
|
if (!tf)
|
||||||
|
return HSM_ERR_FILE_NOT_FOUND;
|
||||||
|
memcpy(dkek, file_read(tf->data+sizeof(uint16_t)), IV_SIZE+32);
|
||||||
|
int ret = aes_decrypt_cfb_256(session_pin, dkek, dkek+IV_SIZE, 32);
|
||||||
|
if (ret != 0)
|
||||||
|
return HSM_EXEC_ERROR;
|
||||||
|
return HSM_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void release_dkek() {
|
||||||
|
memset(dkek, 0, sizeof(dkek));
|
||||||
|
}
|
||||||
|
|
||||||
|
void init_dkek() {
|
||||||
|
release_dkek();
|
||||||
|
memset(tmp_dkek, 0, sizeof(tmp_dkek));
|
||||||
|
}
|
||||||
|
|
||||||
|
int store_dkek_key() {
|
||||||
|
aes_encrypt_cfb_256(session_pin, dkek, dkek+IV_SIZE, 32);
|
||||||
|
file_t *tf = search_by_fid(EF_DKEK, NULL, SPECIFY_EF);
|
||||||
|
if (!tf)
|
||||||
|
return HSM_ERR_FILE_NOT_FOUND;
|
||||||
|
flash_write_data_to_file(tf, dkek, sizeof(dkek));
|
||||||
|
low_flash_available();
|
||||||
|
release_dkek();
|
||||||
|
return HSM_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int save_dkek_key(const uint8_t *key) {
|
||||||
|
const uint8_t *iv = random_bytes_get(32);
|
||||||
|
memcpy(dkek, iv, IV_SIZE);
|
||||||
|
if (!key)
|
||||||
|
key = tmp_dkek;
|
||||||
|
memcpy(dkek+IV_SIZE, key, 32);
|
||||||
|
return store_dkek_key();
|
||||||
|
}
|
||||||
|
|
||||||
|
void import_dkek_share(const uint8_t *share) {
|
||||||
|
for (int i = 0; i < 32; i++)
|
||||||
|
tmp_dkek[i] ^= share[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
int dkek_kcv(uint8_t *kcv) { //kcv 8 bytes
|
||||||
|
uint8_t hsh[32];
|
||||||
|
int r = load_dkek();
|
||||||
|
if (r != HSM_OK)
|
||||||
|
return r;
|
||||||
|
hash256(dkek+IV_SIZE, 32, hsh);
|
||||||
|
release_dkek();
|
||||||
|
memcpy(kcv, hsh, 8);
|
||||||
|
return HSM_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int dkek_kenc(uint8_t *kenc) { //kenc 32 bytes
|
||||||
|
uint8_t buf[32+4];
|
||||||
|
int r = load_dkek();
|
||||||
|
if (r != HSM_OK)
|
||||||
|
return r;
|
||||||
|
memcpy(buf, dkek+IV_SIZE, 32);
|
||||||
|
release_dkek();
|
||||||
|
memcpy(buf+32, "\x0\x0\x0\x1", 4);
|
||||||
|
hash256(buf, sizeof(buf), kenc);
|
||||||
|
memset(buf, 0, sizeof(buf));
|
||||||
|
return HSM_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int dkek_kmac(uint8_t *kmac) { //kmac 32 bytes
|
||||||
|
uint8_t buf[32+4];
|
||||||
|
int r = load_dkek();
|
||||||
|
if (r != HSM_OK)
|
||||||
|
return r;
|
||||||
|
memcpy(buf, dkek+IV_SIZE, 32);
|
||||||
|
release_dkek();
|
||||||
|
memcpy(buf+32, "\x0\x0\x0\x2", 4);
|
||||||
|
hash256(buf, sizeof(buf), kmac);
|
||||||
|
memset(buf, 0, sizeof(buf));
|
||||||
|
return HSM_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int dkek_encrypt(uint8_t *data, size_t len) {
|
||||||
|
int r;
|
||||||
|
if ((r = load_dkek()) != HSM_OK)
|
||||||
|
return r;
|
||||||
|
r = aes_encrypt_cfb_256(dkek+IV_SIZE, dkek, data, len);
|
||||||
|
release_dkek();
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
int dkek_decrypt(uint8_t *data, size_t len) {
|
||||||
|
int r;
|
||||||
|
if ((r = load_dkek()) != HSM_OK)
|
||||||
|
return r;
|
||||||
|
r = aes_decrypt_cfb_256(dkek+IV_SIZE, dkek, data, len);
|
||||||
|
release_dkek();
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
int dkek_encode_key(void *key_ctx, int key_type, uint8_t *out, size_t *out_len) {
|
||||||
|
if (!(key_type & HSM_KEY_RSA) && !(key_type & HSM_KEY_EC) && !(key_type & HSM_KEY_AES))
|
||||||
|
return HSM_WRONG_DATA;
|
||||||
|
|
||||||
|
uint8_t kb[8+2*4+2*4096/8+3+13]; //worst case: RSA-4096 (plus, 13 bytes padding)
|
||||||
|
memset(kb, 0, sizeof(kb));
|
||||||
|
int kb_len = 0;
|
||||||
|
uint8_t *algo = NULL;
|
||||||
|
uint8_t algo_len = 0;
|
||||||
|
uint8_t *allowed = NULL;
|
||||||
|
uint8_t allowed_len = 0;
|
||||||
|
uint8_t kenc[32];
|
||||||
|
memset(kenc, 0, sizeof(kenc));
|
||||||
|
dkek_kenc(kenc);
|
||||||
|
|
||||||
|
uint8_t kcv[8];
|
||||||
|
memset(kcv, 0, sizeof(kcv));
|
||||||
|
dkek_kcv(kcv);
|
||||||
|
|
||||||
|
uint8_t kmac[32];
|
||||||
|
memset(kmac, 0, sizeof(kmac));
|
||||||
|
dkek_kmac(kmac);
|
||||||
|
|
||||||
|
if (key_type & HSM_KEY_AES) {
|
||||||
|
if (key_type & HSM_KEY_AES_128)
|
||||||
|
kb_len = 16;
|
||||||
|
else if (key_type & HSM_KEY_AES_192)
|
||||||
|
kb_len = 24;
|
||||||
|
else if (key_type & HSM_KEY_AES_256)
|
||||||
|
kb_len = 32;
|
||||||
|
|
||||||
|
if (kb_len != 16 && kb_len != 24 && kb_len != 32)
|
||||||
|
return HSM_WRONG_DATA;
|
||||||
|
if (*out_len < 8+1+10+6+4+(2+32+14)+16)
|
||||||
|
return HSM_WRONG_LENGTH;
|
||||||
|
|
||||||
|
put_uint16_t(kb_len, kb+8);
|
||||||
|
memcpy(kb+10, key_ctx, kb_len);
|
||||||
|
kb_len += 2;
|
||||||
|
|
||||||
|
algo = "\x00\x08\x60\x86\x48\x01\x65\x03\x04\x01"; //2.16.840.1.101.3.4.1 (2+8)
|
||||||
|
algo_len = 10;
|
||||||
|
allowed = "\x00\x04\x10\x11\x18\x99"; //(2+4)
|
||||||
|
allowed_len = 6;
|
||||||
|
}
|
||||||
|
else if (key_type & HSM_KEY_RSA) {
|
||||||
|
if (*out_len < 8+1+12+6+(8+2*4+2*4096/8+3+13)+16) //13 bytes pading
|
||||||
|
return HSM_WRONG_LENGTH;
|
||||||
|
mbedtls_rsa_context *rsa = (mbedtls_rsa_context *)key_ctx;
|
||||||
|
kb_len = 0;
|
||||||
|
put_uint16_t(mbedtls_rsa_get_len(rsa)*8, kb+8+kb_len); kb_len += 2;
|
||||||
|
|
||||||
|
put_uint16_t(mbedtls_mpi_size(&rsa->D), kb+8+kb_len); kb_len += 2;
|
||||||
|
mbedtls_mpi_write_binary(&rsa->D, kb+8+kb_len, mbedtls_mpi_size(&rsa->D)); kb_len += mbedtls_mpi_size(&rsa->D);
|
||||||
|
put_uint16_t(mbedtls_mpi_size(&rsa->N), kb+8+kb_len); kb_len += 2;
|
||||||
|
mbedtls_mpi_write_binary(&rsa->N, kb+8+kb_len, mbedtls_mpi_size(&rsa->N)); kb_len += mbedtls_mpi_size(&rsa->N);
|
||||||
|
put_uint16_t(mbedtls_mpi_size(&rsa->E), kb+8+kb_len); kb_len += 2;
|
||||||
|
mbedtls_mpi_write_binary(&rsa->E, kb+8+kb_len, mbedtls_mpi_size(&rsa->E)); kb_len += mbedtls_mpi_size(&rsa->E);
|
||||||
|
|
||||||
|
algo = "\x00\x0A\x04\x00\x7F\x00\x07\x02\x02\x02\x01\x02";
|
||||||
|
algo_len = 12;
|
||||||
|
}
|
||||||
|
else if (key_type & HSM_KEY_EC) {
|
||||||
|
if (*out_len < 8+1+12+6+(8+2*8+9*66+2+4)+16) //4 bytes pading
|
||||||
|
return HSM_WRONG_LENGTH;
|
||||||
|
mbedtls_ecdsa_context *ecdsa = (mbedtls_ecdsa_context *)key_ctx;
|
||||||
|
kb_len = 0;
|
||||||
|
put_uint16_t(mbedtls_mpi_size(&ecdsa->grp.P)*8, kb+8+kb_len); kb_len += 2;
|
||||||
|
put_uint16_t(mbedtls_mpi_size(&ecdsa->grp.A), kb+8+kb_len); kb_len += 2;
|
||||||
|
mbedtls_mpi_write_binary(&ecdsa->grp.A, kb+8+kb_len, mbedtls_mpi_size(&ecdsa->grp.A)); kb_len += mbedtls_mpi_size(&ecdsa->grp.A);
|
||||||
|
put_uint16_t(mbedtls_mpi_size(&ecdsa->grp.B), kb+8+kb_len); kb_len += 2;
|
||||||
|
mbedtls_mpi_write_binary(&ecdsa->grp.B, kb+8+kb_len, mbedtls_mpi_size(&ecdsa->grp.B)); kb_len += mbedtls_mpi_size(&ecdsa->grp.B);
|
||||||
|
put_uint16_t(mbedtls_mpi_size(&ecdsa->grp.P), kb+8+kb_len); kb_len += 2;
|
||||||
|
mbedtls_mpi_write_binary(&ecdsa->grp.P, kb+8+kb_len, mbedtls_mpi_size(&ecdsa->grp.P)); kb_len += mbedtls_mpi_size(&ecdsa->grp.P);
|
||||||
|
put_uint16_t(mbedtls_mpi_size(&ecdsa->grp.N), kb+8+kb_len); kb_len += 2;
|
||||||
|
mbedtls_mpi_write_binary(&ecdsa->grp.N, kb+8+kb_len, mbedtls_mpi_size(&ecdsa->grp.N)); kb_len += mbedtls_mpi_size(&ecdsa->grp.N);
|
||||||
|
put_uint16_t(1+mbedtls_mpi_size(&ecdsa->grp.G.X)+mbedtls_mpi_size(&ecdsa->grp.G.Y), kb+8+kb_len); kb_len += 2;
|
||||||
|
kb[8+kb_len++] = 0x4;
|
||||||
|
mbedtls_mpi_write_binary(&ecdsa->grp.G.X, kb+8+kb_len, mbedtls_mpi_size(&ecdsa->grp.G.X)); kb_len += mbedtls_mpi_size(&ecdsa->grp.G.X);
|
||||||
|
mbedtls_mpi_write_binary(&ecdsa->grp.G.Y, kb+8+kb_len, mbedtls_mpi_size(&ecdsa->grp.G.Y)); kb_len += mbedtls_mpi_size(&ecdsa->grp.G.Y);
|
||||||
|
put_uint16_t(mbedtls_mpi_size(&ecdsa->d), kb+8+kb_len); kb_len += 2;
|
||||||
|
mbedtls_mpi_write_binary(&ecdsa->d, kb+8+kb_len, mbedtls_mpi_size(&ecdsa->d)); kb_len += mbedtls_mpi_size(&ecdsa->d);
|
||||||
|
put_uint16_t(1+mbedtls_mpi_size(&ecdsa->Q.X)+mbedtls_mpi_size(&ecdsa->Q.Y), kb+8+kb_len); kb_len += 2;
|
||||||
|
kb[8+kb_len++] = 0x4;
|
||||||
|
mbedtls_mpi_write_binary(&ecdsa->Q.X, kb+8+kb_len, mbedtls_mpi_size(&ecdsa->Q.X)); kb_len += mbedtls_mpi_size(&ecdsa->Q.X);
|
||||||
|
mbedtls_mpi_write_binary(&ecdsa->Q.Y, kb+8+kb_len, mbedtls_mpi_size(&ecdsa->Q.Y)); kb_len += mbedtls_mpi_size(&ecdsa->Q.Y);
|
||||||
|
|
||||||
|
algo = "\x00\x0A\x04\x00\x7F\x00\x07\x02\x02\x02\x02\x03";
|
||||||
|
algo_len = 12;
|
||||||
|
}
|
||||||
|
memset(out, 0, *out_len);
|
||||||
|
*out_len = 0;
|
||||||
|
|
||||||
|
memcpy(out+*out_len, kcv, 8);
|
||||||
|
*out_len += 8;
|
||||||
|
|
||||||
|
if (key_type & HSM_KEY_AES)
|
||||||
|
out[*out_len] = 15;
|
||||||
|
else if (key_type & HSM_KEY_RSA)
|
||||||
|
out[*out_len] = 5;
|
||||||
|
else if (key_type & HSM_KEY_EC)
|
||||||
|
out[*out_len] = 12;
|
||||||
|
*out_len += 1;
|
||||||
|
|
||||||
|
if (algo) {
|
||||||
|
memcpy(out+*out_len, algo, algo_len);
|
||||||
|
*out_len += algo_len;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
*out_len += 2;
|
||||||
|
|
||||||
|
if (allowed) {
|
||||||
|
memcpy(out+*out_len, allowed, allowed_len);
|
||||||
|
*out_len += allowed_len;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
*out_len += 2;
|
||||||
|
//add 4 zeros
|
||||||
|
*out_len += 4;
|
||||||
|
|
||||||
|
memcpy(kb, random_bytes_get(8), 8);
|
||||||
|
kb_len += 8; //8 random bytes
|
||||||
|
int kb_len_pad = ((int)(kb_len/16))*16;
|
||||||
|
if (kb_len % 16 > 0)
|
||||||
|
kb_len_pad = ((int)(kb_len/16)+1)*16;
|
||||||
|
//key already copied at kb+10
|
||||||
|
if (kb_len < kb_len_pad) {
|
||||||
|
kb[kb_len] = 0x80;
|
||||||
|
}
|
||||||
|
int r = aes_encrypt(kenc, NULL, 256, HSM_AES_MODE_CBC, kb, kb_len_pad);
|
||||||
|
if (r != HSM_OK)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
memcpy(out+*out_len, kb, kb_len_pad);
|
||||||
|
*out_len += kb_len_pad;
|
||||||
|
|
||||||
|
r = mbedtls_cipher_cmac(mbedtls_cipher_info_from_type(MBEDTLS_CIPHER_AES_256_ECB), kmac, 256, out, *out_len, out+*out_len);
|
||||||
|
|
||||||
|
*out_len += 16;
|
||||||
|
if (r != 0)
|
||||||
|
return r;
|
||||||
|
return HSM_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int dkek_type_key(const uint8_t *in) {
|
||||||
|
if (in[8] == 5 || in[8] == 6)
|
||||||
|
return HSM_KEY_RSA;
|
||||||
|
else if (in[8] == 12)
|
||||||
|
return HSM_KEY_EC;
|
||||||
|
else if (in[8] == 15)
|
||||||
|
return HSM_KEY_AES;
|
||||||
|
return 0x0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int dkek_decode_key(void *key_ctx, const uint8_t *in, size_t in_len, int *key_size_out) {
|
||||||
|
uint8_t kcv[8];
|
||||||
|
memset(kcv, 0, sizeof(kcv));
|
||||||
|
dkek_kcv(kcv);
|
||||||
|
|
||||||
|
uint8_t kmac[32];
|
||||||
|
memset(kmac, 0, sizeof(kmac));
|
||||||
|
dkek_kmac(kmac);
|
||||||
|
|
||||||
|
uint8_t kenc[32];
|
||||||
|
memset(kenc, 0, sizeof(kenc));
|
||||||
|
dkek_kenc(kenc);
|
||||||
|
|
||||||
|
if (memcmp(kcv, in, 8) != 0)
|
||||||
|
return HSM_WRONG_DKEK;
|
||||||
|
|
||||||
|
uint8_t signature[16];
|
||||||
|
int r = mbedtls_cipher_cmac(mbedtls_cipher_info_from_type(MBEDTLS_CIPHER_AES_256_ECB), kmac, 256, in, in_len-16, signature);
|
||||||
|
if (r != 0)
|
||||||
|
return HSM_WRONG_SIGNATURE;
|
||||||
|
if (memcmp(signature, in+in_len-16, 16) != 0)
|
||||||
|
return HSM_WRONG_SIGNATURE;
|
||||||
|
|
||||||
|
int key_type = in[8];
|
||||||
|
if (key_type != 5 && key_type != 6 && key_type != 12 && key_type != 15)
|
||||||
|
return HSM_WRONG_DATA;
|
||||||
|
|
||||||
|
if ((key_type == 5 || key_type == 6) && memcmp(in+9, "\x00\x0A\x04\x00\x7F\x00\x07\x02\x02\x02\x01\x02", 12) != 0)
|
||||||
|
return HSM_WRONG_DATA;
|
||||||
|
|
||||||
|
if (key_type == 12 && memcmp(in+9, "\x00\x0A\x04\x00\x7F\x00\x07\x02\x02\x02\x02\x03", 12) != 0)
|
||||||
|
return HSM_WRONG_DATA;
|
||||||
|
|
||||||
|
if (key_type == 15 && memcmp(in+9, "\x00\x08\x60\x86\x48\x01\x65\x03\x04\x01", 10) != 0)
|
||||||
|
return HSM_WRONG_DATA;
|
||||||
|
|
||||||
|
size_t ofs = 9;
|
||||||
|
|
||||||
|
//OID
|
||||||
|
size_t len = get_uint16_t(in, ofs);
|
||||||
|
ofs += len+2;
|
||||||
|
|
||||||
|
//Allowed algorithms
|
||||||
|
len = get_uint16_t(in, ofs);
|
||||||
|
ofs += len+2;
|
||||||
|
|
||||||
|
//Access conditions
|
||||||
|
len = get_uint16_t(in, ofs);
|
||||||
|
ofs += len+2;
|
||||||
|
|
||||||
|
//Key OID
|
||||||
|
len = get_uint16_t(in, ofs);
|
||||||
|
ofs += len+2;
|
||||||
|
|
||||||
|
if ((in_len-16-ofs) % 16 != 0)
|
||||||
|
return HSM_WRONG_PADDING;
|
||||||
|
uint8_t kb[8+2*4+2*4096/8+3+13]; //worst case: RSA-4096 (plus, 13 bytes padding)
|
||||||
|
memset(kb, 0, sizeof(kb));
|
||||||
|
memcpy(kb, in+ofs, in_len-16-ofs);
|
||||||
|
r = aes_decrypt(kenc, NULL, 256, HSM_AES_MODE_CBC, kb, in_len-16-ofs);
|
||||||
|
if (r != HSM_OK)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
int key_size = get_uint16_t(kb, 8);
|
||||||
|
if (key_size_out)
|
||||||
|
*key_size_out = key_size;
|
||||||
|
ofs = 10;
|
||||||
|
if (key_type == 5 || key_type == 6) {
|
||||||
|
mbedtls_rsa_context *rsa = (mbedtls_rsa_context *)key_ctx;
|
||||||
|
mbedtls_rsa_init(rsa);
|
||||||
|
if (key_type == 5) {
|
||||||
|
len = get_uint16_t(kb, ofs); ofs += 2;
|
||||||
|
r = mbedtls_mpi_read_binary(&rsa->D, kb+ofs, len); ofs += len;
|
||||||
|
if (r != 0) {
|
||||||
|
mbedtls_rsa_free(rsa);
|
||||||
|
return HSM_WRONG_DATA;
|
||||||
|
}
|
||||||
|
|
||||||
|
len = get_uint16_t(kb, ofs); ofs += 2;
|
||||||
|
r = mbedtls_mpi_read_binary(&rsa->N, kb+ofs, len); ofs += len;
|
||||||
|
if (r != 0) {
|
||||||
|
mbedtls_rsa_free(rsa);
|
||||||
|
return HSM_WRONG_DATA;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (key_type == 6) {
|
||||||
|
//DP-1
|
||||||
|
len = get_uint16_t(kb, ofs); ofs += len+2;
|
||||||
|
|
||||||
|
//DQ-1
|
||||||
|
len = get_uint16_t(kb, ofs); ofs += len+2;
|
||||||
|
|
||||||
|
len = get_uint16_t(kb, ofs); ofs += 2;
|
||||||
|
r = mbedtls_mpi_read_binary(&rsa->P, kb+ofs, len); ofs += len;
|
||||||
|
if (r != 0) {
|
||||||
|
mbedtls_rsa_free(rsa);
|
||||||
|
return HSM_WRONG_DATA;
|
||||||
|
}
|
||||||
|
|
||||||
|
//PQ
|
||||||
|
len = get_uint16_t(kb, ofs); ofs += len+2;
|
||||||
|
|
||||||
|
len = get_uint16_t(kb, ofs); ofs += 2;
|
||||||
|
r = mbedtls_mpi_read_binary(&rsa->Q, kb+ofs, len); ofs += len;
|
||||||
|
if (r != 0) {
|
||||||
|
mbedtls_rsa_free(rsa);
|
||||||
|
return HSM_WRONG_DATA;
|
||||||
|
}
|
||||||
|
//N
|
||||||
|
len = get_uint16_t(kb, ofs); ofs += len+2;
|
||||||
|
}
|
||||||
|
|
||||||
|
len = get_uint16_t(kb, ofs); ofs += 2;
|
||||||
|
r = mbedtls_mpi_read_binary(&rsa->E, kb+ofs, len); ofs += len;
|
||||||
|
if (r != 0) {
|
||||||
|
mbedtls_rsa_free(rsa);
|
||||||
|
return HSM_WRONG_DATA;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (key_type == 5) {
|
||||||
|
r = mbedtls_rsa_import(rsa, &rsa->N, NULL, NULL, &rsa->D, &rsa->E);
|
||||||
|
if (r != 0) {
|
||||||
|
mbedtls_rsa_free(rsa);
|
||||||
|
return HSM_EXEC_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (key_type == 6) {
|
||||||
|
r = mbedtls_rsa_import(rsa, NULL, &rsa->P, &rsa->Q, NULL, &rsa->E);
|
||||||
|
if (r != 0) {
|
||||||
|
mbedtls_rsa_free(rsa);
|
||||||
|
return HSM_EXEC_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
r = mbedtls_rsa_complete(rsa);
|
||||||
|
if (r != 0) {
|
||||||
|
mbedtls_rsa_free(rsa);
|
||||||
|
return HSM_EXEC_ERROR;
|
||||||
|
}
|
||||||
|
r = mbedtls_rsa_check_privkey(rsa);
|
||||||
|
if (r != 0) {
|
||||||
|
mbedtls_rsa_free(rsa);
|
||||||
|
return HSM_EXEC_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (key_type == 12) {
|
||||||
|
mbedtls_ecdsa_context *ecdsa = (mbedtls_ecdsa_context *)key_ctx;
|
||||||
|
mbedtls_ecdsa_init(ecdsa);
|
||||||
|
|
||||||
|
//A
|
||||||
|
len = get_uint16_t(kb, ofs); ofs += len+2;
|
||||||
|
|
||||||
|
//B
|
||||||
|
len = get_uint16_t(kb, ofs); ofs += len+2;
|
||||||
|
|
||||||
|
//P
|
||||||
|
len = get_uint16_t(kb, ofs); ofs += 2;
|
||||||
|
mbedtls_ecp_group_id ec_id = ec_get_curve_from_prime(kb+ofs, len);
|
||||||
|
if (ec_id == MBEDTLS_ECP_DP_NONE) {
|
||||||
|
mbedtls_ecdsa_free(ecdsa);
|
||||||
|
return HSM_WRONG_DATA;
|
||||||
|
}
|
||||||
|
ofs += len;
|
||||||
|
|
||||||
|
//N
|
||||||
|
len = get_uint16_t(kb, ofs); ofs += len+2;
|
||||||
|
|
||||||
|
//G
|
||||||
|
len = get_uint16_t(kb, ofs); ofs += len+2;
|
||||||
|
|
||||||
|
//d
|
||||||
|
len = get_uint16_t(kb, ofs); ofs += 2;
|
||||||
|
r = mbedtls_ecp_read_key(ec_id, ecdsa, kb+ofs, len);
|
||||||
|
if (r != 0) {
|
||||||
|
mbedtls_ecdsa_free(ecdsa);
|
||||||
|
return HSM_EXEC_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (key_type == 15) {
|
||||||
|
memcpy(key_ctx, kb+ofs, key_size);
|
||||||
|
}
|
||||||
|
return HSM_OK;
|
||||||
|
}
|
||||||
36
src/hsm/dkek.h
Normal file
36
src/hsm/dkek.h
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the Pico HSM distribution (https://github.com/polhenarejos/pico-hsm).
|
||||||
|
* Copyright (c) 2022 Pol Henarejos.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _DKEK_H_
|
||||||
|
#define _DKEK_H_
|
||||||
|
|
||||||
|
extern int load_dkek();
|
||||||
|
extern int save_dkek_key(const uint8_t *key);
|
||||||
|
extern int store_dkek_key();
|
||||||
|
extern void init_dkek();
|
||||||
|
extern void release_dkek();
|
||||||
|
extern void import_dkek_share(const uint8_t *share);
|
||||||
|
extern int dkek_kcv(uint8_t *kcv);
|
||||||
|
extern int dkek_encrypt(uint8_t *data, size_t len);
|
||||||
|
extern int dkek_decrypt(uint8_t *data, size_t len);
|
||||||
|
extern int dkek_encode_key(void *key_ctx, int key_type, uint8_t *out, size_t *out_len);
|
||||||
|
extern int dkek_type_key(const uint8_t *in);
|
||||||
|
extern int dkek_decode_key(void *key_ctx, const uint8_t *in, size_t in_len, int *key_size_out);
|
||||||
|
|
||||||
|
#define MAX_DKEK_ENCODE_KEY_BUFFER (8+1+12+6+(8+2*4+2*4096/8+3+13)+16)
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -1,9 +1,21 @@
|
|||||||
/**
|
/*
|
||||||
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
|
* This file is part of the Pico HSM distribution (https://github.com/polhenarejos/pico-hsm).
|
||||||
|
* Copyright (c) 2022 Pol Henarejos.
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: BSD-3-Clause
|
* 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 <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
// Pico
|
// Pico
|
||||||
@@ -17,14 +29,10 @@
|
|||||||
#include "tusb.h"
|
#include "tusb.h"
|
||||||
#include "usb_descriptors.h"
|
#include "usb_descriptors.h"
|
||||||
#include "device/usbd_pvt.h"
|
#include "device/usbd_pvt.h"
|
||||||
#include "pico/util/queue.h"
|
|
||||||
#include "pico/multicore.h"
|
#include "pico/multicore.h"
|
||||||
#include "gnuk.h"
|
|
||||||
#include "config.h"
|
|
||||||
#include "random.h"
|
#include "random.h"
|
||||||
|
|
||||||
// Device descriptors
|
|
||||||
#include "hsm2040.h"
|
#include "hsm2040.h"
|
||||||
|
#include "hardware/rtc.h"
|
||||||
|
|
||||||
extern void do_flash();
|
extern void do_flash();
|
||||||
extern void low_flash_init();
|
extern void low_flash_init();
|
||||||
@@ -85,7 +93,8 @@ app_t *current_app = NULL;
|
|||||||
|
|
||||||
extern void card_thread();
|
extern void card_thread();
|
||||||
|
|
||||||
static queue_t *card_comm;
|
queue_t *card_comm = NULL;
|
||||||
|
queue_t *ccid_comm = NULL;
|
||||||
extern void low_flash_init_core1();
|
extern void low_flash_init_core1();
|
||||||
|
|
||||||
int register_app(app_t * (*select_aid)()) {
|
int register_app(app_t * (*select_aid)()) {
|
||||||
@@ -293,7 +302,7 @@ static uint16_t ccid_open(uint8_t rhport, tusb_desc_interface_t const *itf_desc,
|
|||||||
vendord_open(rhport, (tusb_desc_interface_t *)itf_vendor, max_len);
|
vendord_open(rhport, (tusb_desc_interface_t *)itf_vendor, max_len);
|
||||||
free(itf_vendor);
|
free(itf_vendor);
|
||||||
|
|
||||||
uint16_t const drv_len = sizeof(tusb_desc_interface_t) + sizeof(class_desc_ccid_t) + 2*sizeof(tusb_desc_endpoint_t);
|
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;
|
||||||
@@ -365,22 +374,28 @@ usbd_class_driver_t const *usbd_app_driver_get_cb(uint8_t *driver_count) {
|
|||||||
return &ccid_driver;
|
return &ccid_driver;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum {
|
|
||||||
BLINK_NOT_MOUNTED = (250 << 16) | 250,
|
|
||||||
BLINK_MOUNTED = (250 << 16) | 250,
|
|
||||||
BLINK_SUSPENDED = (500 << 16) | 1000,
|
|
||||||
BLINK_PROCESSING = (50 << 16) | 50,
|
|
||||||
|
|
||||||
BLINK_RED = 18,
|
|
||||||
BLINK_GREEN = 19,
|
|
||||||
BLINK_BLUE = 20,
|
|
||||||
|
|
||||||
BLINK_ALWAYS_ON = UINT32_MAX,
|
|
||||||
BLINK_ALWAYS_OFF = 0
|
|
||||||
};
|
|
||||||
|
|
||||||
static uint32_t blink_interval_ms = BLINK_NOT_MOUNTED;
|
static uint32_t blink_interval_ms = BLINK_NOT_MOUNTED;
|
||||||
|
|
||||||
|
void led_set_blink(uint32_t mode) {
|
||||||
|
blink_interval_ms = mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
void execute_tasks();
|
||||||
|
|
||||||
|
static void wait_button() {
|
||||||
|
led_set_blink((1000 << 16) | 100);
|
||||||
|
while (board_button_read() == false) {
|
||||||
|
execute_tasks();
|
||||||
|
//sleep_ms(10);
|
||||||
|
}
|
||||||
|
while (board_button_read() == true) {
|
||||||
|
execute_tasks();
|
||||||
|
//sleep_ms(10);
|
||||||
|
}
|
||||||
|
led_set_blink(BLINK_PROCESSING);
|
||||||
|
}
|
||||||
|
|
||||||
void usb_tx_enable(const uint8_t *buf, uint32_t len)
|
void usb_tx_enable(const uint8_t *buf, uint32_t len)
|
||||||
{
|
{
|
||||||
if (len > 0) {
|
if (len > 0) {
|
||||||
@@ -480,7 +495,7 @@ static enum ccid_state ccid_power_on(struct ccid *c)
|
|||||||
|
|
||||||
DEBUG_INFO("ON\r\n");
|
DEBUG_INFO("ON\r\n");
|
||||||
c->tx_busy = 1;
|
c->tx_busy = 1;
|
||||||
blink_interval_ms = BLINK_MOUNTED;
|
led_set_blink(BLINK_MOUNTED);
|
||||||
return CCID_STATE_WAIT;
|
return CCID_STATE_WAIT;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -527,7 +542,7 @@ static enum ccid_state ccid_power_off(struct ccid *c)
|
|||||||
ccid_send_status (c);
|
ccid_send_status (c);
|
||||||
DEBUG_INFO ("OFF\r\n");
|
DEBUG_INFO ("OFF\r\n");
|
||||||
c->tx_busy = 1;
|
c->tx_busy = 1;
|
||||||
blink_interval_ms = BLINK_SUSPENDED;
|
led_set_blink(BLINK_SUSPENDED);
|
||||||
return CCID_STATE_START;
|
return CCID_STATE_START;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1371,7 +1386,7 @@ void prepare_ccid()
|
|||||||
}
|
}
|
||||||
|
|
||||||
int process_apdu() {
|
int process_apdu() {
|
||||||
blink_interval_ms = BLINK_PROCESSING;
|
led_set_blink(BLINK_PROCESSING);
|
||||||
if (!current_app) {
|
if (!current_app) {
|
||||||
if (INS(apdu) == 0xA4 && P1(apdu) == 0x04 && (P2(apdu) == 0x00 || P2(apdu) == 0x4)) { //select by AID
|
if (INS(apdu) == 0xA4 && P1(apdu) == 0x04 && (P2(apdu) == 0x00 || P2(apdu) == 0x4)) { //select by AID
|
||||||
for (int a = 0; a < num_apps; a++) {
|
for (int a = 0; a < num_apps; a++) {
|
||||||
@@ -1401,7 +1416,7 @@ static void card_init (void)
|
|||||||
|
|
||||||
void card_thread()
|
void card_thread()
|
||||||
{
|
{
|
||||||
queue_t *ccid_comm = (queue_t *)multicore_fifo_pop_blocking();
|
ccid_comm = (queue_t *)multicore_fifo_pop_blocking();
|
||||||
card_comm = (queue_t *)multicore_fifo_pop_blocking();
|
card_comm = (queue_t *)multicore_fifo_pop_blocking();
|
||||||
|
|
||||||
card_init ();
|
card_init ();
|
||||||
@@ -1526,7 +1541,7 @@ void ccid_task(void)
|
|||||||
{
|
{
|
||||||
DEBUG_INFO ("ERR05\r\n");
|
DEBUG_INFO ("ERR05\r\n");
|
||||||
}
|
}
|
||||||
blink_interval_ms = BLINK_MOUNTED;
|
led_set_blink(BLINK_MOUNTED);
|
||||||
}
|
}
|
||||||
else if (m == EV_TX_FINISHED)
|
else if (m == EV_TX_FINISHED)
|
||||||
{
|
{
|
||||||
@@ -1537,6 +1552,11 @@ void ccid_task(void)
|
|||||||
if (c->state == APDU_STATE_WAIT_COMMAND || c->state == APDU_STATE_COMMAND_CHAINING || c->state == APDU_STATE_RESULT_GET_RESPONSE)
|
if (c->state == APDU_STATE_WAIT_COMMAND || c->state == APDU_STATE_COMMAND_CHAINING || c->state == APDU_STATE_RESULT_GET_RESPONSE)
|
||||||
ccid_prepare_receive(c);
|
ccid_prepare_receive(c);
|
||||||
}
|
}
|
||||||
|
else if (m == EV_PRESS_BUTTON) {
|
||||||
|
wait_button();
|
||||||
|
uint32_t flag = EV_BUTTON_PRESSED;
|
||||||
|
queue_try_add(&c->card_comm, &flag);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else /* Timeout */
|
else /* Timeout */
|
||||||
{
|
{
|
||||||
@@ -1566,10 +1586,15 @@ void tud_mount_cb()
|
|||||||
|
|
||||||
void led_blinking_task()
|
void led_blinking_task()
|
||||||
{
|
{
|
||||||
|
#ifdef PICO_DEFAULT_LED_PIN
|
||||||
static uint32_t start_ms = 0;
|
static uint32_t start_ms = 0;
|
||||||
static uint8_t led_state = false;
|
static uint8_t led_state = false;
|
||||||
static uint8_t led_color = BLINK_RED;
|
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;
|
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
|
||||||
|
|
||||||
|
|
||||||
// Blink every interval ms
|
// Blink every interval ms
|
||||||
@@ -1579,33 +1604,69 @@ void led_blinking_task()
|
|||||||
|
|
||||||
gpio_put(led_color, led_state);
|
gpio_put(led_color, led_state);
|
||||||
led_state ^= 1; // toggle
|
led_state ^= 1; // toggle
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void led_off_all()
|
void led_off_all()
|
||||||
{
|
{
|
||||||
gpio_put(18, 1);
|
#ifdef PIMORONI_TINY2040
|
||||||
gpio_put(19, 1);
|
gpio_put(TINY2040_LED_R_PIN, 1);
|
||||||
gpio_put(20, 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();
|
||||||
|
|
||||||
pico_unique_board_id_t unique_id;
|
pico_unique_board_id_t unique_id;
|
||||||
|
|
||||||
|
void execute_tasks() {
|
||||||
|
prev_millis = board_millis();
|
||||||
|
ccid_task();
|
||||||
|
tud_task(); // tinyusb device task
|
||||||
|
led_blinking_task();
|
||||||
|
}
|
||||||
|
|
||||||
int main(void)
|
int main(void)
|
||||||
{
|
{
|
||||||
struct apdu *a = &apdu;
|
struct apdu *a = &apdu;
|
||||||
struct ccid *c = &ccid;
|
struct ccid *c = &ccid;
|
||||||
|
|
||||||
printf("BOARD INIT\r\n");
|
|
||||||
board_init();
|
board_init();
|
||||||
|
|
||||||
gpio_init(18);
|
#ifdef PIMORONI_TINY2040
|
||||||
gpio_set_dir(18, GPIO_OUT);
|
gpio_init(TINY2040_LED_R_PIN);
|
||||||
gpio_init(19);
|
gpio_set_dir(TINY2040_LED_R_PIN, GPIO_OUT);
|
||||||
gpio_set_dir(19, GPIO_OUT);
|
gpio_init(TINY2040_LED_G_PIN);
|
||||||
gpio_init(20);
|
gpio_set_dir(TINY2040_LED_G_PIN, GPIO_OUT);
|
||||||
gpio_set_dir(20, 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();
|
led_off_all();
|
||||||
|
|
||||||
@@ -1617,12 +1678,11 @@ int main(void)
|
|||||||
|
|
||||||
low_flash_init();
|
low_flash_init();
|
||||||
|
|
||||||
|
init_rtc();
|
||||||
|
|
||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
prev_millis = board_millis();
|
execute_tasks();
|
||||||
ccid_task();
|
|
||||||
tud_task(); // tinyusb device task
|
|
||||||
led_blinking_task();
|
|
||||||
neug_task();
|
neug_task();
|
||||||
do_flash();
|
do_flash();
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,18 @@
|
|||||||
/**
|
/*
|
||||||
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
|
* This file is part of the Pico HSM distribution (https://github.com/polhenarejos/pico-hsm).
|
||||||
|
* Copyright (c) 2022 Pol Henarejos.
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: BSD-3-Clause
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _HSM2040_H_
|
#ifndef _HSM2040_H_
|
||||||
@@ -11,6 +22,7 @@
|
|||||||
#include "tusb.h"
|
#include "tusb.h"
|
||||||
#include "file.h"
|
#include "file.h"
|
||||||
#include "pico/unique_id.h"
|
#include "pico/unique_id.h"
|
||||||
|
#include "pico/util/queue.h"
|
||||||
|
|
||||||
#define USB_REQ_CCID 0xA1
|
#define USB_REQ_CCID 0xA1
|
||||||
|
|
||||||
@@ -57,6 +69,42 @@ struct apdu {
|
|||||||
uint8_t *res_apdu_data;
|
uint8_t *res_apdu_data;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define MAX_CMD_APDU_DATA_SIZE (24+4+512*4)
|
||||||
|
#define MAX_RES_APDU_DATA_SIZE (5+9+512*4)
|
||||||
|
#define CCID_MSG_HEADER_SIZE 10
|
||||||
|
#define USB_LL_BUF_SIZE 64
|
||||||
|
|
||||||
|
/* CCID thread */
|
||||||
|
#define EV_CARD_CHANGE 1
|
||||||
|
#define EV_TX_FINISHED 2 /* CCID Tx finished */
|
||||||
|
#define EV_EXEC_ACK_REQUIRED 4 /* OpenPGPcard Execution ACK required */
|
||||||
|
#define EV_EXEC_FINISHED 8 /* OpenPGPcard Execution finished */
|
||||||
|
#define EV_RX_DATA_READY 16 /* USB Rx data available */
|
||||||
|
#define EV_PRESS_BUTTON 32
|
||||||
|
|
||||||
|
/* SC HSM thread */
|
||||||
|
#define EV_MODIFY_CMD_AVAILABLE 1
|
||||||
|
#define EV_VERIFY_CMD_AVAILABLE 2
|
||||||
|
#define EV_CMD_AVAILABLE 4
|
||||||
|
#define EV_EXIT 8
|
||||||
|
#define EV_BUTTON_PRESSED 16
|
||||||
|
|
||||||
|
//Variables set by core1
|
||||||
|
extern queue_t *ccid_comm;
|
||||||
|
extern queue_t *card_comm;
|
||||||
|
|
||||||
|
enum ccid_state {
|
||||||
|
CCID_STATE_NOCARD, /* No card available */
|
||||||
|
CCID_STATE_START, /* Initial */
|
||||||
|
CCID_STATE_WAIT, /* Waiting APDU */
|
||||||
|
|
||||||
|
CCID_STATE_EXECUTE, /* Executing command */
|
||||||
|
CCID_STATE_ACK_REQUIRED_0, /* Ack required (executing)*/
|
||||||
|
CCID_STATE_ACK_REQUIRED_1, /* Waiting user's ACK (execution finished) */
|
||||||
|
|
||||||
|
CCID_STATE_EXITED, /* CCID Thread Terminated */
|
||||||
|
CCID_STATE_EXEC_REQUESTED, /* Exec requested */
|
||||||
|
};
|
||||||
|
|
||||||
#define CLS(a) a.cmd_apdu_head[0]
|
#define CLS(a) a.cmd_apdu_head[0]
|
||||||
#define INS(a) a.cmd_apdu_head[1]
|
#define INS(a) a.cmd_apdu_head[1]
|
||||||
@@ -115,4 +163,16 @@ extern void low_flash_available();
|
|||||||
extern int flash_clear_file(file_t *file);
|
extern int flash_clear_file(file_t *file);
|
||||||
|
|
||||||
extern pico_unique_board_id_t unique_id;
|
extern pico_unique_board_id_t unique_id;
|
||||||
|
|
||||||
|
enum {
|
||||||
|
BLINK_NOT_MOUNTED = (250 << 16) | 250,
|
||||||
|
BLINK_MOUNTED = (250 << 16) | 250,
|
||||||
|
BLINK_SUSPENDED = (500 << 16) | 1000,
|
||||||
|
BLINK_PROCESSING = (50 << 16) | 50,
|
||||||
|
|
||||||
|
BLINK_ALWAYS_ON = UINT32_MAX,
|
||||||
|
BLINK_ALWAYS_OFF = 0
|
||||||
|
};
|
||||||
|
extern void led_set_blink(uint32_t mode);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,3 +1,20 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the Pico HSM distribution (https://github.com/polhenarejos/pico-hsm).
|
||||||
|
* Copyright (c) 2022 Pol Henarejos.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
#ifndef _SC_HSM_H_
|
#ifndef _SC_HSM_H_
|
||||||
#define _SC_HSM_H_
|
#define _SC_HSM_H_
|
||||||
|
|
||||||
@@ -9,7 +26,6 @@ extern const uint8_t sc_hsm_aid[];
|
|||||||
|
|
||||||
#define SW_BYTES_REMAINING_00() set_res_sw (0x61, 0x00)
|
#define SW_BYTES_REMAINING_00() set_res_sw (0x61, 0x00)
|
||||||
#define SW_WARNING_STATE_UNCHANGED() set_res_sw (0x62, 0x00)
|
#define SW_WARNING_STATE_UNCHANGED() set_res_sw (0x62, 0x00)
|
||||||
#define SW_PIN_BLOCKED() set_res_sw (0x63, 0x00)
|
|
||||||
#define SW_EXEC_ERROR() set_res_sw (0x64, 0x00)
|
#define SW_EXEC_ERROR() set_res_sw (0x64, 0x00)
|
||||||
#define SW_MEMORY_FAILURE() set_res_sw (0x65, 0x81)
|
#define SW_MEMORY_FAILURE() set_res_sw (0x65, 0x81)
|
||||||
#define SW_WRONG_LENGTH() set_res_sw (0x67, 0x00)
|
#define SW_WRONG_LENGTH() set_res_sw (0x67, 0x00)
|
||||||
@@ -17,7 +33,7 @@ extern const uint8_t sc_hsm_aid[];
|
|||||||
#define SW_LOGICAL_CHANNEL_NOT_SUPPORTED() set_res_sw (0x68, 0x81)
|
#define SW_LOGICAL_CHANNEL_NOT_SUPPORTED() set_res_sw (0x68, 0x81)
|
||||||
#define SW_SECURE_MESSAGING_NOT_SUPPORTED() set_res_sw (0x68, 0x82)
|
#define SW_SECURE_MESSAGING_NOT_SUPPORTED() set_res_sw (0x68, 0x82)
|
||||||
#define SW_SECURITY_STATUS_NOT_SATISFIED() set_res_sw (0x69, 0x82)
|
#define SW_SECURITY_STATUS_NOT_SATISFIED() set_res_sw (0x69, 0x82)
|
||||||
#define SW_FILE_INVALID() set_res_sw (0x69, 0x83)
|
#define SW_PIN_BLOCKED() set_res_sw (0x69, 0x83)
|
||||||
#define SW_DATA_INVALID() set_res_sw (0x69, 0x84)
|
#define SW_DATA_INVALID() set_res_sw (0x69, 0x84)
|
||||||
#define SW_CONDITIONS_NOT_SATISFIED() set_res_sw (0x69, 0x85)
|
#define SW_CONDITIONS_NOT_SATISFIED() set_res_sw (0x69, 0x85)
|
||||||
#define SW_COMMAND_NOT_ALLOWED() set_res_sw (0x69, 0x86)
|
#define SW_COMMAND_NOT_ALLOWED() set_res_sw (0x69, 0x86)
|
||||||
@@ -43,6 +59,11 @@ extern const uint8_t sc_hsm_aid[];
|
|||||||
#define HSM_ERR_BLOCKED -1004
|
#define HSM_ERR_BLOCKED -1004
|
||||||
#define HSM_NO_LOGIN -1005
|
#define HSM_NO_LOGIN -1005
|
||||||
#define HSM_EXEC_ERROR -1006
|
#define HSM_EXEC_ERROR -1006
|
||||||
|
#define HSM_WRONG_LENGTH -1007
|
||||||
|
#define HSM_WRONG_DATA -1008
|
||||||
|
#define HSM_WRONG_DKEK -1009
|
||||||
|
#define HSM_WRONG_SIGNATURE -1010
|
||||||
|
#define HSM_WRONG_PADDING -1011
|
||||||
|
|
||||||
#define ALGO_RSA_RAW 0x20 /* RSA signature with external padding */
|
#define ALGO_RSA_RAW 0x20 /* RSA signature with external padding */
|
||||||
#define ALGO_RSA_DECRYPT 0x21 /* RSA decrypt */
|
#define ALGO_RSA_DECRYPT 0x21 /* RSA decrypt */
|
||||||
@@ -60,11 +81,25 @@ extern const uint8_t sc_hsm_aid[];
|
|||||||
#define ALGO_EC_SHA256 0x73 /* ECDSA signature with SHA-256 hash */
|
#define ALGO_EC_SHA256 0x73 /* ECDSA signature with SHA-256 hash */
|
||||||
#define ALGO_EC_DH 0x80 /* ECDH key derivation */
|
#define ALGO_EC_DH 0x80 /* ECDH key derivation */
|
||||||
|
|
||||||
#define ALGO_EC_DERIVE 0x98 /* Derive EC key from EC key */
|
#define ALGO_EC_DERIVE 0x98 /* Derive EC key from EC key */
|
||||||
|
|
||||||
#define ALGO_AES_CBC_ENCRYPT 0x10
|
#define ALGO_AES_CBC_ENCRYPT 0x10
|
||||||
#define ALGO_AES_CBC_DECRYPT 0x11
|
#define ALGO_AES_CBC_DECRYPT 0x11
|
||||||
#define ALGO_AES_CMAC 0x18
|
#define ALGO_AES_CMAC 0x18
|
||||||
|
#define ALGO_AES_DERIVE 0x99
|
||||||
|
|
||||||
|
#define HSM_OPT_RRC 0x0001
|
||||||
|
#define HSM_OPT_TRANSPORT_PIN 0x0002
|
||||||
|
#define HSM_OPT_SESSION_PIN 0x0004
|
||||||
|
#define HSM_OPT_SESSION_PIN_EXPL 0x000C
|
||||||
|
#define HSM_OPT_REPLACE_PKA 0x0008
|
||||||
|
#define HSM_OPT_COMBINED_AUTH 0x0010
|
||||||
|
#define HSM_OPT_RRC_RESET_ONLY 0x0020
|
||||||
|
#define HSM_OPT_BOOTSEL_BUTTON 0x0100
|
||||||
|
|
||||||
|
#define P15_KEYTYPE_RSA 0x30
|
||||||
|
#define P15_KEYTYPE_ECC 0xA0
|
||||||
|
#define P15_KEYTYPE_AES 0xA8
|
||||||
|
|
||||||
extern int pin_reset_retries(const file_t *pin, bool);
|
extern int pin_reset_retries(const file_t *pin, bool);
|
||||||
extern int pin_wrong_retry(const file_t *pin);
|
extern int pin_wrong_retry(const file_t *pin);
|
||||||
27
src/hsm/version.h
Normal file
27
src/hsm/version.h
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the Pico HSM distribution (https://github.com/polhenarejos/pico-hsm).
|
||||||
|
* Copyright (c) 2022 Pol Henarejos.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __VERSION_H_
|
||||||
|
#define __VERSION_H_
|
||||||
|
|
||||||
|
#define HSM_VERSION 0x010C
|
||||||
|
|
||||||
|
#define HSM_VERSION_MAJOR ((HSM_VERSION >> 8) & 0xff)
|
||||||
|
#define HSM_VERSION_MINOR (HSM_VERSION & 0xff)
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
182
src/rng/neug.c
Normal file
182
src/rng/neug.c
Normal file
@@ -0,0 +1,182 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the Pico HSM distribution (https://github.com/polhenarejos/pico-hsm).
|
||||||
|
* Copyright (c) 2022 Pol Henarejos.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
//Part of the code is taken from GnuK (GPLv3)
|
||||||
|
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "pico/stdlib.h"
|
||||||
|
|
||||||
|
#include "neug.h"
|
||||||
|
#include "hardware/structs/rosc.h"
|
||||||
|
#include "hardware/gpio.h"
|
||||||
|
#include "hardware/adc.h"
|
||||||
|
#include "bsp/board.h"
|
||||||
|
#include "pico/unique_id.h"
|
||||||
|
|
||||||
|
void adc_start() {
|
||||||
|
adc_init();
|
||||||
|
adc_gpio_init(27);
|
||||||
|
adc_select_input(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void adc_stop() {
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint64_t random_word = 0xcbf29ce484222325;
|
||||||
|
static uint8_t ep_round = 0;
|
||||||
|
|
||||||
|
static void ep_init() {
|
||||||
|
random_word = 0xcbf29ce484222325;
|
||||||
|
ep_round = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Here, we assume a little endian architecture. */
|
||||||
|
static int ep_process () {
|
||||||
|
if (ep_round == 0) {
|
||||||
|
ep_init();
|
||||||
|
}
|
||||||
|
uint64_t word = 0x0;
|
||||||
|
for (int n = 0; n < 64; n++) {
|
||||||
|
uint8_t bit1, bit2;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
bit1 = rosc_hw->randombit&0xff;
|
||||||
|
//sleep_ms(1);
|
||||||
|
bit2 = rosc_hw->randombit&0xff;
|
||||||
|
} while(bit1 == bit2);
|
||||||
|
word = (word << 1) | bit1;
|
||||||
|
}
|
||||||
|
random_word ^= word^board_millis()^adc_read();
|
||||||
|
random_word *= 0x00000100000001B3;
|
||||||
|
if (++ep_round == 8) {
|
||||||
|
ep_round = 0;
|
||||||
|
return 2; //2 words
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const uint32_t *ep_output() {
|
||||||
|
return (uint32_t *)&random_word;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct rng_rb {
|
||||||
|
uint32_t *buf;
|
||||||
|
uint8_t head, tail;
|
||||||
|
uint8_t size;
|
||||||
|
unsigned int full :1;
|
||||||
|
unsigned int empty :1;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void rb_init(struct rng_rb *rb, uint32_t *p, uint8_t size) {
|
||||||
|
rb->buf = p;
|
||||||
|
rb->size = size;
|
||||||
|
rb->head = rb->tail = 0;
|
||||||
|
rb->full = 0;
|
||||||
|
rb->empty = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rb_add(struct rng_rb *rb, uint32_t v) {
|
||||||
|
rb->buf[rb->tail++] = v;
|
||||||
|
if (rb->tail == rb->size)
|
||||||
|
rb->tail = 0;
|
||||||
|
if (rb->tail == rb->head)
|
||||||
|
rb->full = 1;
|
||||||
|
rb->empty = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t rb_del(struct rng_rb *rb) {
|
||||||
|
uint32_t v = rb->buf[rb->head++];
|
||||||
|
|
||||||
|
if (rb->head == rb->size)
|
||||||
|
rb->head = 0;
|
||||||
|
if (rb->head == rb->tail)
|
||||||
|
rb->empty = 1;
|
||||||
|
rb->full = 0;
|
||||||
|
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct rng_rb the_ring_buffer;
|
||||||
|
|
||||||
|
void *neug_task() {
|
||||||
|
struct rng_rb *rb = &the_ring_buffer;
|
||||||
|
|
||||||
|
int n;
|
||||||
|
|
||||||
|
if ((n = ep_process())) {
|
||||||
|
int i;
|
||||||
|
const uint32_t *vp;
|
||||||
|
|
||||||
|
vp = ep_output();
|
||||||
|
|
||||||
|
for (i = 0; i < n; i++) {
|
||||||
|
rb_add (rb, *vp++);
|
||||||
|
if (rb->full)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void neug_init(uint32_t *buf, uint8_t size) {
|
||||||
|
pico_unique_board_id_t unique_id;
|
||||||
|
pico_get_unique_board_id(&unique_id);
|
||||||
|
const uint32_t *u = (const uint32_t *)unique_id.id;
|
||||||
|
struct rng_rb *rb = &the_ring_buffer;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
rb_init(rb, buf, size);
|
||||||
|
|
||||||
|
adc_start();
|
||||||
|
|
||||||
|
ep_init();
|
||||||
|
}
|
||||||
|
|
||||||
|
void neug_flush(void) {
|
||||||
|
struct rng_rb *rb = &the_ring_buffer;
|
||||||
|
|
||||||
|
while (!rb->empty)
|
||||||
|
rb_del (rb);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t neug_get(int kick) {
|
||||||
|
struct rng_rb *rb = &the_ring_buffer;
|
||||||
|
uint32_t v;
|
||||||
|
|
||||||
|
while (rb->empty)
|
||||||
|
neug_task();
|
||||||
|
v = rb_del(rb);
|
||||||
|
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
void neug_wait_full(void) { //should be called only on core1
|
||||||
|
struct rng_rb *rb = &the_ring_buffer;
|
||||||
|
|
||||||
|
while (!rb->full) {
|
||||||
|
sleep_ms(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void neug_fini(void) {
|
||||||
|
neug_get(1);
|
||||||
|
}
|
||||||
|
|
||||||
29
src/rng/neug.h
Normal file
29
src/rng/neug.h
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the Pico HSM distribution (https://github.com/polhenarejos/pico-hsm).
|
||||||
|
* Copyright (c) 2022 Pol Henarejos.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _NEUG_H_
|
||||||
|
#define _NEUG_H_
|
||||||
|
|
||||||
|
#define NEUG_PRE_LOOP 32
|
||||||
|
|
||||||
|
void neug_init(uint32_t *buf, uint8_t size);
|
||||||
|
uint32_t neug_get();
|
||||||
|
void neug_flush(void);
|
||||||
|
void neug_wait_full(void);
|
||||||
|
void neug_fini(void);
|
||||||
|
|
||||||
|
#endif
|
||||||
109
src/rng/random.c
Normal file
109
src/rng/random.c
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the Pico HSM distribution (https://github.com/polhenarejos/pico-hsm).
|
||||||
|
* Copyright (c) 2022 Pol Henarejos.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "neug.h"
|
||||||
|
|
||||||
|
#define RANDOM_BYTES_LENGTH 32
|
||||||
|
static uint32_t random_word[RANDOM_BYTES_LENGTH/sizeof (uint32_t)];
|
||||||
|
|
||||||
|
void random_init(void) {
|
||||||
|
int i;
|
||||||
|
|
||||||
|
neug_init(random_word, RANDOM_BYTES_LENGTH/sizeof (uint32_t));
|
||||||
|
|
||||||
|
for (i = 0; i < NEUG_PRE_LOOP; i++)
|
||||||
|
neug_get();
|
||||||
|
}
|
||||||
|
|
||||||
|
void random_fini(void) {
|
||||||
|
neug_fini ();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return pointer to random 32-byte
|
||||||
|
*/
|
||||||
|
void random_bytes_free (const uint8_t *p);
|
||||||
|
#define MAX_RANDOM_BUFFER 1024
|
||||||
|
const uint8_t * random_bytes_get(size_t len) {
|
||||||
|
if (len > MAX_RANDOM_BUFFER)
|
||||||
|
return NULL;
|
||||||
|
static uint32_t return_word[MAX_RANDOM_BUFFER/sizeof(uint32_t)];
|
||||||
|
for (int ix = 0; ix < len; ix += RANDOM_BYTES_LENGTH) {
|
||||||
|
neug_wait_full();
|
||||||
|
memcpy(return_word+ix/sizeof(uint32_t), random_word, RANDOM_BYTES_LENGTH);
|
||||||
|
random_bytes_free((const uint8_t *)random_word);
|
||||||
|
}
|
||||||
|
return (const uint8_t *)return_word;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Free pointer to random 32-byte
|
||||||
|
*/
|
||||||
|
void random_bytes_free(const uint8_t *p) {
|
||||||
|
(void)p;
|
||||||
|
memset(random_word, 0, RANDOM_BYTES_LENGTH);
|
||||||
|
neug_flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return 4-byte salt
|
||||||
|
*/
|
||||||
|
void random_get_salt(uint8_t *p) {
|
||||||
|
uint32_t rnd;
|
||||||
|
|
||||||
|
rnd = neug_get();
|
||||||
|
memcpy(p, &rnd, sizeof (uint32_t));
|
||||||
|
rnd = neug_get();
|
||||||
|
memcpy(p + sizeof (uint32_t), &rnd, sizeof (uint32_t));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Random byte iterator
|
||||||
|
*/
|
||||||
|
int random_gen(void *arg, unsigned char *out, size_t out_len) {
|
||||||
|
uint8_t *index_p = (uint8_t *)arg;
|
||||||
|
uint8_t index = index_p ? *index_p : 0;
|
||||||
|
size_t n;
|
||||||
|
|
||||||
|
while (out_len) {
|
||||||
|
neug_wait_full();
|
||||||
|
|
||||||
|
n = RANDOM_BYTES_LENGTH - index;
|
||||||
|
if (n > out_len)
|
||||||
|
n = out_len;
|
||||||
|
|
||||||
|
memcpy(out, ((unsigned char *)random_word) + index, n);
|
||||||
|
out += n;
|
||||||
|
out_len -= n;
|
||||||
|
index += n;
|
||||||
|
|
||||||
|
if (index >= RANDOM_BYTES_LENGTH) {
|
||||||
|
index = 0;
|
||||||
|
neug_flush();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (index_p)
|
||||||
|
*index_p = index;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
38
src/rng/random.h
Normal file
38
src/rng/random.h
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the Pico HSM distribution (https://github.com/polhenarejos/pico-hsm).
|
||||||
|
* Copyright (c) 2022 Pol Henarejos.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef _RANDOM_H_
|
||||||
|
#define _RANDOM_H_
|
||||||
|
|
||||||
|
#include "stdlib.h"
|
||||||
|
#include "pico/stdlib.h"
|
||||||
|
|
||||||
|
void random_init (void);
|
||||||
|
void random_fini (void);
|
||||||
|
|
||||||
|
/* 32-byte random bytes */
|
||||||
|
const uint8_t *random_bytes_get (size_t);
|
||||||
|
void random_bytes_free (const uint8_t *p);
|
||||||
|
|
||||||
|
/* 8-byte salt */
|
||||||
|
void random_get_salt (uint8_t *p);
|
||||||
|
|
||||||
|
/* iterator returning a byta at a time */
|
||||||
|
int random_gen (void *arg, unsigned char *output, size_t output_len);
|
||||||
|
|
||||||
|
#endif
|
||||||
50
src/usb/ccid.h
Normal file
50
src/usb/ccid.h
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the Pico HSM distribution (https://github.com/polhenarejos/pico-hsm).
|
||||||
|
* Copyright (c) 2022 Pol Henarejos.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _CCID_H_
|
||||||
|
#define _CCID_H_
|
||||||
|
|
||||||
|
#include "libopensc/ccid-types.h"
|
||||||
|
|
||||||
|
static const struct ccid_class_descriptor desc_ccid = {
|
||||||
|
.bLength = sizeof(struct ccid_class_descriptor),
|
||||||
|
.bDescriptorType = 0x21,
|
||||||
|
.bcdCCID = (0x0110),
|
||||||
|
.bMaxSlotIndex = 0,
|
||||||
|
.bVoltageSupport = 0x01, // 5.0V
|
||||||
|
.dwProtocols = (
|
||||||
|
0x01| // T=0
|
||||||
|
0x02), // T=1
|
||||||
|
.dwDefaultClock = (0xDFC),
|
||||||
|
.dwMaximumClock = (0xDFC),
|
||||||
|
.bNumClockSupport = 0,
|
||||||
|
.dwDataRate = (0x2580),
|
||||||
|
.dwMaxDataRate = (0x2580),
|
||||||
|
.bNumDataRatesSupported = 0,
|
||||||
|
.dwMaxIFSD = (0xFE), // IFSD is handled by the real reader driver
|
||||||
|
.dwSynchProtocols = (0),
|
||||||
|
.dwMechanical = (0),
|
||||||
|
.dwFeatures = 0x40840, //USB-ICC, short & extended APDU
|
||||||
|
.dwMaxCCIDMessageLength = 65544+10,
|
||||||
|
.bClassGetResponse = 0xFF,
|
||||||
|
.bclassEnvelope = 0xFF,
|
||||||
|
.wLcdLayout = 0x0,
|
||||||
|
.bPINSupport = 0x0,
|
||||||
|
.bMaxCCIDBusySlots = 0x01,
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
209
src/usb/usb_descriptors.c
Normal file
209
src/usb/usb_descriptors.c
Normal file
@@ -0,0 +1,209 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the Pico HSM distribution (https://github.com/polhenarejos/pico-hsm).
|
||||||
|
* Copyright (c) 2022 Pol Henarejos.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "tusb.h"
|
||||||
|
#include "usb_descriptors.h"
|
||||||
|
#include "ccid.h"
|
||||||
|
#include "pico/unique_id.h"
|
||||||
|
#include "version.h"
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef USB_VID
|
||||||
|
#define USB_VID 0xFEFF
|
||||||
|
#endif
|
||||||
|
#ifndef USB_PID
|
||||||
|
#define USB_PID 0xFCFD
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define USB_BCD 0x0200
|
||||||
|
|
||||||
|
#define USB_CONFIG_ATT_ONE TU_BIT(7)
|
||||||
|
|
||||||
|
#define MAX_USB_POWER 1
|
||||||
|
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
// Device Descriptors
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
tusb_desc_device_t const desc_device =
|
||||||
|
{
|
||||||
|
.bLength = sizeof(tusb_desc_device_t),
|
||||||
|
.bDescriptorType = TUSB_DESC_DEVICE,
|
||||||
|
.bcdUSB = (USB_BCD),
|
||||||
|
|
||||||
|
.bDeviceClass = 0x00,
|
||||||
|
.bDeviceSubClass = 0,
|
||||||
|
.bDeviceProtocol = 0,
|
||||||
|
.bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
|
||||||
|
|
||||||
|
.idVendor = (USB_VID),
|
||||||
|
.idProduct = (USB_PID),
|
||||||
|
.bcdDevice = HSM_VERSION,
|
||||||
|
|
||||||
|
.iManufacturer = 1,
|
||||||
|
.iProduct = 2,
|
||||||
|
.iSerialNumber = 3,
|
||||||
|
|
||||||
|
.bNumConfigurations = 1
|
||||||
|
};
|
||||||
|
|
||||||
|
uint8_t const * tud_descriptor_device_cb(void)
|
||||||
|
{
|
||||||
|
return (uint8_t const *) &desc_device;
|
||||||
|
}
|
||||||
|
|
||||||
|
tusb_desc_interface_t const desc_interface =
|
||||||
|
{
|
||||||
|
.bLength = sizeof(tusb_desc_interface_t),
|
||||||
|
.bDescriptorType = TUSB_DESC_INTERFACE,
|
||||||
|
.bInterfaceNumber = 0,
|
||||||
|
.bAlternateSetting = 0,
|
||||||
|
.bNumEndpoints = 2,
|
||||||
|
.bInterfaceClass = TUSB_CLASS_SMART_CARD,
|
||||||
|
.bInterfaceSubClass = 0,
|
||||||
|
.bInterfaceProtocol = 0,
|
||||||
|
.iInterface = 5,
|
||||||
|
};
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
// Configuration Descriptor
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
|
||||||
|
tusb_desc_configuration_t const desc_config =
|
||||||
|
{
|
||||||
|
.bLength = sizeof(tusb_desc_configuration_t),
|
||||||
|
.bDescriptorType = TUSB_DESC_CONFIGURATION,
|
||||||
|
.wTotalLength = (sizeof(tusb_desc_configuration_t) + sizeof(tusb_desc_interface_t) + sizeof(struct ccid_class_descriptor) + 2*sizeof(tusb_desc_endpoint_t)),
|
||||||
|
.bNumInterfaces = 1,
|
||||||
|
.bConfigurationValue = 1,
|
||||||
|
.iConfiguration = 4,
|
||||||
|
.bmAttributes = USB_CONFIG_ATT_ONE | TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP,
|
||||||
|
.bMaxPower = TUSB_DESC_CONFIG_POWER_MA(MAX_USB_POWER+1),
|
||||||
|
};
|
||||||
|
|
||||||
|
tusb_desc_endpoint_t const desc_ep1 =
|
||||||
|
{
|
||||||
|
.bLength = sizeof(tusb_desc_endpoint_t),
|
||||||
|
.bDescriptorType = TUSB_DESC_ENDPOINT,
|
||||||
|
.bEndpointAddress = TUSB_DIR_IN_MASK | 1,
|
||||||
|
.bmAttributes.xfer = TUSB_XFER_BULK,
|
||||||
|
.wMaxPacketSize.size = (64),
|
||||||
|
.bInterval = 0
|
||||||
|
};
|
||||||
|
|
||||||
|
tusb_desc_endpoint_t const desc_ep2 =
|
||||||
|
{
|
||||||
|
.bLength = sizeof(tusb_desc_endpoint_t),
|
||||||
|
.bDescriptorType = TUSB_DESC_ENDPOINT,
|
||||||
|
.bEndpointAddress = 2,
|
||||||
|
.bmAttributes.xfer = TUSB_XFER_BULK,
|
||||||
|
.wMaxPacketSize.size = (64),
|
||||||
|
.bInterval = 0
|
||||||
|
};
|
||||||
|
|
||||||
|
static uint8_t desc_config_extended[sizeof(tusb_desc_configuration_t) + sizeof(tusb_desc_interface_t) + sizeof(struct ccid_class_descriptor) + 2*sizeof(tusb_desc_endpoint_t)];
|
||||||
|
|
||||||
|
uint8_t const * tud_descriptor_configuration_cb(uint8_t index)
|
||||||
|
{
|
||||||
|
(void) index; // for multiple configurations
|
||||||
|
|
||||||
|
static uint8_t initd = 0;
|
||||||
|
if (initd == 0)
|
||||||
|
{
|
||||||
|
uint8_t *p = desc_config_extended;
|
||||||
|
memcpy(p, &desc_config, sizeof(tusb_desc_configuration_t)); p += sizeof(tusb_desc_configuration_t);
|
||||||
|
memcpy(p, &desc_interface, sizeof(tusb_desc_interface_t)); p += sizeof(tusb_desc_interface_t);
|
||||||
|
memcpy(p, &desc_ccid, sizeof(struct ccid_class_descriptor)); p += sizeof(struct ccid_class_descriptor);
|
||||||
|
memcpy(p, &desc_ep1, sizeof(tusb_desc_endpoint_t)); p += sizeof(tusb_desc_endpoint_t);
|
||||||
|
memcpy(p, &desc_ep2, sizeof(tusb_desc_endpoint_t)); p += sizeof(tusb_desc_endpoint_t);
|
||||||
|
initd = 1;
|
||||||
|
}
|
||||||
|
return (const uint8_t *)desc_config_extended;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define BOS_TOTAL_LEN (TUD_BOS_DESC_LEN)
|
||||||
|
|
||||||
|
#define MS_OS_20_DESC_LEN 0xB2
|
||||||
|
|
||||||
|
uint8_t const desc_bos[] =
|
||||||
|
{
|
||||||
|
// total length, number of device caps
|
||||||
|
TUD_BOS_DESCRIPTOR(BOS_TOTAL_LEN, 2)
|
||||||
|
};
|
||||||
|
|
||||||
|
uint8_t const * tud_descriptor_bos_cb(void)
|
||||||
|
{
|
||||||
|
return desc_bos;
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
// String Descriptors
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
|
||||||
|
// array of pointer to string descriptors
|
||||||
|
char const* string_desc_arr [] =
|
||||||
|
{
|
||||||
|
(const char[]) { 0x09, 0x04 }, // 0: is supported language is English (0x0409)
|
||||||
|
"Pol Henarejos", // 1: Manufacturer
|
||||||
|
"Pico HSM", // 2: Product
|
||||||
|
"11223344", // 3: Serials, should use chip ID
|
||||||
|
"Pico HSM Config", // 4: Vendor Interface
|
||||||
|
"Pico HSM Interface"
|
||||||
|
};
|
||||||
|
|
||||||
|
static uint16_t _desc_str[32];
|
||||||
|
|
||||||
|
uint16_t const* tud_descriptor_string_cb(uint8_t index, uint16_t langid)
|
||||||
|
{
|
||||||
|
(void) langid;
|
||||||
|
|
||||||
|
uint8_t chr_count;
|
||||||
|
|
||||||
|
if (index == 0) {
|
||||||
|
memcpy(&_desc_str[1], string_desc_arr[0], 2);
|
||||||
|
chr_count = 1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Note: the 0xEE index string is a Microsoft OS 1.0 Descriptors.
|
||||||
|
// https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/microsoft-defined-usb-descriptors
|
||||||
|
|
||||||
|
if ( !(index < sizeof(string_desc_arr)/sizeof(string_desc_arr[0])) )
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
const char* str = string_desc_arr[index];
|
||||||
|
char unique_id_str[2 * PICO_UNIQUE_BOARD_ID_SIZE_BYTES + 1];
|
||||||
|
if (index == 3) {
|
||||||
|
pico_unique_board_id_t unique_id;
|
||||||
|
pico_get_unique_board_id(&unique_id);
|
||||||
|
pico_get_unique_board_id_string(unique_id_str, 2 * PICO_UNIQUE_BOARD_ID_SIZE_BYTES + 1);
|
||||||
|
str = unique_id_str;
|
||||||
|
}
|
||||||
|
|
||||||
|
chr_count = strlen(str);
|
||||||
|
if ( chr_count > 31 )
|
||||||
|
chr_count = 31;
|
||||||
|
|
||||||
|
// Convert ASCII string into UTF-16
|
||||||
|
for(uint8_t i=0; i<chr_count; i++) {
|
||||||
|
_desc_str[1+i] = str[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_desc_str[0] = (TUSB_DESC_STRING << 8 ) | (2*chr_count + 2);
|
||||||
|
|
||||||
|
return _desc_str;
|
||||||
|
}
|
||||||
29
src/usb/usb_descriptors.h
Normal file
29
src/usb/usb_descriptors.h
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the Pico HSM distribution (https://github.com/polhenarejos/pico-hsm).
|
||||||
|
* Copyright (c) 2022 Pol Henarejos.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef USB_DESCRIPTORS_H_
|
||||||
|
#define USB_DESCRIPTORS_H_
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
VENDOR_REQUEST_WEBUSB = 1,
|
||||||
|
VENDOR_REQUEST_MICROSOFT = 2
|
||||||
|
};
|
||||||
|
|
||||||
|
extern uint8_t const desc_ms_os_20[];
|
||||||
|
|
||||||
|
#endif /* USB_DESCRIPTORS_H_ */
|
||||||
@@ -1,237 +0,0 @@
|
|||||||
/*
|
|
||||||
* The MIT License (MIT)
|
|
||||||
*
|
|
||||||
* Copyright (c) 2019 Ha Thach (tinyusb.org)
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
|
||||||
* in the Software without restriction, including without limitation the rights
|
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be included in
|
|
||||||
* all copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
* THE SOFTWARE.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "tusb.h"
|
|
||||||
#include "usb_descriptors.h"
|
|
||||||
#include "ccid.h"
|
|
||||||
#include "pico/unique_id.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] MIDI | HID | MSC | CDC [LSB]
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef USB_VID
|
|
||||||
#define USB_VID 0xFEFF
|
|
||||||
#endif
|
|
||||||
#ifndef USB_PID
|
|
||||||
#define USB_PID 0xFCFD
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define USB_BCD 0x0200
|
|
||||||
|
|
||||||
#define USB_CONFIG_ATT_ONE TU_BIT(7)
|
|
||||||
|
|
||||||
#define MAX_USB_POWER 1
|
|
||||||
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------+
|
|
||||||
// Device Descriptors
|
|
||||||
//--------------------------------------------------------------------+
|
|
||||||
tusb_desc_device_t const desc_device =
|
|
||||||
{
|
|
||||||
.bLength = sizeof(tusb_desc_device_t),
|
|
||||||
.bDescriptorType = TUSB_DESC_DEVICE,
|
|
||||||
.bcdUSB = (USB_BCD),
|
|
||||||
|
|
||||||
// Use Interface Association Descriptor (IAD) for CDC
|
|
||||||
// As required by USB Specs IAD's subclass must be common class (2) and protocol must be IAD (1)
|
|
||||||
.bDeviceClass = 0x00,
|
|
||||||
.bDeviceSubClass = 0,
|
|
||||||
.bDeviceProtocol = 0,
|
|
||||||
.bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
|
|
||||||
|
|
||||||
.idVendor = (USB_VID),
|
|
||||||
.idProduct = (USB_PID),
|
|
||||||
.bcdDevice = (0x0301),
|
|
||||||
|
|
||||||
.iManufacturer = 1,
|
|
||||||
.iProduct = 2,
|
|
||||||
.iSerialNumber = 3,
|
|
||||||
|
|
||||||
.bNumConfigurations = 1
|
|
||||||
};
|
|
||||||
|
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
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(class_desc_ccid_t) + 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
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
// Invoked when received GET CONFIGURATION DESCRIPTOR
|
|
||||||
// Application return pointer to descriptor
|
|
||||||
// Descriptor contents must exist long enough for transfer to complete
|
|
||||||
|
|
||||||
|
|
||||||
static uint8_t desc_config_extended[sizeof(tusb_desc_configuration_t) + sizeof(tusb_desc_interface_t) + sizeof(class_desc_ccid_t) + 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(class_desc_ccid_t)); p += sizeof(class_desc_ccid_t);
|
|
||||||
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
|
|
||||||
|
|
||||||
// BOS Descriptor is required for webUSB
|
|
||||||
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
|
|
||||||
"HSM 2040", // 2: Product
|
|
||||||
"11223344", // 3: Serials, should use chip ID
|
|
||||||
"HSM 2040 Config", // 4: Vendor Interface
|
|
||||||
"HSM 2040 Interface"
|
|
||||||
};
|
|
||||||
|
|
||||||
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];
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cap at max char
|
|
||||||
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];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// first byte is length (including header), second byte is string type
|
|
||||||
_desc_str[0] = (TUSB_DESC_STRING << 8 ) | (2*chr_count + 2);
|
|
||||||
|
|
||||||
return _desc_str;
|
|
||||||
}
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
/*
|
|
||||||
* The MIT License (MIT)
|
|
||||||
*
|
|
||||||
* Copyright (c) 2019 Ha Thach (tinyusb.org)
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
|
||||||
* in the Software without restriction, including without limitation the rights
|
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be included in
|
|
||||||
* all copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
* THE SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef USB_DESCRIPTORS_H_
|
|
||||||
#define USB_DESCRIPTORS_H_
|
|
||||||
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
VENDOR_REQUEST_WEBUSB = 1,
|
|
||||||
VENDOR_REQUEST_MICROSOFT = 2
|
|
||||||
};
|
|
||||||
|
|
||||||
extern uint8_t const desc_ms_os_20[];
|
|
||||||
|
|
||||||
#endif /* USB_DESCRIPTORS_H_ */
|
|
||||||
Reference in New Issue
Block a user