mirror of
https://github.com/polhenarejos/pico-keys-sdk.git
synced 2026-08-30 08:33:22 +01:00
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:
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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_
|
||||
Reference in New Issue
Block a user