From d2ebbb2a4492c36d34bd884dfe5c6be9f66cb76f Mon Sep 17 00:00:00 2001 From: Pol Henarejos Date: Fri, 17 Jul 2026 23:16:32 +0200 Subject: [PATCH] Enforce HSM object policy when opening v1 private key material Require verified PIN, SO/admin, or isolated firmware authorization without migrating legacy keys Signed-off-by: Pol Henarejos --- CMakeLists.txt | 1 + pico-keys-sdk | 2 +- src/hsm/kek.c | 4 ++++ src/hsm/object_authorization.c | 23 ++++++++++++++++++++++ src/hsm/object_authorization.h | 4 ++++ tests/hsm_object_authorization_test.c | 28 +++++++++++++++++++++++++++ 6 files changed, 61 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b4a0bdd..3d1150b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -158,6 +158,7 @@ if(NOT ESP_PLATFORM) add_test(NAME hsm_object_provider_test COMMAND hsm_object_provider_test) add_executable(hsm_object_authorization_test + ${CMAKE_CURRENT_LIST_DIR}/pico-keys-sdk/src/fs/object_policy.c ${CMAKE_CURRENT_LIST_DIR}/src/hsm/object_authorization.c ${CMAKE_CURRENT_LIST_DIR}/tests/hsm_object_authorization_test.c ) diff --git a/pico-keys-sdk b/pico-keys-sdk index 5f4032f..b68cc7c 160000 --- a/pico-keys-sdk +++ b/pico-keys-sdk @@ -1 +1 @@ -Subproject commit 5f4032fdfadd84e2516e1af0f5f2773a59f6cdf5 +Subproject commit b68cc7cfb6b77012698fbaefee756d1b1a522d04 diff --git a/src/hsm/kek.c b/src/hsm/kek.c index 81f466e..ca73e1f 100644 --- a/src/hsm/kek.c +++ b/src/hsm/kek.c @@ -22,6 +22,7 @@ #endif #include "kek.h" #include "crypto_utils.h" +#include "object_authorization.h" #include "object_store.h" #include "random.h" #include "mbedtls/md.h" @@ -343,6 +344,9 @@ int mkek_load_file(file_t *file, uint8_t *data, uint16_t *len) { } bool object_file = (file->fid >> 8) == HSM_OBJECT_PREFIX; + if (object_file && !hsm_object_authorization_key_operation(FILE_OBJECT_OPERATION_USE, false)) { + return PICOKEYS_NO_LOGIN; + } uint32_t stored_len = file_get_size(file); file_object_handle_t object_handle = FILE_OBJECT_INVALID_HANDLE; if (object_file) { diff --git a/src/hsm/object_authorization.c b/src/hsm/object_authorization.c index e292d72..8d6ed39 100644 --- a/src/hsm/object_authorization.c +++ b/src/hsm/object_authorization.c @@ -23,6 +23,14 @@ static uint32_t hsm_object_session_epoch = 1; static bool hsm_object_secure_messaging; +// Private-key operations require UV plus a user/admin MKEK session; firmware uses an isolated rule. +static const uint8_t hsm_object_key_policy[] = { + FILE_OBJECT_POLICY_FORMAT_VERSION, 3, + 0x01, 0x7c, 0x00, 0x00, 0x04, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x01, 0x7c, 0x00, 0x00, 0x04, 0x4a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x01, 0x7c, 0x00, 0x00, 0x04, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00 +}; + void hsm_object_authorization_session_invalidate(void) { hsm_object_secure_messaging = false; hsm_object_session_epoch++; @@ -39,6 +47,13 @@ void hsm_object_authorization_command_set_secure_messaging(bool active) { hsm_object_secure_messaging = active; } +const uint8_t *hsm_object_authorization_key_policy(size_t *policy_size) { + if (policy_size) { + *policy_size = sizeof(hsm_object_key_policy); + } + return hsm_object_key_policy; +} + int hsm_object_authorization_context_build(bool internal_firmware, file_object_authorization_context_t *context) { if (!context) { return PICOKEYS_ERR_NULL_PARAM; @@ -69,3 +84,11 @@ int hsm_object_authorization_context_build(bool internal_firmware, file_object_a context->caller_namespace = HSM_OBJECT_NAMESPACE; return PICOKEYS_OK; } + +bool hsm_object_authorization_key_operation(uint16_t operation, bool internal_firmware) { + file_object_authorization_context_t context; + if (hsm_object_authorization_context_build(internal_firmware, &context) != PICOKEYS_OK) { + return false; + } + return file_object_policy_authorize(hsm_object_key_policy, sizeof(hsm_object_key_policy), operation, &context); +} diff --git a/src/hsm/object_authorization.h b/src/hsm/object_authorization.h index 752062b..32adf53 100644 --- a/src/hsm/object_authorization.h +++ b/src/hsm/object_authorization.h @@ -20,7 +20,11 @@ #include "object_policy.h" +#define HSM_OBJECT_KEY_POLICY_ID 0x0101u + int hsm_object_authorization_context_build(bool internal_firmware, file_object_authorization_context_t *context); +const uint8_t *hsm_object_authorization_key_policy(size_t *policy_size); +bool hsm_object_authorization_key_operation(uint16_t operation, bool internal_firmware); void hsm_object_authorization_session_invalidate(void); uint32_t hsm_object_authorization_session_epoch(void); void hsm_object_authorization_command_set_secure_messaging(bool active); diff --git a/tests/hsm_object_authorization_test.c b/tests/hsm_object_authorization_test.c index 827748a..eb5b7dc 100644 --- a/tests/hsm_object_authorization_test.c +++ b/tests/hsm_object_authorization_test.c @@ -108,12 +108,40 @@ static void test_epoch_invalidation(void) { assert(after.facts_epoch == after.session_epoch); } +static void test_key_policy(void) { + size_t policy_size = 0; + const uint8_t *policy = hsm_object_authorization_key_policy(&policy_size); + + assert(policy != NULL); + assert(file_object_policy_validate(policy, policy_size) == PICOKEYS_OK); + + test_state_reset(); + assert(!hsm_object_authorization_key_operation(FILE_OBJECT_OPERATION_USE, false)); + + isUserAuthenticated = true; + assert(!hsm_object_authorization_key_operation(FILE_OBJECT_OPERATION_USE, false)); + + has_session_pin = true; + assert(hsm_object_authorization_key_operation(FILE_OBJECT_OPERATION_USE, false)); + assert(hsm_object_authorization_key_operation(FILE_OBJECT_OPERATION_SIGN, false)); + assert(!hsm_object_authorization_key_operation(FILE_OBJECT_OPERATION_READ, false)); + + has_session_pin = false; + has_session_sopin = true; + assert(hsm_object_authorization_key_operation(FILE_OBJECT_OPERATION_EXPORT, false)); + + test_state_reset(); + assert(hsm_object_authorization_key_operation(FILE_OBJECT_OPERATION_DERIVE, true)); + assert(!hsm_object_authorization_key_operation(FILE_OBJECT_OPERATION_READ, true)); +} + int main(void) { test_unauthenticated_context(); test_authenticated_context(); test_secure_messaging_context(); test_internal_context(); test_epoch_invalidation(); + test_key_policy(); assert(hsm_object_authorization_context_build(false, NULL) == PICOKEYS_ERR_NULL_PARAM); puts("hsm_object_authorization_test: OK"); return 0;