16 Commits
v1.4 ... v1.6

Author SHA1 Message Date
Pol Henarejos
35fb97c58f Upgraded to version 1.6
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-06-06 14:40:34 +02:00
Pol Henarejos
3fa5dbccd0 Upgrade patch tool to version 2.0 of Pico CCID.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-06-06 14:40:19 +02:00
Pol Henarejos
b674708955 Added fixes for Pico CCID.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-06-06 14:38:13 +02:00
Pol Henarejos
86b508f2ae Updated README with new Pico CCID stack.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-06-06 01:47:18 +02:00
Pol Henarejos
167b6d9770 Adapted to Pico CCID 2.0.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-06-06 01:01:52 +02:00
Pol Henarejos
d0c167345e Add fmd flag when selecting the applet.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-05-24 23:31:12 +02:00
Pol Henarejos
ca6affaf5d Adding private identifiers for cardholder certificates.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-05-20 19:03:22 +02:00
Pol Henarejos
7a77b31760 Adding INS GET NEXT DATA
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-05-20 19:02:55 +02:00
Pol Henarejos
9f069a7e31 When PUT DATA or GET DATA with previously selected EF (via SELECT or SELECT DATA), it puts/writes the data into the selected EF.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-05-15 19:48:31 +02:00
Pol Henarejos
a0384f67ca Adding INS A5 to select DO with multiple instances.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-05-15 19:40:17 +02:00
Pol Henarejos
32c6f60b49 Adding INS F1 to get version.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-05-15 18:58:35 +02:00
Pol Henarejos
0ab5526dac Adding FMD when selecting app by AID.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-05-15 18:50:45 +02:00
Pol Henarejos
eb066472b1 Adding AES support for symmetric encryption and decryption. However, there is no any software that supports AES. So, no tested feature.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-05-13 17:44:09 +02:00
Pol Henarejos
a2d1c5cf22 Adding key import.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-05-12 23:49:26 +02:00
Pol Henarejos
436c0744d0 Added clarification about Gnuk and Pico OpenPGP.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-05-09 19:05:50 +02:00
Pol Henarejos
223a1e015b Updated README with new features.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2022-05-09 19:03:31 +02:00
9 changed files with 390 additions and 137 deletions

View File

@@ -37,11 +37,13 @@ if (NOT DEFINED USB_PID)
endif() endif()
add_definitions(-DUSB_PID=${USB_PID}) add_definitions(-DUSB_PID=${USB_PID})
configure_file(${CMAKE_CURRENT_LIST_DIR}/pico-ccid/config/mbedtls_config.h ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/include/mbedtls COPYONLY)
target_sources(pico_openpgp PUBLIC target_sources(pico_openpgp PUBLIC
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/src/ccid/ccid2040.c ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/src/usb/usb.c
${CMAKE_CURRENT_LIST_DIR}/src/openpgp/openpgp.c
${CMAKE_CURRENT_LIST_DIR}/src/openpgp/files.c
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/src/usb/usb_descriptors.c ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/src/usb/usb_descriptors.c
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/src/ccid/ccid2040.c
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/src/ccid/asn1.c
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/src/fs/file.c ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/src/fs/file.c
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/src/fs/flash.c ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/src/fs/flash.c
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/src/fs/low_flash.c ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/src/fs/low_flash.c
@@ -49,40 +51,30 @@ target_sources(pico_openpgp PUBLIC
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/src/rng/neug.c ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/src/rng/neug.c
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/src/ccid/crypto_utils.c ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/src/ccid/crypto_utils.c
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/src/ccid/eac.c ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/src/ccid/eac.c
${CMAKE_CURRENT_LIST_DIR}/src/openpgp/openpgp.c
${CMAKE_CURRENT_LIST_DIR}/src/openpgp/files.c
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/sha256.c
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/aes.c ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/aes.c
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/sha512.c ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/asn1parse.c
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/rsa.c
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/bignum.c ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/bignum.c
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/platform_util.c
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/md.c
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/oid.c
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/rsa_alt_helpers.c
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/constant_time.c
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/ecdsa.c
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/ecp.c
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/ecp_curves.c
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/asn1write.c
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/hmac_drbg.c
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/md5.c
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/ripemd160.c
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/sha1.c
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/ecdh.c
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/cmac.c ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/cmac.c
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/cipher.c ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/cipher.c
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/cipher_wrap.c ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/cipher_wrap.c
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/chachapoly.c ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/constant_time.c
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/camellia.c ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/ecdsa.c
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/chacha20.c ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/ecdh.c
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/aria.c ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/ecp.c
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/poly1305.c ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/ecp_curves.c
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/gcm.c ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/md.c
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/ccm.c ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/md5.c
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/des.c ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/oid.c
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/nist_kw.c ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/platform_util.c
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/hkdf.c ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/ripemd160.c
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/asn1parse.c ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/rsa.c
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/rsa_alt_helpers.c
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/sha1.c
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/sha256.c
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/sha512.c
) )
target_include_directories(pico_openpgp PUBLIC target_include_directories(pico_openpgp PUBLIC
@@ -95,6 +87,11 @@ target_include_directories(pico_openpgp PUBLIC
${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library
) )
target_compile_options(pico_openpgp PUBLIC
-Wall
-Werror
)
pico_add_extra_outputs(pico_openpgp) pico_add_extra_outputs(pico_openpgp)
#target_compile_definitions(pico_openpgp PRIVATE MBEDTLS_ECDSA_DETERMINISTIC=1) #target_compile_definitions(pico_openpgp PRIVATE MBEDTLS_ECDSA_DETERMINISTIC=1)

View File

@@ -21,13 +21,20 @@ Pico OpenPGP has implemented the following features:
- USB/CCID support with OpenSC, openssl, etc. - USB/CCID support with OpenSC, openssl, etc.
- Extended APDU support. - Extended APDU support.
- Lifecycle card (termination and activation). - Lifecycle card (termination and activation).
- Press-to-confirm button.
- User Interaction Flag for enabling/disabling press-to-confirm button.
- Key Derivation Function (KDF) for PIN.
- Manage Security Environment (MSE).
- DEK for internal safe storage.
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.
### About Gnuk ### About Gnuk
This project was inspired by [Gnuk](https://wiki.debian.org/GNUK "Gnuk"), a same project but focused on STM32 processor family. Despite the initial idea was to port Gnuk to the Raspberry Pico family, the underlaying architecture is widely different (although they run on ARM). For instance, the Pico has two ARM cores, with an appropiate SDK able to leverage them. Also, Pico has an internal flash storage, which is farly larger compared to STM32 ROM storage. Finally, the Pico has a complete USB interface based on TinyUSB, which difficults to port Gnuk. These are only few examples of the difficulties of porting Gnuk to the Raspberry Pico. This project was inspired by [Gnuk](https://wiki.debian.org/GNUK "Gnuk"), a same project but focused on STM32 processor family. Despite the initial idea was to port Gnuk to the Raspberry Pico family, the underlaying architecture is widely different (although boh run on ARM). For instance, the Pico has two ARM cores, with an appropiate SDK able to leverage them. Also, Pico has an internal flash storage, which is farly larger compared to STM32 ROM storage. Finally, the Pico has a complete USB interface based on TinyUSB, which difficults to port Gnuk. These are only few examples of the difficulties of porting Gnuk to the Raspberry Pico.
As a consequence, Pico OpenPGP is designed from zero. Well, not strictly from zero, as it borrows some of the buffering between USB and CCID interfaces from Gnuk. Cryptographic operations are implemented with MBEDTLS library. As a consequence, Pico OpenPGP is designed from zero. Well, not strictly from zero, as it borrows some of the cryptographic operations implemented with MbedTLS library.
Whilst Gnuk is OpenPGP 2.0 with small set of enhancements, Pico OpenPGP aims at being OpenPGP 3.4 compliant, with new features (not present in Gnuk), such as Manage Security Environment (MSE) or UIF.
## Security considerations ## Security considerations
All secret keys (asymmetric and symmetric) are stored encrypted in the flash memory of the Raspberry Pico. DEK is used as a 256 bit AES key to protect private and secret keys. Keys are never stored in RAM except for signature and decryption operations and only during the process. All keys (including DEK) are loaded and cleared every time to avoid potential security flaws. All secret keys (asymmetric and symmetric) are stored encrypted in the flash memory of the Raspberry Pico. DEK is used as a 256 bit AES key to protect private and secret keys. Keys are never stored in RAM except for signature and decryption operations and only during the process. All keys (including DEK) are loaded and cleared every time to avoid potential security flaws.
@@ -116,6 +123,5 @@ OpenSC relies on PCSC driver, which reads a list (`Info.plist`) that contains a
## Credits ## Credits
Pico OpenPGP uses the following libraries or portion of code: Pico OpenPGP uses the following libraries or portion of code:
- mbedTLS for cryptographic operations. - mbedTLS for cryptographic operations.
- gnuk for low level CCID procedures support.
- TinyUSB for low level USB procedures. - TinyUSB for low level USB procedures.

View File

@@ -1,7 +1,7 @@
#!/bin/bash #!/bin/bash
VERSION_MAJOR="1" VERSION_MAJOR="1"
VERSION_MINOR="4" VERSION_MINOR="6"
rm -rf release/* rm -rf release/*
cd build_release cd build_release

View File

@@ -17,8 +17,8 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
# #
VERSION_MAJOR="1" #Version of Pico CCID Core VERSION_MAJOR="2" #Version of Pico CCID Core
VERSION_MINOR="1" VERSION_MINOR="0"
echo "----------------------------" echo "----------------------------"
echo "VID/PID patcher for Pico OpenPGP" echo "VID/PID patcher for Pico OpenPGP"

View File

@@ -138,9 +138,12 @@ file_t file_entries[] = {
/* 51 */ { .fid = EF_PW_PRIV, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP }, /* 51 */ { .fid = EF_PW_PRIV, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP },
/* 52 */ { .fid = EF_DEK, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_NONE }, /* 52 */ { .fid = EF_DEK, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_NONE },
/* 53 */ { .fid = EF_KDF, .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP }, /* 53 */ { .fid = EF_KDF, .parent = 0, .name = NULL, .type = FILE_TYPE_WORKING_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_R_WP },
/* 54 */ { .fid = EF_CH_1, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_NONE },
/* 55 */ { .fid = EF_CH_2, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_NONE },
/* 56 */ { .fid = EF_CH_3, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_NONE },
/* 54 */ { .fid = 0x0000, .parent = 0, .name = openpgp_aid, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_RO }, /* 57 */ { .fid = 0x0000, .parent = 0, .name = openpgp_aid, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = ACL_RO },
/* 55 */ { .fid = 0x0000, .parent = 0xff, .name = NULL, .type = FILE_TYPE_UNKNOWN, .data = NULL, .ef_structure = 0, .acl = ACL_NONE } //end /* 58 */ { .fid = 0x0000, .parent = 0xff, .name = NULL, .type = FILE_TYPE_UNKNOWN, .data = NULL, .ef_structure = 0, .acl = ACL_NONE } //end
}; };
const file_t *MF = &file_entries[0]; const file_t *MF = &file_entries[0];

View File

@@ -35,6 +35,9 @@
#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_CH_1 0x1f21
#define EF_CH_2 0x1f22
#define EF_CH_3 0x1f23
#define EF_EXT_HEADER 0x004d //C #define EF_EXT_HEADER 0x004d //C
#define EF_FULL_AID 0x004f //S #define EF_FULL_AID 0x004f //S
@@ -63,6 +66,7 @@
#define EF_TS_DEC 0x00cf //S #define EF_TS_DEC 0x00cf //S
#define EF_TS_AUT 0x00d0 //S #define EF_TS_AUT 0x00d0 //S
#define EF_RESET_CODE 0x00d3 //S #define EF_RESET_CODE 0x00d3 //S
#define EF_AES_KEY 0x00d5 //S
#define EF_UIF_SIG 0x00d6 //S #define EF_UIF_SIG 0x00d6 //S
#define EF_UIF_DEC 0x00d7 //S #define EF_UIF_DEC 0x00d7 //S
#define EF_UIF_AUT 0x00d8 //S #define EF_UIF_AUT 0x00d8 //S

View File

@@ -26,6 +26,7 @@
#include "mbedtls/ecdsa.h" #include "mbedtls/ecdsa.h"
#include "mbedtls/ecdh.h" #include "mbedtls/ecdh.h"
#include "mbedtls/asn1.h" #include "mbedtls/asn1.h"
#include "asn1.h"
bool has_pw1 = false; bool has_pw1 = false;
bool has_pw2 = false; bool has_pw2 = false;
@@ -60,9 +61,9 @@ static bool wait_button(uint16_t fid) {
file_t *ef = search_by_fid(fid, NULL, SPECIFY_ANY); file_t *ef = search_by_fid(fid, NULL, SPECIFY_ANY);
uint32_t val = EV_PRESS_BUTTON; uint32_t val = EV_PRESS_BUTTON;
if (ef && ef->data && file_read_uint8(ef->data+2) > 0) { if (ef && ef->data && file_read_uint8(ef->data+2) > 0) {
queue_try_add(ccid_comm, &val); queue_try_add(&card_to_ccid_q, &val);
do { do {
queue_remove_blocking(card_comm, &val); queue_remove_blocking(&ccid_to_card_q, &val);
} }
while (val != EV_BUTTON_PRESSED && val != EV_BUTTON_TIMEOUT); while (val != EV_BUTTON_PRESSED && val != EV_BUTTON_TIMEOUT);
} }
@@ -94,16 +95,16 @@ static int cmd_select() {
file_t *pe = NULL; file_t *pe = NULL;
uint16_t fid = 0x0; uint16_t fid = 0x0;
if (apdu.cmd_apdu_data_len >= 2) if (apdu.nc >= 2)
fid = get_uint16_t(apdu.cmd_apdu_data, 0); fid = get_uint16_t(apdu.data, 0);
if (!pe) { if (!pe) {
if (p1 == 0x0) { //Select MF, DF or EF - File identifier or absent if (p1 == 0x0) { //Select MF, DF or EF - File identifier or absent
if (apdu.cmd_apdu_data_len == 0) { if (apdu.nc == 0) {
pe = (file_t *)MF; pe = (file_t *)MF;
//ac_fini(); //ac_fini();
} }
else if (apdu.cmd_apdu_data_len == 2) { else if (apdu.nc == 2) {
if (!(pe = search_by_fid(fid, NULL, SPECIFY_ANY))) { if (!(pe = search_by_fid(fid, NULL, SPECIFY_ANY))) {
return SW_REFERENCE_NOT_FOUND(); return SW_REFERENCE_NOT_FOUND();
} }
@@ -120,11 +121,11 @@ static int cmd_select() {
} }
} }
else if (p1 == 0x03) { //Select parent DF of the current DF - Absent else if (p1 == 0x03) { //Select parent DF of the current DF - Absent
if (apdu.cmd_apdu_data_len != 0) if (apdu.nc != 0)
return SW_REFERENCE_NOT_FOUND(); return SW_REFERENCE_NOT_FOUND();
} }
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.cmd_apdu_data, apdu.cmd_apdu_data_len))) { if (!(pe = search_by_name(apdu.data, apdu.nc))) {
return SW_REFERENCE_NOT_FOUND(); return SW_REFERENCE_NOT_FOUND();
} }
if (card_terminated) { if (card_terminated) {
@@ -132,19 +133,19 @@ static 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.cmd_apdu_data, apdu.cmd_apdu_data_len, MF))) { if (!(pe = 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.cmd_apdu_data, apdu.cmd_apdu_data_len, currentDF))) { if (!(pe = 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); process_fci(pe,0);
} }
else else
return SW_INCORRECT_P1P2(); return SW_INCORRECT_P1P2();
@@ -157,11 +158,11 @@ void scan_files() {
file_t *ef; file_t *ef;
if ((ef = search_by_fid(EF_FULL_AID, NULL, SPECIFY_ANY))) { if ((ef = search_by_fid(EF_FULL_AID, NULL, SPECIFY_ANY))) {
ef->data = openpgp_aid_full; ef->data = openpgp_aid_full;
pico_get_unique_board_id_string(ef->data+12, 4); pico_get_unique_board_id_string((char *)ef->data+12, 4);
} }
if ((ef = search_by_fid(EF_PW1, NULL, SPECIFY_ANY))) { if ((ef = search_by_fid(EF_PW1, NULL, SPECIFY_ANY))) {
if (!ef->data) { if (!ef->data) {
TU_LOG1("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[33];
dhash[0] = sizeof(def); dhash[0] = sizeof(def);
@@ -171,7 +172,7 @@ void scan_files() {
} }
if ((ef = search_by_fid(EF_RC, NULL, SPECIFY_ANY))) { if ((ef = search_by_fid(EF_RC, NULL, SPECIFY_ANY))) {
if (!ef->data) { if (!ef->data) {
TU_LOG1("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[33];
@@ -182,7 +183,7 @@ void scan_files() {
} }
if ((ef = search_by_fid(EF_PW3, NULL, SPECIFY_ANY))) { if ((ef = search_by_fid(EF_PW3, NULL, SPECIFY_ANY))) {
if (!ef->data) { if (!ef->data) {
TU_LOG1("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[33];
@@ -193,21 +194,21 @@ void scan_files() {
} }
if ((ef = search_by_fid(EF_SIG_COUNT, NULL, SPECIFY_ANY))) { if ((ef = search_by_fid(EF_SIG_COUNT, NULL, SPECIFY_ANY))) {
if (!ef->data) { if (!ef->data) {
TU_LOG1("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 };
flash_write_data_to_file(ef, def, sizeof(def)); flash_write_data_to_file(ef, def, sizeof(def));
} }
} }
if ((ef = search_by_fid(EF_PW_PRIV, NULL, SPECIFY_ANY))) { if ((ef = search_by_fid(EF_PW_PRIV, NULL, SPECIFY_ANY))) {
if (!ef->data) { if (!ef->data) {
TU_LOG1("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 };
flash_write_data_to_file(ef, def, sizeof(def)); flash_write_data_to_file(ef, def, sizeof(def));
} }
} }
if ((ef = search_by_fid(EF_DEK, NULL, SPECIFY_ANY))) { if ((ef = search_by_fid(EF_DEK, NULL, SPECIFY_ANY))) {
if (!ef->data) { if (!ef->data) {
TU_LOG1("DEK is empty\r\n"); printf("DEK is empty\r\n");
const uint8_t def1[6] = { 0x31,0x32,0x33,0x34,0x35,0x36 }; const uint8_t def1[6] = { 0x31,0x32,0x33,0x34,0x35,0x36 };
const uint8_t def3[8] = { 0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38 }; const uint8_t def3[8] = { 0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38 };
@@ -227,28 +228,28 @@ void scan_files() {
} }
if ((ef = search_by_fid(EF_UIF_SIG, NULL, SPECIFY_ANY))) { if ((ef = search_by_fid(EF_UIF_SIG, NULL, SPECIFY_ANY))) {
if (!ef->data) { if (!ef->data) {
TU_LOG1("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 };
flash_write_data_to_file(ef, def, sizeof(def)); flash_write_data_to_file(ef, def, sizeof(def));
} }
} }
if ((ef = search_by_fid(EF_UIF_DEC, NULL, SPECIFY_ANY))) { if ((ef = search_by_fid(EF_UIF_DEC, NULL, SPECIFY_ANY))) {
if (!ef->data) { if (!ef->data) {
TU_LOG1("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 };
flash_write_data_to_file(ef, def, sizeof(def)); flash_write_data_to_file(ef, def, sizeof(def));
} }
} }
if ((ef = search_by_fid(EF_UIF_AUT, NULL, SPECIFY_ANY))) { if ((ef = search_by_fid(EF_UIF_AUT, NULL, SPECIFY_ANY))) {
if (!ef->data) { if (!ef->data) {
TU_LOG1("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 };
flash_write_data_to_file(ef, def, sizeof(def)); flash_write_data_to_file(ef, def, sizeof(def));
} }
} }
if ((ef = search_by_fid(EF_KDF, NULL, SPECIFY_ANY))) { if ((ef = search_by_fid(EF_KDF, NULL, SPECIFY_ANY))) {
if (!ef->data) { if (!ef->data) {
TU_LOG1("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 };
flash_write_data_to_file(ef, def, sizeof(def)); flash_write_data_to_file(ef, def, sizeof(def));
} }
@@ -320,19 +321,36 @@ int openpgp_unload() {
return CCID_OK; return CCID_OK;
} }
extern char __StackLimit;
int heapLeft() {
char *p = malloc(256); // try to avoid undue fragmentation
int left = &__StackLimit - p;
free(p);
return left;
}
app_t *openpgp_select_aid(app_t *a) { app_t *openpgp_select_aid(app_t *a) {
if (!memcmp(apdu.cmd_apdu_data, openpgp_aid+1, openpgp_aid[0])) { if (!memcmp(apdu.data, openpgp_aid+1, openpgp_aid[0])) {
a->aid = openpgp_aid; a->aid = openpgp_aid;
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);
memcpy(res_APDU+res_APDU_size,"\x64\x06\x53\x04", 4);
res_APDU_size += 4;
int heap_left = heapLeft();
res_APDU[res_APDU_size++] = ((heap_left >> 24) & 0xff);
res_APDU[res_APDU_size++] = ((heap_left >> 16) & 0xff);
res_APDU[res_APDU_size++] = ((heap_left >> 8) & 0xff);
res_APDU[res_APDU_size++] = ((heap_left >> 0) & 0xff);
res_APDU[1] += 8;
return a; return a;
} }
return NULL; return NULL;
} }
void __attribute__ ((constructor)) openpgp_ctor() { void __attribute__ ((constructor)) openpgp_ctor() {
ccid_atr = atr_openpgp; ccid_atr = (uint8_t *)atr_openpgp;
register_app(openpgp_select_aid); register_app(openpgp_select_aid);
} }
@@ -397,7 +415,7 @@ int parse_ch_data(const file_t *f, int mode) {
res_APDU[res_APDU_size++] = 0x82; res_APDU[res_APDU_size++] = 0x82;
uint8_t *lp = res_APDU+res_APDU_size; uint8_t *lp = res_APDU+res_APDU_size;
res_APDU_size += 2; res_APDU_size += 2;
uint16_t data_len = parse_do(fids, mode); parse_do(fids, mode);
uint16_t lpdif = res_APDU+res_APDU_size-lp-2; uint16_t lpdif = res_APDU+res_APDU_size-lp-2;
*lp++ = lpdif >> 8; *lp++ = lpdif >> 8;
*lp++ = lpdif & 0xff; *lp++ = lpdif & 0xff;
@@ -547,7 +565,7 @@ static const uint8_t algorithm_attr_x448[] = {
static const uint8_t algorithm_attr_rsa1k[] = { static const uint8_t algorithm_attr_rsa1k[] = {
6, 6,
ALGO_RSA, ALGO_RSA,
0x04, 0x00, /* Length modulus (in bit): 2048 */ 0x04, 0x00, /* Length modulus (in bit): 1024 */
0x00, 0x20, /* Length exponent (in bit): 32 */ 0x00, 0x20, /* Length exponent (in bit): 32 */
0x00 /* 0: Acceptable format is: P and Q */ 0x00 /* 0: Acceptable format is: P and Q */
}; };
@@ -563,7 +581,7 @@ static const uint8_t algorithm_attr_rsa2k[] = {
static const uint8_t algorithm_attr_rsa3k[] = { static const uint8_t algorithm_attr_rsa3k[] = {
6, 6,
ALGO_RSA, ALGO_RSA,
0x0C, 0x00, /* Length modulus (in bit): 2048 */ 0x0C, 0x00, /* Length modulus (in bit): 3072 */
0x00, 0x20, /* Length exponent (in bit): 32 */ 0x00, 0x20, /* Length exponent (in bit): 32 */
0x00 /* 0: Acceptable format is: P and Q */ 0x00 /* 0: Acceptable format is: P and Q */
}; };
@@ -624,14 +642,6 @@ static const uint8_t algorithm_attr_cv25519[] = {
0x2b, 0x06, 0x01, 0x04, 0x01, 0x97, 0x55, 0x01, 0x05, 0x01 0x2b, 0x06, 0x01, 0x04, 0x01, 0x97, 0x55, 0x01, 0x05, 0x01
}; };
static const uint8_t *algorithm_attr[] = {
algorithm_attr_rsa1k, algorithm_attr_rsa2k, algorithm_attr_rsa3k, algorithm_attr_rsa4k,
algorithm_attr_x448, algorithm_attr_p256k1,
algorithm_attr_p256r1, algorithm_attr_p384r1, algorithm_attr_p521r1,
algorithm_attr_bp256r1, algorithm_attr_bp384r1, algorithm_attr_bp512r1,
algorithm_attr_cv25519
};
int parse_algo(const uint8_t *algo, uint16_t tag) { int parse_algo(const uint8_t *algo, uint16_t tag) {
res_APDU[res_APDU_size++] = tag & 0xff; res_APDU[res_APDU_size++] = tag & 0xff;
memcpy(res_APDU+res_APDU_size, algo, algo[0]+1); memcpy(res_APDU+res_APDU_size, algo, algo[0]+1);
@@ -714,7 +724,7 @@ int parse_app_data(const file_t *f, int mode) {
res_APDU[res_APDU_size++] = 0x82; res_APDU[res_APDU_size++] = 0x82;
uint8_t *lp = res_APDU+res_APDU_size; uint8_t *lp = res_APDU+res_APDU_size;
res_APDU_size += 2; res_APDU_size += 2;
uint16_t data_len = parse_do(fids, mode); parse_do(fids, mode);
uint16_t lpdif = res_APDU+res_APDU_size-lp-2; uint16_t lpdif = res_APDU+res_APDU_size-lp-2;
*lp++ = lpdif >> 8; *lp++ = lpdif >> 8;
*lp++ = lpdif & 0xff; *lp++ = lpdif & 0xff;
@@ -730,7 +740,7 @@ int parse_discrete_do(const file_t *f, int mode) {
res_APDU[res_APDU_size++] = 0x82; res_APDU[res_APDU_size++] = 0x82;
uint8_t *lp = res_APDU+res_APDU_size; uint8_t *lp = res_APDU+res_APDU_size;
res_APDU_size += 2; res_APDU_size += 2;
uint16_t data_len = parse_do(fids, mode); parse_do(fids, mode);
uint16_t lpdif = res_APDU+res_APDU_size-lp-2; uint16_t lpdif = res_APDU+res_APDU_size-lp-2;
*lp++ = lpdif >> 8; *lp++ = lpdif >> 8;
*lp++ = lpdif & 0xff; *lp++ = lpdif & 0xff;
@@ -738,7 +748,7 @@ int parse_discrete_do(const file_t *f, int mode) {
} }
static int cmd_get_data() { static int cmd_get_data() {
if (apdu.cmd_apdu_data_len > 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;
@@ -747,11 +757,16 @@ static int cmd_get_data() {
if (!authenticate_action(ef, ACL_OP_READ_SEARCH)) { if (!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
ef = currentEF;
}
else
select_file(ef);
if (ef->data) { if (ef->data) {
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);
if (apdu.expected_res_size > data_len) if (apdu.ne > data_len)
apdu.expected_res_size = data_len; apdu.ne = data_len;
} }
return SW_OK(); return SW_OK();
} }
@@ -839,7 +854,7 @@ static int cmd_verify() {
uint8_t p2 = P2(apdu); uint8_t p2 = P2(apdu);
if (p1 == 0xFF) { if (p1 == 0xFF) {
if (apdu.cmd_apdu_data_len != 0) if (apdu.nc != 0)
return SW_WRONG_DATA(); return SW_WRONG_DATA();
if (p2 == 0x81) if (p2 == 0x81)
has_pw1 = false; has_pw1 = false;
@@ -851,9 +866,8 @@ static int cmd_verify() {
} }
else if (p1 != 0x0 || (p2 & 0x60) != 0x0) else if (p1 != 0x0 || (p2 & 0x60) != 0x0)
return SW_WRONG_P1P2(); return SW_WRONG_P1P2();
uint8_t qualifier = p2&0x1f;
uint16_t fid = 0x1000 | p2; uint16_t fid = 0x1000 | p2;
if (fid == EF_RC && apdu.cmd_apdu_data_len > 0) if (fid == EF_RC && apdu.nc > 0)
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 = search_by_fid(fid, NULL, SPECIFY_EF)))
@@ -862,8 +876,8 @@ static int cmd_verify() {
return SW_REFERENCE_NOT_FOUND(); return SW_REFERENCE_NOT_FOUND();
if (file_read_uint8(pw->data+2) == 0) //not initialized if (file_read_uint8(pw->data+2) == 0) //not initialized
return SW_REFERENCE_NOT_FOUND(); return SW_REFERENCE_NOT_FOUND();
if (apdu.cmd_apdu_data_len > 0) { if (apdu.nc > 0) {
return check_pin(pw, apdu.cmd_apdu_data, apdu.cmd_apdu_data_len); return check_pin(pw, apdu.data, apdu.nc);
} }
uint8_t retries = file_read_uint8(pw_status->data+2+3+(fid&0x3)); uint8_t retries = file_read_uint8(pw_status->data+2+3+(fid&0x3));
if (retries == 0) if (retries == 0)
@@ -887,10 +901,13 @@ static int cmd_put_data() {
} }
if (fid == EF_PW_STATUS) { if (fid == EF_PW_STATUS) {
fid = EF_PW_PRIV; fid = EF_PW_PRIV;
apdu.cmd_apdu_data_len = 4; //we silently ommit the reset parameters apdu.nc = 4; //we silently ommit the reset parameters
} }
if (apdu.cmd_apdu_data_len > 0 && (ef->type & FILE_DATA_FLASH)) { if (currentEF && (currentEF->fid & 0x1FF0) == (fid & 0x1FF0)) { //previously selected
int r = flash_write_data_to_file(ef, apdu.cmd_apdu_data, apdu.cmd_apdu_data_len); ef = currentEF;
}
if (apdu.nc > 0 && (ef->type & FILE_DATA_FLASH)) {
int r = flash_write_data_to_file(ef, apdu.data, apdu.nc);
if (r != CCID_OK) if (r != CCID_OK)
return SW_MEMORY_FAILURE(); return SW_MEMORY_FAILURE();
low_flash_available(); low_flash_available();
@@ -906,12 +923,12 @@ static int cmd_change_pin() {
if (!(pw = search_by_fid(fid, NULL, SPECIFY_EF))) if (!(pw = search_by_fid(fid, NULL, SPECIFY_EF)))
return SW_REFERENCE_NOT_FOUND(); return SW_REFERENCE_NOT_FOUND();
uint8_t pin_len = file_read_uint8(pw->data+2); uint8_t pin_len = file_read_uint8(pw->data+2);
uint16_t r = check_pin(pw, apdu.cmd_apdu_data, pin_len); uint16_t r = check_pin(pw, apdu.data, pin_len);
if (r != 0x9000) if (r != 0x9000)
return r; return r;
uint8_t dhash[33]; uint8_t dhash[33];
dhash[0] = apdu.cmd_apdu_data_len-pin_len; dhash[0] = apdu.nc-pin_len;
double_hash_pin(apdu.cmd_apdu_data+pin_len, apdu.cmd_apdu_data_len-pin_len, dhash+1); double_hash_pin(apdu.data+pin_len, apdu.nc-pin_len, dhash+1);
flash_write_data_to_file(pw, dhash, sizeof(dhash)); flash_write_data_to_file(pw, dhash, sizeof(dhash));
low_flash_available(); low_flash_available();
return SW_OK(); return SW_OK();
@@ -926,25 +943,25 @@ static int cmd_reset_retry() {
if (!(pw = search_by_fid(EF_PW1, NULL, SPECIFY_EF))) if (!(pw = 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, *pw; file_t *rc;
if (!(rc = search_by_fid(EF_RC, NULL, SPECIFY_EF))) if (!(rc = search_by_fid(EF_RC, NULL, SPECIFY_EF)))
return SW_REFERENCE_NOT_FOUND(); return SW_REFERENCE_NOT_FOUND();
uint8_t pin_len = file_read_uint8(rc->data+2); uint8_t pin_len = file_read_uint8(rc->data+2);
if (apdu.cmd_apdu_data_len <= pin_len) if (apdu.nc <= pin_len)
return SW_WRONG_LENGTH(); return SW_WRONG_LENGTH();
uint16_t r = check_pin(rc, apdu.cmd_apdu_data, pin_len); uint16_t r = check_pin(rc, apdu.data, pin_len);
if (r != 0x9000) if (r != 0x9000)
return r; return r;
newpin_len = apdu.cmd_apdu_data_len-pin_len; newpin_len = apdu.nc-pin_len;
} }
else if (P1(apdu) == 0x2) { else if (P1(apdu) == 0x2) {
if (!has_pw3) if (!has_pw3)
return SW_CONDITIONS_NOT_SATISFIED(); return SW_CONDITIONS_NOT_SATISFIED();
newpin_len = apdu.cmd_apdu_data_len; newpin_len = apdu.nc;
} }
uint8_t dhash[33]; uint8_t dhash[33];
dhash[0] = newpin_len; dhash[0] = newpin_len;
double_hash_pin(apdu.cmd_apdu_data+(apdu.cmd_apdu_data_len-newpin_len), newpin_len, dhash+1); double_hash_pin(apdu.data+(apdu.nc-newpin_len), newpin_len, dhash+1);
flash_write_data_to_file(pw, dhash, sizeof(dhash)); flash_write_data_to_file(pw, dhash, sizeof(dhash));
if (pin_reset_retries(pw, true) != CCID_OK) if (pin_reset_retries(pw, true) != CCID_OK)
return SW_MEMORY_FAILURE(); return SW_MEMORY_FAILURE();
@@ -955,7 +972,7 @@ static int cmd_reset_retry() {
} }
int store_keys(void *key_ctx, int type, uint16_t key_id) { int store_keys(void *key_ctx, int type, uint16_t key_id) {
int r, key_size; int r, key_size = 0;
uint8_t kdata[4096/8]; //worst uint8_t kdata[4096/8]; //worst
//if (!has_pw3) //if (!has_pw3)
@@ -1052,6 +1069,15 @@ int load_private_key_ecdsa(mbedtls_ecdsa_context *ctx, file_t *fkey) {
return CCID_OK; return CCID_OK;
} }
int load_aes_key(uint8_t *aes_key, file_t *fkey) {
int key_size = file_read_uint16(fkey->data);
memcpy(aes_key, file_read(fkey->data+2), key_size);
if (dek_decrypt(aes_key, key_size) != 0) {
return CCID_EXEC_ERROR;
}
return CCID_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) {
if (memcmp(algorithm_attr_p256k1+2, algo, algo_len) == 0) if (memcmp(algorithm_attr_p256k1+2, algo, algo_len) == 0)
return MBEDTLS_ECP_DP_SECP256K1; return MBEDTLS_ECP_DP_SECP256K1;
@@ -1103,18 +1129,18 @@ void make_ecdsa_response(mbedtls_ecdsa_context *ecdsa) {
static int cmd_keypair_gen() { static int cmd_keypair_gen() {
if (P2(apdu) != 0x0) if (P2(apdu) != 0x0)
return SW_INCORRECT_P1P2(); return SW_INCORRECT_P1P2();
if (apdu.cmd_apdu_data_len != 2 && apdu.cmd_apdu_data_len != 5) if (apdu.nc != 2 && apdu.nc != 5)
return SW_WRONG_LENGTH(); return SW_WRONG_LENGTH();
if (!has_pw3 && P1(apdu) == 0x80) if (!has_pw3 && P1(apdu) == 0x80)
return SW_SECURITY_STATUS_NOT_SATISFIED(); return SW_SECURITY_STATUS_NOT_SATISFIED();
uint16_t fid = 0x0; uint16_t fid = 0x0;
int r = CCID_OK; int r = CCID_OK;
if (apdu.cmd_apdu_data[0] == 0xB6) if (apdu.data[0] == 0xB6)
fid = EF_PK_SIG; fid = EF_PK_SIG;
else if (apdu.cmd_apdu_data[0] == 0xB8) else if (apdu.data[0] == 0xB8)
fid = EF_PK_DEC; fid = EF_PK_DEC;
else if (apdu.cmd_apdu_data[0] == 0xA4) else if (apdu.data[0] == 0xA4)
fid = EF_PK_AUT; fid = EF_PK_AUT;
else else
return SW_WRONG_DATA(); return SW_WRONG_DATA();
@@ -1177,6 +1203,17 @@ static int cmd_keypair_gen() {
return SW_EXEC_ERROR(); return SW_EXEC_ERROR();
if (fid == EF_PK_SIG) if (fid == EF_PK_SIG)
reset_sig_count(); reset_sig_count();
else if (fid == EF_PK_DEC) {
// OpenPGP does not allow generating AES keys. So, we generate a new one when gen for DEC is called.
// It is a 256 AES key by default.
uint8_t aes_key[32]; //maximum AES key size
uint8_t key_size = 32;
memcpy(aes_key, random_bytes_get(key_size), key_size);
r = store_keys(aes_key, ALGO_AES_256, EF_AES_KEY);
/* if storing the key fails, we silently continue */
//if (r != CCID_OK)
// return SW_EXEC_ERROR();
}
low_flash_available(); low_flash_available();
return SW_OK(); return SW_OK();
} }
@@ -1246,17 +1283,6 @@ int rsa_sign(mbedtls_rsa_context *ctx, const uint8_t *data, size_t data_len, uin
} }
int ecdsa_sign(mbedtls_ecdsa_context *ctx, const uint8_t *data, size_t data_len, uint8_t *out, size_t *out_len) { int ecdsa_sign(mbedtls_ecdsa_context *ctx, const uint8_t *data, size_t data_len, uint8_t *out, size_t *out_len) {
mbedtls_md_type_t md = MBEDTLS_MD_SHA256;
if (data_len == 32)
md = MBEDTLS_MD_SHA256;
else if (data_len == 20)
md = MBEDTLS_MD_SHA1;
else if (data_len == 28)
md = MBEDTLS_MD_SHA224;
else if (data_len == 48)
md = MBEDTLS_MD_SHA384;
else if (data_len == 64)
md = MBEDTLS_MD_SHA512;
mbedtls_mpi ri, si; mbedtls_mpi ri, si;
mbedtls_mpi_init(&ri); mbedtls_mpi_init(&ri);
mbedtls_mpi_init(&si); mbedtls_mpi_init(&si);
@@ -1275,6 +1301,7 @@ int ecdsa_sign(mbedtls_ecdsa_context *ctx, const uint8_t *data, size_t data_len,
static int cmd_pso() { static int cmd_pso() {
uint16_t algo_fid = 0x0, pk_fid = 0x0; uint16_t algo_fid = 0x0, pk_fid = 0x0;
bool is_aes = false;
if (P1(apdu) == 0x9E && P2(apdu) == 0x9A) { if (P1(apdu) == 0x9E && P2(apdu) == 0x9A) {
if (!has_pw3 && !has_pw1) if (!has_pw3 && !has_pw1)
return SW_SECURITY_STATUS_NOT_SATISFIED(); return SW_SECURITY_STATUS_NOT_SATISFIED();
@@ -1293,11 +1320,15 @@ static int cmd_pso() {
if (!algo_ef) if (!algo_ef)
return SW_REFERENCE_NOT_FOUND(); return SW_REFERENCE_NOT_FOUND();
const uint8_t *algo = algorithm_attr_rsa2k+1; const uint8_t *algo = algorithm_attr_rsa2k+1;
uint16_t algo_len = algorithm_attr_rsa2k[0];
if (algo_ef && algo_ef->data) { if (algo_ef && algo_ef->data) {
algo_len = file_read_uint16(algo_ef->data);
algo = file_read(algo_ef->data+2); algo = file_read(algo_ef->data+2);
} }
if (apdu.data[0] == 0x2) { //AES PSO?
if (((apdu.nc - 1)%16 == 0 && P1(apdu) == 0x80 && P2(apdu) == 0x86) || (apdu.nc%16 == 0 && P1(apdu) == 0x86 && P2(apdu) == 0x80)) {
pk_fid = EF_AES_KEY;
is_aes = true;
}
}
file_t *ef = search_by_fid(pk_fid, NULL, SPECIFY_EF); file_t *ef = search_by_fid(pk_fid, NULL, SPECIFY_EF);
if (!ef) if (!ef)
return SW_REFERENCE_NOT_FOUND(); return SW_REFERENCE_NOT_FOUND();
@@ -1305,6 +1336,32 @@ static int cmd_pso() {
return SW_SECURE_MESSAGE_EXEC_ERROR(); return SW_SECURE_MESSAGE_EXEC_ERROR();
int r = CCID_OK; int r = CCID_OK;
int key_size = file_read_uint16(ef->data); int key_size = file_read_uint16(ef->data);
if (is_aes) {
uint8_t aes_key[32];
r = load_aes_key(aes_key, ef);
if (r != CCID_OK) {
memset(aes_key, 0, sizeof(aes_key));
return SW_EXEC_ERROR();
}
if (P1(apdu) == 0x80 && P2(apdu) == 0x86) { //decipher
r = aes_decrypt(aes_key, NULL, key_size, HSM_AES_MODE_CBC, apdu.data+1, apdu.nc-1);
memset(aes_key, 0, sizeof(aes_key));
if (r != CCID_OK)
return SW_EXEC_ERROR();
memcpy(res_APDU, apdu.data+1, apdu.nc-1);
res_APDU_size = apdu.nc-1;
}
else if (P1(apdu) == 0x86 && P2(apdu) == 0x80) { //encipher
r = aes_encrypt(aes_key, NULL, key_size, HSM_AES_MODE_CBC, apdu.data, apdu.nc);
memset(aes_key, 0, sizeof(aes_key));
if (r != CCID_OK)
return SW_EXEC_ERROR();
res_APDU[0] = 0x2;
memcpy(res_APDU+1, apdu.data, apdu.nc);
res_APDU_size = apdu.nc+1;
}
return SW_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);
@@ -1315,18 +1372,18 @@ static int cmd_pso() {
} }
if (P1(apdu) == 0x9E && P2(apdu) == 0x9A) { if (P1(apdu) == 0x9E && P2(apdu) == 0x9A) {
size_t olen = 0; size_t olen = 0;
r = rsa_sign(&ctx, apdu.cmd_apdu_data, apdu.cmd_apdu_data_len, res_APDU, &olen); r = rsa_sign(&ctx, apdu.data, apdu.nc, res_APDU, &olen);
mbedtls_rsa_free(&ctx); mbedtls_rsa_free(&ctx);
if (r != 0) if (r != 0)
return SW_EXEC_ERROR(); return SW_EXEC_ERROR();
res_APDU_size = olen; res_APDU_size = olen;
//apdu.expected_res_size = key_size; //apdu.ne = key_size;
} }
else if (P1(apdu) == 0x80 && P2(apdu) == 0x86) { else if (P1(apdu) == 0x80 && P2(apdu) == 0x86) {
if (apdu.cmd_apdu_data_len < key_size) //needs padding if (apdu.nc < key_size) //needs padding
memset(apdu.cmd_apdu_data+apdu.cmd_apdu_data_len, 0, key_size-apdu.cmd_apdu_data_len); memset(apdu.data+apdu.nc, 0, key_size-apdu.nc);
size_t olen = 0; size_t olen = 0;
r = mbedtls_rsa_pkcs1_decrypt(&ctx, random_gen, NULL, &olen, apdu.cmd_apdu_data+1, res_APDU, key_size); r = mbedtls_rsa_pkcs1_decrypt(&ctx, 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();
@@ -1344,7 +1401,7 @@ static int cmd_pso() {
return SW_EXEC_ERROR(); return SW_EXEC_ERROR();
} }
size_t olen = 0; size_t olen = 0;
r = ecdsa_sign(&ctx, apdu.cmd_apdu_data, apdu.cmd_apdu_data_len, res_APDU, &olen); r = ecdsa_sign(&ctx, apdu.data, apdu.nc, res_APDU, &olen);
mbedtls_ecdsa_free(&ctx); mbedtls_ecdsa_free(&ctx);
if (r != 0) if (r != 0)
return SW_EXEC_ERROR(); return SW_EXEC_ERROR();
@@ -1353,7 +1410,7 @@ static int cmd_pso() {
else if (P1(apdu) == 0x80 && P2(apdu) == 0x86) { else if (P1(apdu) == 0x80 && P2(apdu) == 0x86) {
mbedtls_ecdh_context ctx; mbedtls_ecdh_context ctx;
uint8_t kdata[67]; uint8_t kdata[67];
uint8_t *data = apdu.cmd_apdu_data, *end = data+apdu.cmd_apdu_data_len; uint8_t *data = apdu.data, *end = data+apdu.nc;
size_t len = 0; size_t len = 0;
if (mbedtls_asn1_get_tag(&data, end, &len, 0xA6) != 0) if (mbedtls_asn1_get_tag(&data, end, &len, 0xA6) != 0)
return SW_WRONG_DATA(); return SW_WRONG_DATA();
@@ -1405,7 +1462,7 @@ static int cmd_terminate_df() {
return SW_REFERENCE_NOT_FOUND(); return SW_REFERENCE_NOT_FOUND();
if (!has_pw3 && file_read_uint8(retries->data+2+6) > 0) if (!has_pw3 && file_read_uint8(retries->data+2+6) > 0)
return SW_SECURITY_STATUS_NOT_SATISFIED(); return SW_SECURITY_STATUS_NOT_SATISFIED();
if (apdu.cmd_apdu_data_len != 0) if (apdu.nc != 0)
return SW_WRONG_LENGTH(); return SW_WRONG_LENGTH();
initialize_flash(true); initialize_flash(true);
scan_files(); scan_files();
@@ -1417,11 +1474,11 @@ static int cmd_activate_file() {
} }
static int cmd_challenge() { static int cmd_challenge() {
uint8_t *rb = (uint8_t *)random_bytes_get(apdu.expected_res_size); uint8_t *rb = (uint8_t *)random_bytes_get(apdu.ne);
if (!rb) if (!rb)
return SW_WRONG_LENGTH(); return SW_WRONG_LENGTH();
memcpy(res_APDU, rb, apdu.expected_res_size); memcpy(res_APDU, rb, apdu.ne);
res_APDU_size = apdu.expected_res_size; res_APDU_size = apdu.ne;
return SW_OK(); return SW_OK();
} }
@@ -1434,9 +1491,7 @@ static int cmd_internal_aut() {
if (!algo_ef) if (!algo_ef)
return SW_REFERENCE_NOT_FOUND(); return SW_REFERENCE_NOT_FOUND();
const uint8_t *algo = algorithm_attr_rsa2k+1; const uint8_t *algo = algorithm_attr_rsa2k+1;
uint16_t algo_len = algorithm_attr_rsa2k[0];
if (algo_ef && algo_ef->data) { if (algo_ef && algo_ef->data) {
algo_len = file_read_uint16(algo_ef->data);
algo = file_read(algo_ef->data+2); algo = file_read(algo_ef->data+2);
} }
file_t *ef = search_by_fid(pk_aut, NULL, SPECIFY_EF); file_t *ef = search_by_fid(pk_aut, NULL, SPECIFY_EF);
@@ -1454,7 +1509,7 @@ static int cmd_internal_aut() {
return SW_EXEC_ERROR(); return SW_EXEC_ERROR();
} }
size_t olen = 0; size_t olen = 0;
r = rsa_sign(&ctx, apdu.cmd_apdu_data, apdu.cmd_apdu_data_len, res_APDU, &olen); r = rsa_sign(&ctx, apdu.data, apdu.nc, res_APDU, &olen);
mbedtls_rsa_free(&ctx); mbedtls_rsa_free(&ctx);
if (r != 0) if (r != 0)
return SW_EXEC_ERROR(); return SW_EXEC_ERROR();
@@ -1469,7 +1524,7 @@ static int cmd_internal_aut() {
return SW_EXEC_ERROR(); return SW_EXEC_ERROR();
} }
size_t olen = 0; size_t olen = 0;
r = ecdsa_sign(&ctx, apdu.cmd_apdu_data, apdu.cmd_apdu_data_len, res_APDU, &olen); r = ecdsa_sign(&ctx, apdu.data, apdu.nc, res_APDU, &olen);
mbedtls_ecdsa_free(&ctx); mbedtls_ecdsa_free(&ctx);
if (r != 0) if (r != 0)
return SW_EXEC_ERROR(); return SW_EXEC_ERROR();
@@ -1481,24 +1536,24 @@ static int cmd_internal_aut() {
static int cmd_mse() { static int cmd_mse() {
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();
if (apdu.cmd_apdu_data[0] != 0x83 || apdu.cmd_apdu_data[1] != 0x1 || (apdu.cmd_apdu_data[2] != 0x2 && apdu.cmd_apdu_data[2] != 0x3)) if (apdu.data[0] != 0x83 || apdu.data[1] != 0x1 || (apdu.data[2] != 0x2 && apdu.data[2] != 0x3))
return SW_WRONG_DATA(); return SW_WRONG_DATA();
if (P2(apdu) == 0xA4) { if (P2(apdu) == 0xA4) {
if (apdu.cmd_apdu_data[2] == 0x2) { if (apdu.data[2] == 0x2) {
algo_dec = EF_ALGO_PRIV2; algo_dec = EF_ALGO_PRIV2;
pk_dec = EF_PK_DEC; pk_dec = EF_PK_DEC;
} }
else if (apdu.cmd_apdu_data[2] == 0x3) { else if (apdu.data[2] == 0x3) {
algo_dec = EF_ALGO_PRIV3; algo_dec = EF_ALGO_PRIV3;
pk_dec = EF_PK_AUT; pk_dec = EF_PK_AUT;
} }
} }
else if (P2(apdu) == 0xB8) { else if (P2(apdu) == 0xB8) {
if (apdu.cmd_apdu_data[2] == 0x2) { if (apdu.data[2] == 0x2) {
algo_aut = EF_ALGO_PRIV2; algo_aut = EF_ALGO_PRIV2;
pk_aut = EF_PK_DEC; pk_aut = EF_PK_DEC;
} }
else if (apdu.cmd_apdu_data[2] == 0x3) { else if (apdu.data[2] == 0x3) {
algo_aut = EF_ALGO_PRIV3; algo_aut = EF_ALGO_PRIV3;
pk_aut = EF_PK_AUT; pk_aut = EF_PK_AUT;
} }
@@ -1506,6 +1561,181 @@ static int cmd_mse() {
return SW_OK(); return SW_OK();
} }
static int cmd_import_data() {
file_t *ef = NULL;
uint16_t fid = 0x0;
if (P1(apdu) != 0x3F || P2(apdu) != 0xFF)
return SW_WRONG_P1P2();
if (apdu.nc < 5)
return SW_WRONG_LENGTH();
if (apdu.data[0] != 0x4D || (apdu.data[2] != 0xB6 && apdu.data[2] != 0xB8 && apdu.data[2] != 0xA4))
return SW_WRONG_DATA();
if (apdu.data[2] == 0xB6)
fid = EF_PK_SIG;
else if (apdu.data[2] != 0xB8)
fid = EF_PK_DEC;
else if (apdu.data[2] != 0xA4)
fid = EF_PK_AUT;
else
return SW_WRONG_DATA();
if (!(ef = search_by_fid(fid, NULL, SPECIFY_EF)))
return SW_REFERENCE_NOT_FOUND();
if (!authenticate_action(ef, ACL_OP_UPDATE_ERASE)) {
return SW_SECURITY_STATUS_NOT_SATISFIED();
}
uint8_t *start = apdu.data + 4 + apdu.data[3];
if (*start++ != 0x7F || *start++ != 0x48)
return SW_WRONG_DATA();
uint8_t tag_len = *start++, *end = start+tag_len, len[9] = {0}, *p[9] = {NULL};
while (start < end) {
uint8_t tag = *start++;
if ((tag >= 0x91 && tag <= 0x97) || tag == 0x99) {
len[tag-0x91] = *start++;
}
else
return SW_WRONG_DATA();
}
if (*start++ != 0x5F || *start++ != 0x48)
return SW_WRONG_DATA();
tag_len = *start++;
end = start+tag_len;
for (int t = 0; start < end; t++) {
if (len[t] > 0) {
p[t] = start;
start += len[t];
}
}
file_t *algo_ef = search_by_fid(fid-0x0010, NULL, SPECIFY_EF);
if (!algo_ef)
return SW_REFERENCE_NOT_FOUND();
const uint8_t *algo = algorithm_attr_rsa2k+1;
uint16_t algo_len = algorithm_attr_rsa2k[0];
if (algo_ef && algo_ef->data) {
algo = file_read(algo_ef->data+2);
algo_len = file_read_uint16(algo_ef->data);
}
int r = 0;
if (algo[0] == ALGO_RSA) {
mbedtls_rsa_context rsa;
if (p[0] == NULL || len[0] == 0 || p[1] == NULL || len[1] == 0 || p[2] == NULL || len[2] == 0)
return SW_WRONG_DATA();
mbedtls_rsa_init(&rsa);
r = mbedtls_mpi_read_binary(&rsa.E, p[0], len[0]);
if (r != 0) {
mbedtls_rsa_free(&rsa);
return SW_EXEC_ERROR();
}
r = mbedtls_mpi_read_binary(&rsa.P, p[1], len[1]);
if (r != 0) {
mbedtls_rsa_free(&rsa);
return SW_EXEC_ERROR();
}
r = mbedtls_mpi_read_binary(&rsa.Q, p[2], len[2]);
if (r != 0) {
mbedtls_rsa_free(&rsa);
return SW_EXEC_ERROR();
}
r = mbedtls_rsa_import(&rsa, NULL, &rsa.P, &rsa.Q, NULL, &rsa.E);
if (r != 0) {
mbedtls_rsa_free(&rsa);
return SW_EXEC_ERROR();
}
r = mbedtls_rsa_complete(&rsa);
if (r != 0) {
mbedtls_rsa_free(&rsa);
return SW_EXEC_ERROR();
}
r = mbedtls_rsa_check_privkey(&rsa);
if (r != 0) {
mbedtls_rsa_free(&rsa);
return SW_EXEC_ERROR();
}
r = store_keys(&rsa, ALGO_RSA, fid);
mbedtls_rsa_free(&rsa);
if (r != CCID_OK)
return SW_EXEC_ERROR();
}
else if (algo[0] == ALGO_ECDSA || algo[0] == ALGO_ECDH) {
mbedtls_ecdsa_context ecdsa;
if (p[1] == NULL || len[1] == 0)
return SW_WRONG_DATA();
mbedtls_ecp_group_id gid = get_ec_group_id_from_attr(algo+1, algo_len-1);
if (gid == MBEDTLS_ECP_DP_NONE)
return SW_FUNC_NOT_SUPPORTED();
mbedtls_ecdsa_init(&ecdsa);
r = mbedtls_ecp_read_key(gid, &ecdsa, p[1], len[1]);
if (r != 0) {
mbedtls_ecdsa_free(&ecdsa);
return SW_EXEC_ERROR();
}
r = store_keys(&ecdsa, ALGO_ECDSA, fid);
mbedtls_ecdsa_free(&ecdsa);
if (r != CCID_OK)
return SW_EXEC_ERROR();
}
if (fid == EF_PK_SIG)
reset_sig_count();
return SW_OK();
}
static int cmd_version() {
res_APDU[res_APDU_size++] = PIPGP_VERSION_MAJOR;
res_APDU[res_APDU_size++] = PIPGP_VERSION_MINOR;
res_APDU[res_APDU_size++] = 0x0;
return SW_OK();
}
static int cmd_select_data() {
file_t *ef = NULL;
uint16_t fid = 0x0;
if (P2(apdu) != 0x4)
return SW_WRONG_P1P2();
if (apdu.data[0] != 0x60)
return SW_WRONG_DATA();
if (apdu.nc != apdu.data[1]+2 || apdu.nc < 5)
return SW_WRONG_LENGTH();
if (apdu.data[2] != 0x5C)
return SW_WRONG_DATA();
if (apdu.data[3] == 2)
fid = (apdu.data[4] << 8) | apdu.data[5];
else
fid = apdu.data[4];
if (!(ef = search_by_fid(fid, NULL, SPECIFY_EF)))
return SW_REFERENCE_NOT_FOUND();
if (!authenticate_action(ef, ACL_OP_UPDATE_ERASE)) {
return SW_SECURITY_STATUS_NOT_SATISFIED();
}
fid &= ~0x6000; //Now get private DO
fid += P1(apdu);
if (!(ef = search_by_fid(fid, NULL, SPECIFY_EF)))
return SW_REFERENCE_NOT_FOUND();
select_file(ef);
return SW_OK();
}
static int cmd_get_next_data() {
file_t *ef = NULL;
if (apdu.nc > 0)
return SW_WRONG_LENGTH();
if (!currentEF)
return SW_RECORD_NOT_FOUND();
uint16_t fid = (P1(apdu) << 8) | P2(apdu);
if (!(ef = search_by_fid(fid, NULL, SPECIFY_EF)))
return SW_REFERENCE_NOT_FOUND();
if (!authenticate_action(ef, ACL_OP_UPDATE_ERASE)) {
return SW_SECURITY_STATUS_NOT_SATISFIED();
}
if ((currentEF->fid & 0x1FF0) != (fid & 0x1FF0))
return SW_WRONG_P1P2();
fid = currentEF->fid + 1; //curentEF contains private DO. so, we select the next one
if (!(ef = search_by_fid(fid, NULL, SPECIFY_EF)))
return SW_REFERENCE_NOT_FOUND();
select_file(ef);
return cmd_get_data();
}
typedef struct cmd typedef struct cmd
{ {
uint8_t ins; uint8_t ins;
@@ -1522,9 +1752,13 @@ typedef struct cmd
#define INS_CHALLENGE 0x84 #define INS_CHALLENGE 0x84
#define INS_INTERNAL_AUT 0x88 #define INS_INTERNAL_AUT 0x88
#define INS_SELECT 0xA4 #define INS_SELECT 0xA4
#define INS_SELECT_DATA 0xA5
#define INS_GET_DATA 0xCA #define INS_GET_DATA 0xCA
#define INS_GET_NEXT_DATA 0xCC
#define INS_PUT_DATA 0xDA #define INS_PUT_DATA 0xDA
#define INS_IMPORT_DATA 0xDB
#define INS_TERMINATE_DF 0xE6 #define INS_TERMINATE_DF 0xE6
#define INS_VERSION 0xF1
static const cmd_t cmds[] = { static const cmd_t cmds[] = {
{ INS_GET_DATA, cmd_get_data }, { INS_GET_DATA, cmd_get_data },
@@ -1540,11 +1774,15 @@ static const cmd_t cmds[] = {
{ INS_CHALLENGE, cmd_challenge }, { INS_CHALLENGE, cmd_challenge },
{ INS_INTERNAL_AUT, cmd_internal_aut }, { INS_INTERNAL_AUT, cmd_internal_aut },
{ INS_MSE, cmd_mse }, { INS_MSE, cmd_mse },
{ INS_IMPORT_DATA, cmd_import_data },
{ INS_VERSION, cmd_version },
{ INS_SELECT_DATA, cmd_select_data },
{ INS_GET_NEXT_DATA, cmd_get_next_data },
{ 0x00, 0x0} { 0x00, 0x0}
}; };
int openpgp_process_apdu() { int openpgp_process_apdu() {
int r = 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)) {
int r = cmd->cmd_handler(); int r = cmd->cmd_handler();

View File

@@ -23,5 +23,10 @@
#define OPGP_VERSION_MAJOR ((OPGP_VERSION >> 8) & 0xff) #define OPGP_VERSION_MAJOR ((OPGP_VERSION >> 8) & 0xff)
#define OPGP_VERSION_MINOR (OPGP_VERSION & 0xff) #define OPGP_VERSION_MINOR (OPGP_VERSION & 0xff)
#endif
#define PIPGP_VERSION 0x0106
#define PIPGP_VERSION_MAJOR ((PIPGP_VERSION >> 8) & 0xff)
#define PIPGP_VERSION_MINOR (PIPGP_VERSION & 0xff)
#endif