mirror of
https://github.com/polhenarejos/pico-keys-sdk
synced 2026-06-15 07:18:23 +02:00
Compare commits
141 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5dfc7d51d2 | ||
|
|
f94c74a74c | ||
|
|
3a142cb575 | ||
|
|
0ed308087a | ||
|
|
d7fb22d39a | ||
|
|
8a87b0d2de | ||
|
|
5fd26200ea | ||
|
|
0245933224 | ||
|
|
13d2e84595 | ||
|
|
f8338f0d01 | ||
|
|
018d4e6ff1 | ||
|
|
b13e2ebe15 | ||
|
|
2ed315cd81 | ||
|
|
9611a81898 | ||
|
|
49edef1d3f | ||
|
|
eb26a96d3b | ||
|
|
d711f33721 | ||
|
|
1a289db1cd | ||
|
|
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 |
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*
|
||||
|
||||
9
.gitmodules
vendored
9
.gitmodules
vendored
@@ -1,9 +0,0 @@
|
||||
[submodule "mbedtls"]
|
||||
path = mbedtls
|
||||
url = https://github.com/ARMmbed/mbedtls
|
||||
[submodule "tinycbor"]
|
||||
path = tinycbor
|
||||
url = https://github.com/intel/tinycbor.git
|
||||
[submodule "mlkem"]
|
||||
path = mlkem
|
||||
url = https://github.com/pq-code-package/mlkem-native/
|
||||
@@ -1,23 +1,23 @@
|
||||
#
|
||||
# This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
|
||||
# Copyright (c) 2022 Pol Henarejos.
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, version 3.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
#
|
||||
# This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
|
||||
# Copyright (c) 2022 Pol Henarejos.
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, version 3.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
if(ESP_PLATFORM)
|
||||
if(ESP_PLATFORM)
|
||||
set(EXTRA_COMPONENT_DIRS src)
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
else()
|
||||
@@ -26,7 +26,7 @@ else()
|
||||
include(pico_sdk_import.cmake)
|
||||
endif()
|
||||
|
||||
project(picokey C CXX ASM)
|
||||
project(pico_rescue C CXX ASM)
|
||||
|
||||
set(CMAKE_C_STANDARD 11)
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
@@ -35,68 +35,55 @@ else()
|
||||
set(__FOR_CI 0)
|
||||
endif()
|
||||
if(__FOR_CI)
|
||||
add_definitions(-D__FOR_CI)
|
||||
add_compile_definitions(__FOR_CI)
|
||||
endif()
|
||||
|
||||
add_executable(picokey)
|
||||
add_executable(pico_rescue)
|
||||
endif()
|
||||
|
||||
set(USB_ITF_CCID 1)
|
||||
set(USB_ITF_WCID 1)
|
||||
include(cmake/version.cmake)
|
||||
include(pico_keys_sdk_import.cmake)
|
||||
include(cmake/options.cmake OPTIONAL)
|
||||
include(picokeys_sdk_import.cmake)
|
||||
if(NOT ESP_PLATFORM)
|
||||
set(SOURCES ${PICO_KEYS_SOURCES})
|
||||
set(SOURCES ${PICOKEYS_SOURCES})
|
||||
endif()
|
||||
set(SOURCES ${SOURCES}
|
||||
list(APPEND SOURCES
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/fs/files.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/version.c
|
||||
)
|
||||
|
||||
SET_VERSION(ver_major ver_minor "${CMAKE_CURRENT_LIST_DIR}/src/pico_keys_version.h" 2)
|
||||
SET_VERSION(ver_major ver_minor "${CMAKE_CURRENT_LIST_DIR}/src/picokeys_version.h")
|
||||
|
||||
if(ESP_PLATFORM)
|
||||
project(picokey)
|
||||
project(pico_rescue)
|
||||
endif()
|
||||
|
||||
if(NOT ESP_PLATFORM)
|
||||
target_sources(picokey PUBLIC ${SOURCES})
|
||||
target_include_directories(picokey PUBLIC ${INCLUDES})
|
||||
target_sources(pico_rescue PUBLIC ${SOURCES})
|
||||
target_include_directories(pico_rescue PUBLIC ${INCLUDES})
|
||||
|
||||
target_compile_options(picokey PUBLIC
|
||||
-Wall
|
||||
)
|
||||
target_compile_options(pico_rescue PRIVATE -Wall)
|
||||
if(NOT MSVC)
|
||||
target_compile_options(picokey PUBLIC
|
||||
-Werror
|
||||
)
|
||||
target_compile_options(pico_rescue PRIVATE -Werror)
|
||||
endif()
|
||||
|
||||
if(ENABLE_EMULATION)
|
||||
if(NOT MSVC)
|
||||
target_compile_options(picokey PUBLIC
|
||||
-fdata-sections
|
||||
-ffunction-sections
|
||||
)
|
||||
target_compile_options(pico_rescue PRIVATE -fdata-sections -ffunction-sections)
|
||||
endif()
|
||||
if(APPLE)
|
||||
target_link_options(picokey PUBLIC
|
||||
-Wl,-dead_strip
|
||||
)
|
||||
target_link_options(pico_rescue PRIVATE -Wl,-dead_strip)
|
||||
elseif(MSVC)
|
||||
target_compile_options(picokey PUBLIC
|
||||
-WX
|
||||
)
|
||||
target_compile_options(pico_rescue PRIVATE -WX)
|
||||
|
||||
target_link_libraries(picokey PUBLIC wsock32 ws2_32 Bcrypt)
|
||||
target_link_libraries(pico_rescue PRIVATE wsock32 ws2_32 Bcrypt Ncrypt)
|
||||
else()
|
||||
target_link_options(picokey PUBLIC
|
||||
-Wl,--gc-sections
|
||||
)
|
||||
endif(APPLE)
|
||||
target_link_libraries(picokey PRIVATE pthread m)
|
||||
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()
|
||||
|
||||
|
||||
189
cmake/build_helpers.cmake
Normal file
189
cmake/build_helpers.cmake
Normal file
@@ -0,0 +1,189 @@
|
||||
#
|
||||
# Pico Keys SDK build helper functions
|
||||
#
|
||||
|
||||
function(picokeys_apply_strict_flags)
|
||||
set(options)
|
||||
set(oneValueArgs FILTER_REGEX)
|
||||
set(multiValueArgs SOURCES)
|
||||
cmake_parse_arguments(PKAS "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
|
||||
|
||||
if(NOT PKAS_SOURCES)
|
||||
return()
|
||||
endif()
|
||||
|
||||
if (MSVC)
|
||||
set(PICOKEYS_STRICT_FLAGS
|
||||
-Wall
|
||||
-Zc:strictStrings
|
||||
-WX
|
||||
)
|
||||
else ()
|
||||
set(PICOKEYS_STRICT_FLAGS
|
||||
-pipe
|
||||
-funsigned-char
|
||||
-fstrict-aliasing
|
||||
-fdiagnostics-color=auto
|
||||
-Wextra
|
||||
-Wchar-subscripts
|
||||
-Wundef
|
||||
-Wshadow
|
||||
-Wcast-align
|
||||
-Wwrite-strings
|
||||
-Wunused
|
||||
-Wuninitialized
|
||||
-Wpointer-arith
|
||||
-Wredundant-decls
|
||||
-Winline
|
||||
-Wformat
|
||||
-Wformat-security
|
||||
-Wswitch-enum
|
||||
-Winit-self
|
||||
-Wmissing-include-dirs
|
||||
-Wempty-body
|
||||
-Wmissing-prototypes
|
||||
-Wstrict-prototypes
|
||||
-Wold-style-definition
|
||||
-Wbad-function-cast
|
||||
-Wnested-externs
|
||||
-Wmissing-declarations
|
||||
-Werror
|
||||
)
|
||||
endif()
|
||||
|
||||
foreach(src IN LISTS PKAS_SOURCES)
|
||||
if(PKAS_FILTER_REGEX)
|
||||
if(NOT src MATCHES "${PKAS_FILTER_REGEX}")
|
||||
continue()
|
||||
endif()
|
||||
endif()
|
||||
set_property(SOURCE "${src}" APPEND PROPERTY COMPILE_OPTIONS ${PICOKEYS_STRICT_FLAGS})
|
||||
endforeach()
|
||||
endfunction()
|
||||
|
||||
function(picokeys_configure_host_target)
|
||||
set(options)
|
||||
set(oneValueArgs TARGET STRICT_FILTER_REGEX MACOS_APP_BUNDLE_ID MACOS_APP_DEVELOPMENT_TEAM)
|
||||
set(multiValueArgs SOURCES INCLUDES)
|
||||
cmake_parse_arguments(PKCHT "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
|
||||
|
||||
if(NOT PKCHT_TARGET OR ESP_PLATFORM)
|
||||
return()
|
||||
endif()
|
||||
|
||||
target_sources(${PKCHT_TARGET} PUBLIC ${PKCHT_SOURCES})
|
||||
target_include_directories(${PKCHT_TARGET} PUBLIC ${PKCHT_INCLUDES})
|
||||
target_compile_options(${PKCHT_TARGET} PRIVATE -Wall)
|
||||
|
||||
picokeys_apply_strict_flags(
|
||||
SOURCES ${PKCHT_SOURCES}
|
||||
FILTER_REGEX "${PKCHT_STRICT_FILTER_REGEX}"
|
||||
)
|
||||
|
||||
if(NOT MSVC)
|
||||
target_compile_options(${PKCHT_TARGET} PRIVATE -Werror)
|
||||
|
||||
string(FIND ${CMAKE_C_COMPILER} ":" COMPILER_COLON)
|
||||
if(${COMPILER_COLON} GREATER_EQUAL 0)
|
||||
target_compile_options(${PKCHT_TARGET} PRIVATE -Wno-error=use-after-free)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(ENABLE_EMULATION)
|
||||
if(NOT MSVC)
|
||||
target_compile_options(${PKCHT_TARGET} PRIVATE -fdata-sections -ffunction-sections)
|
||||
endif()
|
||||
|
||||
if(APPLE)
|
||||
target_link_options(${PKCHT_TARGET} PRIVATE -Wl,-dead_strip)
|
||||
|
||||
if(MACOS_APP)
|
||||
target_link_libraries(${PKCHT_TARGET} PRIVATE
|
||||
"-framework Security"
|
||||
"-framework CoreFoundation"
|
||||
)
|
||||
if(CMAKE_GENERATOR STREQUAL "Xcode")
|
||||
if("${PKCHT_MACOS_APP_DEVELOPMENT_TEAM}" STREQUAL "")
|
||||
message(FATAL_ERROR "MACOS_APP=1 with Xcode requires MACOS_APP_DEVELOPMENT_TEAM")
|
||||
endif()
|
||||
target_compile_options(${PKCHT_TARGET} PRIVATE -Wno-missing-include-dirs)
|
||||
set_target_properties(${PKCHT_TARGET} PROPERTIES
|
||||
MACOSX_BUNDLE TRUE
|
||||
MACOSX_BUNDLE_GUI_IDENTIFIER "${PKCHT_MACOS_APP_BUNDLE_ID}"
|
||||
MACOSX_BUNDLE_BUNDLE_NAME "${PKCHT_TARGET}"
|
||||
XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER "${PKCHT_MACOS_APP_BUNDLE_ID}"
|
||||
XCODE_ATTRIBUTE_CODE_SIGN_STYLE "Automatic"
|
||||
XCODE_ATTRIBUTE_DEVELOPMENT_TEAM "${PKCHT_MACOS_APP_DEVELOPMENT_TEAM}"
|
||||
XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "Apple Development"
|
||||
XCODE_ATTRIBUTE_CODE_SIGN_ENTITLEMENTS "${CMAKE_CURRENT_SOURCE_DIR}/pico_novus.entitlements"
|
||||
XCODE_ATTRIBUTE_ENABLE_HARDENED_RUNTIME "YES"
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(DEBUG_APDU)
|
||||
target_compile_options(${PKCHT_TARGET} PRIVATE
|
||||
-fsanitize=address
|
||||
-g
|
||||
-O1
|
||||
-fno-omit-frame-pointer
|
||||
)
|
||||
target_link_options(${PKCHT_TARGET} PRIVATE
|
||||
-fsanitize=address
|
||||
-g
|
||||
-O1
|
||||
-fno-omit-frame-pointer
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
function(picokeys_add_macos_app_xcode_driver)
|
||||
set(options)
|
||||
set(oneValueArgs TARGET BUNDLE_ID SIGN_IDENTITY DEVELOPMENT_TEAM)
|
||||
cmake_parse_arguments(PKMXD "${options}" "${oneValueArgs}" "" ${ARGN})
|
||||
|
||||
if(NOT PKMXD_TARGET)
|
||||
return()
|
||||
endif()
|
||||
if(NOT (APPLE AND ENABLE_EMULATION AND MACOS_APP AND NOT CMAKE_GENERATOR STREQUAL "Xcode" AND NOT MACOS_APP_XCODE_DRIVER))
|
||||
return()
|
||||
endif()
|
||||
if("${PKMXD_DEVELOPMENT_TEAM}" STREQUAL "")
|
||||
message(FATAL_ERROR "MACOS_APP=1 requires MACOS_APP_DEVELOPMENT_TEAM")
|
||||
endif()
|
||||
|
||||
set(MACOS_APP_XCODE_BUILD_DIR "${CMAKE_CURRENT_SOURCE_DIR}/build-macos-app-xcode")
|
||||
set(MACOS_APP_XCODE_FORWARD_ARGS)
|
||||
get_cmake_property(_cache_vars CACHE_VARIABLES)
|
||||
foreach(_cv ${_cache_vars})
|
||||
if(_cv MATCHES "^(ENABLE_|DEBUG_APDU$|VIDPID$|USB_VID$|USB_PID$|USE_OPENSSL$|CMAKE_BUILD_TYPE$)")
|
||||
get_property(_cv_type CACHE ${_cv} PROPERTY TYPE)
|
||||
if(NOT _cv_type STREQUAL "INTERNAL")
|
||||
set(_cv_val "${${_cv}}")
|
||||
string(REPLACE ";" "\\;" _cv_val "${_cv_val}")
|
||||
list(APPEND MACOS_APP_XCODE_FORWARD_ARGS "-D${_cv}:${_cv_type}=${_cv_val}")
|
||||
endif()
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
add_custom_target(${PKMXD_TARGET}_xcode ALL
|
||||
COMMAND cmake -S "${CMAKE_CURRENT_SOURCE_DIR}" -B "${MACOS_APP_XCODE_BUILD_DIR}" -G Xcode
|
||||
-DENABLE_EMULATION=1
|
||||
-DMACOS_APP=1
|
||||
-DMACOS_APP_XCODE_DRIVER=1
|
||||
-DMACOS_APP_BUNDLE_ID="${PKMXD_BUNDLE_ID}"
|
||||
-DMACOS_APP_SIGN_IDENTITY="${PKMXD_SIGN_IDENTITY}"
|
||||
-DMACOS_APP_DEVELOPMENT_TEAM="${PKMXD_DEVELOPMENT_TEAM}"
|
||||
${MACOS_APP_XCODE_FORWARD_ARGS}
|
||||
COMMAND /bin/mkdir -p "${MACOS_APP_XCODE_BUILD_DIR}/Debug/include"
|
||||
COMMAND /bin/mkdir -p "${MACOS_APP_XCODE_BUILD_DIR}/build/pico_novus.build/Debug/DerivedSources-normal/arm64"
|
||||
COMMAND /bin/mkdir -p "${MACOS_APP_XCODE_BUILD_DIR}/build/pico_novus.build/Debug/DerivedSources/arm64"
|
||||
COMMAND /bin/mkdir -p "${MACOS_APP_XCODE_BUILD_DIR}/build/pico_novus.build/Debug/DerivedSources"
|
||||
COMMAND xcodebuild -allowProvisioningUpdates -project "${MACOS_APP_XCODE_BUILD_DIR}/${PKMXD_TARGET}.xcodeproj" -scheme "${PKMXD_TARGET}" -configuration Debug build
|
||||
COMMENT "Building signed ${PKMXD_TARGET}.app via Xcode"
|
||||
VERBATIM
|
||||
)
|
||||
endfunction()
|
||||
|
||||
131
cmake/deps.cmake
Normal file
131
cmake/deps.cmake
Normal file
@@ -0,0 +1,131 @@
|
||||
include(FetchContent)
|
||||
|
||||
option(ENABLE_EDDSA "Enable/disable EdDSA support" OFF)
|
||||
configure_bool_option(
|
||||
ENABLE_EDDSA
|
||||
""
|
||||
"EdDSA support:\t\t enabled"
|
||||
"EdDSA support:\t\t disabled"
|
||||
)
|
||||
|
||||
set(MBEDTLS_PATH "${CMAKE_CURRENT_LIST_DIR}/../third-party/mbedtls")
|
||||
set(TINYCBOR_PATH "${CMAKE_CURRENT_LIST_DIR}/../third-party/tinycbor")
|
||||
set(CJSON_PATH "${CMAKE_CURRENT_LIST_DIR}/../third-party/cjson")
|
||||
set(MLKEM_PATH "${CMAKE_CURRENT_LIST_DIR}/../third-party/mlkem")
|
||||
set(MLDSA_PATH "${CMAKE_CURRENT_LIST_DIR}/../third-party/mldsa")
|
||||
set(LIBCVC_PATH "${CMAKE_CURRENT_LIST_DIR}/../third-party/libcvc")
|
||||
|
||||
set(PICOKEYS_MBEDTLS_STD_REPO "https://github.com/Mbed-TLS/mbedtls.git")
|
||||
set(PICOKEYS_MBEDTLS_STD_REF "v3.6.6")
|
||||
set(PICOKEYS_MBEDTLS_EDDSA_REPO "https://github.com/polhenarejos/mbedtls.git")
|
||||
set(PICOKEYS_MBEDTLS_EDDSA_REF "mbedtls-3.6-eddsa")
|
||||
|
||||
set(PICOKEYS_TINYCBOR_REPO "https://github.com/intel/tinycbor.git")
|
||||
set(PICOKEYS_TINYCBOR_REF "v0.6.1")
|
||||
set(PICOKEYS_CJSON_REPO "https://github.com/DaveGamble/cJSON.git")
|
||||
set(PICOKEYS_CJSON_REF "v1.7.19")
|
||||
set(PICOKEYS_MLKEM_REPO "https://github.com/pq-code-package/mlkem-native.git")
|
||||
set(PICOKEYS_MLKEM_REF "v1.1.0")
|
||||
set(PICOKEYS_MLDSA_REPO "https://github.com/pq-code-package/mldsa-native.git")
|
||||
set(PICOKEYS_MLDSA_REF "v1.0.0-beta")
|
||||
set(PICOKEYS_LIBCVC_REPO "https://github.com/polhenarejos/libcvc.git")
|
||||
set(PICOKEYS_LIBCVC_REF "main")
|
||||
|
||||
set(PICOKEYS_FETCH_DEPS_ON_DEMAND ON CACHE BOOL "Fetch third-party deps into pico-keys-sdk/third-party when missing")
|
||||
|
||||
function(picokeys_sync_dep name repo ref dest)
|
||||
set(_marker "${dest}/.picokeys_dep_source")
|
||||
set(_need_fetch OFF)
|
||||
|
||||
if(NOT EXISTS "${dest}")
|
||||
if(NOT PICOKEYS_FETCH_DEPS_ON_DEMAND)
|
||||
message(FATAL_ERROR "${name} source code not found at ${dest}. Enable PICOKEYS_FETCH_DEPS_ON_DEMAND or provide the source tree manually.")
|
||||
endif()
|
||||
set(_need_fetch ON)
|
||||
else()
|
||||
set(_repo_ok OFF)
|
||||
set(_ref_ok OFF)
|
||||
if(EXISTS "${_marker}")
|
||||
file(STRINGS "${_marker}" _meta_lines)
|
||||
foreach(_line IN LISTS _meta_lines)
|
||||
if(_line STREQUAL "REPO=${repo}")
|
||||
set(_repo_ok ON)
|
||||
endif()
|
||||
if(_line STREQUAL "REF=${ref}")
|
||||
set(_ref_ok ON)
|
||||
endif()
|
||||
endforeach()
|
||||
endif()
|
||||
if(NOT _repo_ok OR NOT _ref_ok)
|
||||
set(_need_fetch ON)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(_need_fetch)
|
||||
message(STATUS "[deps] ${name}: repo=${repo} ref=${ref} status=updating (this may take a few seconds)")
|
||||
if(EXISTS "${dest}")
|
||||
file(REMOVE_RECURSE "${dest}")
|
||||
endif()
|
||||
execute_process(
|
||||
COMMAND git clone ${repo} ${dest}
|
||||
RESULT_VARIABLE _clone_rc
|
||||
OUTPUT_VARIABLE _clone_out
|
||||
ERROR_VARIABLE _clone_err
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
ERROR_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
if(NOT _clone_rc EQUAL 0)
|
||||
message(FATAL_ERROR "Failed to clone ${name} from ${repo}\nstdout: ${_clone_out}\nstderr: ${_clone_err}")
|
||||
endif()
|
||||
execute_process(
|
||||
COMMAND git -C ${dest} checkout ${ref}
|
||||
RESULT_VARIABLE _checkout_rc
|
||||
OUTPUT_VARIABLE _checkout_out
|
||||
ERROR_VARIABLE _checkout_err
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
ERROR_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
if(NOT _checkout_rc EQUAL 0)
|
||||
message(FATAL_ERROR "Failed to checkout ${name} ref ${ref}\nstdout: ${_checkout_out}\nstderr: ${_checkout_err}")
|
||||
endif()
|
||||
if(NOT EXISTS "${dest}")
|
||||
message(FATAL_ERROR "Failed to fetch ${name} into ${dest}")
|
||||
endif()
|
||||
file(WRITE "${_marker}" "REPO=${repo}\nREF=${ref}\n")
|
||||
else()
|
||||
message(STATUS "[deps] ${name}: repo=${repo} ref=${ref} status=cached")
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
if(NOT ESP_PLATFORM)
|
||||
if(ENABLE_EDDSA)
|
||||
set(MBEDTLS_ORIGIN "${PICOKEYS_MBEDTLS_EDDSA_REPO}")
|
||||
set(MBEDTLS_REF "${PICOKEYS_MBEDTLS_EDDSA_REF}")
|
||||
|
||||
add_compile_definitions(
|
||||
MBEDTLS_ECP_DP_ED25519_ENABLED=1
|
||||
MBEDTLS_ECP_DP_ED448_ENABLED=1
|
||||
MBEDTLS_EDDSA_C=1
|
||||
MBEDTLS_SHA3_C=1
|
||||
)
|
||||
else()
|
||||
set(MBEDTLS_ORIGIN "${PICOKEYS_MBEDTLS_STD_REPO}")
|
||||
set(MBEDTLS_REF "${PICOKEYS_MBEDTLS_STD_REF}")
|
||||
endif()
|
||||
|
||||
picokeys_sync_dep(mbedtls_dep "${MBEDTLS_ORIGIN}" "${MBEDTLS_REF}" "${MBEDTLS_PATH}")
|
||||
endif()
|
||||
|
||||
if(USB_ITF_HID)
|
||||
picokeys_sync_dep(tinycbor_dep "${PICOKEYS_TINYCBOR_REPO}" "${PICOKEYS_TINYCBOR_REF}" "${TINYCBOR_PATH}")
|
||||
endif()
|
||||
if(USB_ITF_LWIP)
|
||||
picokeys_sync_dep(cjson_dep "${PICOKEYS_CJSON_REPO}" "${PICOKEYS_CJSON_REF}" "${CJSON_PATH}")
|
||||
endif()
|
||||
if(ENABLE_PQC)
|
||||
picokeys_sync_dep(mlkem_dep "${PICOKEYS_MLKEM_REPO}" "${PICOKEYS_MLKEM_REF}" "${MLKEM_PATH}")
|
||||
picokeys_sync_dep(mldsa_dep "${PICOKEYS_MLDSA_REPO}" "${PICOKEYS_MLDSA_REF}" "${MLDSA_PATH}")
|
||||
endif()
|
||||
if(ENABLE_LIBCVC)
|
||||
picokeys_sync_dep(libcvc_dep "${PICOKEYS_LIBCVC_REPO}" "${PICOKEYS_LIBCVC_REF}" "${LIBCVC_PATH}")
|
||||
endif()
|
||||
@@ -1,4 +1,4 @@
|
||||
function(dict command dict )
|
||||
function(dict command dict)
|
||||
if(command STREQUAL SET)
|
||||
set(arg_key ${ARGV2})
|
||||
set(arg_value ${ARGV3})
|
||||
@@ -10,7 +10,6 @@ function(dict command dict )
|
||||
|
||||
list(APPEND ${dict} "${arg_key}=${arg_value}")
|
||||
set(${dict} "${${dict}}" PARENT_SCOPE)
|
||||
|
||||
elseif(command STREQUAL GET)
|
||||
set(arg_key ${ARGV2})
|
||||
set(arg_outvar ${ARGV3})
|
||||
@@ -23,7 +22,6 @@ function(dict command dict )
|
||||
list(GET ${dict} ${idx} kv)
|
||||
string(REGEX REPLACE "^[^=]+=(.*)" "\\1" value "${kv}")
|
||||
set(${arg_outvar} "${value}" PARENT_SCOPE)
|
||||
|
||||
elseif(command STREQUAL _IDX)
|
||||
set(arg_key ${ARGV2})
|
||||
set(arg_outvar ${ARGV3})
|
||||
@@ -34,10 +32,9 @@ function(dict command dict )
|
||||
set(${arg_outvar} "${idx}" PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
math(EXPR idx ${idx}+1)
|
||||
math(EXPR idx ${idx} + 1)
|
||||
endforeach()
|
||||
set(${arg_outvar} "-1" PARENT_SCOPE)
|
||||
|
||||
else()
|
||||
message(FATAL_ERROR "dict does not recognize sub-command ${command}")
|
||||
endif()
|
||||
|
||||
144
cmake/openssl.cmake
Normal file
144
cmake/openssl.cmake
Normal file
@@ -0,0 +1,144 @@
|
||||
#
|
||||
# OpenSSL wrapper configuration for Pico Keys SDK.
|
||||
# Keeps OpenSSL-specific build logic out of picokeys_sdk_import.cmake.
|
||||
#
|
||||
|
||||
if(NOT DEFINED USE_OPENSSL)
|
||||
set(USE_OPENSSL 0)
|
||||
endif()
|
||||
|
||||
set(SKIP_MBEDTLS_FOR_OPENSSL_EMULATION 0)
|
||||
set(USE_OPENSSL_EMULATION_WRAPPER 0)
|
||||
|
||||
if(ENABLE_EMULATION AND USE_OPENSSL)
|
||||
find_package(OpenSSL QUIET)
|
||||
if(OpenSSL_FOUND)
|
||||
set(SKIP_MBEDTLS_FOR_OPENSSL_EMULATION 1)
|
||||
set(USE_OPENSSL_EMULATION_WRAPPER 1)
|
||||
message(STATUS "OpenSSL backend:\t\t enabled")
|
||||
else()
|
||||
message(STATUS "OpenSSL backend:\t\t disabled (OpenSSL not found)")
|
||||
endif()
|
||||
elseif(ENABLE_EMULATION)
|
||||
message(STATUS "OpenSSL backend:\t\t disabled")
|
||||
endif()
|
||||
|
||||
if(USE_OPENSSL_EMULATION_WRAPPER)
|
||||
add_definitions(
|
||||
-Dmbedtls_platform_zeroize=openssl_mbedtls_platform_zeroize
|
||||
-Dmbedtls_sha256=openssl_mbedtls_sha256
|
||||
-Dmbedtls_sha256_init=openssl_mbedtls_sha256_init
|
||||
-Dmbedtls_sha256_free=openssl_mbedtls_sha256_free
|
||||
-Dmbedtls_sha256_starts=openssl_mbedtls_sha256_starts
|
||||
-Dmbedtls_sha256_update=openssl_mbedtls_sha256_update
|
||||
-Dmbedtls_sha256_finish=openssl_mbedtls_sha256_finish
|
||||
-Dmbedtls_md_info_from_type=openssl_mbedtls_md_info_from_type
|
||||
-Dmbedtls_md_get_size=openssl_mbedtls_md_get_size
|
||||
-Dmbedtls_md=openssl_mbedtls_md
|
||||
-Dmbedtls_md_hmac=openssl_mbedtls_md_hmac
|
||||
-Dmbedtls_md_init=openssl_mbedtls_md_init
|
||||
-Dmbedtls_md_free=openssl_mbedtls_md_free
|
||||
-Dmbedtls_md_setup=openssl_mbedtls_md_setup
|
||||
-Dmbedtls_md_starts=openssl_mbedtls_md_starts
|
||||
-Dmbedtls_md_update=openssl_mbedtls_md_update
|
||||
-Dmbedtls_md_finish=openssl_mbedtls_md_finish
|
||||
-Dmbedtls_hkdf=openssl_mbedtls_hkdf
|
||||
-Dmbedtls_aes_init=openssl_mbedtls_aes_init
|
||||
-Dmbedtls_aes_free=openssl_mbedtls_aes_free
|
||||
-Dmbedtls_aes_setkey_enc=openssl_mbedtls_aes_setkey_enc
|
||||
-Dmbedtls_aes_setkey_dec=openssl_mbedtls_aes_setkey_dec
|
||||
-Dmbedtls_aes_crypt_ecb=openssl_mbedtls_aes_crypt_ecb
|
||||
-Dmbedtls_aes_crypt_cbc=openssl_mbedtls_aes_crypt_cbc
|
||||
-Dmbedtls_aes_crypt_cfb128=openssl_mbedtls_aes_crypt_cfb128
|
||||
-Dmbedtls_aes_crypt_ofb=openssl_mbedtls_aes_crypt_ofb
|
||||
-Dmbedtls_aes_crypt_ctr=openssl_mbedtls_aes_crypt_ctr
|
||||
-Dmbedtls_aes_xts_init=openssl_mbedtls_aes_xts_init
|
||||
-Dmbedtls_aes_xts_free=openssl_mbedtls_aes_xts_free
|
||||
-Dmbedtls_aes_xts_setkey_enc=openssl_mbedtls_aes_xts_setkey_enc
|
||||
-Dmbedtls_aes_xts_setkey_dec=openssl_mbedtls_aes_xts_setkey_dec
|
||||
-Dmbedtls_aes_crypt_xts=openssl_mbedtls_aes_crypt_xts
|
||||
-Dmbedtls_gcm_init=openssl_mbedtls_gcm_init
|
||||
-Dmbedtls_gcm_free=openssl_mbedtls_gcm_free
|
||||
-Dmbedtls_gcm_setkey=openssl_mbedtls_gcm_setkey
|
||||
-Dmbedtls_gcm_crypt_and_tag=openssl_mbedtls_gcm_crypt_and_tag
|
||||
-Dmbedtls_gcm_auth_decrypt=openssl_mbedtls_gcm_auth_decrypt
|
||||
-Dmbedtls_ccm_init=openssl_mbedtls_ccm_init
|
||||
-Dmbedtls_ccm_free=openssl_mbedtls_ccm_free
|
||||
-Dmbedtls_ccm_setkey=openssl_mbedtls_ccm_setkey
|
||||
-Dmbedtls_ccm_encrypt_and_tag=openssl_mbedtls_ccm_encrypt_and_tag
|
||||
-Dmbedtls_ccm_auth_decrypt=openssl_mbedtls_ccm_auth_decrypt
|
||||
-Dmbedtls_chachapoly_init=openssl_mbedtls_chachapoly_init
|
||||
-Dmbedtls_chachapoly_free=openssl_mbedtls_chachapoly_free
|
||||
-Dmbedtls_chachapoly_setkey=openssl_mbedtls_chachapoly_setkey
|
||||
-Dmbedtls_chachapoly_encrypt_and_tag=openssl_mbedtls_chachapoly_encrypt_and_tag
|
||||
-Dmbedtls_chachapoly_auth_decrypt=openssl_mbedtls_chachapoly_auth_decrypt
|
||||
-Dmbedtls_cipher_info_from_type=openssl_mbedtls_cipher_info_from_type
|
||||
-Dmbedtls_cipher_cmac=openssl_mbedtls_cipher_cmac
|
||||
-Dmbedtls_mpi_init=openssl_mbedtls_mpi_init
|
||||
-Dmbedtls_mpi_free=openssl_mbedtls_mpi_free
|
||||
-Dmbedtls_mpi_grow=openssl_mbedtls_mpi_grow
|
||||
-Dmbedtls_mpi_lset=openssl_mbedtls_mpi_lset
|
||||
-Dmbedtls_mpi_size=openssl_mbedtls_mpi_size
|
||||
-Dmbedtls_mpi_read_binary=openssl_mbedtls_mpi_read_binary
|
||||
-Dmbedtls_mpi_read_binary_le=openssl_mbedtls_mpi_read_binary_le
|
||||
-Dmbedtls_mpi_write_binary=openssl_mbedtls_mpi_write_binary
|
||||
-Dmbedtls_mpi_write_binary_le=openssl_mbedtls_mpi_write_binary_le
|
||||
-Dmbedtls_mpi_copy=openssl_mbedtls_mpi_copy
|
||||
-Dmbedtls_mpi_cmp_mpi=openssl_mbedtls_mpi_cmp_mpi
|
||||
-Dmbedtls_mpi_cmp_int=openssl_mbedtls_mpi_cmp_int
|
||||
-Dmbedtls_mpi_add_mpi=openssl_mbedtls_mpi_add_mpi
|
||||
-Dmbedtls_mpi_add_int=openssl_mbedtls_mpi_add_int
|
||||
-Dmbedtls_mpi_sub_abs=openssl_mbedtls_mpi_sub_abs
|
||||
-Dmbedtls_mpi_mod_mpi=openssl_mbedtls_mpi_mod_mpi
|
||||
-Dmbedtls_asn1_get_tag=openssl_mbedtls_asn1_get_tag
|
||||
-Dmbedtls_asn1_get_int=openssl_mbedtls_asn1_get_int
|
||||
-Dmbedtls_asn1_get_alg_null=openssl_mbedtls_asn1_get_alg_null
|
||||
-Dmbedtls_oid_get_md_hmac=openssl_mbedtls_oid_get_md_hmac
|
||||
-Dmbedtls_pkcs5_pbkdf2_hmac_ext=openssl_mbedtls_pkcs5_pbkdf2_hmac_ext
|
||||
-Dmbedtls_pkcs5_pbes2_ext=openssl_mbedtls_pkcs5_pbes2_ext
|
||||
-Dmbedtls_rsa_gen_key=openssl_mbedtls_rsa_gen_key
|
||||
-Dmbedtls_rsa_init=openssl_mbedtls_rsa_init
|
||||
-Dmbedtls_rsa_free=openssl_mbedtls_rsa_free
|
||||
-Dmbedtls_rsa_set_padding=openssl_mbedtls_rsa_set_padding
|
||||
-Dmbedtls_rsa_get_len=openssl_mbedtls_rsa_get_len
|
||||
-Dmbedtls_rsa_import=openssl_mbedtls_rsa_import
|
||||
-Dmbedtls_rsa_complete=openssl_mbedtls_rsa_complete
|
||||
-Dmbedtls_rsa_check_pubkey=openssl_mbedtls_rsa_check_pubkey
|
||||
-Dmbedtls_rsa_check_privkey=openssl_mbedtls_rsa_check_privkey
|
||||
-Dmbedtls_ecp_curve_info_from_grp_id=openssl_mbedtls_ecp_curve_info_from_grp_id
|
||||
-Dmbedtls_ecp_get_type=openssl_mbedtls_ecp_get_type
|
||||
-Dmbedtls_ecp_group_init=openssl_mbedtls_ecp_group_init
|
||||
-Dmbedtls_ecp_group_free=openssl_mbedtls_ecp_group_free
|
||||
-Dmbedtls_ecp_group_load=openssl_mbedtls_ecp_group_load
|
||||
-Dmbedtls_ecp_keypair_init=openssl_mbedtls_ecp_keypair_init
|
||||
-Dmbedtls_ecp_keypair_free=openssl_mbedtls_ecp_keypair_free
|
||||
-Dmbedtls_ecp_gen_key=openssl_mbedtls_ecp_gen_key
|
||||
-Dmbedtls_ecp_mul=openssl_mbedtls_ecp_mul
|
||||
-Dmbedtls_ecp_read_key=openssl_mbedtls_ecp_read_key
|
||||
-Dmbedtls_ecp_write_key_ext=openssl_mbedtls_ecp_write_key_ext
|
||||
-Dmbedtls_ecp_point_read_binary=openssl_mbedtls_ecp_point_read_binary
|
||||
-Dmbedtls_ecp_point_write_binary=openssl_mbedtls_ecp_point_write_binary
|
||||
-Dmbedtls_ecp_point_edwards=openssl_mbedtls_ecp_point_edwards
|
||||
-Dmbedtls_ecp_check_pubkey=openssl_mbedtls_ecp_check_pubkey
|
||||
-Dmbedtls_ecp_check_pub_priv=openssl_mbedtls_ecp_check_pub_priv
|
||||
-Dmbedtls_ecdsa_init=openssl_mbedtls_ecdsa_init
|
||||
-Dmbedtls_ecdsa_free=openssl_mbedtls_ecdsa_free
|
||||
-Dmbedtls_ecdsa_genkey=openssl_mbedtls_ecdsa_genkey
|
||||
-Dmbedtls_rsa_private=openssl_mbedtls_rsa_private
|
||||
-Dmbedtls_rsa_pkcs1_sign=openssl_mbedtls_rsa_pkcs1_sign
|
||||
-Dmbedtls_rsa_rsassa_pkcs1_v15_sign=openssl_mbedtls_rsa_rsassa_pkcs1_v15_sign
|
||||
-Dmbedtls_rsa_pkcs1_verify=openssl_mbedtls_rsa_pkcs1_verify
|
||||
-Dmbedtls_rsa_pkcs1_decrypt=openssl_mbedtls_rsa_pkcs1_decrypt
|
||||
-Dmbedtls_ecdh_init=openssl_mbedtls_ecdh_init
|
||||
-Dmbedtls_ecdh_free=openssl_mbedtls_ecdh_free
|
||||
-Dmbedtls_ecdh_setup=openssl_mbedtls_ecdh_setup
|
||||
-Dmbedtls_ecdh_gen_public=openssl_mbedtls_ecdh_gen_public
|
||||
-Dmbedtls_ecdh_read_public=openssl_mbedtls_ecdh_read_public
|
||||
-Dmbedtls_ecdh_calc_secret=openssl_mbedtls_ecdh_calc_secret
|
||||
-Dmbedtls_ecdsa_sign=openssl_mbedtls_ecdsa_sign
|
||||
-Dmbedtls_ecdsa_verify=openssl_mbedtls_ecdsa_verify
|
||||
-Dmbedtls_ecdsa_write_signature=openssl_mbedtls_ecdsa_write_signature
|
||||
-Dmbedtls_eddsa_sign=openssl_mbedtls_eddsa_sign
|
||||
-Dmbedtls_eddsa_write_signature=openssl_mbedtls_eddsa_write_signature
|
||||
)
|
||||
endif()
|
||||
10
cmake/options.cmake
Normal file
10
cmake/options.cmake
Normal file
@@ -0,0 +1,10 @@
|
||||
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()
|
||||
message(STATUS "${disabled_msg}")
|
||||
endif()
|
||||
endmacro()
|
||||
209
cmake/trusted.cmake
Normal file
209
cmake/trusted.cmake
Normal file
@@ -0,0 +1,209 @@
|
||||
include_guard(GLOBAL)
|
||||
|
||||
function(picokeys_trusted_region_enabled out_var)
|
||||
if(PICO_RP2350)
|
||||
set(${out_var} TRUE PARENT_SCOPE)
|
||||
else()
|
||||
set(${out_var} FALSE PARENT_SCOPE)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
macro(picokeys_init_trusted_config)
|
||||
set(PICOKEYS_TRUSTED_REGION_FLASH_BASE "0x100B0000" CACHE STRING "Fixed flash base for the trusted measurement region on Pico firmware builds")
|
||||
set(PICOKEYS_TRUSTED_STATE_RAM_BASE "0x20070000" CACHE STRING "Fixed RAM base for trusted writable state on Pico firmware builds")
|
||||
|
||||
set(TRUSTED_MBEDTLS_HELPER_SOURCES
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/trusted/trusted_mem.c
|
||||
)
|
||||
endmacro()
|
||||
|
||||
macro(picokeys_resolve_trusted_toolchain)
|
||||
if(CMAKE_C_COMPILER AND PICO_RP2350)
|
||||
set(PICOKEYS_LIBGCC_QUERY_ARGS -print-libgcc-file-name)
|
||||
set(PICOKEYS_LIBGCC_QUERY_ARGS
|
||||
-mthumb
|
||||
-march=armv8-m.main+fp
|
||||
-mfloat-abi=softfp
|
||||
-print-libgcc-file-name
|
||||
)
|
||||
execute_process(
|
||||
COMMAND ${CMAKE_C_COMPILER} ${PICOKEYS_LIBGCC_QUERY_ARGS}
|
||||
OUTPUT_VARIABLE PICOKEYS_LIBGCC
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
function(configure_picokeys_mbedtls_target target_name)
|
||||
picokeys_trusted_region_enabled(enable_trusted_region)
|
||||
if(enable_trusted_region)
|
||||
target_sources(${target_name} PRIVATE ${TRUSTED_MBEDTLS_HELPER_SOURCES})
|
||||
target_compile_definitions(${target_name} PRIVATE
|
||||
MBEDTLS_PLATFORM_ZEROIZE_ALT
|
||||
memset=picokeys_trusted_memset
|
||||
memcpy=picokeys_trusted_memcpy
|
||||
memmove=picokeys_trusted_memmove
|
||||
memcmp=picokeys_trusted_memcmp
|
||||
)
|
||||
target_compile_options(${target_name} PRIVATE -fno-builtin)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
function(configure_picokeys_trusted_mbedtls_target target_name)
|
||||
target_sources(${target_name} PRIVATE ${TRUSTED_MBEDTLS_HELPER_SOURCES})
|
||||
target_compile_definitions(${target_name} PRIVATE
|
||||
MBEDTLS_PLATFORM_ZEROIZE_ALT
|
||||
memset=picokeys_trusted_memset
|
||||
memcpy=picokeys_trusted_memcpy
|
||||
memmove=picokeys_trusted_memmove
|
||||
memcmp=picokeys_trusted_memcmp
|
||||
strlen=picokeys_trusted_strlen
|
||||
strncmp=picokeys_trusted_strncmp
|
||||
strncpy=picokeys_trusted_strncpy
|
||||
strchr=picokeys_trusted_strchr
|
||||
calloc=picokeys_trusted_calloc
|
||||
free=picokeys_trusted_free
|
||||
at_the_end_of_time=picokeys_trusted_at_the_end_of_time
|
||||
pico_sha256_lock=picokeys_trusted_pico_sha256_lock
|
||||
pico_sha256_unlock=picokeys_trusted_pico_sha256_unlock
|
||||
pico_sha256_cleanup=picokeys_trusted_pico_sha256_cleanup
|
||||
pico_sha256_try_start=picokeys_trusted_pico_sha256_try_start
|
||||
pico_sha256_start_blocking_until=picokeys_trusted_pico_sha256_start_blocking_until
|
||||
pico_sha256_update=picokeys_trusted_pico_sha256_update
|
||||
pico_sha256_update_blocking=picokeys_trusted_pico_sha256_update_blocking
|
||||
pico_sha256_finish=picokeys_trusted_pico_sha256_finish
|
||||
)
|
||||
target_compile_options(${target_name} PRIVATE
|
||||
-fno-builtin
|
||||
-ffunction-sections
|
||||
-fdata-sections
|
||||
)
|
||||
if(CMAKE_C_COMPILER_ID STREQUAL "GNU")
|
||||
target_compile_options(${target_name} PRIVATE
|
||||
-fno-tree-loop-distribute-patterns
|
||||
)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
macro(picokeys_setup_trusted_mbedtls)
|
||||
if(NOT SKIP_MBEDTLS_FOR_OPENSSL_EMULATION AND PICO_PLATFORM AND PICO_RP2350 AND NOT ENABLE_EMULATION)
|
||||
add_library(trusted_mbedtls_build STATIC ${MBEDTLS_SOURCES})
|
||||
target_include_directories(trusted_mbedtls_build SYSTEM PUBLIC
|
||||
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/include
|
||||
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library
|
||||
)
|
||||
configure_picokeys_trusted_mbedtls_target(trusted_mbedtls_build)
|
||||
set(TRUSTED_MBEDTLS_ARCHIVE ${CMAKE_CURRENT_BINARY_DIR}/libtrusted_mbedtls.a)
|
||||
set(TRUSTED_LIBGCC_DIR ${CMAKE_CURRENT_BINARY_DIR}/trusted_libgcc)
|
||||
add_custom_command(
|
||||
OUTPUT ${TRUSTED_MBEDTLS_ARCHIVE}
|
||||
COMMAND ${CMAKE_COMMAND} -E rm -f ${TRUSTED_MBEDTLS_ARCHIVE}
|
||||
COMMAND ${CMAKE_COMMAND} -E rm -rf ${TRUSTED_LIBGCC_DIR}
|
||||
COMMAND ${CMAKE_COMMAND} -E make_directory ${TRUSTED_LIBGCC_DIR}
|
||||
COMMAND ${CMAKE_OBJCOPY}
|
||||
--prefix-alloc-sections=.trusted
|
||||
--redefine-sym memset=picokeys_trusted_memset
|
||||
--redefine-sym mbedtls_sha256_init=picokeys_trusted_sha256_init
|
||||
--redefine-sym mbedtls_sha256_free=picokeys_trusted_sha256_free
|
||||
--redefine-sym mbedtls_sha256_starts=picokeys_trusted_sha256_starts
|
||||
--redefine-sym mbedtls_sha256_update=picokeys_trusted_sha256_update
|
||||
--redefine-sym mbedtls_sha256_finish=picokeys_trusted_sha256_finish
|
||||
--redefine-sym mbedtls_sha256_clone=picokeys_trusted_sha256_clone
|
||||
--redefine-sym __aeabi_uldivmod=picokeys_trusted___aeabi_uldivmod
|
||||
$<TARGET_FILE:trusted_mbedtls_build>
|
||||
${TRUSTED_MBEDTLS_ARCHIVE}
|
||||
COMMAND ${CMAKE_COMMAND} -E chdir ${TRUSTED_LIBGCC_DIR}
|
||||
${CMAKE_AR} x ${PICOKEYS_LIBGCC}
|
||||
_aeabi_uldivmod.o
|
||||
_udivmoddi4.o
|
||||
_dvmd_tls.o
|
||||
COMMAND ${CMAKE_OBJCOPY}
|
||||
--prefix-alloc-sections=.trusted
|
||||
--redefine-sym __aeabi_uldivmod=picokeys_trusted___aeabi_uldivmod
|
||||
--redefine-sym __udivmoddi4=picokeys_trusted___udivmoddi4
|
||||
--redefine-sym __aeabi_idiv0=picokeys_trusted___aeabi_idiv0
|
||||
${TRUSTED_LIBGCC_DIR}/_aeabi_uldivmod.o
|
||||
${TRUSTED_LIBGCC_DIR}/_aeabi_uldivmod.trusted.o
|
||||
COMMAND ${CMAKE_OBJCOPY}
|
||||
--prefix-alloc-sections=.trusted
|
||||
--redefine-sym __udivmoddi4=picokeys_trusted___udivmoddi4
|
||||
${TRUSTED_LIBGCC_DIR}/_udivmoddi4.o
|
||||
${TRUSTED_LIBGCC_DIR}/_udivmoddi4.trusted.o
|
||||
COMMAND ${CMAKE_OBJCOPY}
|
||||
--prefix-alloc-sections=.trusted
|
||||
--redefine-sym __aeabi_idiv0=picokeys_trusted___aeabi_idiv0
|
||||
${TRUSTED_LIBGCC_DIR}/_dvmd_tls.o
|
||||
${TRUSTED_LIBGCC_DIR}/_dvmd_tls.trusted.o
|
||||
COMMAND ${CMAKE_AR} q ${TRUSTED_MBEDTLS_ARCHIVE}
|
||||
${TRUSTED_LIBGCC_DIR}/_aeabi_uldivmod.trusted.o
|
||||
${TRUSTED_LIBGCC_DIR}/_udivmoddi4.trusted.o
|
||||
${TRUSTED_LIBGCC_DIR}/_dvmd_tls.trusted.o
|
||||
COMMAND ${CMAKE_RANLIB} ${TRUSTED_MBEDTLS_ARCHIVE}
|
||||
DEPENDS trusted_mbedtls_build
|
||||
VERBATIM
|
||||
)
|
||||
add_custom_target(trusted_mbedtls_archive DEPENDS ${TRUSTED_MBEDTLS_ARCHIVE})
|
||||
add_library(trusted_mbedtls STATIC IMPORTED GLOBAL)
|
||||
add_dependencies(trusted_mbedtls trusted_mbedtls_archive)
|
||||
set_target_properties(trusted_mbedtls PROPERTIES
|
||||
IMPORTED_LOCATION ${TRUSTED_MBEDTLS_ARCHIVE}
|
||||
)
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
macro(picokeys_configure_trusted_support_sources)
|
||||
picokeys_trusted_region_enabled(enable_trusted_region)
|
||||
if(enable_trusted_region)
|
||||
if(CMAKE_C_COMPILER_ID STREQUAL "GNU")
|
||||
set_source_files_properties(${CMAKE_CURRENT_LIST_DIR}/src/trusted/trusted_mem.c PROPERTIES
|
||||
COMPILE_OPTIONS "-fno-builtin;-fno-tree-loop-distribute-patterns"
|
||||
)
|
||||
else()
|
||||
set_source_files_properties(${CMAKE_CURRENT_LIST_DIR}/src/trusted/trusted_mem.c PROPERTIES
|
||||
COMPILE_OPTIONS "-fno-builtin"
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
if(DEFINED TRUSTED_REGION_EMBED_SOURCE)
|
||||
set_source_files_properties(${TRUSTED_REGION_EMBED_SOURCE} PROPERTIES
|
||||
OBJECT_DEPENDS "${TRUSTED_REGION_EMBED_INPUT}"
|
||||
)
|
||||
list(APPEND PICOKEYS_SOURCES
|
||||
${TRUSTED_REGION_EMBED_SOURCE}
|
||||
)
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
macro(picokeys_configure_rp2350_trusted)
|
||||
if(TARGET trusted_mbedtls_build)
|
||||
target_include_directories(trusted_mbedtls_build PRIVATE
|
||||
${CMAKE_CURRENT_LIST_DIR}/config/rp2350/alt
|
||||
)
|
||||
target_include_directories(${CMAKE_PROJECT_NAME} PUBLIC
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/trusted
|
||||
)
|
||||
target_sources(trusted_mbedtls_build PRIVATE
|
||||
${CMAKE_CURRENT_LIST_DIR}/config/rp2350/alt/sha256_alt.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/trusted/trusted_pico_sha256.c
|
||||
)
|
||||
target_link_libraries(trusted_mbedtls_build PRIVATE
|
||||
pico_sha256_headers
|
||||
pico_bootrom_headers
|
||||
pico_time_headers
|
||||
)
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
macro(picokeys_link_trusted_region target_name)
|
||||
if(TARGET trusted_mbedtls)
|
||||
target_link_options(${target_name} PRIVATE
|
||||
"LINKER:--defsym=__trusted_region_fixed_base=${PICOKEYS_TRUSTED_REGION_FLASH_BASE}"
|
||||
"LINKER:-T,${CMAKE_CURRENT_LIST_DIR}/config/rp2350/ld/trusted_region.ld"
|
||||
"LINKER:-T,${CMAKE_CURRENT_LIST_DIR}/config/rp2350/ld/trusted_state.ld"
|
||||
)
|
||||
set_property(TARGET ${target_name} APPEND PROPERTY LINK_DEPENDS
|
||||
${CMAKE_CURRENT_LIST_DIR}/config/rp2350/ld/trusted_region.ld
|
||||
${CMAKE_CURRENT_LIST_DIR}/config/rp2350/ld/trusted_state.ld
|
||||
)
|
||||
endif()
|
||||
endmacro()
|
||||
@@ -1,39 +1,39 @@
|
||||
|
||||
macro(HEXCHAR2DEC VAR VAL)
|
||||
if(${VAL} MATCHES "[0-9]")
|
||||
SET(${VAR} ${VAL})
|
||||
set(${VAR} ${VAL})
|
||||
elseif(${VAL} MATCHES "[aA]")
|
||||
SET(${VAR} 10)
|
||||
set(${VAR} 10)
|
||||
elseif(${VAL} MATCHES "[bB]")
|
||||
SET(${VAR} 11)
|
||||
set(${VAR} 11)
|
||||
elseif(${VAL} MATCHES "[cC]")
|
||||
SET(${VAR} 12)
|
||||
set(${VAR} 12)
|
||||
elseif(${VAL} MATCHES "[dD]")
|
||||
SET(${VAR} 13)
|
||||
set(${VAR} 13)
|
||||
elseif(${VAL} MATCHES "[eE]")
|
||||
SET(${VAR} 14)
|
||||
set(${VAR} 14)
|
||||
elseif(${VAL} MATCHES "[fF]")
|
||||
SET(${VAR} 15)
|
||||
set(${VAR} 15)
|
||||
else()
|
||||
MESSAGE(FATAL_ERROR "Invalid format for hexidecimal character")
|
||||
message(FATAL_ERROR "Invalid format for hexidecimal character")
|
||||
endif()
|
||||
endmacro(HEXCHAR2DEC)
|
||||
endmacro()
|
||||
|
||||
macro(HEX2DEC VAR VAL)
|
||||
SET(CURINDEX 0)
|
||||
STRING(LENGTH "${VAL}" CURLENGTH)
|
||||
SET(${VAR} 0)
|
||||
set(CURINDEX 0)
|
||||
string(LENGTH "${VAL}" CURLENGTH)
|
||||
set(${VAR} 0)
|
||||
while(CURINDEX LESS CURLENGTH)
|
||||
STRING(SUBSTRING "${VAL}" ${CURINDEX} 1 CHAR)
|
||||
string(SUBSTRING "${VAL}" ${CURINDEX} 1 CHAR)
|
||||
HEXCHAR2DEC(CHAR ${CHAR})
|
||||
MATH(EXPR POWAH "(1<<((${CURLENGTH}-${CURINDEX}-1)*4))")
|
||||
MATH(EXPR CHAR "(${CHAR}*${POWAH})")
|
||||
MATH(EXPR ${VAR} "${${VAR}}+${CHAR}")
|
||||
MATH(EXPR CURINDEX "${CURINDEX}+1")
|
||||
math(EXPR POWAH "(1 << ((${CURLENGTH} - ${CURINDEX} - 1) * 4))")
|
||||
math(EXPR CHAR "(${CHAR} * ${POWAH})")
|
||||
math(EXPR ${VAR} "${${VAR}} + ${CHAR}")
|
||||
math(EXPR CURINDEX "${CURINDEX} + 1")
|
||||
endwhile()
|
||||
endmacro(HEX2DEC)
|
||||
endmacro()
|
||||
|
||||
macro(SET_VERSION MAJOR MINOR FILE ROLLBACK)
|
||||
macro(SET_VERSION MAJOR MINOR FILE)
|
||||
set(ROLLBACK 4)
|
||||
file(READ ${FILE} ver)
|
||||
string(REGEX MATCHALL "0x([0-9A-F])([0-9A-F])([0-9A-F])([0-9A-F])" _ ${ver})
|
||||
string(CONCAT ver_major ${CMAKE_MATCH_1}${CMAKE_MATCH_2})
|
||||
@@ -42,13 +42,22 @@ macro(SET_VERSION MAJOR MINOR FILE ROLLBACK)
|
||||
HEX2DEC(ver_minor ${ver_minor})
|
||||
message(STATUS "Found version:\t\t ${ver_major}.${ver_minor}")
|
||||
if(PICO_PLATFORM)
|
||||
if (PICO_RP2350 AND SECURE_BOOT_PKEY)
|
||||
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})
|
||||
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})
|
||||
pico_set_binary_version(
|
||||
${CMAKE_PROJECT_NAME}
|
||||
MAJOR ${ver_major}
|
||||
MINOR ${ver_minor}
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
set(${MAJOR} ${ver_major})
|
||||
set(${MINOR} ${ver_minor})
|
||||
endmacro(SET_VERSION)
|
||||
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
|
||||
)
|
||||
@@ -1,4 +1,4 @@
|
||||
set(MLKEM_DIR ${CMAKE_CURRENT_LIST_DIR}/../../../../mlkem/mlkem)
|
||||
set(MLKEM_DIR ${CMAKE_CURRENT_LIST_DIR}/../../../../third-party/mlkem/mlkem)
|
||||
|
||||
file(GLOB_RECURSE MLKEM_SOURCES
|
||||
${MLKEM_DIR}/src/*.c
|
||||
@@ -9,6 +9,7 @@ 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
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
set(MLKEM_DIR ${CMAKE_CURRENT_LIST_DIR}/../../../../mlkem/mlkem)
|
||||
set(MLKEM_DIR ${CMAKE_CURRENT_LIST_DIR}/../../../../third-party/mlkem/mlkem)
|
||||
|
||||
file(GLOB_RECURSE MLKEM_SOURCES
|
||||
${MLKEM_DIR}/src/*.c
|
||||
@@ -9,6 +9,7 @@ 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
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
set(MLKEM_DIR ${CMAKE_CURRENT_LIST_DIR}/../../../../mlkem/mlkem)
|
||||
set(MLKEM_DIR ${CMAKE_CURRENT_LIST_DIR}/../../../../third-party/mlkem/mlkem)
|
||||
|
||||
file(GLOB_RECURSE MLKEM_SOURCES
|
||||
${MLKEM_DIR}/src/*.c
|
||||
@@ -9,6 +9,7 @@ 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
|
||||
|
||||
@@ -1,7 +1,46 @@
|
||||
set(PICO_KEYS_SDK_DIR ${CMAKE_CURRENT_LIST_DIR}/../../../..)
|
||||
idf_component_register(
|
||||
SRCS ${PICO_KEYS_SOURCES}
|
||||
INCLUDE_DIRS ${PICO_KEYS_SDK_DIR}/src ${PICO_KEYS_SDK_DIR}/src/fs ${PICO_KEYS_SDK_DIR}/src/rng ${PICO_KEYS_SDK_DIR}/src/usb ${PICO_KEYS_SDK_DIR}/src/led ${PICO_KEYS_SDK_DIR}/tinycbor/src ${PICO_KEYS_SDK_DIR}/mlkem/mlkem ${PICO_KEYS_SDK_DIR}/config/mlkem
|
||||
REQUIRES bootloader_support esp_partition esp_tinyusb efuse mbedtls mlkem512 mlkem768 mlkem1024 tinycbor
|
||||
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,6 +1,8 @@
|
||||
set(PICO_KEYS_SDK_DIR ${CMAKE_CURRENT_LIST_DIR}/../../../..)
|
||||
set(PICOKEYS_SDK_DIR ${CMAKE_CURRENT_LIST_DIR}/../../../..)
|
||||
|
||||
idf_component_register(
|
||||
SRCS ${CBOR_SOURCES}
|
||||
INCLUDE_DIRS ${PICO_KEYS_SDK_DIR}/tinycbor/src
|
||||
INCLUDE_DIRS ${PICOKEYS_SDK_DIR}/third-party/tinycbor/src
|
||||
)
|
||||
|
||||
idf_component_set_property(${COMPONENT_NAME} WHOLE_ARCHIVE ON)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Name, Type, SubType, Offset, Size, Flags
|
||||
# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap
|
||||
|
||||
nvs, data, nvs, 0x9000, 0x6000
|
||||
phy_init, data, phy, 0xf000, 0x1000
|
||||
factory, app, factory, 0x10000, 1M,
|
||||
nvs, data, nvs, 0x11000, 0x6000
|
||||
phy_init, data, phy, 0x17000, 0x1000
|
||||
factory, app, factory, 0x20000, 1M
|
||||
part0, 0x40, 0x1, 0x200000, 1M,
|
||||
|
||||
|
@@ -1276,7 +1276,7 @@
|
||||
*
|
||||
* Enable the checkup functions (*_self_test).
|
||||
*/
|
||||
#define MBEDTLS_SELF_TEST
|
||||
//#define MBEDTLS_SELF_TEST
|
||||
|
||||
/**
|
||||
* \def MBEDTLS_SHA256_SMALLER
|
||||
|
||||
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
|
||||
32
config/rp2350/ld/trusted_region.ld
Normal file
32
config/rp2350/ld/trusted_region.ld
Normal file
@@ -0,0 +1,32 @@
|
||||
SECTIONS
|
||||
{
|
||||
__trusted_region_min_flash_base = ALIGN(LOADADDR(.flash_end) + SIZEOF(.flash_end), 16);
|
||||
__trusted_region_flash_base = DEFINED(__trusted_region_fixed_base) ?
|
||||
__trusted_region_fixed_base :
|
||||
__trusted_region_min_flash_base;
|
||||
|
||||
.trusted_region __trusted_region_flash_base :
|
||||
{
|
||||
. = ALIGN(16);
|
||||
__trusted_start = .;
|
||||
|
||||
libtrusted_mbedtls.a:(.trusted.text .trusted.text.* .trusted.gnu.linkonce.t.*)
|
||||
|
||||
. = ALIGN(16);
|
||||
libtrusted_mbedtls.a:(.trusted.rodata .trusted.rodata.* .trusted.srodata .trusted.srodata.* .trusted.gnu.linkonce.r.*)
|
||||
|
||||
. = ALIGN(16);
|
||||
__trusted_end = .;
|
||||
}
|
||||
|
||||
__trusted_load_start = LOADADDR(.trusted_region);
|
||||
__trusted_load_end = LOADADDR(.trusted_region) + SIZEOF(.trusted_region);
|
||||
__flash_binary_end = __trusted_end;
|
||||
}
|
||||
|
||||
ASSERT(__trusted_end >= __trusted_start, "trusted region symbols are invalid")
|
||||
ASSERT(!DEFINED(__trusted_region_fixed_base) ||
|
||||
(__trusted_region_fixed_base >= __trusted_region_min_flash_base),
|
||||
"PICOKEYS_TRUSTED_REGION_FLASH_BASE is below the end of the regular flash image")
|
||||
|
||||
INSERT AFTER .flash_end;
|
||||
29
config/rp2350/ld/trusted_state.ld
Normal file
29
config/rp2350/ld/trusted_state.ld
Normal file
@@ -0,0 +1,29 @@
|
||||
SECTIONS
|
||||
{
|
||||
__trusted_state_ram_base = DEFINED(__trusted_state_fixed_base) ?
|
||||
__trusted_state_fixed_base :
|
||||
0x20070000;
|
||||
.trusted_data __trusted_state_ram_base : AT (ALIGN(__trusted_load_end, 16))
|
||||
{
|
||||
. = ALIGN(16);
|
||||
__trusted_data_start = .;
|
||||
libtrusted_mbedtls.a:(.trusted.data .trusted.data.*)
|
||||
. = ALIGN(16);
|
||||
__trusted_data_end = .;
|
||||
}
|
||||
__trusted_data_load_start = LOADADDR(.trusted_data);
|
||||
__trusted_data_load_end = LOADADDR(.trusted_data) + SIZEOF(.trusted_data);
|
||||
.trusted_bss ALIGN(__trusted_data_end, 16) (NOLOAD) :
|
||||
{
|
||||
. = ALIGN(16);
|
||||
__trusted_bss_start = .;
|
||||
libtrusted_mbedtls.a:(.trusted.bss .trusted.bss.*)
|
||||
. = ALIGN(16);
|
||||
__trusted_bss_end = .;
|
||||
}
|
||||
}
|
||||
ASSERT(__trusted_bss_end >= __trusted_data_start, "trusted state symbols are invalid")
|
||||
ASSERT(__trusted_state_ram_base >= 0x20000000, "trusted state RAM base is below RP2350 SRAM")
|
||||
ASSERT(__trusted_bss_end <= 0x20080000, "trusted state exceeds RP2350 main SRAM window")
|
||||
INSERT AFTER .trusted_region;
|
||||
|
||||
1
mbedtls
1
mbedtls
Submodule mbedtls deleted from 107ea89daa
1
mlkem
1
mlkem
Submodule mlkem deleted from 1453da5cd1
@@ -1,552 +0,0 @@
|
||||
#
|
||||
# This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
|
||||
# Copyright (c) 2022 Pol Henarejos.
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, version 3.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
include(pico-keys-sdk/cmake/version.cmake OPTIONAL)
|
||||
|
||||
option(VIDPID "Set specific VID/PID from a known platform {NitroHSM, NitroFIDO2, NitroStart, NitroPro, Nitro3, Yubikey5, YubikeyNeo, YubiHSM, Gnuk, GnuPG}" "None")
|
||||
|
||||
message(STATUS "VIDPID:\t\t\t '${VIDPID}'")
|
||||
|
||||
if(VIDPID STREQUAL "NitroHSM")
|
||||
set(USB_VID 0x20A0)
|
||||
set(USB_PID 0x4230)
|
||||
elseif(VIDPID STREQUAL "NitroFIDO2")
|
||||
set(USB_VID 0x20A0)
|
||||
set(USB_PID 0x42B1)
|
||||
elseif(VIDPID STREQUAL "NitroStart")
|
||||
set(USB_VID 0x20A0)
|
||||
set(USB_PID 0x4211)
|
||||
elseif(VIDPID STREQUAL "NitroPro")
|
||||
set(USB_VID 0x20A0)
|
||||
set(USB_PID 0x4108)
|
||||
|
||||
elseif(VIDPID STREQUAL "Nitro3")
|
||||
set(USB_VID 0x20A0)
|
||||
set(USB_PID 0x42B2)
|
||||
elseif(VIDPID STREQUAL "Yubikey5")
|
||||
set(USB_VID 0x1050)
|
||||
set(USB_PID 0x0407)
|
||||
elseif(VIDPID STREQUAL "YubikeyNeo")
|
||||
set(USB_VID 0x1050)
|
||||
set(USB_PID 0x0116)
|
||||
elseif(VIDPID STREQUAL "YubiHSM")
|
||||
set(USB_VID 0x1050)
|
||||
set(USB_PID 0x0030)
|
||||
elseif(VIDPID STREQUAL "Gnuk")
|
||||
set(USB_VID 0x234B)
|
||||
set(USB_PID 0x0000)
|
||||
elseif(VIDPID STREQUAL "GnuPG")
|
||||
set(USB_VID 0x1209)
|
||||
set(USB_PID 0x2440)
|
||||
endif()
|
||||
|
||||
if(ESP_PLATFORM)
|
||||
if(DEFINED CONFIG_TINYUSB_DESC_CUSTOM_VID)
|
||||
set(USB_VID CONFIG_TINYUSB_DESC_CUSTOM_VID)
|
||||
endif()
|
||||
if(DEFINED CONFIG_TINYUSB_DESC_CUSTOM_PID)
|
||||
set(USB_PID CONFIG_TINYUSB_DESC_CUSTOM_PID)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED USB_VID)
|
||||
set(USB_VID 0x2E8A)
|
||||
endif()
|
||||
add_definitions(-DUSB_VID=${USB_VID})
|
||||
|
||||
if(NOT DEFINED USB_PID)
|
||||
set(USB_PID 0x10FD)
|
||||
endif()
|
||||
add_definitions(-DUSB_PID=${USB_PID})
|
||||
|
||||
if(NOT DEFINED DEBUG_APDU)
|
||||
set(DEBUG_APDU 0)
|
||||
endif()
|
||||
if(NOT DEFINED ENABLE_EMULATION)
|
||||
set(ENABLE_EMULATION 0)
|
||||
endif()
|
||||
|
||||
option(ENABLE_DELAYED_BOOT "Enable/disable delayed boot" OFF)
|
||||
if(ENABLE_DELAYED_BOOT)
|
||||
add_definitions(-DPICO_XOSC_STARTUP_DELAY_MULTIPLIER=64)
|
||||
message(STATUS "Delayed boot:\t\t enabled")
|
||||
else()
|
||||
message(STATUS "Delayed boot:\t\t disabled")
|
||||
endif(ENABLE_DELAYED_BOOT)
|
||||
if(USB_ITF_HID)
|
||||
add_definitions(-DUSB_ITF_HID=1)
|
||||
message(STATUS "USB HID Interface:\t\t enabled")
|
||||
endif(USB_ITF_HID)
|
||||
if(USB_ITF_CCID)
|
||||
add_definitions(-DUSB_ITF_CCID=1)
|
||||
message(STATUS "USB CCID Interface:\t\t enabled")
|
||||
if(USB_ITF_WCID)
|
||||
add_definitions(-DUSB_ITF_WCID=1)
|
||||
message(STATUS "USB WebCCID Interface:\t enabled")
|
||||
endif(USB_ITF_WCID)
|
||||
endif(USB_ITF_CCID)
|
||||
add_definitions(-DDEBUG_APDU=${DEBUG_APDU})
|
||||
if(NOT ESP_PLATFORM)
|
||||
add_definitions(-DMBEDTLS_CONFIG_FILE="${CMAKE_CURRENT_LIST_DIR}/config/mbedtls_config.h")
|
||||
else()
|
||||
add_definitions(-DCFG_TUSB_CONFIG_FILE="${CMAKE_CURRENT_LIST_DIR}/src/usb/tusb_config.h")
|
||||
endif()
|
||||
|
||||
message(STATUS "USB VID/PID:\t\t\t ${USB_VID}:${USB_PID}")
|
||||
|
||||
if(NOT ESP_PLATFORM)
|
||||
set(NEED_UPDATE OFF)
|
||||
|
||||
option(ENABLE_EDDSA "Enable/disable EdDSA support" OFF)
|
||||
if(ENABLE_EDDSA)
|
||||
message(STATUS "EdDSA support:\t\t enabled")
|
||||
else()
|
||||
message(STATUS "EdDSA support:\t\t disabled")
|
||||
endif(ENABLE_EDDSA)
|
||||
|
||||
set(MBEDTLS_PATH "${CMAKE_SOURCE_DIR}/pico-keys-sdk/mbedtls")
|
||||
execute_process(
|
||||
COMMAND git config --global --add safe.directory ${MBEDTLS_PATH}
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||
OUTPUT_QUIET ERROR_QUIET
|
||||
)
|
||||
|
||||
if(ENABLE_EDDSA)
|
||||
set(MBEDTLS_ORIGIN "https://github.com/polhenarejos/mbedtls.git")
|
||||
set(MBEDTLS_REF "mbedtls-3.6-eddsa")
|
||||
|
||||
execute_process(
|
||||
COMMAND git -C ${MBEDTLS_PATH} symbolic-ref --quiet --short HEAD
|
||||
OUTPUT_VARIABLE CURRENT_BRANCH
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
RESULT_VARIABLE BRANCH_ERR
|
||||
)
|
||||
|
||||
message(STATUS "Current branch for mbedTLS: ${CURRENT_BRANCH}")
|
||||
message(STATUS "Target branch for mbedTLS: ${MBEDTLS_REF}")
|
||||
|
||||
if(NOT BRANCH_ERR EQUAL 0 OR NOT "${CURRENT_BRANCH}" STREQUAL "${MBEDTLS_REF}")
|
||||
set(NEED_UPDATE ON)
|
||||
else()
|
||||
set(NEED_UPDATE OFF)
|
||||
endif()
|
||||
|
||||
add_definitions(-DMBEDTLS_ECP_DP_ED25519_ENABLED=1 -DMBEDTLS_ECP_DP_ED448_ENABLED=1 -DMBEDTLS_EDDSA_C=1 -DMBEDTLS_SHA3_C=1)
|
||||
|
||||
else()
|
||||
set(MBEDTLS_ORIGIN "https://github.com/Mbed-TLS/mbedtls.git")
|
||||
set(MBEDTLS_REF "v3.6.5")
|
||||
|
||||
execute_process(
|
||||
COMMAND git -C ${MBEDTLS_PATH} describe --tags --exact-match
|
||||
OUTPUT_VARIABLE CURRENT_TAG
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
RESULT_VARIABLE TAG_ERR
|
||||
)
|
||||
|
||||
message(STATUS "Current tag for mbedTLS: ${CURRENT_TAG}")
|
||||
message(STATUS "Target tag for mbedTLS: ${MBEDTLS_REF}")
|
||||
|
||||
if(NOT TAG_ERR EQUAL 0 OR NOT "${CURRENT_TAG}" STREQUAL "${MBEDTLS_REF}")
|
||||
set(NEED_UPDATE ON)
|
||||
else()
|
||||
set(NEED_UPDATE OFF)
|
||||
endif()
|
||||
|
||||
endif()
|
||||
|
||||
if(NEED_UPDATE)
|
||||
message(STATUS "Updating mbedTLS source code...")
|
||||
|
||||
execute_process(
|
||||
COMMAND git -C ${MBEDTLS_PATH} submodule update --init --recursive --remote pico-keys-sdk
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||
OUTPUT_QUIET ERROR_QUIET
|
||||
)
|
||||
|
||||
execute_process(
|
||||
COMMAND git -C ${MBEDTLS_PATH} remote set-url origin ${MBEDTLS_ORIGIN}
|
||||
OUTPUT_QUIET ERROR_QUIET
|
||||
)
|
||||
|
||||
execute_process(
|
||||
COMMAND git -C ${MBEDTLS_PATH} fetch origin +refs/heads/*:refs/remotes/origin/* --tags --force
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||
OUTPUT_QUIET ERROR_QUIET
|
||||
)
|
||||
|
||||
execute_process(
|
||||
COMMAND rm -rf ${MBEDTLS_PATH}/framework
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||
OUTPUT_QUIET ERROR_QUIET
|
||||
)
|
||||
|
||||
if(ENABLE_EDDSA)
|
||||
execute_process(
|
||||
COMMAND git -C ${MBEDTLS_PATH} checkout -B ${MBEDTLS_REF} --track origin/${MBEDTLS_REF}
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||
OUTPUT_QUIET ERROR_QUIET
|
||||
)
|
||||
else()
|
||||
execute_process(
|
||||
COMMAND git -C ${MBEDTLS_PATH} checkout ${MBEDTLS_REF}
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||
OUTPUT_QUIET ERROR_QUIET
|
||||
)
|
||||
endif()
|
||||
else()
|
||||
message(STATUS "mbedTLS source code is up to date.")
|
||||
endif()
|
||||
endif(NOT ESP_PLATFORM)
|
||||
|
||||
option(ENABLE_PQC "Enable/disable PQC support" OFF)
|
||||
if(ENABLE_PQC)
|
||||
message(STATUS "PQC support:\t\t\t enabled")
|
||||
add_definitions(-DENABLE_PQC)
|
||||
else()
|
||||
message(STATUS "PQC support:\t\t\t disabled")
|
||||
endif(ENABLE_PQC)
|
||||
|
||||
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.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/base64.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/pem.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()
|
||||
|
||||
if(ENABLE_PQC)
|
||||
if (NOT ESP_PLATFORM)
|
||||
file(GLOB_RECURSE MLKEM_SOURCES
|
||||
${CMAKE_CURRENT_LIST_DIR}/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}/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}/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}/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
|
||||
)
|
||||
endif()
|
||||
|
||||
set(INCLUDES ${INCLUDES}
|
||||
${CMAKE_CURRENT_LIST_DIR}/mlkem/mlkem
|
||||
${CMAKE_CURRENT_LIST_DIR}/config/mlkem
|
||||
)
|
||||
add_definitions(-DMLK_CONFIG_NAMESPACE_PREFIX=mlkem -DMLK_CONFIG_MULTILEVEL_BUILD=1)
|
||||
endif()
|
||||
|
||||
set(PICO_KEYS_SOURCES ${PICO_KEYS_SOURCES}
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/main.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/usb/usb.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/fs/file.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/fs/flash.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/fs/low_flash.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/fs/otp.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/fs/phy.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/rng/random.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/rng/hwrng.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/eac.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/crypto_utils.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/asn1.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/apdu.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/rescue.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/led/led.c
|
||||
)
|
||||
|
||||
if(ESP_PLATFORM)
|
||||
set(PICO_KEYS_SOURCES ${PICO_KEYS_SOURCES} ${CMAKE_CURRENT_LIST_DIR}/src/led/led_neopixel.c)
|
||||
else()
|
||||
if (NOT ENABLE_EMULATION)
|
||||
set(PICO_KEYS_SOURCES ${PICO_KEYS_SOURCES}
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/led/led_cyw43.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/led/led_pico.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/led/led_pimoroni.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/led/led_ws2812.c
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
## mbedTLS reports an stringop overflow for cmac.c
|
||||
if(NOT ENABLE_EMULATION AND NOT APPLE)
|
||||
set_source_files_properties(
|
||||
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/cmac.c
|
||||
PROPERTIES
|
||||
COMPILE_FLAGS "-Wno-error=stringop-overflow= -Wno-stringop-overflow"
|
||||
)
|
||||
endif()
|
||||
set(INCLUDES ${INCLUDES}
|
||||
${CMAKE_CURRENT_LIST_DIR}/src
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/usb
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/fs
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/rng
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/led
|
||||
${CMAKE_CURRENT_LIST_DIR}/mbedtls/include
|
||||
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library
|
||||
)
|
||||
|
||||
if(USB_ITF_HID)
|
||||
set(MBEDTLS_SOURCES ${MBEDTLS_SOURCES}
|
||||
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/x509write_crt.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/x509_create.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/x509write_csr.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/pk.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/pk_wrap.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/pkwrite.c
|
||||
)
|
||||
|
||||
endif()
|
||||
|
||||
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
|
||||
)
|
||||
set(LIBRARIES
|
||||
mbedtls
|
||||
)
|
||||
|
||||
if (NOT ESP_PLATFORM)
|
||||
add_library(mbedtls STATIC ${MBEDTLS_SOURCES})
|
||||
target_include_directories(mbedtls PUBLIC ${CMAKE_CURRENT_LIST_DIR}/mbedtls/include)
|
||||
if(USB_ITF_HID)
|
||||
add_library(tinycbor STATIC ${CBOR_SOURCES})
|
||||
target_include_directories(tinycbor PUBLIC ${CMAKE_CURRENT_LIST_DIR}/tinycbor/src)
|
||||
set(LIBRARIES ${LIBRARIES} tinycbor)
|
||||
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
|
||||
)
|
||||
endif()
|
||||
|
||||
if (ENABLE_PQC)
|
||||
list(APPEND LIBRARIES
|
||||
mlkem512
|
||||
mlkem768
|
||||
mlkem1024
|
||||
)
|
||||
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")
|
||||
set(LIBRARIES ${LIBRARIES} pico_cyw43_arch_none)
|
||||
set(IS_CYW43 1)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
function(add_impl_library target)
|
||||
add_library(${target} INTERFACE)
|
||||
string(TOUPPER ${target} TARGET_UPPER)
|
||||
target_compile_definitions(${target} INTERFACE LIB_${TARGET_UPPER}=1)
|
||||
endfunction()
|
||||
|
||||
if(USB_ITF_HID)
|
||||
set(PICO_KEYS_SOURCES ${PICO_KEYS_SOURCES}
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/usb/hid/hid.c
|
||||
)
|
||||
set(INCLUDES ${INCLUDES}
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/usb/hid
|
||||
)
|
||||
endif()
|
||||
|
||||
if(USB_ITF_CCID)
|
||||
set(PICO_KEYS_SOURCES ${PICO_KEYS_SOURCES}
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/usb/ccid/ccid.c
|
||||
)
|
||||
set(INCLUDES ${INCLUDES}
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/usb/ccid
|
||||
)
|
||||
endif()
|
||||
|
||||
if(NOT MSVC)
|
||||
add_definitions("-fmacro-prefix-map=${CMAKE_CURRENT_LIST_DIR}/=")
|
||||
endif()
|
||||
if(MSVC)
|
||||
set(PICO_KEYS_SOURCES ${PICO_KEYS_SOURCES}
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/fs/mman.c
|
||||
)
|
||||
endif()
|
||||
if(ENABLE_EMULATION)
|
||||
if(APPLE)
|
||||
add_definitions("-Wno-deprecated-declarations")
|
||||
endif()
|
||||
add_definitions(-DENABLE_EMULATION)
|
||||
set(PICO_KEYS_SOURCES ${PICO_KEYS_SOURCES}
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/usb/emulation/emulation.c
|
||||
)
|
||||
set(MBEDTLS_SOURCES ${MBEDTLS_SOURCES}
|
||||
${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/aesni.c
|
||||
)
|
||||
set(INCLUDES ${INCLUDES}
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/usb/emulation
|
||||
)
|
||||
else()
|
||||
set(PICO_KEYS_SOURCES ${PICO_KEYS_SOURCES}
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/usb/usb_descriptors.c
|
||||
)
|
||||
endif()
|
||||
|
||||
if(MSVC)
|
||||
set(
|
||||
CMAKE_C_FLAGS
|
||||
"${CMAKE_C_FLAGS} -wd4820 -wd4255 -wd5045 -wd4706 -wd4061 -wd5105 -wd4141 -wd4200"
|
||||
)
|
||||
|
||||
add_compile_definitions(_CRT_SECURE_NO_WARNINGS
|
||||
__STDC_WANT_SECURE_LIB__=0
|
||||
_WIN32_WINNT_WIN10_TH2=0
|
||||
_WIN32_WINNT_WIN10_RS1=0
|
||||
_WIN32_WINNT_WIN10_RS2=0
|
||||
_WIN32_WINNT_WIN10_RS3=0
|
||||
_WIN32_WINNT_WIN10_RS4=0
|
||||
_WIN32_WINNT_WIN10_RS5=0
|
||||
_STRALIGN_USE_SECURE_CRT=0
|
||||
NTDDI_WIN11_DT=0)
|
||||
endif()
|
||||
|
||||
if(PICO_PLATFORM)
|
||||
pico_sdk_init()
|
||||
endif()
|
||||
|
||||
if(PICO_RP2350)
|
||||
pico_set_uf2_family(${CMAKE_PROJECT_NAME} "rp2350-arm-s")
|
||||
pico_embed_pt_in_binary(${CMAKE_PROJECT_NAME} "${CMAKE_CURRENT_LIST_DIR}/config/rp2350/pt.json")
|
||||
if (NOT IS_CYW43)
|
||||
pico_set_binary_type(${CMAKE_PROJECT_NAME} copy_to_ram)
|
||||
endif()
|
||||
if (SECURE_BOOT_PKEY)
|
||||
message(STATUS "Secure Boot Key ${SECURE_BOOT_PKEY}")
|
||||
pico_sign_binary(${CMAKE_PROJECT_NAME} ${SECURE_BOOT_PKEY})
|
||||
pico_hash_binary(${CMAKE_PROJECT_NAME})
|
||||
endif()
|
||||
target_link_libraries(${CMAKE_PROJECT_NAME} PRIVATE pico_bootrom)
|
||||
|
||||
set(INCLUDES ${INCLUDES}
|
||||
${CMAKE_CURRENT_LIST_DIR}/config/rp2350/alt
|
||||
)
|
||||
target_include_directories(mbedtls PRIVATE
|
||||
${CMAKE_CURRENT_LIST_DIR}/config/rp2350/alt
|
||||
)
|
||||
target_link_libraries(mbedtls PRIVATE pico_sha256)
|
||||
set(PICO_KEYS_SOURCES ${PICO_KEYS_SOURCES}
|
||||
${CMAKE_CURRENT_LIST_DIR}/config/rp2350/alt/sha256_alt.c
|
||||
)
|
||||
add_definitions(-DMBEDTLS_SHA256_ALT=1)
|
||||
set(LIBRARIES ${LIBRARIES} pico_sha256)
|
||||
endif()
|
||||
set(INTERNAL_SOURCES ${PICO_KEYS_SOURCES})
|
||||
|
||||
if(NOT TARGET pico_keys_sdk)
|
||||
if(PICO_PLATFORM)
|
||||
pico_add_library(pico_keys_sdk)
|
||||
|
||||
target_link_libraries(${CMAKE_PROJECT_NAME} PRIVATE ${LIBRARIES})
|
||||
else()
|
||||
add_impl_library(pico_keys_sdk)
|
||||
endif()
|
||||
target_sources(pico_keys_sdk INTERFACE ${PICO_KEYS_SOURCES})
|
||||
target_include_directories(pico_keys_sdk INTERFACE ${INCLUDES})
|
||||
target_link_libraries(pico_keys_sdk INTERFACE ${LIBRARIES})
|
||||
endif()
|
||||
742
picokeys_sdk_import.cmake
Normal file
742
picokeys_sdk_import.cmake
Normal file
@@ -0,0 +1,742 @@
|
||||
#
|
||||
# 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)
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/cmake/trusted.cmake)
|
||||
picokeys_init_trusted_config()
|
||||
|
||||
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
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/signal.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)
|
||||
if(ESP_PLATFORM OR ENABLE_EMULATION OR NOT PICO_PLATFORM OR PICO_RP2040)
|
||||
list(APPEND LIBRARIES mbedtls)
|
||||
endif()
|
||||
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(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()
|
||||
picokeys_resolve_trusted_toolchain()
|
||||
picokeys_setup_trusted_mbedtls()
|
||||
else()
|
||||
picokeys_resolve_trusted_toolchain()
|
||||
picokeys_setup_trusted_mbedtls()
|
||||
endif()
|
||||
picokeys_configure_trusted_support_sources()
|
||||
|
||||
if(NOT ESP_PLATFORM)
|
||||
if(NOT SKIP_MBEDTLS_FOR_OPENSSL_EMULATION)
|
||||
if(PICO_RP2350)
|
||||
add_library(mbedtls INTERFACE)
|
||||
target_include_directories(mbedtls INTERFACE
|
||||
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/include
|
||||
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library
|
||||
)
|
||||
target_link_libraries(mbedtls INTERFACE trusted_mbedtls)
|
||||
else()
|
||||
add_library(mbedtls STATIC ${MBEDTLS_SOURCES})
|
||||
target_include_directories(mbedtls SYSTEM PUBLIC
|
||||
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/include
|
||||
${CMAKE_CURRENT_LIST_DIR}/third-party/mbedtls/library
|
||||
)
|
||||
configure_picokeys_mbedtls_target(mbedtls)
|
||||
endif()
|
||||
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(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()
|
||||
|
||||
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)
|
||||
add_compile_definitions(PICOKEYS_HAS_TRUSTED_REGION=1)
|
||||
list(APPEND PICOKEYS_SOURCES
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/trusted/trusted.c
|
||||
)
|
||||
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 INTERFACE
|
||||
${CMAKE_CURRENT_LIST_DIR}/config/rp2350/alt
|
||||
)
|
||||
target_link_libraries(mbedtls INTERFACE pico_sha256_headers)
|
||||
endif()
|
||||
picokeys_configure_rp2350_trusted()
|
||||
list(APPEND PICOKEYS_SOURCES
|
||||
${CMAKE_CURRENT_LIST_DIR}/config/rp2350/alt/sha256_alt.c
|
||||
)
|
||||
add_compile_definitions(MBEDTLS_SHA256_ALT=1)
|
||||
if(NOT SKIP_MBEDTLS_FOR_OPENSSL_EMULATION)
|
||||
list(APPEND LIBRARIES mbedtls)
|
||||
endif()
|
||||
list(APPEND LIBRARIES pico_sha256)
|
||||
elseif(PICO_RP2040)
|
||||
if(NOT SKIP_MBEDTLS_FOR_OPENSSL_EMULATION)
|
||||
list(APPEND LIBRARIES mbedtls)
|
||||
endif()
|
||||
endif()
|
||||
set(INTERNAL_SOURCES ${PICOKEYS_SOURCES})
|
||||
|
||||
if(NOT TARGET picokeys_sdk)
|
||||
if(PICO_PLATFORM)
|
||||
pico_add_library(picokeys_sdk)
|
||||
|
||||
picokeys_link_trusted_region(${CMAKE_PROJECT_NAME})
|
||||
target_link_libraries(${CMAKE_PROJECT_NAME} PRIVATE ${LIBRARIES})
|
||||
else()
|
||||
add_impl_library(picokeys_sdk)
|
||||
endif()
|
||||
target_sources(picokeys_sdk INTERFACE ${PICOKEYS_SOURCES})
|
||||
target_include_directories(picokeys_sdk INTERFACE ${INCLUDES})
|
||||
target_include_directories(picokeys_sdk SYSTEM INTERFACE ${SYSTEM_INCLUDES})
|
||||
target_link_libraries(picokeys_sdk INTERFACE ${LIBRARIES})
|
||||
endif()
|
||||
@@ -12,3 +12,4 @@ CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
|
||||
CONFIG_WL_SECTOR_SIZE_512=y
|
||||
CONFIG_WL_SECTOR_MODE_PERF=y
|
||||
COMPILER_OPTIMIZATION="Performance"
|
||||
CONFIG_MBEDTLS_HKDF_C=y
|
||||
|
||||
69
src/apdu.c
69
src/apdu.c
@@ -15,12 +15,13 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "picokeys.h"
|
||||
#include "apdu.h"
|
||||
#include "pico_keys.h"
|
||||
#include "led/led.h"
|
||||
#include "usb.h"
|
||||
#include <stdio.h>
|
||||
#ifdef ESP_PLATFORM
|
||||
#include "esp_compat.h"
|
||||
#include "compat/esp_compat.h"
|
||||
#endif
|
||||
#ifdef ENABLE_EMULATION
|
||||
#include "emulation.h"
|
||||
@@ -30,16 +31,23 @@ uint8_t *rdata_gr = NULL;
|
||||
uint16_t rdata_bk = 0x0;
|
||||
extern uint32_t timeout;
|
||||
bool is_chaining = false;
|
||||
uint8_t chain_buf[4096];
|
||||
uint8_t chain_buf[2038];
|
||||
uint8_t *chain_ptr = NULL;
|
||||
|
||||
int process_apdu() {
|
||||
struct apdu apdu;
|
||||
|
||||
int process_apdu(void) {
|
||||
led_set_mode(MODE_PROCESSING);
|
||||
if (CLA(apdu) & 0x10) {
|
||||
size_t chain_used = 0;
|
||||
if (!is_chaining) {
|
||||
chain_ptr = chain_buf;
|
||||
}
|
||||
if (chain_ptr - chain_buf + apdu.nc >= sizeof(chain_buf)) {
|
||||
chain_used = (size_t)(chain_ptr - chain_buf);
|
||||
if (chain_used + apdu.nc >= sizeof(chain_buf)) {
|
||||
memset(chain_buf, 0, sizeof(chain_buf));
|
||||
chain_ptr = NULL;
|
||||
is_chaining = false;
|
||||
return SW_CLA_NOT_SUPPORTED();
|
||||
}
|
||||
memcpy(chain_ptr, apdu.data, apdu.nc);
|
||||
@@ -52,11 +60,13 @@ int process_apdu() {
|
||||
memmove(apdu.data + (chain_ptr - chain_buf), apdu.data, apdu.nc);
|
||||
memcpy(apdu.data, chain_buf, chain_ptr - chain_buf);
|
||||
apdu.nc += (uint16_t)(chain_ptr - chain_buf);
|
||||
memset(chain_buf, 0, sizeof(chain_buf));
|
||||
chain_ptr = NULL;
|
||||
is_chaining = false;
|
||||
}
|
||||
}
|
||||
if (INS(apdu) == 0xA4 && P1(apdu) == 0x04 && (P2(apdu) == 0x00 || P2(apdu) == 0x4)) { //select by AID
|
||||
if (select_app(apdu.data, apdu.nc) == PICOKEY_OK) {
|
||||
if (select_app(apdu.data, apdu.nc) == PICOKEYS_OK) {
|
||||
return SW_OK();
|
||||
}
|
||||
return SW_FILE_NOT_FOUND();
|
||||
@@ -85,17 +95,17 @@ uint16_t apdu_process(uint8_t itf, const uint8_t *buffer, uint16_t buffer_size)
|
||||
}
|
||||
else if (apdu.header[4] == 0x0 && buffer_size >= 7) {
|
||||
if (buffer_size == 7) {
|
||||
apdu.ne = get_uint16_t_be(apdu.header + 5);
|
||||
apdu.ne = get_uint16_be(apdu.header + 5);
|
||||
if (apdu.ne == 0) {
|
||||
apdu.ne = 65536;
|
||||
}
|
||||
}
|
||||
else {
|
||||
apdu.ne = 0;
|
||||
apdu.nc = get_uint16_t_be(apdu.header + 5);
|
||||
apdu.nc = get_uint16_be(apdu.header + 5);
|
||||
apdu.data = apdu.header + 7;
|
||||
if (apdu.nc + 7 + 2 == buffer_size) {
|
||||
apdu.ne = get_uint16_t_be(apdu.header + buffer_size - 2);
|
||||
apdu.ne = get_uint16_be(apdu.header + buffer_size - 2);
|
||||
if (apdu.ne == 0) {
|
||||
apdu.ne = 65536;
|
||||
}
|
||||
@@ -176,11 +186,11 @@ uint16_t apdu_process(uint8_t itf, const uint8_t *buffer, uint16_t buffer_size)
|
||||
}
|
||||
|
||||
uint16_t set_res_sw(uint8_t sw1, uint8_t sw2) {
|
||||
apdu.sw = make_uint16_t_be(sw1, sw2);
|
||||
apdu.sw = make_uint16_be(sw1, sw2);
|
||||
if (sw1 != 0x90) {
|
||||
res_APDU_size = 0;
|
||||
}
|
||||
return make_uint16_t_be(sw1, sw2);
|
||||
return make_uint16_be(sw1, sw2);
|
||||
}
|
||||
|
||||
void *apdu_thread(void *arg) {
|
||||
@@ -190,7 +200,9 @@ void *apdu_thread(void *arg) {
|
||||
uint32_t m = 0;
|
||||
queue_remove_blocking(&usb_to_card_q, &m);
|
||||
uint32_t flag = m + 1;
|
||||
queue_add_blocking(&card_to_usb_q, &flag);
|
||||
if (m != EV_CMD_AVAILABLE) {
|
||||
queue_add_blocking(&card_to_usb_q, &flag);
|
||||
}
|
||||
|
||||
if (m == EV_VERIFY_CMD_AVAILABLE || m == EV_MODIFY_CMD_AVAILABLE) {
|
||||
set_res_sw(0x6f, 0x00);
|
||||
@@ -220,8 +232,8 @@ done: ;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void apdu_finish() {
|
||||
put_uint16_t_be(apdu.sw, apdu.rdata + apdu.rlen);
|
||||
void apdu_finish(void) {
|
||||
put_uint16_be(apdu.sw, apdu.rdata + apdu.rlen);
|
||||
// timeout_stop();
|
||||
#ifndef ENABLE_EMULATION
|
||||
/* It was fixed in the USB handling. Keep it just in case */
|
||||
@@ -231,7 +243,7 @@ void apdu_finish() {
|
||||
#endif
|
||||
}
|
||||
|
||||
uint16_t apdu_next() {
|
||||
uint16_t apdu_next(void) {
|
||||
if (apdu.sw != 0) {
|
||||
if (apdu.rlen <= apdu.ne) {
|
||||
return apdu.rlen + 2;
|
||||
@@ -252,3 +264,30 @@ uint16_t apdu_next() {
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bulk_cmd(int (*cmd)(void)) {
|
||||
uint8_t *p = apdu.data;
|
||||
uint8_t *rapdu = apdu.rdata;
|
||||
uint16_t rapdu_size = 0;
|
||||
uint8_t *top = apdu.data + apdu.nc;
|
||||
while (p < top) {
|
||||
P1(apdu) = p[0];
|
||||
P2(apdu) = p[1];
|
||||
apdu.nc = p[2];
|
||||
apdu.data = p + 3;
|
||||
*apdu.rdata++ = p[0];
|
||||
*apdu.rdata++ = p[1];
|
||||
*apdu.rdata++ = 0;
|
||||
*apdu.rdata++ = 0;
|
||||
apdu.rlen = 0;
|
||||
cmd();
|
||||
put_uint16_be(apdu.rlen, apdu.rdata - 2);
|
||||
put_uint16_be(apdu.sw, apdu.rdata + apdu.rlen);
|
||||
rapdu_size += 4 + apdu.rlen + 2;
|
||||
apdu.rdata += apdu.rlen + 2;
|
||||
p += 3 + apdu.nc;
|
||||
}
|
||||
apdu.rlen = rapdu_size;
|
||||
apdu.rdata = rapdu;
|
||||
return SW_OK();
|
||||
}
|
||||
|
||||
81
src/apdu.h
81
src/apdu.h
@@ -18,20 +18,16 @@
|
||||
#ifndef _APDU_H_
|
||||
#define _APDU_H_
|
||||
|
||||
#include <stdlib.h>
|
||||
#if defined(PICO_PLATFORM)
|
||||
#include "pico/stdlib.h"
|
||||
#endif
|
||||
#include "compat.h"
|
||||
#include <stdio.h>
|
||||
#include <inttypes.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "compat/compat.h"
|
||||
|
||||
typedef struct app {
|
||||
const uint8_t *aid;
|
||||
int (*process_apdu)();
|
||||
int (*process_apdu)(void);
|
||||
int (*select_aid)(struct app *, uint8_t);
|
||||
int (*unload)();
|
||||
int (*unload)(void);
|
||||
} app_t;
|
||||
|
||||
extern bool app_exists(const uint8_t *aid, size_t aid_len);
|
||||
@@ -40,7 +36,7 @@ extern int select_app(const uint8_t *aid, size_t aid_len);
|
||||
|
||||
typedef struct cmd {
|
||||
uint8_t ins;
|
||||
int (*cmd_handler)();
|
||||
int (*cmd_handler)(void);
|
||||
} cmd_t;
|
||||
|
||||
extern uint8_t num_apps;
|
||||
@@ -69,10 +65,69 @@ PACK(struct apdu {
|
||||
extern struct apdu apdu;
|
||||
|
||||
extern uint16_t set_res_sw(uint8_t sw1, uint8_t sw2);
|
||||
extern int process_apdu();
|
||||
extern int process_apdu(void);
|
||||
extern uint16_t apdu_process(uint8_t, const uint8_t *buffer, uint16_t buffer_size);
|
||||
extern void apdu_finish();
|
||||
extern uint16_t apdu_next();
|
||||
extern void apdu_finish(void);
|
||||
extern uint16_t apdu_next(void);
|
||||
extern void *apdu_thread(void *);
|
||||
extern int bulk_cmd(int (*cmd)(void));
|
||||
|
||||
|
||||
#define SW_BYTES_REMAINING_00() set_res_sw(0x61, 0x00)
|
||||
#define SW_WARNING_STATE_UNCHANGED() set_res_sw(0x62, 0x00)
|
||||
#define SW_WARNING_CORRUPTED() set_res_sw(0x62, 0x81)
|
||||
#define SW_WARNING_EOF() set_res_sw(0x62, 0x82)
|
||||
#define SW_WARNING_EF_DEACTIVATED() set_res_sw(0x62, 0x83)
|
||||
#define SW_WARNING_WRONG_FCI() set_res_sw(0x62, 0x84)
|
||||
#define SW_WARNING_EF_TERMINATED() set_res_sw(0x62, 0x85)
|
||||
|
||||
#define SW_WARNING_NOINFO() set_res_sw(0x63, 0x00)
|
||||
#define SW_WARNING_FILLUP() set_res_sw(0x63, 0x81)
|
||||
|
||||
#define SW_EXEC_ERROR() set_res_sw(0x64, 0x00)
|
||||
|
||||
#define SW_MEMORY_FAILURE() set_res_sw(0x65, 0x81)
|
||||
|
||||
#define SW_SECURE_MESSAGE_EXEC_ERROR() set_res_sw(0x66, 0x00)
|
||||
|
||||
#define SW_WRONG_LENGTH() set_res_sw(0x67, 0x00)
|
||||
#define SW_WRONG_DATA() set_res_sw(0x67, 0x00)
|
||||
|
||||
#define SW_LOGICAL_CHANNEL_NOT_SUPPORTED() set_res_sw(0x68, 0x81)
|
||||
#define SW_SECURE_MESSAGING_NOT_SUPPORTED() set_res_sw(0x68, 0x82)
|
||||
|
||||
#define SW_COMMAND_INCOMPATIBLE() set_res_sw(0x69, 0x81)
|
||||
#define SW_SECURITY_STATUS_NOT_SATISFIED() set_res_sw(0x69, 0x82)
|
||||
#define SW_PIN_BLOCKED() set_res_sw(0x69, 0x83)
|
||||
#define SW_DATA_INVALID() set_res_sw(0x69, 0x84)
|
||||
#define SW_CONDITIONS_NOT_SATISFIED() set_res_sw(0x69, 0x85)
|
||||
#define SW_COMMAND_NOT_ALLOWED() set_res_sw(0x69, 0x86)
|
||||
#define SW_SECURE_MESSAGING_MISSING_DO() set_res_sw(0x69, 0x87)
|
||||
#define SW_SECURE_MESSAGING_INCORRECT_DO() set_res_sw(0x69, 0x88)
|
||||
#define SW_APPLET_SELECT_FAILED() set_res_sw(0x69, 0x99)
|
||||
|
||||
#define SW_INCORRECT_PARAMS() set_res_sw(0x6A, 0x80)
|
||||
#define SW_FUNC_NOT_SUPPORTED() set_res_sw(0x6A, 0x81)
|
||||
#define SW_FILE_NOT_FOUND() set_res_sw(0x6A, 0x82)
|
||||
#define SW_RECORD_NOT_FOUND() set_res_sw(0x6A, 0x83)
|
||||
#define SW_FILE_FULL() set_res_sw(0x6A, 0x84)
|
||||
#define SW_WRONG_NE() set_res_sw(0x6A, 0x85)
|
||||
#define SW_INCORRECT_P1P2() set_res_sw(0x6A, 0x86)
|
||||
#define SW_WRONG_NC() set_res_sw(0x6A, 0x87)
|
||||
#define SW_REFERENCE_NOT_FOUND() set_res_sw(0x6A, 0x88)
|
||||
#define SW_FILE_EXISTS() set_res_sw(0x6A, 0x89)
|
||||
|
||||
#define SW_WRONG_P1P2() set_res_sw(0x6B, 0x00)
|
||||
|
||||
#define SW_CORRECT_LENGTH_00() set_res_sw(0x6C, 0x00)
|
||||
|
||||
#define SW_INS_NOT_SUPPORTED() set_res_sw(0x6D, 0x00)
|
||||
|
||||
#define SW_CLA_NOT_SUPPORTED() set_res_sw(0x6E, 0x00)
|
||||
|
||||
#define SW_UNKNOWN() set_res_sw(0x6F, 0x00)
|
||||
|
||||
#define SW_OK() set_res_sw(0x90, 0x00)
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
50
src/asn1.h
50
src/asn1.h
@@ -1,50 +0,0 @@
|
||||
/*
|
||||
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
|
||||
* Copyright (c) 2022 Pol Henarejos.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU 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 _ASN1_H_
|
||||
#define _ASN1_H_
|
||||
|
||||
#include <stdlib.h>
|
||||
#if defined(PICO_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
|
||||
187
src/button.c
Normal file
187
src/button.c
Normal file
@@ -0,0 +1,187 @@
|
||||
/*
|
||||
* 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"
|
||||
#include "signal.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;
|
||||
bool touch_accept_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;
|
||||
|
||||
int 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) {
|
||||
signal_emit(SIGNAL_USER_PRESENCE_COMPLETED);
|
||||
return 0;
|
||||
}
|
||||
signal_user_presence_request_data_t data = {
|
||||
.timeout = button_timeout / 1000,
|
||||
};
|
||||
signal_emit_param(SIGNAL_USER_PRESENCE_REQUEST, &data);
|
||||
uint32_t start_button = board_millis();
|
||||
const uint32_t button_poll_interval_ms = 2;
|
||||
uint32_t next_button_poll_ms = start_button;
|
||||
bool button_pressed = picok_board_button_read();
|
||||
bool timeout = false;
|
||||
cancel_button = false;
|
||||
uint32_t led_mode = led_get_mode();
|
||||
led_set_mode(MODE_BUTTON);
|
||||
req_button_pending = true;
|
||||
while (button_pressed == false && cancel_button == false) {
|
||||
execute_tasks();
|
||||
uint32_t now = board_millis();
|
||||
if (now >= next_button_poll_ms) {
|
||||
button_pressed = picok_board_button_read();
|
||||
next_button_poll_ms = now + button_poll_interval_ms;
|
||||
}
|
||||
//sleep_ms(10);
|
||||
if (start_button + button_timeout < now) { /* timeout */
|
||||
timeout = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!timeout) {
|
||||
while (button_pressed == true && cancel_button == false) {
|
||||
execute_tasks();
|
||||
uint32_t now = board_millis();
|
||||
if (now >= next_button_poll_ms) {
|
||||
button_pressed = picok_board_button_read();
|
||||
next_button_poll_ms = now + button_poll_interval_ms;
|
||||
}
|
||||
//sleep_ms(10);
|
||||
if (start_button + 15000 < now) { /* timeout */
|
||||
timeout = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
led_set_mode(led_mode);
|
||||
req_button_pending = false;
|
||||
if (timeout) {
|
||||
signal_emit(SIGNAL_USER_PRESENCE_TIMEOUT);
|
||||
return 1;
|
||||
}
|
||||
else if (cancel_button) {
|
||||
signal_emit(SIGNAL_USER_PRESENCE_CANCELLED);
|
||||
return 2;
|
||||
}
|
||||
signal_emit(SIGNAL_USER_PRESENCE_COMPLETED);
|
||||
return 0;
|
||||
}
|
||||
#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
|
||||
}
|
||||
33
src/button.h
Normal file
33
src/button.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 BUTTON_H
|
||||
#define BUTTON_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#if defined(ESP_PLATFORM)
|
||||
#define BOOT_PIN GPIO_NUM_0
|
||||
#endif
|
||||
|
||||
extern int button_wait(void);
|
||||
extern void button_task(void);
|
||||
extern bool cancel_button;
|
||||
extern bool touch_accept_button;
|
||||
|
||||
#endif // BUTTON_H
|
||||
@@ -18,6 +18,7 @@
|
||||
#ifndef _BOARD_H_
|
||||
#define _BOARD_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#ifdef _MSC_VER
|
||||
#include <windows.h>
|
||||
struct timezone;
|
||||
@@ -26,10 +27,11 @@ extern int gettimeofday(struct timeval *tp, struct timezone *tzp);
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
|
||||
static inline uint32_t board_millis() {
|
||||
static inline uint32_t board_millis(void) {
|
||||
struct timeval start;
|
||||
gettimeofday(&start, NULL);
|
||||
return start.tv_sec * 1000 + start.tv_usec / 1000;
|
||||
uint64_t ms = (uint64_t)start.tv_sec * 1000ULL + (uint64_t)start.tv_usec / 1000ULL;
|
||||
return (uint32_t)ms;
|
||||
}
|
||||
|
||||
#endif // _BOARD_H_
|
||||
@@ -21,6 +21,7 @@
|
||||
#define _PTHREAD_H_
|
||||
#include <windows.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
typedef HANDLE pthread_t;
|
||||
typedef CRITICAL_SECTION pthread_mutex_t;
|
||||
@@ -51,6 +52,11 @@ static inline int pthread_mutex_destroy(pthread_mutex_t *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;
|
||||
@@ -19,8 +19,8 @@
|
||||
#define QUEUE_H
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#include "pthread_win32.h"
|
||||
#include "semaphore_win32.h"
|
||||
#include "compat/pthread_win32.h"
|
||||
#include "compat/semaphore_win32.h"
|
||||
#else
|
||||
#include <pthread.h>
|
||||
#include <semaphore.h>
|
||||
@@ -34,6 +34,9 @@ typedef struct {
|
||||
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) {
|
||||
@@ -15,31 +15,17 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#if defined(ESP_PLATFORM)
|
||||
#include "esp_compat.h"
|
||||
#elif defined(PICO_PLATFORM)
|
||||
#include <pico/unique_id.h>
|
||||
#endif
|
||||
#include "picokeys.h"
|
||||
#include "serial.h"
|
||||
#include "mbedtls/md.h"
|
||||
#include "mbedtls/sha256.h"
|
||||
#include "mbedtls/aes.h"
|
||||
#include "mbedtls/hkdf.h"
|
||||
#include "mbedtls/gcm.h"
|
||||
#include "mbedtls/base64.h"
|
||||
#include "crypto_utils.h"
|
||||
#include "pico_keys.h"
|
||||
#include "otp.h"
|
||||
#include "random.h"
|
||||
#include <stdio.h>
|
||||
|
||||
int ct_memcmp(const void *a, const void *b, size_t n) {
|
||||
const volatile uint8_t *x = (const volatile uint8_t *)a;
|
||||
const volatile uint8_t *y = (const volatile uint8_t *)b;
|
||||
uint8_t r = 0;
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
r |= x[i] ^ y[i];
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
static const mbedtls_md_info_t *SHA256(void) {
|
||||
return mbedtls_md_info_from_type(MBEDTLS_MD_SHA256);
|
||||
@@ -80,21 +66,38 @@ 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, uint8_t *out_buf) {
|
||||
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_gen(NULL, nonce, 12);
|
||||
random_fill_buffer(nonce, 12);
|
||||
|
||||
mbedtls_gcm_context gcm;
|
||||
mbedtls_gcm_init(&gcm);
|
||||
uint8_t kenc[32];
|
||||
pin_derive_kenc(key, kenc);
|
||||
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) {
|
||||
@@ -111,24 +114,33 @@ int encrypt_with_aad(const uint8_t key[32], const uint8_t *in_buf, size_t in_len
|
||||
// Input: [nonce|ciphertext|tag] = in_len bytes
|
||||
// Output: decrypted = in_len - 12 - 16 bytes
|
||||
// ------------------------------------------------------------------
|
||||
int decrypt_with_aad(const uint8_t key[32], const uint8_t *in_buf, size_t in_len, uint8_t *out_buf) {
|
||||
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;
|
||||
mbedtls_gcm_init(&gcm);
|
||||
uint8_t kenc[32];
|
||||
pin_derive_kenc(key, kenc);
|
||||
int rc = mbedtls_gcm_setkey(&gcm, MBEDTLS_CIPHER_ID_AES, kenc, 256);
|
||||
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 (rc != 0) {
|
||||
return rc;
|
||||
if (ret != 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
rc = mbedtls_gcm_auth_decrypt(&gcm, in_len - 16 - 12, nonce, 12, pico_serial_hash, sizeof(pico_serial_hash), tag, 16, ct, out_buf);
|
||||
MBEDTLS_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 rc;
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Old functions, kept for compatibility. NOT SECURE, use the new ones above.
|
||||
@@ -141,7 +153,6 @@ void double_hash_pin(const uint8_t *pin, uint16_t len, uint8_t output[32]) {
|
||||
hash_multi(o1, sizeof(o1), output);
|
||||
}
|
||||
|
||||
|
||||
void hash_multi(const uint8_t *input, uint16_t len, uint8_t output[32]) {
|
||||
mbedtls_sha256_context ctx;
|
||||
mbedtls_sha256_init(&ctx);
|
||||
@@ -188,12 +199,20 @@ int aes_encrypt(const uint8_t *key, const uint8_t *iv, uint16_t key_size, int mo
|
||||
}
|
||||
int r = mbedtls_aes_setkey_enc(&aes, key, key_size);
|
||||
if (r != 0) {
|
||||
return PICOKEY_EXEC_ERROR;
|
||||
mbedtls_aes_free(&aes);
|
||||
mbedtls_platform_zeroize(tmp_iv, sizeof(tmp_iv));
|
||||
return PICOKEYS_EXEC_ERROR;
|
||||
}
|
||||
if (mode == PICO_KEYS_AES_MODE_CBC) {
|
||||
return mbedtls_aes_crypt_cbc(&aes, MBEDTLS_AES_ENCRYPT, len, tmp_iv, data, data);
|
||||
int rc = 0;
|
||||
if (mode == PICOKEYS_AES_MODE_CBC) {
|
||||
rc = mbedtls_aes_crypt_cbc(&aes, MBEDTLS_AES_ENCRYPT, len, tmp_iv, data, data);
|
||||
}
|
||||
return mbedtls_aes_crypt_cfb128(&aes, MBEDTLS_AES_ENCRYPT, len, &iv_offset, tmp_iv, data, data);
|
||||
else {
|
||||
rc = mbedtls_aes_crypt_cfb128(&aes, MBEDTLS_AES_ENCRYPT, len, &iv_offset, tmp_iv, data, data);
|
||||
}
|
||||
mbedtls_aes_free(&aes);
|
||||
mbedtls_platform_zeroize(tmp_iv, sizeof(tmp_iv));
|
||||
return rc;
|
||||
}
|
||||
|
||||
int aes_decrypt(const uint8_t *key, const uint8_t *iv, uint16_t key_size, int mode, uint8_t *data, uint16_t len) {
|
||||
@@ -207,31 +226,44 @@ int aes_decrypt(const uint8_t *key, const uint8_t *iv, uint16_t key_size, int mo
|
||||
}
|
||||
int r = mbedtls_aes_setkey_dec(&aes, key, key_size);
|
||||
if (r != 0) {
|
||||
return PICOKEY_EXEC_ERROR;
|
||||
mbedtls_aes_free(&aes);
|
||||
mbedtls_platform_zeroize(tmp_iv, sizeof(tmp_iv));
|
||||
return PICOKEYS_EXEC_ERROR;
|
||||
}
|
||||
if (mode == PICO_KEYS_AES_MODE_CBC) {
|
||||
return mbedtls_aes_crypt_cbc(&aes, MBEDTLS_AES_DECRYPT, len, tmp_iv, data, data);
|
||||
int rc = 0;
|
||||
if (mode == PICOKEYS_AES_MODE_CBC) {
|
||||
rc = mbedtls_aes_crypt_cbc(&aes, MBEDTLS_AES_DECRYPT, len, tmp_iv, data, data);
|
||||
}
|
||||
r = mbedtls_aes_setkey_enc(&aes, key, key_size); //CFB requires set_enc instead set_dec
|
||||
return mbedtls_aes_crypt_cfb128(&aes, MBEDTLS_AES_DECRYPT, len, &iv_offset, tmp_iv, data, data);
|
||||
else {
|
||||
r = mbedtls_aes_setkey_enc(&aes, key, key_size); //CFB requires set_enc instead set_dec
|
||||
if (r != 0) {
|
||||
mbedtls_aes_free(&aes);
|
||||
mbedtls_platform_zeroize(tmp_iv, sizeof(tmp_iv));
|
||||
return PICOKEYS_EXEC_ERROR;
|
||||
}
|
||||
rc = mbedtls_aes_crypt_cfb128(&aes, MBEDTLS_AES_DECRYPT, len, &iv_offset, tmp_iv, data, data);
|
||||
}
|
||||
mbedtls_aes_free(&aes);
|
||||
mbedtls_platform_zeroize(tmp_iv, sizeof(tmp_iv));
|
||||
return rc;
|
||||
}
|
||||
|
||||
int aes_encrypt_cfb_256(const uint8_t *key, const uint8_t *iv, uint8_t *data, uint16_t len) {
|
||||
return aes_encrypt(key, iv, 256, PICO_KEYS_AES_MODE_CFB, data, len);
|
||||
return aes_encrypt(key, iv, 256, PICOKEYS_AES_MODE_CFB, data, len);
|
||||
}
|
||||
int aes_decrypt_cfb_256(const uint8_t *key, const uint8_t *iv, uint8_t *data, uint16_t len) {
|
||||
return aes_decrypt(key, iv, 256, PICO_KEYS_AES_MODE_CFB, data, len);
|
||||
return aes_decrypt(key, iv, 256, PICOKEYS_AES_MODE_CFB, data, len);
|
||||
}
|
||||
|
||||
struct lv_data {
|
||||
PACK(struct lv_data {
|
||||
unsigned char *value;
|
||||
uint8_t len;
|
||||
};
|
||||
});
|
||||
|
||||
struct ec_curve_mbed_id {
|
||||
PACK(struct ec_curve_mbed_id {
|
||||
struct lv_data curve;
|
||||
mbedtls_ecp_group_id id;
|
||||
};
|
||||
});
|
||||
struct ec_curve_mbed_id ec_curves_mbed[] = {
|
||||
{ { (unsigned char *)
|
||||
"\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFE\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF",
|
||||
@@ -291,3 +323,71 @@ uint32_t crc32c(const uint8_t *buf, size_t len) {
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -21,32 +21,40 @@
|
||||
#include "mbedtls/ecp.h"
|
||||
#include "mbedtls/md.h"
|
||||
|
||||
#define PICO_KEYS_KEY_RSA 0x000f // It is a mask
|
||||
#define PICO_KEYS_KEY_RSA_1K 0x0001
|
||||
#define PICO_KEYS_KEY_RSA_2K 0x0002
|
||||
#define PICO_KEYS_KEY_RSA_3K 0x0004
|
||||
#define PICO_KEYS_KEY_RSA_4k 0x0008
|
||||
#define PICO_KEYS_KEY_EC 0x0010
|
||||
#define PICO_KEYS_KEY_AES 0x0f00 // It is a mask
|
||||
#define PICO_KEYS_KEY_AES_128 0x0100
|
||||
#define PICO_KEYS_KEY_AES_192 0x0200
|
||||
#define PICO_KEYS_KEY_AES_256 0x0400
|
||||
#define PICO_KEYS_KEY_AES_512 0x0800 /* For AES XTS */
|
||||
#define PICOKEYS_KEY_RSA 0x000f // It is a mask
|
||||
#define PICOKEYS_KEY_RSA_1K 0x0001
|
||||
#define PICOKEYS_KEY_RSA_2K 0x0002
|
||||
#define PICOKEYS_KEY_RSA_3K 0x0004
|
||||
#define PICOKEYS_KEY_RSA_4k 0x0008
|
||||
#define PICOKEYS_KEY_EC 0x0010
|
||||
#define PICOKEYS_KEY_AES 0x0f00 // It is a mask
|
||||
#define PICOKEYS_KEY_AES_128 0x0100
|
||||
#define PICOKEYS_KEY_AES_192 0x0200
|
||||
#define PICOKEYS_KEY_AES_256 0x0400
|
||||
#define PICOKEYS_KEY_AES_512 0x0800 /* For AES XTS */
|
||||
|
||||
#define PICO_KEYS_AES_MODE_CBC 1
|
||||
#define PICO_KEYS_AES_MODE_CFB 2
|
||||
#define PICOKEYS_AES_MODE_CBC 1
|
||||
#define PICOKEYS_AES_MODE_CFB 2
|
||||
|
||||
#define IV_SIZE 16
|
||||
|
||||
extern int ct_memcmp(const void *a, const void *b, size_t n);
|
||||
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, uint8_t *out_buf);
|
||||
extern int decrypt_with_aad(const uint8_t key[32], const uint8_t *in_buf, size_t in_len, uint8_t *out_buf);
|
||||
extern int encrypt_with_aad(const uint8_t key[32], const uint8_t *in_buf, size_t in_len, const pin_kdf_version_t version, uint8_t *out_buf);
|
||||
extern int decrypt_with_aad(const uint8_t key[32], const uint8_t *in_buf, size_t in_len, const pin_kdf_version_t version, uint8_t *out_buf);
|
||||
extern void double_hash_pin(const uint8_t *pin, uint16_t len, uint8_t output[32]);
|
||||
extern void hash_multi(const uint8_t *input, uint16_t len, uint8_t output[32]);
|
||||
extern void hash256(const uint8_t *input, size_t len, uint8_t output[32]);
|
||||
@@ -57,5 +65,10 @@ extern int aes_encrypt_cfb_256(const uint8_t *key, const uint8_t *iv, uint8_t *d
|
||||
extern int aes_decrypt_cfb_256(const uint8_t *key, const uint8_t *iv, uint8_t *data, uint16_t len);
|
||||
extern mbedtls_ecp_group_id ec_get_curve_from_prime(const uint8_t *prime, size_t prime_len);
|
||||
extern uint32_t crc32c(const uint8_t *buf, size_t len);
|
||||
extern int base64url_encode(unsigned char *dst, size_t dlen, size_t *olen, const unsigned char *src, size_t slen);
|
||||
extern int base64url_decode(unsigned char *dst, size_t dlen, size_t *olen, const unsigned char *src, size_t slen);
|
||||
extern int b64url_decoded_len(size_t n, size_t *out_len);
|
||||
|
||||
#define PIN_KDF_SIZE(x) (12 + (x) + 16)
|
||||
|
||||
#endif
|
||||
|
||||
71
src/debug.h
71
src/debug.h
@@ -19,32 +19,53 @@
|
||||
#define _DEBUG_H_
|
||||
|
||||
#if defined(DEBUG_APDU) && DEBUG_APDU == 1
|
||||
#define DEBUG_PAYLOAD(_p, _s) { \
|
||||
printf("Payload %s (%zu bytes) [%s:%d]:\n", #_p, (size_t)(_s), __FILE__, __LINE__); \
|
||||
for (size_t _i = 0; _i < (size_t)(_s); _i += 16) { \
|
||||
printf("%" PRIxPTR "h : ", (uintptr_t) (_i + _p)); \
|
||||
for (size_t _j = 0; _j < 16; _j++) { \
|
||||
if (_j < (size_t)(_s) - _i) printf("%02X ", (_p)[_i + _j]); \
|
||||
else printf(" "); \
|
||||
if (_j == 7) printf(" "); \
|
||||
} printf(": "); \
|
||||
for (size_t _j = 0; _j < 16; _j++) { \
|
||||
if (_j < (size_t)(_s) - _i && (_p)[_i + _j] > 32 && (_p)[_i + _j] != 127 && (_p)[_i + _j] < 176) printf("%c", (_p)[_i + _j]); \
|
||||
else printf(" "); \
|
||||
if (_j == 7) printf(" "); \
|
||||
} \
|
||||
printf("\n"); \
|
||||
} printf("\n"); \
|
||||
}
|
||||
#define DEBUG_DATA(_p, _s) { \
|
||||
printf("Data %s (%zu bytes) [%s:%d]:\n", #_p, (size_t)(_s), __FILE__, __LINE__); \
|
||||
char *_tmp = (char *) calloc(2 * (_s) + 1, sizeof(char)); \
|
||||
for (size_t _i = 0; _i < (size_t)(_s); _i++) { \
|
||||
sprintf(&_tmp[2 * _i], "%02X", (_p)[_i]); \
|
||||
} \
|
||||
printf("%s\n", _tmp); \
|
||||
free(_tmp); \
|
||||
#include <inttypes.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
static inline void debug_payload_impl(const char *name, const uint8_t *p, size_t s, const char *file, int line) {
|
||||
printf("Payload %s (%zu bytes) [%s:%d]:\n", name, s, file, line);
|
||||
for (size_t i = 0; i < s; i += 16) {
|
||||
printf("%" PRIxPTR "h : ", (uintptr_t)(p + i));
|
||||
for (size_t j = 0; j < 16; j++) {
|
||||
if (j < s - i) {
|
||||
printf("%02X ", p[i + j]);
|
||||
}
|
||||
else {
|
||||
printf(" ");
|
||||
}
|
||||
if (j == 7) {
|
||||
printf(" ");
|
||||
}
|
||||
}
|
||||
printf(": ");
|
||||
for (size_t j = 0; j < 16; j++) {
|
||||
if (j < s - i && p[i + j] > 32 && p[i + j] != 127 && p[i + j] < 176) {
|
||||
printf("%c", p[i + j]);
|
||||
}
|
||||
else {
|
||||
printf(" ");
|
||||
}
|
||||
if (j == 7) {
|
||||
printf(" ");
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
static inline void debug_data_impl(const char *name, const uint8_t *p, size_t s, const char *file, int line) {
|
||||
printf("Data %s (%zu bytes) [%s:%d]:\n", name, s, file, line);
|
||||
for (size_t i = 0; i < s; i++) {
|
||||
printf("%02X", p[i]);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
#define DEBUG_PAYLOAD(_p, _s) debug_payload_impl(#_p, (const uint8_t *)(_p), (size_t)(_s), __FILE__, __LINE__)
|
||||
#define DEBUG_DATA(_p, _s) debug_data_impl(#_p, (const uint8_t *)(_p), (size_t)(_s), __FILE__, __LINE__)
|
||||
|
||||
#else
|
||||
#define DEBUG_PAYLOAD(_p, _s)
|
||||
|
||||
125
src/eac.c
125
src/eac.c
@@ -15,12 +15,18 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "picokeys.h"
|
||||
#include "eac.h"
|
||||
#include "crypto_utils.h"
|
||||
#include "random.h"
|
||||
#include "mbedtls/cmac.h"
|
||||
#include "asn1.h"
|
||||
#include "tlv.h"
|
||||
#include "apdu.h"
|
||||
#ifdef ENABLE_EMULATION
|
||||
#include "usb/emulation/emulation.h"
|
||||
#else
|
||||
#include "usb/usb.h"
|
||||
#endif
|
||||
|
||||
static uint8_t sm_nonce[8];
|
||||
static uint8_t sm_kmac[16];
|
||||
@@ -29,19 +35,13 @@ static MSE_protocol sm_protocol = MSE_NONE;
|
||||
static mbedtls_mpi sm_mSSC;
|
||||
static uint8_t sm_blocksize = 0;
|
||||
static uint8_t sm_iv[16];
|
||||
uint16_t sm_session_pin_len = 0;
|
||||
uint8_t sm_session_pin[16];
|
||||
static bool sm_active = false;
|
||||
|
||||
bool is_secured_apdu() {
|
||||
bool is_secured_apdu(void) {
|
||||
return CLA(apdu) & 0xC;
|
||||
}
|
||||
|
||||
void sm_derive_key(const uint8_t *input,
|
||||
size_t input_len,
|
||||
uint8_t counter,
|
||||
const uint8_t *nonce,
|
||||
size_t nonce_len,
|
||||
uint8_t *out) {
|
||||
static void sm_derive_key(const uint8_t *input, size_t input_len, uint8_t counter, const uint8_t *nonce, size_t nonce_len, uint8_t *out) {
|
||||
uint8_t *b = (uint8_t *) calloc(1, input_len + nonce_len + 4);
|
||||
if (input) {
|
||||
memcpy(b, input, input_len);
|
||||
@@ -60,11 +60,12 @@ void sm_derive_all_keys(const uint8_t *derived, size_t derived_len) {
|
||||
memcpy(sm_nonce, random_bytes_get(8), 8);
|
||||
sm_derive_key(derived, derived_len, 1, sm_nonce, sizeof(sm_nonce), sm_kenc);
|
||||
sm_derive_key(derived, derived_len, 2, sm_nonce, sizeof(sm_nonce), sm_kmac);
|
||||
mbedtls_mpi_free(&sm_mSSC);
|
||||
mbedtls_mpi_init(&sm_mSSC);
|
||||
mbedtls_mpi_grow(&sm_mSSC, sm_blocksize);
|
||||
mbedtls_mpi_lset(&sm_mSSC, 0);
|
||||
memset(sm_iv, 0, sizeof(sm_iv));
|
||||
sm_session_pin_len = 0;
|
||||
sm_active = true;
|
||||
}
|
||||
|
||||
void sm_set_protocol(MSE_protocol proto) {
|
||||
@@ -75,32 +76,38 @@ void sm_set_protocol(MSE_protocol proto) {
|
||||
else if (proto == MSE_3DES) {
|
||||
sm_blocksize = 8;
|
||||
}
|
||||
else {
|
||||
sm_blocksize = 0;
|
||||
}
|
||||
memset(sm_kenc, 0, sizeof(sm_kenc));
|
||||
memset(sm_kmac, 0, sizeof(sm_kmac));
|
||||
memset(sm_nonce, 0, sizeof(sm_nonce));
|
||||
memset(sm_iv, 0, sizeof(sm_iv));
|
||||
sm_active = false;
|
||||
}
|
||||
|
||||
MSE_protocol sm_get_protocol() {
|
||||
MSE_protocol sm_get_protocol(void) {
|
||||
return sm_protocol;
|
||||
}
|
||||
|
||||
uint8_t *sm_get_nonce() {
|
||||
uint8_t *sm_get_nonce(void) {
|
||||
return sm_nonce;
|
||||
}
|
||||
|
||||
int sm_sign(uint8_t *in, size_t in_len, uint8_t *out) {
|
||||
return mbedtls_cipher_cmac(mbedtls_cipher_info_from_type(MBEDTLS_CIPHER_AES_128_ECB),
|
||||
sm_kmac,
|
||||
128,
|
||||
in,
|
||||
in_len,
|
||||
out);
|
||||
int sm_sign(uint8_t *in, size_t in_len, uint8_t out[16]) {
|
||||
return mbedtls_cipher_cmac(mbedtls_cipher_info_from_type(MBEDTLS_CIPHER_AES_128_ECB), sm_kmac, 128, in, in_len, out);
|
||||
}
|
||||
|
||||
int sm_unwrap() {
|
||||
int sm_unwrap(void) {
|
||||
uint8_t sm_indicator = (CLA(apdu) >> 2) & 0x3;
|
||||
if (sm_indicator == 0) {
|
||||
return PICOKEY_OK;
|
||||
return PICOKEYS_OK;
|
||||
}
|
||||
if (!sm_active || sm_blocksize == 0) {
|
||||
return PICOKEYS_EXEC_ERROR;
|
||||
}
|
||||
int r = sm_verify();
|
||||
if (r != PICOKEY_OK) {
|
||||
if (r != PICOKEYS_OK) {
|
||||
return r;
|
||||
}
|
||||
apdu.ne = sm_get_le();
|
||||
@@ -111,10 +118,9 @@ int sm_unwrap() {
|
||||
uint16_t tag = 0x0;
|
||||
uint8_t *tag_data = NULL, *p = NULL;
|
||||
uint16_t tag_len = 0;
|
||||
asn1_ctx_t ctxi;
|
||||
asn1_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi);
|
||||
while (walk_tlv(&ctxi, &p, &tag, &tag_len, &tag_data))
|
||||
{
|
||||
tlv_ctx_t ctxi;
|
||||
tlv_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi);
|
||||
while (tlv_walk(&ctxi, &p, &tag, &tag_len, &tag_data)) {
|
||||
if (tag == 0x87 || tag == 0x85) {
|
||||
body = tag_data;
|
||||
body_size = tag_len;
|
||||
@@ -126,25 +132,28 @@ int sm_unwrap() {
|
||||
}
|
||||
if (!body) {
|
||||
apdu.nc = 0;
|
||||
return PICOKEY_OK;
|
||||
return PICOKEYS_OK;
|
||||
}
|
||||
if (is87 && *body++ != 0x1) {
|
||||
return PICOKEY_WRONG_PADDING;
|
||||
return PICOKEYS_WRONG_PADDING;
|
||||
}
|
||||
sm_update_iv();
|
||||
aes_decrypt(sm_kenc, sm_iv, 128, PICO_KEYS_AES_MODE_CBC, body, body_size);
|
||||
aes_decrypt(sm_kenc, sm_iv, 128, PICOKEYS_AES_MODE_CBC, body, body_size);
|
||||
memmove(apdu.data, body, body_size);
|
||||
apdu.nc = sm_remove_padding(apdu.data, body_size);
|
||||
DEBUG_PAYLOAD(apdu.data, (int) apdu.nc);
|
||||
return PICOKEY_OK;
|
||||
return PICOKEYS_OK;
|
||||
}
|
||||
|
||||
int sm_wrap() {
|
||||
int sm_wrap(void) {
|
||||
uint8_t sm_indicator = (CLA(apdu) >> 2) & 0x3;
|
||||
if (sm_indicator == 0) {
|
||||
return PICOKEY_OK;
|
||||
return PICOKEYS_OK;
|
||||
}
|
||||
uint8_t input[2048];
|
||||
if (!sm_active || sm_blocksize == 0) {
|
||||
return PICOKEYS_EXEC_ERROR;
|
||||
}
|
||||
uint8_t input[USB_BUFFER_SIZE];
|
||||
size_t input_len = 0;
|
||||
memset(input, 0, sizeof(input));
|
||||
mbedtls_mpi ssc;
|
||||
@@ -153,7 +162,7 @@ int sm_wrap() {
|
||||
mbedtls_mpi_copy(&sm_mSSC, &ssc);
|
||||
int r = mbedtls_mpi_write_binary(&ssc, input, sm_blocksize);
|
||||
if (r != 0) {
|
||||
return PICOKEY_EXEC_ERROR;
|
||||
return PICOKEYS_EXEC_ERROR;
|
||||
}
|
||||
input_len += sm_blocksize;
|
||||
mbedtls_mpi_free(&ssc);
|
||||
@@ -163,7 +172,7 @@ int sm_wrap() {
|
||||
res_APDU_size += (sm_blocksize - (res_APDU_size % sm_blocksize));
|
||||
DEBUG_PAYLOAD(res_APDU, res_APDU_size);
|
||||
sm_update_iv();
|
||||
aes_encrypt(sm_kenc, sm_iv, 128, PICO_KEYS_AES_MODE_CBC, res_APDU, res_APDU_size);
|
||||
aes_encrypt(sm_kenc, sm_iv, 128, PICOKEYS_AES_MODE_CBC, res_APDU, res_APDU_size);
|
||||
memmove(res_APDU + 1, res_APDU, res_APDU_size);
|
||||
res_APDU[0] = 0x1;
|
||||
res_APDU_size++;
|
||||
@@ -181,14 +190,14 @@ int sm_wrap() {
|
||||
else {
|
||||
memmove(res_APDU + 4, res_APDU, res_APDU_size);
|
||||
res_APDU[1] = 0x82;
|
||||
put_uint16_t_be(res_APDU_size, res_APDU + 2);
|
||||
put_uint16_be(res_APDU_size, res_APDU + 2);
|
||||
res_APDU_size += 4;
|
||||
}
|
||||
res_APDU[0] = 0x87;
|
||||
}
|
||||
res_APDU[res_APDU_size++] = 0x99;
|
||||
res_APDU[res_APDU_size++] = 2;
|
||||
put_uint16_t_be(apdu.sw, res_APDU + res_APDU_size);
|
||||
put_uint16_be(apdu.sw, res_APDU + res_APDU_size);
|
||||
res_APDU_size += 2;
|
||||
memcpy(input + input_len, res_APDU, res_APDU_size);
|
||||
input_len += res_APDU_size;
|
||||
@@ -202,16 +211,16 @@ int sm_wrap() {
|
||||
apdu.ne = res_APDU_size;
|
||||
}
|
||||
set_res_sw(0x90, 0x00);
|
||||
return PICOKEY_OK;
|
||||
return PICOKEYS_OK;
|
||||
}
|
||||
|
||||
uint16_t sm_get_le() {
|
||||
uint16_t sm_get_le(void) {
|
||||
uint16_t tag = 0x0;
|
||||
uint8_t *tag_data = NULL, *p = NULL;
|
||||
uint16_t tag_len = 0;
|
||||
asn1_ctx_t ctxi;
|
||||
asn1_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi);
|
||||
while (walk_tlv(&ctxi, &p, &tag, &tag_len, &tag_data)) {
|
||||
tlv_ctx_t ctxi;
|
||||
tlv_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi);
|
||||
while (tlv_walk(&ctxi, &p, &tag, &tag_len, &tag_data)) {
|
||||
if (tag == 0x97) {
|
||||
uint16_t le = 0;
|
||||
for (uint16_t t = 1; t <= tag_len; t++) {
|
||||
@@ -223,16 +232,16 @@ uint16_t sm_get_le() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sm_update_iv() {
|
||||
void sm_update_iv(void) {
|
||||
uint8_t tmp_iv[16], sc_counter[16];
|
||||
memset(tmp_iv, 0, sizeof(tmp_iv)); //IV is always 0 for encryption of IV based on counter
|
||||
mbedtls_mpi_write_binary(&sm_mSSC, sc_counter, sizeof(sc_counter));
|
||||
aes_encrypt(sm_kenc, tmp_iv, 128, PICO_KEYS_AES_MODE_CBC, sc_counter, sizeof(sc_counter));
|
||||
aes_encrypt(sm_kenc, tmp_iv, 128, PICOKEYS_AES_MODE_CBC, sc_counter, sizeof(sc_counter));
|
||||
memcpy(sm_iv, sc_counter, sizeof(sc_counter));
|
||||
}
|
||||
|
||||
int sm_verify() {
|
||||
uint8_t input[2048];
|
||||
int sm_verify(void) {
|
||||
uint8_t input[USB_BUFFER_SIZE];
|
||||
memset(input, 0, sizeof(input));
|
||||
uint16_t input_len = 0;
|
||||
int r = 0;
|
||||
@@ -242,7 +251,7 @@ int sm_verify() {
|
||||
data_len += sm_blocksize;
|
||||
}
|
||||
if (data_len + (add_header ? sm_blocksize : 0) > sizeof(input)) {
|
||||
return PICOKEY_WRONG_LENGTH;
|
||||
return PICOKEYS_WRONG_LENGTH;
|
||||
}
|
||||
mbedtls_mpi ssc;
|
||||
mbedtls_mpi_init(&ssc);
|
||||
@@ -252,7 +261,7 @@ int sm_verify() {
|
||||
input_len += sm_blocksize;
|
||||
mbedtls_mpi_free(&ssc);
|
||||
if (r != 0) {
|
||||
return PICOKEY_EXEC_ERROR;
|
||||
return PICOKEYS_EXEC_ERROR;
|
||||
}
|
||||
if (add_header) {
|
||||
input[input_len++] = CLA(apdu);
|
||||
@@ -268,12 +277,12 @@ int sm_verify() {
|
||||
uint16_t tag = 0x0;
|
||||
uint8_t *tag_data = NULL, *p = NULL;
|
||||
uint16_t tag_len = 0;
|
||||
asn1_ctx_t ctxi;
|
||||
asn1_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi);
|
||||
while (walk_tlv(&ctxi, &p, &tag, &tag_len, &tag_data)) {
|
||||
tlv_ctx_t ctxi;
|
||||
tlv_ctx_init(apdu.data, (uint16_t)apdu.nc, &ctxi);
|
||||
while (tlv_walk(&ctxi, &p, &tag, &tag_len, &tag_data)) {
|
||||
if (tag & 0x1) {
|
||||
input[input_len++] = (uint8_t)tag;
|
||||
uint8_t tlen = format_tlv_len(tag_len, input + input_len);
|
||||
uint8_t tlen = tlv_format_len(tag_len, input + input_len);
|
||||
input_len += tlen;
|
||||
memcpy(input + input_len, tag_data, tag_len);
|
||||
input_len += tag_len;
|
||||
@@ -284,8 +293,8 @@ int sm_verify() {
|
||||
mac_len = tag_len;
|
||||
}
|
||||
}
|
||||
if (!mac) {
|
||||
return PICOKEY_WRONG_DATA;
|
||||
if (!mac || mac_len != 8) {
|
||||
return PICOKEYS_WRONG_DATA;
|
||||
}
|
||||
if (some_added) {
|
||||
input[input_len++] = 0x80;
|
||||
@@ -294,12 +303,12 @@ int sm_verify() {
|
||||
uint8_t signature[16];
|
||||
r = sm_sign(input, input_len, signature);
|
||||
if (r != 0) {
|
||||
return PICOKEY_EXEC_ERROR;
|
||||
return PICOKEYS_EXEC_ERROR;
|
||||
}
|
||||
if (memcmp(signature, mac, mac_len) == 0) {
|
||||
return PICOKEY_OK;
|
||||
return PICOKEYS_OK;
|
||||
}
|
||||
return PICOKEY_VERIFICATION_FAILED;
|
||||
return PICOKEYS_VERIFICATION_FAILED;
|
||||
}
|
||||
|
||||
uint16_t sm_remove_padding(const uint8_t *data, uint16_t data_len) {
|
||||
|
||||
24
src/eac.h
24
src/eac.h
@@ -18,7 +18,9 @@
|
||||
#ifndef _EAC_H_
|
||||
#define _EAC_H_
|
||||
|
||||
#include "pico_keys.h"
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
typedef enum MSE_protocol {
|
||||
MSE_AES = 0,
|
||||
@@ -28,17 +30,15 @@ typedef enum MSE_protocol {
|
||||
|
||||
extern void sm_derive_all_keys(const uint8_t *input, size_t input_len);
|
||||
extern void sm_set_protocol(MSE_protocol proto);
|
||||
extern MSE_protocol sm_get_protocol();
|
||||
extern uint8_t *sm_get_nonce();
|
||||
extern int sm_sign(uint8_t *in, size_t in_len, uint8_t *out);
|
||||
int sm_verify();
|
||||
void sm_update_iv();
|
||||
uint16_t sm_get_le();
|
||||
extern int sm_unwrap();
|
||||
extern MSE_protocol sm_get_protocol(void);
|
||||
extern uint8_t *sm_get_nonce(void);
|
||||
extern int sm_sign(uint8_t *in, size_t in_len, uint8_t out[16]);
|
||||
int sm_verify(void);
|
||||
void sm_update_iv(void);
|
||||
uint16_t sm_get_le(void);
|
||||
extern int sm_unwrap(void);
|
||||
uint16_t sm_remove_padding(const uint8_t *data, uint16_t data_len);
|
||||
extern int sm_wrap();
|
||||
extern bool is_secured_apdu();
|
||||
extern uint8_t sm_session_pin[16];
|
||||
extern uint16_t sm_session_pin_len;
|
||||
extern int sm_wrap(void);
|
||||
extern bool is_secured_apdu(void);
|
||||
|
||||
#endif
|
||||
|
||||
220
src/fs/file.c
220
src/fs/file.c
@@ -15,33 +15,27 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "picokeys.h"
|
||||
#include "file.h"
|
||||
#include "pico_keys.h"
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include "asn1.h"
|
||||
#include "tlv.h"
|
||||
#include "apdu.h"
|
||||
#include <stdio.h>
|
||||
|
||||
#define MAX_DEPTH 4
|
||||
|
||||
#define MAX_DYNAMIC_FILES 256
|
||||
|
||||
extern const uintptr_t end_data_pool;
|
||||
extern const uintptr_t start_data_pool;
|
||||
extern const uintptr_t end_rom_pool;
|
||||
extern const uintptr_t start_rom_pool;
|
||||
extern int flash_write_data_to_file(file_t *file, const uint8_t *data, uint16_t len);
|
||||
extern int flash_program_block(uintptr_t addr, const uint8_t *data, size_t len);
|
||||
extern uintptr_t flash_read_uintptr(uintptr_t addr);
|
||||
extern uint16_t flash_read_uint16(uintptr_t addr);
|
||||
extern uint8_t flash_read_uint8(uintptr_t addr);
|
||||
extern uint8_t *flash_read(uintptr_t addr);
|
||||
extern int flash_clear_file(file_t *ef);
|
||||
extern void low_flash_available();
|
||||
|
||||
#ifndef ENABLE_EMULATION
|
||||
file_t sef_phy = {.fid = EF_PHY, .parent = 5, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH | FILE_PERSISTENT, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0xff}};
|
||||
file_t *ef_phy = &sef_phy;
|
||||
#endif
|
||||
|
||||
//puts FCI in the RAPDU
|
||||
void process_fci(const file_t *pe, int fmd) {
|
||||
void file_process_fci(const file_t *pe, int fmd) {
|
||||
res_APDU_size = 0;
|
||||
if (fmd) {
|
||||
res_APDU[res_APDU_size++] = 0x6f;
|
||||
@@ -55,12 +49,13 @@ void process_fci(const file_t *pe, int fmd) {
|
||||
res_APDU[res_APDU_size++] = 2;
|
||||
if (pe->data) {
|
||||
if ((pe->type & FILE_DATA_FUNC) == FILE_DATA_FUNC) {
|
||||
uint16_t len = (uint16_t)((int (*)(const file_t *, int))(pe->data))(pe, 0);
|
||||
res_APDU_size += put_uint16_t_be(len, res_APDU + res_APDU_size);
|
||||
int (*data_fn)(const file_t *, int) = (int (*)(const file_t *, int))(uintptr_t)pe->data;
|
||||
uint16_t len = (uint16_t)data_fn(pe, 0);
|
||||
res_APDU_size += put_uint16_be(len, res_APDU + res_APDU_size);
|
||||
}
|
||||
else {
|
||||
uint16_t v = file_get_size(pe);
|
||||
res_APDU_size += put_uint16_t_be(v, res_APDU + res_APDU_size);
|
||||
res_APDU_size += put_uint16_be(v, res_APDU + res_APDU_size);
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -86,7 +81,7 @@ void process_fci(const file_t *pe, int fmd) {
|
||||
|
||||
res_APDU[res_APDU_size++] = 0x83;
|
||||
res_APDU[res_APDU_size++] = 2;
|
||||
res_APDU_size += put_uint16_t_be(pe->fid, res_APDU + res_APDU_size);
|
||||
res_APDU_size += put_uint16_be(pe->fid, res_APDU + res_APDU_size);
|
||||
if (pe->name) {
|
||||
res_APDU[res_APDU_size++] = 0x84;
|
||||
res_APDU[res_APDU_size++] = MIN(pe->name[0], 16);
|
||||
@@ -115,7 +110,7 @@ file_t dynamic_file[MAX_DYNAMIC_FILES];
|
||||
|
||||
bool card_terminated = false;
|
||||
|
||||
bool is_parent(const file_t *child, const file_t *parent) {
|
||||
static bool is_parent(const file_t *child, const file_t *parent) {
|
||||
if (child == parent) {
|
||||
return true;
|
||||
}
|
||||
@@ -129,7 +124,7 @@ file_t *get_parent(file_t *f) {
|
||||
return &file_entries[f->parent];
|
||||
}
|
||||
|
||||
file_t *search_by_name(uint8_t *name, uint16_t namelen) {
|
||||
file_t *file_search_by_name(uint8_t *name, uint16_t namelen) {
|
||||
for (file_t *p = file_entries; p != file_last; p++) {
|
||||
if (p->name && *p->name == apdu.nc && memcmp(p->name + 1, name, namelen) == 0) {
|
||||
return p;
|
||||
@@ -138,7 +133,7 @@ file_t *search_by_name(uint8_t *name, uint16_t namelen) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
file_t *search_by_fid(const uint16_t fid, const file_t *parent, const uint8_t sp) {
|
||||
file_t *file_search_by_fid(const uint16_t fid, const file_t *parent, const uint8_t sp) {
|
||||
#ifndef ENABLE_EMULATION
|
||||
if (fid == EF_PHY) {
|
||||
return ef_phy;
|
||||
@@ -158,28 +153,37 @@ file_t *search_by_fid(const uint16_t fid, const file_t *parent, const uint8_t sp
|
||||
return NULL;
|
||||
}
|
||||
|
||||
file_t *search_file(const uint16_t fid) {
|
||||
file_t *ef = search_by_fid(fid, NULL, SPECIFY_EF);
|
||||
static file_t *search_dynamic_file(uint16_t fid) {
|
||||
for (int i = 0; i < dynamic_files; i++) {
|
||||
if (dynamic_file[i].fid == fid) {
|
||||
return &dynamic_file[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
file_t *file_search(const uint16_t fid) {
|
||||
file_t *ef = file_search_by_fid(fid, NULL, SPECIFY_EF);
|
||||
if (ef) {
|
||||
return ef;
|
||||
}
|
||||
return search_dynamic_file(fid);
|
||||
}
|
||||
|
||||
uint8_t make_path_buf(const file_t *pe, uint8_t *buf, uint8_t buflen, const file_t *top) {
|
||||
static uint8_t make_path_buf(const file_t *pe, uint8_t *buf, uint8_t buflen, const file_t *top) {
|
||||
if (!buflen) {
|
||||
return 0;
|
||||
}
|
||||
if (pe == top) { //MF or relative DF
|
||||
return 0;
|
||||
}
|
||||
put_uint16_t_be(pe->fid, buf);
|
||||
put_uint16_be(pe->fid, buf);
|
||||
return make_path_buf(&file_entries[pe->parent], buf + 2, buflen - 2, top) + 2;
|
||||
}
|
||||
|
||||
uint8_t make_path(const file_t *pe, const file_t *top, uint8_t *path) {
|
||||
static uint8_t make_path(const file_t *pe, const file_t *top, uint8_t *path) {
|
||||
uint8_t buf[MAX_DEPTH * 2], *p = path;
|
||||
put_uint16_t_be(pe->fid, buf);
|
||||
put_uint16_be(pe->fid, buf);
|
||||
uint8_t depth = make_path_buf(&file_entries[pe->parent], buf + 2, sizeof(buf) - 2, top) + 2;
|
||||
for (int d = depth - 2; d >= 0; d -= 2) {
|
||||
memcpy(p, buf + d, 2);
|
||||
@@ -188,7 +192,7 @@ uint8_t make_path(const file_t *pe, const file_t *top, uint8_t *path) {
|
||||
return depth;
|
||||
}
|
||||
|
||||
file_t *search_by_path(const uint8_t *pe_path, uint8_t pathlen, const file_t *parent) {
|
||||
file_t *file_search_by_path(const uint8_t *pe_path, uint8_t pathlen, const file_t *parent) {
|
||||
uint8_t path[MAX_DEPTH * 2];
|
||||
if (pathlen > sizeof(path)) {
|
||||
return NULL;
|
||||
@@ -207,7 +211,7 @@ file_t *currentDF = NULL;
|
||||
const file_t *selected_applet = NULL;
|
||||
bool isUserAuthenticated = false;
|
||||
|
||||
bool authenticate_action(const file_t *ef, uint8_t op) {
|
||||
bool file_authenticate_action(const file_t *ef, uint8_t op) {
|
||||
uint8_t acl = ef->acl[op];
|
||||
if (acl == 0x0) {
|
||||
return true;
|
||||
@@ -227,11 +231,11 @@ bool authenticate_action(const file_t *ef, uint8_t op) {
|
||||
return false;
|
||||
}
|
||||
|
||||
void initialize_flash(bool hard) {
|
||||
void file_initialize_flash(bool hard) {
|
||||
if (hard) {
|
||||
const uint8_t empty[8] = { 0 };
|
||||
flash_program_block(end_data_pool, empty, sizeof(empty));
|
||||
low_flash_available();
|
||||
flash_commit();
|
||||
}
|
||||
for (file_t *f = file_entries; f != file_last; f++) {
|
||||
if ((f->type & FILE_DATA_FLASH) == FILE_DATA_FLASH) {
|
||||
@@ -243,8 +247,7 @@ void initialize_flash(bool hard) {
|
||||
|
||||
extern uintptr_t last_base;
|
||||
extern uint32_t num_files;
|
||||
void scan_region(bool persistent)
|
||||
{
|
||||
static void scan_region(bool persistent) {
|
||||
uintptr_t endp = end_data_pool, startp = start_data_pool;
|
||||
if (persistent) {
|
||||
endp = end_rom_pool;
|
||||
@@ -261,7 +264,7 @@ void scan_region(bool persistent)
|
||||
|
||||
uint16_t fid = flash_read_uint16(base + sizeof(uintptr_t) + sizeof(uintptr_t));
|
||||
printf("[%x] scan fid %x, len %d\n", (unsigned int) base, fid, flash_read_uint16(base + sizeof(uintptr_t) + sizeof(uintptr_t) + sizeof(uint16_t)));
|
||||
file_t *file = (file_t *) search_by_fid(fid, NULL, SPECIFY_EF);
|
||||
file_t *file = (file_t *) file_search_by_fid(fid, NULL, SPECIFY_EF);
|
||||
if (!file) {
|
||||
file = file_new(fid);
|
||||
}
|
||||
@@ -279,18 +282,17 @@ void scan_region(bool persistent)
|
||||
}
|
||||
}
|
||||
}
|
||||
void wait_flash_finish();
|
||||
void scan_flash() {
|
||||
initialize_flash(false); //soft initialization
|
||||
uint32_t r1 = (uint32_t)(*(uintptr_t *) flash_read(end_rom_pool)), r2 = (uint32_t)(*(uintptr_t *) flash_read(end_rom_pool + sizeof(uintptr_t)));
|
||||
void file_scan_flash(void) {
|
||||
file_initialize_flash(false); //soft initialization
|
||||
uint32_t r1 = (uint32_t)flash_read_uintptr(end_rom_pool);
|
||||
uint32_t r2 = (uint32_t)flash_read_uintptr(end_rom_pool + sizeof(uintptr_t));
|
||||
if ((r1 == 0xffffffff || r1 == 0xefefefef) && (r2 == 0xffffffff || r2 == 0xefefefef)) {
|
||||
printf("First initialization (or corrupted!)\n");
|
||||
uint8_t empty[sizeof(uintptr_t) * 2 + sizeof(uint32_t)];
|
||||
memset(empty, 0, sizeof(empty));
|
||||
flash_program_block(end_data_pool, empty, sizeof(empty));
|
||||
flash_program_block(end_rom_pool, empty, sizeof(empty));
|
||||
//low_flash_available();
|
||||
//wait_flash_finish();
|
||||
//flash_commit();
|
||||
}
|
||||
printf("SCAN\n");
|
||||
scan_region(true);
|
||||
@@ -328,18 +330,9 @@ int file_put_data(file_t *file, const uint8_t *data, uint16_t len) {
|
||||
return flash_write_data_to_file(file, data, len);
|
||||
}
|
||||
|
||||
file_t *search_dynamic_file(uint16_t fid) {
|
||||
for (int i = 0; i < dynamic_files; i++) {
|
||||
if (dynamic_file[i].fid == fid) {
|
||||
return &dynamic_file[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int delete_dynamic_file(file_t *f) {
|
||||
static int delete_dynamic_file(file_t *f) {
|
||||
if (f == NULL) {
|
||||
return PICOKEY_ERR_FILE_NOT_FOUND;
|
||||
return PICOKEYS_ERR_FILE_NOT_FOUND;
|
||||
}
|
||||
for (int i = 0; i < dynamic_files; i++) {
|
||||
if (dynamic_file[i].fid == f->fid) {
|
||||
@@ -347,15 +340,15 @@ int delete_dynamic_file(file_t *f) {
|
||||
memcpy(&dynamic_file[j - 1], &dynamic_file[j], sizeof(file_t));
|
||||
}
|
||||
dynamic_files--;
|
||||
return PICOKEY_OK;
|
||||
return PICOKEYS_OK;
|
||||
}
|
||||
}
|
||||
return PICOKEY_ERR_FILE_NOT_FOUND;
|
||||
return PICOKEYS_ERR_FILE_NOT_FOUND;
|
||||
}
|
||||
|
||||
file_t *file_new(uint16_t fid) {
|
||||
file_t *f;
|
||||
if ((f = search_file(fid))) {
|
||||
if ((f = file_search(fid))) {
|
||||
return f;
|
||||
}
|
||||
if (dynamic_files == MAX_DYNAMIC_FILES) {
|
||||
@@ -377,20 +370,20 @@ file_t *file_new(uint16_t fid) {
|
||||
return f;
|
||||
}
|
||||
uint16_t meta_find(uint16_t fid, uint8_t **out) {
|
||||
file_t *ef = search_file(EF_META);
|
||||
file_t *ef = file_search(EF_META);
|
||||
if (!ef) {
|
||||
return 0;
|
||||
}
|
||||
uint16_t tag = 0x0;
|
||||
uint8_t *tag_data = NULL, *p = NULL;
|
||||
uint16_t tag_len = 0;
|
||||
asn1_ctx_t ctxi;
|
||||
asn1_ctx_init(file_get_data(ef), file_get_size(ef), &ctxi);
|
||||
while (walk_tlv(&ctxi, &p, &tag, &tag_len, &tag_data)) {
|
||||
tlv_ctx_t ctxi;
|
||||
tlv_ctx_init(file_get_data(ef), file_get_size(ef), &ctxi);
|
||||
while (tlv_walk(&ctxi, &p, &tag, &tag_len, &tag_data)) {
|
||||
if (tag_len < 2) {
|
||||
continue;
|
||||
}
|
||||
uint16_t cfid = get_uint16_t_be(tag_data);
|
||||
uint16_t cfid = get_uint16_be(tag_data);
|
||||
if (cfid == fid) {
|
||||
if (out) {
|
||||
*out = tag_data + 2;
|
||||
@@ -401,24 +394,24 @@ uint16_t meta_find(uint16_t fid, uint8_t **out) {
|
||||
return 0;
|
||||
}
|
||||
int meta_delete(uint16_t fid) {
|
||||
file_t *ef = search_file(EF_META);
|
||||
file_t *ef = file_search(EF_META);
|
||||
if (!ef) {
|
||||
return PICOKEY_ERR_FILE_NOT_FOUND;
|
||||
return PICOKEYS_ERR_FILE_NOT_FOUND;
|
||||
}
|
||||
uint16_t tag = 0x0;
|
||||
uint8_t *tag_data = NULL, *p = NULL;
|
||||
uint16_t tag_len = 0;
|
||||
uint8_t *fdata = NULL;
|
||||
asn1_ctx_t ctxi;
|
||||
asn1_ctx_init(file_get_data(ef), file_get_size(ef), &ctxi);
|
||||
while (walk_tlv(&ctxi, &p, &tag, &tag_len, &tag_data)) {
|
||||
uint8_t *tpos = p - tag_len - format_tlv_len(tag_len, NULL) - 1;
|
||||
tlv_ctx_t ctxi;
|
||||
tlv_ctx_init(file_get_data(ef), file_get_size(ef), &ctxi);
|
||||
while (tlv_walk(&ctxi, &p, &tag, &tag_len, &tag_data)) {
|
||||
uint8_t *tpos = p - tag_len - tlv_format_len(tag_len, NULL) - 1;
|
||||
if (tag_len < 2) {
|
||||
continue;
|
||||
}
|
||||
uint16_t cfid = get_uint16_t_be(tag_data);
|
||||
uint16_t cfid = get_uint16_be(tag_data);
|
||||
if (cfid == fid) {
|
||||
uint16_t new_len = ctxi.len - 1 - tag_len - format_tlv_len(tag_len, NULL);
|
||||
uint16_t new_len = ctxi.len - 1 - tag_len - tlv_format_len(tag_len, NULL);
|
||||
if (new_len == 0) {
|
||||
flash_clear_file(ef);
|
||||
}
|
||||
@@ -432,21 +425,21 @@ int meta_delete(uint16_t fid) {
|
||||
}
|
||||
int r = file_put_data(ef, fdata, new_len);
|
||||
free(fdata);
|
||||
if (r != PICOKEY_OK) {
|
||||
return PICOKEY_EXEC_ERROR;
|
||||
if (r != PICOKEYS_OK) {
|
||||
return PICOKEYS_EXEC_ERROR;
|
||||
}
|
||||
}
|
||||
low_flash_available();
|
||||
flash_commit();
|
||||
break;
|
||||
}
|
||||
}
|
||||
return PICOKEY_OK;
|
||||
return PICOKEYS_OK;
|
||||
}
|
||||
int meta_add(uint16_t fid, const uint8_t *data, uint16_t len) {
|
||||
int r;
|
||||
file_t *ef = search_file(EF_META);
|
||||
file_t *ef = file_search(EF_META);
|
||||
if (!ef) {
|
||||
return PICOKEY_ERR_FILE_NOT_FOUND;
|
||||
return PICOKEYS_ERR_FILE_NOT_FOUND;
|
||||
}
|
||||
uint16_t ef_size = file_get_size(ef);
|
||||
uint8_t *fdata = (uint8_t *) calloc(1, ef_size);
|
||||
@@ -454,25 +447,25 @@ int meta_add(uint16_t fid, const uint8_t *data, uint16_t len) {
|
||||
uint16_t tag = 0x0;
|
||||
uint8_t *tag_data = NULL, *p = NULL;
|
||||
uint16_t tag_len = 0;
|
||||
asn1_ctx_t ctxi;
|
||||
asn1_ctx_init(fdata, ef_size, &ctxi);
|
||||
while (walk_tlv(&ctxi, &p, &tag, &tag_len, &tag_data)) {
|
||||
tlv_ctx_t ctxi;
|
||||
tlv_ctx_init(fdata, ef_size, &ctxi);
|
||||
while (tlv_walk(&ctxi, &p, &tag, &tag_len, &tag_data)) {
|
||||
if (tag_len < 2) {
|
||||
continue;
|
||||
}
|
||||
uint16_t cfid = get_uint16_t_be(tag_data);
|
||||
uint16_t cfid = get_uint16_be(tag_data);
|
||||
if (cfid == fid) {
|
||||
if (tag_len - 2 == len) { //an update
|
||||
memcpy(p - tag_len + 2, data, len);
|
||||
r = file_put_data(ef, fdata, ef_size);
|
||||
free(fdata);
|
||||
if (r != PICOKEY_OK) {
|
||||
return PICOKEY_EXEC_ERROR;
|
||||
if (r != PICOKEYS_OK) {
|
||||
return PICOKEYS_EXEC_ERROR;
|
||||
}
|
||||
return PICOKEY_OK;
|
||||
return PICOKEYS_OK;
|
||||
}
|
||||
else { //needs reallocation
|
||||
uint8_t *tpos = p - asn1_len_tag(tag, tag_len);
|
||||
uint8_t *tpos = p - tlv_len_tag(tag, tag_len);
|
||||
memmove(tpos, p, fdata + ef_size - p);
|
||||
tpos += fdata + ef_size - p;
|
||||
volatile uintptr_t meta_offset = tpos - fdata;
|
||||
@@ -484,52 +477,73 @@ int meta_add(uint16_t fid, const uint8_t *data, uint16_t len) {
|
||||
}
|
||||
else {
|
||||
free(fdata);
|
||||
return PICOKEY_ERR_MEMORY_FATAL;
|
||||
return PICOKEYS_ERR_MEMORY_FATAL;
|
||||
}
|
||||
}
|
||||
uint8_t *f = fdata + meta_offset;
|
||||
*f++ = fid & 0xff;
|
||||
f += format_tlv_len(len + 2, f);
|
||||
f += put_uint16_t_be(fid, f);
|
||||
f += tlv_format_len(len + 2, f);
|
||||
f += put_uint16_be(fid, f);
|
||||
memcpy(f, data, len);
|
||||
r = file_put_data(ef, fdata, ef_size);
|
||||
free(fdata);
|
||||
if (r != PICOKEY_OK) {
|
||||
return PICOKEY_EXEC_ERROR;
|
||||
if (r != PICOKEYS_OK) {
|
||||
return PICOKEYS_EXEC_ERROR;
|
||||
}
|
||||
return PICOKEY_OK;
|
||||
return PICOKEYS_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
fdata = (uint8_t *) realloc(fdata, ef_size + asn1_len_tag(fid & 0x1f, len + 2));
|
||||
fdata = (uint8_t *) realloc(fdata, ef_size + tlv_len_tag(fid & 0x1f, len + 2));
|
||||
uint8_t *f = fdata + ef_size;
|
||||
*f++ = fid & 0x1f;
|
||||
f += format_tlv_len(len + 2, f);
|
||||
f += put_uint16_t_be(fid, f);
|
||||
f += tlv_format_len(len + 2, f);
|
||||
f += put_uint16_be(fid, f);
|
||||
memcpy(f, data, len);
|
||||
r = file_put_data(ef, fdata, ef_size + (uint16_t)asn1_len_tag(fid & 0x1f, len + 2));
|
||||
r = file_put_data(ef, fdata, ef_size + (uint16_t)tlv_len_tag(fid & 0x1f, len + 2));
|
||||
free(fdata);
|
||||
if (r != PICOKEY_OK) {
|
||||
return PICOKEY_EXEC_ERROR;
|
||||
if (r != PICOKEYS_OK) {
|
||||
return PICOKEYS_EXEC_ERROR;
|
||||
}
|
||||
return PICOKEY_OK;
|
||||
return PICOKEYS_OK;
|
||||
}
|
||||
|
||||
bool file_has_data(file_t *f) {
|
||||
bool file_has_data(const file_t *f) {
|
||||
return f != NULL && f->data != NULL && file_get_size(f) > 0;
|
||||
}
|
||||
|
||||
int delete_file(file_t *ef) {
|
||||
int file_delete(file_t *ef) {
|
||||
if (ef == NULL) {
|
||||
return PICOKEY_OK;
|
||||
return PICOKEYS_OK;
|
||||
}
|
||||
meta_delete(ef->fid);
|
||||
if (flash_clear_file(ef) != PICOKEY_OK) {
|
||||
return PICOKEY_EXEC_ERROR;
|
||||
if (flash_clear_file(ef) != PICOKEYS_OK) {
|
||||
return PICOKEYS_EXEC_ERROR;
|
||||
}
|
||||
if (delete_dynamic_file(ef) != PICOKEY_OK) {
|
||||
return PICOKEY_EXEC_ERROR;
|
||||
if (delete_dynamic_file(ef) != PICOKEYS_OK) {
|
||||
return PICOKEYS_EXEC_ERROR;
|
||||
}
|
||||
low_flash_available();
|
||||
return PICOKEY_OK;
|
||||
flash_commit();
|
||||
return PICOKEYS_OK;
|
||||
}
|
||||
|
||||
int flash_clear_file(file_t *file) {
|
||||
if (file == NULL || file->data == NULL) {
|
||||
return PICOKEYS_OK;
|
||||
}
|
||||
uintptr_t base_addr = (uintptr_t)(file->data - sizeof(uintptr_t) - sizeof(uint16_t) - sizeof(uintptr_t));
|
||||
uintptr_t prev_addr = flash_read_uintptr(base_addr + sizeof(uintptr_t));
|
||||
uintptr_t next_addr = flash_read_uintptr(base_addr);
|
||||
//printf("nc %lx->%lx %lx->%lx\n",prev_addr,flash_read_uintptr(prev_addr),base_addr,next_addr);
|
||||
flash_program_uintptr(prev_addr, next_addr);
|
||||
flash_program_halfword((uintptr_t) file->data, 0);
|
||||
if (next_addr > 0) {
|
||||
flash_program_uintptr(next_addr + sizeof(uintptr_t), prev_addr);
|
||||
}
|
||||
flash_program_uintptr(base_addr, 0);
|
||||
flash_program_uintptr(base_addr + sizeof(uintptr_t), 0);
|
||||
file->data = NULL;
|
||||
num_files--;
|
||||
//printf("na %lx->%lx\n",prev_addr,flash_read_uintptr(prev_addr));
|
||||
return PICOKEYS_OK;
|
||||
}
|
||||
|
||||
@@ -18,14 +18,10 @@
|
||||
#ifndef _FILE_H_
|
||||
#define _FILE_H_
|
||||
|
||||
#include <stdlib.h>
|
||||
#if defined(PICO_PLATFORM)
|
||||
#include "pico/stdlib.h"
|
||||
#else
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
#include "compat.h"
|
||||
#include <stdbool.h>
|
||||
#include "compat/compat.h"
|
||||
#include "phy.h"
|
||||
|
||||
#define FILE_TYPE_NOT_KNOWN 0x00
|
||||
@@ -55,22 +51,19 @@
|
||||
#define ACL_OP_UPDATE_ERASE 0x05
|
||||
#define ACL_OP_READ_SEARCH 0x06
|
||||
|
||||
#define ACL_NONE { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }
|
||||
#define ACL_ALL { 0 }
|
||||
#define ACL_RO { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00 }
|
||||
#define ACL_RW { 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00 }
|
||||
#define ACL_R_WP { 0xff, 0xff, 0xff, 0xff, 0x90, 0x90, 0x00 }
|
||||
#define ACL_WP { 0xff, 0xff, 0xff, 0xff, 0x90, 0x90, 0xff }
|
||||
|
||||
#define SPECIFY_EF 0x1
|
||||
#define SPECIFY_DF 0x2
|
||||
#define SPECIFY_ANY 0x3
|
||||
|
||||
#define EF_PRKDFS 0x6040
|
||||
#define EF_PUKDFS 0x6041
|
||||
#define EF_CDFS 0x6042
|
||||
#define EF_AODFS 0x6043
|
||||
#define EF_DODFS 0x6044
|
||||
#define EF_SKDFS 0x6045
|
||||
#define EF_META 0xE010
|
||||
|
||||
#define MAX_DEPTH 4
|
||||
|
||||
#define MAX_DYNAMIC_FILES 256
|
||||
|
||||
#ifdef _MSC_VER
|
||||
__pragma( pack(push, 1) )
|
||||
#endif
|
||||
@@ -78,7 +71,7 @@ typedef struct file {
|
||||
const uint8_t *name;
|
||||
uint8_t *data; //should include 2 bytes len at begining
|
||||
const uint16_t fid;
|
||||
const uint8_t acl[7];
|
||||
uint8_t acl[7];
|
||||
const uint8_t parent; //entry number in the whole table!!
|
||||
const uint8_t type;
|
||||
const uint8_t ef_structure;
|
||||
@@ -93,30 +86,22 @@ __attribute__ ((packed))
|
||||
#endif
|
||||
file_t;
|
||||
|
||||
extern bool file_has_data(file_t *);
|
||||
|
||||
extern file_t *currentEF;
|
||||
extern file_t *currentDF;
|
||||
extern const file_t *selected_applet;
|
||||
|
||||
extern const file_t *MF;
|
||||
extern const file_t *file_last;
|
||||
extern const file_t *file_openpgp;
|
||||
extern const file_t *file_sc_hsm;
|
||||
extern bool card_terminated;
|
||||
extern file_t *file_pin1;
|
||||
extern file_t *file_retries_pin1;
|
||||
extern file_t *file_sopin;
|
||||
extern file_t *file_retries_sopin;
|
||||
|
||||
extern file_t *search_by_fid(const uint16_t fid, const file_t *parent, const uint8_t sp);
|
||||
extern file_t *search_file(const uint16_t fid);
|
||||
extern file_t *search_by_name(uint8_t *name, uint16_t namelen);
|
||||
extern file_t *search_by_path(const uint8_t *pe_path, uint8_t pathlen, const file_t *parent);
|
||||
extern bool authenticate_action(const file_t *ef, uint8_t op);
|
||||
extern void process_fci(const file_t *pe, int fmd);
|
||||
extern void scan_flash();
|
||||
extern void initialize_flash(bool);
|
||||
extern file_t *file_search_by_fid(const uint16_t fid, const file_t *parent, const uint8_t sp);
|
||||
extern file_t *file_search(const uint16_t fid);
|
||||
extern file_t *file_search_by_name(uint8_t *name, uint16_t namelen);
|
||||
extern file_t *file_search_by_path(const uint8_t *pe_path, uint8_t pathlen, const file_t *parent);
|
||||
extern bool file_authenticate_action(const file_t *ef, uint8_t op);
|
||||
extern void file_process_fci(const file_t *pe, int fmd);
|
||||
extern void file_scan_flash(void);
|
||||
extern void file_initialize_flash(bool);
|
||||
|
||||
extern file_t file_entries[];
|
||||
|
||||
@@ -124,29 +109,20 @@ extern uint8_t *file_read(const uint8_t *addr);
|
||||
extern uint16_t file_read_uint16(const uint8_t *addr);
|
||||
extern uint8_t file_read_uint8(const file_t *ef);
|
||||
extern uint8_t file_read_uint8_offset(const file_t *ef, const uint16_t offset);
|
||||
extern bool file_has_data(const file_t *);
|
||||
extern uint8_t *file_get_data(const file_t *tf);
|
||||
extern uint16_t file_get_size(const file_t *tf);
|
||||
extern int file_put_data(file_t *file, const uint8_t *data, uint16_t len);
|
||||
extern file_t *file_new(uint16_t);
|
||||
extern int flash_clear_file(file_t *file);
|
||||
extern int file_delete(file_t *ef);
|
||||
file_t *get_parent(file_t *f);
|
||||
|
||||
extern uint16_t dynamic_files;
|
||||
extern file_t dynamic_file[];
|
||||
extern file_t *search_dynamic_file(uint16_t);
|
||||
extern int delete_dynamic_file(file_t *f);
|
||||
|
||||
extern bool isUserAuthenticated;
|
||||
|
||||
extern uint16_t meta_find(uint16_t, uint8_t **out);
|
||||
extern int meta_delete(uint16_t fid);
|
||||
extern int meta_add(uint16_t fid, const uint8_t *data, uint16_t len);
|
||||
extern int delete_file(file_t *ef);
|
||||
|
||||
extern uint32_t flash_free_space();
|
||||
extern uint32_t flash_used_space();
|
||||
extern uint32_t flash_total_space();
|
||||
extern uint32_t flash_num_files();
|
||||
extern uint32_t flash_size();
|
||||
|
||||
#ifndef ENABLE_EMULATION
|
||||
extern file_t *ef_phy;
|
||||
|
||||
@@ -15,14 +15,15 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include "pico_keys.h"
|
||||
#include "picokeys.h"
|
||||
|
||||
#if !defined(PICO_PLATFORM)
|
||||
#define XIP_BASE 0
|
||||
#define FLASH_SECTOR_SIZE 4096
|
||||
#ifdef ENABLE_EMULATION
|
||||
#define FLASH_SECTOR_SIZE 0x4000
|
||||
#else
|
||||
#define FLASH_SECTOR_SIZE 0x1000
|
||||
#endif
|
||||
#ifdef ESP_PLATFORM
|
||||
uint32_t FLASH_SIZE_BYTES = (1 * 1024 * 1024);
|
||||
#else
|
||||
@@ -30,11 +31,12 @@ uint32_t FLASH_SIZE_BYTES = (1 * 1024 * 1024);
|
||||
#endif
|
||||
#else
|
||||
uint32_t FLASH_SIZE_BYTES = (2 * 1024 * 1024);
|
||||
#include "pico/stdlib.h"
|
||||
#include "hardware/flash.h"
|
||||
#endif
|
||||
#include "file.h"
|
||||
#include <stdio.h>
|
||||
|
||||
extern void low_flash_task(void);
|
||||
extern void low_flash_commit(void);
|
||||
|
||||
/*
|
||||
* ------------------------------------------------------
|
||||
@@ -50,15 +52,6 @@ uint32_t FLASH_SIZE_BYTES = (2 * 1024 * 1024);
|
||||
//To avoid possible future allocations, data region starts at the end of flash and goes upwards to the center region
|
||||
uintptr_t end_flash, end_rom_pool, start_rom_pool, end_data_pool, start_data_pool;
|
||||
|
||||
extern int flash_program_block(uintptr_t addr, const uint8_t *data, size_t len);
|
||||
extern int flash_program_halfword(uintptr_t addr, uint16_t data);
|
||||
extern int flash_program_uintptr(uintptr_t, uintptr_t);
|
||||
extern uintptr_t flash_read_uintptr(uintptr_t addr);
|
||||
extern uint16_t flash_read_uint16(uintptr_t addr);
|
||||
extern uint8_t *flash_read(uintptr_t addr);
|
||||
|
||||
extern void low_flash_available();
|
||||
|
||||
uintptr_t last_base;
|
||||
uint32_t num_files = 0;
|
||||
|
||||
@@ -72,7 +65,7 @@ void flash_set_bounds(uintptr_t start, uintptr_t end) {
|
||||
last_base = end_data_pool;
|
||||
}
|
||||
|
||||
uintptr_t allocate_free_addr(uint16_t size, bool persistent) {
|
||||
static uintptr_t allocate_free_addr(uint16_t size, bool persistent) {
|
||||
if (size > FLASH_SECTOR_SIZE) {
|
||||
return 0x0; //ERROR
|
||||
}
|
||||
@@ -119,35 +112,14 @@ uintptr_t allocate_free_addr(uint16_t size, bool persistent) {
|
||||
return 0x0; //probably never reached
|
||||
}
|
||||
|
||||
int flash_clear_file(file_t *file) {
|
||||
if (file == NULL || file->data == NULL) {
|
||||
return PICOKEY_OK;
|
||||
}
|
||||
uintptr_t base_addr = (uintptr_t)(file->data - sizeof(uintptr_t) - sizeof(uint16_t) - sizeof(uintptr_t));
|
||||
uintptr_t prev_addr = flash_read_uintptr(base_addr + sizeof(uintptr_t));
|
||||
uintptr_t next_addr = flash_read_uintptr(base_addr);
|
||||
//printf("nc %lx->%lx %lx->%lx\n",prev_addr,flash_read_uintptr(prev_addr),base_addr,next_addr);
|
||||
flash_program_uintptr(prev_addr, next_addr);
|
||||
flash_program_halfword((uintptr_t) file->data, 0);
|
||||
if (next_addr > 0) {
|
||||
flash_program_uintptr(next_addr + sizeof(uintptr_t), prev_addr);
|
||||
}
|
||||
flash_program_uintptr(base_addr, 0);
|
||||
flash_program_uintptr(base_addr + sizeof(uintptr_t), 0);
|
||||
file->data = NULL;
|
||||
num_files--;
|
||||
//printf("na %lx->%lx\n",prev_addr,flash_read_uintptr(prev_addr));
|
||||
return PICOKEY_OK;
|
||||
}
|
||||
|
||||
int flash_write_data_to_file_offset(file_t *file, const uint8_t *data, uint16_t len, uint16_t offset) {
|
||||
static int flash_write_data_to_file_offset(file_t *file, const uint8_t *data, uint16_t len, uint16_t offset) {
|
||||
if (!file) {
|
||||
return PICOKEY_ERR_NULL_PARAM;
|
||||
return PICOKEYS_ERR_NULL_PARAM;
|
||||
}
|
||||
uint16_t size_file_flash = file->data ? flash_read_uint16((uintptr_t) file->data) : 0;
|
||||
uint8_t *old_data = NULL;
|
||||
if (offset + len > FLASH_SECTOR_SIZE || offset > size_file_flash) {
|
||||
return PICOKEY_ERR_NO_MEMORY;
|
||||
return PICOKEYS_ERR_NO_MEMORY;
|
||||
}
|
||||
if (file->data) { //already in flash
|
||||
if (offset + len <= size_file_flash) { //it fits, no need to move it
|
||||
@@ -155,7 +127,7 @@ int flash_write_data_to_file_offset(file_t *file, const uint8_t *data, uint16_t
|
||||
if (data) {
|
||||
flash_program_block((uintptr_t) file->data + sizeof(uint16_t) + offset, data, len);
|
||||
}
|
||||
return PICOKEY_OK;
|
||||
return PICOKEYS_OK;
|
||||
}
|
||||
else { //we clear the old file
|
||||
flash_clear_file(file);
|
||||
@@ -172,7 +144,7 @@ int flash_write_data_to_file_offset(file_t *file, const uint8_t *data, uint16_t
|
||||
uintptr_t new_addr = allocate_free_addr(len, (file->type & FILE_PERSISTENT) == FILE_PERSISTENT);
|
||||
//printf("na %x\n",new_addr);
|
||||
if (new_addr == 0x0) {
|
||||
return PICOKEY_ERR_NO_MEMORY;
|
||||
return PICOKEYS_ERR_NO_MEMORY;
|
||||
}
|
||||
if (new_addr < last_base) {
|
||||
last_base = new_addr;
|
||||
@@ -187,29 +159,37 @@ int flash_write_data_to_file_offset(file_t *file, const uint8_t *data, uint16_t
|
||||
free(old_data);
|
||||
}
|
||||
num_files++;
|
||||
return PICOKEY_OK;
|
||||
return PICOKEYS_OK;
|
||||
}
|
||||
|
||||
int flash_write_data_to_file(file_t *file, const uint8_t *data, uint16_t len) {
|
||||
return flash_write_data_to_file_offset(file, data, len, 0);
|
||||
}
|
||||
|
||||
uint32_t flash_free_space() {
|
||||
uint32_t flash_free_space(void) {
|
||||
return (uint32_t)(last_base - start_data_pool);
|
||||
}
|
||||
|
||||
uint32_t flash_used_space() {
|
||||
uint32_t flash_used_space(void) {
|
||||
return (uint32_t)(end_data_pool - last_base);
|
||||
}
|
||||
|
||||
uint32_t flash_total_space() {
|
||||
uint32_t flash_total_space(void) {
|
||||
return (uint32_t)(end_data_pool - start_data_pool);
|
||||
}
|
||||
|
||||
uint32_t flash_num_files() {
|
||||
uint32_t flash_num_files(void) {
|
||||
return num_files;
|
||||
}
|
||||
|
||||
uint32_t flash_size() {
|
||||
uint32_t flash_size(void) {
|
||||
return FLASH_SIZE_BYTES;
|
||||
}
|
||||
|
||||
void flash_task(void) {
|
||||
low_flash_task();
|
||||
}
|
||||
|
||||
void flash_commit(void) {
|
||||
low_flash_commit();
|
||||
}
|
||||
|
||||
46
src/fs/flash.h
Normal file
46
src/fs/flash.h
Normal file
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
|
||||
* Copyright (c) 2022 Pol Henarejos.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _FLASH_H
|
||||
#define _FLASH_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
extern uint32_t flash_free_space(void);
|
||||
extern uint32_t flash_used_space(void);
|
||||
extern uint32_t flash_total_space(void);
|
||||
extern uint32_t flash_num_files(void);
|
||||
extern uint32_t flash_size(void);
|
||||
|
||||
extern void flash_set_bounds(uintptr_t start, uintptr_t end);
|
||||
extern int flash_write_data_to_file(file_t *file, const uint8_t *data, uint16_t len);
|
||||
extern int flash_program_block(uintptr_t addr, const uint8_t *data, size_t len);
|
||||
extern int flash_program_halfword(uintptr_t addr, uint16_t data);
|
||||
extern int flash_program_word(uintptr_t addr, uint32_t data);
|
||||
extern int flash_program_uintptr(uintptr_t addr, uintptr_t data);
|
||||
extern uintptr_t flash_read_uintptr(uintptr_t addr);
|
||||
extern uint16_t flash_read_uint16(uintptr_t addr);
|
||||
extern uint8_t flash_read_uint8(uintptr_t addr);
|
||||
extern uint8_t *flash_read(uintptr_t addr);
|
||||
extern int flash_erase_page(uintptr_t addr, size_t page_size);
|
||||
extern bool flash_check_blank(const uint8_t *p_start, size_t size);
|
||||
extern void flash_task(void);
|
||||
extern void low_flash_init(void);
|
||||
extern void flash_commit(void);
|
||||
|
||||
#endif // _FLASH_H
|
||||
@@ -15,16 +15,11 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "pico_keys.h"
|
||||
#include <string.h>
|
||||
#include "picokeys.h"
|
||||
#include "serial.h"
|
||||
#include "crypto_utils.h"
|
||||
#include <stdio.h>
|
||||
#ifdef PICO_PLATFORM
|
||||
#include "pico/stdlib.h"
|
||||
#include "hardware/flash.h"
|
||||
#include "hardware/sync.h"
|
||||
#include "pico/mutex.h"
|
||||
@@ -34,7 +29,7 @@
|
||||
#include "boot/picobin.h"
|
||||
#else
|
||||
#ifdef ESP_PLATFORM
|
||||
#include "esp_compat.h"
|
||||
#include "compat/esp_compat.h"
|
||||
#include "esp_partition.h"
|
||||
const esp_partition_t *part0;
|
||||
#define save_and_disable_interrupts() 1
|
||||
@@ -56,9 +51,13 @@
|
||||
#include <unistd.h>
|
||||
#include <sys/mman.h>
|
||||
#endif
|
||||
#include "queue.h"
|
||||
#include "compat/queue.h"
|
||||
#endif
|
||||
#ifdef ENABLE_EMULATION
|
||||
#define FLASH_SECTOR_SIZE 0x4000
|
||||
#else
|
||||
#define FLASH_SECTOR_SIZE 0x1000
|
||||
#endif
|
||||
#define FLASH_SECTOR_SIZE 4096
|
||||
#define XIP_BASE 0
|
||||
int fd_map = 0;
|
||||
uint8_t *map = NULL;
|
||||
@@ -71,25 +70,22 @@ extern uint32_t FLASH_SIZE_BYTES;
|
||||
#endif
|
||||
|
||||
#define TOTAL_FLASH_PAGES 6
|
||||
#define FLASH_LOCKOUT_RETRIES 5
|
||||
|
||||
extern void flash_set_bounds(uintptr_t start, uintptr_t end);
|
||||
|
||||
extern const uintptr_t start_data_pool;
|
||||
extern const uintptr_t end_rom_pool;
|
||||
|
||||
PACK(
|
||||
typedef struct page_flash {
|
||||
uint8_t page[FLASH_SECTOR_SIZE];
|
||||
uintptr_t address;
|
||||
bool ready;
|
||||
bool erase;
|
||||
size_t page_size; //this param is for easy erase. It allows to erase with a single call. IT DOES NOT APPLY TO WRITE
|
||||
} page_flash_t;
|
||||
}) page_flash_t;
|
||||
|
||||
static page_flash_t flash_pages[TOTAL_FLASH_PAGES];
|
||||
|
||||
static mutex_t mtx_flash;
|
||||
static semaphore_t sem_flash;
|
||||
|
||||
#ifndef ENABLE_EMULATION
|
||||
static bool locked_out = false;
|
||||
@@ -103,23 +99,34 @@ bool flash_available = false;
|
||||
|
||||
|
||||
//this function has to be called from the core 0
|
||||
void do_flash() {
|
||||
void low_flash_task(void);
|
||||
void low_flash_commit(void);
|
||||
|
||||
void low_flash_task(void){
|
||||
if (mutex_try_enter(&mtx_flash, NULL) == true) {
|
||||
if (locked_out == true && flash_available == true && ready_pages > 0) {
|
||||
//printf(" DO_FLASH AVAILABLE\n");
|
||||
for (int r = 0; r < TOTAL_FLASH_PAGES; r++) {
|
||||
if (flash_pages[r].ready == true) {
|
||||
#if defined(PICO_PLATFORM) || defined(ESP_PLATFORM)
|
||||
mutex_exit(&mtx_flash);
|
||||
//printf("WRITTING %X\n",flash_pages[r].address-XIP_BASE);
|
||||
for (int retries = 0; retries < FLASH_LOCKOUT_RETRIES && multicore_lockout_start_timeout_us(1000) == false; retries++) {
|
||||
if (multicore_lockout_start_timeout_us(1000) == false) {
|
||||
printf("WARN: FLASH LOCKOUT START TIMEOUT\n");
|
||||
mutex_enter_blocking(&mtx_flash);
|
||||
continue;
|
||||
}
|
||||
//printf("WRITTING %X\n",flash_pages[r].address-XIP_BASE);
|
||||
uint32_t ints = save_and_disable_interrupts();
|
||||
flash_range_erase(flash_pages[r].address - XIP_BASE, FLASH_SECTOR_SIZE);
|
||||
flash_range_program(flash_pages[r].address - XIP_BASE, flash_pages[r].page, FLASH_SECTOR_SIZE);
|
||||
restore_interrupts(ints);
|
||||
for (int retries = 0; retries < FLASH_LOCKOUT_RETRIES && multicore_lockout_end_timeout_us(1000) == false; retries++) {
|
||||
if (multicore_lockout_end_timeout_us(1000) == false) {
|
||||
printf("WARN: FLASH LOCKOUT END TIMEOUT\n");
|
||||
mutex_enter_blocking(&mtx_flash);
|
||||
continue;
|
||||
}
|
||||
mutex_enter_blocking(&mtx_flash);
|
||||
//printf("WRITEN %X !\n",flash_pages[r].address);
|
||||
#else
|
||||
memcpy(map + flash_pages[r].address, flash_pages[r].page, FLASH_SECTOR_SIZE);
|
||||
@@ -129,12 +136,22 @@ void do_flash() {
|
||||
}
|
||||
else if (flash_pages[r].erase == true) {
|
||||
#if defined(PICO_PLATFORM) || defined(ESP_PLATFORM)
|
||||
for (int retries = 0; retries < FLASH_LOCKOUT_RETRIES && multicore_lockout_start_timeout_us(1000) == false; retries++) {
|
||||
mutex_exit(&mtx_flash);
|
||||
if (multicore_lockout_start_timeout_us(1000) == false) {
|
||||
printf("WARN: FLASH LOCKOUT START TIMEOUT\n");
|
||||
mutex_enter_blocking(&mtx_flash);
|
||||
continue;
|
||||
}
|
||||
//printf("WRITTING\n");
|
||||
uint32_t ints = save_and_disable_interrupts();
|
||||
flash_range_erase(flash_pages[r].address - XIP_BASE, flash_pages[r].page_size ? ((int) (flash_pages[r].page_size / FLASH_SECTOR_SIZE)) * FLASH_SECTOR_SIZE : FLASH_SECTOR_SIZE);
|
||||
for (int retries = 0; retries < FLASH_LOCKOUT_RETRIES && multicore_lockout_end_timeout_us(1000) == false; retries++) {
|
||||
restore_interrupts(ints);
|
||||
if (multicore_lockout_end_timeout_us(1000) == false) {
|
||||
printf("WARN: FLASH LOCKOUT END TIMEOUT\n");
|
||||
mutex_enter_blocking(&mtx_flash);
|
||||
continue;
|
||||
}
|
||||
mutex_enter_blocking(&mtx_flash);
|
||||
#else
|
||||
memset(map + flash_pages[r].address, 0, FLASH_SECTOR_SIZE);
|
||||
#endif
|
||||
@@ -149,27 +166,27 @@ void do_flash() {
|
||||
printf("ERROR: DO FLASH DOES NOT HAVE ZERO PAGES\n");
|
||||
}
|
||||
}
|
||||
flash_available = false;
|
||||
if (ready_pages == 0) {
|
||||
flash_available = false;
|
||||
}
|
||||
#ifdef ESP_PLATFORM
|
||||
esp_partition_munmap(fd_map);
|
||||
esp_partition_mmap(part0, 0, part0->size, ESP_PARTITION_MMAP_DATA, (const void **)&map, (esp_partition_mmap_handle_t *)&fd_map);
|
||||
#endif
|
||||
mutex_exit(&mtx_flash);
|
||||
}
|
||||
sem_release(&sem_flash);
|
||||
}
|
||||
|
||||
#ifdef PICO_RP2040
|
||||
void phymarker_write();
|
||||
void phymarker_write(void);
|
||||
#endif
|
||||
//this function has to be called from the core 0
|
||||
void low_flash_init() {
|
||||
void low_flash_init(void) {
|
||||
#ifdef PICO_RP2040
|
||||
phymarker_write();
|
||||
#endif
|
||||
memset(flash_pages, 0, sizeof(page_flash_t) * TOTAL_FLASH_PAGES);
|
||||
mutex_init(&mtx_flash);
|
||||
sem_init(&sem_flash, 0, 1);
|
||||
|
||||
uint32_t data_start_addr;
|
||||
uint32_t data_end_addr;
|
||||
@@ -186,21 +203,21 @@ void low_flash_init() {
|
||||
|
||||
FLASH_SIZE_BYTES = (1 << rxbuf[3]);
|
||||
#ifdef PICO_RP2350
|
||||
__attribute__((aligned(4))) uint8_t workarea[4 * 1024];
|
||||
int rc = rom_load_partition_table(workarea, sizeof(workarea), false);
|
||||
__attribute__((aligned(4))) uint32_t workarea[1024];
|
||||
int rc = rom_load_partition_table((uint8_t *)workarea, sizeof(workarea), false);
|
||||
if (rc) {
|
||||
reset_usb_boot(0, 0);
|
||||
}
|
||||
|
||||
uint8_t boot_partition = 1;
|
||||
rc = rom_get_partition_table_info((uint32_t*)workarea, 0x8, PT_INFO_PARTITION_LOCATION_AND_FLAGS | PT_INFO_SINGLE_PARTITION | (boot_partition << 24));
|
||||
rc = rom_get_partition_table_info(workarea, 0x8, PT_INFO_PARTITION_LOCATION_AND_FLAGS | PT_INFO_SINGLE_PARTITION | (boot_partition << 24));
|
||||
|
||||
if (rc != 3) {
|
||||
data_start_addr = (FLASH_SIZE_BYTES >> 1);
|
||||
data_end_addr = FLASH_SIZE_BYTES;
|
||||
} else {
|
||||
uint16_t first_sector_number = (((uint32_t*)workarea)[1] & PICOBIN_PARTITION_LOCATION_FIRST_SECTOR_BITS) >> PICOBIN_PARTITION_LOCATION_FIRST_SECTOR_LSB;
|
||||
uint16_t last_sector_number = (((uint32_t*)workarea)[1] & PICOBIN_PARTITION_LOCATION_LAST_SECTOR_BITS) >> PICOBIN_PARTITION_LOCATION_LAST_SECTOR_LSB;
|
||||
uint16_t first_sector_number = (workarea[1] & PICOBIN_PARTITION_LOCATION_FIRST_SECTOR_BITS) >> PICOBIN_PARTITION_LOCATION_FIRST_SECTOR_LSB;
|
||||
uint16_t last_sector_number = (workarea[1] & PICOBIN_PARTITION_LOCATION_LAST_SECTOR_BITS) >> PICOBIN_PARTITION_LOCATION_LAST_SECTOR_LSB;
|
||||
data_start_addr = first_sector_number * FLASH_SECTOR_SIZE;
|
||||
data_end_addr = (last_sector_number + 1) * FLASH_SECTOR_SIZE;
|
||||
if (data_end_addr > FLASH_SIZE_BYTES) {
|
||||
@@ -226,26 +243,20 @@ void low_flash_init() {
|
||||
flash_set_bounds(data_start_addr, data_end_addr);
|
||||
}
|
||||
|
||||
void low_flash_init_core1() {
|
||||
void low_flash_init_core1(void) {
|
||||
mutex_enter_blocking(&mtx_flash);
|
||||
multicore_lockout_victim_init();
|
||||
locked_out = true;
|
||||
mutex_exit(&mtx_flash);
|
||||
}
|
||||
|
||||
void wait_flash_finish() {
|
||||
sem_acquire_blocking(&sem_flash); //blocks until released
|
||||
//wake up
|
||||
sem_acquire_blocking(&sem_flash); //decrease permits
|
||||
}
|
||||
|
||||
void low_flash_available() {
|
||||
void low_flash_commit(void) {
|
||||
mutex_enter_blocking(&mtx_flash);
|
||||
flash_available = true;
|
||||
mutex_exit(&mtx_flash);
|
||||
}
|
||||
|
||||
page_flash_t *find_free_page(uintptr_t addr) {
|
||||
static page_flash_t *find_free_page(uintptr_t addr) {
|
||||
uintptr_t addr_alg = addr & -FLASH_SECTOR_SIZE;
|
||||
page_flash_t *p = NULL;
|
||||
for (int r = 0; r < TOTAL_FLASH_PAGES; r++) {
|
||||
@@ -272,24 +283,24 @@ int flash_program_block(uintptr_t addr, const uint8_t *data, size_t len) {
|
||||
page_flash_t *p = NULL;
|
||||
|
||||
if (!data || len == 0) {
|
||||
return PICOKEY_ERR_NULL_PARAM;
|
||||
return PICOKEYS_ERR_NULL_PARAM;
|
||||
}
|
||||
|
||||
mutex_enter_blocking(&mtx_flash);
|
||||
if (ready_pages == TOTAL_FLASH_PAGES) {
|
||||
mutex_exit(&mtx_flash);
|
||||
printf("ERROR: ALL FLASH PAGES CACHED\n");
|
||||
return PICOKEY_ERR_NO_MEMORY;
|
||||
return PICOKEYS_ERR_NO_MEMORY;
|
||||
}
|
||||
if (!(p = find_free_page(addr))) {
|
||||
mutex_exit(&mtx_flash);
|
||||
printf("ERROR: FLASH CANNOT FIND A PAGE (rare error)\n");
|
||||
return PICOKEY_ERR_MEMORY_FATAL;
|
||||
return PICOKEYS_ERR_MEMORY_FATAL;
|
||||
}
|
||||
memcpy(&p->page[addr & (FLASH_SECTOR_SIZE - 1)], data, len);
|
||||
//printf("Flash: modified page %X with data %x at [%x]\n",(uintptr_t)addr,(uintptr_t)data,addr&(FLASH_SECTOR_SIZE-1));
|
||||
mutex_exit(&mtx_flash);
|
||||
return PICOKEY_OK;
|
||||
return PICOKEYS_OK;
|
||||
}
|
||||
|
||||
int flash_program_halfword(uintptr_t addr, uint16_t data) {
|
||||
@@ -353,19 +364,19 @@ int flash_erase_page(uintptr_t addr, size_t page_size) {
|
||||
if (ready_pages == TOTAL_FLASH_PAGES) {
|
||||
mutex_exit(&mtx_flash);
|
||||
printf("ERROR: ALL FLASH PAGES CACHED\n");
|
||||
return PICOKEY_ERR_NO_MEMORY;
|
||||
return PICOKEYS_ERR_NO_MEMORY;
|
||||
}
|
||||
if (!(p = find_free_page(addr))) {
|
||||
printf("ERROR: FLASH CANNOT FIND A PAGE (rare error)\n");
|
||||
mutex_exit(&mtx_flash);
|
||||
return PICOKEY_ERR_MEMORY_FATAL;
|
||||
return PICOKEYS_ERR_MEMORY_FATAL;
|
||||
}
|
||||
p->erase = true;
|
||||
p->ready = false;
|
||||
p->page_size = page_size;
|
||||
mutex_exit(&mtx_flash);
|
||||
|
||||
return PICOKEY_OK;
|
||||
return PICOKEYS_OK;
|
||||
}
|
||||
|
||||
bool flash_check_blank(const uint8_t *p_start, size_t size) {
|
||||
@@ -392,7 +403,7 @@ uintptr_t __phymarker_start = (uintptr_t)0x10100000;
|
||||
|
||||
const uint64_t PHYSICAL_MARKER_MAGIC = 0x5049434F4B455953ULL; // "PICOKEYS"
|
||||
|
||||
void phymarker_write() {
|
||||
void phymarker_write(void) {
|
||||
const uint64_t magic = *(uint64_t *)__phymarker_start;
|
||||
if (magic == PHYSICAL_MARKER_MAGIC) {
|
||||
return;
|
||||
@@ -406,10 +417,12 @@ void phymarker_write() {
|
||||
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 *)&pm, sizeof(phymarker_t));
|
||||
flash_range_program((uint32_t)__phymarker_start - XIP_BASE, (const uint8_t *)buf, sizeof(buf));
|
||||
|
||||
restore_interrupts(ints);
|
||||
}
|
||||
|
||||
35
src/fs/phy.c
35
src/fs/phy.c
@@ -15,8 +15,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "pico_keys.h"
|
||||
#include "file.h"
|
||||
#include "picokeys.h"
|
||||
#include "otp.h"
|
||||
|
||||
#ifndef ENABLE_EMULATION
|
||||
@@ -25,7 +24,7 @@ phy_data_t phy_data;
|
||||
|
||||
int phy_serialize_data(const phy_data_t *phy, uint8_t *data, uint16_t *len) {
|
||||
if (!phy || !data || !len) {
|
||||
return PICOKEY_ERR_NULL_PARAM;
|
||||
return PICOKEYS_ERR_NULL_PARAM;
|
||||
}
|
||||
uint8_t *p = data;
|
||||
if (phy->vidpid_present) {
|
||||
@@ -48,7 +47,7 @@ int phy_serialize_data(const phy_data_t *phy, uint8_t *data, uint16_t *len) {
|
||||
}
|
||||
*p++ = PHY_OPTS;
|
||||
*p++ = 2;
|
||||
p += put_uint16_t_be(phy->opts, p);
|
||||
p += put_uint16_be(phy->opts, p);
|
||||
if (phy->up_btn_present) {
|
||||
*p++ = PHY_UP_BTN;
|
||||
*p++ = 1;
|
||||
@@ -64,7 +63,7 @@ int phy_serialize_data(const phy_data_t *phy, uint8_t *data, uint16_t *len) {
|
||||
if (phy->enabled_curves_present) {
|
||||
*p++ = PHY_ENABLED_CURVES;
|
||||
*p++ = 4;
|
||||
p += put_uint32_t_be(phy->enabled_curves, p);
|
||||
p += put_uint32_be(phy->enabled_curves, p);
|
||||
}
|
||||
if (phy->enabled_usb_itf_present) {
|
||||
*p++ = PHY_ENABLED_USB_ITF;
|
||||
@@ -78,12 +77,12 @@ int phy_serialize_data(const phy_data_t *phy, uint8_t *data, uint16_t *len) {
|
||||
}
|
||||
|
||||
*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) {
|
||||
if (!phy || !data || !len) {
|
||||
return PICOKEY_ERR_NULL_PARAM;
|
||||
return PICOKEYS_ERR_NULL_PARAM;
|
||||
}
|
||||
const uint8_t *p = data;
|
||||
uint8_t tag, tlen;
|
||||
@@ -115,7 +114,7 @@ int phy_unserialize_data(const uint8_t *data, uint16_t len, phy_data_t *phy) {
|
||||
break;
|
||||
case PHY_OPTS:
|
||||
if (tlen == 2) {
|
||||
phy->opts = get_uint16_t_be(p);
|
||||
phy->opts = get_uint16_be(p);
|
||||
p += 2;
|
||||
}
|
||||
break;
|
||||
@@ -135,7 +134,7 @@ int phy_unserialize_data(const uint8_t *data, uint16_t len, phy_data_t *phy) {
|
||||
break;
|
||||
case PHY_ENABLED_CURVES:
|
||||
if (tlen == 4) {
|
||||
phy->enabled_curves = get_uint32_t_be(p);
|
||||
phy->enabled_curves = get_uint32_be(p);
|
||||
p += 4;
|
||||
phy->enabled_curves_present = true;
|
||||
}
|
||||
@@ -159,33 +158,33 @@ int phy_unserialize_data(const uint8_t *data, uint16_t len, phy_data_t *phy) {
|
||||
}
|
||||
}
|
||||
if (!phy_data.enabled_usb_itf_present) {
|
||||
phy_data.enabled_usb_itf = PHY_USB_ITF_CCID | PHY_USB_ITF_WCID | PHY_USB_ITF_HID | PHY_USB_ITF_KB;
|
||||
phy_data.enabled_usb_itf = PHY_USB_ITF_ALL;
|
||||
phy_data.enabled_usb_itf_present = true;
|
||||
}
|
||||
return PICOKEY_OK;
|
||||
return PICOKEYS_OK;
|
||||
}
|
||||
|
||||
int phy_init() {
|
||||
int phy_init(void) {
|
||||
memset(&phy_data, 0, sizeof(phy_data_t));
|
||||
return phy_load();
|
||||
}
|
||||
|
||||
int phy_save() {
|
||||
int phy_save(void) {
|
||||
uint8_t tmp[PHY_MAX_SIZE] = {0};
|
||||
uint16_t tmp_len = 0;
|
||||
int ret = phy_serialize_data(&phy_data, tmp, &tmp_len);
|
||||
if (ret != PICOKEY_OK) {
|
||||
if (ret != PICOKEYS_OK) {
|
||||
return ret;
|
||||
}
|
||||
file_put_data(ef_phy, tmp, tmp_len);
|
||||
low_flash_available();
|
||||
return PICOKEY_OK;
|
||||
flash_commit();
|
||||
return PICOKEYS_OK;
|
||||
}
|
||||
|
||||
int phy_load() {
|
||||
int phy_load(void) {
|
||||
if (file_has_data(ef_phy)) {
|
||||
return phy_unserialize_data(file_get_data(ef_phy), file_get_size(ef_phy), &phy_data);
|
||||
}
|
||||
return PICOKEY_OK;
|
||||
return PICOKEYS_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
11
src/fs/phy.h
11
src/fs/phy.h
@@ -51,6 +51,8 @@
|
||||
#define PHY_USB_ITF_WCID 0x2
|
||||
#define PHY_USB_ITF_HID 0x4
|
||||
#define PHY_USB_ITF_KB 0x8
|
||||
#define PHY_USB_ITF_LWIP 0x10
|
||||
#define PHY_USB_ITF_ALL (PHY_USB_ITF_CCID | PHY_USB_ITF_WCID | PHY_USB_ITF_HID | PHY_USB_ITF_KB | PHY_USB_ITF_LWIP)
|
||||
|
||||
#define PHY_LED_DRIVER_PICO 0x1
|
||||
#define PHY_LED_DRIVER_PIMORONI 0x2
|
||||
@@ -67,6 +69,7 @@
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
PACK(
|
||||
typedef struct phy_data {
|
||||
union {
|
||||
struct {
|
||||
@@ -97,16 +100,16 @@ typedef struct phy_data {
|
||||
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)+(2+1))
|
||||
|
||||
#ifndef ENABLE_EMULATION
|
||||
extern int phy_serialize_data(const phy_data_t *phy, uint8_t *data, uint16_t *len);
|
||||
extern int phy_unserialize_data(const uint8_t *data, uint16_t len, phy_data_t *phy);
|
||||
extern int phy_init();
|
||||
extern int phy_save();
|
||||
extern int phy_load();
|
||||
extern int phy_init(void);
|
||||
extern int phy_save(void);
|
||||
extern int phy_load(void);
|
||||
extern phy_data_t phy_data;
|
||||
#endif
|
||||
|
||||
|
||||
42
src/json.h
Normal file
42
src/json.h
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
|
||||
* Copyright (c) 2022 Pol Henarejos.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _JSON_H_
|
||||
#define _JSON_H_
|
||||
|
||||
#include "cJSON.h"
|
||||
|
||||
#define CJSON_ADD_GENERIC(hdl, ptr, item, value) do { \
|
||||
if (hdl(ptr, item, value) == NULL) { \
|
||||
response->status_code = 500; \
|
||||
return 1; \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
#define CJSON_ADD_GENERIC_ITEM(hdl, ptr, item, value) do { \
|
||||
if (hdl(ptr, item, value) == false) { \
|
||||
response->status_code = 500; \
|
||||
return 1; \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
#define CJSON_ADD_STRING(ptr, item, value) CJSON_ADD_GENERIC(cJSON_AddStringToObject, (ptr)->json, item, value)
|
||||
#define CJSON_ADD_NUMBER(ptr, item, value) CJSON_ADD_GENERIC(cJSON_AddNumberToObject, (ptr)->json, item, value)
|
||||
#define CJSON_ADD_BOOL(ptr, item, value) CJSON_ADD_GENERIC(cJSON_AddBoolToObject, (ptr)->json, item, value)
|
||||
#define CJSON_ADD_ITEM(ptr, item, value) CJSON_ADD_GENERIC_ITEM(cJSON_AddItemToObject, (ptr)->json, item, value)
|
||||
|
||||
#endif // _JSON_H_
|
||||
@@ -15,14 +15,11 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "pico_keys.h"
|
||||
#ifdef PICO_PLATFORM
|
||||
#include "bsp/board.h"
|
||||
#elif defined(ESP_PLATFORM)
|
||||
#include "picokeys.h"
|
||||
#include "led/led.h"
|
||||
#include "pico_time.h"
|
||||
#if defined(ESP_PLATFORM)
|
||||
#include "driver/gpio.h"
|
||||
#include "esp_compat.h"
|
||||
#elif defined(ENABLE_EMULATION)
|
||||
#include "emulation.h"
|
||||
#endif
|
||||
@@ -35,11 +32,11 @@ void led_set_mode(uint32_t mode) {
|
||||
led_mode = mode;
|
||||
}
|
||||
|
||||
uint32_t led_get_mode() {
|
||||
uint32_t led_get_mode(void) {
|
||||
return led_mode;
|
||||
}
|
||||
|
||||
void led_blinking_task() {
|
||||
void led_blinking_task(void) {
|
||||
#if defined(PICO_PLATFORM) || defined(ESP_PLATFORM)
|
||||
static uint32_t start_ms = 0;
|
||||
static uint32_t stop_ms = 0;
|
||||
@@ -81,7 +78,7 @@ void led_blinking_task() {
|
||||
#endif
|
||||
}
|
||||
|
||||
void led_off_all() {
|
||||
void led_off_all(void) {
|
||||
#if defined(PICO_PLATFORM) || defined(ESP_PLATFORM)
|
||||
led_driver->set_color(LED_COLOR_OFF, 0, 0);
|
||||
#endif
|
||||
@@ -93,11 +90,11 @@ extern led_driver_t led_driver_ws2812;
|
||||
extern led_driver_t led_driver_neopixel;
|
||||
extern led_driver_t led_driver_pimoroni;
|
||||
|
||||
void led_driver_init_dummy() {
|
||||
static void led_driver_init_dummy(void) {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
void led_driver_color_dummy(uint8_t color, uint32_t led_brightness, float progress) {
|
||||
static void led_driver_color_dummy(uint8_t color, uint32_t led_brightness, float progress) {
|
||||
(void)color;
|
||||
(void)led_brightness;
|
||||
(void)progress;
|
||||
@@ -109,7 +106,7 @@ led_driver_t led_driver_dummy = {
|
||||
.set_color = led_driver_color_dummy,
|
||||
};
|
||||
|
||||
void led_init() {
|
||||
void led_init(void) {
|
||||
led_driver = &led_driver_dummy;
|
||||
#if defined(PICO_PLATFORM) || defined(ESP_PLATFORM)
|
||||
// Guess default driver
|
||||
@@ -145,14 +142,14 @@ void led_init() {
|
||||
#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
|
||||
case PHY_LED_DRIVER_PICO:
|
||||
led_driver = &led_driver_pico;
|
||||
break;
|
||||
#ifdef CYW43_WL_GPIO_LED_PIN
|
||||
case PHY_LED_DRIVER_CYW43:
|
||||
led_driver = &led_driver_cyw43;
|
||||
|
||||
@@ -62,13 +62,13 @@ enum {
|
||||
};
|
||||
|
||||
extern void led_set_mode(uint32_t mode);
|
||||
extern uint32_t led_get_mode();
|
||||
extern void led_blinking_task();
|
||||
extern void led_off_all();
|
||||
extern void led_init();
|
||||
extern uint32_t led_get_mode(void);
|
||||
extern void led_blinking_task(void);
|
||||
extern void led_off_all(void);
|
||||
extern void led_init(void);
|
||||
|
||||
typedef struct {
|
||||
void (*init)();
|
||||
void (*init)(void);
|
||||
void (*set_color)(uint8_t color, uint32_t led_brightness, float progress);
|
||||
} led_driver_t;
|
||||
|
||||
|
||||
@@ -15,18 +15,26 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "pico_keys.h"
|
||||
#include "picokeys.h"
|
||||
#include "led/led.h"
|
||||
#ifdef PICO_PLATFORM
|
||||
#include "hardware/gpio.h"
|
||||
#endif
|
||||
|
||||
#ifdef CYW43_WL_GPIO_LED_PIN
|
||||
|
||||
#include "pico/cyw43_arch.h"
|
||||
|
||||
void led_driver_init_cyw43() {
|
||||
void led_driver_init_cyw43(void);
|
||||
void led_driver_color_cyw43(uint8_t color, uint32_t led_brightness, float progress);
|
||||
|
||||
void led_driver_init_cyw43(void) {
|
||||
cyw43_arch_init();
|
||||
}
|
||||
|
||||
void led_driver_color_cyw43(uint8_t color, uint32_t led_brightness, float progress) {
|
||||
(void)led_brightness;
|
||||
(void)color;
|
||||
uint8_t gpio = CYW43_WL_GPIO_LED_PIN;
|
||||
if (phy_data.led_gpio_present) {
|
||||
gpio = phy_data.led_gpio;
|
||||
|
||||
@@ -15,7 +15,11 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "pico_keys.h"
|
||||
#include "picokeys.h"
|
||||
#include "led/led.h"
|
||||
#ifdef PICO_PLATFORM
|
||||
#include "hardware/gpio.h"
|
||||
#endif
|
||||
|
||||
#ifdef ESP_PLATFORM
|
||||
|
||||
@@ -45,7 +49,7 @@ tNeopixel pixel[] = {
|
||||
#define NEOPIXEL_PIN GPIO_NUM_27
|
||||
#endif
|
||||
|
||||
void led_driver_init_neopixel() {
|
||||
void led_driver_init_neopixel(void) {
|
||||
uint8_t gpio = NEOPIXEL_PIN;
|
||||
if (phy_data.led_gpio_present) {
|
||||
gpio = phy_data.led_gpio;
|
||||
|
||||
@@ -15,16 +15,28 @@
|
||||
* 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 PICO_DEFAULT_LED_PIN
|
||||
static uint8_t gpio = PICO_DEFAULT_LED_PIN;
|
||||
#else
|
||||
static uint8_t gpio = 0;
|
||||
#endif
|
||||
|
||||
#ifdef PICO_PLATFORM
|
||||
void led_driver_init_pico() {
|
||||
#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
|
||||
|
||||
#if defined(PICO_PLATFORM) || defined(ESP_PLATFORM)
|
||||
static void led_driver_init_pico(void) {
|
||||
if (phy_data.led_gpio_present) {
|
||||
gpio = phy_data.led_gpio;
|
||||
}
|
||||
@@ -32,7 +44,8 @@ void led_driver_init_pico() {
|
||||
gpio_set_dir(gpio, GPIO_OUT);
|
||||
}
|
||||
|
||||
void led_driver_color_pico(uint8_t color, uint32_t led_brightness, float progress) {
|
||||
static void led_driver_color_pico(uint8_t color, uint32_t led_brightness, float progress) {
|
||||
(void)color;
|
||||
(void)led_brightness;
|
||||
gpio_put(gpio, progress >= 0.5);
|
||||
}
|
||||
|
||||
@@ -15,9 +15,11 @@
|
||||
* 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"
|
||||
#ifdef PICO_DEFAULT_LED_PIN
|
||||
static uint8_t gpio = PICO_DEFAULT_LED_PIN;
|
||||
#else
|
||||
@@ -35,7 +37,7 @@ uint8_t pixel[][3] = {
|
||||
{0, 0, 0} // 7: white
|
||||
};
|
||||
|
||||
void led_driver_init_pimoroni() {
|
||||
static void led_driver_init_pimoroni(void) {
|
||||
if (phy_data.led_gpio_present) {
|
||||
gpio = phy_data.led_gpio;
|
||||
}
|
||||
@@ -47,7 +49,8 @@ void led_driver_init_pimoroni() {
|
||||
gpio_set_dir(gpio+1, GPIO_OUT);
|
||||
}
|
||||
|
||||
void led_driver_color_pimoroni(uint8_t color, uint32_t led_brightness, float progress) {
|
||||
static void led_driver_color_pimoroni(uint8_t color, uint32_t led_brightness, float progress) {
|
||||
(void)led_brightness;
|
||||
if (progress < 0.5) {
|
||||
color = LED_COLOR_OFF;
|
||||
}
|
||||
|
||||
@@ -15,7 +15,8 @@
|
||||
* 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/pio.h"
|
||||
@@ -69,7 +70,7 @@ static inline void ws2812_program_init(PIO pio, uint sm, uint offset, uint pin,
|
||||
pio_sm_set_enabled(pio, sm, true);
|
||||
}
|
||||
|
||||
void led_driver_init_ws2812() {
|
||||
static void led_driver_init_ws2812(void) {
|
||||
PIO pio = pio0;
|
||||
int sm = 0;
|
||||
uint offset = pio_add_program(pio, &ws2812_program);
|
||||
@@ -115,7 +116,7 @@ static inline void ws2812_put_pixel(uint32_t u32_pixel) {
|
||||
pio_sm_put_blocking(pio0, 0, u32_pixel << 8u);
|
||||
}
|
||||
|
||||
void led_driver_color_ws2812(uint8_t color, uint32_t led_brightness, float progress) {
|
||||
static void led_driver_color_ws2812(uint8_t color, uint32_t led_brightness, float progress) {
|
||||
if (!(phy_data.opts & PHY_OPT_DIMM)) {
|
||||
progress = progress >= 0.5 ? 1 : 0;
|
||||
}
|
||||
|
||||
304
src/main.c
304
src/main.c
@@ -15,10 +15,8 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "pico_keys.h"
|
||||
|
||||
#include "picokeys.h"
|
||||
#include "button.h"
|
||||
#if !defined(ENABLE_EMULATION)
|
||||
#include "tusb.h"
|
||||
#endif
|
||||
@@ -28,26 +26,25 @@
|
||||
#include "driver/gpio.h"
|
||||
#include "rom/gpio.h"
|
||||
#include "tinyusb.h"
|
||||
#include "esp_efuse.h"
|
||||
#define BOOT_PIN GPIO_NUM_0
|
||||
#elif defined(PICO_PLATFORM)
|
||||
#include "pico/stdlib.h"
|
||||
#include "bsp/board.h"
|
||||
#include "pico/aon_timer.h"
|
||||
#include "hardware/gpio.h"
|
||||
#include "hardware/sync.h"
|
||||
#include "hardware/structs/ioqspi.h"
|
||||
#include "hardware/structs/sio.h"
|
||||
#include "pico/stdio.h"
|
||||
#endif
|
||||
|
||||
#include "random.h"
|
||||
#include "hwrng.h"
|
||||
#include "apdu.h"
|
||||
#include "usb.h"
|
||||
#include "flash.h"
|
||||
#include "otp.h"
|
||||
#include "led/led.h"
|
||||
#include "pico_time.h"
|
||||
#include "serial.h"
|
||||
#include "mbedtls/sha256.h"
|
||||
|
||||
extern void do_flash();
|
||||
extern void low_flash_init();
|
||||
extern void init_otp_files();
|
||||
#if defined(PICOKEYS_HAS_TRUSTED_REGION)
|
||||
#include "trusted.h"
|
||||
#endif
|
||||
|
||||
app_t apps[16];
|
||||
uint8_t num_apps = 0;
|
||||
@@ -81,269 +78,87 @@ int register_app(int (*select_aid)(app_t *, uint8_t), const uint8_t *aid) {
|
||||
int select_app(const uint8_t *aid, size_t aid_len) {
|
||||
if (current_app && current_app->aid && (current_app->aid + 1 == aid || (aid_len >= current_app->aid[0] && !memcmp(current_app->aid + 1, aid, current_app->aid[0])))) {
|
||||
current_app->select_aid(current_app, 0);
|
||||
return PICOKEY_OK;
|
||||
return PICOKEYS_OK;
|
||||
}
|
||||
for (int a = 0; a < num_apps; a++) {
|
||||
if (aid_len >= apps[a].aid[0] && !memcmp(apps[a].aid + 1, aid, apps[a].aid[0])) {
|
||||
if (current_app) {
|
||||
if (current_app->aid && aid_len >= current_app->aid[0] && !memcmp(current_app->aid + 1, aid, current_app->aid[0])) {
|
||||
current_app->select_aid(current_app, 1);
|
||||
return PICOKEY_OK;
|
||||
return PICOKEYS_OK;
|
||||
}
|
||||
if (current_app->unload) {
|
||||
current_app->unload();
|
||||
}
|
||||
}
|
||||
current_app = &apps[a];
|
||||
if (current_app->select_aid(current_app, 1) == PICOKEY_OK) {
|
||||
return PICOKEY_OK;
|
||||
if (current_app->select_aid(current_app, 1) == PICOKEYS_OK) {
|
||||
return PICOKEYS_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
return PICOKEY_ERR_FILE_NOT_FOUND;
|
||||
return PICOKEYS_ERR_FILE_NOT_FOUND;
|
||||
}
|
||||
|
||||
int (*button_pressed_cb)(uint8_t) = NULL;
|
||||
|
||||
void execute_tasks();
|
||||
|
||||
static bool req_button_pending = false;
|
||||
|
||||
bool is_req_button_pending() {
|
||||
return req_button_pending;
|
||||
}
|
||||
|
||||
bool cancel_button = false;
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#include <windows.h>
|
||||
struct timezone
|
||||
{
|
||||
__int32 tz_minuteswest; /* minutes W of Greenwich */
|
||||
bool tz_dsttime; /* type of dst correction */
|
||||
};
|
||||
int gettimeofday(struct timeval* tp, struct timezone* tzp)
|
||||
{
|
||||
(void)tzp;
|
||||
// Note: some broken versions only have 8 trailing zero's, the correct epoch has 9 trailing zero's
|
||||
// This magic number is the number of 100 nanosecond intervals since January 1, 1601 (UTC)
|
||||
// until 00:00:00 January 1, 1970
|
||||
static const uint64_t EPOCH = ((uint64_t)116444736000000000ULL);
|
||||
|
||||
SYSTEMTIME system_time;
|
||||
FILETIME file_time;
|
||||
uint64_t time;
|
||||
|
||||
GetSystemTime(&system_time);
|
||||
SystemTimeToFileTime(&system_time, &file_time);
|
||||
time = ((uint64_t)file_time.dwLowDateTime);
|
||||
time += ((uint64_t)file_time.dwHighDateTime) << 32;
|
||||
|
||||
tp->tv_sec = (long)((time - EPOCH) / 10000000L);
|
||||
tp->tv_usec = (long)(system_time.wMilliseconds * 1000);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
#if !defined(ENABLE_EMULATION)
|
||||
#ifdef ESP_PLATFORM
|
||||
bool picok_board_button_read() {
|
||||
int boot_state = gpio_get_level(BOOT_PIN);
|
||||
return boot_state == 0;
|
||||
}
|
||||
#elif defined(PICO_PLATFORM)
|
||||
bool __no_inline_not_in_flash_func(picok_get_bootsel_button)() {
|
||||
const uint CS_PIN_INDEX = 1;
|
||||
|
||||
// Must disable interrupts, as interrupt handlers may be in flash, and we
|
||||
// are about to temporarily disable flash access!
|
||||
uint32_t flags = save_and_disable_interrupts();
|
||||
|
||||
// Set chip select to Hi-Z
|
||||
hw_write_masked(&ioqspi_hw->io[CS_PIN_INDEX].ctrl,
|
||||
GPIO_OVERRIDE_LOW << IO_QSPI_GPIO_QSPI_SS_CTRL_OEOVER_LSB,
|
||||
IO_QSPI_GPIO_QSPI_SS_CTRL_OEOVER_BITS);
|
||||
|
||||
// Note we can't call into any sleep functions in flash right now
|
||||
for (volatile int i = 0; i < 1000; ++i);
|
||||
|
||||
// The HI GPIO registers in SIO can observe and control the 6 QSPI pins.
|
||||
// Note the button pulls the pin *low* when pressed.
|
||||
#if PICO_RP2040
|
||||
#define CS_BIT (1u << 1)
|
||||
#else
|
||||
#define CS_BIT SIO_GPIO_HI_IN_QSPI_CSN_BITS
|
||||
#endif
|
||||
bool button_state = !(sio_hw->gpio_hi_in & CS_BIT);
|
||||
|
||||
// Need to restore the state of chip select, else we are going to have a
|
||||
// bad time when we return to code in flash!
|
||||
hw_write_masked(&ioqspi_hw->io[CS_PIN_INDEX].ctrl,
|
||||
GPIO_OVERRIDE_NORMAL << IO_QSPI_GPIO_QSPI_SS_CTRL_OEOVER_LSB,
|
||||
IO_QSPI_GPIO_QSPI_SS_CTRL_OEOVER_BITS);
|
||||
|
||||
restore_interrupts(flags);
|
||||
|
||||
return button_state;
|
||||
}
|
||||
bool picok_board_button_read(void) {
|
||||
return picok_get_bootsel_button();
|
||||
}
|
||||
#else
|
||||
bool picok_board_button_read(void) {
|
||||
return true; // always unpressed
|
||||
}
|
||||
#endif
|
||||
bool button_pressed_state = false;
|
||||
uint32_t button_pressed_time = 0;
|
||||
uint8_t button_press = 0;
|
||||
bool wait_button() {
|
||||
/* 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;
|
||||
}
|
||||
|
||||
__attribute__((weak)) int picokey_init() {
|
||||
WEAK int picokey_init(void) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
bool set_rtc = false;
|
||||
|
||||
bool has_set_rtc() {
|
||||
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 = t, .tv_usec = 0};
|
||||
settimeofday(&tv, NULL);
|
||||
#endif
|
||||
set_rtc = true;
|
||||
}
|
||||
|
||||
time_t get_rtc_time() {
|
||||
#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
|
||||
}
|
||||
|
||||
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 hwrng_task();
|
||||
extern void usb_task();
|
||||
void execute_tasks()
|
||||
{
|
||||
void execute_tasks(void);
|
||||
void execute_tasks(void) {
|
||||
#if !defined(ENABLE_EMULATION) && !defined(ESP_PLATFORM)
|
||||
tud_task(); // tinyusb device task
|
||||
#endif
|
||||
#ifdef USB_ITF_LWIP
|
||||
#if !defined(ENABLE_EMULATION)
|
||||
service_traffic();
|
||||
#endif
|
||||
rest_task();
|
||||
#endif
|
||||
usb_task();
|
||||
led_blinking_task();
|
||||
#ifdef ENABLE_LVGL_UI
|
||||
platform_ui_task();
|
||||
#endif
|
||||
}
|
||||
|
||||
void core0_loop() {
|
||||
static void core0_loop(void *arg) {
|
||||
(void)arg;
|
||||
#if defined(ESP_PLATFORM) && defined(USB_ITF_LWIP)
|
||||
if (ITF_LWIP_TOTAL > 0) {
|
||||
lwip_itf_init();
|
||||
}
|
||||
#endif
|
||||
while (1) {
|
||||
execute_tasks();
|
||||
hwrng_task();
|
||||
do_flash();
|
||||
#ifndef ENABLE_EMULATION
|
||||
if (button_pressed_cb && board_millis() > 1000 && !is_busy()) { // wait 1 second to boot up
|
||||
bool current_button_state = picok_board_button_read();
|
||||
if (current_button_state != button_pressed_state) {
|
||||
if (current_button_state == false) { // unpressed
|
||||
if (button_pressed_time == 0 || button_pressed_time + 1000 > board_millis()) {
|
||||
button_press++;
|
||||
}
|
||||
button_pressed_time = board_millis();
|
||||
}
|
||||
button_pressed_state = current_button_state;
|
||||
}
|
||||
if (button_pressed_time > 0 && button_press > 0 && button_pressed_time + 1000 < board_millis() && button_pressed_state == false) {
|
||||
if (button_pressed_cb != NULL) {
|
||||
(*button_pressed_cb)(button_press);
|
||||
}
|
||||
button_pressed_time = button_press = 0;
|
||||
}
|
||||
}
|
||||
flash_task();
|
||||
button_task();
|
||||
#ifdef PICO_PLATFORM
|
||||
// Avoid a pure busy loop on core0; gives the system a scheduling hint.
|
||||
tight_loop_contents();
|
||||
#endif
|
||||
#ifdef ESP_PLATFORM
|
||||
vTaskDelay(pdMS_TO_TICKS(10));
|
||||
vTaskDelay(pdMS_TO_TICKS(10));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
char pico_serial_str[2 * PICO_UNIQUE_BOARD_ID_SIZE_BYTES + 1];
|
||||
uint8_t pico_serial_hash[32];
|
||||
pico_unique_board_id_t pico_serial;
|
||||
#ifdef ESP_PLATFORM
|
||||
#define pico_get_unique_board_id(a) do { uint32_t value; esp_efuse_read_block(EFUSE_BLK1, &value, 0, 32); memcpy((uint8_t *)(a), &value, sizeof(uint32_t)); esp_efuse_read_block(EFUSE_BLK1, &value, 32, 32); memcpy((uint8_t *)(a)+4, &value, sizeof(uint32_t)); } while(0)
|
||||
extern tinyusb_config_t tusb_cfg;
|
||||
extern const uint8_t desc_config[];
|
||||
extern char *string_desc_arr[];
|
||||
extern char *string_desc_itf[];
|
||||
TaskHandle_t hcore0 = NULL, hcore1 = NULL;
|
||||
int app_main() {
|
||||
int app_main(void) {
|
||||
#else
|
||||
#ifndef PICO_PLATFORM
|
||||
#define pico_get_unique_board_id(a) memset(a, 0, sizeof(*(a)))
|
||||
#endif
|
||||
int main(void) {
|
||||
#endif
|
||||
pico_get_unique_board_id(&pico_serial);
|
||||
memset(pico_serial_str, 0, sizeof(pico_serial_str));
|
||||
for (size_t i = 0; i < sizeof(pico_serial); i++) {
|
||||
snprintf(&pico_serial_str[2 * i], 3, "%02X", pico_serial.id[i]);
|
||||
}
|
||||
mbedtls_sha256(pico_serial.id, sizeof(pico_serial.id), pico_serial_hash, false);
|
||||
#if defined(PICOKEYS_HAS_TRUSTED_REGION)
|
||||
trusted_region_init();
|
||||
#endif
|
||||
serial_init();
|
||||
|
||||
#ifndef ENABLE_EMULATION
|
||||
#ifdef PICO_PLATFORM
|
||||
@@ -357,11 +172,11 @@ int main(void) {
|
||||
|
||||
random_init();
|
||||
|
||||
init_otp_files();
|
||||
otp_init();
|
||||
|
||||
low_flash_init();
|
||||
|
||||
scan_flash();
|
||||
file_scan_flash();
|
||||
|
||||
init_rtc();
|
||||
|
||||
@@ -383,13 +198,16 @@ int main(void) {
|
||||
if (phy_data.usb_product_present) {
|
||||
tusb_cfg.string_descriptor[2] = phy_data.usb_product;
|
||||
}
|
||||
static char tmps[4][32];
|
||||
for (int i = 4; i < tusb_cfg.string_descriptor_count; i++) {
|
||||
strlcpy(tmps[i-4], tusb_cfg.string_descriptor[2], sizeof(tmps[0]));
|
||||
strlcat(tmps[i-4], " ", sizeof(tmps[0]));
|
||||
strlcat(tmps[i-4], tusb_cfg.string_descriptor[i], sizeof(tmps[0]));
|
||||
tusb_cfg.string_descriptor[i] = tmps[i-4];
|
||||
static char tmps[5][32];
|
||||
const int max_desc_slots = 8 - 6;
|
||||
const int itf_desc_count = ITF_TOTAL < max_desc_slots ? ITF_TOTAL : max_desc_slots;
|
||||
for (int i = 0; i < itf_desc_count; i++) {
|
||||
strlcpy(tmps[i], tusb_cfg.string_descriptor[2], sizeof(tmps[0]));
|
||||
strlcat(tmps[i], " ", sizeof(tmps[0]));
|
||||
strlcat(tmps[i], string_desc_itf[i], sizeof(tmps[0]));
|
||||
tusb_cfg.string_descriptor[i+6] = tmps[i];
|
||||
}
|
||||
tusb_cfg.string_descriptor_count = 6 + itf_desc_count;
|
||||
tusb_cfg.configuration_descriptor = desc_config;
|
||||
|
||||
tinyusb_driver_install(&tusb_cfg);
|
||||
@@ -405,7 +223,7 @@ int main(void) {
|
||||
#ifdef ESP_PLATFORM
|
||||
xTaskCreatePinnedToCore(core0_loop, "core0", 4096*ITF_TOTAL*2, NULL, CONFIG_TINYUSB_TASK_PRIORITY - 1, &hcore0, ESP32_CORE0);
|
||||
#else
|
||||
core0_loop();
|
||||
core0_loop(NULL);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
|
||||
39
src/otp/otp.c
Normal file
39
src/otp/otp.c
Normal file
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
|
||||
* Copyright (c) 2022 Pol Henarejos.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "otp.h"
|
||||
#include "otp_platform.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
const uint8_t *otp_key_1 = NULL;
|
||||
const uint8_t *otp_key_2 = NULL;
|
||||
|
||||
int otp_enable_secure_boot(uint8_t bootkey, bool secure_lock) {
|
||||
return otp_platform_enable_secure_boot(bootkey, secure_lock);
|
||||
}
|
||||
|
||||
bool otp_is_secure_boot_enabled(uint8_t *bootkey) {
|
||||
return otp_platform_is_secure_boot_enabled(bootkey);
|
||||
}
|
||||
|
||||
bool otp_is_secure_boot_locked(void) {
|
||||
return otp_platform_is_secure_boot_locked();
|
||||
}
|
||||
|
||||
void otp_init(void) {
|
||||
otp_platform_init(&otp_key_1, &otp_key_2);
|
||||
}
|
||||
@@ -15,42 +15,19 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _OTP_H_
|
||||
#define _OTP_H_
|
||||
|
||||
#ifdef PICO_RP2350
|
||||
|
||||
#define OTP_OLD_MKEK_ROW 0xEF0
|
||||
#define OTP_OLD_DEVK_ROW 0xED0
|
||||
#define OTP_MKEK_ROW 0xE90
|
||||
#define OTP_DEVK_ROW 0xE80
|
||||
|
||||
#define OTP_KEY_1 OTP_MKEK_ROW
|
||||
#define OTP_KEY_2 OTP_DEVK_ROW
|
||||
|
||||
extern const uint8_t* otp_buffer(uint16_t row);
|
||||
extern const uint8_t* otp_buffer_raw(uint16_t row);
|
||||
extern bool is_empty_otp_buffer(uint16_t row, uint16_t len);
|
||||
extern int otp_write_data(uint16_t row, const uint8_t *data, uint16_t len);
|
||||
extern int otp_write_data_raw(uint16_t row, const uint8_t *data, uint16_t len);
|
||||
|
||||
#elif defined(ESP_PLATFORM)
|
||||
|
||||
#include "esp_efuse.h"
|
||||
|
||||
#define OTP_KEY_1 EFUSE_BLK_KEY3
|
||||
#define OTP_KEY_2 EFUSE_BLK_KEY4
|
||||
|
||||
#endif
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
extern int otp_enable_secure_boot(uint8_t bootkey, bool secure_lock);
|
||||
extern void init_otp_files();
|
||||
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;
|
||||
|
||||
extern bool otp_is_secure_boot_enabled(uint8_t *bootkey);
|
||||
extern bool otp_is_secure_boot_locked();
|
||||
|
||||
#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;
|
||||
}
|
||||
@@ -15,21 +15,27 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "file.h"
|
||||
#include "pico_keys.h"
|
||||
#include <stdio.h>
|
||||
#include <stdalign.h>
|
||||
#include "picokeys.h"
|
||||
#include "otp.h"
|
||||
#include "otp_platform.h"
|
||||
|
||||
#ifdef PICO_RP2350
|
||||
#include "pico/bootrom.h"
|
||||
#include "hardware/structs/otp.h"
|
||||
#include "hardware/regs/otp_data.h"
|
||||
#endif
|
||||
|
||||
#include "random.h"
|
||||
#include "mbedtls/ecdsa.h"
|
||||
#include <stdalign.h>
|
||||
|
||||
#ifdef PICO_RP2350
|
||||
#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++) {
|
||||
@@ -49,25 +55,25 @@ static int otp_write_data_mode(uint16_t row, const uint8_t *data, uint16_t len,
|
||||
return ret;
|
||||
}
|
||||
|
||||
int otp_write_data(uint16_t row, const uint8_t *data, uint16_t len) {
|
||||
static int otp_write_data(uint16_t row, const uint8_t *data, uint16_t len) {
|
||||
return otp_write_data_mode(row, data, len, true);
|
||||
}
|
||||
|
||||
int otp_write_data_raw(uint16_t row, const uint8_t *data, uint16_t len) {
|
||||
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);
|
||||
}
|
||||
|
||||
const uint8_t* otp_buffer(uint16_t row) {
|
||||
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;
|
||||
}
|
||||
|
||||
const uint8_t* otp_buffer_raw(uint16_t row) {
|
||||
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;
|
||||
}
|
||||
|
||||
bool is_empty_otp_buffer(uint16_t row, uint16_t len) {
|
||||
static bool is_empty_otp_buffer(uint16_t row, uint16_t len) {
|
||||
return is_empty_buffer(otp_buffer_raw(row), len * 2);
|
||||
}
|
||||
|
||||
@@ -84,54 +90,71 @@ static void otp_lock_page(uint8_t page) {
|
||||
|
||||
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;
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
return esp_efuse_read_field_blob(key_desc, key, key_len * 8);
|
||||
}
|
||||
|
||||
#endif
|
||||
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;
|
||||
}
|
||||
|
||||
const uint8_t *otp_key_1 = NULL;
|
||||
const uint8_t *otp_key_2 = NULL;
|
||||
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;
|
||||
}
|
||||
|
||||
#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
|
||||
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);
|
||||
}
|
||||
|
||||
#ifndef SECURE_BOOT_BOOTKEY_INDEX
|
||||
#define SECURE_BOOT_BOOTKEY_INDEX 0
|
||||
#endif
|
||||
|
||||
bool otp_is_secure_boot_enabled(uint8_t *bootkey) {
|
||||
#ifdef PICO_RP2350
|
||||
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[] = "\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";
|
||||
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);
|
||||
@@ -150,20 +173,16 @@ bool otp_is_secure_boot_enabled(uint8_t *bootkey) {
|
||||
*bootkey = bootkey_idx;
|
||||
}
|
||||
return true;
|
||||
#elif defined(ESP_PLATFORM)
|
||||
// TODO: Implement secure boot check for ESP32-S3
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
bool otp_is_secure_boot_locked() {
|
||||
bool otp_platform_is_secure_boot_locked(void) {
|
||||
uint8_t bootkey_idx = 0xFF;
|
||||
if (otp_is_secure_boot_enabled(&bootkey_idx) == false) {
|
||||
if (otp_platform_is_secure_boot_enabled(&bootkey_idx) == false) {
|
||||
return false;
|
||||
}
|
||||
#ifdef PICO_RP2350
|
||||
const uint8_t *boot_flags1 = otp_buffer_raw(OTP_DATA_BOOT_FLAGS1_ROW);
|
||||
if ((boot_flags1[1] & ((OTP_DATA_BOOT_FLAGS1_KEY_INVALID_BITS >> OTP_DATA_BOOT_FLAGS1_KEY_INVALID_LSB) & (~(1 << bootkey_idx)))) != ((OTP_DATA_BOOT_FLAGS1_KEY_INVALID_BITS >> OTP_DATA_BOOT_FLAGS1_KEY_INVALID_LSB) & (~(1 << bootkey_idx)))) {
|
||||
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);
|
||||
@@ -173,18 +192,14 @@ bool otp_is_secure_boot_locked() {
|
||||
return false;
|
||||
}
|
||||
return bootkey_idx != 0xFF;
|
||||
#elif defined(ESP_PLATFORM)
|
||||
// TODO: Implement secure boot lock check for ESP32-S3
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
int otp_enable_secure_boot(uint8_t bootkey, bool secure_lock) {
|
||||
int otp_platform_enable_secure_boot(uint8_t bootkey, bool secure_lock) {
|
||||
int ret = 0;
|
||||
#ifdef PICO_RP2350
|
||||
|
||||
alignas(2) uint8_t BOOTKEY[] = "\xe1\xd1\x6b\xa7\x64\xab\xd7\x12\xd4\xef\x6e\x3e\xdd\x74\x4e\xd5\x63\x8c\x26\xb\x77\x1c\xf9\x81\x51\x11\xb\xaf\xac\x9b\xc8\x71";
|
||||
if (is_empty_otp_buffer(OTP_DATA_BOOTKEY0_0_ROW + 0x10*bootkey, 32)) {
|
||||
PICOKEY_CHECK(otp_write_data(OTP_DATA_BOOTKEY0_0_ROW + 0x10*bootkey, BOOTKEY, sizeof(BOOTKEY)));
|
||||
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);
|
||||
@@ -193,9 +208,9 @@ int otp_enable_secure_boot(uint8_t bootkey, bool 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)));
|
||||
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 };
|
||||
@@ -204,158 +219,76 @@ int otp_enable_secure_boot(uint8_t bootkey, bool secure_lock) {
|
||||
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)));
|
||||
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 };
|
||||
PICOKEY_CHECK(otp_write_data_raw(OTP_DATA_PAGE1_LOCK1_ROW, flagsp1, sizeof(flagsp1)));
|
||||
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 };
|
||||
PICOKEY_CHECK(otp_write_data_raw(OTP_DATA_PAGE2_LOCK1_ROW, flagsp2, sizeof(flagsp2)));
|
||||
PICOKEYS_CHECK(otp_write_data_raw(OTP_DATA_PAGE2_LOCK1_ROW, flagsp2, sizeof(flagsp2)));
|
||||
}
|
||||
#elif defined(ESP_PLATFORM)
|
||||
// TODO: Implement secure boot for ESP32-S3
|
||||
#else
|
||||
(void)bootkey;
|
||||
(void)secure_lock;
|
||||
#endif // PICO_RP2350
|
||||
|
||||
goto err;
|
||||
err:
|
||||
if (ret != PICOKEY_OK) {
|
||||
err:
|
||||
if (ret != PICOKEYS_OK) {
|
||||
return ret;
|
||||
}
|
||||
return PICOKEY_OK;
|
||||
return PICOKEYS_OK;
|
||||
}
|
||||
|
||||
#ifdef PICO_RP2350
|
||||
static void otp_invalidate_key(uint16_t row, uint16_t len) {
|
||||
if (!is_empty_otp_buffer(row, len)) {
|
||||
uint8_t *inval = (uint8_t *)calloc(len * 2, sizeof(uint8_t));
|
||||
if (inval) {
|
||||
memset(inval, 0xFF, len * 2);
|
||||
otp_write_data_raw(row, inval, len * 2);
|
||||
free(inval);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static otp_ret_t otp_chaff(uint16_t row, uint16_t len) {
|
||||
const uint8_t *raw = otp_buffer_raw(row);
|
||||
uint8_t *chaff = (uint8_t *)calloc(len * 2, sizeof(uint8_t));
|
||||
if (chaff) {
|
||||
memcpy(chaff, raw, len * 2);
|
||||
for (int i = 0; i < len * 2; i++) {
|
||||
chaff[i] ^= 0xFF;
|
||||
}
|
||||
otp_ret_t ret = otp_write_data_raw(row + 32, chaff, len * 2);
|
||||
free(chaff);
|
||||
return ret;
|
||||
}
|
||||
return BOOTROM_ERROR_INVALID_STATE;
|
||||
}
|
||||
|
||||
static otp_ret_t otp_migrate_key(uint16_t new_row, uint16_t old_row, uint16_t len) {
|
||||
if (is_empty_otp_buffer(new_row, len) && !is_empty_otp_buffer(old_row, len)) {
|
||||
const uint8_t *key = otp_buffer(old_row);
|
||||
uint8_t *new_key = (uint8_t *)calloc(len, sizeof(uint8_t));
|
||||
if (new_key) {
|
||||
memcpy(new_key, key, len);
|
||||
otp_ret_t ret = otp_write_data(new_row, new_key, len);
|
||||
if (ret == BOOTROM_OK) {
|
||||
otp_chaff(new_row, len);
|
||||
otp_invalidate_key(old_row, 32);
|
||||
}
|
||||
free(new_key);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
return BOOTROM_ERROR_INVALID_STATE;
|
||||
}
|
||||
|
||||
void otp_migrate_chaff() {
|
||||
otp_migrate_key(OTP_MKEK_ROW, OTP_OLD_MKEK_ROW, 32);
|
||||
otp_migrate_key(OTP_DEVK_ROW, OTP_OLD_DEVK_ROW, 32);
|
||||
otp_lock_page(OTP_MKEK_ROW >> 6);
|
||||
}
|
||||
#endif
|
||||
|
||||
void init_otp_files() {
|
||||
|
||||
#ifdef PICO_RP2350
|
||||
void otp_platform_init(const uint8_t **otp_key_1_out, const uint8_t **otp_key_2_out) {
|
||||
otp_migrate_chaff();
|
||||
#endif
|
||||
|
||||
#if defined(PICO_RP2350) || defined(ESP_PLATFORM)
|
||||
otp_ret_t ret = 0;
|
||||
int ret = 0;
|
||||
uint16_t write_otp[2] = {0xFFFF, 0xFFFF};
|
||||
if (OTP_EMTPY(OTP_KEY_1, 32)) {
|
||||
if (is_empty_otp_buffer(OTP_KEY_1, 32)) {
|
||||
uint8_t mkek[32] = {0};
|
||||
random_gen(NULL, mkek, sizeof(mkek));
|
||||
ret = OTP_WRITE(OTP_KEY_1, mkek, sizeof(mkek));
|
||||
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);
|
||||
}
|
||||
#ifdef PICO_RP2350
|
||||
otp_chaff(OTP_KEY_1, 32);
|
||||
#endif
|
||||
mbedtls_platform_zeroize(mkek, sizeof(mkek));
|
||||
write_otp[0] = OTP_KEY_1;
|
||||
}
|
||||
OTP_READ(OTP_KEY_1, otp_key_1);
|
||||
*otp_key_1_out = otp_buffer(OTP_KEY_1);
|
||||
|
||||
if (OTP_EMTPY(OTP_KEY_2, 32)) {
|
||||
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_gen, NULL);
|
||||
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(OTP_KEY_2, pkey, olen);
|
||||
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));
|
||||
#ifdef PICO_RP2350
|
||||
otp_chaff(OTP_KEY_2, 32);
|
||||
#endif
|
||||
write_otp[1] = OTP_KEY_2;
|
||||
}
|
||||
OTP_READ(OTP_KEY_2, otp_key_2);
|
||||
*otp_key_2_out = otp_buffer(OTP_KEY_2);
|
||||
|
||||
for (int i = 0; i < sizeof(write_otp)/sizeof(uint16_t); i++) {
|
||||
for (size_t i = 0; i < sizeof(write_otp) / sizeof(write_otp[0]); i++) {
|
||||
if (write_otp[i] != 0xFFFF) {
|
||||
#if defined(PICO_RP2350)
|
||||
otp_lock_page(write_otp[i] >> 6);
|
||||
#elif defined(ESP_PLATFORM)
|
||||
ret = esp_efuse_set_key_dis_write(write_otp[i]);
|
||||
if (ret != ESP_OK) {
|
||||
printf("Error setting OTP key %d to read only [%d]\n", i, ret);
|
||||
}
|
||||
ret = esp_efuse_set_keypurpose_dis_write(write_otp[i]);
|
||||
if (ret != ESP_OK) {
|
||||
printf("Error setting OTP key %d purpose to read only [%d]\n", i, ret);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#elif defined(ENABLE_EMULATION)
|
||||
static uint8_t _otp1[32] = {0}, _otp2[32] = {0};
|
||||
memset(_otp1, 0xAC, sizeof(_otp1));
|
||||
memset(_otp2, 0xBE, sizeof(_otp2));
|
||||
otp_key_1 = _otp1;
|
||||
otp_key_2 = _otp2;
|
||||
#endif
|
||||
}
|
||||
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;
|
||||
}
|
||||
258
src/pico_keys.h
258
src/pico_keys.h
@@ -1,258 +0,0 @@
|
||||
/*
|
||||
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
|
||||
* Copyright (c) 2022 Pol Henarejos.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _PICO_KEYS_H_
|
||||
#define _PICO_KEYS_H_
|
||||
|
||||
#define MBEDTLS_ALLOW_PRIVATE_ACCESS
|
||||
|
||||
#if defined(PICO_RP2040) || defined(PICO_RP2350)
|
||||
#define PICO_PLATFORM
|
||||
#endif
|
||||
|
||||
#include "file.h"
|
||||
#include "led/led.h"
|
||||
#include <stdint.h>
|
||||
#if !defined(MIN)
|
||||
#if defined(_MSC_VER)
|
||||
#define MIN(a,b) (((a)<(b))?(a):(b))
|
||||
#else
|
||||
#define MIN(a, b) \
|
||||
({ __typeof__ (a) _a = (a); \
|
||||
__typeof__ (b) _b = (b); \
|
||||
_a < _b ? _a : _b; })
|
||||
#endif
|
||||
#endif
|
||||
#if !defined(MAX)
|
||||
#if defined(_MSC_VER)
|
||||
#define MAX(a,b) (((a)>(b))?(a):(b))
|
||||
#else
|
||||
#define MAX(a, b) \
|
||||
({ __typeof__ (a) _a = (a); \
|
||||
__typeof__ (b) _b = (b); \
|
||||
_a > _b ? _a : _b; })
|
||||
#endif
|
||||
#endif
|
||||
#if defined(PICO_PLATFORM)
|
||||
#include "pico/unique_id.h"
|
||||
#endif
|
||||
#include <string.h>
|
||||
#include "debug.h"
|
||||
|
||||
#if defined(ENABLE_EMULATION)
|
||||
#include <stdbool.h>
|
||||
#elif defined(ESP_PLATFORM)
|
||||
#include "esp_compat.h"
|
||||
#elif defined(PICO_PLATFORM)
|
||||
#include "pico/util/queue.h"
|
||||
#endif
|
||||
|
||||
#ifdef PICO_PLATFORM
|
||||
#include "pico/bootrom.h"
|
||||
#include "hardware/watchdog.h"
|
||||
#include "pico/aon_timer.h"
|
||||
#else
|
||||
#include <sys/time.h>
|
||||
#include <time.h>
|
||||
#endif
|
||||
|
||||
extern bool wait_button();
|
||||
|
||||
extern void low_flash_init_core1();
|
||||
|
||||
static inline uint16_t make_uint16_t_be(uint8_t b1, uint8_t b2) {
|
||||
return (b1 << 8) | b2;
|
||||
}
|
||||
static inline uint16_t make_uint16_t_le(uint8_t b1, uint8_t b2) {
|
||||
return (b2 << 8) | b1;
|
||||
}
|
||||
static inline uint16_t get_uint16_t_be(const uint8_t *b) {
|
||||
return make_uint16_t_be(b[0], b[1]);
|
||||
}
|
||||
static inline uint16_t get_uint16_t_le(const uint8_t *b) {
|
||||
return make_uint16_t_le(b[0], b[1]);
|
||||
}
|
||||
static inline uint8_t put_uint16_t_be(uint16_t n, uint8_t *b) {
|
||||
*b++ = (n >> 8) & 0xff;
|
||||
*b = n & 0xff;
|
||||
return 2;
|
||||
}
|
||||
static inline uint8_t put_uint16_t_le(uint16_t n, uint8_t *b) {
|
||||
*b++ = n & 0xff;
|
||||
*b = (n >> 8) & 0xff;
|
||||
return 2;
|
||||
}
|
||||
|
||||
static inline uint32_t make_uint32_t_be(uint8_t b1, uint8_t b2, uint8_t b3, uint8_t b4) {
|
||||
return (b1 << 24) | (b2 << 16) | (b3 << 8) | b4;
|
||||
}
|
||||
static inline uint32_t make_uint32_t_le(uint8_t b1, uint8_t b2, uint8_t b3, uint8_t b4) {
|
||||
return (b4 << 24) | (b3 << 16) | (b2 << 8) | b1;
|
||||
}
|
||||
static inline uint32_t get_uint32_t_be(const uint8_t *b) {
|
||||
return make_uint32_t_be(b[0], b[1], b[2], b[3]);
|
||||
}
|
||||
static inline uint32_t get_uint32_t_le(const uint8_t *b) {
|
||||
return make_uint32_t_le(b[0], b[1], b[2], b[3]);
|
||||
}
|
||||
static inline uint32_t put_uint32_t_be(uint32_t n, uint8_t *b) {
|
||||
*b++ = (n >> 24) & 0xff;
|
||||
*b++ = (n >> 16) & 0xff;
|
||||
*b++ = (n >> 8) & 0xff;
|
||||
*b = n & 0xff;
|
||||
return 4;
|
||||
}
|
||||
static inline uint32_t put_uint32_t_le(uint32_t n, uint8_t *b) {
|
||||
*b++ = n & 0xff;
|
||||
*b++ = (n >> 8) & 0xff;
|
||||
*b++ = (n >> 16) & 0xff;
|
||||
*b = (n >> 24) & 0xff;
|
||||
return 4;
|
||||
}
|
||||
|
||||
static inline uint64_t make_uint64_t_be(uint8_t b1, uint8_t b2, uint8_t b3, uint8_t b4, uint8_t b5, uint8_t b6, uint8_t b7, uint8_t b8) {
|
||||
return ((uint64_t) b1 << 56) | ((uint64_t) b2 << 48) | ((uint64_t) b3 << 40) | ((uint64_t) b4 << 32) | ((uint64_t) b5 << 24) | ((uint64_t) b6 << 16) | ((uint64_t) b7 << 8) | b8;
|
||||
}
|
||||
static inline uint64_t make_uint64_t_le(uint8_t b1, uint8_t b2, uint8_t b3, uint8_t b4, uint8_t b5, uint8_t b6, uint8_t b7, uint8_t b8) {
|
||||
return ((uint64_t) b8 << 56) | ((uint64_t) b7 << 48) | ((uint64_t) b6 << 40) | ((uint64_t) b5 << 32) | ((uint64_t) b4 << 24) | ((uint64_t) b3 << 16) | ((uint64_t) b2 << 8) | b1;
|
||||
}
|
||||
static inline uint64_t get_uint64_t_be(const uint8_t *b) {
|
||||
return make_uint64_t_be(b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]);
|
||||
}
|
||||
static inline uint64_t get_uint64_t_le(const uint8_t *b) {
|
||||
return make_uint64_t_le(b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]);
|
||||
}
|
||||
static inline uint32_t put_uint64_t_be(uint64_t n, uint8_t *b) {
|
||||
*b++ = (n >> 56) & 0xff;
|
||||
*b++ = (n >> 48) & 0xff;
|
||||
*b++ = (n >> 40) & 0xff;
|
||||
*b++ = (n >> 32) & 0xff;
|
||||
*b++ = (n >> 24) & 0xff;
|
||||
*b++ = (n >> 16) & 0xff;
|
||||
*b++ = (n >> 8) & 0xff;
|
||||
*b = n & 0xff;
|
||||
return 8;
|
||||
}
|
||||
static inline uint32_t put_uint64_t_le(uint64_t n, uint8_t *b) {
|
||||
*b++ = n & 0xff;
|
||||
*b++ = (n >> 8) & 0xff;
|
||||
*b++ = (n >> 16) & 0xff;
|
||||
*b++ = (n >> 24) & 0xff;
|
||||
*b++ = (n >> 32) & 0xff;
|
||||
*b++ = (n >> 40) & 0xff;
|
||||
*b++ = (n >> 48) & 0xff;
|
||||
*b = (n >> 56) & 0xff;
|
||||
return 8;
|
||||
}
|
||||
|
||||
extern void low_flash_available();
|
||||
extern int flash_clear_file(file_t *file);
|
||||
|
||||
extern int (*button_pressed_cb)(uint8_t);
|
||||
|
||||
extern bool is_req_button_pending();
|
||||
|
||||
#define SW_BYTES_REMAINING_00() set_res_sw(0x61, 0x00)
|
||||
#define SW_WARNING_STATE_UNCHANGED() set_res_sw(0x62, 0x00)
|
||||
#define SW_WARNING_CORRUPTED() set_res_sw(0x62, 0x81)
|
||||
#define SW_WARNING_EOF() set_res_sw(0x62, 0x82)
|
||||
#define SW_WARNING_EF_DEACTIVATED() set_res_sw(0x62, 0x83)
|
||||
#define SW_WARNING_WRONG_FCI() set_res_sw(0x62, 0x84)
|
||||
#define SW_WARNING_EF_TERMINATED() set_res_sw(0x62, 0x85)
|
||||
|
||||
#define SW_WARNING_NOINFO() set_res_sw(0x63, 0x00)
|
||||
#define SW_WARNING_FILLUP() set_res_sw(0x63, 0x81)
|
||||
|
||||
#define SW_EXEC_ERROR() set_res_sw(0x64, 0x00)
|
||||
|
||||
#define SW_MEMORY_FAILURE() set_res_sw(0x65, 0x81)
|
||||
|
||||
#define SW_SECURE_MESSAGE_EXEC_ERROR() set_res_sw(0x66, 0x00)
|
||||
|
||||
#define SW_WRONG_LENGTH() set_res_sw(0x67, 0x00)
|
||||
#define SW_WRONG_DATA() set_res_sw(0x67, 0x00)
|
||||
|
||||
#define SW_LOGICAL_CHANNEL_NOT_SUPPORTED() set_res_sw(0x68, 0x81)
|
||||
#define SW_SECURE_MESSAGING_NOT_SUPPORTED() set_res_sw(0x68, 0x82)
|
||||
|
||||
#define SW_COMMAND_INCOMPATIBLE() set_res_sw(0x69, 0x81)
|
||||
#define SW_SECURITY_STATUS_NOT_SATISFIED() set_res_sw(0x69, 0x82)
|
||||
#define SW_PIN_BLOCKED() set_res_sw(0x69, 0x83)
|
||||
#define SW_DATA_INVALID() set_res_sw(0x69, 0x84)
|
||||
#define SW_CONDITIONS_NOT_SATISFIED() set_res_sw(0x69, 0x85)
|
||||
#define SW_COMMAND_NOT_ALLOWED() set_res_sw(0x69, 0x86)
|
||||
#define SW_SECURE_MESSAGING_MISSING_DO() set_res_sw(0x69, 0x87)
|
||||
#define SW_SECURE_MESSAGING_INCORRECT_DO() set_res_sw(0x69, 0x88)
|
||||
#define SW_APPLET_SELECT_FAILED() set_res_sw(0x69, 0x99)
|
||||
|
||||
#define SW_INCORRECT_PARAMS() set_res_sw(0x6A, 0x80)
|
||||
#define SW_FUNC_NOT_SUPPORTED() set_res_sw(0x6A, 0x81)
|
||||
#define SW_FILE_NOT_FOUND() set_res_sw(0x6A, 0x82)
|
||||
#define SW_RECORD_NOT_FOUND() set_res_sw(0x6A, 0x83)
|
||||
#define SW_FILE_FULL() set_res_sw(0x6A, 0x84)
|
||||
#define SW_WRONG_NE() set_res_sw(0x6A, 0x85)
|
||||
#define SW_INCORRECT_P1P2() set_res_sw(0x6A, 0x86)
|
||||
#define SW_WRONG_NC() set_res_sw(0x6A, 0x87)
|
||||
#define SW_REFERENCE_NOT_FOUND() set_res_sw(0x6A, 0x88)
|
||||
#define SW_FILE_EXISTS() set_res_sw(0x6A, 0x89)
|
||||
|
||||
#define SW_WRONG_P1P2() set_res_sw(0x6B, 0x00)
|
||||
|
||||
#define SW_CORRECT_LENGTH_00() set_res_sw(0x6C, 0x00)
|
||||
|
||||
#define SW_INS_NOT_SUPPORTED() set_res_sw(0x6D, 0x00)
|
||||
|
||||
#define SW_CLA_NOT_SUPPORTED() set_res_sw(0x6E, 0x00)
|
||||
|
||||
#define SW_UNKNOWN() set_res_sw(0x6F, 0x00)
|
||||
|
||||
#define SW_OK() set_res_sw(0x90, 0x00)
|
||||
|
||||
#define PICOKEY_OK 0
|
||||
#define PICOKEY_ERR_NO_MEMORY -1000
|
||||
#define PICOKEY_ERR_MEMORY_FATAL -1001
|
||||
#define PICOKEY_ERR_NULL_PARAM -1002
|
||||
#define PICOKEY_ERR_FILE_NOT_FOUND -1003
|
||||
#define PICOKEY_ERR_BLOCKED -1004
|
||||
#define PICOKEY_NO_LOGIN -1005
|
||||
#define PICOKEY_EXEC_ERROR -1006
|
||||
#define PICOKEY_WRONG_LENGTH -1007
|
||||
#define PICOKEY_WRONG_DATA -1008
|
||||
#define PICOKEY_WRONG_DKEK -1009
|
||||
#define PICOKEY_WRONG_SIGNATURE -1010
|
||||
#define PICOKEY_WRONG_PADDING -1011
|
||||
#define PICOKEY_VERIFICATION_FAILED -1012
|
||||
|
||||
#define PICOKEY_CHECK(x) do { ret = (x); if (ret != PICOKEY_OK) goto err; } while (0)
|
||||
|
||||
#if !defined (PICO_PLATFORM)
|
||||
#define PICO_UNIQUE_BOARD_ID_SIZE_BYTES 8
|
||||
typedef struct { uint8_t id[PICO_UNIQUE_BOARD_ID_SIZE_BYTES]; } pico_unique_board_id_t;
|
||||
#endif
|
||||
extern pico_unique_board_id_t pico_serial;
|
||||
extern char pico_serial_str[2 * PICO_UNIQUE_BOARD_ID_SIZE_BYTES + 1];
|
||||
extern uint8_t pico_serial_hash[32];
|
||||
|
||||
#if defined(PICO_PLATFORM)
|
||||
#define multicore_launch_func_core1(a) multicore_launch_core1((void (*) (void))a)
|
||||
#endif
|
||||
|
||||
extern bool has_set_rtc();
|
||||
extern time_t get_rtc_time();
|
||||
extern void set_rtc_time(time_t tv_sec);
|
||||
|
||||
#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
|
||||
@@ -18,9 +18,9 @@
|
||||
#ifndef __VERSION_H_
|
||||
#define __VERSION_H_
|
||||
|
||||
#define PICO_KEYS_SDK_VERSION 0x0805
|
||||
#define PICOKEYS_SDK_VERSION 0x0806
|
||||
|
||||
#define PICO_KEYS_SDK_VERSION_MAJOR ((PICO_KEYS_SDK_VERSION >> 8) & 0xff)
|
||||
#define PICO_KEYS_SDK_VERSION_MINOR (PICO_KEYS_SDK_VERSION & 0xff)
|
||||
#define PICOKEYS_SDK_VERSION_MAJOR ((PICOKEYS_SDK_VERSION >> 8) & 0xff)
|
||||
#define PICOKEYS_SDK_VERSION_MINOR (PICOKEYS_SDK_VERSION & 0xff)
|
||||
|
||||
#endif
|
||||
151
src/rescue.c
151
src/rescue.c
@@ -15,22 +15,33 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "pico_keys.h"
|
||||
#include "picokeys.h"
|
||||
#include "serial.h"
|
||||
#include "led/led.h"
|
||||
#include <time.h>
|
||||
#include "pico_time.h"
|
||||
#ifdef PICO_PLATFORM
|
||||
#include "hardware/watchdog.h"
|
||||
#endif
|
||||
#include "apdu.h"
|
||||
#include "pico_keys_version.h"
|
||||
#include "picokeys_version.h"
|
||||
#include "otp.h"
|
||||
#include "mbedtls/ecdsa.h"
|
||||
#include "mbedtls/sha256.h"
|
||||
#include "random.h"
|
||||
#include "crypto_utils.h"
|
||||
#include "usb.h"
|
||||
#if defined(PICOKEYS_HAS_TRUSTED_REGION)
|
||||
#include "trusted.h"
|
||||
#endif
|
||||
|
||||
#ifdef PICO_PLATFORM
|
||||
extern char __flash_binary_start;
|
||||
extern char __flash_binary_end;
|
||||
#endif
|
||||
|
||||
int rescue_process_apdu();
|
||||
int rescue_unload();
|
||||
static int rescue_process_apdu(void);
|
||||
static int rescue_unload(void);
|
||||
|
||||
const uint8_t rescue_aid[] = {
|
||||
8,
|
||||
@@ -38,13 +49,15 @@ const uint8_t rescue_aid[] = {
|
||||
};
|
||||
|
||||
#ifdef PICO_RP2350
|
||||
#define PICO_MCU 1
|
||||
#elif defined(ESP_PLATFORM)
|
||||
#define PICO_MCU 2
|
||||
const uint8_t PICO_MCU = 1;
|
||||
#elif defined(CONFIG_IDF_TARGET_ESP32S3)
|
||||
const uint8_t PICO_MCU = 2;
|
||||
#elif defined(ENABLE_EMULATION)
|
||||
#define PICO_MCU 3
|
||||
const uint8_t PICO_MCU = 3;
|
||||
#elif defined(CONFIG_IDF_TARGET_ESP32S2)
|
||||
const uint8_t PICO_MCU = 4;
|
||||
#else
|
||||
#define PICO_MCU 0
|
||||
const uint8_t PICO_MCU = 0;
|
||||
#endif
|
||||
|
||||
#define EF_DEVCERT_KEY 0xE0C1
|
||||
@@ -53,7 +66,7 @@ extern uint8_t PICO_PRODUCT;
|
||||
extern uint8_t PICO_VERSION_MAJOR;
|
||||
extern uint8_t PICO_VERSION_MINOR;
|
||||
|
||||
int rescue_select(app_t *a, uint8_t force) {
|
||||
static int rescue_select(app_t *a, uint8_t force) {
|
||||
a->process_apdu = rescue_process_apdu;
|
||||
a->unload = rescue_unload;
|
||||
res_APDU_size = 0;
|
||||
@@ -65,17 +78,29 @@ int rescue_select(app_t *a, uint8_t force) {
|
||||
res_APDU_size += sizeof(pico_serial.id);
|
||||
apdu.ne = res_APDU_size;
|
||||
if (force) {
|
||||
scan_flash();
|
||||
file_scan_flash();
|
||||
}
|
||||
return PICOKEY_OK;
|
||||
return PICOKEYS_OK;
|
||||
}
|
||||
|
||||
const uint8_t atr_rescue[] = {
|
||||
24,
|
||||
0x3B, 0xFE, 0x18, 0x00, 0x00, 0x81, 0x31, 0xFE, 0x45, 0x80, 0x31, 0x81, 0x54, 0x48, 0x53, 0x4D,
|
||||
0x31, 0x73, 0x80, 0x21, 0x40, 0x81, 0x07, 0xFA
|
||||
};
|
||||
|
||||
extern const uint8_t *ccid_atr;
|
||||
WEAK int set_atr(void) {
|
||||
ccid_atr = atr_rescue;
|
||||
return 0;
|
||||
}
|
||||
|
||||
INITIALIZER ( rescue_ctor ) {
|
||||
register_app(rescue_select, rescue_aid);
|
||||
}
|
||||
|
||||
int rescue_unload() {
|
||||
return PICOKEY_OK;
|
||||
static int rescue_unload(void) {
|
||||
return PICOKEYS_OK;
|
||||
}
|
||||
|
||||
static int load_internal_keydev(mbedtls_ecp_keypair *ecp, mbedtls_ecp_group_id ec_id) {
|
||||
@@ -88,7 +113,7 @@ static int load_internal_keydev(mbedtls_ecp_keypair *ecp, mbedtls_ecp_group_id e
|
||||
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, PICO_KEYS_AES_MODE_CBC, pkey, 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) {
|
||||
@@ -99,18 +124,18 @@ static int load_internal_keydev(mbedtls_ecp_keypair *ecp, mbedtls_ecp_group_id e
|
||||
// Generate new key
|
||||
uint8_t pkey[MBEDTLS_ECP_MAX_BYTES] = {0};
|
||||
size_t olen = 0;
|
||||
mbedtls_ecp_gen_key(ec_id, ecp, random_gen, NULL);
|
||||
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, PICO_KEYS_AES_MODE_CBC, pkey, 32);
|
||||
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));
|
||||
low_flash_available();
|
||||
flash_commit();
|
||||
}
|
||||
return PICOKEY_OK;
|
||||
return PICOKEYS_OK;
|
||||
}
|
||||
|
||||
int cmd_keydev_sign() {
|
||||
static int cmd_keydev_sign(void) {
|
||||
uint8_t p1 = P1(apdu);
|
||||
if (p1 == 0x01) {
|
||||
if (apdu.nc != 32) {
|
||||
@@ -121,7 +146,7 @@ int cmd_keydev_sign() {
|
||||
mbedtls_ecp_group_id ec_id = MBEDTLS_ECP_DP_SECP256K1;
|
||||
if (!otp_key_2) {
|
||||
int ret = load_internal_keydev(&ecp, ec_id);
|
||||
if (ret != PICOKEY_OK) {
|
||||
if (ret != PICOKEYS_OK) {
|
||||
mbedtls_ecp_keypair_free(&ecp);
|
||||
return ret;
|
||||
}
|
||||
@@ -138,7 +163,7 @@ int cmd_keydev_sign() {
|
||||
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_gen, NULL);
|
||||
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);
|
||||
@@ -162,7 +187,7 @@ int cmd_keydev_sign() {
|
||||
mbedtls_ecp_group_id ec_id = MBEDTLS_ECP_DP_SECP256K1;
|
||||
if (!otp_key_2) {
|
||||
int ret = load_internal_keydev(&ecp, ec_id);
|
||||
if (ret != PICOKEY_OK) {
|
||||
if (ret != PICOKEYS_OK) {
|
||||
mbedtls_ecp_keypair_free(&ecp);
|
||||
return ret;
|
||||
}
|
||||
@@ -174,13 +199,13 @@ int cmd_keydev_sign() {
|
||||
return SW_EXEC_ERROR();
|
||||
}
|
||||
}
|
||||
int ret = mbedtls_ecp_mul(&ecp.MBEDTLS_PRIVATE(grp), &ecp.MBEDTLS_PRIVATE(Q), &ecp.MBEDTLS_PRIVATE(d), &ecp.MBEDTLS_PRIVATE(grp).G, random_gen, NULL);
|
||||
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, 4096);
|
||||
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();
|
||||
@@ -199,7 +224,7 @@ int cmd_keydev_sign() {
|
||||
}
|
||||
file_put_data(ef_devcert, apdu.data, (uint16_t)apdu.nc);
|
||||
res_APDU_size = 0;
|
||||
low_flash_available();
|
||||
flash_commit();
|
||||
}
|
||||
else {
|
||||
return SW_INCORRECT_P1P2();
|
||||
@@ -208,7 +233,7 @@ int cmd_keydev_sign() {
|
||||
}
|
||||
|
||||
// Blocking CORE1
|
||||
void led_3_blinks() {
|
||||
static void led_3_blinks(void) {
|
||||
#ifndef ENABLE_EMULATION
|
||||
uint32_t mode = led_get_mode();
|
||||
led_set_mode(MODE_PROCESSING);
|
||||
@@ -217,7 +242,7 @@ void led_3_blinks() {
|
||||
#endif
|
||||
}
|
||||
|
||||
int cmd_write() {
|
||||
static int cmd_write(void) {
|
||||
if (apdu.nc < 2) {
|
||||
return SW_WRONG_LENGTH();
|
||||
}
|
||||
@@ -227,8 +252,8 @@ int cmd_write() {
|
||||
if (p1 == 0x1) { // PHY
|
||||
#ifndef ENABLE_EMULATION
|
||||
int ret = phy_unserialize_data(apdu.data, (uint16_t)apdu.nc, &phy_data);
|
||||
if (ret == PICOKEY_OK) {
|
||||
if (phy_save() != PICOKEY_OK) {
|
||||
if (ret == PICOKEYS_OK) {
|
||||
if (phy_save() != PICOKEYS_OK) {
|
||||
return SW_EXEC_ERROR();
|
||||
}
|
||||
}
|
||||
@@ -244,7 +269,7 @@ int cmd_write() {
|
||||
return SW_WRONG_LENGTH();
|
||||
}
|
||||
struct tm tm;
|
||||
tm.tm_year = get_uint16_t_be(apdu.data) - 1900;
|
||||
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];
|
||||
@@ -266,7 +291,7 @@ int cmd_write() {
|
||||
return SW_OK();
|
||||
}
|
||||
|
||||
int cmd_read() {
|
||||
static int cmd_read(void) {
|
||||
if (apdu.nc != 0) {
|
||||
return SW_WRONG_LENGTH();
|
||||
}
|
||||
@@ -276,7 +301,7 @@ int cmd_read() {
|
||||
#ifndef ENABLE_EMULATION
|
||||
uint16_t len = 0;
|
||||
int ret = phy_serialize_data(&phy_data, apdu.rdata, &len);
|
||||
if (ret != PICOKEY_OK) {
|
||||
if (ret != PICOKEYS_OK) {
|
||||
return SW_EXEC_ERROR();
|
||||
}
|
||||
res_APDU_size = len;
|
||||
@@ -285,16 +310,16 @@ int cmd_read() {
|
||||
else if (p1 == 0x2) { // FLASH INFO
|
||||
res_APDU_size = 0;
|
||||
uint32_t free = flash_free_space(), total = flash_total_space(), used = flash_used_space(), nfiles = flash_num_files(), size = flash_size();
|
||||
res_APDU_size += put_uint32_t_be(free, res_APDU + res_APDU_size);
|
||||
res_APDU_size += put_uint32_t_be(used, res_APDU + res_APDU_size);
|
||||
res_APDU_size += put_uint32_t_be(total, res_APDU + res_APDU_size);
|
||||
res_APDU_size += put_uint32_t_be(nfiles, res_APDU + res_APDU_size);
|
||||
res_APDU_size += put_uint32_t_be(size, res_APDU + res_APDU_size);
|
||||
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_t_be(fw_size, res_APDU + res_APDU_size);
|
||||
res_APDU_size += put_uint32_be(fw_size, res_APDU + res_APDU_size);
|
||||
#endif
|
||||
}
|
||||
else if (p1 == 0x3) { // OTP SECURE BOOT STATUS
|
||||
@@ -315,30 +340,39 @@ int cmd_read() {
|
||||
}
|
||||
res_APDU_size = 0;
|
||||
time_t tv_sec = get_rtc_time();
|
||||
#ifdef PICO_PLATFORM
|
||||
struct timespec tv = {.tv_sec = tv_sec, .tv_nsec = 0};
|
||||
#else
|
||||
struct timeval tv = {.tv_sec = tv_sec, .tv_usec = 0};
|
||||
#endif
|
||||
if (p2 == 0x1) {
|
||||
struct tm *tm = localtime(&tv.tv_sec);
|
||||
res_APDU_size += put_uint16_t_be(tm->tm_year + 1900, res_APDU);
|
||||
res_APDU[res_APDU_size++] = tm->tm_mon;
|
||||
res_APDU[res_APDU_size++] = tm->tm_mday;
|
||||
res_APDU[res_APDU_size++] = tm->tm_wday;
|
||||
res_APDU[res_APDU_size++] = tm->tm_hour;
|
||||
res_APDU[res_APDU_size++] = tm->tm_min;
|
||||
res_APDU[res_APDU_size++] = tm->tm_sec;
|
||||
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_t_be((uint32_t)tv.tv_sec, res_APDU);
|
||||
res_APDU_size += put_uint32_be((uint32_t)tv_sec, res_APDU);
|
||||
}
|
||||
}
|
||||
#if defined(PICOKEYS_HAS_TRUSTED_REGION)
|
||||
else if (p1 == 0x5) { // GET TRUST DIGEST
|
||||
uint8_t digest[32];
|
||||
int ret = trusted_region_sha256(digest);
|
||||
if (ret != PICOKEYS_OK) {
|
||||
return SW_EXEC_ERROR();
|
||||
}
|
||||
memcpy(res_APDU, digest, 32);
|
||||
res_APDU_size = 32;
|
||||
}
|
||||
#endif
|
||||
else {
|
||||
return SW_INCORRECT_P1P2();
|
||||
}
|
||||
return SW_OK();
|
||||
}
|
||||
|
||||
#if defined(PICO_RP2350) || defined(ESP_PLATFORM)
|
||||
int cmd_secure() {
|
||||
static int cmd_secure(void) {
|
||||
if (apdu.nc != 0) {
|
||||
return SW_WRONG_LENGTH();
|
||||
}
|
||||
@@ -347,7 +381,7 @@ int cmd_secure() {
|
||||
bool secure_lock = P2(apdu) == 0x1;
|
||||
|
||||
int ret = otp_enable_secure_boot(bootkey, secure_lock);
|
||||
if (ret != 0) {
|
||||
if (ret != PICOKEYS_OK) {
|
||||
return SW_EXEC_ERROR();
|
||||
}
|
||||
led_3_blinks();
|
||||
@@ -356,14 +390,15 @@ int cmd_secure() {
|
||||
#endif
|
||||
|
||||
#ifdef PICO_PLATFORM
|
||||
int cmd_reboot_bootsel() {
|
||||
static int cmd_reboot_bootsel(void) {
|
||||
if (apdu.nc != 0) {
|
||||
return SW_WRONG_LENGTH();
|
||||
}
|
||||
|
||||
if (P1(apdu) == 0x1) {
|
||||
// Reboot to BOOTSEL
|
||||
reset_usb_boot(0, 0);
|
||||
uint32_t val = EV_RESET;
|
||||
queue_try_add(&card_to_usb_q, &val);
|
||||
}
|
||||
else if (P1(apdu) == 0x0) {
|
||||
// Reboot to normal mode
|
||||
@@ -396,7 +431,7 @@ static const cmd_t cmds[] = {
|
||||
{ 0x00, 0x0 }
|
||||
};
|
||||
|
||||
int rescue_process_apdu() {
|
||||
static int rescue_process_apdu(void) {
|
||||
if (CLA(apdu) != 0x80) {
|
||||
return SW_CLA_NOT_SUPPORTED();
|
||||
}
|
||||
|
||||
188
src/rng/hwrng.c
188
src/rng/hwrng.c
@@ -15,29 +15,24 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include "picokeys.h"
|
||||
#include "hwrng.h"
|
||||
#include "pico_time.h"
|
||||
|
||||
#if defined(PICO_PLATFORM)
|
||||
#include "pico/stdlib.h"
|
||||
#include "hwrng.h"
|
||||
#include "bsp/board.h"
|
||||
#include "pico/rand.h"
|
||||
#include "pico/mutex.h"
|
||||
#elif defined(ESP_PLATFORM)
|
||||
#include "bootloader_random.h"
|
||||
#include "esp_random.h"
|
||||
#include "esp_compat.h"
|
||||
#include "compat/esp_compat.h"
|
||||
#else
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include "board.h"
|
||||
#include "compat/queue.h"
|
||||
#endif
|
||||
|
||||
void hwrng_start() {
|
||||
static void hwrng_start(void) {
|
||||
#if defined(ENABLE_EMULATION)
|
||||
srand(time(0));
|
||||
srand((unsigned int)time(NULL));
|
||||
#elif defined(ESP_PLATFORM)
|
||||
bootloader_random_enable();
|
||||
#endif
|
||||
@@ -46,13 +41,13 @@ void hwrng_start() {
|
||||
static uint64_t random_word = 0xcbf29ce484222325;
|
||||
static uint8_t hwrng_mix_round = 0;
|
||||
|
||||
static void hwrng_mix_init() {
|
||||
static void hwrng_mix_init(void) {
|
||||
random_word = 0xcbf29ce484222325;
|
||||
hwrng_mix_round = 0;
|
||||
}
|
||||
|
||||
/* Here, we assume a little endian architecture. */
|
||||
static int hwrng_mix_process() {
|
||||
static int hwrng_mix_process(void) {
|
||||
if (hwrng_mix_round == 0) {
|
||||
hwrng_mix_init();
|
||||
}
|
||||
@@ -76,70 +71,113 @@ static int hwrng_mix_process() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct hwrng_buf {
|
||||
uint32_t *buf;
|
||||
uint8_t head, tail;
|
||||
uint8_t size;
|
||||
unsigned int full : 1;
|
||||
unsigned int empty : 1;
|
||||
};
|
||||
typedef struct hwrng_buf {
|
||||
uint8_t *buf;
|
||||
size_t head;
|
||||
size_t tail;
|
||||
size_t size;
|
||||
size_t count;
|
||||
} hwrng_buf_t;
|
||||
|
||||
static void hwrng_buf_init(struct hwrng_buf *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, uint8_t *p, size_t size) {
|
||||
rb->buf = p;
|
||||
rb->size = size;
|
||||
rb->head = rb->tail = 0;
|
||||
rb->full = 0;
|
||||
rb->empty = 1;
|
||||
rb->count = 0;
|
||||
}
|
||||
|
||||
static void hwrng_buf_add(struct hwrng_buf *rb, uint32_t v) {
|
||||
rb->buf[rb->tail++] = v;
|
||||
if (rb->tail == rb->size) {
|
||||
rb->tail = 0;
|
||||
static size_t hwrng_buf_add(struct hwrng_buf *rb, const uint8_t *data, size_t len) {
|
||||
size_t room = rb->size - rb->count;
|
||||
size_t n = len < room ? len : room;
|
||||
size_t tail = rb->tail;
|
||||
size_t first = n;
|
||||
|
||||
if (first > rb->size - tail) {
|
||||
first = rb->size - tail;
|
||||
}
|
||||
if (rb->tail == rb->head) {
|
||||
rb->full = 1;
|
||||
if (first) {
|
||||
memcpy(rb->buf + tail, data, first);
|
||||
tail += first;
|
||||
if (tail >= rb->size) {
|
||||
tail = 0;
|
||||
}
|
||||
}
|
||||
rb->empty = 0;
|
||||
if (n > first) {
|
||||
size_t second = n - first;
|
||||
memcpy(rb->buf + tail, data + first, second);
|
||||
tail += second;
|
||||
}
|
||||
rb->tail = tail;
|
||||
rb->count += n;
|
||||
return n;
|
||||
}
|
||||
|
||||
static uint32_t hwrng_buf_del(struct hwrng_buf *rb) {
|
||||
uint32_t v = rb->buf[rb->head++];
|
||||
static size_t hwrng_buf_del(struct hwrng_buf *rb, uint8_t *data, size_t len) {
|
||||
size_t n = len < rb->count ? len : rb->count;
|
||||
size_t head = rb->head;
|
||||
size_t first = n;
|
||||
|
||||
if (rb->head == rb->size) {
|
||||
rb->head = 0;
|
||||
if (first > rb->size - head) {
|
||||
first = rb->size - head;
|
||||
}
|
||||
if (rb->head == rb->tail) {
|
||||
rb->empty = 1;
|
||||
if (first) {
|
||||
memcpy(data, rb->buf + head, first);
|
||||
head += first;
|
||||
if (head >= rb->size) {
|
||||
head = 0;
|
||||
}
|
||||
}
|
||||
rb->full = 0;
|
||||
if (n > first) {
|
||||
size_t second = n - first;
|
||||
memcpy(data + first, rb->buf + head, second);
|
||||
head += second;
|
||||
}
|
||||
rb->head = head;
|
||||
rb->count -= n;
|
||||
return n;
|
||||
}
|
||||
|
||||
return v;
|
||||
static inline size_t hwrng_buf_space(const struct hwrng_buf *rb) {
|
||||
return rb->size - rb->count;
|
||||
}
|
||||
|
||||
static inline bool hwrng_buf_full(const struct hwrng_buf *rb) {
|
||||
return rb->count == rb->size;
|
||||
}
|
||||
|
||||
static struct hwrng_buf ring_buffer;
|
||||
|
||||
void *hwrng_task() {
|
||||
void *hwrng_task(void) {
|
||||
struct hwrng_buf *rb = &ring_buffer;
|
||||
|
||||
int n;
|
||||
|
||||
if ((n = hwrng_mix_process())) {
|
||||
const uint32_t *vp = (const uint32_t *) &random_word;
|
||||
|
||||
for (int i = 0; i < n; i++) {
|
||||
hwrng_buf_add(rb, *vp++);
|
||||
if (rb->full) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
hwrng_lock();
|
||||
if (hwrng_buf_space(rb) >= sizeof(random_word) && hwrng_mix_process()) {
|
||||
hwrng_buf_add(rb, (const uint8_t *)&random_word, sizeof(random_word));
|
||||
}
|
||||
hwrng_unlock();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void hwrng_init(uint32_t *buf, uint8_t size) {
|
||||
void hwrng_init(uint8_t *buf, size_t size) {
|
||||
struct hwrng_buf *rb = &ring_buffer;
|
||||
|
||||
mutex_init(&hwrng_mutex);
|
||||
hwrng_mutex_initialized = true;
|
||||
hwrng_buf_init(rb, buf, size);
|
||||
|
||||
hwrng_start();
|
||||
@@ -147,33 +185,55 @@ void hwrng_init(uint32_t *buf, uint8_t size) {
|
||||
hwrng_mix_init();
|
||||
}
|
||||
|
||||
void hwrng_flush(void) {
|
||||
size_t hwrng_read(uint8_t *buf, size_t len) {
|
||||
struct hwrng_buf *rb = &ring_buffer;
|
||||
while (!rb->empty) {
|
||||
hwrng_buf_del(rb);
|
||||
}
|
||||
size_t n;
|
||||
|
||||
hwrng_lock();
|
||||
n = hwrng_buf_del(rb, buf, len);
|
||||
hwrng_unlock();
|
||||
return n;
|
||||
}
|
||||
|
||||
uint32_t hwrng_get() {
|
||||
void hwrng_flush(void) {
|
||||
struct hwrng_buf *rb = &ring_buffer;
|
||||
uint32_t v;
|
||||
hwrng_lock();
|
||||
rb->head = 0;
|
||||
rb->tail = 0;
|
||||
rb->count = 0;
|
||||
hwrng_unlock();
|
||||
}
|
||||
|
||||
while (rb->empty) {
|
||||
hwrng_task();
|
||||
uint32_t hwrng_get(void) {
|
||||
uint32_t v = 0;
|
||||
size_t offset = 0;
|
||||
|
||||
while (offset < sizeof(v)) {
|
||||
size_t n = hwrng_read(((uint8_t *)&v) + offset, sizeof(v) - offset);
|
||||
if (n == 0) {
|
||||
hwrng_task();
|
||||
continue;
|
||||
}
|
||||
offset += n;
|
||||
}
|
||||
v = hwrng_buf_del(rb);
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
void hwrng_wait_full() {
|
||||
void hwrng_wait_full(void) {
|
||||
struct hwrng_buf *rb = &ring_buffer;
|
||||
#ifdef ESP_PLATFORM
|
||||
uint8_t core = xTaskGetCurrentTaskHandle() == hcore1 ? 1 : 0;
|
||||
#elif defined(PICO_PLATFORM)
|
||||
uint core = get_core_num();
|
||||
#endif
|
||||
while (!rb->full) {
|
||||
while (true) {
|
||||
hwrng_lock();
|
||||
bool full = hwrng_buf_full(rb);
|
||||
hwrng_unlock();
|
||||
if (full) {
|
||||
break;
|
||||
}
|
||||
#if defined(PICO_PLATFORM) || defined(ESP_PLATFORM)
|
||||
if (core == 1) {
|
||||
sleep_ms(1);
|
||||
|
||||
@@ -18,10 +18,13 @@
|
||||
#ifndef _NEUG_H_
|
||||
#define _NEUG_H_
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
void hwrng_init(uint32_t *buf, uint8_t size);
|
||||
uint32_t hwrng_get();
|
||||
void hwrng_init(uint8_t *buf, size_t size);
|
||||
size_t hwrng_read(uint8_t *buf, size_t len);
|
||||
void hwrng_flush(void);
|
||||
void hwrng_wait_full();
|
||||
void hwrng_wait_full(void);
|
||||
void *hwrng_task(void);
|
||||
uint32_t hwrng_get(void);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -17,34 +17,21 @@
|
||||
|
||||
#define HWRNG_PRE_LOOP 32
|
||||
|
||||
#include <stdlib.h>
|
||||
#if defined(PICO_PLATFORM)
|
||||
#include "pico/stdlib.h"
|
||||
#endif
|
||||
#include <string.h>
|
||||
|
||||
#include "picokeys.h"
|
||||
#include "hwrng.h"
|
||||
#include "random.h"
|
||||
|
||||
#define RANDOM_BYTES_LENGTH 32
|
||||
static uint32_t random_word[RANDOM_BYTES_LENGTH / sizeof(uint32_t)];
|
||||
static uint8_t random_pool[256];
|
||||
|
||||
void random_init(void) {
|
||||
hwrng_init(random_word, RANDOM_BYTES_LENGTH / sizeof(uint32_t));
|
||||
hwrng_init(random_pool, sizeof(random_pool));
|
||||
|
||||
for (int i = 0; i < HWRNG_PRE_LOOP; i++) {
|
||||
hwrng_get();
|
||||
hwrng_task();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Free pointer to random 32-byte
|
||||
*/
|
||||
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
|
||||
*/
|
||||
@@ -53,11 +40,9 @@ const uint8_t *random_bytes_get(size_t len) {
|
||||
if (len > MAX_RANDOM_BUFFER) {
|
||||
return NULL;
|
||||
}
|
||||
static uint32_t return_word[MAX_RANDOM_BUFFER / sizeof(uint32_t)];
|
||||
for (size_t ix = 0; ix < len; ix += RANDOM_BYTES_LENGTH) {
|
||||
hwrng_wait_full();
|
||||
memcpy(return_word + ix / sizeof(uint32_t), random_word, RANDOM_BYTES_LENGTH);
|
||||
random_bytes_free((const uint8_t *) random_word);
|
||||
static uint8_t return_word[MAX_RANDOM_BUFFER];
|
||||
if (random_fill_buffer(return_word, len) != 0) {
|
||||
return NULL;
|
||||
}
|
||||
return (const uint8_t *) return_word;
|
||||
}
|
||||
@@ -65,39 +50,30 @@ const uint8_t *random_bytes_get(size_t len) {
|
||||
/*
|
||||
* Random byte iterator
|
||||
*/
|
||||
int random_gen(void *arg, unsigned char *out, size_t out_len) {
|
||||
uint8_t *index_p = (uint8_t *) arg;
|
||||
uint8_t index = index_p ? *index_p : 0;
|
||||
uint8_t n;
|
||||
int random_fill_iterator(void *arg, unsigned char *out, size_t out_len) {
|
||||
random_fill_iterator_ctx_t *ctx = (random_fill_iterator_ctx_t *) arg;
|
||||
int ret = 0;
|
||||
|
||||
while (out_len) {
|
||||
hwrng_wait_full();
|
||||
|
||||
n = RANDOM_BYTES_LENGTH - index;
|
||||
if (n > out_len) {
|
||||
n = (uint8_t)out_len;
|
||||
if (ctx && ctx->cancel) {
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
size_t n = hwrng_read(out, out_len);
|
||||
if (n == 0) {
|
||||
hwrng_task();
|
||||
continue;
|
||||
}
|
||||
|
||||
memcpy(out, ((unsigned char *) random_word) + index, n);
|
||||
out += n;
|
||||
out_len -= n;
|
||||
index += n;
|
||||
|
||||
if (index >= RANDOM_BYTES_LENGTH) {
|
||||
index = 0;
|
||||
hwrng_flush();
|
||||
if (ctx) {
|
||||
ctx->index = (uint8_t)((ctx->index + n) % RANDOM_BYTES_LENGTH);
|
||||
}
|
||||
}
|
||||
|
||||
if (index_p) {
|
||||
*index_p = index;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_PQC
|
||||
void randombytes(uint8_t *buf, size_t n) {
|
||||
random_gen(NULL, buf, n);
|
||||
int random_fill_buffer(uint8_t *buf, size_t n) {
|
||||
return random_fill_iterator(NULL, buf, n);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -21,14 +21,18 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
void random_init(void);
|
||||
typedef struct {
|
||||
uint8_t index;
|
||||
volatile bool cancel;
|
||||
} random_fill_iterator_ctx_t;
|
||||
|
||||
/* 32-byte random bytes */
|
||||
const uint8_t *random_bytes_get(size_t);
|
||||
void random_bytes_free(const uint8_t *p);
|
||||
extern void
|
||||
random_init(void);
|
||||
|
||||
/* iterator returning a byta at a time */
|
||||
extern int random_gen(void *arg, unsigned char *output, size_t output_len);
|
||||
extern const uint8_t *random_bytes_get(size_t);
|
||||
extern int random_fill_iterator(void *arg, unsigned char *output, size_t output_len);
|
||||
extern int random_fill_buffer(uint8_t *buf, size_t n);
|
||||
|
||||
#endif
|
||||
|
||||
247
src/serial.c
Normal file
247
src/serial.c
Normal file
@@ -0,0 +1,247 @@
|
||||
/*
|
||||
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
|
||||
* Copyright (c) 2022 Pol Henarejos.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "picokeys.h"
|
||||
#include "serial.h"
|
||||
#include "mbedtls/sha256.h"
|
||||
#if defined(ESP_PLATFORM)
|
||||
#include "esp_efuse.h"
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#ifndef ESP_PLATFORM
|
||||
#include <time.h>
|
||||
#endif
|
||||
|
||||
#if defined(__APPLE__)
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#include <IOKit/IOKitLib.h>
|
||||
|
||||
static int get_macos_serial(uint8_t *out) {
|
||||
io_service_t platformExpert;
|
||||
CFTypeRef serialNumberAsCFString;
|
||||
char serial[32] = {0};
|
||||
if (!out) {
|
||||
return -1;
|
||||
}
|
||||
out[0] = '\0';
|
||||
platformExpert = IOServiceGetMatchingService(kIOMainPortDefault, IOServiceMatching("IOPlatformExpertDevice"));
|
||||
if (!platformExpert) {
|
||||
return -2;
|
||||
}
|
||||
serialNumberAsCFString = IORegistryEntryCreateCFProperty(platformExpert, CFSTR("IOPlatformSerialNumber"), kCFAllocatorDefault, 0);
|
||||
IOObjectRelease(platformExpert);
|
||||
if (!serialNumberAsCFString) {
|
||||
return -3;
|
||||
}
|
||||
Boolean ok = CFStringGetCString(serialNumberAsCFString, serial, sizeof(serial), kCFStringEncodingUTF8);
|
||||
CFRelease(serialNumberAsCFString);
|
||||
if (ok) {
|
||||
mbedtls_sha256((const unsigned char *)serial, strlen(serial), pico_serial_hash, false);
|
||||
memcpy(out, pico_serial_hash, PICO_UNIQUE_BOARD_ID_SIZE_BYTES);
|
||||
}
|
||||
return ok ? 0 : -4;
|
||||
}
|
||||
#elif defined(_MSC_VER)
|
||||
#include <windows.h>
|
||||
#include <wbemidl.h>
|
||||
|
||||
#pragma comment(lib, "wbemuuid.lib")
|
||||
|
||||
static int get_system_uuid(char *out) {
|
||||
char serial[64] = {0};
|
||||
HRESULT hr;
|
||||
IWbemLocator *locator = NULL;
|
||||
IWbemServices *svc = NULL;
|
||||
IEnumWbemClassObject *enumerator = NULL;
|
||||
IWbemClassObject *obj = NULL;
|
||||
ULONG returned = 0;
|
||||
VARIANT vtProp;
|
||||
hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
|
||||
if (FAILED(hr) && hr != RPC_E_CHANGED_MODE)
|
||||
return -1;
|
||||
hr = CoInitializeSecurity( NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_DEFAULT, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE, NULL);
|
||||
if (FAILED(hr) && hr != RPC_E_TOO_LATE) {
|
||||
CoUninitialize();
|
||||
return -2;
|
||||
}
|
||||
hr = CoCreateInstance(&CLSID_WbemLocator, NULL, CLSCTX_INPROC_SERVER, &IID_IWbemLocator, (LPVOID *)&locator);
|
||||
if (FAILED(hr)) {
|
||||
CoUninitialize();
|
||||
return -3;
|
||||
}
|
||||
hr = locator->lpVtbl->ConnectServer(locator, L"ROOT\\CIMV2", NULL, NULL, NULL, 0, NULL, NULL, &svc);
|
||||
if (FAILED(hr)) {
|
||||
locator->lpVtbl->Release(locator);
|
||||
CoUninitialize();
|
||||
return -4;
|
||||
}
|
||||
hr = CoSetProxyBlanket((IUnknown *)svc, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL, RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE);
|
||||
if (FAILED(hr)) {
|
||||
svc->lpVtbl->Release(svc);
|
||||
locator->lpVtbl->Release(locator);
|
||||
CoUninitialize();
|
||||
return -5;
|
||||
}
|
||||
hr = svc->lpVtbl->ExecQuery(svc, L"WQL", L"SELECT UUID FROM Win32_ComputerSystemProduct", WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, NULL, &enumerator);
|
||||
if (FAILED(hr) || !enumerator) {
|
||||
svc->lpVtbl->Release(svc);
|
||||
locator->lpVtbl->Release(locator);
|
||||
CoUninitialize();
|
||||
return -6;
|
||||
}
|
||||
hr = enumerator->lpVtbl->Next( enumerator, WBEM_INFINITE, 1, &obj, &returned);
|
||||
if (returned == 0 || !obj) {
|
||||
enumerator->lpVtbl->Release(enumerator);
|
||||
svc->lpVtbl->Release(svc);
|
||||
locator->lpVtbl->Release(locator);
|
||||
CoUninitialize();
|
||||
return -7;
|
||||
}
|
||||
VariantInit(&vtProp);
|
||||
hr = obj->lpVtbl->Get(obj, L"UUID", 0, &vtProp, NULL, NULL);
|
||||
if (SUCCEEDED(hr) && vtProp.vt == VT_BSTR && vtProp.bstrVal) {
|
||||
WideCharToMultiByte(CP_UTF8, 0, vtProp.bstrVal, -1, serial, (int)sizeof(serial), NULL, NULL);
|
||||
}
|
||||
VariantClear(&vtProp);
|
||||
obj->lpVtbl->Release(obj);
|
||||
enumerator->lpVtbl->Release(enumerator);
|
||||
svc->lpVtbl->Release(svc);
|
||||
locator->lpVtbl->Release(locator);
|
||||
CoUninitialize();
|
||||
if (serial[0]) {
|
||||
mbedtls_sha256((const unsigned char *)serial, strlen(serial), pico_serial_hash, false);
|
||||
memcpy(out, pico_serial_hash, PICO_UNIQUE_BOARD_ID_SIZE_BYTES);
|
||||
}
|
||||
return serial[0] ? 0 : -8;
|
||||
}
|
||||
#elif defined(__linux__)
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
static int read_first_line(const char *path, char *out, size_t out_len) {
|
||||
FILE *f;
|
||||
if (!out || out_len == 0) {
|
||||
return -1;
|
||||
}
|
||||
out[0] = '\0';
|
||||
f = fopen(path, "r");
|
||||
if (!f) {
|
||||
return -2;
|
||||
}
|
||||
if (!fgets(out, out_len, f)) {
|
||||
fclose(f);
|
||||
return -3;
|
||||
}
|
||||
fclose(f);
|
||||
out[strcspn(out, "\r\n")] = '\0';
|
||||
return out[0] ? 0 : -4;
|
||||
}
|
||||
|
||||
static int is_bad_value(const char *s) {
|
||||
if (!s || !s[0])
|
||||
return 1;
|
||||
if (strcasecmp(s, "None") == 0)
|
||||
return 1;
|
||||
if (strcasecmp(s, "Unknown") == 0)
|
||||
return 1;
|
||||
if (strcasecmp(s, "Default string") == 0)
|
||||
return 1;
|
||||
if (strcasecmp(s, "To be filled by O.E.M.") == 0)
|
||||
return 1;
|
||||
if (strcmp(s, "00000000-0000-0000-0000-000000000000") == 0)
|
||||
return 1;
|
||||
if (strcmp(s, "FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF") == 0)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int append_field(char *out, size_t out_len, const char *prefix,const char *path) {
|
||||
char value[256];
|
||||
if (read_first_line(path, value, sizeof(value)) != 0) {
|
||||
return -1;
|
||||
}
|
||||
if (is_bad_value(value)) {
|
||||
return -2;
|
||||
}
|
||||
strncat(out, prefix, out_len - strlen(out) - 1);
|
||||
strncat(out, value, out_len - strlen(out) - 1);
|
||||
strncat(out, ";", out_len - strlen(out) - 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_linux_hardware_id(char *out) {
|
||||
if (!out) {
|
||||
return -1;
|
||||
}
|
||||
char serial[256] = {0};
|
||||
append_field(serial, sizeof(serial), "UUID=", "/sys/class/dmi/id/product_uuid");
|
||||
append_field(serial, sizeof(serial), "BOARD=", "/sys/class/dmi/id/board_serial");
|
||||
append_field(serial, sizeof(serial), "PRODUCT=", "/sys/class/dmi/id/product_serial");
|
||||
append_field(serial, sizeof(serial), "CHASSIS=", "/sys/class/dmi/id/chassis_serial");
|
||||
append_field(serial, sizeof(serial), "MACHINE=", "/etc/machine-id");
|
||||
if (serial[0]) {
|
||||
mbedtls_sha256((const unsigned char *)serial, strlen(serial), pico_serial_hash, false);
|
||||
memcpy(out, pico_serial_hash, PICO_UNIQUE_BOARD_ID_SIZE_BYTES);
|
||||
}
|
||||
return serial[0] ? 0 : -2;
|
||||
}
|
||||
#endif
|
||||
|
||||
char pico_serial_str[2 * PICO_UNIQUE_BOARD_ID_SIZE_BYTES + 1];
|
||||
uint8_t pico_serial_hash[32];
|
||||
picokey_serial_t pico_serial;
|
||||
|
||||
static int serial_id_is_zero(const uint8_t *id, size_t len) {
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
if (id[i] != 0) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
#if defined(ESP_PLATFORM)
|
||||
#define pico_get_unique_board_id(a) do { uint32_t value; esp_efuse_read_block(EFUSE_BLK1, &value, 0, 32); memcpy((uint8_t *)(a), &value, sizeof(uint32_t)); esp_efuse_read_block(EFUSE_BLK1, &value, 32, 32); memcpy((uint8_t *)(a)+4, &value, sizeof(uint32_t)); } while(0)
|
||||
#elif defined(__APPLE__)
|
||||
#define pico_get_unique_board_id(a) get_macos_serial((uint8_t *)(a))
|
||||
#elif defined(_MSC_VER)
|
||||
#define pico_get_unique_board_id(a) get_system_uuid((char *)(a))
|
||||
#elif defined(__linux__)
|
||||
#define pico_get_unique_board_id(a) get_linux_hardware_id((char *)(a))
|
||||
#endif
|
||||
|
||||
void serial_init(void) {
|
||||
int serial_rc = 0;
|
||||
|
||||
#if defined(__APPLE__) || defined(_MSC_VER) || defined(__linux__)
|
||||
serial_rc = pico_get_unique_board_id(&pico_serial);
|
||||
#else
|
||||
pico_get_unique_board_id(&pico_serial);
|
||||
#endif
|
||||
|
||||
if (serial_rc != 0 || serial_id_is_zero(pico_serial.id, sizeof(pico_serial.id))) {
|
||||
printf("serial init: failed to read stable hardware id (rc=%d); using fallback id\n", serial_rc);
|
||||
memset(pico_serial.id, 0, sizeof(pico_serial.id));
|
||||
}
|
||||
|
||||
memset(pico_serial_str, 0, sizeof(pico_serial_str));
|
||||
for (size_t i = 0; i < sizeof(pico_serial); i++) {
|
||||
snprintf(&pico_serial_str[2 * i], 3, "%02X", pico_serial.id[i]);
|
||||
}
|
||||
mbedtls_sha256(pico_serial.id, sizeof(pico_serial.id), pico_serial_hash, false);
|
||||
}
|
||||
40
src/serial.h
Normal file
40
src/serial.h
Normal file
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
|
||||
* Copyright (c) 2022 Pol Henarejos.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _SERIAL_H_
|
||||
#define _SERIAL_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#if !defined (PICO_PLATFORM)
|
||||
#if defined(__APPLE__) || defined(_MSC_VER) || defined(__linux__)
|
||||
#define PICO_UNIQUE_BOARD_ID_SIZE_BYTES 16
|
||||
#else
|
||||
#define PICO_UNIQUE_BOARD_ID_SIZE_BYTES 8
|
||||
#endif
|
||||
typedef struct { uint8_t id[PICO_UNIQUE_BOARD_ID_SIZE_BYTES]; } picokey_serial_t;
|
||||
#else
|
||||
#include "pico/unique_id.h"
|
||||
typedef pico_unique_board_id_t picokey_serial_t;
|
||||
#endif
|
||||
|
||||
extern picokey_serial_t pico_serial;
|
||||
extern char pico_serial_str[2 * PICO_UNIQUE_BOARD_ID_SIZE_BYTES + 1];
|
||||
extern uint8_t pico_serial_hash[32];
|
||||
extern void serial_init(void);
|
||||
|
||||
#endif //_SERIAL_H_
|
||||
65
src/signal.c
Normal file
65
src/signal.c
Normal file
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* 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 "signal.h"
|
||||
|
||||
static signal_t signals[MAX_SIGNALS] = {0};
|
||||
static uint8_t num_signals = 0;
|
||||
|
||||
int signal_add(signal_code_t code, signal_flag_t flags, signal_handler_t handler) {
|
||||
if (num_signals >= MAX_SIGNALS) {
|
||||
return PICOKEYS_ERR_NO_MEMORY;
|
||||
}
|
||||
if (handler == NULL) {
|
||||
return PICOKEYS_ERR_NULL_PARAM;
|
||||
}
|
||||
signals[num_signals].code = code;
|
||||
signals[num_signals].flags = flags;
|
||||
signals[num_signals].handler = handler;
|
||||
num_signals++;
|
||||
return PICOKEYS_OK;
|
||||
}
|
||||
|
||||
int signal_remove(signal_code_t code, signal_handler_t handler) {
|
||||
for (int i = 0; i < num_signals; i++) {
|
||||
if (signals[i].code == code && signals[i].handler == handler) {
|
||||
for (int j = i; j < num_signals - 1; j++) {
|
||||
signals[j] = signals[j + 1];
|
||||
}
|
||||
num_signals--;
|
||||
return PICOKEYS_OK;
|
||||
}
|
||||
}
|
||||
return PICOKEYS_ERR_FILE_NOT_FOUND;
|
||||
}
|
||||
|
||||
int signal_emit_param(signal_code_t code, void *data) {
|
||||
for (int i = 0; i < num_signals; i++) {
|
||||
if (signals[i].code == code) {
|
||||
int ret = signals[i].handler(code, data);
|
||||
if (ret != 0 && (signals[i].flags & SIGNAL_FLAG_ERROR_CONTINUE) == 0) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
return PICOKEYS_ERR_FILE_NOT_FOUND;
|
||||
}
|
||||
|
||||
int signal_emit(signal_code_t code) {
|
||||
return signal_emit_param(code, NULL);
|
||||
}
|
||||
56
src/signal.h
Normal file
56
src/signal.h
Normal file
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* 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 _SIGNAL_H_
|
||||
#define _SIGNAL_H_
|
||||
|
||||
#define MAX_SIGNALS 32
|
||||
typedef enum {
|
||||
SIGNAL_NONE = 0,
|
||||
SIGNAL_BOOT = 1,
|
||||
SIGNAL_USB_MOUNTED = 2,
|
||||
SIGNAL_BUTTON_PRESS = 3,
|
||||
SIGNAL_BUTTON_RELEASE = 4,
|
||||
SIGNAL_USER_PRESENCE_REQUEST = 5,
|
||||
SIGNAL_USER_PRESENCE_COMPLETED = 6,
|
||||
SIGNAL_USER_PRESENCE_CANCELLED = 7,
|
||||
SIGNAL_USER_PRESENCE_TIMEOUT = 8,
|
||||
} signal_code_t;
|
||||
|
||||
typedef enum {
|
||||
SIGNAL_FLAG_NONE = 0x0,
|
||||
SIGNAL_FLAG_ERROR_CONTINUE = 0x1,
|
||||
} signal_flag_t;
|
||||
|
||||
typedef int (*signal_handler_t)(signal_code_t, void *);
|
||||
|
||||
typedef struct {
|
||||
uint32_t timeout;
|
||||
} signal_user_presence_request_data_t;
|
||||
|
||||
typedef struct {
|
||||
signal_code_t code;
|
||||
signal_flag_t flags;
|
||||
signal_handler_t handler;
|
||||
} signal_t;
|
||||
|
||||
extern int signal_add(signal_code_t code, signal_flag_t flags, signal_handler_t handler);
|
||||
extern int signal_remove(signal_code_t code, signal_handler_t handler);
|
||||
extern int signal_emit_param(signal_code_t code, void *data);
|
||||
extern int signal_emit(signal_code_t code);
|
||||
|
||||
#endif // _SIGNAL_H_
|
||||
@@ -15,32 +15,32 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "pico_keys.h"
|
||||
#include "asn1.h"
|
||||
#include "picokeys.h"
|
||||
#include "tlv.h"
|
||||
|
||||
int asn1_ctx_init(uint8_t *data, uint16_t len, asn1_ctx_t *ctx) {
|
||||
int tlv_ctx_init(uint8_t *data, uint16_t len, tlv_ctx_t *ctx) {
|
||||
if (!ctx) {
|
||||
return PICOKEY_ERR_NULL_PARAM;
|
||||
return PICOKEYS_ERR_NULL_PARAM;
|
||||
}
|
||||
ctx->data = data;
|
||||
ctx->len = len;
|
||||
return PICOKEY_OK;
|
||||
return PICOKEYS_OK;
|
||||
}
|
||||
|
||||
int asn1_ctx_clear(asn1_ctx_t *ctx) {
|
||||
int tlv_ctx_clear(tlv_ctx_t *ctx) {
|
||||
ctx->data = NULL;
|
||||
ctx->len = 0;
|
||||
return PICOKEY_OK;
|
||||
return PICOKEYS_OK;
|
||||
}
|
||||
|
||||
uint16_t asn1_len(asn1_ctx_t *ctx) {
|
||||
uint16_t tlv_len(tlv_ctx_t *ctx) {
|
||||
if (ctx->data && ctx->len > 0) {
|
||||
return ctx->len;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t asn1_get_uint(asn1_ctx_t *ctx) {
|
||||
uint32_t tlv_get_uint(tlv_ctx_t *ctx) {
|
||||
uint32_t d = ctx->data[0];
|
||||
for (uint16_t lt = 1; lt < MIN(ctx->len, sizeof(uint32_t)); lt++) {
|
||||
d <<= 8;
|
||||
@@ -49,15 +49,15 @@ uint32_t asn1_get_uint(asn1_ctx_t *ctx) {
|
||||
return d;
|
||||
}
|
||||
|
||||
uint16_t asn1_len_tag(uint16_t tag, uint16_t len) {
|
||||
uint16_t ret = 1 + format_tlv_len(len, NULL) + len;
|
||||
uint16_t tlv_len_tag(uint16_t tag, uint16_t len) {
|
||||
uint16_t ret = 1 + tlv_format_len(len, NULL) + len;
|
||||
if (tag > 0x00ff) {
|
||||
return ret + 1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint8_t format_tlv_len(uint16_t len, uint8_t *out) {
|
||||
uint8_t tlv_format_len(uint16_t len, uint8_t *out) {
|
||||
if (len < 128) {
|
||||
if (out) {
|
||||
*out = (uint8_t)len;
|
||||
@@ -73,16 +73,12 @@ uint8_t format_tlv_len(uint16_t len, uint8_t *out) {
|
||||
}
|
||||
if (out) {
|
||||
*out++ = 0x82;
|
||||
put_uint16_t_be(len, out);
|
||||
put_uint16_be(len, out);
|
||||
}
|
||||
return 3;
|
||||
}
|
||||
|
||||
int walk_tlv(const asn1_ctx_t *ctxi,
|
||||
uint8_t **p,
|
||||
uint16_t *tag,
|
||||
uint16_t *tag_len,
|
||||
uint8_t **data) {
|
||||
int tlv_walk(const tlv_ctx_t *ctxi, uint8_t **p, uint16_t *tag, uint16_t *tag_len, uint8_t **data) {
|
||||
if (!p) {
|
||||
return 0;
|
||||
}
|
||||
@@ -92,8 +88,7 @@ int walk_tlv(const asn1_ctx_t *ctxi,
|
||||
if (*p - ctxi->data >= ctxi->len) {
|
||||
return 0;
|
||||
}
|
||||
uint16_t tg = 0x0;
|
||||
uint16_t tgl = 0;
|
||||
uint16_t tg = 0x0, tgl = 0;
|
||||
tg = *(*p)++;
|
||||
if ((tg & 0x1f) == 0x1f) {
|
||||
tg <<= 8;
|
||||
@@ -120,14 +115,10 @@ int walk_tlv(const asn1_ctx_t *ctxi,
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool asn1_find_tag(const asn1_ctx_t *ctxi,
|
||||
uint16_t itag,
|
||||
asn1_ctx_t *ctxo) {
|
||||
uint16_t tag = 0x0;
|
||||
uint8_t *p = NULL;
|
||||
uint8_t *tdata = NULL;
|
||||
uint16_t tlen = 0;
|
||||
while (walk_tlv(ctxi, &p, &tag, &tlen, &tdata)) {
|
||||
bool tlv_find_tag(const tlv_ctx_t *ctxi, uint16_t itag, tlv_ctx_t *ctxo) {
|
||||
uint16_t tag = 0x0, tlen = 0;
|
||||
uint8_t *p = NULL, *tdata = NULL;
|
||||
while (tlv_walk(ctxi, &p, &tag, &tlen, &tdata)) {
|
||||
if (itag == tag) {
|
||||
if (ctxo != NULL) {
|
||||
ctxo->data = tdata;
|
||||
41
src/tlv.h
Normal file
41
src/tlv.h
Normal file
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk).
|
||||
* Copyright (c) 2022 Pol Henarejos.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _TLV_H_
|
||||
#define _TLV_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "compat/compat.h"
|
||||
|
||||
PACK(
|
||||
typedef struct tlv_ctx {
|
||||
uint8_t *data;
|
||||
uint16_t len;
|
||||
}) tlv_ctx_t;
|
||||
|
||||
extern int tlv_ctx_init(uint8_t *, uint16_t, tlv_ctx_t *);
|
||||
extern int tlv_ctx_clear(tlv_ctx_t *ctx);
|
||||
extern uint16_t tlv_len(tlv_ctx_t *ctx);
|
||||
extern uint32_t tlv_get_uint(tlv_ctx_t *ctx);
|
||||
|
||||
extern int tlv_walk(const tlv_ctx_t *ctxi, uint8_t **p, uint16_t *tag, uint16_t *tag_len, uint8_t **data);
|
||||
extern uint8_t tlv_format_len(uint16_t len, uint8_t *out);
|
||||
extern bool tlv_find_tag(const tlv_ctx_t *ctxi, uint16_t itag, tlv_ctx_t *ctxo);
|
||||
extern uint16_t tlv_len_tag(uint16_t tag, uint16_t len);
|
||||
|
||||
#endif
|
||||
58
src/trusted/trusted.c
Normal file
58
src/trusted/trusted.c
Normal file
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* 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 "trusted.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "mbedtls/sha256.h"
|
||||
|
||||
extern void picokeys_trusted_set_allocators(void *(*calloc_impl)(size_t, size_t),
|
||||
void (*free_impl)(void *));
|
||||
extern void picokeys_trusted_set_memops(picokeys_trusted_memset_fn memset_impl,
|
||||
picokeys_trusted_memcpy_fn memcpy_impl,
|
||||
picokeys_trusted_memmove_fn memmove_impl,
|
||||
picokeys_trusted_memcmp_fn memcmp_impl,
|
||||
picokeys_trusted_strlen_fn strlen_impl,
|
||||
picokeys_trusted_strncmp_fn strncmp_impl,
|
||||
picokeys_trusted_strncpy_fn strncpy_impl,
|
||||
picokeys_trusted_strchr_fn strchr_impl,
|
||||
picokeys_trusted_calloc_fn calloc_impl,
|
||||
picokeys_trusted_free_fn free_impl);
|
||||
|
||||
const uint8_t *trusted_region_start(void) {
|
||||
return __trusted_start;
|
||||
}
|
||||
|
||||
const uint8_t *trusted_region_end(void) {
|
||||
return __trusted_end;
|
||||
}
|
||||
|
||||
size_t trusted_region_size(void) {
|
||||
return (size_t)(__trusted_end - __trusted_start);
|
||||
}
|
||||
|
||||
void trusted_region_init(void) {
|
||||
picokeys_trusted_set_memops(memset, memcpy, memmove, memcmp,
|
||||
strlen, strncmp, strncpy,
|
||||
strchr, calloc, free);
|
||||
}
|
||||
|
||||
int trusted_region_sha256(uint8_t out[32]) {
|
||||
return mbedtls_sha256(__trusted_start, trusted_region_size(), out, 0);
|
||||
}
|
||||
45
src/trusted/trusted.h
Normal file
45
src/trusted/trusted.h
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* 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 TRUSTED_FIRMWARE_H
|
||||
#define TRUSTED_FIRMWARE_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
extern const uint8_t __trusted_start[];
|
||||
extern const uint8_t __trusted_end[];
|
||||
|
||||
/* The canonical trusted measurement is always the flash image range. */
|
||||
const uint8_t *trusted_region_start(void);
|
||||
const uint8_t *trusted_region_end(void);
|
||||
size_t trusted_region_size(void);
|
||||
void trusted_region_init(void);
|
||||
int trusted_region_sha256(uint8_t out[32]);
|
||||
|
||||
typedef void *(*picokeys_trusted_memset_fn)(void *, int, size_t);
|
||||
typedef void *(*picokeys_trusted_memcpy_fn)(void *, const void *, size_t);
|
||||
typedef void *(*picokeys_trusted_memmove_fn)(void *, const void *, size_t);
|
||||
typedef int (*picokeys_trusted_memcmp_fn)(const void *, const void *, size_t);
|
||||
typedef size_t (*picokeys_trusted_strlen_fn)(const char *);
|
||||
typedef int (*picokeys_trusted_strncmp_fn)(const char *, const char *, size_t);
|
||||
typedef char *(*picokeys_trusted_strncpy_fn)(char *, const char *, size_t);
|
||||
typedef char *(*picokeys_trusted_strchr_fn)(const char *, int);
|
||||
typedef void *(*picokeys_trusted_calloc_fn)(size_t, size_t);
|
||||
typedef void (*picokeys_trusted_free_fn)(void *);
|
||||
|
||||
#endif
|
||||
147
src/trusted/trusted_mem.c
Normal file
147
src/trusted/trusted_mem.c
Normal file
@@ -0,0 +1,147 @@
|
||||
/*
|
||||
* 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 "mbedtls/platform_util.h"
|
||||
#include "trusted.h"
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
static picokeys_trusted_memset_fn picokeys_trusted_memset_impl;
|
||||
static picokeys_trusted_memcpy_fn picokeys_trusted_memcpy_impl;
|
||||
static picokeys_trusted_memmove_fn picokeys_trusted_memmove_impl;
|
||||
static picokeys_trusted_memcmp_fn picokeys_trusted_memcmp_impl;
|
||||
static picokeys_trusted_strlen_fn picokeys_trusted_strlen_impl;
|
||||
static picokeys_trusted_strncmp_fn picokeys_trusted_strncmp_impl;
|
||||
static picokeys_trusted_strncpy_fn picokeys_trusted_strncpy_impl;
|
||||
static picokeys_trusted_strchr_fn picokeys_trusted_strchr_impl;
|
||||
static picokeys_trusted_calloc_fn picokeys_trusted_calloc_impl;
|
||||
static picokeys_trusted_free_fn picokeys_trusted_free_impl;
|
||||
|
||||
static void picokeys_trusted_uninitialized_call(void)
|
||||
{
|
||||
__builtin_trap();
|
||||
}
|
||||
|
||||
void picokeys_trusted_set_memops(picokeys_trusted_memset_fn memset_impl,
|
||||
picokeys_trusted_memcpy_fn memcpy_impl,
|
||||
picokeys_trusted_memmove_fn memmove_impl,
|
||||
picokeys_trusted_memcmp_fn memcmp_impl,
|
||||
picokeys_trusted_strlen_fn strlen_impl,
|
||||
picokeys_trusted_strncmp_fn strncmp_impl,
|
||||
picokeys_trusted_strncpy_fn strncpy_impl,
|
||||
picokeys_trusted_strchr_fn strchr_impl,
|
||||
picokeys_trusted_calloc_fn calloc_impl,
|
||||
picokeys_trusted_free_fn free_impl)
|
||||
{
|
||||
picokeys_trusted_memset_impl = memset_impl;
|
||||
picokeys_trusted_memcpy_impl = memcpy_impl;
|
||||
picokeys_trusted_memmove_impl = memmove_impl;
|
||||
picokeys_trusted_memcmp_impl = memcmp_impl;
|
||||
picokeys_trusted_strlen_impl = strlen_impl;
|
||||
picokeys_trusted_strncmp_impl = strncmp_impl;
|
||||
picokeys_trusted_strncpy_impl = strncpy_impl;
|
||||
picokeys_trusted_strchr_impl = strchr_impl;
|
||||
picokeys_trusted_calloc_impl = calloc_impl;
|
||||
picokeys_trusted_free_impl = free_impl;
|
||||
}
|
||||
|
||||
void *picokeys_trusted_memset(void *dst, int value, size_t len)
|
||||
{
|
||||
if (picokeys_trusted_memset_impl == NULL) {
|
||||
picokeys_trusted_uninitialized_call();
|
||||
}
|
||||
return picokeys_trusted_memset_impl(dst, value, len);
|
||||
}
|
||||
|
||||
void *picokeys_trusted_memcpy(void *dst, const void *src, size_t len)
|
||||
{
|
||||
if (picokeys_trusted_memcpy_impl == NULL) {
|
||||
picokeys_trusted_uninitialized_call();
|
||||
}
|
||||
return picokeys_trusted_memcpy_impl(dst, src, len);
|
||||
}
|
||||
|
||||
void *picokeys_trusted_memmove(void *dst, const void *src, size_t len)
|
||||
{
|
||||
if (picokeys_trusted_memmove_impl == NULL) {
|
||||
picokeys_trusted_uninitialized_call();
|
||||
}
|
||||
return picokeys_trusted_memmove_impl(dst, src, len);
|
||||
}
|
||||
|
||||
int picokeys_trusted_memcmp(const void *lhs, const void *rhs, size_t len)
|
||||
{
|
||||
if (picokeys_trusted_memcmp_impl == NULL) {
|
||||
picokeys_trusted_uninitialized_call();
|
||||
}
|
||||
return picokeys_trusted_memcmp_impl(lhs, rhs, len);
|
||||
}
|
||||
|
||||
size_t picokeys_trusted_strlen(const char *s)
|
||||
{
|
||||
if (picokeys_trusted_strlen_impl == NULL) {
|
||||
picokeys_trusted_uninitialized_call();
|
||||
}
|
||||
return picokeys_trusted_strlen_impl(s);
|
||||
}
|
||||
|
||||
int picokeys_trusted_strncmp(const char *lhs, const char *rhs, size_t len)
|
||||
{
|
||||
if (picokeys_trusted_strncmp_impl == NULL) {
|
||||
picokeys_trusted_uninitialized_call();
|
||||
}
|
||||
return picokeys_trusted_strncmp_impl(lhs, rhs, len);
|
||||
}
|
||||
|
||||
char *picokeys_trusted_strncpy(char *dst, const char *src, size_t len)
|
||||
{
|
||||
if (picokeys_trusted_strncpy_impl == NULL) {
|
||||
picokeys_trusted_uninitialized_call();
|
||||
}
|
||||
return picokeys_trusted_strncpy_impl(dst, src, len);
|
||||
}
|
||||
|
||||
char *picokeys_trusted_strchr(const char *s, int c)
|
||||
{
|
||||
if (picokeys_trusted_strchr_impl == NULL) {
|
||||
picokeys_trusted_uninitialized_call();
|
||||
}
|
||||
return picokeys_trusted_strchr_impl(s, c);
|
||||
}
|
||||
|
||||
void *picokeys_trusted_calloc(size_t nmemb, size_t size)
|
||||
{
|
||||
if (picokeys_trusted_calloc_impl == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
return picokeys_trusted_calloc_impl(nmemb, size);
|
||||
}
|
||||
|
||||
void picokeys_trusted_free(void *ptr)
|
||||
{
|
||||
if (picokeys_trusted_free_impl != NULL) {
|
||||
picokeys_trusted_free_impl(ptr);
|
||||
}
|
||||
}
|
||||
|
||||
void mbedtls_platform_zeroize(void *buf, size_t len)
|
||||
{
|
||||
if (buf != NULL && len != 0) {
|
||||
picokeys_trusted_memset(buf, 0, len);
|
||||
__asm__ volatile ("" ::: "memory");
|
||||
}
|
||||
}
|
||||
213
src/trusted/trusted_pico_sha256.c
Normal file
213
src/trusted/trusted_pico_sha256.c
Normal file
@@ -0,0 +1,213 @@
|
||||
/*
|
||||
* 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 <inttypes.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "hardware/sha256.h"
|
||||
#include "pico/bootrom/lock.h"
|
||||
#include "pico/sha256.h"
|
||||
#include "pico/time.h"
|
||||
|
||||
#define SHA256_PADDING_DATA_BYTES 9
|
||||
#define SHA256_BLOCK_SIZE_BYTES 64
|
||||
|
||||
const absolute_time_t ABSOLUTE_TIME_INITIALIZED_VAR(at_the_end_of_time, INT64_MAX);
|
||||
|
||||
bool __weak pico_sha256_lock(pico_sha256_state_t *state)
|
||||
{
|
||||
if (!bootrom_try_acquire_lock(BOOTROM_LOCK_SHA_256)) {
|
||||
return false;
|
||||
}
|
||||
state->locked = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void __weak pico_sha256_unlock(pico_sha256_state_t *state)
|
||||
{
|
||||
assert(state->locked);
|
||||
bootrom_release_lock(BOOTROM_LOCK_SHA_256);
|
||||
state->locked = false;
|
||||
}
|
||||
|
||||
void pico_sha256_cleanup(pico_sha256_state_t *state)
|
||||
{
|
||||
if (state->locked) {
|
||||
pico_sha256_unlock(state);
|
||||
}
|
||||
}
|
||||
|
||||
int pico_sha256_try_start(pico_sha256_state_t *state,
|
||||
enum sha256_endianness endianness,
|
||||
bool use_dma)
|
||||
{
|
||||
(void)use_dma;
|
||||
|
||||
memset(state, 0, sizeof(*state));
|
||||
if (!pico_sha256_lock(state)) {
|
||||
return PICO_ERROR_RESOURCE_IN_USE;
|
||||
}
|
||||
|
||||
state->endianness = endianness;
|
||||
state->channel = -1;
|
||||
sha256_err_not_ready_clear();
|
||||
sha256_set_bswap(endianness == SHA256_BIG_ENDIAN);
|
||||
sha256_start();
|
||||
state->total_data_size = 0;
|
||||
return PICO_OK;
|
||||
}
|
||||
|
||||
int pico_sha256_start_blocking_until(pico_sha256_state_t *state,
|
||||
enum sha256_endianness endianness,
|
||||
bool use_dma,
|
||||
absolute_time_t until)
|
||||
{
|
||||
int rc;
|
||||
|
||||
(void)until;
|
||||
|
||||
do {
|
||||
rc = pico_sha256_try_start(state, endianness, use_dma);
|
||||
} while (rc == PICO_ERROR_RESOURCE_IN_USE);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void write_to_hardware(pico_sha256_state_t *state,
|
||||
const uint8_t *data,
|
||||
size_t data_size_bytes)
|
||||
{
|
||||
if (!state->cache_used && !(((uintptr_t)data) & 3u)) {
|
||||
GCC_Like_Pragma("GCC diagnostic ignored \"-Wcast-align\"")
|
||||
const uint32_t *data32 = (const uint32_t *)data;
|
||||
|
||||
while (data_size_bytes >= 4) {
|
||||
sha256_wait_ready_blocking();
|
||||
sha256_put_word(*data32++);
|
||||
data_size_bytes -= 4;
|
||||
}
|
||||
|
||||
data = (const uint8_t *)data32;
|
||||
}
|
||||
|
||||
while (data_size_bytes--) {
|
||||
state->cache.bytes[state->cache_used++] = *data++;
|
||||
if (state->cache_used == 4) {
|
||||
state->cache_used = 0;
|
||||
sha256_wait_ready_blocking();
|
||||
sha256_put_word(state->cache.word);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void update_internal(pico_sha256_state_t *state,
|
||||
const uint8_t *data,
|
||||
size_t data_size_bytes)
|
||||
{
|
||||
size_t bytes_left;
|
||||
|
||||
assert(state->locked);
|
||||
|
||||
bytes_left = ((state->total_data_size + (SHA256_BLOCK_SIZE_BYTES - 1)) &
|
||||
~(SHA256_BLOCK_SIZE_BYTES - 1)) -
|
||||
state->total_data_size;
|
||||
if (bytes_left > data_size_bytes) {
|
||||
bytes_left = data_size_bytes;
|
||||
}
|
||||
|
||||
if (bytes_left > 0) {
|
||||
write_to_hardware(state, data, bytes_left);
|
||||
state->total_data_size += bytes_left;
|
||||
data_size_bytes -= bytes_left;
|
||||
data += bytes_left;
|
||||
}
|
||||
|
||||
if (data_size_bytes > 0) {
|
||||
write_to_hardware(state, data, data_size_bytes);
|
||||
state->total_data_size += data_size_bytes;
|
||||
}
|
||||
}
|
||||
|
||||
static void add_zero_bytes(pico_sha256_state_t *state, size_t data_size_bytes)
|
||||
{
|
||||
uint32_t zero = 0;
|
||||
|
||||
assert(data_size_bytes < INT32_MAX);
|
||||
while ((int32_t)data_size_bytes > 0) {
|
||||
update_internal(state, (uint8_t *)&zero, MIN(4, data_size_bytes));
|
||||
data_size_bytes -= 4;
|
||||
}
|
||||
}
|
||||
|
||||
void pico_sha256_update(pico_sha256_state_t *state,
|
||||
const uint8_t *data,
|
||||
size_t data_size_bytes)
|
||||
{
|
||||
update_internal(state, data, data_size_bytes);
|
||||
}
|
||||
|
||||
void pico_sha256_update_blocking(pico_sha256_state_t *state,
|
||||
const uint8_t *data,
|
||||
size_t data_size_bytes)
|
||||
{
|
||||
update_internal(state, data, data_size_bytes);
|
||||
}
|
||||
|
||||
static void write_padding(pico_sha256_state_t *state)
|
||||
{
|
||||
uint64_t size;
|
||||
size_t user_data_size = state->total_data_size;
|
||||
size_t padding_size_bytes;
|
||||
const uint8_t one_bit = 0x80;
|
||||
|
||||
size = (state->total_data_size + SHA256_PADDING_DATA_BYTES +
|
||||
(SHA256_BLOCK_SIZE_BYTES - 1)) &
|
||||
~(SHA256_BLOCK_SIZE_BYTES - 1);
|
||||
padding_size_bytes = size - state->total_data_size;
|
||||
|
||||
update_internal(state, &one_bit, 1);
|
||||
add_zero_bytes(state, padding_size_bytes - SHA256_PADDING_DATA_BYTES);
|
||||
|
||||
size = __builtin_bswap64(user_data_size * 8);
|
||||
update_internal(state, (uint8_t *)&size, sizeof(uint64_t));
|
||||
}
|
||||
|
||||
static void trusted_sha256_get_result(sha256_result_t *out,
|
||||
enum sha256_endianness endianness)
|
||||
{
|
||||
for (uint i = 0; i < count_of(out->words); ++i) {
|
||||
uint32_t data = sha256_hw->sum[i];
|
||||
if (endianness == SHA256_BIG_ENDIAN) {
|
||||
data = __builtin_bswap32(data);
|
||||
}
|
||||
out->words[i] = data;
|
||||
}
|
||||
}
|
||||
|
||||
void pico_sha256_finish(pico_sha256_state_t *state, sha256_result_t *out)
|
||||
{
|
||||
assert(state->locked);
|
||||
|
||||
if (out) {
|
||||
write_padding(state);
|
||||
sha256_wait_valid_blocking();
|
||||
trusted_sha256_get_result(out, state->endianness);
|
||||
}
|
||||
|
||||
pico_sha256_unlock(state);
|
||||
}
|
||||
12
src/trusted_region_embed.in.S
Normal file
12
src/trusted_region_embed.in.S
Normal file
@@ -0,0 +1,12 @@
|
||||
@PICOKEYS_TRUSTED_SECTION_DIRECTIVE@
|
||||
.balign 16
|
||||
.globl @PICOKEYS_TRUSTED_START_SYM@
|
||||
@PICOKEYS_TRUSTED_START_SYM@:
|
||||
.globl @PICOKEYS_TRUSTED_LOAD_START_SYM@
|
||||
@PICOKEYS_TRUSTED_LOAD_START_SYM@:
|
||||
.incbin "@TRUSTED_REGION_EMBED_INPUT@"
|
||||
.balign 16
|
||||
.globl @PICOKEYS_TRUSTED_END_SYM@
|
||||
@PICOKEYS_TRUSTED_END_SYM@:
|
||||
.globl @PICOKEYS_TRUSTED_LOAD_END_SYM@
|
||||
@PICOKEYS_TRUSTED_LOAD_END_SYM@:
|
||||
@@ -15,8 +15,9 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "picokeys.h"
|
||||
#include "led/led.h"
|
||||
#include "random.h"
|
||||
#include "pico_keys.h"
|
||||
#ifdef PICO_PLATFORM
|
||||
#include "bsp/board.h"
|
||||
#endif
|
||||
@@ -27,7 +28,6 @@
|
||||
#include "emulation.h"
|
||||
#endif
|
||||
#include "ccid.h"
|
||||
#include "usb_descriptors.h"
|
||||
#include "apdu.h"
|
||||
#include "usb.h"
|
||||
|
||||
@@ -97,21 +97,22 @@ static uint8_t itf_num;
|
||||
static usb_buffer_t *ccid_rx = NULL, *ccid_tx = NULL;
|
||||
|
||||
int driver_process_usb_packet_ccid(uint8_t itf, uint16_t rx_read);
|
||||
void ccid_init(void);
|
||||
void ccid_task(void);
|
||||
#ifdef ENABLE_EMULATION
|
||||
void tud_vendor_rx_cb(uint8_t itf, const uint8_t *buffer, uint16_t bufsize);
|
||||
#endif
|
||||
|
||||
void ccid_write_offset(uint8_t itf, uint16_t size, uint16_t offset) {
|
||||
static void ccid_write_offset(uint8_t itf, uint16_t size, uint16_t offset) {
|
||||
ccid_tx[itf].w_ptr += size + offset;
|
||||
ccid_tx[itf].r_ptr += offset;
|
||||
}
|
||||
|
||||
void ccid_write(uint8_t itf, uint16_t size) {
|
||||
ccid_write_offset(itf, size, 0);
|
||||
}
|
||||
|
||||
ccid_header_t **ccid_response = NULL;
|
||||
ccid_header_t **ccid_resp_fast = NULL;
|
||||
ccid_header_t **ccid_header = NULL;
|
||||
|
||||
uint8_t sc_itf_to_usb_itf(uint8_t itf) {
|
||||
static uint8_t sc_itf_to_usb_itf(uint8_t itf) {
|
||||
if (itf == ITF_SC_CCID) {
|
||||
return ITF_CCID;
|
||||
}
|
||||
@@ -121,7 +122,7 @@ uint8_t sc_itf_to_usb_itf(uint8_t itf) {
|
||||
return itf;
|
||||
}
|
||||
|
||||
void ccid_init_buffers() {
|
||||
static void ccid_init_buffers(void) {
|
||||
if (ITF_SC_TOTAL == 0) {
|
||||
return;
|
||||
}
|
||||
@@ -142,7 +143,7 @@ void ccid_init_buffers() {
|
||||
}
|
||||
}
|
||||
|
||||
int driver_init_ccid(uint8_t itf) {
|
||||
static int driver_init_ccid(uint8_t itf) {
|
||||
ccid_header[itf] = (ccid_header_t *) (ccid_rx[itf].buffer + ccid_rx[itf].r_ptr);
|
||||
ccid_resp_fast[itf] = (ccid_header_t *) (ccid_tx[itf].buffer + sizeof(ccid_tx[itf].buffer) - 64);
|
||||
// apdu.header = &ccid_header->apdu;
|
||||
@@ -153,10 +154,12 @@ int driver_init_ccid(uint8_t itf) {
|
||||
|
||||
//ccid_tx[itf].w_ptr = ccid_tx[itf].r_ptr = 0;
|
||||
|
||||
return PICOKEY_OK;
|
||||
return PICOKEYS_OK;
|
||||
}
|
||||
|
||||
void tud_vendor_rx_cb(uint8_t itf, const uint8_t *buffer, uint16_t bufsize) {
|
||||
(void)buffer;
|
||||
(void)bufsize;
|
||||
uint32_t len = tud_vendor_n_available(itf);
|
||||
do {
|
||||
uint16_t tlen = 0;
|
||||
@@ -173,27 +176,27 @@ void tud_vendor_rx_cb(uint8_t itf, const uint8_t *buffer, uint16_t bufsize) {
|
||||
} while (len > 0);
|
||||
}
|
||||
|
||||
int driver_write_ccid(uint8_t itf, const uint8_t *tx_buffer, uint16_t buffer_size) {
|
||||
static int driver_write_ccid(uint8_t itf, const uint8_t *tx_buffer, uint16_t buffer_size) {
|
||||
if (*tx_buffer != 0x81) {
|
||||
DEBUG_PAYLOAD(tx_buffer, buffer_size);
|
||||
}
|
||||
int r = tud_vendor_n_write(itf, tx_buffer, buffer_size);
|
||||
if (r > 0) {
|
||||
tud_vendor_n_flush(itf);
|
||||
uint32_t written = tud_vendor_n_write(itf, tx_buffer, buffer_size);
|
||||
if (written > 0) {
|
||||
tud_vendor_n_write_flush(itf);
|
||||
|
||||
ccid_tx[itf].r_ptr += (uint16_t)buffer_size;
|
||||
ccid_tx[itf].r_ptr += (uint16_t)written;
|
||||
if (ccid_tx[itf].r_ptr >= ccid_tx[itf].w_ptr) {
|
||||
ccid_tx[itf].r_ptr = ccid_tx[itf].w_ptr = 0;
|
||||
}
|
||||
|
||||
}
|
||||
#ifdef ENABLE_EMULATION
|
||||
tud_vendor_tx_cb(itf, r);
|
||||
tud_vendor_tx_cb(itf, written);
|
||||
#endif
|
||||
return r;
|
||||
return (int)written;
|
||||
}
|
||||
|
||||
int ccid_write_fast(uint8_t itf, const uint8_t *buffer, uint16_t buffer_size) {
|
||||
static int ccid_write_fast(uint8_t itf, const uint8_t *buffer, uint16_t buffer_size) {
|
||||
return driver_write_ccid(itf, buffer, buffer_size);
|
||||
}
|
||||
|
||||
@@ -316,7 +319,7 @@ int driver_process_usb_packet_ccid(uint8_t itf, uint16_t rx_read) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void driver_exec_timeout_ccid(uint8_t itf) {
|
||||
static void driver_exec_timeout_ccid(uint8_t itf) {
|
||||
ccid_resp_fast[itf]->bMessageType = CCID_DATA_BLOCK_RET;
|
||||
ccid_resp_fast[itf]->dwLength = 0;
|
||||
ccid_resp_fast[itf]->bSlot = 0;
|
||||
@@ -341,14 +344,21 @@ void driver_exec_finished_cont_ccid(uint8_t itf, uint16_t size_next, uint16_t of
|
||||
ccid_write_offset(itf, size_next+10, offset);
|
||||
}
|
||||
|
||||
void ccid_task() {
|
||||
for (int itf = 0; itf < ITF_SC_TOTAL; itf++) {
|
||||
int status = card_status(sc_itf_to_usb_itf(itf));
|
||||
if (status == PICOKEY_OK) {
|
||||
driver_exec_finished_ccid(itf, finished_data_size);
|
||||
}
|
||||
else if (status == PICOKEY_ERR_BLOCKED) {
|
||||
driver_exec_timeout_ccid(itf);
|
||||
void ccid_task(void) {
|
||||
const uint32_t status_poll_interval_ms = 1;
|
||||
static uint32_t last_status_poll_ms[8] = {0};
|
||||
uint32_t now_ms = board_millis();
|
||||
for (uint8_t itf = 0; itf < ITF_SC_TOTAL; itf++) {
|
||||
if (itf < (sizeof(last_status_poll_ms) / sizeof(last_status_poll_ms[0])) &&
|
||||
now_ms - last_status_poll_ms[itf] >= status_poll_interval_ms) {
|
||||
last_status_poll_ms[itf] = now_ms;
|
||||
int status = card_status(sc_itf_to_usb_itf(itf));
|
||||
if (status == PICOKEYS_OK) {
|
||||
driver_exec_finished_ccid(itf, finished_data_size);
|
||||
}
|
||||
else if (status == PICOKEYS_ERR_BLOCKED) {
|
||||
driver_exec_timeout_ccid(itf);
|
||||
}
|
||||
}
|
||||
if (ccid_tx[itf].w_ptr > ccid_tx[itf].r_ptr) {
|
||||
if (driver_write_ccid(itf, ccid_tx[itf].buffer + ccid_tx[itf].r_ptr, ccid_tx[itf].w_ptr - ccid_tx[itf].r_ptr) > 0) {
|
||||
@@ -358,17 +368,17 @@ void ccid_task() {
|
||||
}
|
||||
}
|
||||
|
||||
void ccid_init() {
|
||||
void ccid_init(void) {
|
||||
ccid_init_buffers();
|
||||
}
|
||||
|
||||
#ifndef ENABLE_EMULATION
|
||||
|
||||
void tud_vendor_tx_cb(uint8_t itf, uint32_t sent_bytes) {
|
||||
(void) sent_bytes;
|
||||
tud_vendor_n_write_flush(itf);
|
||||
}
|
||||
|
||||
#ifndef ENABLE_EMULATION
|
||||
|
||||
static void ccid_init_cb(void) {
|
||||
vendord_init();
|
||||
}
|
||||
|
||||
@@ -40,4 +40,30 @@ enum ccid_state {
|
||||
|
||||
extern const uint8_t *ccid_atr;
|
||||
|
||||
PACK(
|
||||
struct ccid_class_descriptor {
|
||||
uint8_t bLength;
|
||||
uint8_t bDescriptorType;
|
||||
uint16_t bcdCCID;
|
||||
uint8_t bMaxSlotIndex;
|
||||
uint8_t bVoltageSupport;
|
||||
uint32_t dwProtocols;
|
||||
uint32_t dwDefaultClock;
|
||||
uint32_t dwMaximumClock;
|
||||
uint8_t bNumClockSupport;
|
||||
uint32_t dwDataRate;
|
||||
uint32_t dwMaxDataRate;
|
||||
uint8_t bNumDataRatesSupported;
|
||||
uint32_t dwMaxIFSD;
|
||||
uint32_t dwSynchProtocols;
|
||||
uint32_t dwMechanical;
|
||||
uint32_t dwFeatures;
|
||||
uint32_t dwMaxCCIDMessageLength;
|
||||
uint8_t bClassGetResponse;
|
||||
uint8_t bclassEnvelope;
|
||||
uint16_t wLcdLayout;
|
||||
uint8_t bPINSupport;
|
||||
uint8_t bMaxCCIDBusySlots;
|
||||
});
|
||||
|
||||
#endif //_CCID_H_
|
||||
|
||||
@@ -14,8 +14,14 @@
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "pico_keys.h"
|
||||
#ifdef _MSC_VER
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#include <windows.h>
|
||||
#endif
|
||||
#include "emulation.h"
|
||||
#include <stdio.h>
|
||||
#ifndef _MSC_VER
|
||||
@@ -30,7 +36,6 @@ typedef int socket_t;
|
||||
#define INVALID_SOCKET (-1)
|
||||
#define SOCKET_ERROR (-1)
|
||||
#else
|
||||
#include <ws2tcpip.h>
|
||||
#define O_NONBLOCK _O_NONBLOCK
|
||||
#define close closesocket
|
||||
typedef SOCKET socket_t;
|
||||
@@ -59,8 +64,18 @@ uint16_t emul_rx_size = 0, emul_tx_size = 0;
|
||||
extern int cbor_parse(uint8_t cmd, const uint8_t *data, size_t len);
|
||||
pthread_t hcore0, hcore1;
|
||||
|
||||
#ifdef _MSC_VER
|
||||
static void log_sock_error(const char *ctx) {
|
||||
fprintf(stderr, "%s failed (WSAGetLastError=%d)\n", ctx, WSAGetLastError());
|
||||
}
|
||||
#else
|
||||
static void log_sock_error(const char *ctx) {
|
||||
fprintf(stderr, "%s failed (errno=%d)\n", ctx, errno);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef _MSC_VER
|
||||
int msleep(long msec) {
|
||||
static int msleep(long msec) {
|
||||
struct timespec ts;
|
||||
int res;
|
||||
|
||||
@@ -80,7 +95,7 @@ int msleep(long msec) {
|
||||
}
|
||||
#endif
|
||||
|
||||
int emul_init(char *host, uint16_t port) {
|
||||
int emul_init(const char *host, uint16_t port) {
|
||||
struct sockaddr_in serv_addr;
|
||||
fprintf(stderr, "\n Starting emulation envionrment\n");
|
||||
#ifdef _MSC_VER
|
||||
@@ -90,7 +105,7 @@ int emul_init(char *host, uint16_t port) {
|
||||
}
|
||||
#endif
|
||||
if ((ccid_sock = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
|
||||
perror("socket");
|
||||
log_sock_error("socket(ccid)");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -100,13 +115,13 @@ int emul_init(char *host, uint16_t port) {
|
||||
// Convert IPv4 and IPv6 addresses from text to binary
|
||||
// form
|
||||
if (inet_pton(AF_INET, host, &serv_addr.sin_addr) <= 0) {
|
||||
perror("inet_pton");
|
||||
log_sock_error("inet_pton(ccid)");
|
||||
close(ccid_sock);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (connect(ccid_sock, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) {
|
||||
perror("connect");
|
||||
log_sock_error("connect(ccid)");
|
||||
close(ccid_sock);
|
||||
return -1;
|
||||
}
|
||||
@@ -129,12 +144,12 @@ int emul_init(char *host, uint16_t port) {
|
||||
struct sockaddr_in server_sockaddr;
|
||||
|
||||
if ((hid_server_sock = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
|
||||
perror("socket");
|
||||
log_sock_error("socket(hid_server)");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (setsockopt(hid_server_sock, SOL_SOCKET, SO_REUSEADDR, (void *) &yes, sizeof yes) != 0) {
|
||||
perror("setsockopt");
|
||||
log_sock_error("setsockopt(SO_REUSEADDR)");
|
||||
close(hid_server_sock);
|
||||
return 1;
|
||||
}
|
||||
@@ -154,20 +169,21 @@ int emul_init(char *host, uint16_t port) {
|
||||
|
||||
if (bind(hid_server_sock, (struct sockaddr *) &server_sockaddr,
|
||||
sizeof server_sockaddr) != 0) {
|
||||
perror("bind");
|
||||
log_sock_error("bind(hid_server)");
|
||||
close(hid_server_sock);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (listen(hid_server_sock, 0) != 0) {
|
||||
perror("listen");
|
||||
if (listen(hid_server_sock, SOMAXCONN) != 0) {
|
||||
log_sock_error("listen(hid_server)");
|
||||
close(hid_server_sock);
|
||||
return 1;
|
||||
}
|
||||
fprintf(stderr, "HID server listening on 0.0.0.0:%u\n", hid_port);
|
||||
return 0;
|
||||
}
|
||||
|
||||
socket_t get_sock_itf(uint8_t itf) {
|
||||
static socket_t get_sock_itf(uint8_t itf) {
|
||||
#ifdef USB_ITF_CCID
|
||||
if (itf == ITF_CCID) {
|
||||
return ccid_sock;
|
||||
@@ -200,7 +216,11 @@ uint16_t driver_write_emul(uint8_t itf, const uint8_t *buffer, uint16_t buffer_s
|
||||
uint16_t size = htons(buffer_size);
|
||||
socket_t sock = get_sock_itf(itf);
|
||||
// DEBUG_PAYLOAD(buffer,buffer_size);
|
||||
#ifdef _WIN32
|
||||
int ret = 0;
|
||||
#else
|
||||
ssize_t ret = 0;
|
||||
#endif
|
||||
do {
|
||||
ret = send(sock, (const char *)&size, sizeof(size), 0);
|
||||
if (ret == SOCKET_ERROR) {
|
||||
@@ -279,7 +299,11 @@ uint16_t emul_read(uint8_t itf) {
|
||||
__pragma(warning(pop))
|
||||
#endif
|
||||
struct timeval timeout;
|
||||
#ifdef _WIN32
|
||||
int valread = 0;
|
||||
#else
|
||||
ssize_t valread = 0;
|
||||
#endif
|
||||
timeout.tv_sec = 0;
|
||||
timeout.tv_usec = 0 * 1000;
|
||||
int n = select((int)(sock + 1), &input, NULL, NULL, &timeout);
|
||||
@@ -320,7 +344,7 @@ uint16_t emul_read(uint8_t itf) {
|
||||
}
|
||||
#endif
|
||||
else {
|
||||
emul_rx_size += valread;
|
||||
emul_rx_size += (uint16_t)valread;
|
||||
}
|
||||
return (uint16_t)emul_rx_size;
|
||||
}
|
||||
@@ -333,7 +357,7 @@ uint16_t emul_read(uint8_t itf) {
|
||||
return emul_rx_size;
|
||||
}
|
||||
|
||||
void emul_task() {
|
||||
void emul_task(void) {
|
||||
#ifdef USB_ITF_CCID
|
||||
emul_read(ITF_CCID);
|
||||
#endif
|
||||
|
||||
@@ -20,16 +20,17 @@
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include "queue.h"
|
||||
#include "board.h"
|
||||
#include "compat/queue.h"
|
||||
#include "compat/board.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
#define USB_BUFFER_SIZE 2048
|
||||
extern int emul_init(char *host, uint16_t port);
|
||||
#define USB_BUFFER_SIZE 4096
|
||||
extern int emul_init(const char *host, uint16_t port);
|
||||
extern uint8_t emul_rx[USB_BUFFER_SIZE];
|
||||
extern uint16_t emul_rx_size, emul_tx_size;
|
||||
extern uint16_t driver_write_emul(uint8_t itf, const uint8_t *buffer, uint16_t buffer_size);
|
||||
extern uint16_t emul_read(uint8_t itf);
|
||||
extern void emul_task(void);
|
||||
|
||||
#ifdef USB_ITF_HID
|
||||
typedef uint8_t hid_report_type_t;
|
||||
@@ -51,7 +52,7 @@ static inline uint32_t tud_vendor_n_read(uint8_t itf, uint8_t *buffer, uint32_t
|
||||
}
|
||||
extern void tud_vendor_tx_cb(uint8_t itf, uint32_t sent_bytes);
|
||||
extern uint32_t tud_vendor_n_write(uint8_t itf, const uint8_t *buffer, uint32_t n);
|
||||
static inline uint32_t tud_vendor_n_flush(uint8_t itf) {
|
||||
static inline uint32_t tud_vendor_n_write_flush(uint8_t itf) {
|
||||
(void) itf;
|
||||
return emul_tx_size;
|
||||
}
|
||||
|
||||
3530
src/usb/emulation/openssl.c
Normal file
3530
src/usb/emulation/openssl.c
Normal file
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user