49 Commits

Author SHA1 Message Date
Pol Henarejos
994553bfd7 Fix pico build
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-05-02 12:05:49 +02:00
Pol Henarejos
328c3112ac Use ecp keypair calc public instead.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-05-01 21:04:15 +02:00
Pol Henarejos
5ce888b75b Use dynamic dependence resolver.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-05-01 19:50:40 +02:00
Pol Henarejos
1ef40f5826 Upgrade PicoKeys SDK
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-05-01 18:53:13 +02:00
Pol Henarejos
d9193129c7 Upgrade to v4.6
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-04-08 16:29:38 +02:00
Pol Henarejos
402c92ea83 Upgrade Pico Keys SDK 8.6 and MbedTLS v3.6.6
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-04-06 20:04:37 +02:00
Pol Henarejos
ac1e3af410 Fix include.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-04-06 19:58:14 +02:00
Pol Henarejos
5a7f1dd781 Migrate to the new PIN KDF system.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-04-01 16:39:16 +02:00
Pol Henarejos
a0f8d67821 Apply strict build.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-03-09 12:18:18 +01:00
Pol Henarejos
757a000f77 Update pico keys sdk.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-03-07 18:05:33 +01:00
Pol Henarejos
4fba684a24 Fix duplicated file entry.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-03-07 18:05:20 +01:00
Pol Henarejos
0b7beeec8c Introduce GET BULK DATA to execute GET DATA in multiple DO with a single APDU.
It saves considerable bandwidth since only one APDU/RAPDU are transmitted.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-02-19 18:30:50 +01:00
Pol Henarejos
1f037da326 Do no parse flash data as TLV.
Solves #50.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-02-19 15:57:59 +01:00
Pol Henarejos
ffbdef14b6 Set rollback globally to avoid incompatibilities.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-02-19 15:50:32 +01:00
Pol Henarejos
ad59aa8c1a Fixed ACL for EF_CHR_CERT.
Fixes #51.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-02-18 00:52:49 +01:00
Pol Henarejos
fcca95715e Fixed a bug allowing to write without PW3.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-02-18 00:52:19 +01:00
Pol Henarejos
704df76499 DO is cleared when no data is provided.
Solves #50.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-02-18 00:38:52 +01:00
Pol Henarejos
e6cc190c4f Do not interpret private DO as TLV.
Solves #50.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-02-18 00:29:59 +01:00
Pol Henarejos
615737807a Add support for private DO.
Closes #50.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-02-17 16:46:03 +01:00
Pol Henarejos
e563bb3379 Fixed pw2 verify persistence.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-02-17 16:45:49 +01:00
Pol Henarejos
374cff588c Fix secure boot enable.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-02-16 16:31:12 +01:00
Pol Henarejos
ca8d81fd20 Fix key rotation. Now also rotates cert & metadata.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-02-16 01:32:47 +01:00
Pol Henarejos
5d71e69c1d Do not allow slot move from retired to active.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-02-16 00:52:25 +01:00
Pol Henarejos
75691b6a42 Fix crash when attestating.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-02-16 00:46:58 +01:00
Pol Henarejos
811f33e282 Fix extension set in attestation.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-02-16 00:46:26 +01:00
Pol Henarejos
90b62f067d Add support for HIGH/LOW ESP32 LED
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-02-04 23:47:07 +01:00
Pol Henarejos
2e0f9d6b36 Upgrade to v4.4
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-02-01 20:42:56 +01:00
Pol Henarejos
6ef122528f Fix phy marker write.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-02-01 20:42:43 +01:00
Pol Henarejos
9c1dc102ce Upgrade to Pico Keys SDK 8.5
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-01-29 17:58:40 +01:00
Pol Henarejos
a94603b9e2 Use new VID:PID allocated to Pico OpenPGP.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-01-22 12:34:23 +01:00
Pol Henarejos
6af4cef91b Use new layout
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-01-22 12:14:27 +01:00
Pol Henarejos
551334a447 Clear dek on error.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-01-22 12:14:12 +01:00
Pol Henarejos
2ce4f22622 Update README with up-to-date info.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-01-06 21:20:24 +01:00
Pol Henarejos
822038aba2 Upgrade to v4.2
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-01-05 19:53:41 +01:00
Pol Henarejos
70b5e35bde Upgrade Pico Keys SDK to v8.2
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-01-05 19:52:56 +01:00
Pol Henarejos
4638a1c926 Disable button press by default since LED may not be properly configured until it is commissioned.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2026-01-05 19:41:02 +01:00
Pol Henarejos
b6366ef1c0 Fix build.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-12-29 20:37:17 +01:00
Pol Henarejos
d4d8ad86d5 Blink led three times to acknowledge proper commissioning.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-12-29 20:16:44 +01:00
Pol Henarejos
c51d3e7d5e Fix pimoroni led
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-12-27 22:04:37 +01:00
Pol Henarejos
757d163ce9 Move pointer
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-12-27 16:03:19 +01:00
Pol Henarejos
2513608ba9 Releaser is available up to 6.7.0
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-12-26 19:53:32 +01:00
Pol Henarejos
3710146074 Build only necessary boards
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-12-11 20:03:50 +01:00
Pol Henarejos
5462458622 Update pointer
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-12-11 19:37:06 +01:00
Pol Henarejos
353471c599 Revert "Move EDDSA to another branch."
This reverts commit b1421e176b.
2025-12-11 19:36:39 +01:00
Pol Henarejos
b2538cf2b6 Revert "Move Secure Boot to another branch."
This reverts commit e136bb26e3.
2025-12-11 19:36:33 +01:00
Pol Henarejos
e136bb26e3 Move Secure Boot to another branch.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-12-09 21:40:02 +01:00
Pol Henarejos
b1421e176b Move EDDSA to another branch.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-12-09 16:07:34 +01:00
Pol Henarejos
2a14c771cb Move is_gpg flag for fido2.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-12-07 20:35:08 +01:00
Pol Henarejos
90e77f7c61 Yubico and GnuPG interpretate the standard in different ways. While Yubico follows strictly the spec and expects the TAG encapsulating the output of GET_DATA, GnuPG expects consecutive DO in the response.
A possible workaround is to detect whether sub-DO are called (GnuPG) or management AID is called (Yubico).

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-12-05 19:11:21 +01:00
35 changed files with 1343 additions and 879 deletions

View File

@@ -34,7 +34,7 @@ jobs:
- name: Delete private key - name: Delete private key
run: rm private.pem run: rm private.pem
- name: Update nightly release - name: Update nightly release
uses: pyTooling/Actions/releaser@main uses: pyTooling/Actions/releaser@v6.7.0
with: with:
tag: nightly-${{ matrix.refs }} tag: nightly-${{ matrix.refs }}
rm: true rm: true

View File

@@ -17,8 +17,13 @@
cmake_minimum_required(VERSION 3.13) cmake_minimum_required(VERSION 3.13)
option(OPENPGP_TEST_INIT_LEGACY_PIN "Bootstrap legacy PIN/DEK format for migration tests" OFF)
set(USB_VID 0x2E8A)
set(USB_PID 0x10FF)
if(ESP_PLATFORM) if(ESP_PLATFORM)
set(EXTRA_COMPONENT_DIRS src pico-keys-sdk/src) set(EXTRA_COMPONENT_DIRS pico-keys-sdk/config/esp32/components src/openpgp)
include($ENV{IDF_PATH}/tools/cmake/project.cmake) include($ENV{IDF_PATH}/tools/cmake/project.cmake)
else() else()
if(NOT ENABLE_EMULATION) if(NOT ENABLE_EMULATION)
@@ -43,10 +48,10 @@ endif()
set(USB_ITF_CCID 1) set(USB_ITF_CCID 1)
set(USB_ITF_WCID 1) set(USB_ITF_WCID 1)
include(pico-keys-sdk/pico_keys_sdk_import.cmake) include(pico-keys-sdk/picokeys_sdk_import.cmake)
if(NOT ESP_PLATFORM) if(NOT ESP_PLATFORM)
set(SOURCES ${PICO_KEYS_SOURCES}) set(SOURCES ${PICOKEYS_SOURCES})
endif() endif()
set(SOURCES ${SOURCES} set(SOURCES ${SOURCES}
${CMAKE_CURRENT_LIST_DIR}/src/openpgp/openpgp.c ${CMAKE_CURRENT_LIST_DIR}/src/openpgp/openpgp.c
@@ -73,7 +78,7 @@ set(SOURCES ${SOURCES}
${CMAKE_CURRENT_LIST_DIR}/src/openpgp/defs.c ${CMAKE_CURRENT_LIST_DIR}/src/openpgp/defs.c
) )
SET_VERSION(ver_major ver_minor "${CMAKE_CURRENT_LIST_DIR}/src/openpgp/version.h" 2) SET_VERSION(ver_major ver_minor "${CMAKE_CURRENT_LIST_DIR}/src/openpgp/version.h")
if(ESP_PLATFORM) if(ESP_PLATFORM)
project(pico_openpgp) project(pico_openpgp)
@@ -85,14 +90,27 @@ set(INCLUDES ${INCLUDES}
if(NOT ESP_PLATFORM) if(NOT ESP_PLATFORM)
target_sources(pico_openpgp PUBLIC ${SOURCES}) target_sources(pico_openpgp PUBLIC ${SOURCES})
target_include_directories(pico_openpgp PUBLIC ${INCLUDES}) target_include_directories(pico_openpgp PUBLIC ${INCLUDES})
if(OPENPGP_TEST_INIT_LEGACY_PIN)
target_compile_definitions(pico_openpgp PRIVATE OPENPGP_TEST_INIT_LEGACY_PIN=1)
endif()
target_compile_options(pico_openpgp PUBLIC set(COMMON_COMPILE_OPTIONS
-Wall -Wall
) )
target_compile_options(pico_openpgp PRIVATE ${COMMON_COMPILE_OPTIONS})
picokeys_apply_strict_flags(
SOURCES ${SOURCES}
FILTER_REGEX "/src/openpgp/|/pico-keys-sdk/src/|/pico-keys-sdk/config/"
)
if(NOT MSVC) if(NOT MSVC)
target_compile_options(pico_openpgp PUBLIC string(FIND ${CMAKE_C_COMPILER} ":" COMPILER_COLON)
-Werror if(${COMPILER_COLON} GREATER_EQUAL 0)
) target_compile_options(pico_openpgp PRIVATE
-Wno-error=use-after-free
)
endif()
endif() endif()
if(ENABLE_EMULATION) if(ENABLE_EMULATION)
@@ -117,7 +135,7 @@ if(NOT ESP_PLATFORM)
-Wl,--gc-sections -Wl,--gc-sections
) )
endif(APPLE) endif(APPLE)
target_link_libraries(pico_openpgp PRIVATE pthread m) target_link_libraries(pico_openpgp PRIVATE picokeys_sdk mbedtls pthread m)
else() else()
pico_add_extra_outputs(${CMAKE_PROJECT_NAME}) pico_add_extra_outputs(${CMAKE_PROJECT_NAME})
endif() endif()

View File

@@ -3,7 +3,7 @@ This project aims at transforming your Raspberry Pico or ESP32 microcontroller i
OpenPGP cards are used to manage PGP keys and do cryptographic operations, such as keypair generation, signing and asymmetric deciphering. Pico OpenPGP follows the [**OpenPGP 3.4.1** specifications](https://gnupg.org/ftp/specs/OpenPGP-smart-card-application-3.4.pdf "**OpenPGP 3.4.1** specifications"), available at [GnuPG](http://gnupg.org "GnuPG"). OpenPGP cards are used to manage PGP keys and do cryptographic operations, such as keypair generation, signing and asymmetric deciphering. Pico OpenPGP follows the [**OpenPGP 3.4.1** specifications](https://gnupg.org/ftp/specs/OpenPGP-smart-card-application-3.4.pdf "**OpenPGP 3.4.1** specifications"), available at [GnuPG](http://gnupg.org "GnuPG").
If you are looking for a OpenPGP + Fido, see: https://github.com/polhenarejos/pico-fido2 If you are looking for a OpenPGP + Fido, see: https://github.com/polhenarejos/pico-fido2. Available through [PicoKey App](https://www.picokeys.com/picokeyapp/ "PicoKey App").
## Features ## Features
Pico OpenPGP has implemented the following features: Pico OpenPGP has implemented the following features:
@@ -34,7 +34,7 @@ Pico OpenPGP has implemented the following features:
- Secure Boot and Secure Lock in RP2350 and ESP32-S3 MCUs. - Secure Boot and Secure Lock in RP2350 and ESP32-S3 MCUs.
- One Time Programming to store the master key that encrypts all resident keys and seeds. - One Time Programming to store the master key that encrypts all resident keys and seeds.
- Rescue interface to allow recovery of the device if it becomes unresponsive or undetectable. - Rescue interface to allow recovery of the device if it becomes unresponsive or undetectable.
- LED customization with Pico Commissioner. - LED customization with PicoKey App.
All these features are compliant with the specification. Therefore, if you detect some behaviour that is not expected or it does not follow the rules of specs, please open an issue. All these features are compliant with the specification. Therefore, if you detect some behaviour that is not expected or it does not follow the rules of specs, please open an issue.
@@ -62,26 +62,16 @@ If the Pico is stolen the contents of private and secret keys cannot be read wit
### RP2350 and ESP32-S3 ### RP2350 and ESP32-S3
RP2350 and ESP32-S3 microcontrollers are equipped with advanced security features, including Secure Boot and Secure Lock, ensuring that firmware integrity and authenticity are tightly controlled. Both devices support the storage of the Device Encryption Key (DEK) in an OTP (One-Time Programmable) memory region, making it permanently inaccessible for external access or tampering. This secure, non-volatile region guarantees that critical security keys are embedded into the hardware, preventing unauthorized access and supporting robust defenses against code injection or firmware modification. Together, Secure Boot and Secure Lock enforce firmware authentication, while the DEK in OTP memory solidifies the foundation for secure operations. RP2350 and ESP32-S3 microcontrollers are equipped with advanced security features, including Secure Boot and Secure Lock, ensuring that firmware integrity and authenticity are tightly controlled. Both devices support the storage of the Device Encryption Key (DEK) in an OTP (One-Time Programmable) memory region, making it permanently inaccessible for external access or tampering. This secure, non-volatile region guarantees that critical security keys are embedded into the hardware, preventing unauthorized access and supporting robust defenses against code injection or firmware modification. Together, Secure Boot and Secure Lock enforce firmware authentication, while the DEK in OTP memory solidifies the foundation for secure operations.
### Secure Boot
Secure Boot is a security feature that ensures that only trusted firmware, verified through digital signatures, can be loaded onto the device during the boot process. Once enabled, Secure Boot checks every piece of firmware against a cryptographic signature before execution, rejecting any unauthorized or modified code. This prevents malicious firmware from compromising the devices operation and integrity. With Secure Boot activated, only firmware versions signed by a trusted authority, such as the device manufacturer, will be accepted, ensuring the device remains protected from unauthorized software modifications. **This is irreversible. Once enabled, it CANNOT be disabled.**
**IMPORTANT:** For users wishing to develop and compile custom firmware, a private-public key pair is essential. Activating Secure Boot requires users to generate and manage their own unique private-public key pair. The public key from this pair must be embedded into the device to validate all firmware. Firmware will not boot without a proper digital signature from this key pair. This means that users must sign all future firmware versions with their private key and embed the public key in the device to ensure compatibility.
### Secure Lock
Secure Lock builds on Secure Boot by imposing an even stricter security model. Once activated, Secure Lock prevents any further installation of new boot keys, effectively locking the device to only run firmware that is authorized by the device's primary vendor—in this case, Pico Keys. In addition to preventing additional keys, Secure Lock disables debugging interfaces and puts additional safeguards in place to resist tampering and intrusion attempts. This ensures that the device operates exclusively with the original vendors firmware and resists unauthorized access, making it highly secure against external threats. **This is irreversible. Once enabled, it CANNOT be disabled.**
**IMPORTANT:** Activating Secure Lock not only enables Secure Boot but also invalidates all keys except the official Pico Key. This means that only firmware signed by Pico Key will be recognized, and custom code will no longer be allowed. Once enabled, the Pico Key device will run solely on the official firmware available on the website, with no option for generating or compiling new code for the device.
## Download ## Download
**If you own an ESP32-S3 board, go to [ESP32 Flasher](https://www.picokeys.com/esp32-flasher/) for flashing your Pico OpenPGP.** **If you own an ESP32-S3 board, go to [ESP32 Flasher](https://www.picokeys.com/esp32-flasher/) for flashing your Pico OpenPGP.**
If you own a Raspberry Pico (RP2040 or RP2350), go to [Download page](https://www.picokeys.com/getting-started/), select your vendor and model and download the proper firmware; or go to [Release page](https://www.github.com/polhenarejos/pico-openpgp/releases/) and download the UF2 file for your board. If you own a Raspberry Pico (RP2040 or RP2350), go to [Download page](https://www.picokeys.com/getting-started/), select your vendor and model and download the proper firmware; or go to [Release page](https://www.github.com/polhenarejos/pico-openpgp/releases/) and download the UF2 file for your board.
Note that UF2 files are shiped with a dummy VID/PID to avoid license issues (FEFF:FCFD). If you plan to use it with OpenSC or similar tools, you should modify Info.plist of CCID driver to add these VID/PID or use the [Pico Commissioner](https://www.picokeys.com/pico-commissioner/ "Pico Commissioner"). UF2 files are shiped with a VID/PID granted by RaspberryPi (2E8A:10FF). If you plan to use it with OpenSC or similar tools, you should modify Info.plist of CCID driver to add these VID/PID or use the [PicoKey App](https://www.picokeys.com/picokeyapp/ "PicoKey App").
You can use whatever VID/PID (i.e., 234b:0000 from FISJ), but remember that you are not authorized to distribute the binary with a VID/PID that you do not own. You can use whatever VID/PID for internal purposes, but remember that you are not authorized to distribute the binary with a VID/PID that you do not own.
Note that the pure-browser option [Pico Commissioner](https://www.picokeys.com/pico-commissioner/ "Pico Commissioner") is the most recommended. Note that the [PicoKey App](https://www.picokeys.com/picokeyapp/ "PicoKey App") is the most recommended.
## Build for Raspberry Pico ## Build for Raspberry Pico
Before building, ensure you have installed the toolchain for the Pico and the Pico SDK is properly located in your drive. Before building, ensure you have installed the toolchain for the Pico and the Pico SDK is properly located in your drive.
@@ -169,7 +159,7 @@ The way to communicate is exactly the same as with other cards, such as OpenPGP
### Important ### Important
OpenSC relies on PCSC driver, which reads a list (`Info.plist`) that contains a pair of VID/PID of supported readers. In order to be detectable, you have several options: OpenSC relies on PCSC driver, which reads a list (`Info.plist`) that contains a pair of VID/PID of supported readers. In order to be detectable, you have several options:
- Use the pure-browser online [Pico Commissioner](https://www.picokeys.com/pico-commissioner/ "Pico Commissioner") that commissions the Pico Key on-the-fly without external tools. - Use the [PicoKey App](https://www.picokeys.com/picokeyapp/ "PicoKey App") that commissions the PicoKey on-the-fly without external tools.
- Build and configure the project with the proper VID/PID with `USB_VID` and `USB_PID` parameters in `CMake` (see [Build section](#build "Build section")). Note that you cannot distribute the patched/compiled binary if you do not own the VID/PID or have an explicit authorization. - Build and configure the project with the proper VID/PID with `USB_VID` and `USB_PID` parameters in `CMake` (see [Build section](#build "Build section")). Note that you cannot distribute the patched/compiled binary if you do not own the VID/PID or have an explicit authorization.
## License and Commercial Use ## License and Commercial Use

View File

@@ -1 +0,0 @@
Version=3.6

View File

@@ -1,48 +1,25 @@
#!/bin/bash #!/bin/bash
VERSION_MAJOR="4" VERSION_MAJOR="4"
VERSION_MINOR="0" VERSION_MINOR="6"
NO_EDDSA=0
SUFFIX="${VERSION_MAJOR}.${VERSION_MINOR}" SUFFIX="${VERSION_MAJOR}.${VERSION_MINOR}"
#if ! [[ -z "${GITHUB_SHA}" ]]; then #if ! [[ -z "${GITHUB_SHA}" ]]; then
# SUFFIX="${SUFFIX}.${GITHUB_SHA}" # SUFFIX="${SUFFIX}.${GITHUB_SHA}"
#fi #fi
if [[ $1 == "--no-eddsa" ]]; then
NO_EDDSA=1
echo "Skipping EDDSA build"
fi
mkdir -p build_release mkdir -p build_release
mkdir -p release mkdir -p release
mkdir -p release_eddsa
rm -rf -- release/* rm -rf -- release/*
if [[ $NO_EDDSA -eq 0 ]]; then
rm -rf -- release_eddsa/*
fi
cd build_release cd build_release
PICO_SDK_PATH="${PICO_SDK_PATH:-../../pico-sdk}" PICO_SDK_PATH="${PICO_SDK_PATH:-../../pico-sdk}"
SECURE_BOOT_PKEY="${SECURE_BOOT_PKEY:-../../ec_private_key.pem}" SECURE_BOOT_PKEY="${SECURE_BOOT_PKEY:-../../ec_private_key.pem}"
board_dir=${PICO_SDK_PATH}/src/boards/include/boards boards=("pico" "pico2")
for board in "$board_dir"/*
for board_name in "${boards[@]}"
do do
board_name="$(basename -- "$board" .h)"
rm -rf -- ./* rm -rf -- ./*
PICO_SDK_PATH="${PICO_SDK_PATH}" cmake .. -DPICO_BOARD=$board_name -DSECURE_BOOT_PKEY=${SECURE_BOOT_PKEY} PICO_SDK_PATH="${PICO_SDK_PATH}" cmake .. -DPICO_BOARD=$board_name -DSECURE_BOOT_PKEY=${SECURE_BOOT_PKEY}
make -j`nproc` make -j`nproc`
mv pico_openpgp.uf2 ../release/pico_openpgp_$board_name-$SUFFIX.uf2 mv pico_openpgp.uf2 ../release/pico_openpgp_$board_name-$SUFFIX.uf2
done done
# Build with EDDSA
if [[ $NO_EDDSA -eq 0 ]]; then
for board in "$board_dir"/*
do
board_name="$(basename -- "$board" .h)"
rm -rf -- ./*
PICO_SDK_PATH="${PICO_SDK_PATH}" cmake .. -DPICO_BOARD=$board_name -DSECURE_BOOT_PKEY=${SECURE_BOOT_PKEY} -DENABLE_EDDSA=1
make -j`nproc`
mv pico_openpgp.uf2 ../release_eddsa/pico_openpgp_$board_name-$SUFFIX-eddsa1.uf2
done
fi

View File

@@ -1,6 +1,9 @@
idf_component_register( idf_component_register(
SRCS ${SOURCES} SRCS ${SOURCES}
INCLUDE_DIRS . ../../pico-keys-sdk/src ../../pico-keys-sdk/src/fs ../../pico-keys-sdk/src/rng ../../pico-keys-sdk/src/usb ../../pico-keys-sdk/tinycbor/src INCLUDE_DIRS .
REQUIRES mbedtls efuse REQUIRES mbedtls efuse pico-keys-sdk
) )
if(OPENPGP_TEST_INIT_LEGACY_PIN)
target_compile_definitions(${COMPONENT_LIB} PRIVATE OPENPGP_TEST_INIT_LEGACY_PIN=1)
endif()
idf_component_set_property(${COMPONENT_NAME} WHOLE_ARCHIVE ON) idf_component_set_property(${COMPONENT_NAME} WHOLE_ARCHIVE ON)

View File

@@ -17,6 +17,6 @@
#include "openpgp.h" #include "openpgp.h"
int cmd_activate_file() { int cmd_activate_file(void) {
return SW_OK(); return SW_OK();
} }

View File

@@ -18,7 +18,7 @@
#include "openpgp.h" #include "openpgp.h"
#include "random.h" #include "random.h"
int cmd_challenge() { int cmd_challenge(void) {
uint8_t *rb = (uint8_t *) random_bytes_get(apdu.ne); uint8_t *rb = (uint8_t *) random_bytes_get(apdu.ne);
if (!rb) { if (!rb) {
return SW_WRONG_LENGTH(); return SW_WRONG_LENGTH();

View File

@@ -18,13 +18,13 @@
#include "openpgp.h" #include "openpgp.h"
#include "otp.h" #include "otp.h"
int cmd_change_pin() { int cmd_change_pin(void) {
if (P1(apdu) != 0x0) { if (P1(apdu) != 0x0) {
return SW_WRONG_P1P2(); return SW_WRONG_P1P2();
} }
uint16_t fid = 0x1000 | P2(apdu); uint16_t fid = 0x1000 | P2(apdu);
file_t *pw; file_t *pw;
if (!(pw = search_by_fid(fid, NULL, SPECIFY_EF))) { if (!(pw = file_search_by_fid(fid, NULL, SPECIFY_EF))) {
return SW_REFERENCE_NOT_FOUND(); return SW_REFERENCE_NOT_FOUND();
} }
uint8_t pin_len = file_get_data(pw)[0]; uint8_t pin_len = file_get_data(pw)[0];
@@ -33,37 +33,38 @@ int cmd_change_pin() {
if (r != 0x9000) { if (r != 0x9000) {
return r; return r;
} }
if ((r = load_dek()) != PICOKEY_OK) { if ((r = load_dek()) != PICOKEYS_OK) {
return SW_EXEC_ERROR(); return SW_EXEC_ERROR();
} }
if (otp_key_1) { uint8_t dhash[34];
for (int i = 0; i < 32; i++) {
dek[IV_SIZE + i] ^= otp_key_1[i];
}
}
uint8_t dhash[33];
dhash[0] = apdu.nc - pin_len; dhash[0] = apdu.nc - pin_len;
double_hash_pin(apdu.data + pin_len, apdu.nc - pin_len, dhash + 1); dhash[1] = 0x1; // Format
pin_derive_verifier(apdu.data + pin_len, apdu.nc - pin_len, dhash + 2);
file_put_data(pw, dhash, sizeof(dhash)); file_put_data(pw, dhash, sizeof(dhash));
file_t *tf = search_by_fid(EF_DEK, NULL, SPECIFY_EF);
if (!tf) {
return SW_REFERENCE_NOT_FOUND();
}
uint8_t def[IV_SIZE + 32 + 32 + 32 + 32] = {0};
memcpy(def, file_get_data(tf), file_get_size(tf));
if (P2(apdu) == 0x81) { if (P2(apdu) == 0x81) {
hash_multi(apdu.data + pin_len, apdu.nc - pin_len, session_pw1); file_t *tf = file_search_by_fid(EF_DEK_PW1, NULL, SPECIFY_EF);
memcpy(def + IV_SIZE, dek + IV_SIZE, 32); if (!tf) {
aes_encrypt_cfb_256(session_pw1, def, def + IV_SIZE, 32); return SW_REFERENCE_NOT_FOUND();
}
uint8_t def[DEK_FILE_SIZE];
def[0] = 0x3;
pin_derive_session(apdu.data + pin_len, apdu.nc - pin_len, session_pw1);
encrypt_with_aad(session_pw1, dek, DEK_SIZE, PIN_KDF_DEFAULT_VERSION, def + 1);
r = file_put_data(tf, def, sizeof(def));
} }
else if (P2(apdu) == 0x83) { else if (P2(apdu) == 0x83) {
hash_multi(apdu.data + pin_len, apdu.nc - pin_len, session_pw3); file_t *tf = file_search_by_fid(EF_DEK_PW3, NULL, SPECIFY_EF);
memcpy(def + IV_SIZE + 32 + 32, dek + IV_SIZE, 32); if (!tf) {
aes_encrypt_cfb_256(session_pw3, def, def + IV_SIZE + 32 + 32, 32); return SW_REFERENCE_NOT_FOUND();
}
uint8_t def[DEK_FILE_SIZE];
def[0] = 0x3;
pin_derive_session(apdu.data + pin_len, apdu.nc - pin_len, session_pw3);
encrypt_with_aad(session_pw3, dek, DEK_SIZE, PIN_KDF_DEFAULT_VERSION, def + 1);
r = file_put_data(tf, def, sizeof(def));
} }
file_put_data(tf, def, sizeof(def)); flash_commit();
low_flash_available();
return SW_OK(); return SW_OK();
} }

View File

@@ -18,53 +18,104 @@
#include "openpgp.h" #include "openpgp.h"
#include "asn1.h" #include "asn1.h"
int cmd_get_data() { extern bool is_gpg;
int cmd_get_data(void) {
if (apdu.nc > 0) { if (apdu.nc > 0) {
return SW_WRONG_LENGTH(); return SW_WRONG_LENGTH();
} }
uint16_t fid = (P1(apdu) << 8) | P2(apdu); uint16_t fid = (P1(apdu) << 8) | P2(apdu);
file_t *ef; file_t *ef;
if (!(ef = search_by_fid(fid, NULL, SPECIFY_EF))) { if (!(ef = file_search_by_fid(fid, NULL, SPECIFY_EF))) {
return SW_REFERENCE_NOT_FOUND(); return SW_REFERENCE_NOT_FOUND();
} }
if (!authenticate_action(ef, ACL_OP_READ_SEARCH)) { if (fid == EF_PRIV_DO_3) {
if (!has_pw2 && !has_pw3) {
return SW_SECURITY_STATUS_NOT_SATISFIED();
}
}
else if (fid == EF_PRIV_DO_4) {
if (!has_pw3) {
return SW_SECURITY_STATUS_NOT_SATISFIED();
}
}
else if (!file_authenticate_action(ef, ACL_OP_READ_SEARCH)) {
return SW_SECURITY_STATUS_NOT_SATISFIED(); return SW_SECURITY_STATUS_NOT_SATISFIED();
} }
if (currentEF && (currentEF->fid & 0x1FF0) == (fid & 0x1FF0)) { //previously selected if (currentEF && currentEF->fid == fid) { // previously selected same EF
ef = currentEF; ef = currentEF;
} }
else { else {
select_file(ef); select_file(ef);
} }
if (ef->data) { if (ef->data) {
if (fid == EF_PW_STATUS || fid == EF_HIST_BYTES || fid == EF_FULL_AID || fid == EF_SEC_TPL) {
is_gpg = true;
}
uint16_t fids[] = { 1, fid }; uint16_t fids[] = { 1, fid };
uint16_t data_len = parse_do(fids, 1); uint16_t data_len = parse_do(fids, 1);
uint8_t *p = NULL; if (!(ef->type & FILE_DATA_FLASH)) {
uint16_t tg = 0; uint8_t *p = NULL;
uint16_t tg_len = 0; uint16_t tg = 0;
asn1_ctx_t ctxi; uint16_t tg_len = 0;
asn1_ctx_init(res_APDU, data_len, &ctxi); asn1_ctx_t ctxi;
if (walk_tlv(&ctxi, &p, &tg, &tg_len, NULL)) { asn1_ctx_init(res_APDU, data_len, &ctxi);
uint8_t dec = 2; if (walk_tlv(&ctxi, &p, &tg, &tg_len, NULL)) {
if ((tg & 0x1f) == 0x1f) { uint8_t dec = 2;
dec++; if ((tg & 0x1f) == 0x1f) {
} dec++;
if ((res_APDU[dec - 1] & 0xF0) == 0x80) { }
dec += (res_APDU[dec - 1] & 0x0F); if ((res_APDU[dec - 1] & 0xF0) == 0x80) {
} dec += (res_APDU[dec - 1] & 0x0F);
if (tg_len + dec == data_len) { }
memmove(res_APDU, res_APDU + dec, data_len - dec); if (tg_len + dec == data_len) {
data_len -= dec; memmove(res_APDU, res_APDU + dec, data_len - dec);
res_APDU_size -= dec; data_len -= dec;
res_APDU_size -= dec;
}
} }
} }
//if (apdu.ne > data_len) if (is_gpg == false) {
// apdu.ne = data_len; uint8_t off = 2;
if (P1(apdu) > 0x0) {
off++;
}
if (data_len >= 128) {
off++;
}
if (data_len >= 256) {
off++;
}
memmove(res_APDU + off, res_APDU, data_len);
off = 0;
if (P1(apdu) > 0x0) {
res_APDU[off++] = P1(apdu);
res_APDU[off++] = P2(apdu);
}
else {
res_APDU[off++] = P2(apdu);
}
if (data_len >= 256) {
res_APDU[off++] = 0x82;
res_APDU[off++] = (data_len >> 8) & 0xff;
res_APDU[off++] = data_len & 0xff;
}
else if (data_len >= 128) {
res_APDU[off++] = 0x81;
res_APDU[off++] = data_len;
}
else {
res_APDU[off++] = data_len;
}
res_APDU_size += off;
}
// if (apdu.ne > data_len)
// apdu.ne = data_len;
} }
return SW_OK(); return SW_OK();
} }
int cmd_get_next_data() { int cmd_get_next_data(void) {
file_t *ef = NULL; file_t *ef = NULL;
if (apdu.nc > 0) { if (apdu.nc > 0) {
return SW_WRONG_LENGTH(); return SW_WRONG_LENGTH();
@@ -73,19 +124,26 @@ int cmd_get_next_data() {
return SW_RECORD_NOT_FOUND(); return SW_RECORD_NOT_FOUND();
} }
uint16_t fid = (P1(apdu) << 8) | P2(apdu); uint16_t fid = (P1(apdu) << 8) | P2(apdu);
if (!(ef = search_by_fid(fid, NULL, SPECIFY_EF))) { if (!(ef = file_search_by_fid(fid, NULL, SPECIFY_EF))) {
return SW_REFERENCE_NOT_FOUND(); return SW_REFERENCE_NOT_FOUND();
} }
if (!authenticate_action(ef, ACL_OP_UPDATE_ERASE)) { if (!file_authenticate_action(ef, ACL_OP_UPDATE_ERASE)) {
return SW_SECURITY_STATUS_NOT_SATISFIED(); return SW_SECURITY_STATUS_NOT_SATISFIED();
} }
if ((currentEF->fid & 0x1FF0) != (fid & 0x1FF0)) { if ((currentEF->fid & 0x1FF0) != (fid & 0x1FF0)) {
return SW_WRONG_P1P2(); return SW_WRONG_P1P2();
} }
fid = currentEF->fid + 1; //curentEF contains private DO. so, we select the next one fid = currentEF->fid + 1; //curentEF contains private DO. so, we select the next one
if (!(ef = search_by_fid(fid, NULL, SPECIFY_EF))) { if (!(ef = file_search_by_fid(fid, NULL, SPECIFY_EF))) {
return SW_REFERENCE_NOT_FOUND(); return SW_REFERENCE_NOT_FOUND();
} }
select_file(ef); select_file(ef);
return cmd_get_data(); return cmd_get_data();
} }
int cmd_get_bulk_data(void) {
if (apdu.nc < 3) {
return SW_WRONG_LENGTH();
}
return bulk_cmd(cmd_get_data);
}

View File

@@ -18,14 +18,12 @@
#ifdef ESP_PLATFORM #ifdef ESP_PLATFORM
#include "esp_compat.h" #include "esp_compat.h"
#define MBEDTLS_ALLOW_PRIVATE_ACCESS #define MBEDTLS_ALLOW_PRIVATE_ACCESS
#else
#include "common.h"
#endif #endif
#include "openpgp.h" #include "openpgp.h"
#include "random.h" #include "random.h"
#include "do.h" #include "do.h"
uint16_t tag_len(uint8_t **data) { static uint16_t tag_len(uint8_t **data) {
size_t len = *(*data)++; size_t len = *(*data)++;
if (len == 0x82) { if (len == 0x82) {
len = *(*data)++ << 8; len = *(*data)++ << 8;
@@ -37,7 +35,7 @@ uint16_t tag_len(uint8_t **data) {
return len; return len;
} }
int cmd_import_data() { int cmd_import_data(void) {
file_t *ef = NULL; file_t *ef = NULL;
uint16_t fid = 0x0; uint16_t fid = 0x0;
if (P1(apdu) != 0x3F || P2(apdu) != 0xFF) { if (P1(apdu) != 0x3F || P2(apdu) != 0xFF) {
@@ -67,10 +65,10 @@ int cmd_import_data() {
return SW_WRONG_DATA(); return SW_WRONG_DATA();
} }
start++; start++;
if (!(ef = search_by_fid(fid, NULL, SPECIFY_EF))) { if (!(ef = file_search_by_fid(fid, NULL, SPECIFY_EF))) {
return SW_REFERENCE_NOT_FOUND(); return SW_REFERENCE_NOT_FOUND();
} }
if (!authenticate_action(ef, ACL_OP_UPDATE_ERASE)) { if (!file_authenticate_action(ef, ACL_OP_UPDATE_ERASE)) {
return SW_SECURITY_STATUS_NOT_SATISFIED(); return SW_SECURITY_STATUS_NOT_SATISFIED();
} }
start += (*start + 1); start += (*start + 1);
@@ -101,7 +99,7 @@ int cmd_import_data() {
} }
} }
file_t *algo_ef = search_by_fid(fid - 0x0010, NULL, SPECIFY_EF); file_t *algo_ef = file_search_by_fid(fid - 0x0010, NULL, SPECIFY_EF);
if (!algo_ef) { if (!algo_ef) {
return SW_REFERENCE_NOT_FOUND(); return SW_REFERENCE_NOT_FOUND();
} }
@@ -152,7 +150,7 @@ int cmd_import_data() {
r = store_keys(&rsa, ALGO_RSA, fid, true); r = store_keys(&rsa, ALGO_RSA, fid, true);
make_rsa_response(&rsa); make_rsa_response(&rsa);
mbedtls_rsa_free(&rsa); mbedtls_rsa_free(&rsa);
if (r != PICOKEY_OK) { if (r != PICOKEYS_OK) {
return SW_EXEC_ERROR(); return SW_EXEC_ERROR();
} }
} }
@@ -177,15 +175,7 @@ int cmd_import_data() {
mbedtls_ecp_keypair_free(&ecdsa); mbedtls_ecp_keypair_free(&ecdsa);
return SW_EXEC_ERROR(); return SW_EXEC_ERROR();
} }
#ifdef MBEDTLS_EDDSA_C r = mbedtls_ecp_keypair_calc_public(&ecdsa, random_fill_iterator, NULL);
if (ecdsa.grp.id == MBEDTLS_ECP_DP_ED25519) {
r = mbedtls_ecp_point_edwards(&ecdsa.grp, &ecdsa.Q, &ecdsa.d, random_gen, NULL);
}
else
#endif
{
r = mbedtls_ecp_mul(&ecdsa.grp, &ecdsa.Q, &ecdsa.d, &ecdsa.grp.G, random_gen, NULL);
}
if (r != 0) { if (r != 0) {
mbedtls_ecp_keypair_free(&ecdsa); mbedtls_ecp_keypair_free(&ecdsa);
return SW_EXEC_ERROR(); return SW_EXEC_ERROR();
@@ -193,7 +183,7 @@ int cmd_import_data() {
r = store_keys(&ecdsa, ALGO_ECDSA, fid, true); r = store_keys(&ecdsa, ALGO_ECDSA, fid, true);
make_ecdsa_response(&ecdsa); make_ecdsa_response(&ecdsa);
mbedtls_ecp_keypair_free(&ecdsa); mbedtls_ecp_keypair_free(&ecdsa);
if (r != PICOKEY_OK) { if (r != PICOKEYS_OK) {
return SW_EXEC_ERROR(); return SW_EXEC_ERROR();
} }
} }
@@ -203,12 +193,12 @@ int cmd_import_data() {
if (fid == EF_PK_SIG) { if (fid == EF_PK_SIG) {
reset_sig_count(); reset_sig_count();
} }
file_t *pbef = search_by_fid(fid + 3, NULL, SPECIFY_EF); file_t *pbef = file_search_by_fid(fid + 3, NULL, SPECIFY_EF);
if (!pbef) { if (!pbef) {
return SW_REFERENCE_NOT_FOUND(); return SW_REFERENCE_NOT_FOUND();
} }
r = file_put_data(pbef, res_APDU, res_APDU_size); r = file_put_data(pbef, res_APDU, res_APDU_size);
if (r != PICOKEY_OK) { if (r != PICOKEYS_OK) {
return SW_EXEC_ERROR(); return SW_EXEC_ERROR();
} }
res_APDU_size = 0; //make_*_response sets a response. we need to overwrite res_APDU_size = 0; //make_*_response sets a response. we need to overwrite

View File

@@ -18,14 +18,14 @@
#include "openpgp.h" #include "openpgp.h"
#include "do.h" #include "do.h"
int cmd_internal_aut() { int cmd_internal_aut(void) {
if (P1(apdu) != 0x00 || P2(apdu) != 0x00) { if (P1(apdu) != 0x00 || P2(apdu) != 0x00) {
return SW_WRONG_P1P2(); return SW_WRONG_P1P2();
} }
if (!has_pw3 && !has_pw2) { if (!has_pw3 && !has_pw2) {
return SW_SECURITY_STATUS_NOT_SATISFIED(); return SW_SECURITY_STATUS_NOT_SATISFIED();
} }
file_t *algo_ef = search_by_fid(algo_aut, NULL, SPECIFY_EF); file_t *algo_ef = file_search_by_fid(algo_aut, NULL, SPECIFY_EF);
if (!algo_ef) { if (!algo_ef) {
return SW_REFERENCE_NOT_FOUND(); return SW_REFERENCE_NOT_FOUND();
} }
@@ -33,19 +33,19 @@ int cmd_internal_aut() {
if (algo_ef && algo_ef->data) { if (algo_ef && algo_ef->data) {
algo = file_get_data(algo_ef); algo = file_get_data(algo_ef);
} }
file_t *ef = search_by_fid(pk_aut, NULL, SPECIFY_EF); file_t *ef = file_search_by_fid(pk_aut, NULL, SPECIFY_EF);
if (!ef) { if (!ef) {
return SW_REFERENCE_NOT_FOUND(); return SW_REFERENCE_NOT_FOUND();
} }
if (wait_button_pressed_fid(EF_UIF_AUT) == true) { if (wait_button_pressed_fid(EF_UIF_AUT) == true) {
return SW_SECURE_MESSAGE_EXEC_ERROR(); return SW_SECURE_MESSAGE_EXEC_ERROR();
} }
int r = PICOKEY_OK; int r = PICOKEYS_OK;
if (algo[0] == ALGO_RSA) { if (algo[0] == ALGO_RSA) {
mbedtls_rsa_context ctx; mbedtls_rsa_context ctx;
mbedtls_rsa_init(&ctx); mbedtls_rsa_init(&ctx);
r = load_private_key_rsa(&ctx, ef, true); r = load_private_key_rsa(&ctx, ef, true);
if (r != PICOKEY_OK) { if (r != PICOKEYS_OK) {
mbedtls_rsa_free(&ctx); mbedtls_rsa_free(&ctx);
return SW_EXEC_ERROR(); return SW_EXEC_ERROR();
} }
@@ -61,7 +61,7 @@ int cmd_internal_aut() {
mbedtls_ecp_keypair ctx; mbedtls_ecp_keypair ctx;
mbedtls_ecp_keypair_init(&ctx); mbedtls_ecp_keypair_init(&ctx);
r = load_private_key_ecdsa(&ctx, ef, true); r = load_private_key_ecdsa(&ctx, ef, true);
if (r != PICOKEY_OK) { if (r != PICOKEYS_OK) {
mbedtls_ecp_keypair_free(&ctx); mbedtls_ecp_keypair_free(&ctx);
return SW_EXEC_ERROR(); return SW_EXEC_ERROR();
} }

View File

@@ -15,11 +15,12 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
#include <stdio.h>
#include "openpgp.h" #include "openpgp.h"
#include "do.h" #include "do.h"
#include "random.h" #include "random.h"
int cmd_keypair_gen() { int cmd_keypair_gen(void) {
if (P2(apdu) != 0x0) { if (P2(apdu) != 0x0) {
return SW_INCORRECT_P1P2(); return SW_INCORRECT_P1P2();
} }
@@ -31,7 +32,7 @@ int cmd_keypair_gen() {
} }
uint16_t fid = 0x0; uint16_t fid = 0x0;
int r = PICOKEY_OK; int r = PICOKEYS_OK;
if (apdu.data[0] == 0xB6) { if (apdu.data[0] == 0xB6) {
fid = EF_PK_SIG; fid = EF_PK_SIG;
} }
@@ -45,7 +46,7 @@ int cmd_keypair_gen() {
return SW_WRONG_DATA(); return SW_WRONG_DATA();
} }
file_t *algo_ef = search_by_fid(fid - 0x0010, NULL, SPECIFY_EF); file_t *algo_ef = file_search_by_fid(fid - 0x0010, NULL, SPECIFY_EF);
if (!algo_ef) { if (!algo_ef) {
return SW_REFERENCE_NOT_FOUND(); return SW_REFERENCE_NOT_FOUND();
} }
@@ -63,8 +64,7 @@ int cmd_keypair_gen() {
// return SW_FUNC_NOT_SUPPORTED(); // return SW_FUNC_NOT_SUPPORTED();
mbedtls_rsa_context rsa; mbedtls_rsa_context rsa;
mbedtls_rsa_init(&rsa); mbedtls_rsa_init(&rsa);
uint8_t index = 0; r = mbedtls_rsa_gen_key(&rsa, random_fill_iterator, NULL, nlen, exponent);
r = mbedtls_rsa_gen_key(&rsa, random_gen, &index, nlen, exponent);
if (r != 0) { if (r != 0) {
mbedtls_rsa_free(&rsa); mbedtls_rsa_free(&rsa);
return SW_EXEC_ERROR(); return SW_EXEC_ERROR();
@@ -72,7 +72,7 @@ int cmd_keypair_gen() {
r = store_keys(&rsa, ALGO_RSA, fid, true); r = store_keys(&rsa, ALGO_RSA, fid, true);
make_rsa_response(&rsa); make_rsa_response(&rsa);
mbedtls_rsa_free(&rsa); mbedtls_rsa_free(&rsa);
if (r != PICOKEY_OK) { if (r != PICOKEYS_OK) {
return SW_EXEC_ERROR(); return SW_EXEC_ERROR();
} }
} }
@@ -84,8 +84,7 @@ int cmd_keypair_gen() {
} }
mbedtls_ecp_keypair ecdsa; mbedtls_ecp_keypair ecdsa;
mbedtls_ecp_keypair_init(&ecdsa); mbedtls_ecp_keypair_init(&ecdsa);
uint8_t index = 0; r = mbedtls_ecdsa_genkey(&ecdsa, gid, random_fill_iterator, NULL);
r = mbedtls_ecdsa_genkey(&ecdsa, gid, random_gen, &index);
if (r != 0) { if (r != 0) {
mbedtls_ecp_keypair_free(&ecdsa); mbedtls_ecp_keypair_free(&ecdsa);
return SW_EXEC_ERROR(); return SW_EXEC_ERROR();
@@ -93,19 +92,19 @@ int cmd_keypair_gen() {
r = store_keys(&ecdsa, algo[0], fid, true); r = store_keys(&ecdsa, algo[0], fid, true);
make_ecdsa_response(&ecdsa); make_ecdsa_response(&ecdsa);
mbedtls_ecp_keypair_free(&ecdsa); mbedtls_ecp_keypair_free(&ecdsa);
if (r != PICOKEY_OK) { if (r != PICOKEYS_OK) {
return SW_EXEC_ERROR(); return SW_EXEC_ERROR();
} }
} }
else { else {
return SW_FUNC_NOT_SUPPORTED(); return SW_FUNC_NOT_SUPPORTED();
} }
file_t *pbef = search_by_fid(fid + 3, NULL, SPECIFY_EF); file_t *pbef = file_search_by_fid(fid + 3, NULL, SPECIFY_EF);
if (!pbef) { if (!pbef) {
return SW_REFERENCE_NOT_FOUND(); return SW_REFERENCE_NOT_FOUND();
} }
r = file_put_data(pbef, res_APDU, res_APDU_size); r = file_put_data(pbef, res_APDU, res_APDU_size);
if (r != PICOKEY_OK) { if (r != PICOKEYS_OK) {
return SW_EXEC_ERROR(); return SW_EXEC_ERROR();
} }
if (fid == EF_PK_SIG) { if (fid == EF_PK_SIG) {
@@ -119,14 +118,14 @@ int cmd_keypair_gen() {
memcpy(aes_key, random_bytes_get(key_size), key_size); memcpy(aes_key, random_bytes_get(key_size), key_size);
r = store_keys(aes_key, ALGO_AES_256, EF_AES_KEY, true); r = store_keys(aes_key, ALGO_AES_256, EF_AES_KEY, true);
/* if storing the key fails, we silently continue */ /* if storing the key fails, we silently continue */
//if (r != PICOKEY_OK) //if (r != PICOKEYS_OK)
// return SW_EXEC_ERROR(); // return SW_EXEC_ERROR();
} }
low_flash_available(); flash_commit();
return SW_OK(); return SW_OK();
} }
else if (P1(apdu) == 0x81) { //read else if (P1(apdu) == 0x81) { //read
file_t *ef = search_by_fid(fid + 3, NULL, SPECIFY_EF); file_t *ef = file_search_by_fid(fid + 3, NULL, SPECIFY_EF);
if (!file_has_data(ef)) { if (!file_has_data(ef)) {
return SW_REFERENCE_NOT_FOUND(); return SW_REFERENCE_NOT_FOUND();
} }

View File

@@ -17,7 +17,7 @@
#include "openpgp.h" #include "openpgp.h"
int cmd_mse() { int cmd_mse(void) {
if (P1(apdu) != 0x41 || (P2(apdu) != 0xA4 && P2(apdu) != 0xB8)) { if (P1(apdu) != 0x41 || (P2(apdu) != 0xA4 && P2(apdu) != 0xB8)) {
return SW_WRONG_P1P2(); return SW_WRONG_P1P2();
} }

View File

@@ -18,8 +18,6 @@
#ifdef ESP_PLATFORM #ifdef ESP_PLATFORM
#include "esp_compat.h" #include "esp_compat.h"
#define MBEDTLS_ALLOW_PRIVATE_ACCESS #define MBEDTLS_ALLOW_PRIVATE_ACCESS
#else
#include "common.h"
#endif #endif
#include "openpgp.h" #include "openpgp.h"
#include "do.h" #include "do.h"
@@ -27,7 +25,7 @@
#include "mbedtls/ecdh.h" #include "mbedtls/ecdh.h"
#include "mbedtls/asn1.h" #include "mbedtls/asn1.h"
int cmd_pso() { int cmd_pso(void) {
uint16_t algo_fid = 0x0, pk_fid = 0x0; uint16_t algo_fid = 0x0, pk_fid = 0x0;
bool is_aes = false; bool is_aes = false;
if (P1(apdu) == 0x9E && P2(apdu) == 0x9A) { if (P1(apdu) == 0x9E && P2(apdu) == 0x9A) {
@@ -47,7 +45,7 @@ int cmd_pso() {
else { else {
return SW_INCORRECT_P1P2(); return SW_INCORRECT_P1P2();
} }
file_t *algo_ef = search_by_fid(algo_fid, NULL, SPECIFY_EF); file_t *algo_ef = file_search_by_fid(algo_fid, NULL, SPECIFY_EF);
if (!algo_ef) { if (!algo_ef) {
return SW_REFERENCE_NOT_FOUND(); return SW_REFERENCE_NOT_FOUND();
} }
@@ -62,35 +60,35 @@ int cmd_pso() {
is_aes = true; is_aes = true;
} }
} }
file_t *ef = search_by_fid(pk_fid, NULL, SPECIFY_EF); file_t *ef = file_search_by_fid(pk_fid, NULL, SPECIFY_EF);
if (!ef) { if (!ef) {
return SW_REFERENCE_NOT_FOUND(); return SW_REFERENCE_NOT_FOUND();
} }
if (wait_button_pressed_fid(pk_fid == EF_PK_SIG ? EF_UIF_SIG : EF_UIF_DEC) == true) { if (wait_button_pressed_fid(pk_fid == EF_PK_SIG ? EF_UIF_SIG : EF_UIF_DEC) == true) {
return SW_SECURE_MESSAGE_EXEC_ERROR(); return SW_SECURE_MESSAGE_EXEC_ERROR();
} }
int r = PICOKEY_OK; int r = PICOKEYS_OK;
int key_size = file_get_size(ef); size_t key_size = file_get_size(ef);
if (is_aes) { if (is_aes) {
uint8_t aes_key[32]; uint8_t aes_key[32];
r = load_aes_key(aes_key, ef); r = load_aes_key(aes_key, ef);
if (r != PICOKEY_OK) { if (r != PICOKEYS_OK) {
memset(aes_key, 0, sizeof(aes_key)); memset(aes_key, 0, sizeof(aes_key));
return SW_EXEC_ERROR(); return SW_EXEC_ERROR();
} }
if (P1(apdu) == 0x80 && P2(apdu) == 0x86) { //decipher if (P1(apdu) == 0x80 && P2(apdu) == 0x86) { //decipher
r = aes_decrypt(aes_key, NULL, key_size, PICO_KEYS_AES_MODE_CBC, apdu.data + 1, apdu.nc - 1); r = aes_decrypt(aes_key, NULL, key_size, PICOKEYS_AES_MODE_CBC, apdu.data + 1, apdu.nc - 1);
memset(aes_key, 0, sizeof(aes_key)); memset(aes_key, 0, sizeof(aes_key));
if (r != PICOKEY_OK) { if (r != PICOKEYS_OK) {
return SW_EXEC_ERROR(); return SW_EXEC_ERROR();
} }
memcpy(res_APDU, apdu.data + 1, apdu.nc - 1); memcpy(res_APDU, apdu.data + 1, apdu.nc - 1);
res_APDU_size = apdu.nc - 1; res_APDU_size = apdu.nc - 1;
} }
else if (P1(apdu) == 0x86 && P2(apdu) == 0x80) { //encipher else if (P1(apdu) == 0x86 && P2(apdu) == 0x80) { //encipher
r = aes_encrypt(aes_key, NULL, key_size, PICO_KEYS_AES_MODE_CBC, apdu.data, apdu.nc); r = aes_encrypt(aes_key, NULL, key_size, PICOKEYS_AES_MODE_CBC, apdu.data, apdu.nc);
memset(aes_key, 0, sizeof(aes_key)); memset(aes_key, 0, sizeof(aes_key));
if (r != PICOKEY_OK) { if (r != PICOKEYS_OK) {
return SW_EXEC_ERROR(); return SW_EXEC_ERROR();
} }
res_APDU[0] = 0x2; res_APDU[0] = 0x2;
@@ -103,7 +101,7 @@ int cmd_pso() {
mbedtls_rsa_context ctx; mbedtls_rsa_context ctx;
mbedtls_rsa_init(&ctx); mbedtls_rsa_init(&ctx);
r = load_private_key_rsa(&ctx, ef, true); r = load_private_key_rsa(&ctx, ef, true);
if (r != PICOKEY_OK) { if (r != PICOKEYS_OK) {
mbedtls_rsa_free(&ctx); mbedtls_rsa_free(&ctx);
return SW_EXEC_ERROR(); return SW_EXEC_ERROR();
} }
@@ -123,13 +121,7 @@ int cmd_pso() {
memset(apdu.data + apdu.nc, 0, key_size - apdu.nc); memset(apdu.data + apdu.nc, 0, key_size - apdu.nc);
} }
size_t olen = 0; size_t olen = 0;
r = mbedtls_rsa_pkcs1_decrypt(&ctx, r = mbedtls_rsa_pkcs1_decrypt(&ctx, random_fill_iterator, NULL, &olen, apdu.data + 1, res_APDU, key_size);
random_gen,
NULL,
&olen,
apdu.data + 1,
res_APDU,
key_size);
mbedtls_rsa_free(&ctx); mbedtls_rsa_free(&ctx);
if (r != 0) { if (r != 0) {
return SW_EXEC_ERROR(); return SW_EXEC_ERROR();
@@ -142,7 +134,7 @@ int cmd_pso() {
mbedtls_ecp_keypair ctx; mbedtls_ecp_keypair ctx;
mbedtls_ecp_keypair_init(&ctx); mbedtls_ecp_keypair_init(&ctx);
r = load_private_key_ecdsa(&ctx, ef, true); r = load_private_key_ecdsa(&ctx, ef, true);
if (r != PICOKEY_OK) { if (r != PICOKEYS_OK) {
mbedtls_ecp_keypair_free(&ctx); mbedtls_ecp_keypair_free(&ctx);
return SW_EXEC_ERROR(); return SW_EXEC_ERROR();
} }
@@ -195,12 +187,7 @@ int cmd_pso() {
return SW_DATA_INVALID(); return SW_DATA_INVALID();
} }
size_t olen = 0; size_t olen = 0;
r = mbedtls_ecdh_calc_secret(&ctx, r = mbedtls_ecdh_calc_secret(&ctx, &olen, res_APDU, MBEDTLS_ECP_MAX_BYTES, random_fill_iterator, NULL);
&olen,
res_APDU,
MBEDTLS_ECP_MAX_BYTES,
random_gen,
NULL);
if (r != 0) { if (r != 0) {
mbedtls_ecdh_free(&ctx); mbedtls_ecdh_free(&ctx);
return SW_EXEC_ERROR(); return SW_EXEC_ERROR();

View File

@@ -17,7 +17,7 @@
#include "openpgp.h" #include "openpgp.h"
int cmd_put_data() { int cmd_put_data(void) {
uint16_t fid = (P1(apdu) << 8) | P2(apdu); uint16_t fid = (P1(apdu) << 8) | P2(apdu);
file_t *ef; file_t *ef;
if (fid == EF_RESET_CODE) { if (fid == EF_RESET_CODE) {
@@ -26,49 +26,61 @@ int cmd_put_data() {
else if (fid == EF_ALGO_SIG || fid == EF_ALGO_DEC || fid == EF_ALGO_AUT) { else if (fid == EF_ALGO_SIG || fid == EF_ALGO_DEC || fid == EF_ALGO_AUT) {
fid |= 0x1000; fid |= 0x1000;
} }
if (!(ef = search_by_fid(fid, NULL, SPECIFY_EF))) { if (!(ef = file_search_by_fid(fid, NULL, SPECIFY_EF))) {
return SW_REFERENCE_NOT_FOUND(); return SW_REFERENCE_NOT_FOUND();
} }
if (!authenticate_action(ef, ACL_OP_UPDATE_ERASE)) { if (!file_authenticate_action(ef, ACL_OP_UPDATE_ERASE)) {
return SW_SECURITY_STATUS_NOT_SATISFIED();
}
if ((fid == EF_PRIV_DO_1 || fid == EF_PRIV_DO_3) && (!has_pw2 && !has_pw3)) {
return SW_SECURITY_STATUS_NOT_SATISFIED();
}
if (!(fid == EF_PRIV_DO_1 || fid == EF_PRIV_DO_3) && !has_pw3) {
return SW_SECURITY_STATUS_NOT_SATISFIED(); return SW_SECURITY_STATUS_NOT_SATISFIED();
} }
if (fid == EF_PW_STATUS) { if (fid == EF_PW_STATUS) {
fid = EF_PW_PRIV; fid = EF_PW_PRIV;
apdu.nc = 4; //we silently ommit the reset parameters apdu.nc = 4; //we silently ommit the reset parameters
} }
if (currentEF && (currentEF->fid & 0x1FF0) == (fid & 0x1FF0)) { //previously selected if (currentEF && currentEF->fid == fid) { // previously selected same EF
ef = currentEF; ef = currentEF;
} }
if (apdu.nc > 0 && (ef->type & FILE_DATA_FLASH)) { if (ef->type & FILE_DATA_FLASH) {
int r = 0; int r = 0;
if (fid == EF_RC) { if (apdu.nc > 0) {
has_rc = false; if (fid == EF_RC) {
if ((r = load_dek()) != PICOKEY_OK) { has_rc = false;
return SW_EXEC_ERROR(); if ((r = load_dek()) != PICOKEYS_OK) {
} return SW_EXEC_ERROR();
uint8_t dhash[33]; }
dhash[0] = apdu.nc; uint8_t dhash[34];
double_hash_pin(apdu.data, apdu.nc, dhash + 1); dhash[0] = apdu.nc;
r = file_put_data(ef, dhash, sizeof(dhash)); dhash[1] = 0x1; // Format
pin_derive_verifier(apdu.data, apdu.nc, dhash + 2);
file_put_data(ef, dhash, sizeof(dhash));
file_t *tf = search_by_fid(EF_DEK, NULL, SPECIFY_EF); file_t *tf = file_search_by_fid(EF_DEK, NULL, SPECIFY_EF);
if (!tf) { if (!tf) {
return SW_REFERENCE_NOT_FOUND(); return SW_REFERENCE_NOT_FOUND();
}
uint8_t def[DEK_FILE_SIZE];
def[0] = 0x3;
pin_derive_session(apdu.data, apdu.nc, session_rc);
encrypt_with_aad(session_rc, dek, DEK_SIZE, PIN_KDF_DEFAULT_VERSION, def + 1);
r = file_put_data(tf, def, sizeof(def));
} }
uint8_t def[IV_SIZE + 32 + 32 + 32 + 32]; else {
memcpy(def, file_get_data(tf), file_get_size(tf)); r = file_put_data(ef, apdu.data, apdu.nc);
hash_multi(apdu.data, apdu.nc, session_rc); }
memcpy(def + IV_SIZE + 32, dek + IV_SIZE, 32); if (r != PICOKEYS_OK) {
aes_encrypt_cfb_256(session_rc, def, def + IV_SIZE + 32, 32); return SW_MEMORY_FAILURE();
r = file_put_data(tf, def, sizeof(def)); }
flash_commit();
} }
else { else {
r = file_put_data(ef, apdu.data, apdu.nc); file_delete(ef);
} }
if (r != PICOKEY_OK) {
return SW_MEMORY_FAILURE();
}
low_flash_available();
} }
return SW_OK(); return SW_OK();
} }

View File

@@ -18,7 +18,7 @@
#include "openpgp.h" #include "openpgp.h"
#include "otp.h" #include "otp.h"
int cmd_reset_retry() { int cmd_reset_retry(void) {
if (P2(apdu) != 0x81) { if (P2(apdu) != 0x81) {
return SW_REFERENCE_NOT_FOUND(); return SW_REFERENCE_NOT_FOUND();
} }
@@ -26,12 +26,12 @@ int cmd_reset_retry() {
int newpin_len = 0; int newpin_len = 0;
file_t *pw = NULL; file_t *pw = NULL;
has_pw1 = false; has_pw1 = false;
if (!(pw = search_by_fid(EF_PW1, NULL, SPECIFY_EF))) { if (!(pw = file_search_by_fid(EF_PW1, NULL, SPECIFY_EF))) {
return SW_REFERENCE_NOT_FOUND(); return SW_REFERENCE_NOT_FOUND();
} }
if (P1(apdu) == 0x0) { if (P1(apdu) == 0x0) {
file_t *rc; file_t *rc;
if (!(rc = search_by_fid(EF_RC, NULL, SPECIFY_EF))) { if (!(rc = file_search_by_fid(EF_RC, NULL, SPECIFY_EF))) {
return SW_REFERENCE_NOT_FOUND(); return SW_REFERENCE_NOT_FOUND();
} }
uint8_t pin_len = file_get_data(rc)[0]; uint8_t pin_len = file_get_data(rc)[0];
@@ -44,7 +44,7 @@ int cmd_reset_retry() {
} }
newpin_len = apdu.nc - pin_len; newpin_len = apdu.nc - pin_len;
has_rc = true; has_rc = true;
hash_multi(apdu.data, pin_len, session_rc); pin_derive_session(apdu.data, pin_len, session_rc);
has_pw1 = has_pw3 = false; has_pw1 = has_pw3 = false;
isUserAuthenticated = false; isUserAuthenticated = false;
} }
@@ -55,34 +55,29 @@ int cmd_reset_retry() {
newpin_len = apdu.nc; newpin_len = apdu.nc;
} }
int r = 0; int r = 0;
if ((r = load_dek()) != PICOKEY_OK) { if ((r = load_dek()) != PICOKEYS_OK) {
return SW_EXEC_ERROR(); return SW_EXEC_ERROR();
} }
file_t *tf = search_by_fid(EF_DEK, NULL, SPECIFY_EF); file_t *tf = file_search_by_fid(EF_DEK_PW1, NULL, SPECIFY_EF);
if (!tf) { if (!tf) {
return SW_REFERENCE_NOT_FOUND(); return SW_REFERENCE_NOT_FOUND();
} }
if (otp_key_1) { uint8_t def[DEK_FILE_SIZE];
for (int i = 0; i < 32; i++) { def[0] = 0x03;
dek[IV_SIZE + i] ^= otp_key_1[i]; pin_derive_session(apdu.data + (apdu.nc - newpin_len), newpin_len, session_pw1);
} encrypt_with_aad(session_pw1, dek, DEK_SIZE, PIN_KDF_DEFAULT_VERSION, def + 1);
}
uint8_t def[IV_SIZE + 32 + 32 + 32 + 32];
memcpy(def, file_get_data(tf), file_get_size(tf));
hash_multi(apdu.data + (apdu.nc - newpin_len), newpin_len, session_pw1);
memcpy(def + IV_SIZE, dek + IV_SIZE, 32);
aes_encrypt_cfb_256(session_pw1, def, def + IV_SIZE, 32);
r = file_put_data(tf, def, sizeof(def)); r = file_put_data(tf, def, sizeof(def));
uint8_t dhash[33]; uint8_t dhash[34];
dhash[0] = newpin_len; dhash[0] = newpin_len;
double_hash_pin(apdu.data + (apdu.nc - newpin_len), newpin_len, dhash + 1); dhash[1] = 0x1; // Format
pin_derive_verifier(apdu.data + (apdu.nc - newpin_len), newpin_len, dhash + 2);
file_put_data(pw, dhash, sizeof(dhash)); file_put_data(pw, dhash, sizeof(dhash));
if (pin_reset_retries(pw, true) != PICOKEY_OK) { if (pin_reset_retries(pw, true) != PICOKEYS_OK) {
return SW_MEMORY_FAILURE(); return SW_MEMORY_FAILURE();
} }
low_flash_available(); flash_commit();
if ((r = load_dek()) != PICOKEY_OK) { if ((r = load_dek()) != PICOKEYS_OK) {
return SW_EXEC_ERROR(); return SW_EXEC_ERROR();
} }
return SW_OK(); return SW_OK();

View File

@@ -17,14 +17,14 @@
#include "openpgp.h" #include "openpgp.h"
int cmd_select() { int cmd_select(void) {
uint8_t p1 = P1(apdu); uint8_t p1 = P1(apdu);
uint8_t p2 = P2(apdu); uint8_t p2 = P2(apdu);
file_t *pe = NULL; file_t *pe = NULL;
uint16_t fid = 0x0; uint16_t fid = 0x0;
if (apdu.nc >= 2) { if (apdu.nc >= 2) {
fid = get_uint16_t_be(apdu.data); fid = get_uint16_be(apdu.data);
} }
if (!pe) { if (!pe) {
@@ -34,18 +34,18 @@ int cmd_select() {
//ac_fini(); //ac_fini();
} }
else if (apdu.nc == 2) { else if (apdu.nc == 2) {
if (!(pe = search_by_fid(fid, NULL, SPECIFY_ANY))) { if (!(pe = file_search_by_fid(fid, NULL, SPECIFY_ANY))) {
return SW_REFERENCE_NOT_FOUND(); return SW_REFERENCE_NOT_FOUND();
} }
} }
} }
else if (p1 == 0x01) { //Select child DF - DF identifier else if (p1 == 0x01) { //Select child DF - DF identifier
if (!(pe = search_by_fid(fid, currentDF, SPECIFY_DF))) { if (!(pe = file_search_by_fid(fid, currentDF, SPECIFY_DF))) {
return SW_REFERENCE_NOT_FOUND(); return SW_REFERENCE_NOT_FOUND();
} }
} }
else if (p1 == 0x02) { //Select EF under the current DF - EF identifier else if (p1 == 0x02) { //Select EF under the current DF - EF identifier
if (!(pe = search_by_fid(fid, currentDF, SPECIFY_EF))) { if (!(pe = file_search_by_fid(fid, currentDF, SPECIFY_EF))) {
return SW_REFERENCE_NOT_FOUND(); return SW_REFERENCE_NOT_FOUND();
} }
} }
@@ -55,7 +55,7 @@ int cmd_select() {
} }
} }
else if (p1 == 0x04) { //Select by DF name - e.g., [truncated] application identifier else if (p1 == 0x04) { //Select by DF name - e.g., [truncated] application identifier
if (!(pe = search_by_name(apdu.data, apdu.nc))) { if (!(pe = file_search_by_name(apdu.data, apdu.nc))) {
return SW_REFERENCE_NOT_FOUND(); return SW_REFERENCE_NOT_FOUND();
} }
if (card_terminated) { if (card_terminated) {
@@ -63,19 +63,19 @@ int cmd_select() {
} }
} }
else if (p1 == 0x08) { //Select from the MF - Path without the MF identifier else if (p1 == 0x08) { //Select from the MF - Path without the MF identifier
if (!(pe = search_by_path(apdu.data, apdu.nc, MF))) { if (!(pe = file_search_by_path(apdu.data, apdu.nc, MF))) {
return SW_REFERENCE_NOT_FOUND(); return SW_REFERENCE_NOT_FOUND();
} }
} }
else if (p1 == 0x09) { //Select from the current DF - Path without the current DF identifier else if (p1 == 0x09) { //Select from the current DF - Path without the current DF identifier
if (!(pe = search_by_path(apdu.data, apdu.nc, currentDF))) { if (!(pe = file_search_by_path(apdu.data, apdu.nc, currentDF))) {
return SW_REFERENCE_NOT_FOUND(); return SW_REFERENCE_NOT_FOUND();
} }
} }
} }
if ((p2 & 0xfc) == 0x00 || (p2 & 0xfc) == 0x04) { if ((p2 & 0xfc) == 0x00 || (p2 & 0xfc) == 0x04) {
if ((p2 & 0xfc) == 0x04) { if ((p2 & 0xfc) == 0x04) {
process_fci(pe, 0); file_process_fci(pe, 0);
} }
} }
else { else {

View File

@@ -17,7 +17,7 @@
#include "openpgp.h" #include "openpgp.h"
int cmd_select_data() { int cmd_select_data(void) {
file_t *ef = NULL; file_t *ef = NULL;
uint16_t fid = 0x0; uint16_t fid = 0x0;
if (P2(apdu) != 0x4) { if (P2(apdu) != 0x4) {
@@ -26,7 +26,7 @@ int cmd_select_data() {
if (apdu.data[0] != 0x60) { if (apdu.data[0] != 0x60) {
return SW_WRONG_DATA(); return SW_WRONG_DATA();
} }
if (apdu.nc != apdu.data[1] + 2 || apdu.nc < 5) { if (apdu.nc != (uint32_t) apdu.data[1] + 2u || apdu.nc < 5u) {
return SW_WRONG_LENGTH(); return SW_WRONG_LENGTH();
} }
if (apdu.data[2] != 0x5C) { if (apdu.data[2] != 0x5C) {
@@ -38,15 +38,15 @@ int cmd_select_data() {
else { else {
fid = apdu.data[4]; fid = apdu.data[4];
} }
if (!(ef = search_by_fid(fid, NULL, SPECIFY_EF))) { if (!(ef = file_search_by_fid(fid, NULL, SPECIFY_EF))) {
return SW_REFERENCE_NOT_FOUND(); return SW_REFERENCE_NOT_FOUND();
} }
if (!authenticate_action(ef, ACL_OP_UPDATE_ERASE)) { if (!file_authenticate_action(ef, ACL_OP_UPDATE_ERASE)) {
return SW_SECURITY_STATUS_NOT_SATISFIED(); return SW_SECURITY_STATUS_NOT_SATISFIED();
} }
fid &= ~0x6000; //Now get private DO fid &= ~0x6000; //Now get private DO
fid += P1(apdu); fid += P1(apdu);
if (!(ef = search_by_fid(fid, NULL, SPECIFY_EF))) { if (!(ef = file_search_by_fid(fid, NULL, SPECIFY_EF))) {
return SW_REFERENCE_NOT_FOUND(); return SW_REFERENCE_NOT_FOUND();
} }
select_file(ef); select_file(ef);

View File

@@ -17,12 +17,12 @@
#include "openpgp.h" #include "openpgp.h"
int cmd_terminate_df() { int cmd_terminate_df(void) {
if (P1(apdu) != 0x0 || P2(apdu) != 0x0) { if (P1(apdu) != 0x0 || P2(apdu) != 0x0) {
return SW_INCORRECT_P1P2(); return SW_INCORRECT_P1P2();
} }
file_t *retries; file_t *retries;
if (!(retries = search_by_fid(EF_PW_PRIV, NULL, SPECIFY_EF))) { if (!(retries = file_search_by_fid(EF_PW_PRIV, NULL, SPECIFY_EF))) {
return SW_REFERENCE_NOT_FOUND(); return SW_REFERENCE_NOT_FOUND();
} }
if (!has_pw3 && *(file_get_data(retries) + 6) > 0) { if (!has_pw3 && *(file_get_data(retries) + 6) > 0) {
@@ -31,7 +31,7 @@ int cmd_terminate_df() {
if (apdu.nc != 0) { if (apdu.nc != 0) {
return SW_WRONG_LENGTH(); return SW_WRONG_LENGTH();
} }
initialize_flash(true); file_initialize_flash(true);
scan_files_openpgp(); scan_files_openpgp();
return SW_OK(); return SW_OK();
} }

View File

@@ -17,7 +17,7 @@
#include "openpgp.h" #include "openpgp.h"
int cmd_verify() { int cmd_verify(void) {
uint8_t p1 = P1(apdu); uint8_t p1 = P1(apdu);
uint8_t p2 = P2(apdu); uint8_t p2 = P2(apdu);
@@ -44,10 +44,10 @@ int cmd_verify() {
fid = EF_PW1; fid = EF_PW1;
} }
file_t *pw, *pw_status; file_t *pw, *pw_status;
if (!(pw = search_by_fid(fid, NULL, SPECIFY_EF))) { if (!(pw = file_search_by_fid(fid, NULL, SPECIFY_EF))) {
return SW_REFERENCE_NOT_FOUND(); return SW_REFERENCE_NOT_FOUND();
} }
if (!(pw_status = search_by_fid(EF_PW_PRIV, NULL, SPECIFY_EF))) { if (!(pw_status = file_search_by_fid(EF_PW_PRIV, NULL, SPECIFY_EF))) {
return SW_REFERENCE_NOT_FOUND(); return SW_REFERENCE_NOT_FOUND();
} }
if (file_get_data(pw)[0] == 0) { //not initialized if (file_get_data(pw)[0] == 0) { //not initialized

View File

@@ -18,7 +18,7 @@
#include "openpgp.h" #include "openpgp.h"
#include "version.h" #include "version.h"
int cmd_version_openpgp() { int cmd_version_openpgp(void) {
res_APDU[res_APDU_size++] = PIPGP_VERSION_MAJOR; res_APDU[res_APDU_size++] = PIPGP_VERSION_MAJOR;
res_APDU[res_APDU_size++] = PIPGP_VERSION_MINOR; res_APDU[res_APDU_size++] = PIPGP_VERSION_MINOR;
res_APDU[res_APDU_size++] = 0x0; res_APDU[res_APDU_size++] = 0x0;

View File

@@ -18,14 +18,30 @@
#include "openpgp.h" #include "openpgp.h"
#include "asn1.h" #include "asn1.h"
int parse_trium(uint16_t fid, uint8_t num, size_t size);
int parse_ch_data(const file_t *f, int mode);
int parse_sec_tpl(const file_t *f, int mode);
int parse_ch_cert(const file_t *f, int mode);
int parse_fp(const file_t *f, int mode);
int parse_cafp(const file_t *f, int mode);
int parse_ts(const file_t *f, int mode);
int parse_keyinfo(const file_t *f, int mode);
int parse_pw_status(const file_t *f, int mode);
int parse_algo(const uint8_t *algo, uint16_t tag);
int parse_algoinfo(const file_t *f, int mode);
int parse_app_data(const file_t *f, int mode);
int parse_discrete_do(const file_t *f, int mode);
int parse_do(uint16_t *fids, int mode) { int parse_do(uint16_t *fids, int mode) {
int len = 0; int len = 0;
file_t *ef; file_t *ef;
for (int i = 0; i < fids[0]; i++) { for (int i = 0; i < fids[0]; i++) {
if ((ef = search_by_fid(fids[i + 1], NULL, SPECIFY_EF))) { if ((ef = file_search_by_fid(fids[i + 1], NULL, SPECIFY_EF))) {
uint16_t data_len; uint16_t data_len;
if ((ef->type & FILE_DATA_FUNC) == FILE_DATA_FUNC) { if ((ef->type & FILE_DATA_FUNC) == FILE_DATA_FUNC) {
data_len = ((int (*)(const file_t *, int))(ef->data))((const file_t *) ef, mode); int (*file_data_func)(const file_t *, int) = NULL;
memcpy(&file_data_func, &ef->data, sizeof(file_data_func));
data_len = file_data_func(ef, mode);
} }
else { else {
data_len = file_get_size(ef); data_len = file_get_size(ef);
@@ -55,7 +71,7 @@ int parse_do(uint16_t *fids, int mode) {
int parse_trium(uint16_t fid, uint8_t num, size_t size) { int parse_trium(uint16_t fid, uint8_t num, size_t size) {
for (uint8_t i = 0; i < num; i++) { for (uint8_t i = 0; i < num; i++) {
file_t *ef; file_t *ef;
if ((ef = search_by_fid(fid + i, NULL, SPECIFY_EF)) && ef->data) { if ((ef = file_search_by_fid(fid + i, NULL, SPECIFY_EF)) && ef->data) {
uint16_t data_len = file_get_size(ef); uint16_t data_len = file_get_size(ef);
memcpy(res_APDU + res_APDU_size, file_get_data(ef), data_len); memcpy(res_APDU + res_APDU_size, file_get_data(ef), data_len);
res_APDU_size += data_len; res_APDU_size += data_len;
@@ -69,6 +85,7 @@ int parse_trium(uint16_t fid, uint8_t num, size_t size) {
} }
int parse_ch_data(const file_t *f, int mode) { int parse_ch_data(const file_t *f, int mode) {
(void) f;
uint16_t fids[] = { uint16_t fids[] = {
3, 3,
EF_CH_NAME, EF_LANG_PREF, EF_SEX, EF_CH_NAME, EF_LANG_PREF, EF_SEX,
@@ -85,9 +102,11 @@ int parse_ch_data(const file_t *f, int mode) {
} }
int parse_sec_tpl(const file_t *f, int mode) { int parse_sec_tpl(const file_t *f, int mode) {
(void) f;
(void) mode;
res_APDU[res_APDU_size++] = EF_SEC_TPL & 0xff; res_APDU[res_APDU_size++] = EF_SEC_TPL & 0xff;
res_APDU[res_APDU_size++] = 5; res_APDU[res_APDU_size++] = 5;
file_t *ef = search_by_fid(EF_SIG_COUNT, NULL, SPECIFY_ANY); file_t *ef = file_search_by_fid(EF_SIG_COUNT, NULL, SPECIFY_ANY);
if (ef && ef->data) { if (ef && ef->data) {
res_APDU[res_APDU_size++] = EF_SIG_COUNT & 0xff; res_APDU[res_APDU_size++] = EF_SIG_COUNT & 0xff;
res_APDU[res_APDU_size++] = 3; res_APDU[res_APDU_size++] = 3;
@@ -98,34 +117,44 @@ int parse_sec_tpl(const file_t *f, int mode) {
} }
int parse_ch_cert(const file_t *f, int mode) { int parse_ch_cert(const file_t *f, int mode) {
(void) f;
(void) mode;
return 0; return 0;
} }
int parse_fp(const file_t *f, int mode) { int parse_fp(const file_t *f, int mode) {
(void) f;
(void) mode;
res_APDU[res_APDU_size++] = EF_FP & 0xff; res_APDU[res_APDU_size++] = EF_FP & 0xff;
res_APDU[res_APDU_size++] = 60; res_APDU[res_APDU_size++] = 60;
return parse_trium(EF_FP_SIG, 3, 20) + 2; return parse_trium(EF_FP_SIG, 3, 20) + 2;
} }
int parse_cafp(const file_t *f, int mode) { int parse_cafp(const file_t *f, int mode) {
(void) f;
(void) mode;
res_APDU[res_APDU_size++] = EF_CA_FP & 0xff; res_APDU[res_APDU_size++] = EF_CA_FP & 0xff;
res_APDU[res_APDU_size++] = 60; res_APDU[res_APDU_size++] = 60;
return parse_trium(EF_FP_CA1, 3, 20) + 2; return parse_trium(EF_FP_CA1, 3, 20) + 2;
} }
int parse_ts(const file_t *f, int mode) { int parse_ts(const file_t *f, int mode) {
(void) f;
(void) mode;
res_APDU[res_APDU_size++] = EF_TS_ALL & 0xff; res_APDU[res_APDU_size++] = EF_TS_ALL & 0xff;
res_APDU[res_APDU_size++] = 12; res_APDU[res_APDU_size++] = 12;
return parse_trium(EF_TS_SIG, 3, 4) + 2; return parse_trium(EF_TS_SIG, 3, 4) + 2;
} }
int parse_keyinfo(const file_t *f, int mode) { int parse_keyinfo(const file_t *f, int mode) {
(void) f;
(void) mode;
int init_len = res_APDU_size; int init_len = res_APDU_size;
if (res_APDU_size > 0) { if (res_APDU_size > 0) {
res_APDU[res_APDU_size++] = EF_KEY_INFO & 0xff; res_APDU[res_APDU_size++] = EF_KEY_INFO & 0xff;
res_APDU[res_APDU_size++] = 6; res_APDU[res_APDU_size++] = 6;
} }
file_t *ef = search_by_fid(EF_PK_SIG, NULL, SPECIFY_ANY); file_t *ef = file_search_by_fid(EF_PK_SIG, NULL, SPECIFY_ANY);
res_APDU[res_APDU_size++] = 0x00; res_APDU[res_APDU_size++] = 0x00;
if (ef && ef->data) { if (ef && ef->data) {
res_APDU[res_APDU_size++] = 0x01; res_APDU[res_APDU_size++] = 0x01;
@@ -134,7 +163,7 @@ int parse_keyinfo(const file_t *f, int mode) {
res_APDU[res_APDU_size++] = 0x00; res_APDU[res_APDU_size++] = 0x00;
} }
ef = search_by_fid(EF_PK_DEC, NULL, SPECIFY_ANY); ef = file_search_by_fid(EF_PK_DEC, NULL, SPECIFY_ANY);
res_APDU[res_APDU_size++] = 0x01; res_APDU[res_APDU_size++] = 0x01;
if (ef && ef->data) { if (ef && ef->data) {
res_APDU[res_APDU_size++] = 0x01; res_APDU[res_APDU_size++] = 0x01;
@@ -143,7 +172,7 @@ int parse_keyinfo(const file_t *f, int mode) {
res_APDU[res_APDU_size++] = 0x00; res_APDU[res_APDU_size++] = 0x00;
} }
ef = search_by_fid(EF_PK_AUT, NULL, SPECIFY_ANY); ef = file_search_by_fid(EF_PK_AUT, NULL, SPECIFY_ANY);
res_APDU[res_APDU_size++] = 0x02; res_APDU[res_APDU_size++] = 0x02;
if (ef && ef->data) { if (ef && ef->data) {
res_APDU[res_APDU_size++] = 0x01; res_APDU[res_APDU_size++] = 0x01;
@@ -155,13 +184,15 @@ int parse_keyinfo(const file_t *f, int mode) {
} }
int parse_pw_status(const file_t *f, int mode) { int parse_pw_status(const file_t *f, int mode) {
(void) f;
(void) mode;
file_t *ef; file_t *ef;
int init_len = res_APDU_size; int init_len = res_APDU_size;
if (res_APDU_size > 0) { if (res_APDU_size > 0) {
res_APDU[res_APDU_size++] = EF_PW_STATUS & 0xff; res_APDU[res_APDU_size++] = EF_PW_STATUS & 0xff;
res_APDU[res_APDU_size++] = 7; res_APDU[res_APDU_size++] = 7;
} }
ef = search_by_fid(EF_PW_PRIV, NULL, SPECIFY_ANY); ef = file_search_by_fid(EF_PW_PRIV, NULL, SPECIFY_ANY);
if (ef && ef->data) { if (ef && ef->data) {
memcpy(res_APDU + res_APDU_size, file_get_data(ef), 7); memcpy(res_APDU + res_APDU_size, file_get_data(ef), 7);
res_APDU_size += 7; res_APDU_size += 7;
@@ -278,6 +309,7 @@ int parse_algo(const uint8_t *algo, uint16_t tag) {
} }
int parse_algoinfo(const file_t *f, int mode) { int parse_algoinfo(const file_t *f, int mode) {
(void) mode;
int datalen = 0; int datalen = 0;
if (f->fid == EF_ALGO_INFO) { if (f->fid == EF_ALGO_INFO) {
res_APDU[res_APDU_size++] = EF_ALGO_INFO & 0xff; res_APDU[res_APDU_size++] = EF_ALGO_INFO & 0xff;
@@ -337,7 +369,7 @@ int parse_algoinfo(const file_t *f, int mode) {
else if (f->fid == EF_ALGO_SIG || f->fid == EF_ALGO_DEC || f->fid == EF_ALGO_AUT) { else if (f->fid == EF_ALGO_SIG || f->fid == EF_ALGO_DEC || f->fid == EF_ALGO_AUT) {
uint16_t fid = 0x1000 | f->fid; uint16_t fid = 0x1000 | f->fid;
file_t *ef; file_t *ef;
if (!(ef = search_by_fid(fid, NULL, SPECIFY_EF)) || !ef->data) { if (!(ef = file_search_by_fid(fid, NULL, SPECIFY_EF)) || !ef->data) {
datalen += parse_algo(algorithm_attr_rsa2k, f->fid); datalen += parse_algo(algorithm_attr_rsa2k, f->fid);
} }
else { else {
@@ -356,6 +388,7 @@ int parse_algoinfo(const file_t *f, int mode) {
} }
int parse_app_data(const file_t *f, int mode) { int parse_app_data(const file_t *f, int mode) {
(void) f;
uint16_t fids[] = { uint16_t fids[] = {
6, 6,
EF_FULL_AID, EF_HIST_BYTES, EF_EXLEN_INFO, EF_GFM, EF_DISCRETE_DO, EF_KEY_INFO EF_FULL_AID, EF_HIST_BYTES, EF_EXLEN_INFO, EF_GFM, EF_DISCRETE_DO, EF_KEY_INFO
@@ -372,6 +405,7 @@ int parse_app_data(const file_t *f, int mode) {
} }
int parse_discrete_do(const file_t *f, int mode) { int parse_discrete_do(const file_t *f, int mode) {
(void) f;
uint16_t fids[] = { uint16_t fids[] = {
11, 11,
EF_EXT_CAP, EF_ALGO_SIG, EF_ALGO_DEC, EF_ALGO_AUT, EF_PW_STATUS, EF_FP, EF_CA_FP, EF_TS_ALL, EF_EXT_CAP, EF_ALGO_SIG, EF_ALGO_DEC, EF_ALGO_AUT, EF_PW_STATUS, EF_FP, EF_CA_FP, EF_TS_ALL,

View File

@@ -20,13 +20,6 @@
extern const uint8_t openpgp_aid[]; extern const uint8_t openpgp_aid[];
extern const uint8_t openpgp_aid_full[]; extern const uint8_t openpgp_aid_full[];
#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 }
extern int parse_ch_data(const file_t *f, int mode); extern int parse_ch_data(const file_t *f, int mode);
extern int parse_sec_tpl(const file_t *f, int mode); extern int parse_sec_tpl(const file_t *f, int mode);
extern int parse_ch_cert(const file_t *f, int mode); extern int parse_ch_cert(const file_t *f, int mode);
@@ -55,12 +48,12 @@ uint8_t historical_bytes[] = {
uint8_t extended_capabilities[] = { uint8_t extended_capabilities[] = {
10, 0, 10, 0,
0x77, /* 0x7f, /*
* No Secure Messaging supported * No Secure Messaging supported
* GET CHALLENGE supported * GET CHALLENGE supported
* Key import supported * Key import supported
* PW status byte can be put * PW status byte can be put
* No private_use_DO * private_use_DO
* Algorithm attrs are changable * Algorithm attrs are changable
* ENC/DEC with AES * ENC/DEC with AES
* KDF-DO available * KDF-DO available
@@ -68,7 +61,7 @@ uint8_t extended_capabilities[] = {
0, /* Secure Messaging Algorithm: N/A (TDES=0, AES=1) */ 0, /* Secure Messaging Algorithm: N/A (TDES=0, AES=1) */
0x00, 128, /* Max size of GET CHALLENGE */ 0x00, 128, /* Max size of GET CHALLENGE */
0x08, 0x00, /* max. length of cardholder certificate (2KiB) */ 0x08, 0x00, /* max. length of cardholder certificate (2KiB) */
0x00, 0xff, 0x08, 0x00, /* max. length of private DO (2KiB) */
0x00, 0x1 0x00, 0x1
}; };
@@ -114,7 +107,7 @@ file_t file_entries[] = {
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_RO }, .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_RO },
/* 10 */ { .fid = EF_CH_CERT, .parent = 0, .name = NULL, /* 10 */ { .fid = EF_CH_CERT, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FUNC, .data = (uint8_t *) parse_ch_cert, .type = FILE_TYPE_WORKING_EF | FILE_DATA_FUNC, .data = (uint8_t *) parse_ch_cert,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_RO }, .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP },
/* 11 */ { .fid = EF_EXLEN_INFO, .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF, /* 11 */ { .fid = EF_EXLEN_INFO, .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF,
.data = exlen_info, .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_RO }, .data = exlen_info, .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_RO },
/* 12 */ { .fid = EF_GFM, .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF, /* 12 */ { .fid = EF_GFM, .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF,
@@ -250,236 +243,263 @@ file_t file_entries[] = {
/* 56 */ { .fid = EF_CH_3, .parent = 0, .name = NULL, /* 56 */ { .fid = EF_CH_3, .parent = 0, .name = NULL,
.type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_NONE }, .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_NONE },
// ** PIV ** // /* 57 */ { .fid = EF_DEK_PW1, .parent = 0, .name = NULL,
/* 57 */ { .fid = EF_PIV_ADMIN_DATA, .parent = 0, .name = NULL,
.type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP },
/* 58 */ { .fid = EF_PIV_ATTESTATION, .parent = 0, .name = NULL,
.type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP },
/* 59 */ { .fid = EF_PIV_MSCMAP, .parent = 0, .name = NULL,
.type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP },
/* 60 */ { .fid = EF_PIV_MSROOTS1, .parent = 0, .name = NULL,
.type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP },
/* 61 */ { .fid = EF_PIV_MSROOTS2, .parent = 0, .name = NULL,
.type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP },
/* 62 */ { .fid = EF_PIV_MSROOTS3, .parent = 0, .name = NULL,
.type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP },
/* 63 */ { .fid = EF_PIV_MSROOTS4, .parent = 0, .name = NULL,
.type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP },
/* 64 */ { .fid = EF_PIV_MSROOTS5, .parent = 0, .name = NULL,
.type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP },
/* 65 */ { .fid = EF_PIV_KEY_AUTHENTICATION, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_WP },
/* 66 */ { .fid = EF_PIV_KEY_CARDMGM, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_WP },
/* 67 */ { .fid = EF_PIV_KEY_SIGNATURE, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_WP },
/* 68 */ { .fid = EF_PIV_KEY_KEYMGM, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_WP },
/* 69 */ { .fid = EF_PIV_KEY_CARDAUTH, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_WP },
/* 70 */ { .fid = EF_PIV_KEY_RETIRED1, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_WP },
/* 71 */ { .fid = EF_PIV_KEY_RETIRED2, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_WP },
/* 72 */ { .fid = EF_PIV_KEY_RETIRED3, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_WP },
/* 73 */ { .fid = EF_PIV_KEY_RETIRED4, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_WP },
/* 74 */ { .fid = EF_PIV_KEY_RETIRED5, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_WP },
/* 75 */ { .fid = EF_PIV_KEY_RETIRED6, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_WP },
/* 76 */ { .fid = EF_PIV_KEY_RETIRED7, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_WP },
/* 77 */ { .fid = EF_PIV_KEY_RETIRED8, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_WP },
/* 78 */ { .fid = EF_PIV_KEY_RETIRED9, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_WP },
/* 79 */ { .fid = EF_PIV_KEY_RETIRED10, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_WP },
/* 80 */ { .fid = EF_PIV_KEY_RETIRED11, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_WP },
/* 81 */ { .fid = EF_PIV_KEY_RETIRED12, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_WP },
/* 82 */ { .fid = EF_PIV_KEY_RETIRED12, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_WP },
/* 83 */ { .fid = EF_PIV_KEY_RETIRED13, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_WP },
/* 84 */ { .fid = EF_PIV_KEY_RETIRED14, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_WP },
/* 85 */ { .fid = EF_PIV_KEY_RETIRED15, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_WP },
/* 86 */ { .fid = EF_PIV_KEY_RETIRED16, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_WP },
/* 87 */ { .fid = EF_PIV_KEY_RETIRED17, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_WP },
/* 88 */ { .fid = EF_PIV_KEY_RETIRED18, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_WP },
/* 89 */ { .fid = EF_PIV_KEY_RETIRED19, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_WP },
/* 90 */ { .fid = EF_PIV_KEY_RETIRED20, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_WP },
/* 91 */ { .fid = EF_PIV_KEY_ATTESTATION, .parent = 0, .name = NULL,
.type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_WP },
/* 92 */ { .fid = EF_PIV_CAPABILITY, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP },
/* 93 */ { .fid = EF_PIV_CHUID, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP },
/* 94 */ { .fid = EF_PIV_AUTHENTICATION, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP },
/* 95 */ { .fid = EF_PIV_FINGERPRINTS, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP },
/* 96 */ { .fid = EF_PIV_SECURITY, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP },
/* 97 */ { .fid = EF_PIV_FACIAL, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP },
/* 98 */ { .fid = EF_PIV_PRINTED, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP },
/* 99 */ { .fid = EF_PIV_SIGNATURE, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP },
/* 100 */ { .fid = EF_PIV_KEY_MANAGEMENT, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP },
/* 101 */ { .fid = EF_PIV_CARD_AUTH, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP },
/* 102 */ { .fid = EF_PIV_DISCOVERY, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FUNC, .data = (uint8_t *) piv_parse_discovery,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP },
/* 103 */ { .fid = EF_PIV_KEY_HISTORY, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP },
/* 104 */ { .fid = EF_PIV_IRIS, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP },
/* 105 */ { .fid = EF_PIV_BITGT, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP },
/* 106 */ { .fid = EF_PIV_SM_SIGNER, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP },
/* 107 */ { .fid = EF_PIV_PC_REF_DATA, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP },
/* 108 */ { .fid = EF_PIV_RETIRED1, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP },
/* 109 */ { .fid = EF_PIV_RETIRED2, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP },
/* 110 */ { .fid = EF_PIV_RETIRED3, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP },
/* 111 */ { .fid = EF_PIV_RETIRED4, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP },
/* 112 */ { .fid = EF_PIV_RETIRED5, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP },
/* 113 */ { .fid = EF_PIV_RETIRED6, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP },
/* 114 */ { .fid = EF_PIV_RETIRED7, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP },
/* 115 */ { .fid = EF_PIV_RETIRED8, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP },
/* 116 */ { .fid = EF_PIV_RETIRED9, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP },
/* 117 */ { .fid = EF_PIV_RETIRED10, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP },
/* 118 */ { .fid = EF_PIV_RETIRED11, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP },
/* 119 */ { .fid = EF_PIV_RETIRED12, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP },
/* 120 */ { .fid = EF_PIV_RETIRED13, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP },
/* 121 */ { .fid = EF_PIV_RETIRED14, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP },
/* 122 */ { .fid = EF_PIV_RETIRED15, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP },
/* 123 */ { .fid = EF_PIV_RETIRED16, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP },
/* 124 */ { .fid = EF_PIV_RETIRED17, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP },
/* 125 */ { .fid = EF_PIV_RETIRED18, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP },
/* 126 */ { .fid = EF_PIV_RETIRED19, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP },
/* 127 */ { .fid = EF_PIV_RETIRED20, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP },
/* 128 */ { .fid = EF_PIV_PIN, .parent = 0, .name = NULL,
.type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_WP },
/* 129 */ { .fid = EF_PIV_PUK, .parent = 0, .name = NULL,
.type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_WP },
/* 130 */ { .fid = EF_META, .parent = 0, .name = NULL,
.type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_NONE }, .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_NONE },
/* 131 */ { .fid = EF_PW_RETRIES, .parent = 0, .name = NULL, /* 58 */ { .fid = EF_DEK_RC, .parent = 0, .name = NULL,
.type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_NONE },
/* 59 */ { .fid = EF_DEK_PW3, .parent = 0, .name = NULL,
.type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_NONE },
// ** PIV ** //
/* 60 */ { .fid = EF_PIV_ADMIN_DATA, .parent = 0, .name = NULL,
.type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP }, .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP },
/* 61 */ { .fid = EF_PIV_ATTESTATION, .parent = 0, .name = NULL,
.type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP },
/* 62 */ { .fid = EF_PIV_MSCMAP, .parent = 0, .name = NULL,
.type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP },
/* 63 */ { .fid = EF_PIV_MSROOTS1, .parent = 0, .name = NULL,
.type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP },
/* 64 */ { .fid = EF_PIV_MSROOTS2, .parent = 0, .name = NULL,
.type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP },
/* 65 */ { .fid = EF_PIV_MSROOTS3, .parent = 0, .name = NULL,
.type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP },
/* 66 */ { .fid = EF_PIV_MSROOTS4, .parent = 0, .name = NULL,
.type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP },
/* 67 */ { .fid = EF_PIV_MSROOTS5, .parent = 0, .name = NULL,
.type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP },
/* 68 */ { .fid = EF_PIV_KEY_AUTHENTICATION, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_WP },
/* 69 */ { .fid = EF_PIV_KEY_CARDMGM, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_WP },
/* 70 */ { .fid = EF_PIV_KEY_SIGNATURE, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_WP },
/* 71 */ { .fid = EF_PIV_KEY_KEYMGM, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_WP },
/* 72 */ { .fid = EF_PIV_KEY_CARDAUTH, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_WP },
/* 73 */ { .fid = EF_PIV_KEY_RETIRED1, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_WP },
/* 74 */ { .fid = EF_PIV_KEY_RETIRED2, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_WP },
/* 75 */ { .fid = EF_PIV_KEY_RETIRED3, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_WP },
/* 76 */ { .fid = EF_PIV_KEY_RETIRED4, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_WP },
/* 77 */ { .fid = EF_PIV_KEY_RETIRED5, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_WP },
/* 78 */ { .fid = EF_PIV_KEY_RETIRED6, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_WP },
/* 79 */ { .fid = EF_PIV_KEY_RETIRED7, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_WP },
/* 80 */ { .fid = EF_PIV_KEY_RETIRED8, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_WP },
/* 81 */ { .fid = EF_PIV_KEY_RETIRED9, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_WP },
/* 82 */ { .fid = EF_PIV_KEY_RETIRED10, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_WP },
/* 83 */ { .fid = EF_PIV_KEY_RETIRED11, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_WP },
/* 84 */ { .fid = EF_PIV_KEY_RETIRED12, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_WP },
/* 85 */ { .fid = EF_PIV_KEY_RETIRED13, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_WP },
/* 86 */ { .fid = EF_PIV_KEY_RETIRED14, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_WP },
/* 87 */ { .fid = EF_PIV_KEY_RETIRED15, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_WP },
/* 88 */ { .fid = EF_PIV_KEY_RETIRED16, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_WP },
/* 89 */ { .fid = EF_PIV_KEY_RETIRED17, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_WP },
/* 90 */ { .fid = EF_PIV_KEY_RETIRED18, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_WP },
/* 91 */ { .fid = EF_PIV_KEY_RETIRED19, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_WP },
/* 92 */ { .fid = EF_PIV_KEY_RETIRED20, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_WP },
/* 93 */ { .fid = EF_PIV_KEY_ATTESTATION, .parent = 0, .name = NULL,
.type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_WP },
/* 94 */ { .fid = EF_PIV_CAPABILITY, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP },
/* 95 */ { .fid = EF_PIV_CHUID, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP },
/* 96 */ { .fid = EF_PIV_AUTHENTICATION, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP },
/* 97 */ { .fid = EF_PIV_FINGERPRINTS, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP },
/* 98 */ { .fid = EF_PIV_SECURITY, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP },
/* 99 */ { .fid = EF_PIV_FACIAL, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP },
/* 100 */ { .fid = EF_PIV_PRINTED, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP },
/* 101 */ { .fid = EF_PIV_SIGNATURE, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP },
/* 102 */ { .fid = EF_PIV_KEY_MANAGEMENT, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP },
/* 103 */ { .fid = EF_PIV_CARD_AUTH, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP },
/* 104 */ { .fid = EF_PIV_DISCOVERY, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FUNC, .data = (uint8_t *) piv_parse_discovery,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP },
/* 105 */ { .fid = EF_PIV_KEY_HISTORY, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP },
/* 106 */ { .fid = EF_PIV_IRIS, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP },
/* 107 */ { .fid = EF_PIV_BITGT, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP },
/* 108 */ { .fid = EF_PIV_SM_SIGNER, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP },
/* 109 */ { .fid = EF_PIV_PC_REF_DATA, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP },
/* 110 */ { .fid = EF_PIV_RETIRED1, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP },
/* 111 */ { .fid = EF_PIV_RETIRED2, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP },
/* 112 */ { .fid = EF_PIV_RETIRED3, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP },
/* 113 */ { .fid = EF_PIV_RETIRED4, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP },
/* 114 */ { .fid = EF_PIV_RETIRED5, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP },
/* 115 */ { .fid = EF_PIV_RETIRED6, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP },
/* 116 */ { .fid = EF_PIV_RETIRED7, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP },
/* 117 */ { .fid = EF_PIV_RETIRED8, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP },
/* 118 */ { .fid = EF_PIV_RETIRED9, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP },
/* 119 */ { .fid = EF_PIV_RETIRED10, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP },
/* 120 */ { .fid = EF_PIV_RETIRED11, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP },
/* 121 */ { .fid = EF_PIV_RETIRED12, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP },
/* 122 */ { .fid = EF_PIV_RETIRED13, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP },
/* 123 */ { .fid = EF_PIV_RETIRED14, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP },
/* 124 */ { .fid = EF_PIV_RETIRED15, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP },
/* 125 */ { .fid = EF_PIV_RETIRED16, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP },
/* 126 */ { .fid = EF_PIV_RETIRED17, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP },
/* 127 */ { .fid = EF_PIV_RETIRED18, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP },
/* 128 */ { .fid = EF_PIV_RETIRED19, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP },
/* 129 */ { .fid = EF_PIV_RETIRED20, .parent = 0, .name = NULL,
.type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP },
/* 130 */ { .fid = EF_PIV_PIN, .parent = 0, .name = NULL,
.type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_WP },
/* 131 */ { .fid = EF_PIV_PUK, .parent = 0, .name = NULL,
.type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_WP },
/* 132 */ { .fid = EF_META, .parent = 0, .name = NULL,
.type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_NONE },
/* 133 */ { .fid = EF_PW_RETRIES, .parent = 0, .name = NULL,
.type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP },
/* 134 */ { .fid = EF_PRIV_DO_1, .parent = 0, .name = NULL,
.type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP },
/* 135 */ { .fid = EF_PRIV_DO_2, .parent = 0, .name = NULL,
.type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP },
/* 136 */ { .fid = EF_PRIV_DO_3, .parent = 0, .name = NULL,
.type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_WP },
/* 137 */ { .fid = EF_PRIV_DO_4, .parent = 0, .name = NULL,
.type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_WP },
/* 138 */ { .fid = EF_PW_RETRIES, .parent = 0, .name = NULL,
.type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP },
/* 139 */ { .fid = EF_PW_STATUS, .parent = 0, .name = NULL,
.type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP },
/* 140 */ { .fid = EF_DEK_PWPIV, .parent = 0, .name = NULL,
.type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL,
.ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_NONE },
/* 132 */ { .fid = 0x0000, .parent = 0, .name = openpgp_aid, .type = FILE_TYPE_WORKING_EF, /* 141 */ { .fid = 0x0000, .parent = 0, .name = openpgp_aid, .type = FILE_TYPE_WORKING_EF,
.data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_RO }, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_RO },
/* 133 */ { .fid = 0x0000, .parent = 0xff, .name = NULL, .type = FILE_TYPE_NOT_KNOWN, .data = NULL, /* 142 */ { .fid = 0x0000, .parent = 0xff, .name = NULL, .type = FILE_TYPE_NOT_KNOWN, .data = NULL,
.ef_structure = 0, .acl = ACL_NONE } //end .ef_structure = 0, .acl = ACL_NONE } //end
}; };

View File

@@ -36,6 +36,10 @@
#define EF_PB_DEC 0x10d5 #define EF_PB_DEC 0x10d5
#define EF_PB_AUT 0x10d6 #define EF_PB_AUT 0x10d6
#define EF_DEK 0x1099 #define EF_DEK 0x1099
#define EF_DEK_PW1 0x109a
#define EF_DEK_RC 0x109b
#define EF_DEK_PW3 0x109c
#define EF_DEK_PWPIV 0x109d
#define EF_CH_1 0x1f21 #define EF_CH_1 0x1f21
#define EF_CH_2 0x1f22 #define EF_CH_2 0x1f22
#define EF_CH_3 0x1f23 #define EF_CH_3 0x1f23
@@ -163,4 +167,11 @@
#define EF_DEV_CONF 0x1122 #define EF_DEV_CONF 0x1122
#define EF_PRIV_DO_1 0x0101
#define EF_PRIV_DO_2 0x0102
#define EF_PRIV_DO_3 0x0103
#define EF_PRIV_DO_4 0x0104
extern const file_t *file_openpgp;
#endif #endif

View File

@@ -15,23 +15,27 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
#include "pico_keys.h" #include <stdio.h>
#include "picokeys.h"
#include "serial.h"
#include "apdu.h" #include "apdu.h"
#include "version.h" #include "version.h"
#include "files.h" #include "files.h"
#include "asn1.h" #include "asn1.h"
#include "management.h" #include "management.h"
int man_process_apdu(); bool is_gpg = true;
int man_unload();
static int man_process_apdu(void);
static int man_unload(void);
const uint8_t man_aid[] = { const uint8_t man_aid[] = {
8, 8,
0xa0, 0x00, 0x00, 0x05, 0x27, 0x47, 0x11, 0x17 0xa0, 0x00, 0x00, 0x05, 0x27, 0x47, 0x11, 0x17
}; };
extern void init_piv(); extern void init_piv(void);
int man_select(app_t *a, uint8_t force) { static int man_select(app_t *a, uint8_t force) {
(void) force; (void) force;
a->process_apdu = man_process_apdu; a->process_apdu = man_process_apdu;
a->unload = man_unload; a->unload = man_unload;
@@ -39,19 +43,20 @@ int man_select(app_t *a, uint8_t force) {
res_APDU_size = strlen((char *) res_APDU); res_APDU_size = strlen((char *) res_APDU);
apdu.ne = res_APDU_size; apdu.ne = res_APDU_size;
init_piv(); init_piv();
return PICOKEY_OK; is_gpg = false;
return PICOKEYS_OK;
} }
INITIALIZER( man_ctor ) { INITIALIZER( man_ctor ) {
register_app(man_select, man_aid); register_app(man_select, man_aid);
} }
int man_unload() { static int man_unload(void) {
return PICOKEY_OK; return PICOKEYS_OK;
} }
bool cap_supported(uint16_t cap) { bool cap_supported(uint16_t cap) {
file_t *ef = search_dynamic_file(EF_DEV_CONF); file_t *ef = file_search(EF_DEV_CONF);
if (file_has_data(ef)) { if (file_has_data(ef)) {
uint16_t tag = 0x0; uint16_t tag = 0x0;
uint8_t *tag_data = NULL, *p = NULL; uint8_t *tag_data = NULL, *p = NULL;
@@ -71,8 +76,8 @@ bool cap_supported(uint16_t cap) {
return true; return true;
} }
int man_get_config() { int man_get_config(void) {
file_t *ef = search_dynamic_file(EF_DEV_CONF); file_t *ef = file_search(EF_DEV_CONF);
res_APDU_size = 0; res_APDU_size = 0;
res_APDU[res_APDU_size++] = 0; // Overall length. Filled later res_APDU[res_APDU_size++] = 0; // Overall length. Filled later
res_APDU[res_APDU_size++] = TAG_USB_SUPPORTED; res_APDU[res_APDU_size++] = TAG_USB_SUPPORTED;
@@ -115,18 +120,18 @@ int man_get_config() {
return 0; return 0;
} }
int cmd_read_config() { static int cmd_read_config(void) {
man_get_config(); man_get_config();
return SW_OK(); return SW_OK();
} }
int cmd_write_config() { static int cmd_write_config(void) {
if (apdu.data[0] != apdu.nc - 1) { if (apdu.data[0] != apdu.nc - 1) {
return SW_WRONG_DATA(); return SW_WRONG_DATA();
} }
file_t *ef = file_new(EF_DEV_CONF); file_t *ef = file_new(EF_DEV_CONF);
file_put_data(ef, apdu.data + 1, apdu.nc - 1); file_put_data(ef, apdu.data + 1, apdu.nc - 1);
low_flash_available(); flash_commit();
return SW_OK(); return SW_OK();
} }
@@ -139,7 +144,7 @@ static const cmd_t cmds[] = {
{ 0x00, 0x0 } { 0x00, 0x0 }
}; };
int man_process_apdu() { static int man_process_apdu(void) {
if (CLA(apdu) != 0x00) { if (CLA(apdu) != 0x00) {
return SW_CLA_NOT_SUPPORTED(); return SW_CLA_NOT_SUPPORTED();
} }

View File

@@ -50,6 +50,6 @@
#define FLAG_EJECT 0x80 #define FLAG_EJECT 0x80
extern bool cap_supported(uint16_t cap); extern bool cap_supported(uint16_t cap);
extern int man_get_config(); extern int man_get_config(void);
#endif //_MANAGEMENT_H #endif //_MANAGEMENT_H

View File

@@ -15,13 +15,13 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
#include <stdio.h>
#ifdef ESP_PLATFORM #ifdef ESP_PLATFORM
#include "esp_compat.h" #include "esp_compat.h"
#define MBEDTLS_ALLOW_PRIVATE_ACCESS #define MBEDTLS_ALLOW_PRIVATE_ACCESS
#else
#include "common.h"
#endif #endif
#include "openpgp.h" #include "openpgp.h"
#include "serial.h"
#include "version.h" #include "version.h"
#include "random.h" #include "random.h"
#include "eac.h" #include "eac.h"
@@ -41,7 +41,7 @@ bool has_rc = false;
uint8_t session_pw1[32]; uint8_t session_pw1[32];
uint8_t session_rc[32]; uint8_t session_rc[32];
uint8_t session_pw3[32]; uint8_t session_pw3[32];
uint8_t dek[IV_SIZE + 32]; uint8_t dek[DEK_SIZE];
uint16_t algo_dec = EF_ALGO_PRIV2, algo_aut = EF_ALGO_PRIV3, pk_dec = EF_PK_DEC, pk_aut = EF_PK_AUT; uint16_t algo_dec = EF_ALGO_PRIV2, algo_aut = EF_ALGO_PRIV3, pk_dec = EF_PK_DEC, pk_aut = EF_PK_AUT;
uint8_t openpgp_aid[] = { uint8_t openpgp_aid[] = {
@@ -61,20 +61,22 @@ char atr_openpgp[] = {
0x60, 0x00, 0x90, 0x00, 0x1c 0x60, 0x00, 0x90, 0x00, 0x1c
}; };
int openpgp_process_apdu(); int openpgp_process_apdu(void);
extern uint32_t board_button_read(void); extern uint32_t board_button_read(void);
bool wait_button_pressed_fid(uint16_t fid) { bool wait_button_pressed_fid(uint16_t fid) {
uint32_t val = EV_PRESS_BUTTON; uint32_t val = EV_PRESS_BUTTON;
#ifndef ENABLE_EMULATION #ifndef ENABLE_EMULATION
file_t *ef = search_by_fid(fid, NULL, SPECIFY_ANY); file_t *ef = file_search_by_fid(fid, NULL, SPECIFY_ANY);
if (ef && ef->data && file_get_data(ef)[0] > 0) { if (ef && ef->data && file_get_data(ef)[0] > 0) {
queue_try_add(&card_to_usb_q, &val); queue_try_add(&card_to_usb_q, &val);
do { do {
queue_remove_blocking(&usb_to_card_q, &val); queue_remove_blocking(&usb_to_card_q, &val);
}while (val != EV_BUTTON_PRESSED && val != EV_BUTTON_TIMEOUT); }while (val != EV_BUTTON_PRESSED && val != EV_BUTTON_TIMEOUT);
} }
#else
(void) fid;
#endif #endif
return val == EV_BUTTON_TIMEOUT; return val == EV_BUTTON_TIMEOUT;
} }
@@ -97,171 +99,258 @@ void select_file(file_t *pe) {
} }
} }
void scan_files_openpgp() { void scan_files_openpgp(void) {
scan_flash(); file_scan_flash();
file_t *ef; file_t *ef;
if ((ef = search_by_fid(EF_FULL_AID, NULL, SPECIFY_ANY))) { if ((ef = file_search_by_fid(EF_FULL_AID, NULL, SPECIFY_ANY))) {
ef->data = openpgp_aid_full; ef->data = openpgp_aid_full;
memcpy(ef->data + 12, pico_serial.id, 4); memcpy(ef->data + 12, pico_serial.id, 4);
} }
bool reset_dek = false; bool reset_dek = false;
if ((ef = search_by_fid(EF_DEK, NULL, SPECIFY_ANY))) { bool bootstrap_legacy = false;
if (!ef->data) { file_t *ef_dek = file_search_by_fid(EF_DEK, NULL, SPECIFY_ANY), *ef_dek_pw1 = file_search_by_fid(EF_DEK_PW1, NULL, SPECIFY_ANY), *ef_dek_rc = file_search_by_fid(EF_DEK_RC, NULL, SPECIFY_ANY), *ef_dek_pw3 = file_search_by_fid(EF_DEK_PW3, NULL, SPECIFY_ANY);
printf("DEK is empty\r\n"); if (!file_has_data(ef_dek_pw1) && !file_has_data(ef_dek_rc) && !file_has_data(ef_dek_pw3) && !file_has_data(ef_dek)) {
const uint8_t def1[6] = { 0x31, 0x32, 0x33, 0x34, 0x35, 0x36 }; printf("DEK are empty\r\n");
const uint8_t def3[8] = { 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38 }; const uint8_t *random_dek = random_bytes_get(DEK_SIZE);
const uint8_t def1[6] = {0x31, 0x32, 0x33, 0x34, 0x35, 0x36};
const uint8_t def3[8] = { 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38 };
#ifdef OPENPGP_TEST_INIT_LEGACY_PIN
/* Test hook: bootstrap legacy PIN+DEK format to validate runtime migration paths. */
uint8_t def[IV_SIZE + 32 + 32 + 32]; uint8_t def[IV_SIZE + 32 + 32 + 32];
const uint8_t *dek = random_bytes_get(IV_SIZE + 32); memcpy(def, random_dek, IV_SIZE + 32);
memcpy(def, dek, IV_SIZE + 32); memcpy(def + IV_SIZE + 32, random_dek + IV_SIZE, 32);
memcpy(def + IV_SIZE + 32, dek + IV_SIZE, 32); memcpy(def + IV_SIZE + 32 + 32, random_dek + IV_SIZE, 32);
memcpy(def + IV_SIZE + 32 + 32, dek + IV_SIZE, 32); hash_multi(def1, sizeof(def1), session_pw1);
hash_multi(def1, sizeof(def1), session_pw1); aes_encrypt_cfb_256(session_pw1, def, def + IV_SIZE, 32);
aes_encrypt_cfb_256(session_pw1, def, def + IV_SIZE, 32); memset(session_pw1, 0, sizeof(session_pw1));
memset(session_pw1, 0, sizeof(session_pw1));
hash_multi(def3, sizeof(def3), session_pw3); hash_multi(def3, sizeof(def3), session_pw3);
aes_encrypt_cfb_256(session_pw3, def, def + IV_SIZE + 32, 32); aes_encrypt_cfb_256(session_pw3, def, def + IV_SIZE + 32, 32);
aes_encrypt_cfb_256(session_pw3, def, def + IV_SIZE + 32 + 32, 32); aes_encrypt_cfb_256(session_pw3, def, def + IV_SIZE + 32 + 32, 32);
memset(session_pw3, 0, sizeof(session_pw3)); memset(session_pw3, 0, sizeof(session_pw3));
file_put_data(ef, def, sizeof(def)); file_put_data(ef_dek, def, sizeof(def));
reset_dek = true; bootstrap_legacy = true;
} #else
uint8_t def[DEK_FILE_SIZE];
def[0] = 0x3; // Format
pin_derive_session(def1, sizeof(def1), session_pw1);
encrypt_with_aad(session_pw1, random_dek, DEK_SIZE, PIN_KDF_DEFAULT_VERSION, def + 1);
mbedtls_platform_zeroize(session_pw1, sizeof(session_pw1));
file_put_data(ef_dek_pw1, def, sizeof(def));
pin_derive_session(def3, sizeof(def3), session_pw3);
encrypt_with_aad(session_pw3, random_dek, DEK_SIZE, PIN_KDF_DEFAULT_VERSION, def + 1);
mbedtls_platform_zeroize(session_pw3, sizeof(session_pw3));
file_put_data(ef_dek_rc, def, sizeof(def));
file_put_data(ef_dek_pw3, def, sizeof(def));
#endif
reset_dek = true;
} }
if ((ef = search_by_fid(EF_PW1, NULL, SPECIFY_ANY))) { if ((ef = file_search_by_fid(EF_PW1, NULL, SPECIFY_ANY))) {
if (!ef->data || reset_dek) { if (!ef->data || reset_dek) {
printf("PW1 is empty. Initializing with default password\r\n"); printf("PW1 is empty. Initializing with default password\r\n");
const uint8_t def[6] = { 0x31, 0x32, 0x33, 0x34, 0x35, 0x36 }; const uint8_t def[6] = { 0x31, 0x32, 0x33, 0x34, 0x35, 0x36 };
uint8_t dhash[33]; uint8_t dhash[34];
dhash[0] = sizeof(def); if (bootstrap_legacy) {
double_hash_pin(def, sizeof(def), dhash + 1); dhash[0] = sizeof(def);
file_put_data(ef, dhash, sizeof(dhash)); double_hash_pin(def, sizeof(def), dhash + 1);
file_put_data(ef, dhash, 33);
}
else {
dhash[0] = sizeof(def);
dhash[1] = 0x1; // Format
pin_derive_verifier(def, sizeof(def), dhash + 2);
file_put_data(ef, dhash, sizeof(dhash));
}
} }
} }
if ((ef = search_by_fid(EF_RC, NULL, SPECIFY_ANY))) { if ((ef = file_search_by_fid(EF_RC, NULL, SPECIFY_ANY))) {
if (!ef->data || reset_dek) { if (!ef->data || reset_dek) {
printf("RC is empty. Initializing with default password\r\n"); printf("RC is empty. Initializing with default password\r\n");
const uint8_t def[8] = { 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38 }; const uint8_t def[8] = { 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38 };
uint8_t dhash[33]; uint8_t dhash[34];
dhash[0] = sizeof(def); if (bootstrap_legacy) {
double_hash_pin(def, sizeof(def), dhash + 1); dhash[0] = sizeof(def);
file_put_data(ef, dhash, sizeof(dhash)); double_hash_pin(def, sizeof(def), dhash + 1);
file_put_data(ef, dhash, 33);
}
else {
dhash[0] = sizeof(def);
dhash[1] = 0x1; // Format
pin_derive_verifier(def, sizeof(def), dhash + 2);
file_put_data(ef, dhash, sizeof(dhash));
}
} }
} }
if ((ef = search_by_fid(EF_PW3, NULL, SPECIFY_ANY))) { if ((ef = file_search_by_fid(EF_PW3, NULL, SPECIFY_ANY))) {
if (!ef->data || reset_dek) { if (!ef->data || reset_dek) {
printf("PW3 is empty. Initializing with default password\r\n"); printf("PW3 is empty. Initializing with default password\r\n");
const uint8_t def[8] = { 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38 }; const uint8_t def[8] = { 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38 };
uint8_t dhash[33]; uint8_t dhash[34];
dhash[0] = sizeof(def); if (bootstrap_legacy) {
double_hash_pin(def, sizeof(def), dhash + 1); dhash[0] = sizeof(def);
file_put_data(ef, dhash, sizeof(dhash)); double_hash_pin(def, sizeof(def), dhash + 1);
file_put_data(ef, dhash, 33);
}
else {
dhash[0] = sizeof(def);
dhash[1] = 0x1; // Format
pin_derive_verifier(def, sizeof(def), dhash + 2);
file_put_data(ef, dhash, sizeof(dhash));
}
} }
} }
if ((ef = search_by_fid(EF_SIG_COUNT, NULL, SPECIFY_ANY))) { if ((ef = file_search_by_fid(EF_SIG_COUNT, NULL, SPECIFY_ANY))) {
if (!ef->data) { if (!ef->data) {
printf("SigCount is empty. Initializing to zero\r\n"); printf("SigCount is empty. Initializing to zero\r\n");
const uint8_t def[3] = { 0 }; const uint8_t def[3] = { 0 };
file_put_data(ef, def, sizeof(def)); file_put_data(ef, def, sizeof(def));
} }
} }
if ((ef = search_by_fid(EF_PW_PRIV, NULL, SPECIFY_ANY))) { if ((ef = file_search_by_fid(EF_PW_PRIV, NULL, SPECIFY_ANY))) {
if (!ef->data) { if (!ef->data) {
printf("PW status is empty. Initializing to default\r\n"); printf("PW status is empty. Initializing to default\r\n");
const uint8_t def[] = { 0x1, 127, 127, 127, 3, 3, 3 }; const uint8_t def[] = { 0x1, 127, 127, 127, 3, 3, 3 };
file_put_data(ef, def, sizeof(def)); file_put_data(ef, def, sizeof(def));
} }
} }
if ((ef = search_by_fid(EF_UIF_SIG, NULL, SPECIFY_ANY))) { if ((ef = file_search_by_fid(EF_UIF_SIG, NULL, SPECIFY_ANY))) {
if (!ef->data) { if (!ef->data) {
printf("UIF SIG is empty. Initializing to default\r\n"); printf("UIF SIG is empty. Initializing to default\r\n");
const uint8_t def[] = { 0x0, 0x20 }; const uint8_t def[] = { 0x0, 0x20 };
file_put_data(ef, def, sizeof(def)); file_put_data(ef, def, sizeof(def));
} }
} }
if ((ef = search_by_fid(EF_UIF_DEC, NULL, SPECIFY_ANY))) { if ((ef = file_search_by_fid(EF_UIF_DEC, NULL, SPECIFY_ANY))) {
if (!ef->data) { if (!ef->data) {
printf("UIF DEC is empty. Initializing to default\r\n"); printf("UIF DEC is empty. Initializing to default\r\n");
const uint8_t def[] = { 0x0, 0x20 }; const uint8_t def[] = { 0x0, 0x20 };
file_put_data(ef, def, sizeof(def)); file_put_data(ef, def, sizeof(def));
} }
} }
if ((ef = search_by_fid(EF_UIF_AUT, NULL, SPECIFY_ANY))) { if ((ef = file_search_by_fid(EF_UIF_AUT, NULL, SPECIFY_ANY))) {
if (!ef->data) { if (!ef->data) {
printf("UIF AUT is empty. Initializing to default\r\n"); printf("UIF AUT is empty. Initializing to default\r\n");
const uint8_t def[] = { 0x0, 0x20 }; const uint8_t def[] = { 0x0, 0x20 };
file_put_data(ef, def, sizeof(def)); file_put_data(ef, def, sizeof(def));
} }
} }
if ((ef = search_by_fid(EF_KDF, NULL, SPECIFY_ANY))) { if ((ef = file_search_by_fid(EF_KDF, NULL, SPECIFY_ANY))) {
if (!ef->data) { if (!ef->data) {
printf("KDF is empty. Initializing to default\r\n"); printf("KDF is empty. Initializing to default\r\n");
const uint8_t def[] = { 0x81, 0x1, 0x0 }; const uint8_t def[] = { 0x81, 0x1, 0x0 };
file_put_data(ef, def, sizeof(def)); file_put_data(ef, def, sizeof(def));
} }
} }
if ((ef = search_by_fid(EF_SEX, NULL, SPECIFY_ANY))) { if ((ef = file_search_by_fid(EF_SEX, NULL, SPECIFY_ANY))) {
if (!ef->data) { if (!ef->data) {
printf("Sex is empty. Initializing to default\r\n"); printf("Sex is empty. Initializing to default\r\n");
const uint8_t def[] = { 0x30 }; const uint8_t def[] = { 0x30 };
file_put_data(ef, def, sizeof(def)); file_put_data(ef, def, sizeof(def));
} }
} }
if ((ef = search_by_fid(EF_PW_RETRIES, NULL, SPECIFY_ANY))) { if ((ef = file_search_by_fid(EF_PW_RETRIES, NULL, SPECIFY_ANY))) {
if (!ef->data) { if (!ef->data) {
printf("PW retries is empty. Initializing to default\r\n"); printf("PW retries is empty. Initializing to default\r\n");
const uint8_t def[] = { 0x1, 3, 3, 3 }; const uint8_t def[] = { 0x1, 3, 3, 3 };
file_put_data(ef, def, sizeof(def)); file_put_data(ef, def, sizeof(def));
} }
} }
low_flash_available(); flash_commit();
}
static void release_dek(void) {
memset(dek, 0, sizeof(dek));
} }
extern bool has_pwpiv; extern bool has_pwpiv;
extern uint8_t session_pwpiv[32]; extern uint8_t session_pwpiv[32];
int load_dek() { int load_dek(void) {
if (!has_pw1 && !has_pw2 && !has_pw3 && !has_pwpiv) { if (!has_pw1 && !has_pw2 && !has_pw3 && !has_pwpiv) {
return PICOKEY_NO_LOGIN; return PICOKEYS_NO_LOGIN;
} }
file_t *tf = search_by_fid(EF_DEK, NULL, SPECIFY_EF); int r = PICOKEYS_OK;
if (!tf) {
return PICOKEY_ERR_FILE_NOT_FOUND;
}
int r = PICOKEY_OK;
if (has_pw1 || has_pw2) { if (has_pw1 || has_pw2) {
memcpy(dek, file_get_data(tf), IV_SIZE + 32); file_t *ef_dek_pw1 = file_search(EF_DEK_PW1);
r = aes_decrypt_cfb_256(session_pw1, dek, dek + IV_SIZE, 32); if (file_has_data(ef_dek_pw1)) {
} uint8_t *ef_data = file_get_data(ef_dek_pw1);
else if (has_pw3) { if (ef_data[0] == 0x3) { // Format
memcpy(dek, file_get_data(tf), IV_SIZE); r = decrypt_with_aad(session_pw1, ef_data + 1, DEK_AAD_SIZE, PIN_KDF_DEFAULT_VERSION, dek);
memcpy(dek + IV_SIZE, file_get_data(tf) + IV_SIZE + 32 + 32, 32); }
r = aes_decrypt_cfb_256(session_pw3, dek, dek + IV_SIZE, 32); else {
} return PICOKEYS_ERR_NULL_PARAM;
else if (has_pwpiv) { }
memcpy(dek, file_get_data(tf), IV_SIZE); }
memcpy(dek + IV_SIZE, file_get_data(tf) + IV_SIZE + 32 + 32 + 32, 32); else {
r = aes_decrypt_cfb_256(session_pwpiv, dek, dek + IV_SIZE, 32); file_t *tf = file_search_by_fid(EF_DEK, NULL, SPECIFY_EF);
} if (!tf) {
if (r != 0) { return PICOKEYS_ERR_FILE_NOT_FOUND;
return PICOKEY_EXEC_ERROR; }
}
if (otp_key_1) { memcpy(dek, file_get_data(tf), IV_SIZE + 32);
for (int i = 0; i < 32; i++) { r = aes_decrypt_cfb_256(session_pw1, dek, dek + IV_SIZE, 32);
dek[IV_SIZE + i] ^= otp_key_1[i];
} }
} }
return PICOKEY_OK; else if (has_pw3) {
} file_t *ef_dek_pw3 = file_search(EF_DEK_PW3);
if (file_has_data(ef_dek_pw3)) {
uint8_t *ef_data = file_get_data(ef_dek_pw3);
if (ef_data[0] == 0x3) { // Format
r = decrypt_with_aad(session_pw3, ef_data + 1, DEK_AAD_SIZE, PIN_KDF_DEFAULT_VERSION, dek);
}
else {
return PICOKEYS_ERR_NULL_PARAM;
}
}
else {
file_t *tf = file_search_by_fid(EF_DEK, NULL, SPECIFY_EF);
if (!tf) {
return PICOKEYS_ERR_FILE_NOT_FOUND;
}
void release_dek() { memcpy(dek, file_get_data(tf), IV_SIZE);
memset(dek, 0, sizeof(dek)); memcpy(dek + IV_SIZE, file_get_data(tf) + IV_SIZE + 32 + 32, 32);
r = aes_decrypt_cfb_256(session_pw3, dek, dek + IV_SIZE, 32);
}
}
else if (has_pwpiv) {
file_t *ef_dek_pwpiv = file_search(EF_DEK_PWPIV);
if (file_has_data(ef_dek_pwpiv)) {
uint8_t *ef_data = file_get_data(ef_dek_pwpiv);
if (ef_data[0] == 0x3) { // Format
r = decrypt_with_aad(session_pwpiv, ef_data + 1, DEK_AAD_SIZE, PIN_KDF_DEFAULT_VERSION, dek);
}
else {
return PICOKEYS_ERR_NULL_PARAM;
}
}
else {
file_t *tf = file_search_by_fid(EF_DEK, NULL, SPECIFY_EF);
if (!tf) {
return PICOKEYS_ERR_FILE_NOT_FOUND;
}
memcpy(dek, file_get_data(tf), IV_SIZE);
memcpy(dek + IV_SIZE, file_get_data(tf) + IV_SIZE + 32 + 32 + 32, 32);
r = aes_decrypt_cfb_256(session_pwpiv, dek, dek + IV_SIZE, 32);
}
}
if (r != 0) {
release_dek();
return PICOKEYS_EXEC_ERROR;
}
return PICOKEYS_OK;
} }
int dek_encrypt(uint8_t *data, size_t len) { int dek_encrypt(uint8_t *data, size_t len) {
int r; int r;
if ((r = load_dek()) != PICOKEY_OK) { if ((r = load_dek()) != PICOKEYS_OK) {
return r; return r;
} }
r = aes_encrypt_cfb_256(dek + IV_SIZE, dek, data, len); r = aes_encrypt_cfb_256(dek + IV_SIZE, dek, data, len);
@@ -271,7 +360,7 @@ int dek_encrypt(uint8_t *data, size_t len) {
int dek_decrypt(uint8_t *data, size_t len) { int dek_decrypt(uint8_t *data, size_t len) {
int r; int r;
if ((r = load_dek()) != PICOKEY_OK) { if ((r = load_dek()) != PICOKEYS_OK) {
return r; return r;
} }
r = aes_decrypt_cfb_256(dek + IV_SIZE, dek, data, len); r = aes_decrypt_cfb_256(dek + IV_SIZE, dek, data, len);
@@ -279,9 +368,9 @@ int dek_decrypt(uint8_t *data, size_t len) {
return r; return r;
} }
void init_openpgp() { static void init_openpgp(void) {
isUserAuthenticated = false; isUserAuthenticated = false;
has_pw1 = has_pw3 = false; has_pw1 = has_pw2 = has_pw3 = false;
algo_dec = EF_ALGO_PRIV2; algo_dec = EF_ALGO_PRIV2;
algo_aut = EF_ALGO_PRIV3; algo_aut = EF_ALGO_PRIV3;
pk_dec = EF_PK_DEC; pk_dec = EF_PK_DEC;
@@ -290,18 +379,18 @@ void init_openpgp() {
//cmd_select(); //cmd_select();
} }
int openpgp_unload() { static int openpgp_unload(void) {
isUserAuthenticated = false; isUserAuthenticated = false;
has_pw1 = has_pw3 = false; has_pw1 = has_pw2 = has_pw3 = false;
algo_dec = EF_ALGO_PRIV2; algo_dec = EF_ALGO_PRIV2;
algo_aut = EF_ALGO_PRIV3; algo_aut = EF_ALGO_PRIV3;
pk_dec = EF_PK_DEC; pk_dec = EF_PK_DEC;
pk_aut = EF_PK_AUT; pk_aut = EF_PK_AUT;
return PICOKEY_OK; return PICOKEYS_OK;
} }
extern char __StackLimit; extern char __StackLimit;
int heapLeft() { static int heapLeft(void) {
#if !defined(ENABLE_EMULATION) && !defined(ESP_PLATFORM) #if !defined(ENABLE_EMULATION) && !defined(ESP_PLATFORM)
char *p = malloc(256); // try to avoid undue fragmentation char *p = malloc(256); // try to avoid undue fragmentation
int left = &__StackLimit - p; int left = &__StackLimit - p;
@@ -312,12 +401,12 @@ int heapLeft() {
return left; return left;
} }
int openpgp_select_aid(app_t *a, uint8_t force) { static int openpgp_select_aid(app_t *a, uint8_t force) {
(void) force; (void) force;
a->process_apdu = openpgp_process_apdu; a->process_apdu = openpgp_process_apdu;
a->unload = openpgp_unload; a->unload = openpgp_unload;
init_openpgp(); init_openpgp();
process_fci(file_openpgp, 1); file_process_fci(file_openpgp, 1);
memcpy(res_APDU + res_APDU_size, "\x64\x06\x53\x04", 4); memcpy(res_APDU + res_APDU_size, "\x64\x06\x53\x04", 4);
res_APDU_size += 4; res_APDU_size += 4;
int heap_left = heapLeft(); int heap_left = heapLeft();
@@ -327,94 +416,170 @@ int openpgp_select_aid(app_t *a, uint8_t force) {
res_APDU[res_APDU_size++] = ((heap_left >> 0) & 0xff); res_APDU[res_APDU_size++] = ((heap_left >> 0) & 0xff);
res_APDU[1] += 8; res_APDU[1] += 8;
apdu.ne = res_APDU_size; apdu.ne = res_APDU_size;
return PICOKEY_OK; return PICOKEYS_OK;
} }
INITIALIZER( openpgp_ctor ) { INITIALIZER( openpgp_ctor ) {
ccid_atr = (uint8_t *) atr_openpgp;
register_app(openpgp_select_aid, openpgp_aid); register_app(openpgp_select_aid, openpgp_aid);
} }
int set_atr(void) {
ccid_atr = (uint8_t *) atr_openpgp;
return 0;
}
int pin_reset_retries(const file_t *pin, bool force) { int pin_reset_retries(const file_t *pin, bool force) {
if (!pin) { if (!pin) {
return PICOKEY_ERR_NULL_PARAM; return PICOKEYS_ERR_NULL_PARAM;
} }
file_t *pw_status = search_by_fid(EF_PW_PRIV, NULL, SPECIFY_EF); file_t *pw_status = file_search_by_fid(EF_PW_PRIV, NULL, SPECIFY_EF);
file_t *pw_retries = search_by_fid(EF_PW_RETRIES, NULL, SPECIFY_EF); file_t *pw_retries = file_search_by_fid(EF_PW_RETRIES, NULL, SPECIFY_EF);
if (!pw_status || !pw_retries) { if (!pw_status || !pw_retries) {
return PICOKEY_ERR_FILE_NOT_FOUND; return PICOKEYS_ERR_FILE_NOT_FOUND;
} }
if (3 + (pin->fid & 0xf) >= file_get_size(pw_status) || (pin->fid & 0xf) >= file_get_size(pw_retries)) { if (3 + (pin->fid & 0xf) >= file_get_size(pw_status) || (pin->fid & 0xf) >= file_get_size(pw_retries)) {
return PICOKEY_ERR_MEMORY_FATAL; return PICOKEYS_ERR_MEMORY_FATAL;
} }
uint8_t p[64]; uint8_t p[64];
memcpy(p, file_get_data(pw_status), file_get_size(pw_status)); memcpy(p, file_get_data(pw_status), file_get_size(pw_status));
uint8_t retries = p[3 + (pin->fid & 0xf)]; uint8_t retries = p[3 + (pin->fid & 0xf)];
if (retries == 0 && force == false) { //blocked if (retries == 0 && force == false) { //blocked
return PICOKEY_ERR_BLOCKED; return PICOKEYS_ERR_BLOCKED;
} }
uint8_t max_retries = file_get_data(pw_retries)[(pin->fid & 0xf)]; uint8_t max_retries = file_get_data(pw_retries)[(pin->fid & 0xf)];
p[3 + (pin->fid & 0xf)] = max_retries; p[3 + (pin->fid & 0xf)] = max_retries;
int r = file_put_data(pw_status, p, file_get_size(pw_status)); int r = file_put_data(pw_status, p, file_get_size(pw_status));
low_flash_available(); flash_commit();
return r; return r;
} }
int pin_wrong_retry(const file_t *pin) { static int pin_wrong_retry(const file_t *pin) {
if (!pin) { if (!pin) {
return PICOKEY_ERR_NULL_PARAM; return PICOKEYS_ERR_NULL_PARAM;
} }
file_t *pw_status = search_by_fid(EF_PW_PRIV, NULL, SPECIFY_EF); file_t *pw_status = file_search_by_fid(EF_PW_PRIV, NULL, SPECIFY_EF);
if (!pw_status) { if (!pw_status) {
return PICOKEY_ERR_FILE_NOT_FOUND; return PICOKEYS_ERR_FILE_NOT_FOUND;
} }
uint8_t p[64]; uint8_t p[64];
memcpy(p, file_get_data(pw_status), file_get_size(pw_status)); memcpy(p, file_get_data(pw_status), file_get_size(pw_status));
if (p[3 + (pin->fid & 0xf)] > 0) { if (p[3 + (pin->fid & 0xf)] > 0) {
p[3 + (pin->fid & 0xf)] -= 1; p[3 + (pin->fid & 0xf)] -= 1;
int r = file_put_data(pw_status, p, file_get_size(pw_status)); int r = file_put_data(pw_status, p, file_get_size(pw_status));
if (r != PICOKEY_OK) { if (r != PICOKEYS_OK) {
return r; return r;
} }
low_flash_available(); flash_commit();
if (p[3 + (pin->fid & 0xf)] == 0) { if (p[3 + (pin->fid & 0xf)] == 0) {
return PICOKEY_ERR_BLOCKED; return PICOKEYS_ERR_BLOCKED;
} }
return p[3 + (pin->fid & 0xf)]; return p[3 + (pin->fid & 0xf)];
} }
return PICOKEY_ERR_BLOCKED; return PICOKEYS_ERR_BLOCKED;
} }
int check_pin(const file_t *pin, const uint8_t *data, size_t len) { int check_pin(const file_t *pin, const uint8_t *data, size_t len) {
if (!pin) { if (!file_has_data(pin)) {
return SW_REFERENCE_NOT_FOUND();
}
if (!pin->data) {
return SW_REFERENCE_NOT_FOUND(); return SW_REFERENCE_NOT_FOUND();
} }
isUserAuthenticated = false; isUserAuthenticated = false;
//has_pw1 = has_pw3 = false; //has_pw1 = has_pw3 = false;
uint8_t dhash[32]; uint8_t dhash[32], off = 2;
double_hash_pin(data, len, dhash); if (file_get_size(pin) == 33) {
if (sizeof(dhash) != file_get_size(pin) - 1) { //1 byte for pin len off = 1;
double_hash_pin(data, len, dhash);
}
else {
pin_derive_verifier(data, len, dhash);
}
if (sizeof(dhash) != file_get_size(pin) - off) { //1 byte for pin len and 1 byte for format
return SW_CONDITIONS_NOT_SATISFIED(); return SW_CONDITIONS_NOT_SATISFIED();
} }
if (memcmp(file_get_data(pin) + 1, dhash, sizeof(dhash)) != 0) { if (memcmp(file_get_data(pin) + off, dhash, sizeof(dhash)) != 0) {
int retries; int retries;
if ((retries = pin_wrong_retry(pin)) < PICOKEY_OK) { if ((retries = pin_wrong_retry(pin)) < PICOKEYS_OK) {
return SW_PIN_BLOCKED(); return SW_PIN_BLOCKED();
} }
return set_res_sw(0x63, 0xc0 | retries); return set_res_sw(0x63, 0xc0 | retries);
} }
int r = pin_reset_retries(pin, false); int r = pin_reset_retries(pin, false);
if (r == PICOKEY_ERR_BLOCKED) { if (r == PICOKEYS_ERR_BLOCKED) {
return SW_PIN_BLOCKED(); return SW_PIN_BLOCKED();
} }
if (r != PICOKEY_OK) { if (r != PICOKEYS_OK) {
return SW_MEMORY_FAILURE(); return SW_MEMORY_FAILURE();
} }
if (off == 1) {
uint8_t pin_data[34], *pin_sp = NULL;
pin_data[0] = len;
pin_data[1] = 0x1; // Format
pin_derive_verifier(data, len, pin_data + 2);
file_put_data((file_t *)pin, pin_data, sizeof(pin_data));
has_pw1 = has_pw2 = has_pw3 = false;
if (pin->fid == EF_PW1) {
if (P2(apdu) == 0x81) {
has_pw1 = true;
}
else {
has_pw2 = true;
}
pin_sp = session_pw1;
}
else if (pin->fid == EF_PW3) {
has_pw3 = true;
pin_sp = session_pw3;
}
else if (pin->fid == EF_PIV_PIN) {
has_pwpiv = true;
pin_sp = session_pwpiv;
}
if (pin_sp) {
hash_multi(data, len, pin_sp);
r = load_dek();
if (r != PICOKEYS_OK) {
return SW_EXEC_ERROR();
}
uint8_t old_data[DEK_FILE_SIZE_OLD], ef_data[DEK_FILE_SIZE];
file_t *ef_dek_pw = NULL;
if (has_pw1 || has_pw2) {
ef_dek_pw = file_search_by_fid(EF_DEK_PW1, NULL, SPECIFY_EF);
}
else if (has_pw3) {
ef_dek_pw = file_search_by_fid(EF_DEK_PW3, NULL, SPECIFY_EF);
}
else if (has_pwpiv) {
ef_dek_pw = file_search_by_fid(EF_DEK_PWPIV, NULL, SPECIFY_EF);
}
if (!ef_dek_pw) {
return PICOKEYS_ERR_FILE_NOT_FOUND;
}
ef_data[0] = 0x3; // Format
pin_derive_session(data, len, pin_sp);
encrypt_with_aad(pin_sp, dek, DEK_SIZE, PIN_KDF_DEFAULT_VERSION, ef_data + 1);
file_put_data(ef_dek_pw, ef_data, sizeof(ef_data));
file_t *ef_dek = file_search_by_fid(EF_DEK, NULL, SPECIFY_EF);
if (!ef_dek) {
return PICOKEYS_ERR_FILE_NOT_FOUND;
}
memcpy(old_data, file_get_data(ef_dek), sizeof(old_data));
if (has_pw1 || has_pw2) {
memset(old_data + IV_SIZE, 0, 32);
}
else if (has_pw3) {
memset(old_data + IV_SIZE + 32 + 32, 0, 32);
}
else if (has_pwpiv) {
memset(old_data + IV_SIZE + 32 + 32 + 32, 0, 32);
}
file_put_data(ef_dek, old_data, sizeof(old_data));
flash_commit();
}
has_pw1 = has_pw2 = has_pw3 = false;
}
isUserAuthenticated = true; isUserAuthenticated = true;
if (pin->fid == EF_PW1) { if (pin->fid == EF_PW1) {
if (P2(apdu) == 0x81) { if (P2(apdu) == 0x81) {
@@ -423,51 +588,51 @@ int check_pin(const file_t *pin, const uint8_t *data, size_t len) {
else { else {
has_pw2 = true; has_pw2 = true;
} }
hash_multi(data, len, session_pw1); pin_derive_session(data, len, session_pw1);
} }
else if (pin->fid == EF_PW3) { else if (pin->fid == EF_PW3) {
has_pw3 = true; has_pw3 = true;
hash_multi(data, len, session_pw3); pin_derive_session(data, len, session_pw3);
} }
return SW_OK(); return SW_OK();
} }
int inc_sig_count() { int inc_sig_count(void) {
file_t *pw_status; file_t *pw_status;
if (!(pw_status = search_by_fid(EF_PW_PRIV, NULL, SPECIFY_EF)) || !pw_status->data) { if (!(pw_status = file_search_by_fid(EF_PW_PRIV, NULL, SPECIFY_EF)) || !pw_status->data) {
return SW_REFERENCE_NOT_FOUND(); return SW_REFERENCE_NOT_FOUND();
} }
if (file_get_data(pw_status)[0] == 0) { if (file_get_data(pw_status)[0] == 0) {
has_pw1 = false; has_pw1 = false;
} }
file_t *ef = search_by_fid(EF_SIG_COUNT, NULL, SPECIFY_ANY); file_t *ef = file_search_by_fid(EF_SIG_COUNT, NULL, SPECIFY_ANY);
if (!ef || !ef->data) { if (!ef || !ef->data) {
return PICOKEY_ERR_FILE_NOT_FOUND; return PICOKEYS_ERR_FILE_NOT_FOUND;
} }
uint8_t *p = file_get_data(ef); uint8_t *p = file_get_data(ef);
uint32_t counter = (p[0] << 16) | (p[1] << 8) | p[2]; uint32_t counter = (p[0] << 16) | (p[1] << 8) | p[2];
counter++; counter++;
uint8_t q[3] = { (counter >> 16) & 0xff, (counter >> 8) & 0xff, counter & 0xff }; uint8_t q[3] = { (counter >> 16) & 0xff, (counter >> 8) & 0xff, counter & 0xff };
int r = file_put_data(ef, q, sizeof(q)); int r = file_put_data(ef, q, sizeof(q));
if (r != PICOKEY_OK) { if (r != PICOKEYS_OK) {
return PICOKEY_EXEC_ERROR; return PICOKEYS_EXEC_ERROR;
} }
low_flash_available(); flash_commit();
return PICOKEY_OK; return PICOKEYS_OK;
} }
int reset_sig_count() { int reset_sig_count(void) {
file_t *ef = search_by_fid(EF_SIG_COUNT, NULL, SPECIFY_ANY); file_t *ef = file_search_by_fid(EF_SIG_COUNT, NULL, SPECIFY_ANY);
if (!ef || !ef->data) { if (!ef || !ef->data) {
return PICOKEY_ERR_FILE_NOT_FOUND; return PICOKEYS_ERR_FILE_NOT_FOUND;
} }
uint8_t q[3] = { 0 }; uint8_t q[3] = { 0 };
int r = file_put_data(ef, q, sizeof(q)); int r = file_put_data(ef, q, sizeof(q));
if (r != PICOKEY_OK) { if (r != PICOKEYS_OK) {
return PICOKEY_EXEC_ERROR; return PICOKEYS_EXEC_ERROR;
} }
low_flash_available(); flash_commit();
return PICOKEY_OK; return PICOKEYS_OK;
} }
int store_keys(void *key_ctx, int type, uint16_t key_id, bool use_kek) { int store_keys(void *key_ctx, int type, uint16_t key_id, bool use_kek) {
@@ -475,13 +640,13 @@ int store_keys(void *key_ctx, int type, uint16_t key_id, bool use_kek) {
uint8_t kdata[4096 / 8]; //worst uint8_t kdata[4096 / 8]; //worst
//if (!has_pw3) //if (!has_pw3)
// return PICOKEY_NO_LOGIN; // return PICOKEYS_NO_LOGIN;
//file_t *pw3 = search_by_fid(EF_PW3, NULL, SPECIFY_EF); //file_t *pw3 = file_search_by_fid(EF_PW3, NULL, SPECIFY_EF);
//if (!pw3) //if (!pw3)
// return PICOKEY_ERR_FILE_NOT_FOUND; // return PICOKEYS_ERR_FILE_NOT_FOUND;
file_t *ef = search_by_fid(key_id, NULL, SPECIFY_EF); file_t *ef = file_search_by_fid(key_id, NULL, SPECIFY_EF);
if (!ef) { if (!ef) {
return PICOKEY_ERR_FILE_NOT_FOUND; return PICOKEYS_ERR_FILE_NOT_FOUND;
} }
if (type == ALGO_RSA) { if (type == ALGO_RSA) {
mbedtls_rsa_context *rsa = (mbedtls_rsa_context *) key_ctx; mbedtls_rsa_context *rsa = (mbedtls_rsa_context *) key_ctx;
@@ -510,19 +675,19 @@ int store_keys(void *key_ctx, int type, uint16_t key_id, bool use_kek) {
} }
if (use_kek) { if (use_kek) {
r = dek_encrypt(kdata, key_size); r = dek_encrypt(kdata, key_size);
if (r != PICOKEY_OK) { if (r != PICOKEYS_OK) {
return r; return r;
} }
} }
//r = aes_encrypt_cfb_256(file_read(pw3->data+2), session_pw3, kdata, key_size); //r = aes_encrypt_cfb_256(file_read(pw3->data+2), session_pw3, kdata, key_size);
//if (r != PICOKEY_OK) //if (r != PICOKEYS_OK)
// return r; // return r;
r = file_put_data(ef, kdata, key_size); r = file_put_data(ef, kdata, key_size);
if (r != PICOKEY_OK) { if (r != PICOKEYS_OK) {
return r; return r;
} }
low_flash_available(); flash_commit();
return PICOKEY_OK; return PICOKEYS_OK;
} }
int load_private_key_rsa(mbedtls_rsa_context *ctx, file_t *fkey, bool use_dek) { int load_private_key_rsa(mbedtls_rsa_context *ctx, file_t *fkey, bool use_dek) {
@@ -530,33 +695,33 @@ int load_private_key_rsa(mbedtls_rsa_context *ctx, file_t *fkey, bool use_dek) {
uint8_t kdata[4096 / 8]; uint8_t kdata[4096 / 8];
memcpy(kdata, file_get_data(fkey), key_size); memcpy(kdata, file_get_data(fkey), key_size);
if (use_dek && dek_decrypt(kdata, key_size) != 0) { if (use_dek && dek_decrypt(kdata, key_size) != 0) {
return PICOKEY_EXEC_ERROR; return PICOKEYS_EXEC_ERROR;
} }
if (mbedtls_mpi_read_binary(&ctx->P, kdata, key_size / 2) != 0) { if (mbedtls_mpi_read_binary(&ctx->P, kdata, key_size / 2) != 0) {
mbedtls_rsa_free(ctx); mbedtls_rsa_free(ctx);
return PICOKEY_WRONG_DATA; return PICOKEYS_WRONG_DATA;
} }
if (mbedtls_mpi_read_binary(&ctx->Q, kdata + key_size / 2, key_size / 2) != 0) { if (mbedtls_mpi_read_binary(&ctx->Q, kdata + key_size / 2, key_size / 2) != 0) {
mbedtls_rsa_free(ctx); mbedtls_rsa_free(ctx);
return PICOKEY_WRONG_DATA; return PICOKEYS_WRONG_DATA;
} }
if (mbedtls_mpi_lset(&ctx->E, 0x10001) != 0) { if (mbedtls_mpi_lset(&ctx->E, 0x10001) != 0) {
mbedtls_rsa_free(ctx); mbedtls_rsa_free(ctx);
return PICOKEY_EXEC_ERROR; return PICOKEYS_EXEC_ERROR;
} }
if (mbedtls_rsa_import(ctx, NULL, &ctx->P, &ctx->Q, NULL, &ctx->E) != 0) { if (mbedtls_rsa_import(ctx, NULL, &ctx->P, &ctx->Q, NULL, &ctx->E) != 0) {
mbedtls_rsa_free(ctx); mbedtls_rsa_free(ctx);
return PICOKEY_WRONG_DATA; return PICOKEYS_WRONG_DATA;
} }
if (mbedtls_rsa_complete(ctx) != 0) { if (mbedtls_rsa_complete(ctx) != 0) {
mbedtls_rsa_free(ctx); mbedtls_rsa_free(ctx);
return PICOKEY_WRONG_DATA; return PICOKEYS_WRONG_DATA;
} }
if (mbedtls_rsa_check_privkey(ctx) != 0) { if (mbedtls_rsa_check_privkey(ctx) != 0) {
mbedtls_rsa_free(ctx); mbedtls_rsa_free(ctx);
return PICOKEY_WRONG_DATA; return PICOKEYS_WRONG_DATA;
} }
return PICOKEY_OK; return PICOKEYS_OK;
} }
int load_private_key_ecdsa(mbedtls_ecp_keypair *ctx, file_t *fkey, bool use_dek) { int load_private_key_ecdsa(mbedtls_ecp_keypair *ctx, file_t *fkey, bool use_dek) {
@@ -564,38 +729,30 @@ int load_private_key_ecdsa(mbedtls_ecp_keypair *ctx, file_t *fkey, bool use_dek)
uint8_t kdata[67]; //Worst case, 521 bit + 1byte uint8_t kdata[67]; //Worst case, 521 bit + 1byte
memcpy(kdata, file_get_data(fkey), key_size); memcpy(kdata, file_get_data(fkey), key_size);
if (use_dek && dek_decrypt(kdata, key_size) != 0) { if (use_dek && dek_decrypt(kdata, key_size) != 0) {
return PICOKEY_EXEC_ERROR; return PICOKEYS_EXEC_ERROR;
} }
mbedtls_ecp_group_id gid = kdata[0]; mbedtls_ecp_group_id gid = kdata[0];
int r = mbedtls_ecp_read_key(gid, ctx, kdata + 1, key_size - 1); int r = mbedtls_ecp_read_key(gid, ctx, kdata + 1, key_size - 1);
if (r != 0) { if (r != 0) {
mbedtls_ecp_keypair_free(ctx); mbedtls_ecp_keypair_free(ctx);
return PICOKEY_EXEC_ERROR; return PICOKEYS_EXEC_ERROR;
} }
mbedtls_platform_zeroize(kdata, sizeof(kdata)); mbedtls_platform_zeroize(kdata, sizeof(kdata));
#ifdef MBEDTLS_EDDSA_C r = mbedtls_ecp_keypair_calc_public(ctx, random_fill_iterator, NULL);
if (ctx->grp.id == MBEDTLS_ECP_DP_ED25519 || ctx->grp.id == MBEDTLS_ECP_DP_ED448) {
r = mbedtls_ecp_point_edwards(&ctx->grp, &ctx->Q, &ctx->d, random_gen, NULL);
}
else
#endif
{
r = mbedtls_ecp_mul(&ctx->grp, &ctx->Q, &ctx->d, &ctx->grp.G, random_gen, NULL);
}
if (r != 0) { if (r != 0) {
mbedtls_ecdsa_free(ctx); mbedtls_ecp_keypair_free(ctx);
return PICOKEY_EXEC_ERROR; return PICOKEYS_EXEC_ERROR;
} }
return PICOKEY_OK; return PICOKEYS_OK;
} }
int load_aes_key(uint8_t *aes_key, file_t *fkey) { int load_aes_key(uint8_t *aes_key, file_t *fkey) {
int key_size = file_get_size(fkey); int key_size = file_get_size(fkey);
memcpy(aes_key, file_get_data(fkey), key_size); memcpy(aes_key, file_get_data(fkey), key_size);
if (dek_decrypt(aes_key, key_size) != 0) { if (dek_decrypt(aes_key, key_size) != 0) {
return PICOKEY_EXEC_ERROR; return PICOKEYS_EXEC_ERROR;
} }
return PICOKEY_OK; return PICOKEYS_OK;
} }
mbedtls_ecp_group_id get_ec_group_id_from_attr(const uint8_t *algo, size_t algo_len) { mbedtls_ecp_group_id get_ec_group_id_from_attr(const uint8_t *algo, size_t algo_len) {
@@ -642,25 +799,20 @@ void make_rsa_response(mbedtls_rsa_context *rsa) {
res_APDU_size = 5; res_APDU_size = 5;
res_APDU[res_APDU_size++] = 0x81; res_APDU[res_APDU_size++] = 0x81;
res_APDU[res_APDU_size++] = 0x82; res_APDU[res_APDU_size++] = 0x82;
put_uint16_t_be(mbedtls_mpi_size(&rsa->N), res_APDU + res_APDU_size); res_APDU_size += 2; put_uint16_be(mbedtls_mpi_size(&rsa->N), res_APDU + res_APDU_size); res_APDU_size += 2;
mbedtls_mpi_write_binary(&rsa->N, res_APDU + res_APDU_size, mbedtls_mpi_size(&rsa->N)); mbedtls_mpi_write_binary(&rsa->N, res_APDU + res_APDU_size, mbedtls_mpi_size(&rsa->N));
res_APDU_size += mbedtls_mpi_size(&rsa->N); res_APDU_size += mbedtls_mpi_size(&rsa->N);
res_APDU[res_APDU_size++] = 0x82; res_APDU[res_APDU_size++] = 0x82;
res_APDU[res_APDU_size++] = mbedtls_mpi_size(&rsa->E) & 0xff; res_APDU[res_APDU_size++] = mbedtls_mpi_size(&rsa->E) & 0xff;
mbedtls_mpi_write_binary(&rsa->E, res_APDU + res_APDU_size, mbedtls_mpi_size(&rsa->E)); mbedtls_mpi_write_binary(&rsa->E, res_APDU + res_APDU_size, mbedtls_mpi_size(&rsa->E));
res_APDU_size += mbedtls_mpi_size(&rsa->E); res_APDU_size += mbedtls_mpi_size(&rsa->E);
put_uint16_t_be(res_APDU_size - 5, res_APDU + 3); put_uint16_be(res_APDU_size - 5, res_APDU + 3);
} }
void make_ecdsa_response(mbedtls_ecp_keypair *ecdsa) { void make_ecdsa_response(mbedtls_ecp_keypair *ecdsa) {
uint8_t pt[MBEDTLS_ECP_MAX_PT_LEN]; uint8_t pt[MBEDTLS_ECP_MAX_PT_LEN];
size_t plen = 0; size_t plen = 0;
mbedtls_ecp_point_write_binary(&ecdsa->grp, mbedtls_ecp_point_write_binary(&ecdsa->grp, &ecdsa->Q, MBEDTLS_ECP_PF_UNCOMPRESSED, &plen, pt, sizeof(pt));
&ecdsa->Q,
MBEDTLS_ECP_PF_UNCOMPRESSED,
&plen,
pt,
sizeof(pt));
res_APDU[res_APDU_size++] = 0x7f; res_APDU[res_APDU_size++] = 0x7f;
res_APDU[res_APDU_size++] = 0x49; res_APDU[res_APDU_size++] = 0x49;
if (plen >= 128) { if (plen >= 128) {
@@ -676,17 +828,13 @@ void make_ecdsa_response(mbedtls_ecp_keypair *ecdsa) {
res_APDU_size += plen; res_APDU_size += plen;
} }
int rsa_sign(mbedtls_rsa_context *ctx, int rsa_sign(mbedtls_rsa_context *ctx, const uint8_t *data, size_t data_len, uint8_t *out, size_t *out_len) {
const uint8_t *data,
size_t data_len,
uint8_t *out,
size_t *out_len) {
uint8_t *d = (uint8_t *) data, *end = d + data_len, *hsh = NULL; uint8_t *d = (uint8_t *) data, *end = d + data_len, *hsh = NULL;
size_t seq_len = 0, hash_len = 0; size_t seq_len = 0, hash_len = 0;
int key_size = ctx->len, r = 0; size_t key_size = ctx->len;
int r = 0;
mbedtls_md_type_t md = MBEDTLS_MD_NONE; mbedtls_md_type_t md = MBEDTLS_MD_NONE;
if (mbedtls_asn1_get_tag(&d, end, &seq_len, if (mbedtls_asn1_get_tag(&d, end, &seq_len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE) == 0) {
MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE) == 0) {
mbedtls_asn1_buf mdb; mbedtls_asn1_buf mdb;
r = mbedtls_asn1_get_alg_null(&d, end, &mdb); r = mbedtls_asn1_get_alg_null(&d, end, &mdb);
if (r == 0) { if (r == 0) {
@@ -733,11 +881,11 @@ int rsa_sign(mbedtls_rsa_context *ctx,
if (data_len < key_size) { //needs padding if (data_len < key_size) { //needs padding
memset((uint8_t *) data + data_len, 0, key_size - data_len); memset((uint8_t *) data + data_len, 0, key_size - data_len);
} }
r = mbedtls_rsa_private(ctx, random_gen, NULL, data, out); r = mbedtls_rsa_private(ctx, random_fill_iterator, NULL, data, out);
} }
else { else {
uint8_t *signature = (uint8_t *) calloc(key_size, sizeof(uint8_t)); uint8_t *signature = (uint8_t *) calloc(key_size, sizeof(uint8_t));
r = mbedtls_rsa_pkcs1_sign(ctx, random_gen, NULL, md, hash_len, hsh, signature); r = mbedtls_rsa_pkcs1_sign(ctx, random_fill_iterator, NULL, md, hash_len, hsh, signature);
memcpy(out, signature, key_size); memcpy(out, signature, key_size);
free(signature); free(signature);
} }
@@ -745,16 +893,12 @@ int rsa_sign(mbedtls_rsa_context *ctx,
return r; return r;
} }
int ecdsa_sign(mbedtls_ecp_keypair *ctx, int ecdsa_sign(mbedtls_ecp_keypair *ctx, const uint8_t *data, size_t data_len, uint8_t *out, size_t *out_len) {
const uint8_t *data,
size_t data_len,
uint8_t *out,
size_t *out_len) {
int r = 0; int r = 0;
#ifdef MBEDTLS_EDDSA_C #ifdef MBEDTLS_EDDSA_C
if (ctx->grp.id == MBEDTLS_ECP_DP_ED25519 || ctx->grp.id == MBEDTLS_ECP_DP_ED448) { if (ctx->grp.id == MBEDTLS_ECP_DP_ED25519 || ctx->grp.id == MBEDTLS_ECP_DP_ED448) {
r = mbedtls_eddsa_write_signature(ctx, data, data_len, out, 114, out_len, MBEDTLS_EDDSA_PURE, NULL, 0, random_gen, NULL); r = mbedtls_eddsa_write_signature(ctx, data, data_len, out, 114, out_len, MBEDTLS_EDDSA_PURE, NULL, 0, random_fill_iterator, NULL);
} }
else else
#endif #endif
@@ -762,7 +906,7 @@ int ecdsa_sign(mbedtls_ecp_keypair *ctx,
mbedtls_mpi ri, si; mbedtls_mpi ri, si;
mbedtls_mpi_init(&ri); mbedtls_mpi_init(&ri);
mbedtls_mpi_init(&si); mbedtls_mpi_init(&si);
r = mbedtls_ecdsa_sign(&ctx->grp, &ri, &si, &ctx->d, data, data_len, random_gen, NULL); r = mbedtls_ecdsa_sign(&ctx->grp, &ri, &si, &ctx->d, data, data_len, random_fill_iterator, NULL);
if (r == 0) { if (r == 0) {
size_t plen = (ctx->grp.nbits + 7) / 8; size_t plen = (ctx->grp.nbits + 7) / 8;
mbedtls_mpi_write_binary(&ri, out, plen); mbedtls_mpi_write_binary(&ri, out, plen);
@@ -775,24 +919,6 @@ int ecdsa_sign(mbedtls_ecp_keypair *ctx,
return r; return r;
} }
extern int cmd_select();
extern int cmd_get_data();
extern int cmd_get_next_data();
extern int cmd_put_data();
extern int cmd_verify();
extern int cmd_select_data();
extern int cmd_version_openpgp();
extern int cmd_import_data();
extern int cmd_change_pin();
extern int cmd_mse();
extern int cmd_internal_aut();
extern int cmd_challenge();
extern int cmd_activate_file();
extern int cmd_terminate_df();
extern int cmd_pso();
extern int cmd_keypair_gen();
extern int cmd_reset_retry();
#define INS_VERIFY 0x20 #define INS_VERIFY 0x20
#define INS_MSE 0x22 #define INS_MSE 0x22
#define INS_CHANGE_PIN 0x24 #define INS_CHANGE_PIN 0x24
@@ -806,6 +932,7 @@ extern int cmd_reset_retry();
#define INS_SELECT_DATA 0xA5 #define INS_SELECT_DATA 0xA5
#define INS_GET_DATA 0xCA #define INS_GET_DATA 0xCA
#define INS_GET_NEXT_DATA 0xCC #define INS_GET_NEXT_DATA 0xCC
#define INS_GET_BULK_DATA 0xCE
#define INS_PUT_DATA 0xDA #define INS_PUT_DATA 0xDA
#define INS_IMPORT_DATA 0xDB #define INS_IMPORT_DATA 0xDB
#define INS_TERMINATE_DF 0xE6 #define INS_TERMINATE_DF 0xE6
@@ -829,10 +956,11 @@ static const cmd_t cmds[] = {
{ INS_VERSION, cmd_version_openpgp }, { INS_VERSION, cmd_version_openpgp },
{ INS_SELECT_DATA, cmd_select_data }, { INS_SELECT_DATA, cmd_select_data },
{ INS_GET_NEXT_DATA, cmd_get_next_data }, { INS_GET_NEXT_DATA, cmd_get_next_data },
{ 0x00, 0x0 } { INS_GET_BULK_DATA, cmd_get_bulk_data },
{ 0x00, NULL }
}; };
int openpgp_process_apdu() { int openpgp_process_apdu(void) {
sm_unwrap(); sm_unwrap();
for (const cmd_t *cmd = cmds; cmd->ins != 0x00; cmd++) { for (const cmd_t *cmd = cmds; cmd->ins != 0x00; cmd++) {
if (cmd->ins == INS(apdu)) { if (cmd->ins == INS(apdu)) {

View File

@@ -23,7 +23,7 @@
#include <pico/stdlib.h> #include <pico/stdlib.h>
#endif #endif
#include "pico_keys.h" #include "picokeys.h"
#include "apdu.h" #include "apdu.h"
#include "mbedtls/rsa.h" #include "mbedtls/rsa.h"
#include "mbedtls/ecdsa.h" #include "mbedtls/ecdsa.h"
@@ -67,16 +67,41 @@ extern int pin_reset_retries(const file_t *pin, bool force);
extern void select_file(file_t *pe); extern void select_file(file_t *pe);
extern int parse_do(uint16_t *fids, int mode); extern int parse_do(uint16_t *fids, int mode);
extern int load_dek(); extern int load_dek(void);
extern int check_pin(const file_t *pin, const uint8_t *data, size_t len); extern int check_pin(const file_t *pin, const uint8_t *data, size_t len);
extern mbedtls_ecp_group_id get_ec_group_id_from_attr(const uint8_t *algo, size_t algo_len); extern mbedtls_ecp_group_id get_ec_group_id_from_attr(const uint8_t *algo, size_t algo_len);
extern int reset_sig_count(); extern int reset_sig_count(void);
extern uint16_t algo_dec, algo_aut, pk_dec, pk_aut; extern uint16_t algo_dec, algo_aut, pk_dec, pk_aut;
extern bool wait_button_pressed_fid(uint16_t fid); extern bool wait_button_pressed_fid(uint16_t fid);
extern void scan_files_openpgp(); extern void scan_files_openpgp(void);
extern int load_aes_key(uint8_t *aes_key, file_t *fkey); extern int load_aes_key(uint8_t *aes_key, file_t *fkey);
extern int inc_sig_count(); extern int inc_sig_count(void);
extern int dek_encrypt(uint8_t *data, size_t len); extern int dek_encrypt(uint8_t *data, size_t len);
extern int dek_decrypt(uint8_t *data, size_t len); extern int dek_decrypt(uint8_t *data, size_t len);
int cmd_select(void);
int cmd_get_data(void);
int cmd_get_next_data(void);
int cmd_put_data(void);
int cmd_verify(void);
int cmd_select_data(void);
int cmd_version_openpgp(void);
int cmd_import_data(void);
int cmd_change_pin(void);
int cmd_mse(void);
int cmd_internal_aut(void);
int cmd_challenge(void);
int cmd_activate_file(void);
int cmd_terminate_df(void);
int cmd_pso(void);
int cmd_keypair_gen(void);
int cmd_reset_retry(void);
int cmd_get_bulk_data(void);
#define DEK_SIZE (IV_SIZE + 32)
#define DEK_AAD_SIZE (PIN_KDF_SIZE(DEK_SIZE))
#define DEK_FILE_SIZE (1 + DEK_AAD_SIZE)
#define DEK_FILE_SIZE_OLD (IV_SIZE + 32 + 32 + 32 + 32)
#endif #endif

View File

@@ -15,15 +15,15 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
#include <stdio.h>
#ifdef ESP_PLATFORM #ifdef ESP_PLATFORM
#include "esp_compat.h" #include "esp_compat.h"
#define MBEDTLS_ALLOW_PRIVATE_ACCESS #define MBEDTLS_ALLOW_PRIVATE_ACCESS
#else
#include "common.h"
#endif #endif
#include "files.h" #include "files.h"
#include "apdu.h" #include "apdu.h"
#include "pico_keys.h" #include "picokeys.h"
#include "serial.h"
#include "random.h" #include "random.h"
#include "eac.h" #include "eac.h"
#include "crypto_utils.h" #include "crypto_utils.h"
@@ -76,9 +76,11 @@ uint8_t yk_aid[] = {
bool has_pwpiv = false; bool has_pwpiv = false;
uint8_t session_pwpiv[32]; uint8_t session_pwpiv[32];
int piv_process_apdu(); int piv_process_apdu(void);
void init_piv(void);
int piv_parse_discovery(const file_t *ef);
static int get_serial() { static int get_serial(void) {
uint32_t serial = (pico_serial.id[0] & 0x7F) << 24 | pico_serial.id[1] << 16 | pico_serial.id[2] << 8 | pico_serial.id[3]; uint32_t serial = (pico_serial.id[0] & 0x7F) << 24 | pico_serial.id[1] << 16 | pico_serial.id[2] << 8 | pico_serial.id[3];
return serial; return serial;
} }
@@ -89,7 +91,7 @@ static int x509_create_cert(void *pk_ctx, uint8_t algo, uint8_t slot, bool attes
mbedtls_x509write_crt_set_version(&ctx, MBEDTLS_X509_CRT_VERSION_3); mbedtls_x509write_crt_set_version(&ctx, MBEDTLS_X509_CRT_VERSION_3);
mbedtls_x509write_crt_set_validity(&ctx, "20240325000000", "20741231235959"); mbedtls_x509write_crt_set_validity(&ctx, "20240325000000", "20741231235959");
uint8_t serial[20]; uint8_t serial[20];
random_gen(NULL, serial, sizeof(serial)); random_fill_buffer(serial, sizeof(serial));
mbedtls_x509write_crt_set_serial_raw(&ctx, serial, sizeof(serial)); mbedtls_x509write_crt_set_serial_raw(&ctx, serial, sizeof(serial));
mbedtls_pk_context skey, ikey; mbedtls_pk_context skey, ikey;
mbedtls_ecdsa_context actx; // attestation key mbedtls_ecdsa_context actx; // attestation key
@@ -108,7 +110,7 @@ static int x509_create_cert(void *pk_ctx, uint8_t algo, uint8_t slot, bool attes
sprintf(buf_sname, "C=ES,O=Pico Keys,CN=Pico OpenPGP PIV Attestation %X", slot); sprintf(buf_sname, "C=ES,O=Pico Keys,CN=Pico OpenPGP PIV Attestation %X", slot);
mbedtls_x509write_crt_set_subject_name(&ctx, buf_sname); mbedtls_x509write_crt_set_subject_name(&ctx, buf_sname);
mbedtls_x509write_crt_set_issuer_name(&ctx, "C=ES,O=Pico Keys,CN=Pico OpenPGP PIV Slot F9"); mbedtls_x509write_crt_set_issuer_name(&ctx, "C=ES,O=Pico Keys,CN=Pico OpenPGP PIV Slot F9");
file_t *ef_key = search_by_fid(EF_PIV_KEY_ATTESTATION, NULL, SPECIFY_EF); file_t *ef_key = file_search_by_fid(EF_PIV_KEY_ATTESTATION, NULL, SPECIFY_EF);
mbedtls_ecdsa_init(&actx); mbedtls_ecdsa_init(&actx);
load_private_key_ecdsa(&actx, ef_key, false); load_private_key_ecdsa(&actx, ef_key, false);
mbedtls_pk_setup(&ikey, mbedtls_pk_info_from_type(MBEDTLS_PK_ECKEY)); mbedtls_pk_setup(&ikey, mbedtls_pk_info_from_type(MBEDTLS_PK_ECKEY));
@@ -116,15 +118,15 @@ static int x509_create_cert(void *pk_ctx, uint8_t algo, uint8_t slot, bool attes
mbedtls_x509write_crt_set_issuer_key(&ctx, &ikey); mbedtls_x509write_crt_set_issuer_key(&ctx, &ikey);
uint8_t ver[] = {PIV_VERSION_MAJOR, PIV_VERSION_MINOR, 0}; uint8_t ver[] = {PIV_VERSION_MAJOR, PIV_VERSION_MINOR, 0};
mbedtls_x509write_crt_set_extension(&ctx, "\x2B\x06\x01\x04\x01\x82\xC4\x0A\x03\x03", 10, 0, ver, sizeof(ver)); mbedtls_x509write_crt_set_extension(&ctx, "\x2B\x06\x01\x04\x01\x82\xC4\x0A\x03\x03", 10, 0, ver, sizeof(ver));
uint32_t serial = get_serial(); uint32_t device_serial = get_serial();
mbedtls_x509write_crt_set_extension(&ctx, "\x2B\x06\x01\x04\x01\x82\xC4\x0A\x03\x07", 10, 0, (const uint8_t *)&serial, sizeof(serial)); mbedtls_x509write_crt_set_extension(&ctx, "\x2B\x06\x01\x04\x01\x82\xC4\x0A\x03\x07", 10, 0, (const uint8_t *)&device_serial, sizeof(device_serial));
int meta_len = 0; int meta_len = 0;
uint8_t *meta; uint8_t *meta;
if ((meta_len = meta_find(slot, &meta)) >= 0) { if ((meta_len = meta_find(slot, &meta)) >= 0) {
mbedtls_x509write_crt_set_extension(&ctx, "\x2B\x06\x01\x04\x01\x82\xC4\x0A\x03\x08", 10, 0, &meta[1], 2); mbedtls_x509write_crt_set_extension(&ctx, "\x2B\x06\x01\x04\x01\x82\xC4\x0A\x03\x08", 10, 0, &meta[1], 2);
} }
uint8_t v = 1; uint8_t v = 1;
mbedtls_x509write_crt_set_extension(&ctx, "\x2B\x06\x01\x04\x01\x82\xC4\x0A\x03\x09", 10, 0, &v, sizeof(serial)); mbedtls_x509write_crt_set_extension(&ctx, "\x2B\x06\x01\x04\x01\x82\xC4\x0A\x03\x09", 10, 0, &v, sizeof(v));
} }
else { else {
uint8_t wslot = slot; uint8_t wslot = slot;
@@ -153,10 +155,8 @@ static int x509_create_cert(void *pk_ctx, uint8_t algo, uint8_t slot, bool attes
} }
mbedtls_x509write_crt_set_subject_key_identifier(&ctx); mbedtls_x509write_crt_set_subject_key_identifier(&ctx);
mbedtls_x509write_crt_set_authority_key_identifier(&ctx); mbedtls_x509write_crt_set_authority_key_identifier(&ctx);
mbedtls_x509write_crt_set_key_usage(&ctx, mbedtls_x509write_crt_set_key_usage(&ctx, MBEDTLS_X509_KU_DIGITAL_SIGNATURE | MBEDTLS_X509_KU_KEY_CERT_SIGN);
MBEDTLS_X509_KU_DIGITAL_SIGNATURE | int ret = mbedtls_x509write_crt_der(&ctx, buffer, buffer_size, random_fill_iterator, NULL);
MBEDTLS_X509_KU_KEY_CERT_SIGN);
int ret = mbedtls_x509write_crt_der(&ctx, buffer, buffer_size, random_gen, NULL);
/* skey cannot be freed, as it is freed later */ /* skey cannot be freed, as it is freed later */
if (attestation) { if (attestation) {
mbedtls_ecdsa_free(&actx); mbedtls_ecdsa_free(&actx);
@@ -165,10 +165,10 @@ static int x509_create_cert(void *pk_ctx, uint8_t algo, uint8_t slot, bool attes
return ret; return ret;
} }
static void scan_files_piv() { static void scan_files_piv(void) {
scan_flash(); file_scan_flash();
file_t *ef = search_by_fid(EF_PIV_KEY_CARDMGM, NULL, SPECIFY_EF); file_t *ef = file_search_by_fid(EF_PIV_KEY_CARDMGM, NULL, SPECIFY_EF);
if ((ef = search_by_fid(EF_PW_PRIV, NULL, SPECIFY_ANY))) { if ((ef = file_search_by_fid(EF_PW_PRIV, NULL, SPECIFY_ANY))) {
if (file_get_size(ef) == 0) { if (file_get_size(ef) == 0) {
printf("PW status is empty. Initializing to default\r\n"); printf("PW status is empty. Initializing to default\r\n");
const uint8_t def[] = { 0x1, 127, 127, 127, 3, 3, 3, 3, 3 }; const uint8_t def[] = { 0x1, 127, 127, 127, 3, 3, 3, 3, 3 };
@@ -182,7 +182,7 @@ static void scan_files_piv() {
file_put_data(ef, def, sizeof(def)); file_put_data(ef, def, sizeof(def));
} }
} }
if ((ef = search_by_fid(EF_PW_RETRIES, NULL, SPECIFY_ANY))) { if ((ef = file_search_by_fid(EF_PW_RETRIES, NULL, SPECIFY_ANY))) {
if (file_get_size(ef) == 0) { if (file_get_size(ef) == 0) {
printf("PW retries is empty. Initializing to default\r\n"); printf("PW retries is empty. Initializing to default\r\n");
const uint8_t def[] = { 0x1, 3, 3, 3, 3, 3 }; const uint8_t def[] = { 0x1, 3, 3, 3, 3, 3 };
@@ -197,83 +197,77 @@ static void scan_files_piv() {
} }
} }
bool reset_dek = false; bool reset_dek = false;
if ((ef = search_by_fid(EF_DEK, NULL, SPECIFY_ANY))) { if ((ef = file_search_by_fid(EF_DEK_PWPIV, NULL, SPECIFY_ANY)) && !file_has_data(ef)) {
if (file_get_size(ef) == 0 || file_get_size(ef) == IV_SIZE+32*3) { printf("DEK PIV is empty or older\r\n");
printf("DEK is empty or older\r\n"); const uint8_t defpin[8] = { 0x31, 0x32, 0x33, 0x34, 0x35, 0x36 };
const uint8_t defpin[6] = { 0x31, 0x32, 0x33, 0x34, 0x35, 0x36 }; const uint8_t *random_dek = random_bytes_get(IV_SIZE + 32);
const uint8_t *dek = random_bytes_get(IV_SIZE + 32);
uint8_t def[IV_SIZE + 32 + 32 + 32 + 32];
if (file_get_size(ef) > 0) {
memcpy(def, file_get_data(ef), file_get_size(ef));
}
else {
memcpy(def, dek, IV_SIZE);
}
memcpy(def + IV_SIZE + 32*3, dek + IV_SIZE, 32);
hash_multi(defpin, sizeof(defpin), session_pwpiv);
aes_encrypt_cfb_256(session_pwpiv, def, def + IV_SIZE + 32*3, 32);
file_put_data(ef, def, sizeof(def));
has_pwpiv = true; uint8_t def[DEK_FILE_SIZE];
uint8_t *key = (uint8_t *)"\x01\x02\x03\x04\x05\x06\x07\x08\x01\x02\x03\x04\x05\x06\x07\x08\x01\x02\x03\x04\x05\x06\x07\x08"; def[0] = 0x3; // Format
file_t *ef = search_by_fid(EF_PIV_KEY_CARDMGM, NULL, SPECIFY_ANY);
file_put_data(ef, key, 24);
uint8_t meta[] = { PIV_ALGO_AES192, PINPOLICY_ALWAYS, TOUCHPOLICY_ALWAYS };
meta_add(EF_PIV_KEY_CARDMGM, meta, sizeof(meta));
has_pwpiv = false;
memset(session_pwpiv, 0, sizeof(session_pwpiv));
reset_dek = true; pin_derive_session(defpin, sizeof(defpin), session_pwpiv);
} encrypt_with_aad(session_pwpiv, random_dek, DEK_SIZE, PIN_KDF_DEFAULT_VERSION, def + 1);
mbedtls_platform_zeroize(session_pwpiv, sizeof(session_pwpiv));
file_put_data(ef, def, sizeof(def));
uint8_t *key = (uint8_t *)"\x01\x02\x03\x04\x05\x06\x07\x08\x01\x02\x03\x04\x05\x06\x07\x08\x01\x02\x03\x04\x05\x06\x07\x08";
file_t *ef_cardmgm = file_search_by_fid(EF_PIV_KEY_CARDMGM, NULL, SPECIFY_ANY);
file_put_data(ef_cardmgm, key, 24);
uint8_t meta[] = { PIV_ALGO_AES192, PINPOLICY_ALWAYS, TOUCHPOLICY_ALWAYS };
meta_add(EF_PIV_KEY_CARDMGM, meta, sizeof(meta));
reset_dek = true;
} }
if ((ef = search_by_fid(EF_PIV_PIN, NULL, SPECIFY_ANY))) { if ((ef = file_search_by_fid(EF_PIV_PIN, NULL, SPECIFY_ANY))) {
if (!ef->data || reset_dek) { if (!ef->data || reset_dek) {
printf("PIV PIN is empty. Initializing with default password\r\n"); printf("PIV PIN is empty. Initializing with default password\r\n");
const uint8_t def[8] = { 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0xFF, 0xFF }; const uint8_t def[8] = { 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0xFF, 0xFF };
uint8_t dhash[33]; uint8_t dhash[34];
dhash[0] = sizeof(def); dhash[0] = sizeof(def);
double_hash_pin(def, sizeof(def), dhash + 1); dhash[1] = 0x1; // Format
pin_derive_verifier(def, sizeof(def), dhash + 2);
file_put_data(ef, dhash, sizeof(dhash)); file_put_data(ef, dhash, sizeof(dhash));
} }
} }
if ((ef = search_by_fid(EF_PIV_PUK, NULL, SPECIFY_ANY))) { if ((ef = file_search_by_fid(EF_PIV_PUK, NULL, SPECIFY_ANY))) {
if (!ef->data) { if (!ef->data) {
printf("PIV PUK is empty. Initializing with default password\r\n"); printf("PIV PUK is empty. Initializing with default password\r\n");
const uint8_t def[8] = { 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38 }; const uint8_t def[8] = { 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38 };
uint8_t dhash[33]; uint8_t dhash[34];
dhash[0] = sizeof(def); dhash[0] = sizeof(def);
double_hash_pin(def, sizeof(def), dhash + 1); dhash[1] = 0x1; // Format
pin_derive_verifier(def, sizeof(def), dhash + 2);
file_put_data(ef, dhash, sizeof(dhash)); file_put_data(ef, dhash, sizeof(dhash));
} }
} }
if ((ef = search_by_fid(EF_PIV_KEY_ATTESTATION, NULL, SPECIFY_ANY))) { if ((ef = file_search_by_fid(EF_PIV_KEY_ATTESTATION, NULL, SPECIFY_ANY))) {
if (!ef->data) { if (!ef->data) {
printf("ATTESTATION key is empty. Initializing with random one\r\n"); printf("ATTESTATION key is empty. Initializing with random one\r\n");
mbedtls_ecdsa_context ecdsa; mbedtls_ecdsa_context ecdsa;
mbedtls_ecdsa_init(&ecdsa); mbedtls_ecdsa_init(&ecdsa);
int r = mbedtls_ecdsa_genkey(&ecdsa, MBEDTLS_ECP_DP_SECP384R1, random_gen, NULL); int r = mbedtls_ecdsa_genkey(&ecdsa, MBEDTLS_ECP_DP_SECP384R1, random_fill_iterator, NULL);
r = store_keys(&ecdsa, ALGO_ECDSA, EF_PIV_KEY_ATTESTATION, false); r = store_keys(&ecdsa, ALGO_ECDSA, EF_PIV_KEY_ATTESTATION, false);
uint8_t cert[2048]; uint8_t cert[2048];
r = x509_create_cert(&ecdsa, PIV_ALGO_ECCP384, EF_PIV_KEY_ATTESTATION, false, cert, sizeof(cert)); r = x509_create_cert(&ecdsa, PIV_ALGO_ECCP384, EF_PIV_KEY_ATTESTATION, false, cert, sizeof(cert));
ef = search_by_fid(EF_PIV_ATTESTATION, NULL, SPECIFY_ANY); ef = file_search_by_fid(EF_PIV_ATTESTATION, NULL, SPECIFY_ANY);
file_put_data(ef, cert + sizeof(cert) - r, r); file_put_data(ef, cert + sizeof(cert) - r, r);
mbedtls_ecdsa_free(&ecdsa); mbedtls_ecdsa_free(&ecdsa);
} }
} }
low_flash_available(); flash_commit();
} }
void init_piv() { void init_piv(void) {
scan_files_piv(); scan_files_piv();
has_pwpiv = false; has_pwpiv = false;
// cmd_select(); // cmd_select();
} }
int piv_unload() { static int piv_unload(void) {
return PICOKEY_OK; return PICOKEYS_OK;
} }
void select_piv_aid() { static void select_piv_aid(void) {
res_APDU[res_APDU_size++] = 0x61; res_APDU[res_APDU_size++] = 0x61;
res_APDU[res_APDU_size++] = 0; //filled later res_APDU[res_APDU_size++] = 0; //filled later
res_APDU[res_APDU_size++] = 0x4F; res_APDU[res_APDU_size++] = 0x4F;
@@ -300,13 +294,13 @@ void select_piv_aid() {
res_APDU[res_APDU_size++] = 0x00; res_APDU[res_APDU_size++] = 0x00;
} }
int piv_select_aid(app_t *a, uint8_t force) { static int piv_select_aid(app_t *a, uint8_t force) {
(void) force; (void) force;
a->process_apdu = piv_process_apdu; a->process_apdu = piv_process_apdu;
a->unload = piv_unload; a->unload = piv_unload;
init_piv(); init_piv();
select_piv_aid(); select_piv_aid();
return PICOKEY_OK; return PICOKEYS_OK;
} }
INITIALIZER( piv_ctor ) { INITIALIZER( piv_ctor ) {
@@ -314,14 +308,14 @@ INITIALIZER( piv_ctor ) {
register_app(piv_select_aid, yk_aid); register_app(piv_select_aid, yk_aid);
} }
static int cmd_version() { static int cmd_version(void) {
res_APDU[res_APDU_size++] = PIV_VERSION_MAJOR; res_APDU[res_APDU_size++] = PIV_VERSION_MAJOR;
res_APDU[res_APDU_size++] = PIV_VERSION_MINOR; res_APDU[res_APDU_size++] = PIV_VERSION_MINOR;
res_APDU[res_APDU_size++] = 0x0; res_APDU[res_APDU_size++] = 0x0;
return SW_OK(); return SW_OK();
} }
static int cmd_select() { static int cmd_piv_select(void) {
if (P2(apdu) != 0x1) { if (P2(apdu) != 0x1) {
return SW_WRONG_P1P2(); return SW_WRONG_P1P2();
} }
@@ -332,12 +326,13 @@ static int cmd_select() {
} }
int piv_parse_discovery(const file_t *ef) { int piv_parse_discovery(const file_t *ef) {
(void) ef;
memcpy(res_APDU, "\x7E\x12\x4F\x0B\xA0\x00\x00\x03\x08\x00\x00\x10\x00\x01\x00\x5F\x2F\x02\x40\x10", 20); memcpy(res_APDU, "\x7E\x12\x4F\x0B\xA0\x00\x00\x03\x08\x00\x00\x10\x00\x01\x00\x5F\x2F\x02\x40\x10", 20);
res_APDU_size = 20; res_APDU_size = 20;
return res_APDU_size; return res_APDU_size;
} }
static int cmd_get_serial() { static int cmd_get_serial(void) {
uint32_t serial = get_serial(); uint32_t serial = get_serial();
res_APDU[res_APDU_size++] = serial >> 24; res_APDU[res_APDU_size++] = serial >> 24;
res_APDU[res_APDU_size++] = serial >> 16; res_APDU[res_APDU_size++] = serial >> 16;
@@ -346,8 +341,7 @@ static int cmd_get_serial() {
return SW_OK(); return SW_OK();
} }
extern int check_pin(const file_t *pin, const uint8_t *data, size_t len); static int cmd_piv_verify(void) {
static int cmd_verify() {
uint8_t key_ref = P2(apdu); uint8_t key_ref = P2(apdu);
if (P1(apdu) != 0x00 && P1(apdu) != 0xFF) { if (P1(apdu) != 0x00 && P1(apdu) != 0xFF) {
return SW_INCORRECT_P1P2(); return SW_INCORRECT_P1P2();
@@ -357,10 +351,10 @@ static int cmd_verify() {
} }
file_t *pw, *pw_status; file_t *pw, *pw_status;
uint16_t fid = EF_PIV_PIN; uint16_t fid = EF_PIV_PIN;
if (!(pw = search_by_fid(fid, NULL, SPECIFY_EF))) { if (!(pw = file_search_by_fid(fid, NULL, SPECIFY_EF))) {
return SW_REFERENCE_NOT_FOUND(); return SW_REFERENCE_NOT_FOUND();
} }
if (!(pw_status = search_by_fid(EF_PW_PRIV, NULL, SPECIFY_EF))) { if (!(pw_status = file_search_by_fid(EF_PW_PRIV, NULL, SPECIFY_EF))) {
return SW_REFERENCE_NOT_FOUND(); return SW_REFERENCE_NOT_FOUND();
} }
if (file_get_data(pw)[0] == 0) { //not initialized if (file_get_data(pw)[0] == 0) { //not initialized
@@ -384,7 +378,7 @@ static int cmd_verify() {
return set_res_sw(0x63, 0xc0 | retries); return set_res_sw(0x63, 0xc0 | retries);
} }
static int cmd_get_data() { static int cmd_piv_get_data(void) {
if (P1(apdu) != 0x3F || P2(apdu) != 0xFF) { if (P1(apdu) != 0x3F || P2(apdu) != 0xFF) {
return SW_INCORRECT_P1P2(); return SW_INCORRECT_P1P2();
} }
@@ -400,11 +394,13 @@ static int cmd_get_data() {
return SW_FILE_NOT_FOUND(); return SW_FILE_NOT_FOUND();
} }
file_t *ef = NULL; file_t *ef = NULL;
if ((ef = search_by_fid((uint16_t)(fid & 0xFFFF), NULL, SPECIFY_EF))) { if ((ef = file_search_by_fid((uint16_t)(fid & 0xFFFF), NULL, SPECIFY_EF))) {
uint16_t data_len = 0; uint16_t data_len = 0;
res_APDU_size = 2; // Minimum: TAG+LEN res_APDU_size = 2; // Minimum: TAG+LEN
if ((ef->type & FILE_DATA_FUNC) == FILE_DATA_FUNC) { if ((ef->type & FILE_DATA_FUNC) == FILE_DATA_FUNC) {
data_len = ((int (*)(const file_t *))(ef->data))((const file_t *) ef); int (*file_data_func)(const file_t *) = NULL;
memcpy(&file_data_func, &ef->data, sizeof(file_data_func));
data_len = file_data_func(ef);
} }
else { else {
if (ef->data) { if (ef->data) {
@@ -430,7 +426,7 @@ static int cmd_get_data() {
return SW_OK(); return SW_OK();
} }
static int cmd_get_metadata() { static int cmd_get_metadata(void) {
if (P1(apdu) != 0x00) { if (P1(apdu) != 0x00) {
return SW_INCORRECT_P1P2(); return SW_INCORRECT_P1P2();
} }
@@ -442,7 +438,7 @@ static int cmd_get_metadata() {
else if (key_ref == 0x81) { else if (key_ref == 0x81) {
key_ref = EF_PIV_PUK; key_ref = EF_PIV_PUK;
} }
file_t *ef_key = search_by_fid(key_ref, NULL, SPECIFY_EF); file_t *ef_key = file_search_by_fid(key_ref, NULL, SPECIFY_EF);
if (!file_has_data(ef_key)) { if (!file_has_data(ef_key)) {
return SW_REFERENCE_NOT_FOUND(); return SW_REFERENCE_NOT_FOUND();
} }
@@ -470,13 +466,13 @@ static int cmd_get_metadata() {
mbedtls_rsa_context ctx; mbedtls_rsa_context ctx;
mbedtls_rsa_init(&ctx); mbedtls_rsa_init(&ctx);
int r = load_private_key_rsa(&ctx, ef_key, false); int r = load_private_key_rsa(&ctx, ef_key, false);
if (r != PICOKEY_OK) { if (r != PICOKEYS_OK) {
mbedtls_rsa_free(&ctx); mbedtls_rsa_free(&ctx);
return SW_EXEC_ERROR(); return SW_EXEC_ERROR();
} }
res_APDU[res_APDU_size++] = 0x81; res_APDU[res_APDU_size++] = 0x81;
res_APDU[res_APDU_size++] = 0x82; res_APDU[res_APDU_size++] = 0x82;
put_uint16_t_be(mbedtls_mpi_size(&ctx.N), res_APDU + res_APDU_size); res_APDU_size += 2; put_uint16_be(mbedtls_mpi_size(&ctx.N), res_APDU + res_APDU_size); res_APDU_size += 2;
mbedtls_mpi_write_binary(&ctx.N, res_APDU + res_APDU_size, mbedtls_mpi_size(&ctx.N)); mbedtls_mpi_write_binary(&ctx.N, res_APDU + res_APDU_size, mbedtls_mpi_size(&ctx.N));
res_APDU_size += mbedtls_mpi_size(&ctx.N); res_APDU_size += mbedtls_mpi_size(&ctx.N);
res_APDU[res_APDU_size++] = 0x82; res_APDU[res_APDU_size++] = 0x82;
@@ -489,7 +485,7 @@ static int cmd_get_metadata() {
mbedtls_ecdsa_context ctx; mbedtls_ecdsa_context ctx;
mbedtls_ecdsa_init(&ctx); mbedtls_ecdsa_init(&ctx);
int r = load_private_key_ecdsa(&ctx, ef_key, false); int r = load_private_key_ecdsa(&ctx, ef_key, false);
if (r != PICOKEY_OK) { if (r != PICOKEYS_OK) {
mbedtls_ecdsa_free(&ctx); mbedtls_ecdsa_free(&ctx);
return SW_EXEC_ERROR(); return SW_EXEC_ERROR();
} }
@@ -529,26 +525,27 @@ static int cmd_get_metadata() {
uint8_t dhash[32]; uint8_t dhash[32];
int32_t eq = 0; int32_t eq = 0;
if (key_ref == EF_PIV_PIN) { if (key_ref == EF_PIV_PIN) {
double_hash_pin((const uint8_t *)"\x31\x32\x33\x34\x35\x36\xFF\xFF", 8, dhash); pin_derive_verifier((const uint8_t *)"\x31\x32\x33\x34\x35\x36\xFF\xFF", 8, dhash);
eq = memcmp(dhash, file_get_data(ef_key) + 1, file_get_size(ef_key) - 1); eq = memcmp(dhash, file_get_data(ef_key) + 1, file_get_size(ef_key) - 1);
} }
else if (key_ref == EF_PIV_PUK) { else if (key_ref == EF_PIV_PUK) {
double_hash_pin((const uint8_t *)"\x31\x32\x33\x34\x35\x36\x37\x38", 8, dhash); pin_derive_verifier((const uint8_t *)"\x31\x32\x33\x34\x35\x36\x37\x38", 8, dhash);
eq = memcmp(dhash, file_get_data(ef_key) + 1, file_get_size(ef_key) - 1); eq = memcmp(dhash, file_get_data(ef_key) + 1, file_get_size(ef_key) - 1);
} }
else if (key_ref == EF_PIV_KEY_CARDMGM) { else if (key_ref == EF_PIV_KEY_CARDMGM) {
eq = memcmp("\x01\x02\x03\x04\x05\x06\x07\x08\x01\x02\x03\x04\x05\x06\x07\x08\x01\x02\x03\x04\x05\x06\x07\x08", file_get_data(ef_key), file_get_size(ef_key)); pin_derive_verifier((const uint8_t *)"\x01\x02\x03\x04\x05\x06\x07\x08\x01\x02\x03\x04\x05\x06\x07\x08\x01\x02\x03\x04\x05\x06\x07\x08", 24, dhash);
eq = memcmp(dhash, file_get_data(ef_key), file_get_size(ef_key));
} }
res_APDU[res_APDU_size++] = 0x5; res_APDU[res_APDU_size++] = 0x5;
res_APDU[res_APDU_size++] = 1; res_APDU[res_APDU_size++] = 1;
res_APDU[res_APDU_size++] = eq == 0; res_APDU[res_APDU_size++] = eq == 0;
if (key_ref == EF_PIV_PIN || key_ref == EF_PIV_PUK) { if (key_ref == EF_PIV_PIN || key_ref == EF_PIV_PUK) {
file_t *pw_status; file_t *pw_status;
if (!(pw_status = search_by_fid(EF_PW_PRIV, NULL, SPECIFY_EF))) { if (!(pw_status = file_search_by_fid(EF_PW_PRIV, NULL, SPECIFY_EF))) {
return SW_REFERENCE_NOT_FOUND(); return SW_REFERENCE_NOT_FOUND();
} }
uint8_t retries = *(file_get_data(pw_status) + 3 + (key_ref & 0xf)); uint8_t retries = *(file_get_data(pw_status) + 3 + (key_ref & 0xf));
if (!(pw_status = search_by_fid(EF_PW_RETRIES, NULL, SPECIFY_EF))) { if (!(pw_status = file_search_by_fid(EF_PW_RETRIES, NULL, SPECIFY_EF))) {
return SW_REFERENCE_NOT_FOUND(); return SW_REFERENCE_NOT_FOUND();
} }
uint8_t total = *(file_get_data(pw_status) + (key_ref & 0xf)); uint8_t total = *(file_get_data(pw_status) + (key_ref & 0xf));
@@ -563,7 +560,7 @@ static int cmd_get_metadata() {
uint8_t challenge[16]; uint8_t challenge[16];
bool has_challenge = false; bool has_challenge = false;
bool has_mgm = false; bool has_mgm = false;
static int cmd_authenticate() { static int cmd_authenticate(void) {
uint8_t algo = P1(apdu), key_ref = P2(apdu); uint8_t algo = P1(apdu), key_ref = P2(apdu);
if (apdu.nc == 0) { if (apdu.nc == 0) {
return SW_WRONG_LENGTH(); return SW_WRONG_LENGTH();
@@ -575,7 +572,7 @@ static int cmd_authenticate() {
if (algo != PIV_ALGO_AES128 && algo != PIV_ALGO_AES192 && algo != PIV_ALGO_AES256 && algo != PIV_ALGO_3DES) { if (algo != PIV_ALGO_AES128 && algo != PIV_ALGO_AES192 && algo != PIV_ALGO_AES256 && algo != PIV_ALGO_3DES) {
return SW_INCORRECT_P1P2(); return SW_INCORRECT_P1P2();
} }
file_t *ef_mgm = search_by_fid(key_ref, NULL, SPECIFY_EF); file_t *ef_mgm = file_search_by_fid(key_ref, NULL, SPECIFY_EF);
if (!file_has_data(ef_mgm)) { if (!file_has_data(ef_mgm)) {
return SW_MEMORY_FAILURE(); return SW_MEMORY_FAILURE();
} }
@@ -617,7 +614,7 @@ static int cmd_authenticate() {
if (key_ref != EF_PIV_KEY_CARDMGM) { if (key_ref != EF_PIV_KEY_CARDMGM) {
return SW_INCORRECT_P1P2(); return SW_INCORRECT_P1P2();
} }
file_t *ef_mgm = search_by_fid(key_ref, NULL, SPECIFY_EF); file_t *ef_mgm = file_search_by_fid(key_ref, NULL, SPECIFY_EF);
if (!file_has_data(ef_mgm)) { if (!file_has_data(ef_mgm)) {
return SW_MEMORY_FAILURE(); return SW_MEMORY_FAILURE();
} }
@@ -684,7 +681,7 @@ static int cmd_authenticate() {
has_challenge = true; has_challenge = true;
} }
else { else {
file_t *ef_key = search_by_fid(key_ref == 0x93 ? EF_PIV_KEY_RETIRED18 : key_ref, NULL, SPECIFY_EF); file_t *ef_key = file_search_by_fid(key_ref == 0x93 ? EF_PIV_KEY_RETIRED18 : key_ref, NULL, SPECIFY_EF);
if (!file_has_data(ef_key)) { if (!file_has_data(ef_key)) {
return SW_MEMORY_FAILURE(); return SW_MEMORY_FAILURE();
} }
@@ -692,7 +689,7 @@ static int cmd_authenticate() {
mbedtls_rsa_context ctx; mbedtls_rsa_context ctx;
mbedtls_rsa_init(&ctx); mbedtls_rsa_init(&ctx);
int r = load_private_key_rsa(&ctx, ef_key, false); int r = load_private_key_rsa(&ctx, ef_key, false);
if (r != PICOKEY_OK) { if (r != PICOKEYS_OK) {
mbedtls_rsa_free(&ctx); mbedtls_rsa_free(&ctx);
return SW_EXEC_ERROR(); return SW_EXEC_ERROR();
} }
@@ -705,7 +702,7 @@ static int cmd_authenticate() {
memcpy(res_APDU, "\x7C\x82\x00\x00\x82\x82\x00\x00", 8); memcpy(res_APDU, "\x7C\x82\x00\x00\x82\x82\x00\x00", 8);
res_APDU_size = 8; res_APDU_size = 8;
} }
r = mbedtls_rsa_private(&ctx, random_gen, NULL, a81.data, res_APDU + res_APDU_size); r = mbedtls_rsa_private(&ctx, random_fill_iterator, NULL, a81.data, res_APDU + res_APDU_size);
mbedtls_rsa_free(&ctx); mbedtls_rsa_free(&ctx);
if (algo == PIV_ALGO_RSA1024) { if (algo == PIV_ALGO_RSA1024) {
res_APDU[res_APDU_size - 1] = olen; res_APDU[res_APDU_size - 1] = olen;
@@ -726,14 +723,14 @@ static int cmd_authenticate() {
mbedtls_ecdsa_context ctx; mbedtls_ecdsa_context ctx;
mbedtls_ecdsa_init(&ctx); mbedtls_ecdsa_init(&ctx);
int r = load_private_key_ecdsa(&ctx, ef_key, false); int r = load_private_key_ecdsa(&ctx, ef_key, false);
if (r != PICOKEY_OK) { if (r != PICOKEYS_OK) {
mbedtls_ecdsa_free(&ctx); mbedtls_ecdsa_free(&ctx);
return SW_EXEC_ERROR(); return SW_EXEC_ERROR();
} }
size_t olen = 0; size_t olen = 0;
memcpy(res_APDU, "\x7C\x00\x82\x00", 4); memcpy(res_APDU, "\x7C\x00\x82\x00", 4);
res_APDU_size = 4; res_APDU_size = 4;
r = mbedtls_ecdsa_write_signature(&ctx, algo == PIV_ALGO_ECCP256 ? MBEDTLS_MD_SHA256 : MBEDTLS_MD_SHA384, a81.data, a81.len, res_APDU + res_APDU_size, MBEDTLS_ECDSA_MAX_LEN, &olen, random_gen, NULL); r = mbedtls_ecdsa_write_signature(&ctx, algo == PIV_ALGO_ECCP256 ? MBEDTLS_MD_SHA256 : MBEDTLS_MD_SHA384, a81.data, a81.len, res_APDU + res_APDU_size, MBEDTLS_ECDSA_MAX_LEN, &olen, random_fill_iterator, NULL);
mbedtls_ecdsa_free(&ctx); mbedtls_ecdsa_free(&ctx);
res_APDU[res_APDU_size - 1] = olen; res_APDU[res_APDU_size - 1] = olen;
res_APDU[res_APDU_size - 3] = olen + 2; res_APDU[res_APDU_size - 3] = olen + 2;
@@ -797,7 +794,7 @@ static int cmd_authenticate() {
if (chal_len != a82.len) { if (chal_len != a82.len) {
return SW_DATA_INVALID(); return SW_DATA_INVALID();
} }
file_t *ef_key = search_by_fid(key_ref, NULL, SPECIFY_EF); file_t *ef_key = file_search_by_fid(key_ref, NULL, SPECIFY_EF);
if (!file_has_data(ef_key)) { if (!file_has_data(ef_key)) {
return SW_MEMORY_FAILURE(); return SW_MEMORY_FAILURE();
} }
@@ -840,7 +837,7 @@ static int cmd_authenticate() {
return SW_OK(); return SW_OK();
} }
static int cmd_asym_keygen() { static int cmd_asym_keygen(void) {
uint8_t key_ref = P2(apdu); uint8_t key_ref = P2(apdu);
if (apdu.nc == 0) { if (apdu.nc == 0) {
return SW_WRONG_LENGTH(); return SW_WRONG_LENGTH();
@@ -895,7 +892,7 @@ static int cmd_asym_keygen() {
if (asn1_len(&a81)) { if (asn1_len(&a81)) {
exponent = (int)asn1_get_uint(&a81); exponent = (int)asn1_get_uint(&a81);
} }
int r = mbedtls_rsa_gen_key(&rsa, random_gen, NULL, nlen, exponent); int r = mbedtls_rsa_gen_key(&rsa, random_fill_iterator, NULL, nlen, exponent);
if (r != 0) { if (r != 0) {
mbedtls_rsa_free(&rsa); mbedtls_rsa_free(&rsa);
return SW_EXEC_ERROR(); return SW_EXEC_ERROR();
@@ -903,11 +900,11 @@ static int cmd_asym_keygen() {
make_rsa_response(&rsa); make_rsa_response(&rsa);
uint8_t cert[2048]; uint8_t cert[2048];
r = x509_create_cert(&rsa, a80.data[0], key_ref, false, cert, sizeof(cert)); r = x509_create_cert(&rsa, a80.data[0], key_ref, false, cert, sizeof(cert));
file_t *ef = search_by_fid(key_cert, NULL, SPECIFY_ANY); file_t *ef = file_search_by_fid(key_cert, NULL, SPECIFY_ANY);
file_put_data(ef, cert + sizeof(cert) - r, r); file_put_data(ef, cert + sizeof(cert) - r, r);
r = store_keys(&rsa, ALGO_RSA, key_ref == 0x93 ? EF_PIV_KEY_RETIRED18 : key_ref, false); r = store_keys(&rsa, ALGO_RSA, key_ref == 0x93 ? EF_PIV_KEY_RETIRED18 : key_ref, false);
mbedtls_rsa_free(&rsa); mbedtls_rsa_free(&rsa);
if (r != PICOKEY_OK) { if (r != PICOKEYS_OK) {
return SW_EXEC_ERROR(); return SW_EXEC_ERROR();
} }
} }
@@ -916,7 +913,7 @@ static int cmd_asym_keygen() {
mbedtls_ecp_group_id gid = a80.data[0] == PIV_ALGO_ECCP256 ? MBEDTLS_ECP_DP_SECP256R1 : MBEDTLS_ECP_DP_SECP384R1; mbedtls_ecp_group_id gid = a80.data[0] == PIV_ALGO_ECCP256 ? MBEDTLS_ECP_DP_SECP256R1 : MBEDTLS_ECP_DP_SECP384R1;
mbedtls_ecdsa_context ecdsa; mbedtls_ecdsa_context ecdsa;
mbedtls_ecdsa_init(&ecdsa); mbedtls_ecdsa_init(&ecdsa);
int r = mbedtls_ecdsa_genkey(&ecdsa, gid, random_gen, NULL); int r = mbedtls_ecdsa_genkey(&ecdsa, gid, random_fill_iterator, NULL);
if (r != 0) { if (r != 0) {
mbedtls_ecdsa_free(&ecdsa); mbedtls_ecdsa_free(&ecdsa);
return SW_EXEC_ERROR(); return SW_EXEC_ERROR();
@@ -924,11 +921,11 @@ static int cmd_asym_keygen() {
make_ecdsa_response(&ecdsa); make_ecdsa_response(&ecdsa);
uint8_t cert[2048]; uint8_t cert[2048];
r = x509_create_cert(&ecdsa, a80.data[0], key_ref, false, cert, sizeof(cert)); r = x509_create_cert(&ecdsa, a80.data[0], key_ref, false, cert, sizeof(cert));
file_t *ef = search_by_fid(key_cert, NULL, SPECIFY_ANY); file_t *ef = file_search_by_fid(key_cert, NULL, SPECIFY_ANY);
file_put_data(ef, cert + sizeof(cert) - r, r); file_put_data(ef, cert + sizeof(cert) - r, r);
r = store_keys(&ecdsa, ALGO_ECDSA, key_ref == 0x93 ? EF_PIV_KEY_RETIRED18 : key_ref, false); r = store_keys(&ecdsa, ALGO_ECDSA, key_ref == 0x93 ? EF_PIV_KEY_RETIRED18 : key_ref, false);
mbedtls_ecdsa_free(&ecdsa); mbedtls_ecdsa_free(&ecdsa);
if (r != PICOKEY_OK) { if (r != PICOKEYS_OK) {
return SW_EXEC_ERROR(); return SW_EXEC_ERROR();
} }
} }
@@ -943,11 +940,11 @@ static int cmd_asym_keygen() {
} }
uint8_t meta[] = {a80.data[0], asn1_len(&aaa) ? aaa.data[0] : def_pinpol, asn1_len(&aab) ? aab.data[0] : TOUCHPOLICY_ALWAYS, ORIGIN_GENERATED}; uint8_t meta[] = {a80.data[0], asn1_len(&aaa) ? aaa.data[0] : def_pinpol, asn1_len(&aab) ? aab.data[0] : TOUCHPOLICY_ALWAYS, ORIGIN_GENERATED};
meta_add(key_ref, meta, sizeof(meta)); meta_add(key_ref, meta, sizeof(meta));
low_flash_available(); flash_commit();
return SW_OK(); return SW_OK();
} }
static int cmd_put_data() { static int cmd_piv_put_data(void) {
if (P1(apdu) != 0x3F || P2(apdu) != 0xFF) { if (P1(apdu) != 0x3F || P2(apdu) != 0xFF) {
return SW_INCORRECT_P1P2(); return SW_INCORRECT_P1P2();
} }
@@ -961,7 +958,7 @@ static int cmd_put_data() {
return SW_WRONG_DATA(); return SW_WRONG_DATA();
} }
uint16_t fid = (a5c.data[1] << 8 | a5c.data[2]); uint16_t fid = (a5c.data[1] << 8 | a5c.data[2]);
file_t *ef = search_by_fid(fid, NULL, SPECIFY_EF); file_t *ef = file_search_by_fid(fid, NULL, SPECIFY_EF);
if (!ef) { if (!ef) {
return SW_MEMORY_FAILURE(); return SW_MEMORY_FAILURE();
} }
@@ -971,12 +968,12 @@ static int cmd_put_data() {
else { else {
flash_clear_file(ef); flash_clear_file(ef);
} }
low_flash_available(); flash_commit();
} }
return SW_OK(); return SW_OK();
} }
static int cmd_set_mgmkey() { static int cmd_set_mgmkey(void) {
if (P1(apdu) != 0xFF) { if (P1(apdu) != 0xFF) {
return SW_INCORRECT_P1P2(); return SW_INCORRECT_P1P2();
} }
@@ -997,7 +994,7 @@ static int cmd_set_mgmkey() {
if ((key_ref != EF_PIV_KEY_CARDMGM) || (!(algo == PIV_ALGO_AES128 && pinlen == 16) && !(algo == PIV_ALGO_AES192 && pinlen == 24) && !(algo == PIV_ALGO_AES256 && pinlen == 32) && !(algo == PIV_ALGO_3DES && pinlen == 24))) { if ((key_ref != EF_PIV_KEY_CARDMGM) || (!(algo == PIV_ALGO_AES128 && pinlen == 16) && !(algo == PIV_ALGO_AES192 && pinlen == 24) && !(algo == PIV_ALGO_AES256 && pinlen == 32) && !(algo == PIV_ALGO_3DES && pinlen == 24))) {
return SW_WRONG_DATA(); return SW_WRONG_DATA();
} }
file_t *ef = search_by_fid(key_ref, NULL, SPECIFY_ANY); file_t *ef = file_search_by_fid(key_ref, NULL, SPECIFY_ANY);
file_put_data(ef, apdu.data + 3, pinlen); file_put_data(ef, apdu.data + 3, pinlen);
uint8_t *meta = NULL, new_meta[4]; uint8_t *meta = NULL, new_meta[4];
int meta_len = 0; int meta_len = 0;
@@ -1008,11 +1005,11 @@ static int cmd_set_mgmkey() {
new_meta[0] = algo; new_meta[0] = algo;
new_meta[2] = touch; new_meta[2] = touch;
meta_add(key_ref, new_meta, sizeof(new_meta)); meta_add(key_ref, new_meta, sizeof(new_meta));
low_flash_available(); flash_commit();
return SW_OK(); return SW_OK();
} }
static int cmd_move_key() { static int cmd_move_key(void) {
if (apdu.nc != 0) { if (apdu.nc != 0) {
return SW_WRONG_LENGTH(); return SW_WRONG_LENGTH();
} }
@@ -1020,6 +1017,9 @@ static int cmd_move_key() {
if ((!IS_KEY(to) && to != 0xFF) || !IS_KEY(from)) { if ((!IS_KEY(to) && to != 0xFF) || !IS_KEY(from)) {
return SW_INCORRECT_P1P2(); return SW_INCORRECT_P1P2();
} }
if (IS_RETIRED(from) && IS_ACTIVE(to)) {
return SW_INCORRECT_P1P2();
}
if (from == 0x93) { if (from == 0x93) {
from = EF_PIV_KEY_RETIRED18; from = EF_PIV_KEY_RETIRED18;
} }
@@ -1027,23 +1027,99 @@ static int cmd_move_key() {
to = EF_PIV_KEY_RETIRED18; to = EF_PIV_KEY_RETIRED18;
} }
file_t *efs, *efd; file_t *efs, *efd;
if (!(efs = search_by_fid(from, NULL, SPECIFY_EF)) || (!(efd = search_by_fid(to, NULL, SPECIFY_EF)) && to != 0xFF)) { if (!(efs = file_search_by_fid(from, NULL, SPECIFY_EF)) || (!(efd = file_search_by_fid(to, NULL, SPECIFY_EF)) && to != 0xFF)) {
return SW_FILE_NOT_FOUND(); return SW_FILE_NOT_FOUND();
} }
uint16_t cert_from_fid = 0;
uint16_t cert_to_fid = 0;
if (from == EF_PIV_KEY_AUTHENTICATION) {
cert_from_fid = EF_PIV_AUTHENTICATION;
}
else if (from == EF_PIV_KEY_SIGNATURE) {
cert_from_fid = EF_PIV_SIGNATURE;
}
else if (from == EF_PIV_KEY_KEYMGM) {
cert_from_fid = EF_PIV_KEY_MANAGEMENT;
}
else if (from == EF_PIV_KEY_CARDAUTH) {
cert_from_fid = EF_PIV_CARD_AUTH;
}
else if (from == EF_PIV_KEY_RETIRED18) {
cert_from_fid = EF_PIV_RETIRED18;
}
else {
cert_from_fid = from + 0xC08B;
}
if (to != 0xFF) {
if (to == EF_PIV_KEY_AUTHENTICATION) {
cert_to_fid = EF_PIV_AUTHENTICATION;
}
else if (to == EF_PIV_KEY_SIGNATURE) {
cert_to_fid = EF_PIV_SIGNATURE;
}
else if (to == EF_PIV_KEY_KEYMGM) {
cert_to_fid = EF_PIV_KEY_MANAGEMENT;
}
else if (to == EF_PIV_KEY_CARDAUTH) {
cert_to_fid = EF_PIV_CARD_AUTH;
}
else if (to == EF_PIV_KEY_RETIRED18) {
cert_to_fid = EF_PIV_RETIRED18;
}
else {
cert_to_fid = to + 0xC08B;
}
}
if (to != 0xFF) { if (to != 0xFF) {
file_put_data(efd, file_get_data(efs), file_get_size(efs)); file_put_data(efd, file_get_data(efs), file_get_size(efs));
} }
file_t *ef_cert_from = file_search_by_fid(cert_from_fid, NULL, SPECIFY_EF);
if (to != 0xFF) {
file_t *ef_cert_to = file_search_by_fid(cert_to_fid, NULL, SPECIFY_EF);
if (!ef_cert_to) {
return SW_FILE_NOT_FOUND();
}
if (file_has_data(ef_cert_from)) {
file_put_data(ef_cert_to, file_get_data(ef_cert_from), file_get_size(ef_cert_from));
}
else {
flash_clear_file(ef_cert_to);
}
}
if (ef_cert_from) {
flash_clear_file(ef_cert_from);
}
uint8_t *meta_src = NULL;
int meta_len = meta_find(from, &meta_src);
if (to != 0xFF) {
if (meta_len > 0 && meta_src != NULL) {
uint8_t *meta_copy = (uint8_t *)calloc(1, (size_t)meta_len);
if (!meta_copy) {
return SW_MEMORY_FAILURE();
}
memcpy(meta_copy, meta_src, (size_t)meta_len);
meta_add(to, meta_copy, (uint16_t)meta_len);
free(meta_copy);
}
else {
meta_delete(to);
}
}
meta_delete(from);
flash_clear_file(efs); flash_clear_file(efs);
low_flash_available(); flash_commit();
return SW_OK(); return SW_OK();
} }
static int cmd_change_pin() { static int cmd_piv_change_pin(void) {
uint8_t pin_ref = P2(apdu); uint8_t pin_ref = P2(apdu);
if (P1(apdu) != 0x0 || (pin_ref != 0x80 && pin_ref != 0x81)) { if (P1(apdu) != 0x0 || (pin_ref != 0x80 && pin_ref != 0x81)) {
return SW_INCORRECT_P1P2(); return SW_INCORRECT_P1P2();
} }
file_t *ef = search_by_fid(pin_ref == 0x80 ? EF_PIV_PIN : EF_PIV_PUK, NULL, SPECIFY_ANY); file_t *ef = file_search_by_fid(pin_ref == 0x80 ? EF_PIV_PIN : EF_PIV_PUK, NULL, SPECIFY_ANY);
if (!ef) { if (!ef) {
return SW_MEMORY_FAILURE(); return SW_MEMORY_FAILURE();
} }
@@ -1052,19 +1128,21 @@ static int cmd_change_pin() {
if (ret != 0x9000) { if (ret != 0x9000) {
return ret; return ret;
} }
uint8_t dhash[33];
uint8_t dhash[34];
dhash[0] = pin_len; dhash[0] = pin_len;
double_hash_pin(apdu.data + pin_data[0], pin_len, dhash + 1); dhash[1] = 0x1; // Format
pin_derive_verifier(apdu.data + pin_data[0], pin_len, dhash + 2);
file_put_data(ef, dhash, sizeof(dhash)); file_put_data(ef, dhash, sizeof(dhash));
low_flash_available(); flash_commit();
return SW_OK(); return SW_OK();
} }
static int cmd_reset_retry() { static int cmd_piv_reset_retry(void) {
if (P1(apdu) != 0x0 || P2(apdu) != 0x80) { if (P1(apdu) != 0x0 || P2(apdu) != 0x80) {
return SW_INCORRECT_P1P2(); return SW_INCORRECT_P1P2();
} }
file_t *ef = search_by_fid(EF_PIV_PUK, NULL, SPECIFY_ANY); file_t *ef = file_search_by_fid(EF_PIV_PUK, NULL, SPECIFY_ANY);
if (!ef) { if (!ef) {
return SW_MEMORY_FAILURE(); return SW_MEMORY_FAILURE();
} }
@@ -1073,18 +1151,19 @@ static int cmd_reset_retry() {
if (ret != 0x9000) { if (ret != 0x9000) {
return ret; return ret;
} }
uint8_t dhash[33]; uint8_t dhash[34];
dhash[0] = pin_len; dhash[0] = pin_len;
double_hash_pin(apdu.data + puk_data[0], pin_len, dhash + 1); dhash[1] = 0x1; // Format
ef = search_by_fid(EF_PIV_PIN, NULL, SPECIFY_ANY); pin_derive_verifier(apdu.data + puk_data[0], pin_len, dhash + 2);
ef = file_search_by_fid(EF_PIV_PIN, NULL, SPECIFY_ANY);
file_put_data(ef, dhash, sizeof(dhash)); file_put_data(ef, dhash, sizeof(dhash));
pin_reset_retries(ef, true); pin_reset_retries(ef, true);
low_flash_available(); flash_commit();
return SW_OK(); return SW_OK();
} }
static int cmd_set_retries() { static int cmd_set_retries(void) {
file_t *ef = search_by_fid(EF_PW_RETRIES, NULL, SPECIFY_ANY); file_t *ef = file_search_by_fid(EF_PW_RETRIES, NULL, SPECIFY_ANY);
if (!ef) { if (!ef) {
return SW_MEMORY_FAILURE(); return SW_MEMORY_FAILURE();
} }
@@ -1095,31 +1174,34 @@ static int cmd_set_retries() {
file_put_data(ef, tmp, file_get_size(ef)); file_put_data(ef, tmp, file_get_size(ef));
free(tmp); free(tmp);
ef = search_by_fid(EF_PIV_PIN, NULL, SPECIFY_ANY); ef = file_search_by_fid(EF_PIV_PIN, NULL, SPECIFY_ANY);
const uint8_t def_pin[8] = { 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0xFF, 0xFF }; const uint8_t def_pin[8] = { 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0xFF, 0xFF };
uint8_t dhash[33];
uint8_t dhash[34];
dhash[0] = sizeof(def_pin); dhash[0] = sizeof(def_pin);
double_hash_pin(def_pin, sizeof(def_pin), dhash + 1); dhash[1] = 0x1; // Format
pin_derive_verifier(def_pin, sizeof(def_pin), dhash + 2);
file_put_data(ef, dhash, sizeof(dhash)); file_put_data(ef, dhash, sizeof(dhash));
pin_reset_retries(ef, true); pin_reset_retries(ef, true);
ef = search_by_fid(EF_PIV_PUK, NULL, SPECIFY_ANY); ef = file_search_by_fid(EF_PIV_PUK, NULL, SPECIFY_ANY);
const uint8_t def_puk[8] = {0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38}; const uint8_t def_puk[8] = {0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38};
dhash[0] = sizeof(def_puk); dhash[0] = sizeof(def_puk);
double_hash_pin(def_puk, sizeof(def_puk), dhash + 1); dhash[1] = 0x1; // Format
pin_derive_verifier(def_puk, sizeof(def_puk), dhash + 2);
file_put_data(ef, dhash, sizeof(dhash)); file_put_data(ef, dhash, sizeof(dhash));
pin_reset_retries(ef, true); pin_reset_retries(ef, true);
low_flash_available(); flash_commit();
return SW_OK(); return SW_OK();
} }
static int cmd_reset() { static int cmd_reset(void) {
if (P1(apdu) != 0x0 || P2(apdu) != 0x0) { if (P1(apdu) != 0x0 || P2(apdu) != 0x0) {
return SW_INCORRECT_P1P2(); return SW_INCORRECT_P1P2();
} }
file_t *pw_status; file_t *pw_status;
if (!(pw_status = search_by_fid(EF_PW_PRIV, NULL, SPECIFY_EF))) if (!(pw_status = file_search_by_fid(EF_PW_PRIV, NULL, SPECIFY_EF)))
{ {
return SW_REFERENCE_NOT_FOUND(); return SW_REFERENCE_NOT_FOUND();
} }
@@ -1127,13 +1209,13 @@ static int cmd_reset() {
if (retPIN != 0 || retPUK != 0) { if (retPIN != 0 || retPUK != 0) {
return SW_INCORRECT_PARAMS(); return SW_INCORRECT_PARAMS();
} }
initialize_flash(true); file_initialize_flash(true);
low_flash_available(); flash_commit();
init_piv(); init_piv();
return SW_OK(); return SW_OK();
} }
static int cmd_attestation() { static int cmd_attestation(void) {
uint8_t key_ref = P1(apdu); uint8_t key_ref = P1(apdu);
if (P2(apdu) != 0x00) { if (P2(apdu) != 0x00) {
return SW_INCORRECT_P1P2(); return SW_INCORRECT_P1P2();
@@ -1144,7 +1226,7 @@ static int cmd_attestation() {
file_t *ef_key = NULL; file_t *ef_key = NULL;
int meta_len = 0; int meta_len = 0;
uint8_t *meta = NULL; uint8_t *meta = NULL;
if (!(ef_key = search_by_fid(key_ref == 0x93 ? EF_PIV_KEY_RETIRED18 : key_ref, NULL, SPECIFY_EF)) || !file_has_data(ef_key)) { if (!(ef_key = file_search_by_fid(key_ref == 0x93 ? EF_PIV_KEY_RETIRED18 : key_ref, NULL, SPECIFY_EF)) || !file_has_data(ef_key)) {
return SW_REFERENCE_NOT_FOUND(); return SW_REFERENCE_NOT_FOUND();
} }
if ((meta_len = meta_find(key_ref, &meta)) <= 0) { if ((meta_len = meta_find(key_ref, &meta)) <= 0) {
@@ -1154,26 +1236,27 @@ static int cmd_attestation() {
return SW_INCORRECT_PARAMS(); return SW_INCORRECT_PARAMS();
} }
int r = 0; int r = 0;
uint8_t abuf[2048];
if (meta[0] == PIV_ALGO_RSA1024 || meta[0] == PIV_ALGO_RSA2048) { if (meta[0] == PIV_ALGO_RSA1024 || meta[0] == PIV_ALGO_RSA2048) {
mbedtls_rsa_context ctx; mbedtls_rsa_context ctx;
mbedtls_rsa_init(&ctx); mbedtls_rsa_init(&ctx);
r = load_private_key_rsa(&ctx, ef_key, false); r = load_private_key_rsa(&ctx, ef_key, false);
if (r != PICOKEY_OK) { if (r != PICOKEYS_OK) {
mbedtls_rsa_free(&ctx); mbedtls_rsa_free(&ctx);
return SW_EXEC_ERROR(); return SW_EXEC_ERROR();
} }
r = x509_create_cert(&ctx, meta[0], key_ref, true, res_APDU, 2048); r = x509_create_cert(&ctx, meta[0], key_ref, true, abuf, sizeof(abuf));
mbedtls_rsa_free(&ctx); mbedtls_rsa_free(&ctx);
} }
else if (meta[0] == PIV_ALGO_ECCP256 || meta[0] == PIV_ALGO_ECCP384) { else if (meta[0] == PIV_ALGO_ECCP256 || meta[0] == PIV_ALGO_ECCP384) {
mbedtls_ecdsa_context ctx; mbedtls_ecdsa_context ctx;
mbedtls_ecdsa_init(&ctx); mbedtls_ecdsa_init(&ctx);
r = load_private_key_ecdsa(&ctx, ef_key, false); r = load_private_key_ecdsa(&ctx, ef_key, false);
if (r != PICOKEY_OK) { if (r != PICOKEYS_OK) {
mbedtls_ecdsa_free(&ctx); mbedtls_ecdsa_free(&ctx);
return SW_EXEC_ERROR(); return SW_EXEC_ERROR();
} }
r = x509_create_cert(&ctx, meta[0], key_ref, true, res_APDU, 2048); r = x509_create_cert(&ctx, meta[0], key_ref, true, abuf, sizeof(abuf));
mbedtls_ecdsa_free(&ctx); mbedtls_ecdsa_free(&ctx);
} }
else { else {
@@ -1182,12 +1265,12 @@ static int cmd_attestation() {
if (r <= 0) { if (r <= 0) {
return SW_EXEC_ERROR(); return SW_EXEC_ERROR();
} }
memmove(res_APDU, res_APDU + 2048 - r, r); memcpy(res_APDU, abuf + sizeof(abuf) - r, r);
res_APDU_size = r; res_APDU_size = r;
return SW_OK(); return SW_OK();
} }
static int cmd_import_asym() { static int cmd_import_asym(void) {
uint8_t algo = P1(apdu), key_ref = P2(apdu); uint8_t algo = P1(apdu), key_ref = P2(apdu);
if (key_ref != EF_PIV_KEY_AUTHENTICATION && key_ref != EF_PIV_KEY_SIGNATURE && key_ref != EF_PIV_KEY_KEYMGM && key_ref != EF_PIV_KEY_CARDAUTH && !(key_ref >= EF_PIV_KEY_RETIRED1 && key_ref <= EF_PIV_KEY_RETIRED20)) { if (key_ref != EF_PIV_KEY_AUTHENTICATION && key_ref != EF_PIV_KEY_SIGNATURE && key_ref != EF_PIV_KEY_KEYMGM && key_ref != EF_PIV_KEY_CARDAUTH && !(key_ref >= EF_PIV_KEY_RETIRED1 && key_ref <= EF_PIV_KEY_RETIRED20)) {
return SW_INCORRECT_P1P2(); return SW_INCORRECT_P1P2();
@@ -1252,12 +1335,12 @@ static int cmd_import_asym() {
mbedtls_ecdsa_free(&ecdsa); mbedtls_ecdsa_free(&ecdsa);
return SW_EXEC_ERROR(); return SW_EXEC_ERROR();
} }
r = mbedtls_ecp_mul(&ecdsa.grp, &ecdsa.Q, &ecdsa.d, &ecdsa.grp.G, random_gen, NULL); r = mbedtls_ecp_keypair_calc_public(&ecdsa, random_fill_iterator, NULL);
if (r != 0) { if (r != 0) {
mbedtls_ecdsa_free(&ecdsa); mbedtls_ecdsa_free(&ecdsa);
return SW_EXEC_ERROR(); return SW_EXEC_ERROR();
} }
r = mbedtls_ecp_check_pub_priv(&ecdsa, &ecdsa, random_gen, NULL); r = mbedtls_ecp_check_pub_priv(&ecdsa, &ecdsa, random_fill_iterator, NULL);
if (r != 0) { if (r != 0) {
mbedtls_ecdsa_free(&ecdsa); mbedtls_ecdsa_free(&ecdsa);
return SW_EXEC_ERROR(); return SW_EXEC_ERROR();
@@ -1301,18 +1384,18 @@ static int cmd_import_asym() {
static const cmd_t cmds[] = { static const cmd_t cmds[] = {
{ INS_VERSION, cmd_version }, { INS_VERSION, cmd_version },
{ INS_SELECT, cmd_select }, { INS_SELECT, cmd_piv_select },
{ INS_YK_SERIAL, cmd_get_serial }, { INS_YK_SERIAL, cmd_get_serial },
{ INS_VERIFY, cmd_verify }, { INS_VERIFY, cmd_piv_verify },
{ INS_GET_DATA, cmd_get_data }, { INS_GET_DATA, cmd_piv_get_data },
{ INS_GET_METADATA, cmd_get_metadata }, { INS_GET_METADATA, cmd_get_metadata },
{ INS_AUTHENTICATE, cmd_authenticate }, { INS_AUTHENTICATE, cmd_authenticate },
{ INS_ASYM_KEYGEN, cmd_asym_keygen }, { INS_ASYM_KEYGEN, cmd_asym_keygen },
{ INS_PUT_DATA, cmd_put_data }, { INS_PUT_DATA, cmd_piv_put_data },
{ INS_SET_MGMKEY, cmd_set_mgmkey }, { INS_SET_MGMKEY, cmd_set_mgmkey },
{ INS_MOVE_KEY, cmd_move_key }, { INS_MOVE_KEY, cmd_move_key },
{ INS_CHANGE_PIN, cmd_change_pin }, { INS_CHANGE_PIN, cmd_piv_change_pin },
{ INS_RESET_RETRY, cmd_reset_retry }, { INS_RESET_RETRY, cmd_piv_reset_retry },
{ INS_SET_RETRIES, cmd_set_retries }, { INS_SET_RETRIES, cmd_set_retries },
{ INS_RESET, cmd_reset }, { INS_RESET, cmd_reset },
{ INS_ATTESTATION, cmd_attestation }, { INS_ATTESTATION, cmd_attestation },
@@ -1320,7 +1403,7 @@ static const cmd_t cmds[] = {
{ 0x00, 0x0 } { 0x00, 0x0 }
}; };
int piv_process_apdu() { int piv_process_apdu(void) {
sm_unwrap(); sm_unwrap();
for (const cmd_t *cmd = cmds; cmd->ins != 0x00; cmd++) { for (const cmd_t *cmd = cmds; cmd->ins != 0x00; cmd++) {
if (cmd->ins == INS(apdu)) { if (cmd->ins == INS(apdu)) {

View File

@@ -29,7 +29,7 @@
#define PIV_VERSION_MINOR (PIV_VERSION & 0xff) #define PIV_VERSION_MINOR (PIV_VERSION & 0xff)
#define PIPGP_VERSION 0x0400 #define PIPGP_VERSION 0x0406
#define PIPGP_VERSION_MAJOR ((PIPGP_VERSION >> 8) & 0xff) #define PIPGP_VERSION_MAJOR ((PIPGP_VERSION >> 8) & 0xff)
#define PIPGP_VERSION_MINOR (PIPGP_VERSION & 0xff) #define PIPGP_VERSION_MINOR (PIPGP_VERSION & 0xff)

View File

@@ -3,5 +3,5 @@
source tests/docker_env.sh source tests/docker_env.sh
#run_in_docker rm -rf CMakeFiles #run_in_docker rm -rf CMakeFiles
run_in_docker mkdir -p build_in_docker run_in_docker mkdir -p build_in_docker
run_in_docker -w "$PWD/build_in_docker" cmake -DENABLE_EMULATION=1 -DENABLE_EDDSA=1 .. run_in_docker -w "$PWD/build_in_docker" cmake -DENABLE_EMULATION=1 -DENABLE_EDDSA=1 -DOPENPGP_TEST_INIT_LEGACY_PIN=ON ..
run_in_docker -w "$PWD/build_in_docker" make -j ${NUM_PROC} run_in_docker -w "$PWD/build_in_docker" make -j ${NUM_PROC}

View File

@@ -201,7 +201,7 @@ def test_extended_capabilities(card):
pytest.skip("Yubikey returns 6B00 when no key") pytest.skip("Yubikey returns 6B00 when no key")
else: else:
a = get_data_object(card, 0xc0) a = get_data_object(card, 0xc0)
assert a == None or match(b'[\x70\x74\x75\x77]\x00\x00.[\x00\x08]\x00\x00\xff[\x00\x01][\x00\x01]', a) assert a == None or match(b'[\x70\x7F\x75\x77]\x00\x00.[\x00\x08]\x00\x08\x00[\x00\x01][\x00\x01]', a)
def test_key_attributes_1(card): def test_key_attributes_1(card):
if card.is_yubikey: if card.is_yubikey:

View File

@@ -28,6 +28,26 @@ from card_const import *
from constants_for_test import * from constants_for_test import *
import pytest import pytest
PRIVATE_DO_0101 = (0x01, 0x01)
PRIVATE_DO_0102 = (0x01, 0x02)
PRIVATE_DO_0103 = (0x01, 0x03)
PRIVATE_DO_0104 = (0x01, 0x04)
def _assert_sw(e, sw_list):
sw = e.args[0]
assert sw in sw_list
def _expect_security_error(callable_):
try:
callable_()
except ValueError as e:
_assert_sw(e, ["6982", "6985"])
return
assert False
class Test_Card_Personalize_Card_2(object): class Test_Card_Personalize_Card_2(object):
def test_verify_pw3_0(self, card): def test_verify_pw3_0(self, card):
v = card.verify(3, PW3_TEST0) v = card.verify(3, PW3_TEST0)
@@ -202,3 +222,112 @@ class Test_Card_Personalize_Card_2(object):
def test_verify_pw3_2(self, card): def test_verify_pw3_2(self, card):
v = card.verify(3, PW3_TEST0) v = card.verify(3, PW3_TEST0)
assert v assert v
def test_private_do_0101_write_ok_with_pw3(self, card):
card.cmd_select_openpgp()
v = card.verify(3, PW3_TEST0)
assert v
r = card.cmd_put_data(PRIVATE_DO_0101[0], PRIVATE_DO_0101[1], b"priv0101_pw3_ok")
assert r
def test_private_do_0101_write_fail_with_pw1_81(self, card):
card.cmd_select_openpgp()
v = card.verify(1, PW1_TEST4)
assert v
_expect_security_error(
lambda: card.cmd_put_data(PRIVATE_DO_0101[0], PRIVATE_DO_0101[1], b"priv0101_pw1_81")
)
def test_private_do_0101_write_ok_with_pw1_82(self, card):
card.cmd_select_openpgp()
v = card.verify(2, PW1_TEST4)
assert v
r = card.cmd_put_data(PRIVATE_DO_0101[0], PRIVATE_DO_0101[1], b"priv0101_ok")
assert r
def test_private_do_0101_read_always(self, card):
card.cmd_select_openpgp()
data = get_data_object(card, 0x0101)
assert data == b"priv0101_ok" or data == b"priv0101_pw3_ok"
def test_private_do_0102_write_fail_with_pw1(self, card):
card.cmd_select_openpgp()
v = card.verify(2, PW1_TEST4)
assert v
_expect_security_error(
lambda: card.cmd_put_data(PRIVATE_DO_0102[0], PRIVATE_DO_0102[1], b"priv0102_pw1")
)
def test_private_do_0102_write_ok_with_pw3(self, card):
card.cmd_select_openpgp()
v = card.verify(3, PW3_TEST0)
assert v
r = card.cmd_put_data(PRIVATE_DO_0102[0], PRIVATE_DO_0102[1], b"priv0102_ok")
assert r
def test_private_do_0102_read_always(self, card):
card.cmd_select_openpgp()
data = get_data_object(card, 0x0102)
assert data == b"priv0102_ok"
def test_private_do_0103_read_fail_without_auth(self, card):
card.cmd_select_openpgp()
_expect_security_error(lambda: get_data_object(card, 0x0103))
def test_private_do_0103_read_fail_with_pw1_81(self, card):
card.cmd_select_openpgp()
v = card.verify(1, PW1_TEST4)
assert v
_expect_security_error(lambda: get_data_object(card, 0x0103))
def test_private_do_0103_write_ok_with_pw3(self, card):
card.cmd_select_openpgp()
v = card.verify(3, PW3_TEST0)
assert v
r = card.cmd_put_data(PRIVATE_DO_0103[0], PRIVATE_DO_0103[1], b"priv0103_pw3_ok")
assert r
def test_private_do_0103_read_ok_with_pw3(self, card):
card.cmd_select_openpgp()
v = card.verify(3, PW3_TEST0)
assert v
data = get_data_object(card, 0x0103)
assert data == b"priv0103_pw3_ok"
def test_private_do_0103_write_ok_with_pw1_82(self, card):
card.cmd_select_openpgp()
v = card.verify(2, PW1_TEST4)
assert v
r = card.cmd_put_data(PRIVATE_DO_0103[0], PRIVATE_DO_0103[1], b"priv0103_ok")
assert r
def test_private_do_0103_read_ok_with_pw1_82(self, card):
card.cmd_select_openpgp()
v = card.verify(2, PW1_TEST4)
assert v
data = get_data_object(card, 0x0103)
assert data == b"priv0103_ok"
def test_private_do_0104_read_fail_without_auth(self, card):
card.cmd_select_openpgp()
_expect_security_error(lambda: get_data_object(card, 0x0104))
def test_private_do_0104_read_fail_with_pw1(self, card):
card.cmd_select_openpgp()
v = card.verify(2, PW1_TEST4)
assert v
_expect_security_error(lambda: get_data_object(card, 0x0104))
def test_private_do_0104_write_ok_with_pw3(self, card):
card.cmd_select_openpgp()
v = card.verify(3, PW3_TEST0)
assert v
r = card.cmd_put_data(PRIVATE_DO_0104[0], PRIVATE_DO_0104[1], b"priv0104_ok")
assert r
def test_private_do_0104_read_ok_with_pw3(self, card):
card.cmd_select_openpgp()
v = card.verify(3, PW3_TEST0)
assert v
data = get_data_object(card, 0x0104)
assert data == b"priv0104_ok"