From 8ee7be69f3ba83626de3e814a3e18b4cc952d0dd Mon Sep 17 00:00:00 2001 From: Pol Henarejos Date: Thu, 16 Jul 2026 16:11:11 +0200 Subject: [PATCH] Add more api functions. Signed-off-by: Pol Henarejos --- picokeys_sdk_import.cmake | 9 ++- src/apdu.h | 6 +- src/audit.c | 39 ----------- src/audit.h | 64 ----------------- src/main.c | 7 +- src/plugin/core_plugin_region_assert.ld | 6 +- src/plugin/picokeys_plugin_api.h | 75 +++++++++++++++++++- src/plugin/plugin_loader.c | 92 +++++++++++++++++++++++++ src/rescue.c | 32 +++++---- 9 files changed, 196 insertions(+), 134 deletions(-) delete mode 100644 src/audit.c delete mode 100644 src/audit.h diff --git a/picokeys_sdk_import.cmake b/picokeys_sdk_import.cmake index d60da51..84cae21 100644 --- a/picokeys_sdk_import.cmake +++ b/picokeys_sdk_import.cmake @@ -116,10 +116,10 @@ else() endif() if(PICO_RP2350 OR ENABLE_EMULATION) - set(PICOKEYS_PLUGIN_FLASH_BASE "0x10112000" CACHE STRING "XIP address where the premium plugin UF2 starts" FORCE) - set(PICOKEYS_PLUGIN_FLASH_SIZE "0x000fa000" CACHE STRING "Maximum premium plugin size in bytes" FORCE) - set(PICOKEYS_PLUGIN_RAM_BASE "0x2007c000" CACHE STRING "RAM base reserved for premium plugin mutable state" FORCE) - set(PICOKEYS_PLUGIN_RAM_SIZE "0x00004000" CACHE STRING "Maximum premium plugin RAM usage in bytes" FORCE) + set(PICOKEYS_PLUGIN_FLASH_BASE "0x10112000" CACHE STRING "XIP address where the plugin UF2 starts" FORCE) + set(PICOKEYS_PLUGIN_FLASH_SIZE "0x000fa000" CACHE STRING "Maximum plugin size in bytes" FORCE) + set(PICOKEYS_PLUGIN_RAM_BASE "0x2007c000" CACHE STRING "RAM base reserved for plugin mutable state" FORCE) + set(PICOKEYS_PLUGIN_RAM_SIZE "0x00004000" CACHE STRING "Maximum plugin RAM usage in bytes" FORCE) set(PICOKEYS_PLUGIN_DIR "" CACHE PATH "Optional external PicoKeys plugin source directory") include(${CMAKE_CURRENT_LIST_DIR}/cmake/plugin.cmake) endif() @@ -344,7 +344,6 @@ list(APPEND PICOKEYS_SOURCES ${CMAKE_CURRENT_LIST_DIR}/src/button.c ${CMAKE_CURRENT_LIST_DIR}/src/led/led.c ${CMAKE_CURRENT_LIST_DIR}/src/signal.c - ${CMAKE_CURRENT_LIST_DIR}/src/audit.c ) if(ESP_PLATFORM) diff --git a/src/apdu.h b/src/apdu.h index 5874f49..c34a011 100644 --- a/src/apdu.h +++ b/src/apdu.h @@ -35,9 +35,9 @@ extern int register_app(int (*)(app_t *, uint8_t), const uint8_t *); extern int select_app(const uint8_t *aid, size_t aid_len); typedef enum { - CMD_FLAG_NONE = 0x00, - CMD_FLAG_AUDIT_LOG = 0x01, - CMD_FLAG_CRITICAL = 0x02, + CMD_FLAG_NONE = 0x00, + CMD_FLAG_NOTIFY_PLUGIN = 0x01, + CMD_FLAG_SECURITY_SENSITIVE = 0x02, } cmd_flags_t; typedef struct cmd { diff --git a/src/audit.c b/src/audit.c deleted file mode 100644 index 9fd0fee..0000000 --- a/src/audit.c +++ /dev/null @@ -1,39 +0,0 @@ -/* - * This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk). - * Copyright (c) 2022 Pol Henarejos. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, version 3. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -#include "picokeys.h" -#include "signal.h" -#include "audit.h" - -void audit_entry_set_current_event(uint16_t event) { - signal_audit_evt_data_t data = {.cmd = AUDIT_CMD_EVT, .value = event}; - signal_emit_param(SIGNAL_AUDIT_EVT, &data); -} - -void audit_log_current_entry_with_result(uint16_t result) { - signal_audit_evt_data_t data = {.cmd = AUDIT_CMD_LOG, .value = result}; - signal_emit_param(SIGNAL_AUDIT_EVT, &data); -} - -void audit_entry_set_current_flags(audit_entry_flags_t flags) { - signal_audit_evt_data_t data = {.cmd = AUDIT_CMD_SET_FLAGS, .value = flags}; - signal_emit_param(SIGNAL_AUDIT_EVT, &data); -} -void audit_entry_set_current_object(uint16_t object_id) { - signal_audit_evt_data_t data = {.cmd = AUDIT_CMD_SET_OBJECT, .value = object_id}; - signal_emit_param(SIGNAL_AUDIT_EVT, &data); -} diff --git a/src/audit.h b/src/audit.h deleted file mode 100644 index 6422949..0000000 --- a/src/audit.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * This file is part of the Pico Keys SDK distribution (https://github.com/polhenarejos/pico-keys-sdk). - * Copyright (c) 2022 Pol Henarejos. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, version 3. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -#ifndef _AUDIT_H_ -#define _AUDIT_H_ - -#include - -static const uint8_t SIGNAL_AUDIT_EVT = 11; -#define AUDIT_EVT_APP_EVT 0x8000 - -typedef enum { - AUDIT_EVT_LOG_READ = 0x0001, - AUDIT_EVT_LOG_CLEARED, - AUDIT_EVT_FIRMWARE_UPDATE, - AUDIT_EVT_INIT, - AUDIT_EVT_POWER_UP, - AUDIT_EVT_SET_RTC, -} audit_evt_t; - -typedef enum { - AUDIT_EF_SUCCESS = 0x0001, - AUDIT_EF_FAIL = 0x0002, - AUDIT_EF_DENIED = 0x0004, - - AUDIT_EF_USER = 0x0010, - AUDIT_EF_ADMIN = 0x0020, - - AUDIT_EF_CRITICAL = 0x0100, - AUDIT_EF_TIME_UNSYNCED = 0x0200, -} audit_entry_flags_t; - -typedef enum { - AUDIT_CMD_EVT = 1, - AUDIT_CMD_SET_OBJECT = 2, - AUDIT_CMD_SET_FLAGS = 3, - AUDIT_CMD_LOG = 4 -} audit_cmd_t; - -typedef struct { - audit_cmd_t cmd; - uint16_t value; -} signal_audit_evt_data_t; - -extern void audit_entry_set_current_event(uint16_t event); -extern void audit_entry_set_current_flags(audit_entry_flags_t flags); -extern void audit_entry_set_current_object(uint16_t object_id); -extern void audit_log_current_entry_with_result(uint16_t res); - -#endif // _AUDIT_H_ diff --git a/src/main.c b/src/main.c index b59f923..dfc9d46 100644 --- a/src/main.c +++ b/src/main.c @@ -43,6 +43,9 @@ #include "serial.h" #include "mbedtls/sha256.h" #include "signal.h" +#if defined(PICO_RP2350) || defined(ENABLE_EMULATION) +#include "picokeys_plugin_api.h" +#endif app_t apps[16]; uint8_t num_apps = 0; @@ -104,10 +107,6 @@ WEAK int picokey_init(void) { } -#if defined(PICO_RP2350) || defined(ENABLE_EMULATION) -void plugin_init(void); -#endif - void execute_tasks(void); void execute_tasks(void) { #if !defined(ENABLE_EMULATION) && !defined(ESP_PLATFORM) diff --git a/src/plugin/core_plugin_region_assert.ld b/src/plugin/core_plugin_region_assert.ld index 190852b..501d2db 100644 --- a/src/plugin/core_plugin_region_assert.ld +++ b/src/plugin/core_plugin_region_assert.ld @@ -1,11 +1,11 @@ ASSERT(!DEFINED(__picokeys_plugin_flash_base) || __flash_binary_end <= __picokeys_plugin_flash_base, - "pico_fido flash image overlaps the premium plugin region") + "pico_fido flash image overlaps the plugin region") ASSERT(!DEFINED(__picokeys_plugin_ram_base) || __end__ <= __picokeys_plugin_ram_base, - "pico_fido RAM image overlaps the premium plugin RAM region") + "pico_fido RAM image overlaps the plugin RAM region") ASSERT(!DEFINED(__picokeys_plugin_ram_base) || !DEFINED(__picokeys_plugin_ram_size) || ((__picokeys_plugin_ram_base + __picokeys_plugin_ram_size) <= 0x20080000), - "premium plugin RAM region exceeds RP2350 main RAM") + "plugin RAM region exceeds RP2350 main RAM") __HeapLimit = DEFINED(__picokeys_plugin_ram_base) ? __picokeys_plugin_ram_base : __HeapLimit; diff --git a/src/plugin/picokeys_plugin_api.h b/src/plugin/picokeys_plugin_api.h index da45c03..1962c8a 100644 --- a/src/plugin/picokeys_plugin_api.h +++ b/src/plugin/picokeys_plugin_api.h @@ -43,7 +43,9 @@ #endif #define PICOKEYS_PLUGIN_MAGIC 0x504b504cUL /* PKPL */ -#define PICOKEYS_PLUGIN_ABI_VERSION 5u +#define PICOKEYS_PLUGIN_ABI_VERSION 1u + +#define PICOKEYS_PLUGIN_SIGNAL_EVENT 11u #ifndef PICOKEYS_PLUGIN_FLASH_BASE #define PICOKEYS_PLUGIN_FLASH_BASE 0x10112000UL @@ -88,9 +90,47 @@ typedef struct pk_plugin_imports { uint8_t *(*get_res_apdu)(void); uint16_t (*get_res_apdu_size)(void); void (*set_res_apdu_size)(uint16_t size); + uint8_t (*get_apdu_cla)(void); + uint8_t (*get_apdu_ins)(void); + uint8_t (*get_apdu_p1)(void); + uint8_t (*get_apdu_p2)(void); + const uint8_t *(*get_apdu_data)(void); + size_t (*get_apdu_data_size)(void); + uint16_t (*set_res_sw)(uint8_t sw1, uint8_t sw2); + void *(*file_search)(uint16_t fid); + void *(*file_new)(uint16_t fid); + int (*file_has_data)(const void *file); + const uint8_t *(*file_get_data)(const void *file); + uint16_t (*file_get_size)(const void *file); + int (*file_put_data)(void *file, const uint8_t *data, uint16_t len); + int (*file_delete)(void *file); } pk_plugin_imports_t; -typedef void (*pk_plugin_init_fn)(pk_plugin_imports_t *imports); +typedef enum pk_plugin_event_type { + PK_PLUGIN_EVENT_COMMAND_COMPLETED = 1, +} pk_plugin_event_type_t; + +#define PK_PLUGIN_EVENT_SOURCE_CORE 0x0000u + +typedef enum pk_plugin_event_flags { + PK_PLUGIN_EVENT_FLAG_NONE = 0, + PK_PLUGIN_EVENT_FLAG_SECURITY_SENSITIVE = 1u << 0, +} pk_plugin_event_flags_t; + +typedef struct pk_plugin_event { + uint16_t type; + uint16_t source; + uint16_t command; + uint16_t object; + uint16_t flags; + uint16_t struct_size; + int32_t result; +} pk_plugin_event_t; + +typedef void (*pk_plugin_init_fn)(const pk_plugin_imports_t *imports); +typedef int (*pk_plugin_call_fn)(uint32_t hook, void *data); + +#define PK_PLUGIN_CALL_UNHANDLED (-1) typedef struct pk_plugin_header { uint32_t magic; @@ -103,8 +143,39 @@ typedef struct pk_plugin_header { uintptr_t bss_start; uint32_t bss_size; pk_plugin_init_fn init; + pk_plugin_call_fn call; } pk_plugin_header_t; +#if defined(PICO_RP2350) || defined(ENABLE_EMULATION) void plugin_init(void); +void pk_plugin_dispatch_event(const pk_plugin_event_t *event); +int pk_plugin_call(uint32_t hook, void *data); +#else +static inline void pk_plugin_dispatch_event(const pk_plugin_event_t *event) { + (void)event; +} +static inline int pk_plugin_call(uint32_t hook, void *data) { + (void)hook; + (void)data; + return PK_PLUGIN_CALL_UNHANDLED; +} +#endif + +static inline void pk_plugin_notify_command(uint16_t source, + uint16_t command, + uint16_t object, + pk_plugin_event_flags_t flags, + int32_t result) { + const pk_plugin_event_t event = { + .type = PK_PLUGIN_EVENT_COMMAND_COMPLETED, + .source = source, + .command = command, + .object = object, + .flags = (uint16_t)flags, + .struct_size = sizeof(event), + .result = result, + }; + pk_plugin_dispatch_event(&event); +} #endif diff --git a/src/plugin/plugin_loader.c b/src/plugin/plugin_loader.c index 8344578..728bd0b 100644 --- a/src/plugin/plugin_loader.c +++ b/src/plugin/plugin_loader.c @@ -30,6 +30,7 @@ #include static pk_plugin_imports_t plugin_imports; +static const pk_plugin_header_t *active_plugin; _Static_assert(sizeof(pk_plugin_sha256_context_t) >= sizeof(mbedtls_sha256_context), "pk_plugin_sha256_context_t too small for mbedtls_sha256_context"); @@ -86,6 +87,77 @@ static void pk_plugin_set_res_apdu_size(uint16_t size) { apdu.rlen = size; } +static uint8_t pk_plugin_get_apdu_cla(void) { + return apdu.header ? CLA(apdu) : 0; +} + +static uint8_t pk_plugin_get_apdu_ins(void) { + return apdu.header ? INS(apdu) : 0; +} + +static uint8_t pk_plugin_get_apdu_p1(void) { + return apdu.header ? P1(apdu) : 0; +} + +static uint8_t pk_plugin_get_apdu_p2(void) { + return apdu.header ? P2(apdu) : 0; +} + +static const uint8_t *pk_plugin_get_apdu_data(void) { + return apdu.data; +} + +static size_t pk_plugin_get_apdu_data_size(void) { + return apdu.nc; +} + +static void *pk_plugin_file_search(uint16_t fid) { + return file_search(fid); +} + +static void *pk_plugin_file_new(uint16_t fid) { + return file_new(fid); +} + +static int pk_plugin_file_has_data(const void *file) { + return file_has_data((const file_t *)file) ? 1 : 0; +} + +static const uint8_t *pk_plugin_file_get_data(const void *file) { + return file_get_data((const file_t *)file); +} + +static uint16_t pk_plugin_file_get_size(const void *file) { + return file_get_size((const file_t *)file); +} + +static int pk_plugin_file_put_data(void *file, const uint8_t *data, uint16_t len) { + return file_put_data((file_t *)file, data, len); +} + +static int pk_plugin_file_delete(void *file) { + return file_delete((file_t *)file); +} + +static int pk_plugin_has_call(const pk_plugin_header_t *plugin) { + return plugin && + plugin->header_size >= offsetof(pk_plugin_header_t, call) + sizeof(plugin->call) && + plugin->call; +} + +void pk_plugin_dispatch_event(const pk_plugin_event_t *event) { + if (event) { + signal_emit_param(PICOKEYS_PLUGIN_SIGNAL_EVENT, (void *)event); + } +} + +int pk_plugin_call(uint32_t hook, void *data) { + if (!pk_plugin_has_call(active_plugin)) { + return PK_PLUGIN_CALL_UNHANDLED; + } + return active_plugin->call(hook, data); +} + #ifdef ENABLE_EMULATION #ifdef _WIN32 #include @@ -249,6 +321,11 @@ static const pk_plugin_header_t *pk_plugin_get_valid(void) { printf("Plugin rejected: init pointer out of range\n"); return NULL; } + if (plugin->header_size >= offsetof(pk_plugin_header_t, call) + sizeof(plugin->call) && + plugin->call && !pk_plugin_ptr_in_range((const void *)plugin->call)) { + printf("Plugin rejected: call pointer out of range\n"); + return NULL; + } return plugin; } #endif @@ -266,6 +343,7 @@ void plugin_init(void) { } #endif + active_plugin = plugin; plugin_imports = (pk_plugin_imports_t){ .abi_version = PICOKEYS_PLUGIN_ABI_VERSION, .struct_size = sizeof(plugin_imports), @@ -289,6 +367,20 @@ void plugin_init(void) { .get_res_apdu = pk_plugin_get_res_apdu, .get_res_apdu_size = pk_plugin_get_res_apdu_size, .set_res_apdu_size = pk_plugin_set_res_apdu_size, + .get_apdu_cla = pk_plugin_get_apdu_cla, + .get_apdu_ins = pk_plugin_get_apdu_ins, + .get_apdu_p1 = pk_plugin_get_apdu_p1, + .get_apdu_p2 = pk_plugin_get_apdu_p2, + .get_apdu_data = pk_plugin_get_apdu_data, + .get_apdu_data_size = pk_plugin_get_apdu_data_size, + .set_res_sw = set_res_sw, + .file_search = pk_plugin_file_search, + .file_new = pk_plugin_file_new, + .file_has_data = pk_plugin_file_has_data, + .file_get_data = pk_plugin_file_get_data, + .file_get_size = pk_plugin_file_get_size, + .file_put_data = pk_plugin_file_put_data, + .file_delete = pk_plugin_file_delete, }; plugin->init(&plugin_imports); } diff --git a/src/rescue.c b/src/rescue.c index 5ca0350..2d9df9e 100644 --- a/src/rescue.c +++ b/src/rescue.c @@ -31,7 +31,7 @@ #include "random.h" #include "crypto_utils.h" #include "usb.h" -#include "audit.h" +#include "picokeys_plugin_api.h" #include "signal.h" #ifdef PICO_PLATFORM @@ -259,7 +259,6 @@ static int cmd_write(void) { #endif } else if (p1 == 0x2) { // SET TIME - audit_entry_set_current_event(AUDIT_EVT_SET_RTC); time_t tv_sec = 0; if (p2 != 0x1 && p2 != 0x2) { return SW_INCORRECT_P1P2(); @@ -408,10 +407,10 @@ static int cmd_reboot_bootsel(void) { #define INS_REBOOT_BOOTSEL 0x1F static const cmd_t cmds[] = { - { INS_KEYDEV_SIGN, cmd_keydev_sign, CMD_FLAG_AUDIT_LOG }, - { INS_WRITE, cmd_write, CMD_FLAG_AUDIT_LOG | CMD_FLAG_CRITICAL }, + { INS_KEYDEV_SIGN, cmd_keydev_sign, CMD_FLAG_NOTIFY_PLUGIN }, + { INS_WRITE, cmd_write, CMD_FLAG_NOTIFY_PLUGIN | CMD_FLAG_SECURITY_SENSITIVE }, #if defined(PICO_RP2350) || defined(ESP_PLATFORM) - { INS_SECURE, cmd_secure, CMD_FLAG_AUDIT_LOG | CMD_FLAG_CRITICAL }, + { INS_SECURE, cmd_secure, CMD_FLAG_NOTIFY_PLUGIN | CMD_FLAG_SECURITY_SENSITIVE }, #endif { INS_READ, cmd_read, CMD_FLAG_NONE }, #ifdef PICO_PLATFORM @@ -427,21 +426,26 @@ static int rescue_process_apdu(void) { } for (const cmd_t *cmd = cmds; cmd->ins != 0x00; cmd++) { if (cmd->ins == INS(apdu)) { - audit_entry_set_current_event(AUDIT_EVT_APP_EVT | INS(apdu)); - audit_entry_set_current_object(make_uint16_be(P1(apdu), P2(apdu))); int r = cmd->cmd_handler(); - if (cmd->flags & CMD_FLAG_AUDIT_LOG) { - if (cmd->flags & CMD_FLAG_CRITICAL) { - audit_entry_set_current_flags(AUDIT_EF_CRITICAL); - } - audit_log_current_entry_with_result(r); + if (cmd->flags & CMD_FLAG_NOTIFY_PLUGIN) { + pk_plugin_notify_command( + PK_PLUGIN_EVENT_SOURCE_CORE, + INS(apdu), + make_uint16_be(P1(apdu), P2(apdu)), + (cmd->flags & CMD_FLAG_SECURITY_SENSITIVE) + ? PK_PLUGIN_EVENT_FLAG_SECURITY_SENSITIVE + : PK_PLUGIN_EVENT_FLAG_NONE, + r); } return r; } } int ret = signal_emit(SIGNAL_RESCUE_NOT_FOUND); - if (ret != 0) { + if (ret == PICOKEYS_ERR_FILE_NOT_FOUND) { return SW_INS_NOT_SUPPORTED(); } + if (ret != PICOKEYS_OK) { + return ret; + } return SW_OK(); -} \ No newline at end of file +}