diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml
new file mode 100644
index 0000000..61a9640
--- /dev/null
+++ b/.github/workflows/nightly.yml
@@ -0,0 +1,35 @@
+name: "Nightly deploy"
+
+on:
+ schedule:
+ - cron: '0 2 * * *'
+ workflow_dispatch:
+
+jobs:
+ nightly:
+ name: Deploy nightly
+ strategy:
+ fail-fast: false
+ matrix:
+ refs: [main]
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v4
+ with:
+ ref: ${{ matrix.refs }}
+ submodules: 'recursive'
+ - name : Build
+ env:
+ PICO_SDK_PATH: ../pico-sdk
+ run: |
+ ./workflows/autobuild.sh pico
+ ./build_pico_openpgp.sh
+ ./workflows/autobuild.sh esp32
+ - name: Update nightly release
+ uses: pyTooling/Actions/releaser@main
+ with:
+ tag: nightly-${{ matrix.refs }}
+ rm: true
+ token: ${{ secrets.GITHUB_TOKEN }}
+ files: release/*.*
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 1207dbd..8de5559 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -21,18 +21,23 @@ if(ESP_PLATFORM)
set(EXTRA_COMPONENT_DIRS src pico-keys-sdk/src)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
else()
- if(ENABLE_EMULATION)
- else()
- include(pico_sdk_import.cmake)
+ if(NOT ENABLE_EMULATION)
+ include(pico_sdk_import.cmake)
endif()
project(pico_openpgp C CXX ASM)
set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)
- if(ENABLE_EMULATION)
- else()
- pico_sdk_init()
+ if(NOT ENABLE_EMULATION)
+ pico_sdk_init()
+ endif()
+
+ if(NOT DEFINED __FOR_CI)
+ set(__FOR_CI 0)
+ endif()
+ if(__FOR_CI)
+ add_definitions(-D__FOR_CI)
endif()
add_executable(pico_openpgp)
@@ -43,11 +48,31 @@ set(SOURCES ${SOURCES}
${CMAKE_CURRENT_LIST_DIR}/src/openpgp/files.c
${CMAKE_CURRENT_LIST_DIR}/src/openpgp/piv.c
${CMAKE_CURRENT_LIST_DIR}/src/openpgp/management.c
+ ${CMAKE_CURRENT_LIST_DIR}/src/openpgp/cmd_select.c
+ ${CMAKE_CURRENT_LIST_DIR}/src/openpgp/cmd_get_data.c
+ ${CMAKE_CURRENT_LIST_DIR}/src/openpgp/cmd_verify.c
+ ${CMAKE_CURRENT_LIST_DIR}/src/openpgp/cmd_put_data.c
+ ${CMAKE_CURRENT_LIST_DIR}/src/openpgp/cmd_select_data.c
+ ${CMAKE_CURRENT_LIST_DIR}/src/openpgp/cmd_import_data.c
+ ${CMAKE_CURRENT_LIST_DIR}/src/openpgp/cmd_version.c
+ ${CMAKE_CURRENT_LIST_DIR}/src/openpgp/cmd_change_pin.c
+ ${CMAKE_CURRENT_LIST_DIR}/src/openpgp/cmd_mse.c
+ ${CMAKE_CURRENT_LIST_DIR}/src/openpgp/cmd_internal_aut.c
+ ${CMAKE_CURRENT_LIST_DIR}/src/openpgp/cmd_challenge.c
+ ${CMAKE_CURRENT_LIST_DIR}/src/openpgp/cmd_activate_file.c
+ ${CMAKE_CURRENT_LIST_DIR}/src/openpgp/cmd_terminate_df.c
+ ${CMAKE_CURRENT_LIST_DIR}/src/openpgp/cmd_pso.c
+ ${CMAKE_CURRENT_LIST_DIR}/src/openpgp/cmd_keypair_gen.c
+ ${CMAKE_CURRENT_LIST_DIR}/src/openpgp/cmd_reset_retry.c
+ ${CMAKE_CURRENT_LIST_DIR}/src/openpgp/do.c
)
set(USB_ITF_CCID 1)
set(USB_ITF_WCID 1)
include(pico-keys-sdk/pico_keys_sdk_import.cmake)
+
+SET_VERSION(ver_major ver_minor "${CMAKE_CURRENT_LIST_DIR}/src/openpgp/version.h")
+
if(ESP_PLATFORM)
project(pico_openpgp)
endif()
@@ -60,7 +85,7 @@ if(NOT ESP_PLATFORM)
target_include_directories(pico_openpgp PUBLIC ${INCLUDES})
target_compile_options(pico_openpgp PUBLIC
- -Wall
+ -Wall
)
if(NOT MSVC)
target_compile_options(pico_openpgp PUBLIC
@@ -91,6 +116,7 @@ if(NOT ESP_PLATFORM)
)
endif(APPLE)
target_link_libraries(pico_openpgp PRIVATE pthread m)
+ else()
+ pico_add_extra_outputs(${CMAKE_PROJECT_NAME})
endif()
endif()
-
diff --git a/pico-keys-sdk b/pico-keys-sdk
index 1d86efa..c42a6e1 160000
--- a/pico-keys-sdk
+++ b/pico-keys-sdk
@@ -1 +1 @@
-Subproject commit 1d86efa33bf1b3c118947eac14280f9953a49bc9
+Subproject commit c42a6e1a83da1a604c696f97bcefd8405b05d3ed
diff --git a/sdkconfig.defaults b/sdkconfig.defaults
index d917312..d5613aa 100644
--- a/sdkconfig.defaults
+++ b/sdkconfig.defaults
@@ -4,6 +4,7 @@
IGNORE_UNKNOWN_FILES_FOR_MANAGED_COMPONENTS=1
CONFIG_TINYUSB=y
+CONFIG_TINYUSB_TASK_STACK_SIZE=16384
CONFIG_PARTITION_TABLE_CUSTOM=y
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="pico-keys-sdk/config/esp32/partitions.csv"
diff --git a/src/openpgp/cmd_activate_file.c b/src/openpgp/cmd_activate_file.c
new file mode 100644
index 0000000..77a2c23
--- /dev/null
+++ b/src/openpgp/cmd_activate_file.c
@@ -0,0 +1,22 @@
+/*
+ * This file is part of the Pico OpenPGP distribution (https://github.com/polhenarejos/pico-openpgp).
+ * Copyright (c) 2022 Pol Henarejos.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#include "openpgp.h"
+
+int cmd_activate_file() {
+ return SW_OK();
+}
\ No newline at end of file
diff --git a/src/openpgp/cmd_challenge.c b/src/openpgp/cmd_challenge.c
new file mode 100644
index 0000000..8e9db61
--- /dev/null
+++ b/src/openpgp/cmd_challenge.c
@@ -0,0 +1,29 @@
+/*
+ * This file is part of the Pico OpenPGP distribution (https://github.com/polhenarejos/pico-openpgp).
+ * Copyright (c) 2022 Pol Henarejos.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#include "openpgp.h"
+#include "random.h"
+
+int cmd_challenge() {
+ uint8_t *rb = (uint8_t *) random_bytes_get(apdu.ne);
+ if (!rb) {
+ return SW_WRONG_LENGTH();
+ }
+ memcpy(res_APDU, rb, apdu.ne);
+ res_APDU_size = apdu.ne;
+ return SW_OK();
+}
diff --git a/src/openpgp/cmd_change_pin.c b/src/openpgp/cmd_change_pin.c
new file mode 100644
index 0000000..b39c098
--- /dev/null
+++ b/src/openpgp/cmd_change_pin.c
@@ -0,0 +1,69 @@
+/*
+ * This file is part of the Pico OpenPGP distribution (https://github.com/polhenarejos/pico-openpgp).
+ * Copyright (c) 2022 Pol Henarejos.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#include "openpgp.h"
+#include "otp.h"
+
+int cmd_change_pin() {
+ if (P1(apdu) != 0x0) {
+ return SW_WRONG_P1P2();
+ }
+ uint16_t fid = 0x1000 | P2(apdu);
+ file_t *pw;
+ if (!(pw = search_by_fid(fid, NULL, SPECIFY_EF))) {
+ return SW_REFERENCE_NOT_FOUND();
+ }
+ uint8_t pin_len = file_get_data(pw)[0];
+ uint16_t r = 0;
+ if ((r = load_dek()) != PICOKEY_OK) {
+ return SW_EXEC_ERROR();
+ }
+
+ if (otp_key_1) {
+ for (int i = 0; i < 32; i++) {
+ dek[IV_SIZE + i] ^= otp_key_1[i];
+ }
+ }
+ r = check_pin(pw, apdu.data, pin_len);
+ if (r != 0x9000) {
+ return r;
+ }
+ uint8_t dhash[33];
+ dhash[0] = apdu.nc - pin_len;
+ double_hash_pin(apdu.data + pin_len, apdu.nc - pin_len, dhash + 1);
+ 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) {
+ hash_multi(apdu.data + pin_len, apdu.nc - pin_len, session_pw1);
+ memcpy(def + IV_SIZE, dek + IV_SIZE, 32);
+ aes_encrypt_cfb_256(session_pw1, def, def + IV_SIZE, 32);
+ }
+ else if (P2(apdu) == 0x83) {
+ hash_multi(apdu.data + pin_len, apdu.nc - pin_len, session_pw3);
+ memcpy(def + IV_SIZE + 32 + 32, dek + IV_SIZE, 32);
+ aes_encrypt_cfb_256(session_pw3, def, def + IV_SIZE + 32 + 32, 32);
+ }
+ file_put_data(tf, def, sizeof(def));
+ low_flash_available();
+ return SW_OK();
+}
diff --git a/src/openpgp/cmd_get_data.c b/src/openpgp/cmd_get_data.c
new file mode 100644
index 0000000..20e034f
--- /dev/null
+++ b/src/openpgp/cmd_get_data.c
@@ -0,0 +1,91 @@
+/*
+ * This file is part of the Pico OpenPGP distribution (https://github.com/polhenarejos/pico-openpgp).
+ * Copyright (c) 2022 Pol Henarejos.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#include "openpgp.h"
+#include "asn1.h"
+
+int cmd_get_data() {
+ if (apdu.nc > 0) {
+ return SW_WRONG_LENGTH();
+ }
+ uint16_t fid = (P1(apdu) << 8) | P2(apdu);
+ file_t *ef;
+ if (!(ef = search_by_fid(fid, NULL, SPECIFY_EF))) {
+ return SW_REFERENCE_NOT_FOUND();
+ }
+ if (!authenticate_action(ef, ACL_OP_READ_SEARCH)) {
+ return SW_SECURITY_STATUS_NOT_SATISFIED();
+ }
+ if (currentEF && (currentEF->fid & 0x1FF0) == (fid & 0x1FF0)) { //previously selected
+ ef = currentEF;
+ }
+ else {
+ select_file(ef);
+ }
+ if (ef->data) {
+ uint16_t fids[] = { 1, fid };
+ uint16_t data_len = parse_do(fids, 1);
+ uint8_t *p = NULL;
+ uint16_t tg = 0;
+ uint16_t tg_len = 0;
+ asn1_ctx_t ctxi;
+ asn1_ctx_init(res_APDU, data_len, &ctxi);
+ if (walk_tlv(&ctxi, &p, &tg, &tg_len, NULL)) {
+ uint8_t dec = 2;
+ if ((tg & 0x1f) == 0x1f) {
+ dec++;
+ }
+ 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);
+ data_len -= dec;
+ res_APDU_size -= dec;
+ }
+ }
+ //if (apdu.ne > data_len)
+ // apdu.ne = data_len;
+ }
+ return SW_OK();
+}
+
+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();
+}
diff --git a/src/openpgp/cmd_import_data.c b/src/openpgp/cmd_import_data.c
new file mode 100644
index 0000000..982a6a0
--- /dev/null
+++ b/src/openpgp/cmd_import_data.c
@@ -0,0 +1,213 @@
+/*
+ * This file is part of the Pico OpenPGP distribution (https://github.com/polhenarejos/pico-openpgp).
+ * Copyright (c) 2022 Pol Henarejos.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#ifdef ESP_PLATFORM
+#include "esp_compat.h"
+#define MBEDTLS_ALLOW_PRIVATE_ACCESS
+#else
+#include "common.h"
+#endif
+#include "openpgp.h"
+#include "random.h"
+#include "do.h"
+
+uint16_t tag_len(uint8_t **data) {
+ size_t len = *(*data)++;
+ if (len == 0x82) {
+ len = *(*data)++ << 8;
+ len |= *(*data)++;
+ }
+ else if (len == 0x81) {
+ len = *(*data)++;
+ }
+ return len;
+}
+
+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();
+ }
+ uint8_t *start = apdu.data;
+ if (*start++ != 0x4D) {
+ return SW_WRONG_DATA();
+ }
+ uint16_t tgl = tag_len(&start);
+ if (*start != 0xB6 && *start != 0xB8 && *start != 0xA4) {
+ return SW_WRONG_DATA();
+ }
+ if (*start == 0xB6) {
+ fid = EF_PK_SIG;
+ }
+ else if (*start == 0xB8) {
+ fid = EF_PK_DEC;
+ }
+ else if (*start == 0xA4) {
+ fid = EF_PK_AUT;
+ }
+ else {
+ return SW_WRONG_DATA();
+ }
+ start++;
+ 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();
+ }
+ start += (*start + 1);
+ if (*start++ != 0x7F || *start++ != 0x48) {
+ return SW_WRONG_DATA();
+ }
+ tgl = tag_len(&start);
+ uint8_t *end = start + tgl, *p[9] = { 0 };
+ uint16_t len[9] = { 0 };
+ while (start < end) {
+ uint8_t tag = *start++;
+ if ((tag >= 0x91 && tag <= 0x97) || tag == 0x99) {
+ len[tag - 0x91] = tag_len(&start);
+ }
+ else {
+ return SW_WRONG_DATA();
+ }
+ }
+ if (*start++ != 0x5F || *start++ != 0x48) {
+ return SW_WRONG_DATA();
+ }
+ tgl = tag_len(&start);
+ end = start + tgl;
+ for (int t = 0; start < end && t < 9; 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_get_data(algo_ef);
+ algo_len = file_get_size(algo_ef);
+ }
+ 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, true);
+ make_rsa_response(&rsa);
+ mbedtls_rsa_free(&rsa);
+ if (r != PICOKEY_OK) {
+ return SW_EXEC_ERROR();
+ }
+ }
+ else if (algo[0] == ALGO_ECDSA || algo[0] == ALGO_ECDH || algo[0] == ALGO_EDDSA) {
+ mbedtls_ecp_keypair 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_ecp_keypair_init(&ecdsa);
+ if (gid == MBEDTLS_ECP_DP_CURVE25519) {
+ mbedtls_ecp_group_load(&ecdsa.grp, gid);
+ r = mbedtls_mpi_read_binary(&ecdsa.d, p[1], len[1]);
+ }
+ else {
+ r = mbedtls_ecp_read_key(gid, &ecdsa, p[1], len[1]);
+ }
+ if (r != 0) {
+ mbedtls_ecp_keypair_free(&ecdsa);
+ return SW_EXEC_ERROR();
+ }
+ if (ecdsa.grp.id == MBEDTLS_ECP_DP_ED25519) {
+ r = mbedtls_ecp_point_edwards(&ecdsa.grp, &ecdsa.Q, &ecdsa.d, random_gen, NULL);
+ }
+ else {
+ r = mbedtls_ecp_mul(&ecdsa.grp, &ecdsa.Q, &ecdsa.d, &ecdsa.grp.G, random_gen, NULL);
+ }
+ if (r != 0) {
+ mbedtls_ecp_keypair_free(&ecdsa);
+ return SW_EXEC_ERROR();
+ }
+ r = store_keys(&ecdsa, ALGO_ECDSA, fid, true);
+ make_ecdsa_response(&ecdsa);
+ mbedtls_ecp_keypair_free(&ecdsa);
+ if (r != PICOKEY_OK) {
+ return SW_EXEC_ERROR();
+ }
+ }
+ else {
+ return SW_FUNC_NOT_SUPPORTED();
+ }
+ if (fid == EF_PK_SIG) {
+ reset_sig_count();
+ }
+ file_t *pbef = search_by_fid(fid + 3, NULL, SPECIFY_EF);
+ if (!pbef) {
+ return SW_REFERENCE_NOT_FOUND();
+ }
+ r = file_put_data(pbef, res_APDU, res_APDU_size);
+ if (r != PICOKEY_OK) {
+ return SW_EXEC_ERROR();
+ }
+ res_APDU_size = 0; //make_*_response sets a response. we need to overwrite
+ return SW_OK();
+}
diff --git a/src/openpgp/cmd_internal_aut.c b/src/openpgp/cmd_internal_aut.c
new file mode 100644
index 0000000..869bb22
--- /dev/null
+++ b/src/openpgp/cmd_internal_aut.c
@@ -0,0 +1,77 @@
+/*
+ * This file is part of the Pico OpenPGP distribution (https://github.com/polhenarejos/pico-openpgp).
+ * Copyright (c) 2022 Pol Henarejos.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#include "openpgp.h"
+#include "do.h"
+
+int cmd_internal_aut() {
+ if (P1(apdu) != 0x00 || P2(apdu) != 0x00) {
+ return SW_WRONG_P1P2();
+ }
+ if (!has_pw3 && !has_pw2) {
+ return SW_SECURITY_STATUS_NOT_SATISFIED();
+ }
+ file_t *algo_ef = search_by_fid(algo_aut, NULL, SPECIFY_EF);
+ if (!algo_ef) {
+ return SW_REFERENCE_NOT_FOUND();
+ }
+ const uint8_t *algo = algorithm_attr_rsa2k + 1;
+ if (algo_ef && algo_ef->data) {
+ algo = file_get_data(algo_ef);
+ }
+ file_t *ef = search_by_fid(pk_aut, NULL, SPECIFY_EF);
+ if (!ef) {
+ return SW_REFERENCE_NOT_FOUND();
+ }
+ if (wait_button_pressed(EF_UIF_AUT) == true) {
+ return SW_SECURE_MESSAGE_EXEC_ERROR();
+ }
+ int r = PICOKEY_OK;
+ if (algo[0] == ALGO_RSA) {
+ mbedtls_rsa_context ctx;
+ mbedtls_rsa_init(&ctx);
+ r = load_private_key_rsa(&ctx, ef, true);
+ if (r != PICOKEY_OK) {
+ mbedtls_rsa_free(&ctx);
+ return SW_EXEC_ERROR();
+ }
+ size_t olen = 0;
+ r = rsa_sign(&ctx, apdu.data, apdu.nc, res_APDU, &olen);
+ mbedtls_rsa_free(&ctx);
+ if (r != 0) {
+ return SW_EXEC_ERROR();
+ }
+ res_APDU_size = olen;
+ }
+ else if (algo[0] == ALGO_ECDH || algo[0] == ALGO_ECDSA || algo[0] == ALGO_EDDSA) {
+ mbedtls_ecp_keypair ctx;
+ mbedtls_ecp_keypair_init(&ctx);
+ r = load_private_key_ecdsa(&ctx, ef, true);
+ if (r != PICOKEY_OK) {
+ mbedtls_ecp_keypair_free(&ctx);
+ return SW_EXEC_ERROR();
+ }
+ size_t olen = 0;
+ r = ecdsa_sign(&ctx, apdu.data, apdu.nc, res_APDU, &olen);
+ mbedtls_ecp_keypair_free(&ctx);
+ if (r != 0) {
+ return SW_EXEC_ERROR();
+ }
+ res_APDU_size = olen;
+ }
+ return SW_OK();
+}
diff --git a/src/openpgp/cmd_keypair_gen.c b/src/openpgp/cmd_keypair_gen.c
new file mode 100644
index 0000000..6ee8c38
--- /dev/null
+++ b/src/openpgp/cmd_keypair_gen.c
@@ -0,0 +1,139 @@
+/*
+ * This file is part of the Pico OpenPGP distribution (https://github.com/polhenarejos/pico-openpgp).
+ * Copyright (c) 2022 Pol Henarejos.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#include "openpgp.h"
+#include "do.h"
+#include "random.h"
+#include "mbedtls/eddsa.h"
+
+int cmd_keypair_gen() {
+ if (P2(apdu) != 0x0) {
+ return SW_INCORRECT_P1P2();
+ }
+ if (apdu.nc != 2 && apdu.nc != 5) {
+ return SW_WRONG_LENGTH();
+ }
+ if (!has_pw3 && P1(apdu) == 0x80) {
+ return SW_SECURITY_STATUS_NOT_SATISFIED();
+ }
+
+ uint16_t fid = 0x0;
+ int r = PICOKEY_OK;
+ if (apdu.data[0] == 0xB6) {
+ fid = EF_PK_SIG;
+ }
+ else if (apdu.data[0] == 0xB8) {
+ fid = EF_PK_DEC;
+ }
+ else if (apdu.data[0] == 0xA4) {
+ fid = EF_PK_AUT;
+ }
+ else {
+ return SW_WRONG_DATA();
+ }
+
+ 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_get_data(algo_ef);
+ algo_len = file_get_size(algo_ef);
+ }
+ if (P1(apdu) == 0x80) { //generate
+ if (algo[0] == ALGO_RSA) {
+ int exponent = 65537, nlen = (algo[1] << 8) | algo[2];
+ printf("KEYPAIR RSA %d\r\n", nlen);
+ //if (nlen != 2048 && nlen != 4096)
+ // return SW_FUNC_NOT_SUPPORTED();
+ mbedtls_rsa_context rsa;
+ mbedtls_rsa_init(&rsa);
+ uint8_t index = 0;
+ r = mbedtls_rsa_gen_key(&rsa, random_gen, &index, nlen, exponent);
+ if (r != 0) {
+ mbedtls_rsa_free(&rsa);
+ return SW_EXEC_ERROR();
+ }
+ r = store_keys(&rsa, ALGO_RSA, fid, true);
+ make_rsa_response(&rsa);
+ mbedtls_rsa_free(&rsa);
+ if (r != PICOKEY_OK) {
+ return SW_EXEC_ERROR();
+ }
+ }
+ else if (algo[0] == ALGO_ECDH || algo[0] == ALGO_ECDSA || algo[0] == ALGO_EDDSA) {
+ printf("KEYPAIR ECDSA\r\n");
+ 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_ecp_keypair ecdsa;
+ mbedtls_ecp_keypair_init(&ecdsa);
+ uint8_t index = 0;
+ r = mbedtls_ecdsa_genkey(&ecdsa, gid, random_gen, &index);
+ if (r != 0) {
+ mbedtls_ecp_keypair_free(&ecdsa);
+ return SW_EXEC_ERROR();
+ }
+ r = store_keys(&ecdsa, algo[0], fid, true);
+ make_ecdsa_response(&ecdsa);
+ mbedtls_ecp_keypair_free(&ecdsa);
+ if (r != PICOKEY_OK) {
+ return SW_EXEC_ERROR();
+ }
+ }
+ else {
+ return SW_FUNC_NOT_SUPPORTED();
+ }
+ file_t *pbef = search_by_fid(fid + 3, NULL, SPECIFY_EF);
+ if (!pbef) {
+ return SW_REFERENCE_NOT_FOUND();
+ }
+ r = file_put_data(pbef, res_APDU, res_APDU_size);
+ if (r != PICOKEY_OK) {
+ return SW_EXEC_ERROR();
+ }
+ if (fid == EF_PK_SIG) {
+ 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, true);
+ /* if storing the key fails, we silently continue */
+ //if (r != PICOKEY_OK)
+ // return SW_EXEC_ERROR();
+ }
+ low_flash_available();
+ return SW_OK();
+ }
+ else if (P1(apdu) == 0x81) { //read
+ file_t *ef = search_by_fid(fid + 3, NULL, SPECIFY_EF);
+ if (!ef || !ef->data) {
+ return SW_REFERENCE_NOT_FOUND();
+ }
+ res_APDU_size = file_get_size(ef);
+ memcpy(res_APDU, file_get_data(ef), res_APDU_size);
+ return SW_OK();
+ }
+ return SW_INCORRECT_P1P2();
+}
diff --git a/src/openpgp/cmd_mse.c b/src/openpgp/cmd_mse.c
new file mode 100644
index 0000000..4be170d
--- /dev/null
+++ b/src/openpgp/cmd_mse.c
@@ -0,0 +1,49 @@
+/*
+ * This file is part of the Pico OpenPGP distribution (https://github.com/polhenarejos/pico-openpgp).
+ * Copyright (c) 2022 Pol Henarejos.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#include "openpgp.h"
+
+int cmd_mse() {
+ if (P1(apdu) != 0x41 || (P2(apdu) != 0xA4 && P2(apdu) != 0xB8)) {
+ return SW_WRONG_P1P2();
+ }
+ if (apdu.data[0] != 0x83 || apdu.data[1] != 0x1 ||
+ (apdu.data[2] != 0x2 && apdu.data[2] != 0x3)) {
+ return SW_WRONG_DATA();
+ }
+ if (P2(apdu) == 0xA4) {
+ if (apdu.data[2] == 0x2) {
+ algo_dec = EF_ALGO_PRIV2;
+ pk_dec = EF_PK_DEC;
+ }
+ else if (apdu.data[2] == 0x3) {
+ algo_dec = EF_ALGO_PRIV3;
+ pk_dec = EF_PK_AUT;
+ }
+ }
+ else if (P2(apdu) == 0xB8) {
+ if (apdu.data[2] == 0x2) {
+ algo_aut = EF_ALGO_PRIV2;
+ pk_aut = EF_PK_DEC;
+ }
+ else if (apdu.data[2] == 0x3) {
+ algo_aut = EF_ALGO_PRIV3;
+ pk_aut = EF_PK_AUT;
+ }
+ }
+ return SW_OK();
+}
diff --git a/src/openpgp/cmd_pso.c b/src/openpgp/cmd_pso.c
new file mode 100644
index 0000000..e2e9ba0
--- /dev/null
+++ b/src/openpgp/cmd_pso.c
@@ -0,0 +1,213 @@
+/*
+ * This file is part of the Pico OpenPGP distribution (https://github.com/polhenarejos/pico-openpgp).
+ * Copyright (c) 2022 Pol Henarejos.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#ifdef ESP_PLATFORM
+#include "esp_compat.h"
+#define MBEDTLS_ALLOW_PRIVATE_ACCESS
+#else
+#include "common.h"
+#endif
+#include "openpgp.h"
+#include "do.h"
+#include "random.h"
+#include "mbedtls/ecdh.h"
+#include "mbedtls/asn1.h"
+
+int cmd_pso() {
+ uint16_t algo_fid = 0x0, pk_fid = 0x0;
+ bool is_aes = false;
+ if (P1(apdu) == 0x9E && P2(apdu) == 0x9A) {
+ if (!has_pw3 && !has_pw1) {
+ return SW_SECURITY_STATUS_NOT_SATISFIED();
+ }
+ algo_fid = EF_ALGO_PRIV1;
+ pk_fid = EF_PK_SIG;
+ }
+ else if (P1(apdu) == 0x80 && P2(apdu) == 0x86) {
+ if (!has_pw3 && !has_pw2) {
+ return SW_SECURITY_STATUS_NOT_SATISFIED();
+ }
+ algo_fid = algo_dec;
+ pk_fid = pk_dec;
+ }
+ else {
+ return SW_INCORRECT_P1P2();
+ }
+ file_t *algo_ef = search_by_fid(algo_fid, NULL, SPECIFY_EF);
+ if (!algo_ef) {
+ return SW_REFERENCE_NOT_FOUND();
+ }
+ const uint8_t *algo = algorithm_attr_rsa2k + 1;
+ if (algo_ef && algo_ef->data) {
+ algo = file_get_data(algo_ef);
+ }
+ 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);
+ if (!ef) {
+ return SW_REFERENCE_NOT_FOUND();
+ }
+ if (wait_button_pressed(pk_fid == EF_PK_SIG ? EF_UIF_SIG : EF_UIF_DEC) == true) {
+ return SW_SECURE_MESSAGE_EXEC_ERROR();
+ }
+ int r = PICOKEY_OK;
+ int key_size = file_get_size(ef);
+ if (is_aes) {
+ uint8_t aes_key[32];
+ r = load_aes_key(aes_key, ef);
+ if (r != PICOKEY_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, PICO_KEYS_AES_MODE_CBC, apdu.data + 1, apdu.nc - 1);
+ memset(aes_key, 0, sizeof(aes_key));
+ if (r != PICOKEY_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, PICO_KEYS_AES_MODE_CBC, apdu.data, apdu.nc);
+ memset(aes_key, 0, sizeof(aes_key));
+ if (r != PICOKEY_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) {
+ mbedtls_rsa_context ctx;
+ mbedtls_rsa_init(&ctx);
+ r = load_private_key_rsa(&ctx, ef, true);
+ if (r != PICOKEY_OK) {
+ mbedtls_rsa_free(&ctx);
+ return SW_EXEC_ERROR();
+ }
+ if (P1(apdu) == 0x9E && P2(apdu) == 0x9A) {
+ size_t olen = 0;
+ r = rsa_sign(&ctx, apdu.data, apdu.nc, res_APDU, &olen);
+ mbedtls_rsa_free(&ctx);
+ if (r != 0) {
+ return SW_EXEC_ERROR();
+ }
+ res_APDU_size = olen;
+ //apdu.ne = key_size;
+ inc_sig_count();
+ }
+ else if (P1(apdu) == 0x80 && P2(apdu) == 0x86) {
+ if (apdu.nc < key_size) { //needs padding
+ memset(apdu.data + apdu.nc, 0, key_size - apdu.nc);
+ }
+ size_t olen = 0;
+ r = mbedtls_rsa_pkcs1_decrypt(&ctx,
+ random_gen,
+ NULL,
+ &olen,
+ apdu.data + 1,
+ res_APDU,
+ key_size);
+ mbedtls_rsa_free(&ctx);
+ if (r != 0) {
+ return SW_EXEC_ERROR();
+ }
+ res_APDU_size = olen;
+ }
+ }
+ else if (algo[0] == ALGO_ECDH || algo[0] == ALGO_ECDSA || algo[0] == ALGO_EDDSA) {
+ if (P1(apdu) == 0x9E && P2(apdu) == 0x9A) {
+ mbedtls_ecp_keypair ctx;
+ mbedtls_ecp_keypair_init(&ctx);
+ r = load_private_key_ecdsa(&ctx, ef, true);
+ if (r != PICOKEY_OK) {
+ mbedtls_ecp_keypair_free(&ctx);
+ return SW_EXEC_ERROR();
+ }
+ size_t olen = 0;
+ r = ecdsa_sign(&ctx, apdu.data, apdu.nc, res_APDU, &olen);
+ mbedtls_ecp_keypair_free(&ctx);
+ if (r != 0) {
+ return SW_EXEC_ERROR();
+ }
+ res_APDU_size = olen;
+ inc_sig_count();
+ }
+ else if (P1(apdu) == 0x80 && P2(apdu) == 0x86) {
+ mbedtls_ecdh_context ctx;
+ uint8_t kdata[67];
+ uint8_t *data = apdu.data, *end = data + apdu.nc;
+ size_t len = 0;
+ if (mbedtls_asn1_get_tag(&data, end, &len, 0xA6) != 0) {
+ return SW_WRONG_DATA();
+ }
+ if (*data++ != 0x7f) {
+ return SW_WRONG_DATA();
+ }
+ if (mbedtls_asn1_get_tag(&data, end, &len,
+ 0x49) != 0 ||
+ mbedtls_asn1_get_tag(&data, end, &len, 0x86) != 0) {
+ return SW_WRONG_DATA();
+ }
+ //if (len != 2*key_size-1)
+ // return SW_WRONG_LENGTH();
+ memcpy(kdata, file_get_data(ef), key_size);
+ if (dek_decrypt(kdata, key_size) != 0) {
+ return SW_EXEC_ERROR();
+ }
+ mbedtls_ecdh_init(&ctx);
+ mbedtls_ecp_group_id gid = kdata[0];
+ r = mbedtls_ecdh_setup(&ctx, gid);
+ if (r != 0) {
+ mbedtls_ecdh_free(&ctx);
+ return SW_DATA_INVALID();
+ }
+ r = mbedtls_ecp_read_key(gid, (mbedtls_ecdsa_context *)&ctx.ctx.mbed_ecdh, kdata + 1, key_size - 1);
+ if (r != 0) {
+ mbedtls_ecdh_free(&ctx);
+ return SW_DATA_INVALID();
+ }
+ r = mbedtls_ecdh_read_public(&ctx, data - 1, len + 1);
+ if (r != 0) {
+ mbedtls_ecdh_free(&ctx);
+ return SW_DATA_INVALID();
+ }
+ size_t olen = 0;
+ r = mbedtls_ecdh_calc_secret(&ctx,
+ &olen,
+ res_APDU,
+ MBEDTLS_ECP_MAX_BYTES,
+ random_gen,
+ NULL);
+ if (r != 0) {
+ mbedtls_ecdh_free(&ctx);
+ return SW_EXEC_ERROR();
+ }
+ res_APDU_size = olen;
+ mbedtls_ecdh_free(&ctx);
+ }
+ }
+ return SW_OK();
+}
diff --git a/src/openpgp/cmd_put_data.c b/src/openpgp/cmd_put_data.c
new file mode 100644
index 0000000..1e39ca6
--- /dev/null
+++ b/src/openpgp/cmd_put_data.c
@@ -0,0 +1,74 @@
+/*
+ * This file is part of the Pico OpenPGP distribution (https://github.com/polhenarejos/pico-openpgp).
+ * Copyright (c) 2022 Pol Henarejos.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#include "openpgp.h"
+
+int cmd_put_data() {
+ uint16_t fid = (P1(apdu) << 8) | P2(apdu);
+ file_t *ef;
+ if (fid == EF_RESET_CODE) {
+ fid = EF_RC;
+ }
+ else if (fid == EF_ALGO_SIG || fid == EF_ALGO_DEC || fid == EF_ALGO_AUT) {
+ fid |= 0x1000;
+ }
+ 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 (fid == EF_PW_STATUS) {
+ fid = EF_PW_PRIV;
+ apdu.nc = 4; //we silently ommit the reset parameters
+ }
+ if (currentEF && (currentEF->fid & 0x1FF0) == (fid & 0x1FF0)) { //previously selected
+ ef = currentEF;
+ }
+ if (apdu.nc > 0 && (ef->type & FILE_DATA_FLASH)) {
+ int r = 0;
+ if (fid == EF_RC) {
+ has_rc = false;
+ if ((r = load_dek()) != PICOKEY_OK) {
+ return SW_EXEC_ERROR();
+ }
+ uint8_t dhash[33];
+ dhash[0] = apdu.nc;
+ double_hash_pin(apdu.data, apdu.nc, dhash + 1);
+ r = file_put_data(ef, 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];
+ memcpy(def, file_get_data(tf), file_get_size(tf));
+ hash_multi(apdu.data, apdu.nc, session_rc);
+ memcpy(def + IV_SIZE + 32, dek + IV_SIZE, 32);
+ aes_encrypt_cfb_256(session_rc, def, def + IV_SIZE + 32, 32);
+ r = file_put_data(tf, def, sizeof(def));
+ }
+ else {
+ r = file_put_data(ef, apdu.data, apdu.nc);
+ }
+ if (r != PICOKEY_OK) {
+ return SW_MEMORY_FAILURE();
+ }
+ low_flash_available();
+ }
+ return SW_OK();
+}
diff --git a/src/openpgp/cmd_reset_retry.c b/src/openpgp/cmd_reset_retry.c
new file mode 100644
index 0000000..0df7f45
--- /dev/null
+++ b/src/openpgp/cmd_reset_retry.c
@@ -0,0 +1,80 @@
+/*
+ * This file is part of the Pico OpenPGP distribution (https://github.com/polhenarejos/pico-openpgp).
+ * Copyright (c) 2022 Pol Henarejos.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#include "openpgp.h"
+
+int cmd_reset_retry() {
+ if (P2(apdu) != 0x81) {
+ return SW_REFERENCE_NOT_FOUND();
+ }
+ if (P1(apdu) == 0x0 || P1(apdu) == 0x2) {
+ int newpin_len = 0;
+ file_t *pw = NULL;
+ has_pw1 = false;
+ if (!(pw = search_by_fid(EF_PW1, NULL, SPECIFY_EF))) {
+ return SW_REFERENCE_NOT_FOUND();
+ }
+ if (P1(apdu) == 0x0) {
+ file_t *rc;
+ if (!(rc = search_by_fid(EF_RC, NULL, SPECIFY_EF))) {
+ return SW_REFERENCE_NOT_FOUND();
+ }
+ uint8_t pin_len = file_get_data(rc)[0];
+ if (apdu.nc <= pin_len) {
+ return SW_WRONG_LENGTH();
+ }
+ uint16_t r = check_pin(rc, apdu.data, pin_len);
+ if (r != 0x9000) {
+ return r;
+ }
+ newpin_len = apdu.nc - pin_len;
+ has_rc = true;
+ hash_multi(apdu.data, pin_len, session_rc);
+ }
+ else if (P1(apdu) == 0x2) {
+ if (!has_pw3) {
+ return SW_CONDITIONS_NOT_SATISFIED();
+ }
+ newpin_len = apdu.nc;
+ }
+ int r = 0;
+ if ((r = load_dek()) != PICOKEY_OK) {
+ return SW_EXEC_ERROR();
+ }
+ 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];
+ 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));
+
+ uint8_t dhash[33];
+ dhash[0] = newpin_len;
+ double_hash_pin(apdu.data + (apdu.nc - newpin_len), newpin_len, dhash + 1);
+ file_put_data(pw, dhash, sizeof(dhash));
+ if (pin_reset_retries(pw, true) != PICOKEY_OK) {
+ return SW_MEMORY_FAILURE();
+ }
+ low_flash_available();
+ return SW_OK();
+ }
+ return SW_INCORRECT_P1P2();
+}
diff --git a/src/openpgp/cmd_select.c b/src/openpgp/cmd_select.c
new file mode 100644
index 0000000..95f94cf
--- /dev/null
+++ b/src/openpgp/cmd_select.c
@@ -0,0 +1,86 @@
+/*
+ * This file is part of the Pico OpenPGP distribution (https://github.com/polhenarejos/pico-openpgp).
+ * Copyright (c) 2022 Pol Henarejos.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#include "openpgp.h"
+
+int cmd_select() {
+ uint8_t p1 = P1(apdu);
+ uint8_t p2 = P2(apdu);
+ file_t *pe = NULL;
+ uint16_t fid = 0x0;
+
+ if (apdu.nc >= 2) {
+ fid = get_uint16_t_be(apdu.data);
+ }
+
+ if (!pe) {
+ if (p1 == 0x0) { //Select MF, DF or EF - File identifier or absent
+ if (apdu.nc == 0) {
+ pe = (file_t *) MF;
+ //ac_fini();
+ }
+ else if (apdu.nc == 2) {
+ if (!(pe = search_by_fid(fid, NULL, SPECIFY_ANY))) {
+ return SW_REFERENCE_NOT_FOUND();
+ }
+ }
+ }
+ else if (p1 == 0x01) { //Select child DF - DF identifier
+ if (!(pe = search_by_fid(fid, currentDF, SPECIFY_DF))) {
+ return SW_REFERENCE_NOT_FOUND();
+ }
+ }
+ else if (p1 == 0x02) { //Select EF under the current DF - EF identifier
+ if (!(pe = search_by_fid(fid, currentDF, SPECIFY_EF))) {
+ return SW_REFERENCE_NOT_FOUND();
+ }
+ }
+ else if (p1 == 0x03) { //Select parent DF of the current DF - Absent
+ if (apdu.nc != 0) {
+ return SW_REFERENCE_NOT_FOUND();
+ }
+ }
+ else if (p1 == 0x04) { //Select by DF name - e.g., [truncated] application identifier
+ if (!(pe = search_by_name(apdu.data, apdu.nc))) {
+ return SW_REFERENCE_NOT_FOUND();
+ }
+ if (card_terminated) {
+ return set_res_sw(0x62, 0x85);
+ }
+ }
+ else if (p1 == 0x08) { //Select from the MF - Path without the MF identifier
+ if (!(pe = search_by_path(apdu.data, apdu.nc, MF))) {
+ return SW_REFERENCE_NOT_FOUND();
+ }
+ }
+ 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))) {
+ return SW_REFERENCE_NOT_FOUND();
+ }
+ }
+ }
+ if ((p2 & 0xfc) == 0x00 || (p2 & 0xfc) == 0x04) {
+ if ((p2 & 0xfc) == 0x04) {
+ process_fci(pe, 0);
+ }
+ }
+ else {
+ return SW_INCORRECT_P1P2();
+ }
+ select_file(pe);
+ return SW_OK();
+}
diff --git a/src/openpgp/cmd_select_data.c b/src/openpgp/cmd_select_data.c
new file mode 100644
index 0000000..c99d3b2
--- /dev/null
+++ b/src/openpgp/cmd_select_data.c
@@ -0,0 +1,54 @@
+/*
+ * This file is part of the Pico OpenPGP distribution (https://github.com/polhenarejos/pico-openpgp).
+ * Copyright (c) 2022 Pol Henarejos.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#include "openpgp.h"
+
+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();
+}
diff --git a/src/openpgp/cmd_terminate_df.c b/src/openpgp/cmd_terminate_df.c
new file mode 100644
index 0000000..b69071d
--- /dev/null
+++ b/src/openpgp/cmd_terminate_df.c
@@ -0,0 +1,37 @@
+/*
+ * This file is part of the Pico OpenPGP distribution (https://github.com/polhenarejos/pico-openpgp).
+ * Copyright (c) 2022 Pol Henarejos.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#include "openpgp.h"
+
+int cmd_terminate_df() {
+ if (P1(apdu) != 0x0 || P2(apdu) != 0x0) {
+ return SW_INCORRECT_P1P2();
+ }
+ file_t *retries;
+ if (!(retries = search_by_fid(EF_PW_PRIV, NULL, SPECIFY_EF))) {
+ return SW_REFERENCE_NOT_FOUND();
+ }
+ if (!has_pw3 && *(file_get_data(retries) + 6) > 0) {
+ return SW_SECURITY_STATUS_NOT_SATISFIED();
+ }
+ if (apdu.nc != 0) {
+ return SW_WRONG_LENGTH();
+ }
+ initialize_flash(true);
+ scan_files();
+ return SW_OK();
+}
diff --git a/src/openpgp/cmd_verify.c b/src/openpgp/cmd_verify.c
new file mode 100644
index 0000000..da12e51
--- /dev/null
+++ b/src/openpgp/cmd_verify.c
@@ -0,0 +1,67 @@
+/*
+ * This file is part of the Pico OpenPGP distribution (https://github.com/polhenarejos/pico-openpgp).
+ * Copyright (c) 2022 Pol Henarejos.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#include "openpgp.h"
+
+int cmd_verify() {
+ uint8_t p1 = P1(apdu);
+ uint8_t p2 = P2(apdu);
+
+ if (p1 == 0xFF) {
+ if (apdu.nc != 0) {
+ return SW_WRONG_DATA();
+ }
+ if (p2 == 0x81) {
+ has_pw1 = false;
+ }
+ else if (p2 == 0x82) {
+ has_pw2 = false;
+ }
+ else if (p2 == 0x83) {
+ has_pw3 = false;
+ }
+ return SW_OK();
+ }
+ else if (p1 != 0x0 || (p2 & 0x60) != 0x0) {
+ return SW_WRONG_P1P2();
+ }
+ uint16_t fid = 0x1000 | p2;
+ if (fid == EF_RC && apdu.nc > 0) {
+ fid = EF_PW1;
+ }
+ file_t *pw, *pw_status;
+ if (!(pw = search_by_fid(fid, NULL, SPECIFY_EF))) {
+ return SW_REFERENCE_NOT_FOUND();
+ }
+ if (!(pw_status = search_by_fid(EF_PW_PRIV, NULL, SPECIFY_EF))) {
+ return SW_REFERENCE_NOT_FOUND();
+ }
+ if (file_get_data(pw)[0] == 0) { //not initialized
+ return SW_REFERENCE_NOT_FOUND();
+ }
+ if (apdu.nc > 0) {
+ return check_pin(pw, apdu.data, apdu.nc);
+ }
+ uint8_t retries = *(file_get_data(pw_status) + 3 + (fid & 0xf));
+ if (retries == 0) {
+ return SW_PIN_BLOCKED();
+ }
+ if ((p2 == 0x81 && has_pw1) || (p2 == 0x82 && has_pw2) || (p2 == 0x83 && has_pw3)) {
+ return SW_OK();
+ }
+ return set_res_sw(0x63, 0xc0 | retries);
+}
diff --git a/src/openpgp/cmd_version.c b/src/openpgp/cmd_version.c
new file mode 100644
index 0000000..858914b
--- /dev/null
+++ b/src/openpgp/cmd_version.c
@@ -0,0 +1,26 @@
+/*
+ * This file is part of the Pico OpenPGP distribution (https://github.com/polhenarejos/pico-openpgp).
+ * Copyright (c) 2022 Pol Henarejos.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#include "openpgp.h"
+#include "version.h"
+
+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();
+}
\ No newline at end of file
diff --git a/src/openpgp/do.c b/src/openpgp/do.c
new file mode 100644
index 0000000..2aa4ebe
--- /dev/null
+++ b/src/openpgp/do.c
@@ -0,0 +1,395 @@
+/*
+ * This file is part of the Pico OpenPGP distribution (https://github.com/polhenarejos/pico-openpgp).
+ * Copyright (c) 2022 Pol Henarejos.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#include "openpgp.h"
+#include "asn1.h"
+
+int parse_do(uint16_t *fids, int mode) {
+ int len = 0;
+ file_t *ef;
+ for (int i = 0; i < fids[0]; i++) {
+ if ((ef = search_by_fid(fids[i + 1], NULL, SPECIFY_EF))) {
+ uint16_t data_len;
+ if ((ef->type & FILE_DATA_FUNC) == FILE_DATA_FUNC) {
+ data_len = ((int (*)(const file_t *, int))(ef->data))((const file_t *) ef, mode);
+ }
+ else {
+ if (ef->data) {
+ data_len = file_get_size(ef);
+ }
+ else {
+ data_len = 0;
+ }
+ if (mode == 1) {
+ if (fids[0] > 1 && res_APDU_size > 0) {
+ if (fids[i + 1] < 0x0100) {
+ res_APDU[res_APDU_size++] = fids[i + 1] & 0xff;
+ }
+ else {
+ res_APDU[res_APDU_size++] = fids[i + 1] >> 8;
+ res_APDU[res_APDU_size++] = fids[i + 1] & 0xff;
+ }
+ res_APDU_size += format_tlv_len(data_len, res_APDU + res_APDU_size);
+ }
+ if (ef->data) {
+ memcpy(res_APDU + res_APDU_size, file_get_data(ef), data_len);
+ }
+ res_APDU_size += data_len;
+ }
+ }
+ len += data_len;
+ }
+ }
+ return len;
+}
+
+int parse_trium(uint16_t fid, uint8_t num, size_t size) {
+ for (uint8_t i = 0; i < num; i++) {
+ file_t *ef;
+ if ((ef = search_by_fid(fid + i, NULL, SPECIFY_EF)) && ef->data) {
+ uint16_t data_len = file_get_size(ef);
+ memcpy(res_APDU + res_APDU_size, file_get_data(ef), data_len);
+ res_APDU_size += data_len;
+ }
+ else {
+ memset(res_APDU + res_APDU_size, 0, size);
+ res_APDU_size += size;
+ }
+ }
+ return num * size;
+}
+
+int parse_ch_data(const file_t *f, int mode) {
+ uint16_t fids[] = {
+ 3,
+ EF_CH_NAME, EF_LANG_PREF, EF_SEX,
+ };
+ res_APDU[res_APDU_size++] = EF_CH_DATA & 0xff;
+ res_APDU[res_APDU_size++] = 0x82;
+ uint8_t *lp = res_APDU + res_APDU_size;
+ res_APDU_size += 2;
+ parse_do(fids, mode);
+ uint16_t lpdif = res_APDU + res_APDU_size - lp - 2;
+ *lp++ = lpdif >> 8;
+ *lp++ = lpdif & 0xff;
+ return lpdif + 4;
+}
+
+int parse_sec_tpl(const file_t *f, int mode) {
+ res_APDU[res_APDU_size++] = EF_SEC_TPL & 0xff;
+ res_APDU[res_APDU_size++] = 5;
+ file_t *ef = search_by_fid(EF_SIG_COUNT, NULL, SPECIFY_ANY);
+ if (ef && ef->data) {
+ res_APDU[res_APDU_size++] = EF_SIG_COUNT & 0xff;
+ res_APDU[res_APDU_size++] = 3;
+ memcpy(res_APDU + res_APDU_size, file_get_data(ef), 3);
+ res_APDU_size += 3;
+ }
+ return 5 + 2;
+}
+
+int parse_ch_cert(const file_t *f, int mode) {
+ return 0;
+}
+
+int parse_fp(const file_t *f, int mode) {
+ res_APDU[res_APDU_size++] = EF_FP & 0xff;
+ res_APDU[res_APDU_size++] = 60;
+ return parse_trium(EF_FP_SIG, 3, 20) + 2;
+}
+
+int parse_cafp(const file_t *f, int mode) {
+ res_APDU[res_APDU_size++] = EF_CA_FP & 0xff;
+ res_APDU[res_APDU_size++] = 60;
+ return parse_trium(EF_FP_CA1, 3, 20) + 2;
+}
+
+int parse_ts(const file_t *f, int mode) {
+ res_APDU[res_APDU_size++] = EF_TS_ALL & 0xff;
+ res_APDU[res_APDU_size++] = 12;
+ return parse_trium(EF_TS_SIG, 3, 4) + 2;
+}
+
+int parse_keyinfo(const file_t *f, int mode) {
+ int init_len = res_APDU_size;
+ if (res_APDU_size > 0) {
+ res_APDU[res_APDU_size++] = EF_KEY_INFO & 0xff;
+ res_APDU[res_APDU_size++] = 6;
+ }
+ file_t *ef = search_by_fid(EF_PK_SIG, NULL, SPECIFY_ANY);
+ res_APDU[res_APDU_size++] = 0x00;
+ if (ef && ef->data) {
+ res_APDU[res_APDU_size++] = 0x01;
+ }
+ else {
+ res_APDU[res_APDU_size++] = 0x00;
+ }
+
+ ef = search_by_fid(EF_PK_DEC, NULL, SPECIFY_ANY);
+ res_APDU[res_APDU_size++] = 0x01;
+ if (ef && ef->data) {
+ res_APDU[res_APDU_size++] = 0x01;
+ }
+ else {
+ res_APDU[res_APDU_size++] = 0x00;
+ }
+
+ ef = search_by_fid(EF_PK_AUT, NULL, SPECIFY_ANY);
+ res_APDU[res_APDU_size++] = 0x02;
+ if (ef && ef->data) {
+ res_APDU[res_APDU_size++] = 0x01;
+ }
+ else {
+ res_APDU[res_APDU_size++] = 0x00;
+ }
+ return res_APDU_size - init_len;
+}
+
+int parse_pw_status(const file_t *f, int mode) {
+ file_t *ef;
+ int init_len = res_APDU_size;
+ if (res_APDU_size > 0) {
+ res_APDU[res_APDU_size++] = EF_PW_STATUS & 0xff;
+ res_APDU[res_APDU_size++] = 7;
+ }
+ ef = search_by_fid(EF_PW_PRIV, NULL, SPECIFY_ANY);
+ if (ef && ef->data) {
+ memcpy(res_APDU + res_APDU_size, file_get_data(ef), 7);
+ res_APDU_size += 7;
+ }
+ return res_APDU_size - init_len;
+}
+
+#define ALGO_RSA_1K 0
+#define ALGO_RSA_2k 1
+#define ALGO_RSA_3K 2
+#define ALGO_RSA_4K 3
+#define ALGO_X448 4
+#define ALGO_P256K1 5
+#define ALGO_P256R1 6
+#define ALGO_P384R1 7
+#define ALGO_P521R1 8
+#define ALGO_BP256R1 9
+#define ALGO_BP384R1 10
+#define ALGO_BP512R1 11
+#define ALGO_CV22519 12
+
+const uint8_t algorithm_attr_x448[] = {
+ 4,
+ ALGO_ECDH,
+ /* OID of X448 */
+ 0x2b, 0x65, 0x6f
+};
+
+const uint8_t algorithm_attr_rsa1k[] = {
+ 6,
+ ALGO_RSA,
+ 0x04, 0x00, /* Length modulus (in bit): 1024 */
+ 0x00, 0x20, /* Length exponent (in bit): 32 */
+ 0x00 /* 0: Acceptable format is: P and Q */
+};
+
+const uint8_t algorithm_attr_rsa2k[] = {
+ 6,
+ ALGO_RSA,
+ 0x08, 0x00, /* Length modulus (in bit): 2048 */
+ 0x00, 0x20, /* Length exponent (in bit): 32 */
+ 0x00 /* 0: Acceptable format is: P and Q */
+};
+
+const uint8_t algorithm_attr_rsa3k[] = {
+ 6,
+ ALGO_RSA,
+ 0x0C, 0x00, /* Length modulus (in bit): 3072 */
+ 0x00, 0x20, /* Length exponent (in bit): 32 */
+ 0x00 /* 0: Acceptable format is: P and Q */
+};
+
+const uint8_t algorithm_attr_rsa4k[] = {
+ 6,
+ ALGO_RSA,
+ 0x10, 0x00, /* Length modulus (in bit): 4096 */
+ 0x00, 0x20, /* Length exponent (in bit): 32 */
+ 0x00 /* 0: Acceptable format is: P and Q */
+};
+
+const uint8_t algorithm_attr_p256k1[] = {
+ 6,
+ ALGO_ECDSA,
+ 0x2b, 0x81, 0x04, 0x00, 0x0a
+};
+
+const uint8_t algorithm_attr_p256r1[] = {
+ 9,
+ ALGO_ECDSA,
+ 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07
+};
+
+const uint8_t algorithm_attr_p384r1[] = {
+ 6,
+ ALGO_ECDSA,
+ 0x2B, 0x81, 0x04, 0x00, 0x22
+};
+
+const uint8_t algorithm_attr_p521r1[] = {
+ 6,
+ ALGO_ECDSA,
+ 0x2B, 0x81, 0x04, 0x00, 0x23
+};
+
+const uint8_t algorithm_attr_bp256r1[] = {
+ 10,
+ ALGO_ECDSA,
+ 0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x07
+};
+
+const uint8_t algorithm_attr_bp384r1[] = {
+ 10,
+ ALGO_ECDSA,
+ 0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x0B
+};
+
+const uint8_t algorithm_attr_bp512r1[] = {
+ 10,
+ ALGO_ECDSA,
+ 0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x0D
+};
+
+const uint8_t algorithm_attr_cv25519[] = {
+ 11,
+ ALGO_ECDH,
+ 0x2b, 0x06, 0x01, 0x04, 0x01, 0x97, 0x55, 0x01, 0x05, 0x01
+};
+
+const uint8_t algorithm_attr_ed25519[] = {
+ 10,
+ ALGO_EDDSA,
+ 0x2b, 0x06, 0x01, 0x04, 0x01, 0xda, 0x47, 0x0f, 0x01
+ };
+
+
+int parse_algo(const uint8_t *algo, uint16_t tag) {
+ res_APDU[res_APDU_size++] = tag & 0xff;
+ memcpy(res_APDU + res_APDU_size, algo, algo[0] + 1);
+ res_APDU_size += algo[0] + 1;
+ return algo[0] + 2;
+}
+
+int parse_algoinfo(const file_t *f, int mode) {
+ int datalen = 0;
+ if (f->fid == EF_ALGO_INFO) {
+ res_APDU[res_APDU_size++] = EF_ALGO_INFO & 0xff;
+ res_APDU[res_APDU_size++] = 0x82;
+ uint8_t *lp = res_APDU + res_APDU_size;
+ res_APDU_size += 2;
+ datalen += parse_algo(algorithm_attr_rsa1k, EF_ALGO_SIG);
+ datalen += parse_algo(algorithm_attr_rsa2k, EF_ALGO_SIG);
+ datalen += parse_algo(algorithm_attr_rsa3k, EF_ALGO_SIG);
+ datalen += parse_algo(algorithm_attr_rsa4k, EF_ALGO_SIG);
+ datalen += parse_algo(algorithm_attr_p256k1, EF_ALGO_SIG);
+ datalen += parse_algo(algorithm_attr_p256r1, EF_ALGO_SIG);
+ datalen += parse_algo(algorithm_attr_p384r1, EF_ALGO_SIG);
+ datalen += parse_algo(algorithm_attr_p521r1, EF_ALGO_SIG);
+ datalen += parse_algo(algorithm_attr_bp256r1, EF_ALGO_SIG);
+ datalen += parse_algo(algorithm_attr_bp384r1, EF_ALGO_SIG);
+ datalen += parse_algo(algorithm_attr_bp512r1, EF_ALGO_SIG);
+ datalen += parse_algo(algorithm_attr_ed25519, EF_ALGO_SIG);
+
+ datalen += parse_algo(algorithm_attr_rsa1k, EF_ALGO_DEC);
+ datalen += parse_algo(algorithm_attr_rsa2k, EF_ALGO_DEC);
+ datalen += parse_algo(algorithm_attr_rsa3k, EF_ALGO_DEC);
+ datalen += parse_algo(algorithm_attr_rsa4k, EF_ALGO_DEC);
+ datalen += parse_algo(algorithm_attr_p256k1, EF_ALGO_DEC);
+ datalen += parse_algo(algorithm_attr_p256r1, EF_ALGO_DEC);
+ datalen += parse_algo(algorithm_attr_p384r1, EF_ALGO_DEC);
+ datalen += parse_algo(algorithm_attr_p521r1, EF_ALGO_DEC);
+ datalen += parse_algo(algorithm_attr_bp256r1, EF_ALGO_DEC);
+ datalen += parse_algo(algorithm_attr_bp384r1, EF_ALGO_DEC);
+ datalen += parse_algo(algorithm_attr_bp512r1, EF_ALGO_DEC);
+ datalen += parse_algo(algorithm_attr_cv25519, EF_ALGO_DEC);
+ datalen += parse_algo(algorithm_attr_x448, EF_ALGO_DEC);
+
+ datalen += parse_algo(algorithm_attr_rsa1k, EF_ALGO_AUT);
+ datalen += parse_algo(algorithm_attr_rsa2k, EF_ALGO_AUT);
+ datalen += parse_algo(algorithm_attr_rsa3k, EF_ALGO_AUT);
+ datalen += parse_algo(algorithm_attr_rsa4k, EF_ALGO_AUT);
+ datalen += parse_algo(algorithm_attr_p256k1, EF_ALGO_AUT);
+ datalen += parse_algo(algorithm_attr_p256r1, EF_ALGO_AUT);
+ datalen += parse_algo(algorithm_attr_p384r1, EF_ALGO_AUT);
+ datalen += parse_algo(algorithm_attr_p521r1, EF_ALGO_AUT);
+ datalen += parse_algo(algorithm_attr_bp256r1, EF_ALGO_AUT);
+ datalen += parse_algo(algorithm_attr_bp384r1, EF_ALGO_AUT);
+ datalen += parse_algo(algorithm_attr_bp512r1, EF_ALGO_AUT);
+ datalen += parse_algo(algorithm_attr_ed25519, EF_ALGO_AUT);
+ uint16_t lpdif = res_APDU + res_APDU_size - lp - 2;
+ *lp++ = lpdif >> 8;
+ *lp++ = lpdif & 0xff;
+ datalen = lpdif + 4;
+ }
+ else if (f->fid == EF_ALGO_SIG || f->fid == EF_ALGO_DEC || f->fid == EF_ALGO_AUT) {
+ uint16_t fid = 0x1000 | f->fid;
+ file_t *ef;
+ if (!(ef = search_by_fid(fid, NULL, SPECIFY_EF)) || !ef->data) {
+ datalen += parse_algo(algorithm_attr_rsa2k, f->fid);
+ }
+ else {
+ uint16_t len = file_get_size(ef);
+ if (res_APDU_size > 0) {
+ res_APDU[res_APDU_size++] = f->fid & 0xff;
+ res_APDU[res_APDU_size++] = len & 0xff;
+ datalen += 2;
+ }
+ memcpy(res_APDU + res_APDU_size, file_get_data(ef), len);
+ res_APDU_size += len;
+ datalen += len;
+ }
+ }
+ return datalen;
+}
+
+int parse_app_data(const file_t *f, int mode) {
+ uint16_t fids[] = {
+ 6,
+ EF_FULL_AID, EF_HIST_BYTES, EF_EXLEN_INFO, EF_GFM, EF_DISCRETE_DO, EF_KEY_INFO
+ };
+ res_APDU[res_APDU_size++] = EF_APP_DATA & 0xff;
+ res_APDU[res_APDU_size++] = 0x82;
+ uint8_t *lp = res_APDU + res_APDU_size;
+ res_APDU_size += 2;
+ parse_do(fids, mode);
+ uint16_t lpdif = res_APDU + res_APDU_size - lp - 2;
+ *lp++ = lpdif >> 8;
+ *lp++ = lpdif & 0xff;
+ return lpdif + 4;
+}
+
+int parse_discrete_do(const file_t *f, int mode) {
+ uint16_t fids[] = {
+ 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_UIF_SIG, EF_UIF_DEC, EF_UIF_AUT
+ };
+ res_APDU[res_APDU_size++] = EF_DISCRETE_DO & 0xff;
+ res_APDU[res_APDU_size++] = 0x82;
+ uint8_t *lp = res_APDU + res_APDU_size;
+ res_APDU_size += 2;
+ parse_do(fids, mode);
+ uint16_t lpdif = res_APDU + res_APDU_size - lp - 2;
+ *lp++ = lpdif >> 8;
+ *lp++ = lpdif & 0xff;
+ return lpdif + 4;
+}
diff --git a/src/openpgp/do.h b/src/openpgp/do.h
new file mode 100644
index 0000000..ea81c2d
--- /dev/null
+++ b/src/openpgp/do.h
@@ -0,0 +1,29 @@
+/*
+ * This file is part of the Pico OpenPGP distribution (https://github.com/polhenarejos/pico-openpgp).
+ * Copyright (c) 2022 Pol Henarejos.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+extern const uint8_t algorithm_attr_p256k1[];
+extern const uint8_t algorithm_attr_p256r1[];
+extern const uint8_t algorithm_attr_p384r1[];
+extern const uint8_t algorithm_attr_p521r1[];
+extern const uint8_t algorithm_attr_bp256r1[];
+extern const uint8_t algorithm_attr_bp384r1[];
+extern const uint8_t algorithm_attr_bp512r1[];
+extern const uint8_t algorithm_attr_cv25519[];
+extern const uint8_t algorithm_attr_ed25519[];
+extern const uint8_t algorithm_attr_x448[];
+extern const uint8_t algorithm_attr_rsa2k[];
+extern const uint8_t algorithm_attr_rsa4096[];
diff --git a/src/openpgp/openpgp.c b/src/openpgp/openpgp.c
index ec44493..f310c01 100644
--- a/src/openpgp/openpgp.c
+++ b/src/openpgp/openpgp.c
@@ -23,17 +23,14 @@
#endif
#include "openpgp.h"
#include "version.h"
-#include "files.h"
#include "random.h"
#include "eac.h"
-#include "crypto_utils.h"
-#include "mbedtls/ecdh.h"
#include "mbedtls/asn1.h"
-#include "asn1.h"
+#include "mbedtls/eddsa.h"
#include "usb.h"
#include "ccid/ccid.h"
#include "otp.h"
-#include "mbedtls/eddsa.h"
+#include "do.h"
uint8_t PICO_PRODUCT = 3;
@@ -44,9 +41,8 @@ bool has_rc = false;
uint8_t session_pw1[32];
uint8_t session_rc[32];
uint8_t session_pw3[32];
-static uint8_t dek[IV_SIZE + 32];
-static uint16_t algo_dec = EF_ALGO_PRIV2, algo_aut = EF_ALGO_PRIV3, pk_dec = EF_PK_DEC,
- pk_aut = EF_PK_AUT;
+uint8_t dek[IV_SIZE + 32];
+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[] = {
6,
@@ -69,7 +65,7 @@ int openpgp_process_apdu();
extern uint32_t board_button_read(void);
-static bool wait_button_pressed(uint16_t fid) {
+bool wait_button_pressed(uint16_t fid) {
uint32_t val = EV_PRESS_BUTTON;
#ifndef ENABLE_EMULATION
file_t *ef = search_by_fid(fid, NULL, SPECIFY_ANY);
@@ -101,74 +97,6 @@ void select_file(file_t *pe) {
}
}
-static int cmd_select() {
- uint8_t p1 = P1(apdu);
- uint8_t p2 = P2(apdu);
- file_t *pe = NULL;
- uint16_t fid = 0x0;
-
- if (apdu.nc >= 2) {
- fid = get_uint16_t(apdu.data, 0);
- }
-
- if (!pe) {
- if (p1 == 0x0) { //Select MF, DF or EF - File identifier or absent
- if (apdu.nc == 0) {
- pe = (file_t *) MF;
- //ac_fini();
- }
- else if (apdu.nc == 2) {
- if (!(pe = search_by_fid(fid, NULL, SPECIFY_ANY))) {
- return SW_REFERENCE_NOT_FOUND();
- }
- }
- }
- else if (p1 == 0x01) { //Select child DF - DF identifier
- if (!(pe = search_by_fid(fid, currentDF, SPECIFY_DF))) {
- return SW_REFERENCE_NOT_FOUND();
- }
- }
- else if (p1 == 0x02) { //Select EF under the current DF - EF identifier
- if (!(pe = search_by_fid(fid, currentDF, SPECIFY_EF))) {
- return SW_REFERENCE_NOT_FOUND();
- }
- }
- else if (p1 == 0x03) { //Select parent DF of the current DF - Absent
- if (apdu.nc != 0) {
- return SW_REFERENCE_NOT_FOUND();
- }
- }
- else if (p1 == 0x04) { //Select by DF name - e.g., [truncated] application identifier
- if (!(pe = search_by_name(apdu.data, apdu.nc))) {
- return SW_REFERENCE_NOT_FOUND();
- }
- if (card_terminated) {
- return set_res_sw(0x62, 0x85);
- }
- }
- else if (p1 == 0x08) { //Select from the MF - Path without the MF identifier
- if (!(pe = search_by_path(apdu.data, apdu.nc, MF))) {
- return SW_REFERENCE_NOT_FOUND();
- }
- }
- 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))) {
- return SW_REFERENCE_NOT_FOUND();
- }
- }
- }
- if ((p2 & 0xfc) == 0x00 || (p2 & 0xfc) == 0x04) {
- if ((p2 & 0xfc) == 0x04) {
- process_fci(pe, 0);
- }
- }
- else {
- return SW_INCORRECT_P1P2();
- }
- select_file(pe);
- return SW_OK();
-}
-
void scan_files() {
scan_flash();
file_t *ef;
@@ -407,465 +335,6 @@ INITIALIZER( openpgp_ctor ) {
register_app(openpgp_select_aid, openpgp_aid);
}
-int parse_do(uint16_t *fids, int mode) {
- int len = 0;
- file_t *ef;
- for (int i = 0; i < fids[0]; i++) {
- if ((ef = search_by_fid(fids[i + 1], NULL, SPECIFY_EF))) {
- uint16_t data_len;
- if ((ef->type & FILE_DATA_FUNC) == FILE_DATA_FUNC) {
- data_len = ((int (*)(const file_t *, int))(ef->data))((const file_t *) ef, mode);
- }
- else {
- if (ef->data) {
- data_len = file_get_size(ef);
- }
- else {
- data_len = 0;
- }
- if (mode == 1) {
- if (fids[0] > 1 && res_APDU_size > 0) {
- if (fids[i + 1] < 0x0100) {
- res_APDU[res_APDU_size++] = fids[i + 1] & 0xff;
- }
- else {
- res_APDU[res_APDU_size++] = fids[i + 1] >> 8;
- res_APDU[res_APDU_size++] = fids[i + 1] & 0xff;
- }
- res_APDU_size += format_tlv_len(data_len, res_APDU + res_APDU_size);
- }
- if (ef->data) {
- memcpy(res_APDU + res_APDU_size, file_get_data(ef), data_len);
- }
- res_APDU_size += data_len;
- }
- }
- len += data_len;
- }
- }
- return len;
-}
-
-int parse_trium(uint16_t fid, uint8_t num, size_t size) {
- for (uint8_t i = 0; i < num; i++) {
- file_t *ef;
- if ((ef = search_by_fid(fid + i, NULL, SPECIFY_EF)) && ef->data) {
- uint16_t data_len = file_get_size(ef);
- memcpy(res_APDU + res_APDU_size, file_get_data(ef), data_len);
- res_APDU_size += data_len;
- }
- else {
- memset(res_APDU + res_APDU_size, 0, size);
- res_APDU_size += size;
- }
- }
- return num * size;
-}
-
-int parse_ch_data(const file_t *f, int mode) {
- uint16_t fids[] = {
- 3,
- EF_CH_NAME, EF_LANG_PREF, EF_SEX,
- };
- res_APDU[res_APDU_size++] = EF_CH_DATA & 0xff;
- res_APDU[res_APDU_size++] = 0x82;
- uint8_t *lp = res_APDU + res_APDU_size;
- res_APDU_size += 2;
- parse_do(fids, mode);
- uint16_t lpdif = res_APDU + res_APDU_size - lp - 2;
- *lp++ = lpdif >> 8;
- *lp++ = lpdif & 0xff;
- return lpdif + 4;
-}
-
-int inc_sig_count() {
- file_t *pw_status;
- if (!(pw_status = search_by_fid(EF_PW_PRIV, NULL, SPECIFY_EF)) || !pw_status->data) {
- return SW_REFERENCE_NOT_FOUND();
- }
- if (file_get_data(pw_status)[0] == 0) {
- has_pw1 = false;
- }
- file_t *ef = search_by_fid(EF_SIG_COUNT, NULL, SPECIFY_ANY);
- if (!ef || !ef->data) {
- return PICOKEY_ERR_FILE_NOT_FOUND;
- }
- uint8_t *p = file_get_data(ef);
- uint32_t counter = (p[0] << 16) | (p[1] << 8) | p[2];
- counter++;
- uint8_t q[3] = { (counter >> 16) & 0xff, (counter >> 8) & 0xff, counter & 0xff };
- int r = file_put_data(ef, q, sizeof(q));
- if (r != PICOKEY_OK) {
- return PICOKEY_EXEC_ERROR;
- }
- low_flash_available();
- return PICOKEY_OK;
-}
-
-int reset_sig_count() {
- file_t *ef = search_by_fid(EF_SIG_COUNT, NULL, SPECIFY_ANY);
- if (!ef || !ef->data) {
- return PICOKEY_ERR_FILE_NOT_FOUND;
- }
- uint8_t q[3] = { 0 };
- int r = file_put_data(ef, q, sizeof(q));
- if (r != PICOKEY_OK) {
- return PICOKEY_EXEC_ERROR;
- }
- low_flash_available();
- return PICOKEY_OK;
-}
-
-int parse_sec_tpl(const file_t *f, int mode) {
- res_APDU[res_APDU_size++] = EF_SEC_TPL & 0xff;
- res_APDU[res_APDU_size++] = 5;
- file_t *ef = search_by_fid(EF_SIG_COUNT, NULL, SPECIFY_ANY);
- if (ef && ef->data) {
- res_APDU[res_APDU_size++] = EF_SIG_COUNT & 0xff;
- res_APDU[res_APDU_size++] = 3;
- memcpy(res_APDU + res_APDU_size, file_get_data(ef), 3);
- res_APDU_size += 3;
- }
- return 5 + 2;
-}
-
-int parse_ch_cert(const file_t *f, int mode) {
- return 0;
-}
-
-int parse_fp(const file_t *f, int mode) {
- res_APDU[res_APDU_size++] = EF_FP & 0xff;
- res_APDU[res_APDU_size++] = 60;
- return parse_trium(EF_FP_SIG, 3, 20) + 2;
-}
-
-int parse_cafp(const file_t *f, int mode) {
- res_APDU[res_APDU_size++] = EF_CA_FP & 0xff;
- res_APDU[res_APDU_size++] = 60;
- return parse_trium(EF_FP_CA1, 3, 20) + 2;
-}
-
-int parse_ts(const file_t *f, int mode) {
- res_APDU[res_APDU_size++] = EF_TS_ALL & 0xff;
- res_APDU[res_APDU_size++] = 12;
- return parse_trium(EF_TS_SIG, 3, 4) + 2;
-}
-
-int parse_keyinfo(const file_t *f, int mode) {
- int init_len = res_APDU_size;
- if (res_APDU_size > 0) {
- res_APDU[res_APDU_size++] = EF_KEY_INFO & 0xff;
- res_APDU[res_APDU_size++] = 6;
- }
- file_t *ef = search_by_fid(EF_PK_SIG, NULL, SPECIFY_ANY);
- res_APDU[res_APDU_size++] = 0x00;
- if (ef && ef->data) {
- res_APDU[res_APDU_size++] = 0x01;
- }
- else {
- res_APDU[res_APDU_size++] = 0x00;
- }
-
- ef = search_by_fid(EF_PK_DEC, NULL, SPECIFY_ANY);
- res_APDU[res_APDU_size++] = 0x01;
- if (ef && ef->data) {
- res_APDU[res_APDU_size++] = 0x01;
- }
- else {
- res_APDU[res_APDU_size++] = 0x00;
- }
-
- ef = search_by_fid(EF_PK_AUT, NULL, SPECIFY_ANY);
- res_APDU[res_APDU_size++] = 0x02;
- if (ef && ef->data) {
- res_APDU[res_APDU_size++] = 0x01;
- }
- else {
- res_APDU[res_APDU_size++] = 0x00;
- }
- return res_APDU_size - init_len;
-}
-
-int parse_pw_status(const file_t *f, int mode) {
- file_t *ef;
- int init_len = res_APDU_size;
- if (res_APDU_size > 0) {
- res_APDU[res_APDU_size++] = EF_PW_STATUS & 0xff;
- res_APDU[res_APDU_size++] = 7;
- }
- ef = search_by_fid(EF_PW_PRIV, NULL, SPECIFY_ANY);
- if (ef && ef->data) {
- memcpy(res_APDU + res_APDU_size, file_get_data(ef), 7);
- res_APDU_size += 7;
- }
- return res_APDU_size - init_len;
-}
-
-#define ALGO_RSA_1K 0
-#define ALGO_RSA_2k 1
-#define ALGO_RSA_3K 2
-#define ALGO_RSA_4K 3
-#define ALGO_X448 4
-#define ALGO_P256K1 5
-#define ALGO_P256R1 6
-#define ALGO_P384R1 7
-#define ALGO_P521R1 8
-#define ALGO_BP256R1 9
-#define ALGO_BP384R1 10
-#define ALGO_BP512R1 11
-#define ALGO_CV22519 12
-
-static const uint8_t algorithm_attr_x448[] = {
- 4,
- ALGO_ECDH,
- /* OID of X448 */
- 0x2b, 0x65, 0x6f
-};
-
-static const uint8_t algorithm_attr_rsa1k[] = {
- 6,
- ALGO_RSA,
- 0x04, 0x00, /* Length modulus (in bit): 1024 */
- 0x00, 0x20, /* Length exponent (in bit): 32 */
- 0x00 /* 0: Acceptable format is: P and Q */
-};
-
-static const uint8_t algorithm_attr_rsa2k[] = {
- 6,
- ALGO_RSA,
- 0x08, 0x00, /* Length modulus (in bit): 2048 */
- 0x00, 0x20, /* Length exponent (in bit): 32 */
- 0x00 /* 0: Acceptable format is: P and Q */
-};
-
-static const uint8_t algorithm_attr_rsa3k[] = {
- 6,
- ALGO_RSA,
- 0x0C, 0x00, /* Length modulus (in bit): 3072 */
- 0x00, 0x20, /* Length exponent (in bit): 32 */
- 0x00 /* 0: Acceptable format is: P and Q */
-};
-
-static const uint8_t algorithm_attr_rsa4k[] = {
- 6,
- ALGO_RSA,
- 0x10, 0x00, /* Length modulus (in bit): 4096 */
- 0x00, 0x20, /* Length exponent (in bit): 32 */
- 0x00 /* 0: Acceptable format is: P and Q */
-};
-
-static const uint8_t algorithm_attr_p256k1[] = {
- 6,
- ALGO_ECDSA,
- 0x2b, 0x81, 0x04, 0x00, 0x0a
-};
-
-static const uint8_t algorithm_attr_p256r1[] = {
- 9,
- ALGO_ECDSA,
- 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07
-};
-
-static const uint8_t algorithm_attr_p384r1[] = {
- 6,
- ALGO_ECDSA,
- 0x2B, 0x81, 0x04, 0x00, 0x22
-};
-
-static const uint8_t algorithm_attr_p521r1[] = {
- 6,
- ALGO_ECDSA,
- 0x2B, 0x81, 0x04, 0x00, 0x23
-};
-
-static const uint8_t algorithm_attr_bp256r1[] = {
- 10,
- ALGO_ECDSA,
- 0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x07
-};
-
-static const uint8_t algorithm_attr_bp384r1[] = {
- 10,
- ALGO_ECDSA,
- 0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x0B
-};
-
-static const uint8_t algorithm_attr_bp512r1[] = {
- 10,
- ALGO_ECDSA,
- 0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x0D
-};
-
-static const uint8_t algorithm_attr_cv25519[] = {
- 11,
- ALGO_ECDH,
- 0x2b, 0x06, 0x01, 0x04, 0x01, 0x97, 0x55, 0x01, 0x05, 0x01
-};
-
-static const uint8_t algorithm_attr_ed25519[] = {
- 10,
- ALGO_EDDSA,
- 0x2b, 0x06, 0x01, 0x04, 0x01, 0xda, 0x47, 0x0f, 0x01
- };
-
-int parse_algo(const uint8_t *algo, uint16_t tag) {
- res_APDU[res_APDU_size++] = tag & 0xff;
- memcpy(res_APDU + res_APDU_size, algo, algo[0] + 1);
- res_APDU_size += algo[0] + 1;
- return algo[0] + 2;
-}
-
-int parse_algoinfo(const file_t *f, int mode) {
- int datalen = 0;
- if (f->fid == EF_ALGO_INFO) {
- res_APDU[res_APDU_size++] = EF_ALGO_INFO & 0xff;
- res_APDU[res_APDU_size++] = 0x82;
- uint8_t *lp = res_APDU + res_APDU_size;
- res_APDU_size += 2;
- datalen += parse_algo(algorithm_attr_rsa1k, EF_ALGO_SIG);
- datalen += parse_algo(algorithm_attr_rsa2k, EF_ALGO_SIG);
- datalen += parse_algo(algorithm_attr_rsa3k, EF_ALGO_SIG);
- datalen += parse_algo(algorithm_attr_rsa4k, EF_ALGO_SIG);
- datalen += parse_algo(algorithm_attr_p256k1, EF_ALGO_SIG);
- datalen += parse_algo(algorithm_attr_p256r1, EF_ALGO_SIG);
- datalen += parse_algo(algorithm_attr_p384r1, EF_ALGO_SIG);
- datalen += parse_algo(algorithm_attr_p521r1, EF_ALGO_SIG);
- datalen += parse_algo(algorithm_attr_bp256r1, EF_ALGO_SIG);
- datalen += parse_algo(algorithm_attr_bp384r1, EF_ALGO_SIG);
- datalen += parse_algo(algorithm_attr_bp512r1, EF_ALGO_SIG);
- datalen += parse_algo(algorithm_attr_ed25519, EF_ALGO_SIG);
-
- datalen += parse_algo(algorithm_attr_rsa1k, EF_ALGO_DEC);
- datalen += parse_algo(algorithm_attr_rsa2k, EF_ALGO_DEC);
- datalen += parse_algo(algorithm_attr_rsa3k, EF_ALGO_DEC);
- datalen += parse_algo(algorithm_attr_rsa4k, EF_ALGO_DEC);
- datalen += parse_algo(algorithm_attr_p256k1, EF_ALGO_DEC);
- datalen += parse_algo(algorithm_attr_p256r1, EF_ALGO_DEC);
- datalen += parse_algo(algorithm_attr_p384r1, EF_ALGO_DEC);
- datalen += parse_algo(algorithm_attr_p521r1, EF_ALGO_DEC);
- datalen += parse_algo(algorithm_attr_bp256r1, EF_ALGO_DEC);
- datalen += parse_algo(algorithm_attr_bp384r1, EF_ALGO_DEC);
- datalen += parse_algo(algorithm_attr_bp512r1, EF_ALGO_DEC);
- datalen += parse_algo(algorithm_attr_cv25519, EF_ALGO_DEC);
- datalen += parse_algo(algorithm_attr_x448, EF_ALGO_DEC);
-
- datalen += parse_algo(algorithm_attr_rsa1k, EF_ALGO_AUT);
- datalen += parse_algo(algorithm_attr_rsa2k, EF_ALGO_AUT);
- datalen += parse_algo(algorithm_attr_rsa3k, EF_ALGO_AUT);
- datalen += parse_algo(algorithm_attr_rsa4k, EF_ALGO_AUT);
- datalen += parse_algo(algorithm_attr_p256k1, EF_ALGO_AUT);
- datalen += parse_algo(algorithm_attr_p256r1, EF_ALGO_AUT);
- datalen += parse_algo(algorithm_attr_p384r1, EF_ALGO_AUT);
- datalen += parse_algo(algorithm_attr_p521r1, EF_ALGO_AUT);
- datalen += parse_algo(algorithm_attr_bp256r1, EF_ALGO_AUT);
- datalen += parse_algo(algorithm_attr_bp384r1, EF_ALGO_AUT);
- datalen += parse_algo(algorithm_attr_bp512r1, EF_ALGO_AUT);
- datalen += parse_algo(algorithm_attr_ed25519, EF_ALGO_AUT);
- uint16_t lpdif = res_APDU + res_APDU_size - lp - 2;
- *lp++ = lpdif >> 8;
- *lp++ = lpdif & 0xff;
- datalen = lpdif + 4;
- }
- else if (f->fid == EF_ALGO_SIG || f->fid == EF_ALGO_DEC || f->fid == EF_ALGO_AUT) {
- uint16_t fid = 0x1000 | f->fid;
- file_t *ef;
- if (!(ef = search_by_fid(fid, NULL, SPECIFY_EF)) || !ef->data) {
- datalen += parse_algo(algorithm_attr_rsa2k, f->fid);
- }
- else {
- uint16_t len = file_get_size(ef);
- if (res_APDU_size > 0) {
- res_APDU[res_APDU_size++] = f->fid & 0xff;
- res_APDU[res_APDU_size++] = len & 0xff;
- datalen += 2;
- }
- memcpy(res_APDU + res_APDU_size, file_get_data(ef), len);
- res_APDU_size += len;
- datalen += len;
- }
- }
- return datalen;
-}
-
-int parse_app_data(const file_t *f, int mode) {
- uint16_t fids[] = {
- 6,
- EF_FULL_AID, EF_HIST_BYTES, EF_EXLEN_INFO, EF_GFM, EF_DISCRETE_DO, EF_KEY_INFO
- };
- res_APDU[res_APDU_size++] = EF_APP_DATA & 0xff;
- res_APDU[res_APDU_size++] = 0x82;
- uint8_t *lp = res_APDU + res_APDU_size;
- res_APDU_size += 2;
- parse_do(fids, mode);
- uint16_t lpdif = res_APDU + res_APDU_size - lp - 2;
- *lp++ = lpdif >> 8;
- *lp++ = lpdif & 0xff;
- return lpdif + 4;
-}
-
-int parse_discrete_do(const file_t *f, int mode) {
- uint16_t fids[] = {
- 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_UIF_SIG, EF_UIF_DEC, EF_UIF_AUT
- };
- res_APDU[res_APDU_size++] = EF_DISCRETE_DO & 0xff;
- res_APDU[res_APDU_size++] = 0x82;
- uint8_t *lp = res_APDU + res_APDU_size;
- res_APDU_size += 2;
- parse_do(fids, mode);
- uint16_t lpdif = res_APDU + res_APDU_size - lp - 2;
- *lp++ = lpdif >> 8;
- *lp++ = lpdif & 0xff;
- return lpdif + 4;
-}
-
-static int cmd_get_data() {
- if (apdu.nc > 0) {
- return SW_WRONG_LENGTH();
- }
- uint16_t fid = (P1(apdu) << 8) | P2(apdu);
- file_t *ef;
- if (!(ef = search_by_fid(fid, NULL, SPECIFY_EF))) {
- return SW_REFERENCE_NOT_FOUND();
- }
- if (!authenticate_action(ef, ACL_OP_READ_SEARCH)) {
- return SW_SECURITY_STATUS_NOT_SATISFIED();
- }
- if (currentEF && (currentEF->fid & 0x1FF0) == (fid & 0x1FF0)) { //previously selected
- ef = currentEF;
- }
- else {
- select_file(ef);
- }
- if (ef->data) {
- uint16_t fids[] = { 1, fid };
- uint16_t data_len = parse_do(fids, 1);
- uint8_t *p = NULL;
- uint16_t tg = 0;
- uint16_t tg_len = 0;
- asn1_ctx_t ctxi;
- asn1_ctx_init(res_APDU, data_len, &ctxi);
- if (walk_tlv(&ctxi, &p, &tg, &tg_len, NULL)) {
- uint8_t dec = 2;
- if ((tg & 0x1f) == 0x1f) {
- dec++;
- }
- 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);
- data_len -= dec;
- res_APDU_size -= dec;
- }
- }
- //if (apdu.ne > data_len)
- // apdu.ne = data_len;
- }
- return SW_OK();
-}
-
int pin_reset_retries(const file_t *pin, bool force) {
if (!pin) {
return PICOKEY_ERR_NULL_PARAM;
@@ -963,220 +432,47 @@ int check_pin(const file_t *pin, const uint8_t *data, size_t len) {
return SW_OK();
}
-static int cmd_verify() {
- uint8_t p1 = P1(apdu);
- uint8_t p2 = P2(apdu);
-
- if (p1 == 0xFF) {
- if (apdu.nc != 0) {
- return SW_WRONG_DATA();
- }
- if (p2 == 0x81) {
- has_pw1 = false;
- }
- else if (p2 == 0x82) {
- has_pw2 = false;
- }
- else if (p2 == 0x83) {
- has_pw3 = false;
- }
- return SW_OK();
- }
- else if (p1 != 0x0 || (p2 & 0x60) != 0x0) {
- return SW_WRONG_P1P2();
- }
- uint16_t fid = 0x1000 | p2;
- if (fid == EF_RC && apdu.nc > 0) {
- fid = EF_PW1;
- }
- file_t *pw, *pw_status;
- if (!(pw = search_by_fid(fid, NULL, SPECIFY_EF))) {
+int inc_sig_count() {
+ file_t *pw_status;
+ if (!(pw_status = search_by_fid(EF_PW_PRIV, NULL, SPECIFY_EF)) || !pw_status->data) {
return SW_REFERENCE_NOT_FOUND();
}
- if (!(pw_status = search_by_fid(EF_PW_PRIV, NULL, SPECIFY_EF))) {
- return SW_REFERENCE_NOT_FOUND();
+ if (file_get_data(pw_status)[0] == 0) {
+ has_pw1 = false;
}
- if (file_get_data(pw)[0] == 0) { //not initialized
- return SW_REFERENCE_NOT_FOUND();
+ file_t *ef = search_by_fid(EF_SIG_COUNT, NULL, SPECIFY_ANY);
+ if (!ef || !ef->data) {
+ return PICOKEY_ERR_FILE_NOT_FOUND;
}
- if (apdu.nc > 0) {
- return check_pin(pw, apdu.data, apdu.nc);
- }
- uint8_t retries = *(file_get_data(pw_status) + 3 + (fid & 0xf));
- if (retries == 0) {
- return SW_PIN_BLOCKED();
- }
- if ((p2 == 0x81 && has_pw1) || (p2 == 0x82 && has_pw2) || (p2 == 0x83 && has_pw3)) {
- return SW_OK();
- }
- return set_res_sw(0x63, 0xc0 | retries);
-}
-
-static int cmd_put_data() {
- uint16_t fid = (P1(apdu) << 8) | P2(apdu);
- file_t *ef;
- if (fid == EF_RESET_CODE) {
- fid = EF_RC;
- }
- else if (fid == EF_ALGO_SIG || fid == EF_ALGO_DEC || fid == EF_ALGO_AUT) {
- fid |= 0x1000;
- }
- 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 (fid == EF_PW_STATUS) {
- fid = EF_PW_PRIV;
- apdu.nc = 4; //we silently ommit the reset parameters
- }
- if (currentEF && (currentEF->fid & 0x1FF0) == (fid & 0x1FF0)) { //previously selected
- ef = currentEF;
- }
- if (apdu.nc > 0 && (ef->type & FILE_DATA_FLASH)) {
- int r = 0;
- if (fid == EF_RC) {
- has_rc = false;
- if ((r = load_dek()) != PICOKEY_OK) {
- return SW_EXEC_ERROR();
- }
- uint8_t dhash[33];
- dhash[0] = apdu.nc;
- double_hash_pin(apdu.data, apdu.nc, dhash + 1);
- r = file_put_data(ef, 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];
- memcpy(def, file_get_data(tf), file_get_size(tf));
- hash_multi(apdu.data, apdu.nc, session_rc);
- memcpy(def + IV_SIZE + 32, dek + IV_SIZE, 32);
- aes_encrypt_cfb_256(session_rc, def, def + IV_SIZE + 32, 32);
- r = file_put_data(tf, def, sizeof(def));
- }
- else {
- r = file_put_data(ef, apdu.data, apdu.nc);
- }
- if (r != PICOKEY_OK) {
- return SW_MEMORY_FAILURE();
- }
- low_flash_available();
- }
- return SW_OK();
-}
-
-static int cmd_change_pin() {
- if (P1(apdu) != 0x0) {
- return SW_WRONG_P1P2();
- }
- uint16_t fid = 0x1000 | P2(apdu);
- file_t *pw;
- if (!(pw = search_by_fid(fid, NULL, SPECIFY_EF))) {
- return SW_REFERENCE_NOT_FOUND();
- }
- uint8_t pin_len = file_get_data(pw)[0];
- uint16_t r = 0;
- if ((r = load_dek()) != PICOKEY_OK) {
- return SW_EXEC_ERROR();
+ uint8_t *p = file_get_data(ef);
+ uint32_t counter = (p[0] << 16) | (p[1] << 8) | p[2];
+ counter++;
+ uint8_t q[3] = { (counter >> 16) & 0xff, (counter >> 8) & 0xff, counter & 0xff };
+ int r = file_put_data(ef, q, sizeof(q));
+ if (r != PICOKEY_OK) {
+ return PICOKEY_EXEC_ERROR;
}
+ low_flash_available();
+ return PICOKEY_OK;
if (otp_key_1) {
for (int i = 0; i < 32; i++) {
dek[IV_SIZE + i] ^= otp_key_1[i];
}
}
- r = check_pin(pw, apdu.data, pin_len);
- if (r != 0x9000) {
- return r;
- }
- uint8_t dhash[33];
- dhash[0] = apdu.nc - pin_len;
- double_hash_pin(apdu.data + pin_len, apdu.nc - pin_len, dhash + 1);
- 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) {
- hash_multi(apdu.data + pin_len, apdu.nc - pin_len, session_pw1);
- memcpy(def + IV_SIZE, dek + IV_SIZE, 32);
- aes_encrypt_cfb_256(session_pw1, def, def + IV_SIZE, 32);
- }
- else if (P2(apdu) == 0x83) {
- hash_multi(apdu.data + pin_len, apdu.nc - pin_len, session_pw3);
- memcpy(def + IV_SIZE + 32 + 32, dek + IV_SIZE, 32);
- aes_encrypt_cfb_256(session_pw3, def, def + IV_SIZE + 32 + 32, 32);
- }
- file_put_data(tf, def, sizeof(def));
- low_flash_available();
- return SW_OK();
}
-static int cmd_reset_retry() {
- if (P2(apdu) != 0x81) {
- return SW_REFERENCE_NOT_FOUND();
+int reset_sig_count() {
+ file_t *ef = search_by_fid(EF_SIG_COUNT, NULL, SPECIFY_ANY);
+ if (!ef || !ef->data) {
+ return PICOKEY_ERR_FILE_NOT_FOUND;
}
- if (P1(apdu) == 0x0 || P1(apdu) == 0x2) {
- int newpin_len = 0;
- file_t *pw = NULL;
- has_pw1 = false;
- if (!(pw = search_by_fid(EF_PW1, NULL, SPECIFY_EF))) {
- return SW_REFERENCE_NOT_FOUND();
- }
- if (P1(apdu) == 0x0) {
- file_t *rc;
- if (!(rc = search_by_fid(EF_RC, NULL, SPECIFY_EF))) {
- return SW_REFERENCE_NOT_FOUND();
- }
- uint8_t pin_len = file_get_data(rc)[0];
- if (apdu.nc <= pin_len) {
- return SW_WRONG_LENGTH();
- }
- uint16_t r = check_pin(rc, apdu.data, pin_len);
- if (r != 0x9000) {
- return r;
- }
- newpin_len = apdu.nc - pin_len;
- has_rc = true;
- hash_multi(apdu.data, pin_len, session_rc);
- }
- else if (P1(apdu) == 0x2) {
- if (!has_pw3) {
- return SW_CONDITIONS_NOT_SATISFIED();
- }
- newpin_len = apdu.nc;
- }
- int r = 0;
- if ((r = load_dek()) != PICOKEY_OK) {
- return SW_EXEC_ERROR();
- }
- 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];
- 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));
-
- uint8_t dhash[33];
- dhash[0] = newpin_len;
- double_hash_pin(apdu.data + (apdu.nc - newpin_len), newpin_len, dhash + 1);
- file_put_data(pw, dhash, sizeof(dhash));
- if (pin_reset_retries(pw, true) != PICOKEY_OK) {
- return SW_MEMORY_FAILURE();
- }
- low_flash_available();
- return SW_OK();
+ uint8_t q[3] = { 0 };
+ int r = file_put_data(ef, q, sizeof(q));
+ if (r != PICOKEY_OK) {
+ return PICOKEY_EXEC_ERROR;
}
- return SW_INCORRECT_P1P2();
+ low_flash_available();
+ return PICOKEY_OK;
}
int store_keys(void *key_ctx, int type, uint16_t key_id, bool use_kek) {
@@ -1343,14 +639,14 @@ void make_rsa_response(mbedtls_rsa_context *rsa) {
res_APDU_size = 5;
res_APDU[res_APDU_size++] = 0x81;
res_APDU[res_APDU_size++] = 0x82;
- put_uint16_t(mbedtls_mpi_size(&rsa->N), res_APDU + res_APDU_size); res_APDU_size += 2;
+ put_uint16_t_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));
res_APDU_size += mbedtls_mpi_size(&rsa->N);
res_APDU[res_APDU_size++] = 0x82;
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));
res_APDU_size += mbedtls_mpi_size(&rsa->E);
- put_uint16_t(res_APDU_size - 5, res_APDU + 3);
+ put_uint16_t_be(res_APDU_size - 5, res_APDU + 3);
}
void make_ecdsa_response(mbedtls_ecp_keypair *ecdsa) {
@@ -1377,124 +673,6 @@ void make_ecdsa_response(mbedtls_ecp_keypair *ecdsa) {
res_APDU_size += plen;
}
-static int cmd_keypair_gen() {
- if (P2(apdu) != 0x0) {
- return SW_INCORRECT_P1P2();
- }
- if (apdu.nc != 2 && apdu.nc != 5) {
- return SW_WRONG_LENGTH();
- }
- if (!has_pw3 && P1(apdu) == 0x80) {
- return SW_SECURITY_STATUS_NOT_SATISFIED();
- }
-
- uint16_t fid = 0x0;
- int r = PICOKEY_OK;
- if (apdu.data[0] == 0xB6) {
- fid = EF_PK_SIG;
- }
- else if (apdu.data[0] == 0xB8) {
- fid = EF_PK_DEC;
- }
- else if (apdu.data[0] == 0xA4) {
- fid = EF_PK_AUT;
- }
- else {
- return SW_WRONG_DATA();
- }
-
- 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_get_data(algo_ef);
- algo_len = file_get_size(algo_ef);
- }
- if (P1(apdu) == 0x80) { //generate
- if (algo[0] == ALGO_RSA) {
- int exponent = 65537, nlen = (algo[1] << 8) | algo[2];
- printf("KEYPAIR RSA %d\r\n", nlen);
- //if (nlen != 2048 && nlen != 4096)
- // return SW_FUNC_NOT_SUPPORTED();
- mbedtls_rsa_context rsa;
- mbedtls_rsa_init(&rsa);
- uint8_t index = 0;
- r = mbedtls_rsa_gen_key(&rsa, random_gen, &index, nlen, exponent);
- if (r != 0) {
- mbedtls_rsa_free(&rsa);
- return SW_EXEC_ERROR();
- }
- r = store_keys(&rsa, ALGO_RSA, fid, true);
- make_rsa_response(&rsa);
- mbedtls_rsa_free(&rsa);
- if (r != PICOKEY_OK) {
- return SW_EXEC_ERROR();
- }
- }
- else if (algo[0] == ALGO_ECDH || algo[0] == ALGO_ECDSA || algo[0] == ALGO_EDDSA) {
- printf("KEYPAIR ECDSA\r\n");
- 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_ecp_keypair ecdsa;
- mbedtls_ecp_keypair_init(&ecdsa);
- uint8_t index = 0;
- r = mbedtls_ecdsa_genkey(&ecdsa, gid, random_gen, &index);
- if (r != 0) {
- mbedtls_ecp_keypair_free(&ecdsa);
- return SW_EXEC_ERROR();
- }
- r = store_keys(&ecdsa, algo[0], fid, true);
- make_ecdsa_response(&ecdsa);
- mbedtls_ecp_keypair_free(&ecdsa);
- if (r != PICOKEY_OK) {
- return SW_EXEC_ERROR();
- }
- }
- else {
- return SW_FUNC_NOT_SUPPORTED();
- }
- file_t *pbef = search_by_fid(fid + 3, NULL, SPECIFY_EF);
- if (!pbef) {
- return SW_REFERENCE_NOT_FOUND();
- }
- r = file_put_data(pbef, res_APDU, res_APDU_size);
- if (r != PICOKEY_OK) {
- return SW_EXEC_ERROR();
- }
- if (fid == EF_PK_SIG) {
- 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, true);
- /* if storing the key fails, we silently continue */
- //if (r != PICOKEY_OK)
- // return SW_EXEC_ERROR();
- }
- low_flash_available();
- return SW_OK();
- }
- else if (P1(apdu) == 0x81) { //read
- file_t *ef = search_by_fid(fid + 3, NULL, SPECIFY_EF);
- if (!ef || !ef->data) {
- return SW_REFERENCE_NOT_FOUND();
- }
- res_APDU_size = file_get_size(ef);
- memcpy(res_APDU, file_get_data(ef), res_APDU_size);
- return SW_OK();
- }
- return SW_INCORRECT_P1P2();
-}
-
int rsa_sign(mbedtls_rsa_context *ctx,
const uint8_t *data,
size_t data_len,
@@ -1591,568 +769,23 @@ int ecdsa_sign(mbedtls_ecp_keypair *ctx,
return r;
}
-static int cmd_pso() {
- uint16_t algo_fid = 0x0, pk_fid = 0x0;
- bool is_aes = false;
- if (P1(apdu) == 0x9E && P2(apdu) == 0x9A) {
- if (!has_pw3 && !has_pw1) {
- return SW_SECURITY_STATUS_NOT_SATISFIED();
- }
- algo_fid = EF_ALGO_PRIV1;
- pk_fid = EF_PK_SIG;
- }
- else if (P1(apdu) == 0x80 && P2(apdu) == 0x86) {
- if (!has_pw3 && !has_pw2) {
- return SW_SECURITY_STATUS_NOT_SATISFIED();
- }
- algo_fid = algo_dec;
- pk_fid = pk_dec;
- }
- else {
- return SW_INCORRECT_P1P2();
- }
- file_t *algo_ef = search_by_fid(algo_fid, NULL, SPECIFY_EF);
- if (!algo_ef) {
- return SW_REFERENCE_NOT_FOUND();
- }
- const uint8_t *algo = algorithm_attr_rsa2k + 1;
- if (algo_ef && algo_ef->data) {
- algo = file_get_data(algo_ef);
- }
- 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);
- if (!ef) {
- return SW_REFERENCE_NOT_FOUND();
- }
- if (wait_button_pressed(pk_fid == EF_PK_SIG ? EF_UIF_SIG : EF_UIF_DEC) == true) {
- return SW_SECURE_MESSAGE_EXEC_ERROR();
- }
- int r = PICOKEY_OK;
- int key_size = file_get_size(ef);
- if (is_aes) {
- uint8_t aes_key[32];
- r = load_aes_key(aes_key, ef);
- if (r != PICOKEY_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, PICO_KEYS_AES_MODE_CBC, apdu.data + 1, apdu.nc - 1);
- memset(aes_key, 0, sizeof(aes_key));
- if (r != PICOKEY_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, PICO_KEYS_AES_MODE_CBC, apdu.data, apdu.nc);
- memset(aes_key, 0, sizeof(aes_key));
- if (r != PICOKEY_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) {
- mbedtls_rsa_context ctx;
- mbedtls_rsa_init(&ctx);
- r = load_private_key_rsa(&ctx, ef, true);
- if (r != PICOKEY_OK) {
- mbedtls_rsa_free(&ctx);
- return SW_EXEC_ERROR();
- }
- if (P1(apdu) == 0x9E && P2(apdu) == 0x9A) {
- size_t olen = 0;
- r = rsa_sign(&ctx, apdu.data, apdu.nc, res_APDU, &olen);
- mbedtls_rsa_free(&ctx);
- if (r != 0) {
- return SW_EXEC_ERROR();
- }
- res_APDU_size = olen;
- //apdu.ne = key_size;
- inc_sig_count();
- }
- else if (P1(apdu) == 0x80 && P2(apdu) == 0x86) {
- if (apdu.nc < key_size) { //needs padding
- memset(apdu.data + apdu.nc, 0, key_size - apdu.nc);
- }
- size_t olen = 0;
- r = mbedtls_rsa_pkcs1_decrypt(&ctx,
- random_gen,
- NULL,
- &olen,
- apdu.data + 1,
- res_APDU,
- key_size);
- mbedtls_rsa_free(&ctx);
- if (r != 0) {
- return SW_EXEC_ERROR();
- }
- res_APDU_size = olen;
- }
- }
- else if (algo[0] == ALGO_ECDH || algo[0] == ALGO_ECDSA || algo[0] == ALGO_EDDSA) {
- if (P1(apdu) == 0x9E && P2(apdu) == 0x9A) {
- mbedtls_ecp_keypair ctx;
- mbedtls_ecp_keypair_init(&ctx);
- r = load_private_key_ecdsa(&ctx, ef, true);
- if (r != PICOKEY_OK) {
- mbedtls_ecp_keypair_free(&ctx);
- return SW_EXEC_ERROR();
- }
- size_t olen = 0;
- r = ecdsa_sign(&ctx, apdu.data, apdu.nc, res_APDU, &olen);
- mbedtls_ecp_keypair_free(&ctx);
- if (r != 0) {
- return SW_EXEC_ERROR();
- }
- res_APDU_size = olen;
- inc_sig_count();
- }
- else if (P1(apdu) == 0x80 && P2(apdu) == 0x86) {
- mbedtls_ecdh_context ctx;
- uint8_t kdata[67];
- uint8_t *data = apdu.data, *end = data + apdu.nc;
- size_t len = 0;
- if (mbedtls_asn1_get_tag(&data, end, &len, 0xA6) != 0) {
- return SW_WRONG_DATA();
- }
- if (*data++ != 0x7f) {
- return SW_WRONG_DATA();
- }
- if (mbedtls_asn1_get_tag(&data, end, &len,
- 0x49) != 0 ||
- mbedtls_asn1_get_tag(&data, end, &len, 0x86) != 0) {
- return SW_WRONG_DATA();
- }
- //if (len != 2*key_size-1)
- // return SW_WRONG_LENGTH();
- memcpy(kdata, file_get_data(ef), key_size);
- if (dek_decrypt(kdata, key_size) != 0) {
- return SW_EXEC_ERROR();
- }
- mbedtls_ecdh_init(&ctx);
- mbedtls_ecp_group_id gid = kdata[0];
- r = mbedtls_ecdh_setup(&ctx, gid);
- if (r != 0) {
- mbedtls_ecdh_free(&ctx);
- return SW_DATA_INVALID();
- }
- r = mbedtls_ecp_read_key(gid, (mbedtls_ecdsa_context *)&ctx.ctx.mbed_ecdh, kdata + 1, key_size - 1);
- if (r != 0) {
- mbedtls_ecdh_free(&ctx);
- return SW_DATA_INVALID();
- }
- r = mbedtls_ecdh_read_public(&ctx, data - 1, len + 1);
- if (r != 0) {
- mbedtls_ecdh_free(&ctx);
- return SW_DATA_INVALID();
- }
- size_t olen = 0;
- r = mbedtls_ecdh_calc_secret(&ctx,
- &olen,
- res_APDU,
- MBEDTLS_ECP_MAX_BYTES,
- random_gen,
- NULL);
- if (r != 0) {
- mbedtls_ecdh_free(&ctx);
- return SW_EXEC_ERROR();
- }
- res_APDU_size = olen;
- mbedtls_ecdh_free(&ctx);
- }
- }
- return SW_OK();
-}
-
-static int cmd_terminate_df() {
- if (P1(apdu) != 0x0 || P2(apdu) != 0x0) {
- return SW_INCORRECT_P1P2();
- }
- file_t *retries;
- if (!(retries = search_by_fid(EF_PW_PRIV, NULL, SPECIFY_EF))) {
- return SW_REFERENCE_NOT_FOUND();
- }
- if (!has_pw3 && *(file_get_data(retries) + 6) > 0) {
- return SW_SECURITY_STATUS_NOT_SATISFIED();
- }
- if (apdu.nc != 0) {
- return SW_WRONG_LENGTH();
- }
- initialize_flash(true);
- scan_files();
- return SW_OK();
-}
-
-static int cmd_activate_file() {
- return SW_OK();
-}
-
-static int cmd_challenge() {
- uint8_t *rb = (uint8_t *) random_bytes_get(apdu.ne);
- if (!rb) {
- return SW_WRONG_LENGTH();
- }
- memcpy(res_APDU, rb, apdu.ne);
- res_APDU_size = apdu.ne;
- return SW_OK();
-}
-
-static int cmd_internal_aut() {
- if (P1(apdu) != 0x00 || P2(apdu) != 0x00) {
- return SW_WRONG_P1P2();
- }
- if (!has_pw3 && !has_pw2) {
- return SW_SECURITY_STATUS_NOT_SATISFIED();
- }
- file_t *algo_ef = search_by_fid(algo_aut, NULL, SPECIFY_EF);
- if (!algo_ef) {
- return SW_REFERENCE_NOT_FOUND();
- }
- const uint8_t *algo = algorithm_attr_rsa2k + 1;
- if (algo_ef && algo_ef->data) {
- algo = file_get_data(algo_ef);
- }
- file_t *ef = search_by_fid(pk_aut, NULL, SPECIFY_EF);
- if (!ef) {
- return SW_REFERENCE_NOT_FOUND();
- }
- if (wait_button_pressed(EF_UIF_AUT) == true) {
- return SW_SECURE_MESSAGE_EXEC_ERROR();
- }
- int r = PICOKEY_OK;
- if (algo[0] == ALGO_RSA) {
- mbedtls_rsa_context ctx;
- mbedtls_rsa_init(&ctx);
- r = load_private_key_rsa(&ctx, ef, true);
- if (r != PICOKEY_OK) {
- mbedtls_rsa_free(&ctx);
- return SW_EXEC_ERROR();
- }
- size_t olen = 0;
- r = rsa_sign(&ctx, apdu.data, apdu.nc, res_APDU, &olen);
- mbedtls_rsa_free(&ctx);
- if (r != 0) {
- return SW_EXEC_ERROR();
- }
- res_APDU_size = olen;
- }
- else if (algo[0] == ALGO_ECDH || algo[0] == ALGO_ECDSA || algo[0] == ALGO_EDDSA) {
- mbedtls_ecp_keypair ctx;
- mbedtls_ecp_keypair_init(&ctx);
- r = load_private_key_ecdsa(&ctx, ef, true);
- if (r != PICOKEY_OK) {
- mbedtls_ecp_keypair_free(&ctx);
- return SW_EXEC_ERROR();
- }
- size_t olen = 0;
- r = ecdsa_sign(&ctx, apdu.data, apdu.nc, res_APDU, &olen);
- mbedtls_ecp_keypair_free(&ctx);
- if (r != 0) {
- return SW_EXEC_ERROR();
- }
- res_APDU_size = olen;
- }
- return SW_OK();
-}
-
-static int cmd_mse() {
- if (P1(apdu) != 0x41 || (P2(apdu) != 0xA4 && P2(apdu) != 0xB8)) {
- return SW_WRONG_P1P2();
- }
- if (apdu.data[0] != 0x83 || apdu.data[1] != 0x1 ||
- (apdu.data[2] != 0x2 && apdu.data[2] != 0x3)) {
- return SW_WRONG_DATA();
- }
- if (P2(apdu) == 0xA4) {
- if (apdu.data[2] == 0x2) {
- algo_dec = EF_ALGO_PRIV2;
- pk_dec = EF_PK_DEC;
- }
- else if (apdu.data[2] == 0x3) {
- algo_dec = EF_ALGO_PRIV3;
- pk_dec = EF_PK_AUT;
- }
- }
- else if (P2(apdu) == 0xB8) {
- if (apdu.data[2] == 0x2) {
- algo_aut = EF_ALGO_PRIV2;
- pk_aut = EF_PK_DEC;
- }
- else if (apdu.data[2] == 0x3) {
- algo_aut = EF_ALGO_PRIV3;
- pk_aut = EF_PK_AUT;
- }
- }
- return SW_OK();
-}
-
-uint16_t tag_len(uint8_t **data) {
- size_t len = *(*data)++;
- if (len == 0x82) {
- len = *(*data)++ << 8;
- len |= *(*data)++;
- }
- else if (len == 0x81) {
- len = *(*data)++;
- }
- return len;
-}
-
-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();
- }
- uint8_t *start = apdu.data;
- if (*start++ != 0x4D) {
- return SW_WRONG_DATA();
- }
- uint16_t tgl = tag_len(&start);
- if (*start != 0xB6 && *start != 0xB8 && *start != 0xA4) {
- return SW_WRONG_DATA();
- }
- if (*start == 0xB6) {
- fid = EF_PK_SIG;
- }
- else if (*start == 0xB8) {
- fid = EF_PK_DEC;
- }
- else if (*start == 0xA4) {
- fid = EF_PK_AUT;
- }
- else {
- return SW_WRONG_DATA();
- }
- start++;
- 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();
- }
- start += (*start + 1);
- if (*start++ != 0x7F || *start++ != 0x48) {
- return SW_WRONG_DATA();
- }
- tgl = tag_len(&start);
- uint8_t *end = start + tgl, *p[9] = { 0 };
- uint16_t len[9] = { 0 };
- while (start < end) {
- uint8_t tag = *start++;
- if ((tag >= 0x91 && tag <= 0x97) || tag == 0x99) {
- len[tag - 0x91] = tag_len(&start);
- }
- else {
- return SW_WRONG_DATA();
- }
- }
- if (*start++ != 0x5F || *start++ != 0x48) {
- return SW_WRONG_DATA();
- }
- tgl = tag_len(&start);
- end = start + tgl;
- for (int t = 0; start < end && t < 9; 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_get_data(algo_ef);
- algo_len = file_get_size(algo_ef);
- }
- 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, true);
- make_rsa_response(&rsa);
- mbedtls_rsa_free(&rsa);
- if (r != PICOKEY_OK) {
- return SW_EXEC_ERROR();
- }
- }
- else if (algo[0] == ALGO_ECDSA || algo[0] == ALGO_ECDH || algo[0] == ALGO_EDDSA) {
- mbedtls_ecp_keypair 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_ecp_keypair_init(&ecdsa);
- if (gid == MBEDTLS_ECP_DP_CURVE25519) {
- mbedtls_ecp_group_load(&ecdsa.grp, gid);
- r = mbedtls_mpi_read_binary(&ecdsa.d, p[1], len[1]);
- }
- else {
- r = mbedtls_ecp_read_key(gid, &ecdsa, p[1], len[1]);
- }
- if (r != 0) {
- mbedtls_ecp_keypair_free(&ecdsa);
- return SW_EXEC_ERROR();
- }
- if (ecdsa.grp.id == MBEDTLS_ECP_DP_ED25519) {
- r = mbedtls_ecp_point_edwards(&ecdsa.grp, &ecdsa.Q, &ecdsa.d, random_gen, NULL);
- }
- else {
- r = mbedtls_ecp_mul(&ecdsa.grp, &ecdsa.Q, &ecdsa.d, &ecdsa.grp.G, random_gen, NULL);
- }
- if (r != 0) {
- mbedtls_ecp_keypair_free(&ecdsa);
- return SW_EXEC_ERROR();
- }
- r = store_keys(&ecdsa, ALGO_ECDSA, fid, true);
- make_ecdsa_response(&ecdsa);
- mbedtls_ecp_keypair_free(&ecdsa);
- if (r != PICOKEY_OK) {
- return SW_EXEC_ERROR();
- }
- }
- else {
- return SW_FUNC_NOT_SUPPORTED();
- }
- if (fid == EF_PK_SIG) {
- reset_sig_count();
- }
- file_t *pbef = search_by_fid(fid + 3, NULL, SPECIFY_EF);
- if (!pbef) {
- return SW_REFERENCE_NOT_FOUND();
- }
- r = file_put_data(pbef, res_APDU, res_APDU_size);
- if (r != PICOKEY_OK) {
- return SW_EXEC_ERROR();
- }
- res_APDU_size = 0; //make_*_response sets a response. we need to overwrite
- 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();
-}
+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();
+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_MSE 0x22
diff --git a/src/openpgp/openpgp.h b/src/openpgp/openpgp.h
index ce33599..c08ff75 100644
--- a/src/openpgp/openpgp.h
+++ b/src/openpgp/openpgp.h
@@ -27,9 +27,17 @@
#include "apdu.h"
#include "mbedtls/rsa.h"
#include "mbedtls/ecdsa.h"
+#include "crypto_utils.h"
+#include "files.h"
extern bool has_pw1;
+extern bool has_pw2;
extern bool has_pw3;
+extern bool has_rc;
+extern uint8_t session_pw1[32];
+extern uint8_t session_rc[32];
+extern uint8_t session_pw3[32];
+extern uint8_t dek[IV_SIZE + 32];
extern int store_keys(void *key_ctx, int type, uint16_t key_id, bool use_kek);
extern void make_rsa_response(mbedtls_rsa_context *rsa);
@@ -57,4 +65,18 @@ extern int pin_reset_retries(const file_t *pin, bool force);
#define ALGO_AES_192 0x72
#define ALGO_AES_256 0x74
+extern void select_file(file_t *pe);
+extern int parse_do(uint16_t *fids, int mode);
+extern int load_dek();
+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 int reset_sig_count();
+extern uint16_t algo_dec, algo_aut, pk_dec, pk_aut;
+extern bool wait_button_pressed(uint16_t fid);
+extern void scan_files();
+extern int load_aes_key(uint8_t *aes_key, file_t *fkey);
+extern int inc_sig_count();
+extern int dek_encrypt(uint8_t *data, size_t len);
+extern int dek_decrypt(uint8_t *data, size_t len);
+
#endif
diff --git a/src/openpgp/piv.c b/src/openpgp/piv.c
index 6b37772..e2568bf 100644
--- a/src/openpgp/piv.c
+++ b/src/openpgp/piv.c
@@ -165,7 +165,7 @@ static int x509_create_cert(void *pk_ctx, uint8_t algo, uint8_t slot, bool attes
return ret;
}
-static void scan_files() {
+static void scan_files_piv() {
scan_flash();
file_t *ef = search_by_fid(EF_PIV_KEY_CARDMGM, NULL, SPECIFY_EF);
if ((ef = search_by_fid(EF_PW_PRIV, NULL, SPECIFY_ANY))) {
@@ -264,7 +264,7 @@ static void scan_files() {
}
void init_piv() {
- scan_files();
+ scan_files_piv();
has_pwpiv = false;
// cmd_select();
}
@@ -475,7 +475,7 @@ static int cmd_get_metadata() {
}
res_APDU[res_APDU_size++] = 0x81;
res_APDU[res_APDU_size++] = 0x82;
- put_uint16_t(mbedtls_mpi_size(&ctx.N), res_APDU + res_APDU_size); res_APDU_size += 2;
+ put_uint16_t_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));
res_APDU_size += mbedtls_mpi_size(&ctx.N);
res_APDU[res_APDU_size++] = 0x82;
@@ -945,7 +945,7 @@ static int cmd_asym_keygen() {
return SW_OK();
}
-int cmd_put_data() {
+static int cmd_put_data() {
if (P1(apdu) != 0x3F || P2(apdu) != 0xFF) {
return SW_INCORRECT_P1P2();
}
diff --git a/src/openpgp/version.h b/src/openpgp/version.h
index 2d4ae1b..554c686 100644
--- a/src/openpgp/version.h
+++ b/src/openpgp/version.h
@@ -23,15 +23,15 @@
#define OPGP_VERSION_MAJOR ((OPGP_VERSION >> 8) & 0xff)
#define OPGP_VERSION_MINOR (OPGP_VERSION & 0xff)
+#define PIV_VERSION 0x0507
+
+#define PIV_VERSION_MAJOR ((PIV_VERSION >> 8) & 0xff)
+#define PIV_VERSION_MINOR (PIV_VERSION & 0xff)
+
#define PIPGP_VERSION 0x0300
#define PIPGP_VERSION_MAJOR ((PIPGP_VERSION >> 8) & 0xff)
#define PIPGP_VERSION_MINOR (PIPGP_VERSION & 0xff)
-#define PIV_VERSION 0x0507
-
-#define PIV_VERSION_MAJOR ((PIV_VERSION >> 8) & 0xff)
-#define PIV_VERSION_MINOR (PIV_VERSION & 0xff)
-
#endif
diff --git a/workflows/autobuild.sh b/workflows/autobuild.sh
index 8f830c3..16c9600 100755
--- a/workflows/autobuild.sh
+++ b/workflows/autobuild.sh
@@ -22,6 +22,7 @@ mkdir build_pico
cd build_pico
cmake -DPICO_SDK_PATH=../pico-sdk ..
make
+cd ..
elif [[ $1 == "esp32" ]]; then
sudo apt install -y git wget flex bison gperf python3 python3-pip python3-venv cmake ninja-build ccache libffi-dev libssl-dev dfu-util libusb-1.0-0
git clone --recursive https://github.com/espressif/esp-idf.git
@@ -31,6 +32,10 @@ cd esp-idf
cd ..
idf.py set-target esp32s3
idf.py all
+mkdir -p release
+cd build
+esptool.py --chip ESP32-S3 merge_bin -o ../release/pico_openpgp_esp32-s3.bin @flash_args
+cd ..
else
mkdir build
cd build