mirror of
https://github.com/polhenarejos/pico-keys-sdk
synced 2026-05-29 01:21:21 +02:00
Compare commits
229 Commits
eb75ad4efa
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b3ce44f569 | ||
|
|
3ddb459e5c | ||
|
|
a9261e34ad | ||
|
|
6e2a2aef71 | ||
|
|
f4d0ca2933 | ||
|
|
e83f0b6b52 | ||
|
|
24dd4b2e69 | ||
|
|
6f9bc55004 | ||
|
|
3d55f3a991 | ||
|
|
54317f8d43 | ||
|
|
7f53d7f748 | ||
|
|
08507069bd | ||
|
|
d590a21738 | ||
|
|
141d62da01 | ||
|
|
4507bb68a6 | ||
|
|
d868a351da | ||
|
|
61457e1b8e | ||
|
|
15148acab5 | ||
|
|
d3ce3c20dc | ||
|
|
a4a1651ed4 | ||
|
|
b3c91f068d | ||
|
|
45017a514e | ||
|
|
4a168ae6c0 | ||
|
|
525b87cd72 | ||
|
|
5838d6f443 | ||
|
|
1be7acaedd | ||
|
|
49564e2e5e | ||
|
|
084aa8c44b | ||
|
|
e0a8380dcd | ||
|
|
f8db7613b6 | ||
|
|
869ef09f34 | ||
|
|
0cc24a9637 | ||
|
|
c4bffd5433 | ||
|
|
d24cdd6c16 | ||
|
|
9cb83e3abc | ||
|
|
92b8c644d8 | ||
|
|
810c1a88c3 | ||
|
|
dbc8ff4a4a | ||
|
|
e7be1171da | ||
|
|
b4813e9db2 | ||
|
|
ee13b6904a | ||
|
|
3a03000df1 | ||
|
|
707cdf7bf4 | ||
|
|
0abea5b6b2 | ||
|
|
3fa5204949 | ||
|
|
3d3b46a5b5 | ||
|
|
cbc48dd8d7 | ||
|
|
6069c3dc2e | ||
|
|
dcf747a766 | ||
|
|
3789ed3596 | ||
|
|
7ed012c6f5 | ||
|
|
b73a7e4a72 | ||
|
|
a7b143f0d8 | ||
|
|
c8b5bf8f82 | ||
|
|
a906628318 | ||
|
|
9ab9d96af5 | ||
|
|
11a8923148 | ||
|
|
0eeac93416 | ||
|
|
dfeb5b973b | ||
|
|
cc78469c01 | ||
|
|
e24eb9b150 | ||
|
|
0d3a1bdf51 | ||
|
|
3836ee70e4 | ||
|
|
50bb75bdd6 | ||
|
|
26de18608f | ||
|
|
fa07b59cc7 | ||
|
|
7db11c21f6 | ||
|
|
2b28e19e61 | ||
|
|
febae0e664 | ||
|
|
f8cbb145f4 | ||
|
|
9b4c2840c2 | ||
|
|
8099d699e4 | ||
|
|
b244d2a484 | ||
|
|
28aa1f2dcf | ||
|
|
70b1daac82 | ||
|
|
2fa03e1170 | ||
|
|
5705a3d026 | ||
|
|
32bbdc4684 | ||
|
|
194b48773a | ||
|
|
8821728cc7 | ||
|
|
7b8d09550a | ||
|
|
f84b6bed93 | ||
|
|
89d44e8c32 | ||
|
|
bfc20f4c14 | ||
|
|
44ee025416 | ||
|
|
45fc1700a3 | ||
|
|
f76bc631d2 | ||
|
|
189567eebe | ||
|
|
8df41a6789 | ||
|
|
00c03fff25 | ||
|
|
9ca3647695 | ||
|
|
89a8042634 | ||
|
|
a9ac2779b7 | ||
|
|
5e9ae65046 | ||
|
|
38cf771fc1 | ||
|
|
9c0575418e | ||
|
|
0df1914cde | ||
|
|
39c3339b38 | ||
|
|
8aad7bdef9 | ||
|
|
94ab2ccef7 | ||
|
|
e5079e510f | ||
|
|
5302942ae3 | ||
|
|
8e6c6c1fcc | ||
|
|
802a706587 | ||
|
|
34633828d7 | ||
|
|
ba1046c172 | ||
|
|
4cd437ed35 | ||
|
|
4c88d712b4 | ||
|
|
6c7b254183 | ||
|
|
1be3691a95 | ||
|
|
6b483029a5 | ||
|
|
57e88f85ee | ||
|
|
5dd2f7fa73 | ||
|
|
636f929f2d | ||
|
|
7abedc5b0e | ||
|
|
a83742cc3f | ||
|
|
766879991e | ||
|
|
b8aa0221db | ||
|
|
87e9f9e58b | ||
|
|
a4090e87f5 | ||
|
|
6f996c67c2 | ||
|
|
a51b17b54d | ||
|
|
d0faf6d6a3 | ||
|
|
61d4515ecc | ||
|
|
2cd21f7dd2 | ||
|
|
081f473815 | ||
|
|
56f4fca657 | ||
|
|
2f77e1c3fa | ||
|
|
da94e24b45 | ||
|
|
8075611f15 | ||
|
|
474e8b8b46 | ||
|
|
668b1ac1dd | ||
|
|
20f2b3b74b | ||
|
|
50488cc890 | ||
|
|
860f77a45b | ||
|
|
42267cb237 | ||
|
|
b5c2e55c71 | ||
|
|
68600291d0 | ||
|
|
132ec29424 | ||
|
|
1125b05f9c | ||
|
|
8412727e03 | ||
|
|
8a0ef0b30c | ||
|
|
f108eebb93 | ||
|
|
263e554cc6 | ||
|
|
7de98552d1 | ||
|
|
08dc94a144 | ||
|
|
7e6e3c8f3c | ||
|
|
6305ea11ab | ||
|
|
4df616082e | ||
|
|
3bf035d68a | ||
|
|
7dc7be0909 | ||
|
|
015fb61759 | ||
|
|
1f4d638119 | ||
|
|
05fe0596ef | ||
|
|
d86371bb2c | ||
|
|
8cb2484aa3 | ||
|
|
7583ecff18 | ||
|
|
09ec0767b6 | ||
|
|
d0dea3d0c5 | ||
|
|
53d3a7ac91 | ||
|
|
2438356d83 | ||
|
|
79b69bfd7e | ||
|
|
d189c2978c | ||
|
|
c1cc33fd9d | ||
|
|
2d72a157d5 | ||
|
|
711a4df490 | ||
|
|
66f31c15b6 | ||
|
|
fa119d0c6e | ||
|
|
b67e9ac143 | ||
|
|
5d3d10b62b | ||
|
|
27938f0d9b | ||
|
|
20117d1609 | ||
|
|
8f4f5373cf | ||
|
|
d4971bba19 | ||
|
|
2001006a16 | ||
|
|
7c5f729b69 | ||
|
|
07bbadf34c | ||
|
|
ed848d005f | ||
|
|
e6c0227996 | ||
|
|
84f7952817 | ||
|
|
116aca7697 | ||
|
|
d410a4cfc2 | ||
|
|
9b6d6f6736 | ||
|
|
8f907b25ba | ||
|
|
233e6594c6 | ||
|
|
eca6807f8e | ||
|
|
14d5a75571 | ||
|
|
e56624948b | ||
|
|
200d59f91b | ||
|
|
c165ae4838 | ||
|
|
0ddfdf8134 | ||
|
|
031d76737b | ||
|
|
df94d10f8f | ||
|
|
b3b2b67034 | ||
|
|
3eff2442c6 | ||
|
|
a7e1cf028b | ||
|
|
e14a12b002 | ||
|
|
d39732c613 | ||
|
|
56c2ef0cc1 | ||
|
|
9b294b9685 | ||
|
|
5048e07f81 | ||
|
|
d63ed56e0e | ||
|
|
afe2b28fab | ||
|
|
838f342877 | ||
|
|
1a1d03ab2f | ||
|
|
809dc3d16d | ||
|
|
70c0c1bf81 | ||
|
|
cff3f8f677 | ||
|
|
6f6004c57b | ||
|
|
0b49fe4e1b | ||
|
|
4edc506759 | ||
|
|
e55014cfb3 | ||
|
|
2211fafe32 | ||
|
|
276f1b2ae8 | ||
|
|
202d32d13d | ||
|
|
95f02b6ea7 | ||
|
|
2e2b78445c | ||
|
|
da44fd21d4 | ||
|
|
365567d12b | ||
|
|
a3406572cd | ||
|
|
8321db1f67 | ||
|
|
5984d1f72d | ||
|
|
685e660ec0 | ||
|
|
3863842536 | ||
|
|
113e720fca | ||
|
|
c45c97ee1f | ||
|
|
d66d1c85b9 | ||
|
|
f01aca5518 | ||
|
|
da3a7f25d0 |
50
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
50
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
## Summary
|
||||
|
||||
Describe in plain language what this PR does and why.
|
||||
|
||||
- What problem does it solve?
|
||||
- Is it a bug fix, a new feature, a cleanup/refactor…?
|
||||
|
||||
|
||||
## Details / Impact
|
||||
|
||||
Please include any relevant details:
|
||||
|
||||
- Hardware / board(s) tested:
|
||||
- Firmware / commit/base version:
|
||||
- Security impact (if any):
|
||||
- e.g. changes PIN handling, touches key storage, affects attestation, etc.
|
||||
- Behavior changes:
|
||||
- e.g. new command, new API surface, different defaults, etc.
|
||||
|
||||
|
||||
## Testing
|
||||
|
||||
How did you test this change?
|
||||
|
||||
- Steps to reproduce / validate:
|
||||
- Expected vs actual results:
|
||||
- Any logs / traces (please remove secrets):
|
||||
|
||||
|
||||
## Licensing confirmation (required)
|
||||
|
||||
By checking the box below, you confirm ALL of the following:
|
||||
|
||||
- You are the author of this contribution, or you have the right to contribute it.
|
||||
- You have read `CONTRIBUTING.md`.
|
||||
- You agree that this contribution may be merged, used, modified, and redistributed:
|
||||
- under the AGPLv3 Community Edition, **and**
|
||||
- under any proprietary / commercial / Enterprise editions of this project,
|
||||
now or in the future.
|
||||
- You understand that submitting this PR does not create any support obligation,
|
||||
SLA, or guarantee of merge.
|
||||
|
||||
**I confirm the above licensing terms:**
|
||||
|
||||
- [ ] Yes, I agree
|
||||
|
||||
|
||||
## Anything else?
|
||||
|
||||
Optional: mention known limitations, follow-ups, or if this is related to an existing Issue.
|
||||
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
*.DS_Store*
|
||||
|
||||
6
.gitmodules
vendored
6
.gitmodules
vendored
@@ -1,6 +0,0 @@
|
||||
[submodule "mbedtls"]
|
||||
path = mbedtls
|
||||
url = https://github.com/ARMmbed/mbedtls
|
||||
[submodule "tinycbor"]
|
||||
path = tinycbor
|
||||
url = https://github.com/intel/tinycbor.git
|
||||
139
CMakeLists.txt
139
CMakeLists.txt
@@ -1,82 +1,89 @@
|
||||
#
|
||||
# This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
|
||||
# Copyright (c) 2022 Pol Henarejos.
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, version 3.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
#
|
||||
# This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
|
||||
# Copyright (c) 2022 Pol Henarejos.
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, version 3.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
if(ESP_PLATFORM)
|
||||
set(EXTRA_COMPONENT_DIRS src)
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
set(USB_ITF_CCID 1)
|
||||
#set(USB_ITF_HID 1)
|
||||
include(pico_keys_sdk_import.cmake)
|
||||
project(pico_keys_sdk)
|
||||
set(EXTRA_COMPONENT_DIRS src)
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
else()
|
||||
if(NOT ENABLE_EMULATION)
|
||||
set(PICO_USE_FASTEST_SUPPORTED_CLOCK 1)
|
||||
include(pico_sdk_import.cmake)
|
||||
endif()
|
||||
|
||||
if(ENABLE_EMULATION)
|
||||
else()
|
||||
include(pico_sdk_import.cmake)
|
||||
endif()
|
||||
project(pico_rescue C CXX ASM)
|
||||
|
||||
project(pico_keys C CXX ASM)
|
||||
set(CMAKE_C_STANDARD 11)
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
|
||||
set(CMAKE_C_STANDARD 11)
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
if(NOT DEFINED __FOR_CI)
|
||||
set(__FOR_CI 0)
|
||||
endif()
|
||||
if(__FOR_CI)
|
||||
add_compile_definitions(__FOR_CI)
|
||||
endif()
|
||||
|
||||
if(ENABLE_EMULATION)
|
||||
else()
|
||||
pico_sdk_init()
|
||||
endif()
|
||||
|
||||
if (NOT DEFINED __FOR_CI)
|
||||
set(__FOR_CI 0)
|
||||
endif()
|
||||
if (__FOR_CI)
|
||||
add_definitions(-D__FOR_CI)
|
||||
endif()
|
||||
add_executable(pico_rescue)
|
||||
endif()
|
||||
|
||||
set(USB_ITF_CCID 1)
|
||||
set(USB_ITF_HID 1)
|
||||
include(pico_keys_sdk_import.cmake)
|
||||
|
||||
add_executable(pico_keys_sdk_exe)
|
||||
|
||||
target_compile_options(pico_keys_sdk_exe PUBLIC
|
||||
-Wall
|
||||
-Werror
|
||||
set(USB_ITF_WCID 1)
|
||||
include(cmake/version.cmake)
|
||||
include(cmake/options.cmake OPTIONAL)
|
||||
include(picokeys_sdk_import.cmake)
|
||||
if(NOT ESP_PLATFORM)
|
||||
set(SOURCES ${PICOKEYS_SOURCES})
|
||||
endif()
|
||||
list(APPEND SOURCES
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/fs/files.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/version.c
|
||||
)
|
||||
|
||||
if(ENABLE_EMULATION)
|
||||
target_compile_options(pico_keys_sdk_exe PUBLIC
|
||||
-fdata-sections
|
||||
-ffunction-sections
|
||||
)
|
||||
if(APPLE)
|
||||
target_link_options(pico_keys_sdk_exe PUBLIC
|
||||
-Wl,-dead_strip
|
||||
)
|
||||
else()
|
||||
target_link_options(pico_keys_sdk_exe PUBLIC
|
||||
-Wl,--gc-sections
|
||||
)
|
||||
endif (APPLE)
|
||||
else()
|
||||
pico_add_extra_outputs(pico_keys_sdk_exe)
|
||||
SET_VERSION(ver_major ver_minor "${CMAKE_CURRENT_LIST_DIR}/src/picokeys_version.h")
|
||||
|
||||
target_link_libraries(pico_keys_sdk_exe PRIVATE pico_keys_sdk pico_stdlib pico_multicore hardware_flash hardware_sync hardware_adc pico_unique_id hardware_rtc tinyusb_device tinyusb_board)
|
||||
if(ESP_PLATFORM)
|
||||
project(pico_rescue)
|
||||
endif()
|
||||
|
||||
if(NOT ESP_PLATFORM)
|
||||
target_sources(pico_rescue PUBLIC ${SOURCES})
|
||||
target_include_directories(pico_rescue PUBLIC ${INCLUDES})
|
||||
|
||||
target_compile_options(pico_rescue PRIVATE -Wall)
|
||||
if(NOT MSVC)
|
||||
target_compile_options(pico_rescue PRIVATE -Werror)
|
||||
endif()
|
||||
|
||||
if(ENABLE_EMULATION)
|
||||
if(NOT MSVC)
|
||||
target_compile_options(pico_rescue PRIVATE -fdata-sections -ffunction-sections)
|
||||
endif()
|
||||
if(APPLE)
|
||||
target_link_options(pico_rescue PRIVATE -Wl,-dead_strip)
|
||||
elseif(MSVC)
|
||||
target_compile_options(pico_rescue PRIVATE -WX)
|
||||
|
||||
target_link_libraries(pico_rescue PRIVATE wsock32 ws2_32 Bcrypt Ncrypt)
|
||||
else()
|
||||
target_link_options(pico_rescue PRIVATE -Wl,--gc-sections)
|
||||
endif()
|
||||
target_link_libraries(pico_rescue PRIVATE pthread m)
|
||||
else()
|
||||
pico_add_extra_outputs(${CMAKE_PROJECT_NAME})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
141
LICENSE
141
LICENSE
@@ -1,5 +1,5 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
GNU AFFERO GENERAL PUBLIC LICENSE
|
||||
Version 3, 19 November 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
@@ -7,17 +7,15 @@
|
||||
|
||||
Preamble
|
||||
|
||||
The GNU General Public License is a free, copyleft license for
|
||||
software and other kinds of works.
|
||||
The GNU Affero General Public License is a free, copyleft license for
|
||||
software and other kinds of works, specifically designed to ensure
|
||||
cooperation with the community in the case of network server software.
|
||||
|
||||
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
|
||||
our General Public Licenses are 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.
|
||||
software for all its users.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
@@ -26,44 +24,34 @@ 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.
|
||||
Developers that use our General Public Licenses protect your rights
|
||||
with two steps: (1) assert copyright on the software, and (2) offer
|
||||
you this License which gives you legal permission to copy, distribute
|
||||
and/or modify the software.
|
||||
|
||||
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.
|
||||
A secondary benefit of defending all users' freedom is that
|
||||
improvements made in alternate versions of the program, if they
|
||||
receive widespread use, become available for other developers to
|
||||
incorporate. Many developers of free software are heartened and
|
||||
encouraged by the resulting cooperation. However, in the case of
|
||||
software used on network servers, this result may fail to come about.
|
||||
The GNU General Public License permits making a modified version and
|
||||
letting the public access it on a server without ever releasing its
|
||||
source code to the public.
|
||||
|
||||
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.
|
||||
The GNU Affero General Public License is designed specifically to
|
||||
ensure that, in such cases, the modified source code becomes available
|
||||
to the community. It requires the operator of a network server to
|
||||
provide the source code of the modified version running there to the
|
||||
users of that server. Therefore, public use of a modified version, on
|
||||
a publicly accessible server, gives the public access to the source
|
||||
code of the modified version.
|
||||
|
||||
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.
|
||||
An older license, called the Affero General Public License and
|
||||
published by Affero, was designed to accomplish similar goals. This is
|
||||
a different license, not a version of the Affero GPL, but Affero has
|
||||
released a new version of the Affero GPL which permits relicensing under
|
||||
this license.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
@@ -72,7 +60,7 @@ modification follow.
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU General Public License.
|
||||
"This License" refers to version 3 of the GNU Affero General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
@@ -549,35 +537,45 @@ 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.
|
||||
13. Remote Network Interaction; Use with the GNU General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, if you modify the
|
||||
Program, your modified version must prominently offer all users
|
||||
interacting with it remotely through a computer network (if your version
|
||||
supports such interaction) an opportunity to receive the Corresponding
|
||||
Source of your version by providing access to the Corresponding Source
|
||||
from a network server at no charge, through some standard or customary
|
||||
means of facilitating copying of software. This Corresponding Source
|
||||
shall include the Corresponding Source for any work covered by version 3
|
||||
of the GNU General Public License that is incorporated pursuant to the
|
||||
following paragraph.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
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
|
||||
under version 3 of the GNU 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.
|
||||
but the work with which it is combined will remain governed by version
|
||||
3 of the GNU General Public License.
|
||||
|
||||
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
|
||||
the GNU Affero 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
|
||||
Program specifies that a certain numbered version of the GNU Affero 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
|
||||
GNU Affero 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
|
||||
versions of the GNU Affero 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.
|
||||
|
||||
@@ -635,40 +633,29 @@ the "copyright" line and a pointer to where the full notice is found.
|
||||
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
|
||||
it under the terms of the GNU Affero 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.
|
||||
GNU Affero 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 Affero 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".
|
||||
If your software can interact with users remotely through a computer
|
||||
network, you should also make sure that it provides a way for users to
|
||||
get its source. For example, if your program is a web application, its
|
||||
interface could display a "Source" link that leads users to an archive
|
||||
of the code. There are many ways you could offer source, and different
|
||||
solutions will be better for different programs; see section 13 for the
|
||||
specific requirements.
|
||||
|
||||
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
|
||||
For more information on this, and how to apply and follow the GNU AGPL, 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>.
|
||||
|
||||
189
cmake/build_helpers.cmake
Normal file
189
cmake/build_helpers.cmake
Normal file
@@ -0,0 +1,189 @@
|
||||
#
|
||||
# Pico Keys SDK build helper functions
|
||||
#
|
||||
|
||||
function(picokeys_apply_strict_flags)
|
||||
set(options)
|
||||
set(oneValueArgs FILTER_REGEX)
|
||||
set(multiValueArgs SOURCES)
|
||||
cmake_parse_arguments(PKAS "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
|
||||
|
||||
if(NOT PKAS_SOURCES)
|
||||
return()
|
||||
endif()
|
||||
|
||||
if (MSVC)
|
||||
set(PICOKEYS_STRICT_FLAGS
|
||||
-Wall
|
||||
-Zc:strictStrings
|
||||
-WX
|
||||
)
|
||||
else ()
|
||||
set(PICOKEYS_STRICT_FLAGS
|
||||
-pipe
|
||||
-funsigned-char
|
||||
-fstrict-aliasing
|
||||
-fdiagnostics-color=auto
|
||||
-Wextra
|
||||
-Wchar-subscripts
|
||||
-Wundef
|
||||
-Wshadow
|
||||
-Wcast-align
|
||||
-Wwrite-strings
|
||||
-Wunused
|
||||
-Wuninitialized
|
||||
-Wpointer-arith
|
||||
-Wredundant-decls
|
||||
-Winline
|
||||
-Wformat
|
||||
-Wformat-security
|
||||
-Wswitch-enum
|
||||
-Winit-self
|
||||
-Wmissing-include-dirs
|
||||
-Wempty-body
|
||||
-Wmissing-prototypes
|
||||
-Wstrict-prototypes
|
||||
-Wold-style-definition
|
||||
-Wbad-function-cast
|
||||
-Wnested-externs
|
||||
-Wmissing-declarations
|
||||
-Werror
|
||||
)
|
||||
endif()
|
||||
|
||||
foreach(src IN LISTS PKAS_SOURCES)
|
||||
if(PKAS_FILTER_REGEX)
|
||||
if(NOT src MATCHES "${PKAS_FILTER_REGEX}")
|
||||
continue()
|
||||
endif()
|
||||
endif()
|
||||
set_property(SOURCE "${src}" APPEND PROPERTY COMPILE_OPTIONS ${PICOKEYS_STRICT_FLAGS})
|
||||
endforeach()
|
||||
endfunction()
|
||||
|
||||
function(picokeys_configure_host_target)
|
||||
set(options)
|
||||
set(oneValueArgs TARGET STRICT_FILTER_REGEX MACOS_APP_BUNDLE_ID MACOS_APP_DEVELOPMENT_TEAM)
|
||||
set(multiValueArgs SOURCES INCLUDES)
|
||||
cmake_parse_arguments(PKCHT "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
|
||||
|
||||
if(NOT PKCHT_TARGET OR ESP_PLATFORM)
|
||||
return()
|
||||
endif()
|
||||
|
||||
target_sources(${PKCHT_TARGET} PUBLIC ${PKCHT_SOURCES})
|
||||
target_include_directories(${PKCHT_TARGET} PUBLIC ${PKCHT_INCLUDES})
|
||||
target_compile_options(${PKCHT_TARGET} PRIVATE -Wall)
|
||||
|
||||
picokeys_apply_strict_flags(
|
||||
SOURCES ${PKCHT_SOURCES}
|
||||
FILTER_REGEX "${PKCHT_STRICT_FILTER_REGEX}"
|
||||
)
|
||||
|
||||
if(NOT MSVC)
|
||||
target_compile_options(${PKCHT_TARGET} PRIVATE -Werror)
|
||||
|
||||
string(FIND ${CMAKE_C_COMPILER} ":" COMPILER_COLON)
|
||||
if(${COMPILER_COLON} GREATER_EQUAL 0)
|
||||
target_compile_options(${PKCHT_TARGET} PRIVATE -Wno-error=use-after-free)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(ENABLE_EMULATION)
|
||||
if(NOT MSVC)
|
||||
target_compile_options(${PKCHT_TARGET} PRIVATE -fdata-sections -ffunction-sections)
|
||||
endif()
|
||||
|
||||
if(APPLE)
|
||||
target_link_options(${PKCHT_TARGET} PRIVATE -Wl,-dead_strip)
|
||||
|
||||
if(MACOS_APP)
|
||||
target_link_libraries(${PKCHT_TARGET} PRIVATE
|
||||
"-framework Security"
|
||||
"-framework CoreFoundation"
|
||||
)
|
||||
if(CMAKE_GENERATOR STREQUAL "Xcode")
|
||||
if("${PKCHT_MACOS_APP_DEVELOPMENT_TEAM}" STREQUAL "")
|
||||
message(FATAL_ERROR "MACOS_APP=1 with Xcode requires MACOS_APP_DEVELOPMENT_TEAM")
|
||||
endif()
|
||||
target_compile_options(${PKCHT_TARGET} PRIVATE -Wno-missing-include-dirs)
|
||||
set_target_properties(${PKCHT_TARGET} PROPERTIES
|
||||
MACOSX_BUNDLE TRUE
|
||||
MACOSX_BUNDLE_GUI_IDENTIFIER "${PKCHT_MACOS_APP_BUNDLE_ID}"
|
||||
MACOSX_BUNDLE_BUNDLE_NAME "${PKCHT_TARGET}"
|
||||
XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER "${PKCHT_MACOS_APP_BUNDLE_ID}"
|
||||
XCODE_ATTRIBUTE_CODE_SIGN_STYLE "Automatic"
|
||||
XCODE_ATTRIBUTE_DEVELOPMENT_TEAM "${PKCHT_MACOS_APP_DEVELOPMENT_TEAM}"
|
||||
XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "Apple Development"
|
||||
XCODE_ATTRIBUTE_CODE_SIGN_ENTITLEMENTS "${CMAKE_CURRENT_SOURCE_DIR}/pico_novus.entitlements"
|
||||
XCODE_ATTRIBUTE_ENABLE_HARDENED_RUNTIME "YES"
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(DEBUG_APDU)
|
||||
target_compile_options(${PKCHT_TARGET} PRIVATE
|
||||
-fsanitize=address
|
||||
-g
|
||||
-O1
|
||||
-fno-omit-frame-pointer
|
||||
)
|
||||
target_link_options(${PKCHT_TARGET} PRIVATE
|
||||
-fsanitize=address
|
||||
-g
|
||||
-O1
|
||||
-fno-omit-frame-pointer
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
function(picokeys_add_macos_app_xcode_driver)
|
||||
set(options)
|
||||
set(oneValueArgs TARGET BUNDLE_ID SIGN_IDENTITY DEVELOPMENT_TEAM)
|
||||
cmake_parse_arguments(PKMXD "${options}" "${oneValueArgs}" "" ${ARGN})
|
||||
|
||||
if(NOT PKMXD_TARGET)
|
||||
return()
|
||||
endif()
|
||||
if(NOT (APPLE AND ENABLE_EMULATION AND MACOS_APP AND NOT CMAKE_GENERATOR STREQUAL "Xcode" AND NOT MACOS_APP_XCODE_DRIVER))
|
||||
return()
|
||||
endif()
|
||||
if("${PKMXD_DEVELOPMENT_TEAM}" STREQUAL "")
|
||||
message(FATAL_ERROR "MACOS_APP=1 requires MACOS_APP_DEVELOPMENT_TEAM")
|
||||
endif()
|
||||
|
||||
set(MACOS_APP_XCODE_BUILD_DIR "${CMAKE_CURRENT_SOURCE_DIR}/build-macos-app-xcode")
|
||||
set(MACOS_APP_XCODE_FORWARD_ARGS)
|
||||
get_cmake_property(_cache_vars CACHE_VARIABLES)
|
||||
foreach(_cv ${_cache_vars})
|
||||
if(_cv MATCHES "^(ENABLE_|DEBUG_APDU$|VIDPID$|USB_VID$|USB_PID$|USE_OPENSSL$|CMAKE_BUILD_TYPE$)")
|
||||
get_property(_cv_type CACHE ${_cv} PROPERTY TYPE)
|
||||
if(NOT _cv_type STREQUAL "INTERNAL")
|
||||
set(_cv_val "${${_cv}}")
|
||||
string(REPLACE ";" "\\;" _cv_val "${_cv_val}")
|
||||
list(APPEND MACOS_APP_XCODE_FORWARD_ARGS "-D${_cv}:${_cv_type}=${_cv_val}")
|
||||
endif()
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
add_custom_target(${PKMXD_TARGET}_xcode ALL
|
||||
COMMAND cmake -S "${CMAKE_CURRENT_SOURCE_DIR}" -B "${MACOS_APP_XCODE_BUILD_DIR}" -G Xcode
|
||||
-DENABLE_EMULATION=1
|
||||
-DMACOS_APP=1
|
||||
-DMACOS_APP_XCODE_DRIVER=1
|
||||
-DMACOS_APP_BUNDLE_ID="${PKMXD_BUNDLE_ID}"
|
||||
-DMACOS_APP_SIGN_IDENTITY="${PKMXD_SIGN_IDENTITY}"
|
||||
-DMACOS_APP_DEVELOPMENT_TEAM="${PKMXD_DEVELOPMENT_TEAM}"
|
||||
${MACOS_APP_XCODE_FORWARD_ARGS}
|
||||
COMMAND /bin/mkdir -p "${MACOS_APP_XCODE_BUILD_DIR}/Debug/include"
|
||||
COMMAND /bin/mkdir -p "${MACOS_APP_XCODE_BUILD_DIR}/build/pico_novus.build/Debug/DerivedSources-normal/arm64"
|
||||
COMMAND /bin/mkdir -p "${MACOS_APP_XCODE_BUILD_DIR}/build/pico_novus.build/Debug/DerivedSources/arm64"
|
||||
COMMAND /bin/mkdir -p "${MACOS_APP_XCODE_BUILD_DIR}/build/pico_novus.build/Debug/DerivedSources"
|
||||
COMMAND xcodebuild -allowProvisioningUpdates -project "${MACOS_APP_XCODE_BUILD_DIR}/${PKMXD_TARGET}.xcodeproj" -scheme "${PKMXD_TARGET}" -configuration Debug build
|
||||
COMMENT "Building signed ${PKMXD_TARGET}.app via Xcode"
|
||||
VERBATIM
|
||||
)
|
||||
endfunction()
|
||||
|
||||
131
cmake/deps.cmake
Normal file
131
cmake/deps.cmake
Normal file
@@ -0,0 +1,131 @@
|
||||
include(FetchContent)
|
||||
|
||||
option(ENABLE_EDDSA "Enable/disable EdDSA support" OFF)
|
||||
configure_bool_option(
|
||||
ENABLE_EDDSA
|
||||
""
|
||||
"EdDSA support:\t\t enabled"
|
||||
"EdDSA support:\t\t disabled"
|
||||
)
|
||||
|
||||
set(MBEDTLS_PATH "${CMAKE_CURRENT_LIST_DIR}/../third-party/mbedtls")
|
||||
set(TINYCBOR_PATH "${CMAKE_CURRENT_LIST_DIR}/../third-party/tinycbor")
|
||||
set(CJSON_PATH "${CMAKE_CURRENT_LIST_DIR}/../third-party/cjson")
|
||||
set(MLKEM_PATH "${CMAKE_CURRENT_LIST_DIR}/../third-party/mlkem")
|
||||
set(MLDSA_PATH "${CMAKE_CURRENT_LIST_DIR}/../third-party/mldsa")
|
||||
set(LIBCVC_PATH "${CMAKE_CURRENT_LIST_DIR}/../third-party/libcvc")
|
||||
|
||||
set(PICOKEYS_MBEDTLS_STD_REPO "https://github.com/Mbed-TLS/mbedtls.git")
|
||||
set(PICOKEYS_MBEDTLS_STD_REF "v3.6.6")
|
||||
set(PICOKEYS_MBEDTLS_EDDSA_REPO "https://github.com/polhenarejos/mbedtls.git")
|
||||
set(PICOKEYS_MBEDTLS_EDDSA_REF "mbedtls-3.6-eddsa")
|
||||
|
||||
set(PICOKEYS_TINYCBOR_REPO "https://github.com/intel/tinycbor.git")
|
||||
set(PICOKEYS_TINYCBOR_REF "v0.6.1")
|
||||
set(PICOKEYS_CJSON_REPO "https://github.com/DaveGamble/cJSON.git")
|
||||
set(PICOKEYS_CJSON_REF "v1.7.19")
|
||||
set(PICOKEYS_MLKEM_REPO "https://github.com/pq-code-package/mlkem-native.git")
|
||||
set(PICOKEYS_MLKEM_REF "v1.1.0")
|
||||
set(PICOKEYS_MLDSA_REPO "https://github.com/pq-code-package/mldsa-native.git")
|
||||
set(PICOKEYS_MLDSA_REF "v1.0.0-beta")
|
||||
set(PICOKEYS_LIBCVC_REPO "https://github.com/polhenarejos/libcvc.git")
|
||||
set(PICOKEYS_LIBCVC_REF "main")
|
||||
|
||||
set(PICOKEYS_FETCH_DEPS_ON_DEMAND ON CACHE BOOL "Fetch third-party deps into pico-keys-sdk/third-party when missing")
|
||||
|
||||
function(picokeys_sync_dep name repo ref dest)
|
||||
set(_marker "${dest}/.picokeys_dep_source")
|
||||
set(_need_fetch OFF)
|
||||
|
||||
if(NOT EXISTS "${dest}")
|
||||
if(NOT PICOKEYS_FETCH_DEPS_ON_DEMAND)
|
||||
message(FATAL_ERROR "${name} source code not found at ${dest}. Enable PICOKEYS_FETCH_DEPS_ON_DEMAND or provide the source tree manually.")
|
||||
endif()
|
||||
set(_need_fetch ON)
|
||||
else()
|
||||
set(_repo_ok OFF)
|
||||
set(_ref_ok OFF)
|
||||
if(EXISTS "${_marker}")
|
||||
file(STRINGS "${_marker}" _meta_lines)
|
||||
foreach(_line IN LISTS _meta_lines)
|
||||
if(_line STREQUAL "REPO=${repo}")
|
||||
set(_repo_ok ON)
|
||||
endif()
|
||||
if(_line STREQUAL "REF=${ref}")
|
||||
set(_ref_ok ON)
|
||||
endif()
|
||||
endforeach()
|
||||
endif()
|
||||
if(NOT _repo_ok OR NOT _ref_ok)
|
||||
set(_need_fetch ON)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(_need_fetch)
|
||||
message(STATUS "[deps] ${name}: repo=${repo} ref=${ref} status=updating (this may take a few seconds)")
|
||||
if(EXISTS "${dest}")
|
||||
file(REMOVE_RECURSE "${dest}")
|
||||
endif()
|
||||
execute_process(
|
||||
COMMAND git clone ${repo} ${dest}
|
||||
RESULT_VARIABLE _clone_rc
|
||||
OUTPUT_VARIABLE _clone_out
|
||||
ERROR_VARIABLE _clone_err
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
ERROR_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
if(NOT _clone_rc EQUAL 0)
|
||||
message(FATAL_ERROR "Failed to clone ${name} from ${repo}\nstdout: ${_clone_out}\nstderr: ${_clone_err}")
|
||||
endif()
|
||||
execute_process(
|
||||
COMMAND git -C ${dest} checkout ${ref}
|
||||
RESULT_VARIABLE _checkout_rc
|
||||
OUTPUT_VARIABLE _checkout_out
|
||||
ERROR_VARIABLE _checkout_err
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
ERROR_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
if(NOT _checkout_rc EQUAL 0)
|
||||
message(FATAL_ERROR "Failed to checkout ${name} ref ${ref}\nstdout: ${_checkout_out}\nstderr: ${_checkout_err}")
|
||||
endif()
|
||||
if(NOT EXISTS "${dest}")
|
||||
message(FATAL_ERROR "Failed to fetch ${name} into ${dest}")
|
||||
endif()
|
||||
file(WRITE "${_marker}" "REPO=${repo}\nREF=${ref}\n")
|
||||
else()
|
||||
message(STATUS "[deps] ${name}: repo=${repo} ref=${ref} status=cached")
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
if(NOT ESP_PLATFORM)
|
||||
if(ENABLE_EDDSA)
|
||||
set(MBEDTLS_ORIGIN "${PICOKEYS_MBEDTLS_EDDSA_REPO}")
|
||||
set(MBEDTLS_REF "${PICOKEYS_MBEDTLS_EDDSA_REF}")
|
||||
|
||||
add_compile_definitions(
|
||||
MBEDTLS_ECP_DP_ED25519_ENABLED=1
|
||||
MBEDTLS_ECP_DP_ED448_ENABLED=1
|
||||
MBEDTLS_EDDSA_C=1
|
||||
MBEDTLS_SHA3_C=1
|
||||
)
|
||||
else()
|
||||
set(MBEDTLS_ORIGIN "${PICOKEYS_MBEDTLS_STD_REPO}")
|
||||
set(MBEDTLS_REF "${PICOKEYS_MBEDTLS_STD_REF}")
|
||||
endif()
|
||||
|
||||
picokeys_sync_dep(mbedtls_dep "${MBEDTLS_ORIGIN}" "${MBEDTLS_REF}" "${MBEDTLS_PATH}")
|
||||
endif()
|
||||
|
||||
if(USB_ITF_HID)
|
||||
picokeys_sync_dep(tinycbor_dep "${PICOKEYS_TINYCBOR_REPO}" "${PICOKEYS_TINYCBOR_REF}" "${TINYCBOR_PATH}")
|
||||
endif()
|
||||
if(USB_ITF_LWIP)
|
||||
picokeys_sync_dep(cjson_dep "${PICOKEYS_CJSON_REPO}" "${PICOKEYS_CJSON_REF}" "${CJSON_PATH}")
|
||||
endif()
|
||||
if(ENABLE_PQC)
|
||||
picokeys_sync_dep(mlkem_dep "${PICOKEYS_MLKEM_REPO}" "${PICOKEYS_MLKEM_REF}" "${MLKEM_PATH}")
|
||||
picokeys_sync_dep(mldsa_dep "${PICOKEYS_MLDSA_REPO}" "${PICOKEYS_MLDSA_REF}" "${MLDSA_PATH}")
|
||||
endif()
|
||||
if(ENABLE_LIBCVC)
|
||||
picokeys_sync_dep(libcvc_dep "${PICOKEYS_LIBCVC_REPO}" "${PICOKEYS_LIBCVC_REF}" "${LIBCVC_PATH}")
|
||||
endif()
|
||||
@@ -1,4 +1,4 @@
|
||||
function(dict command dict )
|
||||
function(dict command dict)
|
||||
if(command STREQUAL SET)
|
||||
set(arg_key ${ARGV2})
|
||||
set(arg_value ${ARGV3})
|
||||
@@ -10,7 +10,6 @@ function(dict command dict )
|
||||
|
||||
list(APPEND ${dict} "${arg_key}=${arg_value}")
|
||||
set(${dict} "${${dict}}" PARENT_SCOPE)
|
||||
|
||||
elseif(command STREQUAL GET)
|
||||
set(arg_key ${ARGV2})
|
||||
set(arg_outvar ${ARGV3})
|
||||
@@ -23,7 +22,6 @@ function(dict command dict )
|
||||
list(GET ${dict} ${idx} kv)
|
||||
string(REGEX REPLACE "^[^=]+=(.*)" "\\1" value "${kv}")
|
||||
set(${arg_outvar} "${value}" PARENT_SCOPE)
|
||||
|
||||
elseif(command STREQUAL _IDX)
|
||||
set(arg_key ${ARGV2})
|
||||
set(arg_outvar ${ARGV3})
|
||||
@@ -34,10 +32,9 @@ function(dict command dict )
|
||||
set(${arg_outvar} "${idx}" PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
math(EXPR idx ${idx}+1)
|
||||
math(EXPR idx ${idx} + 1)
|
||||
endforeach()
|
||||
set(${arg_outvar} "-1" PARENT_SCOPE)
|
||||
|
||||
else()
|
||||
message(FATAL_ERROR "dict does not recognize sub-command ${command}")
|
||||
endif()
|
||||
|
||||
144
cmake/openssl.cmake
Normal file
144
cmake/openssl.cmake
Normal file
@@ -0,0 +1,144 @@
|
||||
#
|
||||
# OpenSSL wrapper configuration for Pico Keys SDK.
|
||||
# Keeps OpenSSL-specific build logic out of picokeys_sdk_import.cmake.
|
||||
#
|
||||
|
||||
if(NOT DEFINED USE_OPENSSL)
|
||||
set(USE_OPENSSL 0)
|
||||
endif()
|
||||
|
||||
set(SKIP_MBEDTLS_FOR_OPENSSL_EMULATION 0)
|
||||
set(USE_OPENSSL_EMULATION_WRAPPER 0)
|
||||
|
||||
if(ENABLE_EMULATION AND USE_OPENSSL)
|
||||
find_package(OpenSSL QUIET)
|
||||
if(OpenSSL_FOUND)
|
||||
set(SKIP_MBEDTLS_FOR_OPENSSL_EMULATION 1)
|
||||
set(USE_OPENSSL_EMULATION_WRAPPER 1)
|
||||
message(STATUS "OpenSSL backend:\t\t enabled")
|
||||
else()
|
||||
message(STATUS "OpenSSL backend:\t\t disabled (OpenSSL not found)")
|
||||
endif()
|
||||
elseif(ENABLE_EMULATION)
|
||||
message(STATUS "OpenSSL backend:\t\t disabled")
|
||||
endif()
|
||||
|
||||
if(USE_OPENSSL_EMULATION_WRAPPER)
|
||||
add_definitions(
|
||||
-Dmbedtls_platform_zeroize=openssl_mbedtls_platform_zeroize
|
||||
-Dmbedtls_sha256=openssl_mbedtls_sha256
|
||||
-Dmbedtls_sha256_init=openssl_mbedtls_sha256_init
|
||||
-Dmbedtls_sha256_free=openssl_mbedtls_sha256_free
|
||||
-Dmbedtls_sha256_starts=openssl_mbedtls_sha256_starts
|
||||
-Dmbedtls_sha256_update=openssl_mbedtls_sha256_update
|
||||
-Dmbedtls_sha256_finish=openssl_mbedtls_sha256_finish
|
||||
-Dmbedtls_md_info_from_type=openssl_mbedtls_md_info_from_type
|
||||
-Dmbedtls_md_get_size=openssl_mbedtls_md_get_size
|
||||
-Dmbedtls_md=openssl_mbedtls_md
|
||||
-Dmbedtls_md_hmac=openssl_mbedtls_md_hmac
|
||||
-Dmbedtls_md_init=openssl_mbedtls_md_init
|
||||
-Dmbedtls_md_free=openssl_mbedtls_md_free
|
||||
-Dmbedtls_md_setup=openssl_mbedtls_md_setup
|
||||
-Dmbedtls_md_starts=openssl_mbedtls_md_starts
|
||||
-Dmbedtls_md_update=openssl_mbedtls_md_update
|
||||
-Dmbedtls_md_finish=openssl_mbedtls_md_finish
|
||||
-Dmbedtls_hkdf=openssl_mbedtls_hkdf
|
||||
-Dmbedtls_aes_init=openssl_mbedtls_aes_init
|
||||
-Dmbedtls_aes_free=openssl_mbedtls_aes_free
|
||||
-Dmbedtls_aes_setkey_enc=openssl_mbedtls_aes_setkey_enc
|
||||
-Dmbedtls_aes_setkey_dec=openssl_mbedtls_aes_setkey_dec
|
||||
-Dmbedtls_aes_crypt_ecb=openssl_mbedtls_aes_crypt_ecb
|
||||
-Dmbedtls_aes_crypt_cbc=openssl_mbedtls_aes_crypt_cbc
|
||||
-Dmbedtls_aes_crypt_cfb128=openssl_mbedtls_aes_crypt_cfb128
|
||||
-Dmbedtls_aes_crypt_ofb=openssl_mbedtls_aes_crypt_ofb
|
||||
-Dmbedtls_aes_crypt_ctr=openssl_mbedtls_aes_crypt_ctr
|
||||
-Dmbedtls_aes_xts_init=openssl_mbedtls_aes_xts_init
|
||||
-Dmbedtls_aes_xts_free=openssl_mbedtls_aes_xts_free
|
||||
-Dmbedtls_aes_xts_setkey_enc=openssl_mbedtls_aes_xts_setkey_enc
|
||||
-Dmbedtls_aes_xts_setkey_dec=openssl_mbedtls_aes_xts_setkey_dec
|
||||
-Dmbedtls_aes_crypt_xts=openssl_mbedtls_aes_crypt_xts
|
||||
-Dmbedtls_gcm_init=openssl_mbedtls_gcm_init
|
||||
-Dmbedtls_gcm_free=openssl_mbedtls_gcm_free
|
||||
-Dmbedtls_gcm_setkey=openssl_mbedtls_gcm_setkey
|
||||
-Dmbedtls_gcm_crypt_and_tag=openssl_mbedtls_gcm_crypt_and_tag
|
||||
-Dmbedtls_gcm_auth_decrypt=openssl_mbedtls_gcm_auth_decrypt
|
||||
-Dmbedtls_ccm_init=openssl_mbedtls_ccm_init
|
||||
-Dmbedtls_ccm_free=openssl_mbedtls_ccm_free
|
||||
-Dmbedtls_ccm_setkey=openssl_mbedtls_ccm_setkey
|
||||
-Dmbedtls_ccm_encrypt_and_tag=openssl_mbedtls_ccm_encrypt_and_tag
|
||||
-Dmbedtls_ccm_auth_decrypt=openssl_mbedtls_ccm_auth_decrypt
|
||||
-Dmbedtls_chachapoly_init=openssl_mbedtls_chachapoly_init
|
||||
-Dmbedtls_chachapoly_free=openssl_mbedtls_chachapoly_free
|
||||
-Dmbedtls_chachapoly_setkey=openssl_mbedtls_chachapoly_setkey
|
||||
-Dmbedtls_chachapoly_encrypt_and_tag=openssl_mbedtls_chachapoly_encrypt_and_tag
|
||||
-Dmbedtls_chachapoly_auth_decrypt=openssl_mbedtls_chachapoly_auth_decrypt
|
||||
-Dmbedtls_cipher_info_from_type=openssl_mbedtls_cipher_info_from_type
|
||||
-Dmbedtls_cipher_cmac=openssl_mbedtls_cipher_cmac
|
||||
-Dmbedtls_mpi_init=openssl_mbedtls_mpi_init
|
||||
-Dmbedtls_mpi_free=openssl_mbedtls_mpi_free
|
||||
-Dmbedtls_mpi_grow=openssl_mbedtls_mpi_grow
|
||||
-Dmbedtls_mpi_lset=openssl_mbedtls_mpi_lset
|
||||
-Dmbedtls_mpi_size=openssl_mbedtls_mpi_size
|
||||
-Dmbedtls_mpi_read_binary=openssl_mbedtls_mpi_read_binary
|
||||
-Dmbedtls_mpi_read_binary_le=openssl_mbedtls_mpi_read_binary_le
|
||||
-Dmbedtls_mpi_write_binary=openssl_mbedtls_mpi_write_binary
|
||||
-Dmbedtls_mpi_write_binary_le=openssl_mbedtls_mpi_write_binary_le
|
||||
-Dmbedtls_mpi_copy=openssl_mbedtls_mpi_copy
|
||||
-Dmbedtls_mpi_cmp_mpi=openssl_mbedtls_mpi_cmp_mpi
|
||||
-Dmbedtls_mpi_cmp_int=openssl_mbedtls_mpi_cmp_int
|
||||
-Dmbedtls_mpi_add_mpi=openssl_mbedtls_mpi_add_mpi
|
||||
-Dmbedtls_mpi_add_int=openssl_mbedtls_mpi_add_int
|
||||
-Dmbedtls_mpi_sub_abs=openssl_mbedtls_mpi_sub_abs
|
||||
-Dmbedtls_mpi_mod_mpi=openssl_mbedtls_mpi_mod_mpi
|
||||
-Dmbedtls_asn1_get_tag=openssl_mbedtls_asn1_get_tag
|
||||
-Dmbedtls_asn1_get_int=openssl_mbedtls_asn1_get_int
|
||||
-Dmbedtls_asn1_get_alg_null=openssl_mbedtls_asn1_get_alg_null
|
||||
-Dmbedtls_oid_get_md_hmac=openssl_mbedtls_oid_get_md_hmac
|
||||
-Dmbedtls_pkcs5_pbkdf2_hmac_ext=openssl_mbedtls_pkcs5_pbkdf2_hmac_ext
|
||||
-Dmbedtls_pkcs5_pbes2_ext=openssl_mbedtls_pkcs5_pbes2_ext
|
||||
-Dmbedtls_rsa_gen_key=openssl_mbedtls_rsa_gen_key
|
||||
-Dmbedtls_rsa_init=openssl_mbedtls_rsa_init
|
||||
-Dmbedtls_rsa_free=openssl_mbedtls_rsa_free
|
||||
-Dmbedtls_rsa_set_padding=openssl_mbedtls_rsa_set_padding
|
||||
-Dmbedtls_rsa_get_len=openssl_mbedtls_rsa_get_len
|
||||
-Dmbedtls_rsa_import=openssl_mbedtls_rsa_import
|
||||
-Dmbedtls_rsa_complete=openssl_mbedtls_rsa_complete
|
||||
-Dmbedtls_rsa_check_pubkey=openssl_mbedtls_rsa_check_pubkey
|
||||
-Dmbedtls_rsa_check_privkey=openssl_mbedtls_rsa_check_privkey
|
||||
-Dmbedtls_ecp_curve_info_from_grp_id=openssl_mbedtls_ecp_curve_info_from_grp_id
|
||||
-Dmbedtls_ecp_get_type=openssl_mbedtls_ecp_get_type
|
||||
-Dmbedtls_ecp_group_init=openssl_mbedtls_ecp_group_init
|
||||
-Dmbedtls_ecp_group_free=openssl_mbedtls_ecp_group_free
|
||||
-Dmbedtls_ecp_group_load=openssl_mbedtls_ecp_group_load
|
||||
-Dmbedtls_ecp_keypair_init=openssl_mbedtls_ecp_keypair_init
|
||||
-Dmbedtls_ecp_keypair_free=openssl_mbedtls_ecp_keypair_free
|
||||
-Dmbedtls_ecp_gen_key=openssl_mbedtls_ecp_gen_key
|
||||
-Dmbedtls_ecp_mul=openssl_mbedtls_ecp_mul
|
||||
-Dmbedtls_ecp_read_key=openssl_mbedtls_ecp_read_key
|
||||
-Dmbedtls_ecp_write_key_ext=openssl_mbedtls_ecp_write_key_ext
|
||||
-Dmbedtls_ecp_point_read_binary=openssl_mbedtls_ecp_point_read_binary
|
||||
-Dmbedtls_ecp_point_write_binary=openssl_mbedtls_ecp_point_write_binary
|
||||
-Dmbedtls_ecp_point_edwards=openssl_mbedtls_ecp_point_edwards
|
||||
-Dmbedtls_ecp_check_pubkey=openssl_mbedtls_ecp_check_pubkey
|
||||
-Dmbedtls_ecp_check_pub_priv=openssl_mbedtls_ecp_check_pub_priv
|
||||
-Dmbedtls_ecdsa_init=openssl_mbedtls_ecdsa_init
|
||||
-Dmbedtls_ecdsa_free=openssl_mbedtls_ecdsa_free
|
||||
-Dmbedtls_ecdsa_genkey=openssl_mbedtls_ecdsa_genkey
|
||||
-Dmbedtls_rsa_private=openssl_mbedtls_rsa_private
|
||||
-Dmbedtls_rsa_pkcs1_sign=openssl_mbedtls_rsa_pkcs1_sign
|
||||
-Dmbedtls_rsa_rsassa_pkcs1_v15_sign=openssl_mbedtls_rsa_rsassa_pkcs1_v15_sign
|
||||
-Dmbedtls_rsa_pkcs1_verify=openssl_mbedtls_rsa_pkcs1_verify
|
||||
-Dmbedtls_rsa_pkcs1_decrypt=openssl_mbedtls_rsa_pkcs1_decrypt
|
||||
-Dmbedtls_ecdh_init=openssl_mbedtls_ecdh_init
|
||||
-Dmbedtls_ecdh_free=openssl_mbedtls_ecdh_free
|
||||
-Dmbedtls_ecdh_setup=openssl_mbedtls_ecdh_setup
|
||||
-Dmbedtls_ecdh_gen_public=openssl_mbedtls_ecdh_gen_public
|
||||
-Dmbedtls_ecdh_read_public=openssl_mbedtls_ecdh_read_public
|
||||
-Dmbedtls_ecdh_calc_secret=openssl_mbedtls_ecdh_calc_secret
|
||||
-Dmbedtls_ecdsa_sign=openssl_mbedtls_ecdsa_sign
|
||||
-Dmbedtls_ecdsa_verify=openssl_mbedtls_ecdsa_verify
|
||||
-Dmbedtls_ecdsa_write_signature=openssl_mbedtls_ecdsa_write_signature
|
||||
-Dmbedtls_eddsa_sign=openssl_mbedtls_eddsa_sign
|
||||
-Dmbedtls_eddsa_write_signature=openssl_mbedtls_eddsa_write_signature
|
||||
)
|
||||
endif()
|
||||
14
cmake/options.cmake
Normal file
14
cmake/options.cmake
Normal file
@@ -0,0 +1,14 @@
|
||||
macro(configure_bool_option option_name define_name enabled_msg disabled_msg)
|
||||
if(${option_name})
|
||||
if(NOT "${define_name}" STREQUAL "")
|
||||
add_compile_definitions(${define_name}=1)
|
||||
endif()
|
||||
message(STATUS "${enabled_msg}")
|
||||
else()
|
||||
if(NOT "${define_name}" STREQUAL "")
|
||||
add_compile_definitions(${define_name}=0)
|
||||
endif()
|
||||
message(STATUS "${disabled_msg}")
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
@@ -1,39 +1,39 @@
|
||||
|
||||
macro(HEXCHAR2DEC VAR VAL)
|
||||
if(${VAL} MATCHES "[0-9]")
|
||||
SET(${VAR} ${VAL})
|
||||
set(${VAR} ${VAL})
|
||||
elseif(${VAL} MATCHES "[aA]")
|
||||
SET(${VAR} 10)
|
||||
set(${VAR} 10)
|
||||
elseif(${VAL} MATCHES "[bB]")
|
||||
SET(${VAR} 11)
|
||||
set(${VAR} 11)
|
||||
elseif(${VAL} MATCHES "[cC]")
|
||||
SET(${VAR} 12)
|
||||
set(${VAR} 12)
|
||||
elseif(${VAL} MATCHES "[dD]")
|
||||
SET(${VAR} 13)
|
||||
set(${VAR} 13)
|
||||
elseif(${VAL} MATCHES "[eE]")
|
||||
SET(${VAR} 14)
|
||||
set(${VAR} 14)
|
||||
elseif(${VAL} MATCHES "[fF]")
|
||||
SET(${VAR} 15)
|
||||
set(${VAR} 15)
|
||||
else()
|
||||
MESSAGE(FATAL_ERROR "Invalid format for hexidecimal character")
|
||||
message(FATAL_ERROR "Invalid format for hexidecimal character")
|
||||
endif()
|
||||
endmacro(HEXCHAR2DEC)
|
||||
endmacro()
|
||||
|
||||
macro(HEX2DEC VAR VAL)
|
||||
SET(CURINDEX 0)
|
||||
STRING(LENGTH "${VAL}" CURLENGTH)
|
||||
SET(${VAR} 0)
|
||||
set(CURINDEX 0)
|
||||
string(LENGTH "${VAL}" CURLENGTH)
|
||||
set(${VAR} 0)
|
||||
while(CURINDEX LESS CURLENGTH)
|
||||
STRING(SUBSTRING "${VAL}" ${CURINDEX} 1 CHAR)
|
||||
string(SUBSTRING "${VAL}" ${CURINDEX} 1 CHAR)
|
||||
HEXCHAR2DEC(CHAR ${CHAR})
|
||||
MATH(EXPR POWAH "(1<<((${CURLENGTH}-${CURINDEX}-1)*4))")
|
||||
MATH(EXPR CHAR "(${CHAR}*${POWAH})")
|
||||
MATH(EXPR ${VAR} "${${VAR}}+${CHAR}")
|
||||
MATH(EXPR CURINDEX "${CURINDEX}+1")
|
||||
math(EXPR POWAH "(1 << ((${CURLENGTH} - ${CURINDEX} - 1) * 4))")
|
||||
math(EXPR CHAR "(${CHAR} * ${POWAH})")
|
||||
math(EXPR ${VAR} "${${VAR}} + ${CHAR}")
|
||||
math(EXPR CURINDEX "${CURINDEX} + 1")
|
||||
endwhile()
|
||||
endmacro(HEX2DEC)
|
||||
endmacro()
|
||||
|
||||
macro(SET_VERSION MAJOR MINOR FILE)
|
||||
set(ROLLBACK 4)
|
||||
file(READ ${FILE} ver)
|
||||
string(REGEX MATCHALL "0x([0-9A-F])([0-9A-F])([0-9A-F])([0-9A-F])" _ ${ver})
|
||||
string(CONCAT ver_major ${CMAKE_MATCH_1}${CMAKE_MATCH_2})
|
||||
@@ -41,9 +41,23 @@ macro(SET_VERSION MAJOR MINOR FILE)
|
||||
HEX2DEC(ver_major ${ver_major})
|
||||
HEX2DEC(ver_minor ${ver_minor})
|
||||
message(STATUS "Found version:\t\t ${ver_major}.${ver_minor}")
|
||||
if(NOT ENABLE_EMULATION AND NOT ESP_PLATFORM)
|
||||
pico_set_binary_version(${CMAKE_PROJECT_NAME} MAJOR ${ver_major} MINOR ${ver_minor})
|
||||
if(PICO_PLATFORM)
|
||||
if(PICO_RP2350 AND SECURE_BOOT_PKEY)
|
||||
message(STATUS "Setting rollback version:\t ${ROLLBACK}")
|
||||
pico_set_binary_version(
|
||||
${CMAKE_PROJECT_NAME}
|
||||
MAJOR ${ver_major}
|
||||
MINOR ${ver_minor}
|
||||
ROLLBACK ${ROLLBACK}
|
||||
)
|
||||
else()
|
||||
pico_set_binary_version(
|
||||
${CMAKE_PROJECT_NAME}
|
||||
MAJOR ${ver_major}
|
||||
MINOR ${ver_minor}
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
SET(${MAJOR} ${ver_major})
|
||||
SET(${MINOR} ${ver_minor})
|
||||
endmacro(SET_VERSION)
|
||||
set(${MAJOR} ${ver_major})
|
||||
set(${MINOR} ${ver_minor})
|
||||
endmacro()
|
||||
|
||||
8
config/esp32/components/cjson/CMakeLists.txt
Executable file
8
config/esp32/components/cjson/CMakeLists.txt
Executable file
@@ -0,0 +1,8 @@
|
||||
set(PICOKEYS_SDK_DIR ${CMAKE_CURRENT_LIST_DIR}/../../../..)
|
||||
|
||||
idf_component_register(
|
||||
SRCS ${CJSON_SOURCES}
|
||||
INCLUDE_DIRS ${PICOKEYS_SDK_DIR}/third-party/cjson
|
||||
)
|
||||
|
||||
idf_component_set_property(${COMPONENT_NAME} WHOLE_ARCHIVE ON)
|
||||
9
config/esp32/components/libcvc/CMakeLists.txt
Executable file
9
config/esp32/components/libcvc/CMakeLists.txt
Executable file
@@ -0,0 +1,9 @@
|
||||
set(PICOKEYS_SDK_DIR ${CMAKE_CURRENT_LIST_DIR}/../../../..)
|
||||
|
||||
idf_component_register(
|
||||
SRCS ${LIBCVC_SOURCES}
|
||||
INCLUDE_DIRS ${PICOKEYS_SDK_DIR}/third-party/libcvc/src ${PICOKEYS_SDK_DIR}/third-party/libcvc/include
|
||||
REQUIRES mbedtls
|
||||
)
|
||||
|
||||
idf_component_set_property(${COMPONENT_NAME} WHOLE_ARCHIVE ON)
|
||||
24
config/esp32/components/mldsa44/CMakeLists.txt
Normal file
24
config/esp32/components/mldsa44/CMakeLists.txt
Normal file
@@ -0,0 +1,24 @@
|
||||
set(MLDSA_DIR ${CMAKE_CURRENT_LIST_DIR}/../../../../third-party/mldsa/mldsa)
|
||||
|
||||
file(GLOB_RECURSE MLDSA_SOURCES
|
||||
${MLDSA_DIR}/src/*.c
|
||||
)
|
||||
list(FILTER MLDSA_SOURCES EXCLUDE REGEX "/native/")
|
||||
|
||||
idf_component_register(
|
||||
SRCS ${MLDSA_SOURCES}
|
||||
INCLUDE_DIRS ${MLDSA_DIR}
|
||||
)
|
||||
idf_component_set_property(${COMPONENT_NAME} WHOLE_ARCHIVE ON)
|
||||
|
||||
target_compile_definitions(${COMPONENT_LIB} PRIVATE
|
||||
MLD_CONFIG_PARAMETER_SET=44
|
||||
MLD_CONFIG_MULTILEVEL_WITH_SHARED
|
||||
MLD_CONFIG_NAMESPACE_PREFIX=mldsa
|
||||
)
|
||||
|
||||
target_compile_options(${COMPONENT_LIB} PRIVATE
|
||||
-O2
|
||||
-fno-builtin
|
||||
-fno-strict-aliasing
|
||||
)
|
||||
24
config/esp32/components/mldsa65/CMakeLists.txt
Normal file
24
config/esp32/components/mldsa65/CMakeLists.txt
Normal file
@@ -0,0 +1,24 @@
|
||||
set(MLDSA_DIR ${CMAKE_CURRENT_LIST_DIR}/../../../../third-party/mldsa/mldsa)
|
||||
|
||||
file(GLOB_RECURSE MLDSA_SOURCES
|
||||
${MLDSA_DIR}/src/*.c
|
||||
)
|
||||
list(FILTER MLDSA_SOURCES EXCLUDE REGEX "/native/")
|
||||
|
||||
idf_component_register(
|
||||
SRCS ${MLDSA_SOURCES}
|
||||
INCLUDE_DIRS ${MLDSA_DIR}
|
||||
)
|
||||
idf_component_set_property(${COMPONENT_NAME} WHOLE_ARCHIVE ON)
|
||||
|
||||
target_compile_definitions(${COMPONENT_LIB} PRIVATE
|
||||
MLD_CONFIG_PARAMETER_SET=65
|
||||
MLD_CONFIG_MULTILEVEL_NO_SHARED
|
||||
MLD_CONFIG_NAMESPACE_PREFIX=mldsa
|
||||
)
|
||||
|
||||
target_compile_options(${COMPONENT_LIB} PRIVATE
|
||||
-O2
|
||||
-fno-builtin
|
||||
-fno-strict-aliasing
|
||||
)
|
||||
24
config/esp32/components/mldsa87/CMakeLists.txt
Normal file
24
config/esp32/components/mldsa87/CMakeLists.txt
Normal file
@@ -0,0 +1,24 @@
|
||||
set(MLDSA_DIR ${CMAKE_CURRENT_LIST_DIR}/../../../../third-party/mldsa/mldsa)
|
||||
|
||||
file(GLOB_RECURSE MLDSA_SOURCES
|
||||
${MLDSA_DIR}/src/*.c
|
||||
)
|
||||
list(FILTER MLDSA_SOURCES EXCLUDE REGEX "/native/")
|
||||
|
||||
idf_component_register(
|
||||
SRCS ${MLDSA_SOURCES}
|
||||
INCLUDE_DIRS ${MLDSA_DIR}
|
||||
)
|
||||
idf_component_set_property(${COMPONENT_NAME} WHOLE_ARCHIVE ON)
|
||||
|
||||
target_compile_definitions(${COMPONENT_LIB} PRIVATE
|
||||
MLD_CONFIG_PARAMETER_SET=87
|
||||
MLD_CONFIG_MULTILEVEL_NO_SHARED
|
||||
MLD_CONFIG_NAMESPACE_PREFIX=mldsa
|
||||
)
|
||||
|
||||
target_compile_options(${COMPONENT_LIB} PRIVATE
|
||||
-O2
|
||||
-fno-builtin
|
||||
-fno-strict-aliasing
|
||||
)
|
||||
24
config/esp32/components/mlkem1024/CMakeLists.txt
Normal file
24
config/esp32/components/mlkem1024/CMakeLists.txt
Normal file
@@ -0,0 +1,24 @@
|
||||
set(MLKEM_DIR ${CMAKE_CURRENT_LIST_DIR}/../../../../third-party/mlkem/mlkem)
|
||||
|
||||
file(GLOB_RECURSE MLKEM_SOURCES
|
||||
${MLKEM_DIR}/src/*.c
|
||||
)
|
||||
list(FILTER MLKEM_SOURCES EXCLUDE REGEX "/native/")
|
||||
|
||||
idf_component_register(
|
||||
SRCS ${MLKEM_SOURCES}
|
||||
INCLUDE_DIRS ${MLKEM_DIR}
|
||||
)
|
||||
idf_component_set_property(${COMPONENT_NAME} WHOLE_ARCHIVE ON)
|
||||
|
||||
target_compile_definitions(${COMPONENT_LIB} PRIVATE
|
||||
MLK_CONFIG_PARAMETER_SET=1024
|
||||
MLK_CONFIG_MULTILEVEL_NO_SHARED
|
||||
MLK_CONFIG_NAMESPACE_PREFIX=mlkem
|
||||
)
|
||||
|
||||
target_compile_options(${COMPONENT_LIB} PRIVATE
|
||||
-O2
|
||||
-fno-builtin
|
||||
-fno-strict-aliasing
|
||||
)
|
||||
24
config/esp32/components/mlkem512/CMakeLists.txt
Normal file
24
config/esp32/components/mlkem512/CMakeLists.txt
Normal file
@@ -0,0 +1,24 @@
|
||||
set(MLKEM_DIR ${CMAKE_CURRENT_LIST_DIR}/../../../../third-party/mlkem/mlkem)
|
||||
|
||||
file(GLOB_RECURSE MLKEM_SOURCES
|
||||
${MLKEM_DIR}/src/*.c
|
||||
)
|
||||
list(FILTER MLKEM_SOURCES EXCLUDE REGEX "/native/")
|
||||
|
||||
idf_component_register(
|
||||
SRCS ${MLKEM_SOURCES}
|
||||
INCLUDE_DIRS ${MLKEM_DIR}
|
||||
)
|
||||
idf_component_set_property(${COMPONENT_NAME} WHOLE_ARCHIVE ON)
|
||||
|
||||
target_compile_definitions(${COMPONENT_LIB} PRIVATE
|
||||
MLK_CONFIG_PARAMETER_SET=512
|
||||
MLK_CONFIG_MULTILEVEL_WITH_SHARED
|
||||
MLK_CONFIG_NAMESPACE_PREFIX=mlkem
|
||||
)
|
||||
|
||||
target_compile_options(${COMPONENT_LIB} PRIVATE
|
||||
-O2
|
||||
-fno-builtin
|
||||
-fno-strict-aliasing
|
||||
)
|
||||
24
config/esp32/components/mlkem768/CMakeLists.txt
Normal file
24
config/esp32/components/mlkem768/CMakeLists.txt
Normal file
@@ -0,0 +1,24 @@
|
||||
set(MLKEM_DIR ${CMAKE_CURRENT_LIST_DIR}/../../../../third-party/mlkem/mlkem)
|
||||
|
||||
file(GLOB_RECURSE MLKEM_SOURCES
|
||||
${MLKEM_DIR}/src/*.c
|
||||
)
|
||||
list(FILTER MLKEM_SOURCES EXCLUDE REGEX "/native/")
|
||||
|
||||
idf_component_register(
|
||||
SRCS ${MLKEM_SOURCES}
|
||||
INCLUDE_DIRS ${MLKEM_DIR}
|
||||
)
|
||||
idf_component_set_property(${COMPONENT_NAME} WHOLE_ARCHIVE ON)
|
||||
|
||||
target_compile_definitions(${COMPONENT_LIB} PRIVATE
|
||||
MLK_CONFIG_PARAMETER_SET=768
|
||||
MLK_CONFIG_MULTILEVEL_NO_SHARED
|
||||
MLK_CONFIG_NAMESPACE_PREFIX=mlkem
|
||||
)
|
||||
|
||||
target_compile_options(${COMPONENT_LIB} PRIVATE
|
||||
-O2
|
||||
-fno-builtin
|
||||
-fno-strict-aliasing
|
||||
)
|
||||
46
config/esp32/components/pico-keys-sdk/CMakeLists.txt
Executable file
46
config/esp32/components/pico-keys-sdk/CMakeLists.txt
Executable file
@@ -0,0 +1,46 @@
|
||||
set(PICOKEYS_SDK_DIR ${CMAKE_CURRENT_LIST_DIR}/../../../..)
|
||||
|
||||
set(PICOKEYS_INCLUDE_DIRS
|
||||
${PICOKEYS_SDK_DIR}/src
|
||||
${PICOKEYS_SDK_DIR}/src/fs
|
||||
${PICOKEYS_SDK_DIR}/src/otp
|
||||
${PICOKEYS_SDK_DIR}/src/rng
|
||||
${PICOKEYS_SDK_DIR}/src/usb
|
||||
${PICOKEYS_SDK_DIR}/src/led
|
||||
)
|
||||
|
||||
set(PICOKEYS_REQUIRES
|
||||
bootloader_support
|
||||
esp_partition
|
||||
esp_tinyusb
|
||||
efuse
|
||||
mbedtls
|
||||
tinycbor
|
||||
lwip
|
||||
cjson
|
||||
)
|
||||
|
||||
if(ENABLE_PQC)
|
||||
list(APPEND PICOKEYS_INCLUDE_DIRS
|
||||
${PICOKEYS_SDK_DIR}/third-party/mlkem/mlkem
|
||||
${PICOKEYS_SDK_DIR}/config/mlkem
|
||||
${PICOKEYS_SDK_DIR}/third-party/mldsa/mldsa
|
||||
${PICOKEYS_SDK_DIR}/config/mldsa
|
||||
)
|
||||
list(APPEND PICOKEYS_REQUIRES
|
||||
mlkem512
|
||||
mlkem768
|
||||
mlkem1024
|
||||
mldsa44
|
||||
mldsa65
|
||||
mldsa87
|
||||
)
|
||||
endif()
|
||||
|
||||
idf_component_register(
|
||||
SRCS ${PICOKEYS_SOURCES}
|
||||
INCLUDE_DIRS ${PICOKEYS_INCLUDE_DIRS}
|
||||
REQUIRES ${PICOKEYS_REQUIRES}
|
||||
)
|
||||
|
||||
idf_component_set_property(${COMPONENT_NAME} WHOLE_ARCHIVE ON)
|
||||
@@ -1,5 +1,5 @@
|
||||
## IDF Component Manager Manifest File
|
||||
dependencies:
|
||||
espressif/esp_tinyusb: "^1.7.2"
|
||||
espressif/esp_tinyusb: "^1.7.6"
|
||||
#espressif/tinyusb: "^0.15.0"
|
||||
zorxx/neopixel: "^1.0.4"
|
||||
8
config/esp32/components/tinycbor/CMakeLists.txt
Executable file
8
config/esp32/components/tinycbor/CMakeLists.txt
Executable file
@@ -0,0 +1,8 @@
|
||||
set(PICOKEYS_SDK_DIR ${CMAKE_CURRENT_LIST_DIR}/../../../..)
|
||||
|
||||
idf_component_register(
|
||||
SRCS ${CBOR_SOURCES}
|
||||
INCLUDE_DIRS ${PICOKEYS_SDK_DIR}/third-party/tinycbor/src
|
||||
)
|
||||
|
||||
idf_component_set_property(${COMPONENT_NAME} WHOLE_ARCHIVE ON)
|
||||
@@ -1,7 +1,7 @@
|
||||
# Name, Type, SubType, Offset, Size, Flags
|
||||
# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap
|
||||
|
||||
nvs, data, nvs, 0x9000, 0x6000
|
||||
phy_init, data, phy, 0xf000, 0x1000
|
||||
factory, app, factory, 0x10000, 1M,
|
||||
nvs, data, nvs, 0x11000, 0x6000
|
||||
phy_init, data, phy, 0x17000, 0x1000
|
||||
factory, app, factory, 0x20000, 1M
|
||||
part0, 0x40, 0x1, 0x200000, 1M,
|
||||
|
||||
|
@@ -330,7 +330,7 @@
|
||||
//#define MBEDTLS_RSA_ALT
|
||||
//#define MBEDTLS_SHA1_ALT
|
||||
#ifdef PICO_RP2350
|
||||
#define MBEDTLS_SHA256_ALT
|
||||
//#define MBEDTLS_SHA256_ALT
|
||||
#endif
|
||||
//#define MBEDTLS_SHA512_ALT
|
||||
|
||||
|
||||
29
config/mldsa/mldsa_native_all.h
Normal file
29
config/mldsa/mldsa_native_all.h
Normal file
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (c) The mlkem-native project authors
|
||||
* Copyright (c) The mldsa-native project authors
|
||||
* SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT
|
||||
*/
|
||||
|
||||
#ifndef MLD_ALL_H
|
||||
#define MLD_ALL_H
|
||||
|
||||
|
||||
/* API for MLDSA-44 */
|
||||
#define MLD_CONFIG_PARAMETER_SET 44
|
||||
#include "mldsa_native.h"
|
||||
#undef MLD_CONFIG_PARAMETER_SET
|
||||
#undef MLD_H
|
||||
|
||||
/* API for MLDSA-65 */
|
||||
#define MLD_CONFIG_PARAMETER_SET 65
|
||||
#include "mldsa_native.h"
|
||||
#undef MLD_CONFIG_PARAMETER_SET
|
||||
#undef MLD_H
|
||||
|
||||
/* API for MLDSA-87 */
|
||||
#define MLD_CONFIG_PARAMETER_SET 87
|
||||
#include "mldsa_native.h"
|
||||
#undef MLD_CONFIG_PARAMETER_SET
|
||||
#undef MLD_H
|
||||
|
||||
#endif /* !MLD_ALL_H */
|
||||
10
config/mldsa/mldsa_native_config.h
Normal file
10
config/mldsa/mldsa_native_config.h
Normal file
@@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
/* Disable all native/asm backends */
|
||||
// #define MLD_CONFIG_USE_NATIVE_BACKEND_ARITH
|
||||
|
||||
/* No SuperCop */
|
||||
#define MLD_CONFIG_NO_SUPERCOP
|
||||
|
||||
/* No verification API */
|
||||
#define MLD_CONFIG_NO_VERIFY_API
|
||||
27
config/mlkem/mlkem_native_all.h
Normal file
27
config/mlkem/mlkem_native_all.h
Normal file
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (c) The mlkem-native project authors
|
||||
* SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT
|
||||
*/
|
||||
|
||||
#if !defined(MLK_ALL_H)
|
||||
#define MLK_ALL_H
|
||||
|
||||
/* API for MLKEM-512 */
|
||||
#define MLK_CONFIG_PARAMETER_SET 512
|
||||
#include "mlkem_native.h"
|
||||
#undef MLK_CONFIG_PARAMETER_SET
|
||||
#undef MLK_H
|
||||
|
||||
/* API for MLKEM-768 */
|
||||
#define MLK_CONFIG_PARAMETER_SET 768
|
||||
#include "mlkem_native.h"
|
||||
#undef MLK_CONFIG_PARAMETER_SET
|
||||
#undef MLK_H
|
||||
|
||||
/* API for MLKEM-1024 */
|
||||
#define MLK_CONFIG_PARAMETER_SET 1024
|
||||
#include "mlkem_native.h"
|
||||
#undef MLK_CONFIG_PARAMETER_SET
|
||||
#undef MLK_H
|
||||
|
||||
#endif /* !MLK_ALL_H */
|
||||
13
config/mlkem/mlkem_native_config.h
Normal file
13
config/mlkem/mlkem_native_config.h
Normal file
@@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
/* Disable all native/asm backends */
|
||||
#define MLK_NO_NATIVE_BACKENDS 1
|
||||
|
||||
/* No CBMC */
|
||||
#undef CBMC
|
||||
|
||||
/* Platform characteristics */
|
||||
#define MLK_LITTLE_ENDIAN 1
|
||||
|
||||
/* Memory model */
|
||||
#define MLK_NO_MALLOC 1
|
||||
@@ -3,16 +3,16 @@
|
||||
* 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
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
@@ -286,3 +286,9 @@ int mbedtls_sha256_finish(mbedtls_sha256_context *ctx, unsigned char *output) {
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void mbedtls_sha256_clone(mbedtls_sha256_context *dst,
|
||||
const mbedtls_sha256_context *src)
|
||||
{
|
||||
*dst = *src;
|
||||
}
|
||||
|
||||
@@ -3,22 +3,21 @@
|
||||
* 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
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _SHA256_ALT_H_
|
||||
#define _SHA256_ALT_H_
|
||||
|
||||
#include "pico_keys.h"
|
||||
#include "pico/sha256.h"
|
||||
|
||||
typedef struct mbedtls_sha256_context {
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
},
|
||||
"partitions": [
|
||||
{
|
||||
"name": "Pico Keys Firmware",
|
||||
"name": "PicoKeys Firmware",
|
||||
"id": 0,
|
||||
"start": 0,
|
||||
"size": "1024K",
|
||||
@@ -22,15 +22,30 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Pico Keys Data",
|
||||
"name": "PicoKeys Data",
|
||||
"id": 1,
|
||||
"start": "2048K",
|
||||
"size": "2048K",
|
||||
"start": "1032K",
|
||||
"size": "3064K",
|
||||
"families": ["data"],
|
||||
"permissions": {
|
||||
"secure": "rw",
|
||||
"nonsecure": "rw",
|
||||
"bootloader": "rw"
|
||||
"nonsecure": "",
|
||||
"bootloader": "r"
|
||||
},
|
||||
"link": ["owner", 0],
|
||||
"ignored_during_arm_boot": true,
|
||||
"ignored_during_riscv_boot": true
|
||||
},
|
||||
{
|
||||
"name": "PicoKeys Binding",
|
||||
"id": 2,
|
||||
"start": "1024K",
|
||||
"size": "8K",
|
||||
"families": ["data"],
|
||||
"permissions": {
|
||||
"secure": "r",
|
||||
"nonsecure": "",
|
||||
"bootloader": "w"
|
||||
},
|
||||
"link": ["owner", 0],
|
||||
"ignored_during_arm_boot": true,
|
||||
|
||||
1
mbedtls
1
mbedtls
Submodule mbedtls deleted from 107ea89daa
@@ -1,436 +0,0 @@
|
||||
#
|
||||
# This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
|
||||
# Copyright (c) 2022 Pol Henarejos.
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, version 3.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
include(pico-keys-sdk/cmake/version.cmake)
|
||||
|
||||
option(VIDPID "Set specific VID/PID from a known platform {NitroHSM, NitroFIDO2, NitroStart, NitroPro, Nitro3, Yubikey5, YubikeyNeo, YubiHSM, Gnuk, GnuPG}" "None")
|
||||
|
||||
message(STATUS "VIDPID:\t\t\t '${VIDPID}'")
|
||||
|
||||
if(VIDPID STREQUAL "NitroHSM")
|
||||
set(USB_VID 0x20A0)
|
||||
set(USB_PID 0x4230)
|
||||
elseif(VIDPID STREQUAL "NitroFIDO2")
|
||||
set(USB_VID 0x20A0)
|
||||
set(USB_PID 0x42B1)
|
||||
elseif(VIDPID STREQUAL "NitroStart")
|
||||
set(USB_VID 0x20A0)
|
||||
set(USB_PID 0x4211)
|
||||
elseif(VIDPID STREQUAL "NitroPro")
|
||||
set(USB_VID 0x20A0)
|
||||
set(USB_PID 0x4108)
|
||||
|
||||
elseif(VIDPID STREQUAL "Nitro3")
|
||||
set(USB_VID 0x20A0)
|
||||
set(USB_PID 0x42B2)
|
||||
elseif(VIDPID STREQUAL "Yubikey5")
|
||||
set(USB_VID 0x1050)
|
||||
set(USB_PID 0x0407)
|
||||
elseif(VIDPID STREQUAL "YubikeyNeo")
|
||||
set(USB_VID 0x1050)
|
||||
set(USB_PID 0x0116)
|
||||
elseif(VIDPID STREQUAL "YubiHSM")
|
||||
set(USB_VID 0x1050)
|
||||
set(USB_PID 0x0030)
|
||||
elseif(VIDPID STREQUAL "Gnuk")
|
||||
set(USB_VID 0x234B)
|
||||
set(USB_PID 0x0000)
|
||||
elseif(VIDPID STREQUAL "GnuPG")
|
||||
set(USB_VID 0x1209)
|
||||
set(USB_PID 0x2440)
|
||||
endif()
|
||||
|
||||
if(ESP_PLATFORM)
|
||||
if(DEFINED CONFIG_TINYUSB_DESC_CUSTOM_VID)
|
||||
set(USB_VID CONFIG_TINYUSB_DESC_CUSTOM_VID)
|
||||
endif()
|
||||
if(DEFINED CONFIG_TINYUSB_DESC_CUSTOM_PID)
|
||||
set(USB_PID CONFIG_TINYUSB_DESC_CUSTOM_PID)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED USB_VID)
|
||||
set(USB_VID 0xFEFF)
|
||||
endif()
|
||||
add_definitions(-DUSB_VID=${USB_VID})
|
||||
|
||||
if(NOT DEFINED USB_PID)
|
||||
set(USB_PID 0xFCFD)
|
||||
endif()
|
||||
add_definitions(-DUSB_PID=${USB_PID})
|
||||
|
||||
if(NOT DEFINED DEBUG_APDU)
|
||||
set(DEBUG_APDU 0)
|
||||
endif()
|
||||
if(NOT DEFINED ENABLE_EMULATION)
|
||||
set(ENABLE_EMULATION 0)
|
||||
endif()
|
||||
|
||||
option(ENABLE_DELAYED_BOOT "Enable/disable delayed boot" OFF)
|
||||
if(ENABLE_DELAYED_BOOT)
|
||||
add_definitions(-DPICO_XOSC_STARTUP_DELAY_MULTIPLIER=64)
|
||||
message(STATUS "Delayed boot:\t\t enabled")
|
||||
else()
|
||||
message(STATUS "Delayed boot:\t\t disabled")
|
||||
endif(ENABLE_DELAYED_BOOT)
|
||||
if(USB_ITF_HID)
|
||||
add_definitions(-DUSB_ITF_HID=1)
|
||||
message(STATUS "USB HID Interface:\t\t enabled")
|
||||
endif(USB_ITF_HID)
|
||||
if(USB_ITF_CCID)
|
||||
add_definitions(-DUSB_ITF_CCID=1)
|
||||
message(STATUS "USB CCID Interface:\t\t enabled")
|
||||
if(USB_ITF_WCID)
|
||||
add_definitions(-DUSB_ITF_WCID=1)
|
||||
message(STATUS "USB WebCCID Interface:\t enabled")
|
||||
endif(USB_ITF_WCID)
|
||||
endif(USB_ITF_CCID)
|
||||
add_definitions(-DDEBUG_APDU=${DEBUG_APDU})
|
||||
if(NOT ESP_PLATFORM)
|
||||
add_definitions(-DMBEDTLS_CONFIG_FILE="${CMAKE_CURRENT_LIST_DIR}/config/mbedtls_config.h")
|
||||
else()
|
||||
add_definitions(-DCFG_TUSB_CONFIG_FILE="${CMAKE_CURRENT_LIST_DIR}/src/usb/tusb_config.h")
|
||||
endif()
|
||||
|
||||
message(STATUS "USB VID/PID:\t\t\t ${USB_VID}:${USB_PID}")
|
||||
|
||||
if(NOT ESP_PLATFORM)
|
||||
option(ENABLE_EDDSA "Enable/disable EdDSA support" OFF)
|
||||
if(ENABLE_EDDSA)
|
||||
message(STATUS "EdDSA support:\t\t enabled")
|
||||
else()
|
||||
message(STATUS "EdDSA support:\t\t disabled")
|
||||
endif(ENABLE_EDDSA)
|
||||
|
||||
set(MBEDTLS_PATH "${CMAKE_SOURCE_DIR}/pico-keys-sdk/mbedtls")
|
||||
|
||||
if(ENABLE_EDDSA)
|
||||
set(MBEDTLS_ORIGIN "https://github.com/polhenarejos/mbedtls.git")
|
||||
set(MBEDTLS_REF "mbedtls-3.6-eddsa")
|
||||
add_definitions(-DMBEDTLS_ECP_DP_ED25519_ENABLED=1 -DMBEDTLS_ECP_DP_ED448_ENABLED=1 -DMBEDTLS_EDDSA_C=1 -DMBEDTLS_SHA3_C=1)
|
||||
else()
|
||||
set(MBEDTLS_ORIGIN "https://github.com/Mbed-TLS/mbedtls.git")
|
||||
set(MBEDTLS_REF "v3.6.3")
|
||||
endif()
|
||||
|
||||
execute_process(
|
||||
COMMAND git config --global --add safe.directory ${MBEDTLS_PATH}
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||
OUTPUT_QUIET ERROR_QUIET
|
||||
)
|
||||
|
||||
execute_process(
|
||||
COMMAND git -C ${MBEDTLS_PATH} submodule update --init --recursive pico-keys-sdk
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||
OUTPUT_QUIET ERROR_QUIET
|
||||
)
|
||||
|
||||
execute_process(
|
||||
COMMAND git -C ${MBEDTLS_PATH} remote get-url origin
|
||||
OUTPUT_VARIABLE CURRENT_ORIGIN
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
|
||||
if(NOT "${CURRENT_ORIGIN}" STREQUAL "${MBEDTLS_ORIGIN}")
|
||||
execute_process(
|
||||
COMMAND git -C ${MBEDTLS_PATH} remote set-url origin ${MBEDTLS_ORIGIN}
|
||||
OUTPUT_QUIET ERROR_QUIET
|
||||
)
|
||||
endif()
|
||||
|
||||
execute_process(
|
||||
COMMAND git -C ${MBEDTLS_PATH} rev-parse --verify ${MBEDTLS_REF}
|
||||
OUTPUT_VARIABLE CURRENT_REF
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
RESULT_VARIABLE REF_EXISTS
|
||||
)
|
||||
|
||||
if(NOT REF_EXISTS EQUAL 0 OR NOT CURRENT_REF STREQUAL "${MBEDTLS_REF}")
|
||||
|
||||
execute_process(
|
||||
COMMAND git -C ${MBEDTLS_PATH} fetch origin +refs/heads/*:refs/remotes/origin/* --tags --force
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||
OUTPUT_QUIET ERROR_QUIET
|
||||
)
|
||||
|
||||
execute_process(
|
||||
COMMAND rm -rf ${MBEDTLS_PATH}/framework
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||
OUTPUT_QUIET ERROR_QUIET
|
||||
)
|
||||
|
||||
if(ENABLE_EDDSA)
|
||||
execute_process(
|
||||
COMMAND git -C ${MBEDTLS_PATH} checkout -B ${MBEDTLS_REF} --track origin/${MBEDTLS_REF}
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||
OUTPUT_QUIET ERROR_QUIET
|
||||
)
|
||||
else()
|
||||
execute_process(
|
||||
COMMAND git -C ${MBEDTLS_PATH} checkout ${MBEDTLS_REF}
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||
OUTPUT_QUIET ERROR_QUIET
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
endif(NOT ESP_PLATFORM)
|
||||
|
||||
set(MBEDTLS_SOURCES
|
||||
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/aes.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/asn1parse.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/asn1write.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/bignum.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/bignum_core.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/ccm.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/cmac.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/cipher.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/cipher_wrap.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/constant_time.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/ecdsa.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/ecdh.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/ecp.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/ecp_curves.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/gcm.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/hkdf.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/md.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/md5.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/oid.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/pkcs5.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/platform_util.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/rsa.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/rsa_alt_helpers.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/sha1.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/sha256.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/sha512.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/chachapoly.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/chacha20.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/poly1305.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/ripemd160.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/des.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/x509write_crt.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/x509_create.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/x509write_csr.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/pk.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/pk_wrap.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/pkwrite.c
|
||||
)
|
||||
|
||||
if (ENABLE_EDDSA)
|
||||
set(MBEDTLS_SOURCES ${MBEDTLS_SOURCES}
|
||||
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/eddsa.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/sha3.c
|
||||
)
|
||||
endif()
|
||||
|
||||
set(SOURCES ${SOURCES}
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/main.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/usb/usb.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/fs/file.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/fs/flash.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/fs/low_flash.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/fs/otp.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/fs/phy.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/rng/random.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/rng/hwrng.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/eac.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/crypto_utils.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/asn1.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/apdu.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/rescue.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/led/led.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/led/led_cyw43.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/led/led_pico.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/led/led_pimoroni.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/led/led_ws2812.c
|
||||
)
|
||||
|
||||
if(ESP_PLATFORM)
|
||||
set(SOURCES ${SOURCES} ${CMAKE_CURRENT_LIST_DIR}/src/led/led_neopixel.c)
|
||||
endif()
|
||||
|
||||
## mbedTLS reports an stringop overflow for cmac.c
|
||||
if(NOT ENABLE_EMULATION AND NOT APPLE)
|
||||
set_source_files_properties(
|
||||
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/cmac.c
|
||||
PROPERTIES
|
||||
COMPILE_FLAGS "-Wno-error=stringop-overflow= -Wno-stringop-overflow"
|
||||
)
|
||||
endif()
|
||||
set(INCLUDES ${INCLUDES}
|
||||
${CMAKE_CURRENT_LIST_DIR}/src
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/usb
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/fs
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/rng
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/led
|
||||
${CMAKE_CURRENT_LIST_DIR}/mbedtls/include
|
||||
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library
|
||||
)
|
||||
|
||||
if(USB_ITF_HID)
|
||||
set(MBEDTLS_SOURCES ${MBEDTLS_SOURCES}
|
||||
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/x509write_crt.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/x509_create.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/x509write_csr.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/pk.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/pk_wrap.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/pkwrite.c
|
||||
)
|
||||
set(CBOR_SOURCES
|
||||
${CMAKE_CURRENT_LIST_DIR}/tinycbor/src/cborencoder.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/tinycbor/src/cborparser.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/tinycbor/src/cborparser_dup_string.c
|
||||
)
|
||||
|
||||
set(INCLUDES ${INCLUDES}
|
||||
${CMAKE_CURRENT_LIST_DIR}/tinycbor/src
|
||||
)
|
||||
endif()
|
||||
|
||||
set(LIBRARIES
|
||||
pico_stdlib
|
||||
pico_multicore
|
||||
pico_rand
|
||||
pico_aon_timer
|
||||
hardware_flash
|
||||
pico_unique_id
|
||||
tinyusb_device
|
||||
tinyusb_board
|
||||
hardware_pio
|
||||
)
|
||||
|
||||
set(IS_CYW43 0)
|
||||
if (NOT ENABLE_EMULATION AND NOT ESP_PLATFORM)
|
||||
file(READ ${PICO_SDK_PATH}/src/boards/include/boards/${PICO_BOARD}.h content)
|
||||
string(REGEX MATCHALL "CYW43_WL_GPIO_LED_PIN" _ ${content})
|
||||
if (CMAKE_MATCH_0)
|
||||
message(STATUS "Found cyw43 LED:\t\t true")
|
||||
set(LIBRARIES ${LIBRARIES} pico_cyw43_arch_none)
|
||||
set(IS_CYW43 1)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
function(add_impl_library target)
|
||||
add_library(${target} INTERFACE)
|
||||
string(TOUPPER ${target} TARGET_UPPER)
|
||||
target_compile_definitions(${target} INTERFACE LIB_${TARGET_UPPER}=1)
|
||||
endfunction()
|
||||
|
||||
if(USB_ITF_HID)
|
||||
set(SOURCES ${SOURCES}
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/usb/hid/hid.c
|
||||
)
|
||||
set(INCLUDES ${INCLUDES}
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/usb/hid
|
||||
)
|
||||
endif()
|
||||
|
||||
if(USB_ITF_CCID)
|
||||
set(SOURCES ${SOURCES}
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/usb/ccid/ccid.c
|
||||
)
|
||||
set(INCLUDES ${INCLUDES}
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/usb/ccid
|
||||
)
|
||||
endif()
|
||||
|
||||
add_definitions("-fmacro-prefix-map=${CMAKE_CURRENT_LIST_DIR}/=")
|
||||
|
||||
if(ENABLE_EMULATION)
|
||||
if(APPLE)
|
||||
add_definitions("-Wno-deprecated-declarations")
|
||||
elseif(MSVC)
|
||||
set(SOURCES ${SOURCES}
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/fs/mman.c
|
||||
)
|
||||
endif()
|
||||
add_definitions(-DENABLE_EMULATION)
|
||||
set(SOURCES ${SOURCES}
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/usb/emulation/emulation.c
|
||||
)
|
||||
set(MBEDTLS_SOURCES ${MBEDTLS_SOURCES}
|
||||
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/aesni.c
|
||||
)
|
||||
set(INCLUDES ${INCLUDES}
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/usb/emulation
|
||||
)
|
||||
else()
|
||||
set(SOURCES ${SOURCES}
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/usb/usb_descriptors.c
|
||||
)
|
||||
endif()
|
||||
set(EXTERNAL_SOURCES ${CBOR_SOURCES})
|
||||
if(NOT ESP_PLATFORM)
|
||||
set(EXTERNAL_SOURCES ${EXTERNAL_SOURCES} ${MBEDTLS_SOURCES})
|
||||
endif()
|
||||
if(MSVC)
|
||||
set(
|
||||
CMAKE_C_FLAGS
|
||||
"${CMAKE_C_FLAGS} -wd4820 -wd4255 -wd5045 -wd4706 -wd4061 -wd5105"
|
||||
)
|
||||
|
||||
add_compile_definitions(_CRT_SECURE_NO_WARNINGS
|
||||
__STDC_WANT_SECURE_LIB__=0
|
||||
_WIN32_WINNT_WIN10_TH2=0
|
||||
_WIN32_WINNT_WIN10_RS1=0
|
||||
_WIN32_WINNT_WIN10_RS2=0
|
||||
_WIN32_WINNT_WIN10_RS3=0
|
||||
_WIN32_WINNT_WIN10_RS4=0
|
||||
_WIN32_WINNT_WIN10_RS5=0
|
||||
_STRALIGN_USE_SECURE_CRT=0
|
||||
NTDDI_WIN10_CU=0)
|
||||
set_source_files_properties(
|
||||
${EXTERNAL_SOURCES}
|
||||
PROPERTIES
|
||||
COMPILE_FLAGS " -W3 -wd4242 -wd4065"
|
||||
)
|
||||
endif()
|
||||
if(PICO_RP2350)
|
||||
pico_set_uf2_family(${CMAKE_PROJECT_NAME} "rp2350-arm-s")
|
||||
pico_embed_pt_in_binary(${CMAKE_PROJECT_NAME} "${CMAKE_CURRENT_LIST_DIR}/config/rp2350/pt.json")
|
||||
if (NOT IS_CYW43)
|
||||
pico_set_binary_type(${CMAKE_PROJECT_NAME} copy_to_ram)
|
||||
endif()
|
||||
if (SECURE_BOOT_PKEY)
|
||||
message(STATUS "Secure Boot Key ${SECURE_BOOT_PKEY}")
|
||||
pico_sign_binary(${CMAKE_PROJECT_NAME} ${SECURE_BOOT_PKEY})
|
||||
pico_hash_binary(${CMAKE_PROJECT_NAME})
|
||||
endif()
|
||||
target_link_libraries(${CMAKE_PROJECT_NAME} PRIVATE pico_bootrom)
|
||||
|
||||
set(INCLUDES ${INCLUDES}
|
||||
${CMAKE_CURRENT_LIST_DIR}/config/rp2350/alt
|
||||
)
|
||||
set(SOURCES ${SOURCES}
|
||||
${CMAKE_CURRENT_LIST_DIR}/config/rp2350/alt/sha256_alt.c
|
||||
)
|
||||
set(LIBRARIES ${LIBRARIES} pico_sha256)
|
||||
endif()
|
||||
set(INTERNAL_SOURCES ${SOURCES})
|
||||
set(SOURCES ${SOURCES} ${EXTERNAL_SOURCES})
|
||||
if(NOT TARGET pico_keys_sdk)
|
||||
if(ENABLE_EMULATION OR ESP_PLATFORM)
|
||||
add_impl_library(pico_keys_sdk)
|
||||
else()
|
||||
pico_add_library(pico_keys_sdk)
|
||||
|
||||
target_link_libraries(${CMAKE_PROJECT_NAME} PRIVATE ${LIBRARIES})
|
||||
endif()
|
||||
target_sources(pico_keys_sdk INTERFACE ${SOURCES})
|
||||
target_include_directories(pico_keys_sdk INTERFACE ${INCLUDES})
|
||||
target_link_libraries(pico_keys_sdk INTERFACE ${LIBRARIES})
|
||||
endif()
|
||||
671
picokeys_sdk_import.cmake
Normal file
671
picokeys_sdk_import.cmake
Normal file
@@ -0,0 +1,671 @@
|
||||
#
|
||||
# This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
|
||||
# Copyright (c) 2022 Pol Henarejos.
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, version 3.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
include(pico-keys-sdk/cmake/version.cmake OPTIONAL)
|
||||
include(pico-keys-sdk/cmake/options.cmake OPTIONAL)
|
||||
|
||||
option(VIDPID "Set specific VID/PID from a known platform {NitroHSM, NitroFIDO2, NitroStart, NitroPro, Nitro3, Yubikey5, YubikeyNeo, YubiHSM, Gnuk, GnuPG}" "None")
|
||||
|
||||
message(STATUS "VIDPID:\t\t\t '${VIDPID}'")
|
||||
|
||||
if(VIDPID STREQUAL "NitroHSM")
|
||||
set(USB_VID 0x20A0)
|
||||
set(USB_PID 0x4230)
|
||||
elseif(VIDPID STREQUAL "NitroFIDO2")
|
||||
set(USB_VID 0x20A0)
|
||||
set(USB_PID 0x42B1)
|
||||
elseif(VIDPID STREQUAL "NitroStart")
|
||||
set(USB_VID 0x20A0)
|
||||
set(USB_PID 0x4211)
|
||||
elseif(VIDPID STREQUAL "NitroPro")
|
||||
set(USB_VID 0x20A0)
|
||||
set(USB_PID 0x4108)
|
||||
elseif(VIDPID STREQUAL "Nitro3")
|
||||
set(USB_VID 0x20A0)
|
||||
set(USB_PID 0x42B2)
|
||||
elseif(VIDPID STREQUAL "Yubikey5")
|
||||
set(USB_VID 0x1050)
|
||||
set(USB_PID 0x0407)
|
||||
elseif(VIDPID STREQUAL "YubikeyNeo")
|
||||
set(USB_VID 0x1050)
|
||||
set(USB_PID 0x0116)
|
||||
elseif(VIDPID STREQUAL "YubiHSM")
|
||||
set(USB_VID 0x1050)
|
||||
set(USB_PID 0x0030)
|
||||
elseif(VIDPID STREQUAL "Gnuk")
|
||||
set(USB_VID 0x234B)
|
||||
set(USB_PID 0x0000)
|
||||
elseif(VIDPID STREQUAL "GnuPG")
|
||||
set(USB_VID 0x1209)
|
||||
set(USB_PID 0x2440)
|
||||
endif()
|
||||
|
||||
if(ESP_PLATFORM)
|
||||
if(DEFINED CONFIG_TINYUSB_DESC_CUSTOM_VID)
|
||||
set(USB_VID CONFIG_TINYUSB_DESC_CUSTOM_VID)
|
||||
endif()
|
||||
if(DEFINED CONFIG_TINYUSB_DESC_CUSTOM_PID)
|
||||
set(USB_PID CONFIG_TINYUSB_DESC_CUSTOM_PID)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED USB_VID)
|
||||
set(USB_VID 0x2E8A)
|
||||
endif()
|
||||
add_compile_definitions(USB_VID=${USB_VID})
|
||||
|
||||
if(NOT DEFINED USB_PID)
|
||||
set(USB_PID 0x10FD)
|
||||
endif()
|
||||
add_compile_definitions(USB_PID=${USB_PID})
|
||||
|
||||
if(NOT DEFINED DEBUG_APDU)
|
||||
set(DEBUG_APDU 0)
|
||||
endif()
|
||||
if(NOT DEFINED ENABLE_EMULATION)
|
||||
set(ENABLE_EMULATION 0)
|
||||
endif()
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/cmake/openssl.cmake)
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/cmake/build_helpers.cmake)
|
||||
|
||||
option(ENABLE_DELAYED_BOOT "Enable/disable delayed boot" OFF)
|
||||
configure_bool_option(
|
||||
ENABLE_DELAYED_BOOT
|
||||
""
|
||||
"Delayed boot:\t\t enabled"
|
||||
"Delayed boot:\t\t disabled"
|
||||
)
|
||||
if(ENABLE_DELAYED_BOOT)
|
||||
add_compile_definitions(PICO_XOSC_STARTUP_DELAY_MULTIPLIER=64)
|
||||
endif()
|
||||
if(USB_ITF_HID)
|
||||
add_compile_definitions(USB_ITF_HID=1)
|
||||
message(STATUS "USB HID Interface:\t\t enabled")
|
||||
endif()
|
||||
if(USB_ITF_CCID)
|
||||
add_compile_definitions(USB_ITF_CCID=1)
|
||||
message(STATUS "USB CCID Interface:\t\t enabled")
|
||||
if(USB_ITF_WCID)
|
||||
add_compile_definitions(USB_ITF_WCID=1)
|
||||
message(STATUS "USB WebCCID Interface:\t enabled")
|
||||
endif()
|
||||
endif()
|
||||
if(USB_ITF_LWIP)
|
||||
add_compile_definitions(USB_ITF_LWIP=1)
|
||||
message(STATUS "USB LWIP Interface:\t\t enabled")
|
||||
endif()
|
||||
add_compile_definitions(DEBUG_APDU=${DEBUG_APDU})
|
||||
if(NOT ESP_PLATFORM)
|
||||
add_compile_definitions(MBEDTLS_CONFIG_FILE="${CMAKE_CURRENT_LIST_DIR}/config/mbedtls_config.h")
|
||||
else()
|
||||
add_compile_definitions(CFG_TUSB_CONFIG_FILE="${CMAKE_CURRENT_LIST_DIR}/src/usb/tusb_config.h")
|
||||
endif()
|
||||
|
||||
message(STATUS "USB VID/PID:\t\t\t ${USB_VID}:${USB_PID}")
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/cmake/deps.cmake)
|
||||
|
||||
option(ENABLE_PQC "Enable/disable PQC support" OFF)
|
||||
configure_bool_option(
|
||||
ENABLE_PQC
|
||||
""
|
||||
"PQC support:\t\t\t enabled"
|
||||
"PQC support:\t\t\t disabled"
|
||||
)
|
||||
if(ENABLE_PQC)
|
||||
add_compile_definitions(ENABLE_PQC)
|
||||
endif()
|
||||
|
||||
set(MBEDTLS_SOURCES
|
||||
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library/aes.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library/asn1parse.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library/asn1write.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library/bignum.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library/bignum_core.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library/ccm.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library/cmac.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library/cipher.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library/cipher_wrap.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library/constant_time.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library/ecdsa.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library/ecdh.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library/ecp.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library/ecp_curves.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library/gcm.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library/hkdf.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library/md.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library/md5.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library/oid.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library/pkcs5.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library/platform_util.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library/rsa.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library/rsa_alt_helpers.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library/sha1.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library/sha256.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library/sha512.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library/chachapoly.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library/chacha20.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library/poly1305.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library/ripemd160.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library/des.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library/x509write.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library/x509write_crt.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library/x509_create.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library/x509write_csr.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library/base64.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library/pem.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library/pk.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library/pk_wrap.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library/pkwrite.c
|
||||
)
|
||||
|
||||
if(ENABLE_EDDSA)
|
||||
list(APPEND MBEDTLS_SOURCES
|
||||
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library/eddsa.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library/sha3.c
|
||||
)
|
||||
endif()
|
||||
|
||||
if(ENABLE_PQC)
|
||||
if(NOT ESP_PLATFORM)
|
||||
file(GLOB_RECURSE MLKEM_SOURCES
|
||||
${CMAKE_CURRENT_LIST_DIR}/third-party/mlkem/mlkem/src/*.c
|
||||
)
|
||||
list(FILTER MLKEM_SOURCES EXCLUDE REGEX "/native/")
|
||||
|
||||
add_library(mlkem512 STATIC ${MLKEM_SOURCES})
|
||||
target_include_directories(mlkem512 PRIVATE
|
||||
${CMAKE_CURRENT_LIST_DIR}/third-party/mlkem/mlkem/src
|
||||
${CMAKE_CURRENT_LIST_DIR}/config/mlkem
|
||||
)
|
||||
target_compile_definitions(mlkem512 PRIVATE
|
||||
MLK_CONFIG_PARAMETER_SET=512
|
||||
MLK_CONFIG_MULTILEVEL_WITH_SHARED
|
||||
MLK_CONFIG_NAMESPACE_PREFIX=mlkem
|
||||
)
|
||||
|
||||
add_library(mlkem768 STATIC ${MLKEM_SOURCES})
|
||||
target_include_directories(mlkem768 PRIVATE
|
||||
${CMAKE_CURRENT_LIST_DIR}/third-party/mlkem/mlkem/src
|
||||
${CMAKE_CURRENT_LIST_DIR}/config/mlkem
|
||||
)
|
||||
target_compile_definitions(mlkem768 PRIVATE
|
||||
MLK_CONFIG_PARAMETER_SET=768
|
||||
MLK_CONFIG_MULTILEVEL_NO_SHARED
|
||||
MLK_CONFIG_NAMESPACE_PREFIX=mlkem
|
||||
)
|
||||
|
||||
add_library(mlkem1024 STATIC ${MLKEM_SOURCES})
|
||||
target_include_directories(mlkem1024 PRIVATE
|
||||
${CMAKE_CURRENT_LIST_DIR}/third-party/mlkem/mlkem/src
|
||||
${CMAKE_CURRENT_LIST_DIR}/config/mlkem
|
||||
)
|
||||
target_compile_definitions(mlkem1024 PRIVATE
|
||||
MLK_CONFIG_PARAMETER_SET=1024
|
||||
MLK_CONFIG_MULTILEVEL_NO_SHARED
|
||||
MLK_CONFIG_NAMESPACE_PREFIX=mlkem
|
||||
)
|
||||
|
||||
file(GLOB_RECURSE MLDSA_SOURCES
|
||||
${CMAKE_CURRENT_LIST_DIR}/third-party/mldsa/mldsa/src/*.c
|
||||
)
|
||||
list(FILTER MLDSA_SOURCES EXCLUDE REGEX "/native/")
|
||||
|
||||
add_library(mldsa44 STATIC ${MLDSA_SOURCES})
|
||||
target_include_directories(mldsa44 PRIVATE
|
||||
${CMAKE_CURRENT_LIST_DIR}/third-party/mldsa/mldsa/src
|
||||
${CMAKE_CURRENT_LIST_DIR}/config/mldsa
|
||||
)
|
||||
target_compile_definitions(mldsa44 PRIVATE
|
||||
MLD_CONFIG_PARAMETER_SET=44
|
||||
MLD_CONFIG_MULTILEVEL_WITH_SHARED
|
||||
MLD_CONFIG_NAMESPACE_PREFIX=mldsa
|
||||
)
|
||||
|
||||
add_library(mldsa65 STATIC ${MLDSA_SOURCES})
|
||||
target_include_directories(mldsa65 PRIVATE
|
||||
${CMAKE_CURRENT_LIST_DIR}/third-party/mldsa/mldsa/src
|
||||
${CMAKE_CURRENT_LIST_DIR}/config/mldsa
|
||||
)
|
||||
target_compile_definitions(mldsa65 PRIVATE
|
||||
MLD_CONFIG_PARAMETER_SET=65
|
||||
MLD_CONFIG_MULTILEVEL_NO_SHARED
|
||||
MLD_CONFIG_NAMESPACE_PREFIX=mldsa
|
||||
)
|
||||
|
||||
add_library(mldsa87 STATIC ${MLDSA_SOURCES})
|
||||
target_include_directories(mldsa87 PRIVATE
|
||||
${CMAKE_CURRENT_LIST_DIR}/third-party/mldsa/mldsa/src
|
||||
${CMAKE_CURRENT_LIST_DIR}/config/mldsa
|
||||
)
|
||||
target_compile_definitions(mldsa87 PRIVATE
|
||||
MLD_CONFIG_PARAMETER_SET=87
|
||||
MLD_CONFIG_MULTILEVEL_NO_SHARED
|
||||
MLD_CONFIG_NAMESPACE_PREFIX=mldsa
|
||||
)
|
||||
endif()
|
||||
|
||||
list(APPEND INCLUDES
|
||||
${CMAKE_CURRENT_LIST_DIR}/third-party/mlkem/mlkem
|
||||
${CMAKE_CURRENT_LIST_DIR}/config/mlkem
|
||||
${CMAKE_CURRENT_LIST_DIR}/third-party/mldsa/mldsa
|
||||
${CMAKE_CURRENT_LIST_DIR}/config/mldsa
|
||||
)
|
||||
list(APPEND SYSTEM_INCLUDES
|
||||
${CMAKE_CURRENT_LIST_DIR}/third-party/mlkem/mlkem
|
||||
${CMAKE_CURRENT_LIST_DIR}/config/mlkem
|
||||
${CMAKE_CURRENT_LIST_DIR}/third-party/mldsa/mldsa
|
||||
${CMAKE_CURRENT_LIST_DIR}/config/mldsa
|
||||
)
|
||||
add_compile_definitions(
|
||||
MLK_CONFIG_NAMESPACE_PREFIX=mlkem
|
||||
MLK_CONFIG_MULTILEVEL_BUILD=1
|
||||
MLD_CONFIG_NAMESPACE_PREFIX=mldsa
|
||||
MLD_CONFIG_MULTILEVEL_BUILD=1
|
||||
)
|
||||
endif()
|
||||
|
||||
if(ESP_PLATFORM)
|
||||
list(APPEND PICOKEYS_SOURCES
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/otp/otp_esp32.c
|
||||
)
|
||||
elseif(ENABLE_EMULATION)
|
||||
if(MSVC)
|
||||
list(APPEND PICOKEYS_SOURCES
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/otp/otp_windows.c
|
||||
)
|
||||
elseif(APPLE)
|
||||
list(APPEND PICOKEYS_SOURCES
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/otp/otp_macos.c
|
||||
)
|
||||
elseif(UNIX AND NOT APPLE)
|
||||
add_compile_definitions(OTP_LINUX_USE_TSS=1)
|
||||
list(APPEND PICOKEYS_SOURCES
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/otp/otp_linux.c
|
||||
)
|
||||
else()
|
||||
list(APPEND PICOKEYS_SOURCES
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/otp/otp_emulation.c
|
||||
)
|
||||
endif()
|
||||
elseif(PICO_RP2350)
|
||||
list(APPEND PICOKEYS_SOURCES
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/otp/otp_rp2350.c
|
||||
)
|
||||
elseif(PICO_RP2040)
|
||||
list(APPEND PICOKEYS_SOURCES
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/otp/otp_rp2040.c
|
||||
)
|
||||
endif()
|
||||
|
||||
list(APPEND PICOKEYS_SOURCES
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/main.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/usb/usb.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/fs/file.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/fs/flash.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/fs/low_flash.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/fs/phy.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/otp/otp.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/rng/random.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/rng/hwrng.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/eac.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/crypto_utils.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/tlv.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/apdu.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/rescue.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/serial.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/pico_time.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/button.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/led/led.c
|
||||
)
|
||||
|
||||
if(ESP_PLATFORM)
|
||||
list(APPEND PICOKEYS_SOURCES
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/led/led_neopixel.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/led/led_pico.c
|
||||
)
|
||||
else()
|
||||
if(NOT ENABLE_EMULATION)
|
||||
list(APPEND PICOKEYS_SOURCES
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/led/led_cyw43.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/led/led_pico.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/led/led_pimoroni.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/led/led_ws2812.c
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
## mbedTLS reports an stringop overflow for cmac.c
|
||||
if(NOT ENABLE_EMULATION AND NOT APPLE)
|
||||
set_source_files_properties(
|
||||
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library/cmac.c
|
||||
PROPERTIES
|
||||
COMPILE_FLAGS "-Wno-error=stringop-overflow= -Wno-stringop-overflow"
|
||||
)
|
||||
endif()
|
||||
list(APPEND INCLUDES
|
||||
${CMAKE_CURRENT_LIST_DIR}/src
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/usb
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/fs
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/rng
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/led
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/otp
|
||||
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library
|
||||
)
|
||||
set(SYSTEM_INCLUDES
|
||||
${SYSTEM_INCLUDES}
|
||||
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/include
|
||||
)
|
||||
if(USB_ITF_HID)
|
||||
list(APPEND SYSTEM_INCLUDES
|
||||
${CMAKE_CURRENT_LIST_DIR}/third-party/tinycbor/src
|
||||
)
|
||||
endif()
|
||||
if(USB_ITF_LWIP)
|
||||
list(APPEND SYSTEM_INCLUDES
|
||||
${CMAKE_CURRENT_LIST_DIR}/third-party/cjson
|
||||
)
|
||||
endif()
|
||||
|
||||
if(USB_ITF_LWIP)
|
||||
if (NOT ESP_PLATFORM)
|
||||
add_compile_definitions(
|
||||
MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED
|
||||
MBEDTLS_SSL_PROTO_TLS1_2
|
||||
MBEDTLS_SSL_SRV_C
|
||||
MBEDTLS_SSL_TLS_C
|
||||
)
|
||||
endif()
|
||||
list(APPEND MBEDTLS_SOURCES
|
||||
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library/pkparse.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library/pk_ecc.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library/pkcs12.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library/ssl_ciphersuites.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library/ssl_msg.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library/ssl_tls.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library/ssl_tls12_server.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library/x509.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library/x509_crt.c
|
||||
)
|
||||
endif()
|
||||
if(USB_ITF_HID)
|
||||
list(APPEND MBEDTLS_SOURCES
|
||||
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library/x509write_crt.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library/x509_create.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library/x509write_csr.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library/pk.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library/pk_wrap.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library/pkwrite.c
|
||||
)
|
||||
endif()
|
||||
|
||||
set(CBOR_SOURCES
|
||||
${CMAKE_CURRENT_LIST_DIR}/third-party/tinycbor/src/cborencoder.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/third-party/tinycbor/src/cborparser.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/third-party/tinycbor/src/cborparser_dup_string.c
|
||||
)
|
||||
|
||||
set(CJSON_SOURCES
|
||||
${CMAKE_CURRENT_LIST_DIR}/third-party/cjson/cJSON.c
|
||||
)
|
||||
|
||||
set(LIBCVC_SOURCES
|
||||
${CMAKE_CURRENT_LIST_DIR}/third-party/libcvc/src/cvc_build.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/third-party/libcvc/src/cvc_parse.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/third-party/libcvc/src/cvc_sign.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/third-party/libcvc/src/cvc_tlv.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/third-party/libcvc/src/cvc_write.c
|
||||
)
|
||||
|
||||
set(LIBRARIES)
|
||||
if(NOT SKIP_MBEDTLS_FOR_OPENSSL_EMULATION)
|
||||
list(APPEND LIBRARIES mbedtls)
|
||||
endif()
|
||||
if(USE_OPENSSL_EMULATION_WRAPPER)
|
||||
list(APPEND LIBRARIES OpenSSL::Crypto)
|
||||
endif()
|
||||
|
||||
if(UNIX AND NOT APPLE AND ENABLE_EMULATION)
|
||||
find_library(TSS2_ESYS_LIB NAMES tss2-esys)
|
||||
find_library(TSS2_TCTILDR_LIB NAMES tss2-tctildr)
|
||||
if(TSS2_ESYS_LIB AND TSS2_TCTILDR_LIB)
|
||||
list(APPEND LIBRARIES ${TSS2_ESYS_LIB} ${TSS2_TCTILDR_LIB})
|
||||
else()
|
||||
message(WARNING "Linux OTP TPM backend enabled but tpm2-tss libraries not found (need tss2-esys and tss2-tctildr)")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(NOT ESP_PLATFORM)
|
||||
if(NOT SKIP_MBEDTLS_FOR_OPENSSL_EMULATION)
|
||||
add_library(mbedtls STATIC ${MBEDTLS_SOURCES})
|
||||
target_include_directories(mbedtls SYSTEM PUBLIC ${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/include)
|
||||
endif()
|
||||
if(ENABLE_LIBCVC)
|
||||
add_library(libcvc STATIC ${LIBCVC_SOURCES})
|
||||
target_include_directories(libcvc SYSTEM PUBLIC ${CMAKE_CURRENT_LIST_DIR}/third-party/libcvc/src ${CMAKE_CURRENT_LIST_DIR}/third-party/libcvc/include)
|
||||
target_link_libraries(libcvc PRIVATE mbedtls)
|
||||
list(APPEND LIBRARIES libcvc)
|
||||
endif()
|
||||
if(USB_ITF_HID)
|
||||
add_library(tinycbor STATIC ${CBOR_SOURCES})
|
||||
target_include_directories(tinycbor SYSTEM PUBLIC ${CMAKE_CURRENT_LIST_DIR}/third-party/tinycbor/src)
|
||||
list(APPEND LIBRARIES tinycbor)
|
||||
endif()
|
||||
if(USB_ITF_LWIP)
|
||||
add_library(cjson STATIC ${CJSON_SOURCES})
|
||||
target_include_directories(cjson SYSTEM PUBLIC ${CMAKE_CURRENT_LIST_DIR}/third-party/cjson)
|
||||
list(APPEND LIBRARIES cjson)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(PICO_PLATFORM)
|
||||
list(APPEND LIBRARIES
|
||||
pico_stdlib
|
||||
pico_multicore
|
||||
pico_rand
|
||||
pico_aon_timer
|
||||
hardware_flash
|
||||
pico_unique_id
|
||||
tinyusb_device
|
||||
tinyusb_board
|
||||
hardware_pio
|
||||
)
|
||||
if(USB_ITF_LWIP)
|
||||
list(APPEND LIBRARIES
|
||||
pico_lwip
|
||||
pico_lwip_nosys
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(ENABLE_PQC)
|
||||
list(APPEND LIBRARIES
|
||||
mlkem768
|
||||
mlkem1024
|
||||
mlkem512
|
||||
mldsa44
|
||||
mldsa65
|
||||
mldsa87
|
||||
)
|
||||
endif()
|
||||
|
||||
set(IS_CYW43 0)
|
||||
if(PICO_PLATFORM)
|
||||
file(READ ${PICO_SDK_PATH}/src/boards/include/boards/${PICO_BOARD}.h content)
|
||||
string(REGEX MATCHALL "CYW43_WL_GPIO_LED_PIN" _ ${content})
|
||||
if(CMAKE_MATCH_0)
|
||||
message(STATUS "Found cyw43 LED:\t\t true")
|
||||
list(APPEND LIBRARIES pico_cyw43_arch_none)
|
||||
set(IS_CYW43 1)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
function(add_impl_library target)
|
||||
add_library(${target} INTERFACE)
|
||||
string(TOUPPER ${target} TARGET_UPPER)
|
||||
target_compile_definitions(${target} INTERFACE LIB_${TARGET_UPPER}=1)
|
||||
endfunction()
|
||||
|
||||
if(USB_ITF_HID)
|
||||
list(APPEND PICOKEYS_SOURCES
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/usb/hid/hid.c
|
||||
)
|
||||
list(APPEND INCLUDES
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/usb/hid
|
||||
)
|
||||
endif()
|
||||
|
||||
if(USB_ITF_CCID)
|
||||
list(APPEND PICOKEYS_SOURCES
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/usb/ccid/ccid.c
|
||||
)
|
||||
list(APPEND INCLUDES
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/usb/ccid
|
||||
)
|
||||
endif()
|
||||
|
||||
if(NOT MSVC)
|
||||
add_compile_options("-fmacro-prefix-map=${CMAKE_CURRENT_LIST_DIR}/=")
|
||||
else()
|
||||
list(APPEND PICOKEYS_SOURCES
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/fs/mman.c
|
||||
)
|
||||
endif()
|
||||
if(ENABLE_EMULATION)
|
||||
if(APPLE)
|
||||
add_definitions("-Wno-deprecated-declarations")
|
||||
target_link_libraries(${CMAKE_PROJECT_NAME} PRIVATE
|
||||
"-framework IOKit"
|
||||
"-framework CoreFoundation"
|
||||
)
|
||||
elseif(MSVC)
|
||||
target_link_libraries(${CMAKE_PROJECT_NAME} PRIVATE Ncrypt)
|
||||
elseif(UNIX AND NOT APPLE AND TSS2_ESYS_LIB AND TSS2_TCTILDR_LIB)
|
||||
target_link_libraries(${CMAKE_PROJECT_NAME} PRIVATE ${TSS2_ESYS_LIB} ${TSS2_TCTILDR_LIB})
|
||||
endif()
|
||||
add_compile_definitions(ENABLE_EMULATION)
|
||||
list(APPEND PICOKEYS_SOURCES
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/usb/emulation/emulation.c
|
||||
)
|
||||
if(USE_OPENSSL_EMULATION_WRAPPER)
|
||||
list(APPEND PICOKEYS_SOURCES
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/usb/emulation/openssl.c
|
||||
)
|
||||
endif()
|
||||
list(APPEND MBEDTLS_SOURCES
|
||||
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library/aesni.c
|
||||
)
|
||||
list(APPEND INCLUDES
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/usb/emulation
|
||||
)
|
||||
else()
|
||||
list(APPEND PICOKEYS_SOURCES
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/usb/usb_descriptors.c
|
||||
)
|
||||
endif()
|
||||
|
||||
if(MSVC)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -wd5045 -wd4820 -wd5105")
|
||||
|
||||
add_compile_definitions(
|
||||
_CRT_SECURE_NO_WARNINGS
|
||||
__STDC_WANT_SECURE_LIB__=0
|
||||
_WIN32_WINNT_WIN10_TH2=0
|
||||
_WIN32_WINNT_WIN10_RS1=0
|
||||
_WIN32_WINNT_WIN10_RS2=0
|
||||
_WIN32_WINNT_WIN10_RS3=0
|
||||
_WIN32_WINNT_WIN10_RS4=0
|
||||
_WIN32_WINNT_WIN10_RS5=0
|
||||
_STRALIGN_USE_SECURE_CRT=0
|
||||
NTDDI_WIN11_DT=0
|
||||
)
|
||||
endif()
|
||||
|
||||
if(PICO_PLATFORM)
|
||||
pico_sdk_init()
|
||||
endif()
|
||||
|
||||
if(USB_ITF_LWIP)
|
||||
list(APPEND PICOKEYS_SOURCES
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/usb/lwip/rest.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/usb/lwip/rest_server.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/usb/lwip/rest_server_tls.c
|
||||
)
|
||||
list(APPEND INCLUDES
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/usb/lwip
|
||||
)
|
||||
if(NOT ENABLE_EMULATION)
|
||||
list(APPEND PICOKEYS_SOURCES
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/usb/lwip/lwip.c
|
||||
)
|
||||
if ((NOT ESP_PLATFORM) AND (NOT IDF_TARGET))
|
||||
list(APPEND PICOKEYS_SOURCES
|
||||
${PICO_TINYUSB_PATH}/lib/networking/dhserver.c
|
||||
${PICO_TINYUSB_PATH}/lib/networking/dnserver.c
|
||||
)
|
||||
list(APPEND INCLUDES
|
||||
${PICO_TINYUSB_PATH}/lib/networking
|
||||
${PICO_LWIP_PATH}/src/include/lwip/apps
|
||||
)
|
||||
message(STATUS "TINYUSB_PATH:\t\t ${PICO_TINYUSB_PATH}")
|
||||
message(STATUS "LWIP_PATH:\t\t ${PICO_LWIP_PATH}")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(PICO_RP2350)
|
||||
pico_set_uf2_family(${CMAKE_PROJECT_NAME} "rp2350-arm-s")
|
||||
pico_embed_pt_in_binary(${CMAKE_PROJECT_NAME} "${CMAKE_CURRENT_LIST_DIR}/config/rp2350/pt.json")
|
||||
if(NOT IS_CYW43)
|
||||
pico_set_binary_type(${CMAKE_PROJECT_NAME} copy_to_ram)
|
||||
endif()
|
||||
if(SECURE_BOOT_PKEY)
|
||||
message(STATUS "Secure Boot Key ${SECURE_BOOT_PKEY}")
|
||||
pico_sign_binary(${CMAKE_PROJECT_NAME} ${SECURE_BOOT_PKEY})
|
||||
pico_hash_binary(${CMAKE_PROJECT_NAME})
|
||||
endif()
|
||||
target_link_libraries(${CMAKE_PROJECT_NAME} PRIVATE pico_bootrom)
|
||||
|
||||
list(APPEND INCLUDES
|
||||
${CMAKE_CURRENT_LIST_DIR}/config/rp2350/alt
|
||||
)
|
||||
if(TARGET mbedtls)
|
||||
target_include_directories(mbedtls PRIVATE
|
||||
${CMAKE_CURRENT_LIST_DIR}/config/rp2350/alt
|
||||
)
|
||||
target_link_libraries(mbedtls PRIVATE pico_sha256)
|
||||
endif()
|
||||
list(APPEND PICOKEYS_SOURCES
|
||||
${CMAKE_CURRENT_LIST_DIR}/config/rp2350/alt/sha256_alt.c
|
||||
)
|
||||
add_compile_definitions(MBEDTLS_SHA256_ALT=1)
|
||||
list(APPEND LIBRARIES pico_sha256)
|
||||
endif()
|
||||
set(INTERNAL_SOURCES ${PICOKEYS_SOURCES})
|
||||
|
||||
if(NOT TARGET picokeys_sdk)
|
||||
if(PICO_PLATFORM)
|
||||
pico_add_library(picokeys_sdk)
|
||||
|
||||
target_link_libraries(${CMAKE_PROJECT_NAME} PRIVATE ${LIBRARIES})
|
||||
else()
|
||||
add_impl_library(picokeys_sdk)
|
||||
endif()
|
||||
target_sources(picokeys_sdk INTERFACE ${PICOKEYS_SOURCES})
|
||||
target_include_directories(picokeys_sdk INTERFACE ${INCLUDES})
|
||||
target_include_directories(picokeys_sdk SYSTEM INTERFACE ${SYSTEM_INCLUDES})
|
||||
target_link_libraries(picokeys_sdk INTERFACE ${LIBRARIES})
|
||||
endif()
|
||||
@@ -12,3 +12,4 @@ CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
|
||||
CONFIG_WL_SECTOR_SIZE_512=y
|
||||
CONFIG_WL_SECTOR_MODE_PERF=y
|
||||
COMPILER_OPTIMIZATION="Performance"
|
||||
CONFIG_MBEDTLS_HKDF_C=y
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
idf_component_register(
|
||||
SRCS ${INTERNAL_SOURCES}
|
||||
INCLUDE_DIRS . fs rng usb led ../mbedtls/include ../tinycbor/src
|
||||
REQUIRES bootloader_support esp_partition esp_tinyusb efuse
|
||||
)
|
||||
101
src/apdu.c
101
src/apdu.c
@@ -3,24 +3,25 @@
|
||||
* 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
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
* Affero 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/>.
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "picokeys.h"
|
||||
#include "apdu.h"
|
||||
#include "pico_keys.h"
|
||||
#include "led/led.h"
|
||||
#include "usb.h"
|
||||
#include <stdio.h>
|
||||
#ifdef ESP_PLATFORM
|
||||
#include "esp_compat.h"
|
||||
#include "compat/esp_compat.h"
|
||||
#endif
|
||||
#ifdef ENABLE_EMULATION
|
||||
#include "emulation.h"
|
||||
@@ -30,16 +31,23 @@ uint8_t *rdata_gr = NULL;
|
||||
uint16_t rdata_bk = 0x0;
|
||||
extern uint32_t timeout;
|
||||
bool is_chaining = false;
|
||||
uint8_t chain_buf[4096];
|
||||
uint8_t chain_buf[2038];
|
||||
uint8_t *chain_ptr = NULL;
|
||||
|
||||
int process_apdu() {
|
||||
struct apdu apdu;
|
||||
|
||||
int process_apdu(void) {
|
||||
led_set_mode(MODE_PROCESSING);
|
||||
if (CLA(apdu) & 0x10) {
|
||||
size_t chain_used = 0;
|
||||
if (!is_chaining) {
|
||||
chain_ptr = chain_buf;
|
||||
}
|
||||
if (chain_ptr - chain_buf + apdu.nc >= sizeof(chain_buf)) {
|
||||
chain_used = (size_t)(chain_ptr - chain_buf);
|
||||
if (chain_used + apdu.nc >= sizeof(chain_buf)) {
|
||||
memset(chain_buf, 0, sizeof(chain_buf));
|
||||
chain_ptr = NULL;
|
||||
is_chaining = false;
|
||||
return SW_CLA_NOT_SUPPORTED();
|
||||
}
|
||||
memcpy(chain_ptr, apdu.data, apdu.nc);
|
||||
@@ -52,11 +60,13 @@ int process_apdu() {
|
||||
memmove(apdu.data + (chain_ptr - chain_buf), apdu.data, apdu.nc);
|
||||
memcpy(apdu.data, chain_buf, chain_ptr - chain_buf);
|
||||
apdu.nc += (uint16_t)(chain_ptr - chain_buf);
|
||||
memset(chain_buf, 0, sizeof(chain_buf));
|
||||
chain_ptr = NULL;
|
||||
is_chaining = false;
|
||||
}
|
||||
}
|
||||
if (INS(apdu) == 0xA4 && P1(apdu) == 0x04 && (P2(apdu) == 0x00 || P2(apdu) == 0x4)) { //select by AID
|
||||
if (select_app(apdu.data, apdu.nc) == PICOKEY_OK) {
|
||||
if (select_app(apdu.data, apdu.nc) == PICOKEYS_OK) {
|
||||
return SW_OK();
|
||||
}
|
||||
return SW_FILE_NOT_FOUND();
|
||||
@@ -85,17 +95,17 @@ uint16_t apdu_process(uint8_t itf, const uint8_t *buffer, uint16_t buffer_size)
|
||||
}
|
||||
else if (apdu.header[4] == 0x0 && buffer_size >= 7) {
|
||||
if (buffer_size == 7) {
|
||||
apdu.ne = get_uint16_t_be(apdu.header + 5);
|
||||
apdu.ne = get_uint16_be(apdu.header + 5);
|
||||
if (apdu.ne == 0) {
|
||||
apdu.ne = 65536;
|
||||
}
|
||||
}
|
||||
else {
|
||||
apdu.ne = 0;
|
||||
apdu.nc = get_uint16_t_be(apdu.header + 5);
|
||||
apdu.nc = get_uint16_be(apdu.header + 5);
|
||||
apdu.data = apdu.header + 7;
|
||||
if (apdu.nc + 7 + 2 == buffer_size) {
|
||||
apdu.ne = get_uint16_t_be(apdu.header + buffer_size - 2);
|
||||
apdu.ne = get_uint16_be(apdu.header + buffer_size - 2);
|
||||
if (apdu.ne == 0) {
|
||||
apdu.ne = 65536;
|
||||
}
|
||||
@@ -113,21 +123,22 @@ uint16_t apdu_process(uint8_t itf, const uint8_t *buffer, uint16_t buffer_size)
|
||||
}
|
||||
}
|
||||
}
|
||||
//printf("apdu.nc %ld, apdu.ne %ld\n",apdu.nc,apdu.ne);
|
||||
//printf("apdu.nc %u, apdu.ne %u\n",apdu.nc,apdu.ne);
|
||||
if (apdu.header[1] == 0xc0) {
|
||||
//printf("apdu.ne %u, apdu.rlen %d, bk %x\n",apdu.ne,apdu.rlen,rdata_bk);
|
||||
timeout_stop();
|
||||
*(uint16_t *) rdata_gr = rdata_bk;
|
||||
rdata_gr[0] = rdata_bk >> 8;
|
||||
rdata_gr[1] = rdata_bk & 0xff;
|
||||
if (apdu.rlen <= apdu.ne) {
|
||||
#ifndef ENABLE_EMULATION
|
||||
#ifdef USB_ITF_HID
|
||||
if (itf == ITF_HID_CTAP) {
|
||||
driver_exec_finished_cont_hid(itf, apdu.rlen + 2, rdata_gr - apdu.rdata);
|
||||
driver_exec_finished_cont_hid(itf, apdu.rlen + 2, (uint16_t)(rdata_gr - apdu.rdata));
|
||||
}
|
||||
#endif
|
||||
#ifdef USB_ITF_CCID
|
||||
if (itf == ITF_SC_CCID || itf == ITF_SC_WCID) {
|
||||
driver_exec_finished_cont_ccid(itf, apdu.rlen + 2, rdata_gr - apdu.rdata);
|
||||
driver_exec_finished_cont_ccid(itf, apdu.rlen + 2, (uint16_t)(rdata_gr - apdu.rdata));
|
||||
}
|
||||
#endif
|
||||
#else
|
||||
@@ -140,7 +151,7 @@ uint16_t apdu_process(uint8_t itf, const uint8_t *buffer, uint16_t buffer_size)
|
||||
}
|
||||
else {
|
||||
rdata_gr += apdu.ne;
|
||||
rdata_bk = *(uint16_t *) rdata_gr;
|
||||
rdata_bk = (rdata_gr[0] << 8) | rdata_gr[1];
|
||||
rdata_gr[0] = 0x61;
|
||||
if (apdu.rlen - apdu.ne >= 256) {
|
||||
rdata_gr[1] = 0;
|
||||
@@ -151,12 +162,12 @@ uint16_t apdu_process(uint8_t itf, const uint8_t *buffer, uint16_t buffer_size)
|
||||
#ifndef ENABLE_EMULATION
|
||||
#ifdef USB_ITF_HID
|
||||
if (itf == ITF_HID_CTAP) {
|
||||
driver_exec_finished_cont_hid(itf, apdu.ne + 2, rdata_gr - apdu.ne - apdu.rdata);
|
||||
driver_exec_finished_cont_hid(itf, (uint16_t)(apdu.ne + 2), (uint16_t)(rdata_gr - apdu.ne - apdu.rdata));
|
||||
}
|
||||
#endif
|
||||
#ifdef USB_ITF_CCID
|
||||
if (itf == ITF_SC_CCID || itf == ITF_SC_WCID) {
|
||||
driver_exec_finished_cont_ccid(itf, apdu.ne + 2, rdata_gr - apdu.ne - apdu.rdata);
|
||||
driver_exec_finished_cont_ccid(itf, (uint16_t)(apdu.ne + 2), (uint16_t)(rdata_gr - apdu.ne - apdu.rdata));
|
||||
}
|
||||
#endif
|
||||
#else
|
||||
@@ -175,20 +186,23 @@ uint16_t apdu_process(uint8_t itf, const uint8_t *buffer, uint16_t buffer_size)
|
||||
}
|
||||
|
||||
uint16_t set_res_sw(uint8_t sw1, uint8_t sw2) {
|
||||
apdu.sw = make_uint16_t_be(sw1, sw2);
|
||||
apdu.sw = make_uint16_be(sw1, sw2);
|
||||
if (sw1 != 0x90) {
|
||||
res_APDU_size = 0;
|
||||
}
|
||||
return make_uint16_t_be(sw1, sw2);
|
||||
return make_uint16_be(sw1, sw2);
|
||||
}
|
||||
|
||||
void apdu_thread(void) {
|
||||
void *apdu_thread(void *arg) {
|
||||
(void)arg;
|
||||
card_init_core1();
|
||||
while (1) {
|
||||
uint32_t m = 0;
|
||||
queue_remove_blocking(&usb_to_card_q, &m);
|
||||
uint32_t flag = m + 1;
|
||||
queue_add_blocking(&card_to_usb_q, &flag);
|
||||
if (m != EV_CMD_AVAILABLE) {
|
||||
queue_add_blocking(&card_to_usb_q, &flag);
|
||||
}
|
||||
|
||||
if (m == EV_VERIFY_CMD_AVAILABLE || m == EV_MODIFY_CMD_AVAILABLE) {
|
||||
set_res_sw(0x6f, 0x00);
|
||||
@@ -215,13 +229,11 @@ done: ;
|
||||
current_app->unload();
|
||||
current_app = NULL;
|
||||
}
|
||||
#ifdef ESP_PLATFORM
|
||||
vTaskDelete(NULL);
|
||||
#endif
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void apdu_finish() {
|
||||
put_uint16_t_be(apdu.sw, apdu.rdata + apdu.rlen);
|
||||
void apdu_finish(void) {
|
||||
put_uint16_be(apdu.sw, apdu.rdata + apdu.rlen);
|
||||
// timeout_stop();
|
||||
#ifndef ENABLE_EMULATION
|
||||
/* It was fixed in the USB handling. Keep it just in case */
|
||||
@@ -231,14 +243,14 @@ void apdu_finish() {
|
||||
#endif
|
||||
}
|
||||
|
||||
uint16_t apdu_next() {
|
||||
uint16_t apdu_next(void) {
|
||||
if (apdu.sw != 0) {
|
||||
if (apdu.rlen <= apdu.ne) {
|
||||
return apdu.rlen + 2;
|
||||
}
|
||||
else {
|
||||
rdata_gr = apdu.rdata + apdu.ne;
|
||||
rdata_bk = *(uint16_t *) rdata_gr;
|
||||
rdata_bk = (rdata_gr[0] << 8) | rdata_gr[1];
|
||||
rdata_gr[0] = 0x61;
|
||||
if (apdu.rlen - apdu.ne >= 256) {
|
||||
rdata_gr[1] = 0;
|
||||
@@ -252,3 +264,30 @@ uint16_t apdu_next() {
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bulk_cmd(int (*cmd)(void)) {
|
||||
uint8_t *p = apdu.data;
|
||||
uint8_t *rapdu = apdu.rdata;
|
||||
uint16_t rapdu_size = 0;
|
||||
uint8_t *top = apdu.data + apdu.nc;
|
||||
while (p < top) {
|
||||
P1(apdu) = p[0];
|
||||
P2(apdu) = p[1];
|
||||
apdu.nc = p[2];
|
||||
apdu.data = p + 3;
|
||||
*apdu.rdata++ = p[0];
|
||||
*apdu.rdata++ = p[1];
|
||||
*apdu.rdata++ = 0;
|
||||
*apdu.rdata++ = 0;
|
||||
apdu.rlen = 0;
|
||||
cmd();
|
||||
put_uint16_be(apdu.rlen, apdu.rdata - 2);
|
||||
put_uint16_be(apdu.sw, apdu.rdata + apdu.rlen);
|
||||
rapdu_size += 4 + apdu.rlen + 2;
|
||||
apdu.rdata += apdu.rlen + 2;
|
||||
p += 3 + apdu.nc;
|
||||
}
|
||||
apdu.rlen = rapdu_size;
|
||||
apdu.rdata = rapdu;
|
||||
return SW_OK();
|
||||
}
|
||||
|
||||
94
src/apdu.h
94
src/apdu.h
@@ -3,34 +3,31 @@
|
||||
* 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
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
* Affero 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/>.
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _APDU_H_
|
||||
#define _APDU_H_
|
||||
|
||||
#include <stdlib.h>
|
||||
#if !defined(ENABLE_EMULATION) && !defined(ESP_PLATFORM)
|
||||
#include "pico/stdlib.h"
|
||||
#endif
|
||||
#include "compat.h"
|
||||
#include <stdio.h>
|
||||
#include <inttypes.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "compat/compat.h"
|
||||
|
||||
typedef struct app {
|
||||
const uint8_t *aid;
|
||||
int (*process_apdu)();
|
||||
int (*process_apdu)(void);
|
||||
int (*select_aid)(struct app *, uint8_t);
|
||||
int (*unload)();
|
||||
int (*unload)(void);
|
||||
} app_t;
|
||||
|
||||
extern bool app_exists(const uint8_t *aid, size_t aid_len);
|
||||
@@ -39,11 +36,11 @@ extern int select_app(const uint8_t *aid, size_t aid_len);
|
||||
|
||||
typedef struct cmd {
|
||||
uint8_t ins;
|
||||
int (*cmd_handler)();
|
||||
int (*cmd_handler)(void);
|
||||
} cmd_t;
|
||||
|
||||
extern uint8_t num_apps;
|
||||
extern app_t apps[8];
|
||||
extern app_t apps[16];
|
||||
extern app_t *current_app;
|
||||
|
||||
PACK(struct apdu {
|
||||
@@ -68,10 +65,69 @@ PACK(struct apdu {
|
||||
extern struct apdu apdu;
|
||||
|
||||
extern uint16_t set_res_sw(uint8_t sw1, uint8_t sw2);
|
||||
extern int process_apdu();
|
||||
extern int process_apdu(void);
|
||||
extern uint16_t apdu_process(uint8_t, const uint8_t *buffer, uint16_t buffer_size);
|
||||
extern void apdu_finish();
|
||||
extern uint16_t apdu_next();
|
||||
extern void apdu_thread();
|
||||
extern void apdu_finish(void);
|
||||
extern uint16_t apdu_next(void);
|
||||
extern void *apdu_thread(void *);
|
||||
extern int bulk_cmd(int (*cmd)(void));
|
||||
|
||||
|
||||
#define SW_BYTES_REMAINING_00() set_res_sw(0x61, 0x00)
|
||||
#define SW_WARNING_STATE_UNCHANGED() set_res_sw(0x62, 0x00)
|
||||
#define SW_WARNING_CORRUPTED() set_res_sw(0x62, 0x81)
|
||||
#define SW_WARNING_EOF() set_res_sw(0x62, 0x82)
|
||||
#define SW_WARNING_EF_DEACTIVATED() set_res_sw(0x62, 0x83)
|
||||
#define SW_WARNING_WRONG_FCI() set_res_sw(0x62, 0x84)
|
||||
#define SW_WARNING_EF_TERMINATED() set_res_sw(0x62, 0x85)
|
||||
|
||||
#define SW_WARNING_NOINFO() set_res_sw(0x63, 0x00)
|
||||
#define SW_WARNING_FILLUP() set_res_sw(0x63, 0x81)
|
||||
|
||||
#define SW_EXEC_ERROR() set_res_sw(0x64, 0x00)
|
||||
|
||||
#define SW_MEMORY_FAILURE() set_res_sw(0x65, 0x81)
|
||||
|
||||
#define SW_SECURE_MESSAGE_EXEC_ERROR() set_res_sw(0x66, 0x00)
|
||||
|
||||
#define SW_WRONG_LENGTH() set_res_sw(0x67, 0x00)
|
||||
#define SW_WRONG_DATA() set_res_sw(0x67, 0x00)
|
||||
|
||||
#define SW_LOGICAL_CHANNEL_NOT_SUPPORTED() set_res_sw(0x68, 0x81)
|
||||
#define SW_SECURE_MESSAGING_NOT_SUPPORTED() set_res_sw(0x68, 0x82)
|
||||
|
||||
#define SW_COMMAND_INCOMPATIBLE() set_res_sw(0x69, 0x81)
|
||||
#define SW_SECURITY_STATUS_NOT_SATISFIED() set_res_sw(0x69, 0x82)
|
||||
#define SW_PIN_BLOCKED() set_res_sw(0x69, 0x83)
|
||||
#define SW_DATA_INVALID() set_res_sw(0x69, 0x84)
|
||||
#define SW_CONDITIONS_NOT_SATISFIED() set_res_sw(0x69, 0x85)
|
||||
#define SW_COMMAND_NOT_ALLOWED() set_res_sw(0x69, 0x86)
|
||||
#define SW_SECURE_MESSAGING_MISSING_DO() set_res_sw(0x69, 0x87)
|
||||
#define SW_SECURE_MESSAGING_INCORRECT_DO() set_res_sw(0x69, 0x88)
|
||||
#define SW_APPLET_SELECT_FAILED() set_res_sw(0x69, 0x99)
|
||||
|
||||
#define SW_INCORRECT_PARAMS() set_res_sw(0x6A, 0x80)
|
||||
#define SW_FUNC_NOT_SUPPORTED() set_res_sw(0x6A, 0x81)
|
||||
#define SW_FILE_NOT_FOUND() set_res_sw(0x6A, 0x82)
|
||||
#define SW_RECORD_NOT_FOUND() set_res_sw(0x6A, 0x83)
|
||||
#define SW_FILE_FULL() set_res_sw(0x6A, 0x84)
|
||||
#define SW_WRONG_NE() set_res_sw(0x6A, 0x85)
|
||||
#define SW_INCORRECT_P1P2() set_res_sw(0x6A, 0x86)
|
||||
#define SW_WRONG_NC() set_res_sw(0x6A, 0x87)
|
||||
#define SW_REFERENCE_NOT_FOUND() set_res_sw(0x6A, 0x88)
|
||||
#define SW_FILE_EXISTS() set_res_sw(0x6A, 0x89)
|
||||
|
||||
#define SW_WRONG_P1P2() set_res_sw(0x6B, 0x00)
|
||||
|
||||
#define SW_CORRECT_LENGTH_00() set_res_sw(0x6C, 0x00)
|
||||
|
||||
#define SW_INS_NOT_SUPPORTED() set_res_sw(0x6D, 0x00)
|
||||
|
||||
#define SW_CLA_NOT_SUPPORTED() set_res_sw(0x6E, 0x00)
|
||||
|
||||
#define SW_UNKNOWN() set_res_sw(0x6F, 0x00)
|
||||
|
||||
#define SW_OK() set_res_sw(0x90, 0x00)
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
50
src/asn1.h
50
src/asn1.h
@@ -1,50 +0,0 @@
|
||||
/*
|
||||
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
|
||||
* Copyright (c) 2022 Pol Henarejos.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _ASN1_H_
|
||||
#define _ASN1_H_
|
||||
|
||||
#include <stdlib.h>
|
||||
#if !defined(ENABLE_EMULATION) && !defined(ESP_PLATFORM)
|
||||
#include "pico/stdlib.h"
|
||||
#else
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#endif
|
||||
|
||||
typedef struct asn1_ctx {
|
||||
uint8_t *data;
|
||||
uint16_t len;
|
||||
} asn1_ctx_t;
|
||||
|
||||
extern int asn1_ctx_init(uint8_t *, uint16_t, asn1_ctx_t *);
|
||||
extern int asn1_ctx_clear(asn1_ctx_t *ctx);
|
||||
extern uint16_t asn1_len(asn1_ctx_t *ctx);
|
||||
extern uint32_t asn1_get_uint(asn1_ctx_t *ctx);
|
||||
|
||||
extern int walk_tlv(const asn1_ctx_t *ctxi,
|
||||
uint8_t **p,
|
||||
uint16_t *tag,
|
||||
uint16_t *tag_len,
|
||||
uint8_t **data);
|
||||
extern uint8_t format_tlv_len(uint16_t len, uint8_t *out);
|
||||
extern bool asn1_find_tag(const asn1_ctx_t *ctxi,
|
||||
uint16_t itag,
|
||||
asn1_ctx_t *ctxo);
|
||||
extern uint16_t asn1_len_tag(uint16_t tag, uint16_t len);
|
||||
|
||||
#endif
|
||||
159
src/button.c
Normal file
159
src/button.c
Normal file
@@ -0,0 +1,159 @@
|
||||
/*
|
||||
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
|
||||
* Copyright (c) 2022 Pol Henarejos.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "picokeys.h"
|
||||
#include "button.h"
|
||||
#include "led/led.h"
|
||||
#include "pico_time.h"
|
||||
#if defined(PICO_PLATFORM)
|
||||
#include "hardware/sync.h"
|
||||
#include "hardware/structs/ioqspi.h"
|
||||
#include "hardware/gpio.h"
|
||||
#elif defined(ESP_PLATFORM)
|
||||
#include "driver/gpio.h"
|
||||
#endif
|
||||
#include "usb.h"
|
||||
|
||||
extern void execute_tasks(void);
|
||||
|
||||
int (*button_pressed_cb)(uint8_t) = NULL;
|
||||
|
||||
static bool req_button_pending = false;
|
||||
|
||||
bool is_req_button_pending(void) {
|
||||
return req_button_pending;
|
||||
}
|
||||
|
||||
bool cancel_button = false;
|
||||
|
||||
#if !defined(ENABLE_EMULATION)
|
||||
#ifdef ESP_PLATFORM
|
||||
static bool picok_board_button_read(void) {
|
||||
int boot_state = gpio_get_level(BOOT_PIN);
|
||||
return boot_state == 0;
|
||||
}
|
||||
#elif defined(PICO_PLATFORM)
|
||||
static bool __no_inline_not_in_flash_func(picok_get_bootsel_button)(void) {
|
||||
const uint CS_PIN_INDEX = 1;
|
||||
|
||||
// Must disable interrupts, as interrupt handlers may be in flash, and we
|
||||
// are about to temporarily disable flash access!
|
||||
uint32_t flags = save_and_disable_interrupts();
|
||||
|
||||
// Set chip select to Hi-Z
|
||||
hw_write_masked(&ioqspi_hw->io[CS_PIN_INDEX].ctrl,
|
||||
GPIO_OVERRIDE_LOW << IO_QSPI_GPIO_QSPI_SS_CTRL_OEOVER_LSB,
|
||||
IO_QSPI_GPIO_QSPI_SS_CTRL_OEOVER_BITS);
|
||||
|
||||
// Note we can't call into any sleep functions in flash right now
|
||||
for (volatile int i = 0; i < 1000; ++i);
|
||||
|
||||
// The HI GPIO registers in SIO can observe and control the 6 QSPI pins.
|
||||
// Note the button pulls the pin *low* when pressed.
|
||||
#ifdef PICO_RP2040
|
||||
#define CS_BIT (1u << 1)
|
||||
#else
|
||||
#define CS_BIT SIO_GPIO_HI_IN_QSPI_CSN_BITS
|
||||
#endif
|
||||
bool button_state = !(sio_hw->gpio_hi_in & CS_BIT);
|
||||
|
||||
// Need to restore the state of chip select, else we are going to have a
|
||||
// bad time when we return to code in flash!
|
||||
hw_write_masked(&ioqspi_hw->io[CS_PIN_INDEX].ctrl,
|
||||
GPIO_OVERRIDE_NORMAL << IO_QSPI_GPIO_QSPI_SS_CTRL_OEOVER_LSB,
|
||||
IO_QSPI_GPIO_QSPI_SS_CTRL_OEOVER_BITS);
|
||||
|
||||
restore_interrupts(flags);
|
||||
|
||||
return button_state;
|
||||
}
|
||||
static bool picok_board_button_read(void) {
|
||||
return picok_get_bootsel_button();
|
||||
}
|
||||
#else
|
||||
static bool picok_board_button_read(void) {
|
||||
return true; // always unpressed
|
||||
}
|
||||
#endif
|
||||
static bool button_pressed_state = false;
|
||||
static uint32_t button_pressed_time = 0;
|
||||
static uint8_t button_press = 0;
|
||||
|
||||
bool button_wait(void) {
|
||||
/* Disabled by default. As LED may not be properly configured,
|
||||
it will not be possible to indicate button press unless it
|
||||
is commissioned. */
|
||||
uint32_t button_timeout = 0;
|
||||
if (phy_data.up_btn_present) {
|
||||
button_timeout = phy_data.up_btn * 1000;
|
||||
}
|
||||
if (button_timeout == 0) {
|
||||
return false;
|
||||
}
|
||||
uint32_t start_button = board_millis();
|
||||
bool timeout = false;
|
||||
cancel_button = false;
|
||||
uint32_t led_mode = led_get_mode();
|
||||
led_set_mode(MODE_BUTTON);
|
||||
req_button_pending = true;
|
||||
while (picok_board_button_read() == false && cancel_button == false) {
|
||||
execute_tasks();
|
||||
//sleep_ms(10);
|
||||
if (start_button + button_timeout < board_millis()) { /* timeout */
|
||||
timeout = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!timeout) {
|
||||
while (picok_board_button_read() == true && cancel_button == false) {
|
||||
execute_tasks();
|
||||
//sleep_ms(10);
|
||||
if (start_button + 15000 < board_millis()) { /* timeout */
|
||||
timeout = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
led_set_mode(led_mode);
|
||||
req_button_pending = false;
|
||||
return timeout || cancel_button;
|
||||
}
|
||||
#endif
|
||||
|
||||
void button_task(void) {
|
||||
#ifndef ENABLE_EMULATION
|
||||
if (button_pressed_cb && board_millis() > 1000 && !is_busy()) { // wait 1 second to boot up
|
||||
bool current_button_state = picok_board_button_read();
|
||||
if (current_button_state != button_pressed_state) {
|
||||
if (current_button_state == false) { // unpressed
|
||||
if (button_pressed_time == 0 || button_pressed_time + 1000 > board_millis()) {
|
||||
button_press++;
|
||||
}
|
||||
button_pressed_time = board_millis();
|
||||
}
|
||||
button_pressed_state = current_button_state;
|
||||
}
|
||||
if (button_pressed_time > 0 && button_press > 0 && button_pressed_time + 1000 < board_millis() && button_pressed_state == false) {
|
||||
if (button_pressed_cb != NULL) {
|
||||
(*button_pressed_cb)(button_press);
|
||||
}
|
||||
button_pressed_time = button_press = 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
31
src/button.h
Normal file
31
src/button.h
Normal file
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
|
||||
* Copyright (c) 2022 Pol Henarejos.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef BUTTON_H
|
||||
#define BUTTON_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#if defined(ESP_PLATFORM)
|
||||
#define BOOT_PIN GPIO_NUM_0
|
||||
#endif
|
||||
|
||||
extern bool button_wait(void);
|
||||
extern void button_task(void);
|
||||
|
||||
#endif // BUTTON_H
|
||||
37
src/compat/board.h
Normal file
37
src/compat/board.h
Normal file
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
|
||||
* Copyright (c) 2022 Pol Henarejos.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _BOARD_H_
|
||||
#define _BOARD_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#ifdef _MSC_VER
|
||||
#include <windows.h>
|
||||
struct timezone;
|
||||
extern int gettimeofday(struct timeval *tp, struct timezone *tzp);
|
||||
#else
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
|
||||
static inline uint32_t board_millis(void) {
|
||||
struct timeval start;
|
||||
gettimeofday(&start, NULL);
|
||||
uint64_t ms = (uint64_t)start.tv_sec * 1000ULL + (uint64_t)start.tv_usec / 1000ULL;
|
||||
return (uint32_t)ms;
|
||||
}
|
||||
|
||||
#endif // _BOARD_H_
|
||||
@@ -3,16 +3,16 @@
|
||||
* 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
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
* Affero 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/>.
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _COMPAT_H_
|
||||
@@ -47,4 +47,23 @@
|
||||
static void f(void)
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#ifndef HAVE_STRLCPY
|
||||
static inline size_t strlcpy(char *dst, const char *src, size_t size)
|
||||
{
|
||||
size_t srclen = strlen(src);
|
||||
|
||||
if (size != 0) {
|
||||
size_t copylen = (srclen >= size) ? size - 1 : srclen;
|
||||
memcpy(dst, src, copylen);
|
||||
dst[copylen] = '\0';
|
||||
}
|
||||
|
||||
return srclen;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif // _COMPAT_H
|
||||
@@ -3,16 +3,16 @@
|
||||
* 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
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
* Affero 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/>.
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __ESP_COMPAT_H_
|
||||
@@ -37,7 +37,12 @@ extern TaskHandle_t hcore0, hcore1;
|
||||
#define ESP32_CORE0 tskNO_AFFINITY
|
||||
#define ESP32_CORE1 tskNO_AFFINITY
|
||||
#endif
|
||||
#define multicore_launch_core1(a) xTaskCreatePinnedToCore((void(*)(void *))a, "core1", 4096*ITF_TOTAL*2, NULL, CONFIG_TINYUSB_TASK_PRIORITY - 2, &hcore1, ESP32_CORE1)
|
||||
static inline void task_wrapper(void *arg) {
|
||||
void* (*func)(void*) = (void* (*)(void*))arg;
|
||||
func(NULL);
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
#define multicore_launch_func_core1(func) xTaskCreatePinnedToCore(task_wrapper, "core1", 4096*ITF_TOTAL*2, (void *)func, CONFIG_TINYUSB_TASK_PRIORITY - 2, &hcore1, ESP32_CORE1)
|
||||
#define multicore_reset_core1() do { if (hcore1) { eTaskState e = eTaskGetState(hcore1); if (e <= eSuspended) { vTaskDelete(hcore1); }} }while(0)
|
||||
#define sleep_ms(a) vTaskDelay(a / portTICK_PERIOD_MS)
|
||||
static inline uint32_t board_millis(void) {
|
||||
119
src/compat/pthread_win32.h
Normal file
119
src/compat/pthread_win32.h
Normal file
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
|
||||
* Copyright (c) 2022 Pol Henarejos.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#ifndef _PTHREAD_H_
|
||||
#define _PTHREAD_H_
|
||||
#include <windows.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
typedef HANDLE pthread_t;
|
||||
typedef CRITICAL_SECTION pthread_mutex_t;
|
||||
|
||||
typedef struct {
|
||||
CONDITION_VARIABLE cond;
|
||||
} pthread_cond_t;
|
||||
|
||||
// Mutex
|
||||
static inline int pthread_mutex_init(pthread_mutex_t *m, void *a) {
|
||||
(void)a;
|
||||
InitializeCriticalSection(m);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int pthread_mutex_lock(pthread_mutex_t *m) {
|
||||
EnterCriticalSection(m);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int pthread_mutex_unlock(pthread_mutex_t *m) {
|
||||
LeaveCriticalSection(m);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int pthread_mutex_destroy(pthread_mutex_t *m) {
|
||||
DeleteCriticalSection(m);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int pthread_detach(pthread_t t) {
|
||||
CloseHandle(t);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Thread
|
||||
static DWORD WINAPI thread_entry(LPVOID param) {
|
||||
void **args = (void **)param;
|
||||
void *(*fn)(void *) = (void *(*)(void *))(uintptr_t)args[0];
|
||||
void *arg = args[1];
|
||||
fn(arg);
|
||||
free(param);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int pthread_create(pthread_t *t, void *a, void *(*fn)(void *), void *arg) {
|
||||
(void)a;
|
||||
void **params = malloc(2 * sizeof(void *));
|
||||
if (!params) return -1;
|
||||
params[0] = (void *)(uintptr_t)fn;
|
||||
params[1] = arg;
|
||||
*t = CreateThread(NULL, 0, thread_entry, params, 0, NULL);
|
||||
return *t ? 0 : -1;
|
||||
}
|
||||
|
||||
static inline int pthread_join(pthread_t t, void **ret) {
|
||||
WaitForSingleObject(t, INFINITE);
|
||||
CloseHandle(t);
|
||||
if (ret) *ret = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Condition variable
|
||||
static inline int pthread_cond_init(pthread_cond_t *c, void *a) {
|
||||
(void)a;
|
||||
InitializeConditionVariable(&c->cond);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int pthread_cond_destroy(pthread_cond_t *c) {
|
||||
(void)c;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int pthread_cond_wait(pthread_cond_t *c, pthread_mutex_t *m) {
|
||||
SleepConditionVariableCS(&c->cond, m, INFINITE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int pthread_cond_signal(pthread_cond_t *c) {
|
||||
WakeConditionVariable(&c->cond);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int pthread_cond_broadcast(pthread_cond_t *c) {
|
||||
WakeAllConditionVariable(&c->cond);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int pthread_mutex_trylock(pthread_mutex_t *m){
|
||||
return TryEnterCriticalSection(m) ? 0 : EBUSY;
|
||||
}
|
||||
|
||||
#endif // _PTHREAD_H_
|
||||
#endif // _MSC_VER
|
||||
135
src/compat/queue.h
Normal file
135
src/compat/queue.h
Normal file
@@ -0,0 +1,135 @@
|
||||
/*
|
||||
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
|
||||
* Copyright (c) 2022 Pol Henarejos.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef QUEUE_H
|
||||
#define QUEUE_H
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#include "compat/pthread_win32.h"
|
||||
#include "compat/semaphore_win32.h"
|
||||
#else
|
||||
#include <pthread.h>
|
||||
#include <semaphore.h>
|
||||
#endif
|
||||
#include <stdbool.h>
|
||||
typedef struct {
|
||||
pthread_mutex_t mtx;
|
||||
pthread_cond_t cnd;
|
||||
size_t size_elem;
|
||||
size_t num_elem;
|
||||
size_t max_elem;
|
||||
uint8_t buf[1024];
|
||||
bool is_init;
|
||||
#ifdef _MSC_VER
|
||||
char padding[sizeof(void *) - sizeof(bool)];
|
||||
#endif
|
||||
} queue_t;
|
||||
|
||||
static inline void queue_free(queue_t *a) {
|
||||
pthread_mutex_destroy(&a->mtx);
|
||||
pthread_cond_destroy(&a->cnd);
|
||||
a->is_init = false;
|
||||
}
|
||||
static inline void queue_init(queue_t *a, size_t size_elem, size_t max_elem) {
|
||||
if (a->is_init) {
|
||||
queue_free(a);
|
||||
}
|
||||
pthread_mutex_init(&a->mtx, NULL);
|
||||
pthread_cond_init(&a->cnd, NULL);
|
||||
a->size_elem = size_elem;
|
||||
a->max_elem = max_elem;
|
||||
a->num_elem = 0;
|
||||
a->is_init = true;
|
||||
}
|
||||
static inline void queue_add_blocking(queue_t *a, const void *b) {
|
||||
pthread_mutex_lock(&a->mtx);
|
||||
while (a->num_elem == a->max_elem) {
|
||||
pthread_cond_wait(&a->cnd, &a->mtx);
|
||||
}
|
||||
memcpy(a->buf + a->num_elem * a->size_elem, b, a->size_elem);
|
||||
a->num_elem++;
|
||||
pthread_cond_signal(&a->cnd);
|
||||
pthread_mutex_unlock(&a->mtx);
|
||||
}
|
||||
static inline void queue_remove_blocking(queue_t *a, void *b) {
|
||||
pthread_mutex_lock(&a->mtx);
|
||||
while (a->num_elem == 0) {
|
||||
pthread_cond_wait(&a->cnd, &a->mtx);
|
||||
}
|
||||
memcpy(b, a->buf, a->size_elem);
|
||||
memmove(a->buf, a->buf + a->size_elem, a->size_elem * (a->num_elem - 1));
|
||||
a->num_elem--;
|
||||
pthread_cond_signal(&a->cnd);
|
||||
pthread_mutex_unlock(&a->mtx);
|
||||
}
|
||||
static inline int queue_try_add(queue_t *a, const void *b) {
|
||||
pthread_mutex_lock(&a->mtx);
|
||||
if (a->num_elem == a->max_elem) {
|
||||
pthread_mutex_unlock(&a->mtx);
|
||||
return 0;
|
||||
}
|
||||
memcpy(a->buf + a->num_elem * a->size_elem, b, a->size_elem);
|
||||
a->num_elem++;
|
||||
pthread_cond_signal(&a->cnd);
|
||||
pthread_mutex_unlock(&a->mtx);
|
||||
return 1;
|
||||
}
|
||||
static inline int queue_try_remove(queue_t *a, void *b) {
|
||||
pthread_mutex_lock(&a->mtx);
|
||||
if (a->num_elem == 0) {
|
||||
pthread_mutex_unlock(&a->mtx);
|
||||
return 0;
|
||||
}
|
||||
memcpy(b, a->buf, a->size_elem);
|
||||
memmove(a->buf, a->buf + a->size_elem, a->size_elem * (a->num_elem - 1));
|
||||
a->num_elem--;
|
||||
pthread_cond_signal(&a->cnd);
|
||||
pthread_mutex_unlock(&a->mtx);
|
||||
return 1;
|
||||
}
|
||||
static inline int queue_is_empty(queue_t *a) {
|
||||
pthread_mutex_lock(&a->mtx);
|
||||
bool ret = a->num_elem == 0;
|
||||
pthread_mutex_unlock(&a->mtx);
|
||||
return ret;
|
||||
}
|
||||
static inline int queue_is_full(queue_t *a) {
|
||||
pthread_mutex_lock(&a->mtx);
|
||||
bool ret = a->num_elem == a->max_elem;
|
||||
pthread_mutex_unlock(&a->mtx);
|
||||
return ret;
|
||||
}
|
||||
static inline void queue_clear(queue_t *a) {
|
||||
pthread_mutex_lock(&a->mtx);
|
||||
a->num_elem = 0;
|
||||
pthread_mutex_unlock(&a->mtx);
|
||||
}
|
||||
extern pthread_t hcore0, hcore1;
|
||||
#define multicore_launch_func_core1(a) pthread_create(&hcore1, NULL, (void *(*) (void *))a, NULL)
|
||||
#define multicore_reset_core1()
|
||||
|
||||
typedef pthread_mutex_t mutex_t;
|
||||
typedef sem_t semaphore_t;
|
||||
#define mutex_init(a) pthread_mutex_init(a, NULL)
|
||||
#define mutex_try_enter(a,b) (pthread_mutex_trylock(a) == 0)
|
||||
#define mutex_enter_blocking(a) pthread_mutex_lock(a)
|
||||
#define mutex_exit(a) pthread_mutex_unlock(a)
|
||||
#define sem_release(a) sem_post(a)
|
||||
#define sem_acquire_blocking(a) sem_wait(a)
|
||||
#define multicore_lockout_victim_init() (void)0
|
||||
|
||||
#endif // QUEUE_H
|
||||
47
src/compat/semaphore_win32.h
Normal file
47
src/compat/semaphore_win32.h
Normal file
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
|
||||
* Copyright (c) 2022 Pol Henarejos.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#ifndef _SEMAPHORE_H_
|
||||
#define _SEMAPHORE_H_
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
typedef struct {
|
||||
HANDLE handle;
|
||||
} sem_t;
|
||||
|
||||
static inline int sem_init(sem_t *sem, int pshared, unsigned int value) {
|
||||
(void)pshared;
|
||||
sem->handle = CreateSemaphore(NULL, value, 0x7FFFFFFF, NULL);
|
||||
return sem->handle ? 0 : -1;
|
||||
}
|
||||
|
||||
static inline int sem_wait(sem_t *sem) {
|
||||
return WaitForSingleObject(sem->handle, INFINITE) == WAIT_OBJECT_0 ? 0 : -1;
|
||||
}
|
||||
|
||||
static inline int sem_post(sem_t *sem) {
|
||||
return ReleaseSemaphore(sem->handle, 1, NULL) ? 0 : -1;
|
||||
}
|
||||
|
||||
static inline int sem_destroy(sem_t *sem) {
|
||||
return CloseHandle(sem->handle) ? 0 : -1;
|
||||
}
|
||||
|
||||
#endif // _SEMAPHORE_H_
|
||||
#endif // _MSC_VER
|
||||
@@ -3,34 +3,151 @@
|
||||
* 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
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
* Affero 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/>.
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#if defined(ENABLE_EMULATION)
|
||||
#elif defined(ESP_PLATFORM)
|
||||
#include "esp_compat.h"
|
||||
#else
|
||||
#include <pico/unique_id.h>
|
||||
#endif
|
||||
#include "picokeys.h"
|
||||
#include "serial.h"
|
||||
#include "mbedtls/md.h"
|
||||
#include "mbedtls/sha256.h"
|
||||
#include "mbedtls/aes.h"
|
||||
#include "mbedtls/hkdf.h"
|
||||
#include "mbedtls/gcm.h"
|
||||
#include "mbedtls/base64.h"
|
||||
#include "crypto_utils.h"
|
||||
#include "pico_keys.h"
|
||||
#include "otp.h"
|
||||
#include "random.h"
|
||||
|
||||
static const mbedtls_md_info_t *SHA256(void) {
|
||||
return mbedtls_md_info_from_type(MBEDTLS_MD_SHA256);
|
||||
}
|
||||
|
||||
void derive_kbase(uint8_t kbase[32]) {
|
||||
const uint8_t nootp_salt[] = "NO-OTP";
|
||||
if (otp_key_1) {
|
||||
mbedtls_hkdf(SHA256(), pico_serial_hash, sizeof(pico_serial_hash), otp_key_1, 32, (const uint8_t *)"DEVICE/ROOT", 12, kbase, 32);
|
||||
}
|
||||
else {
|
||||
mbedtls_hkdf(SHA256(), nootp_salt, sizeof(nootp_salt)-1, pico_serial_hash, sizeof(pico_serial_hash), (const uint8_t *)"DEVICE/ROOT", 12, kbase, 32);
|
||||
}
|
||||
}
|
||||
|
||||
void derive_kver(const uint8_t *pin, size_t pin_len, uint8_t kver[32]) {
|
||||
uint8_t kbase[32];
|
||||
derive_kbase(kbase);
|
||||
mbedtls_md_hmac(SHA256(), kbase, 32, pin, pin_len, kver);
|
||||
mbedtls_platform_zeroize(kbase, sizeof(kbase));
|
||||
}
|
||||
|
||||
void pin_derive_verifier(const uint8_t *pin, size_t pin_len, uint8_t verifier[32]) {
|
||||
uint8_t kver[32];
|
||||
derive_kver(pin, pin_len, kver);
|
||||
mbedtls_hkdf(SHA256(), pico_serial_hash, sizeof(pico_serial_hash), kver, 32, (const uint8_t *)"PIN/VERIFY", 10, verifier, 32);
|
||||
mbedtls_platform_zeroize(kver, sizeof(kver));
|
||||
}
|
||||
|
||||
void pin_derive_session(const uint8_t *pin, size_t pin_len, uint8_t pin_token[32]) {
|
||||
uint8_t kver[32];
|
||||
derive_kver(pin, pin_len, kver);
|
||||
mbedtls_hkdf(SHA256(), pico_serial_hash, sizeof(pico_serial_hash), kver, 32, (const uint8_t *)"PIN/TOKEN", 9, pin_token, 32);
|
||||
mbedtls_platform_zeroize(kver, sizeof(kver));
|
||||
}
|
||||
|
||||
void pin_derive_kenc(const uint8_t pin_token[32], uint8_t kenc[32]) {
|
||||
mbedtls_hkdf(SHA256(), pico_serial_hash, sizeof(pico_serial_hash), pin_token, 32, (const uint8_t *)"PIN/ENC", 7, kenc, 32);
|
||||
}
|
||||
|
||||
void pin_derive_kenc2(const uint8_t pin_token[32], uint8_t kenc[32]) {
|
||||
uint8_t kbase[64];
|
||||
derive_kbase(kbase);
|
||||
memcpy(kbase + 32, pin_token, 32);
|
||||
mbedtls_hkdf(SHA256(), pico_serial_hash, sizeof(pico_serial_hash), kbase, 64, (const uint8_t *)"PIN/ENC2", 8, kenc, 32);
|
||||
mbedtls_platform_zeroize(kbase, sizeof(kbase));
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// Encrypt 32-byte device key using AES-256-GCM
|
||||
// Output: [nonce|ciphertext|tag] = 12 + in_len + 16 = 60 bytes
|
||||
// ------------------------------------------------------------------
|
||||
int encrypt_with_aad(const uint8_t key[32], const uint8_t *in_buf, size_t in_len, const pin_kdf_version_t version, uint8_t *out_buf) {
|
||||
uint8_t *nonce = out_buf;
|
||||
uint8_t *ct = out_buf + 12;
|
||||
uint8_t *tag = out_buf + 12 + in_len;
|
||||
|
||||
random_fill_buffer(nonce, 12);
|
||||
|
||||
mbedtls_gcm_context gcm;
|
||||
mbedtls_gcm_init(&gcm);
|
||||
uint8_t kenc[32];
|
||||
if (version == PIN_KDF_V2) {
|
||||
pin_derive_kenc2(key, kenc);
|
||||
}
|
||||
else if (version == PIN_KDF_V1) {
|
||||
pin_derive_kenc(key, kenc);
|
||||
}
|
||||
else {
|
||||
mbedtls_gcm_free(&gcm);
|
||||
return PICOKEYS_WRONG_DATA;
|
||||
}
|
||||
int rc = mbedtls_gcm_setkey(&gcm, MBEDTLS_CIPHER_ID_AES, kenc, 256);
|
||||
mbedtls_platform_zeroize(kenc, sizeof(kenc));
|
||||
if (rc != 0) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = mbedtls_gcm_crypt_and_tag(&gcm, MBEDTLS_GCM_ENCRYPT, in_len, nonce, 12, pico_serial_hash, sizeof(pico_serial_hash), in_buf, ct, 16, tag);
|
||||
mbedtls_gcm_free(&gcm);
|
||||
return rc;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// Decrypt & verify 32-byte device key using AES-256-GCM
|
||||
// Input: [nonce|ciphertext|tag] = in_len bytes
|
||||
// Output: decrypted = in_len - 12 - 16 bytes
|
||||
// ------------------------------------------------------------------
|
||||
int decrypt_with_aad(const uint8_t key[32], const uint8_t *in_buf, size_t in_len, const pin_kdf_version_t version, uint8_t *out_buf) {
|
||||
const uint8_t *nonce = in_buf;
|
||||
const uint8_t *ct = in_buf + 12;
|
||||
const uint8_t *tag = in_buf + in_len - 16;
|
||||
|
||||
mbedtls_gcm_context gcm;
|
||||
uint8_t kenc[32];
|
||||
if (version == PIN_KDF_V2) {
|
||||
pin_derive_kenc2(key, kenc);
|
||||
}
|
||||
else if (version == PIN_KDF_V1) {
|
||||
pin_derive_kenc(key, kenc);
|
||||
}
|
||||
else {
|
||||
return PICOKEYS_WRONG_DATA;
|
||||
}
|
||||
mbedtls_gcm_init(&gcm);
|
||||
int ret = mbedtls_gcm_setkey(&gcm, MBEDTLS_CIPHER_ID_AES, kenc, 256);
|
||||
mbedtls_platform_zeroize(kenc, sizeof(kenc));
|
||||
if (ret != 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
MBEDTLS_MPI_CHK(mbedtls_gcm_auth_decrypt(&gcm, in_len - 16 - 12, nonce, 12, pico_serial_hash, sizeof(pico_serial_hash), tag, 16, ct, out_buf));
|
||||
cleanup:
|
||||
mbedtls_gcm_free(&gcm);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Old functions, kept for compatibility. NOT SECURE, use the new ones above.
|
||||
void double_hash_pin(const uint8_t *pin, uint16_t len, uint8_t output[32]) {
|
||||
uint8_t o1[32];
|
||||
hash_multi(pin, len, o1);
|
||||
for (int i = 0; i < sizeof(o1); i++) {
|
||||
for (size_t i = 0; i < sizeof(o1); i++) {
|
||||
o1[i] ^= pin[i % len];
|
||||
}
|
||||
hash_multi(o1, sizeof(o1), output);
|
||||
@@ -82,12 +199,20 @@ int aes_encrypt(const uint8_t *key, const uint8_t *iv, uint16_t key_size, int mo
|
||||
}
|
||||
int r = mbedtls_aes_setkey_enc(&aes, key, key_size);
|
||||
if (r != 0) {
|
||||
return PICOKEY_EXEC_ERROR;
|
||||
mbedtls_aes_free(&aes);
|
||||
mbedtls_platform_zeroize(tmp_iv, sizeof(tmp_iv));
|
||||
return PICOKEYS_EXEC_ERROR;
|
||||
}
|
||||
if (mode == PICO_KEYS_AES_MODE_CBC) {
|
||||
return mbedtls_aes_crypt_cbc(&aes, MBEDTLS_AES_ENCRYPT, len, tmp_iv, data, data);
|
||||
int rc = 0;
|
||||
if (mode == PICOKEYS_AES_MODE_CBC) {
|
||||
rc = 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);
|
||||
else {
|
||||
rc = mbedtls_aes_crypt_cfb128(&aes, MBEDTLS_AES_ENCRYPT, len, &iv_offset, tmp_iv, data, data);
|
||||
}
|
||||
mbedtls_aes_free(&aes);
|
||||
mbedtls_platform_zeroize(tmp_iv, sizeof(tmp_iv));
|
||||
return rc;
|
||||
}
|
||||
|
||||
int aes_decrypt(const uint8_t *key, const uint8_t *iv, uint16_t key_size, int mode, uint8_t *data, uint16_t len) {
|
||||
@@ -101,31 +226,44 @@ int aes_decrypt(const uint8_t *key, const uint8_t *iv, uint16_t key_size, int mo
|
||||
}
|
||||
int r = mbedtls_aes_setkey_dec(&aes, key, key_size);
|
||||
if (r != 0) {
|
||||
return PICOKEY_EXEC_ERROR;
|
||||
mbedtls_aes_free(&aes);
|
||||
mbedtls_platform_zeroize(tmp_iv, sizeof(tmp_iv));
|
||||
return PICOKEYS_EXEC_ERROR;
|
||||
}
|
||||
if (mode == PICO_KEYS_AES_MODE_CBC) {
|
||||
return mbedtls_aes_crypt_cbc(&aes, MBEDTLS_AES_DECRYPT, len, tmp_iv, data, data);
|
||||
int rc = 0;
|
||||
if (mode == PICOKEYS_AES_MODE_CBC) {
|
||||
rc = 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);
|
||||
else {
|
||||
r = mbedtls_aes_setkey_enc(&aes, key, key_size); //CFB requires set_enc instead set_dec
|
||||
if (r != 0) {
|
||||
mbedtls_aes_free(&aes);
|
||||
mbedtls_platform_zeroize(tmp_iv, sizeof(tmp_iv));
|
||||
return PICOKEYS_EXEC_ERROR;
|
||||
}
|
||||
rc = mbedtls_aes_crypt_cfb128(&aes, MBEDTLS_AES_DECRYPT, len, &iv_offset, tmp_iv, data, data);
|
||||
}
|
||||
mbedtls_aes_free(&aes);
|
||||
mbedtls_platform_zeroize(tmp_iv, sizeof(tmp_iv));
|
||||
return rc;
|
||||
}
|
||||
|
||||
int aes_encrypt_cfb_256(const uint8_t *key, const uint8_t *iv, uint8_t *data, uint16_t len) {
|
||||
return aes_encrypt(key, iv, 256, PICO_KEYS_AES_MODE_CFB, data, len);
|
||||
return aes_encrypt(key, iv, 256, PICOKEYS_AES_MODE_CFB, data, len);
|
||||
}
|
||||
int aes_decrypt_cfb_256(const uint8_t *key, const uint8_t *iv, uint8_t *data, uint16_t len) {
|
||||
return aes_decrypt(key, iv, 256, PICO_KEYS_AES_MODE_CFB, data, len);
|
||||
return aes_decrypt(key, iv, 256, PICOKEYS_AES_MODE_CFB, data, len);
|
||||
}
|
||||
|
||||
struct lv_data {
|
||||
PACK(struct lv_data {
|
||||
unsigned char *value;
|
||||
uint8_t len;
|
||||
};
|
||||
});
|
||||
|
||||
struct ec_curve_mbed_id {
|
||||
PACK(struct ec_curve_mbed_id {
|
||||
struct 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",
|
||||
@@ -172,3 +310,84 @@ mbedtls_ecp_group_id ec_get_curve_from_prime(const uint8_t *prime, size_t prime_
|
||||
}
|
||||
return MBEDTLS_ECP_DP_NONE;
|
||||
}
|
||||
|
||||
#define POLY 0xedb88320
|
||||
|
||||
uint32_t crc32c(const uint8_t *buf, size_t len) {
|
||||
uint32_t crc = 0xffffffff;
|
||||
while (len--) {
|
||||
crc ^= *buf++;
|
||||
for (int k = 0; k < 8; k++) {
|
||||
crc = (crc >> 1) ^ (POLY & (0 - (crc & 1)));
|
||||
}
|
||||
}
|
||||
return ~crc;
|
||||
}
|
||||
|
||||
int base64url_encode(unsigned char *dst, size_t dlen, size_t *olen, const unsigned char *src, size_t slen) {
|
||||
int rc = mbedtls_base64_encode(dst, dlen, olen, src, slen);
|
||||
if (rc != 0) {
|
||||
return rc;
|
||||
}
|
||||
for (size_t i = 0; i < *olen; i++) {
|
||||
if (dst[i] == '+') {
|
||||
dst[i] = '-';
|
||||
}
|
||||
else if (dst[i] == '/') {
|
||||
dst[i] = '_';
|
||||
}
|
||||
}
|
||||
if (*olen == 0) {
|
||||
return 0;
|
||||
}
|
||||
uint8_t *p = dst + *olen - 1;
|
||||
while (*p == '=') {
|
||||
*p-- = '\0';
|
||||
(*olen)--;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int base64url_decode(unsigned char *dst, size_t dlen, size_t *olen, const unsigned char *src, size_t slen) {
|
||||
// First convert from base64url to standard base64
|
||||
if ((slen % 4) == 1) return MBEDTLS_ERR_BASE64_INVALID_CHARACTER;
|
||||
size_t padding = (4 - (slen % 4)) % 4;
|
||||
unsigned char *b64_src = malloc(slen + padding);
|
||||
if (b64_src == NULL) {
|
||||
return PICOKEYS_ERR_MEMORY_FATAL;
|
||||
}
|
||||
for (size_t i = 0; i < slen; i++) {
|
||||
if (src[i] == '-') {
|
||||
b64_src[i] = '+';
|
||||
}
|
||||
else if (src[i] == '_') {
|
||||
b64_src[i] = '/';
|
||||
}
|
||||
else {
|
||||
b64_src[i] = src[i];
|
||||
}
|
||||
}
|
||||
for (size_t i = 0; i < padding; i++) {
|
||||
b64_src[slen + i] = '=';
|
||||
}
|
||||
size_t b64_len = slen + padding;
|
||||
|
||||
int rc = mbedtls_base64_decode(dst, dlen, olen, b64_src, b64_len);
|
||||
free(b64_src);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int b64url_decoded_len(size_t n, size_t *out_len) {
|
||||
if (out_len == NULL) return -1;
|
||||
if ((n % 4) == 1) return -2; // longitud base64url invàlida
|
||||
|
||||
size_t pad = (4 - (n % 4)) % 4; // 0,1,2
|
||||
size_t total = n + pad;
|
||||
size_t out = (total / 4) * 3;
|
||||
|
||||
if (pad == 1) out -= 1;
|
||||
else if (pad == 2) out -= 2;
|
||||
|
||||
*out_len = out;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -3,16 +3,16 @@
|
||||
* 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
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
* Affero 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/>.
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _CRYPTO_UTILS_H_
|
||||
@@ -21,23 +21,40 @@
|
||||
#include "mbedtls/ecp.h"
|
||||
#include "mbedtls/md.h"
|
||||
|
||||
#define PICO_KEYS_KEY_RSA 0x000f // It is a mask
|
||||
#define PICO_KEYS_KEY_RSA_1K 0x0001
|
||||
#define PICO_KEYS_KEY_RSA_2K 0x0002
|
||||
#define PICO_KEYS_KEY_RSA_3K 0x0004
|
||||
#define PICO_KEYS_KEY_RSA_4k 0x0008
|
||||
#define PICO_KEYS_KEY_EC 0x0010
|
||||
#define PICO_KEYS_KEY_AES 0x0f00 // It is a mask
|
||||
#define PICO_KEYS_KEY_AES_128 0x0100
|
||||
#define PICO_KEYS_KEY_AES_192 0x0200
|
||||
#define PICO_KEYS_KEY_AES_256 0x0400
|
||||
#define PICO_KEYS_KEY_AES_512 0x0800 /* For AES XTS */
|
||||
#define PICOKEYS_KEY_RSA 0x000f // It is a mask
|
||||
#define PICOKEYS_KEY_RSA_1K 0x0001
|
||||
#define PICOKEYS_KEY_RSA_2K 0x0002
|
||||
#define PICOKEYS_KEY_RSA_3K 0x0004
|
||||
#define PICOKEYS_KEY_RSA_4k 0x0008
|
||||
#define PICOKEYS_KEY_EC 0x0010
|
||||
#define PICOKEYS_KEY_AES 0x0f00 // It is a mask
|
||||
#define PICOKEYS_KEY_AES_128 0x0100
|
||||
#define PICOKEYS_KEY_AES_192 0x0200
|
||||
#define PICOKEYS_KEY_AES_256 0x0400
|
||||
#define PICOKEYS_KEY_AES_512 0x0800 /* For AES XTS */
|
||||
|
||||
#define PICO_KEYS_AES_MODE_CBC 1
|
||||
#define PICO_KEYS_AES_MODE_CFB 2
|
||||
#define PICOKEYS_AES_MODE_CBC 1
|
||||
#define PICOKEYS_AES_MODE_CFB 2
|
||||
|
||||
#define IV_SIZE 16
|
||||
|
||||
typedef enum {
|
||||
PIN_KDF_V1 = 1,
|
||||
PIN_KDF_V2 = 2,
|
||||
PIN_KDF_UNKNOWN = 0xff
|
||||
} pin_kdf_version_t;
|
||||
|
||||
#define PIN_KDF_DEFAULT_VERSION PIN_KDF_V2
|
||||
|
||||
// Newer and safe functions
|
||||
extern void derive_kbase(uint8_t kbase[32]);
|
||||
extern void derive_kver(const uint8_t *pin, size_t pin_len, uint8_t kver[32]);
|
||||
extern void pin_derive_kenc(const uint8_t pin_token[32], uint8_t kenc[32]);
|
||||
extern void pin_derive_kenc2(const uint8_t pin_token[32], uint8_t kenc[32]);
|
||||
extern void pin_derive_session(const uint8_t *pin, size_t pin_len, uint8_t pin_token[32]);
|
||||
extern void pin_derive_verifier(const uint8_t *pin, size_t pin_len, uint8_t verifier[32]);
|
||||
extern int encrypt_with_aad(const uint8_t key[32], const uint8_t *in_buf, size_t in_len, const pin_kdf_version_t version, uint8_t *out_buf);
|
||||
extern int decrypt_with_aad(const uint8_t key[32], const uint8_t *in_buf, size_t in_len, const pin_kdf_version_t version, uint8_t *out_buf);
|
||||
extern void double_hash_pin(const uint8_t *pin, uint16_t len, uint8_t output[32]);
|
||||
extern void hash_multi(const uint8_t *input, uint16_t len, uint8_t output[32]);
|
||||
extern void hash256(const uint8_t *input, size_t len, uint8_t output[32]);
|
||||
@@ -47,5 +64,11 @@ extern int aes_decrypt(const uint8_t *key, const uint8_t *iv, uint16_t key_size,
|
||||
extern int aes_encrypt_cfb_256(const uint8_t *key, const uint8_t *iv, uint8_t *data, uint16_t len);
|
||||
extern int aes_decrypt_cfb_256(const uint8_t *key, const uint8_t *iv, uint8_t *data, uint16_t len);
|
||||
extern mbedtls_ecp_group_id ec_get_curve_from_prime(const uint8_t *prime, size_t prime_len);
|
||||
extern uint32_t crc32c(const uint8_t *buf, size_t len);
|
||||
extern int base64url_encode(unsigned char *dst, size_t dlen, size_t *olen, const unsigned char *src, size_t slen);
|
||||
extern int base64url_decode(unsigned char *dst, size_t dlen, size_t *olen, const unsigned char *src, size_t slen);
|
||||
extern int b64url_decoded_len(size_t n, size_t *out_len);
|
||||
|
||||
#define PIN_KDF_SIZE(x) (12 + (x) + 16)
|
||||
|
||||
#endif
|
||||
|
||||
79
src/debug.h
79
src/debug.h
@@ -3,48 +3,69 @@
|
||||
* 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
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
* Affero 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/>.
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _DEBUG_H_
|
||||
#define _DEBUG_H_
|
||||
|
||||
#if defined(DEBUG_APDU) && DEBUG_APDU == 1
|
||||
#define DEBUG_PAYLOAD(_p, _s) { \
|
||||
printf("Payload %s (%d bytes) [%s:%d]:\n", #_p, (int) (_s), __FILE__, __LINE__); \
|
||||
for (int _i = 0; _i < _s; _i += 16) { \
|
||||
printf("%" PRIxPTR "h : ", (uintptr_t) (_i + _p)); \
|
||||
for (int _j = 0; _j < 16; _j++) { \
|
||||
if (_j < _s - _i) printf("%02X ", (_p)[_i + _j]); \
|
||||
else printf(" "); \
|
||||
if (_j == 7) printf(" "); \
|
||||
} printf(": "); \
|
||||
for (int _j = 0; _j < 16; _j++) { \
|
||||
if (_j < _s - _i && (_p)[_i + _j] > 32 && (_p)[_i + _j] != 127 && (_p)[_i + _j] < 176) printf("%c", (_p)[_i + _j]); \
|
||||
else printf(" "); \
|
||||
if (_j == 7) printf(" "); \
|
||||
} \
|
||||
printf("\n"); \
|
||||
} printf("\n"); \
|
||||
}
|
||||
#define DEBUG_DATA(_p, _s) { \
|
||||
printf("Data %s (%d bytes) [%s:%d]:\n", #_p, (int) (_s), __FILE__, __LINE__); \
|
||||
char *_tmp = (char *) calloc(1, 2 * _s + 1); \
|
||||
for (int _i = 0; _i < _s; _i++) { \
|
||||
sprintf(&_tmp[2 * _i], "%02X", (_p)[_i]); \
|
||||
} \
|
||||
printf("%s\n", _tmp); \
|
||||
free(_tmp); \
|
||||
#include <inttypes.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
static inline void debug_payload_impl(const char *name, const uint8_t *p, size_t s, const char *file, int line) {
|
||||
printf("Payload %s (%zu bytes) [%s:%d]:\n", name, s, file, line);
|
||||
for (size_t i = 0; i < s; i += 16) {
|
||||
printf("%" PRIxPTR "h : ", (uintptr_t)(p + i));
|
||||
for (size_t j = 0; j < 16; j++) {
|
||||
if (j < s - i) {
|
||||
printf("%02X ", p[i + j]);
|
||||
}
|
||||
else {
|
||||
printf(" ");
|
||||
}
|
||||
if (j == 7) {
|
||||
printf(" ");
|
||||
}
|
||||
}
|
||||
printf(": ");
|
||||
for (size_t j = 0; j < 16; j++) {
|
||||
if (j < s - i && p[i + j] > 32 && p[i + j] != 127 && p[i + j] < 176) {
|
||||
printf("%c", p[i + j]);
|
||||
}
|
||||
else {
|
||||
printf(" ");
|
||||
}
|
||||
if (j == 7) {
|
||||
printf(" ");
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
static inline void debug_data_impl(const char *name, const uint8_t *p, size_t s, const char *file, int line) {
|
||||
printf("Data %s (%zu bytes) [%s:%d]:\n", name, s, file, line);
|
||||
for (size_t i = 0; i < s; i++) {
|
||||
printf("%02X", p[i]);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
#define DEBUG_PAYLOAD(_p, _s) debug_payload_impl(#_p, (const uint8_t *)(_p), (size_t)(_s), __FILE__, __LINE__)
|
||||
#define DEBUG_DATA(_p, _s) debug_data_impl(#_p, (const uint8_t *)(_p), (size_t)(_s), __FILE__, __LINE__)
|
||||
|
||||
#else
|
||||
#define DEBUG_PAYLOAD(_p, _s)
|
||||
|
||||
135
src/eac.c
135
src/eac.c
@@ -3,24 +3,30 @@
|
||||
* 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
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
* Affero 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/>.
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "picokeys.h"
|
||||
#include "eac.h"
|
||||
#include "crypto_utils.h"
|
||||
#include "random.h"
|
||||
#include "mbedtls/cmac.h"
|
||||
#include "asn1.h"
|
||||
#include "tlv.h"
|
||||
#include "apdu.h"
|
||||
#ifdef ENABLE_EMULATION
|
||||
#include "usb/emulation/emulation.h"
|
||||
#else
|
||||
#include "usb/usb.h"
|
||||
#endif
|
||||
|
||||
static uint8_t sm_nonce[8];
|
||||
static uint8_t sm_kmac[16];
|
||||
@@ -29,19 +35,13 @@ static MSE_protocol sm_protocol = MSE_NONE;
|
||||
static mbedtls_mpi sm_mSSC;
|
||||
static uint8_t sm_blocksize = 0;
|
||||
static uint8_t sm_iv[16];
|
||||
uint16_t sm_session_pin_len = 0;
|
||||
uint8_t sm_session_pin[16];
|
||||
static bool sm_active = false;
|
||||
|
||||
bool is_secured_apdu() {
|
||||
bool is_secured_apdu(void) {
|
||||
return CLA(apdu) & 0xC;
|
||||
}
|
||||
|
||||
void sm_derive_key(const uint8_t *input,
|
||||
size_t input_len,
|
||||
uint8_t counter,
|
||||
const uint8_t *nonce,
|
||||
size_t nonce_len,
|
||||
uint8_t *out) {
|
||||
static void sm_derive_key(const uint8_t *input, size_t input_len, uint8_t counter, const uint8_t *nonce, size_t nonce_len, uint8_t *out) {
|
||||
uint8_t *b = (uint8_t *) calloc(1, input_len + nonce_len + 4);
|
||||
if (input) {
|
||||
memcpy(b, input, input_len);
|
||||
@@ -60,11 +60,12 @@ void sm_derive_all_keys(const uint8_t *derived, size_t derived_len) {
|
||||
memcpy(sm_nonce, random_bytes_get(8), 8);
|
||||
sm_derive_key(derived, derived_len, 1, sm_nonce, sizeof(sm_nonce), sm_kenc);
|
||||
sm_derive_key(derived, derived_len, 2, sm_nonce, sizeof(sm_nonce), sm_kmac);
|
||||
mbedtls_mpi_free(&sm_mSSC);
|
||||
mbedtls_mpi_init(&sm_mSSC);
|
||||
mbedtls_mpi_grow(&sm_mSSC, sm_blocksize);
|
||||
mbedtls_mpi_lset(&sm_mSSC, 0);
|
||||
memset(sm_iv, 0, sizeof(sm_iv));
|
||||
sm_session_pin_len = 0;
|
||||
sm_active = true;
|
||||
}
|
||||
|
||||
void sm_set_protocol(MSE_protocol proto) {
|
||||
@@ -75,32 +76,38 @@ void sm_set_protocol(MSE_protocol proto) {
|
||||
else if (proto == MSE_3DES) {
|
||||
sm_blocksize = 8;
|
||||
}
|
||||
else {
|
||||
sm_blocksize = 0;
|
||||
}
|
||||
memset(sm_kenc, 0, sizeof(sm_kenc));
|
||||
memset(sm_kmac, 0, sizeof(sm_kmac));
|
||||
memset(sm_nonce, 0, sizeof(sm_nonce));
|
||||
memset(sm_iv, 0, sizeof(sm_iv));
|
||||
sm_active = false;
|
||||
}
|
||||
|
||||
MSE_protocol sm_get_protocol() {
|
||||
MSE_protocol sm_get_protocol(void) {
|
||||
return sm_protocol;
|
||||
}
|
||||
|
||||
uint8_t *sm_get_nonce() {
|
||||
uint8_t *sm_get_nonce(void) {
|
||||
return sm_nonce;
|
||||
}
|
||||
|
||||
int sm_sign(uint8_t *in, size_t in_len, uint8_t *out) {
|
||||
return mbedtls_cipher_cmac(mbedtls_cipher_info_from_type(MBEDTLS_CIPHER_AES_128_ECB),
|
||||
sm_kmac,
|
||||
128,
|
||||
in,
|
||||
in_len,
|
||||
out);
|
||||
int sm_sign(uint8_t *in, size_t in_len, uint8_t out[16]) {
|
||||
return mbedtls_cipher_cmac(mbedtls_cipher_info_from_type(MBEDTLS_CIPHER_AES_128_ECB), sm_kmac, 128, in, in_len, out);
|
||||
}
|
||||
|
||||
int sm_unwrap() {
|
||||
int sm_unwrap(void) {
|
||||
uint8_t sm_indicator = (CLA(apdu) >> 2) & 0x3;
|
||||
if (sm_indicator == 0) {
|
||||
return PICOKEY_OK;
|
||||
return PICOKEYS_OK;
|
||||
}
|
||||
if (!sm_active || sm_blocksize == 0) {
|
||||
return PICOKEYS_EXEC_ERROR;
|
||||
}
|
||||
int r = sm_verify();
|
||||
if (r != PICOKEY_OK) {
|
||||
if (r != PICOKEYS_OK) {
|
||||
return r;
|
||||
}
|
||||
apdu.ne = sm_get_le();
|
||||
@@ -111,10 +118,9 @@ int sm_unwrap() {
|
||||
uint16_t tag = 0x0;
|
||||
uint8_t *tag_data = NULL, *p = NULL;
|
||||
uint16_t tag_len = 0;
|
||||
asn1_ctx_t ctxi;
|
||||
asn1_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi);
|
||||
while (walk_tlv(&ctxi, &p, &tag, &tag_len, &tag_data))
|
||||
{
|
||||
tlv_ctx_t ctxi;
|
||||
tlv_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi);
|
||||
while (tlv_walk(&ctxi, &p, &tag, &tag_len, &tag_data)) {
|
||||
if (tag == 0x87 || tag == 0x85) {
|
||||
body = tag_data;
|
||||
body_size = tag_len;
|
||||
@@ -126,25 +132,28 @@ int sm_unwrap() {
|
||||
}
|
||||
if (!body) {
|
||||
apdu.nc = 0;
|
||||
return PICOKEY_OK;
|
||||
return PICOKEYS_OK;
|
||||
}
|
||||
if (is87 && *body++ != 0x1) {
|
||||
return PICOKEY_WRONG_PADDING;
|
||||
return PICOKEYS_WRONG_PADDING;
|
||||
}
|
||||
sm_update_iv();
|
||||
aes_decrypt(sm_kenc, sm_iv, 128, PICO_KEYS_AES_MODE_CBC, body, body_size);
|
||||
aes_decrypt(sm_kenc, sm_iv, 128, PICOKEYS_AES_MODE_CBC, body, body_size);
|
||||
memmove(apdu.data, body, body_size);
|
||||
apdu.nc = sm_remove_padding(apdu.data, body_size);
|
||||
DEBUG_PAYLOAD(apdu.data, (int) apdu.nc);
|
||||
return PICOKEY_OK;
|
||||
return PICOKEYS_OK;
|
||||
}
|
||||
|
||||
int sm_wrap() {
|
||||
int sm_wrap(void) {
|
||||
uint8_t sm_indicator = (CLA(apdu) >> 2) & 0x3;
|
||||
if (sm_indicator == 0) {
|
||||
return PICOKEY_OK;
|
||||
return PICOKEYS_OK;
|
||||
}
|
||||
uint8_t input[2048];
|
||||
if (!sm_active || sm_blocksize == 0) {
|
||||
return PICOKEYS_EXEC_ERROR;
|
||||
}
|
||||
uint8_t input[USB_BUFFER_SIZE];
|
||||
size_t input_len = 0;
|
||||
memset(input, 0, sizeof(input));
|
||||
mbedtls_mpi ssc;
|
||||
@@ -153,7 +162,7 @@ int sm_wrap() {
|
||||
mbedtls_mpi_copy(&sm_mSSC, &ssc);
|
||||
int r = mbedtls_mpi_write_binary(&ssc, input, sm_blocksize);
|
||||
if (r != 0) {
|
||||
return PICOKEY_EXEC_ERROR;
|
||||
return PICOKEYS_EXEC_ERROR;
|
||||
}
|
||||
input_len += sm_blocksize;
|
||||
mbedtls_mpi_free(&ssc);
|
||||
@@ -163,7 +172,7 @@ int sm_wrap() {
|
||||
res_APDU_size += (sm_blocksize - (res_APDU_size % sm_blocksize));
|
||||
DEBUG_PAYLOAD(res_APDU, res_APDU_size);
|
||||
sm_update_iv();
|
||||
aes_encrypt(sm_kenc, sm_iv, 128, PICO_KEYS_AES_MODE_CBC, res_APDU, res_APDU_size);
|
||||
aes_encrypt(sm_kenc, sm_iv, 128, PICOKEYS_AES_MODE_CBC, res_APDU, res_APDU_size);
|
||||
memmove(res_APDU + 1, res_APDU, res_APDU_size);
|
||||
res_APDU[0] = 0x1;
|
||||
res_APDU_size++;
|
||||
@@ -181,14 +190,14 @@ int sm_wrap() {
|
||||
else {
|
||||
memmove(res_APDU + 4, res_APDU, res_APDU_size);
|
||||
res_APDU[1] = 0x82;
|
||||
put_uint16_t_be(res_APDU_size, res_APDU + 2);
|
||||
put_uint16_be(res_APDU_size, res_APDU + 2);
|
||||
res_APDU_size += 4;
|
||||
}
|
||||
res_APDU[0] = 0x87;
|
||||
}
|
||||
res_APDU[res_APDU_size++] = 0x99;
|
||||
res_APDU[res_APDU_size++] = 2;
|
||||
put_uint16_t_be(apdu.sw, res_APDU + res_APDU_size);
|
||||
put_uint16_be(apdu.sw, res_APDU + res_APDU_size);
|
||||
res_APDU_size += 2;
|
||||
memcpy(input + input_len, res_APDU, res_APDU_size);
|
||||
input_len += res_APDU_size;
|
||||
@@ -202,16 +211,16 @@ int sm_wrap() {
|
||||
apdu.ne = res_APDU_size;
|
||||
}
|
||||
set_res_sw(0x90, 0x00);
|
||||
return PICOKEY_OK;
|
||||
return PICOKEYS_OK;
|
||||
}
|
||||
|
||||
uint16_t sm_get_le() {
|
||||
uint16_t sm_get_le(void) {
|
||||
uint16_t tag = 0x0;
|
||||
uint8_t *tag_data = NULL, *p = NULL;
|
||||
uint16_t tag_len = 0;
|
||||
asn1_ctx_t ctxi;
|
||||
asn1_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi);
|
||||
while (walk_tlv(&ctxi, &p, &tag, &tag_len, &tag_data)) {
|
||||
tlv_ctx_t ctxi;
|
||||
tlv_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi);
|
||||
while (tlv_walk(&ctxi, &p, &tag, &tag_len, &tag_data)) {
|
||||
if (tag == 0x97) {
|
||||
uint16_t le = 0;
|
||||
for (uint16_t t = 1; t <= tag_len; t++) {
|
||||
@@ -223,26 +232,26 @@ uint16_t sm_get_le() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sm_update_iv() {
|
||||
void sm_update_iv(void) {
|
||||
uint8_t tmp_iv[16], sc_counter[16];
|
||||
memset(tmp_iv, 0, sizeof(tmp_iv)); //IV is always 0 for encryption of IV based on counter
|
||||
mbedtls_mpi_write_binary(&sm_mSSC, sc_counter, sizeof(sc_counter));
|
||||
aes_encrypt(sm_kenc, tmp_iv, 128, PICO_KEYS_AES_MODE_CBC, sc_counter, sizeof(sc_counter));
|
||||
aes_encrypt(sm_kenc, tmp_iv, 128, PICOKEYS_AES_MODE_CBC, sc_counter, sizeof(sc_counter));
|
||||
memcpy(sm_iv, sc_counter, sizeof(sc_counter));
|
||||
}
|
||||
|
||||
int sm_verify() {
|
||||
uint8_t input[2048];
|
||||
int sm_verify(void) {
|
||||
uint8_t input[USB_BUFFER_SIZE];
|
||||
memset(input, 0, sizeof(input));
|
||||
uint16_t input_len = 0;
|
||||
int r = 0;
|
||||
bool add_header = (CLA(apdu) & 0xC) == 0xC;
|
||||
int data_len = (int) (apdu.nc / sm_blocksize) * sm_blocksize;
|
||||
size_t data_len = (size_t)(apdu.nc / sm_blocksize) * sm_blocksize;
|
||||
if (data_len % sm_blocksize) {
|
||||
data_len += sm_blocksize;
|
||||
}
|
||||
if (data_len + (add_header ? sm_blocksize : 0) > sizeof(input)) {
|
||||
return PICOKEY_WRONG_LENGTH;
|
||||
return PICOKEYS_WRONG_LENGTH;
|
||||
}
|
||||
mbedtls_mpi ssc;
|
||||
mbedtls_mpi_init(&ssc);
|
||||
@@ -252,7 +261,7 @@ int sm_verify() {
|
||||
input_len += sm_blocksize;
|
||||
mbedtls_mpi_free(&ssc);
|
||||
if (r != 0) {
|
||||
return PICOKEY_EXEC_ERROR;
|
||||
return PICOKEYS_EXEC_ERROR;
|
||||
}
|
||||
if (add_header) {
|
||||
input[input_len++] = CLA(apdu);
|
||||
@@ -268,12 +277,12 @@ int sm_verify() {
|
||||
uint16_t tag = 0x0;
|
||||
uint8_t *tag_data = NULL, *p = NULL;
|
||||
uint16_t tag_len = 0;
|
||||
asn1_ctx_t ctxi;
|
||||
asn1_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi);
|
||||
while (walk_tlv(&ctxi, &p, &tag, &tag_len, &tag_data)) {
|
||||
tlv_ctx_t ctxi;
|
||||
tlv_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi);
|
||||
while (tlv_walk(&ctxi, &p, &tag, &tag_len, &tag_data)) {
|
||||
if (tag & 0x1) {
|
||||
input[input_len++] = (uint8_t)tag;
|
||||
uint8_t tlen = format_tlv_len(tag_len, input + input_len);
|
||||
uint8_t tlen = tlv_format_len(tag_len, input + input_len);
|
||||
input_len += tlen;
|
||||
memcpy(input + input_len, tag_data, tag_len);
|
||||
input_len += tag_len;
|
||||
@@ -284,8 +293,8 @@ int sm_verify() {
|
||||
mac_len = tag_len;
|
||||
}
|
||||
}
|
||||
if (!mac) {
|
||||
return PICOKEY_WRONG_DATA;
|
||||
if (!mac || mac_len != 8) {
|
||||
return PICOKEYS_WRONG_DATA;
|
||||
}
|
||||
if (some_added) {
|
||||
input[input_len++] = 0x80;
|
||||
@@ -294,12 +303,12 @@ int sm_verify() {
|
||||
uint8_t signature[16];
|
||||
r = sm_sign(input, input_len, signature);
|
||||
if (r != 0) {
|
||||
return PICOKEY_EXEC_ERROR;
|
||||
return PICOKEYS_EXEC_ERROR;
|
||||
}
|
||||
if (memcmp(signature, mac, mac_len) == 0) {
|
||||
return PICOKEY_OK;
|
||||
return PICOKEYS_OK;
|
||||
}
|
||||
return PICOKEY_VERIFICATION_FAILED;
|
||||
return PICOKEYS_VERIFICATION_FAILED;
|
||||
}
|
||||
|
||||
uint16_t sm_remove_padding(const uint8_t *data, uint16_t data_len) {
|
||||
|
||||
32
src/eac.h
32
src/eac.h
@@ -3,22 +3,24 @@
|
||||
* 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
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
* Affero 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/>.
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _EAC_H_
|
||||
#define _EAC_H_
|
||||
|
||||
#include "pico_keys.h"
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
typedef enum MSE_protocol {
|
||||
MSE_AES = 0,
|
||||
@@ -28,17 +30,15 @@ typedef enum MSE_protocol {
|
||||
|
||||
extern void sm_derive_all_keys(const uint8_t *input, size_t input_len);
|
||||
extern void sm_set_protocol(MSE_protocol proto);
|
||||
extern MSE_protocol sm_get_protocol();
|
||||
extern uint8_t *sm_get_nonce();
|
||||
extern int sm_sign(uint8_t *in, size_t in_len, uint8_t *out);
|
||||
int sm_verify();
|
||||
void sm_update_iv();
|
||||
uint16_t sm_get_le();
|
||||
extern int sm_unwrap();
|
||||
extern MSE_protocol sm_get_protocol(void);
|
||||
extern uint8_t *sm_get_nonce(void);
|
||||
extern int sm_sign(uint8_t *in, size_t in_len, uint8_t out[16]);
|
||||
int sm_verify(void);
|
||||
void sm_update_iv(void);
|
||||
uint16_t sm_get_le(void);
|
||||
extern int sm_unwrap(void);
|
||||
uint16_t sm_remove_padding(const uint8_t *data, uint16_t data_len);
|
||||
extern int sm_wrap();
|
||||
extern bool is_secured_apdu();
|
||||
extern uint8_t sm_session_pin[16];
|
||||
extern uint16_t sm_session_pin_len;
|
||||
extern int sm_wrap(void);
|
||||
extern bool is_secured_apdu(void);
|
||||
|
||||
#endif
|
||||
|
||||
228
src/fs/file.c
228
src/fs/file.c
@@ -3,45 +3,39 @@
|
||||
* 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
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
* Affero 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/>.
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "picokeys.h"
|
||||
#include "file.h"
|
||||
#include "pico_keys.h"
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include "asn1.h"
|
||||
#include "tlv.h"
|
||||
#include "apdu.h"
|
||||
#include <stdio.h>
|
||||
|
||||
#define MAX_DEPTH 4
|
||||
|
||||
#define MAX_DYNAMIC_FILES 256
|
||||
|
||||
extern const uintptr_t end_data_pool;
|
||||
extern const uintptr_t start_data_pool;
|
||||
extern const uintptr_t end_rom_pool;
|
||||
extern const uintptr_t start_rom_pool;
|
||||
extern int flash_write_data_to_file(file_t *file, const uint8_t *data, uint16_t len);
|
||||
extern int flash_program_block(uintptr_t addr, const uint8_t *data, size_t len);
|
||||
extern uintptr_t flash_read_uintptr(uintptr_t addr);
|
||||
extern uint16_t flash_read_uint16(uintptr_t addr);
|
||||
extern uint8_t flash_read_uint8(uintptr_t addr);
|
||||
extern uint8_t *flash_read(uintptr_t addr);
|
||||
extern int flash_clear_file(file_t *ef);
|
||||
extern void low_flash_available();
|
||||
|
||||
#ifndef ENABLE_EMULATION
|
||||
file_t sef_phy = {.fid = EF_PHY, .parent = 5, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH | FILE_PERSISTENT, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff}};
|
||||
file_t *ef_phy = &sef_phy;
|
||||
#endif
|
||||
|
||||
//puts FCI in the RAPDU
|
||||
void process_fci(const file_t *pe, int fmd) {
|
||||
void file_process_fci(const file_t *pe, int fmd) {
|
||||
res_APDU_size = 0;
|
||||
if (fmd) {
|
||||
res_APDU[res_APDU_size++] = 0x6f;
|
||||
@@ -55,12 +49,13 @@ void process_fci(const file_t *pe, int fmd) {
|
||||
res_APDU[res_APDU_size++] = 2;
|
||||
if (pe->data) {
|
||||
if ((pe->type & FILE_DATA_FUNC) == FILE_DATA_FUNC) {
|
||||
uint16_t len = (uint16_t)((int (*)(const file_t *, int))(pe->data))(pe, 0);
|
||||
res_APDU_size += put_uint16_t_be(len, res_APDU + res_APDU_size);
|
||||
int (*data_fn)(const file_t *, int) = (int (*)(const file_t *, int))(uintptr_t)pe->data;
|
||||
uint16_t len = (uint16_t)data_fn(pe, 0);
|
||||
res_APDU_size += put_uint16_be(len, res_APDU + res_APDU_size);
|
||||
}
|
||||
else {
|
||||
uint16_t v = file_get_size(pe);
|
||||
res_APDU_size += put_uint16_t_be(v, res_APDU + res_APDU_size);
|
||||
res_APDU_size += put_uint16_be(v, res_APDU + res_APDU_size);
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -86,7 +81,7 @@ void process_fci(const file_t *pe, int fmd) {
|
||||
|
||||
res_APDU[res_APDU_size++] = 0x83;
|
||||
res_APDU[res_APDU_size++] = 2;
|
||||
res_APDU_size += put_uint16_t_be(pe->fid, res_APDU + res_APDU_size);
|
||||
res_APDU_size += put_uint16_be(pe->fid, res_APDU + res_APDU_size);
|
||||
if (pe->name) {
|
||||
res_APDU[res_APDU_size++] = 0x84;
|
||||
res_APDU[res_APDU_size++] = MIN(pe->name[0], 16);
|
||||
@@ -115,7 +110,7 @@ file_t dynamic_file[MAX_DYNAMIC_FILES];
|
||||
|
||||
bool card_terminated = false;
|
||||
|
||||
bool is_parent(const file_t *child, const file_t *parent) {
|
||||
static bool is_parent(const file_t *child, const file_t *parent) {
|
||||
if (child == parent) {
|
||||
return true;
|
||||
}
|
||||
@@ -129,7 +124,7 @@ file_t *get_parent(file_t *f) {
|
||||
return &file_entries[f->parent];
|
||||
}
|
||||
|
||||
file_t *search_by_name(uint8_t *name, uint16_t namelen) {
|
||||
file_t *file_search_by_name(uint8_t *name, uint16_t namelen) {
|
||||
for (file_t *p = file_entries; p != file_last; p++) {
|
||||
if (p->name && *p->name == apdu.nc && memcmp(p->name + 1, name, namelen) == 0) {
|
||||
return p;
|
||||
@@ -138,7 +133,7 @@ file_t *search_by_name(uint8_t *name, uint16_t namelen) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
file_t *search_by_fid(const uint16_t fid, const file_t *parent, const uint8_t sp) {
|
||||
file_t *file_search_by_fid(const uint16_t fid, const file_t *parent, const uint8_t sp) {
|
||||
#ifndef ENABLE_EMULATION
|
||||
if (fid == EF_PHY) {
|
||||
return ef_phy;
|
||||
@@ -158,28 +153,37 @@ file_t *search_by_fid(const uint16_t fid, const file_t *parent, const uint8_t sp
|
||||
return NULL;
|
||||
}
|
||||
|
||||
file_t *search_file(const uint16_t fid) {
|
||||
file_t *ef = search_by_fid(fid, NULL, SPECIFY_EF);
|
||||
static file_t *search_dynamic_file(uint16_t fid) {
|
||||
for (int i = 0; i < dynamic_files; i++) {
|
||||
if (dynamic_file[i].fid == fid) {
|
||||
return &dynamic_file[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
file_t *file_search(const uint16_t fid) {
|
||||
file_t *ef = file_search_by_fid(fid, NULL, SPECIFY_EF);
|
||||
if (ef) {
|
||||
return ef;
|
||||
}
|
||||
return search_dynamic_file(fid);
|
||||
}
|
||||
|
||||
uint8_t make_path_buf(const file_t *pe, uint8_t *buf, uint8_t buflen, const file_t *top) {
|
||||
static uint8_t make_path_buf(const file_t *pe, uint8_t *buf, uint8_t buflen, const file_t *top) {
|
||||
if (!buflen) {
|
||||
return 0;
|
||||
}
|
||||
if (pe == top) { //MF or relative DF
|
||||
return 0;
|
||||
}
|
||||
put_uint16_t_be(pe->fid, buf);
|
||||
put_uint16_be(pe->fid, buf);
|
||||
return make_path_buf(&file_entries[pe->parent], buf + 2, buflen - 2, top) + 2;
|
||||
}
|
||||
|
||||
uint8_t make_path(const file_t *pe, const file_t *top, uint8_t *path) {
|
||||
static uint8_t make_path(const file_t *pe, const file_t *top, uint8_t *path) {
|
||||
uint8_t buf[MAX_DEPTH * 2], *p = path;
|
||||
put_uint16_t_be(pe->fid, buf);
|
||||
put_uint16_be(pe->fid, buf);
|
||||
uint8_t depth = make_path_buf(&file_entries[pe->parent], buf + 2, sizeof(buf) - 2, top) + 2;
|
||||
for (int d = depth - 2; d >= 0; d -= 2) {
|
||||
memcpy(p, buf + d, 2);
|
||||
@@ -188,7 +192,7 @@ uint8_t make_path(const file_t *pe, const file_t *top, uint8_t *path) {
|
||||
return depth;
|
||||
}
|
||||
|
||||
file_t *search_by_path(const uint8_t *pe_path, uint8_t pathlen, const file_t *parent) {
|
||||
file_t *file_search_by_path(const uint8_t *pe_path, uint8_t pathlen, const file_t *parent) {
|
||||
uint8_t path[MAX_DEPTH * 2];
|
||||
if (pathlen > sizeof(path)) {
|
||||
return NULL;
|
||||
@@ -207,7 +211,7 @@ file_t *currentDF = NULL;
|
||||
const file_t *selected_applet = NULL;
|
||||
bool isUserAuthenticated = false;
|
||||
|
||||
bool authenticate_action(const file_t *ef, uint8_t op) {
|
||||
bool file_authenticate_action(const file_t *ef, uint8_t op) {
|
||||
uint8_t acl = ef->acl[op];
|
||||
if (acl == 0x0) {
|
||||
return true;
|
||||
@@ -227,11 +231,11 @@ bool authenticate_action(const file_t *ef, uint8_t op) {
|
||||
return false;
|
||||
}
|
||||
|
||||
void initialize_flash(bool hard) {
|
||||
void file_initialize_flash(bool hard) {
|
||||
if (hard) {
|
||||
const uint8_t empty[8] = { 0 };
|
||||
flash_program_block(end_data_pool, empty, sizeof(empty));
|
||||
low_flash_available();
|
||||
flash_commit();
|
||||
}
|
||||
for (file_t *f = file_entries; f != file_last; f++) {
|
||||
if ((f->type & FILE_DATA_FLASH) == FILE_DATA_FLASH) {
|
||||
@@ -243,8 +247,7 @@ void initialize_flash(bool hard) {
|
||||
|
||||
extern uintptr_t last_base;
|
||||
extern uint32_t num_files;
|
||||
void scan_region(bool persistent)
|
||||
{
|
||||
static void scan_region(bool persistent) {
|
||||
uintptr_t endp = end_data_pool, startp = start_data_pool;
|
||||
if (persistent) {
|
||||
endp = end_rom_pool;
|
||||
@@ -261,7 +264,7 @@ void scan_region(bool persistent)
|
||||
|
||||
uint16_t fid = flash_read_uint16(base + sizeof(uintptr_t) + sizeof(uintptr_t));
|
||||
printf("[%x] scan fid %x, len %d\n", (unsigned int) base, fid, flash_read_uint16(base + sizeof(uintptr_t) + sizeof(uintptr_t) + sizeof(uint16_t)));
|
||||
file_t *file = (file_t *) search_by_fid(fid, NULL, SPECIFY_EF);
|
||||
file_t *file = (file_t *) file_search_by_fid(fid, NULL, SPECIFY_EF);
|
||||
if (!file) {
|
||||
file = file_new(fid);
|
||||
}
|
||||
@@ -279,18 +282,17 @@ void scan_region(bool persistent)
|
||||
}
|
||||
}
|
||||
}
|
||||
void wait_flash_finish();
|
||||
void scan_flash() {
|
||||
initialize_flash(false); //soft initialization
|
||||
uint32_t r1 = *(uintptr_t *) flash_read(end_rom_pool), r2 = *(uintptr_t *) flash_read(end_rom_pool + sizeof(uintptr_t));
|
||||
void file_scan_flash(void) {
|
||||
file_initialize_flash(false); //soft initialization
|
||||
uint32_t r1 = (uint32_t)flash_read_uintptr(end_rom_pool);
|
||||
uint32_t r2 = (uint32_t)flash_read_uintptr(end_rom_pool + sizeof(uintptr_t));
|
||||
if ((r1 == 0xffffffff || r1 == 0xefefefef) && (r2 == 0xffffffff || r2 == 0xefefefef)) {
|
||||
printf("First initialization (or corrupted!)\n");
|
||||
uint8_t empty[sizeof(uintptr_t) * 2 + sizeof(uint32_t)];
|
||||
memset(empty, 0, sizeof(empty));
|
||||
flash_program_block(end_data_pool, empty, sizeof(empty));
|
||||
flash_program_block(end_rom_pool, empty, sizeof(empty));
|
||||
//low_flash_available();
|
||||
//wait_flash_finish();
|
||||
//flash_commit();
|
||||
}
|
||||
printf("SCAN\n");
|
||||
scan_region(true);
|
||||
@@ -328,18 +330,9 @@ int file_put_data(file_t *file, const uint8_t *data, uint16_t len) {
|
||||
return flash_write_data_to_file(file, data, len);
|
||||
}
|
||||
|
||||
file_t *search_dynamic_file(uint16_t fid) {
|
||||
for (int i = 0; i < dynamic_files; i++) {
|
||||
if (dynamic_file[i].fid == fid) {
|
||||
return &dynamic_file[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int delete_dynamic_file(file_t *f) {
|
||||
static int delete_dynamic_file(file_t *f) {
|
||||
if (f == NULL) {
|
||||
return PICOKEY_ERR_FILE_NOT_FOUND;
|
||||
return PICOKEYS_ERR_FILE_NOT_FOUND;
|
||||
}
|
||||
for (int i = 0; i < dynamic_files; i++) {
|
||||
if (dynamic_file[i].fid == f->fid) {
|
||||
@@ -347,15 +340,15 @@ int delete_dynamic_file(file_t *f) {
|
||||
memcpy(&dynamic_file[j - 1], &dynamic_file[j], sizeof(file_t));
|
||||
}
|
||||
dynamic_files--;
|
||||
return PICOKEY_OK;
|
||||
return PICOKEYS_OK;
|
||||
}
|
||||
}
|
||||
return PICOKEY_ERR_FILE_NOT_FOUND;
|
||||
return PICOKEYS_ERR_FILE_NOT_FOUND;
|
||||
}
|
||||
|
||||
file_t *file_new(uint16_t fid) {
|
||||
file_t *f;
|
||||
if ((f = search_file(fid))) {
|
||||
if ((f = file_search(fid))) {
|
||||
return f;
|
||||
}
|
||||
if (dynamic_files == MAX_DYNAMIC_FILES) {
|
||||
@@ -377,20 +370,20 @@ file_t *file_new(uint16_t fid) {
|
||||
return f;
|
||||
}
|
||||
uint16_t meta_find(uint16_t fid, uint8_t **out) {
|
||||
file_t *ef = search_file(EF_META);
|
||||
file_t *ef = file_search(EF_META);
|
||||
if (!ef) {
|
||||
return 0;
|
||||
}
|
||||
uint16_t tag = 0x0;
|
||||
uint8_t *tag_data = NULL, *p = NULL;
|
||||
uint16_t tag_len = 0;
|
||||
asn1_ctx_t ctxi;
|
||||
asn1_ctx_init(file_get_data(ef), file_get_size(ef), &ctxi);
|
||||
while (walk_tlv(&ctxi, &p, &tag, &tag_len, &tag_data)) {
|
||||
tlv_ctx_t ctxi;
|
||||
tlv_ctx_init(file_get_data(ef), file_get_size(ef), &ctxi);
|
||||
while (tlv_walk(&ctxi, &p, &tag, &tag_len, &tag_data)) {
|
||||
if (tag_len < 2) {
|
||||
continue;
|
||||
}
|
||||
uint16_t cfid = get_uint16_t_be(tag_data);
|
||||
uint16_t cfid = get_uint16_be(tag_data);
|
||||
if (cfid == fid) {
|
||||
if (out) {
|
||||
*out = tag_data + 2;
|
||||
@@ -401,24 +394,24 @@ uint16_t meta_find(uint16_t fid, uint8_t **out) {
|
||||
return 0;
|
||||
}
|
||||
int meta_delete(uint16_t fid) {
|
||||
file_t *ef = search_file(EF_META);
|
||||
file_t *ef = file_search(EF_META);
|
||||
if (!ef) {
|
||||
return PICOKEY_ERR_FILE_NOT_FOUND;
|
||||
return PICOKEYS_ERR_FILE_NOT_FOUND;
|
||||
}
|
||||
uint16_t tag = 0x0;
|
||||
uint8_t *tag_data = NULL, *p = NULL;
|
||||
uint16_t tag_len = 0;
|
||||
uint8_t *fdata = NULL;
|
||||
asn1_ctx_t ctxi;
|
||||
asn1_ctx_init(file_get_data(ef), file_get_size(ef), &ctxi);
|
||||
while (walk_tlv(&ctxi, &p, &tag, &tag_len, &tag_data)) {
|
||||
uint8_t *tpos = p - tag_len - format_tlv_len(tag_len, NULL) - 1;
|
||||
tlv_ctx_t ctxi;
|
||||
tlv_ctx_init(file_get_data(ef), file_get_size(ef), &ctxi);
|
||||
while (tlv_walk(&ctxi, &p, &tag, &tag_len, &tag_data)) {
|
||||
uint8_t *tpos = p - tag_len - tlv_format_len(tag_len, NULL) - 1;
|
||||
if (tag_len < 2) {
|
||||
continue;
|
||||
}
|
||||
uint16_t cfid = get_uint16_t_be(tag_data);
|
||||
uint16_t cfid = get_uint16_be(tag_data);
|
||||
if (cfid == fid) {
|
||||
uint16_t new_len = ctxi.len - 1 - tag_len - format_tlv_len(tag_len, NULL);
|
||||
uint16_t new_len = ctxi.len - 1 - tag_len - tlv_format_len(tag_len, NULL);
|
||||
if (new_len == 0) {
|
||||
flash_clear_file(ef);
|
||||
}
|
||||
@@ -432,21 +425,21 @@ int meta_delete(uint16_t fid) {
|
||||
}
|
||||
int r = file_put_data(ef, fdata, new_len);
|
||||
free(fdata);
|
||||
if (r != PICOKEY_OK) {
|
||||
return PICOKEY_EXEC_ERROR;
|
||||
if (r != PICOKEYS_OK) {
|
||||
return PICOKEYS_EXEC_ERROR;
|
||||
}
|
||||
}
|
||||
low_flash_available();
|
||||
flash_commit();
|
||||
break;
|
||||
}
|
||||
}
|
||||
return PICOKEY_OK;
|
||||
return PICOKEYS_OK;
|
||||
}
|
||||
int meta_add(uint16_t fid, const uint8_t *data, uint16_t len) {
|
||||
int r;
|
||||
file_t *ef = search_file(EF_META);
|
||||
file_t *ef = file_search(EF_META);
|
||||
if (!ef) {
|
||||
return PICOKEY_ERR_FILE_NOT_FOUND;
|
||||
return PICOKEYS_ERR_FILE_NOT_FOUND;
|
||||
}
|
||||
uint16_t ef_size = file_get_size(ef);
|
||||
uint8_t *fdata = (uint8_t *) calloc(1, ef_size);
|
||||
@@ -454,25 +447,25 @@ int meta_add(uint16_t fid, const uint8_t *data, uint16_t len) {
|
||||
uint16_t tag = 0x0;
|
||||
uint8_t *tag_data = NULL, *p = NULL;
|
||||
uint16_t tag_len = 0;
|
||||
asn1_ctx_t ctxi;
|
||||
asn1_ctx_init(fdata, ef_size, &ctxi);
|
||||
while (walk_tlv(&ctxi, &p, &tag, &tag_len, &tag_data)) {
|
||||
tlv_ctx_t ctxi;
|
||||
tlv_ctx_init(fdata, ef_size, &ctxi);
|
||||
while (tlv_walk(&ctxi, &p, &tag, &tag_len, &tag_data)) {
|
||||
if (tag_len < 2) {
|
||||
continue;
|
||||
}
|
||||
uint16_t cfid = get_uint16_t_be(tag_data);
|
||||
uint16_t cfid = get_uint16_be(tag_data);
|
||||
if (cfid == fid) {
|
||||
if (tag_len - 2 == len) { //an update
|
||||
memcpy(p - tag_len + 2, data, len);
|
||||
r = file_put_data(ef, fdata, ef_size);
|
||||
free(fdata);
|
||||
if (r != PICOKEY_OK) {
|
||||
return PICOKEY_EXEC_ERROR;
|
||||
if (r != PICOKEYS_OK) {
|
||||
return PICOKEYS_EXEC_ERROR;
|
||||
}
|
||||
return PICOKEY_OK;
|
||||
return PICOKEYS_OK;
|
||||
}
|
||||
else { //needs reallocation
|
||||
uint8_t *tpos = p - asn1_len_tag(tag, tag_len);
|
||||
uint8_t *tpos = p - tlv_len_tag(tag, tag_len);
|
||||
memmove(tpos, p, fdata + ef_size - p);
|
||||
tpos += fdata + ef_size - p;
|
||||
volatile uintptr_t meta_offset = tpos - fdata;
|
||||
@@ -484,52 +477,73 @@ int meta_add(uint16_t fid, const uint8_t *data, uint16_t len) {
|
||||
}
|
||||
else {
|
||||
free(fdata);
|
||||
return PICOKEY_ERR_MEMORY_FATAL;
|
||||
return PICOKEYS_ERR_MEMORY_FATAL;
|
||||
}
|
||||
}
|
||||
uint8_t *f = fdata + meta_offset;
|
||||
*f++ = fid & 0xff;
|
||||
f += format_tlv_len(len + 2, f);
|
||||
f += put_uint16_t_be(fid, f);
|
||||
f += tlv_format_len(len + 2, f);
|
||||
f += put_uint16_be(fid, f);
|
||||
memcpy(f, data, len);
|
||||
r = file_put_data(ef, fdata, ef_size);
|
||||
free(fdata);
|
||||
if (r != PICOKEY_OK) {
|
||||
return PICOKEY_EXEC_ERROR;
|
||||
if (r != PICOKEYS_OK) {
|
||||
return PICOKEYS_EXEC_ERROR;
|
||||
}
|
||||
return PICOKEY_OK;
|
||||
return PICOKEYS_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
fdata = (uint8_t *) realloc(fdata, ef_size + asn1_len_tag(fid & 0x1f, len + 2));
|
||||
fdata = (uint8_t *) realloc(fdata, ef_size + tlv_len_tag(fid & 0x1f, len + 2));
|
||||
uint8_t *f = fdata + ef_size;
|
||||
*f++ = fid & 0x1f;
|
||||
f += format_tlv_len(len + 2, f);
|
||||
f += put_uint16_t_be(fid, f);
|
||||
f += tlv_format_len(len + 2, f);
|
||||
f += put_uint16_be(fid, f);
|
||||
memcpy(f, data, len);
|
||||
r = file_put_data(ef, fdata, ef_size + (uint16_t)asn1_len_tag(fid & 0x1f, len + 2));
|
||||
r = file_put_data(ef, fdata, ef_size + (uint16_t)tlv_len_tag(fid & 0x1f, len + 2));
|
||||
free(fdata);
|
||||
if (r != PICOKEY_OK) {
|
||||
return PICOKEY_EXEC_ERROR;
|
||||
if (r != PICOKEYS_OK) {
|
||||
return PICOKEYS_EXEC_ERROR;
|
||||
}
|
||||
return PICOKEY_OK;
|
||||
return PICOKEYS_OK;
|
||||
}
|
||||
|
||||
bool file_has_data(file_t *f) {
|
||||
bool file_has_data(const file_t *f) {
|
||||
return f != NULL && f->data != NULL && file_get_size(f) > 0;
|
||||
}
|
||||
|
||||
int delete_file(file_t *ef) {
|
||||
int file_delete(file_t *ef) {
|
||||
if (ef == NULL) {
|
||||
return PICOKEY_OK;
|
||||
return PICOKEYS_OK;
|
||||
}
|
||||
meta_delete(ef->fid);
|
||||
if (flash_clear_file(ef) != PICOKEY_OK) {
|
||||
return PICOKEY_EXEC_ERROR;
|
||||
if (flash_clear_file(ef) != PICOKEYS_OK) {
|
||||
return PICOKEYS_EXEC_ERROR;
|
||||
}
|
||||
if (delete_dynamic_file(ef) != PICOKEY_OK) {
|
||||
return PICOKEY_EXEC_ERROR;
|
||||
if (delete_dynamic_file(ef) != PICOKEYS_OK) {
|
||||
return PICOKEYS_EXEC_ERROR;
|
||||
}
|
||||
low_flash_available();
|
||||
return PICOKEY_OK;
|
||||
flash_commit();
|
||||
return PICOKEYS_OK;
|
||||
}
|
||||
|
||||
int flash_clear_file(file_t *file) {
|
||||
if (file == NULL || file->data == NULL) {
|
||||
return PICOKEYS_OK;
|
||||
}
|
||||
uintptr_t base_addr = (uintptr_t)(file->data - sizeof(uintptr_t) - sizeof(uint16_t) - sizeof(uintptr_t));
|
||||
uintptr_t prev_addr = flash_read_uintptr(base_addr + sizeof(uintptr_t));
|
||||
uintptr_t next_addr = flash_read_uintptr(base_addr);
|
||||
//printf("nc %lx->%lx %lx->%lx\n",prev_addr,flash_read_uintptr(prev_addr),base_addr,next_addr);
|
||||
flash_program_uintptr(prev_addr, next_addr);
|
||||
flash_program_halfword((uintptr_t) file->data, 0);
|
||||
if (next_addr > 0) {
|
||||
flash_program_uintptr(next_addr + sizeof(uintptr_t), prev_addr);
|
||||
}
|
||||
flash_program_uintptr(base_addr, 0);
|
||||
flash_program_uintptr(base_addr + sizeof(uintptr_t), 0);
|
||||
file->data = NULL;
|
||||
num_files--;
|
||||
//printf("na %lx->%lx\n",prev_addr,flash_read_uintptr(prev_addr));
|
||||
return PICOKEYS_OK;
|
||||
}
|
||||
|
||||
@@ -3,29 +3,25 @@
|
||||
* 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
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
* Affero 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/>.
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _FILE_H_
|
||||
#define _FILE_H_
|
||||
|
||||
#include <stdlib.h>
|
||||
#if !defined(ENABLE_EMULATION) && !defined(ESP_PLATFORM)
|
||||
#include "pico/stdlib.h"
|
||||
#else
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
#include "compat.h"
|
||||
#include <stdbool.h>
|
||||
#include "compat/compat.h"
|
||||
#include "phy.h"
|
||||
|
||||
#define FILE_TYPE_NOT_KNOWN 0x00
|
||||
@@ -55,36 +51,40 @@
|
||||
#define ACL_OP_UPDATE_ERASE 0x05
|
||||
#define ACL_OP_READ_SEARCH 0x06
|
||||
|
||||
#define ACL_NONE { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }
|
||||
#define ACL_ALL { 0 }
|
||||
#define ACL_RO { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00 }
|
||||
#define ACL_RW { 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00 }
|
||||
#define ACL_R_WP { 0xff, 0xff, 0xff, 0xff, 0x90, 0x90, 0x00 }
|
||||
#define ACL_WP { 0xff, 0xff, 0xff, 0xff, 0x90, 0x90, 0xff }
|
||||
|
||||
#define SPECIFY_EF 0x1
|
||||
#define SPECIFY_DF 0x2
|
||||
#define SPECIFY_ANY 0x3
|
||||
|
||||
#define EF_PRKDFS 0x6040
|
||||
#define EF_PUKDFS 0x6041
|
||||
#define EF_CDFS 0x6042
|
||||
#define EF_AODFS 0x6043
|
||||
#define EF_DODFS 0x6044
|
||||
#define EF_SKDFS 0x6045
|
||||
#define EF_META 0xE010
|
||||
|
||||
#define MAX_DEPTH 4
|
||||
|
||||
#define MAX_DYNAMIC_FILES 256
|
||||
|
||||
#ifdef _MSC_VER
|
||||
__pragma( pack(push, 1) )
|
||||
#endif
|
||||
typedef struct file {
|
||||
const uint8_t *name;
|
||||
uint8_t *data; //should include 2 bytes len at begining
|
||||
const uint16_t fid;
|
||||
const uint8_t acl[7];
|
||||
uint8_t acl[7];
|
||||
const uint8_t parent; //entry number in the whole table!!
|
||||
const uint8_t type;
|
||||
const uint8_t ef_structure;
|
||||
#ifdef ENABLE_EMULATION
|
||||
uint32_t _padding;
|
||||
#endif
|
||||
} __attribute__ ((packed)) file_t;
|
||||
|
||||
extern bool file_has_data(file_t *);
|
||||
}
|
||||
#ifdef _MSC_VER
|
||||
__pragma( pack(pop) )
|
||||
#else
|
||||
__attribute__ ((packed))
|
||||
#endif
|
||||
file_t;
|
||||
|
||||
extern file_t *currentEF;
|
||||
extern file_t *currentDF;
|
||||
@@ -92,22 +92,16 @@ extern const file_t *selected_applet;
|
||||
|
||||
extern const file_t *MF;
|
||||
extern const file_t *file_last;
|
||||
extern const file_t *file_openpgp;
|
||||
extern const file_t *file_sc_hsm;
|
||||
extern bool card_terminated;
|
||||
extern file_t *file_pin1;
|
||||
extern file_t *file_retries_pin1;
|
||||
extern file_t *file_sopin;
|
||||
extern file_t *file_retries_sopin;
|
||||
|
||||
extern file_t *search_by_fid(const uint16_t fid, const file_t *parent, const uint8_t sp);
|
||||
extern file_t *search_file(const uint16_t fid);
|
||||
extern file_t *search_by_name(uint8_t *name, uint16_t namelen);
|
||||
extern file_t *search_by_path(const uint8_t *pe_path, uint8_t pathlen, const file_t *parent);
|
||||
extern bool authenticate_action(const file_t *ef, uint8_t op);
|
||||
extern void process_fci(const file_t *pe, int fmd);
|
||||
extern void scan_flash();
|
||||
extern void initialize_flash(bool);
|
||||
extern file_t *file_search_by_fid(const uint16_t fid, const file_t *parent, const uint8_t sp);
|
||||
extern file_t *file_search(const uint16_t fid);
|
||||
extern file_t *file_search_by_name(uint8_t *name, uint16_t namelen);
|
||||
extern file_t *file_search_by_path(const uint8_t *pe_path, uint8_t pathlen, const file_t *parent);
|
||||
extern bool file_authenticate_action(const file_t *ef, uint8_t op);
|
||||
extern void file_process_fci(const file_t *pe, int fmd);
|
||||
extern void file_scan_flash(void);
|
||||
extern void file_initialize_flash(bool);
|
||||
|
||||
extern file_t file_entries[];
|
||||
|
||||
@@ -115,29 +109,20 @@ extern uint8_t *file_read(const uint8_t *addr);
|
||||
extern uint16_t file_read_uint16(const uint8_t *addr);
|
||||
extern uint8_t file_read_uint8(const file_t *ef);
|
||||
extern uint8_t file_read_uint8_offset(const file_t *ef, const uint16_t offset);
|
||||
extern bool file_has_data(const file_t *);
|
||||
extern uint8_t *file_get_data(const file_t *tf);
|
||||
extern uint16_t file_get_size(const file_t *tf);
|
||||
extern int file_put_data(file_t *file, const uint8_t *data, uint16_t len);
|
||||
extern file_t *file_new(uint16_t);
|
||||
extern int flash_clear_file(file_t *file);
|
||||
extern int file_delete(file_t *ef);
|
||||
file_t *get_parent(file_t *f);
|
||||
|
||||
extern uint16_t dynamic_files;
|
||||
extern file_t dynamic_file[];
|
||||
extern file_t *search_dynamic_file(uint16_t);
|
||||
extern int delete_dynamic_file(file_t *f);
|
||||
|
||||
extern bool isUserAuthenticated;
|
||||
|
||||
extern uint16_t meta_find(uint16_t, uint8_t **out);
|
||||
extern int meta_delete(uint16_t fid);
|
||||
extern int meta_add(uint16_t fid, const uint8_t *data, uint16_t len);
|
||||
extern int delete_file(file_t *ef);
|
||||
|
||||
extern uint32_t flash_free_space();
|
||||
extern uint32_t flash_used_space();
|
||||
extern uint32_t flash_total_space();
|
||||
extern uint32_t flash_num_files();
|
||||
extern uint32_t flash_size();
|
||||
|
||||
#ifndef ENABLE_EMULATION
|
||||
extern file_t *ef_phy;
|
||||
|
||||
28
src/fs/files.c
Normal file
28
src/fs/files.c
Normal file
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
|
||||
* Copyright (c) 2022 Pol Henarejos.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "file.h"
|
||||
|
||||
file_t file_entries[] = {
|
||||
/* 0 */ { .fid = 0x3f00, .parent = 0xff, .name = NULL, .type = FILE_TYPE_DF, .data = NULL,
|
||||
.ef_structure = 0, .acl = { 0 } }, // MF
|
||||
/* 1 */ { .fid = 0x0000, .parent = 0xff, .name = NULL, .type = FILE_TYPE_NOT_KNOWN, .data = NULL,
|
||||
.ef_structure = 0, .acl = { 0 } } //end
|
||||
};
|
||||
|
||||
const file_t *MF = &file_entries[0];
|
||||
const file_t *file_last = &file_entries[sizeof(file_entries) / sizeof(file_t) - 1];
|
||||
103
src/fs/flash.c
103
src/fs/flash.c
@@ -3,37 +3,40 @@
|
||||
* 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
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
* Affero 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/>.
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "picokeys.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#if defined(ENABLE_EMULATION) || defined(ESP_PLATFORM)
|
||||
#if !defined(PICO_PLATFORM)
|
||||
#define XIP_BASE 0
|
||||
#define FLASH_SECTOR_SIZE 4096
|
||||
#ifdef ESP_PLATFORM
|
||||
uint32_t PICO_FLASH_SIZE_BYTES = (1 * 1024 * 1024);
|
||||
#ifdef ENABLE_EMULATION
|
||||
#define FLASH_SECTOR_SIZE 0x4000
|
||||
#else
|
||||
#define PICO_FLASH_SIZE_BYTES (8 * 1024 * 1024)
|
||||
#define FLASH_SECTOR_SIZE 0x1000
|
||||
#endif
|
||||
#ifdef ESP_PLATFORM
|
||||
uint32_t FLASH_SIZE_BYTES = (1 * 1024 * 1024);
|
||||
#else
|
||||
#define FLASH_SIZE_BYTES (8 * 1024 * 1024)
|
||||
#endif
|
||||
#else
|
||||
#include "pico/stdlib.h"
|
||||
uint32_t FLASH_SIZE_BYTES = (2 * 1024 * 1024);
|
||||
#include "hardware/flash.h"
|
||||
#endif
|
||||
#include "pico_keys.h"
|
||||
#include "file.h"
|
||||
#include <stdio.h>
|
||||
|
||||
extern void low_flash_task(void);
|
||||
extern void low_flash_commit(void);
|
||||
|
||||
/*
|
||||
* ------------------------------------------------------
|
||||
@@ -49,15 +52,6 @@ uint32_t PICO_FLASH_SIZE_BYTES = (1 * 1024 * 1024);
|
||||
//To avoid possible future allocations, data region starts at the end of flash and goes upwards to the center region
|
||||
uintptr_t end_flash, end_rom_pool, start_rom_pool, end_data_pool, start_data_pool;
|
||||
|
||||
extern int flash_program_block(uintptr_t addr, const uint8_t *data, size_t len);
|
||||
extern int flash_program_halfword(uintptr_t addr, uint16_t data);
|
||||
extern int flash_program_uintptr(uintptr_t, uintptr_t);
|
||||
extern uintptr_t flash_read_uintptr(uintptr_t addr);
|
||||
extern uint16_t flash_read_uint16(uintptr_t addr);
|
||||
extern uint8_t *flash_read(uintptr_t addr);
|
||||
|
||||
extern void low_flash_available();
|
||||
|
||||
uintptr_t last_base;
|
||||
uint32_t num_files = 0;
|
||||
|
||||
@@ -71,7 +65,7 @@ void flash_set_bounds(uintptr_t start, uintptr_t end) {
|
||||
last_base = end_data_pool;
|
||||
}
|
||||
|
||||
uintptr_t allocate_free_addr(uint16_t size, bool persistent) {
|
||||
static uintptr_t allocate_free_addr(uint16_t size, bool persistent) {
|
||||
if (size > FLASH_SECTOR_SIZE) {
|
||||
return 0x0; //ERROR
|
||||
}
|
||||
@@ -118,35 +112,14 @@ uintptr_t allocate_free_addr(uint16_t size, bool persistent) {
|
||||
return 0x0; //probably never reached
|
||||
}
|
||||
|
||||
int flash_clear_file(file_t *file) {
|
||||
if (file == NULL || file->data == NULL) {
|
||||
return PICOKEY_OK;
|
||||
}
|
||||
uintptr_t base_addr = (uintptr_t)(file->data - sizeof(uintptr_t) - sizeof(uint16_t) - sizeof(uintptr_t));
|
||||
uintptr_t prev_addr = flash_read_uintptr(base_addr + sizeof(uintptr_t));
|
||||
uintptr_t next_addr = flash_read_uintptr(base_addr);
|
||||
//printf("nc %lx->%lx %lx->%lx\n",prev_addr,flash_read_uintptr(prev_addr),base_addr,next_addr);
|
||||
flash_program_uintptr(prev_addr, next_addr);
|
||||
flash_program_halfword((uintptr_t) file->data, 0);
|
||||
if (next_addr > 0) {
|
||||
flash_program_uintptr(next_addr + sizeof(uintptr_t), prev_addr);
|
||||
}
|
||||
flash_program_uintptr(base_addr, 0);
|
||||
flash_program_uintptr(base_addr + sizeof(uintptr_t), 0);
|
||||
file->data = NULL;
|
||||
num_files--;
|
||||
//printf("na %lx->%lx\n",prev_addr,flash_read_uintptr(prev_addr));
|
||||
return PICOKEY_OK;
|
||||
}
|
||||
|
||||
int flash_write_data_to_file_offset(file_t *file, const uint8_t *data, uint16_t len, uint16_t offset) {
|
||||
static int flash_write_data_to_file_offset(file_t *file, const uint8_t *data, uint16_t len, uint16_t offset) {
|
||||
if (!file) {
|
||||
return PICOKEY_ERR_NULL_PARAM;
|
||||
return PICOKEYS_ERR_NULL_PARAM;
|
||||
}
|
||||
uint16_t size_file_flash = file->data ? flash_read_uint16((uintptr_t) file->data) : 0;
|
||||
uint8_t *old_data = NULL;
|
||||
if (offset + len > FLASH_SECTOR_SIZE || offset > size_file_flash) {
|
||||
return PICOKEY_ERR_NO_MEMORY;
|
||||
return PICOKEYS_ERR_NO_MEMORY;
|
||||
}
|
||||
if (file->data) { //already in flash
|
||||
if (offset + len <= size_file_flash) { //it fits, no need to move it
|
||||
@@ -154,7 +127,7 @@ int flash_write_data_to_file_offset(file_t *file, const uint8_t *data, uint16_t
|
||||
if (data) {
|
||||
flash_program_block((uintptr_t) file->data + sizeof(uint16_t) + offset, data, len);
|
||||
}
|
||||
return PICOKEY_OK;
|
||||
return PICOKEYS_OK;
|
||||
}
|
||||
else { //we clear the old file
|
||||
flash_clear_file(file);
|
||||
@@ -171,7 +144,7 @@ int flash_write_data_to_file_offset(file_t *file, const uint8_t *data, uint16_t
|
||||
uintptr_t new_addr = allocate_free_addr(len, (file->type & FILE_PERSISTENT) == FILE_PERSISTENT);
|
||||
//printf("na %x\n",new_addr);
|
||||
if (new_addr == 0x0) {
|
||||
return PICOKEY_ERR_NO_MEMORY;
|
||||
return PICOKEYS_ERR_NO_MEMORY;
|
||||
}
|
||||
if (new_addr < last_base) {
|
||||
last_base = new_addr;
|
||||
@@ -186,29 +159,37 @@ int flash_write_data_to_file_offset(file_t *file, const uint8_t *data, uint16_t
|
||||
free(old_data);
|
||||
}
|
||||
num_files++;
|
||||
return PICOKEY_OK;
|
||||
return PICOKEYS_OK;
|
||||
}
|
||||
|
||||
int flash_write_data_to_file(file_t *file, const uint8_t *data, uint16_t len) {
|
||||
return flash_write_data_to_file_offset(file, data, len, 0);
|
||||
}
|
||||
|
||||
uint32_t flash_free_space() {
|
||||
return last_base - start_data_pool;
|
||||
uint32_t flash_free_space(void) {
|
||||
return (uint32_t)(last_base - start_data_pool);
|
||||
}
|
||||
|
||||
uint32_t flash_used_space() {
|
||||
return end_data_pool - last_base;
|
||||
uint32_t flash_used_space(void) {
|
||||
return (uint32_t)(end_data_pool - last_base);
|
||||
}
|
||||
|
||||
uint32_t flash_total_space() {
|
||||
return end_data_pool - start_data_pool;
|
||||
uint32_t flash_total_space(void) {
|
||||
return (uint32_t)(end_data_pool - start_data_pool);
|
||||
}
|
||||
|
||||
uint32_t flash_num_files() {
|
||||
uint32_t flash_num_files(void) {
|
||||
return num_files;
|
||||
}
|
||||
|
||||
uint32_t flash_size() {
|
||||
return PICO_FLASH_SIZE_BYTES;
|
||||
uint32_t flash_size(void) {
|
||||
return FLASH_SIZE_BYTES;
|
||||
}
|
||||
|
||||
void flash_task(void) {
|
||||
low_flash_task();
|
||||
}
|
||||
|
||||
void flash_commit(void) {
|
||||
low_flash_commit();
|
||||
}
|
||||
|
||||
46
src/fs/flash.h
Normal file
46
src/fs/flash.h
Normal file
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
|
||||
* Copyright (c) 2022 Pol Henarejos.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _FLASH_H
|
||||
#define _FLASH_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
extern uint32_t flash_free_space(void);
|
||||
extern uint32_t flash_used_space(void);
|
||||
extern uint32_t flash_total_space(void);
|
||||
extern uint32_t flash_num_files(void);
|
||||
extern uint32_t flash_size(void);
|
||||
|
||||
extern void flash_set_bounds(uintptr_t start, uintptr_t end);
|
||||
extern int flash_write_data_to_file(file_t *file, const uint8_t *data, uint16_t len);
|
||||
extern int flash_program_block(uintptr_t addr, const uint8_t *data, size_t len);
|
||||
extern int flash_program_halfword(uintptr_t addr, uint16_t data);
|
||||
extern int flash_program_word(uintptr_t addr, uint32_t data);
|
||||
extern int flash_program_uintptr(uintptr_t addr, uintptr_t data);
|
||||
extern uintptr_t flash_read_uintptr(uintptr_t addr);
|
||||
extern uint16_t flash_read_uint16(uintptr_t addr);
|
||||
extern uint8_t flash_read_uint8(uintptr_t addr);
|
||||
extern uint8_t *flash_read(uintptr_t addr);
|
||||
extern int flash_erase_page(uintptr_t addr, size_t page_size);
|
||||
extern bool flash_check_blank(const uint8_t *p_start, size_t size);
|
||||
extern void flash_task(void);
|
||||
extern void low_flash_init(void);
|
||||
extern void flash_commit(void);
|
||||
|
||||
#endif // _FLASH_H
|
||||
@@ -3,27 +3,23 @@
|
||||
* 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
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
* Affero 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/>.
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include "picokeys.h"
|
||||
#include "serial.h"
|
||||
#include "crypto_utils.h"
|
||||
#include <stdio.h>
|
||||
|
||||
#include "pico_keys.h"
|
||||
#include <string.h>
|
||||
#ifdef PICO_PLATFORM
|
||||
#include "pico/stdlib.h"
|
||||
#include "hardware/flash.h"
|
||||
#include "hardware/sync.h"
|
||||
#include "pico/mutex.h"
|
||||
@@ -32,62 +28,64 @@
|
||||
#include "pico/bootrom.h"
|
||||
#include "boot/picobin.h"
|
||||
#else
|
||||
#ifdef _MSC_VER
|
||||
#include <windows.h>
|
||||
#include <io.h>
|
||||
#define O_RDWR _O_RDWR
|
||||
#define O_CREAT _O_CREAT
|
||||
#define open _open
|
||||
#define write _write
|
||||
#define mode_t unsigned short
|
||||
#define lseek _lseek
|
||||
#include "mman.h"
|
||||
#ifdef ESP_PLATFORM
|
||||
#include "compat/esp_compat.h"
|
||||
#include "esp_partition.h"
|
||||
const esp_partition_t *part0;
|
||||
#define save_and_disable_interrupts() 1
|
||||
#define flash_range_erase(a,b) esp_partition_erase_range(part0, a, b)
|
||||
#define flash_range_program(a,b,c) esp_partition_write(part0, a, b, c);
|
||||
#define restore_interrupts(a) (void)a
|
||||
#else
|
||||
#ifdef ESP_PLATFORM
|
||||
#include "esp_compat.h"
|
||||
#include "esp_partition.h"
|
||||
const esp_partition_t *part0;
|
||||
#define save_and_disable_interrupts() 1
|
||||
#define flash_range_erase(a,b) esp_partition_erase_range(part0, a, b)
|
||||
#define flash_range_program(a,b,c) esp_partition_write(part0, a, b, c);
|
||||
#define restore_interrupts(a) (void)a
|
||||
#ifdef _MSC_VER
|
||||
#include <windows.h>
|
||||
#include <io.h>
|
||||
#define O_RDWR _O_RDWR
|
||||
#define O_CREAT _O_CREAT
|
||||
#define open _open
|
||||
#define write _write
|
||||
#define mode_t unsigned short
|
||||
#define lseek _lseek
|
||||
#include "mman.h"
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#include <sys/mman.h>
|
||||
#include "emulation.h"
|
||||
#endif
|
||||
#include "compat/queue.h"
|
||||
#endif
|
||||
#define FLASH_SECTOR_SIZE 4096
|
||||
#ifdef ESP_PLATFORM
|
||||
extern uint32_t PICO_FLASH_SIZE_BYTES;
|
||||
#ifdef ENABLE_EMULATION
|
||||
#define FLASH_SECTOR_SIZE 0x4000
|
||||
#else
|
||||
#define PICO_FLASH_SIZE_BYTES (8 * 1024 * 1024)
|
||||
#define FLASH_SECTOR_SIZE 0x1000
|
||||
#endif
|
||||
#define XIP_BASE 0
|
||||
int fd_map = 0;
|
||||
uint8_t *map = NULL;
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
#if defined(PICO_PLATFORM) || defined(ESP_PLATFORM)
|
||||
extern uint32_t FLASH_SIZE_BYTES;
|
||||
#else
|
||||
#define FLASH_SIZE_BYTES (8 * 1024 * 1024)
|
||||
#endif
|
||||
|
||||
#define TOTAL_FLASH_PAGES 6
|
||||
|
||||
extern void flash_set_bounds(uintptr_t start, uintptr_t end);
|
||||
|
||||
extern const uintptr_t start_data_pool;
|
||||
extern const uintptr_t end_rom_pool;
|
||||
|
||||
PACK(
|
||||
typedef struct page_flash {
|
||||
uint8_t page[FLASH_SECTOR_SIZE];
|
||||
uintptr_t address;
|
||||
bool ready;
|
||||
bool erase;
|
||||
size_t page_size; //this param is for easy erase. It allows to erase with a single call. IT DOES NOT APPLY TO WRITE
|
||||
} page_flash_t;
|
||||
}) page_flash_t;
|
||||
|
||||
static page_flash_t flash_pages[TOTAL_FLASH_PAGES];
|
||||
|
||||
static mutex_t mtx_flash;
|
||||
static semaphore_t sem_flash;
|
||||
|
||||
#ifndef ENABLE_EMULATION
|
||||
static bool locked_out = false;
|
||||
@@ -101,25 +99,34 @@ bool flash_available = false;
|
||||
|
||||
|
||||
//this function has to be called from the core 0
|
||||
void do_flash() {
|
||||
void low_flash_task(void);
|
||||
void low_flash_commit(void);
|
||||
|
||||
void low_flash_task(void){
|
||||
if (mutex_try_enter(&mtx_flash, NULL) == true) {
|
||||
if (locked_out == true && flash_available == true && ready_pages > 0) {
|
||||
//printf(" DO_FLASH AVAILABLE\n");
|
||||
for (int r = 0; r < TOTAL_FLASH_PAGES; r++) {
|
||||
if (flash_pages[r].ready == true) {
|
||||
#ifndef ENABLE_EMULATION
|
||||
#if defined(PICO_PLATFORM) || defined(ESP_PLATFORM)
|
||||
mutex_exit(&mtx_flash);
|
||||
//printf("WRITTING %X\n",flash_pages[r].address-XIP_BASE);
|
||||
while (multicore_lockout_start_timeout_us(1000) == false) {
|
||||
;
|
||||
if (multicore_lockout_start_timeout_us(1000) == false) {
|
||||
printf("WARN: FLASH LOCKOUT START TIMEOUT\n");
|
||||
mutex_enter_blocking(&mtx_flash);
|
||||
continue;
|
||||
}
|
||||
//printf("WRITTING %X\n",flash_pages[r].address-XIP_BASE);
|
||||
uint32_t ints = save_and_disable_interrupts();
|
||||
flash_range_erase(flash_pages[r].address - XIP_BASE, FLASH_SECTOR_SIZE);
|
||||
flash_range_program(flash_pages[r].address - XIP_BASE, flash_pages[r].page, FLASH_SECTOR_SIZE);
|
||||
restore_interrupts(ints);
|
||||
while (multicore_lockout_end_timeout_us(1000) == false) {
|
||||
;
|
||||
if (multicore_lockout_end_timeout_us(1000) == false) {
|
||||
printf("WARN: FLASH LOCKOUT END TIMEOUT\n");
|
||||
mutex_enter_blocking(&mtx_flash);
|
||||
continue;
|
||||
}
|
||||
mutex_enter_blocking(&mtx_flash);
|
||||
//printf("WRITEN %X !\n",flash_pages[r].address);
|
||||
#else
|
||||
memcpy(map + flash_pages[r].address, flash_pages[r].page, FLASH_SECTOR_SIZE);
|
||||
@@ -128,15 +135,23 @@ void do_flash() {
|
||||
ready_pages--;
|
||||
}
|
||||
else if (flash_pages[r].erase == true) {
|
||||
#ifndef ENABLE_EMULATION
|
||||
while (multicore_lockout_start_timeout_us(1000) == false) {
|
||||
;
|
||||
#if defined(PICO_PLATFORM) || defined(ESP_PLATFORM)
|
||||
mutex_exit(&mtx_flash);
|
||||
if (multicore_lockout_start_timeout_us(1000) == false) {
|
||||
printf("WARN: FLASH LOCKOUT START TIMEOUT\n");
|
||||
mutex_enter_blocking(&mtx_flash);
|
||||
continue;
|
||||
}
|
||||
//printf("WRITTING\n");
|
||||
uint32_t ints = save_and_disable_interrupts();
|
||||
flash_range_erase(flash_pages[r].address - XIP_BASE, flash_pages[r].page_size ? ((int) (flash_pages[r].page_size / FLASH_SECTOR_SIZE)) * FLASH_SECTOR_SIZE : FLASH_SECTOR_SIZE);
|
||||
while (multicore_lockout_end_timeout_us(1000) == false) {
|
||||
;
|
||||
restore_interrupts(ints);
|
||||
if (multicore_lockout_end_timeout_us(1000) == false) {
|
||||
printf("WARN: FLASH LOCKOUT END TIMEOUT\n");
|
||||
mutex_enter_blocking(&mtx_flash);
|
||||
continue;
|
||||
}
|
||||
mutex_enter_blocking(&mtx_flash);
|
||||
#else
|
||||
memset(map + flash_pages[r].address, 0, FLASH_SECTOR_SIZE);
|
||||
#endif
|
||||
@@ -144,96 +159,104 @@ void do_flash() {
|
||||
ready_pages--;
|
||||
}
|
||||
}
|
||||
#ifdef ENABLE_EMULATION
|
||||
msync(map, PICO_FLASH_SIZE_BYTES, MS_SYNC);
|
||||
#if !defined(PICO_PLATFORM) && !defined(ESP_PLATFORM)
|
||||
msync(map, FLASH_SIZE_BYTES, MS_SYNC);
|
||||
#endif
|
||||
if (ready_pages != 0) {
|
||||
printf("ERROR: DO FLASH DOES NOT HAVE ZERO PAGES\n");
|
||||
}
|
||||
}
|
||||
flash_available = false;
|
||||
if (ready_pages == 0) {
|
||||
flash_available = false;
|
||||
}
|
||||
#ifdef ESP_PLATFORM
|
||||
esp_partition_munmap(fd_map);
|
||||
esp_partition_mmap(part0, 0, part0->size, ESP_PARTITION_MMAP_DATA, (const void **)&map, (esp_partition_mmap_handle_t *)&fd_map);
|
||||
#endif
|
||||
mutex_exit(&mtx_flash);
|
||||
}
|
||||
sem_release(&sem_flash);
|
||||
}
|
||||
|
||||
#ifdef PICO_RP2040
|
||||
void phymarker_write(void);
|
||||
#endif
|
||||
//this function has to be called from the core 0
|
||||
void low_flash_init() {
|
||||
void low_flash_init(void) {
|
||||
#ifdef PICO_RP2040
|
||||
phymarker_write();
|
||||
#endif
|
||||
memset(flash_pages, 0, sizeof(page_flash_t) * TOTAL_FLASH_PAGES);
|
||||
mutex_init(&mtx_flash);
|
||||
sem_init(&sem_flash, 0, 1);
|
||||
|
||||
uint32_t data_start_addr;
|
||||
uint32_t data_end_addr;
|
||||
#if defined(ENABLE_EMULATION)
|
||||
fd_map = open("memory.flash", O_RDWR | O_CREAT, (mode_t) 0600);
|
||||
lseek(fd_map, PICO_FLASH_SIZE_BYTES - 1, SEEK_SET);
|
||||
write(fd_map, "", 1);
|
||||
map = mmap(0, PICO_FLASH_SIZE_BYTES, PROT_READ | PROT_WRITE, MAP_SHARED, fd_map, 0);
|
||||
data_start_addr = 0;
|
||||
data_end_addr = PICO_FLASH_SIZE_BYTES;
|
||||
#elif defined(ESP_PLATFORM)
|
||||
#if defined(ESP_PLATFORM)
|
||||
part0 = esp_partition_find_first(0x40, 0x1, "part0");
|
||||
esp_partition_mmap(part0, 0, part0->size, ESP_PARTITION_MMAP_DATA, (const void **)&map, (esp_partition_mmap_handle_t *)&fd_map);
|
||||
data_start_addr = 0;
|
||||
data_end_addr = part0->size;
|
||||
PICO_FLASH_SIZE_BYTES = part0->size;
|
||||
FLASH_SIZE_BYTES = part0->size;
|
||||
#elif defined(PICO_PLATFORM)
|
||||
uint8_t txbuf[6] = {0x9f};
|
||||
uint8_t rxbuf[6] = {0};
|
||||
flash_do_cmd(txbuf, rxbuf, 4);
|
||||
|
||||
FLASH_SIZE_BYTES = (1 << rxbuf[3]);
|
||||
#ifdef PICO_RP2350
|
||||
__attribute__((aligned(4))) uint8_t workarea[4 * 1024];
|
||||
int rc = rom_load_partition_table(workarea, sizeof(workarea), false);
|
||||
__attribute__((aligned(4))) uint32_t workarea[1024];
|
||||
int rc = rom_load_partition_table((uint8_t *)workarea, sizeof(workarea), false);
|
||||
if (rc) {
|
||||
reset_usb_boot(0, 0);
|
||||
}
|
||||
|
||||
uint8_t boot_partition = 1;
|
||||
rc = rom_get_partition_table_info((uint32_t*)workarea, 0x8, PT_INFO_PARTITION_LOCATION_AND_FLAGS | PT_INFO_SINGLE_PARTITION | (boot_partition << 24));
|
||||
rc = rom_get_partition_table_info(workarea, 0x8, PT_INFO_PARTITION_LOCATION_AND_FLAGS | PT_INFO_SINGLE_PARTITION | (boot_partition << 24));
|
||||
|
||||
if (rc != 3) {
|
||||
data_start_addr = (PICO_FLASH_SIZE_BYTES >> 1);
|
||||
data_end_addr = PICO_FLASH_SIZE_BYTES;
|
||||
data_start_addr = (FLASH_SIZE_BYTES >> 1);
|
||||
data_end_addr = FLASH_SIZE_BYTES;
|
||||
} else {
|
||||
uint16_t first_sector_number = (((uint32_t*)workarea)[1] & PICOBIN_PARTITION_LOCATION_FIRST_SECTOR_BITS) >> PICOBIN_PARTITION_LOCATION_FIRST_SECTOR_LSB;
|
||||
uint16_t last_sector_number = (((uint32_t*)workarea)[1] & PICOBIN_PARTITION_LOCATION_LAST_SECTOR_BITS) >> PICOBIN_PARTITION_LOCATION_LAST_SECTOR_LSB;
|
||||
uint16_t first_sector_number = (workarea[1] & PICOBIN_PARTITION_LOCATION_FIRST_SECTOR_BITS) >> PICOBIN_PARTITION_LOCATION_FIRST_SECTOR_LSB;
|
||||
uint16_t last_sector_number = (workarea[1] & PICOBIN_PARTITION_LOCATION_LAST_SECTOR_BITS) >> PICOBIN_PARTITION_LOCATION_LAST_SECTOR_LSB;
|
||||
data_start_addr = first_sector_number * FLASH_SECTOR_SIZE;
|
||||
data_end_addr = (last_sector_number + 1) * FLASH_SECTOR_SIZE;
|
||||
if (data_end_addr > FLASH_SIZE_BYTES) {
|
||||
data_end_addr = FLASH_SIZE_BYTES;
|
||||
}
|
||||
}
|
||||
data_end_addr -= 2 * FLASH_SECTOR_SIZE;
|
||||
#else
|
||||
data_start_addr = (PICO_FLASH_SIZE_BYTES >> 1);
|
||||
data_end_addr = PICO_FLASH_SIZE_BYTES;
|
||||
data_start_addr = (FLASH_SIZE_BYTES >> 1);
|
||||
data_end_addr = FLASH_SIZE_BYTES;
|
||||
#endif
|
||||
|
||||
data_start_addr += XIP_BASE;
|
||||
data_end_addr += XIP_BASE;
|
||||
#else
|
||||
fd_map = open("memory.flash", O_RDWR | O_CREAT, (mode_t) 0600);
|
||||
lseek(fd_map, FLASH_SIZE_BYTES - 1, SEEK_SET);
|
||||
write(fd_map, "", 1);
|
||||
map = mmap(0, FLASH_SIZE_BYTES, PROT_READ | PROT_WRITE, MAP_SHARED, fd_map, 0);
|
||||
data_start_addr = 0;
|
||||
data_end_addr = FLASH_SIZE_BYTES;
|
||||
#endif
|
||||
flash_set_bounds(data_start_addr, data_end_addr);
|
||||
}
|
||||
|
||||
void low_flash_init_core1() {
|
||||
void low_flash_init_core1(void) {
|
||||
mutex_enter_blocking(&mtx_flash);
|
||||
multicore_lockout_victim_init();
|
||||
locked_out = true;
|
||||
mutex_exit(&mtx_flash);
|
||||
}
|
||||
|
||||
void wait_flash_finish() {
|
||||
sem_acquire_blocking(&sem_flash); //blocks until released
|
||||
//wake up
|
||||
sem_acquire_blocking(&sem_flash); //decrease permits
|
||||
}
|
||||
|
||||
void low_flash_available() {
|
||||
void low_flash_commit(void) {
|
||||
mutex_enter_blocking(&mtx_flash);
|
||||
flash_available = true;
|
||||
mutex_exit(&mtx_flash);
|
||||
}
|
||||
|
||||
page_flash_t *find_free_page(uintptr_t addr) {
|
||||
static page_flash_t *find_free_page(uintptr_t addr) {
|
||||
uintptr_t addr_alg = addr & -FLASH_SECTOR_SIZE;
|
||||
page_flash_t *p = NULL;
|
||||
for (int r = 0; r < TOTAL_FLASH_PAGES; r++) {
|
||||
@@ -260,24 +283,24 @@ int flash_program_block(uintptr_t addr, const uint8_t *data, size_t len) {
|
||||
page_flash_t *p = NULL;
|
||||
|
||||
if (!data || len == 0) {
|
||||
return PICOKEY_ERR_NULL_PARAM;
|
||||
return PICOKEYS_ERR_NULL_PARAM;
|
||||
}
|
||||
|
||||
mutex_enter_blocking(&mtx_flash);
|
||||
if (ready_pages == TOTAL_FLASH_PAGES) {
|
||||
mutex_exit(&mtx_flash);
|
||||
printf("ERROR: ALL FLASH PAGES CACHED\n");
|
||||
return PICOKEY_ERR_NO_MEMORY;
|
||||
return PICOKEYS_ERR_NO_MEMORY;
|
||||
}
|
||||
if (!(p = find_free_page(addr))) {
|
||||
mutex_exit(&mtx_flash);
|
||||
printf("ERROR: FLASH CANNOT FIND A PAGE (rare error)\n");
|
||||
return PICOKEY_ERR_MEMORY_FATAL;
|
||||
return PICOKEYS_ERR_MEMORY_FATAL;
|
||||
}
|
||||
memcpy(&p->page[addr & (FLASH_SECTOR_SIZE - 1)], data, len);
|
||||
//printf("Flash: modified page %X with data %x at [%x]\n",(uintptr_t)addr,(uintptr_t)data,addr&(FLASH_SECTOR_SIZE-1));
|
||||
mutex_exit(&mtx_flash);
|
||||
return PICOKEY_OK;
|
||||
return PICOKEYS_OK;
|
||||
}
|
||||
|
||||
int flash_program_halfword(uintptr_t addr, uint16_t data) {
|
||||
@@ -306,7 +329,7 @@ uint8_t *flash_read(uintptr_t addr) {
|
||||
}
|
||||
uint8_t *v = (uint8_t *) addr;
|
||||
mutex_exit(&mtx_flash);
|
||||
#if defined(ENABLE_EMULATION) || defined(ESP_PLATFORM)
|
||||
#if !defined(PICO_PLATFORM)
|
||||
if (addr >= start_data_pool && addr <= end_rom_pool + sizeof(uintptr_t)) {
|
||||
v += (uintptr_t) map;
|
||||
}
|
||||
@@ -317,7 +340,7 @@ uint8_t *flash_read(uintptr_t addr) {
|
||||
uintptr_t flash_read_uintptr(uintptr_t addr) {
|
||||
uint8_t *p = flash_read(addr);
|
||||
uintptr_t v = 0x0;
|
||||
for (int i = 0; i < sizeof(uintptr_t); i++) {
|
||||
for (size_t i = 0; i < sizeof(uintptr_t); i++) {
|
||||
v |= (uintptr_t) p[i] << (8 * i);
|
||||
}
|
||||
return v;
|
||||
@@ -325,7 +348,7 @@ uintptr_t flash_read_uintptr(uintptr_t addr) {
|
||||
uint16_t flash_read_uint16(uintptr_t addr) {
|
||||
uint8_t *p = flash_read(addr);
|
||||
uint16_t v = 0x0;
|
||||
for (int i = 0; i < sizeof(uint16_t); i++) {
|
||||
for (size_t i = 0; i < sizeof(uint16_t); i++) {
|
||||
v |= p[i] << (8 * i);
|
||||
}
|
||||
return v;
|
||||
@@ -341,19 +364,19 @@ int flash_erase_page(uintptr_t addr, size_t page_size) {
|
||||
if (ready_pages == TOTAL_FLASH_PAGES) {
|
||||
mutex_exit(&mtx_flash);
|
||||
printf("ERROR: ALL FLASH PAGES CACHED\n");
|
||||
return PICOKEY_ERR_NO_MEMORY;
|
||||
return PICOKEYS_ERR_NO_MEMORY;
|
||||
}
|
||||
if (!(p = find_free_page(addr))) {
|
||||
printf("ERROR: FLASH CANNOT FIND A PAGE (rare error)\n");
|
||||
mutex_exit(&mtx_flash);
|
||||
return PICOKEY_ERR_MEMORY_FATAL;
|
||||
return PICOKEYS_ERR_MEMORY_FATAL;
|
||||
}
|
||||
p->erase = true;
|
||||
p->ready = false;
|
||||
p->page_size = page_size;
|
||||
mutex_exit(&mtx_flash);
|
||||
|
||||
return PICOKEY_OK;
|
||||
return PICOKEYS_OK;
|
||||
}
|
||||
|
||||
bool flash_check_blank(const uint8_t *p_start, size_t size) {
|
||||
@@ -366,3 +389,42 @@ bool flash_check_blank(const uint8_t *p_start, size_t size) {
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef PICO_RP2040
|
||||
typedef struct {
|
||||
uint64_t magic;
|
||||
uint16_t version;
|
||||
uint16_t flags;
|
||||
uint8_t uid[PICO_UNIQUE_BOARD_ID_SIZE_BYTES];
|
||||
uint32_t crc32;
|
||||
} __attribute__ ((packed)) phymarker_t;
|
||||
|
||||
uintptr_t __phymarker_start = (uintptr_t)0x10100000;
|
||||
|
||||
const uint64_t PHYSICAL_MARKER_MAGIC = 0x5049434F4B455953ULL; // "PICOKEYS"
|
||||
|
||||
void phymarker_write(void) {
|
||||
const uint64_t magic = *(uint64_t *)__phymarker_start;
|
||||
if (magic == PHYSICAL_MARKER_MAGIC) {
|
||||
return;
|
||||
}
|
||||
phymarker_t pm = {
|
||||
.magic = PHYSICAL_MARKER_MAGIC, // "PICOKEYS"
|
||||
.version = 0x0001,
|
||||
.flags = 0x0000,
|
||||
.crc32 = 0x00000000
|
||||
};
|
||||
memcpy(pm.uid, pico_serial.id, PICO_UNIQUE_BOARD_ID_SIZE_BYTES);
|
||||
pm.crc32 = crc32c((const uint8_t *)&pm, sizeof(phymarker_t) - sizeof(uint32_t));
|
||||
|
||||
uint8_t buf[FLASH_PAGE_SIZE] = {0};
|
||||
memcpy(buf, &pm, sizeof(phymarker_t));
|
||||
uint32_t ints = save_and_disable_interrupts();
|
||||
|
||||
flash_range_erase((uint32_t)__phymarker_start - XIP_BASE, FLASH_SECTOR_SIZE);
|
||||
flash_range_program((uint32_t)__phymarker_start - XIP_BASE, (const uint8_t *)buf, sizeof(buf));
|
||||
|
||||
restore_interrupts(ints);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,3 +1,20 @@
|
||||
/*
|
||||
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
|
||||
* Copyright (c) 2022 Pol Henarejos.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#include <windows.h>
|
||||
#include <errno.h>
|
||||
|
||||
@@ -1,8 +1,21 @@
|
||||
/*
|
||||
* sys/mman.h
|
||||
* mman-win32
|
||||
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
|
||||
* Copyright (c) 2022 Pol Henarejos.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _SYS_MMAN_H_
|
||||
#define _SYS_MMAN_H_
|
||||
|
||||
|
||||
241
src/fs/otp.c
241
src/fs/otp.c
@@ -1,241 +0,0 @@
|
||||
/*
|
||||
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
|
||||
* Copyright (c) 2022 Pol Henarejos.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "file.h"
|
||||
#include "pico_keys.h"
|
||||
#include <stdio.h>
|
||||
#include "otp.h"
|
||||
|
||||
#ifdef PICO_RP2350
|
||||
#include "pico/bootrom.h"
|
||||
#include "hardware/structs/otp.h"
|
||||
#include "hardware/regs/otp_data.h"
|
||||
#endif
|
||||
#include "random.h"
|
||||
#include "mbedtls/ecdsa.h"
|
||||
|
||||
#ifdef PICO_RP2350
|
||||
|
||||
static bool is_empty_buffer(const uint8_t *buffer, uint16_t buffer_len) {
|
||||
for (int i = 0; i < buffer_len; i++) {
|
||||
if (buffer[i] != 0x00) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static int otp_write_data_mode(uint16_t row, uint8_t *data, uint16_t len, bool is_ecc) {
|
||||
otp_cmd_t cmd = { .flags = row | (is_ecc ? OTP_CMD_ECC_BITS : 0) | OTP_CMD_WRITE_BITS };
|
||||
uint32_t ret = rom_func_otp_access(data, len, cmd);
|
||||
if (ret) {
|
||||
printf("OTP Write failed with error: %ld\n", ret);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int otp_write_data(uint16_t row, uint8_t *data, uint16_t len) {
|
||||
return otp_write_data_mode(row, data, len, true);
|
||||
}
|
||||
|
||||
int otp_write_data_raw(uint16_t row, uint8_t *data, uint16_t len) {
|
||||
return otp_write_data_mode(row, data, len, false);
|
||||
}
|
||||
|
||||
uint8_t* otp_buffer(uint16_t row) {
|
||||
volatile uint32_t *p = ((uint32_t *)(OTP_DATA_BASE + (row*2)));
|
||||
return (uint8_t *)p;
|
||||
}
|
||||
|
||||
uint8_t* otp_buffer_raw(uint16_t row) {
|
||||
volatile uint32_t *p = ((uint32_t *)(OTP_DATA_RAW_BASE + (row*4)));
|
||||
return (uint8_t *)p;
|
||||
}
|
||||
|
||||
bool is_empty_otp_buffer(uint16_t row, uint16_t len) {
|
||||
return is_empty_buffer(otp_buffer(row), len);
|
||||
}
|
||||
|
||||
static bool is_otp_locked_page(uint8_t page) {
|
||||
volatile uint32_t *p = ((uint32_t *)(OTP_DATA_BASE + ((OTP_DATA_PAGE0_LOCK0_ROW + page*2)*2)));
|
||||
return ((p[0] & 0xFFFF0000) == 0x3C3C0000 && (p[1] & 0xFF) == 0x3C);
|
||||
}
|
||||
|
||||
static void otp_lock_page(uint8_t page) {
|
||||
if (!is_otp_locked_page(page)) {
|
||||
uint32_t value = 0x3c3c3c;
|
||||
otp_write_data_raw(OTP_DATA_PAGE0_LOCK0_ROW + page*2 + 1, (uint8_t *)&value, sizeof(value));
|
||||
}
|
||||
|
||||
otp_hw->sw_lock[page] = 0b1100;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ESP_PLATFORM
|
||||
|
||||
uint8_t _otp_key_1[32] = {0};
|
||||
uint8_t _otp_key_2[32] = {0};
|
||||
|
||||
esp_err_t read_key_from_efuse(esp_efuse_block_t block, uint8_t *key, size_t key_len) {
|
||||
const esp_efuse_desc_t **key_desc = esp_efuse_get_key(block);
|
||||
|
||||
if (!key_desc) {
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
return esp_efuse_read_field_blob(key_desc, key, key_len * 8);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
const uint8_t *otp_key_1 = NULL;
|
||||
const uint8_t *otp_key_2 = NULL;
|
||||
|
||||
#ifdef PICO_RP2350
|
||||
typedef int otp_ret_t;
|
||||
#define OTP_WRITE(ROW, DATA, LEN) otp_write_data(ROW, DATA, LEN)
|
||||
#define OTP_READ(ROW, PTR) do { PTR = otp_buffer(ROW); } while(0)
|
||||
#define OTP_EMTPY(ROW, LEN) is_empty_otp_buffer(ROW, LEN)
|
||||
#elif defined(ESP_PLATFORM)
|
||||
typedef esp_err_t otp_ret_t;
|
||||
#define OTP_WRITE(ROW, DATA, LEN) esp_efuse_write_key(ROW, ESP_EFUSE_KEY_PURPOSE_USER, DATA, LEN);
|
||||
#define OTP_READ(ROW, PTR) do { \
|
||||
esp_err_t ret = read_key_from_efuse(ROW, _##PTR, sizeof(_##PTR)); \
|
||||
if (ret != ESP_OK) { printf("Error reading OTP key 1 [%d]\n", ret); } \
|
||||
PTR = _##PTR; } while(0)
|
||||
#define OTP_EMTPY(ROW, LEN) esp_efuse_key_block_unused(ROW)
|
||||
#endif
|
||||
|
||||
#ifndef SECURE_BOOT_BOOTKEY_INDEX
|
||||
#define SECURE_BOOT_BOOTKEY_INDEX 0
|
||||
#endif
|
||||
|
||||
int otp_enable_secure_boot(uint8_t bootkey, bool secure_lock) {
|
||||
int ret = 0;
|
||||
#ifdef PICO_RP2350
|
||||
uint8_t BOOTKEY[] = "\xe1\xd1\x6b\xa7\x64\xab\xd7\x12\xd4\xef\x6e\x3e\xdd\x74\x4e\xd5\x63\x8c\x26\xb\x77\x1c\xf9\x81\x51\x11\xb\xaf\xac\x9b\xc8\x71";
|
||||
if (is_empty_otp_buffer(OTP_DATA_BOOTKEY0_0_ROW + 0x10*bootkey, 32)) {
|
||||
PICOKEY_CHECK(otp_write_data(OTP_DATA_BOOTKEY0_0_ROW + 0x10*bootkey, BOOTKEY, sizeof(BOOTKEY)));
|
||||
}
|
||||
|
||||
uint8_t *boot_flags1 = otp_buffer_raw(OTP_DATA_BOOT_FLAGS1_ROW);
|
||||
uint8_t flagsb1[] = { boot_flags1[0] | (1 << (bootkey + OTP_DATA_BOOT_FLAGS1_KEY_VALID_LSB)), boot_flags1[1], boot_flags1[2], 0x00 };
|
||||
if (secure_lock) {
|
||||
flagsb1[1] |= ((OTP_DATA_BOOT_FLAGS1_KEY_INVALID_BITS >> OTP_DATA_BOOT_FLAGS1_KEY_INVALID_LSB) & (~(1 << bootkey)));
|
||||
}
|
||||
|
||||
PICOKEY_CHECK(otp_write_data_raw(OTP_DATA_BOOT_FLAGS1_ROW, flagsb1, sizeof(flagsb1)));
|
||||
PICOKEY_CHECK(otp_write_data_raw(OTP_DATA_BOOT_FLAGS1_R1_ROW, flagsb1, sizeof(flagsb1)));
|
||||
PICOKEY_CHECK(otp_write_data_raw(OTP_DATA_BOOT_FLAGS1_R2_ROW, flagsb1, sizeof(flagsb1)));
|
||||
|
||||
uint8_t *crit1 = otp_buffer_raw(OTP_DATA_CRIT1_ROW);
|
||||
uint8_t flagsc1[] = { crit1[0] | (1 << OTP_DATA_CRIT1_SECURE_BOOT_ENABLE_LSB), crit1[1], crit1[2], 0x00 };
|
||||
if (secure_lock) {
|
||||
flagsc1[0] |= (1 << OTP_DATA_CRIT1_DEBUG_DISABLE_LSB);
|
||||
flagsc1[0] |= (1 << OTP_DATA_CRIT1_GLITCH_DETECTOR_ENABLE_LSB);
|
||||
flagsc1[0] |= (3 << OTP_DATA_CRIT1_GLITCH_DETECTOR_SENS_LSB);
|
||||
}
|
||||
PICOKEY_CHECK(otp_write_data_raw(OTP_DATA_CRIT1_ROW, flagsc1, sizeof(flagsc1)));
|
||||
PICOKEY_CHECK(otp_write_data_raw(OTP_DATA_CRIT1_R1_ROW, flagsc1, sizeof(flagsc1)));
|
||||
PICOKEY_CHECK(otp_write_data_raw(OTP_DATA_CRIT1_R2_ROW, flagsc1, sizeof(flagsc1)));
|
||||
PICOKEY_CHECK(otp_write_data_raw(OTP_DATA_CRIT1_R3_ROW, flagsc1, sizeof(flagsc1)));
|
||||
PICOKEY_CHECK(otp_write_data_raw(OTP_DATA_CRIT1_R4_ROW, flagsc1, sizeof(flagsc1)));
|
||||
PICOKEY_CHECK(otp_write_data_raw(OTP_DATA_CRIT1_R5_ROW, flagsc1, sizeof(flagsc1)));
|
||||
PICOKEY_CHECK(otp_write_data_raw(OTP_DATA_CRIT1_R6_ROW, flagsc1, sizeof(flagsc1)));
|
||||
PICOKEY_CHECK(otp_write_data_raw(OTP_DATA_CRIT1_R7_ROW, flagsc1, sizeof(flagsc1)));
|
||||
|
||||
if (secure_lock) {
|
||||
uint8_t *page1 = otp_buffer_raw(OTP_DATA_PAGE1_LOCK1_ROW);
|
||||
uint8_t page1v = page1[0] | (OTP_DATA_PAGE1_LOCK1_LOCK_BL_VALUE_READ_ONLY << OTP_DATA_PAGE1_LOCK1_LOCK_BL_LSB);
|
||||
uint8_t flagsp1[] = { page1v, page1v, page1v, 0x00 };
|
||||
PICOKEY_CHECK(otp_write_data_raw(OTP_DATA_PAGE1_LOCK1_ROW, flagsp1, sizeof(flagsp1)));
|
||||
uint8_t *page2 = otp_buffer_raw(OTP_DATA_PAGE2_LOCK1_ROW);
|
||||
uint8_t page2v = page2[0] | (OTP_DATA_PAGE2_LOCK1_LOCK_BL_VALUE_READ_ONLY << OTP_DATA_PAGE2_LOCK1_LOCK_BL_LSB);
|
||||
uint8_t flagsp2[] = { page2v, page2v, page2v, 0x00 };
|
||||
PICOKEY_CHECK(otp_write_data_raw(OTP_DATA_PAGE2_LOCK1_ROW, flagsp2, sizeof(flagsp2)));
|
||||
}
|
||||
#elif defined(ESP_PLATFORM)
|
||||
// TODO: Implement secure boot for ESP32-S3
|
||||
#endif // PICO_RP2350
|
||||
goto err;
|
||||
err:
|
||||
if (ret != PICOKEY_OK) {
|
||||
return ret;
|
||||
}
|
||||
return PICOKEY_OK;
|
||||
}
|
||||
|
||||
void init_otp_files() {
|
||||
|
||||
#if defined(PICO_RP2350) || defined(ESP_PLATFORM)
|
||||
otp_ret_t ret = 0;
|
||||
uint16_t write_otp[2] = {0xFFFF, 0xFFFF};
|
||||
if (OTP_EMTPY(OTP_KEY_1, 32)) {
|
||||
uint8_t mkek[32] = {0};
|
||||
random_gen(NULL, mkek, sizeof(mkek));
|
||||
ret = OTP_WRITE(OTP_KEY_1, mkek, sizeof(mkek));
|
||||
if (ret != 0) {
|
||||
printf("Error writing OTP key 1 [%d]\n", ret);
|
||||
}
|
||||
write_otp[0] = OTP_KEY_1;
|
||||
}
|
||||
OTP_READ(OTP_KEY_1, otp_key_1);
|
||||
|
||||
if (OTP_EMTPY(OTP_KEY_2, 32)) {
|
||||
mbedtls_ecdsa_context ecdsa;
|
||||
size_t olen = 0;
|
||||
uint8_t pkey[MBEDTLS_ECP_MAX_BYTES];
|
||||
while (olen != 32) {
|
||||
mbedtls_ecdsa_init(&ecdsa);
|
||||
mbedtls_ecp_group_id ec_id = MBEDTLS_ECP_DP_SECP256K1;
|
||||
mbedtls_ecdsa_genkey(&ecdsa, ec_id, random_gen, NULL);
|
||||
mbedtls_ecp_write_key_ext(&ecdsa, &olen, pkey, sizeof(pkey));
|
||||
mbedtls_ecdsa_free(&ecdsa);
|
||||
}
|
||||
ret = OTP_WRITE(OTP_KEY_2, pkey, olen);
|
||||
if (ret != 0) {
|
||||
printf("Error writing OTP key 2 [%d]\n", ret);
|
||||
}
|
||||
write_otp[1] = OTP_KEY_2;
|
||||
}
|
||||
OTP_READ(OTP_KEY_2, otp_key_2);
|
||||
|
||||
for (int i = 0; i < sizeof(write_otp)/sizeof(uint16_t); i++) {
|
||||
if (write_otp[i] != 0xFFFF) {
|
||||
#if defined(PICO_RP2350)
|
||||
otp_lock_page(write_otp[i] >> 6);
|
||||
#elif defined(ESP_PLATFORM)
|
||||
ret = esp_efuse_set_key_dis_write(write_otp[i]);
|
||||
if (ret != ESP_OK) {
|
||||
printf("Error setting OTP key %d to read only [%d]\n", i, ret);
|
||||
}
|
||||
ret = esp_efuse_set_keypurpose_dis_write(write_otp[i]);
|
||||
if (ret != ESP_OK) {
|
||||
printf("Error setting OTP key %d purpose to read only [%d]\n", i, ret);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif // PICO_RP2350 || ESP_PLATFORM
|
||||
#ifdef ENABLE_EMULATION
|
||||
static uint8_t _otp1[32] = {0}, _otp2[32] = {0};
|
||||
memset(_otp1, 0xAC, sizeof(_otp1));
|
||||
memset(_otp2, 0xBE, sizeof(_otp2));
|
||||
otp_key_1 = _otp1;
|
||||
otp_key_2 = _otp2;
|
||||
#endif
|
||||
}
|
||||
51
src/fs/otp.h
51
src/fs/otp.h
@@ -1,51 +0,0 @@
|
||||
/*
|
||||
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
|
||||
* Copyright (c) 2022 Pol Henarejos.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _OTP_H_
|
||||
#define _OTP_H_
|
||||
|
||||
#ifdef PICO_RP2350
|
||||
|
||||
#define OTP_MKEK_ROW 0xEF0
|
||||
#define OTP_DEVK_ROW 0xED0
|
||||
|
||||
#define OTP_KEY_1 OTP_MKEK_ROW
|
||||
#define OTP_KEY_2 OTP_DEVK_ROW
|
||||
|
||||
extern uint8_t* otp_buffer(uint16_t row);
|
||||
extern uint8_t* otp_buffer_raw(uint16_t row);
|
||||
extern bool is_empty_otp_buffer(uint16_t row, uint16_t len);
|
||||
extern int otp_write_data(uint16_t row, uint8_t *data, uint16_t len);
|
||||
extern int otp_write_data_raw(uint16_t row, uint8_t *data, uint16_t len);
|
||||
|
||||
#elif defined(ESP_PLATFORM)
|
||||
|
||||
#include "esp_efuse.h"
|
||||
|
||||
#define OTP_KEY_1 EFUSE_BLK_KEY3
|
||||
#define OTP_KEY_2 EFUSE_BLK_KEY4
|
||||
|
||||
#endif
|
||||
|
||||
extern int otp_enable_secure_boot(uint8_t bootkey, bool secure_lock);
|
||||
extern void init_otp_files();
|
||||
|
||||
extern const uint8_t *otp_key_1;
|
||||
extern const uint8_t *otp_key_2;
|
||||
|
||||
#endif // _OTP_H_
|
||||
59
src/fs/phy.c
59
src/fs/phy.c
@@ -3,20 +3,20 @@
|
||||
* 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
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
* Affero 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/>.
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "pico_keys.h"
|
||||
#include "file.h"
|
||||
#include "picokeys.h"
|
||||
#include "otp.h"
|
||||
|
||||
#ifndef ENABLE_EMULATION
|
||||
|
||||
@@ -24,7 +24,7 @@ phy_data_t phy_data;
|
||||
|
||||
int phy_serialize_data(const phy_data_t *phy, uint8_t *data, uint16_t *len) {
|
||||
if (!phy || !data || !len) {
|
||||
return PICOKEY_ERR_NULL_PARAM;
|
||||
return PICOKEYS_ERR_NULL_PARAM;
|
||||
}
|
||||
uint8_t *p = data;
|
||||
if (phy->vidpid_present) {
|
||||
@@ -47,7 +47,7 @@ int phy_serialize_data(const phy_data_t *phy, uint8_t *data, uint16_t *len) {
|
||||
}
|
||||
*p++ = PHY_OPTS;
|
||||
*p++ = 2;
|
||||
p += put_uint16_t_be(phy->opts, p);
|
||||
p += put_uint16_be(phy->opts, p);
|
||||
if (phy->up_btn_present) {
|
||||
*p++ = PHY_UP_BTN;
|
||||
*p++ = 1;
|
||||
@@ -55,7 +55,7 @@ int phy_serialize_data(const phy_data_t *phy, uint8_t *data, uint16_t *len) {
|
||||
}
|
||||
if (phy->usb_product_present) {
|
||||
*p++ = PHY_USB_PRODUCT;
|
||||
*p++ = strlen(phy->usb_product) + 1;
|
||||
*p++ = (uint8_t)strlen(phy->usb_product) + 1;
|
||||
strcpy((char *)p, phy->usb_product);
|
||||
p += strlen(phy->usb_product);
|
||||
*p++ = '\0';
|
||||
@@ -63,21 +63,26 @@ int phy_serialize_data(const phy_data_t *phy, uint8_t *data, uint16_t *len) {
|
||||
if (phy->enabled_curves_present) {
|
||||
*p++ = PHY_ENABLED_CURVES;
|
||||
*p++ = 4;
|
||||
p += put_uint32_t_be(phy->enabled_curves, p);
|
||||
p += put_uint32_be(phy->enabled_curves, p);
|
||||
}
|
||||
if (phy->enabled_usb_itf_present) {
|
||||
*p++ = PHY_ENABLED_USB_ITF;
|
||||
*p++ = 1;
|
||||
*p++ = phy->enabled_usb_itf;
|
||||
}
|
||||
if (phy->led_driver_present) {
|
||||
*p++ = PHY_LED_DRIVER;
|
||||
*p++ = 1;
|
||||
*p++ = phy->led_driver;
|
||||
}
|
||||
|
||||
*len = p - data;
|
||||
return PICOKEY_OK;
|
||||
*len = (uint8_t)(p - data);
|
||||
return PICOKEYS_OK;
|
||||
}
|
||||
|
||||
int phy_unserialize_data(const uint8_t *data, uint16_t len, phy_data_t *phy) {
|
||||
if (!phy || !data || !len) {
|
||||
return PICOKEY_ERR_NULL_PARAM;
|
||||
return PICOKEYS_ERR_NULL_PARAM;
|
||||
}
|
||||
const uint8_t *p = data;
|
||||
uint8_t tag, tlen;
|
||||
@@ -109,7 +114,7 @@ int phy_unserialize_data(const uint8_t *data, uint16_t len, phy_data_t *phy) {
|
||||
break;
|
||||
case PHY_OPTS:
|
||||
if (tlen == 2) {
|
||||
phy->opts = get_uint16_t_be(p);
|
||||
phy->opts = get_uint16_be(p);
|
||||
p += 2;
|
||||
}
|
||||
break;
|
||||
@@ -129,7 +134,7 @@ int phy_unserialize_data(const uint8_t *data, uint16_t len, phy_data_t *phy) {
|
||||
break;
|
||||
case PHY_ENABLED_CURVES:
|
||||
if (tlen == 4) {
|
||||
phy->enabled_curves = get_uint32_t_be(p);
|
||||
phy->enabled_curves = get_uint32_be(p);
|
||||
p += 4;
|
||||
phy->enabled_curves_present = true;
|
||||
}
|
||||
@@ -141,39 +146,45 @@ int phy_unserialize_data(const uint8_t *data, uint16_t len, phy_data_t *phy) {
|
||||
phy->enabled_usb_itf_present = true;
|
||||
}
|
||||
break;
|
||||
case PHY_LED_DRIVER:
|
||||
if (tlen == 1) {
|
||||
phy->led_driver = *p++;
|
||||
phy->led_driver_present = true;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
p += tlen;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!phy_data.enabled_usb_itf_present) {
|
||||
phy_data.enabled_usb_itf = PHY_USB_ITF_CCID | PHY_USB_ITF_WCID | PHY_USB_ITF_HID | PHY_USB_ITF_KB;
|
||||
phy_data.enabled_usb_itf = PHY_USB_ITF_ALL;
|
||||
phy_data.enabled_usb_itf_present = true;
|
||||
}
|
||||
return PICOKEY_OK;
|
||||
return PICOKEYS_OK;
|
||||
}
|
||||
|
||||
int phy_init() {
|
||||
int phy_init(void) {
|
||||
memset(&phy_data, 0, sizeof(phy_data_t));
|
||||
return phy_load();
|
||||
}
|
||||
|
||||
int phy_save() {
|
||||
int phy_save(void) {
|
||||
uint8_t tmp[PHY_MAX_SIZE] = {0};
|
||||
uint16_t tmp_len = 0;
|
||||
int ret = phy_serialize_data(&phy_data, tmp, &tmp_len);
|
||||
if (ret != PICOKEY_OK) {
|
||||
if (ret != PICOKEYS_OK) {
|
||||
return ret;
|
||||
}
|
||||
file_put_data(ef_phy, tmp, tmp_len);
|
||||
low_flash_available();
|
||||
return PICOKEY_OK;
|
||||
flash_commit();
|
||||
return PICOKEYS_OK;
|
||||
}
|
||||
|
||||
int phy_load() {
|
||||
int phy_load(void) {
|
||||
if (file_has_data(ef_phy)) {
|
||||
return phy_unserialize_data(file_get_data(ef_phy), file_get_size(ef_phy), &phy_data);
|
||||
}
|
||||
return PICOKEY_OK;
|
||||
return PICOKEYS_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
36
src/fs/phy.h
36
src/fs/phy.h
@@ -3,16 +3,16 @@
|
||||
* 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
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
* Affero 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/>.
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _PHY_H_
|
||||
@@ -28,6 +28,7 @@
|
||||
#define PHY_USB_PRODUCT 0x9
|
||||
#define PHY_ENABLED_CURVES 0xA
|
||||
#define PHY_ENABLED_USB_ITF 0xB
|
||||
#define PHY_LED_DRIVER 0xC
|
||||
|
||||
#define PHY_OPT_WCID 0x1
|
||||
#define PHY_OPT_DIMM 0x2
|
||||
@@ -50,10 +51,25 @@
|
||||
#define PHY_USB_ITF_WCID 0x2
|
||||
#define PHY_USB_ITF_HID 0x4
|
||||
#define PHY_USB_ITF_KB 0x8
|
||||
#define PHY_USB_ITF_LWIP 0x10
|
||||
#define PHY_USB_ITF_ALL (PHY_USB_ITF_CCID | PHY_USB_ITF_WCID | PHY_USB_ITF_HID | PHY_USB_ITF_KB | PHY_USB_ITF_LWIP)
|
||||
|
||||
#define PHY_LED_DRIVER_PICO 0x1
|
||||
#define PHY_LED_DRIVER_PIMORONI 0x2
|
||||
#define PHY_LED_DRIVER_WS2812 0x3
|
||||
#ifdef CYW43_WL_GPIO_LED_PIN
|
||||
#define PHY_LED_DRIVER_CYW43 0x4
|
||||
#endif
|
||||
#ifdef ESP_PLATFORM
|
||||
#define PHY_LED_DRIVER_NEOPIXEL 0x5
|
||||
#endif
|
||||
|
||||
#define PHY_LED_DRIVER_NONE 0xFF
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
PACK(
|
||||
typedef struct phy_data {
|
||||
union {
|
||||
struct {
|
||||
@@ -73,6 +89,7 @@ typedef struct phy_data {
|
||||
uint8_t led_brightness;
|
||||
uint8_t up_btn;
|
||||
uint8_t enabled_usb_itf;
|
||||
uint8_t led_driver;
|
||||
|
||||
bool vidpid_present;
|
||||
bool led_gpio_present;
|
||||
@@ -81,17 +98,18 @@ typedef struct phy_data {
|
||||
bool usb_product_present;
|
||||
bool enabled_curves_present;
|
||||
bool enabled_usb_itf_present;
|
||||
bool led_driver_present;
|
||||
|
||||
} phy_data_t;
|
||||
}) phy_data_t;
|
||||
|
||||
#define PHY_MAX_SIZE ((2+4)+(2+4)+(2+32)+(2+2)+(2+1)+(2+1)+(2+1)+(2+1))
|
||||
#define PHY_MAX_SIZE ((2+4)+(2+4)+(2+32)+(2+2)+(2+1)+(2+1)+(2+1)+(2+1)+(2+1))
|
||||
|
||||
#ifndef ENABLE_EMULATION
|
||||
extern int phy_serialize_data(const phy_data_t *phy, uint8_t *data, uint16_t *len);
|
||||
extern int phy_unserialize_data(const uint8_t *data, uint16_t len, phy_data_t *phy);
|
||||
extern int phy_init();
|
||||
extern int phy_save();
|
||||
extern int phy_load();
|
||||
extern int phy_init(void);
|
||||
extern int phy_save(void);
|
||||
extern int phy_load(void);
|
||||
extern phy_data_t phy_data;
|
||||
#endif
|
||||
|
||||
|
||||
42
src/json.h
Normal file
42
src/json.h
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
|
||||
* Copyright (c) 2022 Pol Henarejos.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _JSON_H_
|
||||
#define _JSON_H_
|
||||
|
||||
#include "cJSON.h"
|
||||
|
||||
#define CJSON_ADD_GENERIC(hdl, ptr, item, value) do { \
|
||||
if (hdl(ptr, item, value) == NULL) { \
|
||||
response->status_code = 500; \
|
||||
return 1; \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
#define CJSON_ADD_GENERIC_ITEM(hdl, ptr, item, value) do { \
|
||||
if (hdl(ptr, item, value) == false) { \
|
||||
response->status_code = 500; \
|
||||
return 1; \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
#define CJSON_ADD_STRING(ptr, item, value) CJSON_ADD_GENERIC(cJSON_AddStringToObject, (ptr)->json, item, value)
|
||||
#define CJSON_ADD_NUMBER(ptr, item, value) CJSON_ADD_GENERIC(cJSON_AddNumberToObject, (ptr)->json, item, value)
|
||||
#define CJSON_ADD_BOOL(ptr, item, value) CJSON_ADD_GENERIC(cJSON_AddBoolToObject, (ptr)->json, item, value)
|
||||
#define CJSON_ADD_ITEM(ptr, item, value) CJSON_ADD_GENERIC_ITEM(cJSON_AddItemToObject, (ptr)->json, item, value)
|
||||
|
||||
#endif // _JSON_H_
|
||||
149
src/led/led.c
149
src/led/led.c
@@ -1,33 +1,30 @@
|
||||
/*
|
||||
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
|
||||
* Copyright (c) 2022 Pol Henarejos.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/*
|
||||
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
|
||||
* Copyright (c) 2022 Pol Henarejos.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "pico_keys.h"
|
||||
#ifdef PICO_PLATFORM
|
||||
#include "bsp/board.h"
|
||||
#elif defined(ESP_PLATFORM)
|
||||
#include "esp_compat.h"
|
||||
#include "picokeys.h"
|
||||
#include "led/led.h"
|
||||
#include "pico_time.h"
|
||||
#if defined(ESP_PLATFORM)
|
||||
#include "driver/gpio.h"
|
||||
#elif defined(ENABLE_EMULATION)
|
||||
#include "emulation.h"
|
||||
#endif
|
||||
|
||||
extern void led_driver_init();
|
||||
extern void led_driver_color(uint8_t, uint32_t, float);
|
||||
led_driver_t *led_driver = NULL;
|
||||
|
||||
static uint32_t led_mode = MODE_NOT_MOUNTED;
|
||||
|
||||
@@ -35,12 +32,12 @@ void led_set_mode(uint32_t mode) {
|
||||
led_mode = mode;
|
||||
}
|
||||
|
||||
uint32_t led_get_mode() {
|
||||
uint32_t led_get_mode(void) {
|
||||
return led_mode;
|
||||
}
|
||||
|
||||
void led_blinking_task() {
|
||||
#ifndef ENABLE_EMULATION
|
||||
void led_blinking_task(void) {
|
||||
#if defined(PICO_PLATFORM) || defined(ESP_PLATFORM)
|
||||
static uint32_t start_ms = 0;
|
||||
static uint32_t stop_ms = 0;
|
||||
static uint32_t last_led_update_ms = 0;
|
||||
@@ -69,7 +66,7 @@ void led_blinking_task() {
|
||||
|
||||
// limit the frequency of LED status updates
|
||||
if (board_millis() - last_led_update_ms > 2) {
|
||||
led_driver_color(led_color, led_brightness, progress);
|
||||
led_driver->set_color(led_color, led_brightness, progress);
|
||||
last_led_update_ms = board_millis();
|
||||
}
|
||||
|
||||
@@ -81,15 +78,97 @@ void led_blinking_task() {
|
||||
#endif
|
||||
}
|
||||
|
||||
void led_off_all() {
|
||||
#ifndef ENABLE_EMULATION
|
||||
led_driver_color(LED_COLOR_OFF, 0, 0);
|
||||
void led_off_all(void) {
|
||||
#if defined(PICO_PLATFORM) || defined(ESP_PLATFORM)
|
||||
led_driver->set_color(LED_COLOR_OFF, 0, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
void led_init() {
|
||||
#ifndef ENABLE_EMULATION
|
||||
led_driver_init();
|
||||
extern led_driver_t led_driver_pico;
|
||||
extern led_driver_t led_driver_cyw43;
|
||||
extern led_driver_t led_driver_ws2812;
|
||||
extern led_driver_t led_driver_neopixel;
|
||||
extern led_driver_t led_driver_pimoroni;
|
||||
|
||||
static void led_driver_init_dummy(void) {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
static void led_driver_color_dummy(uint8_t color, uint32_t led_brightness, float progress) {
|
||||
(void)color;
|
||||
(void)led_brightness;
|
||||
(void)progress;
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
led_driver_t led_driver_dummy = {
|
||||
.init = led_driver_init_dummy,
|
||||
.set_color = led_driver_color_dummy,
|
||||
};
|
||||
|
||||
void led_init(void) {
|
||||
led_driver = &led_driver_dummy;
|
||||
#if defined(PICO_PLATFORM) || defined(ESP_PLATFORM)
|
||||
// Guess default driver
|
||||
#if defined(PIMORONI_TINY2040) || defined(PIMORONI_TINY2350)
|
||||
led_driver = &led_driver_pimoroni;
|
||||
phy_data.led_driver = phy_data.led_driver_present ? phy_data.led_driver : PHY_LED_DRIVER_PIMORONI;
|
||||
phy_data.led_gpio = phy_data.led_gpio_present ? phy_data.led_gpio : PICO_DEFAULT_LED_PIN;
|
||||
#elif defined(CYW43_WL_GPIO_LED_PIN)
|
||||
led_driver = &led_driver_cyw43;
|
||||
phy_data.led_driver = phy_data.led_driver_present ? phy_data.led_driver : PHY_LED_DRIVER_CYW43;
|
||||
phy_data.led_gpio = phy_data.led_gpio_present ? phy_data.led_gpio : CYW43_WL_GPIO_LED_PIN;
|
||||
#elif defined(PICO_DEFAULT_WS2812_PIN)
|
||||
led_driver = &led_driver_ws2812;
|
||||
phy_data.led_driver = phy_data.led_driver_present ? phy_data.led_driver : PHY_LED_DRIVER_WS2812;
|
||||
phy_data.led_gpio = phy_data.led_gpio_present ? phy_data.led_gpio : PICO_DEFAULT_WS2812_PIN;
|
||||
#elif defined(ESP_PLATFORM)
|
||||
#if defined(CONFIG_IDF_TARGET_ESP32S3)
|
||||
#define NEOPIXEL_PIN GPIO_NUM_48
|
||||
#elif defined(CONFIG_IDF_TARGET_ESP32S2)
|
||||
#define NEOPIXEL_PIN GPIO_NUM_15
|
||||
#elif defined(CONFIG_IDF_TARGET_ESP32C6)
|
||||
#define NEOPIXEL_PIN GPIO_NUM_8
|
||||
#else
|
||||
#define NEOPIXEL_PIN GPIO_NUM_27
|
||||
#endif
|
||||
led_driver = &led_driver_neopixel;
|
||||
phy_data.led_driver = phy_data.led_driver_present ? phy_data.led_driver : PHY_LED_DRIVER_NEOPIXEL;
|
||||
phy_data.led_gpio = phy_data.led_gpio_present ? phy_data.led_gpio : NEOPIXEL_PIN;
|
||||
#elif defined(PICO_DEFAULT_LED_PIN)
|
||||
led_driver = &led_driver_pico;
|
||||
phy_data.led_driver = phy_data.led_driver_present ? phy_data.led_driver : PHY_LED_DRIVER_PICO;
|
||||
phy_data.led_gpio = phy_data.led_gpio_present ? phy_data.led_gpio : PICO_DEFAULT_LED_PIN;
|
||||
#endif
|
||||
if (phy_data.led_driver_present) {
|
||||
switch (phy_data.led_driver) {
|
||||
case PHY_LED_DRIVER_PICO:
|
||||
led_driver = &led_driver_pico;
|
||||
break;
|
||||
#ifdef ESP_PLATFORM
|
||||
case PHY_LED_DRIVER_NEOPIXEL:
|
||||
led_driver = &led_driver_neopixel;
|
||||
break;
|
||||
#else
|
||||
#ifdef CYW43_WL_GPIO_LED_PIN
|
||||
case PHY_LED_DRIVER_CYW43:
|
||||
led_driver = &led_driver_cyw43;
|
||||
break;
|
||||
#endif
|
||||
case PHY_LED_DRIVER_WS2812:
|
||||
led_driver = &led_driver_ws2812;
|
||||
break;
|
||||
case PHY_LED_DRIVER_PIMORONI:
|
||||
led_driver = &led_driver_pimoroni;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
phy_data.led_driver_present = true;
|
||||
phy_data.led_gpio_present = true;
|
||||
led_driver->init();
|
||||
led_set_mode(MODE_NOT_MOUNTED);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -3,16 +3,16 @@
|
||||
* 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
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
* Affero 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/>.
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _LED_H_
|
||||
@@ -62,9 +62,16 @@ enum {
|
||||
};
|
||||
|
||||
extern void led_set_mode(uint32_t mode);
|
||||
extern uint32_t led_get_mode();
|
||||
extern void led_blinking_task();
|
||||
extern void led_off_all();
|
||||
extern void led_init();
|
||||
extern uint32_t led_get_mode(void);
|
||||
extern void led_blinking_task(void);
|
||||
extern void led_off_all(void);
|
||||
extern void led_init(void);
|
||||
|
||||
typedef struct {
|
||||
void (*init)(void);
|
||||
void (*set_color)(uint8_t color, uint32_t led_brightness, float progress);
|
||||
} led_driver_t;
|
||||
|
||||
extern led_driver_t *led_driver;
|
||||
|
||||
#endif // _LED_H_
|
||||
|
||||
@@ -3,30 +3,38 @@
|
||||
* 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
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
* Affero 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/>.
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "pico_keys.h"
|
||||
#include "picokeys.h"
|
||||
#include "led/led.h"
|
||||
#ifdef PICO_PLATFORM
|
||||
#include "hardware/gpio.h"
|
||||
#endif
|
||||
|
||||
#ifdef CYW43_WL_GPIO_LED_PIN
|
||||
|
||||
#include "pico/cyw43_arch.h"
|
||||
|
||||
void led_driver_init() {
|
||||
void led_driver_init_cyw43(void);
|
||||
void led_driver_color_cyw43(uint8_t color, uint32_t led_brightness, float progress);
|
||||
|
||||
void led_driver_init_cyw43(void) {
|
||||
cyw43_arch_init();
|
||||
}
|
||||
|
||||
void led_driver_color(uint8_t color, uint32_t led_brightness, float progress) {
|
||||
void led_driver_color_cyw43(uint8_t color, uint32_t led_brightness, float progress) {
|
||||
(void)led_brightness;
|
||||
(void)color;
|
||||
uint8_t gpio = CYW43_WL_GPIO_LED_PIN;
|
||||
if (phy_data.led_gpio_present) {
|
||||
gpio = phy_data.led_gpio;
|
||||
@@ -34,4 +42,9 @@ void led_driver_color(uint8_t color, uint32_t led_brightness, float progress) {
|
||||
cyw43_arch_gpio_put(gpio, progress >= 0.5);
|
||||
}
|
||||
|
||||
led_driver_t led_driver_cyw43 = {
|
||||
.init = led_driver_init_cyw43,
|
||||
.set_color = led_driver_color_cyw43,
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -3,19 +3,23 @@
|
||||
* 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
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
* Affero 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/>.
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "pico_keys.h"
|
||||
#include "picokeys.h"
|
||||
#include "led/led.h"
|
||||
#ifdef PICO_PLATFORM
|
||||
#include "hardware/gpio.h"
|
||||
#endif
|
||||
|
||||
#ifdef ESP_PLATFORM
|
||||
|
||||
@@ -45,7 +49,7 @@ tNeopixel pixel[] = {
|
||||
#define NEOPIXEL_PIN GPIO_NUM_27
|
||||
#endif
|
||||
|
||||
void led_driver_init() {
|
||||
void led_driver_init_neopixel(void) {
|
||||
uint8_t gpio = NEOPIXEL_PIN;
|
||||
if (phy_data.led_gpio_present) {
|
||||
gpio = phy_data.led_gpio;
|
||||
@@ -53,7 +57,7 @@ void led_driver_init() {
|
||||
neopixel = neopixel_Init(1, gpio);
|
||||
}
|
||||
|
||||
void led_driver_color(uint8_t color, uint32_t led_brightness, float progress) {
|
||||
void led_driver_color_neopixel(uint8_t color, uint32_t led_brightness, float progress) {
|
||||
static tNeopixel spx = {.index = 0, .rgb = 0};
|
||||
if (!(phy_data.opts & PHY_OPT_DIMM)) {
|
||||
progress = progress >= 0.5 ? 1 : 0;
|
||||
@@ -72,4 +76,9 @@ void led_driver_color(uint8_t color, uint32_t led_brightness, float progress) {
|
||||
neopixel_SetPixel(neopixel, &spx, 1);
|
||||
}
|
||||
|
||||
led_driver_t led_driver_neopixel = {
|
||||
.init = led_driver_init_neopixel,
|
||||
.set_color = led_driver_color_neopixel,
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -3,25 +3,40 @@
|
||||
* 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
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
* Affero 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/>.
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "pico_keys.h"
|
||||
#include "picokeys.h"
|
||||
#include "led/led.h"
|
||||
|
||||
#if defined(PICO_DEFAULT_LED_PIN) && !defined(PICO_DEFAULT_WS2812_PIN) && !defined(PIMORONI_TINY2040) && !defined(PIMORONI_TINY2350)
|
||||
#ifdef PICO_PLATFORM
|
||||
#include "hardware/gpio.h"
|
||||
#endif
|
||||
#ifdef PICO_DEFAULT_LED_PIN
|
||||
static uint8_t gpio = PICO_DEFAULT_LED_PIN;
|
||||
#else
|
||||
static uint8_t gpio = 0;
|
||||
#endif
|
||||
|
||||
uint8_t gpio = PICO_DEFAULT_LED_PIN;
|
||||
#ifdef ESP_PLATFORM
|
||||
#include "driver/gpio.h"
|
||||
#define gpio_init gpio_reset_pin
|
||||
#define gpio_set_dir gpio_set_direction
|
||||
#define gpio_put gpio_set_level
|
||||
#define GPIO_OUT GPIO_MODE_OUTPUT
|
||||
#endif
|
||||
|
||||
void led_driver_init() {
|
||||
#if defined(PICO_PLATFORM) || defined(ESP_PLATFORM)
|
||||
static void led_driver_init_pico(void) {
|
||||
if (phy_data.led_gpio_present) {
|
||||
gpio = phy_data.led_gpio;
|
||||
}
|
||||
@@ -29,9 +44,15 @@ void led_driver_init() {
|
||||
gpio_set_dir(gpio, GPIO_OUT);
|
||||
}
|
||||
|
||||
void led_driver_color(uint8_t color, uint32_t led_brightness, float progress) {
|
||||
static void led_driver_color_pico(uint8_t color, uint32_t led_brightness, float progress) {
|
||||
(void)color;
|
||||
(void)led_brightness;
|
||||
gpio_put(gpio, progress >= 0.5);
|
||||
}
|
||||
|
||||
led_driver_t led_driver_pico = {
|
||||
.init = led_driver_init_pico,
|
||||
.set_color = led_driver_color_pico,
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -3,30 +3,27 @@
|
||||
* 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
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
* Affero 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/>.
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "pico_keys.h"
|
||||
#include "picokeys.h"
|
||||
#include "led/led.h"
|
||||
|
||||
#if defined(PIMORONI_TINY2040) || defined(PIMORONI_TINY2350)
|
||||
|
||||
#ifdef PIMORONI_TINY2040
|
||||
#define LED_R_PIN TINY2040_LED_R_PIN
|
||||
#define LED_G_PIN TINY2040_LED_G_PIN
|
||||
#define LED_B_PIN TINY2040_LED_B_PIN
|
||||
#elif defined(PIMORONI_TINY2350)
|
||||
#define LED_R_PIN TINY2350_LED_R_PIN
|
||||
#define LED_G_PIN TINY2350_LED_G_PIN
|
||||
#define LED_B_PIN TINY2350_LED_B_PIN
|
||||
#ifdef PICO_PLATFORM
|
||||
#include "hardware/gpio.h"
|
||||
#ifdef PICO_DEFAULT_LED_PIN
|
||||
static uint8_t gpio = PICO_DEFAULT_LED_PIN;
|
||||
#else
|
||||
static uint8_t gpio = 0;
|
||||
#endif
|
||||
|
||||
uint8_t pixel[][3] = {
|
||||
@@ -40,22 +37,31 @@ uint8_t pixel[][3] = {
|
||||
{0, 0, 0} // 7: white
|
||||
};
|
||||
|
||||
void led_driver_init() {
|
||||
gpio_init(LED_R_PIN);
|
||||
gpio_set_dir(LED_R_PIN, GPIO_OUT);
|
||||
gpio_init(LED_G_PIN);
|
||||
gpio_set_dir(LED_G_PIN, GPIO_OUT);
|
||||
gpio_init(LED_B_PIN);
|
||||
gpio_set_dir(LED_B_PIN, GPIO_OUT);
|
||||
static void led_driver_init_pimoroni(void) {
|
||||
if (phy_data.led_gpio_present) {
|
||||
gpio = phy_data.led_gpio;
|
||||
}
|
||||
gpio_init(gpio-1);
|
||||
gpio_set_dir(gpio-1, GPIO_OUT);
|
||||
gpio_init(gpio);
|
||||
gpio_set_dir(gpio, GPIO_OUT);
|
||||
gpio_init(gpio+1);
|
||||
gpio_set_dir(gpio+1, GPIO_OUT);
|
||||
}
|
||||
|
||||
void led_driver_color(uint8_t color, uint32_t led_brightness, float progress) {
|
||||
static void led_driver_color_pimoroni(uint8_t color, uint32_t led_brightness, float progress) {
|
||||
(void)led_brightness;
|
||||
if (progress < 0.5) {
|
||||
color = LED_COLOR_OFF;
|
||||
}
|
||||
gpio_put(LED_R_PIN, pixel[color][0]);
|
||||
gpio_put(LED_G_PIN, pixel[color][1]);
|
||||
gpio_put(LED_B_PIN, pixel[color][2]);
|
||||
gpio_put(gpio-1, pixel[color][0]);
|
||||
gpio_put(gpio, pixel[color][1]);
|
||||
gpio_put(gpio+1, pixel[color][2]);
|
||||
}
|
||||
|
||||
led_driver_t led_driver_pimoroni = {
|
||||
.init = led_driver_init_pimoroni,
|
||||
.set_color = led_driver_color_pimoroni,
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -3,22 +3,22 @@
|
||||
* 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
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
* Affero 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/>.
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "pico_keys.h"
|
||||
|
||||
#ifdef PICO_DEFAULT_WS2812_PIN
|
||||
#include "picokeys.h"
|
||||
#include "led/led.h"
|
||||
|
||||
#ifdef PICO_PLATFORM
|
||||
#include "hardware/pio.h"
|
||||
#include "hardware/clocks.h"
|
||||
|
||||
@@ -70,11 +70,14 @@ static inline void ws2812_program_init(PIO pio, uint sm, uint offset, uint pin,
|
||||
pio_sm_set_enabled(pio, sm, true);
|
||||
}
|
||||
|
||||
void led_driver_init() {
|
||||
static void led_driver_init_ws2812(void) {
|
||||
PIO pio = pio0;
|
||||
int sm = 0;
|
||||
uint offset = pio_add_program(pio, &ws2812_program);
|
||||
uint8_t gpio = PICO_DEFAULT_WS2812_PIN;
|
||||
uint8_t gpio = 0;
|
||||
#ifdef PICO_DEFAULT_WS2812_PIN
|
||||
gpio = PICO_DEFAULT_WS2812_PIN;
|
||||
#endif
|
||||
if (phy_data.led_gpio_present) {
|
||||
gpio = phy_data.led_gpio;
|
||||
}
|
||||
@@ -113,7 +116,7 @@ static inline void ws2812_put_pixel(uint32_t u32_pixel) {
|
||||
pio_sm_put_blocking(pio0, 0, u32_pixel << 8u);
|
||||
}
|
||||
|
||||
void led_driver_color(uint8_t color, uint32_t led_brightness, float progress) {
|
||||
static void led_driver_color_ws2812(uint8_t color, uint32_t led_brightness, float progress) {
|
||||
if (!(phy_data.opts & PHY_OPT_DIMM)) {
|
||||
progress = progress >= 0.5 ? 1 : 0;
|
||||
}
|
||||
@@ -128,4 +131,9 @@ void led_driver_color(uint8_t color, uint32_t led_brightness, float progress) {
|
||||
ws2812_put_pixel(urgb_u32(pixel_color.r, pixel_color.g, pixel_color.b));
|
||||
}
|
||||
|
||||
led_driver_t led_driver_ws2812 = {
|
||||
.init = led_driver_init_ws2812,
|
||||
.set_color = led_driver_color_ws2812,
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
289
src/main.c
289
src/main.c
@@ -3,51 +3,47 @@
|
||||
* 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
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
* Affero 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/>.
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
// Pico
|
||||
|
||||
#include "picokeys.h"
|
||||
#include "button.h"
|
||||
#if !defined(ENABLE_EMULATION)
|
||||
#include "tusb.h"
|
||||
#endif
|
||||
#if defined(ENABLE_EMULATION)
|
||||
#include "emulation.h"
|
||||
#elif defined(ESP_PLATFORM)
|
||||
#include "tusb.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "rom/gpio.h"
|
||||
#include "tinyusb.h"
|
||||
#include "esp_efuse.h"
|
||||
#define BOOT_PIN GPIO_NUM_0
|
||||
#else
|
||||
#include "pico/stdlib.h"
|
||||
#elif defined(PICO_PLATFORM)
|
||||
#include "bsp/board.h"
|
||||
#include "pico/aon_timer.h"
|
||||
#include "hardware/gpio.h"
|
||||
#include "hardware/sync.h"
|
||||
#include "hardware/structs/ioqspi.h"
|
||||
#include "hardware/structs/sio.h"
|
||||
#include "pico/stdio.h"
|
||||
#endif
|
||||
|
||||
#include "random.h"
|
||||
#include "pico_keys.h"
|
||||
#include "hwrng.h"
|
||||
#include "apdu.h"
|
||||
#include "usb.h"
|
||||
extern void do_flash();
|
||||
extern void low_flash_init();
|
||||
extern void init_otp_files();
|
||||
#include "flash.h"
|
||||
#include "otp.h"
|
||||
#include "led/led.h"
|
||||
#include "pico_time.h"
|
||||
#include "serial.h"
|
||||
#include "mbedtls/sha256.h"
|
||||
|
||||
app_t apps[8];
|
||||
app_t apps[16];
|
||||
uint8_t num_apps = 0;
|
||||
|
||||
app_t *current_app = NULL;
|
||||
@@ -55,11 +51,8 @@ app_t *current_app = NULL;
|
||||
const uint8_t *ccid_atr = NULL;
|
||||
|
||||
bool app_exists(const uint8_t *aid, size_t aid_len) {
|
||||
if (current_app && current_app->aid && (current_app->aid + 1 == aid || !memcmp(current_app->aid + 1, aid, aid_len))) {
|
||||
return true;
|
||||
}
|
||||
for (int a = 0; a < num_apps; a++) {
|
||||
if (!memcmp(apps[a].aid + 1, aid, MIN(aid_len, apps[a].aid[0]))) {
|
||||
if (aid_len >= apps[a].aid[0] && !memcmp(apps[a].aid + 1, aid, apps[a].aid[0])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -80,233 +73,82 @@ int register_app(int (*select_aid)(app_t *, uint8_t), const uint8_t *aid) {
|
||||
}
|
||||
|
||||
int select_app(const uint8_t *aid, size_t aid_len) {
|
||||
if (current_app && current_app->aid && (current_app->aid + 1 == aid || !memcmp(current_app->aid + 1, aid, aid_len))) {
|
||||
if (current_app && current_app->aid && (current_app->aid + 1 == aid || (aid_len >= current_app->aid[0] && !memcmp(current_app->aid + 1, aid, current_app->aid[0])))) {
|
||||
current_app->select_aid(current_app, 0);
|
||||
return PICOKEY_OK;
|
||||
return PICOKEYS_OK;
|
||||
}
|
||||
for (int a = 0; a < num_apps; a++) {
|
||||
if (!memcmp(apps[a].aid + 1, aid, MIN(aid_len, apps[a].aid[0]))) {
|
||||
if (aid_len >= apps[a].aid[0] && !memcmp(apps[a].aid + 1, aid, apps[a].aid[0])) {
|
||||
if (current_app) {
|
||||
if (current_app->aid && !memcmp(current_app->aid + 1, aid, aid_len)) {
|
||||
if (current_app->aid && aid_len >= current_app->aid[0] && !memcmp(current_app->aid + 1, aid, current_app->aid[0])) {
|
||||
current_app->select_aid(current_app, 1);
|
||||
return PICOKEY_OK;
|
||||
return PICOKEYS_OK;
|
||||
}
|
||||
if (current_app->unload) {
|
||||
current_app->unload();
|
||||
}
|
||||
}
|
||||
current_app = &apps[a];
|
||||
if (current_app->select_aid(current_app, 1) == PICOKEY_OK) {
|
||||
return PICOKEY_OK;
|
||||
if (current_app->select_aid(current_app, 1) == PICOKEYS_OK) {
|
||||
return PICOKEYS_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
return PICOKEY_ERR_FILE_NOT_FOUND;
|
||||
return PICOKEYS_ERR_FILE_NOT_FOUND;
|
||||
}
|
||||
|
||||
int (*button_pressed_cb)(uint8_t) = NULL;
|
||||
|
||||
void execute_tasks();
|
||||
|
||||
static bool req_button_pending = false;
|
||||
|
||||
bool is_req_button_pending() {
|
||||
return req_button_pending;
|
||||
}
|
||||
|
||||
bool cancel_button = false;
|
||||
|
||||
#ifdef ENABLE_EMULATION
|
||||
#ifdef _MSC_VER
|
||||
#include <windows.h>
|
||||
struct timezone
|
||||
{
|
||||
__int32 tz_minuteswest; /* minutes W of Greenwich */
|
||||
bool tz_dsttime; /* type of dst correction */
|
||||
};
|
||||
int gettimeofday(struct timeval* tp, struct timezone* tzp)
|
||||
{
|
||||
(void)tzp;
|
||||
// Note: some broken versions only have 8 trailing zero's, the correct epoch has 9 trailing zero's
|
||||
// This magic number is the number of 100 nanosecond intervals since January 1, 1601 (UTC)
|
||||
// until 00:00:00 January 1, 1970
|
||||
static const uint64_t EPOCH = ((uint64_t)116444736000000000ULL);
|
||||
|
||||
SYSTEMTIME system_time;
|
||||
FILETIME file_time;
|
||||
uint64_t time;
|
||||
|
||||
GetSystemTime(&system_time);
|
||||
SystemTimeToFileTime(&system_time, &file_time);
|
||||
time = ((uint64_t)file_time.dwLowDateTime);
|
||||
time += ((uint64_t)file_time.dwHighDateTime) << 32;
|
||||
|
||||
tp->tv_sec = (long)((time - EPOCH) / 10000000L);
|
||||
tp->tv_usec = (long)(system_time.wMilliseconds * 1000);
|
||||
WEAK int picokey_init(void) {
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
#else
|
||||
#ifdef ESP_PLATFORM
|
||||
bool picok_board_button_read() {
|
||||
int boot_state = gpio_get_level(BOOT_PIN);
|
||||
return boot_state == 0;
|
||||
}
|
||||
#else
|
||||
bool __no_inline_not_in_flash_func(picok_get_bootsel_button)() {
|
||||
const uint CS_PIN_INDEX = 1;
|
||||
|
||||
// Must disable interrupts, as interrupt handlers may be in flash, and we
|
||||
// are about to temporarily disable flash access!
|
||||
uint32_t flags = save_and_disable_interrupts();
|
||||
|
||||
// Set chip select to Hi-Z
|
||||
hw_write_masked(&ioqspi_hw->io[CS_PIN_INDEX].ctrl,
|
||||
GPIO_OVERRIDE_LOW << IO_QSPI_GPIO_QSPI_SS_CTRL_OEOVER_LSB,
|
||||
IO_QSPI_GPIO_QSPI_SS_CTRL_OEOVER_BITS);
|
||||
|
||||
// Note we can't call into any sleep functions in flash right now
|
||||
for (volatile int i = 0; i < 1000; ++i);
|
||||
|
||||
// The HI GPIO registers in SIO can observe and control the 6 QSPI pins.
|
||||
// Note the button pulls the pin *low* when pressed.
|
||||
#if PICO_RP2040
|
||||
#define CS_BIT (1u << 1)
|
||||
#else
|
||||
#define CS_BIT SIO_GPIO_HI_IN_QSPI_CSN_BITS
|
||||
#endif
|
||||
bool button_state = !(sio_hw->gpio_hi_in & CS_BIT);
|
||||
|
||||
// Need to restore the state of chip select, else we are going to have a
|
||||
// bad time when we return to code in flash!
|
||||
hw_write_masked(&ioqspi_hw->io[CS_PIN_INDEX].ctrl,
|
||||
GPIO_OVERRIDE_NORMAL << IO_QSPI_GPIO_QSPI_SS_CTRL_OEOVER_LSB,
|
||||
IO_QSPI_GPIO_QSPI_SS_CTRL_OEOVER_BITS);
|
||||
|
||||
restore_interrupts(flags);
|
||||
|
||||
return button_state;
|
||||
}
|
||||
uint32_t picok_board_button_read(void)
|
||||
{
|
||||
return picok_get_bootsel_button();
|
||||
}
|
||||
#endif
|
||||
bool button_pressed_state = false;
|
||||
uint32_t button_pressed_time = 0;
|
||||
uint8_t button_press = 0;
|
||||
bool wait_button() {
|
||||
uint32_t button_timeout = 15000;
|
||||
if (phy_data.up_btn_present) {
|
||||
button_timeout = phy_data.up_btn * 1000;
|
||||
if (button_timeout == 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
uint32_t start_button = board_millis();
|
||||
bool timeout = false;
|
||||
cancel_button = false;
|
||||
uint32_t led_mode = led_get_mode();
|
||||
led_set_mode(MODE_BUTTON);
|
||||
req_button_pending = true;
|
||||
while (picok_board_button_read() == false && cancel_button == false) {
|
||||
execute_tasks();
|
||||
//sleep_ms(10);
|
||||
if (start_button + button_timeout < board_millis()) { /* timeout */
|
||||
timeout = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!timeout) {
|
||||
while (picok_board_button_read() == true && cancel_button == false) {
|
||||
execute_tasks();
|
||||
//sleep_ms(10);
|
||||
if (start_button + 15000 < board_millis()) { /* timeout */
|
||||
timeout = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
led_set_mode(led_mode);
|
||||
req_button_pending = false;
|
||||
return timeout || cancel_button;
|
||||
}
|
||||
#endif
|
||||
|
||||
struct apdu apdu;
|
||||
|
||||
void init_rtc() {
|
||||
#ifdef PICO_PLATFORM
|
||||
struct timespec tv = {0};
|
||||
tv.tv_sec = 1577836800; // 2020-01-01
|
||||
aon_timer_start(&tv);
|
||||
#endif
|
||||
}
|
||||
|
||||
extern void neug_task();
|
||||
extern void usb_task();
|
||||
void execute_tasks()
|
||||
{
|
||||
void execute_tasks(void);
|
||||
void execute_tasks(void) {
|
||||
#if !defined(ENABLE_EMULATION) && !defined(ESP_PLATFORM)
|
||||
tud_task(); // tinyusb device task
|
||||
#endif
|
||||
#ifdef USB_ITF_LWIP
|
||||
#if !defined(ENABLE_EMULATION)
|
||||
service_traffic();
|
||||
#endif
|
||||
rest_task();
|
||||
#endif
|
||||
usb_task();
|
||||
led_blinking_task();
|
||||
}
|
||||
|
||||
void core0_loop() {
|
||||
static void core0_loop(void *arg) {
|
||||
(void)arg;
|
||||
#if defined(ESP_PLATFORM) && defined(USB_ITF_LWIP)
|
||||
if (ITF_LWIP_TOTAL > 0) {
|
||||
lwip_itf_init();
|
||||
}
|
||||
#endif
|
||||
while (1) {
|
||||
execute_tasks();
|
||||
neug_task();
|
||||
do_flash();
|
||||
#ifndef ENABLE_EMULATION
|
||||
if (button_pressed_cb && board_millis() > 1000 && !is_busy()) { // wait 1 second to boot up
|
||||
bool current_button_state = picok_board_button_read();
|
||||
if (current_button_state != button_pressed_state) {
|
||||
if (current_button_state == false) { // unpressed
|
||||
if (button_pressed_time == 0 || button_pressed_time + 1000 > board_millis()) {
|
||||
button_press++;
|
||||
}
|
||||
button_pressed_time = board_millis();
|
||||
}
|
||||
button_pressed_state = current_button_state;
|
||||
}
|
||||
if (button_pressed_time > 0 && button_press > 0 && button_pressed_time + 1000 < board_millis() && button_pressed_state == false) {
|
||||
if (button_pressed_cb != NULL) {
|
||||
(*button_pressed_cb)(button_press);
|
||||
}
|
||||
button_pressed_time = button_press = 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
hwrng_task();
|
||||
flash_task();
|
||||
button_task();
|
||||
#ifdef ESP_PLATFORM
|
||||
vTaskDelay(pdMS_TO_TICKS(10));
|
||||
vTaskDelay(pdMS_TO_TICKS(10));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
char pico_serial_str[2 * PICO_UNIQUE_BOARD_ID_SIZE_BYTES + 1];
|
||||
pico_unique_board_id_t pico_serial;
|
||||
#ifdef ESP_PLATFORM
|
||||
#define pico_get_unique_board_id(a) do { uint32_t value; esp_efuse_read_block(EFUSE_BLK1, &value, 0, 32); memcpy((uint8_t *)(a), &value, sizeof(uint32_t)); esp_efuse_read_block(EFUSE_BLK1, &value, 32, 32); memcpy((uint8_t *)(a)+4, &value, sizeof(uint32_t)); } while(0)
|
||||
extern tinyusb_config_t tusb_cfg;
|
||||
extern const uint8_t desc_config[];
|
||||
extern char *string_desc_arr[];
|
||||
extern char *string_desc_itf[];
|
||||
TaskHandle_t hcore0 = NULL, hcore1 = NULL;
|
||||
int app_main() {
|
||||
int app_main(void) {
|
||||
#else
|
||||
#ifdef ENABLE_EMULATION
|
||||
#define pico_get_unique_board_id(a) memset(a, 0, sizeof(*(a)))
|
||||
#endif
|
||||
int main(void) {
|
||||
#endif
|
||||
pico_get_unique_board_id(&pico_serial);
|
||||
memset(pico_serial_str, 0, sizeof(pico_serial_str));
|
||||
for (int i = 0; i < sizeof(pico_serial); i++) {
|
||||
snprintf(&pico_serial_str[2 * i], 3, "%02X", pico_serial.id[i]);
|
||||
}
|
||||
serial_init();
|
||||
|
||||
#ifndef ENABLE_EMULATION
|
||||
#ifndef ESP_PLATFORM
|
||||
#ifdef PICO_PLATFORM
|
||||
board_init();
|
||||
stdio_init_all();
|
||||
#endif
|
||||
@@ -317,11 +159,11 @@ int main(void) {
|
||||
|
||||
random_init();
|
||||
|
||||
init_otp_files();
|
||||
otp_init();
|
||||
|
||||
low_flash_init();
|
||||
|
||||
scan_flash();
|
||||
file_scan_flash();
|
||||
|
||||
init_rtc();
|
||||
|
||||
@@ -343,13 +185,16 @@ int main(void) {
|
||||
if (phy_data.usb_product_present) {
|
||||
tusb_cfg.string_descriptor[2] = phy_data.usb_product;
|
||||
}
|
||||
static char tmps[4][32];
|
||||
for (int i = 4; i < tusb_cfg.string_descriptor_count; i++) {
|
||||
strlcpy(tmps[i-4], tusb_cfg.string_descriptor[2], sizeof(tmps[0]));
|
||||
strlcat(tmps[i-4], " ", sizeof(tmps[0]));
|
||||
strlcat(tmps[i-4], tusb_cfg.string_descriptor[i], sizeof(tmps[0]));
|
||||
tusb_cfg.string_descriptor[i] = tmps[i-4];
|
||||
static char tmps[5][32];
|
||||
const int max_desc_slots = 8 - 6;
|
||||
const int itf_desc_count = ITF_TOTAL < max_desc_slots ? ITF_TOTAL : max_desc_slots;
|
||||
for (int i = 0; i < itf_desc_count; i++) {
|
||||
strlcpy(tmps[i], tusb_cfg.string_descriptor[2], sizeof(tmps[0]));
|
||||
strlcat(tmps[i], " ", sizeof(tmps[0]));
|
||||
strlcat(tmps[i], string_desc_itf[i], sizeof(tmps[0]));
|
||||
tusb_cfg.string_descriptor[i+6] = tmps[i];
|
||||
}
|
||||
tusb_cfg.string_descriptor_count = 6 + itf_desc_count;
|
||||
tusb_cfg.configuration_descriptor = desc_config;
|
||||
|
||||
tinyusb_driver_install(&tusb_cfg);
|
||||
@@ -358,10 +203,14 @@ int main(void) {
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef ENABLE_EMULATION
|
||||
picokey_init();
|
||||
#endif
|
||||
|
||||
#ifdef ESP_PLATFORM
|
||||
xTaskCreatePinnedToCore(core0_loop, "core0", 4096*ITF_TOTAL*2, NULL, CONFIG_TINYUSB_TASK_PRIORITY - 1, &hcore0, ESP32_CORE0);
|
||||
#else
|
||||
core0_loop();
|
||||
core0_loop(NULL);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
|
||||
39
src/otp/otp.c
Normal file
39
src/otp/otp.c
Normal file
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
|
||||
* Copyright (c) 2022 Pol Henarejos.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "otp.h"
|
||||
#include "otp_platform.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
const uint8_t *otp_key_1 = NULL;
|
||||
const uint8_t *otp_key_2 = NULL;
|
||||
|
||||
int otp_enable_secure_boot(uint8_t bootkey, bool secure_lock) {
|
||||
return otp_platform_enable_secure_boot(bootkey, secure_lock);
|
||||
}
|
||||
|
||||
bool otp_is_secure_boot_enabled(uint8_t *bootkey) {
|
||||
return otp_platform_is_secure_boot_enabled(bootkey);
|
||||
}
|
||||
|
||||
bool otp_is_secure_boot_locked(void) {
|
||||
return otp_platform_is_secure_boot_locked();
|
||||
}
|
||||
|
||||
void otp_init(void) {
|
||||
otp_platform_init(&otp_key_1, &otp_key_2);
|
||||
}
|
||||
33
src/otp/otp.h
Normal file
33
src/otp/otp.h
Normal file
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
|
||||
* Copyright (c) 2022 Pol Henarejos.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _OTP_H_
|
||||
#define _OTP_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
extern int otp_enable_secure_boot(uint8_t bootkey, bool secure_lock);
|
||||
extern void otp_init(void);
|
||||
|
||||
extern bool otp_is_secure_boot_enabled(uint8_t *bootkey);
|
||||
extern bool otp_is_secure_boot_locked(void);
|
||||
|
||||
extern const uint8_t *otp_key_1;
|
||||
extern const uint8_t *otp_key_2;
|
||||
|
||||
#endif // _OTP_H_
|
||||
47
src/otp/otp_emulation.c
Normal file
47
src/otp/otp_emulation.c
Normal file
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
|
||||
* Copyright (c) 2022 Pol Henarejos.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "picokeys.h"
|
||||
#include "otp_platform.h"
|
||||
|
||||
int otp_platform_enable_secure_boot(uint8_t bootkey, bool secure_lock) {
|
||||
(void)bootkey;
|
||||
(void)secure_lock;
|
||||
return PICOKEYS_OK;
|
||||
}
|
||||
|
||||
bool otp_platform_is_secure_boot_enabled(uint8_t *bootkey) {
|
||||
(void)bootkey;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool otp_platform_is_secure_boot_locked(void) {
|
||||
return false;
|
||||
}
|
||||
|
||||
void otp_platform_init(const uint8_t **otp_key_1_out, const uint8_t **otp_key_2_out) {
|
||||
static uint8_t _otp1[32] = {0};
|
||||
static uint8_t _otp2[32] = {0};
|
||||
|
||||
memset(_otp1, 0xAC, sizeof(_otp1));
|
||||
memset(_otp2, 0xBE, sizeof(_otp2));
|
||||
|
||||
*otp_key_1_out = _otp1;
|
||||
*otp_key_2_out = _otp2;
|
||||
}
|
||||
341
src/otp/otp_esp32.c
Normal file
341
src/otp/otp_esp32.c
Normal file
@@ -0,0 +1,341 @@
|
||||
/*
|
||||
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
|
||||
* Copyright (c) 2022 Pol Henarejos.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "picokeys.h"
|
||||
#include "otp.h"
|
||||
#include "otp_platform.h"
|
||||
|
||||
#include "random.h"
|
||||
#include "mbedtls/ecdsa.h"
|
||||
|
||||
#include "esp_efuse.h"
|
||||
#include "esp_efuse_table.h"
|
||||
|
||||
#define OTP_KEY_1 EFUSE_BLK_KEY3
|
||||
#define OTP_KEY_2 EFUSE_BLK_KEY4
|
||||
|
||||
uint8_t _otp_key_1[32] = {0};
|
||||
uint8_t _otp_key_2[32] = {0};
|
||||
|
||||
static const uint8_t esp_secure_boot_digest[32] = {
|
||||
0x0c, 0x1e, 0xce, 0xf3, 0xb4, 0x8f, 0x4a, 0x81,
|
||||
0x45, 0x6c, 0x85, 0x39, 0x15, 0xcc, 0x05, 0x36,
|
||||
0xbe, 0x23, 0x24, 0xee, 0xac, 0x8e, 0x3b, 0xb5,
|
||||
0x77, 0x6f, 0x2d, 0xb9, 0x62, 0x38, 0x75, 0x6a
|
||||
};
|
||||
|
||||
#ifndef SECURE_BOOT_BOOTKEY_INDEX
|
||||
#define SECURE_BOOT_BOOTKEY_INDEX 0
|
||||
#endif
|
||||
#ifndef PICOKEYS_REQUIRE_SECURE_BOOT_BEFORE_LOCK
|
||||
#define PICOKEYS_REQUIRE_SECURE_BOOT_BEFORE_LOCK 1
|
||||
#endif
|
||||
|
||||
static esp_efuse_purpose_t esp_secure_boot_purpose(uint8_t digest_idx) {
|
||||
switch (digest_idx) {
|
||||
case 0: return ESP_EFUSE_KEY_PURPOSE_SECURE_BOOT_DIGEST0;
|
||||
case 1: return ESP_EFUSE_KEY_PURPOSE_SECURE_BOOT_DIGEST1;
|
||||
case 2: return ESP_EFUSE_KEY_PURPOSE_SECURE_BOOT_DIGEST2;
|
||||
default: return ESP_EFUSE_KEY_PURPOSE_MAX;
|
||||
}
|
||||
}
|
||||
|
||||
static bool esp_find_secure_boot_block(uint8_t digest_idx, esp_efuse_block_t *out_block) {
|
||||
esp_efuse_purpose_t purpose = esp_secure_boot_purpose(digest_idx);
|
||||
if (purpose == ESP_EFUSE_KEY_PURPOSE_MAX) {
|
||||
return false;
|
||||
}
|
||||
for (esp_efuse_block_t blk = EFUSE_BLK_KEY0; blk < EFUSE_BLK_KEY_MAX; blk++) {
|
||||
if (esp_efuse_get_key_purpose(blk) == purpose) {
|
||||
if (out_block) {
|
||||
*out_block = blk;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static esp_err_t esp_provision_secure_boot_digest(uint8_t digest_idx, esp_efuse_block_t *out_block) {
|
||||
esp_efuse_purpose_t purpose = esp_secure_boot_purpose(digest_idx);
|
||||
if (purpose == ESP_EFUSE_KEY_PURPOSE_MAX) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
esp_efuse_block_t block = EFUSE_BLK_KEY_MAX;
|
||||
if (esp_find_secure_boot_block(digest_idx, &block)) {
|
||||
const esp_efuse_desc_t **key_desc = esp_efuse_get_key(block);
|
||||
if (!key_desc) {
|
||||
return ESP_FAIL;
|
||||
}
|
||||
uint8_t existing[32] = {0};
|
||||
esp_err_t err = esp_efuse_read_field_blob(key_desc, existing, sizeof(existing) * 8);
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
if (memcmp(existing, esp_secure_boot_digest, sizeof(existing)) != 0) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
if (out_block) {
|
||||
*out_block = block;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
block = esp_efuse_find_unused_key_block();
|
||||
if (block == EFUSE_BLK_KEY_MAX) {
|
||||
return ESP_ERR_NOT_FOUND;
|
||||
}
|
||||
|
||||
esp_err_t err = esp_efuse_batch_write_begin();
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
err = esp_efuse_set_key_purpose(block, purpose);
|
||||
if (err == ESP_OK) {
|
||||
const esp_efuse_desc_t **key_desc = esp_efuse_get_key(block);
|
||||
if (!key_desc) {
|
||||
err = ESP_FAIL;
|
||||
} else {
|
||||
err = esp_efuse_write_field_blob(key_desc, esp_secure_boot_digest, sizeof(esp_secure_boot_digest) * 8);
|
||||
}
|
||||
}
|
||||
|
||||
if (err == ESP_OK) {
|
||||
err = esp_efuse_batch_write_commit();
|
||||
} else {
|
||||
esp_efuse_batch_write_cancel();
|
||||
}
|
||||
|
||||
if (err == ESP_OK && out_block) {
|
||||
*out_block = block;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
static esp_err_t esp_disable_debug_interfaces(void) {
|
||||
esp_err_t err = ESP_OK;
|
||||
|
||||
#ifdef ESP_EFUSE_SOFT_DIS_JTAG
|
||||
err = esp_efuse_write_field_bit(ESP_EFUSE_SOFT_DIS_JTAG);
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
#endif
|
||||
#ifdef ESP_EFUSE_HARD_DIS_JTAG
|
||||
err = esp_efuse_write_field_bit(ESP_EFUSE_HARD_DIS_JTAG);
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
#endif
|
||||
#ifdef ESP_EFUSE_DIS_USB_JTAG
|
||||
err = esp_efuse_write_field_bit(ESP_EFUSE_DIS_USB_JTAG);
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
#endif
|
||||
#ifdef ESP_EFUSE_DIS_USB_SERIAL_JTAG
|
||||
err = esp_efuse_write_field_bit(ESP_EFUSE_DIS_USB_SERIAL_JTAG);
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
#endif
|
||||
#ifdef ESP_EFUSE_DIS_PAD_JTAG
|
||||
err = esp_efuse_write_field_bit(ESP_EFUSE_DIS_PAD_JTAG);
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
#endif
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static esp_err_t read_key_from_efuse(esp_efuse_block_t block, uint8_t *key, size_t key_len) {
|
||||
const esp_efuse_desc_t **key_desc = esp_efuse_get_key(block);
|
||||
if (!key_desc) {
|
||||
return ESP_FAIL;
|
||||
}
|
||||
return esp_efuse_read_field_blob(key_desc, key, key_len * 8);
|
||||
}
|
||||
|
||||
bool otp_platform_is_secure_boot_enabled(uint8_t *bootkey) {
|
||||
if (!esp_efuse_read_field_bit(ESP_EFUSE_SECURE_BOOT_EN)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t preferred = SECURE_BOOT_BOOTKEY_INDEX;
|
||||
if (preferred <= 2 && esp_find_secure_boot_block(preferred, NULL)
|
||||
&& !esp_efuse_get_digest_revoke(preferred)) {
|
||||
if (bootkey) {
|
||||
*bootkey = preferred;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
for (uint8_t idx = 0; idx <= 2; idx++) {
|
||||
if (esp_find_secure_boot_block(idx, NULL) && !esp_efuse_get_digest_revoke(idx)) {
|
||||
if (bootkey) {
|
||||
*bootkey = idx;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool otp_platform_is_secure_boot_locked(void) {
|
||||
uint8_t bootkey_idx = 0xFF;
|
||||
if (!otp_platform_is_secure_boot_enabled(&bootkey_idx)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (uint8_t idx = 0; idx <= 2; idx++) {
|
||||
if (idx == bootkey_idx) {
|
||||
continue;
|
||||
}
|
||||
if (!esp_efuse_get_digest_revoke(idx)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int otp_platform_enable_secure_boot(uint8_t bootkey, bool secure_lock) {
|
||||
if (bootkey > 2) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
if (secure_lock && PICOKEYS_REQUIRE_SECURE_BOOT_BEFORE_LOCK && !esp_efuse_read_field_bit(ESP_EFUSE_SECURE_BOOT_EN)) {
|
||||
printf("Secure lock requires SECURE_BOOT_EN already set. Enable secure boot first.\n");
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
esp_efuse_block_t key_block = EFUSE_BLK_KEY_MAX;
|
||||
esp_err_t err = esp_provision_secure_boot_digest(bootkey, &key_block);
|
||||
if (err != ESP_OK) {
|
||||
printf("Error provisioning secure boot digest %u [%d]\n", bootkey, err);
|
||||
return err;
|
||||
}
|
||||
|
||||
if (!esp_efuse_read_field_bit(ESP_EFUSE_SECURE_BOOT_EN)) {
|
||||
err = esp_efuse_write_field_bit(ESP_EFUSE_SECURE_BOOT_EN);
|
||||
if (err != ESP_OK) {
|
||||
printf("Error enabling secure boot [%d]\n", err);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
if (secure_lock) {
|
||||
for (uint8_t idx = 0; idx <= 2; idx++) {
|
||||
if (idx == bootkey) {
|
||||
continue;
|
||||
}
|
||||
err = esp_efuse_set_digest_revoke(idx);
|
||||
if (err != ESP_OK) {
|
||||
printf("Error revoking secure boot digest %u [%d]\n", idx, err);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
err = esp_efuse_set_key_dis_write(key_block);
|
||||
if (err != ESP_OK) {
|
||||
printf("Error setting secure boot key block read only [%d]\n", err);
|
||||
return err;
|
||||
}
|
||||
err = esp_efuse_set_keypurpose_dis_write(key_block);
|
||||
if (err != ESP_OK) {
|
||||
printf("Error setting secure boot key purpose read only [%d]\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* // Not sure if it allows future upgrades if ROM download mode is disabled, so leaving it enabled for now
|
||||
err = esp_efuse_disable_rom_download_mode();
|
||||
if (err != ESP_OK) {
|
||||
printf("Error disabling ROM download mode [%d]\n", err);
|
||||
return err;
|
||||
}
|
||||
*/
|
||||
|
||||
err = esp_disable_debug_interfaces();
|
||||
if (err != ESP_OK) {
|
||||
printf("Error disabling JTAG interfaces [%d]\n", err);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
return PICOKEYS_OK;
|
||||
}
|
||||
|
||||
void otp_platform_init(const uint8_t **otp_key_1_out, const uint8_t **otp_key_2_out) {
|
||||
esp_err_t ret = 0;
|
||||
uint16_t write_otp[2] = {0xFFFF, 0xFFFF};
|
||||
|
||||
if (esp_efuse_key_block_unused(OTP_KEY_1)) {
|
||||
uint8_t mkek[32] = {0};
|
||||
random_fill_buffer(mkek, sizeof(mkek));
|
||||
ret = esp_efuse_write_key(OTP_KEY_1, ESP_EFUSE_KEY_PURPOSE_USER, mkek, sizeof(mkek));
|
||||
if (ret != 0) {
|
||||
printf("Error writing OTP key 1 [%d]\n", ret);
|
||||
}
|
||||
mbedtls_platform_zeroize(mkek, sizeof(mkek));
|
||||
write_otp[0] = OTP_KEY_1;
|
||||
}
|
||||
ret = read_key_from_efuse(OTP_KEY_1, _otp_key_1, sizeof(_otp_key_1));
|
||||
if (ret != ESP_OK) {
|
||||
printf("Error reading OTP key 1 [%d]\n", ret);
|
||||
}
|
||||
*otp_key_1_out = _otp_key_1;
|
||||
|
||||
if (esp_efuse_key_block_unused(OTP_KEY_2)) {
|
||||
mbedtls_ecdsa_context ecdsa;
|
||||
size_t olen = 0;
|
||||
uint8_t pkey[MBEDTLS_ECP_MAX_BYTES];
|
||||
while (olen != 32) {
|
||||
mbedtls_ecdsa_init(&ecdsa);
|
||||
mbedtls_ecp_group_id ec_id = MBEDTLS_ECP_DP_SECP256K1;
|
||||
mbedtls_ecdsa_genkey(&ecdsa, ec_id, random_fill_iterator, NULL);
|
||||
mbedtls_ecp_write_key_ext(&ecdsa, &olen, pkey, sizeof(pkey));
|
||||
mbedtls_ecdsa_free(&ecdsa);
|
||||
}
|
||||
ret = esp_efuse_write_key(OTP_KEY_2, ESP_EFUSE_KEY_PURPOSE_USER, pkey, olen);
|
||||
if (ret != 0) {
|
||||
printf("Error writing OTP key 2 [%d]\n", ret);
|
||||
}
|
||||
mbedtls_platform_zeroize(pkey, sizeof(pkey));
|
||||
write_otp[1] = OTP_KEY_2;
|
||||
}
|
||||
ret = read_key_from_efuse(OTP_KEY_2, _otp_key_2, sizeof(_otp_key_2));
|
||||
if (ret != ESP_OK) {
|
||||
printf("Error reading OTP key 2 [%d]\n", ret);
|
||||
}
|
||||
*otp_key_2_out = _otp_key_2;
|
||||
|
||||
for (size_t i = 0; i < sizeof(write_otp) / sizeof(write_otp[0]); i++) {
|
||||
if (write_otp[i] != 0xFFFF) {
|
||||
ret = esp_efuse_set_key_dis_write(write_otp[i]);
|
||||
if (ret != ESP_OK) {
|
||||
printf("Error setting OTP key %d to read only [%d]\n", i, ret);
|
||||
}
|
||||
ret = esp_efuse_set_keypurpose_dis_write(write_otp[i]);
|
||||
if (ret != ESP_OK) {
|
||||
printf("Error setting OTP key %d purpose to read only [%d]\n", i, ret);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
623
src/otp/otp_linux.c
Normal file
623
src/otp/otp_linux.c
Normal file
@@ -0,0 +1,623 @@
|
||||
/*
|
||||
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
|
||||
* Copyright (c) 2022 Pol Henarejos.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <termios.h>
|
||||
|
||||
#include "picokeys.h"
|
||||
#include "otp_platform.h"
|
||||
#include "random.h"
|
||||
|
||||
#include "mbedtls/bignum.h"
|
||||
#include "mbedtls/ecp.h"
|
||||
#include "mbedtls/entropy.h"
|
||||
#include "mbedtls/ctr_drbg.h"
|
||||
#include "mbedtls/sha256.h"
|
||||
|
||||
#include <tss2/tss2_esys.h>
|
||||
#include <tss2/tss2_tctildr.h>
|
||||
|
||||
#define OTP_LINUX_DEFAULT_TPM_HANDLE "0x81010001"
|
||||
#define OTP_LINUX_DEFAULT_PEER_KEY_FILE ".config/pico-novus/otp_peer_p256.bin"
|
||||
|
||||
static int read_tpm_pin_prompt(const char *prompt, char *pin_out, size_t pin_out_size) {
|
||||
const char *pin_env = getenv("PICO_NOVUS_TPM_PIN");
|
||||
if (!pin_out || pin_out_size < 2) {
|
||||
return -1;
|
||||
}
|
||||
if (pin_env && pin_env[0] != '\0') {
|
||||
size_t n = strlen(pin_env);
|
||||
if (n >= pin_out_size) {
|
||||
return -1;
|
||||
}
|
||||
memcpy(pin_out, pin_env, n + 1);
|
||||
return 0;
|
||||
}
|
||||
if (!isatty(STDIN_FILENO)) {
|
||||
fprintf(stderr, "[otp-linux] No TTY for PIN prompt; set PICO_NOVUS_TPM_PIN\n");
|
||||
return -1;
|
||||
}
|
||||
struct termios oldt;
|
||||
struct termios newt;
|
||||
if (tcgetattr(STDIN_FILENO, &oldt) != 0) {
|
||||
return -1;
|
||||
}
|
||||
newt = oldt;
|
||||
newt.c_lflag &= ~(ECHO);
|
||||
fprintf(stderr, "%s", prompt ? prompt : "Enter TPM key PIN: ");
|
||||
fflush(stderr);
|
||||
if (tcsetattr(STDIN_FILENO, TCSANOW, &newt) != 0) {
|
||||
return -1;
|
||||
}
|
||||
if (!fgets(pin_out, (int)pin_out_size, stdin)) {
|
||||
tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
|
||||
fprintf(stderr, "\n");
|
||||
return -1;
|
||||
}
|
||||
tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
|
||||
fprintf(stderr, "\n");
|
||||
{
|
||||
size_t n = strlen(pin_out);
|
||||
if (n > 0 && pin_out[n - 1] == '\n') {
|
||||
pin_out[n - 1] = '\0';
|
||||
}
|
||||
}
|
||||
return (pin_out[0] != '\0') ? 0 : -1;
|
||||
}
|
||||
|
||||
static int derive_secp256k1_privkey_from_secret(const uint8_t *secret, size_t secret_len, uint8_t out_key32[32]) {
|
||||
int rc = -1;
|
||||
uint8_t digest[32];
|
||||
const uint8_t label[] = "pico-novus/se-ecdh-to-k1-v1";
|
||||
mbedtls_ecp_group grp;
|
||||
mbedtls_mpi x, n_minus_1;
|
||||
|
||||
if (!secret || secret_len == 0 || !out_key32) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
mbedtls_sha256_context sha;
|
||||
mbedtls_sha256_init(&sha);
|
||||
mbedtls_sha256_starts(&sha, 0);
|
||||
mbedtls_sha256_update(&sha, label, sizeof(label) - 1);
|
||||
mbedtls_sha256_update(&sha, secret, secret_len);
|
||||
mbedtls_sha256_finish(&sha, digest);
|
||||
mbedtls_sha256_free(&sha);
|
||||
|
||||
mbedtls_ecp_group_init(&grp);
|
||||
mbedtls_mpi_init(&x);
|
||||
mbedtls_mpi_init(&n_minus_1);
|
||||
|
||||
if (mbedtls_ecp_group_load(&grp, MBEDTLS_ECP_DP_SECP256K1) != 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
if (mbedtls_mpi_read_binary(&x, digest, sizeof(digest)) != 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
if (mbedtls_mpi_copy(&n_minus_1, &grp.N) != 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
if (mbedtls_mpi_sub_int(&n_minus_1, &n_minus_1, 1) != 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
if (mbedtls_mpi_mod_mpi(&x, &x, &n_minus_1) != 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
if (mbedtls_mpi_add_int(&x, &x, 1) != 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
if (mbedtls_mpi_write_binary(&x, out_key32, 32) != 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
rc = 0;
|
||||
|
||||
cleanup:
|
||||
mbedtls_mpi_free(&n_minus_1);
|
||||
mbedtls_mpi_free(&x);
|
||||
mbedtls_ecp_group_free(&grp);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int ensure_parent_dir(const char *path) {
|
||||
char tmp[512];
|
||||
char *slash;
|
||||
|
||||
if (!path || strlen(path) >= sizeof(tmp)) {
|
||||
return -1;
|
||||
}
|
||||
strncpy(tmp, path, sizeof(tmp) - 1);
|
||||
tmp[sizeof(tmp) - 1] = '\0';
|
||||
|
||||
slash = strrchr(tmp, '/');
|
||||
if (!slash) {
|
||||
return 0;
|
||||
}
|
||||
*slash = '\0';
|
||||
if (tmp[0] == '\0') {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (mkdir(tmp, 0700) == 0 || errno == EEXIST) {
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int random_fill_buffer_rng(void *ctx, unsigned char *output, size_t output_len) {
|
||||
(void)ctx;
|
||||
random_fill_buffer(output, output_len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int is_valid_p256_privkey(const uint8_t priv32[32]) {
|
||||
int ok = 0;
|
||||
mbedtls_ecp_group grp;
|
||||
mbedtls_mpi d;
|
||||
|
||||
mbedtls_ecp_group_init(&grp);
|
||||
mbedtls_mpi_init(&d);
|
||||
|
||||
if (mbedtls_ecp_group_load(&grp, MBEDTLS_ECP_DP_SECP256R1) != 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
if (mbedtls_mpi_read_binary(&d, priv32, 32) != 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
if (mbedtls_mpi_cmp_int(&d, 1) < 0 || mbedtls_mpi_cmp_mpi(&d, &grp.N) >= 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
ok = 1;
|
||||
|
||||
cleanup:
|
||||
mbedtls_mpi_free(&d);
|
||||
mbedtls_ecp_group_free(&grp);
|
||||
return ok;
|
||||
}
|
||||
|
||||
static int generate_valid_p256_privkey(uint8_t out_priv32[32]) {
|
||||
int rc = -1;
|
||||
mbedtls_ecp_group grp;
|
||||
mbedtls_mpi d;
|
||||
|
||||
mbedtls_ecp_group_init(&grp);
|
||||
mbedtls_mpi_init(&d);
|
||||
|
||||
if (mbedtls_ecp_group_load(&grp, MBEDTLS_ECP_DP_SECP256R1) != 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
if (mbedtls_ecp_gen_privkey(&grp, &d, random_fill_buffer_rng, NULL) != 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
if (mbedtls_mpi_write_binary(&d, out_priv32, 32) != 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
rc = 0;
|
||||
|
||||
cleanup:
|
||||
mbedtls_mpi_free(&d);
|
||||
mbedtls_ecp_group_free(&grp);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int load_or_create_peer_p256_privkey(uint8_t out_priv32[32]) {
|
||||
int rc = -1;
|
||||
FILE *fp = NULL;
|
||||
const char *custom = getenv("PICO_NOVUS_PEER_KEY_FILE");
|
||||
const char *home = getenv("HOME");
|
||||
char path[512];
|
||||
|
||||
if (custom && custom[0] != '\0') {
|
||||
strncpy(path, custom, sizeof(path) - 1);
|
||||
path[sizeof(path) - 1] = '\0';
|
||||
}
|
||||
else if (home && home[0] != '\0') {
|
||||
if (snprintf(path, sizeof(path), "%s/%s", home, OTP_LINUX_DEFAULT_PEER_KEY_FILE) >= (int)sizeof(path)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (snprintf(path, sizeof(path), "%s", OTP_LINUX_DEFAULT_PEER_KEY_FILE) >= (int)sizeof(path)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
fp = fopen(path, "rb");
|
||||
if (fp) {
|
||||
size_t n = fread(out_priv32, 1, 32, fp);
|
||||
fclose(fp);
|
||||
if (n == 32 && is_valid_p256_privkey(out_priv32)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (generate_valid_p256_privkey(out_priv32) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ensure_parent_dir(path) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
fp = fopen(path, "wb");
|
||||
if (!fp) {
|
||||
return -1;
|
||||
}
|
||||
if (fwrite(out_priv32, 1, 32, fp) != 32) {
|
||||
fclose(fp);
|
||||
return -1;
|
||||
}
|
||||
fclose(fp);
|
||||
chmod(path, 0600);
|
||||
|
||||
rc = 0;
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int peer_priv_to_pub_point(const uint8_t priv32[32], TPM2B_ECC_POINT *pub_out) {
|
||||
int rc = -1;
|
||||
mbedtls_ecp_group grp;
|
||||
mbedtls_mpi d;
|
||||
mbedtls_ecp_point q;
|
||||
uint8_t x[32] = {0};
|
||||
uint8_t y[32] = {0};
|
||||
|
||||
if (!priv32 || !pub_out) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
mbedtls_ecp_group_init(&grp);
|
||||
mbedtls_mpi_init(&d);
|
||||
mbedtls_ecp_point_init(&q);
|
||||
|
||||
if (mbedtls_ecp_group_load(&grp, MBEDTLS_ECP_DP_SECP256R1) != 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
if (mbedtls_mpi_read_binary(&d, priv32, 32) != 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (!is_valid_p256_privkey(priv32)) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (mbedtls_ecp_mul(&grp, &q, &d, &grp.G, random_fill_buffer_rng, NULL) != 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
if (mbedtls_mpi_write_binary(&q.X, x, sizeof(x)) != 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
if (mbedtls_mpi_write_binary(&q.Y, y, sizeof(y)) != 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
memset(pub_out, 0, sizeof(*pub_out));
|
||||
pub_out->point.x.size = sizeof(x);
|
||||
memcpy(pub_out->point.x.buffer, x, sizeof(x));
|
||||
pub_out->point.y.size = sizeof(y);
|
||||
memcpy(pub_out->point.y.buffer, y, sizeof(y));
|
||||
|
||||
rc = 0;
|
||||
|
||||
cleanup:
|
||||
mbedtls_ecp_point_free(&q);
|
||||
mbedtls_mpi_free(&d);
|
||||
mbedtls_ecp_group_free(&grp);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int load_or_create_tpm_p256_key(ESYS_CONTEXT *esys, TPM2_HANDLE handle, const char *pin, ESYS_TR *key_out, int *created_out) {
|
||||
TSS2_RC rc;
|
||||
ESYS_TR key = ESYS_TR_NONE;
|
||||
ESYS_TR transient = ESYS_TR_NONE;
|
||||
ESYS_TR persisted = ESYS_TR_NONE;
|
||||
TPM2B_PUBLIC in_public = {0};
|
||||
TPM2B_SENSITIVE_CREATE in_sensitive = {0};
|
||||
TPM2B_DATA outside_info = {0};
|
||||
TPML_PCR_SELECTION creation_pcr = {0};
|
||||
TPM2B_PUBLIC *out_public = NULL;
|
||||
TPM2B_CREATION_DATA *creation_data = NULL;
|
||||
TPM2B_DIGEST *creation_hash = NULL;
|
||||
TPMT_TK_CREATION *creation_ticket = NULL;
|
||||
TPMS_CAPABILITY_DATA *cap_data = NULL;
|
||||
TPMI_YES_NO more_data = TPM2_NO;
|
||||
TPM2B_AUTH auth = {0};
|
||||
|
||||
if (!esys || !key_out) {
|
||||
return -1;
|
||||
}
|
||||
*key_out = ESYS_TR_NONE;
|
||||
if (created_out) {
|
||||
*created_out = 0;
|
||||
}
|
||||
if (pin && pin[0] != '\0') {
|
||||
size_t pin_len = strlen(pin);
|
||||
if (pin_len > sizeof(auth.buffer)) {
|
||||
return -1;
|
||||
}
|
||||
auth.size = (UINT16)pin_len;
|
||||
memcpy(auth.buffer, pin, pin_len);
|
||||
}
|
||||
|
||||
rc = Esys_GetCapability(esys, ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE, TPM2_CAP_HANDLES, handle, 1, &more_data, &cap_data);
|
||||
if (rc != TSS2_RC_SUCCESS) {
|
||||
fprintf(stderr, "[otp-linux] Esys_GetCapability failed while checking key handle: 0x%x\n", rc);
|
||||
goto cleanup;
|
||||
}
|
||||
if (cap_data && cap_data->data.handles.count > 0 && cap_data->data.handles.handle[0] == handle) {
|
||||
rc = Esys_TR_FromTPMPublic(esys, handle, ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE, &key);
|
||||
if (rc != TSS2_RC_SUCCESS) {
|
||||
fprintf(stderr, "[otp-linux] Esys_TR_FromTPMPublic failed for existing key: 0x%x\n", rc);
|
||||
goto cleanup;
|
||||
}
|
||||
if (auth.size > 0) {
|
||||
rc = Esys_TR_SetAuth(esys, key, &auth);
|
||||
if (rc != TSS2_RC_SUCCESS) {
|
||||
Esys_TR_Close(esys, &key);
|
||||
key = ESYS_TR_NONE;
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
*key_out = key;
|
||||
key = ESYS_TR_NONE;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
in_public.publicArea.type = TPM2_ALG_ECC;
|
||||
in_public.publicArea.nameAlg = TPM2_ALG_SHA256;
|
||||
in_public.publicArea.objectAttributes = TPMA_OBJECT_USERWITHAUTH | TPMA_OBJECT_DECRYPT | TPMA_OBJECT_FIXEDTPM | TPMA_OBJECT_FIXEDPARENT | TPMA_OBJECT_SENSITIVEDATAORIGIN;
|
||||
in_public.publicArea.parameters.eccDetail.symmetric.algorithm = TPM2_ALG_NULL;
|
||||
in_public.publicArea.parameters.eccDetail.scheme.scheme = TPM2_ALG_NULL;
|
||||
in_public.publicArea.parameters.eccDetail.curveID = TPM2_ECC_NIST_P256;
|
||||
in_public.publicArea.parameters.eccDetail.kdf.scheme = TPM2_ALG_NULL;
|
||||
|
||||
if (auth.size > 0) {
|
||||
in_sensitive.sensitive.userAuth = auth;
|
||||
}
|
||||
rc = Esys_CreatePrimary(esys, ESYS_TR_RH_OWNER, ESYS_TR_PASSWORD, ESYS_TR_NONE, ESYS_TR_NONE, &in_sensitive, &in_public, &outside_info, &creation_pcr, &transient, &out_public, &creation_data, &creation_hash, &creation_ticket);
|
||||
if (rc != TSS2_RC_SUCCESS || transient == ESYS_TR_NONE) {
|
||||
fprintf(stderr, "[otp-linux] Esys_CreatePrimary failed while provisioning TPM key: 0x%x\n", rc);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
rc = Esys_EvictControl(esys, ESYS_TR_RH_OWNER, transient, ESYS_TR_PASSWORD, ESYS_TR_NONE, ESYS_TR_NONE, handle, &persisted);
|
||||
if (rc != TSS2_RC_SUCCESS) {
|
||||
/* If another process persisted it first, try to load the handle again. */
|
||||
ESYS_TR retry = ESYS_TR_NONE;
|
||||
rc = Esys_TR_FromTPMPublic(esys, handle, ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE, &retry);
|
||||
if (rc == TSS2_RC_SUCCESS) {
|
||||
*key_out = retry;
|
||||
goto cleanup;
|
||||
}
|
||||
fprintf(stderr, "[otp-linux] Esys_EvictControl failed while provisioning TPM key: 0x%x\n", rc);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (persisted != ESYS_TR_NONE) {
|
||||
Esys_TR_Close(esys, &persisted);
|
||||
persisted = ESYS_TR_NONE;
|
||||
}
|
||||
rc = Esys_TR_FromTPMPublic(esys, handle, ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE, key_out);
|
||||
if (rc != TSS2_RC_SUCCESS) {
|
||||
fprintf(stderr, "[otp-linux] Persisted key created but reload failed: 0x%x\n", rc);
|
||||
*key_out = ESYS_TR_NONE;
|
||||
goto cleanup;
|
||||
}
|
||||
if (auth.size > 0) {
|
||||
rc = Esys_TR_SetAuth(esys, *key_out, &auth);
|
||||
if (rc != TSS2_RC_SUCCESS) {
|
||||
Esys_TR_Close(esys, key_out);
|
||||
*key_out = ESYS_TR_NONE;
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
if (created_out) {
|
||||
*created_out = 1;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
if (cap_data) {
|
||||
Esys_Free(cap_data);
|
||||
}
|
||||
if (creation_ticket) {
|
||||
Esys_Free(creation_ticket);
|
||||
}
|
||||
if (creation_hash) {
|
||||
Esys_Free(creation_hash);
|
||||
}
|
||||
if (creation_data) {
|
||||
Esys_Free(creation_data);
|
||||
}
|
||||
if (out_public) {
|
||||
Esys_Free(out_public);
|
||||
}
|
||||
if (persisted != ESYS_TR_NONE) {
|
||||
Esys_TR_Close(esys, &persisted);
|
||||
}
|
||||
if (transient != ESYS_TR_NONE) {
|
||||
Esys_TR_Close(esys, &transient);
|
||||
}
|
||||
return (*key_out != ESYS_TR_NONE) ? 0 : -1;
|
||||
}
|
||||
|
||||
static int linux_tpm_vault_load_or_create_key(uint8_t out_key32[32]) {
|
||||
TSS2_TCTI_CONTEXT *tcti = NULL;
|
||||
ESYS_CONTEXT *esys = NULL;
|
||||
ESYS_TR tpm_key = ESYS_TR_NONE;
|
||||
TPM2B_ECC_POINT peer_pub = {0};
|
||||
TPM2B_ECC_POINT *z_point = NULL;
|
||||
TPM2B_PUBLIC *tpm_pub = NULL;
|
||||
uint8_t peer_priv[32] = {0};
|
||||
uint8_t ecdh_secret[132] = {0};
|
||||
size_t ecdh_secret_len = 0;
|
||||
char pin[128] = {0};
|
||||
int created_now = 0;
|
||||
|
||||
int rc_out = -1;
|
||||
TSS2_RC rc;
|
||||
|
||||
const char *tcti_name = getenv("PICO_NOVUS_TCTI");
|
||||
const char *handle_hex = getenv("PICO_NOVUS_TPM_HANDLE");
|
||||
|
||||
if (!tcti_name || tcti_name[0] == '\0') {
|
||||
tcti_name = getenv("TPM2TOOLS_TCTI");
|
||||
}
|
||||
if (!handle_hex || handle_hex[0] == '\0') {
|
||||
handle_hex = OTP_LINUX_DEFAULT_TPM_HANDLE;
|
||||
}
|
||||
|
||||
if (tcti_name && tcti_name[0] != '\0') {
|
||||
rc = Tss2_TctiLdr_Initialize(tcti_name, &tcti);
|
||||
}
|
||||
else {
|
||||
rc = Tss2_TctiLdr_Initialize(NULL, &tcti);
|
||||
if (rc != TSS2_RC_SUCCESS) {
|
||||
rc = Tss2_TctiLdr_Initialize("swtpm:host=127.0.0.1,port=2321", &tcti);
|
||||
if (rc != TSS2_RC_SUCCESS) {
|
||||
rc = Tss2_TctiLdr_Initialize("mssim:host=127.0.0.1,port=2321", &tcti);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (rc != TSS2_RC_SUCCESS) {
|
||||
fprintf(stderr, "[otp-linux] Tss2_TctiLdr_Initialize failed: 0x%x\n", rc);
|
||||
goto cleanup;
|
||||
}
|
||||
rc = Esys_Initialize(&esys, tcti, NULL);
|
||||
if (rc != TSS2_RC_SUCCESS) {
|
||||
fprintf(stderr, "[otp-linux] Esys_Initialize failed: 0x%x\n", rc);
|
||||
goto cleanup;
|
||||
}
|
||||
unsigned long handle_num = strtoul(handle_hex, NULL, 0);
|
||||
if (read_tpm_pin_prompt("Enter or set TPM key PIN: ", pin, sizeof(pin)) != 0) {
|
||||
fprintf(stderr, "[otp-linux] PIN is required to unlock/provision TPM key\n");
|
||||
goto cleanup;
|
||||
}
|
||||
if (load_or_create_tpm_p256_key(esys, (TPM2_HANDLE)handle_num, pin, &tpm_key, &created_now) != 0) {
|
||||
fprintf(stderr, "[otp-linux] Cannot load/create persistent TPM key at handle: %s\n", handle_hex);
|
||||
goto cleanup;
|
||||
}
|
||||
if (created_now && !getenv("PICO_NOVUS_TPM_PIN") && isatty(STDIN_FILENO)) {
|
||||
char confirm[128] = {0};
|
||||
if (read_tpm_pin_prompt("Confirm TPM key PIN: ", confirm, sizeof(confirm)) != 0 || strcmp(pin, confirm) != 0) {
|
||||
fprintf(stderr, "[otp-linux] PIN confirmation mismatch\n");
|
||||
memset(confirm, 0, sizeof(confirm));
|
||||
goto cleanup;
|
||||
}
|
||||
memset(confirm, 0, sizeof(confirm));
|
||||
}
|
||||
|
||||
rc = Esys_ReadPublic(esys, tpm_key, ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE, &tpm_pub, NULL, NULL);
|
||||
if (rc != TSS2_RC_SUCCESS || !tpm_pub) {
|
||||
fprintf(stderr, "[otp-linux] Esys_ReadPublic failed: 0x%x\n", rc);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (tpm_pub->publicArea.type != TPM2_ALG_ECC || tpm_pub->publicArea.parameters.eccDetail.curveID != TPM2_ECC_NIST_P256) {
|
||||
fprintf(stderr, "[otp-linux] TPM key must be ECC P-256\n");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (load_or_create_peer_p256_privkey(peer_priv) != 0) {
|
||||
fprintf(stderr, "[otp-linux] Cannot load/create software peer key\n");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (peer_priv_to_pub_point(peer_priv, &peer_pub) != 0) {
|
||||
fprintf(stderr, "[otp-linux] Cannot derive software peer public key\n");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
rc = Esys_ECDH_ZGen(esys, tpm_key, ESYS_TR_PASSWORD, ESYS_TR_NONE, ESYS_TR_NONE, &peer_pub, &z_point);
|
||||
if (rc != TSS2_RC_SUCCESS || !z_point) {
|
||||
if (rc == TPM2_RC_AUTH_FAIL || rc == TPM2_RC_BAD_AUTH) {
|
||||
fprintf(stderr, "[otp-linux] TPM key auth failed (wrong PIN?)\n");
|
||||
}
|
||||
fprintf(stderr, "[otp-linux] Esys_ECDH_ZGen failed: 0x%x\n", rc);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (z_point->point.x.size > 66 || z_point->point.y.size > 66) {
|
||||
fprintf(stderr, "[otp-linux] Unexpected ECDH point size\n");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
memcpy(ecdh_secret + ecdh_secret_len, z_point->point.x.buffer, z_point->point.x.size);
|
||||
ecdh_secret_len += z_point->point.x.size;
|
||||
memcpy(ecdh_secret + ecdh_secret_len, z_point->point.y.buffer, z_point->point.y.size);
|
||||
ecdh_secret_len += z_point->point.y.size;
|
||||
|
||||
if (derive_secp256k1_privkey_from_secret(ecdh_secret, ecdh_secret_len, out_key32) != 0) {
|
||||
fprintf(stderr, "[otp-linux] Failed deriving secp256k1 key\n");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
rc_out = 0;
|
||||
|
||||
cleanup:
|
||||
memset(pin, 0, sizeof(pin));
|
||||
if (z_point) {
|
||||
Esys_Free(z_point);
|
||||
}
|
||||
if (tpm_pub) {
|
||||
Esys_Free(tpm_pub);
|
||||
}
|
||||
if (esys) {
|
||||
if (tpm_key != ESYS_TR_NONE) {
|
||||
Esys_TR_Close(esys, &tpm_key);
|
||||
}
|
||||
Esys_Finalize(&esys);
|
||||
}
|
||||
if (tcti) {
|
||||
Tss2_TctiLdr_Finalize(&tcti);
|
||||
}
|
||||
return rc_out;
|
||||
}
|
||||
|
||||
int otp_platform_enable_secure_boot(uint8_t bootkey, bool secure_lock) {
|
||||
(void)bootkey;
|
||||
(void)secure_lock;
|
||||
return PICOKEYS_OK;
|
||||
}
|
||||
|
||||
bool otp_platform_is_secure_boot_enabled(uint8_t *bootkey) {
|
||||
(void)bootkey;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool otp_platform_is_secure_boot_locked(void) {
|
||||
return false;
|
||||
}
|
||||
|
||||
void otp_platform_init(const uint8_t **otp_key_1_out, const uint8_t **otp_key_2_out) {
|
||||
static uint8_t _otp1[32] = {0};
|
||||
static uint8_t _otp2[32] = {0};
|
||||
|
||||
memset(_otp1, 0xAC, sizeof(_otp1));
|
||||
memset(_otp2, 0xBE, sizeof(_otp2));
|
||||
|
||||
if (linux_tpm_vault_load_or_create_key(_otp2) != 0) {
|
||||
printf("[otp-linux] Warning: TPM path unavailable, using emulated otp_key_2\n");
|
||||
}
|
||||
|
||||
*otp_key_1_out = _otp1;
|
||||
*otp_key_2_out = _otp2;
|
||||
}
|
||||
273
src/otp/otp_macos.c
Normal file
273
src/otp/otp_macos.c
Normal file
@@ -0,0 +1,273 @@
|
||||
/*
|
||||
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
|
||||
* Copyright (c) 2022 Pol Henarejos.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "picokeys.h"
|
||||
#include "otp_platform.h"
|
||||
|
||||
#if defined(MACOS_APP) && MACOS_APP
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#include <Security/Security.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "mbedtls/bignum.h"
|
||||
#include "mbedtls/ecp.h"
|
||||
#include "mbedtls/sha256.h"
|
||||
|
||||
#define CF_SAFE_RELEASE(x) do { if ((x) != NULL) CFRelease(x); } while (0)
|
||||
#define SE_KEY_TAG "com.picokeys.novus.se.key"
|
||||
#define LOCAL_KEY_TAG "com.picokeys.novus.local.ecdh.key"
|
||||
|
||||
static int sec_err(const char *ctx, OSStatus st) {
|
||||
fprintf(stderr, "[macos-se] %s failed: OSStatus=%d\n", ctx, (int)st);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int derive_secp256k1_privkey_from_secret(const uint8_t *secret, size_t secret_len, uint8_t out_key32[32]) {
|
||||
int rc = -1;
|
||||
uint8_t digest[32];
|
||||
const uint8_t label[] = "pico-novus/se-ecdh-to-k1-v1";
|
||||
mbedtls_ecp_group grp;
|
||||
mbedtls_mpi x, n_minus_1;
|
||||
|
||||
if (!secret || secret_len == 0 || !out_key32) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
mbedtls_sha256_context sha;
|
||||
mbedtls_sha256_init(&sha);
|
||||
mbedtls_sha256_starts(&sha, 0);
|
||||
mbedtls_sha256_update(&sha, label, sizeof(label) - 1);
|
||||
mbedtls_sha256_update(&sha, secret, secret_len);
|
||||
mbedtls_sha256_finish(&sha, digest);
|
||||
mbedtls_sha256_free(&sha);
|
||||
|
||||
mbedtls_ecp_group_init(&grp);
|
||||
mbedtls_mpi_init(&x);
|
||||
mbedtls_mpi_init(&n_minus_1);
|
||||
|
||||
if (mbedtls_ecp_group_load(&grp, MBEDTLS_ECP_DP_SECP256K1) != 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
if (mbedtls_mpi_read_binary(&x, digest, sizeof(digest)) != 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
if (mbedtls_mpi_copy(&n_minus_1, &grp.N) != 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
if (mbedtls_mpi_sub_int(&n_minus_1, &n_minus_1, 1) != 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
if (mbedtls_mpi_mod_mpi(&x, &x, &n_minus_1) != 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
if (mbedtls_mpi_add_int(&x, &x, 1) != 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
if (mbedtls_mpi_write_binary(&x, out_key32, 32) != 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
rc = 0;
|
||||
|
||||
cleanup:
|
||||
mbedtls_mpi_free(&n_minus_1);
|
||||
mbedtls_mpi_free(&x);
|
||||
mbedtls_ecp_group_free(&grp);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int load_or_create_p256_key(const char *tag_str, bool in_secure_enclave, SecKeyRef *out_private_key) {
|
||||
SecKeyRef private_key = NULL;
|
||||
CFDataRef tag = NULL;
|
||||
CFDictionaryRef find_query = NULL;
|
||||
CFDictionaryRef priv_attrs = NULL;
|
||||
CFNumberRef key_size_num = NULL;
|
||||
CFDictionaryRef attrs = NULL;
|
||||
CFErrorRef err = NULL;
|
||||
OSStatus st;
|
||||
int rc = -1;
|
||||
|
||||
if (!tag_str || !out_private_key) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
*out_private_key = NULL;
|
||||
tag = CFDataCreate(NULL, (const UInt8 *)tag_str, (CFIndex)strlen(tag_str));
|
||||
if (!tag) {
|
||||
fprintf(stderr, "[macos-se] CFDataCreate(tag) failed\n");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
const void *find_keys[] = { kSecClass, kSecAttrApplicationTag, kSecAttrKeyType, kSecReturnRef };
|
||||
const void *find_vals[] = { kSecClassKey, tag, kSecAttrKeyTypeECSECPrimeRandom, kCFBooleanTrue };
|
||||
find_query = CFDictionaryCreate(NULL, find_keys, find_vals, 4, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
|
||||
if (!find_query) {
|
||||
fprintf(stderr, "[macos-se] CFDictionaryCreate(find_query) failed\n");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
st = SecItemCopyMatching(find_query, (CFTypeRef *)&private_key);
|
||||
if (st == errSecItemNotFound) {
|
||||
const void *priv_keys[] = { kSecAttrIsPermanent, kSecAttrApplicationTag };
|
||||
const void *priv_vals[] = { kCFBooleanTrue, tag };
|
||||
priv_attrs = CFDictionaryCreate(NULL, priv_keys, priv_vals, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
|
||||
if (!priv_attrs) {
|
||||
fprintf(stderr, "[macos-se] CFDictionaryCreate(priv_attrs) failed\n");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
int key_size = 256;
|
||||
key_size_num = CFNumberCreate(NULL, kCFNumberIntType, &key_size);
|
||||
if (!key_size_num) {
|
||||
fprintf(stderr, "[macos-se] CFNumberCreate(key_size) failed\n");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (in_secure_enclave) {
|
||||
const void *keys[] = { kSecAttrKeyType, kSecAttrKeySizeInBits, kSecAttrTokenID, kSecPrivateKeyAttrs };
|
||||
const void *vals[] = { kSecAttrKeyTypeECSECPrimeRandom, key_size_num, kSecAttrTokenIDSecureEnclave, priv_attrs };
|
||||
attrs = CFDictionaryCreate(NULL, keys, vals, 4, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
|
||||
} else {
|
||||
const void *keys[] = { kSecAttrKeyType, kSecAttrKeySizeInBits, kSecPrivateKeyAttrs };
|
||||
const void *vals[] = { kSecAttrKeyTypeECSECPrimeRandom, key_size_num, priv_attrs };
|
||||
attrs = CFDictionaryCreate(NULL, keys, vals, 3, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
|
||||
}
|
||||
if (!attrs) {
|
||||
fprintf(stderr, "[macos-se] CFDictionaryCreate(attrs) failed\n");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
private_key = SecKeyCreateRandomKey(attrs, &err);
|
||||
if (!private_key) {
|
||||
fprintf(stderr, "[macos-se] SecKeyCreateRandomKey failed\n");
|
||||
if (err) {
|
||||
CFShow(err);
|
||||
}
|
||||
goto cleanup;
|
||||
}
|
||||
printf("[macos-se] Created key '%s'%s\n", tag_str, in_secure_enclave ? " in Secure Enclave" : "");
|
||||
} else if (st != errSecSuccess) {
|
||||
sec_err("SecItemCopyMatching", st);
|
||||
goto cleanup;
|
||||
} else {
|
||||
printf("[macos-se] Using existing key '%s'\n", tag_str);
|
||||
}
|
||||
|
||||
*out_private_key = private_key;
|
||||
private_key = NULL;
|
||||
rc = 0;
|
||||
|
||||
cleanup:
|
||||
if (err) {
|
||||
CFRelease(err);
|
||||
}
|
||||
CF_SAFE_RELEASE(attrs);
|
||||
CF_SAFE_RELEASE(key_size_num);
|
||||
CF_SAFE_RELEASE(priv_attrs);
|
||||
CF_SAFE_RELEASE(find_query);
|
||||
CF_SAFE_RELEASE(tag);
|
||||
CF_SAFE_RELEASE(private_key);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int macos_se_vault_load_or_create_key(uint8_t out_key32[32]) {
|
||||
int rc = -1;
|
||||
SecKeyRef se_private_key = NULL;
|
||||
SecKeyRef local_private_key = NULL;
|
||||
SecKeyRef local_public_key = NULL;
|
||||
CFDataRef shared_secret = NULL;
|
||||
CFDictionaryRef ecdh_params = NULL;
|
||||
CFErrorRef err = NULL;
|
||||
|
||||
if (load_or_create_p256_key(SE_KEY_TAG, true, &se_private_key) != 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
if (load_or_create_p256_key(LOCAL_KEY_TAG, false, &local_private_key) != 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
local_public_key = SecKeyCopyPublicKey(local_private_key);
|
||||
if (!local_public_key) {
|
||||
fprintf(stderr, "[macos-se] SecKeyCopyPublicKey(local_private_key) failed\n");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
ecdh_params = CFDictionaryCreate(NULL, NULL, NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
|
||||
if (!ecdh_params) {
|
||||
fprintf(stderr, "[macos-se] CFDictionaryCreate(ecdh_params) failed\n");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
shared_secret = SecKeyCopyKeyExchangeResult(se_private_key, kSecKeyAlgorithmECDHKeyExchangeStandard, local_public_key, ecdh_params, &err);
|
||||
if (!shared_secret) {
|
||||
fprintf(stderr, "[macos-se] SecKeyCopyKeyExchangeResult failed\n");
|
||||
if (err) {
|
||||
CFShow(err);
|
||||
}
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (derive_secp256k1_privkey_from_secret(CFDataGetBytePtr(shared_secret), (size_t)CFDataGetLength(shared_secret), out_key32) != 0) {
|
||||
fprintf(stderr, "[macos-se] failed deriving secp256k1 private key from ECDH secret\n");
|
||||
goto cleanup;
|
||||
}
|
||||
rc = 0;
|
||||
|
||||
cleanup:
|
||||
if (err) {
|
||||
CFRelease(err);
|
||||
}
|
||||
CF_SAFE_RELEASE(ecdh_params);
|
||||
CF_SAFE_RELEASE(shared_secret);
|
||||
CF_SAFE_RELEASE(local_public_key);
|
||||
CF_SAFE_RELEASE(local_private_key);
|
||||
CF_SAFE_RELEASE(se_private_key);
|
||||
return rc;
|
||||
}
|
||||
#endif
|
||||
|
||||
int otp_platform_enable_secure_boot(uint8_t bootkey, bool secure_lock) {
|
||||
(void)bootkey;
|
||||
(void)secure_lock;
|
||||
return PICOKEYS_OK;
|
||||
}
|
||||
|
||||
bool otp_platform_is_secure_boot_enabled(uint8_t *bootkey) {
|
||||
(void)bootkey;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool otp_platform_is_secure_boot_locked(void) {
|
||||
return false;
|
||||
}
|
||||
|
||||
void otp_platform_init(const uint8_t **otp_key_1_out, const uint8_t **otp_key_2_out) {
|
||||
static uint8_t _otp1[32] = {0};
|
||||
static uint8_t _otp2[32] = {0};
|
||||
|
||||
memset(_otp1, 0xAC, sizeof(_otp1));
|
||||
memset(_otp2, 0xBE, sizeof(_otp2));
|
||||
|
||||
#if defined(MACOS_APP) && MACOS_APP
|
||||
if (macos_se_vault_load_or_create_key(_otp2) != 0) {
|
||||
printf("Warning: failed to load MACOS_APP Secure Enclave key; using dummy otp_key_2\n");
|
||||
}
|
||||
#endif
|
||||
*otp_key_1_out = _otp1;
|
||||
*otp_key_2_out = _otp2;
|
||||
}
|
||||
29
src/otp/otp_platform.h
Normal file
29
src/otp/otp_platform.h
Normal file
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
|
||||
* Copyright (c) 2022 Pol Henarejos.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _OTP_PLATFORM_H_
|
||||
#define _OTP_PLATFORM_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
int otp_platform_enable_secure_boot(uint8_t bootkey, bool secure_lock);
|
||||
bool otp_platform_is_secure_boot_enabled(uint8_t *bootkey);
|
||||
bool otp_platform_is_secure_boot_locked(void);
|
||||
void otp_platform_init(const uint8_t **otp_key_1_out, const uint8_t **otp_key_2_out);
|
||||
|
||||
#endif
|
||||
47
src/otp/otp_rp2040.c
Normal file
47
src/otp/otp_rp2040.c
Normal file
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
|
||||
* Copyright (c) 2022 Pol Henarejos.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "picokeys.h"
|
||||
#include "otp_platform.h"
|
||||
|
||||
int otp_platform_enable_secure_boot(uint8_t bootkey, bool secure_lock) {
|
||||
(void)bootkey;
|
||||
(void)secure_lock;
|
||||
return PICOKEYS_WRONG_DATA;
|
||||
}
|
||||
|
||||
bool otp_platform_is_secure_boot_enabled(uint8_t *bootkey) {
|
||||
(void)bootkey;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool otp_platform_is_secure_boot_locked(void) {
|
||||
return false;
|
||||
}
|
||||
|
||||
void otp_platform_init(const uint8_t **otp_key_1_out, const uint8_t **otp_key_2_out) {
|
||||
static uint8_t _otp1[32] = {0};
|
||||
static uint8_t _otp2[32] = {0};
|
||||
|
||||
memset(_otp1, 0xDF, sizeof(_otp1));
|
||||
memset(_otp2, 0x93, sizeof(_otp2));
|
||||
|
||||
*otp_key_1_out = _otp1;
|
||||
*otp_key_2_out = _otp2;
|
||||
}
|
||||
294
src/otp/otp_rp2350.c
Normal file
294
src/otp/otp_rp2350.c
Normal file
@@ -0,0 +1,294 @@
|
||||
/*
|
||||
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
|
||||
* Copyright (c) 2022 Pol Henarejos.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdalign.h>
|
||||
#include "picokeys.h"
|
||||
#include "otp.h"
|
||||
#include "otp_platform.h"
|
||||
|
||||
#include "pico/bootrom.h"
|
||||
#include "hardware/structs/otp.h"
|
||||
#include "hardware/regs/otp_data.h"
|
||||
|
||||
#include "random.h"
|
||||
#include "mbedtls/ecdsa.h"
|
||||
|
||||
#define OTP_OLD_MKEK_ROW 0xEF0
|
||||
#define OTP_OLD_DEVK_ROW 0xED0
|
||||
#define OTP_MKEK_ROW 0xE90
|
||||
#define OTP_DEVK_ROW 0xE80
|
||||
|
||||
#define OTP_KEY_1 OTP_MKEK_ROW
|
||||
#define OTP_KEY_2 OTP_DEVK_ROW
|
||||
|
||||
|
||||
static bool is_empty_buffer(const uint8_t *buffer, uint16_t buffer_len) {
|
||||
for (int i = 0; i < buffer_len; i++) {
|
||||
if (buffer[i] != 0x00) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static int otp_write_data_mode(uint16_t row, const uint8_t *data, uint16_t len, bool is_ecc) {
|
||||
otp_cmd_t cmd = { .flags = row | (is_ecc ? OTP_CMD_ECC_BITS : 0) | OTP_CMD_WRITE_BITS };
|
||||
uint32_t ret = rom_func_otp_access((uint8_t *)data, len, cmd);
|
||||
if (ret) {
|
||||
printf("OTP Write failed with error: %ld\n", ret);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int otp_write_data(uint16_t row, const uint8_t *data, uint16_t len) {
|
||||
return otp_write_data_mode(row, data, len, true);
|
||||
}
|
||||
|
||||
static int otp_write_data_raw(uint16_t row, const uint8_t *data, uint16_t len) {
|
||||
return otp_write_data_mode(row, data, len, false);
|
||||
}
|
||||
|
||||
static const uint8_t* otp_buffer(uint16_t row) {
|
||||
volatile uint32_t *p = ((uint32_t *)(OTP_DATA_BASE + (row*2)));
|
||||
return (const uint8_t *)p;
|
||||
}
|
||||
|
||||
static const uint8_t* otp_buffer_raw(uint16_t row) {
|
||||
volatile uint32_t *p = ((uint32_t *)(OTP_DATA_RAW_BASE + (row*4)));
|
||||
return (const uint8_t *)p;
|
||||
}
|
||||
|
||||
static bool is_empty_otp_buffer(uint16_t row, uint16_t len) {
|
||||
return is_empty_buffer(otp_buffer_raw(row), len * 2);
|
||||
}
|
||||
|
||||
static bool is_otp_locked_page(uint8_t page) {
|
||||
volatile uint32_t *p = ((uint32_t *)(OTP_DATA_BASE + ((OTP_DATA_PAGE0_LOCK0_ROW + page*2)*2)));
|
||||
return ((p[0] & 0xFFFF0000) == 0x3C3C0000 && (p[1] & 0xFF) == 0x3C);
|
||||
}
|
||||
|
||||
static void otp_lock_page(uint8_t page) {
|
||||
if (!is_otp_locked_page(page)) {
|
||||
alignas(4) uint32_t value = 0x3c3c3c;
|
||||
otp_write_data_raw(OTP_DATA_PAGE0_LOCK0_ROW + page*2 + 1, (uint8_t *)&value, sizeof(value));
|
||||
}
|
||||
|
||||
otp_hw->sw_lock[page] = 0b1100;
|
||||
}
|
||||
|
||||
static void otp_invalidate_key(uint16_t row, uint16_t len) {
|
||||
if (!is_empty_otp_buffer(row, len)) {
|
||||
uint8_t *inval = (uint8_t *)calloc(len * 2, sizeof(uint8_t));
|
||||
if (inval) {
|
||||
memset(inval, 0xFF, len * 2);
|
||||
otp_write_data_raw(row, inval, len * 2);
|
||||
mbedtls_platform_zeroize(inval, len * 2);
|
||||
free(inval);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int otp_chaff(uint16_t row, uint16_t len) {
|
||||
const uint8_t *raw = otp_buffer_raw(row);
|
||||
uint8_t *chaff = (uint8_t *)calloc(len * 2, sizeof(uint8_t));
|
||||
if (chaff) {
|
||||
memcpy(chaff, raw, len * 2);
|
||||
for (int i = 0; i < len * 2; i++) {
|
||||
chaff[i] ^= 0xFF;
|
||||
}
|
||||
int ret = otp_write_data_raw(row + 32, chaff, len * 2);
|
||||
mbedtls_platform_zeroize(chaff, len * 2);
|
||||
free(chaff);
|
||||
return ret;
|
||||
}
|
||||
return BOOTROM_ERROR_INVALID_STATE;
|
||||
}
|
||||
|
||||
static int otp_migrate_key(uint16_t new_row, uint16_t old_row, uint16_t len) {
|
||||
if (is_empty_otp_buffer(new_row, len) && !is_empty_otp_buffer(old_row, len)) {
|
||||
const uint8_t *key = otp_buffer(old_row);
|
||||
uint8_t *new_key = (uint8_t *)calloc(len, sizeof(uint8_t));
|
||||
if (new_key) {
|
||||
memcpy(new_key, key, len);
|
||||
int ret = otp_write_data(new_row, new_key, len);
|
||||
if (ret == BOOTROM_OK) {
|
||||
otp_chaff(new_row, len);
|
||||
otp_invalidate_key(old_row, 32);
|
||||
}
|
||||
mbedtls_platform_zeroize(new_key, len);
|
||||
free(new_key);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
return BOOTROM_ERROR_INVALID_STATE;
|
||||
}
|
||||
|
||||
static void otp_migrate_chaff(void) {
|
||||
otp_migrate_key(OTP_MKEK_ROW, OTP_OLD_MKEK_ROW, 32);
|
||||
otp_migrate_key(OTP_DEVK_ROW, OTP_OLD_DEVK_ROW, 32);
|
||||
otp_lock_page(OTP_MKEK_ROW >> 6);
|
||||
}
|
||||
|
||||
bool otp_platform_is_secure_boot_enabled(uint8_t *bootkey) {
|
||||
const uint8_t *crit1 = otp_buffer(OTP_DATA_CRIT1_ROW);
|
||||
if ((crit1[0] & (1 << OTP_DATA_CRIT1_SECURE_BOOT_ENABLE_LSB)) == 0) {
|
||||
return false;
|
||||
}
|
||||
alignas(2) uint8_t BOOTKEY[32] = {
|
||||
0xE1, 0xD1, 0x6B, 0xA7, 0x64, 0xAB, 0xD7, 0x12,
|
||||
0xD4, 0xEF, 0x6E, 0x3E, 0xDD, 0x74, 0x4E, 0xD5,
|
||||
0x63, 0x8C, 0x26, 0x0B, 0x77, 0x1C, 0xF9, 0x81,
|
||||
0x51, 0x11, 0x0B, 0xAF, 0xAC, 0x9B, 0xC8, 0x71
|
||||
};
|
||||
uint8_t bootkey_idx = 0;
|
||||
for (; bootkey_idx < 6; bootkey_idx++) {
|
||||
const uint8_t *bootkey_row = otp_buffer(OTP_DATA_BOOTKEY0_0_ROW + 0x10 * bootkey_idx);
|
||||
if (memcmp(bootkey_row, BOOTKEY, sizeof(BOOTKEY)) == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (bootkey_idx == 6) {
|
||||
return false;
|
||||
}
|
||||
const uint8_t *boot_flags1 = otp_buffer(OTP_DATA_BOOT_FLAGS1_ROW);
|
||||
if ((boot_flags1[0] & (1 << (bootkey_idx + OTP_DATA_BOOT_FLAGS1_KEY_VALID_LSB))) == 0) {
|
||||
return false;
|
||||
}
|
||||
if (bootkey) {
|
||||
*bootkey = bootkey_idx;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool otp_platform_is_secure_boot_locked(void) {
|
||||
uint8_t bootkey_idx = 0xFF;
|
||||
if (otp_platform_is_secure_boot_enabled(&bootkey_idx) == false) {
|
||||
return false;
|
||||
}
|
||||
const uint8_t *boot_flags1 = otp_buffer_raw(OTP_DATA_BOOT_FLAGS1_ROW);
|
||||
if ((boot_flags1[1] & ((OTP_DATA_BOOT_FLAGS1_KEY_INVALID_BITS >> OTP_DATA_BOOT_FLAGS1_KEY_INVALID_LSB) & (~(1 << bootkey_idx)))) !=
|
||||
((OTP_DATA_BOOT_FLAGS1_KEY_INVALID_BITS >> OTP_DATA_BOOT_FLAGS1_KEY_INVALID_LSB) & (~(1 << bootkey_idx)))) {
|
||||
return false;
|
||||
}
|
||||
const uint8_t *crit1 = otp_buffer_raw(OTP_DATA_CRIT1_ROW);
|
||||
if ((crit1[0] & (1 << OTP_DATA_CRIT1_DEBUG_DISABLE_LSB)) == 0
|
||||
|| (crit1[0] & (1 << OTP_DATA_CRIT1_GLITCH_DETECTOR_ENABLE_LSB)) == 0
|
||||
|| ((crit1[0] & (3 << OTP_DATA_CRIT1_GLITCH_DETECTOR_SENS_LSB)) != (3 << OTP_DATA_CRIT1_GLITCH_DETECTOR_SENS_LSB))) {
|
||||
return false;
|
||||
}
|
||||
return bootkey_idx != 0xFF;
|
||||
}
|
||||
|
||||
int otp_platform_enable_secure_boot(uint8_t bootkey, bool secure_lock) {
|
||||
int ret = 0;
|
||||
|
||||
alignas(2) uint8_t BOOTKEY[] = "\xe1\xd1\x6b\xa7\x64\xab\xd7\x12\xd4\xef\x6e\x3e\xdd\x74\x4e\xd5\x63\x8c\x26\xb\x77\x1c\xf9\x81\x51\x11\xb\xaf\xac\x9b\xc8\x71";
|
||||
if (is_empty_otp_buffer(OTP_DATA_BOOTKEY0_0_ROW + 0x10*bootkey, 32)) {
|
||||
PICOKEYS_CHECK(otp_write_data(OTP_DATA_BOOTKEY0_0_ROW + 0x10*bootkey, BOOTKEY, sizeof(BOOTKEY)));
|
||||
}
|
||||
|
||||
const uint8_t *boot_flags1 = otp_buffer_raw(OTP_DATA_BOOT_FLAGS1_ROW);
|
||||
alignas(4) uint8_t flagsb1[] = { boot_flags1[0] | (1 << (bootkey + OTP_DATA_BOOT_FLAGS1_KEY_VALID_LSB)), boot_flags1[1], boot_flags1[2], 0x00 };
|
||||
if (secure_lock) {
|
||||
flagsb1[1] |= ((OTP_DATA_BOOT_FLAGS1_KEY_INVALID_BITS >> OTP_DATA_BOOT_FLAGS1_KEY_INVALID_LSB) & (~(1 << bootkey)));
|
||||
}
|
||||
|
||||
PICOKEYS_CHECK(otp_write_data_raw(OTP_DATA_BOOT_FLAGS1_ROW, flagsb1, sizeof(flagsb1)));
|
||||
PICOKEYS_CHECK(otp_write_data_raw(OTP_DATA_BOOT_FLAGS1_R1_ROW, flagsb1, sizeof(flagsb1)));
|
||||
PICOKEYS_CHECK(otp_write_data_raw(OTP_DATA_BOOT_FLAGS1_R2_ROW, flagsb1, sizeof(flagsb1)));
|
||||
|
||||
const uint8_t *crit1 = otp_buffer_raw(OTP_DATA_CRIT1_ROW);
|
||||
alignas(4) uint8_t flagsc1[] = { crit1[0] | (1 << OTP_DATA_CRIT1_SECURE_BOOT_ENABLE_LSB), crit1[1], crit1[2], 0x00 };
|
||||
if (secure_lock) {
|
||||
flagsc1[0] |= (1 << OTP_DATA_CRIT1_DEBUG_DISABLE_LSB);
|
||||
flagsc1[0] |= (1 << OTP_DATA_CRIT1_GLITCH_DETECTOR_ENABLE_LSB);
|
||||
flagsc1[0] |= (3 << OTP_DATA_CRIT1_GLITCH_DETECTOR_SENS_LSB);
|
||||
}
|
||||
PICOKEYS_CHECK(otp_write_data_raw(OTP_DATA_CRIT1_ROW, flagsc1, sizeof(flagsc1)));
|
||||
PICOKEYS_CHECK(otp_write_data_raw(OTP_DATA_CRIT1_R1_ROW, flagsc1, sizeof(flagsc1)));
|
||||
PICOKEYS_CHECK(otp_write_data_raw(OTP_DATA_CRIT1_R2_ROW, flagsc1, sizeof(flagsc1)));
|
||||
PICOKEYS_CHECK(otp_write_data_raw(OTP_DATA_CRIT1_R3_ROW, flagsc1, sizeof(flagsc1)));
|
||||
PICOKEYS_CHECK(otp_write_data_raw(OTP_DATA_CRIT1_R4_ROW, flagsc1, sizeof(flagsc1)));
|
||||
PICOKEYS_CHECK(otp_write_data_raw(OTP_DATA_CRIT1_R5_ROW, flagsc1, sizeof(flagsc1)));
|
||||
PICOKEYS_CHECK(otp_write_data_raw(OTP_DATA_CRIT1_R6_ROW, flagsc1, sizeof(flagsc1)));
|
||||
PICOKEYS_CHECK(otp_write_data_raw(OTP_DATA_CRIT1_R7_ROW, flagsc1, sizeof(flagsc1)));
|
||||
|
||||
if (secure_lock) {
|
||||
const uint8_t *page1 = otp_buffer_raw(OTP_DATA_PAGE1_LOCK1_ROW);
|
||||
uint8_t page1v = page1[0] | (OTP_DATA_PAGE1_LOCK1_LOCK_BL_VALUE_READ_ONLY << OTP_DATA_PAGE1_LOCK1_LOCK_BL_LSB);
|
||||
alignas(4) uint8_t flagsp1[] = { page1v, page1v, page1v, 0x00 };
|
||||
PICOKEYS_CHECK(otp_write_data_raw(OTP_DATA_PAGE1_LOCK1_ROW, flagsp1, sizeof(flagsp1)));
|
||||
const uint8_t *page2 = otp_buffer_raw(OTP_DATA_PAGE2_LOCK1_ROW);
|
||||
uint8_t page2v = page2[0] | (OTP_DATA_PAGE2_LOCK1_LOCK_BL_VALUE_READ_ONLY << OTP_DATA_PAGE2_LOCK1_LOCK_BL_LSB);
|
||||
alignas(4) uint8_t flagsp2[] = { page2v, page2v, page2v, 0x00 };
|
||||
PICOKEYS_CHECK(otp_write_data_raw(OTP_DATA_PAGE2_LOCK1_ROW, flagsp2, sizeof(flagsp2)));
|
||||
}
|
||||
|
||||
goto err;
|
||||
err:
|
||||
if (ret != PICOKEYS_OK) {
|
||||
return ret;
|
||||
}
|
||||
return PICOKEYS_OK;
|
||||
}
|
||||
|
||||
void otp_platform_init(const uint8_t **otp_key_1_out, const uint8_t **otp_key_2_out) {
|
||||
otp_migrate_chaff();
|
||||
|
||||
int ret = 0;
|
||||
uint16_t write_otp[2] = {0xFFFF, 0xFFFF};
|
||||
if (is_empty_otp_buffer(OTP_KEY_1, 32)) {
|
||||
uint8_t mkek[32] = {0};
|
||||
random_fill_buffer(mkek, sizeof(mkek));
|
||||
ret = otp_write_data(OTP_KEY_1, mkek, sizeof(mkek));
|
||||
if (ret != 0) {
|
||||
printf("Error writing OTP key 1 [%d]\n", ret);
|
||||
}
|
||||
otp_chaff(OTP_KEY_1, 32);
|
||||
mbedtls_platform_zeroize(mkek, sizeof(mkek));
|
||||
write_otp[0] = OTP_KEY_1;
|
||||
}
|
||||
*otp_key_1_out = otp_buffer(OTP_KEY_1);
|
||||
|
||||
if (is_empty_otp_buffer(OTP_KEY_2, 32)) {
|
||||
mbedtls_ecdsa_context ecdsa;
|
||||
size_t olen = 0;
|
||||
uint8_t pkey[MBEDTLS_ECP_MAX_BYTES];
|
||||
while (olen != 32) {
|
||||
mbedtls_ecdsa_init(&ecdsa);
|
||||
mbedtls_ecp_group_id ec_id = MBEDTLS_ECP_DP_SECP256K1;
|
||||
mbedtls_ecdsa_genkey(&ecdsa, ec_id, random_fill_iterator, NULL);
|
||||
mbedtls_ecp_write_key_ext(&ecdsa, &olen, pkey, sizeof(pkey));
|
||||
mbedtls_ecdsa_free(&ecdsa);
|
||||
}
|
||||
ret = otp_write_data(OTP_KEY_2, pkey, olen);
|
||||
if (ret != 0) {
|
||||
printf("Error writing OTP key 2 [%d]\n", ret);
|
||||
}
|
||||
mbedtls_platform_zeroize(pkey, sizeof(pkey));
|
||||
otp_chaff(OTP_KEY_2, 32);
|
||||
write_otp[1] = OTP_KEY_2;
|
||||
}
|
||||
*otp_key_2_out = otp_buffer(OTP_KEY_2);
|
||||
|
||||
for (size_t i = 0; i < sizeof(write_otp) / sizeof(write_otp[0]); i++) {
|
||||
if (write_otp[i] != 0xFFFF) {
|
||||
otp_lock_page(write_otp[i] >> 6);
|
||||
}
|
||||
}
|
||||
}
|
||||
577
src/otp/otp_windows.c
Normal file
577
src/otp/otp_windows.c
Normal file
@@ -0,0 +1,577 @@
|
||||
/*
|
||||
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
|
||||
* Copyright (c) 2022 Pol Henarejos.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "picokeys.h"
|
||||
#include "otp_platform.h"
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#include <windows.h>
|
||||
#include <ncrypt.h>
|
||||
#include <bcrypt.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <io.h>
|
||||
|
||||
#include "mbedtls/bignum.h"
|
||||
#include "mbedtls/ecp.h"
|
||||
#include "mbedtls/sha256.h"
|
||||
|
||||
#ifndef BCRYPT_KDF_RAW_SECRET
|
||||
#define BCRYPT_KDF_RAW_SECRET L"RAW_SECRET"
|
||||
#endif
|
||||
|
||||
#define TPM_KEY_NAME L"pico_novus_tpm_ecdh"
|
||||
#define SW_PEER_NAME L"pico_novus_sw_peer_ecdh"
|
||||
#define SW_LOCAL_NAME L"pico_novus_sw_local_ecdh"
|
||||
|
||||
#ifndef OTP_WINDOWS_TPM_STRICT
|
||||
#define OTP_WINDOWS_TPM_STRICT 1
|
||||
#endif
|
||||
|
||||
static int win_err(const char *ctx, SECURITY_STATUS st) {
|
||||
fprintf(stderr, "[win-tpm] %s failed: 0x%08lx\n", ctx, (unsigned long)st);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static const char *ncrypt_status_hint(SECURITY_STATUS st) {
|
||||
switch (st) {
|
||||
case NTE_DEVICE_NOT_READY:
|
||||
return "TPM is not ready (disabled, uninitialized, or inaccessible)";
|
||||
case NTE_NOT_SUPPORTED:
|
||||
return "operation/algorithm not supported by this provider";
|
||||
case NTE_BAD_KEYSET:
|
||||
return "keyset not found";
|
||||
case NTE_PERM:
|
||||
return "permission denied";
|
||||
default:
|
||||
return "unmapped status";
|
||||
}
|
||||
}
|
||||
|
||||
static int read_tpm_pin_prompt(const char *prompt, char *pin_out, size_t pin_out_size) {
|
||||
const char *pin_env = getenv("PICO_NOVUS_TPM_PIN");
|
||||
if (!pin_out || pin_out_size < 2) {
|
||||
return -1;
|
||||
}
|
||||
if (pin_env && pin_env[0] != '\0') {
|
||||
size_t n = strlen(pin_env);
|
||||
if (n >= pin_out_size) {
|
||||
return -1;
|
||||
}
|
||||
memcpy(pin_out, pin_env, n + 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!_isatty(_fileno(stdin))) {
|
||||
fprintf(stderr, "[win-tpm] No TTY for PIN prompt; set PICO_NOVUS_TPM_PIN\n");
|
||||
return -1;
|
||||
}
|
||||
HANDLE h_in = GetStdHandle(STD_INPUT_HANDLE);
|
||||
DWORD old_mode = 0;
|
||||
DWORD new_mode = 0;
|
||||
|
||||
if (h_in == INVALID_HANDLE_VALUE || !GetConsoleMode(h_in, &old_mode)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
new_mode = old_mode & (~ENABLE_ECHO_INPUT);
|
||||
fprintf(stderr, "%s", prompt ? prompt : "Enter TPM key PIN: ");
|
||||
fflush(stderr);
|
||||
|
||||
if (!SetConsoleMode(h_in, new_mode)) {
|
||||
return -1;
|
||||
}
|
||||
if (!fgets(pin_out, (int)pin_out_size, stdin)) {
|
||||
SetConsoleMode(h_in, old_mode);
|
||||
fprintf(stderr, "\n");
|
||||
return -1;
|
||||
}
|
||||
SetConsoleMode(h_in, old_mode);
|
||||
fprintf(stderr, "\n");
|
||||
size_t n = strlen(pin_out);
|
||||
if (n > 0 && pin_out[n - 1] == '\n') {
|
||||
pin_out[n - 1] = '\0';
|
||||
}
|
||||
if (n > 1 && pin_out[n - 2] == '\r') {
|
||||
pin_out[n - 2] = '\0';
|
||||
}
|
||||
return (pin_out[0] != '\0') ? 0 : -1;
|
||||
}
|
||||
|
||||
static int key_exists_by_name(NCRYPT_PROV_HANDLE prov, LPCWSTR key_name, int *exists_out) {
|
||||
SECURITY_STATUS st;
|
||||
NCRYPT_KEY_HANDLE key = 0;
|
||||
|
||||
if (!exists_out) {
|
||||
return -1;
|
||||
}
|
||||
*exists_out = 0;
|
||||
|
||||
st = NCryptOpenKey(prov, &key, key_name, 0, 0);
|
||||
if (st == ERROR_SUCCESS) {
|
||||
*exists_out = 1;
|
||||
NCryptFreeObject(key);
|
||||
return 0;
|
||||
}
|
||||
if (st == NTE_BAD_KEYSET) {
|
||||
return 0;
|
||||
}
|
||||
return win_err("NCryptOpenKey(exists)", st);
|
||||
}
|
||||
|
||||
static int delete_persisted_key_if_exists(NCRYPT_PROV_HANDLE prov, LPCWSTR key_name) {
|
||||
SECURITY_STATUS st;
|
||||
NCRYPT_KEY_HANDLE key = 0;
|
||||
|
||||
st = NCryptOpenKey(prov, &key, key_name, 0, 0);
|
||||
if (st == NTE_BAD_KEYSET) {
|
||||
return 0;
|
||||
}
|
||||
if (st != ERROR_SUCCESS) {
|
||||
return win_err("NCryptOpenKey(delete)", st);
|
||||
}
|
||||
|
||||
st = NCryptDeleteKey(key, 0);
|
||||
if (st != ERROR_SUCCESS) {
|
||||
NCryptFreeObject(key);
|
||||
return win_err("NCryptDeleteKey", st);
|
||||
}
|
||||
|
||||
printf("[win-tpm] Deleted key '%ls'\n", key_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int set_tpm_usage_pin(NCRYPT_KEY_HANDLE key, const char *pin, const char *ctx) {
|
||||
SECURITY_STATUS st;
|
||||
int wlen;
|
||||
wchar_t wpin[128];
|
||||
|
||||
if (!pin || pin[0] == '\0') {
|
||||
return 0;
|
||||
}
|
||||
|
||||
memset(wpin, 0, sizeof(wpin));
|
||||
wlen = MultiByteToWideChar(CP_UTF8, 0, pin, -1, wpin, (int)(sizeof(wpin) / sizeof(wpin[0])));
|
||||
if (wlen <= 1) {
|
||||
fprintf(stderr, "[win-tpm] invalid PIN encoding\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* PCP usage auth is expected as WCHAR string (including terminator). */
|
||||
st = NCryptSetProperty(
|
||||
key,
|
||||
NCRYPT_PCP_USAGEAUTH_PROPERTY,
|
||||
(PBYTE)wpin,
|
||||
(DWORD)(wlen * sizeof(wchar_t)),
|
||||
0
|
||||
);
|
||||
SecureZeroMemory(wpin, sizeof(wpin));
|
||||
if (st != ERROR_SUCCESS) {
|
||||
if (st == NTE_NOT_SUPPORTED) {
|
||||
fprintf(stderr, "[win-tpm] TPM provider does not support PIN auth property on this machine\n");
|
||||
return 1;
|
||||
}
|
||||
return win_err(ctx, st);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int probe_tpm_native_pin_support(NCRYPT_PROV_HANDLE prov) {
|
||||
SECURITY_STATUS st;
|
||||
NCRYPT_KEY_HANDLE probe_key = 0;
|
||||
const wchar_t probe_name[] = L"pico_novus_pin_probe_tmp";
|
||||
const wchar_t probe_pin[] = L"0";
|
||||
|
||||
st = NCryptCreatePersistedKey(prov, &probe_key, NCRYPT_ECDH_P256_ALGORITHM, probe_name, 0, NCRYPT_OVERWRITE_KEY_FLAG);
|
||||
if (st != ERROR_SUCCESS) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
st = NCryptSetProperty(
|
||||
probe_key,
|
||||
NCRYPT_PCP_USAGEAUTH_PROPERTY,
|
||||
(PBYTE)probe_pin,
|
||||
(DWORD)(sizeof(probe_pin)),
|
||||
0
|
||||
);
|
||||
if (st == NTE_NOT_SUPPORTED) {
|
||||
NCryptDeleteKey(probe_key, 0);
|
||||
return 0;
|
||||
}
|
||||
if (st != ERROR_SUCCESS) {
|
||||
NCryptDeleteKey(probe_key, 0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
st = NCryptDeleteKey(probe_key, 0);
|
||||
if (st != ERROR_SUCCESS) {
|
||||
return -1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int derive_secp256k1_privkey_from_secret(const uint8_t *secret, size_t secret_len, uint8_t out_key32[32]) {
|
||||
int rc = -1;
|
||||
uint8_t digest[32];
|
||||
const uint8_t label[] = "pico-novus/se-ecdh-to-k1-v1";
|
||||
mbedtls_ecp_group grp;
|
||||
mbedtls_mpi x, n_minus_1;
|
||||
|
||||
if (!secret || secret_len == 0 || !out_key32) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
mbedtls_sha256_context sha;
|
||||
mbedtls_sha256_init(&sha);
|
||||
mbedtls_sha256_starts(&sha, 0);
|
||||
mbedtls_sha256_update(&sha, label, sizeof(label) - 1);
|
||||
mbedtls_sha256_update(&sha, secret, secret_len);
|
||||
mbedtls_sha256_finish(&sha, digest);
|
||||
mbedtls_sha256_free(&sha);
|
||||
|
||||
mbedtls_ecp_group_init(&grp);
|
||||
mbedtls_mpi_init(&x);
|
||||
mbedtls_mpi_init(&n_minus_1);
|
||||
|
||||
if (mbedtls_ecp_group_load(&grp, MBEDTLS_ECP_DP_SECP256K1) != 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
if (mbedtls_mpi_read_binary(&x, digest, sizeof(digest)) != 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
if (mbedtls_mpi_copy(&n_minus_1, &grp.N) != 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
if (mbedtls_mpi_sub_int(&n_minus_1, &n_minus_1, 1) != 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
if (mbedtls_mpi_mod_mpi(&x, &x, &n_minus_1) != 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
if (mbedtls_mpi_add_int(&x, &x, 1) != 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
if (mbedtls_mpi_write_binary(&x, out_key32, 32) != 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
rc = 0;
|
||||
|
||||
cleanup:
|
||||
mbedtls_mpi_free(&n_minus_1);
|
||||
mbedtls_mpi_free(&x);
|
||||
mbedtls_ecp_group_free(&grp);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int open_or_create_persisted_ecdh_p256_key(NCRYPT_PROV_HANDLE prov, LPCWSTR key_name, const char *pin, NCRYPT_KEY_HANDLE *out_key, int *created_out) {
|
||||
SECURITY_STATUS st;
|
||||
NCRYPT_KEY_HANDLE key = 0;
|
||||
DWORD pin_len = 0;
|
||||
int pin_rc = 0;
|
||||
|
||||
if (!out_key) {
|
||||
return -1;
|
||||
}
|
||||
*out_key = 0;
|
||||
if (created_out) {
|
||||
*created_out = 0;
|
||||
}
|
||||
if (pin && pin[0] != '\0') {
|
||||
pin_len = (DWORD)strlen(pin);
|
||||
}
|
||||
|
||||
st = NCryptOpenKey(prov, &key, key_name, 0, 0);
|
||||
if (st == NTE_BAD_KEYSET) {
|
||||
st = NCryptCreatePersistedKey(prov, &key, NCRYPT_ECDH_P256_ALGORITHM, key_name, 0, 0);
|
||||
if (st != ERROR_SUCCESS) {
|
||||
return win_err("NCryptCreatePersistedKey", st);
|
||||
}
|
||||
if (pin_len > 0) {
|
||||
pin_rc = set_tpm_usage_pin(key, pin, "NCryptSetProperty(NCRYPT_PCP_USAGEAUTH_PROPERTY/create)");
|
||||
if (pin_rc == 1) {
|
||||
fprintf(stderr, "[win-tpm] PIN protection unsupported by TPM provider; continuing without TPM-native PIN\n");
|
||||
}
|
||||
else if (pin_rc != 0) {
|
||||
NCryptFreeObject(key);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
st = NCryptFinalizeKey(key, 0);
|
||||
if (st != ERROR_SUCCESS) {
|
||||
NCryptFreeObject(key);
|
||||
return win_err("NCryptFinalizeKey", st);
|
||||
}
|
||||
printf("[win-tpm] Created key '%ls'\n", key_name);
|
||||
if (created_out) {
|
||||
*created_out = 1;
|
||||
}
|
||||
}
|
||||
else if (st != ERROR_SUCCESS) {
|
||||
return win_err("NCryptOpenKey", st);
|
||||
}
|
||||
else {
|
||||
printf("[win-tpm] Using existing key '%ls'\n", key_name);
|
||||
}
|
||||
|
||||
if (pin_len > 0) {
|
||||
pin_rc = set_tpm_usage_pin(key, pin, "NCryptSetProperty(NCRYPT_PCP_USAGEAUTH_PROPERTY/open)");
|
||||
if (pin_rc == 1) {
|
||||
fprintf(stderr, "[win-tpm] PIN protection unsupported by TPM provider; continuing without TPM-native PIN\n");
|
||||
}
|
||||
else if (pin_rc != 0) {
|
||||
NCryptFreeObject(key);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
*out_key = key;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int windows_tpm_vault_load_or_create_key(uint8_t out_key32[32]) {
|
||||
int rc = -1;
|
||||
SECURITY_STATUS st;
|
||||
NCRYPT_PROV_HANDLE tpm_prov = 0;
|
||||
NCRYPT_PROV_HANDLE sw_prov = 0;
|
||||
NCRYPT_KEY_HANDLE tpm_key = 0;
|
||||
NCRYPT_KEY_HANDLE sw_peer_key = 0;
|
||||
NCRYPT_KEY_HANDLE imported_peer_pub = 0;
|
||||
NCRYPT_SECRET_HANDLE secret = 0;
|
||||
PBYTE raw_secret = NULL;
|
||||
DWORD raw_secret_len = 0;
|
||||
PBYTE peer_pub_blob = NULL;
|
||||
DWORD peer_pub_blob_len = 0;
|
||||
char pin[128] = {0};
|
||||
int key_exists = 0;
|
||||
int pin_supported = 0;
|
||||
|
||||
st = NCryptOpenStorageProvider(&tpm_prov, MS_PLATFORM_CRYPTO_PROVIDER, 0);
|
||||
if (st != ERROR_SUCCESS) {
|
||||
fprintf(stderr, "[win-tpm] MS_PLATFORM_CRYPTO_PROVIDER unavailable: 0x%08lx (%s)\n", (unsigned long)st, ncrypt_status_hint(st));
|
||||
#if OTP_WINDOWS_TPM_STRICT
|
||||
return -1;
|
||||
#else
|
||||
st = NCryptOpenStorageProvider(&sw_prov, MS_KEY_STORAGE_PROVIDER, 0);
|
||||
if (st != ERROR_SUCCESS) {
|
||||
return win_err("NCryptOpenStorageProvider(MS_KEY_STORAGE_PROVIDER)", st);
|
||||
}
|
||||
printf("[win-tpm] Falling back to software KSP (MS_KEY_STORAGE_PROVIDER)\n");
|
||||
if (open_or_create_persisted_ecdh_p256_key(sw_prov, SW_LOCAL_NAME, NULL, &tpm_key, NULL) != 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
if (open_or_create_persisted_ecdh_p256_key(sw_prov, SW_PEER_NAME, NULL, &sw_peer_key, NULL) != 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
st = NCryptSecretAgreement(tpm_key, sw_peer_key, &secret, 0);
|
||||
if (st != ERROR_SUCCESS) {
|
||||
win_err("NCryptSecretAgreement(fallback)", st);
|
||||
goto cleanup;
|
||||
}
|
||||
st = NCryptDeriveKey(secret, BCRYPT_KDF_RAW_SECRET, NULL, NULL, 0, &raw_secret_len, 0);
|
||||
if (st != ERROR_SUCCESS || raw_secret_len == 0) {
|
||||
win_err("NCryptDeriveKey(size/fallback)", st);
|
||||
goto cleanup;
|
||||
}
|
||||
raw_secret = (PBYTE)malloc(raw_secret_len);
|
||||
if (!raw_secret) {
|
||||
fprintf(stderr, "[win-tpm] malloc(%lu) failed\n", (unsigned long)raw_secret_len);
|
||||
goto cleanup;
|
||||
}
|
||||
st = NCryptDeriveKey(secret, BCRYPT_KDF_RAW_SECRET, NULL, raw_secret, raw_secret_len, &raw_secret_len, 0);
|
||||
if (st != ERROR_SUCCESS) {
|
||||
win_err("NCryptDeriveKey(data/fallback)", st);
|
||||
goto cleanup;
|
||||
}
|
||||
if (derive_secp256k1_privkey_from_secret(raw_secret, (size_t)raw_secret_len, out_key32) != 0) {
|
||||
fprintf(stderr, "[win-tpm] failed deriving secp256k1 private key in software fallback\n");
|
||||
goto cleanup;
|
||||
}
|
||||
rc = 0;
|
||||
goto cleanup;
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
printf("[win-tpm] Using TPM platform provider\n");
|
||||
}
|
||||
|
||||
st = NCryptOpenStorageProvider(&sw_prov, MS_KEY_STORAGE_PROVIDER, 0);
|
||||
if (st != ERROR_SUCCESS) {
|
||||
win_err("NCryptOpenStorageProvider(MS_KEY_STORAGE_PROVIDER)", st);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
pin_supported = probe_tpm_native_pin_support(tpm_prov);
|
||||
if (pin_supported < 0) {
|
||||
fprintf(stderr, "[win-tpm] Cannot determine TPM-native PIN support; continuing without PIN\n");
|
||||
pin_supported = 0;
|
||||
}
|
||||
else if (pin_supported == 0) {
|
||||
fprintf(stderr, "[win-tpm] TPM provider does not support native PIN auth; continuing without PIN\n");
|
||||
}
|
||||
|
||||
if (key_exists_by_name(tpm_prov, TPM_KEY_NAME, &key_exists) != 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
if (pin_supported) {
|
||||
if (!key_exists) {
|
||||
if (read_tpm_pin_prompt("Set TPM key PIN: ", pin, sizeof(pin)) != 0) {
|
||||
fprintf(stderr, "[win-tpm] PIN is required to provision TPM key\n");
|
||||
goto cleanup;
|
||||
}
|
||||
if (!getenv("PICO_NOVUS_TPM_PIN") && _isatty(_fileno(stdin))) {
|
||||
char confirm[128] = {0};
|
||||
if (read_tpm_pin_prompt("Confirm TPM key PIN: ", confirm, sizeof(confirm)) != 0 || strcmp(pin, confirm) != 0) {
|
||||
fprintf(stderr, "[win-tpm] PIN confirmation mismatch\n");
|
||||
SecureZeroMemory(confirm, sizeof(confirm));
|
||||
goto cleanup;
|
||||
}
|
||||
SecureZeroMemory(confirm, sizeof(confirm));
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (read_tpm_pin_prompt("Enter TPM key PIN: ", pin, sizeof(pin)) != 0) {
|
||||
fprintf(stderr, "[win-tpm] PIN is required to unlock TPM key\n");
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (open_or_create_persisted_ecdh_p256_key(tpm_prov, TPM_KEY_NAME, pin_supported ? pin : NULL, &tpm_key, NULL) != 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (open_or_create_persisted_ecdh_p256_key(sw_prov, SW_PEER_NAME, NULL, &sw_peer_key, NULL) != 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
st = NCryptExportKey(sw_peer_key, 0, BCRYPT_ECCPUBLIC_BLOB, NULL, NULL, 0, &peer_pub_blob_len, 0);
|
||||
if (st != ERROR_SUCCESS || peer_pub_blob_len == 0) {
|
||||
win_err("NCryptExportKey(size)", st);
|
||||
goto cleanup;
|
||||
}
|
||||
peer_pub_blob = (PBYTE)malloc(peer_pub_blob_len);
|
||||
if (!peer_pub_blob) {
|
||||
fprintf(stderr, "[win-tpm] malloc(%lu) failed\n", (unsigned long)peer_pub_blob_len);
|
||||
goto cleanup;
|
||||
}
|
||||
st = NCryptExportKey(sw_peer_key, 0, BCRYPT_ECCPUBLIC_BLOB, NULL, peer_pub_blob, peer_pub_blob_len, &peer_pub_blob_len, 0);
|
||||
if (st != ERROR_SUCCESS) {
|
||||
win_err("NCryptExportKey(data)", st);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
st = NCryptImportKey(tpm_prov, 0, BCRYPT_ECCPUBLIC_BLOB, NULL, &imported_peer_pub, peer_pub_blob, peer_pub_blob_len, 0);
|
||||
if (st != ERROR_SUCCESS) {
|
||||
win_err("NCryptImportKey(BCRYPT_ECCPUBLIC_BLOB)", st);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
st = NCryptSecretAgreement(tpm_key, imported_peer_pub, &secret, 0);
|
||||
if (st != ERROR_SUCCESS) {
|
||||
win_err("NCryptSecretAgreement", st);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
st = NCryptDeriveKey(secret, BCRYPT_KDF_RAW_SECRET, NULL, NULL, 0, &raw_secret_len, 0);
|
||||
if (st != ERROR_SUCCESS || raw_secret_len == 0) {
|
||||
win_err("NCryptDeriveKey(size)", st);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
raw_secret = (PBYTE)malloc(raw_secret_len);
|
||||
if (!raw_secret) {
|
||||
fprintf(stderr, "[win-tpm] malloc(%lu) failed\n", (unsigned long)raw_secret_len);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
st = NCryptDeriveKey(secret, BCRYPT_KDF_RAW_SECRET, NULL, raw_secret, raw_secret_len, &raw_secret_len, 0);
|
||||
if (st != ERROR_SUCCESS) {
|
||||
win_err("NCryptDeriveKey(data)", st);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (derive_secp256k1_privkey_from_secret(raw_secret, (size_t)raw_secret_len, out_key32) != 0) {
|
||||
fprintf(stderr, "[win-tpm] failed deriving secp256k1 private key from ECDH secret\n");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
rc = 0;
|
||||
|
||||
cleanup:
|
||||
SecureZeroMemory(pin, sizeof(pin));
|
||||
if (peer_pub_blob) {
|
||||
SecureZeroMemory(peer_pub_blob, peer_pub_blob_len);
|
||||
free(peer_pub_blob);
|
||||
}
|
||||
if (raw_secret) {
|
||||
SecureZeroMemory(raw_secret, raw_secret_len);
|
||||
free(raw_secret);
|
||||
}
|
||||
if (secret) {
|
||||
NCryptFreeObject(secret);
|
||||
}
|
||||
if (imported_peer_pub) {
|
||||
NCryptFreeObject(imported_peer_pub);
|
||||
}
|
||||
if (sw_peer_key) {
|
||||
NCryptFreeObject(sw_peer_key);
|
||||
}
|
||||
if (tpm_key) {
|
||||
NCryptFreeObject(tpm_key);
|
||||
}
|
||||
if (sw_prov) {
|
||||
NCryptFreeObject(sw_prov);
|
||||
}
|
||||
if (tpm_prov) {
|
||||
NCryptFreeObject(tpm_prov);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
#endif
|
||||
|
||||
int otp_platform_enable_secure_boot(uint8_t bootkey, bool secure_lock) {
|
||||
(void)bootkey;
|
||||
(void)secure_lock;
|
||||
return PICOKEYS_OK;
|
||||
}
|
||||
|
||||
bool otp_platform_is_secure_boot_enabled(uint8_t *bootkey) {
|
||||
(void)bootkey;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool otp_platform_is_secure_boot_locked(void) {
|
||||
return false;
|
||||
}
|
||||
|
||||
void otp_platform_init(const uint8_t **otp_key_1_out, const uint8_t **otp_key_2_out) {
|
||||
static uint8_t _otp1[32] = {0};
|
||||
static uint8_t _otp2[32] = {0};
|
||||
|
||||
memset(_otp1, 0xAC, sizeof(_otp1));
|
||||
memset(_otp2, 0xBE, sizeof(_otp2));
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
if (windows_tpm_vault_load_or_create_key(_otp2) != 0) {
|
||||
printf("Warning: failed to load Windows TPM key; using dummy otp_key_2\n");
|
||||
}
|
||||
#endif
|
||||
*otp_key_1_out = _otp1;
|
||||
*otp_key_2_out = _otp2;
|
||||
}
|
||||
240
src/pico_keys.h
240
src/pico_keys.h
@@ -1,240 +0,0 @@
|
||||
/*
|
||||
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
|
||||
* Copyright (c) 2022 Pol Henarejos.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _PICO_KEYS_H_
|
||||
#define _PICO_KEYS_H_
|
||||
|
||||
#if defined(PICO_RP2040) || defined(PICO_RP2350)
|
||||
#define PICO_PLATFORM
|
||||
#endif
|
||||
|
||||
#include "file.h"
|
||||
#include "led/led.h"
|
||||
#if defined(ENABLE_EMULATION) || defined(ESP_PLATFORM)
|
||||
#include <stdint.h>
|
||||
#if !defined(MIN)
|
||||
#if defined(_MSC_VER)
|
||||
#define MIN(a,b) (((a)<(b))?(a):(b))
|
||||
#else
|
||||
#define MIN(a, b) \
|
||||
({ __typeof__ (a) _a = (a); \
|
||||
__typeof__ (b) _b = (b); \
|
||||
_a < _b ? _a : _b; })
|
||||
#endif
|
||||
#endif
|
||||
#if !defined(MAX)
|
||||
#if defined(_MSC_VER)
|
||||
#define MAX(a,b) (((a)>(b))?(a):(b))
|
||||
#else
|
||||
#define MAX(a, b) \
|
||||
({ __typeof__ (a) _a = (a); \
|
||||
__typeof__ (b) _b = (b); \
|
||||
_a > _b ? _a : _b; })
|
||||
#endif
|
||||
#endif
|
||||
#else
|
||||
#include "pico/unique_id.h"
|
||||
#endif
|
||||
#include <string.h>
|
||||
#include "debug.h"
|
||||
|
||||
#if defined(ENABLE_EMULATION)
|
||||
#include <stdbool.h>
|
||||
#elif defined(ESP_PLATFORM)
|
||||
#include "esp_compat.h"
|
||||
#else
|
||||
#include "pico/util/queue.h"
|
||||
#endif
|
||||
|
||||
extern bool wait_button();
|
||||
|
||||
extern void low_flash_init_core1();
|
||||
|
||||
static inline uint16_t make_uint16_t_be(uint8_t b1, uint8_t b2) {
|
||||
return (b1 << 8) | b2;
|
||||
}
|
||||
static inline uint16_t make_uint16_t_le(uint8_t b1, uint8_t b2) {
|
||||
return (b2 << 8) | b1;
|
||||
}
|
||||
static inline uint16_t get_uint16_t_be(const uint8_t *b) {
|
||||
return make_uint16_t_be(b[0], b[1]);
|
||||
}
|
||||
static inline uint16_t get_uint16_t_le(const uint8_t *b) {
|
||||
return make_uint16_t_le(b[0], b[1]);
|
||||
}
|
||||
static inline uint32_t put_uint16_t_be(uint16_t n, uint8_t *b) {
|
||||
*b++ = (n >> 8) & 0xff;
|
||||
*b = n & 0xff;
|
||||
return 2;
|
||||
}
|
||||
static inline uint32_t put_uint16_t_le(uint16_t n, uint8_t *b) {
|
||||
*b++ = n & 0xff;
|
||||
*b = (n >> 8) & 0xff;
|
||||
return 2;
|
||||
}
|
||||
|
||||
static inline uint32_t make_uint32_t_be(uint8_t b1, uint8_t b2, uint8_t b3, uint8_t b4) {
|
||||
return (b1 << 24) | (b2 << 16) | (b3 << 8) | b4;
|
||||
}
|
||||
static inline uint32_t make_uint32_t_le(uint8_t b1, uint8_t b2, uint8_t b3, uint8_t b4) {
|
||||
return (b4 << 24) | (b3 << 16) | (b2 << 8) | b1;
|
||||
}
|
||||
static inline uint32_t get_uint32_t_be(const uint8_t *b) {
|
||||
return make_uint32_t_be(b[0], b[1], b[2], b[3]);
|
||||
}
|
||||
static inline uint32_t get_uint32_t_le(const uint8_t *b) {
|
||||
return make_uint32_t_le(b[0], b[1], b[2], b[3]);
|
||||
}
|
||||
static inline uint32_t put_uint32_t_be(uint32_t n, uint8_t *b) {
|
||||
*b++ = (n >> 24) & 0xff;
|
||||
*b++ = (n >> 16) & 0xff;
|
||||
*b++ = (n >> 8) & 0xff;
|
||||
*b = n & 0xff;
|
||||
return 4;
|
||||
}
|
||||
static inline uint32_t put_uint32_t_le(uint32_t n, uint8_t *b) {
|
||||
*b++ = n & 0xff;
|
||||
*b++ = (n >> 8) & 0xff;
|
||||
*b++ = (n >> 16) & 0xff;
|
||||
*b = (n >> 24) & 0xff;
|
||||
return 4;
|
||||
}
|
||||
|
||||
static inline uint64_t make_uint64_t_be(uint8_t b1, uint8_t b2, uint8_t b3, uint8_t b4, uint8_t b5, uint8_t b6, uint8_t b7, uint8_t b8) {
|
||||
return ((uint64_t) b1 << 56) | ((uint64_t) b2 << 48) | ((uint64_t) b3 << 40) | ((uint64_t) b4 << 32) | ((uint64_t) b5 << 24) | ((uint64_t) b6 << 16) | ((uint64_t) b7 << 8) | b8;
|
||||
}
|
||||
static inline uint64_t make_uint64_t_le(uint8_t b1, uint8_t b2, uint8_t b3, uint8_t b4, uint8_t b5, uint8_t b6, uint8_t b7, uint8_t b8) {
|
||||
return ((uint64_t) b8 << 56) | ((uint64_t) b7 << 48) | ((uint64_t) b6 << 40) | ((uint64_t) b5 << 32) | ((uint64_t) b4 << 24) | ((uint64_t) b3 << 16) | ((uint64_t) b2 << 8) | b1;
|
||||
}
|
||||
static inline uint64_t get_uint64_t_be(const uint8_t *b) {
|
||||
return make_uint64_t_be(b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]);
|
||||
}
|
||||
static inline uint64_t get_uint64_t_le(const uint8_t *b) {
|
||||
return make_uint64_t_le(b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]);
|
||||
}
|
||||
static inline uint32_t put_uint64_t_be(uint64_t n, uint8_t *b) {
|
||||
*b++ = (n >> 56) & 0xff;
|
||||
*b++ = (n >> 48) & 0xff;
|
||||
*b++ = (n >> 40) & 0xff;
|
||||
*b++ = (n >> 32) & 0xff;
|
||||
*b++ = (n >> 24) & 0xff;
|
||||
*b++ = (n >> 16) & 0xff;
|
||||
*b++ = (n >> 8) & 0xff;
|
||||
*b = n & 0xff;
|
||||
return 8;
|
||||
}
|
||||
static inline uint32_t put_uint64_t_le(uint64_t n, uint8_t *b) {
|
||||
*b++ = n & 0xff;
|
||||
*b++ = (n >> 8) & 0xff;
|
||||
*b++ = (n >> 16) & 0xff;
|
||||
*b++ = (n >> 24) & 0xff;
|
||||
*b++ = (n >> 32) & 0xff;
|
||||
*b++ = (n >> 40) & 0xff;
|
||||
*b++ = (n >> 48) & 0xff;
|
||||
*b = (n >> 56) & 0xff;
|
||||
return 8;
|
||||
}
|
||||
|
||||
extern void low_flash_available();
|
||||
extern int flash_clear_file(file_t *file);
|
||||
|
||||
extern int (*button_pressed_cb)(uint8_t);
|
||||
|
||||
extern bool is_req_button_pending();
|
||||
extern uint32_t button_timeout;
|
||||
|
||||
#define SW_BYTES_REMAINING_00() set_res_sw(0x61, 0x00)
|
||||
#define SW_WARNING_STATE_UNCHANGED() set_res_sw(0x62, 0x00)
|
||||
#define SW_WARNING_CORRUPTED() set_res_sw(0x62, 0x81)
|
||||
#define SW_WARNING_EOF() set_res_sw(0x62, 0x82)
|
||||
#define SW_WARNING_EF_DEACTIVATED() set_res_sw(0x62, 0x83)
|
||||
#define SW_WARNING_WRONG_FCI() set_res_sw(0x62, 0x84)
|
||||
#define SW_WARNING_EF_TERMINATED() set_res_sw(0x62, 0x85)
|
||||
|
||||
#define SW_WARNING_NOINFO() set_res_sw(0x63, 0x00)
|
||||
#define SW_WARNING_FILLUP() set_res_sw(0x63, 0x81)
|
||||
|
||||
#define SW_EXEC_ERROR() set_res_sw(0x64, 0x00)
|
||||
|
||||
#define SW_MEMORY_FAILURE() set_res_sw(0x65, 0x81)
|
||||
|
||||
#define SW_SECURE_MESSAGE_EXEC_ERROR() set_res_sw(0x66, 0x00)
|
||||
|
||||
#define SW_WRONG_LENGTH() set_res_sw(0x67, 0x00)
|
||||
#define SW_WRONG_DATA() set_res_sw(0x67, 0x00)
|
||||
|
||||
#define SW_LOGICAL_CHANNEL_NOT_SUPPORTED() set_res_sw(0x68, 0x81)
|
||||
#define SW_SECURE_MESSAGING_NOT_SUPPORTED() set_res_sw(0x68, 0x82)
|
||||
|
||||
#define SW_COMMAND_INCOMPATIBLE() set_res_sw(0x69, 0x81)
|
||||
#define SW_SECURITY_STATUS_NOT_SATISFIED() set_res_sw(0x69, 0x82)
|
||||
#define SW_PIN_BLOCKED() set_res_sw(0x69, 0x83)
|
||||
#define SW_DATA_INVALID() set_res_sw(0x69, 0x84)
|
||||
#define SW_CONDITIONS_NOT_SATISFIED() set_res_sw(0x69, 0x85)
|
||||
#define SW_COMMAND_NOT_ALLOWED() set_res_sw(0x69, 0x86)
|
||||
#define SW_SECURE_MESSAGING_MISSING_DO() set_res_sw(0x69, 0x87)
|
||||
#define SW_SECURE_MESSAGING_INCORRECT_DO() set_res_sw(0x69, 0x88)
|
||||
#define SW_APPLET_SELECT_FAILED() set_res_sw(0x69, 0x99)
|
||||
|
||||
#define SW_INCORRECT_PARAMS() set_res_sw(0x6A, 0x80)
|
||||
#define SW_FUNC_NOT_SUPPORTED() set_res_sw(0x6A, 0x81)
|
||||
#define SW_FILE_NOT_FOUND() set_res_sw(0x6A, 0x82)
|
||||
#define SW_RECORD_NOT_FOUND() set_res_sw(0x6A, 0x83)
|
||||
#define SW_FILE_FULL() set_res_sw(0x6A, 0x84)
|
||||
#define SW_WRONG_NE() set_res_sw(0x6A, 0x85)
|
||||
#define SW_INCORRECT_P1P2() set_res_sw(0x6A, 0x86)
|
||||
#define SW_WRONG_NC() set_res_sw(0x6A, 0x87)
|
||||
#define SW_REFERENCE_NOT_FOUND() set_res_sw(0x6A, 0x88)
|
||||
#define SW_FILE_EXISTS() set_res_sw(0x6A, 0x89)
|
||||
|
||||
#define SW_WRONG_P1P2() set_res_sw(0x6B, 0x00)
|
||||
|
||||
#define SW_CORRECT_LENGTH_00() set_res_sw(0x6C, 0x00)
|
||||
|
||||
#define SW_INS_NOT_SUPPORTED() set_res_sw(0x6D, 0x00)
|
||||
|
||||
#define SW_CLA_NOT_SUPPORTED() set_res_sw(0x6E, 0x00)
|
||||
|
||||
#define SW_UNKNOWN() set_res_sw(0x6F, 0x00)
|
||||
|
||||
#define SW_OK() set_res_sw(0x90, 0x00)
|
||||
|
||||
#define PICOKEY_OK 0
|
||||
#define PICOKEY_ERR_NO_MEMORY -1000
|
||||
#define PICOKEY_ERR_MEMORY_FATAL -1001
|
||||
#define PICOKEY_ERR_NULL_PARAM -1002
|
||||
#define PICOKEY_ERR_FILE_NOT_FOUND -1003
|
||||
#define PICOKEY_ERR_BLOCKED -1004
|
||||
#define PICOKEY_NO_LOGIN -1005
|
||||
#define PICOKEY_EXEC_ERROR -1006
|
||||
#define PICOKEY_WRONG_LENGTH -1007
|
||||
#define PICOKEY_WRONG_DATA -1008
|
||||
#define PICOKEY_WRONG_DKEK -1009
|
||||
#define PICOKEY_WRONG_SIGNATURE -1010
|
||||
#define PICOKEY_WRONG_PADDING -1011
|
||||
#define PICOKEY_VERIFICATION_FAILED -1012
|
||||
|
||||
#define PICOKEY_CHECK(x) do { ret = (x); if (ret != PICOKEY_OK) goto err; } while (0)
|
||||
|
||||
#if defined(ENABLE_EMULATION) || defined(ESP_PLATFORM)
|
||||
#define PICO_UNIQUE_BOARD_ID_SIZE_BYTES 8
|
||||
typedef struct { uint8_t id[PICO_UNIQUE_BOARD_ID_SIZE_BYTES]; } pico_unique_board_id_t;
|
||||
#endif
|
||||
extern pico_unique_board_id_t pico_serial;
|
||||
extern char pico_serial_str[2 * PICO_UNIQUE_BOARD_ID_SIZE_BYTES + 1];
|
||||
|
||||
#endif
|
||||
117
src/pico_time.c
Normal file
117
src/pico_time.c
Normal file
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
|
||||
* Copyright (c) 2022 Pol Henarejos.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "picokeys.h"
|
||||
#include "pico_time.h"
|
||||
#ifdef ESP_PLATFORM
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#include <windows.h>
|
||||
PACK(struct timezone
|
||||
{
|
||||
__int32 tz_minuteswest; /* minutes W of Greenwich */
|
||||
bool tz_dsttime; /* type of dst correction */
|
||||
});
|
||||
int gettimeofday(struct timeval* tp, struct timezone* tzp) {
|
||||
(void)tzp;
|
||||
// Note: some broken versions only have 8 trailing zero's, the correct epoch has 9 trailing zero's
|
||||
// This magic number is the number of 100 nanosecond intervals since January 1, 1601 (UTC)
|
||||
// until 00:00:00 January 1, 1970
|
||||
static const uint64_t EPOCH = ((uint64_t)116444736000000000ULL);
|
||||
|
||||
SYSTEMTIME system_time;
|
||||
FILETIME file_time;
|
||||
uint64_t time;
|
||||
|
||||
GetSystemTime(&system_time);
|
||||
SystemTimeToFileTime(&system_time, &file_time);
|
||||
time = ((uint64_t)file_time.dwLowDateTime);
|
||||
time += ((uint64_t)file_time.dwHighDateTime) << 32;
|
||||
|
||||
tp->tv_sec = (long)((time - EPOCH) / 10000000L);
|
||||
tp->tv_usec = (long)(system_time.wMilliseconds * 1000);
|
||||
return 0;
|
||||
}
|
||||
int settimeofday(const struct timeval* tp, const struct timezone* tzp) {
|
||||
(void)tzp;
|
||||
SYSTEMTIME st;
|
||||
FILETIME ft;
|
||||
uint64_t time;
|
||||
|
||||
time = ((uint64_t)tp->tv_sec * 10000000L) + ((uint64_t)tp->tv_usec * 10) + ((uint64_t)116444736000000000ULL);
|
||||
ft.dwLowDateTime = (uint32_t)(time & 0xFFFFFFFF);
|
||||
ft.dwHighDateTime = (uint32_t)(time >> 32);
|
||||
FileTimeToSystemTime(&ft, &st);
|
||||
return SetSystemTime(&st);
|
||||
}
|
||||
#endif
|
||||
|
||||
struct tm *gmtime_utc(const time_t *timep, struct tm *result) {
|
||||
#ifdef _WIN32
|
||||
struct tm *tmp = gmtime(timep);
|
||||
if (tmp == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
*result = *tmp;
|
||||
return result;
|
||||
#else
|
||||
return gmtime_r(timep, result);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef ENABLE_EMULATION
|
||||
bool set_rtc = true;
|
||||
#else
|
||||
bool set_rtc = false;
|
||||
#endif
|
||||
|
||||
bool has_set_rtc(void) {
|
||||
return set_rtc;
|
||||
}
|
||||
|
||||
void set_rtc_time(time_t t) {
|
||||
#ifdef PICO_PLATFORM
|
||||
struct timespec tv = {.tv_sec = t, .tv_nsec = 0};
|
||||
aon_timer_set_time(&tv);
|
||||
#else
|
||||
struct timeval tv = {.tv_sec = (long)t, .tv_usec = 0};
|
||||
settimeofday(&tv, NULL);
|
||||
#endif
|
||||
set_rtc = true;
|
||||
}
|
||||
|
||||
time_t get_rtc_time(void) {
|
||||
#ifdef PICO_PLATFORM
|
||||
struct timespec tv;
|
||||
aon_timer_get_time(&tv);
|
||||
return tv.tv_sec;
|
||||
#else
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
return tv.tv_sec;
|
||||
#endif
|
||||
}
|
||||
|
||||
void init_rtc(void) {
|
||||
#ifdef PICO_PLATFORM
|
||||
struct timespec tv = {0};
|
||||
tv.tv_sec = 1577836800; // 2020-01-01
|
||||
aon_timer_start(&tv);
|
||||
#endif
|
||||
}
|
||||
41
src/pico_time.h
Normal file
41
src/pico_time.h
Normal file
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
|
||||
* Copyright (c) 2022 Pol Henarejos.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef TIME_H
|
||||
#define TIME_H
|
||||
|
||||
#if defined(PICO_PLATFORM)
|
||||
#include "pico/aon_timer.h"
|
||||
#include "bsp/board.h"
|
||||
#elif defined(ESP_PLATFORM)
|
||||
#include "compat/esp_compat.h"
|
||||
#include <time.h>
|
||||
#else
|
||||
#ifndef _MSC_VER
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
#include <time.h>
|
||||
#include "compat/board.h"
|
||||
#endif
|
||||
|
||||
extern struct tm *gmtime_utc(const time_t *timep, struct tm *result);
|
||||
extern bool has_set_rtc(void);
|
||||
extern time_t get_rtc_time(void);
|
||||
extern void set_rtc_time(time_t tv_sec);
|
||||
extern void init_rtc(void);
|
||||
|
||||
#endif // TIME_H
|
||||
175
src/picokeys.h
Normal file
175
src/picokeys.h
Normal file
@@ -0,0 +1,175 @@
|
||||
/*
|
||||
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
|
||||
* Copyright (c) 2022 Pol Henarejos.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _PICOKEYS_H_
|
||||
#define _PICOKEYS_H_
|
||||
|
||||
#define MBEDTLS_ALLOW_PRIVATE_ACCESS
|
||||
|
||||
#if defined(PICO_RP2040) || defined(PICO_RP2350)
|
||||
#define PICO_PLATFORM
|
||||
#endif
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "file.h"
|
||||
#include "flash.h"
|
||||
#include "debug.h"
|
||||
|
||||
#if !defined(MIN)
|
||||
#if defined(_MSC_VER)
|
||||
#define MIN(a,b) (((a)<(b))?(a):(b))
|
||||
#else
|
||||
#define MIN(a, b) \
|
||||
({ __typeof__ (a) _a = (a); \
|
||||
__typeof__ (b) _b = (b); \
|
||||
_a < _b ? _a : _b; })
|
||||
#endif
|
||||
#endif
|
||||
#if !defined(MAX)
|
||||
#if defined(_MSC_VER)
|
||||
#define MAX(a,b) (((a)>(b))?(a):(b))
|
||||
#else
|
||||
#define MAX(a, b) \
|
||||
({ __typeof__ (a) _a = (a); \
|
||||
__typeof__ (b) _b = (b); \
|
||||
_a > _b ? _a : _b; })
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define WEAK
|
||||
#else
|
||||
#define WEAK __attribute__((weak))
|
||||
#endif
|
||||
|
||||
extern int picokey_init(void);
|
||||
|
||||
extern void low_flash_init_core1(void);
|
||||
|
||||
static inline uint16_t make_uint16_be(uint8_t b1, uint8_t b2) {
|
||||
return (b1 << 8) | b2;
|
||||
}
|
||||
static inline uint16_t make_uint16_le(uint8_t b1, uint8_t b2) {
|
||||
return (b2 << 8) | b1;
|
||||
}
|
||||
static inline uint16_t get_uint16_be(const uint8_t *b) {
|
||||
return make_uint16_be(b[0], b[1]);
|
||||
}
|
||||
static inline uint16_t get_uint16_le(const uint8_t *b) {
|
||||
return make_uint16_le(b[0], b[1]);
|
||||
}
|
||||
static inline uint8_t put_uint16_be(uint16_t n, uint8_t *b) {
|
||||
*b++ = (n >> 8) & 0xff;
|
||||
*b = n & 0xff;
|
||||
return 2;
|
||||
}
|
||||
static inline uint8_t put_uint16_le(uint16_t n, uint8_t *b) {
|
||||
*b++ = n & 0xff;
|
||||
*b = (n >> 8) & 0xff;
|
||||
return 2;
|
||||
}
|
||||
|
||||
static inline uint32_t make_uint32_be(uint8_t b1, uint8_t b2, uint8_t b3, uint8_t b4) {
|
||||
return (b1 << 24) | (b2 << 16) | (b3 << 8) | b4;
|
||||
}
|
||||
static inline uint32_t make_uint32_le(uint8_t b1, uint8_t b2, uint8_t b3, uint8_t b4) {
|
||||
return (b4 << 24) | (b3 << 16) | (b2 << 8) | b1;
|
||||
}
|
||||
static inline uint32_t get_uint32_be(const uint8_t *b) {
|
||||
return make_uint32_be(b[0], b[1], b[2], b[3]);
|
||||
}
|
||||
static inline uint32_t get_uint32_le(const uint8_t *b) {
|
||||
return make_uint32_le(b[0], b[1], b[2], b[3]);
|
||||
}
|
||||
static inline uint8_t put_uint32_be(uint32_t n, uint8_t *b) {
|
||||
*b++ = (n >> 24) & 0xff;
|
||||
*b++ = (n >> 16) & 0xff;
|
||||
*b++ = (n >> 8) & 0xff;
|
||||
*b = n & 0xff;
|
||||
return 4;
|
||||
}
|
||||
static inline uint8_t put_uint32_le(uint32_t n, uint8_t *b) {
|
||||
*b++ = n & 0xff;
|
||||
*b++ = (n >> 8) & 0xff;
|
||||
*b++ = (n >> 16) & 0xff;
|
||||
*b = (n >> 24) & 0xff;
|
||||
return 4;
|
||||
}
|
||||
|
||||
static inline uint64_t make_uint64_be(uint8_t b1, uint8_t b2, uint8_t b3, uint8_t b4, uint8_t b5, uint8_t b6, uint8_t b7, uint8_t b8) {
|
||||
return ((uint64_t) b1 << 56) | ((uint64_t) b2 << 48) | ((uint64_t) b3 << 40) | ((uint64_t) b4 << 32) | ((uint64_t) b5 << 24) | ((uint64_t) b6 << 16) | ((uint64_t) b7 << 8) | b8;
|
||||
}
|
||||
static inline uint64_t make_uint64_le(uint8_t b1, uint8_t b2, uint8_t b3, uint8_t b4, uint8_t b5, uint8_t b6, uint8_t b7, uint8_t b8) {
|
||||
return ((uint64_t) b8 << 56) | ((uint64_t) b7 << 48) | ((uint64_t) b6 << 40) | ((uint64_t) b5 << 32) | ((uint64_t) b4 << 24) | ((uint64_t) b3 << 16) | ((uint64_t) b2 << 8) | b1;
|
||||
}
|
||||
static inline uint64_t get_uint64_be(const uint8_t *b) {
|
||||
return make_uint64_be(b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]);
|
||||
}
|
||||
static inline uint64_t get_uint64_le(const uint8_t *b) {
|
||||
return make_uint64_le(b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]);
|
||||
}
|
||||
static inline uint32_t put_uint64_be(uint64_t n, uint8_t *b) {
|
||||
*b++ = (n >> 56) & 0xff;
|
||||
*b++ = (n >> 48) & 0xff;
|
||||
*b++ = (n >> 40) & 0xff;
|
||||
*b++ = (n >> 32) & 0xff;
|
||||
*b++ = (n >> 24) & 0xff;
|
||||
*b++ = (n >> 16) & 0xff;
|
||||
*b++ = (n >> 8) & 0xff;
|
||||
*b = n & 0xff;
|
||||
return 8;
|
||||
}
|
||||
static inline uint32_t put_uint64_le(uint64_t n, uint8_t *b) {
|
||||
*b++ = n & 0xff;
|
||||
*b++ = (n >> 8) & 0xff;
|
||||
*b++ = (n >> 16) & 0xff;
|
||||
*b++ = (n >> 24) & 0xff;
|
||||
*b++ = (n >> 32) & 0xff;
|
||||
*b++ = (n >> 40) & 0xff;
|
||||
*b++ = (n >> 48) & 0xff;
|
||||
*b = (n >> 56) & 0xff;
|
||||
return 8;
|
||||
}
|
||||
|
||||
extern int (*button_pressed_cb)(uint8_t);
|
||||
|
||||
extern bool is_req_button_pending(void);
|
||||
|
||||
#define PICOKEYS_OK 0
|
||||
#define PICOKEYS_ERR_NO_MEMORY -1000
|
||||
#define PICOKEYS_ERR_MEMORY_FATAL -1001
|
||||
#define PICOKEYS_ERR_NULL_PARAM -1002
|
||||
#define PICOKEYS_ERR_FILE_NOT_FOUND -1003
|
||||
#define PICOKEYS_ERR_BLOCKED -1004
|
||||
#define PICOKEYS_NO_LOGIN -1005
|
||||
#define PICOKEYS_EXEC_ERROR -1006
|
||||
#define PICOKEYS_WRONG_LENGTH -1007
|
||||
#define PICOKEYS_WRONG_DATA -1008
|
||||
#define PICOKEYS_WRONG_DKEK -1009
|
||||
#define PICOKEYS_WRONG_SIGNATURE -1010
|
||||
#define PICOKEYS_WRONG_PADDING -1011
|
||||
#define PICOKEYS_VERIFICATION_FAILED -1012
|
||||
|
||||
#define PICOKEYS_CHECK(x) do { ret = (x); if (ret != PICOKEYS_OK) goto err; } while (0)
|
||||
|
||||
extern int set_atr(void);
|
||||
|
||||
#endif
|
||||
@@ -3,24 +3,24 @@
|
||||
* 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
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
* Affero 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/>.
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __VERSION_H_
|
||||
#define __VERSION_H_
|
||||
|
||||
#define PICO_KEYS_SDK_VERSION 0x0700
|
||||
#define PICOKEYS_SDK_VERSION 0x0806
|
||||
|
||||
#define PICO_KEYS_SDK_VERSION_MAJOR ((PICO_KEYS_SDK_VERSION >> 8) & 0xff)
|
||||
#define PICO_KEYS_SDK_VERSION_MINOR (PICO_KEYS_SDK_VERSION & 0xff)
|
||||
#define PICOKEYS_SDK_VERSION_MAJOR ((PICOKEYS_SDK_VERSION >> 8) & 0xff)
|
||||
#define PICOKEYS_SDK_VERSION_MINOR (PICOKEYS_SDK_VERSION & 0xff)
|
||||
|
||||
#endif
|
||||
364
src/rescue.c
364
src/rescue.c
@@ -3,25 +3,43 @@
|
||||
* 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
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
* Affero 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/>.
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "pico_keys.h"
|
||||
#include "picokeys.h"
|
||||
#include "serial.h"
|
||||
#include "led/led.h"
|
||||
#include <time.h>
|
||||
#include "pico_time.h"
|
||||
#ifdef PICO_PLATFORM
|
||||
#include "hardware/watchdog.h"
|
||||
#endif
|
||||
#include "apdu.h"
|
||||
#include "pico_keys_version.h"
|
||||
#include "picokeys_version.h"
|
||||
#include "otp.h"
|
||||
#include "mbedtls/ecdsa.h"
|
||||
#include "mbedtls/sha256.h"
|
||||
#include "random.h"
|
||||
#include "crypto_utils.h"
|
||||
#include "usb.h"
|
||||
|
||||
int rescue_process_apdu();
|
||||
int rescue_unload();
|
||||
|
||||
#ifdef PICO_PLATFORM
|
||||
extern char __flash_binary_start;
|
||||
extern char __flash_binary_end;
|
||||
#endif
|
||||
|
||||
static int rescue_process_apdu(void);
|
||||
static int rescue_unload(void);
|
||||
|
||||
const uint8_t rescue_aid[] = {
|
||||
8,
|
||||
@@ -29,60 +47,316 @@ const uint8_t rescue_aid[] = {
|
||||
};
|
||||
|
||||
#ifdef PICO_RP2350
|
||||
#define PICO_MCU 1
|
||||
#elif defined(ESP_PLATFORM)
|
||||
#define PICO_MCU 2
|
||||
const uint8_t PICO_MCU = 1;
|
||||
#elif defined(CONFIG_IDF_TARGET_ESP32S3)
|
||||
const uint8_t PICO_MCU = 2;
|
||||
#elif defined(ENABLE_EMULATION)
|
||||
#define PICO_MCU 3
|
||||
const uint8_t PICO_MCU = 3;
|
||||
#elif defined(CONFIG_IDF_TARGET_ESP32S2)
|
||||
const uint8_t PICO_MCU = 4;
|
||||
#else
|
||||
#define PICO_MCU 0
|
||||
const uint8_t PICO_MCU = 0;
|
||||
#endif
|
||||
|
||||
extern uint8_t PICO_PRODUCT;
|
||||
#define EF_DEVCERT_KEY 0xE0C1
|
||||
|
||||
int rescue_select(app_t *a, uint8_t force) {
|
||||
extern uint8_t PICO_PRODUCT;
|
||||
extern uint8_t PICO_VERSION_MAJOR;
|
||||
extern uint8_t PICO_VERSION_MINOR;
|
||||
|
||||
static int rescue_select(app_t *a, uint8_t force) {
|
||||
a->process_apdu = rescue_process_apdu;
|
||||
a->unload = rescue_unload;
|
||||
res_APDU_size = 0;
|
||||
res_APDU[res_APDU_size++] = PICO_MCU;
|
||||
res_APDU[res_APDU_size++] = PICO_PRODUCT;
|
||||
res_APDU[res_APDU_size++] = PICO_KEYS_SDK_VERSION_MAJOR;
|
||||
res_APDU[res_APDU_size++] = PICO_KEYS_SDK_VERSION_MINOR;
|
||||
res_APDU[res_APDU_size++] = PICO_VERSION_MAJOR;
|
||||
res_APDU[res_APDU_size++] = PICO_VERSION_MINOR;
|
||||
memcpy(res_APDU + res_APDU_size, pico_serial.id, sizeof(pico_serial.id));
|
||||
res_APDU_size += sizeof(pico_serial.id);
|
||||
apdu.ne = res_APDU_size;
|
||||
if (force) {
|
||||
scan_flash();
|
||||
file_scan_flash();
|
||||
}
|
||||
return PICOKEY_OK;
|
||||
return PICOKEYS_OK;
|
||||
}
|
||||
|
||||
const uint8_t atr_rescue[] = {
|
||||
24,
|
||||
0x3B, 0xFE, 0x18, 0x00, 0x00, 0x81, 0x31, 0xFE, 0x45, 0x80, 0x31, 0x81, 0x54, 0x48, 0x53, 0x4D,
|
||||
0x31, 0x73, 0x80, 0x21, 0x40, 0x81, 0x07, 0xFA
|
||||
};
|
||||
|
||||
extern const uint8_t *ccid_atr;
|
||||
WEAK int set_atr(void) {
|
||||
ccid_atr = atr_rescue;
|
||||
return 0;
|
||||
}
|
||||
|
||||
INITIALIZER ( rescue_ctor ) {
|
||||
register_app(rescue_select, rescue_aid);
|
||||
}
|
||||
|
||||
int rescue_unload() {
|
||||
return PICOKEY_OK;
|
||||
static int rescue_unload(void) {
|
||||
return PICOKEYS_OK;
|
||||
}
|
||||
|
||||
int cmd_write() {
|
||||
static int load_internal_keydev(mbedtls_ecp_keypair *ecp, mbedtls_ecp_group_id ec_id) {
|
||||
file_t *ef_devcert_key = file_new(EF_DEVCERT_KEY);
|
||||
if (!ef_devcert_key) {
|
||||
return SW_FILE_NOT_FOUND();
|
||||
}
|
||||
uint8_t kbase[32] = {0};
|
||||
derive_kbase(kbase);
|
||||
if (file_has_data(ef_devcert_key)) {
|
||||
uint8_t pkey[32] = {0};
|
||||
memcpy(pkey, file_get_data(ef_devcert_key), 32);
|
||||
aes_decrypt(kbase, pico_serial_hash, 32 * 8, PICOKEYS_AES_MODE_CBC, pkey, 32);
|
||||
int ret = mbedtls_ecp_read_key(ec_id, ecp, pkey, 32);
|
||||
mbedtls_platform_zeroize(pkey, sizeof(pkey));
|
||||
if (ret != 0) {
|
||||
return SW_EXEC_ERROR();
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Generate new key
|
||||
uint8_t pkey[MBEDTLS_ECP_MAX_BYTES] = {0};
|
||||
size_t olen = 0;
|
||||
mbedtls_ecp_gen_key(ec_id, ecp, random_fill_iterator, NULL);
|
||||
mbedtls_ecp_write_key_ext(ecp, &olen, pkey, sizeof(pkey));
|
||||
|
||||
aes_encrypt(kbase, pico_serial_hash, 32 * 8, PICOKEYS_AES_MODE_CBC, pkey, 32);
|
||||
file_put_data(ef_devcert_key, pkey, (uint16_t)olen);
|
||||
mbedtls_platform_zeroize(pkey, sizeof(pkey));
|
||||
flash_commit();
|
||||
}
|
||||
return PICOKEYS_OK;
|
||||
}
|
||||
|
||||
static int cmd_keydev_sign(void) {
|
||||
uint8_t p1 = P1(apdu);
|
||||
if (p1 == 0x01) {
|
||||
if (apdu.nc != 32) {
|
||||
return SW_WRONG_LENGTH();
|
||||
}
|
||||
mbedtls_ecp_keypair ecp;
|
||||
mbedtls_ecp_keypair_init(&ecp);
|
||||
mbedtls_ecp_group_id ec_id = MBEDTLS_ECP_DP_SECP256K1;
|
||||
if (!otp_key_2) {
|
||||
int ret = load_internal_keydev(&ecp, ec_id);
|
||||
if (ret != PICOKEYS_OK) {
|
||||
mbedtls_ecp_keypair_free(&ecp);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
else {
|
||||
int ret = mbedtls_ecp_read_key(ec_id, &ecp, otp_key_2, 32);
|
||||
if (ret != 0) {
|
||||
mbedtls_ecp_keypair_free(&ecp);
|
||||
return SW_EXEC_ERROR();
|
||||
}
|
||||
}
|
||||
uint16_t key_size = 2 * (int)((mbedtls_ecp_curve_info_from_grp_id(ec_id)->bit_size + 7) / 8);
|
||||
mbedtls_mpi r, s;
|
||||
mbedtls_mpi_init(&r);
|
||||
mbedtls_mpi_init(&s);
|
||||
|
||||
int ret = mbedtls_ecdsa_sign(&ecp.MBEDTLS_PRIVATE(grp), &r, &s, &ecp.MBEDTLS_PRIVATE(d), apdu.data, apdu.nc, random_fill_iterator, NULL);
|
||||
if (ret != 0) {
|
||||
mbedtls_ecp_keypair_free(&ecp);
|
||||
mbedtls_mpi_free(&r);
|
||||
mbedtls_mpi_free(&s);
|
||||
return SW_EXEC_ERROR();
|
||||
}
|
||||
|
||||
mbedtls_mpi_write_binary(&r, res_APDU, key_size / 2); res_APDU_size = key_size / 2;
|
||||
mbedtls_mpi_write_binary(&s, res_APDU + res_APDU_size, key_size / 2); res_APDU_size += key_size / 2;
|
||||
mbedtls_ecp_keypair_free(&ecp);
|
||||
mbedtls_mpi_free(&r);
|
||||
mbedtls_mpi_free(&s);
|
||||
}
|
||||
else if (p1 == 0x02) {
|
||||
// Return public key
|
||||
if (apdu.nc != 0) {
|
||||
return SW_WRONG_LENGTH();
|
||||
}
|
||||
mbedtls_ecp_keypair ecp;
|
||||
mbedtls_ecp_keypair_init(&ecp);
|
||||
mbedtls_ecp_group_id ec_id = MBEDTLS_ECP_DP_SECP256K1;
|
||||
if (!otp_key_2) {
|
||||
int ret = load_internal_keydev(&ecp, ec_id);
|
||||
if (ret != PICOKEYS_OK) {
|
||||
mbedtls_ecp_keypair_free(&ecp);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
else {
|
||||
int ret = mbedtls_ecp_read_key(ec_id, &ecp, otp_key_2, 32);
|
||||
if (ret != 0) {
|
||||
mbedtls_ecp_keypair_free(&ecp);
|
||||
return SW_EXEC_ERROR();
|
||||
}
|
||||
}
|
||||
int ret = mbedtls_ecp_keypair_calc_public(&ecp, random_fill_iterator, NULL);
|
||||
if (ret != 0) {
|
||||
mbedtls_ecp_keypair_free(&ecp);
|
||||
return SW_EXEC_ERROR();
|
||||
}
|
||||
size_t olen = 0;
|
||||
ret = mbedtls_ecp_point_write_binary(&ecp.MBEDTLS_PRIVATE(grp), &ecp.MBEDTLS_PRIVATE(Q), MBEDTLS_ECP_PF_UNCOMPRESSED, &olen, res_APDU, 2038);
|
||||
if (ret != 0) {
|
||||
mbedtls_ecp_keypair_free(&ecp);
|
||||
return SW_EXEC_ERROR();
|
||||
}
|
||||
res_APDU_size = (uint16_t)olen;
|
||||
mbedtls_ecp_keypair_free(&ecp);
|
||||
}
|
||||
else if (p1 == 0x03) {
|
||||
// Upload device attestation certificate
|
||||
if (apdu.nc == 0) {
|
||||
return SW_WRONG_LENGTH();
|
||||
}
|
||||
file_t *ef_devcert = file_new(0x2F02); // EF_DEVCERT
|
||||
if (!ef_devcert) {
|
||||
return SW_FILE_NOT_FOUND();
|
||||
}
|
||||
file_put_data(ef_devcert, apdu.data, (uint16_t)apdu.nc);
|
||||
res_APDU_size = 0;
|
||||
flash_commit();
|
||||
}
|
||||
else {
|
||||
return SW_INCORRECT_P1P2();
|
||||
}
|
||||
return SW_OK();
|
||||
}
|
||||
|
||||
// Blocking CORE1
|
||||
static void led_3_blinks(void) {
|
||||
#ifndef ENABLE_EMULATION
|
||||
uint32_t mode = led_get_mode();
|
||||
led_set_mode(MODE_PROCESSING);
|
||||
sleep_ms(500);
|
||||
led_set_mode(mode);
|
||||
#endif
|
||||
}
|
||||
|
||||
static int cmd_write(void) {
|
||||
if (apdu.nc < 2) {
|
||||
return SW_WRONG_LENGTH();
|
||||
}
|
||||
|
||||
if (P1(apdu) == 0x1) { // PHY
|
||||
uint8_t p1 = P1(apdu), p2 = P2(apdu);
|
||||
|
||||
if (p1 == 0x1) { // PHY
|
||||
#ifndef ENABLE_EMULATION
|
||||
int ret = phy_unserialize_data(apdu.data, apdu.nc, &phy_data);
|
||||
if (ret == PICOKEY_OK) {
|
||||
if (phy_save() != PICOKEY_OK) {
|
||||
int ret = phy_unserialize_data(apdu.data, (uint16_t)apdu.nc, &phy_data);
|
||||
if (ret == PICOKEYS_OK) {
|
||||
if (phy_save() != PICOKEYS_OK) {
|
||||
return SW_EXEC_ERROR();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else if (p1 == 0x2) { // SET TIME
|
||||
time_t tv_sec = 0;
|
||||
if (p2 != 0x1 && p2 != 0x2) {
|
||||
return SW_INCORRECT_P1P2();
|
||||
}
|
||||
if (p2 == 0x1) {
|
||||
if (apdu.nc != 8) {
|
||||
return SW_WRONG_LENGTH();
|
||||
}
|
||||
struct tm tm;
|
||||
tm.tm_year = get_uint16_be(apdu.data) - 1900;
|
||||
tm.tm_mon = apdu.data[2];
|
||||
tm.tm_mday = apdu.data[3];
|
||||
tm.tm_wday = apdu.data[4];
|
||||
tm.tm_hour = apdu.data[5];
|
||||
tm.tm_min = apdu.data[6];
|
||||
tm.tm_sec = apdu.data[7];
|
||||
tv_sec = mktime(&tm);
|
||||
}
|
||||
else if (p2 == 0x2) {
|
||||
if (apdu.nc != 4) {
|
||||
return SW_WRONG_LENGTH();
|
||||
}
|
||||
uint32_t t = (apdu.data[0] << 24) | (apdu.data[1] << 16) | (apdu.data[2] << 8) | apdu.data[3];
|
||||
tv_sec = (time_t)t;
|
||||
}
|
||||
set_rtc_time(tv_sec);
|
||||
}
|
||||
led_3_blinks();
|
||||
return SW_OK();
|
||||
}
|
||||
|
||||
static int cmd_read(void) {
|
||||
if (apdu.nc != 0) {
|
||||
return SW_WRONG_LENGTH();
|
||||
}
|
||||
|
||||
uint8_t p1 = P1(apdu), p2 = P2(apdu);
|
||||
if (p1 == 0x1) { // PHY
|
||||
#ifndef ENABLE_EMULATION
|
||||
uint16_t len = 0;
|
||||
int ret = phy_serialize_data(&phy_data, apdu.rdata, &len);
|
||||
if (ret != PICOKEYS_OK) {
|
||||
return SW_EXEC_ERROR();
|
||||
}
|
||||
res_APDU_size = len;
|
||||
#endif
|
||||
}
|
||||
else if (p1 == 0x2) { // FLASH INFO
|
||||
res_APDU_size = 0;
|
||||
uint32_t free = flash_free_space(), total = flash_total_space(), used = flash_used_space(), nfiles = flash_num_files(), size = flash_size();
|
||||
res_APDU_size += put_uint32_be(free, res_APDU + res_APDU_size);
|
||||
res_APDU_size += put_uint32_be(used, res_APDU + res_APDU_size);
|
||||
res_APDU_size += put_uint32_be(total, res_APDU + res_APDU_size);
|
||||
res_APDU_size += put_uint32_be(nfiles, res_APDU + res_APDU_size);
|
||||
res_APDU_size += put_uint32_be(size, res_APDU + res_APDU_size);
|
||||
#ifdef PICO_PLATFORM
|
||||
uintptr_t start = (uintptr_t) &__flash_binary_start;
|
||||
uintptr_t end = (uintptr_t) &__flash_binary_end;
|
||||
uint32_t fw_size = (uint32_t)(end - start);
|
||||
res_APDU_size += put_uint32_be(fw_size, res_APDU + res_APDU_size);
|
||||
#endif
|
||||
}
|
||||
else if (p1 == 0x3) { // OTP SECURE BOOT STATUS
|
||||
res_APDU_size = 0;
|
||||
uint8_t bootkey = 0xFF;
|
||||
bool enabled = otp_is_secure_boot_enabled(&bootkey);
|
||||
bool locked = otp_is_secure_boot_locked();
|
||||
res_APDU[res_APDU_size++] = enabled ? 0x1 : 0x0;
|
||||
res_APDU[res_APDU_size++] = locked ? 0x1 : 0x0;
|
||||
res_APDU[res_APDU_size++] = bootkey;
|
||||
}
|
||||
else if (p1 == 0x4) { // GET TIME
|
||||
if (p2 != 0x1 && p2 != 0x2) {
|
||||
return SW_INCORRECT_P1P2();
|
||||
}
|
||||
if (!has_set_rtc()) {
|
||||
return SW_CONDITIONS_NOT_SATISFIED();
|
||||
}
|
||||
res_APDU_size = 0;
|
||||
time_t tv_sec = get_rtc_time();
|
||||
if (p2 == 0x1) {
|
||||
struct tm *tm = localtime(&tv_sec);
|
||||
res_APDU_size += put_uint16_be((uint16_t)(tm->tm_year + 1900), res_APDU);
|
||||
res_APDU[res_APDU_size++] = (uint8_t)tm->tm_mon;
|
||||
res_APDU[res_APDU_size++] = (uint8_t)tm->tm_mday;
|
||||
res_APDU[res_APDU_size++] = (uint8_t)tm->tm_wday;
|
||||
res_APDU[res_APDU_size++] = (uint8_t)tm->tm_hour;
|
||||
res_APDU[res_APDU_size++] = (uint8_t)tm->tm_min;
|
||||
res_APDU[res_APDU_size++] = (uint8_t)tm->tm_sec;
|
||||
}
|
||||
else if (p2 == 0x2) {
|
||||
res_APDU_size += put_uint32_be((uint32_t)tv_sec, res_APDU);
|
||||
}
|
||||
}
|
||||
return SW_OK();
|
||||
}
|
||||
|
||||
#if defined(PICO_RP2350) || defined(ESP_PLATFORM)
|
||||
int cmd_secure() {
|
||||
static int cmd_secure(void) {
|
||||
if (apdu.nc != 0) {
|
||||
return SW_WRONG_LENGTH();
|
||||
}
|
||||
@@ -91,25 +365,57 @@ int cmd_secure() {
|
||||
bool secure_lock = P2(apdu) == 0x1;
|
||||
|
||||
int ret = otp_enable_secure_boot(bootkey, secure_lock);
|
||||
if (ret != 0) {
|
||||
if (ret != PICOKEYS_OK) {
|
||||
return SW_EXEC_ERROR();
|
||||
}
|
||||
led_3_blinks();
|
||||
return SW_OK();
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef PICO_PLATFORM
|
||||
static int cmd_reboot_bootsel(void) {
|
||||
if (apdu.nc != 0) {
|
||||
return SW_WRONG_LENGTH();
|
||||
}
|
||||
|
||||
if (P1(apdu) == 0x1) {
|
||||
// Reboot to BOOTSEL
|
||||
uint32_t val = EV_RESET;
|
||||
queue_try_add(&card_to_usb_q, &val);
|
||||
}
|
||||
else if (P1(apdu) == 0x0) {
|
||||
// Reboot to normal mode
|
||||
watchdog_reboot(0, 0, 100);
|
||||
}
|
||||
else {
|
||||
return SW_INCORRECT_P1P2();
|
||||
}
|
||||
|
||||
return SW_OK();
|
||||
}
|
||||
#endif
|
||||
|
||||
#define INS_KEYDEV_SIGN 0x10
|
||||
#define INS_WRITE 0x1C
|
||||
#define INS_SECURE 0x1D
|
||||
#define INS_READ 0x1E
|
||||
#define INS_REBOOT_BOOTSEL 0x1F
|
||||
|
||||
static const cmd_t cmds[] = {
|
||||
{ INS_KEYDEV_SIGN, cmd_keydev_sign },
|
||||
{ INS_WRITE, cmd_write },
|
||||
#if defined(PICO_RP2350) || defined(ESP_PLATFORM)
|
||||
{ INS_SECURE, cmd_secure },
|
||||
#endif
|
||||
{ INS_READ, cmd_read },
|
||||
#ifdef PICO_PLATFORM
|
||||
{ INS_REBOOT_BOOTSEL, cmd_reboot_bootsel },
|
||||
#endif
|
||||
{ 0x00, 0x0 }
|
||||
};
|
||||
|
||||
int rescue_process_apdu() {
|
||||
static int rescue_process_apdu(void) {
|
||||
if (CLA(apdu) != 0x80) {
|
||||
return SW_CLA_NOT_SUPPORTED();
|
||||
}
|
||||
|
||||
192
src/rng/hwrng.c
192
src/rng/hwrng.c
@@ -3,87 +3,100 @@
|
||||
* 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
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
* Affero 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/>.
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#if defined(ENABLE_EMULATION)
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include "emulation.h"
|
||||
#elif (ESP_PLATFORM)
|
||||
#include "picokeys.h"
|
||||
#include "hwrng.h"
|
||||
#include "pico_time.h"
|
||||
|
||||
#if defined(PICO_PLATFORM)
|
||||
#include "pico/rand.h"
|
||||
#include "pico/mutex.h"
|
||||
#elif defined(ESP_PLATFORM)
|
||||
#include "bootloader_random.h"
|
||||
#include "esp_random.h"
|
||||
#include "esp_compat.h"
|
||||
#include "compat/esp_compat.h"
|
||||
#else
|
||||
#include "pico/stdlib.h"
|
||||
#include "hwrng.h"
|
||||
#include "bsp/board.h"
|
||||
#include "pico/rand.h"
|
||||
#include "compat/queue.h"
|
||||
#endif
|
||||
|
||||
void hwrng_start() {
|
||||
static void hwrng_start(void) {
|
||||
#if defined(ENABLE_EMULATION)
|
||||
srand(time(0));
|
||||
srand((unsigned int)time(NULL));
|
||||
#elif defined(ESP_PLATFORM)
|
||||
bootloader_random_enable();
|
||||
#endif
|
||||
}
|
||||
|
||||
static uint64_t random_word = 0xcbf29ce484222325;
|
||||
static uint8_t ep_round = 0;
|
||||
static uint8_t hwrng_mix_round = 0;
|
||||
|
||||
static void ep_init() {
|
||||
static void hwrng_mix_init(void) {
|
||||
random_word = 0xcbf29ce484222325;
|
||||
ep_round = 0;
|
||||
hwrng_mix_round = 0;
|
||||
}
|
||||
|
||||
/* Here, we assume a little endian architecture. */
|
||||
static int ep_process() {
|
||||
if (ep_round == 0) {
|
||||
ep_init();
|
||||
static int hwrng_mix_process(void) {
|
||||
if (hwrng_mix_round == 0) {
|
||||
hwrng_mix_init();
|
||||
}
|
||||
uint64_t word = 0x0;
|
||||
|
||||
#if defined(ENABLE_EMULATION)
|
||||
word = rand();
|
||||
word <<= 32;
|
||||
word |= rand();
|
||||
#if defined(PICO_PLATFORM)
|
||||
word = get_rand_64();
|
||||
#elif defined(ESP_PLATFORM)
|
||||
esp_fill_random((uint8_t *)&word, sizeof(word));
|
||||
#else
|
||||
word = get_rand_64();
|
||||
word = rand();
|
||||
word <<= 32;
|
||||
word |= rand();
|
||||
#endif
|
||||
random_word ^= word ^ board_millis();
|
||||
random_word *= 0x00000100000001B3;
|
||||
if (++ep_round == 8) {
|
||||
ep_round = 0;
|
||||
return 2; //2 words
|
||||
if (++hwrng_mix_round == 8) {
|
||||
hwrng_mix_round = 0;
|
||||
return sizeof(uint64_t) / sizeof(uint32_t); //2 words
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct rng_rb {
|
||||
PACK(
|
||||
typedef struct hwrng_buf {
|
||||
uint32_t *buf;
|
||||
uint8_t head, tail;
|
||||
uint8_t head;
|
||||
uint8_t tail;
|
||||
uint8_t size;
|
||||
unsigned int full : 1;
|
||||
unsigned int empty : 1;
|
||||
};
|
||||
}) hwrng_buf_t;
|
||||
|
||||
static void rb_init(struct rng_rb *rb, uint32_t *p, uint8_t size) {
|
||||
static mutex_t hwrng_mutex;
|
||||
static bool hwrng_mutex_initialized = false;
|
||||
|
||||
static inline void hwrng_lock(void) {
|
||||
if (hwrng_mutex_initialized) {
|
||||
mutex_enter_blocking(&hwrng_mutex);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void hwrng_unlock(void) {
|
||||
if (hwrng_mutex_initialized) {
|
||||
mutex_exit(&hwrng_mutex);
|
||||
}
|
||||
}
|
||||
|
||||
static void hwrng_buf_init(struct hwrng_buf *rb, uint32_t *p, uint8_t size) {
|
||||
rb->buf = p;
|
||||
rb->size = size;
|
||||
rb->head = rb->tail = 0;
|
||||
@@ -91,23 +104,35 @@ static void rb_init(struct rng_rb *rb, uint32_t *p, uint8_t size) {
|
||||
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;
|
||||
static void hwrng_buf_add(struct hwrng_buf *rb, uint32_t v) {
|
||||
if (rb->full) {
|
||||
return;
|
||||
}
|
||||
if (rb->tail == rb->head) {
|
||||
rb->full = 1;
|
||||
|
||||
uint8_t tail = rb->tail;
|
||||
rb->buf[tail] = v;
|
||||
tail++;
|
||||
if (tail >= rb->size) {
|
||||
tail = 0;
|
||||
}
|
||||
rb->tail = tail;
|
||||
rb->full = (rb->tail == rb->head);
|
||||
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;
|
||||
static uint32_t hwrng_buf_del(struct hwrng_buf *rb) {
|
||||
uint32_t v = 0;
|
||||
if (rb->empty) {
|
||||
return v;
|
||||
}
|
||||
|
||||
uint8_t head = rb->head;
|
||||
v = rb->buf[head];
|
||||
head++;
|
||||
if (head >= rb->size) {
|
||||
head = 0;
|
||||
}
|
||||
rb->head = head;
|
||||
if (rb->head == rb->tail) {
|
||||
rb->empty = 1;
|
||||
}
|
||||
@@ -116,73 +141,86 @@ static uint32_t rb_del(struct rng_rb *rb) {
|
||||
return v;
|
||||
}
|
||||
|
||||
static struct rng_rb the_ring_buffer;
|
||||
static struct hwrng_buf ring_buffer;
|
||||
|
||||
void *neug_task() {
|
||||
struct rng_rb *rb = &the_ring_buffer;
|
||||
void *hwrng_task(void) {
|
||||
struct hwrng_buf *rb = &ring_buffer;
|
||||
|
||||
int n;
|
||||
|
||||
if ((n = ep_process())) {
|
||||
int i;
|
||||
hwrng_lock();
|
||||
if ((n = hwrng_mix_process())) {
|
||||
const uint32_t *vp = (const uint32_t *) &random_word;
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
rb_add(rb, *vp++);
|
||||
for (int i = 0; i < n; i++) {
|
||||
hwrng_buf_add(rb, *vp++);
|
||||
if (rb->full) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
hwrng_unlock();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void neug_init(uint32_t *buf, uint8_t size) {
|
||||
struct rng_rb *rb = &the_ring_buffer;
|
||||
void hwrng_init(uint32_t *buf, uint8_t size) {
|
||||
struct hwrng_buf *rb = &ring_buffer;
|
||||
|
||||
rb_init(rb, buf, size);
|
||||
mutex_init(&hwrng_mutex);
|
||||
hwrng_mutex_initialized = true;
|
||||
hwrng_buf_init(rb, buf, size);
|
||||
|
||||
hwrng_start();
|
||||
|
||||
ep_init();
|
||||
hwrng_mix_init();
|
||||
}
|
||||
|
||||
void neug_flush(void) {
|
||||
struct rng_rb *rb = &the_ring_buffer;
|
||||
|
||||
void hwrng_flush(void) {
|
||||
struct hwrng_buf *rb = &ring_buffer;
|
||||
hwrng_lock();
|
||||
while (!rb->empty) {
|
||||
rb_del(rb);
|
||||
hwrng_buf_del(rb);
|
||||
}
|
||||
hwrng_unlock();
|
||||
}
|
||||
|
||||
uint32_t neug_get() {
|
||||
struct rng_rb *rb = &the_ring_buffer;
|
||||
uint32_t hwrng_get(void) {
|
||||
struct hwrng_buf *rb = &ring_buffer;
|
||||
uint32_t v;
|
||||
|
||||
while (rb->empty) {
|
||||
neug_task();
|
||||
while (true) {
|
||||
hwrng_lock();
|
||||
if (!rb->empty) {
|
||||
v = hwrng_buf_del(rb);
|
||||
hwrng_unlock();
|
||||
break;
|
||||
}
|
||||
hwrng_unlock();
|
||||
hwrng_task();
|
||||
}
|
||||
v = rb_del(rb);
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
void neug_wait_full() {
|
||||
struct rng_rb *rb = &the_ring_buffer;
|
||||
#ifndef ENABLE_EMULATION
|
||||
void hwrng_wait_full(void) {
|
||||
struct hwrng_buf *rb = &ring_buffer;
|
||||
#ifdef ESP_PLATFORM
|
||||
uint8_t core = xTaskGetCurrentTaskHandle() == hcore1 ? 1 : 0;
|
||||
#else
|
||||
#elif defined(PICO_PLATFORM)
|
||||
uint core = get_core_num();
|
||||
#endif
|
||||
#endif
|
||||
while (!rb->full) {
|
||||
#ifndef ENABLE_EMULATION
|
||||
while (true) {
|
||||
hwrng_lock();
|
||||
hwrng_unlock();
|
||||
if (rb->full) {
|
||||
break;
|
||||
}
|
||||
#if defined(PICO_PLATFORM) || defined(ESP_PLATFORM)
|
||||
if (core == 1) {
|
||||
sleep_ms(1);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
neug_task();
|
||||
hwrng_task();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,31 +3,26 @@
|
||||
* 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
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
* Affero 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/>.
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _NEUG_H_
|
||||
#define _NEUG_H_
|
||||
#include <stdint.h>
|
||||
|
||||
#define NEUG_PRE_LOOP 32
|
||||
|
||||
#include <stdlib.h>
|
||||
#if !defined(ENABLE_EMULATION) && !defined(ESP_PLATFORM)
|
||||
#include "pico/stdlib.h"
|
||||
#endif
|
||||
|
||||
void neug_init(uint32_t *buf, uint8_t size);
|
||||
uint32_t neug_get();
|
||||
void neug_flush(void);
|
||||
void neug_wait_full();
|
||||
void hwrng_init(uint32_t *buf, uint8_t size);
|
||||
uint32_t hwrng_get(void);
|
||||
void hwrng_flush(void);
|
||||
void hwrng_wait_full(void);
|
||||
void *hwrng_task(void);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -3,75 +3,96 @@
|
||||
* 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
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
* Affero 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/>.
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#define HWRNG_PRE_LOOP 32
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "picokeys.h"
|
||||
#include "hwrng.h"
|
||||
#include "random.h"
|
||||
#if defined(PICO_PLATFORM)
|
||||
#include "pico/mutex.h"
|
||||
#elif defined(ESP_PLATFORM)
|
||||
#include "compat/esp_compat.h"
|
||||
#else
|
||||
#include "compat/queue.h"
|
||||
#endif
|
||||
|
||||
#define RANDOM_BYTES_LENGTH 32
|
||||
static uint32_t random_word[RANDOM_BYTES_LENGTH / sizeof(uint32_t)];
|
||||
static mutex_t random_mutex;
|
||||
static bool random_mutex_initialized = false;
|
||||
|
||||
void random_init(void) {
|
||||
int i;
|
||||
mutex_init(&random_mutex);
|
||||
random_mutex_initialized = true;
|
||||
hwrng_init(random_word, RANDOM_BYTES_LENGTH / sizeof(uint32_t));
|
||||
|
||||
neug_init(random_word, RANDOM_BYTES_LENGTH / sizeof(uint32_t));
|
||||
|
||||
for (i = 0; i < NEUG_PRE_LOOP; i++) {
|
||||
neug_get();
|
||||
for (int i = 0; i < HWRNG_PRE_LOOP; i++) {
|
||||
hwrng_get();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Free pointer to random 32-byte
|
||||
*/
|
||||
static void random_bytes_free(const uint8_t *p) {
|
||||
(void) p;
|
||||
memset(random_word, 0, RANDOM_BYTES_LENGTH);
|
||||
hwrng_flush();
|
||||
}
|
||||
|
||||
/*
|
||||
* 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)];
|
||||
if (random_mutex_initialized) {
|
||||
mutex_enter_blocking(&random_mutex);
|
||||
}
|
||||
for (size_t ix = 0; ix < len; ix += RANDOM_BYTES_LENGTH) {
|
||||
neug_wait_full();
|
||||
hwrng_wait_full();
|
||||
memcpy(return_word + ix / sizeof(uint32_t), random_word, RANDOM_BYTES_LENGTH);
|
||||
random_bytes_free((const uint8_t *) random_word);
|
||||
}
|
||||
if (random_mutex_initialized) {
|
||||
mutex_exit(&random_mutex);
|
||||
}
|
||||
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();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* 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;
|
||||
int random_fill_iterator(void *arg, unsigned char *out, size_t out_len) {
|
||||
random_fill_iterator_ctx_t *ctx = (random_fill_iterator_ctx_t *) arg;
|
||||
uint8_t index = ctx ? ctx->index : 0;
|
||||
uint8_t n;
|
||||
int ret = 0;
|
||||
|
||||
if (random_mutex_initialized) {
|
||||
mutex_enter_blocking(&random_mutex);
|
||||
}
|
||||
while (out_len) {
|
||||
neug_wait_full();
|
||||
if (ctx && ctx->cancel) {
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
hwrng_wait_full();
|
||||
|
||||
n = RANDOM_BYTES_LENGTH - index;
|
||||
if (n > out_len) {
|
||||
@@ -85,13 +106,20 @@ int random_gen(void *arg, unsigned char *out, size_t out_len) {
|
||||
|
||||
if (index >= RANDOM_BYTES_LENGTH) {
|
||||
index = 0;
|
||||
neug_flush();
|
||||
hwrng_flush();
|
||||
}
|
||||
}
|
||||
|
||||
if (index_p) {
|
||||
*index_p = index;
|
||||
if (ctx) {
|
||||
ctx->index = index;
|
||||
}
|
||||
if (random_mutex_initialized) {
|
||||
mutex_exit(&random_mutex);
|
||||
}
|
||||
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int random_fill_buffer(uint8_t *buf, size_t n) {
|
||||
return random_fill_iterator(NULL, buf, n);
|
||||
}
|
||||
|
||||
@@ -3,16 +3,16 @@
|
||||
* 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
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
* Affero 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/>.
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
@@ -21,14 +21,18 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
void random_init(void);
|
||||
typedef struct {
|
||||
uint8_t index;
|
||||
volatile bool cancel;
|
||||
} random_fill_iterator_ctx_t;
|
||||
|
||||
/* 32-byte random bytes */
|
||||
const uint8_t *random_bytes_get(size_t);
|
||||
void random_bytes_free(const uint8_t *p);
|
||||
extern void
|
||||
random_init(void);
|
||||
|
||||
/* iterator returning a byta at a time */
|
||||
extern int random_gen(void *arg, unsigned char *output, size_t output_len);
|
||||
extern const uint8_t *random_bytes_get(size_t);
|
||||
extern int random_fill_iterator(void *arg, unsigned char *output, size_t output_len);
|
||||
extern int random_fill_buffer(uint8_t *buf, size_t n);
|
||||
|
||||
#endif
|
||||
|
||||
247
src/serial.c
Normal file
247
src/serial.c
Normal file
@@ -0,0 +1,247 @@
|
||||
/*
|
||||
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
|
||||
* Copyright (c) 2022 Pol Henarejos.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "picokeys.h"
|
||||
#include "serial.h"
|
||||
#include "mbedtls/sha256.h"
|
||||
#if defined(ESP_PLATFORM)
|
||||
#include "esp_efuse.h"
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#ifndef ESP_PLATFORM
|
||||
#include <time.h>
|
||||
#endif
|
||||
|
||||
#if defined(__APPLE__)
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#include <IOKit/IOKitLib.h>
|
||||
|
||||
static int get_macos_serial(uint8_t *out) {
|
||||
io_service_t platformExpert;
|
||||
CFTypeRef serialNumberAsCFString;
|
||||
char serial[32] = {0};
|
||||
if (!out) {
|
||||
return -1;
|
||||
}
|
||||
out[0] = '\0';
|
||||
platformExpert = IOServiceGetMatchingService(kIOMainPortDefault, IOServiceMatching("IOPlatformExpertDevice"));
|
||||
if (!platformExpert) {
|
||||
return -2;
|
||||
}
|
||||
serialNumberAsCFString = IORegistryEntryCreateCFProperty(platformExpert, CFSTR("IOPlatformSerialNumber"), kCFAllocatorDefault, 0);
|
||||
IOObjectRelease(platformExpert);
|
||||
if (!serialNumberAsCFString) {
|
||||
return -3;
|
||||
}
|
||||
Boolean ok = CFStringGetCString(serialNumberAsCFString, serial, sizeof(serial), kCFStringEncodingUTF8);
|
||||
CFRelease(serialNumberAsCFString);
|
||||
if (ok) {
|
||||
mbedtls_sha256((const unsigned char *)serial, strlen(serial), pico_serial_hash, false);
|
||||
memcpy(out, pico_serial_hash, PICO_UNIQUE_BOARD_ID_SIZE_BYTES);
|
||||
}
|
||||
return ok ? 0 : -4;
|
||||
}
|
||||
#elif defined(_MSC_VER)
|
||||
#include <windows.h>
|
||||
#include <wbemidl.h>
|
||||
|
||||
#pragma comment(lib, "wbemuuid.lib")
|
||||
|
||||
static int get_system_uuid(char *out) {
|
||||
char serial[64] = {0};
|
||||
HRESULT hr;
|
||||
IWbemLocator *locator = NULL;
|
||||
IWbemServices *svc = NULL;
|
||||
IEnumWbemClassObject *enumerator = NULL;
|
||||
IWbemClassObject *obj = NULL;
|
||||
ULONG returned = 0;
|
||||
VARIANT vtProp;
|
||||
hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
|
||||
if (FAILED(hr) && hr != RPC_E_CHANGED_MODE)
|
||||
return -1;
|
||||
hr = CoInitializeSecurity( NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_DEFAULT, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE, NULL);
|
||||
if (FAILED(hr) && hr != RPC_E_TOO_LATE) {
|
||||
CoUninitialize();
|
||||
return -2;
|
||||
}
|
||||
hr = CoCreateInstance(&CLSID_WbemLocator, NULL, CLSCTX_INPROC_SERVER, &IID_IWbemLocator, (LPVOID *)&locator);
|
||||
if (FAILED(hr)) {
|
||||
CoUninitialize();
|
||||
return -3;
|
||||
}
|
||||
hr = locator->lpVtbl->ConnectServer(locator, L"ROOT\\CIMV2", NULL, NULL, NULL, 0, NULL, NULL, &svc);
|
||||
if (FAILED(hr)) {
|
||||
locator->lpVtbl->Release(locator);
|
||||
CoUninitialize();
|
||||
return -4;
|
||||
}
|
||||
hr = CoSetProxyBlanket((IUnknown *)svc, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL, RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE);
|
||||
if (FAILED(hr)) {
|
||||
svc->lpVtbl->Release(svc);
|
||||
locator->lpVtbl->Release(locator);
|
||||
CoUninitialize();
|
||||
return -5;
|
||||
}
|
||||
hr = svc->lpVtbl->ExecQuery(svc, L"WQL", L"SELECT UUID FROM Win32_ComputerSystemProduct", WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, NULL, &enumerator);
|
||||
if (FAILED(hr) || !enumerator) {
|
||||
svc->lpVtbl->Release(svc);
|
||||
locator->lpVtbl->Release(locator);
|
||||
CoUninitialize();
|
||||
return -6;
|
||||
}
|
||||
hr = enumerator->lpVtbl->Next( enumerator, WBEM_INFINITE, 1, &obj, &returned);
|
||||
if (returned == 0 || !obj) {
|
||||
enumerator->lpVtbl->Release(enumerator);
|
||||
svc->lpVtbl->Release(svc);
|
||||
locator->lpVtbl->Release(locator);
|
||||
CoUninitialize();
|
||||
return -7;
|
||||
}
|
||||
VariantInit(&vtProp);
|
||||
hr = obj->lpVtbl->Get(obj, L"UUID", 0, &vtProp, NULL, NULL);
|
||||
if (SUCCEEDED(hr) && vtProp.vt == VT_BSTR && vtProp.bstrVal) {
|
||||
WideCharToMultiByte(CP_UTF8, 0, vtProp.bstrVal, -1, serial, (int)sizeof(serial), NULL, NULL);
|
||||
}
|
||||
VariantClear(&vtProp);
|
||||
obj->lpVtbl->Release(obj);
|
||||
enumerator->lpVtbl->Release(enumerator);
|
||||
svc->lpVtbl->Release(svc);
|
||||
locator->lpVtbl->Release(locator);
|
||||
CoUninitialize();
|
||||
if (serial[0]) {
|
||||
mbedtls_sha256((const unsigned char *)serial, strlen(serial), pico_serial_hash, false);
|
||||
memcpy(out, pico_serial_hash, PICO_UNIQUE_BOARD_ID_SIZE_BYTES);
|
||||
}
|
||||
return serial[0] ? 0 : -8;
|
||||
}
|
||||
#elif defined(__linux__)
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
static int read_first_line(const char *path, char *out, size_t out_len) {
|
||||
FILE *f;
|
||||
if (!out || out_len == 0) {
|
||||
return -1;
|
||||
}
|
||||
out[0] = '\0';
|
||||
f = fopen(path, "r");
|
||||
if (!f) {
|
||||
return -2;
|
||||
}
|
||||
if (!fgets(out, out_len, f)) {
|
||||
fclose(f);
|
||||
return -3;
|
||||
}
|
||||
fclose(f);
|
||||
out[strcspn(out, "\r\n")] = '\0';
|
||||
return out[0] ? 0 : -4;
|
||||
}
|
||||
|
||||
static int is_bad_value(const char *s) {
|
||||
if (!s || !s[0])
|
||||
return 1;
|
||||
if (strcasecmp(s, "None") == 0)
|
||||
return 1;
|
||||
if (strcasecmp(s, "Unknown") == 0)
|
||||
return 1;
|
||||
if (strcasecmp(s, "Default string") == 0)
|
||||
return 1;
|
||||
if (strcasecmp(s, "To be filled by O.E.M.") == 0)
|
||||
return 1;
|
||||
if (strcmp(s, "00000000-0000-0000-0000-000000000000") == 0)
|
||||
return 1;
|
||||
if (strcmp(s, "FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF") == 0)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int append_field(char *out, size_t out_len, const char *prefix,const char *path) {
|
||||
char value[256];
|
||||
if (read_first_line(path, value, sizeof(value)) != 0) {
|
||||
return -1;
|
||||
}
|
||||
if (is_bad_value(value)) {
|
||||
return -2;
|
||||
}
|
||||
strncat(out, prefix, out_len - strlen(out) - 1);
|
||||
strncat(out, value, out_len - strlen(out) - 1);
|
||||
strncat(out, ";", out_len - strlen(out) - 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_linux_hardware_id(char *out) {
|
||||
if (!out) {
|
||||
return -1;
|
||||
}
|
||||
char serial[256] = {0};
|
||||
append_field(serial, sizeof(serial), "UUID=", "/sys/class/dmi/id/product_uuid");
|
||||
append_field(serial, sizeof(serial), "BOARD=", "/sys/class/dmi/id/board_serial");
|
||||
append_field(serial, sizeof(serial), "PRODUCT=", "/sys/class/dmi/id/product_serial");
|
||||
append_field(serial, sizeof(serial), "CHASSIS=", "/sys/class/dmi/id/chassis_serial");
|
||||
append_field(serial, sizeof(serial), "MACHINE=", "/etc/machine-id");
|
||||
if (serial[0]) {
|
||||
mbedtls_sha256((const unsigned char *)serial, strlen(serial), pico_serial_hash, false);
|
||||
memcpy(out, pico_serial_hash, PICO_UNIQUE_BOARD_ID_SIZE_BYTES);
|
||||
}
|
||||
return serial[0] ? 0 : -2;
|
||||
}
|
||||
#endif
|
||||
|
||||
char pico_serial_str[2 * PICO_UNIQUE_BOARD_ID_SIZE_BYTES + 1];
|
||||
uint8_t pico_serial_hash[32];
|
||||
picokey_serial_t pico_serial;
|
||||
|
||||
static int serial_id_is_zero(const uint8_t *id, size_t len) {
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
if (id[i] != 0) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
#if defined(ESP_PLATFORM)
|
||||
#define pico_get_unique_board_id(a) do { uint32_t value; esp_efuse_read_block(EFUSE_BLK1, &value, 0, 32); memcpy((uint8_t *)(a), &value, sizeof(uint32_t)); esp_efuse_read_block(EFUSE_BLK1, &value, 32, 32); memcpy((uint8_t *)(a)+4, &value, sizeof(uint32_t)); } while(0)
|
||||
#elif defined(__APPLE__)
|
||||
#define pico_get_unique_board_id(a) get_macos_serial((uint8_t *)(a))
|
||||
#elif defined(_MSC_VER)
|
||||
#define pico_get_unique_board_id(a) get_system_uuid((char *)(a))
|
||||
#elif defined(__linux__)
|
||||
#define pico_get_unique_board_id(a) get_linux_hardware_id((char *)(a))
|
||||
#endif
|
||||
|
||||
void serial_init(void) {
|
||||
int serial_rc = 0;
|
||||
|
||||
#if defined(__APPLE__) || defined(_MSC_VER) || defined(__linux__)
|
||||
serial_rc = pico_get_unique_board_id(&pico_serial);
|
||||
#else
|
||||
pico_get_unique_board_id(&pico_serial);
|
||||
#endif
|
||||
|
||||
if (serial_rc != 0 || serial_id_is_zero(pico_serial.id, sizeof(pico_serial.id))) {
|
||||
printf("serial init: failed to read stable hardware id (rc=%d); using fallback id\n", serial_rc);
|
||||
memset(pico_serial.id, 0, sizeof(pico_serial.id));
|
||||
}
|
||||
|
||||
memset(pico_serial_str, 0, sizeof(pico_serial_str));
|
||||
for (size_t i = 0; i < sizeof(pico_serial); i++) {
|
||||
snprintf(&pico_serial_str[2 * i], 3, "%02X", pico_serial.id[i]);
|
||||
}
|
||||
mbedtls_sha256(pico_serial.id, sizeof(pico_serial.id), pico_serial_hash, false);
|
||||
}
|
||||
40
src/serial.h
Normal file
40
src/serial.h
Normal file
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
|
||||
* Copyright (c) 2022 Pol Henarejos.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _SERIAL_H_
|
||||
#define _SERIAL_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#if !defined (PICO_PLATFORM)
|
||||
#if defined(__APPLE__) || defined(_MSC_VER) || defined(__linux__)
|
||||
#define PICO_UNIQUE_BOARD_ID_SIZE_BYTES 16
|
||||
#else
|
||||
#define PICO_UNIQUE_BOARD_ID_SIZE_BYTES 8
|
||||
#endif
|
||||
typedef struct { uint8_t id[PICO_UNIQUE_BOARD_ID_SIZE_BYTES]; } picokey_serial_t;
|
||||
#else
|
||||
#include "pico/unique_id.h"
|
||||
typedef pico_unique_board_id_t picokey_serial_t;
|
||||
#endif
|
||||
|
||||
extern picokey_serial_t pico_serial;
|
||||
extern char pico_serial_str[2 * PICO_UNIQUE_BOARD_ID_SIZE_BYTES + 1];
|
||||
extern uint8_t pico_serial_hash[32];
|
||||
extern void serial_init(void);
|
||||
|
||||
#endif //_SERIAL_H_
|
||||
@@ -3,44 +3,44 @@
|
||||
* 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
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
* Affero 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/>.
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "pico_keys.h"
|
||||
#include "asn1.h"
|
||||
#include "picokeys.h"
|
||||
#include "tlv.h"
|
||||
|
||||
int asn1_ctx_init(uint8_t *data, uint16_t len, asn1_ctx_t *ctx) {
|
||||
int tlv_ctx_init(uint8_t *data, uint16_t len, tlv_ctx_t *ctx) {
|
||||
if (!ctx) {
|
||||
return PICOKEY_ERR_NULL_PARAM;
|
||||
return PICOKEYS_ERR_NULL_PARAM;
|
||||
}
|
||||
ctx->data = data;
|
||||
ctx->len = len;
|
||||
return PICOKEY_OK;
|
||||
return PICOKEYS_OK;
|
||||
}
|
||||
|
||||
int asn1_ctx_clear(asn1_ctx_t *ctx) {
|
||||
int tlv_ctx_clear(tlv_ctx_t *ctx) {
|
||||
ctx->data = NULL;
|
||||
ctx->len = 0;
|
||||
return PICOKEY_OK;
|
||||
return PICOKEYS_OK;
|
||||
}
|
||||
|
||||
uint16_t asn1_len(asn1_ctx_t *ctx) {
|
||||
uint16_t tlv_len(tlv_ctx_t *ctx) {
|
||||
if (ctx->data && ctx->len > 0) {
|
||||
return ctx->len;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t asn1_get_uint(asn1_ctx_t *ctx) {
|
||||
uint32_t tlv_get_uint(tlv_ctx_t *ctx) {
|
||||
uint32_t d = ctx->data[0];
|
||||
for (uint16_t lt = 1; lt < MIN(ctx->len, sizeof(uint32_t)); lt++) {
|
||||
d <<= 8;
|
||||
@@ -49,15 +49,15 @@ uint32_t asn1_get_uint(asn1_ctx_t *ctx) {
|
||||
return d;
|
||||
}
|
||||
|
||||
uint16_t asn1_len_tag(uint16_t tag, uint16_t len) {
|
||||
uint16_t ret = 1 + format_tlv_len(len, NULL) + len;
|
||||
uint16_t tlv_len_tag(uint16_t tag, uint16_t len) {
|
||||
uint16_t ret = 1 + tlv_format_len(len, NULL) + len;
|
||||
if (tag > 0x00ff) {
|
||||
return ret + 1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint8_t format_tlv_len(uint16_t len, uint8_t *out) {
|
||||
uint8_t tlv_format_len(uint16_t len, uint8_t *out) {
|
||||
if (len < 128) {
|
||||
if (out) {
|
||||
*out = (uint8_t)len;
|
||||
@@ -73,16 +73,12 @@ uint8_t format_tlv_len(uint16_t len, uint8_t *out) {
|
||||
}
|
||||
if (out) {
|
||||
*out++ = 0x82;
|
||||
put_uint16_t_be(len, out);
|
||||
put_uint16_be(len, out);
|
||||
}
|
||||
return 3;
|
||||
}
|
||||
|
||||
int walk_tlv(const asn1_ctx_t *ctxi,
|
||||
uint8_t **p,
|
||||
uint16_t *tag,
|
||||
uint16_t *tag_len,
|
||||
uint8_t **data) {
|
||||
int tlv_walk(const tlv_ctx_t *ctxi, uint8_t **p, uint16_t *tag, uint16_t *tag_len, uint8_t **data) {
|
||||
if (!p) {
|
||||
return 0;
|
||||
}
|
||||
@@ -92,8 +88,7 @@ int walk_tlv(const asn1_ctx_t *ctxi,
|
||||
if (*p - ctxi->data >= ctxi->len) {
|
||||
return 0;
|
||||
}
|
||||
uint16_t tg = 0x0;
|
||||
uint16_t tgl = 0;
|
||||
uint16_t tg = 0x0, tgl = 0;
|
||||
tg = *(*p)++;
|
||||
if ((tg & 0x1f) == 0x1f) {
|
||||
tg <<= 8;
|
||||
@@ -120,14 +115,10 @@ int walk_tlv(const asn1_ctx_t *ctxi,
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool asn1_find_tag(const asn1_ctx_t *ctxi,
|
||||
uint16_t itag,
|
||||
asn1_ctx_t *ctxo) {
|
||||
uint16_t tag = 0x0;
|
||||
uint8_t *p = NULL;
|
||||
uint8_t *tdata = NULL;
|
||||
uint16_t tlen = 0;
|
||||
while (walk_tlv(ctxi, &p, &tag, &tlen, &tdata)) {
|
||||
bool tlv_find_tag(const tlv_ctx_t *ctxi, uint16_t itag, tlv_ctx_t *ctxo) {
|
||||
uint16_t tag = 0x0, tlen = 0;
|
||||
uint8_t *p = NULL, *tdata = NULL;
|
||||
while (tlv_walk(ctxi, &p, &tag, &tlen, &tdata)) {
|
||||
if (itag == tag) {
|
||||
if (ctxo != NULL) {
|
||||
ctxo->data = tdata;
|
||||
41
src/tlv.h
Normal file
41
src/tlv.h
Normal file
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
|
||||
* Copyright (c) 2022 Pol Henarejos.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _TLV_H_
|
||||
#define _TLV_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "compat/compat.h"
|
||||
|
||||
PACK(
|
||||
typedef struct tlv_ctx {
|
||||
uint8_t *data;
|
||||
uint16_t len;
|
||||
}) tlv_ctx_t;
|
||||
|
||||
extern int tlv_ctx_init(uint8_t *, uint16_t, tlv_ctx_t *);
|
||||
extern int tlv_ctx_clear(tlv_ctx_t *ctx);
|
||||
extern uint16_t tlv_len(tlv_ctx_t *ctx);
|
||||
extern uint32_t tlv_get_uint(tlv_ctx_t *ctx);
|
||||
|
||||
extern int tlv_walk(const tlv_ctx_t *ctxi, uint8_t **p, uint16_t *tag, uint16_t *tag_len, uint8_t **data);
|
||||
extern uint8_t tlv_format_len(uint16_t len, uint8_t *out);
|
||||
extern bool tlv_find_tag(const tlv_ctx_t *ctxi, uint16_t itag, tlv_ctx_t *ctxo);
|
||||
extern uint16_t tlv_len_tag(uint16_t tag, uint16_t len);
|
||||
|
||||
#endif
|
||||
@@ -3,20 +3,21 @@
|
||||
* 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
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
* Affero 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/>.
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "picokeys.h"
|
||||
#include "led/led.h"
|
||||
#include "random.h"
|
||||
#include "pico_keys.h"
|
||||
#ifdef PICO_PLATFORM
|
||||
#include "bsp/board.h"
|
||||
#endif
|
||||
@@ -27,7 +28,6 @@
|
||||
#include "emulation.h"
|
||||
#endif
|
||||
#include "ccid.h"
|
||||
#include "usb_descriptors.h"
|
||||
#include "apdu.h"
|
||||
#include "usb.h"
|
||||
|
||||
@@ -97,21 +97,22 @@ static uint8_t itf_num;
|
||||
static usb_buffer_t *ccid_rx = NULL, *ccid_tx = NULL;
|
||||
|
||||
int driver_process_usb_packet_ccid(uint8_t itf, uint16_t rx_read);
|
||||
void ccid_init(void);
|
||||
void ccid_task(void);
|
||||
#ifdef ENABLE_EMULATION
|
||||
void tud_vendor_rx_cb(uint8_t itf, const uint8_t *buffer, uint16_t bufsize);
|
||||
#endif
|
||||
|
||||
void ccid_write_offset(uint8_t itf, uint16_t size, uint16_t offset) {
|
||||
static void ccid_write_offset(uint8_t itf, uint16_t size, uint16_t offset) {
|
||||
ccid_tx[itf].w_ptr += size + offset;
|
||||
ccid_tx[itf].r_ptr += offset;
|
||||
}
|
||||
|
||||
void ccid_write(uint8_t itf, uint16_t size) {
|
||||
ccid_write_offset(itf, size, 0);
|
||||
}
|
||||
|
||||
ccid_header_t **ccid_response = NULL;
|
||||
ccid_header_t **ccid_resp_fast = NULL;
|
||||
ccid_header_t **ccid_header = NULL;
|
||||
|
||||
uint8_t sc_itf_to_usb_itf(uint8_t itf) {
|
||||
static uint8_t sc_itf_to_usb_itf(uint8_t itf) {
|
||||
if (itf == ITF_SC_CCID) {
|
||||
return ITF_CCID;
|
||||
}
|
||||
@@ -121,7 +122,7 @@ uint8_t sc_itf_to_usb_itf(uint8_t itf) {
|
||||
return itf;
|
||||
}
|
||||
|
||||
void ccid_init_buffers() {
|
||||
static void ccid_init_buffers(void) {
|
||||
if (ITF_SC_TOTAL == 0) {
|
||||
return;
|
||||
}
|
||||
@@ -142,7 +143,7 @@ void ccid_init_buffers() {
|
||||
}
|
||||
}
|
||||
|
||||
int driver_init_ccid(uint8_t itf) {
|
||||
static int driver_init_ccid(uint8_t itf) {
|
||||
ccid_header[itf] = (ccid_header_t *) (ccid_rx[itf].buffer + ccid_rx[itf].r_ptr);
|
||||
ccid_resp_fast[itf] = (ccid_header_t *) (ccid_tx[itf].buffer + sizeof(ccid_tx[itf].buffer) - 64);
|
||||
// apdu.header = &ccid_header->apdu;
|
||||
@@ -153,10 +154,12 @@ int driver_init_ccid(uint8_t itf) {
|
||||
|
||||
//ccid_tx[itf].w_ptr = ccid_tx[itf].r_ptr = 0;
|
||||
|
||||
return PICOKEY_OK;
|
||||
return PICOKEYS_OK;
|
||||
}
|
||||
|
||||
void tud_vendor_rx_cb(uint8_t itf, const uint8_t *buffer, uint16_t bufsize) {
|
||||
(void)buffer;
|
||||
(void)bufsize;
|
||||
uint32_t len = tud_vendor_n_available(itf);
|
||||
do {
|
||||
uint16_t tlen = 0;
|
||||
@@ -173,27 +176,27 @@ void tud_vendor_rx_cb(uint8_t itf, const uint8_t *buffer, uint16_t bufsize) {
|
||||
} while (len > 0);
|
||||
}
|
||||
|
||||
int driver_write_ccid(uint8_t itf, const uint8_t *tx_buffer, uint16_t buffer_size) {
|
||||
static int driver_write_ccid(uint8_t itf, const uint8_t *tx_buffer, uint16_t buffer_size) {
|
||||
if (*tx_buffer != 0x81) {
|
||||
DEBUG_PAYLOAD(tx_buffer, buffer_size);
|
||||
}
|
||||
int r = tud_vendor_n_write(itf, tx_buffer, buffer_size);
|
||||
if (r > 0) {
|
||||
tud_vendor_n_flush(itf);
|
||||
uint32_t written = tud_vendor_n_write(itf, tx_buffer, buffer_size);
|
||||
if (written > 0) {
|
||||
tud_vendor_n_write_flush(itf);
|
||||
|
||||
ccid_tx[itf].r_ptr += (uint16_t)buffer_size;
|
||||
ccid_tx[itf].r_ptr += (uint16_t)written;
|
||||
if (ccid_tx[itf].r_ptr >= ccid_tx[itf].w_ptr) {
|
||||
ccid_tx[itf].r_ptr = ccid_tx[itf].w_ptr = 0;
|
||||
}
|
||||
|
||||
}
|
||||
#ifdef ENABLE_EMULATION
|
||||
tud_vendor_tx_cb(itf, r);
|
||||
tud_vendor_tx_cb(itf, written);
|
||||
#endif
|
||||
return r;
|
||||
return (int)written;
|
||||
}
|
||||
|
||||
int ccid_write_fast(uint8_t itf, const uint8_t *buffer, uint16_t buffer_size) {
|
||||
static int ccid_write_fast(uint8_t itf, const uint8_t *buffer, uint16_t buffer_size) {
|
||||
return driver_write_ccid(itf, buffer, buffer_size);
|
||||
}
|
||||
|
||||
@@ -201,6 +204,20 @@ int driver_process_usb_packet_ccid(uint8_t itf, uint16_t rx_read) {
|
||||
(void) rx_read;
|
||||
if (ccid_rx[itf].w_ptr - ccid_rx[itf].r_ptr >= 10) {
|
||||
driver_init_ccid(itf);
|
||||
if (ccid_header[itf]->dwLength > USB_BUFFER_SIZE - 10) {
|
||||
//Invalid length
|
||||
ccid_rx[itf].r_ptr = ccid_rx[itf].w_ptr = 0;
|
||||
|
||||
ccid_resp_fast[itf]->bMessageType = CCID_DATA_BLOCK_RET;
|
||||
ccid_resp_fast[itf]->dwLength = 2;
|
||||
ccid_resp_fast[itf]->bSlot = 0;
|
||||
ccid_resp_fast[itf]->bSeq = ccid_header[itf]->bSeq;
|
||||
ccid_resp_fast[itf]->abRFU0 = ccid_status;
|
||||
ccid_resp_fast[itf]->abRFU1 = 0;
|
||||
memcpy(&ccid_resp_fast[itf]->apdu, "\x6F\x00", 2);
|
||||
ccid_write_fast(itf, (const uint8_t *)ccid_resp_fast[itf], 12);
|
||||
return 0;
|
||||
}
|
||||
//printf("ccid_process %ld %d %x %x %d\n",ccid_header[itf]->dwLength,rx_read-10,ccid_header[itf]->bMessageType,ccid_header[itf]->bSeq,ccid_rx[itf].w_ptr - ccid_rx[itf].r_ptr - 10);
|
||||
if (ccid_header[itf]->dwLength <= (uint32_t)(ccid_rx[itf].w_ptr - ccid_rx[itf].r_ptr - 10)){
|
||||
ccid_rx[itf].r_ptr += (uint16_t)(ccid_header[itf]->dwLength + 10);
|
||||
@@ -302,7 +319,7 @@ int driver_process_usb_packet_ccid(uint8_t itf, uint16_t rx_read) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void driver_exec_timeout_ccid(uint8_t itf) {
|
||||
static void driver_exec_timeout_ccid(uint8_t itf) {
|
||||
ccid_resp_fast[itf]->bMessageType = CCID_DATA_BLOCK_RET;
|
||||
ccid_resp_fast[itf]->dwLength = 0;
|
||||
ccid_resp_fast[itf]->bSlot = 0;
|
||||
@@ -327,13 +344,13 @@ void driver_exec_finished_cont_ccid(uint8_t itf, uint16_t size_next, uint16_t of
|
||||
ccid_write_offset(itf, size_next+10, offset);
|
||||
}
|
||||
|
||||
void ccid_task() {
|
||||
for (int itf = 0; itf < ITF_SC_TOTAL; itf++) {
|
||||
void ccid_task(void) {
|
||||
for (uint8_t itf = 0; itf < ITF_SC_TOTAL; itf++) {
|
||||
int status = card_status(sc_itf_to_usb_itf(itf));
|
||||
if (status == PICOKEY_OK) {
|
||||
if (status == PICOKEYS_OK) {
|
||||
driver_exec_finished_ccid(itf, finished_data_size);
|
||||
}
|
||||
else if (status == PICOKEY_ERR_BLOCKED) {
|
||||
else if (status == PICOKEYS_ERR_BLOCKED) {
|
||||
driver_exec_timeout_ccid(itf);
|
||||
}
|
||||
if (ccid_tx[itf].w_ptr > ccid_tx[itf].r_ptr) {
|
||||
@@ -344,17 +361,17 @@ void ccid_task() {
|
||||
}
|
||||
}
|
||||
|
||||
void ccid_init() {
|
||||
void ccid_init(void) {
|
||||
ccid_init_buffers();
|
||||
}
|
||||
|
||||
#ifndef ENABLE_EMULATION
|
||||
|
||||
void tud_vendor_tx_cb(uint8_t itf, uint32_t sent_bytes) {
|
||||
(void) sent_bytes;
|
||||
tud_vendor_n_write_flush(itf);
|
||||
}
|
||||
|
||||
#ifndef ENABLE_EMULATION
|
||||
|
||||
static void ccid_init_cb(void) {
|
||||
vendord_init();
|
||||
}
|
||||
@@ -378,7 +395,11 @@ static uint16_t ccid_open(uint8_t rhport, tusb_desc_interface_t const *itf_desc,
|
||||
tusb_desc_endpoint_t const *desc_ep = (tusb_desc_endpoint_t const *)((uint8_t *)itf_desc + drv_len - sizeof(tusb_desc_endpoint_t));
|
||||
TU_ASSERT(usbd_edpt_open(rhport, desc_ep), 0);
|
||||
uint8_t msg[] = { 0x50, 0x03 };
|
||||
#if defined(PICO_PLATFORM) || defined(ESP_PLATFORM)
|
||||
usbd_edpt_xfer(rhport, desc_ep->bEndpointAddress, msg, sizeof(msg));
|
||||
#else
|
||||
usbd_edpt_xfer(rhport, desc_ep->bEndpointAddress, msg, sizeof(msg), sizeof(msg));
|
||||
#endif
|
||||
#else
|
||||
vendord_open(rhport, (tusb_desc_interface_t *)itf_vendor, max_len);
|
||||
#endif
|
||||
|
||||
@@ -3,16 +3,16 @@
|
||||
* 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
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
* Affero 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/>.
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _CCID_H_
|
||||
@@ -40,4 +40,30 @@ enum ccid_state {
|
||||
|
||||
extern const uint8_t *ccid_atr;
|
||||
|
||||
PACK(
|
||||
struct ccid_class_descriptor {
|
||||
uint8_t bLength;
|
||||
uint8_t bDescriptorType;
|
||||
uint16_t bcdCCID;
|
||||
uint8_t bMaxSlotIndex;
|
||||
uint8_t bVoltageSupport;
|
||||
uint32_t dwProtocols;
|
||||
uint32_t dwDefaultClock;
|
||||
uint32_t dwMaximumClock;
|
||||
uint8_t bNumClockSupport;
|
||||
uint32_t dwDataRate;
|
||||
uint32_t dwMaxDataRate;
|
||||
uint8_t bNumDataRatesSupported;
|
||||
uint32_t dwMaxIFSD;
|
||||
uint32_t dwSynchProtocols;
|
||||
uint32_t dwMechanical;
|
||||
uint32_t dwFeatures;
|
||||
uint32_t dwMaxCCIDMessageLength;
|
||||
uint8_t bClassGetResponse;
|
||||
uint8_t bclassEnvelope;
|
||||
uint16_t wLcdLayout;
|
||||
uint8_t bPINSupport;
|
||||
uint8_t bMaxCCIDBusySlots;
|
||||
});
|
||||
|
||||
#endif //_CCID_H_
|
||||
|
||||
@@ -3,18 +3,25 @@
|
||||
* 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
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
* Affero 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/>.
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#include <windows.h>
|
||||
#endif
|
||||
#include "emulation.h"
|
||||
#include <stdio.h>
|
||||
#ifndef _MSC_VER
|
||||
@@ -29,7 +36,6 @@ typedef int socket_t;
|
||||
#define INVALID_SOCKET (-1)
|
||||
#define SOCKET_ERROR (-1)
|
||||
#else
|
||||
#include <ws2tcpip.h>
|
||||
#define O_NONBLOCK _O_NONBLOCK
|
||||
#define close closesocket
|
||||
typedef SOCKET socket_t;
|
||||
@@ -41,7 +47,6 @@ typedef int socklen_t;
|
||||
#include <errno.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "pico_keys.h"
|
||||
#include "apdu.h"
|
||||
#include "usb.h"
|
||||
#include "ccid/ccid.h"
|
||||
@@ -59,8 +64,18 @@ uint16_t emul_rx_size = 0, emul_tx_size = 0;
|
||||
extern int cbor_parse(uint8_t cmd, const uint8_t *data, size_t len);
|
||||
pthread_t hcore0, hcore1;
|
||||
|
||||
#ifdef _MSC_VER
|
||||
static void log_sock_error(const char *ctx) {
|
||||
fprintf(stderr, "%s failed (WSAGetLastError=%d)\n", ctx, WSAGetLastError());
|
||||
}
|
||||
#else
|
||||
static void log_sock_error(const char *ctx) {
|
||||
fprintf(stderr, "%s failed (errno=%d)\n", ctx, errno);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef _MSC_VER
|
||||
int msleep(long msec) {
|
||||
static int msleep(long msec) {
|
||||
struct timespec ts;
|
||||
int res;
|
||||
|
||||
@@ -80,7 +95,7 @@ int msleep(long msec) {
|
||||
}
|
||||
#endif
|
||||
|
||||
int emul_init(char *host, uint16_t port) {
|
||||
int emul_init(const char *host, uint16_t port) {
|
||||
struct sockaddr_in serv_addr;
|
||||
fprintf(stderr, "\n Starting emulation envionrment\n");
|
||||
#ifdef _MSC_VER
|
||||
@@ -90,7 +105,7 @@ int emul_init(char *host, uint16_t port) {
|
||||
}
|
||||
#endif
|
||||
if ((ccid_sock = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
|
||||
perror("socket");
|
||||
log_sock_error("socket(ccid)");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -100,13 +115,13 @@ int emul_init(char *host, uint16_t port) {
|
||||
// Convert IPv4 and IPv6 addresses from text to binary
|
||||
// form
|
||||
if (inet_pton(AF_INET, host, &serv_addr.sin_addr) <= 0) {
|
||||
perror("inet_pton");
|
||||
log_sock_error("inet_pton(ccid)");
|
||||
close(ccid_sock);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (connect(ccid_sock, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) {
|
||||
perror("connect");
|
||||
log_sock_error("connect(ccid)");
|
||||
close(ccid_sock);
|
||||
return -1;
|
||||
}
|
||||
@@ -129,12 +144,12 @@ int emul_init(char *host, uint16_t port) {
|
||||
struct sockaddr_in server_sockaddr;
|
||||
|
||||
if ((hid_server_sock = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
|
||||
perror("socket");
|
||||
log_sock_error("socket(hid_server)");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (setsockopt(hid_server_sock, SOL_SOCKET, SO_REUSEADDR, (void *) &yes, sizeof yes) != 0) {
|
||||
perror("setsockopt");
|
||||
log_sock_error("setsockopt(SO_REUSEADDR)");
|
||||
close(hid_server_sock);
|
||||
return 1;
|
||||
}
|
||||
@@ -154,20 +169,21 @@ int emul_init(char *host, uint16_t port) {
|
||||
|
||||
if (bind(hid_server_sock, (struct sockaddr *) &server_sockaddr,
|
||||
sizeof server_sockaddr) != 0) {
|
||||
perror("bind");
|
||||
log_sock_error("bind(hid_server)");
|
||||
close(hid_server_sock);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (listen(hid_server_sock, 0) != 0) {
|
||||
perror("listen");
|
||||
if (listen(hid_server_sock, SOMAXCONN) != 0) {
|
||||
log_sock_error("listen(hid_server)");
|
||||
close(hid_server_sock);
|
||||
return 1;
|
||||
}
|
||||
fprintf(stderr, "HID server listening on 0.0.0.0:%u\n", hid_port);
|
||||
return 0;
|
||||
}
|
||||
|
||||
socket_t get_sock_itf(uint8_t itf) {
|
||||
static socket_t get_sock_itf(uint8_t itf) {
|
||||
#ifdef USB_ITF_CCID
|
||||
if (itf == ITF_CCID) {
|
||||
return ccid_sock;
|
||||
@@ -200,7 +216,11 @@ uint16_t driver_write_emul(uint8_t itf, const uint8_t *buffer, uint16_t buffer_s
|
||||
uint16_t size = htons(buffer_size);
|
||||
socket_t sock = get_sock_itf(itf);
|
||||
// DEBUG_PAYLOAD(buffer,buffer_size);
|
||||
#ifdef _WIN32
|
||||
int ret = 0;
|
||||
#else
|
||||
ssize_t ret = 0;
|
||||
#endif
|
||||
do {
|
||||
ret = send(sock, (const char *)&size, sizeof(size), 0);
|
||||
if (ret == SOCKET_ERROR) {
|
||||
@@ -279,7 +299,11 @@ uint16_t emul_read(uint8_t itf) {
|
||||
__pragma(warning(pop))
|
||||
#endif
|
||||
struct timeval timeout;
|
||||
#ifdef _WIN32
|
||||
int valread = 0;
|
||||
#else
|
||||
ssize_t valread = 0;
|
||||
#endif
|
||||
timeout.tv_sec = 0;
|
||||
timeout.tv_usec = 0 * 1000;
|
||||
int n = select((int)(sock + 1), &input, NULL, NULL, &timeout);
|
||||
@@ -320,7 +344,7 @@ uint16_t emul_read(uint8_t itf) {
|
||||
}
|
||||
#endif
|
||||
else {
|
||||
emul_rx_size += valread;
|
||||
emul_rx_size += (uint16_t)valread;
|
||||
}
|
||||
return (uint16_t)emul_rx_size;
|
||||
}
|
||||
@@ -333,7 +357,7 @@ uint16_t emul_read(uint8_t itf) {
|
||||
return emul_rx_size;
|
||||
}
|
||||
|
||||
void emul_task() {
|
||||
void emul_task(void) {
|
||||
#ifdef USB_ITF_CCID
|
||||
emul_read(ITF_CCID);
|
||||
#endif
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user