mirror of
https://github.com/polhenarejos/pico-keys-sdk
synced 2026-05-28 17:11:23 +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).
|
# This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
|
||||||
# Copyright (c) 2022 Pol Henarejos.
|
# Copyright (c) 2022 Pol Henarejos.
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# This program is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
# the Free Software Foundation, version 3.
|
# the Free Software Foundation, version 3.
|
||||||
#
|
#
|
||||||
# This program is distributed in the hope that it will be useful, but
|
# This program is distributed in the hope that it will be useful, but
|
||||||
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
# General Public License for more details.
|
# General Public License for more details.
|
||||||
#
|
#
|
||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
#
|
#
|
||||||
|
|
||||||
cmake_minimum_required(VERSION 3.16)
|
cmake_minimum_required(VERSION 3.16)
|
||||||
|
|
||||||
if(ESP_PLATFORM)
|
if(ESP_PLATFORM)
|
||||||
set(EXTRA_COMPONENT_DIRS src)
|
set(EXTRA_COMPONENT_DIRS src)
|
||||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
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)
|
|
||||||
else()
|
else()
|
||||||
|
if(NOT ENABLE_EMULATION)
|
||||||
|
set(PICO_USE_FASTEST_SUPPORTED_CLOCK 1)
|
||||||
|
include(pico_sdk_import.cmake)
|
||||||
|
endif()
|
||||||
|
|
||||||
if(ENABLE_EMULATION)
|
project(pico_rescue C CXX ASM)
|
||||||
else()
|
|
||||||
include(pico_sdk_import.cmake)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
project(pico_keys C CXX ASM)
|
set(CMAKE_C_STANDARD 11)
|
||||||
|
set(CMAKE_CXX_STANDARD 17)
|
||||||
|
|
||||||
set(CMAKE_C_STANDARD 11)
|
if(NOT DEFINED __FOR_CI)
|
||||||
set(CMAKE_CXX_STANDARD 17)
|
set(__FOR_CI 0)
|
||||||
|
endif()
|
||||||
|
if(__FOR_CI)
|
||||||
|
add_compile_definitions(__FOR_CI)
|
||||||
|
endif()
|
||||||
|
|
||||||
if(ENABLE_EMULATION)
|
add_executable(pico_rescue)
|
||||||
else()
|
endif()
|
||||||
pico_sdk_init()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if (NOT DEFINED __FOR_CI)
|
|
||||||
set(__FOR_CI 0)
|
|
||||||
endif()
|
|
||||||
if (__FOR_CI)
|
|
||||||
add_definitions(-D__FOR_CI)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
set(USB_ITF_CCID 1)
|
set(USB_ITF_CCID 1)
|
||||||
set(USB_ITF_HID 1)
|
set(USB_ITF_WCID 1)
|
||||||
include(pico_keys_sdk_import.cmake)
|
include(cmake/version.cmake)
|
||||||
|
include(cmake/options.cmake OPTIONAL)
|
||||||
add_executable(pico_keys_sdk_exe)
|
include(picokeys_sdk_import.cmake)
|
||||||
|
if(NOT ESP_PLATFORM)
|
||||||
target_compile_options(pico_keys_sdk_exe PUBLIC
|
set(SOURCES ${PICOKEYS_SOURCES})
|
||||||
-Wall
|
endif()
|
||||||
-Werror
|
list(APPEND SOURCES
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/src/fs/files.c
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/src/version.c
|
||||||
)
|
)
|
||||||
|
|
||||||
if(ENABLE_EMULATION)
|
SET_VERSION(ver_major ver_minor "${CMAKE_CURRENT_LIST_DIR}/src/picokeys_version.h")
|
||||||
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)
|
|
||||||
|
|
||||||
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()
|
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()
|
endif()
|
||||||
|
|||||||
141
LICENSE
141
LICENSE
@@ -1,5 +1,5 @@
|
|||||||
GNU GENERAL PUBLIC LICENSE
|
GNU AFFERO GENERAL PUBLIC LICENSE
|
||||||
Version 3, 29 June 2007
|
Version 3, 19 November 2007
|
||||||
|
|
||||||
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||||
Everyone is permitted to copy and distribute verbatim copies
|
Everyone is permitted to copy and distribute verbatim copies
|
||||||
@@ -7,17 +7,15 @@
|
|||||||
|
|
||||||
Preamble
|
Preamble
|
||||||
|
|
||||||
The GNU General Public License is a free, copyleft license for
|
The GNU Affero General Public License is a free, copyleft license for
|
||||||
software and other kinds of works.
|
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
|
The licenses for most software and other practical works are designed
|
||||||
to take away your freedom to share and change the works. By contrast,
|
to take away your freedom to share and change the works. By contrast,
|
||||||
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
|
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
|
software for all its users.
|
||||||
GNU General Public License for most of our software; it applies also to
|
|
||||||
any other work released this way by its authors. You can apply it to
|
|
||||||
your programs, too.
|
|
||||||
|
|
||||||
When we speak of free software, we are referring to freedom, not
|
When we speak of free software, we are referring to freedom, not
|
||||||
price. Our General Public Licenses are designed to make sure that you
|
price. Our General Public Licenses are designed to make sure that you
|
||||||
@@ -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
|
want it, that you can change the software or use pieces of it in new
|
||||||
free programs, and that you know you can do these things.
|
free programs, and that you know you can do these things.
|
||||||
|
|
||||||
To protect your rights, we need to prevent others from denying you
|
Developers that use our General Public Licenses protect your rights
|
||||||
these rights or asking you to surrender the rights. Therefore, you have
|
with two steps: (1) assert copyright on the software, and (2) offer
|
||||||
certain responsibilities if you distribute copies of the software, or if
|
you this License which gives you legal permission to copy, distribute
|
||||||
you modify it: responsibilities to respect the freedom of others.
|
and/or modify the software.
|
||||||
|
|
||||||
For example, if you distribute copies of such a program, whether
|
A secondary benefit of defending all users' freedom is that
|
||||||
gratis or for a fee, you must pass on to the recipients the same
|
improvements made in alternate versions of the program, if they
|
||||||
freedoms that you received. You must make sure that they, too, receive
|
receive widespread use, become available for other developers to
|
||||||
or can get the source code. And you must show them these terms so they
|
incorporate. Many developers of free software are heartened and
|
||||||
know their rights.
|
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:
|
The GNU Affero General Public License is designed specifically to
|
||||||
(1) assert copyright on the software, and (2) offer you this License
|
ensure that, in such cases, the modified source code becomes available
|
||||||
giving you legal permission to copy, distribute and/or modify it.
|
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
|
An older license, called the Affero General Public License and
|
||||||
that there is no warranty for this free software. For both users' and
|
published by Affero, was designed to accomplish similar goals. This is
|
||||||
authors' sake, the GPL requires that modified versions be marked as
|
a different license, not a version of the Affero GPL, but Affero has
|
||||||
changed, so that their problems will not be attributed erroneously to
|
released a new version of the Affero GPL which permits relicensing under
|
||||||
authors of previous versions.
|
this license.
|
||||||
|
|
||||||
Some devices are designed to deny users access to install or run
|
|
||||||
modified versions of the software inside them, although the manufacturer
|
|
||||||
can do so. This is fundamentally incompatible with the aim of
|
|
||||||
protecting users' freedom to change the software. The systematic
|
|
||||||
pattern of such abuse occurs in the area of products for individuals to
|
|
||||||
use, which is precisely where it is most unacceptable. Therefore, we
|
|
||||||
have designed this version of the GPL to prohibit the practice for those
|
|
||||||
products. If such problems arise substantially in other domains, we
|
|
||||||
stand ready to extend this provision to those domains in future versions
|
|
||||||
of the GPL, as needed to protect the freedom of users.
|
|
||||||
|
|
||||||
Finally, every program is threatened constantly by software patents.
|
|
||||||
States should not allow patents to restrict development and use of
|
|
||||||
software on general-purpose computers, but in those that do, we wish to
|
|
||||||
avoid the special danger that patents applied to a free program could
|
|
||||||
make it effectively proprietary. To prevent this, the GPL assures that
|
|
||||||
patents cannot be used to render the program non-free.
|
|
||||||
|
|
||||||
The precise terms and conditions for copying, distribution and
|
The precise terms and conditions for copying, distribution and
|
||||||
modification follow.
|
modification follow.
|
||||||
@@ -72,7 +60,7 @@ modification follow.
|
|||||||
|
|
||||||
0. Definitions.
|
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
|
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||||
works, such as semiconductor masks.
|
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
|
the Program, the only way you could satisfy both those terms and this
|
||||||
License would be to refrain entirely from conveying the Program.
|
License would be to refrain entirely from conveying the Program.
|
||||||
|
|
||||||
13. 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
|
Notwithstanding any other provision of this License, you have
|
||||||
permission to link or combine any covered work with a work licensed
|
permission to link or combine any covered work with a work licensed
|
||||||
under version 3 of the GNU 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
|
combined work, and to convey the resulting work. The terms of this
|
||||||
License will continue to apply to the part which is the covered work,
|
License will continue to apply to the part which is the covered work,
|
||||||
but the special requirements of the GNU Affero General Public License,
|
but the work with which it is combined will remain governed by version
|
||||||
section 13, concerning interaction through a network will apply to the
|
3 of the GNU General Public License.
|
||||||
combination as such.
|
|
||||||
|
|
||||||
14. Revised Versions of this License.
|
14. Revised Versions of this License.
|
||||||
|
|
||||||
The Free Software Foundation may publish revised and/or new versions of
|
The Free Software Foundation may publish revised and/or new versions of
|
||||||
the GNU General Public License from time to time. Such new versions will
|
the GNU Affero General Public License from time to time. Such new versions
|
||||||
be similar in spirit to the present version, but may differ in detail to
|
will be similar in spirit to the present version, but may differ in detail to
|
||||||
address new problems or concerns.
|
address new problems or concerns.
|
||||||
|
|
||||||
Each version is given a distinguishing version number. If the
|
Each version is given a distinguishing version number. If the
|
||||||
Program specifies that a certain numbered version of the GNU 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
|
Public License "or any later version" applies to it, you have the
|
||||||
option of following the terms and conditions either of that numbered
|
option of following the terms and conditions either of that numbered
|
||||||
version or of any later version published by the Free Software
|
version or of any later version published by the Free Software
|
||||||
Foundation. If the Program does not specify a version number of the
|
Foundation. If the Program does not specify a version number of the
|
||||||
GNU 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.
|
by the Free Software Foundation.
|
||||||
|
|
||||||
If the Program specifies that a proxy can decide which future
|
If the Program specifies that a proxy can decide which future
|
||||||
versions of the GNU 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
|
public statement of acceptance of a version permanently authorizes you
|
||||||
to choose that version for the Program.
|
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>
|
Copyright (C) <year> <name of author>
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
This program is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU 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
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
(at your option) any later version.
|
(at your option) any later version.
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
This program is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
GNU 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/>.
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
Also add information on how to contact you by electronic and paper mail.
|
Also add information on how to contact you by electronic and paper mail.
|
||||||
|
|
||||||
If the program does terminal interaction, make it output a short
|
If your software can interact with users remotely through a computer
|
||||||
notice like this when it starts in an interactive mode:
|
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
|
||||||
<program> Copyright (C) <year> <name of author>
|
interface could display a "Source" link that leads users to an archive
|
||||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
of the code. There are many ways you could offer source, and different
|
||||||
This is free software, and you are welcome to redistribute it
|
solutions will be better for different programs; see section 13 for the
|
||||||
under certain conditions; type `show c' for details.
|
specific requirements.
|
||||||
|
|
||||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
|
||||||
parts of the General Public License. Of course, your program's commands
|
|
||||||
might be different; for a GUI interface, you would use an "about box".
|
|
||||||
|
|
||||||
You should also get your employer (if you work as a programmer) or school,
|
You should also get your employer (if you work as a programmer) or school,
|
||||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||||
For more information on this, and how to apply and follow the GNU GPL, see
|
For more information on this, and how to apply and follow the GNU AGPL, see
|
||||||
<https://www.gnu.org/licenses/>.
|
<https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
The GNU General Public License does not permit incorporating your program
|
|
||||||
into proprietary programs. If your program is a subroutine library, you
|
|
||||||
may consider it more useful to permit linking proprietary applications with
|
|
||||||
the library. If this is what you want to do, use the GNU Lesser General
|
|
||||||
Public License instead of this License. But first, please read
|
|
||||||
<https://www.gnu.org/licenses/why-not-lgpl.html>.
|
|
||||||
|
|||||||
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)
|
if(command STREQUAL SET)
|
||||||
set(arg_key ${ARGV2})
|
set(arg_key ${ARGV2})
|
||||||
set(arg_value ${ARGV3})
|
set(arg_value ${ARGV3})
|
||||||
@@ -10,7 +10,6 @@ function(dict command dict )
|
|||||||
|
|
||||||
list(APPEND ${dict} "${arg_key}=${arg_value}")
|
list(APPEND ${dict} "${arg_key}=${arg_value}")
|
||||||
set(${dict} "${${dict}}" PARENT_SCOPE)
|
set(${dict} "${${dict}}" PARENT_SCOPE)
|
||||||
|
|
||||||
elseif(command STREQUAL GET)
|
elseif(command STREQUAL GET)
|
||||||
set(arg_key ${ARGV2})
|
set(arg_key ${ARGV2})
|
||||||
set(arg_outvar ${ARGV3})
|
set(arg_outvar ${ARGV3})
|
||||||
@@ -23,7 +22,6 @@ function(dict command dict )
|
|||||||
list(GET ${dict} ${idx} kv)
|
list(GET ${dict} ${idx} kv)
|
||||||
string(REGEX REPLACE "^[^=]+=(.*)" "\\1" value "${kv}")
|
string(REGEX REPLACE "^[^=]+=(.*)" "\\1" value "${kv}")
|
||||||
set(${arg_outvar} "${value}" PARENT_SCOPE)
|
set(${arg_outvar} "${value}" PARENT_SCOPE)
|
||||||
|
|
||||||
elseif(command STREQUAL _IDX)
|
elseif(command STREQUAL _IDX)
|
||||||
set(arg_key ${ARGV2})
|
set(arg_key ${ARGV2})
|
||||||
set(arg_outvar ${ARGV3})
|
set(arg_outvar ${ARGV3})
|
||||||
@@ -34,10 +32,9 @@ function(dict command dict )
|
|||||||
set(${arg_outvar} "${idx}" PARENT_SCOPE)
|
set(${arg_outvar} "${idx}" PARENT_SCOPE)
|
||||||
return()
|
return()
|
||||||
endif()
|
endif()
|
||||||
math(EXPR idx ${idx}+1)
|
math(EXPR idx ${idx} + 1)
|
||||||
endforeach()
|
endforeach()
|
||||||
set(${arg_outvar} "-1" PARENT_SCOPE)
|
set(${arg_outvar} "-1" PARENT_SCOPE)
|
||||||
|
|
||||||
else()
|
else()
|
||||||
message(FATAL_ERROR "dict does not recognize sub-command ${command}")
|
message(FATAL_ERROR "dict does not recognize sub-command ${command}")
|
||||||
endif()
|
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)
|
macro(HEXCHAR2DEC VAR VAL)
|
||||||
if(${VAL} MATCHES "[0-9]")
|
if(${VAL} MATCHES "[0-9]")
|
||||||
SET(${VAR} ${VAL})
|
set(${VAR} ${VAL})
|
||||||
elseif(${VAL} MATCHES "[aA]")
|
elseif(${VAL} MATCHES "[aA]")
|
||||||
SET(${VAR} 10)
|
set(${VAR} 10)
|
||||||
elseif(${VAL} MATCHES "[bB]")
|
elseif(${VAL} MATCHES "[bB]")
|
||||||
SET(${VAR} 11)
|
set(${VAR} 11)
|
||||||
elseif(${VAL} MATCHES "[cC]")
|
elseif(${VAL} MATCHES "[cC]")
|
||||||
SET(${VAR} 12)
|
set(${VAR} 12)
|
||||||
elseif(${VAL} MATCHES "[dD]")
|
elseif(${VAL} MATCHES "[dD]")
|
||||||
SET(${VAR} 13)
|
set(${VAR} 13)
|
||||||
elseif(${VAL} MATCHES "[eE]")
|
elseif(${VAL} MATCHES "[eE]")
|
||||||
SET(${VAR} 14)
|
set(${VAR} 14)
|
||||||
elseif(${VAL} MATCHES "[fF]")
|
elseif(${VAL} MATCHES "[fF]")
|
||||||
SET(${VAR} 15)
|
set(${VAR} 15)
|
||||||
else()
|
else()
|
||||||
MESSAGE(FATAL_ERROR "Invalid format for hexidecimal character")
|
message(FATAL_ERROR "Invalid format for hexidecimal character")
|
||||||
endif()
|
endif()
|
||||||
endmacro(HEXCHAR2DEC)
|
endmacro()
|
||||||
|
|
||||||
macro(HEX2DEC VAR VAL)
|
macro(HEX2DEC VAR VAL)
|
||||||
SET(CURINDEX 0)
|
set(CURINDEX 0)
|
||||||
STRING(LENGTH "${VAL}" CURLENGTH)
|
string(LENGTH "${VAL}" CURLENGTH)
|
||||||
SET(${VAR} 0)
|
set(${VAR} 0)
|
||||||
while(CURINDEX LESS CURLENGTH)
|
while(CURINDEX LESS CURLENGTH)
|
||||||
STRING(SUBSTRING "${VAL}" ${CURINDEX} 1 CHAR)
|
string(SUBSTRING "${VAL}" ${CURINDEX} 1 CHAR)
|
||||||
HEXCHAR2DEC(CHAR ${CHAR})
|
HEXCHAR2DEC(CHAR ${CHAR})
|
||||||
MATH(EXPR POWAH "(1<<((${CURLENGTH}-${CURINDEX}-1)*4))")
|
math(EXPR POWAH "(1 << ((${CURLENGTH} - ${CURINDEX} - 1) * 4))")
|
||||||
MATH(EXPR CHAR "(${CHAR}*${POWAH})")
|
math(EXPR CHAR "(${CHAR} * ${POWAH})")
|
||||||
MATH(EXPR ${VAR} "${${VAR}}+${CHAR}")
|
math(EXPR ${VAR} "${${VAR}} + ${CHAR}")
|
||||||
MATH(EXPR CURINDEX "${CURINDEX}+1")
|
math(EXPR CURINDEX "${CURINDEX} + 1")
|
||||||
endwhile()
|
endwhile()
|
||||||
endmacro(HEX2DEC)
|
endmacro()
|
||||||
|
|
||||||
macro(SET_VERSION MAJOR MINOR FILE)
|
macro(SET_VERSION MAJOR MINOR FILE)
|
||||||
|
set(ROLLBACK 4)
|
||||||
file(READ ${FILE} ver)
|
file(READ ${FILE} ver)
|
||||||
string(REGEX MATCHALL "0x([0-9A-F])([0-9A-F])([0-9A-F])([0-9A-F])" _ ${ver})
|
string(REGEX MATCHALL "0x([0-9A-F])([0-9A-F])([0-9A-F])([0-9A-F])" _ ${ver})
|
||||||
string(CONCAT ver_major ${CMAKE_MATCH_1}${CMAKE_MATCH_2})
|
string(CONCAT ver_major ${CMAKE_MATCH_1}${CMAKE_MATCH_2})
|
||||||
@@ -41,9 +41,23 @@ macro(SET_VERSION MAJOR MINOR FILE)
|
|||||||
HEX2DEC(ver_major ${ver_major})
|
HEX2DEC(ver_major ${ver_major})
|
||||||
HEX2DEC(ver_minor ${ver_minor})
|
HEX2DEC(ver_minor ${ver_minor})
|
||||||
message(STATUS "Found version:\t\t ${ver_major}.${ver_minor}")
|
message(STATUS "Found version:\t\t ${ver_major}.${ver_minor}")
|
||||||
if(NOT ENABLE_EMULATION AND NOT ESP_PLATFORM)
|
if(PICO_PLATFORM)
|
||||||
pico_set_binary_version(${CMAKE_PROJECT_NAME} MAJOR ${ver_major} MINOR ${ver_minor})
|
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()
|
endif()
|
||||||
SET(${MAJOR} ${ver_major})
|
set(${MAJOR} ${ver_major})
|
||||||
SET(${MINOR} ${ver_minor})
|
set(${MINOR} ${ver_minor})
|
||||||
endmacro(SET_VERSION)
|
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
|
## IDF Component Manager Manifest File
|
||||||
dependencies:
|
dependencies:
|
||||||
espressif/esp_tinyusb: "^1.7.2"
|
espressif/esp_tinyusb: "^1.7.6"
|
||||||
#espressif/tinyusb: "^0.15.0"
|
#espressif/tinyusb: "^0.15.0"
|
||||||
zorxx/neopixel: "^1.0.4"
|
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
|
# Name, Type, SubType, Offset, Size, Flags
|
||||||
# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap
|
# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap
|
||||||
|
|
||||||
nvs, data, nvs, 0x9000, 0x6000
|
nvs, data, nvs, 0x11000, 0x6000
|
||||||
phy_init, data, phy, 0xf000, 0x1000
|
phy_init, data, phy, 0x17000, 0x1000
|
||||||
factory, app, factory, 0x10000, 1M,
|
factory, app, factory, 0x20000, 1M
|
||||||
part0, 0x40, 0x1, 0x200000, 1M,
|
part0, 0x40, 0x1, 0x200000, 1M,
|
||||||
|
|||||||
|
@@ -330,7 +330,7 @@
|
|||||||
//#define MBEDTLS_RSA_ALT
|
//#define MBEDTLS_RSA_ALT
|
||||||
//#define MBEDTLS_SHA1_ALT
|
//#define MBEDTLS_SHA1_ALT
|
||||||
#ifdef PICO_RP2350
|
#ifdef PICO_RP2350
|
||||||
#define MBEDTLS_SHA256_ALT
|
//#define MBEDTLS_SHA256_ALT
|
||||||
#endif
|
#endif
|
||||||
//#define MBEDTLS_SHA512_ALT
|
//#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.
|
* Copyright (c) 2022 Pol Henarejos.
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU 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.
|
* the Free Software Foundation, version 3.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful, but
|
* This program is distributed in the hope that it will be useful,
|
||||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* 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 <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
@@ -286,3 +286,9 @@ int mbedtls_sha256_finish(mbedtls_sha256_context *ctx, unsigned char *output) {
|
|||||||
}
|
}
|
||||||
return 0;
|
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.
|
* Copyright (c) 2022 Pol Henarejos.
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU 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.
|
* the Free Software Foundation, version 3.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful, but
|
* This program is distributed in the hope that it will be useful,
|
||||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* 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 <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _SHA256_ALT_H_
|
#ifndef _SHA256_ALT_H_
|
||||||
#define _SHA256_ALT_H_
|
#define _SHA256_ALT_H_
|
||||||
|
|
||||||
#include "pico_keys.h"
|
|
||||||
#include "pico/sha256.h"
|
#include "pico/sha256.h"
|
||||||
|
|
||||||
typedef struct mbedtls_sha256_context {
|
typedef struct mbedtls_sha256_context {
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
},
|
},
|
||||||
"partitions": [
|
"partitions": [
|
||||||
{
|
{
|
||||||
"name": "Pico Keys Firmware",
|
"name": "PicoKeys Firmware",
|
||||||
"id": 0,
|
"id": 0,
|
||||||
"start": 0,
|
"start": 0,
|
||||||
"size": "1024K",
|
"size": "1024K",
|
||||||
@@ -22,15 +22,30 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Pico Keys Data",
|
"name": "PicoKeys Data",
|
||||||
"id": 1,
|
"id": 1,
|
||||||
"start": "2048K",
|
"start": "1032K",
|
||||||
"size": "2048K",
|
"size": "3064K",
|
||||||
"families": ["data"],
|
"families": ["data"],
|
||||||
"permissions": {
|
"permissions": {
|
||||||
"secure": "rw",
|
"secure": "rw",
|
||||||
"nonsecure": "rw",
|
"nonsecure": "",
|
||||||
"bootloader": "rw"
|
"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],
|
"link": ["owner", 0],
|
||||||
"ignored_during_arm_boot": true,
|
"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_SIZE_512=y
|
||||||
CONFIG_WL_SECTOR_MODE_PERF=y
|
CONFIG_WL_SECTOR_MODE_PERF=y
|
||||||
COMPILER_OPTIMIZATION="Performance"
|
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.
|
* Copyright (c) 2022 Pol Henarejos.
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU 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.
|
* the Free Software Foundation, version 3.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful, but
|
* This program is distributed in the hope that it will be useful, but
|
||||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* 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
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "picokeys.h"
|
||||||
#include "apdu.h"
|
#include "apdu.h"
|
||||||
#include "pico_keys.h"
|
#include "led/led.h"
|
||||||
#include "usb.h"
|
#include "usb.h"
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#ifdef ESP_PLATFORM
|
#ifdef ESP_PLATFORM
|
||||||
#include "esp_compat.h"
|
#include "compat/esp_compat.h"
|
||||||
#endif
|
#endif
|
||||||
#ifdef ENABLE_EMULATION
|
#ifdef ENABLE_EMULATION
|
||||||
#include "emulation.h"
|
#include "emulation.h"
|
||||||
@@ -30,16 +31,23 @@ uint8_t *rdata_gr = NULL;
|
|||||||
uint16_t rdata_bk = 0x0;
|
uint16_t rdata_bk = 0x0;
|
||||||
extern uint32_t timeout;
|
extern uint32_t timeout;
|
||||||
bool is_chaining = false;
|
bool is_chaining = false;
|
||||||
uint8_t chain_buf[4096];
|
uint8_t chain_buf[2038];
|
||||||
uint8_t *chain_ptr = NULL;
|
uint8_t *chain_ptr = NULL;
|
||||||
|
|
||||||
int process_apdu() {
|
struct apdu apdu;
|
||||||
|
|
||||||
|
int process_apdu(void) {
|
||||||
led_set_mode(MODE_PROCESSING);
|
led_set_mode(MODE_PROCESSING);
|
||||||
if (CLA(apdu) & 0x10) {
|
if (CLA(apdu) & 0x10) {
|
||||||
|
size_t chain_used = 0;
|
||||||
if (!is_chaining) {
|
if (!is_chaining) {
|
||||||
chain_ptr = chain_buf;
|
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();
|
return SW_CLA_NOT_SUPPORTED();
|
||||||
}
|
}
|
||||||
memcpy(chain_ptr, apdu.data, apdu.nc);
|
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);
|
memmove(apdu.data + (chain_ptr - chain_buf), apdu.data, apdu.nc);
|
||||||
memcpy(apdu.data, chain_buf, chain_ptr - chain_buf);
|
memcpy(apdu.data, chain_buf, chain_ptr - chain_buf);
|
||||||
apdu.nc += (uint16_t)(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;
|
is_chaining = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (INS(apdu) == 0xA4 && P1(apdu) == 0x04 && (P2(apdu) == 0x00 || P2(apdu) == 0x4)) { //select by AID
|
if (INS(apdu) == 0xA4 && P1(apdu) == 0x04 && (P2(apdu) == 0x00 || P2(apdu) == 0x4)) { //select by AID
|
||||||
if (select_app(apdu.data, apdu.nc) == PICOKEY_OK) {
|
if (select_app(apdu.data, apdu.nc) == PICOKEYS_OK) {
|
||||||
return SW_OK();
|
return SW_OK();
|
||||||
}
|
}
|
||||||
return SW_FILE_NOT_FOUND();
|
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) {
|
else if (apdu.header[4] == 0x0 && buffer_size >= 7) {
|
||||||
if (buffer_size == 7) {
|
if (buffer_size == 7) {
|
||||||
apdu.ne = get_uint16_t_be(apdu.header + 5);
|
apdu.ne = get_uint16_be(apdu.header + 5);
|
||||||
if (apdu.ne == 0) {
|
if (apdu.ne == 0) {
|
||||||
apdu.ne = 65536;
|
apdu.ne = 65536;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
apdu.ne = 0;
|
apdu.ne = 0;
|
||||||
apdu.nc = get_uint16_t_be(apdu.header + 5);
|
apdu.nc = get_uint16_be(apdu.header + 5);
|
||||||
apdu.data = apdu.header + 7;
|
apdu.data = apdu.header + 7;
|
||||||
if (apdu.nc + 7 + 2 == buffer_size) {
|
if (apdu.nc + 7 + 2 == buffer_size) {
|
||||||
apdu.ne = get_uint16_t_be(apdu.header + buffer_size - 2);
|
apdu.ne = get_uint16_be(apdu.header + buffer_size - 2);
|
||||||
if (apdu.ne == 0) {
|
if (apdu.ne == 0) {
|
||||||
apdu.ne = 65536;
|
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) {
|
if (apdu.header[1] == 0xc0) {
|
||||||
//printf("apdu.ne %u, apdu.rlen %d, bk %x\n",apdu.ne,apdu.rlen,rdata_bk);
|
//printf("apdu.ne %u, apdu.rlen %d, bk %x\n",apdu.ne,apdu.rlen,rdata_bk);
|
||||||
timeout_stop();
|
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) {
|
if (apdu.rlen <= apdu.ne) {
|
||||||
#ifndef ENABLE_EMULATION
|
#ifndef ENABLE_EMULATION
|
||||||
#ifdef USB_ITF_HID
|
#ifdef USB_ITF_HID
|
||||||
if (itf == ITF_HID_CTAP) {
|
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
|
#endif
|
||||||
#ifdef USB_ITF_CCID
|
#ifdef USB_ITF_CCID
|
||||||
if (itf == ITF_SC_CCID || itf == ITF_SC_WCID) {
|
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
|
#endif
|
||||||
#else
|
#else
|
||||||
@@ -140,7 +151,7 @@ uint16_t apdu_process(uint8_t itf, const uint8_t *buffer, uint16_t buffer_size)
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
rdata_gr += apdu.ne;
|
rdata_gr += apdu.ne;
|
||||||
rdata_bk = *(uint16_t *) rdata_gr;
|
rdata_bk = (rdata_gr[0] << 8) | rdata_gr[1];
|
||||||
rdata_gr[0] = 0x61;
|
rdata_gr[0] = 0x61;
|
||||||
if (apdu.rlen - apdu.ne >= 256) {
|
if (apdu.rlen - apdu.ne >= 256) {
|
||||||
rdata_gr[1] = 0;
|
rdata_gr[1] = 0;
|
||||||
@@ -151,12 +162,12 @@ uint16_t apdu_process(uint8_t itf, const uint8_t *buffer, uint16_t buffer_size)
|
|||||||
#ifndef ENABLE_EMULATION
|
#ifndef ENABLE_EMULATION
|
||||||
#ifdef USB_ITF_HID
|
#ifdef USB_ITF_HID
|
||||||
if (itf == ITF_HID_CTAP) {
|
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
|
#endif
|
||||||
#ifdef USB_ITF_CCID
|
#ifdef USB_ITF_CCID
|
||||||
if (itf == ITF_SC_CCID || itf == ITF_SC_WCID) {
|
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
|
#endif
|
||||||
#else
|
#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) {
|
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) {
|
if (sw1 != 0x90) {
|
||||||
res_APDU_size = 0;
|
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();
|
card_init_core1();
|
||||||
while (1) {
|
while (1) {
|
||||||
uint32_t m = 0;
|
uint32_t m = 0;
|
||||||
queue_remove_blocking(&usb_to_card_q, &m);
|
queue_remove_blocking(&usb_to_card_q, &m);
|
||||||
uint32_t flag = m + 1;
|
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) {
|
if (m == EV_VERIFY_CMD_AVAILABLE || m == EV_MODIFY_CMD_AVAILABLE) {
|
||||||
set_res_sw(0x6f, 0x00);
|
set_res_sw(0x6f, 0x00);
|
||||||
@@ -215,13 +229,11 @@ done: ;
|
|||||||
current_app->unload();
|
current_app->unload();
|
||||||
current_app = NULL;
|
current_app = NULL;
|
||||||
}
|
}
|
||||||
#ifdef ESP_PLATFORM
|
return NULL;
|
||||||
vTaskDelete(NULL);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void apdu_finish() {
|
void apdu_finish(void) {
|
||||||
put_uint16_t_be(apdu.sw, apdu.rdata + apdu.rlen);
|
put_uint16_be(apdu.sw, apdu.rdata + apdu.rlen);
|
||||||
// timeout_stop();
|
// timeout_stop();
|
||||||
#ifndef ENABLE_EMULATION
|
#ifndef ENABLE_EMULATION
|
||||||
/* It was fixed in the USB handling. Keep it just in case */
|
/* It was fixed in the USB handling. Keep it just in case */
|
||||||
@@ -231,14 +243,14 @@ void apdu_finish() {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t apdu_next() {
|
uint16_t apdu_next(void) {
|
||||||
if (apdu.sw != 0) {
|
if (apdu.sw != 0) {
|
||||||
if (apdu.rlen <= apdu.ne) {
|
if (apdu.rlen <= apdu.ne) {
|
||||||
return apdu.rlen + 2;
|
return apdu.rlen + 2;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
rdata_gr = apdu.rdata + apdu.ne;
|
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;
|
rdata_gr[0] = 0x61;
|
||||||
if (apdu.rlen - apdu.ne >= 256) {
|
if (apdu.rlen - apdu.ne >= 256) {
|
||||||
rdata_gr[1] = 0;
|
rdata_gr[1] = 0;
|
||||||
@@ -252,3 +264,30 @@ uint16_t apdu_next() {
|
|||||||
}
|
}
|
||||||
return 0;
|
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.
|
* Copyright (c) 2022 Pol Henarejos.
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU 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.
|
* the Free Software Foundation, version 3.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful, but
|
* This program is distributed in the hope that it will be useful, but
|
||||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* 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
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _APDU_H_
|
#ifndef _APDU_H_
|
||||||
#define _APDU_H_
|
#define _APDU_H_
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stddef.h>
|
||||||
#if !defined(ENABLE_EMULATION) && !defined(ESP_PLATFORM)
|
#include <stdint.h>
|
||||||
#include "pico/stdlib.h"
|
#include <stdbool.h>
|
||||||
#endif
|
#include "compat/compat.h"
|
||||||
#include "compat.h"
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <inttypes.h>
|
|
||||||
|
|
||||||
typedef struct app {
|
typedef struct app {
|
||||||
const uint8_t *aid;
|
const uint8_t *aid;
|
||||||
int (*process_apdu)();
|
int (*process_apdu)(void);
|
||||||
int (*select_aid)(struct app *, uint8_t);
|
int (*select_aid)(struct app *, uint8_t);
|
||||||
int (*unload)();
|
int (*unload)(void);
|
||||||
} app_t;
|
} app_t;
|
||||||
|
|
||||||
extern bool app_exists(const uint8_t *aid, size_t aid_len);
|
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 {
|
typedef struct cmd {
|
||||||
uint8_t ins;
|
uint8_t ins;
|
||||||
int (*cmd_handler)();
|
int (*cmd_handler)(void);
|
||||||
} cmd_t;
|
} cmd_t;
|
||||||
|
|
||||||
extern uint8_t num_apps;
|
extern uint8_t num_apps;
|
||||||
extern app_t apps[8];
|
extern app_t apps[16];
|
||||||
extern app_t *current_app;
|
extern app_t *current_app;
|
||||||
|
|
||||||
PACK(struct apdu {
|
PACK(struct apdu {
|
||||||
@@ -68,10 +65,69 @@ PACK(struct apdu {
|
|||||||
extern struct apdu apdu;
|
extern struct apdu apdu;
|
||||||
|
|
||||||
extern uint16_t set_res_sw(uint8_t sw1, uint8_t sw2);
|
extern uint16_t set_res_sw(uint8_t sw1, uint8_t sw2);
|
||||||
extern int process_apdu();
|
extern int process_apdu(void);
|
||||||
extern uint16_t apdu_process(uint8_t, const uint8_t *buffer, uint16_t buffer_size);
|
extern uint16_t apdu_process(uint8_t, const uint8_t *buffer, uint16_t buffer_size);
|
||||||
extern void apdu_finish();
|
extern void apdu_finish(void);
|
||||||
extern uint16_t apdu_next();
|
extern uint16_t apdu_next(void);
|
||||||
extern void apdu_thread();
|
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
|
#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.
|
* Copyright (c) 2022 Pol Henarejos.
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU 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.
|
* the Free Software Foundation, version 3.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful, but
|
* This program is distributed in the hope that it will be useful, but
|
||||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* 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
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _COMPAT_H_
|
#ifndef _COMPAT_H_
|
||||||
@@ -47,4 +47,23 @@
|
|||||||
static void f(void)
|
static void f(void)
|
||||||
#endif
|
#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
|
#endif // _COMPAT_H
|
||||||
@@ -3,16 +3,16 @@
|
|||||||
* Copyright (c) 2022 Pol Henarejos.
|
* Copyright (c) 2022 Pol Henarejos.
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU 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.
|
* the Free Software Foundation, version 3.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful, but
|
* This program is distributed in the hope that it will be useful, but
|
||||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* 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
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __ESP_COMPAT_H_
|
#ifndef __ESP_COMPAT_H_
|
||||||
@@ -37,7 +37,12 @@ extern TaskHandle_t hcore0, hcore1;
|
|||||||
#define ESP32_CORE0 tskNO_AFFINITY
|
#define ESP32_CORE0 tskNO_AFFINITY
|
||||||
#define ESP32_CORE1 tskNO_AFFINITY
|
#define ESP32_CORE1 tskNO_AFFINITY
|
||||||
#endif
|
#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 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)
|
#define sleep_ms(a) vTaskDelay(a / portTICK_PERIOD_MS)
|
||||||
static inline uint32_t board_millis(void) {
|
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.
|
* Copyright (c) 2022 Pol Henarejos.
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU 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.
|
* the Free Software Foundation, version 3.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful, but
|
* This program is distributed in the hope that it will be useful, but
|
||||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* 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
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#if defined(ENABLE_EMULATION)
|
#include "picokeys.h"
|
||||||
#elif defined(ESP_PLATFORM)
|
#include "serial.h"
|
||||||
#include "esp_compat.h"
|
|
||||||
#else
|
|
||||||
#include <pico/unique_id.h>
|
|
||||||
#endif
|
|
||||||
#include "mbedtls/md.h"
|
#include "mbedtls/md.h"
|
||||||
#include "mbedtls/sha256.h"
|
#include "mbedtls/sha256.h"
|
||||||
#include "mbedtls/aes.h"
|
#include "mbedtls/aes.h"
|
||||||
|
#include "mbedtls/hkdf.h"
|
||||||
|
#include "mbedtls/gcm.h"
|
||||||
|
#include "mbedtls/base64.h"
|
||||||
#include "crypto_utils.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]) {
|
void double_hash_pin(const uint8_t *pin, uint16_t len, uint8_t output[32]) {
|
||||||
uint8_t o1[32];
|
uint8_t o1[32];
|
||||||
hash_multi(pin, len, o1);
|
hash_multi(pin, len, o1);
|
||||||
for (int i = 0; i < sizeof(o1); i++) {
|
for (size_t i = 0; i < sizeof(o1); i++) {
|
||||||
o1[i] ^= pin[i % len];
|
o1[i] ^= pin[i % len];
|
||||||
}
|
}
|
||||||
hash_multi(o1, sizeof(o1), output);
|
hash_multi(o1, sizeof(o1), output);
|
||||||
@@ -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);
|
int r = mbedtls_aes_setkey_enc(&aes, key, key_size);
|
||||||
if (r != 0) {
|
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) {
|
int rc = 0;
|
||||||
return mbedtls_aes_crypt_cbc(&aes, MBEDTLS_AES_ENCRYPT, len, tmp_iv, data, data);
|
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) {
|
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);
|
int r = mbedtls_aes_setkey_dec(&aes, key, key_size);
|
||||||
if (r != 0) {
|
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) {
|
int rc = 0;
|
||||||
return mbedtls_aes_crypt_cbc(&aes, MBEDTLS_AES_DECRYPT, len, tmp_iv, data, data);
|
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
|
else {
|
||||||
return mbedtls_aes_crypt_cfb128(&aes, MBEDTLS_AES_DECRYPT, len, &iv_offset, tmp_iv, data, data);
|
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) {
|
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) {
|
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;
|
unsigned char *value;
|
||||||
uint8_t len;
|
uint8_t len;
|
||||||
};
|
});
|
||||||
|
|
||||||
struct ec_curve_mbed_id {
|
PACK(struct ec_curve_mbed_id {
|
||||||
struct lv_data curve;
|
struct lv_data curve;
|
||||||
mbedtls_ecp_group_id id;
|
mbedtls_ecp_group_id id;
|
||||||
};
|
});
|
||||||
struct ec_curve_mbed_id ec_curves_mbed[] = {
|
struct ec_curve_mbed_id ec_curves_mbed[] = {
|
||||||
{ { (unsigned char *)
|
{ { (unsigned char *)
|
||||||
"\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFE\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF",
|
"\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;
|
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.
|
* Copyright (c) 2022 Pol Henarejos.
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU 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.
|
* the Free Software Foundation, version 3.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful, but
|
* This program is distributed in the hope that it will be useful, but
|
||||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* 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
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _CRYPTO_UTILS_H_
|
#ifndef _CRYPTO_UTILS_H_
|
||||||
@@ -21,23 +21,40 @@
|
|||||||
#include "mbedtls/ecp.h"
|
#include "mbedtls/ecp.h"
|
||||||
#include "mbedtls/md.h"
|
#include "mbedtls/md.h"
|
||||||
|
|
||||||
#define PICO_KEYS_KEY_RSA 0x000f // It is a mask
|
#define PICOKEYS_KEY_RSA 0x000f // It is a mask
|
||||||
#define PICO_KEYS_KEY_RSA_1K 0x0001
|
#define PICOKEYS_KEY_RSA_1K 0x0001
|
||||||
#define PICO_KEYS_KEY_RSA_2K 0x0002
|
#define PICOKEYS_KEY_RSA_2K 0x0002
|
||||||
#define PICO_KEYS_KEY_RSA_3K 0x0004
|
#define PICOKEYS_KEY_RSA_3K 0x0004
|
||||||
#define PICO_KEYS_KEY_RSA_4k 0x0008
|
#define PICOKEYS_KEY_RSA_4k 0x0008
|
||||||
#define PICO_KEYS_KEY_EC 0x0010
|
#define PICOKEYS_KEY_EC 0x0010
|
||||||
#define PICO_KEYS_KEY_AES 0x0f00 // It is a mask
|
#define PICOKEYS_KEY_AES 0x0f00 // It is a mask
|
||||||
#define PICO_KEYS_KEY_AES_128 0x0100
|
#define PICOKEYS_KEY_AES_128 0x0100
|
||||||
#define PICO_KEYS_KEY_AES_192 0x0200
|
#define PICOKEYS_KEY_AES_192 0x0200
|
||||||
#define PICO_KEYS_KEY_AES_256 0x0400
|
#define PICOKEYS_KEY_AES_256 0x0400
|
||||||
#define PICO_KEYS_KEY_AES_512 0x0800 /* For AES XTS */
|
#define PICOKEYS_KEY_AES_512 0x0800 /* For AES XTS */
|
||||||
|
|
||||||
#define PICO_KEYS_AES_MODE_CBC 1
|
#define PICOKEYS_AES_MODE_CBC 1
|
||||||
#define PICO_KEYS_AES_MODE_CFB 2
|
#define PICOKEYS_AES_MODE_CFB 2
|
||||||
|
|
||||||
#define IV_SIZE 16
|
#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 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 hash_multi(const uint8_t *input, uint16_t len, uint8_t output[32]);
|
||||||
extern void hash256(const uint8_t *input, size_t len, uint8_t output[32]);
|
extern void hash256(const uint8_t *input, size_t len, uint8_t output[32]);
|
||||||
@@ -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_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 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 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
|
#endif
|
||||||
|
|||||||
79
src/debug.h
79
src/debug.h
@@ -3,48 +3,69 @@
|
|||||||
* Copyright (c) 2022 Pol Henarejos.
|
* Copyright (c) 2022 Pol Henarejos.
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU 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.
|
* the Free Software Foundation, version 3.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful, but
|
* This program is distributed in the hope that it will be useful, but
|
||||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* 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
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _DEBUG_H_
|
#ifndef _DEBUG_H_
|
||||||
#define _DEBUG_H_
|
#define _DEBUG_H_
|
||||||
|
|
||||||
#if defined(DEBUG_APDU) && DEBUG_APDU == 1
|
#if defined(DEBUG_APDU) && DEBUG_APDU == 1
|
||||||
#define DEBUG_PAYLOAD(_p, _s) { \
|
#include <inttypes.h>
|
||||||
printf("Payload %s (%d bytes) [%s:%d]:\n", #_p, (int) (_s), __FILE__, __LINE__); \
|
#include <stddef.h>
|
||||||
for (int _i = 0; _i < _s; _i += 16) { \
|
#include <stdint.h>
|
||||||
printf("%" PRIxPTR "h : ", (uintptr_t) (_i + _p)); \
|
#include <stdio.h>
|
||||||
for (int _j = 0; _j < 16; _j++) { \
|
|
||||||
if (_j < _s - _i) printf("%02X ", (_p)[_i + _j]); \
|
static inline void debug_payload_impl(const char *name, const uint8_t *p, size_t s, const char *file, int line) {
|
||||||
else printf(" "); \
|
printf("Payload %s (%zu bytes) [%s:%d]:\n", name, s, file, line);
|
||||||
if (_j == 7) printf(" "); \
|
for (size_t i = 0; i < s; i += 16) {
|
||||||
} printf(": "); \
|
printf("%" PRIxPTR "h : ", (uintptr_t)(p + i));
|
||||||
for (int _j = 0; _j < 16; _j++) { \
|
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]); \
|
if (j < s - i) {
|
||||||
else printf(" "); \
|
printf("%02X ", p[i + j]);
|
||||||
if (_j == 7) printf(" "); \
|
}
|
||||||
} \
|
else {
|
||||||
printf("\n"); \
|
printf(" ");
|
||||||
} printf("\n"); \
|
}
|
||||||
}
|
if (j == 7) {
|
||||||
#define DEBUG_DATA(_p, _s) { \
|
printf(" ");
|
||||||
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++) { \
|
printf(": ");
|
||||||
sprintf(&_tmp[2 * _i], "%02X", (_p)[_i]); \
|
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("%s\n", _tmp); \
|
printf("%c", p[i + j]);
|
||||||
free(_tmp); \
|
}
|
||||||
|
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
|
#else
|
||||||
#define DEBUG_PAYLOAD(_p, _s)
|
#define DEBUG_PAYLOAD(_p, _s)
|
||||||
|
|||||||
135
src/eac.c
135
src/eac.c
@@ -3,24 +3,30 @@
|
|||||||
* Copyright (c) 2022 Pol Henarejos.
|
* Copyright (c) 2022 Pol Henarejos.
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU 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.
|
* the Free Software Foundation, version 3.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful, but
|
* This program is distributed in the hope that it will be useful, but
|
||||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* 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
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "picokeys.h"
|
||||||
#include "eac.h"
|
#include "eac.h"
|
||||||
#include "crypto_utils.h"
|
#include "crypto_utils.h"
|
||||||
#include "random.h"
|
#include "random.h"
|
||||||
#include "mbedtls/cmac.h"
|
#include "mbedtls/cmac.h"
|
||||||
#include "asn1.h"
|
#include "tlv.h"
|
||||||
#include "apdu.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_nonce[8];
|
||||||
static uint8_t sm_kmac[16];
|
static uint8_t sm_kmac[16];
|
||||||
@@ -29,19 +35,13 @@ static MSE_protocol sm_protocol = MSE_NONE;
|
|||||||
static mbedtls_mpi sm_mSSC;
|
static mbedtls_mpi sm_mSSC;
|
||||||
static uint8_t sm_blocksize = 0;
|
static uint8_t sm_blocksize = 0;
|
||||||
static uint8_t sm_iv[16];
|
static uint8_t sm_iv[16];
|
||||||
uint16_t sm_session_pin_len = 0;
|
static bool sm_active = false;
|
||||||
uint8_t sm_session_pin[16];
|
|
||||||
|
|
||||||
bool is_secured_apdu() {
|
bool is_secured_apdu(void) {
|
||||||
return CLA(apdu) & 0xC;
|
return CLA(apdu) & 0xC;
|
||||||
}
|
}
|
||||||
|
|
||||||
void sm_derive_key(const uint8_t *input,
|
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) {
|
||||||
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);
|
uint8_t *b = (uint8_t *) calloc(1, input_len + nonce_len + 4);
|
||||||
if (input) {
|
if (input) {
|
||||||
memcpy(b, input, input_len);
|
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);
|
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, 1, sm_nonce, sizeof(sm_nonce), sm_kenc);
|
||||||
sm_derive_key(derived, derived_len, 2, sm_nonce, sizeof(sm_nonce), sm_kmac);
|
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_init(&sm_mSSC);
|
||||||
mbedtls_mpi_grow(&sm_mSSC, sm_blocksize);
|
mbedtls_mpi_grow(&sm_mSSC, sm_blocksize);
|
||||||
mbedtls_mpi_lset(&sm_mSSC, 0);
|
mbedtls_mpi_lset(&sm_mSSC, 0);
|
||||||
memset(sm_iv, 0, sizeof(sm_iv));
|
memset(sm_iv, 0, sizeof(sm_iv));
|
||||||
sm_session_pin_len = 0;
|
sm_active = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void sm_set_protocol(MSE_protocol proto) {
|
void sm_set_protocol(MSE_protocol proto) {
|
||||||
@@ -75,32 +76,38 @@ void sm_set_protocol(MSE_protocol proto) {
|
|||||||
else if (proto == MSE_3DES) {
|
else if (proto == MSE_3DES) {
|
||||||
sm_blocksize = 8;
|
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;
|
return sm_protocol;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t *sm_get_nonce() {
|
uint8_t *sm_get_nonce(void) {
|
||||||
return sm_nonce;
|
return sm_nonce;
|
||||||
}
|
}
|
||||||
|
|
||||||
int sm_sign(uint8_t *in, size_t in_len, uint8_t *out) {
|
int sm_sign(uint8_t *in, size_t in_len, uint8_t out[16]) {
|
||||||
return mbedtls_cipher_cmac(mbedtls_cipher_info_from_type(MBEDTLS_CIPHER_AES_128_ECB),
|
return mbedtls_cipher_cmac(mbedtls_cipher_info_from_type(MBEDTLS_CIPHER_AES_128_ECB), sm_kmac, 128, in, in_len, out);
|
||||||
sm_kmac,
|
|
||||||
128,
|
|
||||||
in,
|
|
||||||
in_len,
|
|
||||||
out);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int sm_unwrap() {
|
int sm_unwrap(void) {
|
||||||
uint8_t sm_indicator = (CLA(apdu) >> 2) & 0x3;
|
uint8_t sm_indicator = (CLA(apdu) >> 2) & 0x3;
|
||||||
if (sm_indicator == 0) {
|
if (sm_indicator == 0) {
|
||||||
return PICOKEY_OK;
|
return PICOKEYS_OK;
|
||||||
|
}
|
||||||
|
if (!sm_active || sm_blocksize == 0) {
|
||||||
|
return PICOKEYS_EXEC_ERROR;
|
||||||
}
|
}
|
||||||
int r = sm_verify();
|
int r = sm_verify();
|
||||||
if (r != PICOKEY_OK) {
|
if (r != PICOKEYS_OK) {
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
apdu.ne = sm_get_le();
|
apdu.ne = sm_get_le();
|
||||||
@@ -111,10 +118,9 @@ int sm_unwrap() {
|
|||||||
uint16_t tag = 0x0;
|
uint16_t tag = 0x0;
|
||||||
uint8_t *tag_data = NULL, *p = NULL;
|
uint8_t *tag_data = NULL, *p = NULL;
|
||||||
uint16_t tag_len = 0;
|
uint16_t tag_len = 0;
|
||||||
asn1_ctx_t ctxi;
|
tlv_ctx_t ctxi;
|
||||||
asn1_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi);
|
tlv_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi);
|
||||||
while (walk_tlv(&ctxi, &p, &tag, &tag_len, &tag_data))
|
while (tlv_walk(&ctxi, &p, &tag, &tag_len, &tag_data)) {
|
||||||
{
|
|
||||||
if (tag == 0x87 || tag == 0x85) {
|
if (tag == 0x87 || tag == 0x85) {
|
||||||
body = tag_data;
|
body = tag_data;
|
||||||
body_size = tag_len;
|
body_size = tag_len;
|
||||||
@@ -126,25 +132,28 @@ int sm_unwrap() {
|
|||||||
}
|
}
|
||||||
if (!body) {
|
if (!body) {
|
||||||
apdu.nc = 0;
|
apdu.nc = 0;
|
||||||
return PICOKEY_OK;
|
return PICOKEYS_OK;
|
||||||
}
|
}
|
||||||
if (is87 && *body++ != 0x1) {
|
if (is87 && *body++ != 0x1) {
|
||||||
return PICOKEY_WRONG_PADDING;
|
return PICOKEYS_WRONG_PADDING;
|
||||||
}
|
}
|
||||||
sm_update_iv();
|
sm_update_iv();
|
||||||
aes_decrypt(sm_kenc, sm_iv, 128, PICO_KEYS_AES_MODE_CBC, body, body_size);
|
aes_decrypt(sm_kenc, sm_iv, 128, PICOKEYS_AES_MODE_CBC, body, body_size);
|
||||||
memmove(apdu.data, body, body_size);
|
memmove(apdu.data, body, body_size);
|
||||||
apdu.nc = sm_remove_padding(apdu.data, body_size);
|
apdu.nc = sm_remove_padding(apdu.data, body_size);
|
||||||
DEBUG_PAYLOAD(apdu.data, (int) apdu.nc);
|
DEBUG_PAYLOAD(apdu.data, (int) apdu.nc);
|
||||||
return PICOKEY_OK;
|
return PICOKEYS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int sm_wrap() {
|
int sm_wrap(void) {
|
||||||
uint8_t sm_indicator = (CLA(apdu) >> 2) & 0x3;
|
uint8_t sm_indicator = (CLA(apdu) >> 2) & 0x3;
|
||||||
if (sm_indicator == 0) {
|
if (sm_indicator == 0) {
|
||||||
return PICOKEY_OK;
|
return 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;
|
size_t input_len = 0;
|
||||||
memset(input, 0, sizeof(input));
|
memset(input, 0, sizeof(input));
|
||||||
mbedtls_mpi ssc;
|
mbedtls_mpi ssc;
|
||||||
@@ -153,7 +162,7 @@ int sm_wrap() {
|
|||||||
mbedtls_mpi_copy(&sm_mSSC, &ssc);
|
mbedtls_mpi_copy(&sm_mSSC, &ssc);
|
||||||
int r = mbedtls_mpi_write_binary(&ssc, input, sm_blocksize);
|
int r = mbedtls_mpi_write_binary(&ssc, input, sm_blocksize);
|
||||||
if (r != 0) {
|
if (r != 0) {
|
||||||
return PICOKEY_EXEC_ERROR;
|
return PICOKEYS_EXEC_ERROR;
|
||||||
}
|
}
|
||||||
input_len += sm_blocksize;
|
input_len += sm_blocksize;
|
||||||
mbedtls_mpi_free(&ssc);
|
mbedtls_mpi_free(&ssc);
|
||||||
@@ -163,7 +172,7 @@ int sm_wrap() {
|
|||||||
res_APDU_size += (sm_blocksize - (res_APDU_size % sm_blocksize));
|
res_APDU_size += (sm_blocksize - (res_APDU_size % sm_blocksize));
|
||||||
DEBUG_PAYLOAD(res_APDU, res_APDU_size);
|
DEBUG_PAYLOAD(res_APDU, res_APDU_size);
|
||||||
sm_update_iv();
|
sm_update_iv();
|
||||||
aes_encrypt(sm_kenc, sm_iv, 128, PICO_KEYS_AES_MODE_CBC, res_APDU, res_APDU_size);
|
aes_encrypt(sm_kenc, sm_iv, 128, PICOKEYS_AES_MODE_CBC, res_APDU, res_APDU_size);
|
||||||
memmove(res_APDU + 1, res_APDU, res_APDU_size);
|
memmove(res_APDU + 1, res_APDU, res_APDU_size);
|
||||||
res_APDU[0] = 0x1;
|
res_APDU[0] = 0x1;
|
||||||
res_APDU_size++;
|
res_APDU_size++;
|
||||||
@@ -181,14 +190,14 @@ int sm_wrap() {
|
|||||||
else {
|
else {
|
||||||
memmove(res_APDU + 4, res_APDU, res_APDU_size);
|
memmove(res_APDU + 4, res_APDU, res_APDU_size);
|
||||||
res_APDU[1] = 0x82;
|
res_APDU[1] = 0x82;
|
||||||
put_uint16_t_be(res_APDU_size, res_APDU + 2);
|
put_uint16_be(res_APDU_size, res_APDU + 2);
|
||||||
res_APDU_size += 4;
|
res_APDU_size += 4;
|
||||||
}
|
}
|
||||||
res_APDU[0] = 0x87;
|
res_APDU[0] = 0x87;
|
||||||
}
|
}
|
||||||
res_APDU[res_APDU_size++] = 0x99;
|
res_APDU[res_APDU_size++] = 0x99;
|
||||||
res_APDU[res_APDU_size++] = 2;
|
res_APDU[res_APDU_size++] = 2;
|
||||||
put_uint16_t_be(apdu.sw, res_APDU + res_APDU_size);
|
put_uint16_be(apdu.sw, res_APDU + res_APDU_size);
|
||||||
res_APDU_size += 2;
|
res_APDU_size += 2;
|
||||||
memcpy(input + input_len, res_APDU, res_APDU_size);
|
memcpy(input + input_len, res_APDU, res_APDU_size);
|
||||||
input_len += res_APDU_size;
|
input_len += res_APDU_size;
|
||||||
@@ -202,16 +211,16 @@ int sm_wrap() {
|
|||||||
apdu.ne = res_APDU_size;
|
apdu.ne = res_APDU_size;
|
||||||
}
|
}
|
||||||
set_res_sw(0x90, 0x00);
|
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;
|
uint16_t tag = 0x0;
|
||||||
uint8_t *tag_data = NULL, *p = NULL;
|
uint8_t *tag_data = NULL, *p = NULL;
|
||||||
uint16_t tag_len = 0;
|
uint16_t tag_len = 0;
|
||||||
asn1_ctx_t ctxi;
|
tlv_ctx_t ctxi;
|
||||||
asn1_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi);
|
tlv_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi);
|
||||||
while (walk_tlv(&ctxi, &p, &tag, &tag_len, &tag_data)) {
|
while (tlv_walk(&ctxi, &p, &tag, &tag_len, &tag_data)) {
|
||||||
if (tag == 0x97) {
|
if (tag == 0x97) {
|
||||||
uint16_t le = 0;
|
uint16_t le = 0;
|
||||||
for (uint16_t t = 1; t <= tag_len; t++) {
|
for (uint16_t t = 1; t <= tag_len; t++) {
|
||||||
@@ -223,26 +232,26 @@ uint16_t sm_get_le() {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void sm_update_iv() {
|
void sm_update_iv(void) {
|
||||||
uint8_t tmp_iv[16], sc_counter[16];
|
uint8_t tmp_iv[16], sc_counter[16];
|
||||||
memset(tmp_iv, 0, sizeof(tmp_iv)); //IV is always 0 for encryption of IV based on counter
|
memset(tmp_iv, 0, sizeof(tmp_iv)); //IV is always 0 for encryption of IV based on counter
|
||||||
mbedtls_mpi_write_binary(&sm_mSSC, sc_counter, sizeof(sc_counter));
|
mbedtls_mpi_write_binary(&sm_mSSC, sc_counter, sizeof(sc_counter));
|
||||||
aes_encrypt(sm_kenc, tmp_iv, 128, PICO_KEYS_AES_MODE_CBC, sc_counter, sizeof(sc_counter));
|
aes_encrypt(sm_kenc, tmp_iv, 128, PICOKEYS_AES_MODE_CBC, sc_counter, sizeof(sc_counter));
|
||||||
memcpy(sm_iv, sc_counter, sizeof(sc_counter));
|
memcpy(sm_iv, sc_counter, sizeof(sc_counter));
|
||||||
}
|
}
|
||||||
|
|
||||||
int sm_verify() {
|
int sm_verify(void) {
|
||||||
uint8_t input[2048];
|
uint8_t input[USB_BUFFER_SIZE];
|
||||||
memset(input, 0, sizeof(input));
|
memset(input, 0, sizeof(input));
|
||||||
uint16_t input_len = 0;
|
uint16_t input_len = 0;
|
||||||
int r = 0;
|
int r = 0;
|
||||||
bool add_header = (CLA(apdu) & 0xC) == 0xC;
|
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) {
|
if (data_len % sm_blocksize) {
|
||||||
data_len += sm_blocksize;
|
data_len += sm_blocksize;
|
||||||
}
|
}
|
||||||
if (data_len + (add_header ? sm_blocksize : 0) > sizeof(input)) {
|
if (data_len + (add_header ? sm_blocksize : 0) > sizeof(input)) {
|
||||||
return PICOKEY_WRONG_LENGTH;
|
return PICOKEYS_WRONG_LENGTH;
|
||||||
}
|
}
|
||||||
mbedtls_mpi ssc;
|
mbedtls_mpi ssc;
|
||||||
mbedtls_mpi_init(&ssc);
|
mbedtls_mpi_init(&ssc);
|
||||||
@@ -252,7 +261,7 @@ int sm_verify() {
|
|||||||
input_len += sm_blocksize;
|
input_len += sm_blocksize;
|
||||||
mbedtls_mpi_free(&ssc);
|
mbedtls_mpi_free(&ssc);
|
||||||
if (r != 0) {
|
if (r != 0) {
|
||||||
return PICOKEY_EXEC_ERROR;
|
return PICOKEYS_EXEC_ERROR;
|
||||||
}
|
}
|
||||||
if (add_header) {
|
if (add_header) {
|
||||||
input[input_len++] = CLA(apdu);
|
input[input_len++] = CLA(apdu);
|
||||||
@@ -268,12 +277,12 @@ int sm_verify() {
|
|||||||
uint16_t tag = 0x0;
|
uint16_t tag = 0x0;
|
||||||
uint8_t *tag_data = NULL, *p = NULL;
|
uint8_t *tag_data = NULL, *p = NULL;
|
||||||
uint16_t tag_len = 0;
|
uint16_t tag_len = 0;
|
||||||
asn1_ctx_t ctxi;
|
tlv_ctx_t ctxi;
|
||||||
asn1_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi);
|
tlv_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi);
|
||||||
while (walk_tlv(&ctxi, &p, &tag, &tag_len, &tag_data)) {
|
while (tlv_walk(&ctxi, &p, &tag, &tag_len, &tag_data)) {
|
||||||
if (tag & 0x1) {
|
if (tag & 0x1) {
|
||||||
input[input_len++] = (uint8_t)tag;
|
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;
|
input_len += tlen;
|
||||||
memcpy(input + input_len, tag_data, tag_len);
|
memcpy(input + input_len, tag_data, tag_len);
|
||||||
input_len += tag_len;
|
input_len += tag_len;
|
||||||
@@ -284,8 +293,8 @@ int sm_verify() {
|
|||||||
mac_len = tag_len;
|
mac_len = tag_len;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!mac) {
|
if (!mac || mac_len != 8) {
|
||||||
return PICOKEY_WRONG_DATA;
|
return PICOKEYS_WRONG_DATA;
|
||||||
}
|
}
|
||||||
if (some_added) {
|
if (some_added) {
|
||||||
input[input_len++] = 0x80;
|
input[input_len++] = 0x80;
|
||||||
@@ -294,12 +303,12 @@ int sm_verify() {
|
|||||||
uint8_t signature[16];
|
uint8_t signature[16];
|
||||||
r = sm_sign(input, input_len, signature);
|
r = sm_sign(input, input_len, signature);
|
||||||
if (r != 0) {
|
if (r != 0) {
|
||||||
return PICOKEY_EXEC_ERROR;
|
return PICOKEYS_EXEC_ERROR;
|
||||||
}
|
}
|
||||||
if (memcmp(signature, mac, mac_len) == 0) {
|
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) {
|
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.
|
* Copyright (c) 2022 Pol Henarejos.
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU 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.
|
* the Free Software Foundation, version 3.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful, but
|
* This program is distributed in the hope that it will be useful, but
|
||||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* 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
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _EAC_H_
|
#ifndef _EAC_H_
|
||||||
#define _EAC_H_
|
#define _EAC_H_
|
||||||
|
|
||||||
#include "pico_keys.h"
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
typedef enum MSE_protocol {
|
typedef enum MSE_protocol {
|
||||||
MSE_AES = 0,
|
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_derive_all_keys(const uint8_t *input, size_t input_len);
|
||||||
extern void sm_set_protocol(MSE_protocol proto);
|
extern void sm_set_protocol(MSE_protocol proto);
|
||||||
extern MSE_protocol sm_get_protocol();
|
extern MSE_protocol sm_get_protocol(void);
|
||||||
extern uint8_t *sm_get_nonce();
|
extern uint8_t *sm_get_nonce(void);
|
||||||
extern int sm_sign(uint8_t *in, size_t in_len, uint8_t *out);
|
extern int sm_sign(uint8_t *in, size_t in_len, uint8_t out[16]);
|
||||||
int sm_verify();
|
int sm_verify(void);
|
||||||
void sm_update_iv();
|
void sm_update_iv(void);
|
||||||
uint16_t sm_get_le();
|
uint16_t sm_get_le(void);
|
||||||
extern int sm_unwrap();
|
extern int sm_unwrap(void);
|
||||||
uint16_t sm_remove_padding(const uint8_t *data, uint16_t data_len);
|
uint16_t sm_remove_padding(const uint8_t *data, uint16_t data_len);
|
||||||
extern int sm_wrap();
|
extern int sm_wrap(void);
|
||||||
extern bool is_secured_apdu();
|
extern bool is_secured_apdu(void);
|
||||||
extern uint8_t sm_session_pin[16];
|
|
||||||
extern uint16_t sm_session_pin_len;
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
228
src/fs/file.c
228
src/fs/file.c
@@ -3,45 +3,39 @@
|
|||||||
* Copyright (c) 2022 Pol Henarejos.
|
* Copyright (c) 2022 Pol Henarejos.
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU 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.
|
* the Free Software Foundation, version 3.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful, but
|
* This program is distributed in the hope that it will be useful, but
|
||||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* 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
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "picokeys.h"
|
||||||
#include "file.h"
|
#include "file.h"
|
||||||
#include "pico_keys.h"
|
#include "tlv.h"
|
||||||
#include <string.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include "asn1.h"
|
|
||||||
#include "apdu.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 end_data_pool;
|
||||||
extern const uintptr_t start_data_pool;
|
extern const uintptr_t start_data_pool;
|
||||||
extern const uintptr_t end_rom_pool;
|
extern const uintptr_t end_rom_pool;
|
||||||
extern const uintptr_t start_rom_pool;
|
extern const uintptr_t start_rom_pool;
|
||||||
extern int flash_write_data_to_file(file_t *file, const uint8_t *data, uint16_t len);
|
|
||||||
extern int flash_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
|
#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 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;
|
file_t *ef_phy = &sef_phy;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//puts FCI in the RAPDU
|
//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;
|
res_APDU_size = 0;
|
||||||
if (fmd) {
|
if (fmd) {
|
||||||
res_APDU[res_APDU_size++] = 0x6f;
|
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;
|
res_APDU[res_APDU_size++] = 2;
|
||||||
if (pe->data) {
|
if (pe->data) {
|
||||||
if ((pe->type & FILE_DATA_FUNC) == FILE_DATA_FUNC) {
|
if ((pe->type & FILE_DATA_FUNC) == FILE_DATA_FUNC) {
|
||||||
uint16_t len = (uint16_t)((int (*)(const file_t *, int))(pe->data))(pe, 0);
|
int (*data_fn)(const file_t *, int) = (int (*)(const file_t *, int))(uintptr_t)pe->data;
|
||||||
res_APDU_size += put_uint16_t_be(len, res_APDU + res_APDU_size);
|
uint16_t len = (uint16_t)data_fn(pe, 0);
|
||||||
|
res_APDU_size += put_uint16_be(len, res_APDU + res_APDU_size);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
uint16_t v = file_get_size(pe);
|
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 {
|
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++] = 0x83;
|
||||||
res_APDU[res_APDU_size++] = 2;
|
res_APDU[res_APDU_size++] = 2;
|
||||||
res_APDU_size += put_uint16_t_be(pe->fid, res_APDU + res_APDU_size);
|
res_APDU_size += put_uint16_be(pe->fid, res_APDU + res_APDU_size);
|
||||||
if (pe->name) {
|
if (pe->name) {
|
||||||
res_APDU[res_APDU_size++] = 0x84;
|
res_APDU[res_APDU_size++] = 0x84;
|
||||||
res_APDU[res_APDU_size++] = MIN(pe->name[0], 16);
|
res_APDU[res_APDU_size++] = MIN(pe->name[0], 16);
|
||||||
@@ -115,7 +110,7 @@ file_t dynamic_file[MAX_DYNAMIC_FILES];
|
|||||||
|
|
||||||
bool card_terminated = false;
|
bool card_terminated = false;
|
||||||
|
|
||||||
bool is_parent(const file_t *child, const file_t *parent) {
|
static bool is_parent(const file_t *child, const file_t *parent) {
|
||||||
if (child == parent) {
|
if (child == parent) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -129,7 +124,7 @@ file_t *get_parent(file_t *f) {
|
|||||||
return &file_entries[f->parent];
|
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++) {
|
for (file_t *p = file_entries; p != file_last; p++) {
|
||||||
if (p->name && *p->name == apdu.nc && memcmp(p->name + 1, name, namelen) == 0) {
|
if (p->name && *p->name == apdu.nc && memcmp(p->name + 1, name, namelen) == 0) {
|
||||||
return p;
|
return p;
|
||||||
@@ -138,7 +133,7 @@ file_t *search_by_name(uint8_t *name, uint16_t namelen) {
|
|||||||
return NULL;
|
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
|
#ifndef ENABLE_EMULATION
|
||||||
if (fid == EF_PHY) {
|
if (fid == EF_PHY) {
|
||||||
return 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;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
file_t *search_file(const uint16_t fid) {
|
static file_t *search_dynamic_file(uint16_t fid) {
|
||||||
file_t *ef = search_by_fid(fid, NULL, SPECIFY_EF);
|
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) {
|
if (ef) {
|
||||||
return ef;
|
return ef;
|
||||||
}
|
}
|
||||||
return search_dynamic_file(fid);
|
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) {
|
if (!buflen) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (pe == top) { //MF or relative DF
|
if (pe == top) { //MF or relative DF
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
put_uint16_t_be(pe->fid, buf);
|
put_uint16_be(pe->fid, buf);
|
||||||
return make_path_buf(&file_entries[pe->parent], buf + 2, buflen - 2, top) + 2;
|
return make_path_buf(&file_entries[pe->parent], buf + 2, buflen - 2, top) + 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t make_path(const file_t *pe, const file_t *top, uint8_t *path) {
|
static uint8_t make_path(const file_t *pe, const file_t *top, uint8_t *path) {
|
||||||
uint8_t buf[MAX_DEPTH * 2], *p = path;
|
uint8_t buf[MAX_DEPTH * 2], *p = path;
|
||||||
put_uint16_t_be(pe->fid, buf);
|
put_uint16_be(pe->fid, buf);
|
||||||
uint8_t depth = make_path_buf(&file_entries[pe->parent], buf + 2, sizeof(buf) - 2, top) + 2;
|
uint8_t depth = make_path_buf(&file_entries[pe->parent], buf + 2, sizeof(buf) - 2, top) + 2;
|
||||||
for (int d = depth - 2; d >= 0; d -= 2) {
|
for (int d = depth - 2; d >= 0; d -= 2) {
|
||||||
memcpy(p, buf + d, 2);
|
memcpy(p, buf + d, 2);
|
||||||
@@ -188,7 +192,7 @@ uint8_t make_path(const file_t *pe, const file_t *top, uint8_t *path) {
|
|||||||
return depth;
|
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];
|
uint8_t path[MAX_DEPTH * 2];
|
||||||
if (pathlen > sizeof(path)) {
|
if (pathlen > sizeof(path)) {
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -207,7 +211,7 @@ file_t *currentDF = NULL;
|
|||||||
const file_t *selected_applet = NULL;
|
const file_t *selected_applet = NULL;
|
||||||
bool isUserAuthenticated = false;
|
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];
|
uint8_t acl = ef->acl[op];
|
||||||
if (acl == 0x0) {
|
if (acl == 0x0) {
|
||||||
return true;
|
return true;
|
||||||
@@ -227,11 +231,11 @@ bool authenticate_action(const file_t *ef, uint8_t op) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void initialize_flash(bool hard) {
|
void file_initialize_flash(bool hard) {
|
||||||
if (hard) {
|
if (hard) {
|
||||||
const uint8_t empty[8] = { 0 };
|
const uint8_t empty[8] = { 0 };
|
||||||
flash_program_block(end_data_pool, empty, sizeof(empty));
|
flash_program_block(end_data_pool, empty, sizeof(empty));
|
||||||
low_flash_available();
|
flash_commit();
|
||||||
}
|
}
|
||||||
for (file_t *f = file_entries; f != file_last; f++) {
|
for (file_t *f = file_entries; f != file_last; f++) {
|
||||||
if ((f->type & FILE_DATA_FLASH) == FILE_DATA_FLASH) {
|
if ((f->type & FILE_DATA_FLASH) == FILE_DATA_FLASH) {
|
||||||
@@ -243,8 +247,7 @@ void initialize_flash(bool hard) {
|
|||||||
|
|
||||||
extern uintptr_t last_base;
|
extern uintptr_t last_base;
|
||||||
extern uint32_t num_files;
|
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;
|
uintptr_t endp = end_data_pool, startp = start_data_pool;
|
||||||
if (persistent) {
|
if (persistent) {
|
||||||
endp = end_rom_pool;
|
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));
|
uint16_t fid = flash_read_uint16(base + sizeof(uintptr_t) + sizeof(uintptr_t));
|
||||||
printf("[%x] scan fid %x, len %d\n", (unsigned int) base, fid, flash_read_uint16(base + sizeof(uintptr_t) + sizeof(uintptr_t) + sizeof(uint16_t)));
|
printf("[%x] scan fid %x, len %d\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) {
|
if (!file) {
|
||||||
file = file_new(fid);
|
file = file_new(fid);
|
||||||
}
|
}
|
||||||
@@ -279,18 +282,17 @@ void scan_region(bool persistent)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void wait_flash_finish();
|
void file_scan_flash(void) {
|
||||||
void scan_flash() {
|
file_initialize_flash(false); //soft initialization
|
||||||
initialize_flash(false); //soft initialization
|
uint32_t r1 = (uint32_t)flash_read_uintptr(end_rom_pool);
|
||||||
uint32_t r1 = *(uintptr_t *) flash_read(end_rom_pool), r2 = *(uintptr_t *) flash_read(end_rom_pool + sizeof(uintptr_t));
|
uint32_t r2 = (uint32_t)flash_read_uintptr(end_rom_pool + sizeof(uintptr_t));
|
||||||
if ((r1 == 0xffffffff || r1 == 0xefefefef) && (r2 == 0xffffffff || r2 == 0xefefefef)) {
|
if ((r1 == 0xffffffff || r1 == 0xefefefef) && (r2 == 0xffffffff || r2 == 0xefefefef)) {
|
||||||
printf("First initialization (or corrupted!)\n");
|
printf("First initialization (or corrupted!)\n");
|
||||||
uint8_t empty[sizeof(uintptr_t) * 2 + sizeof(uint32_t)];
|
uint8_t empty[sizeof(uintptr_t) * 2 + sizeof(uint32_t)];
|
||||||
memset(empty, 0, sizeof(empty));
|
memset(empty, 0, sizeof(empty));
|
||||||
flash_program_block(end_data_pool, empty, sizeof(empty));
|
flash_program_block(end_data_pool, empty, sizeof(empty));
|
||||||
flash_program_block(end_rom_pool, empty, sizeof(empty));
|
flash_program_block(end_rom_pool, empty, sizeof(empty));
|
||||||
//low_flash_available();
|
//flash_commit();
|
||||||
//wait_flash_finish();
|
|
||||||
}
|
}
|
||||||
printf("SCAN\n");
|
printf("SCAN\n");
|
||||||
scan_region(true);
|
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);
|
return flash_write_data_to_file(file, data, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
file_t *search_dynamic_file(uint16_t fid) {
|
static int delete_dynamic_file(file_t *f) {
|
||||||
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) {
|
|
||||||
if (f == NULL) {
|
if (f == NULL) {
|
||||||
return PICOKEY_ERR_FILE_NOT_FOUND;
|
return PICOKEYS_ERR_FILE_NOT_FOUND;
|
||||||
}
|
}
|
||||||
for (int i = 0; i < dynamic_files; i++) {
|
for (int i = 0; i < dynamic_files; i++) {
|
||||||
if (dynamic_file[i].fid == f->fid) {
|
if (dynamic_file[i].fid == f->fid) {
|
||||||
@@ -347,15 +340,15 @@ int delete_dynamic_file(file_t *f) {
|
|||||||
memcpy(&dynamic_file[j - 1], &dynamic_file[j], sizeof(file_t));
|
memcpy(&dynamic_file[j - 1], &dynamic_file[j], sizeof(file_t));
|
||||||
}
|
}
|
||||||
dynamic_files--;
|
dynamic_files--;
|
||||||
return PICOKEY_OK;
|
return PICOKEYS_OK;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return PICOKEY_ERR_FILE_NOT_FOUND;
|
return PICOKEYS_ERR_FILE_NOT_FOUND;
|
||||||
}
|
}
|
||||||
|
|
||||||
file_t *file_new(uint16_t fid) {
|
file_t *file_new(uint16_t fid) {
|
||||||
file_t *f;
|
file_t *f;
|
||||||
if ((f = search_file(fid))) {
|
if ((f = file_search(fid))) {
|
||||||
return f;
|
return f;
|
||||||
}
|
}
|
||||||
if (dynamic_files == MAX_DYNAMIC_FILES) {
|
if (dynamic_files == MAX_DYNAMIC_FILES) {
|
||||||
@@ -377,20 +370,20 @@ file_t *file_new(uint16_t fid) {
|
|||||||
return f;
|
return f;
|
||||||
}
|
}
|
||||||
uint16_t meta_find(uint16_t fid, uint8_t **out) {
|
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) {
|
if (!ef) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
uint16_t tag = 0x0;
|
uint16_t tag = 0x0;
|
||||||
uint8_t *tag_data = NULL, *p = NULL;
|
uint8_t *tag_data = NULL, *p = NULL;
|
||||||
uint16_t tag_len = 0;
|
uint16_t tag_len = 0;
|
||||||
asn1_ctx_t ctxi;
|
tlv_ctx_t ctxi;
|
||||||
asn1_ctx_init(file_get_data(ef), file_get_size(ef), &ctxi);
|
tlv_ctx_init(file_get_data(ef), file_get_size(ef), &ctxi);
|
||||||
while (walk_tlv(&ctxi, &p, &tag, &tag_len, &tag_data)) {
|
while (tlv_walk(&ctxi, &p, &tag, &tag_len, &tag_data)) {
|
||||||
if (tag_len < 2) {
|
if (tag_len < 2) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
uint16_t cfid = get_uint16_t_be(tag_data);
|
uint16_t cfid = get_uint16_be(tag_data);
|
||||||
if (cfid == fid) {
|
if (cfid == fid) {
|
||||||
if (out) {
|
if (out) {
|
||||||
*out = tag_data + 2;
|
*out = tag_data + 2;
|
||||||
@@ -401,24 +394,24 @@ uint16_t meta_find(uint16_t fid, uint8_t **out) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
int meta_delete(uint16_t fid) {
|
int meta_delete(uint16_t fid) {
|
||||||
file_t *ef = search_file(EF_META);
|
file_t *ef = file_search(EF_META);
|
||||||
if (!ef) {
|
if (!ef) {
|
||||||
return PICOKEY_ERR_FILE_NOT_FOUND;
|
return PICOKEYS_ERR_FILE_NOT_FOUND;
|
||||||
}
|
}
|
||||||
uint16_t tag = 0x0;
|
uint16_t tag = 0x0;
|
||||||
uint8_t *tag_data = NULL, *p = NULL;
|
uint8_t *tag_data = NULL, *p = NULL;
|
||||||
uint16_t tag_len = 0;
|
uint16_t tag_len = 0;
|
||||||
uint8_t *fdata = NULL;
|
uint8_t *fdata = NULL;
|
||||||
asn1_ctx_t ctxi;
|
tlv_ctx_t ctxi;
|
||||||
asn1_ctx_init(file_get_data(ef), file_get_size(ef), &ctxi);
|
tlv_ctx_init(file_get_data(ef), file_get_size(ef), &ctxi);
|
||||||
while (walk_tlv(&ctxi, &p, &tag, &tag_len, &tag_data)) {
|
while (tlv_walk(&ctxi, &p, &tag, &tag_len, &tag_data)) {
|
||||||
uint8_t *tpos = p - tag_len - format_tlv_len(tag_len, NULL) - 1;
|
uint8_t *tpos = p - tag_len - tlv_format_len(tag_len, NULL) - 1;
|
||||||
if (tag_len < 2) {
|
if (tag_len < 2) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
uint16_t cfid = get_uint16_t_be(tag_data);
|
uint16_t cfid = get_uint16_be(tag_data);
|
||||||
if (cfid == fid) {
|
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) {
|
if (new_len == 0) {
|
||||||
flash_clear_file(ef);
|
flash_clear_file(ef);
|
||||||
}
|
}
|
||||||
@@ -432,21 +425,21 @@ int meta_delete(uint16_t fid) {
|
|||||||
}
|
}
|
||||||
int r = file_put_data(ef, fdata, new_len);
|
int r = file_put_data(ef, fdata, new_len);
|
||||||
free(fdata);
|
free(fdata);
|
||||||
if (r != PICOKEY_OK) {
|
if (r != PICOKEYS_OK) {
|
||||||
return PICOKEY_EXEC_ERROR;
|
return PICOKEYS_EXEC_ERROR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
low_flash_available();
|
flash_commit();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return PICOKEY_OK;
|
return PICOKEYS_OK;
|
||||||
}
|
}
|
||||||
int meta_add(uint16_t fid, const uint8_t *data, uint16_t len) {
|
int meta_add(uint16_t fid, const uint8_t *data, uint16_t len) {
|
||||||
int r;
|
int r;
|
||||||
file_t *ef = search_file(EF_META);
|
file_t *ef = file_search(EF_META);
|
||||||
if (!ef) {
|
if (!ef) {
|
||||||
return PICOKEY_ERR_FILE_NOT_FOUND;
|
return PICOKEYS_ERR_FILE_NOT_FOUND;
|
||||||
}
|
}
|
||||||
uint16_t ef_size = file_get_size(ef);
|
uint16_t ef_size = file_get_size(ef);
|
||||||
uint8_t *fdata = (uint8_t *) calloc(1, ef_size);
|
uint8_t *fdata = (uint8_t *) calloc(1, ef_size);
|
||||||
@@ -454,25 +447,25 @@ int meta_add(uint16_t fid, const uint8_t *data, uint16_t len) {
|
|||||||
uint16_t tag = 0x0;
|
uint16_t tag = 0x0;
|
||||||
uint8_t *tag_data = NULL, *p = NULL;
|
uint8_t *tag_data = NULL, *p = NULL;
|
||||||
uint16_t tag_len = 0;
|
uint16_t tag_len = 0;
|
||||||
asn1_ctx_t ctxi;
|
tlv_ctx_t ctxi;
|
||||||
asn1_ctx_init(fdata, ef_size, &ctxi);
|
tlv_ctx_init(fdata, ef_size, &ctxi);
|
||||||
while (walk_tlv(&ctxi, &p, &tag, &tag_len, &tag_data)) {
|
while (tlv_walk(&ctxi, &p, &tag, &tag_len, &tag_data)) {
|
||||||
if (tag_len < 2) {
|
if (tag_len < 2) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
uint16_t cfid = get_uint16_t_be(tag_data);
|
uint16_t cfid = get_uint16_be(tag_data);
|
||||||
if (cfid == fid) {
|
if (cfid == fid) {
|
||||||
if (tag_len - 2 == len) { //an update
|
if (tag_len - 2 == len) { //an update
|
||||||
memcpy(p - tag_len + 2, data, len);
|
memcpy(p - tag_len + 2, data, len);
|
||||||
r = file_put_data(ef, fdata, ef_size);
|
r = file_put_data(ef, fdata, ef_size);
|
||||||
free(fdata);
|
free(fdata);
|
||||||
if (r != PICOKEY_OK) {
|
if (r != PICOKEYS_OK) {
|
||||||
return PICOKEY_EXEC_ERROR;
|
return PICOKEYS_EXEC_ERROR;
|
||||||
}
|
}
|
||||||
return PICOKEY_OK;
|
return PICOKEYS_OK;
|
||||||
}
|
}
|
||||||
else { //needs reallocation
|
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);
|
memmove(tpos, p, fdata + ef_size - p);
|
||||||
tpos += fdata + ef_size - p;
|
tpos += fdata + ef_size - p;
|
||||||
volatile uintptr_t meta_offset = tpos - fdata;
|
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 {
|
else {
|
||||||
free(fdata);
|
free(fdata);
|
||||||
return PICOKEY_ERR_MEMORY_FATAL;
|
return PICOKEYS_ERR_MEMORY_FATAL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
uint8_t *f = fdata + meta_offset;
|
uint8_t *f = fdata + meta_offset;
|
||||||
*f++ = fid & 0xff;
|
*f++ = fid & 0xff;
|
||||||
f += format_tlv_len(len + 2, f);
|
f += tlv_format_len(len + 2, f);
|
||||||
f += put_uint16_t_be(fid, f);
|
f += put_uint16_be(fid, f);
|
||||||
memcpy(f, data, len);
|
memcpy(f, data, len);
|
||||||
r = file_put_data(ef, fdata, ef_size);
|
r = file_put_data(ef, fdata, ef_size);
|
||||||
free(fdata);
|
free(fdata);
|
||||||
if (r != PICOKEY_OK) {
|
if (r != PICOKEYS_OK) {
|
||||||
return PICOKEY_EXEC_ERROR;
|
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;
|
uint8_t *f = fdata + ef_size;
|
||||||
*f++ = fid & 0x1f;
|
*f++ = fid & 0x1f;
|
||||||
f += format_tlv_len(len + 2, f);
|
f += tlv_format_len(len + 2, f);
|
||||||
f += put_uint16_t_be(fid, f);
|
f += put_uint16_be(fid, f);
|
||||||
memcpy(f, data, len);
|
memcpy(f, data, len);
|
||||||
r = file_put_data(ef, fdata, ef_size + (uint16_t)asn1_len_tag(fid & 0x1f, len + 2));
|
r = file_put_data(ef, fdata, ef_size + (uint16_t)tlv_len_tag(fid & 0x1f, len + 2));
|
||||||
free(fdata);
|
free(fdata);
|
||||||
if (r != PICOKEY_OK) {
|
if (r != PICOKEYS_OK) {
|
||||||
return PICOKEY_EXEC_ERROR;
|
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;
|
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) {
|
if (ef == NULL) {
|
||||||
return PICOKEY_OK;
|
return PICOKEYS_OK;
|
||||||
}
|
}
|
||||||
meta_delete(ef->fid);
|
meta_delete(ef->fid);
|
||||||
if (flash_clear_file(ef) != PICOKEY_OK) {
|
if (flash_clear_file(ef) != PICOKEYS_OK) {
|
||||||
return PICOKEY_EXEC_ERROR;
|
return PICOKEYS_EXEC_ERROR;
|
||||||
}
|
}
|
||||||
if (delete_dynamic_file(ef) != PICOKEY_OK) {
|
if (delete_dynamic_file(ef) != PICOKEYS_OK) {
|
||||||
return PICOKEY_EXEC_ERROR;
|
return PICOKEYS_EXEC_ERROR;
|
||||||
}
|
}
|
||||||
low_flash_available();
|
flash_commit();
|
||||||
return PICOKEY_OK;
|
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.
|
* Copyright (c) 2022 Pol Henarejos.
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU 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.
|
* the Free Software Foundation, version 3.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful, but
|
* This program is distributed in the hope that it will be useful, but
|
||||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* 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
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _FILE_H_
|
#ifndef _FILE_H_
|
||||||
#define _FILE_H_
|
#define _FILE_H_
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stddef.h>
|
||||||
#if !defined(ENABLE_EMULATION) && !defined(ESP_PLATFORM)
|
|
||||||
#include "pico/stdlib.h"
|
|
||||||
#else
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#endif
|
#include <stdbool.h>
|
||||||
#include "compat.h"
|
#include "compat/compat.h"
|
||||||
#include "phy.h"
|
#include "phy.h"
|
||||||
|
|
||||||
#define FILE_TYPE_NOT_KNOWN 0x00
|
#define FILE_TYPE_NOT_KNOWN 0x00
|
||||||
@@ -55,36 +51,40 @@
|
|||||||
#define ACL_OP_UPDATE_ERASE 0x05
|
#define ACL_OP_UPDATE_ERASE 0x05
|
||||||
#define ACL_OP_READ_SEARCH 0x06
|
#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_EF 0x1
|
||||||
#define SPECIFY_DF 0x2
|
#define SPECIFY_DF 0x2
|
||||||
#define SPECIFY_ANY 0x3
|
#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 EF_META 0xE010
|
||||||
|
|
||||||
#define MAX_DEPTH 4
|
#ifdef _MSC_VER
|
||||||
|
__pragma( pack(push, 1) )
|
||||||
#define MAX_DYNAMIC_FILES 256
|
#endif
|
||||||
|
|
||||||
typedef struct file {
|
typedef struct file {
|
||||||
const uint8_t *name;
|
const uint8_t *name;
|
||||||
uint8_t *data; //should include 2 bytes len at begining
|
uint8_t *data; //should include 2 bytes len at begining
|
||||||
const uint16_t fid;
|
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 parent; //entry number in the whole table!!
|
||||||
const uint8_t type;
|
const uint8_t type;
|
||||||
const uint8_t ef_structure;
|
const uint8_t ef_structure;
|
||||||
#ifdef ENABLE_EMULATION
|
#ifdef ENABLE_EMULATION
|
||||||
uint32_t _padding;
|
uint32_t _padding;
|
||||||
#endif
|
#endif
|
||||||
} __attribute__ ((packed)) file_t;
|
}
|
||||||
|
#ifdef _MSC_VER
|
||||||
extern bool file_has_data(file_t *);
|
__pragma( pack(pop) )
|
||||||
|
#else
|
||||||
|
__attribute__ ((packed))
|
||||||
|
#endif
|
||||||
|
file_t;
|
||||||
|
|
||||||
extern file_t *currentEF;
|
extern file_t *currentEF;
|
||||||
extern file_t *currentDF;
|
extern file_t *currentDF;
|
||||||
@@ -92,22 +92,16 @@ extern const file_t *selected_applet;
|
|||||||
|
|
||||||
extern const file_t *MF;
|
extern const file_t *MF;
|
||||||
extern const file_t *file_last;
|
extern const file_t *file_last;
|
||||||
extern const file_t *file_openpgp;
|
|
||||||
extern const file_t *file_sc_hsm;
|
|
||||||
extern bool card_terminated;
|
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 *file_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 *file_search(const uint16_t fid);
|
||||||
extern file_t *search_by_name(uint8_t *name, uint16_t namelen);
|
extern file_t *file_search_by_name(uint8_t *name, uint16_t namelen);
|
||||||
extern file_t *search_by_path(const uint8_t *pe_path, uint8_t pathlen, const file_t *parent);
|
extern file_t *file_search_by_path(const uint8_t *pe_path, uint8_t pathlen, const file_t *parent);
|
||||||
extern bool authenticate_action(const file_t *ef, uint8_t op);
|
extern bool file_authenticate_action(const file_t *ef, uint8_t op);
|
||||||
extern void process_fci(const file_t *pe, int fmd);
|
extern void file_process_fci(const file_t *pe, int fmd);
|
||||||
extern void scan_flash();
|
extern void file_scan_flash(void);
|
||||||
extern void initialize_flash(bool);
|
extern void file_initialize_flash(bool);
|
||||||
|
|
||||||
extern file_t file_entries[];
|
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 uint16_t file_read_uint16(const uint8_t *addr);
|
||||||
extern uint8_t file_read_uint8(const file_t *ef);
|
extern uint8_t file_read_uint8(const file_t *ef);
|
||||||
extern uint8_t file_read_uint8_offset(const file_t *ef, const uint16_t offset);
|
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 uint8_t *file_get_data(const file_t *tf);
|
||||||
extern uint16_t file_get_size(const file_t *tf);
|
extern uint16_t file_get_size(const file_t *tf);
|
||||||
extern int file_put_data(file_t *file, const uint8_t *data, uint16_t len);
|
extern int file_put_data(file_t *file, const uint8_t *data, uint16_t len);
|
||||||
extern file_t *file_new(uint16_t);
|
extern file_t *file_new(uint16_t);
|
||||||
|
extern int flash_clear_file(file_t *file);
|
||||||
|
extern int file_delete(file_t *ef);
|
||||||
file_t *get_parent(file_t *f);
|
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 bool isUserAuthenticated;
|
||||||
|
|
||||||
extern uint16_t meta_find(uint16_t, uint8_t **out);
|
extern uint16_t meta_find(uint16_t, uint8_t **out);
|
||||||
extern int meta_delete(uint16_t fid);
|
extern int meta_delete(uint16_t fid);
|
||||||
extern int meta_add(uint16_t fid, const uint8_t *data, uint16_t len);
|
extern int meta_add(uint16_t fid, const uint8_t *data, uint16_t len);
|
||||||
extern int delete_file(file_t *ef);
|
|
||||||
|
|
||||||
extern uint32_t flash_free_space();
|
|
||||||
extern uint32_t flash_used_space();
|
|
||||||
extern uint32_t flash_total_space();
|
|
||||||
extern uint32_t flash_num_files();
|
|
||||||
extern uint32_t flash_size();
|
|
||||||
|
|
||||||
#ifndef ENABLE_EMULATION
|
#ifndef ENABLE_EMULATION
|
||||||
extern file_t *ef_phy;
|
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.
|
* Copyright (c) 2022 Pol Henarejos.
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU 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.
|
* the Free Software Foundation, version 3.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful, but
|
* This program is distributed in the hope that it will be useful, but
|
||||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* 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
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "picokeys.h"
|
||||||
|
|
||||||
#include <stdint.h>
|
#if !defined(PICO_PLATFORM)
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#if defined(ENABLE_EMULATION) || defined(ESP_PLATFORM)
|
|
||||||
#define XIP_BASE 0
|
#define XIP_BASE 0
|
||||||
#define FLASH_SECTOR_SIZE 4096
|
#ifdef ENABLE_EMULATION
|
||||||
#ifdef ESP_PLATFORM
|
#define FLASH_SECTOR_SIZE 0x4000
|
||||||
uint32_t PICO_FLASH_SIZE_BYTES = (1 * 1024 * 1024);
|
|
||||||
#else
|
#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
|
#endif
|
||||||
#else
|
#else
|
||||||
#include "pico/stdlib.h"
|
uint32_t FLASH_SIZE_BYTES = (2 * 1024 * 1024);
|
||||||
#include "hardware/flash.h"
|
#include "hardware/flash.h"
|
||||||
#endif
|
#endif
|
||||||
#include "pico_keys.h"
|
|
||||||
#include "file.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
|
//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;
|
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;
|
uintptr_t last_base;
|
||||||
uint32_t num_files = 0;
|
uint32_t num_files = 0;
|
||||||
|
|
||||||
@@ -71,7 +65,7 @@ void flash_set_bounds(uintptr_t start, uintptr_t end) {
|
|||||||
last_base = end_data_pool;
|
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) {
|
if (size > FLASH_SECTOR_SIZE) {
|
||||||
return 0x0; //ERROR
|
return 0x0; //ERROR
|
||||||
}
|
}
|
||||||
@@ -118,35 +112,14 @@ uintptr_t allocate_free_addr(uint16_t size, bool persistent) {
|
|||||||
return 0x0; //probably never reached
|
return 0x0; //probably never reached
|
||||||
}
|
}
|
||||||
|
|
||||||
int flash_clear_file(file_t *file) {
|
static int flash_write_data_to_file_offset(file_t *file, const uint8_t *data, uint16_t len, uint16_t offset) {
|
||||||
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) {
|
|
||||||
if (!file) {
|
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;
|
uint16_t size_file_flash = file->data ? flash_read_uint16((uintptr_t) file->data) : 0;
|
||||||
uint8_t *old_data = NULL;
|
uint8_t *old_data = NULL;
|
||||||
if (offset + len > FLASH_SECTOR_SIZE || offset > size_file_flash) {
|
if (offset + len > FLASH_SECTOR_SIZE || offset > size_file_flash) {
|
||||||
return PICOKEY_ERR_NO_MEMORY;
|
return PICOKEYS_ERR_NO_MEMORY;
|
||||||
}
|
}
|
||||||
if (file->data) { //already in flash
|
if (file->data) { //already in flash
|
||||||
if (offset + len <= size_file_flash) { //it fits, no need to move it
|
if (offset + len <= size_file_flash) { //it fits, no need to move it
|
||||||
@@ -154,7 +127,7 @@ int flash_write_data_to_file_offset(file_t *file, const uint8_t *data, uint16_t
|
|||||||
if (data) {
|
if (data) {
|
||||||
flash_program_block((uintptr_t) file->data + sizeof(uint16_t) + offset, data, len);
|
flash_program_block((uintptr_t) file->data + sizeof(uint16_t) + offset, data, len);
|
||||||
}
|
}
|
||||||
return PICOKEY_OK;
|
return PICOKEYS_OK;
|
||||||
}
|
}
|
||||||
else { //we clear the old file
|
else { //we clear the old file
|
||||||
flash_clear_file(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);
|
uintptr_t new_addr = allocate_free_addr(len, (file->type & FILE_PERSISTENT) == FILE_PERSISTENT);
|
||||||
//printf("na %x\n",new_addr);
|
//printf("na %x\n",new_addr);
|
||||||
if (new_addr == 0x0) {
|
if (new_addr == 0x0) {
|
||||||
return PICOKEY_ERR_NO_MEMORY;
|
return PICOKEYS_ERR_NO_MEMORY;
|
||||||
}
|
}
|
||||||
if (new_addr < last_base) {
|
if (new_addr < last_base) {
|
||||||
last_base = new_addr;
|
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);
|
free(old_data);
|
||||||
}
|
}
|
||||||
num_files++;
|
num_files++;
|
||||||
return PICOKEY_OK;
|
return PICOKEYS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int flash_write_data_to_file(file_t *file, const uint8_t *data, uint16_t len) {
|
int flash_write_data_to_file(file_t *file, const uint8_t *data, uint16_t len) {
|
||||||
return flash_write_data_to_file_offset(file, data, len, 0);
|
return flash_write_data_to_file_offset(file, data, len, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t flash_free_space() {
|
uint32_t flash_free_space(void) {
|
||||||
return last_base - start_data_pool;
|
return (uint32_t)(last_base - start_data_pool);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t flash_used_space() {
|
uint32_t flash_used_space(void) {
|
||||||
return end_data_pool - last_base;
|
return (uint32_t)(end_data_pool - last_base);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t flash_total_space() {
|
uint32_t flash_total_space(void) {
|
||||||
return end_data_pool - start_data_pool;
|
return (uint32_t)(end_data_pool - start_data_pool);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t flash_num_files() {
|
uint32_t flash_num_files(void) {
|
||||||
return num_files;
|
return num_files;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t flash_size() {
|
uint32_t flash_size(void) {
|
||||||
return PICO_FLASH_SIZE_BYTES;
|
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.
|
* Copyright (c) 2022 Pol Henarejos.
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU 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.
|
* the Free Software Foundation, version 3.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful, but
|
* This program is distributed in the hope that it will be useful, but
|
||||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* 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
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "picokeys.h"
|
||||||
#include <stdint.h>
|
#include "serial.h"
|
||||||
#include <stdlib.h>
|
#include "crypto_utils.h"
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
#include "pico_keys.h"
|
|
||||||
#include <string.h>
|
|
||||||
#ifdef PICO_PLATFORM
|
#ifdef PICO_PLATFORM
|
||||||
#include "pico/stdlib.h"
|
|
||||||
#include "hardware/flash.h"
|
#include "hardware/flash.h"
|
||||||
#include "hardware/sync.h"
|
#include "hardware/sync.h"
|
||||||
#include "pico/mutex.h"
|
#include "pico/mutex.h"
|
||||||
@@ -32,62 +28,64 @@
|
|||||||
#include "pico/bootrom.h"
|
#include "pico/bootrom.h"
|
||||||
#include "boot/picobin.h"
|
#include "boot/picobin.h"
|
||||||
#else
|
#else
|
||||||
#ifdef _MSC_VER
|
#ifdef ESP_PLATFORM
|
||||||
#include <windows.h>
|
#include "compat/esp_compat.h"
|
||||||
#include <io.h>
|
#include "esp_partition.h"
|
||||||
#define O_RDWR _O_RDWR
|
const esp_partition_t *part0;
|
||||||
#define O_CREAT _O_CREAT
|
#define save_and_disable_interrupts() 1
|
||||||
#define open _open
|
#define flash_range_erase(a,b) esp_partition_erase_range(part0, a, b)
|
||||||
#define write _write
|
#define flash_range_program(a,b,c) esp_partition_write(part0, a, b, c);
|
||||||
#define mode_t unsigned short
|
#define restore_interrupts(a) (void)a
|
||||||
#define lseek _lseek
|
|
||||||
#include "mman.h"
|
|
||||||
#else
|
#else
|
||||||
#ifdef ESP_PLATFORM
|
#ifdef _MSC_VER
|
||||||
#include "esp_compat.h"
|
#include <windows.h>
|
||||||
#include "esp_partition.h"
|
#include <io.h>
|
||||||
const esp_partition_t *part0;
|
#define O_RDWR _O_RDWR
|
||||||
#define save_and_disable_interrupts() 1
|
#define O_CREAT _O_CREAT
|
||||||
#define flash_range_erase(a,b) esp_partition_erase_range(part0, a, b)
|
#define open _open
|
||||||
#define flash_range_program(a,b,c) esp_partition_write(part0, a, b, c);
|
#define write _write
|
||||||
#define restore_interrupts(a) (void)a
|
#define mode_t unsigned short
|
||||||
|
#define lseek _lseek
|
||||||
|
#include "mman.h"
|
||||||
#else
|
#else
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
#include "emulation.h"
|
|
||||||
#endif
|
#endif
|
||||||
|
#include "compat/queue.h"
|
||||||
#endif
|
#endif
|
||||||
#define FLASH_SECTOR_SIZE 4096
|
#ifdef ENABLE_EMULATION
|
||||||
#ifdef ESP_PLATFORM
|
#define FLASH_SECTOR_SIZE 0x4000
|
||||||
extern uint32_t PICO_FLASH_SIZE_BYTES;
|
|
||||||
#else
|
#else
|
||||||
#define PICO_FLASH_SIZE_BYTES (8 * 1024 * 1024)
|
#define FLASH_SECTOR_SIZE 0x1000
|
||||||
#endif
|
#endif
|
||||||
#define XIP_BASE 0
|
#define XIP_BASE 0
|
||||||
int fd_map = 0;
|
int fd_map = 0;
|
||||||
uint8_t *map = NULL;
|
uint8_t *map = NULL;
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#endif
|
#endif
|
||||||
|
#if defined(PICO_PLATFORM) || defined(ESP_PLATFORM)
|
||||||
|
extern uint32_t FLASH_SIZE_BYTES;
|
||||||
|
#else
|
||||||
|
#define FLASH_SIZE_BYTES (8 * 1024 * 1024)
|
||||||
|
#endif
|
||||||
|
|
||||||
#define TOTAL_FLASH_PAGES 6
|
#define TOTAL_FLASH_PAGES 6
|
||||||
|
|
||||||
extern void flash_set_bounds(uintptr_t start, uintptr_t end);
|
|
||||||
|
|
||||||
extern const uintptr_t start_data_pool;
|
extern const uintptr_t start_data_pool;
|
||||||
extern const uintptr_t end_rom_pool;
|
extern const uintptr_t end_rom_pool;
|
||||||
|
|
||||||
|
PACK(
|
||||||
typedef struct page_flash {
|
typedef struct page_flash {
|
||||||
uint8_t page[FLASH_SECTOR_SIZE];
|
uint8_t page[FLASH_SECTOR_SIZE];
|
||||||
uintptr_t address;
|
uintptr_t address;
|
||||||
bool ready;
|
bool ready;
|
||||||
bool erase;
|
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
|
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 page_flash_t flash_pages[TOTAL_FLASH_PAGES];
|
||||||
|
|
||||||
static mutex_t mtx_flash;
|
static mutex_t mtx_flash;
|
||||||
static semaphore_t sem_flash;
|
|
||||||
|
|
||||||
#ifndef ENABLE_EMULATION
|
#ifndef ENABLE_EMULATION
|
||||||
static bool locked_out = false;
|
static bool locked_out = false;
|
||||||
@@ -101,25 +99,34 @@ bool flash_available = false;
|
|||||||
|
|
||||||
|
|
||||||
//this function has to be called from the core 0
|
//this function has to be called from the core 0
|
||||||
void do_flash() {
|
void low_flash_task(void);
|
||||||
|
void low_flash_commit(void);
|
||||||
|
|
||||||
|
void low_flash_task(void){
|
||||||
if (mutex_try_enter(&mtx_flash, NULL) == true) {
|
if (mutex_try_enter(&mtx_flash, NULL) == true) {
|
||||||
if (locked_out == true && flash_available == true && ready_pages > 0) {
|
if (locked_out == true && flash_available == true && ready_pages > 0) {
|
||||||
//printf(" DO_FLASH AVAILABLE\n");
|
//printf(" DO_FLASH AVAILABLE\n");
|
||||||
for (int r = 0; r < TOTAL_FLASH_PAGES; r++) {
|
for (int r = 0; r < TOTAL_FLASH_PAGES; r++) {
|
||||||
if (flash_pages[r].ready == true) {
|
if (flash_pages[r].ready == true) {
|
||||||
#ifndef ENABLE_EMULATION
|
#if defined(PICO_PLATFORM) || defined(ESP_PLATFORM)
|
||||||
|
mutex_exit(&mtx_flash);
|
||||||
//printf("WRITTING %X\n",flash_pages[r].address-XIP_BASE);
|
//printf("WRITTING %X\n",flash_pages[r].address-XIP_BASE);
|
||||||
while (multicore_lockout_start_timeout_us(1000) == false) {
|
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);
|
//printf("WRITTING %X\n",flash_pages[r].address-XIP_BASE);
|
||||||
uint32_t ints = save_and_disable_interrupts();
|
uint32_t ints = save_and_disable_interrupts();
|
||||||
flash_range_erase(flash_pages[r].address - XIP_BASE, FLASH_SECTOR_SIZE);
|
flash_range_erase(flash_pages[r].address - XIP_BASE, FLASH_SECTOR_SIZE);
|
||||||
flash_range_program(flash_pages[r].address - XIP_BASE, flash_pages[r].page, FLASH_SECTOR_SIZE);
|
flash_range_program(flash_pages[r].address - XIP_BASE, flash_pages[r].page, FLASH_SECTOR_SIZE);
|
||||||
restore_interrupts(ints);
|
restore_interrupts(ints);
|
||||||
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);
|
//printf("WRITEN %X !\n",flash_pages[r].address);
|
||||||
#else
|
#else
|
||||||
memcpy(map + flash_pages[r].address, flash_pages[r].page, FLASH_SECTOR_SIZE);
|
memcpy(map + flash_pages[r].address, flash_pages[r].page, FLASH_SECTOR_SIZE);
|
||||||
@@ -128,15 +135,23 @@ void do_flash() {
|
|||||||
ready_pages--;
|
ready_pages--;
|
||||||
}
|
}
|
||||||
else if (flash_pages[r].erase == true) {
|
else if (flash_pages[r].erase == true) {
|
||||||
#ifndef ENABLE_EMULATION
|
#if defined(PICO_PLATFORM) || defined(ESP_PLATFORM)
|
||||||
while (multicore_lockout_start_timeout_us(1000) == false) {
|
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");
|
//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);
|
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
|
#else
|
||||||
memset(map + flash_pages[r].address, 0, FLASH_SECTOR_SIZE);
|
memset(map + flash_pages[r].address, 0, FLASH_SECTOR_SIZE);
|
||||||
#endif
|
#endif
|
||||||
@@ -144,96 +159,104 @@ void do_flash() {
|
|||||||
ready_pages--;
|
ready_pages--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#ifdef ENABLE_EMULATION
|
#if !defined(PICO_PLATFORM) && !defined(ESP_PLATFORM)
|
||||||
msync(map, PICO_FLASH_SIZE_BYTES, MS_SYNC);
|
msync(map, FLASH_SIZE_BYTES, MS_SYNC);
|
||||||
#endif
|
#endif
|
||||||
if (ready_pages != 0) {
|
if (ready_pages != 0) {
|
||||||
printf("ERROR: DO FLASH DOES NOT HAVE ZERO PAGES\n");
|
printf("ERROR: DO FLASH DOES NOT HAVE ZERO PAGES\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
flash_available = false;
|
if (ready_pages == 0) {
|
||||||
|
flash_available = false;
|
||||||
|
}
|
||||||
#ifdef ESP_PLATFORM
|
#ifdef ESP_PLATFORM
|
||||||
esp_partition_munmap(fd_map);
|
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);
|
esp_partition_mmap(part0, 0, part0->size, ESP_PARTITION_MMAP_DATA, (const void **)&map, (esp_partition_mmap_handle_t *)&fd_map);
|
||||||
#endif
|
#endif
|
||||||
mutex_exit(&mtx_flash);
|
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
|
//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);
|
memset(flash_pages, 0, sizeof(page_flash_t) * TOTAL_FLASH_PAGES);
|
||||||
mutex_init(&mtx_flash);
|
mutex_init(&mtx_flash);
|
||||||
sem_init(&sem_flash, 0, 1);
|
|
||||||
|
|
||||||
uint32_t data_start_addr;
|
uint32_t data_start_addr;
|
||||||
uint32_t data_end_addr;
|
uint32_t data_end_addr;
|
||||||
#if defined(ENABLE_EMULATION)
|
#if defined(ESP_PLATFORM)
|
||||||
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)
|
|
||||||
part0 = esp_partition_find_first(0x40, 0x1, "part0");
|
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);
|
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_start_addr = 0;
|
||||||
data_end_addr = part0->size;
|
data_end_addr = part0->size;
|
||||||
PICO_FLASH_SIZE_BYTES = part0->size;
|
FLASH_SIZE_BYTES = part0->size;
|
||||||
#elif defined(PICO_PLATFORM)
|
#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
|
#ifdef PICO_RP2350
|
||||||
__attribute__((aligned(4))) uint8_t workarea[4 * 1024];
|
__attribute__((aligned(4))) uint32_t workarea[1024];
|
||||||
int rc = rom_load_partition_table(workarea, sizeof(workarea), false);
|
int rc = rom_load_partition_table((uint8_t *)workarea, sizeof(workarea), false);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
reset_usb_boot(0, 0);
|
reset_usb_boot(0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t boot_partition = 1;
|
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) {
|
if (rc != 3) {
|
||||||
data_start_addr = (PICO_FLASH_SIZE_BYTES >> 1);
|
data_start_addr = (FLASH_SIZE_BYTES >> 1);
|
||||||
data_end_addr = PICO_FLASH_SIZE_BYTES;
|
data_end_addr = FLASH_SIZE_BYTES;
|
||||||
} else {
|
} else {
|
||||||
uint16_t first_sector_number = (((uint32_t*)workarea)[1] & PICOBIN_PARTITION_LOCATION_FIRST_SECTOR_BITS) >> PICOBIN_PARTITION_LOCATION_FIRST_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 = (((uint32_t*)workarea)[1] & PICOBIN_PARTITION_LOCATION_LAST_SECTOR_BITS) >> PICOBIN_PARTITION_LOCATION_LAST_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_start_addr = first_sector_number * FLASH_SECTOR_SIZE;
|
||||||
data_end_addr = (last_sector_number + 1) * 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;
|
data_end_addr -= 2 * FLASH_SECTOR_SIZE;
|
||||||
#else
|
#else
|
||||||
data_start_addr = (PICO_FLASH_SIZE_BYTES >> 1);
|
data_start_addr = (FLASH_SIZE_BYTES >> 1);
|
||||||
data_end_addr = PICO_FLASH_SIZE_BYTES;
|
data_end_addr = FLASH_SIZE_BYTES;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
data_start_addr += XIP_BASE;
|
data_start_addr += XIP_BASE;
|
||||||
data_end_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
|
#endif
|
||||||
flash_set_bounds(data_start_addr, data_end_addr);
|
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);
|
mutex_enter_blocking(&mtx_flash);
|
||||||
multicore_lockout_victim_init();
|
multicore_lockout_victim_init();
|
||||||
locked_out = true;
|
locked_out = true;
|
||||||
mutex_exit(&mtx_flash);
|
mutex_exit(&mtx_flash);
|
||||||
}
|
}
|
||||||
|
|
||||||
void wait_flash_finish() {
|
void low_flash_commit(void) {
|
||||||
sem_acquire_blocking(&sem_flash); //blocks until released
|
|
||||||
//wake up
|
|
||||||
sem_acquire_blocking(&sem_flash); //decrease permits
|
|
||||||
}
|
|
||||||
|
|
||||||
void low_flash_available() {
|
|
||||||
mutex_enter_blocking(&mtx_flash);
|
mutex_enter_blocking(&mtx_flash);
|
||||||
flash_available = true;
|
flash_available = true;
|
||||||
mutex_exit(&mtx_flash);
|
mutex_exit(&mtx_flash);
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
uintptr_t addr_alg = addr & -FLASH_SECTOR_SIZE;
|
||||||
page_flash_t *p = NULL;
|
page_flash_t *p = NULL;
|
||||||
for (int r = 0; r < TOTAL_FLASH_PAGES; r++) {
|
for (int r = 0; r < TOTAL_FLASH_PAGES; r++) {
|
||||||
@@ -260,24 +283,24 @@ int flash_program_block(uintptr_t addr, const uint8_t *data, size_t len) {
|
|||||||
page_flash_t *p = NULL;
|
page_flash_t *p = NULL;
|
||||||
|
|
||||||
if (!data || len == 0) {
|
if (!data || len == 0) {
|
||||||
return PICOKEY_ERR_NULL_PARAM;
|
return PICOKEYS_ERR_NULL_PARAM;
|
||||||
}
|
}
|
||||||
|
|
||||||
mutex_enter_blocking(&mtx_flash);
|
mutex_enter_blocking(&mtx_flash);
|
||||||
if (ready_pages == TOTAL_FLASH_PAGES) {
|
if (ready_pages == TOTAL_FLASH_PAGES) {
|
||||||
mutex_exit(&mtx_flash);
|
mutex_exit(&mtx_flash);
|
||||||
printf("ERROR: ALL FLASH PAGES CACHED\n");
|
printf("ERROR: ALL FLASH PAGES CACHED\n");
|
||||||
return PICOKEY_ERR_NO_MEMORY;
|
return PICOKEYS_ERR_NO_MEMORY;
|
||||||
}
|
}
|
||||||
if (!(p = find_free_page(addr))) {
|
if (!(p = find_free_page(addr))) {
|
||||||
mutex_exit(&mtx_flash);
|
mutex_exit(&mtx_flash);
|
||||||
printf("ERROR: FLASH CANNOT FIND A PAGE (rare error)\n");
|
printf("ERROR: FLASH CANNOT FIND A PAGE (rare error)\n");
|
||||||
return PICOKEY_ERR_MEMORY_FATAL;
|
return PICOKEYS_ERR_MEMORY_FATAL;
|
||||||
}
|
}
|
||||||
memcpy(&p->page[addr & (FLASH_SECTOR_SIZE - 1)], data, len);
|
memcpy(&p->page[addr & (FLASH_SECTOR_SIZE - 1)], data, len);
|
||||||
//printf("Flash: modified page %X with data %x at [%x]\n",(uintptr_t)addr,(uintptr_t)data,addr&(FLASH_SECTOR_SIZE-1));
|
//printf("Flash: modified page %X with data %x at [%x]\n",(uintptr_t)addr,(uintptr_t)data,addr&(FLASH_SECTOR_SIZE-1));
|
||||||
mutex_exit(&mtx_flash);
|
mutex_exit(&mtx_flash);
|
||||||
return PICOKEY_OK;
|
return PICOKEYS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int flash_program_halfword(uintptr_t addr, uint16_t data) {
|
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;
|
uint8_t *v = (uint8_t *) addr;
|
||||||
mutex_exit(&mtx_flash);
|
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)) {
|
if (addr >= start_data_pool && addr <= end_rom_pool + sizeof(uintptr_t)) {
|
||||||
v += (uintptr_t) map;
|
v += (uintptr_t) map;
|
||||||
}
|
}
|
||||||
@@ -317,7 +340,7 @@ uint8_t *flash_read(uintptr_t addr) {
|
|||||||
uintptr_t flash_read_uintptr(uintptr_t addr) {
|
uintptr_t flash_read_uintptr(uintptr_t addr) {
|
||||||
uint8_t *p = flash_read(addr);
|
uint8_t *p = flash_read(addr);
|
||||||
uintptr_t v = 0x0;
|
uintptr_t v = 0x0;
|
||||||
for (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);
|
v |= (uintptr_t) p[i] << (8 * i);
|
||||||
}
|
}
|
||||||
return v;
|
return v;
|
||||||
@@ -325,7 +348,7 @@ uintptr_t flash_read_uintptr(uintptr_t addr) {
|
|||||||
uint16_t flash_read_uint16(uintptr_t addr) {
|
uint16_t flash_read_uint16(uintptr_t addr) {
|
||||||
uint8_t *p = flash_read(addr);
|
uint8_t *p = flash_read(addr);
|
||||||
uint16_t v = 0x0;
|
uint16_t v = 0x0;
|
||||||
for (int i = 0; i < sizeof(uint16_t); i++) {
|
for (size_t i = 0; i < sizeof(uint16_t); i++) {
|
||||||
v |= p[i] << (8 * i);
|
v |= p[i] << (8 * i);
|
||||||
}
|
}
|
||||||
return v;
|
return v;
|
||||||
@@ -341,19 +364,19 @@ int flash_erase_page(uintptr_t addr, size_t page_size) {
|
|||||||
if (ready_pages == TOTAL_FLASH_PAGES) {
|
if (ready_pages == TOTAL_FLASH_PAGES) {
|
||||||
mutex_exit(&mtx_flash);
|
mutex_exit(&mtx_flash);
|
||||||
printf("ERROR: ALL FLASH PAGES CACHED\n");
|
printf("ERROR: ALL FLASH PAGES CACHED\n");
|
||||||
return PICOKEY_ERR_NO_MEMORY;
|
return PICOKEYS_ERR_NO_MEMORY;
|
||||||
}
|
}
|
||||||
if (!(p = find_free_page(addr))) {
|
if (!(p = find_free_page(addr))) {
|
||||||
printf("ERROR: FLASH CANNOT FIND A PAGE (rare error)\n");
|
printf("ERROR: FLASH CANNOT FIND A PAGE (rare error)\n");
|
||||||
mutex_exit(&mtx_flash);
|
mutex_exit(&mtx_flash);
|
||||||
return PICOKEY_ERR_MEMORY_FATAL;
|
return PICOKEYS_ERR_MEMORY_FATAL;
|
||||||
}
|
}
|
||||||
p->erase = true;
|
p->erase = true;
|
||||||
p->ready = false;
|
p->ready = false;
|
||||||
p->page_size = page_size;
|
p->page_size = page_size;
|
||||||
mutex_exit(&mtx_flash);
|
mutex_exit(&mtx_flash);
|
||||||
|
|
||||||
return PICOKEY_OK;
|
return PICOKEYS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool flash_check_blank(const uint8_t *p_start, size_t size) {
|
bool flash_check_blank(const uint8_t *p_start, size_t size) {
|
||||||
@@ -366,3 +389,42 @@ bool flash_check_blank(const uint8_t *p_start, size_t size) {
|
|||||||
}
|
}
|
||||||
return true;
|
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 <windows.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|||||||
@@ -1,8 +1,21 @@
|
|||||||
/*
|
/*
|
||||||
* sys/mman.h
|
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
|
||||||
* mman-win32
|
* 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_
|
#ifndef _SYS_MMAN_H_
|
||||||
#define _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.
|
* Copyright (c) 2022 Pol Henarejos.
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU 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.
|
* the Free Software Foundation, version 3.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful, but
|
* This program is distributed in the hope that it will be useful, but
|
||||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* 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
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "pico_keys.h"
|
#include "picokeys.h"
|
||||||
#include "file.h"
|
#include "otp.h"
|
||||||
|
|
||||||
#ifndef ENABLE_EMULATION
|
#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) {
|
int phy_serialize_data(const phy_data_t *phy, uint8_t *data, uint16_t *len) {
|
||||||
if (!phy || !data || !len) {
|
if (!phy || !data || !len) {
|
||||||
return PICOKEY_ERR_NULL_PARAM;
|
return PICOKEYS_ERR_NULL_PARAM;
|
||||||
}
|
}
|
||||||
uint8_t *p = data;
|
uint8_t *p = data;
|
||||||
if (phy->vidpid_present) {
|
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++ = PHY_OPTS;
|
||||||
*p++ = 2;
|
*p++ = 2;
|
||||||
p += put_uint16_t_be(phy->opts, p);
|
p += put_uint16_be(phy->opts, p);
|
||||||
if (phy->up_btn_present) {
|
if (phy->up_btn_present) {
|
||||||
*p++ = PHY_UP_BTN;
|
*p++ = PHY_UP_BTN;
|
||||||
*p++ = 1;
|
*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) {
|
if (phy->usb_product_present) {
|
||||||
*p++ = PHY_USB_PRODUCT;
|
*p++ = PHY_USB_PRODUCT;
|
||||||
*p++ = strlen(phy->usb_product) + 1;
|
*p++ = (uint8_t)strlen(phy->usb_product) + 1;
|
||||||
strcpy((char *)p, phy->usb_product);
|
strcpy((char *)p, phy->usb_product);
|
||||||
p += strlen(phy->usb_product);
|
p += strlen(phy->usb_product);
|
||||||
*p++ = '\0';
|
*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) {
|
if (phy->enabled_curves_present) {
|
||||||
*p++ = PHY_ENABLED_CURVES;
|
*p++ = PHY_ENABLED_CURVES;
|
||||||
*p++ = 4;
|
*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) {
|
if (phy->enabled_usb_itf_present) {
|
||||||
*p++ = PHY_ENABLED_USB_ITF;
|
*p++ = PHY_ENABLED_USB_ITF;
|
||||||
*p++ = 1;
|
*p++ = 1;
|
||||||
*p++ = phy->enabled_usb_itf;
|
*p++ = phy->enabled_usb_itf;
|
||||||
}
|
}
|
||||||
|
if (phy->led_driver_present) {
|
||||||
|
*p++ = PHY_LED_DRIVER;
|
||||||
|
*p++ = 1;
|
||||||
|
*p++ = phy->led_driver;
|
||||||
|
}
|
||||||
|
|
||||||
*len = p - data;
|
*len = (uint8_t)(p - data);
|
||||||
return PICOKEY_OK;
|
return PICOKEYS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int phy_unserialize_data(const uint8_t *data, uint16_t len, phy_data_t *phy) {
|
int phy_unserialize_data(const uint8_t *data, uint16_t len, phy_data_t *phy) {
|
||||||
if (!phy || !data || !len) {
|
if (!phy || !data || !len) {
|
||||||
return PICOKEY_ERR_NULL_PARAM;
|
return PICOKEYS_ERR_NULL_PARAM;
|
||||||
}
|
}
|
||||||
const uint8_t *p = data;
|
const uint8_t *p = data;
|
||||||
uint8_t tag, tlen;
|
uint8_t tag, tlen;
|
||||||
@@ -109,7 +114,7 @@ int phy_unserialize_data(const uint8_t *data, uint16_t len, phy_data_t *phy) {
|
|||||||
break;
|
break;
|
||||||
case PHY_OPTS:
|
case PHY_OPTS:
|
||||||
if (tlen == 2) {
|
if (tlen == 2) {
|
||||||
phy->opts = get_uint16_t_be(p);
|
phy->opts = get_uint16_be(p);
|
||||||
p += 2;
|
p += 2;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -129,7 +134,7 @@ int phy_unserialize_data(const uint8_t *data, uint16_t len, phy_data_t *phy) {
|
|||||||
break;
|
break;
|
||||||
case PHY_ENABLED_CURVES:
|
case PHY_ENABLED_CURVES:
|
||||||
if (tlen == 4) {
|
if (tlen == 4) {
|
||||||
phy->enabled_curves = get_uint32_t_be(p);
|
phy->enabled_curves = get_uint32_be(p);
|
||||||
p += 4;
|
p += 4;
|
||||||
phy->enabled_curves_present = true;
|
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;
|
phy->enabled_usb_itf_present = true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case PHY_LED_DRIVER:
|
||||||
|
if (tlen == 1) {
|
||||||
|
phy->led_driver = *p++;
|
||||||
|
phy->led_driver_present = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
p += tlen;
|
p += tlen;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!phy_data.enabled_usb_itf_present) {
|
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;
|
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));
|
memset(&phy_data, 0, sizeof(phy_data_t));
|
||||||
return phy_load();
|
return phy_load();
|
||||||
}
|
}
|
||||||
|
|
||||||
int phy_save() {
|
int phy_save(void) {
|
||||||
uint8_t tmp[PHY_MAX_SIZE] = {0};
|
uint8_t tmp[PHY_MAX_SIZE] = {0};
|
||||||
uint16_t tmp_len = 0;
|
uint16_t tmp_len = 0;
|
||||||
int ret = phy_serialize_data(&phy_data, tmp, &tmp_len);
|
int ret = phy_serialize_data(&phy_data, tmp, &tmp_len);
|
||||||
if (ret != PICOKEY_OK) {
|
if (ret != PICOKEYS_OK) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
file_put_data(ef_phy, tmp, tmp_len);
|
file_put_data(ef_phy, tmp, tmp_len);
|
||||||
low_flash_available();
|
flash_commit();
|
||||||
return PICOKEY_OK;
|
return PICOKEYS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int phy_load() {
|
int phy_load(void) {
|
||||||
if (file_has_data(ef_phy)) {
|
if (file_has_data(ef_phy)) {
|
||||||
return phy_unserialize_data(file_get_data(ef_phy), file_get_size(ef_phy), &phy_data);
|
return phy_unserialize_data(file_get_data(ef_phy), file_get_size(ef_phy), &phy_data);
|
||||||
}
|
}
|
||||||
return PICOKEY_OK;
|
return PICOKEYS_OK;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
36
src/fs/phy.h
36
src/fs/phy.h
@@ -3,16 +3,16 @@
|
|||||||
* Copyright (c) 2022 Pol Henarejos.
|
* Copyright (c) 2022 Pol Henarejos.
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU 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.
|
* the Free Software Foundation, version 3.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful, but
|
* This program is distributed in the hope that it will be useful, but
|
||||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* 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
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _PHY_H_
|
#ifndef _PHY_H_
|
||||||
@@ -28,6 +28,7 @@
|
|||||||
#define PHY_USB_PRODUCT 0x9
|
#define PHY_USB_PRODUCT 0x9
|
||||||
#define PHY_ENABLED_CURVES 0xA
|
#define PHY_ENABLED_CURVES 0xA
|
||||||
#define PHY_ENABLED_USB_ITF 0xB
|
#define PHY_ENABLED_USB_ITF 0xB
|
||||||
|
#define PHY_LED_DRIVER 0xC
|
||||||
|
|
||||||
#define PHY_OPT_WCID 0x1
|
#define PHY_OPT_WCID 0x1
|
||||||
#define PHY_OPT_DIMM 0x2
|
#define PHY_OPT_DIMM 0x2
|
||||||
@@ -50,10 +51,25 @@
|
|||||||
#define PHY_USB_ITF_WCID 0x2
|
#define PHY_USB_ITF_WCID 0x2
|
||||||
#define PHY_USB_ITF_HID 0x4
|
#define PHY_USB_ITF_HID 0x4
|
||||||
#define PHY_USB_ITF_KB 0x8
|
#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 <stdint.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
PACK(
|
||||||
typedef struct phy_data {
|
typedef struct phy_data {
|
||||||
union {
|
union {
|
||||||
struct {
|
struct {
|
||||||
@@ -73,6 +89,7 @@ typedef struct phy_data {
|
|||||||
uint8_t led_brightness;
|
uint8_t led_brightness;
|
||||||
uint8_t up_btn;
|
uint8_t up_btn;
|
||||||
uint8_t enabled_usb_itf;
|
uint8_t enabled_usb_itf;
|
||||||
|
uint8_t led_driver;
|
||||||
|
|
||||||
bool vidpid_present;
|
bool vidpid_present;
|
||||||
bool led_gpio_present;
|
bool led_gpio_present;
|
||||||
@@ -81,17 +98,18 @@ typedef struct phy_data {
|
|||||||
bool usb_product_present;
|
bool usb_product_present;
|
||||||
bool enabled_curves_present;
|
bool enabled_curves_present;
|
||||||
bool enabled_usb_itf_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
|
#ifndef ENABLE_EMULATION
|
||||||
extern int phy_serialize_data(const phy_data_t *phy, uint8_t *data, uint16_t *len);
|
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_unserialize_data(const uint8_t *data, uint16_t len, phy_data_t *phy);
|
||||||
extern int phy_init();
|
extern int phy_init(void);
|
||||||
extern int phy_save();
|
extern int phy_save(void);
|
||||||
extern int phy_load();
|
extern int phy_load(void);
|
||||||
extern phy_data_t phy_data;
|
extern phy_data_t phy_data;
|
||||||
#endif
|
#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).
|
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
|
||||||
* Copyright (c) 2022 Pol Henarejos.
|
* Copyright (c) 2022 Pol Henarejos.
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU 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.
|
* the Free Software Foundation, version 3.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful, but
|
* This program is distributed in the hope that it will be useful, but
|
||||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* 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
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdio.h>
|
#include "picokeys.h"
|
||||||
#include <stdlib.h>
|
#include "led/led.h"
|
||||||
#include "pico_keys.h"
|
#include "pico_time.h"
|
||||||
#ifdef PICO_PLATFORM
|
#if defined(ESP_PLATFORM)
|
||||||
#include "bsp/board.h"
|
#include "driver/gpio.h"
|
||||||
#elif defined(ESP_PLATFORM)
|
|
||||||
#include "esp_compat.h"
|
|
||||||
#elif defined(ENABLE_EMULATION)
|
#elif defined(ENABLE_EMULATION)
|
||||||
#include "emulation.h"
|
#include "emulation.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
extern void led_driver_init();
|
led_driver_t *led_driver = NULL;
|
||||||
extern void led_driver_color(uint8_t, uint32_t, float);
|
|
||||||
|
|
||||||
static uint32_t led_mode = MODE_NOT_MOUNTED;
|
static uint32_t led_mode = MODE_NOT_MOUNTED;
|
||||||
|
|
||||||
@@ -35,12 +32,12 @@ void led_set_mode(uint32_t mode) {
|
|||||||
led_mode = mode;
|
led_mode = mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t led_get_mode() {
|
uint32_t led_get_mode(void) {
|
||||||
return led_mode;
|
return led_mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
void led_blinking_task() {
|
void led_blinking_task(void) {
|
||||||
#ifndef ENABLE_EMULATION
|
#if defined(PICO_PLATFORM) || defined(ESP_PLATFORM)
|
||||||
static uint32_t start_ms = 0;
|
static uint32_t start_ms = 0;
|
||||||
static uint32_t stop_ms = 0;
|
static uint32_t stop_ms = 0;
|
||||||
static uint32_t last_led_update_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
|
// limit the frequency of LED status updates
|
||||||
if (board_millis() - last_led_update_ms > 2) {
|
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();
|
last_led_update_ms = board_millis();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -81,15 +78,97 @@ void led_blinking_task() {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void led_off_all() {
|
void led_off_all(void) {
|
||||||
#ifndef ENABLE_EMULATION
|
#if defined(PICO_PLATFORM) || defined(ESP_PLATFORM)
|
||||||
led_driver_color(LED_COLOR_OFF, 0, 0);
|
led_driver->set_color(LED_COLOR_OFF, 0, 0);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void led_init() {
|
extern led_driver_t led_driver_pico;
|
||||||
#ifndef ENABLE_EMULATION
|
extern led_driver_t led_driver_cyw43;
|
||||||
led_driver_init();
|
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);
|
led_set_mode(MODE_NOT_MOUNTED);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,16 +3,16 @@
|
|||||||
* Copyright (c) 2022 Pol Henarejos.
|
* Copyright (c) 2022 Pol Henarejos.
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU 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.
|
* the Free Software Foundation, version 3.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful, but
|
* This program is distributed in the hope that it will be useful, but
|
||||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* 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
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _LED_H_
|
#ifndef _LED_H_
|
||||||
@@ -62,9 +62,16 @@ enum {
|
|||||||
};
|
};
|
||||||
|
|
||||||
extern void led_set_mode(uint32_t mode);
|
extern void led_set_mode(uint32_t mode);
|
||||||
extern uint32_t led_get_mode();
|
extern uint32_t led_get_mode(void);
|
||||||
extern void led_blinking_task();
|
extern void led_blinking_task(void);
|
||||||
extern void led_off_all();
|
extern void led_off_all(void);
|
||||||
extern void led_init();
|
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_
|
#endif // _LED_H_
|
||||||
|
|||||||
@@ -3,30 +3,38 @@
|
|||||||
* Copyright (c) 2022 Pol Henarejos.
|
* Copyright (c) 2022 Pol Henarejos.
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU 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.
|
* the Free Software Foundation, version 3.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful, but
|
* This program is distributed in the hope that it will be useful, but
|
||||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* 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
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* 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
|
#ifdef CYW43_WL_GPIO_LED_PIN
|
||||||
|
|
||||||
#include "pico/cyw43_arch.h"
|
#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();
|
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)led_brightness;
|
||||||
|
(void)color;
|
||||||
uint8_t gpio = CYW43_WL_GPIO_LED_PIN;
|
uint8_t gpio = CYW43_WL_GPIO_LED_PIN;
|
||||||
if (phy_data.led_gpio_present) {
|
if (phy_data.led_gpio_present) {
|
||||||
gpio = phy_data.led_gpio;
|
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);
|
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
|
#endif
|
||||||
|
|||||||
@@ -3,19 +3,23 @@
|
|||||||
* Copyright (c) 2022 Pol Henarejos.
|
* Copyright (c) 2022 Pol Henarejos.
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU 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.
|
* the Free Software Foundation, version 3.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful, but
|
* This program is distributed in the hope that it will be useful, but
|
||||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* 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
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* 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
|
#ifdef ESP_PLATFORM
|
||||||
|
|
||||||
@@ -45,7 +49,7 @@ tNeopixel pixel[] = {
|
|||||||
#define NEOPIXEL_PIN GPIO_NUM_27
|
#define NEOPIXEL_PIN GPIO_NUM_27
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void led_driver_init() {
|
void led_driver_init_neopixel(void) {
|
||||||
uint8_t gpio = NEOPIXEL_PIN;
|
uint8_t gpio = NEOPIXEL_PIN;
|
||||||
if (phy_data.led_gpio_present) {
|
if (phy_data.led_gpio_present) {
|
||||||
gpio = phy_data.led_gpio;
|
gpio = phy_data.led_gpio;
|
||||||
@@ -53,7 +57,7 @@ void led_driver_init() {
|
|||||||
neopixel = neopixel_Init(1, gpio);
|
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};
|
static tNeopixel spx = {.index = 0, .rgb = 0};
|
||||||
if (!(phy_data.opts & PHY_OPT_DIMM)) {
|
if (!(phy_data.opts & PHY_OPT_DIMM)) {
|
||||||
progress = progress >= 0.5 ? 1 : 0;
|
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);
|
neopixel_SetPixel(neopixel, &spx, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
led_driver_t led_driver_neopixel = {
|
||||||
|
.init = led_driver_init_neopixel,
|
||||||
|
.set_color = led_driver_color_neopixel,
|
||||||
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -3,25 +3,40 @@
|
|||||||
* Copyright (c) 2022 Pol Henarejos.
|
* Copyright (c) 2022 Pol Henarejos.
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU 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.
|
* the Free Software Foundation, version 3.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful, but
|
* This program is distributed in the hope that it will be useful, but
|
||||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* 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
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* 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) {
|
if (phy_data.led_gpio_present) {
|
||||||
gpio = phy_data.led_gpio;
|
gpio = phy_data.led_gpio;
|
||||||
}
|
}
|
||||||
@@ -29,9 +44,15 @@ void led_driver_init() {
|
|||||||
gpio_set_dir(gpio, GPIO_OUT);
|
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;
|
(void)led_brightness;
|
||||||
gpio_put(gpio, progress >= 0.5);
|
gpio_put(gpio, progress >= 0.5);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
led_driver_t led_driver_pico = {
|
||||||
|
.init = led_driver_init_pico,
|
||||||
|
.set_color = led_driver_color_pico,
|
||||||
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -3,30 +3,27 @@
|
|||||||
* Copyright (c) 2022 Pol Henarejos.
|
* Copyright (c) 2022 Pol Henarejos.
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU 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.
|
* the Free Software Foundation, version 3.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful, but
|
* This program is distributed in the hope that it will be useful, but
|
||||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* 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
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* 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 PICO_PLATFORM
|
||||||
|
#include "hardware/gpio.h"
|
||||||
#ifdef PIMORONI_TINY2040
|
#ifdef PICO_DEFAULT_LED_PIN
|
||||||
#define LED_R_PIN TINY2040_LED_R_PIN
|
static uint8_t gpio = PICO_DEFAULT_LED_PIN;
|
||||||
#define LED_G_PIN TINY2040_LED_G_PIN
|
#else
|
||||||
#define LED_B_PIN TINY2040_LED_B_PIN
|
static uint8_t gpio = 0;
|
||||||
#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
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
uint8_t pixel[][3] = {
|
uint8_t pixel[][3] = {
|
||||||
@@ -40,22 +37,31 @@ uint8_t pixel[][3] = {
|
|||||||
{0, 0, 0} // 7: white
|
{0, 0, 0} // 7: white
|
||||||
};
|
};
|
||||||
|
|
||||||
void led_driver_init() {
|
static void led_driver_init_pimoroni(void) {
|
||||||
gpio_init(LED_R_PIN);
|
if (phy_data.led_gpio_present) {
|
||||||
gpio_set_dir(LED_R_PIN, GPIO_OUT);
|
gpio = phy_data.led_gpio;
|
||||||
gpio_init(LED_G_PIN);
|
}
|
||||||
gpio_set_dir(LED_G_PIN, GPIO_OUT);
|
gpio_init(gpio-1);
|
||||||
gpio_init(LED_B_PIN);
|
gpio_set_dir(gpio-1, GPIO_OUT);
|
||||||
gpio_set_dir(LED_B_PIN, 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) {
|
if (progress < 0.5) {
|
||||||
color = LED_COLOR_OFF;
|
color = LED_COLOR_OFF;
|
||||||
}
|
}
|
||||||
gpio_put(LED_R_PIN, pixel[color][0]);
|
gpio_put(gpio-1, pixel[color][0]);
|
||||||
gpio_put(LED_G_PIN, pixel[color][1]);
|
gpio_put(gpio, pixel[color][1]);
|
||||||
gpio_put(LED_B_PIN, pixel[color][2]);
|
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
|
#endif
|
||||||
|
|||||||
@@ -3,22 +3,22 @@
|
|||||||
* Copyright (c) 2022 Pol Henarejos.
|
* Copyright (c) 2022 Pol Henarejos.
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU 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.
|
* the Free Software Foundation, version 3.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful, but
|
* This program is distributed in the hope that it will be useful, but
|
||||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* 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
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* 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_DEFAULT_WS2812_PIN
|
|
||||||
|
|
||||||
|
#ifdef PICO_PLATFORM
|
||||||
#include "hardware/pio.h"
|
#include "hardware/pio.h"
|
||||||
#include "hardware/clocks.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);
|
pio_sm_set_enabled(pio, sm, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void led_driver_init() {
|
static void led_driver_init_ws2812(void) {
|
||||||
PIO pio = pio0;
|
PIO pio = pio0;
|
||||||
int sm = 0;
|
int sm = 0;
|
||||||
uint offset = pio_add_program(pio, &ws2812_program);
|
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) {
|
if (phy_data.led_gpio_present) {
|
||||||
gpio = phy_data.led_gpio;
|
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);
|
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)) {
|
if (!(phy_data.opts & PHY_OPT_DIMM)) {
|
||||||
progress = progress >= 0.5 ? 1 : 0;
|
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));
|
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
|
#endif
|
||||||
|
|||||||
289
src/main.c
289
src/main.c
@@ -3,51 +3,47 @@
|
|||||||
* Copyright (c) 2022 Pol Henarejos.
|
* Copyright (c) 2022 Pol Henarejos.
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU 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.
|
* the Free Software Foundation, version 3.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful, but
|
* This program is distributed in the hope that it will be useful, but
|
||||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* 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
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdio.h>
|
#include "picokeys.h"
|
||||||
#include <stdlib.h>
|
#include "button.h"
|
||||||
|
#if !defined(ENABLE_EMULATION)
|
||||||
// Pico
|
#include "tusb.h"
|
||||||
|
#endif
|
||||||
#if defined(ENABLE_EMULATION)
|
#if defined(ENABLE_EMULATION)
|
||||||
#include "emulation.h"
|
#include "emulation.h"
|
||||||
#elif defined(ESP_PLATFORM)
|
#elif defined(ESP_PLATFORM)
|
||||||
#include "tusb.h"
|
|
||||||
#include "driver/gpio.h"
|
#include "driver/gpio.h"
|
||||||
#include "rom/gpio.h"
|
#include "rom/gpio.h"
|
||||||
#include "tinyusb.h"
|
#include "tinyusb.h"
|
||||||
#include "esp_efuse.h"
|
#elif defined(PICO_PLATFORM)
|
||||||
#define BOOT_PIN GPIO_NUM_0
|
|
||||||
#else
|
|
||||||
#include "pico/stdlib.h"
|
|
||||||
#include "bsp/board.h"
|
#include "bsp/board.h"
|
||||||
#include "pico/aon_timer.h"
|
|
||||||
#include "hardware/gpio.h"
|
|
||||||
#include "hardware/sync.h"
|
|
||||||
#include "hardware/structs/ioqspi.h"
|
#include "hardware/structs/ioqspi.h"
|
||||||
#include "hardware/structs/sio.h"
|
#include "pico/stdio.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "random.h"
|
#include "random.h"
|
||||||
#include "pico_keys.h"
|
#include "hwrng.h"
|
||||||
#include "apdu.h"
|
#include "apdu.h"
|
||||||
#include "usb.h"
|
#include "usb.h"
|
||||||
extern void do_flash();
|
#include "flash.h"
|
||||||
extern void low_flash_init();
|
#include "otp.h"
|
||||||
extern void init_otp_files();
|
#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;
|
uint8_t num_apps = 0;
|
||||||
|
|
||||||
app_t *current_app = NULL;
|
app_t *current_app = NULL;
|
||||||
@@ -55,11 +51,8 @@ app_t *current_app = NULL;
|
|||||||
const uint8_t *ccid_atr = NULL;
|
const uint8_t *ccid_atr = NULL;
|
||||||
|
|
||||||
bool app_exists(const uint8_t *aid, size_t aid_len) {
|
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++) {
|
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;
|
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) {
|
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);
|
current_app->select_aid(current_app, 0);
|
||||||
return PICOKEY_OK;
|
return PICOKEYS_OK;
|
||||||
}
|
}
|
||||||
for (int a = 0; a < num_apps; a++) {
|
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) {
|
||||||
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);
|
current_app->select_aid(current_app, 1);
|
||||||
return PICOKEY_OK;
|
return PICOKEYS_OK;
|
||||||
}
|
}
|
||||||
if (current_app->unload) {
|
if (current_app->unload) {
|
||||||
current_app->unload();
|
current_app->unload();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
current_app = &apps[a];
|
current_app = &apps[a];
|
||||||
if (current_app->select_aid(current_app, 1) == PICOKEY_OK) {
|
if (current_app->select_aid(current_app, 1) == PICOKEYS_OK) {
|
||||||
return PICOKEY_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();
|
WEAK int picokey_init(void) {
|
||||||
|
|
||||||
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);
|
|
||||||
return 0;
|
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
|
void execute_tasks(void);
|
||||||
// are about to temporarily disable flash access!
|
void execute_tasks(void) {
|
||||||
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()
|
|
||||||
{
|
|
||||||
#if !defined(ENABLE_EMULATION) && !defined(ESP_PLATFORM)
|
#if !defined(ENABLE_EMULATION) && !defined(ESP_PLATFORM)
|
||||||
tud_task(); // tinyusb device task
|
tud_task(); // tinyusb device task
|
||||||
|
#endif
|
||||||
|
#ifdef USB_ITF_LWIP
|
||||||
|
#if !defined(ENABLE_EMULATION)
|
||||||
|
service_traffic();
|
||||||
|
#endif
|
||||||
|
rest_task();
|
||||||
#endif
|
#endif
|
||||||
usb_task();
|
usb_task();
|
||||||
led_blinking_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) {
|
while (1) {
|
||||||
execute_tasks();
|
execute_tasks();
|
||||||
neug_task();
|
hwrng_task();
|
||||||
do_flash();
|
flash_task();
|
||||||
#ifndef ENABLE_EMULATION
|
button_task();
|
||||||
if (button_pressed_cb && board_millis() > 1000 && !is_busy()) { // wait 1 second to boot up
|
|
||||||
bool current_button_state = picok_board_button_read();
|
|
||||||
if (current_button_state != button_pressed_state) {
|
|
||||||
if (current_button_state == false) { // unpressed
|
|
||||||
if (button_pressed_time == 0 || button_pressed_time + 1000 > board_millis()) {
|
|
||||||
button_press++;
|
|
||||||
}
|
|
||||||
button_pressed_time = board_millis();
|
|
||||||
}
|
|
||||||
button_pressed_state = current_button_state;
|
|
||||||
}
|
|
||||||
if (button_pressed_time > 0 && button_press > 0 && button_pressed_time + 1000 < board_millis() && button_pressed_state == false) {
|
|
||||||
if (button_pressed_cb != NULL) {
|
|
||||||
(*button_pressed_cb)(button_press);
|
|
||||||
}
|
|
||||||
button_pressed_time = button_press = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#ifdef ESP_PLATFORM
|
#ifdef ESP_PLATFORM
|
||||||
vTaskDelay(pdMS_TO_TICKS(10));
|
vTaskDelay(pdMS_TO_TICKS(10));
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
char pico_serial_str[2 * PICO_UNIQUE_BOARD_ID_SIZE_BYTES + 1];
|
|
||||||
pico_unique_board_id_t pico_serial;
|
|
||||||
#ifdef ESP_PLATFORM
|
#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 tinyusb_config_t tusb_cfg;
|
||||||
extern const uint8_t desc_config[];
|
extern const uint8_t desc_config[];
|
||||||
|
extern char *string_desc_arr[];
|
||||||
|
extern char *string_desc_itf[];
|
||||||
TaskHandle_t hcore0 = NULL, hcore1 = NULL;
|
TaskHandle_t hcore0 = NULL, hcore1 = NULL;
|
||||||
int app_main() {
|
int app_main(void) {
|
||||||
#else
|
#else
|
||||||
#ifdef ENABLE_EMULATION
|
|
||||||
#define pico_get_unique_board_id(a) memset(a, 0, sizeof(*(a)))
|
|
||||||
#endif
|
|
||||||
int main(void) {
|
int main(void) {
|
||||||
#endif
|
#endif
|
||||||
pico_get_unique_board_id(&pico_serial);
|
serial_init();
|
||||||
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]);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifndef ENABLE_EMULATION
|
#ifndef ENABLE_EMULATION
|
||||||
#ifndef ESP_PLATFORM
|
#ifdef PICO_PLATFORM
|
||||||
board_init();
|
board_init();
|
||||||
stdio_init_all();
|
stdio_init_all();
|
||||||
#endif
|
#endif
|
||||||
@@ -317,11 +159,11 @@ int main(void) {
|
|||||||
|
|
||||||
random_init();
|
random_init();
|
||||||
|
|
||||||
init_otp_files();
|
otp_init();
|
||||||
|
|
||||||
low_flash_init();
|
low_flash_init();
|
||||||
|
|
||||||
scan_flash();
|
file_scan_flash();
|
||||||
|
|
||||||
init_rtc();
|
init_rtc();
|
||||||
|
|
||||||
@@ -343,13 +185,16 @@ int main(void) {
|
|||||||
if (phy_data.usb_product_present) {
|
if (phy_data.usb_product_present) {
|
||||||
tusb_cfg.string_descriptor[2] = phy_data.usb_product;
|
tusb_cfg.string_descriptor[2] = phy_data.usb_product;
|
||||||
}
|
}
|
||||||
static char tmps[4][32];
|
static char tmps[5][32];
|
||||||
for (int i = 4; i < tusb_cfg.string_descriptor_count; i++) {
|
const int max_desc_slots = 8 - 6;
|
||||||
strlcpy(tmps[i-4], tusb_cfg.string_descriptor[2], sizeof(tmps[0]));
|
const int itf_desc_count = ITF_TOTAL < max_desc_slots ? ITF_TOTAL : max_desc_slots;
|
||||||
strlcat(tmps[i-4], " ", sizeof(tmps[0]));
|
for (int i = 0; i < itf_desc_count; i++) {
|
||||||
strlcat(tmps[i-4], tusb_cfg.string_descriptor[i], sizeof(tmps[0]));
|
strlcpy(tmps[i], tusb_cfg.string_descriptor[2], sizeof(tmps[0]));
|
||||||
tusb_cfg.string_descriptor[i] = tmps[i-4];
|
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;
|
tusb_cfg.configuration_descriptor = desc_config;
|
||||||
|
|
||||||
tinyusb_driver_install(&tusb_cfg);
|
tinyusb_driver_install(&tusb_cfg);
|
||||||
@@ -358,10 +203,14 @@ int main(void) {
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef ENABLE_EMULATION
|
||||||
|
picokey_init();
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef ESP_PLATFORM
|
#ifdef ESP_PLATFORM
|
||||||
xTaskCreatePinnedToCore(core0_loop, "core0", 4096*ITF_TOTAL*2, NULL, CONFIG_TINYUSB_TASK_PRIORITY - 1, &hcore0, ESP32_CORE0);
|
xTaskCreatePinnedToCore(core0_loop, "core0", 4096*ITF_TOTAL*2, NULL, CONFIG_TINYUSB_TASK_PRIORITY - 1, &hcore0, ESP32_CORE0);
|
||||||
#else
|
#else
|
||||||
core0_loop();
|
core0_loop(NULL);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return 0;
|
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.
|
* Copyright (c) 2022 Pol Henarejos.
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU 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.
|
* the Free Software Foundation, version 3.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful, but
|
* This program is distributed in the hope that it will be useful, but
|
||||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* 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
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __VERSION_H_
|
#ifndef __VERSION_H_
|
||||||
#define __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 PICOKEYS_SDK_VERSION_MAJOR ((PICOKEYS_SDK_VERSION >> 8) & 0xff)
|
||||||
#define PICO_KEYS_SDK_VERSION_MINOR (PICO_KEYS_SDK_VERSION & 0xff)
|
#define PICOKEYS_SDK_VERSION_MINOR (PICOKEYS_SDK_VERSION & 0xff)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
364
src/rescue.c
364
src/rescue.c
@@ -3,25 +3,43 @@
|
|||||||
* Copyright (c) 2022 Pol Henarejos.
|
* Copyright (c) 2022 Pol Henarejos.
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU 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.
|
* the Free Software Foundation, version 3.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful, but
|
* This program is distributed in the hope that it will be useful, but
|
||||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* 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
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* 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 "apdu.h"
|
||||||
#include "pico_keys_version.h"
|
#include "picokeys_version.h"
|
||||||
#include "otp.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[] = {
|
const uint8_t rescue_aid[] = {
|
||||||
8,
|
8,
|
||||||
@@ -29,60 +47,316 @@ const uint8_t rescue_aid[] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
#ifdef PICO_RP2350
|
#ifdef PICO_RP2350
|
||||||
#define PICO_MCU 1
|
const uint8_t PICO_MCU = 1;
|
||||||
#elif defined(ESP_PLATFORM)
|
#elif defined(CONFIG_IDF_TARGET_ESP32S3)
|
||||||
#define PICO_MCU 2
|
const uint8_t PICO_MCU = 2;
|
||||||
#elif defined(ENABLE_EMULATION)
|
#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
|
#else
|
||||||
#define PICO_MCU 0
|
const uint8_t PICO_MCU = 0;
|
||||||
#endif
|
#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->process_apdu = rescue_process_apdu;
|
||||||
a->unload = rescue_unload;
|
a->unload = rescue_unload;
|
||||||
res_APDU_size = 0;
|
res_APDU_size = 0;
|
||||||
res_APDU[res_APDU_size++] = PICO_MCU;
|
res_APDU[res_APDU_size++] = PICO_MCU;
|
||||||
res_APDU[res_APDU_size++] = PICO_PRODUCT;
|
res_APDU[res_APDU_size++] = PICO_PRODUCT;
|
||||||
res_APDU[res_APDU_size++] = PICO_KEYS_SDK_VERSION_MAJOR;
|
res_APDU[res_APDU_size++] = PICO_VERSION_MAJOR;
|
||||||
res_APDU[res_APDU_size++] = PICO_KEYS_SDK_VERSION_MINOR;
|
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;
|
apdu.ne = res_APDU_size;
|
||||||
if (force) {
|
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 ) {
|
INITIALIZER ( rescue_ctor ) {
|
||||||
register_app(rescue_select, rescue_aid);
|
register_app(rescue_select, rescue_aid);
|
||||||
}
|
}
|
||||||
|
|
||||||
int rescue_unload() {
|
static int rescue_unload(void) {
|
||||||
return PICOKEY_OK;
|
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) {
|
if (apdu.nc < 2) {
|
||||||
return SW_WRONG_LENGTH();
|
return SW_WRONG_LENGTH();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (P1(apdu) == 0x1) { // PHY
|
uint8_t p1 = P1(apdu), p2 = P2(apdu);
|
||||||
|
|
||||||
|
if (p1 == 0x1) { // PHY
|
||||||
#ifndef ENABLE_EMULATION
|
#ifndef ENABLE_EMULATION
|
||||||
int ret = phy_unserialize_data(apdu.data, apdu.nc, &phy_data);
|
int ret = phy_unserialize_data(apdu.data, (uint16_t)apdu.nc, &phy_data);
|
||||||
if (ret == PICOKEY_OK) {
|
if (ret == PICOKEYS_OK) {
|
||||||
if (phy_save() != PICOKEY_OK) {
|
if (phy_save() != PICOKEYS_OK) {
|
||||||
return SW_EXEC_ERROR();
|
return SW_EXEC_ERROR();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#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();
|
return SW_OK();
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(PICO_RP2350) || defined(ESP_PLATFORM)
|
#if defined(PICO_RP2350) || defined(ESP_PLATFORM)
|
||||||
int cmd_secure() {
|
static int cmd_secure(void) {
|
||||||
if (apdu.nc != 0) {
|
if (apdu.nc != 0) {
|
||||||
return SW_WRONG_LENGTH();
|
return SW_WRONG_LENGTH();
|
||||||
}
|
}
|
||||||
@@ -91,25 +365,57 @@ int cmd_secure() {
|
|||||||
bool secure_lock = P2(apdu) == 0x1;
|
bool secure_lock = P2(apdu) == 0x1;
|
||||||
|
|
||||||
int ret = otp_enable_secure_boot(bootkey, secure_lock);
|
int ret = otp_enable_secure_boot(bootkey, secure_lock);
|
||||||
if (ret != 0) {
|
if (ret != PICOKEYS_OK) {
|
||||||
return SW_EXEC_ERROR();
|
return SW_EXEC_ERROR();
|
||||||
}
|
}
|
||||||
|
led_3_blinks();
|
||||||
return SW_OK();
|
return SW_OK();
|
||||||
}
|
}
|
||||||
#endif
|
#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_WRITE 0x1C
|
||||||
#define INS_SECURE 0x1D
|
#define INS_SECURE 0x1D
|
||||||
|
#define INS_READ 0x1E
|
||||||
|
#define INS_REBOOT_BOOTSEL 0x1F
|
||||||
|
|
||||||
static const cmd_t cmds[] = {
|
static const cmd_t cmds[] = {
|
||||||
|
{ INS_KEYDEV_SIGN, cmd_keydev_sign },
|
||||||
{ INS_WRITE, cmd_write },
|
{ INS_WRITE, cmd_write },
|
||||||
#if defined(PICO_RP2350) || defined(ESP_PLATFORM)
|
#if defined(PICO_RP2350) || defined(ESP_PLATFORM)
|
||||||
{ INS_SECURE, cmd_secure },
|
{ INS_SECURE, cmd_secure },
|
||||||
|
#endif
|
||||||
|
{ INS_READ, cmd_read },
|
||||||
|
#ifdef PICO_PLATFORM
|
||||||
|
{ INS_REBOOT_BOOTSEL, cmd_reboot_bootsel },
|
||||||
#endif
|
#endif
|
||||||
{ 0x00, 0x0 }
|
{ 0x00, 0x0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
int rescue_process_apdu() {
|
static int rescue_process_apdu(void) {
|
||||||
if (CLA(apdu) != 0x80) {
|
if (CLA(apdu) != 0x80) {
|
||||||
return SW_CLA_NOT_SUPPORTED();
|
return SW_CLA_NOT_SUPPORTED();
|
||||||
}
|
}
|
||||||
|
|||||||
192
src/rng/hwrng.c
192
src/rng/hwrng.c
@@ -3,87 +3,100 @@
|
|||||||
* Copyright (c) 2022 Pol Henarejos.
|
* Copyright (c) 2022 Pol Henarejos.
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU 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.
|
* the Free Software Foundation, version 3.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful, but
|
* This program is distributed in the hope that it will be useful, but
|
||||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* 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
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdint.h>
|
#include "picokeys.h"
|
||||||
#include <string.h>
|
#include "hwrng.h"
|
||||||
#include <stdio.h>
|
#include "pico_time.h"
|
||||||
#if defined(ENABLE_EMULATION)
|
|
||||||
#include <stdbool.h>
|
#if defined(PICO_PLATFORM)
|
||||||
#include <stdlib.h>
|
#include "pico/rand.h"
|
||||||
#include <time.h>
|
#include "pico/mutex.h"
|
||||||
#include "emulation.h"
|
#elif defined(ESP_PLATFORM)
|
||||||
#elif (ESP_PLATFORM)
|
|
||||||
#include "bootloader_random.h"
|
#include "bootloader_random.h"
|
||||||
#include "esp_random.h"
|
#include "esp_random.h"
|
||||||
#include "esp_compat.h"
|
#include "compat/esp_compat.h"
|
||||||
#else
|
#else
|
||||||
#include "pico/stdlib.h"
|
#include "compat/queue.h"
|
||||||
#include "hwrng.h"
|
|
||||||
#include "bsp/board.h"
|
|
||||||
#include "pico/rand.h"
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void hwrng_start() {
|
static void hwrng_start(void) {
|
||||||
#if defined(ENABLE_EMULATION)
|
#if defined(ENABLE_EMULATION)
|
||||||
srand(time(0));
|
srand((unsigned int)time(NULL));
|
||||||
#elif defined(ESP_PLATFORM)
|
#elif defined(ESP_PLATFORM)
|
||||||
bootloader_random_enable();
|
bootloader_random_enable();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint64_t random_word = 0xcbf29ce484222325;
|
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;
|
random_word = 0xcbf29ce484222325;
|
||||||
ep_round = 0;
|
hwrng_mix_round = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Here, we assume a little endian architecture. */
|
/* Here, we assume a little endian architecture. */
|
||||||
static int ep_process() {
|
static int hwrng_mix_process(void) {
|
||||||
if (ep_round == 0) {
|
if (hwrng_mix_round == 0) {
|
||||||
ep_init();
|
hwrng_mix_init();
|
||||||
}
|
}
|
||||||
uint64_t word = 0x0;
|
uint64_t word = 0x0;
|
||||||
|
|
||||||
#if defined(ENABLE_EMULATION)
|
#if defined(PICO_PLATFORM)
|
||||||
word = rand();
|
word = get_rand_64();
|
||||||
word <<= 32;
|
|
||||||
word |= rand();
|
|
||||||
#elif defined(ESP_PLATFORM)
|
#elif defined(ESP_PLATFORM)
|
||||||
esp_fill_random((uint8_t *)&word, sizeof(word));
|
esp_fill_random((uint8_t *)&word, sizeof(word));
|
||||||
#else
|
#else
|
||||||
word = get_rand_64();
|
word = rand();
|
||||||
|
word <<= 32;
|
||||||
|
word |= rand();
|
||||||
#endif
|
#endif
|
||||||
random_word ^= word ^ board_millis();
|
random_word ^= word ^ board_millis();
|
||||||
random_word *= 0x00000100000001B3;
|
random_word *= 0x00000100000001B3;
|
||||||
if (++ep_round == 8) {
|
if (++hwrng_mix_round == 8) {
|
||||||
ep_round = 0;
|
hwrng_mix_round = 0;
|
||||||
return 2; //2 words
|
return sizeof(uint64_t) / sizeof(uint32_t); //2 words
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct rng_rb {
|
PACK(
|
||||||
|
typedef struct hwrng_buf {
|
||||||
uint32_t *buf;
|
uint32_t *buf;
|
||||||
uint8_t head, tail;
|
uint8_t head;
|
||||||
|
uint8_t tail;
|
||||||
uint8_t size;
|
uint8_t size;
|
||||||
unsigned int full : 1;
|
unsigned int full : 1;
|
||||||
unsigned int empty : 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->buf = p;
|
||||||
rb->size = size;
|
rb->size = size;
|
||||||
rb->head = rb->tail = 0;
|
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;
|
rb->empty = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rb_add(struct rng_rb *rb, uint32_t v) {
|
static void hwrng_buf_add(struct hwrng_buf *rb, uint32_t v) {
|
||||||
rb->buf[rb->tail++] = v;
|
if (rb->full) {
|
||||||
if (rb->tail == rb->size) {
|
return;
|
||||||
rb->tail = 0;
|
|
||||||
}
|
}
|
||||||
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;
|
rb->empty = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t rb_del(struct rng_rb *rb) {
|
static uint32_t hwrng_buf_del(struct hwrng_buf *rb) {
|
||||||
uint32_t v = rb->buf[rb->head++];
|
uint32_t v = 0;
|
||||||
|
if (rb->empty) {
|
||||||
if (rb->head == rb->size) {
|
return v;
|
||||||
rb->head = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint8_t head = rb->head;
|
||||||
|
v = rb->buf[head];
|
||||||
|
head++;
|
||||||
|
if (head >= rb->size) {
|
||||||
|
head = 0;
|
||||||
|
}
|
||||||
|
rb->head = head;
|
||||||
if (rb->head == rb->tail) {
|
if (rb->head == rb->tail) {
|
||||||
rb->empty = 1;
|
rb->empty = 1;
|
||||||
}
|
}
|
||||||
@@ -116,73 +141,86 @@ static uint32_t rb_del(struct rng_rb *rb) {
|
|||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct rng_rb the_ring_buffer;
|
static struct hwrng_buf ring_buffer;
|
||||||
|
|
||||||
void *neug_task() {
|
void *hwrng_task(void) {
|
||||||
struct rng_rb *rb = &the_ring_buffer;
|
struct hwrng_buf *rb = &ring_buffer;
|
||||||
|
|
||||||
int n;
|
int n;
|
||||||
|
|
||||||
if ((n = ep_process())) {
|
hwrng_lock();
|
||||||
int i;
|
if ((n = hwrng_mix_process())) {
|
||||||
const uint32_t *vp = (const uint32_t *) &random_word;
|
const uint32_t *vp = (const uint32_t *) &random_word;
|
||||||
|
|
||||||
for (i = 0; i < n; i++) {
|
for (int i = 0; i < n; i++) {
|
||||||
rb_add(rb, *vp++);
|
hwrng_buf_add(rb, *vp++);
|
||||||
if (rb->full) {
|
if (rb->full) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
hwrng_unlock();
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void neug_init(uint32_t *buf, uint8_t size) {
|
void hwrng_init(uint32_t *buf, uint8_t size) {
|
||||||
struct rng_rb *rb = &the_ring_buffer;
|
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();
|
hwrng_start();
|
||||||
|
|
||||||
ep_init();
|
hwrng_mix_init();
|
||||||
}
|
}
|
||||||
|
|
||||||
void neug_flush(void) {
|
void hwrng_flush(void) {
|
||||||
struct rng_rb *rb = &the_ring_buffer;
|
struct hwrng_buf *rb = &ring_buffer;
|
||||||
|
hwrng_lock();
|
||||||
while (!rb->empty) {
|
while (!rb->empty) {
|
||||||
rb_del(rb);
|
hwrng_buf_del(rb);
|
||||||
}
|
}
|
||||||
|
hwrng_unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t neug_get() {
|
uint32_t hwrng_get(void) {
|
||||||
struct rng_rb *rb = &the_ring_buffer;
|
struct hwrng_buf *rb = &ring_buffer;
|
||||||
uint32_t v;
|
uint32_t v;
|
||||||
|
|
||||||
while (rb->empty) {
|
while (true) {
|
||||||
neug_task();
|
hwrng_lock();
|
||||||
|
if (!rb->empty) {
|
||||||
|
v = hwrng_buf_del(rb);
|
||||||
|
hwrng_unlock();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
hwrng_unlock();
|
||||||
|
hwrng_task();
|
||||||
}
|
}
|
||||||
v = rb_del(rb);
|
|
||||||
|
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
void neug_wait_full() {
|
void hwrng_wait_full(void) {
|
||||||
struct rng_rb *rb = &the_ring_buffer;
|
struct hwrng_buf *rb = &ring_buffer;
|
||||||
#ifndef ENABLE_EMULATION
|
|
||||||
#ifdef ESP_PLATFORM
|
#ifdef ESP_PLATFORM
|
||||||
uint8_t core = xTaskGetCurrentTaskHandle() == hcore1 ? 1 : 0;
|
uint8_t core = xTaskGetCurrentTaskHandle() == hcore1 ? 1 : 0;
|
||||||
#else
|
#elif defined(PICO_PLATFORM)
|
||||||
uint core = get_core_num();
|
uint core = get_core_num();
|
||||||
#endif
|
#endif
|
||||||
#endif
|
while (true) {
|
||||||
while (!rb->full) {
|
hwrng_lock();
|
||||||
#ifndef ENABLE_EMULATION
|
hwrng_unlock();
|
||||||
|
if (rb->full) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#if defined(PICO_PLATFORM) || defined(ESP_PLATFORM)
|
||||||
if (core == 1) {
|
if (core == 1) {
|
||||||
sleep_ms(1);
|
sleep_ms(1);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
neug_task();
|
hwrng_task();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,31 +3,26 @@
|
|||||||
* Copyright (c) 2022 Pol Henarejos.
|
* Copyright (c) 2022 Pol Henarejos.
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU 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.
|
* the Free Software Foundation, version 3.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful, but
|
* This program is distributed in the hope that it will be useful, but
|
||||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* 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
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _NEUG_H_
|
#ifndef _NEUG_H_
|
||||||
#define _NEUG_H_
|
#define _NEUG_H_
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
#define NEUG_PRE_LOOP 32
|
void hwrng_init(uint32_t *buf, uint8_t size);
|
||||||
|
uint32_t hwrng_get(void);
|
||||||
#include <stdlib.h>
|
void hwrng_flush(void);
|
||||||
#if !defined(ENABLE_EMULATION) && !defined(ESP_PLATFORM)
|
void hwrng_wait_full(void);
|
||||||
#include "pico/stdlib.h"
|
void *hwrng_task(void);
|
||||||
#endif
|
|
||||||
|
|
||||||
void neug_init(uint32_t *buf, uint8_t size);
|
|
||||||
uint32_t neug_get();
|
|
||||||
void neug_flush(void);
|
|
||||||
void neug_wait_full();
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -3,75 +3,96 @@
|
|||||||
* Copyright (c) 2022 Pol Henarejos.
|
* Copyright (c) 2022 Pol Henarejos.
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU 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.
|
* the Free Software Foundation, version 3.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful, but
|
* This program is distributed in the hope that it will be useful, but
|
||||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* 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
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#define HWRNG_PRE_LOOP 32
|
||||||
|
|
||||||
#include <stdint.h>
|
#include "picokeys.h"
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include "hwrng.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
|
#define RANDOM_BYTES_LENGTH 32
|
||||||
static uint32_t random_word[RANDOM_BYTES_LENGTH / sizeof(uint32_t)];
|
static uint32_t random_word[RANDOM_BYTES_LENGTH / sizeof(uint32_t)];
|
||||||
|
static mutex_t random_mutex;
|
||||||
|
static bool random_mutex_initialized = false;
|
||||||
|
|
||||||
void random_init(void) {
|
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 (int i = 0; i < HWRNG_PRE_LOOP; i++) {
|
||||||
|
hwrng_get();
|
||||||
for (i = 0; i < NEUG_PRE_LOOP; i++) {
|
|
||||||
neug_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
|
* Return pointer to random 32-byte
|
||||||
*/
|
*/
|
||||||
void random_bytes_free(const uint8_t *p);
|
|
||||||
#define MAX_RANDOM_BUFFER 1024
|
#define MAX_RANDOM_BUFFER 1024
|
||||||
const uint8_t *random_bytes_get(size_t len) {
|
const uint8_t *random_bytes_get(size_t len) {
|
||||||
if (len > MAX_RANDOM_BUFFER) {
|
if (len > MAX_RANDOM_BUFFER) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
static uint32_t return_word[MAX_RANDOM_BUFFER / sizeof(uint32_t)];
|
static uint32_t return_word[MAX_RANDOM_BUFFER / sizeof(uint32_t)];
|
||||||
|
if (random_mutex_initialized) {
|
||||||
|
mutex_enter_blocking(&random_mutex);
|
||||||
|
}
|
||||||
for (size_t ix = 0; ix < len; ix += RANDOM_BYTES_LENGTH) {
|
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);
|
memcpy(return_word + ix / sizeof(uint32_t), random_word, RANDOM_BYTES_LENGTH);
|
||||||
random_bytes_free((const uint8_t *) random_word);
|
random_bytes_free((const uint8_t *) random_word);
|
||||||
}
|
}
|
||||||
|
if (random_mutex_initialized) {
|
||||||
|
mutex_exit(&random_mutex);
|
||||||
|
}
|
||||||
return (const uint8_t *) return_word;
|
return (const uint8_t *) return_word;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Free pointer to random 32-byte
|
|
||||||
*/
|
|
||||||
void random_bytes_free(const uint8_t *p) {
|
|
||||||
(void) p;
|
|
||||||
memset(random_word, 0, RANDOM_BYTES_LENGTH);
|
|
||||||
neug_flush();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Random byte iterator
|
* Random byte iterator
|
||||||
*/
|
*/
|
||||||
int random_gen(void *arg, unsigned char *out, size_t out_len) {
|
int random_fill_iterator(void *arg, unsigned char *out, size_t out_len) {
|
||||||
uint8_t *index_p = (uint8_t *) arg;
|
random_fill_iterator_ctx_t *ctx = (random_fill_iterator_ctx_t *) arg;
|
||||||
uint8_t index = index_p ? *index_p : 0;
|
uint8_t index = ctx ? ctx->index : 0;
|
||||||
uint8_t n;
|
uint8_t n;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
if (random_mutex_initialized) {
|
||||||
|
mutex_enter_blocking(&random_mutex);
|
||||||
|
}
|
||||||
while (out_len) {
|
while (out_len) {
|
||||||
neug_wait_full();
|
if (ctx && ctx->cancel) {
|
||||||
|
ret = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
hwrng_wait_full();
|
||||||
|
|
||||||
n = RANDOM_BYTES_LENGTH - index;
|
n = RANDOM_BYTES_LENGTH - index;
|
||||||
if (n > out_len) {
|
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) {
|
if (index >= RANDOM_BYTES_LENGTH) {
|
||||||
index = 0;
|
index = 0;
|
||||||
neug_flush();
|
hwrng_flush();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (index_p) {
|
if (ctx) {
|
||||||
*index_p = index;
|
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.
|
* Copyright (c) 2022 Pol Henarejos.
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU 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.
|
* the Free Software Foundation, version 3.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful, but
|
* This program is distributed in the hope that it will be useful, but
|
||||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* 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
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
@@ -21,14 +21,18 @@
|
|||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdint.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 */
|
extern void
|
||||||
const uint8_t *random_bytes_get(size_t);
|
random_init(void);
|
||||||
void random_bytes_free(const uint8_t *p);
|
|
||||||
|
|
||||||
/* iterator returning a byta at a time */
|
extern const uint8_t *random_bytes_get(size_t);
|
||||||
extern int random_gen(void *arg, unsigned char *output, size_t output_len);
|
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
|
#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.
|
* Copyright (c) 2022 Pol Henarejos.
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU 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.
|
* the Free Software Foundation, version 3.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful, but
|
* This program is distributed in the hope that it will be useful, but
|
||||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* 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
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "pico_keys.h"
|
#include "picokeys.h"
|
||||||
#include "asn1.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) {
|
if (!ctx) {
|
||||||
return PICOKEY_ERR_NULL_PARAM;
|
return PICOKEYS_ERR_NULL_PARAM;
|
||||||
}
|
}
|
||||||
ctx->data = data;
|
ctx->data = data;
|
||||||
ctx->len = len;
|
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->data = NULL;
|
||||||
ctx->len = 0;
|
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) {
|
if (ctx->data && ctx->len > 0) {
|
||||||
return ctx->len;
|
return ctx->len;
|
||||||
}
|
}
|
||||||
return 0;
|
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];
|
uint32_t d = ctx->data[0];
|
||||||
for (uint16_t lt = 1; lt < MIN(ctx->len, sizeof(uint32_t)); lt++) {
|
for (uint16_t lt = 1; lt < MIN(ctx->len, sizeof(uint32_t)); lt++) {
|
||||||
d <<= 8;
|
d <<= 8;
|
||||||
@@ -49,15 +49,15 @@ uint32_t asn1_get_uint(asn1_ctx_t *ctx) {
|
|||||||
return d;
|
return d;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t asn1_len_tag(uint16_t tag, uint16_t len) {
|
uint16_t tlv_len_tag(uint16_t tag, uint16_t len) {
|
||||||
uint16_t ret = 1 + format_tlv_len(len, NULL) + len;
|
uint16_t ret = 1 + tlv_format_len(len, NULL) + len;
|
||||||
if (tag > 0x00ff) {
|
if (tag > 0x00ff) {
|
||||||
return ret + 1;
|
return ret + 1;
|
||||||
}
|
}
|
||||||
return ret;
|
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 (len < 128) {
|
||||||
if (out) {
|
if (out) {
|
||||||
*out = (uint8_t)len;
|
*out = (uint8_t)len;
|
||||||
@@ -73,16 +73,12 @@ uint8_t format_tlv_len(uint16_t len, uint8_t *out) {
|
|||||||
}
|
}
|
||||||
if (out) {
|
if (out) {
|
||||||
*out++ = 0x82;
|
*out++ = 0x82;
|
||||||
put_uint16_t_be(len, out);
|
put_uint16_be(len, out);
|
||||||
}
|
}
|
||||||
return 3;
|
return 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
int walk_tlv(const asn1_ctx_t *ctxi,
|
int tlv_walk(const tlv_ctx_t *ctxi, uint8_t **p, uint16_t *tag, uint16_t *tag_len, uint8_t **data) {
|
||||||
uint8_t **p,
|
|
||||||
uint16_t *tag,
|
|
||||||
uint16_t *tag_len,
|
|
||||||
uint8_t **data) {
|
|
||||||
if (!p) {
|
if (!p) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -92,8 +88,7 @@ int walk_tlv(const asn1_ctx_t *ctxi,
|
|||||||
if (*p - ctxi->data >= ctxi->len) {
|
if (*p - ctxi->data >= ctxi->len) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
uint16_t tg = 0x0;
|
uint16_t tg = 0x0, tgl = 0;
|
||||||
uint16_t tgl = 0;
|
|
||||||
tg = *(*p)++;
|
tg = *(*p)++;
|
||||||
if ((tg & 0x1f) == 0x1f) {
|
if ((tg & 0x1f) == 0x1f) {
|
||||||
tg <<= 8;
|
tg <<= 8;
|
||||||
@@ -120,14 +115,10 @@ int walk_tlv(const asn1_ctx_t *ctxi,
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool asn1_find_tag(const asn1_ctx_t *ctxi,
|
bool tlv_find_tag(const tlv_ctx_t *ctxi, uint16_t itag, tlv_ctx_t *ctxo) {
|
||||||
uint16_t itag,
|
uint16_t tag = 0x0, tlen = 0;
|
||||||
asn1_ctx_t *ctxo) {
|
uint8_t *p = NULL, *tdata = NULL;
|
||||||
uint16_t tag = 0x0;
|
while (tlv_walk(ctxi, &p, &tag, &tlen, &tdata)) {
|
||||||
uint8_t *p = NULL;
|
|
||||||
uint8_t *tdata = NULL;
|
|
||||||
uint16_t tlen = 0;
|
|
||||||
while (walk_tlv(ctxi, &p, &tag, &tlen, &tdata)) {
|
|
||||||
if (itag == tag) {
|
if (itag == tag) {
|
||||||
if (ctxo != NULL) {
|
if (ctxo != NULL) {
|
||||||
ctxo->data = tdata;
|
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.
|
* Copyright (c) 2022 Pol Henarejos.
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU 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.
|
* the Free Software Foundation, version 3.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful, but
|
* This program is distributed in the hope that it will be useful, but
|
||||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* 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
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "picokeys.h"
|
||||||
|
#include "led/led.h"
|
||||||
#include "random.h"
|
#include "random.h"
|
||||||
#include "pico_keys.h"
|
|
||||||
#ifdef PICO_PLATFORM
|
#ifdef PICO_PLATFORM
|
||||||
#include "bsp/board.h"
|
#include "bsp/board.h"
|
||||||
#endif
|
#endif
|
||||||
@@ -27,7 +28,6 @@
|
|||||||
#include "emulation.h"
|
#include "emulation.h"
|
||||||
#endif
|
#endif
|
||||||
#include "ccid.h"
|
#include "ccid.h"
|
||||||
#include "usb_descriptors.h"
|
|
||||||
#include "apdu.h"
|
#include "apdu.h"
|
||||||
#include "usb.h"
|
#include "usb.h"
|
||||||
|
|
||||||
@@ -97,21 +97,22 @@ static uint8_t itf_num;
|
|||||||
static usb_buffer_t *ccid_rx = NULL, *ccid_tx = NULL;
|
static usb_buffer_t *ccid_rx = NULL, *ccid_tx = NULL;
|
||||||
|
|
||||||
int driver_process_usb_packet_ccid(uint8_t itf, uint16_t rx_read);
|
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].w_ptr += size + offset;
|
||||||
ccid_tx[itf].r_ptr += 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_response = NULL;
|
||||||
ccid_header_t **ccid_resp_fast = NULL;
|
ccid_header_t **ccid_resp_fast = NULL;
|
||||||
ccid_header_t **ccid_header = 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) {
|
if (itf == ITF_SC_CCID) {
|
||||||
return ITF_CCID;
|
return ITF_CCID;
|
||||||
}
|
}
|
||||||
@@ -121,7 +122,7 @@ uint8_t sc_itf_to_usb_itf(uint8_t itf) {
|
|||||||
return itf;
|
return itf;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ccid_init_buffers() {
|
static void ccid_init_buffers(void) {
|
||||||
if (ITF_SC_TOTAL == 0) {
|
if (ITF_SC_TOTAL == 0) {
|
||||||
return;
|
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_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);
|
ccid_resp_fast[itf] = (ccid_header_t *) (ccid_tx[itf].buffer + sizeof(ccid_tx[itf].buffer) - 64);
|
||||||
// apdu.header = &ccid_header->apdu;
|
// 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;
|
//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 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);
|
uint32_t len = tud_vendor_n_available(itf);
|
||||||
do {
|
do {
|
||||||
uint16_t tlen = 0;
|
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);
|
} 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) {
|
if (*tx_buffer != 0x81) {
|
||||||
DEBUG_PAYLOAD(tx_buffer, buffer_size);
|
DEBUG_PAYLOAD(tx_buffer, buffer_size);
|
||||||
}
|
}
|
||||||
int r = tud_vendor_n_write(itf, tx_buffer, buffer_size);
|
uint32_t written = tud_vendor_n_write(itf, tx_buffer, buffer_size);
|
||||||
if (r > 0) {
|
if (written > 0) {
|
||||||
tud_vendor_n_flush(itf);
|
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) {
|
if (ccid_tx[itf].r_ptr >= ccid_tx[itf].w_ptr) {
|
||||||
ccid_tx[itf].r_ptr = ccid_tx[itf].w_ptr = 0;
|
ccid_tx[itf].r_ptr = ccid_tx[itf].w_ptr = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
#ifdef ENABLE_EMULATION
|
#ifdef ENABLE_EMULATION
|
||||||
tud_vendor_tx_cb(itf, r);
|
tud_vendor_tx_cb(itf, written);
|
||||||
#endif
|
#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);
|
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;
|
(void) rx_read;
|
||||||
if (ccid_rx[itf].w_ptr - ccid_rx[itf].r_ptr >= 10) {
|
if (ccid_rx[itf].w_ptr - ccid_rx[itf].r_ptr >= 10) {
|
||||||
driver_init_ccid(itf);
|
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);
|
//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)){
|
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);
|
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;
|
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]->bMessageType = CCID_DATA_BLOCK_RET;
|
||||||
ccid_resp_fast[itf]->dwLength = 0;
|
ccid_resp_fast[itf]->dwLength = 0;
|
||||||
ccid_resp_fast[itf]->bSlot = 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);
|
ccid_write_offset(itf, size_next+10, offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ccid_task() {
|
void ccid_task(void) {
|
||||||
for (int itf = 0; itf < ITF_SC_TOTAL; itf++) {
|
for (uint8_t itf = 0; itf < ITF_SC_TOTAL; itf++) {
|
||||||
int status = card_status(sc_itf_to_usb_itf(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);
|
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);
|
driver_exec_timeout_ccid(itf);
|
||||||
}
|
}
|
||||||
if (ccid_tx[itf].w_ptr > ccid_tx[itf].r_ptr) {
|
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();
|
ccid_init_buffers();
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef ENABLE_EMULATION
|
|
||||||
|
|
||||||
void tud_vendor_tx_cb(uint8_t itf, uint32_t sent_bytes) {
|
void tud_vendor_tx_cb(uint8_t itf, uint32_t sent_bytes) {
|
||||||
(void) sent_bytes;
|
(void) sent_bytes;
|
||||||
tud_vendor_n_write_flush(itf);
|
tud_vendor_n_write_flush(itf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef ENABLE_EMULATION
|
||||||
|
|
||||||
static void ccid_init_cb(void) {
|
static void ccid_init_cb(void) {
|
||||||
vendord_init();
|
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));
|
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);
|
TU_ASSERT(usbd_edpt_open(rhport, desc_ep), 0);
|
||||||
uint8_t msg[] = { 0x50, 0x03 };
|
uint8_t msg[] = { 0x50, 0x03 };
|
||||||
|
#if defined(PICO_PLATFORM) || defined(ESP_PLATFORM)
|
||||||
usbd_edpt_xfer(rhport, desc_ep->bEndpointAddress, msg, sizeof(msg));
|
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
|
#else
|
||||||
vendord_open(rhport, (tusb_desc_interface_t *)itf_vendor, max_len);
|
vendord_open(rhport, (tusb_desc_interface_t *)itf_vendor, max_len);
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -3,16 +3,16 @@
|
|||||||
* Copyright (c) 2022 Pol Henarejos.
|
* Copyright (c) 2022 Pol Henarejos.
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU 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.
|
* the Free Software Foundation, version 3.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful, but
|
* This program is distributed in the hope that it will be useful, but
|
||||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* 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
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _CCID_H_
|
#ifndef _CCID_H_
|
||||||
@@ -40,4 +40,30 @@ enum ccid_state {
|
|||||||
|
|
||||||
extern const uint8_t *ccid_atr;
|
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_
|
#endif //_CCID_H_
|
||||||
|
|||||||
@@ -3,18 +3,25 @@
|
|||||||
* Copyright (c) 2022 Pol Henarejos.
|
* Copyright (c) 2022 Pol Henarejos.
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU 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.
|
* the Free Software Foundation, version 3.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful, but
|
* This program is distributed in the hope that it will be useful, but
|
||||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* 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
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* 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 "emulation.h"
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#ifndef _MSC_VER
|
#ifndef _MSC_VER
|
||||||
@@ -29,7 +36,6 @@ typedef int socket_t;
|
|||||||
#define INVALID_SOCKET (-1)
|
#define INVALID_SOCKET (-1)
|
||||||
#define SOCKET_ERROR (-1)
|
#define SOCKET_ERROR (-1)
|
||||||
#else
|
#else
|
||||||
#include <ws2tcpip.h>
|
|
||||||
#define O_NONBLOCK _O_NONBLOCK
|
#define O_NONBLOCK _O_NONBLOCK
|
||||||
#define close closesocket
|
#define close closesocket
|
||||||
typedef SOCKET socket_t;
|
typedef SOCKET socket_t;
|
||||||
@@ -41,7 +47,6 @@ typedef int socklen_t;
|
|||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
#include "pico_keys.h"
|
|
||||||
#include "apdu.h"
|
#include "apdu.h"
|
||||||
#include "usb.h"
|
#include "usb.h"
|
||||||
#include "ccid/ccid.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);
|
extern int cbor_parse(uint8_t cmd, const uint8_t *data, size_t len);
|
||||||
pthread_t hcore0, hcore1;
|
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
|
#ifndef _MSC_VER
|
||||||
int msleep(long msec) {
|
static int msleep(long msec) {
|
||||||
struct timespec ts;
|
struct timespec ts;
|
||||||
int res;
|
int res;
|
||||||
|
|
||||||
@@ -80,7 +95,7 @@ int msleep(long msec) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int emul_init(char *host, uint16_t port) {
|
int emul_init(const char *host, uint16_t port) {
|
||||||
struct sockaddr_in serv_addr;
|
struct sockaddr_in serv_addr;
|
||||||
fprintf(stderr, "\n Starting emulation envionrment\n");
|
fprintf(stderr, "\n Starting emulation envionrment\n");
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
@@ -90,7 +105,7 @@ int emul_init(char *host, uint16_t port) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if ((ccid_sock = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
|
if ((ccid_sock = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
|
||||||
perror("socket");
|
log_sock_error("socket(ccid)");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,13 +115,13 @@ int emul_init(char *host, uint16_t port) {
|
|||||||
// Convert IPv4 and IPv6 addresses from text to binary
|
// Convert IPv4 and IPv6 addresses from text to binary
|
||||||
// form
|
// form
|
||||||
if (inet_pton(AF_INET, host, &serv_addr.sin_addr) <= 0) {
|
if (inet_pton(AF_INET, host, &serv_addr.sin_addr) <= 0) {
|
||||||
perror("inet_pton");
|
log_sock_error("inet_pton(ccid)");
|
||||||
close(ccid_sock);
|
close(ccid_sock);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (connect(ccid_sock, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) {
|
if (connect(ccid_sock, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) {
|
||||||
perror("connect");
|
log_sock_error("connect(ccid)");
|
||||||
close(ccid_sock);
|
close(ccid_sock);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -129,12 +144,12 @@ int emul_init(char *host, uint16_t port) {
|
|||||||
struct sockaddr_in server_sockaddr;
|
struct sockaddr_in server_sockaddr;
|
||||||
|
|
||||||
if ((hid_server_sock = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
|
if ((hid_server_sock = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
|
||||||
perror("socket");
|
log_sock_error("socket(hid_server)");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (setsockopt(hid_server_sock, SOL_SOCKET, SO_REUSEADDR, (void *) &yes, sizeof yes) != 0) {
|
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);
|
close(hid_server_sock);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -154,20 +169,21 @@ int emul_init(char *host, uint16_t port) {
|
|||||||
|
|
||||||
if (bind(hid_server_sock, (struct sockaddr *) &server_sockaddr,
|
if (bind(hid_server_sock, (struct sockaddr *) &server_sockaddr,
|
||||||
sizeof server_sockaddr) != 0) {
|
sizeof server_sockaddr) != 0) {
|
||||||
perror("bind");
|
log_sock_error("bind(hid_server)");
|
||||||
close(hid_server_sock);
|
close(hid_server_sock);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (listen(hid_server_sock, 0) != 0) {
|
if (listen(hid_server_sock, SOMAXCONN) != 0) {
|
||||||
perror("listen");
|
log_sock_error("listen(hid_server)");
|
||||||
close(hid_server_sock);
|
close(hid_server_sock);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
fprintf(stderr, "HID server listening on 0.0.0.0:%u\n", hid_port);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
socket_t get_sock_itf(uint8_t itf) {
|
static socket_t get_sock_itf(uint8_t itf) {
|
||||||
#ifdef USB_ITF_CCID
|
#ifdef USB_ITF_CCID
|
||||||
if (itf == ITF_CCID) {
|
if (itf == ITF_CCID) {
|
||||||
return ccid_sock;
|
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);
|
uint16_t size = htons(buffer_size);
|
||||||
socket_t sock = get_sock_itf(itf);
|
socket_t sock = get_sock_itf(itf);
|
||||||
// DEBUG_PAYLOAD(buffer,buffer_size);
|
// DEBUG_PAYLOAD(buffer,buffer_size);
|
||||||
|
#ifdef _WIN32
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
#else
|
||||||
|
ssize_t ret = 0;
|
||||||
|
#endif
|
||||||
do {
|
do {
|
||||||
ret = send(sock, (const char *)&size, sizeof(size), 0);
|
ret = send(sock, (const char *)&size, sizeof(size), 0);
|
||||||
if (ret == SOCKET_ERROR) {
|
if (ret == SOCKET_ERROR) {
|
||||||
@@ -279,7 +299,11 @@ uint16_t emul_read(uint8_t itf) {
|
|||||||
__pragma(warning(pop))
|
__pragma(warning(pop))
|
||||||
#endif
|
#endif
|
||||||
struct timeval timeout;
|
struct timeval timeout;
|
||||||
|
#ifdef _WIN32
|
||||||
int valread = 0;
|
int valread = 0;
|
||||||
|
#else
|
||||||
|
ssize_t valread = 0;
|
||||||
|
#endif
|
||||||
timeout.tv_sec = 0;
|
timeout.tv_sec = 0;
|
||||||
timeout.tv_usec = 0 * 1000;
|
timeout.tv_usec = 0 * 1000;
|
||||||
int n = select((int)(sock + 1), &input, NULL, NULL, &timeout);
|
int n = select((int)(sock + 1), &input, NULL, NULL, &timeout);
|
||||||
@@ -320,7 +344,7 @@ uint16_t emul_read(uint8_t itf) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
else {
|
else {
|
||||||
emul_rx_size += valread;
|
emul_rx_size += (uint16_t)valread;
|
||||||
}
|
}
|
||||||
return (uint16_t)emul_rx_size;
|
return (uint16_t)emul_rx_size;
|
||||||
}
|
}
|
||||||
@@ -333,7 +357,7 @@ uint16_t emul_read(uint8_t itf) {
|
|||||||
return emul_rx_size;
|
return emul_rx_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
void emul_task() {
|
void emul_task(void) {
|
||||||
#ifdef USB_ITF_CCID
|
#ifdef USB_ITF_CCID
|
||||||
emul_read(ITF_CCID);
|
emul_read(ITF_CCID);
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user