Add more api functions.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
This commit is contained in:
Pol Henarejos
2026-07-16 16:11:11 +02:00
parent 2776b39a49
commit 8ee7be69f3
9 changed files with 196 additions and 134 deletions
+4 -5
View File
@@ -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)
+3 -3
View File
@@ -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 {
-39
View File
@@ -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 <https://www.gnu.org/licenses/>.
*/
#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);
}
-64
View File
@@ -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 <https://www.gnu.org/licenses/>.
*/
#ifndef _AUDIT_H_
#define _AUDIT_H_
#include <stdint.h>
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_
+3 -4
View File
@@ -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)
+3 -3
View File
@@ -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;
+73 -2
View File
@@ -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
+92
View File
@@ -30,6 +30,7 @@
#include <string.h>
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 <windows.h>
@@ -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);
}
+18 -14
View File
@@ -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();
}
}