Add bounded object-policy evaluation to the SDK

Validate operations, authorization facts, namespaces and session epochs with default-deny tests

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
This commit is contained in:
Pol Henarejos
2026-07-17 22:14:38 +02:00
parent 5e2c0336d1
commit 5f4032fdfa
3 changed files with 186 additions and 0 deletions
+1
View File
@@ -318,6 +318,7 @@ list(APPEND PICOKEYS_SOURCES
${CMAKE_CURRENT_LIST_DIR}/src/fs/object_store.c
${CMAKE_CURRENT_LIST_DIR}/src/fs/object_store_txn.c
${CMAKE_CURRENT_LIST_DIR}/src/fs/object_container.c
${CMAKE_CURRENT_LIST_DIR}/src/fs/object_policy.c
${CMAKE_CURRENT_LIST_DIR}/src/fs/object_crypto_provider.c
${CMAKE_CURRENT_LIST_DIR}/src/fs/flash.c
${CMAKE_CURRENT_LIST_DIR}/src/fs/low_flash.c
+114
View File
@@ -0,0 +1,114 @@
/*
* 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 "object_policy.h"
#include <mbedtls/sha256.h>
#define FILE_OBJECT_POLICY_RULE_OPERATION_OFFSET 0u
#define FILE_OBJECT_POLICY_RULE_REQUIRED_FACTS_OFFSET 2u
#define FILE_OBJECT_POLICY_RULE_FORBIDDEN_FACTS_OFFSET 6u
#define FILE_OBJECT_POLICY_RULE_CALLER_NAMESPACE_OFFSET 10u
#define FILE_OBJECT_POLICY_RULE_FLAGS_OFFSET 12u
static bool file_object_policy_rule_valid(const uint8_t *rule) {
uint16_t operations = get_uint16_be(rule + FILE_OBJECT_POLICY_RULE_OPERATION_OFFSET);
uint32_t required_facts = get_uint32_be(rule + FILE_OBJECT_POLICY_RULE_REQUIRED_FACTS_OFFSET);
uint32_t forbidden_facts = get_uint32_be(rule + FILE_OBJECT_POLICY_RULE_FORBIDDEN_FACTS_OFFSET);
uint16_t caller_namespace = get_uint16_be(rule + FILE_OBJECT_POLICY_RULE_CALLER_NAMESPACE_OFFSET);
uint16_t flags = get_uint16_be(rule + FILE_OBJECT_POLICY_RULE_FLAGS_OFFSET);
if (operations == 0 || (operations & ~FILE_OBJECT_OPERATION_MASK) != 0) {
return false;
}
if (((required_facts | forbidden_facts) & ~FILE_OBJECT_FACT_MASK) != 0 || (required_facts & forbidden_facts) != 0) {
return false;
}
if (caller_namespace == 0 || (flags & ~FILE_OBJECT_POLICY_RULE_FLAG_MASK) != 0) {
return false;
}
return true;
}
int file_object_policy_validate(const uint8_t *policy, size_t policy_size) {
if (!policy) {
return PICOKEYS_ERR_NULL_PARAM;
}
if (policy_size < FILE_OBJECT_POLICY_HEADER_SIZE || policy[0] != FILE_OBJECT_POLICY_FORMAT_VERSION || policy[1] > FILE_OBJECT_POLICY_MAX_RULES) {
return PICOKEYS_WRONG_DATA;
}
size_t expected_size = FILE_OBJECT_POLICY_HEADER_SIZE + (size_t)policy[1] * FILE_OBJECT_POLICY_RULE_SIZE;
if (policy_size != expected_size) {
return PICOKEYS_WRONG_LENGTH;
}
for (uint8_t i = 0; i < policy[1]; i++) {
const uint8_t *rule = policy + FILE_OBJECT_POLICY_HEADER_SIZE + (size_t)i * FILE_OBJECT_POLICY_RULE_SIZE;
if (!file_object_policy_rule_valid(rule)) {
return PICOKEYS_WRONG_DATA;
}
}
return PICOKEYS_OK;
}
int file_object_policy_hash(const uint8_t *policy, size_t policy_size, uint8_t hash[FILE_OBJECT_POLICY_HASH_SIZE]) {
if (!hash) {
return PICOKEYS_ERR_NULL_PARAM;
}
memset(hash, 0, FILE_OBJECT_POLICY_HASH_SIZE);
int r = file_object_policy_validate(policy, policy_size);
if (r != PICOKEYS_OK) {
return r;
}
uint8_t full_hash[32];
if (mbedtls_sha256(policy, policy_size, full_hash, 0) != 0) {
memset(full_hash, 0, sizeof(full_hash));
return PICOKEYS_EXEC_ERROR;
}
memcpy(hash, full_hash, FILE_OBJECT_POLICY_HASH_SIZE);
memset(full_hash, 0, sizeof(full_hash));
return PICOKEYS_OK;
}
bool file_object_policy_authorize(const uint8_t *policy, size_t policy_size, uint16_t operation, const file_object_authorization_context_t *context) {
if (file_object_policy_validate(policy, policy_size) != PICOKEYS_OK || !context) {
return false;
}
if (operation == 0 || (operation & ~FILE_OBJECT_OPERATION_MASK) != 0 || (operation & (operation - 1u)) != 0) {
return false;
}
if (context->caller_namespace == 0 || context->caller_namespace == FILE_OBJECT_POLICY_NAMESPACE_ANY || context->session_epoch == 0 || context->session_epoch != context->facts_epoch || (context->facts & ~FILE_OBJECT_FACT_MASK) != 0) {
return false;
}
for (uint8_t i = 0; i < policy[1]; i++) {
const uint8_t *rule = policy + FILE_OBJECT_POLICY_HEADER_SIZE + (size_t)i * FILE_OBJECT_POLICY_RULE_SIZE;
uint16_t operations = get_uint16_be(rule + FILE_OBJECT_POLICY_RULE_OPERATION_OFFSET);
uint32_t required_facts = get_uint32_be(rule + FILE_OBJECT_POLICY_RULE_REQUIRED_FACTS_OFFSET);
uint32_t forbidden_facts = get_uint32_be(rule + FILE_OBJECT_POLICY_RULE_FORBIDDEN_FACTS_OFFSET);
uint16_t caller_namespace = get_uint16_be(rule + FILE_OBJECT_POLICY_RULE_CALLER_NAMESPACE_OFFSET);
if ((operations & operation) != 0 && (caller_namespace == FILE_OBJECT_POLICY_NAMESPACE_ANY || caller_namespace == context->caller_namespace) && (context->facts & required_facts) == required_facts && (context->facts & forbidden_facts) == 0) {
return true;
}
}
return false;
}
+71
View File
@@ -0,0 +1,71 @@
/*
* 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 _OBJECT_POLICY_H_
#define _OBJECT_POLICY_H_
#include "object_container.h"
#define FILE_OBJECT_POLICY_FORMAT_VERSION 1u
#define FILE_OBJECT_POLICY_HEADER_SIZE 2u
#define FILE_OBJECT_POLICY_RULE_SIZE 14u
#define FILE_OBJECT_POLICY_MAX_RULES 8u
#define FILE_OBJECT_POLICY_MAX_SIZE (FILE_OBJECT_POLICY_HEADER_SIZE + FILE_OBJECT_POLICY_MAX_RULES * FILE_OBJECT_POLICY_RULE_SIZE)
#define FILE_OBJECT_POLICY_NAMESPACE_ANY 0xffffu
#define FILE_OBJECT_OPERATION_READ 0x0001u
#define FILE_OBJECT_OPERATION_ENUMERATE 0x0002u
#define FILE_OBJECT_OPERATION_USE 0x0004u
#define FILE_OBJECT_OPERATION_SIGN 0x0008u
#define FILE_OBJECT_OPERATION_DECRYPT 0x0010u
#define FILE_OBJECT_OPERATION_DERIVE 0x0020u
#define FILE_OBJECT_OPERATION_WRAP 0x0040u
#define FILE_OBJECT_OPERATION_UNWRAP 0x0080u
#define FILE_OBJECT_OPERATION_EXPORT 0x0100u
#define FILE_OBJECT_OPERATION_UPDATE 0x0200u
#define FILE_OBJECT_OPERATION_DELETE 0x0400u
#define FILE_OBJECT_OPERATION_CHANGE_POLICY 0x0800u
#define FILE_OBJECT_OPERATION_ADMIN_RECOVERY 0x1000u
#define FILE_OBJECT_OPERATION_MASK 0x1fffu
#define FILE_OBJECT_FACT_USER_PRESENCE 0x00000001u
#define FILE_OBJECT_FACT_USER_VERIFICATION 0x00000002u
#define FILE_OBJECT_FACT_APP_PIN 0x00000004u
#define FILE_OBJECT_FACT_ADMIN 0x00000008u
#define FILE_OBJECT_FACT_SECURE_MESSAGING 0x00000010u
#define FILE_OBJECT_FACT_INTERNAL_FIRMWARE 0x00000020u
#define FILE_OBJECT_FACT_OWNING_APPLICATION 0x00000040u
#define FILE_OBJECT_FACT_PHYSICAL_CONFIRMATION 0x00000080u
#define FILE_OBJECT_FACT_DEVICE_STATE 0x00000100u
#define FILE_OBJECT_FACT_ONE_TIME_AUTHORIZATION 0x00000200u
#define FILE_OBJECT_FACT_SESSION_BOUND 0x00000400u
#define FILE_OBJECT_FACT_MASK 0x000007ffu
#define FILE_OBJECT_POLICY_RULE_FLAG_MASK 0x0000u
typedef struct file_object_authorization_context {
uint32_t facts;
uint32_t session_epoch;
uint32_t facts_epoch;
uint16_t caller_namespace;
} file_object_authorization_context_t;
int file_object_policy_validate(const uint8_t *policy, size_t policy_size);
int file_object_policy_hash(const uint8_t *policy, size_t policy_size, uint8_t hash[FILE_OBJECT_POLICY_HASH_SIZE]);
bool file_object_policy_authorize(const uint8_t *policy, size_t policy_size, uint16_t operation, const file_object_authorization_context_t *context);
#endif // _OBJECT_POLICY_H_