From 2b9fa33fe21b3e490e88bc2ffccbf2bb262b5b10 Mon Sep 17 00:00:00 2001 From: Athul Mallappallil Date: Thu, 23 Jul 2026 13:04:44 +0200 Subject: [PATCH 01/25] Make shared deployment loader and writer --- .../slot/deployment => common/storage}/BUILD | 16 +-- .../common/storage/deployment_descriptor.cpp | 19 +++ .../common/storage/deployment_descriptor.hpp | 74 +++++++++++ .../storage}/deployment_path_utils.hpp | 20 +-- .../common/storage/i_deployment_loader.hpp | 42 ++++++ .../common/storage/i_deployment_writer.hpp | 41 ++++++ .../storage/kv/kv_deployment_loader.cpp | 84 ++++++++++++ .../storage/kv/kv_deployment_loader.hpp | 54 ++++++++ .../storage}/kv/kv_deployment_writer.cpp | 34 +++-- .../storage/kv/kv_deployment_writer.hpp | 41 ++++++ score/crypto/src/daemon/key_management/BUILD | 4 +- .../slot/deployment/i_deployment_loader.hpp | 54 -------- .../slot/deployment/i_deployment_writer.hpp | 55 -------- .../deployment/kv/kv_deployment_loader.cpp | 120 ------------------ .../deployment/kv/kv_deployment_loader.hpp | 55 -------- .../deployment/kv/kv_deployment_writer.hpp | 45 ------- .../key_management/slot/deployment_loader.cpp | 17 ++- .../key_management/slot/deployment_writer.cpp | 11 +- 18 files changed, 406 insertions(+), 380 deletions(-) rename score/crypto/src/daemon/{key_management/slot/deployment => common/storage}/BUILD (68%) create mode 100644 score/crypto/src/daemon/common/storage/deployment_descriptor.cpp create mode 100644 score/crypto/src/daemon/common/storage/deployment_descriptor.hpp rename score/crypto/src/daemon/{key_management/slot/deployment => common/storage}/deployment_path_utils.hpp (59%) create mode 100644 score/crypto/src/daemon/common/storage/i_deployment_loader.hpp create mode 100644 score/crypto/src/daemon/common/storage/i_deployment_writer.hpp create mode 100644 score/crypto/src/daemon/common/storage/kv/kv_deployment_loader.cpp create mode 100644 score/crypto/src/daemon/common/storage/kv/kv_deployment_loader.hpp rename score/crypto/src/daemon/{key_management/slot/deployment => common/storage}/kv/kv_deployment_writer.cpp (62%) create mode 100644 score/crypto/src/daemon/common/storage/kv/kv_deployment_writer.hpp delete mode 100644 score/crypto/src/daemon/key_management/slot/deployment/i_deployment_loader.hpp delete mode 100644 score/crypto/src/daemon/key_management/slot/deployment/i_deployment_writer.hpp delete mode 100644 score/crypto/src/daemon/key_management/slot/deployment/kv/kv_deployment_loader.cpp delete mode 100644 score/crypto/src/daemon/key_management/slot/deployment/kv/kv_deployment_loader.hpp delete mode 100644 score/crypto/src/daemon/key_management/slot/deployment/kv/kv_deployment_writer.hpp diff --git a/score/crypto/src/daemon/key_management/slot/deployment/BUILD b/score/crypto/src/daemon/common/storage/BUILD similarity index 68% rename from score/crypto/src/daemon/key_management/slot/deployment/BUILD rename to score/crypto/src/daemon/common/storage/BUILD index 4039b8e1a..a0f30c38e 100644 --- a/score/crypto/src/daemon/key_management/slot/deployment/BUILD +++ b/score/crypto/src/daemon/common/storage/BUILD @@ -13,12 +13,13 @@ load("@rules_cc//cc:cc_library.bzl", "cc_library") -# Header-only: interfaces + shared path validation utility. -# No format-specific deps — adding a new format (json, flatbuffer, ...) only -# requires adding a new cc_library target in this file; nothing else changes. cc_library( name = "deployment_iface", + srcs = [ + "deployment_descriptor.cpp", + ], hdrs = [ + "deployment_descriptor.hpp", "deployment_path_utils.hpp", "i_deployment_loader.hpp", "i_deployment_writer.hpp", @@ -27,13 +28,9 @@ cc_library( deps = [ "//score/crypto/src/common:common_types", "//score/crypto/src/daemon/common", - "//score/crypto/src/daemon/key_management:key_management_headers", ], ) -# KV format implementation. Stdlib-only — no extra library deps required. -# To add a new format, create an analogous target here (e.g. json_deployment) -# and add it as a dep to //score/crypto/src/daemon/key_management:key_management. cc_library( name = "kv_deployment", srcs = [ @@ -45,5 +42,8 @@ cc_library( "kv/kv_deployment_writer.hpp", ], visibility = ["//:__subpackages__"], - deps = [":deployment_iface"], + deps = [ + ":deployment_iface", + "@score_baselibs//score/mw/log", + ], ) diff --git a/score/crypto/src/daemon/common/storage/deployment_descriptor.cpp b/score/crypto/src/daemon/common/storage/deployment_descriptor.cpp new file mode 100644 index 000000000..1c2598718 --- /dev/null +++ b/score/crypto/src/daemon/common/storage/deployment_descriptor.cpp @@ -0,0 +1,19 @@ +/******************************************************************************** + * Copyright (c) 2026 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ + +#include "score/crypto/src/daemon/common/storage/deployment_descriptor.hpp" + +namespace score::crypto::daemon::common::storage +{ +const std::string DeploymentDescriptor::kEmptyString{}; +} // namespace score::crypto::daemon::common::storage diff --git a/score/crypto/src/daemon/common/storage/deployment_descriptor.hpp b/score/crypto/src/daemon/common/storage/deployment_descriptor.hpp new file mode 100644 index 000000000..4edcb1e4d --- /dev/null +++ b/score/crypto/src/daemon/common/storage/deployment_descriptor.hpp @@ -0,0 +1,74 @@ +/******************************************************************************** + * Copyright (c) 2026 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ + +#ifndef SCORE_CRYPTO_SRC_DAEMON_COMMON_STORAGE_DEPLOYMENT_DESCRIPTOR_HPP +#define SCORE_CRYPTO_SRC_DAEMON_COMMON_STORAGE_DEPLOYMENT_DESCRIPTOR_HPP + +#include +#include + +namespace score::crypto::daemon::common::storage +{ + +/// @brief Generic section-based key-value deployment descriptor. +/// +/// Represents the parsed content of a deployment descriptor file as a nested map: +/// section name -> { key -> value } +/// +/// This is the generic in-memory representation. Specific components +/// (cert_management, future components) interpret section names and keys +/// according to their own schema. +struct DeploymentDescriptor +{ + /// @brief Section name -> (key -> value) map. + std::unordered_map> sections; + + /// @brief Get a value from a section, returning default_val if absent. + [[nodiscard]] const std::string& Get(const std::string& section, + const std::string& key, + const std::string& default_val = kEmptyString) const noexcept + { + const auto sit = sections.find(section); + if (sit == sections.end()) + { + return default_val; + } + const auto kit = sit->second.find(key); + return (kit != sit->second.end()) ? kit->second : default_val; + } + + /// @brief True if the named section is present (even if empty). + [[nodiscard]] bool HasSection(const std::string& section) const noexcept + { + return sections.count(section) > 0U; + } + + /// @brief Set a key in a section (creates section if absent). + void Set(const std::string& section, const std::string& key, const std::string& value) + { + sections[section][key] = value; + } + + /// @brief Remove the named section entirely. + void RemoveSection(const std::string& section) + { + sections.erase(section); + } + + private: + static const std::string kEmptyString; +}; + +} // namespace score::crypto::daemon::common::storage + +#endif // SCORE_CRYPTO_SRC_DAEMON_COMMON_STORAGE_DEPLOYMENT_DESCRIPTOR_HPP diff --git a/score/crypto/src/daemon/key_management/slot/deployment/deployment_path_utils.hpp b/score/crypto/src/daemon/common/storage/deployment_path_utils.hpp similarity index 59% rename from score/crypto/src/daemon/key_management/slot/deployment/deployment_path_utils.hpp rename to score/crypto/src/daemon/common/storage/deployment_path_utils.hpp index 5f7af12b6..2ece49a06 100644 --- a/score/crypto/src/daemon/key_management/slot/deployment/deployment_path_utils.hpp +++ b/score/crypto/src/daemon/common/storage/deployment_path_utils.hpp @@ -11,42 +11,34 @@ * SPDX-License-Identifier: Apache-2.0 ********************************************************************************/ -#ifndef SCORE_CRYPTO_SRC_DAEMON_KEY_MANAGEMENT_SLOT_DEPLOYMENT_DEPLOYMENT_PATH_UTILS_HPP -#define SCORE_CRYPTO_SRC_DAEMON_KEY_MANAGEMENT_SLOT_DEPLOYMENT_DEPLOYMENT_PATH_UTILS_HPP +#ifndef SCORE_CRYPTO_SRC_DAEMON_COMMON_STORAGE_DEPLOYMENT_PATH_UTILS_HPP +#define SCORE_CRYPTO_SRC_DAEMON_COMMON_STORAGE_DEPLOYMENT_PATH_UTILS_HPP #include -namespace score::crypto::daemon::key_management +namespace score::crypto::daemon::common::storage { /// @brief Returns true if the path is absolute and contains no ".." path traversal components. -/// -/// Used as a single shared security pre-check by DeploymentLoaderFactory and -/// DeploymentWriterFactory before dispatching to a format-specific implementation. -/// Centralises path validation so it is not duplicated across every format class. [[nodiscard]] inline bool IsDeploymentPathSafe(const std::string& path) noexcept { if (path.empty()) { return false; } - - // Require absolute path (Unix: starts with '/'). const bool is_absolute = (path[0] == '/') || (path.size() >= 3U && path[1] == ':'); if (!is_absolute) { return false; } - - // Reject path traversal: ".." as a standalone component. if (path.find("..") != std::string::npos) { return false; } - return true; } -} // namespace score::crypto::daemon::key_management +} // namespace score::crypto::daemon::common::storage + -#endif // SCORE_CRYPTO_SRC_DAEMON_KEY_MANAGEMENT_SLOT_DEPLOYMENT_DEPLOYMENT_PATH_UTILS_HPP +#endif // SCORE_CRYPTO_SRC_DAEMON_COMMON_STORAGE_DEPLOYMENT_PATH_UTILS_HPP diff --git a/score/crypto/src/daemon/common/storage/i_deployment_loader.hpp b/score/crypto/src/daemon/common/storage/i_deployment_loader.hpp new file mode 100644 index 000000000..917d67dfa --- /dev/null +++ b/score/crypto/src/daemon/common/storage/i_deployment_loader.hpp @@ -0,0 +1,42 @@ +/******************************************************************************** + * Copyright (c) 2026 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ + +#ifndef SCORE_CRYPTO_SRC_DAEMON_COMMON_STORAGE_I_DEPLOYMENT_LOADER_HPP +#define SCORE_CRYPTO_SRC_DAEMON_COMMON_STORAGE_I_DEPLOYMENT_LOADER_HPP + +#include "score/crypto/src/common/types.hpp" +#include "score/crypto/src/daemon/common/daemon_error.hpp" +#include "score/crypto/src/daemon/common/storage/deployment_descriptor.hpp" + +#include + +namespace score::crypto::daemon::common::storage +{ + +/// @brief Interface for format-specific deployment descriptor loaders. +/// +/// Each concrete implementation handles exactly one serialization format. +/// Path safety pre-checks are performed by the factory before calling Load(). +class IDeploymentLoader +{ + public: + virtual ~IDeploymentLoader() = default; + + /// @brief Load a DeploymentDescriptor from the given (pre-validated) path. + [[nodiscard]] virtual score::crypto::Expected + Load(const std::string& path) = 0; +}; + +} // namespace score::crypto::daemon::common::storage + +#endif // SCORE_CRYPTO_SRC_DAEMON_COMMON_STORAGE_I_DEPLOYMENT_LOADER_HPP diff --git a/score/crypto/src/daemon/common/storage/i_deployment_writer.hpp b/score/crypto/src/daemon/common/storage/i_deployment_writer.hpp new file mode 100644 index 000000000..01cc65a3e --- /dev/null +++ b/score/crypto/src/daemon/common/storage/i_deployment_writer.hpp @@ -0,0 +1,41 @@ +/******************************************************************************** + * Copyright (c) 2026 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ + +#ifndef SCORE_CRYPTO_SRC_DAEMON_COMMON_STORAGE_I_DEPLOYMENT_WRITER_HPP +#define SCORE_CRYPTO_SRC_DAEMON_COMMON_STORAGE_I_DEPLOYMENT_WRITER_HPP + +#include "score/crypto/src/common/types.hpp" +#include "score/crypto/src/daemon/common/daemon_error.hpp" +#include "score/crypto/src/daemon/common/storage/deployment_descriptor.hpp" + +#include +#include + +namespace score::crypto::daemon::common::storage +{ + +/// @brief Interface for format-specific deployment descriptor writers. +class IDeploymentWriter +{ + public: + virtual ~IDeploymentWriter() = default; + + /// @brief Write a DeploymentDescriptor to the given (pre-validated) path. + [[nodiscard]] virtual score::crypto::Expected Write( + const std::string& path, + const DeploymentDescriptor& descriptor) = 0; +}; + +} // namespace score::crypto::daemon::common::storage + +#endif // SCORE_CRYPTO_SRC_DAEMON_COMMON_STORAGE_I_DEPLOYMENT_WRITER_HPP diff --git a/score/crypto/src/daemon/common/storage/kv/kv_deployment_loader.cpp b/score/crypto/src/daemon/common/storage/kv/kv_deployment_loader.cpp new file mode 100644 index 000000000..eda2e4204 --- /dev/null +++ b/score/crypto/src/daemon/common/storage/kv/kv_deployment_loader.cpp @@ -0,0 +1,84 @@ +/******************************************************************************** + * Copyright (c) 2026 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ + +#include "score/crypto/src/daemon/common/storage/kv/kv_deployment_loader.hpp" + +#include "score/mw/log/logging.h" + +#include +#include +#include + +namespace score::crypto::daemon::common::storage +{ + +namespace +{ + +[[nodiscard]] std::string Trim(std::string_view sv) noexcept +{ + const auto start = sv.find_first_not_of(" \t\r\n"); + if (start == std::string_view::npos) + { + return {}; + } + const auto end = sv.find_last_not_of(" \t\r\n"); + return std::string{sv.substr(start, end - start + 1U)}; +} + +} // namespace + +score::crypto::Expected KvDeploymentLoader::Load( + const std::string& path) +{ + std::ifstream file(path); + if (!file.is_open()) + { + score::mw::log::LogError() << kLogPrefix << "Cannot open: " << path; + return score::crypto::make_unexpected(score::crypto::daemon::common::DaemonErrorCode::kInternalError); + } + + DeploymentDescriptor descriptor; + std::string current_section; + std::string line; + + while (std::getline(file, line)) + { + const std::string trimmed = Trim(line); + if (trimmed.empty() || trimmed[0] == '#') + { + continue; + } + if (trimmed.front() == '[' && trimmed.back() == ']') + { + current_section = Trim(trimmed.substr(1U, trimmed.size() - 2U)); + continue; + } + if (current_section.empty()) + { + continue; + } + const auto eq_pos = trimmed.find('='); + if (eq_pos == std::string::npos) + { + continue; + } + const std::string key = Trim(trimmed.substr(0U, eq_pos)); + const std::string value = Trim(trimmed.substr(eq_pos + 1U)); + descriptor.sections[current_section][key] = value; + } + + return descriptor; +} + +} // namespace score::crypto::daemon::common::storage diff --git a/score/crypto/src/daemon/common/storage/kv/kv_deployment_loader.hpp b/score/crypto/src/daemon/common/storage/kv/kv_deployment_loader.hpp new file mode 100644 index 000000000..7ecdbe64d --- /dev/null +++ b/score/crypto/src/daemon/common/storage/kv/kv_deployment_loader.hpp @@ -0,0 +1,54 @@ +/******************************************************************************** + * Copyright (c) 2026 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ + +#ifndef SCORE_CRYPTO_SRC_DAEMON_COMMON_STORAGE_KV_KV_DEPLOYMENT_LOADER_HPP +#define SCORE_CRYPTO_SRC_DAEMON_COMMON_STORAGE_KV_KV_DEPLOYMENT_LOADER_HPP + +#include "score/crypto/src/daemon/common/storage/i_deployment_loader.hpp" + +#include + +namespace score::crypto::daemon::common::storage +{ + +/// @brief Loads a DeploymentDescriptor from a key=value text file. +/// +/// File format: +/// @code +/// # comment +/// [section_name] +/// key = value +/// another_key = another_value +/// +/// [another_section] +/// foo = bar +/// @endcode +/// +/// - Lines starting with '#' are comments (ignored). +/// - Blank lines are ignored. +/// - Section headers switch the active section. +/// - Lines without '=' are silently skipped. +/// - Keys and values are whitespace-trimmed. +class KvDeploymentLoader final : public IDeploymentLoader +{ + public: + [[nodiscard]] score::crypto::Expected Load( + const std::string& path) override; + + private: + static constexpr std::string_view kLogPrefix = "[KV_DEPLOYMENT_LOADER_COMMON] "; +}; + +} // namespace score::crypto::daemon::common::storage + +#endif // SCORE_CRYPTO_SRC_DAEMON_COMMON_STORAGE_KV_KV_DEPLOYMENT_LOADER_HPP diff --git a/score/crypto/src/daemon/key_management/slot/deployment/kv/kv_deployment_writer.cpp b/score/crypto/src/daemon/common/storage/kv/kv_deployment_writer.cpp similarity index 62% rename from score/crypto/src/daemon/key_management/slot/deployment/kv/kv_deployment_writer.cpp rename to score/crypto/src/daemon/common/storage/kv/kv_deployment_writer.cpp index dd4f6a0bb..72d67a59f 100644 --- a/score/crypto/src/daemon/key_management/slot/deployment/kv/kv_deployment_writer.cpp +++ b/score/crypto/src/daemon/common/storage/kv/kv_deployment_writer.cpp @@ -11,46 +11,42 @@ * SPDX-License-Identifier: Apache-2.0 ********************************************************************************/ -#include "score/crypto/src/daemon/key_management/slot/deployment/kv/kv_deployment_writer.hpp" +#include "score/crypto/src/daemon/common/storage/kv/kv_deployment_writer.hpp" #include "score/mw/log/logging.h" -#include -#include +#include -namespace score::crypto::daemon::key_management +namespace score::crypto::daemon::common::storage { score::crypto::Expected KvDeploymentWriter::Write( const std::string& path, - const SlotDeploymentInfo& info) + const DeploymentDescriptor& descriptor) { std::ofstream file(path, std::ios::trunc); if (!file.is_open()) { - score::mw::log::LogError() << kLogPrefix << "Cannot open deployment descriptor for writing:" << path; - return score::crypto::make_unexpected(score::crypto::daemon::common::DaemonErrorCode::kInvalidArgument); - } - - file << "[metadata]\n"; - for (const auto& [key, value] : info.metadata) - { - file << key << '=' << value << '\n'; + score::mw::log::LogError() << kLogPrefix << "Cannot open for writing: " << path; + return score::crypto::make_unexpected(score::crypto::daemon::common::DaemonErrorCode::kInternalError); } - file << "\n[key]\n"; - for (const auto& [key, value] : info.key_properties) + for (const auto& [section, entries] : descriptor.sections) { - file << key << '=' << value << '\n'; + file << '[' << section << ']' << '\n'; + for (const auto& [key, value] : entries) + { + file << key << " = " << value << '\n'; + } + file << '\n'; } if (!file.good()) { - score::mw::log::LogError() << kLogPrefix << "Write error for deployment descriptor:" << path; + score::mw::log::LogError() << kLogPrefix << "Write failed for: " << path; return score::crypto::make_unexpected(score::crypto::daemon::common::DaemonErrorCode::kInternalError); } - return std::monostate{}; } -} // namespace score::crypto::daemon::key_management +} // namespace score::crypto::daemon::common::storage diff --git a/score/crypto/src/daemon/common/storage/kv/kv_deployment_writer.hpp b/score/crypto/src/daemon/common/storage/kv/kv_deployment_writer.hpp new file mode 100644 index 000000000..2ccb65420 --- /dev/null +++ b/score/crypto/src/daemon/common/storage/kv/kv_deployment_writer.hpp @@ -0,0 +1,41 @@ +/******************************************************************************** + * Copyright (c) 2026 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ + +#ifndef SCORE_CRYPTO_SRC_DAEMON_COMMON_STORAGE_KV_KV_DEPLOYMENT_WRITER_HPP +#define SCORE_CRYPTO_SRC_DAEMON_COMMON_STORAGE_KV_KV_DEPLOYMENT_WRITER_HPP + +#include "score/crypto/src/daemon/common/storage/i_deployment_writer.hpp" + +#include + +namespace score::crypto::daemon::common::storage +{ + +/// @brief Writes a DeploymentDescriptor to a key=value text file. +/// +/// Produces the same section/key=value format that KvDeploymentLoader can read back. +/// Existing file content is replaced (opened with std::ios::trunc). +class KvDeploymentWriter final : public IDeploymentWriter +{ + public: + [[nodiscard]] score::crypto::Expected Write( + const std::string& path, + const DeploymentDescriptor& descriptor) override; + + private: + static constexpr std::string_view kLogPrefix = "[KV_DEPLOYMENT_WRITER_COMMON] "; +}; + +} // namespace score::crypto::daemon::common::storage + +#endif // SCORE_CRYPTO_SRC_DAEMON_COMMON_STORAGE_KV_KV_DEPLOYMENT_WRITER_HPP diff --git a/score/crypto/src/daemon/key_management/BUILD b/score/crypto/src/daemon/key_management/BUILD index 09d5232e0..07dc910e1 100644 --- a/score/crypto/src/daemon/key_management/BUILD +++ b/score/crypto/src/daemon/key_management/BUILD @@ -108,11 +108,11 @@ cc_library( visibility = ["//:__subpackages__"], deps = [ ":key_management_headers", - "//score/crypto/src/api/common:crypto_common", "//score/crypto/src/daemon/common", + "//score/crypto/src/daemon/common/storage:kv_deployment", "//score/crypto/src/daemon/data_manager", - "//score/crypto/src/daemon/key_management/slot/deployment:kv_deployment", "//score/crypto/src/daemon/provider:provider_headers", "//score/crypto/src/daemon/provider:provider_manager", + "//score/crypto/src/api/common:crypto_common", ], ) diff --git a/score/crypto/src/daemon/key_management/slot/deployment/i_deployment_loader.hpp b/score/crypto/src/daemon/key_management/slot/deployment/i_deployment_loader.hpp deleted file mode 100644 index 0febd0acc..000000000 --- a/score/crypto/src/daemon/key_management/slot/deployment/i_deployment_loader.hpp +++ /dev/null @@ -1,54 +0,0 @@ -/******************************************************************************** - * Copyright (c) 2026 Contributors to the Eclipse Foundation - * - * See the NOTICE file(s) distributed with this work for additional - * information regarding copyright ownership. - * - * This program and the accompanying materials are made available under the - * terms of the Apache License Version 2.0 which is available at - * https://www.apache.org/licenses/LICENSE-2.0 - * - * SPDX-License-Identifier: Apache-2.0 - ********************************************************************************/ - -#ifndef SCORE_CRYPTO_SRC_DAEMON_KEY_MANAGEMENT_SLOT_DEPLOYMENT_I_DEPLOYMENT_LOADER_HPP -#define SCORE_CRYPTO_SRC_DAEMON_KEY_MANAGEMENT_SLOT_DEPLOYMENT_I_DEPLOYMENT_LOADER_HPP - -#include "score/crypto/src/common/types.hpp" -#include "score/crypto/src/daemon/common/daemon_error.hpp" -#include "score/crypto/src/daemon/key_management/interfaces/key_slot_config.hpp" - -#include - -namespace score::crypto::daemon::key_management -{ - -/// @brief Interface for format-specific deployment descriptor loaders. -/// -/// Each concrete implementation handles exactly one serialization format -/// (kv, json, flatbuffer, custom, ...). The path safety pre-check is -/// performed by DeploymentLoaderFactory *before* calling Load(), so -/// implementations can assume a valid, absolute, traversal-free path. -/// -/// ### Adding a new format -/// 1. Implement this interface in a new class (e.g., `JsonDeploymentLoader`). -/// 2. Place the class under `slot/deployment//`. -/// 3. Register it in `DeploymentLoaderFactory::Create()`. -/// No other files need to change. -class IDeploymentLoader -{ - public: - virtual ~IDeploymentLoader() = default; - - /// @brief Load a SlotDeploymentInfo from the given (pre-validated) path. - /// - /// @param path Absolute path to the deployment descriptor file. The caller - /// (factory) has already verified it is safe. - /// @return Parsed SlotDeploymentInfo on success, or DaemonErrorCode on failure. - [[nodiscard]] virtual score::crypto::Expected - Load(const std::string& path) = 0; -}; - -} // namespace score::crypto::daemon::key_management - -#endif // SCORE_CRYPTO_SRC_DAEMON_KEY_MANAGEMENT_SLOT_DEPLOYMENT_I_DEPLOYMENT_LOADER_HPP diff --git a/score/crypto/src/daemon/key_management/slot/deployment/i_deployment_writer.hpp b/score/crypto/src/daemon/key_management/slot/deployment/i_deployment_writer.hpp deleted file mode 100644 index 02aa2978d..000000000 --- a/score/crypto/src/daemon/key_management/slot/deployment/i_deployment_writer.hpp +++ /dev/null @@ -1,55 +0,0 @@ -/******************************************************************************** - * Copyright (c) 2026 Contributors to the Eclipse Foundation - * - * See the NOTICE file(s) distributed with this work for additional - * information regarding copyright ownership. - * - * This program and the accompanying materials are made available under the - * terms of the Apache License Version 2.0 which is available at - * https://www.apache.org/licenses/LICENSE-2.0 - * - * SPDX-License-Identifier: Apache-2.0 - ********************************************************************************/ - -#ifndef SCORE_CRYPTO_SRC_DAEMON_KEY_MANAGEMENT_SLOT_DEPLOYMENT_I_DEPLOYMENT_WRITER_HPP -#define SCORE_CRYPTO_SRC_DAEMON_KEY_MANAGEMENT_SLOT_DEPLOYMENT_I_DEPLOYMENT_WRITER_HPP - -#include "score/crypto/src/common/types.hpp" -#include "score/crypto/src/daemon/common/daemon_error.hpp" -#include "score/crypto/src/daemon/key_management/interfaces/key_slot_config.hpp" - -#include -#include - -namespace score::crypto::daemon::key_management -{ - -/// @brief Interface for format-specific deployment descriptor writers. -/// -/// Mirrors IDeploymentLoader: one concrete class per serialization format. -/// The path safety pre-check is performed by DeploymentWriterFactory *before* -/// calling Write(), so implementations can assume a valid path. -/// -/// ### Adding a new format -/// 1. Implement this interface in a new class (e.g., `JsonDeploymentWriter`). -/// 2. Place the class under `slot/deployment//`. -/// 3. Register it in `DeploymentWriterFactory::Create()`. -class IDeploymentWriter -{ - public: - virtual ~IDeploymentWriter() = default; - - /// @brief Write a SlotDeploymentInfo to the given (pre-validated) path. - /// - /// @param path Absolute path to the deployment descriptor file. The caller - /// (factory) has already verified it is safe. - /// @param info The deployment info to persist. - /// @return std::monostate on success, or DaemonErrorCode on failure. - [[nodiscard]] virtual score::crypto::Expected Write( - const std::string& path, - const SlotDeploymentInfo& info) = 0; -}; - -} // namespace score::crypto::daemon::key_management - -#endif // SCORE_CRYPTO_SRC_DAEMON_KEY_MANAGEMENT_SLOT_DEPLOYMENT_I_DEPLOYMENT_WRITER_HPP diff --git a/score/crypto/src/daemon/key_management/slot/deployment/kv/kv_deployment_loader.cpp b/score/crypto/src/daemon/key_management/slot/deployment/kv/kv_deployment_loader.cpp deleted file mode 100644 index 2e7665608..000000000 --- a/score/crypto/src/daemon/key_management/slot/deployment/kv/kv_deployment_loader.cpp +++ /dev/null @@ -1,120 +0,0 @@ -/******************************************************************************** - * Copyright (c) 2026 Contributors to the Eclipse Foundation - * - * See the NOTICE file(s) distributed with this work for additional - * information regarding copyright ownership. - * - * This program and the accompanying materials are made available under the - * terms of the Apache License Version 2.0 which is available at - * https://www.apache.org/licenses/LICENSE-2.0 - * - * SPDX-License-Identifier: Apache-2.0 - ********************************************************************************/ - -#include "score/crypto/src/daemon/key_management/slot/deployment/kv/kv_deployment_loader.hpp" - -#include "score/mw/log/logging.h" -#include -#include -#include - -#include - -namespace score::crypto::daemon::key_management -{ - -score::crypto::Expected KvDeploymentLoader::Load( - const std::string& path) -{ - std::ifstream file(path); - if (!file.is_open()) - { - score::mw::log::LogError() << kLogPrefix << "Cannot open deployment descriptor:" << path; - return score::crypto::make_unexpected(score::crypto::daemon::common::DaemonErrorCode::kInvalidArgument); - } - - SlotDeploymentInfo info{}; - - enum class Section : uint8_t - { - kMetadata, - kKey - }; - auto current_section = Section::kMetadata; - - std::string line; - while (std::getline(file, line)) - { - // Trim leading/trailing whitespace. - std::size_t start = line.find_first_not_of(" \t\r\n"); - if (start == std::string::npos) - { - continue; // blank line - } - std::size_t end = line.find_last_not_of(" \t\r\n"); - line = line.substr(start, end - start + 1U); - - // Skip comments. - if (line[0] == '#') - { - continue; - } - - // Section headers. - if (line == "[metadata]") - { - current_section = Section::kMetadata; - continue; - } - if (line == "[key]") - { - current_section = Section::kKey; - continue; - } - - // Parse key=value pairs. - const auto eq_pos = line.find('='); - if (eq_pos == std::string::npos) - { - continue; // malformed line — skip - } - - std::string key = line.substr(0U, eq_pos); - std::string value = line.substr(eq_pos + 1U); - - // Trim key and value. - auto trim = [](std::string& s) { - std::size_t s_start = s.find_first_not_of(" \t"); - std::size_t s_end = s.find_last_not_of(" \t"); - if (s_start == std::string::npos) - { - s.clear(); - } - else - { - s = s.substr(s_start, s_end - s_start + 1U); - } - }; - trim(key); - trim(value); - - if (key.empty()) - { - continue; - } - - switch (current_section) - { - case Section::kMetadata: - info.metadata[std::move(key)] = std::move(value); - break; - case Section::kKey: - info.key_properties[std::move(key)] = std::move(value); - break; - } - } - - return info; -} - -} // namespace score::crypto::daemon::key_management diff --git a/score/crypto/src/daemon/key_management/slot/deployment/kv/kv_deployment_loader.hpp b/score/crypto/src/daemon/key_management/slot/deployment/kv/kv_deployment_loader.hpp deleted file mode 100644 index e9973725c..000000000 --- a/score/crypto/src/daemon/key_management/slot/deployment/kv/kv_deployment_loader.hpp +++ /dev/null @@ -1,55 +0,0 @@ -/******************************************************************************** - * Copyright (c) 2026 Contributors to the Eclipse Foundation - * - * See the NOTICE file(s) distributed with this work for additional - * information regarding copyright ownership. - * - * This program and the accompanying materials are made available under the - * terms of the Apache License Version 2.0 which is available at - * https://www.apache.org/licenses/LICENSE-2.0 - * - * SPDX-License-Identifier: Apache-2.0 - ********************************************************************************/ - -#ifndef SCORE_CRYPTO_SRC_DAEMON_KEY_MANAGEMENT_SLOT_DEPLOYMENT_KV_KV_DEPLOYMENT_LOADER_HPP -#define SCORE_CRYPTO_SRC_DAEMON_KEY_MANAGEMENT_SLOT_DEPLOYMENT_KV_KV_DEPLOYMENT_LOADER_HPP - -#include "score/crypto/src/daemon/key_management/slot/deployment/i_deployment_loader.hpp" - -#include - -namespace score::crypto::daemon::key_management -{ - -/// @brief Loads a SlotDeploymentInfo from a key=value text file. -/// -/// File format: -/// @code -/// # comment -/// [metadata] -/// availability = active -/// provisioned_at = 2025-11-03T08:42:00Z -/// -/// [key] -/// key_path = /etc/crypto/keys/hmac.bin -/// key_format = raw -/// @endcode -/// -/// - Lines starting with `#` are comments and are ignored. -/// - Blank lines are ignored. -/// - Section headers `[metadata]` and `[key]` switch the active map. -/// - Lines without a `=` separator are silently skipped. -/// - Keys and values are whitespace-trimmed. -class KvDeploymentLoader : public IDeploymentLoader -{ - public: - [[nodiscard]] score::crypto::Expected Load( - const std::string& path) override; - - private: - static constexpr std::string_view kLogPrefix = "[KV_DEPLOYMENT_LOADER] "; -}; - -} // namespace score::crypto::daemon::key_management - -#endif // SCORE_CRYPTO_SRC_DAEMON_KEY_MANAGEMENT_SLOT_DEPLOYMENT_KV_KV_DEPLOYMENT_LOADER_HPP diff --git a/score/crypto/src/daemon/key_management/slot/deployment/kv/kv_deployment_writer.hpp b/score/crypto/src/daemon/key_management/slot/deployment/kv/kv_deployment_writer.hpp deleted file mode 100644 index 1f62ef027..000000000 --- a/score/crypto/src/daemon/key_management/slot/deployment/kv/kv_deployment_writer.hpp +++ /dev/null @@ -1,45 +0,0 @@ -/******************************************************************************** - * Copyright (c) 2026 Contributors to the Eclipse Foundation - * - * See the NOTICE file(s) distributed with this work for additional - * information regarding copyright ownership. - * - * This program and the accompanying materials are made available under the - * terms of the Apache License Version 2.0 which is available at - * https://www.apache.org/licenses/LICENSE-2.0 - * - * SPDX-License-Identifier: Apache-2.0 - ********************************************************************************/ - -#ifndef SCORE_CRYPTO_SRC_DAEMON_KEY_MANAGEMENT_SLOT_DEPLOYMENT_KV_KV_DEPLOYMENT_WRITER_HPP -#define SCORE_CRYPTO_SRC_DAEMON_KEY_MANAGEMENT_SLOT_DEPLOYMENT_KV_KV_DEPLOYMENT_WRITER_HPP - -#include "score/crypto/src/daemon/key_management/slot/deployment/i_deployment_writer.hpp" - -#include - -namespace score::crypto::daemon::key_management -{ - -/// @brief Writes a SlotDeploymentInfo to a key=value text file. -/// -/// Produces the same `[metadata]` / `[key]` section format that -/// KvDeploymentLoader can read back. Existing file content is replaced -/// (opened with `std::ios::trunc`). -/// -/// @note Writes are not currently atomic. A future extension may implement -/// write-then-rename to protect against partial writes on crash. -class KvDeploymentWriter : public IDeploymentWriter -{ - public: - [[nodiscard]] score::crypto::Expected Write( - const std::string& path, - const SlotDeploymentInfo& info) override; - - private: - static constexpr std::string_view kLogPrefix = "[KV_DEPLOYMENT_WRITER] "; -}; - -} // namespace score::crypto::daemon::key_management - -#endif // SCORE_CRYPTO_SRC_DAEMON_KEY_MANAGEMENT_SLOT_DEPLOYMENT_KV_KV_DEPLOYMENT_WRITER_HPP diff --git a/score/crypto/src/daemon/key_management/slot/deployment_loader.cpp b/score/crypto/src/daemon/key_management/slot/deployment_loader.cpp index e6d5691fe..cbd555cd3 100644 --- a/score/crypto/src/daemon/key_management/slot/deployment_loader.cpp +++ b/score/crypto/src/daemon/key_management/slot/deployment_loader.cpp @@ -13,8 +13,8 @@ #include "score/crypto/src/daemon/key_management/slot/deployment_loader.hpp" -#include "score/crypto/src/daemon/key_management/slot/deployment/deployment_path_utils.hpp" -#include "score/crypto/src/daemon/key_management/slot/deployment/kv/kv_deployment_loader.hpp" +#include "score/crypto/src/daemon/common/storage/deployment_path_utils.hpp" +#include "score/crypto/src/daemon/common/storage/kv/kv_deployment_loader.hpp" #include "score/mw/log/logging.h" @@ -27,7 +27,7 @@ score::crypto::Expectedsections["metadata"]; + info.key_properties = descriptor->sections["key"]; + return info; } // To add a new format: include its header above and add a branch here. // Example: if (format == "json") { return JsonDeploymentLoader{}.Load(path); } diff --git a/score/crypto/src/daemon/key_management/slot/deployment_writer.cpp b/score/crypto/src/daemon/key_management/slot/deployment_writer.cpp index 4bd3d1dc9..bc1d75917 100644 --- a/score/crypto/src/daemon/key_management/slot/deployment_writer.cpp +++ b/score/crypto/src/daemon/key_management/slot/deployment_writer.cpp @@ -13,8 +13,8 @@ #include "score/crypto/src/daemon/key_management/slot/deployment_writer.hpp" -#include "score/crypto/src/daemon/key_management/slot/deployment/deployment_path_utils.hpp" -#include "score/crypto/src/daemon/key_management/slot/deployment/kv/kv_deployment_writer.hpp" +#include "score/crypto/src/daemon/common/storage/deployment_path_utils.hpp" +#include "score/crypto/src/daemon/common/storage/kv/kv_deployment_writer.hpp" #include "score/mw/log/logging.h" @@ -26,7 +26,7 @@ namespace score::crypto::daemon::key_management score::crypto::Expected DeploymentWriter::Write(const std::string& path, const std::string& format, const SlotDeploymentInfo& info) { - if (!IsDeploymentPathSafe(path)) + if (!score::crypto::daemon::common::storage::IsDeploymentPathSafe(path)) { score::mw::log::LogError() << LOG_PREFIX << "Unsafe deployment path rejected:" << path; return score::crypto::make_unexpected(score::crypto::daemon::common::DaemonErrorCode::kInvalidArgument); @@ -34,7 +34,10 @@ DeploymentWriter::Write(const std::string& path, const std::string& format, cons if (format == "kv") { - return KvDeploymentWriter{}.Write(path, info); + score::crypto::daemon::common::storage::DeploymentDescriptor descriptor{}; + descriptor.sections["metadata"] = info.metadata; + descriptor.sections["key"] = info.key_properties; + return score::crypto::daemon::common::storage::KvDeploymentWriter{}.Write(path, descriptor); } // To add a new format: include its header above and add a branch here. // Example: if (format == "json") { return JsonDeploymentWriter{}.Write(path, info); } From a2cc0270ce28a61d7523e3a6d41f312857d89acc Mon Sep 17 00:00:00 2001 From: Athul Mallappallil Date: Thu, 30 Jul 2026 21:58:50 +0200 Subject: [PATCH 02/25] API update for cert mgmnt and ops --- score/crypto/src/api/certificate/BUILD | 29 +++++ .../{future => }/certificate/cert_types.hpp | 15 ++- .../certificate/i_ocsp_request_export.hpp | 6 +- score/crypto/src/api/common/types.hpp | 21 +++- score/crypto/src/api/config/BUILD | 14 +++ .../config/certificate_context_config.hpp | 6 +- ...ertificate_verification_context_config.hpp | 6 +- score/crypto/src/api/contexts/BUILD | 19 +++ .../i_certificate_management_context.hpp | 111 ++++++++++-------- .../i_certificate_verification_context.hpp | 108 +++++++++++------ score/crypto/src/api/future/certificate/BUILD | 5 +- score/crypto/src/api/future/config/BUILD | 5 +- score/crypto/src/api/future/contexts/BUILD | 10 +- score/crypto/src/api/future/objects/BUILD | 5 +- score/crypto/src/api/objects/BUILD | 16 +++ .../objects/i_cert_slot_object.hpp | 6 +- .../objects/i_certificate_object.hpp | 6 +- 17 files changed, 272 insertions(+), 116 deletions(-) create mode 100644 score/crypto/src/api/certificate/BUILD rename score/crypto/src/api/{future => }/certificate/cert_types.hpp (78%) rename score/crypto/src/api/{future => }/certificate/i_ocsp_request_export.hpp (89%) rename score/crypto/src/api/{future => }/config/certificate_context_config.hpp (89%) rename score/crypto/src/api/{future => }/config/certificate_verification_context_config.hpp (91%) rename score/crypto/src/api/{future => }/contexts/i_certificate_management_context.hpp (77%) rename score/crypto/src/api/{future => }/contexts/i_certificate_verification_context.hpp (53%) rename score/crypto/src/api/{future => }/objects/i_cert_slot_object.hpp (88%) rename score/crypto/src/api/{future => }/objects/i_certificate_object.hpp (95%) diff --git a/score/crypto/src/api/certificate/BUILD b/score/crypto/src/api/certificate/BUILD new file mode 100644 index 000000000..a0e9c52e4 --- /dev/null +++ b/score/crypto/src/api/certificate/BUILD @@ -0,0 +1,29 @@ +# ******************************************************************************* +# Copyright (c) 2026 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* + +load("@rules_cc//cc:defs.bzl", "cc_library") + +cc_library( + name = "cert_types", + hdrs = [ + "cert_types.hpp", + "i_ocsp_request_export.hpp", + ], + includes = ["."], + visibility = ["//visibility:public"], + deps = [ + "//score/crypto/src/api/common:crypto_common", + "@score_baselibs//score/language/futurecpp", + "@score_baselibs//score/result", + ], +) diff --git a/score/crypto/src/api/future/certificate/cert_types.hpp b/score/crypto/src/api/certificate/cert_types.hpp similarity index 78% rename from score/crypto/src/api/future/certificate/cert_types.hpp rename to score/crypto/src/api/certificate/cert_types.hpp index 9d14deb7b..cd2f697be 100644 --- a/score/crypto/src/api/future/certificate/cert_types.hpp +++ b/score/crypto/src/api/certificate/cert_types.hpp @@ -11,8 +11,8 @@ * SPDX-License-Identifier: Apache-2.0 ********************************************************************************/ -#ifndef SCORE_CRYPTO_SRC_API_FUTURE_CERTIFICATE_CERT_TYPES_HPP -#define SCORE_CRYPTO_SRC_API_FUTURE_CERTIFICATE_CERT_TYPES_HPP +#ifndef SCORE_CRYPTO_SRC_API_CERTIFICATE_CERT_TYPES_HPP +#define SCORE_CRYPTO_SRC_API_CERTIFICATE_CERT_TYPES_HPP #include "score/crypto/src/api/common/types.hpp" @@ -39,6 +39,15 @@ enum class CertVerifyResult : uint8_t kUnknownError ///< Unspecified verification failure }; +/// @brief Controls where certificate-chain verification may terminate. +enum class ChainTerminationPolicy : uint8_t +{ + /// Require a complete path ending at a self-signed trust-store root. + kRootRequired, + /// Permit termination at the first certificate present in the trust store. + kTrustStoreTerminated +}; + /// @brief Status of an OCSP response. enum class OcspStatus : uint8_t { @@ -52,4 +61,4 @@ enum class OcspStatus : uint8_t } // namespace score -#endif // SCORE_CRYPTO_SRC_API_FUTURE_CERTIFICATE_CERT_TYPES_HPP +#endif // SCORE_CRYPTO_SRC_API_CERTIFICATE_CERT_TYPES_HPP diff --git a/score/crypto/src/api/future/certificate/i_ocsp_request_export.hpp b/score/crypto/src/api/certificate/i_ocsp_request_export.hpp similarity index 89% rename from score/crypto/src/api/future/certificate/i_ocsp_request_export.hpp rename to score/crypto/src/api/certificate/i_ocsp_request_export.hpp index 0627e7df2..93690bc23 100644 --- a/score/crypto/src/api/future/certificate/i_ocsp_request_export.hpp +++ b/score/crypto/src/api/certificate/i_ocsp_request_export.hpp @@ -11,8 +11,8 @@ * SPDX-License-Identifier: Apache-2.0 ********************************************************************************/ -#ifndef SCORE_CRYPTO_SRC_API_FUTURE_CERTIFICATE_I_OCSP_REQUEST_EXPORT_HPP -#define SCORE_CRYPTO_SRC_API_FUTURE_CERTIFICATE_I_OCSP_REQUEST_EXPORT_HPP +#ifndef SCORE_CRYPTO_SRC_API_CERTIFICATE_I_OCSP_REQUEST_EXPORT_HPP +#define SCORE_CRYPTO_SRC_API_CERTIFICATE_I_OCSP_REQUEST_EXPORT_HPP #include "score/result/result.h" #include "score/span.hpp" @@ -61,4 +61,4 @@ class IOcspRequestExport } // namespace score -#endif // SCORE_CRYPTO_SRC_API_FUTURE_CERTIFICATE_I_OCSP_REQUEST_EXPORT_HPP +#endif // SCORE_CRYPTO_SRC_API_CERTIFICATE_I_OCSP_REQUEST_EXPORT_HPP diff --git a/score/crypto/src/api/common/types.hpp b/score/crypto/src/api/common/types.hpp index ebeb4918c..31f75584f 100644 --- a/score/crypto/src/api/common/types.hpp +++ b/score/crypto/src/api/common/types.hpp @@ -133,6 +133,18 @@ enum class KeySlotState : uint8_t kLocked ///< Slot is in use and cannot be modified }; +/// @brief State of a certificate slot. +/// +/// Certificate slots contain certificate/CRL storage and are not bound to a +/// certificate-operation provider. Provider selection is made by the +/// operation/context that parses or verifies the material. +enum class CertificateSlotState : uint8_t +{ + kEmpty, ///< Slot contains no certificate + kOccupied, ///< Slot contains a certificate + kLocked ///< Slot is in use and cannot be modified +}; + /// @brief Validity status of a certificate. enum class CertificateStatus : uint8_t { @@ -284,14 +296,15 @@ inline constexpr bool HasPermission(KeyOperationPermission granted, KeyOperation return (g & r) == r; } -/// @brief Information about a certificate slot and its contents. +/// @brief Lightweight information about certificate-slot storage. /// /// Returned by ICertificateManagementContext::GetCertificateSlotInfo(). +/// Certificate-specific details such as subject, issuer, algorithm, and +/// validity are obtained by loading/parsing the certificate. struct CertificateSlotInfo { - bool occupied{false}; ///< Whether the slot contains a certificate - AlgorithmId algorithm{}; ///< Public key algorithm of the stored certificate (empty if unoccupied) - uint16_t primary_provider{0U}; ///< Provider/device that owns this slot + CertificateSlotState state{CertificateSlotState::kEmpty}; + bool has_crl{false}; ///< Whether a CRL is currently associated with the slot }; /// @brief Information about a key slot and its contents. diff --git a/score/crypto/src/api/config/BUILD b/score/crypto/src/api/config/BUILD index 5ff3b764a..1dd33a64e 100644 --- a/score/crypto/src/api/config/BUILD +++ b/score/crypto/src/api/config/BUILD @@ -29,3 +29,17 @@ cc_library( "//score/crypto/src/api/common:crypto_common", ], ) + +cc_library( + name = "cert_context_configs", + hdrs = [ + "certificate_context_config.hpp", + "certificate_verification_context_config.hpp", + ], + includes = ["."], + visibility = ["//visibility:public"], + deps = [ + ":context_configs", + "//score/crypto/src/api/common:crypto_common", + ], +) diff --git a/score/crypto/src/api/future/config/certificate_context_config.hpp b/score/crypto/src/api/config/certificate_context_config.hpp similarity index 89% rename from score/crypto/src/api/future/config/certificate_context_config.hpp rename to score/crypto/src/api/config/certificate_context_config.hpp index e47ea0183..8808c2def 100644 --- a/score/crypto/src/api/future/config/certificate_context_config.hpp +++ b/score/crypto/src/api/config/certificate_context_config.hpp @@ -11,8 +11,8 @@ * SPDX-License-Identifier: Apache-2.0 ********************************************************************************/ -#ifndef SCORE_CRYPTO_SRC_API_FUTURE_CONFIG_CERTIFICATE_CONTEXT_CONFIG_HPP -#define SCORE_CRYPTO_SRC_API_FUTURE_CONFIG_CERTIFICATE_CONTEXT_CONFIG_HPP +#ifndef SCORE_CRYPTO_SRC_API_CONFIG_CERTIFICATE_CONTEXT_CONFIG_HPP +#define SCORE_CRYPTO_SRC_API_CONFIG_CERTIFICATE_CONTEXT_CONFIG_HPP #include "score/crypto/src/api/config/base_context_config.hpp" @@ -67,4 +67,4 @@ struct CertificateContextConfig : public BaseContextConfig } // namespace score -#endif // SCORE_CRYPTO_SRC_API_FUTURE_CONFIG_CERTIFICATE_CONTEXT_CONFIG_HPP +#endif // SCORE_CRYPTO_SRC_API_CONFIG_CERTIFICATE_CONTEXT_CONFIG_HPP diff --git a/score/crypto/src/api/future/config/certificate_verification_context_config.hpp b/score/crypto/src/api/config/certificate_verification_context_config.hpp similarity index 91% rename from score/crypto/src/api/future/config/certificate_verification_context_config.hpp rename to score/crypto/src/api/config/certificate_verification_context_config.hpp index fb87cbb10..838fd0c75 100644 --- a/score/crypto/src/api/future/config/certificate_verification_context_config.hpp +++ b/score/crypto/src/api/config/certificate_verification_context_config.hpp @@ -11,8 +11,8 @@ * SPDX-License-Identifier: Apache-2.0 ********************************************************************************/ -#ifndef SCORE_CRYPTO_SRC_API_FUTURE_CONFIG_CERTIFICATE_VERIFICATION_CONTEXT_CONFIG_HPP -#define SCORE_CRYPTO_SRC_API_FUTURE_CONFIG_CERTIFICATE_VERIFICATION_CONTEXT_CONFIG_HPP +#ifndef SCORE_CRYPTO_SRC_API_CONFIG_CERTIFICATE_VERIFICATION_CONTEXT_CONFIG_HPP +#define SCORE_CRYPTO_SRC_API_CONFIG_CERTIFICATE_VERIFICATION_CONTEXT_CONFIG_HPP #include "score/crypto/src/api/common/types.hpp" #include "score/crypto/src/api/config/base_context_config.hpp" @@ -86,4 +86,4 @@ struct CertificateVerificationContextConfig : public BaseContextConfig } // namespace score -#endif // SCORE_CRYPTO_SRC_API_FUTURE_CONFIG_CERTIFICATE_VERIFICATION_CONTEXT_CONFIG_HPP +#endif // SCORE_CRYPTO_SRC_API_CONFIG_CERTIFICATE_VERIFICATION_CONTEXT_CONFIG_HPP diff --git a/score/crypto/src/api/contexts/BUILD b/score/crypto/src/api/contexts/BUILD index 6f905b7b3..06375baa8 100644 --- a/score/crypto/src/api/contexts/BUILD +++ b/score/crypto/src/api/contexts/BUILD @@ -48,6 +48,25 @@ cc_library( ], ) +cc_library( + name = "cert_contexts", + hdrs = [ + "i_certificate_management_context.hpp", + "i_certificate_verification_context.hpp", + ], + includes = ["."], + visibility = ["//visibility:public"], + deps = [ + ":context_bases", + "//score/crypto/src/api/certificate:cert_types", + "//score/crypto/src/api/common:crypto_common", + "//score/crypto/src/api/config:cert_context_configs", + "//score/crypto/src/api/objects:cert_objects", + "@score_baselibs//score/language/futurecpp", + "@score_baselibs//score/result", + ], +) + cc_library( name = "crypto_contexts_impl", srcs = [ diff --git a/score/crypto/src/api/future/contexts/i_certificate_management_context.hpp b/score/crypto/src/api/contexts/i_certificate_management_context.hpp similarity index 77% rename from score/crypto/src/api/future/contexts/i_certificate_management_context.hpp rename to score/crypto/src/api/contexts/i_certificate_management_context.hpp index 4f8747a8f..48491e34f 100644 --- a/score/crypto/src/api/future/contexts/i_certificate_management_context.hpp +++ b/score/crypto/src/api/contexts/i_certificate_management_context.hpp @@ -11,14 +11,14 @@ * SPDX-License-Identifier: Apache-2.0 ********************************************************************************/ -#ifndef SCORE_CRYPTO_SRC_API_FUTURE_CONTEXTS_I_CERTIFICATE_MANAGEMENT_CONTEXT_HPP -#define SCORE_CRYPTO_SRC_API_FUTURE_CONTEXTS_I_CERTIFICATE_MANAGEMENT_CONTEXT_HPP +#ifndef SCORE_CRYPTO_SRC_API_CONTEXTS_I_CERTIFICATE_MANAGEMENT_CONTEXT_HPP +#define SCORE_CRYPTO_SRC_API_CONTEXTS_I_CERTIFICATE_MANAGEMENT_CONTEXT_HPP #include "score/crypto/src/api/certificate/i_ocsp_request_export.hpp" #include "score/crypto/src/api/common/crypto_resource_guard.hpp" #include "score/crypto/src/api/common/types.hpp" #include "score/crypto/src/api/contexts/i_context.hpp" -#include "score/crypto/src/api/future/objects/i_certificate_object.hpp" +#include "score/crypto/src/api/objects/i_certificate_object.hpp" #include "score/result/result.h" #include "score/span.hpp" @@ -44,8 +44,8 @@ namespace crypto /// ICertificateObject goes out of scope). /// - **Export / convert** using a two-call pattern: query the required buffer /// size first, then fill the caller-supplied span. -/// - **Slot management**, **CRL management**, and **trust store management** -/// are all co-located here. +/// - **Slot management** and **trust store management** are co-located here. +/// - CRL, OCSP, and CSR operations are defined in future/ and not yet active. /// /// **ParseCertificate lifecycle**: /// @code @@ -170,46 +170,10 @@ class ICertificateManagementContext : public IContext /// @brief Queries the occupancy and metadata of a certificate slot. /// @param slot Handle to the slot (type = kCertSlot) - /// @return CertificateSlotInfo with occupancy, algorithm, and provider binding + /// @return CertificateSlotInfo with certificate-slot state and CRL presence virtual score::Result GetCertificateSlotInfo(const CryptoResourceId& slot) = 0; - // ---- CRL management ---- - - /// @brief Imports a Certificate Revocation List and associates it with its issuer. - /// - /// The returned CryptoResourceId uses ResourceType::kCrl and carries the - /// same numeric id as the resolved issuer certificate — callers can look up - /// the applicable CRL for any issuer by re-resolving with ResourceType::kCrl. - /// - /// @param crl_data Encoded CRL data - /// @param format Encoding format of the CRL - /// @param issuer_cert Handle to the issuer certificate - /// (type = kCertificate or kCertSlot). The daemon validates that the - /// CRL issuer DN matches and that the CRL signature is correct. - /// @param persist When true, the CRL survives the guard's destructor - /// (kPersistent — daemon retains the CRL when the client releases its - /// reference). When false, the CRL is deleted when the guard is destroyed. - /// @return Guard wrapping a handle with type = kCrl. Pass guard.GetId() to - /// SetCrl() or re-resolve via ResourceType::kCrl on the issuer id. - virtual score::Result ImportCrl(score::cpp::span crl_data, - FormatType format, - const CryptoResourceId& issuer_cert, - bool persist) = 0; - - /// @brief Removes a specific CRL from the store. - /// @param crl Handle to the CRL to delete (type = kCrl) - /// @return std::monostate on success, error if the CRL is not found - virtual score::Result DeleteCrl(const CryptoResourceId& crl) = 0; - - /// @brief Bulk-deletes expired CRLs from the store. - /// @return Number of CRLs deleted - virtual score::Result DeleteExpiredCrls() = 0; - - /// @brief Bulk-deletes expired certificates from persistent slots. - /// @return Number of certificates deleted - virtual score::Result DeleteExpiredCertificates() = 0; - - // ---- Key extraction and OCSP ---- + // ---- Key extraction ---- /// @brief Extracts the public key from a certificate as an ephemeral key resource. /// @@ -223,17 +187,64 @@ class ICertificateManagementContext : public IContext virtual score::Result> LoadCertificatePublicKey( const CryptoResourceId& cert) = 0; - /// @brief Constructs an OCSP request for a certificate's revocation status. + /// @brief Bulk-deletes expired certificates from persistent slots. + /// @return Number of certificates deleted + virtual score::Result DeleteExpiredCertificates() = 0; + + // ---- CRL management (not yet active — IPC implementation pending) ---- +#if 0 + /// @brief Imports a Certificate Revocation List and associates it with its issuer certificate. /// - /// The returned object exposes the DER-encoded OCSP request and the responder URL. - /// Send the request to the URL via HTTP POST, then feed the response to - /// ICertificateVerificationContext::SetOcspResponse(). + /// The CRL lifecycle follows the lifecycle of @p issuer_cert: + /// - kCertSlot + persist=true: CRL written to the slot's [crl] section; write access required. + /// - kCertSlot or kCertificate + persist=false (default): session-scoped; no write access needed. + /// + /// @param crl_data Encoded CRL data + /// @param format Encoding format of the CRL + /// @param issuer_cert Handle to the issuer certificate (type = kCertSlot or kCertificate) + /// @param persist When true, store permanently to the issuer slot (kCertSlot only). + /// @return std::monostate on success, error if validation fails or access is denied + virtual score::Result ImportCrl(score::cpp::span crl_data, + FormatType format, + const CryptoResourceId& issuer_cert, + bool persist = false) = 0; + + /// @brief Removes the CRL stored in a certificate slot. + /// @param cert_slot Handle to the slot whose CRL should be removed (type = kCertSlot) + /// @return std::monostate on success, error if no CRL is present or access is denied + virtual score::Result DeleteCrl(const CryptoResourceId& cert_slot) = 0; + + /// @brief Bulk-deletes expired CRLs across all certificate slots. + /// @return Number of CRLs deleted + virtual score::Result DeleteExpiredCrls() = 0; +#endif // CRL management + + // ---- OCSP (not yet active — IPC implementation pending) ---- +#if 0 + /// @brief Constructs an OCSP request for a certificate's revocation status. /// /// @param cert Handle to the certificate to check (type = kCertificate or kCertSlot) - /// @param issuer_cert Handle to the issuer certificate (required for OCSP request construction) - /// @return Export object providing the encoded request and responder URL + /// @param issuer_cert Handle to the issuer certificate + /// @return Export object providing the DER-encoded request and responder URL virtual score::Result GetOcspRequestData(const CryptoResourceId& cert, const CryptoResourceId& issuer_cert) = 0; +#endif // OCSP + + // ---- Trust-store membership management ---- + + /// @brief Adds a certificate to a persistent trust store. + /// + /// The certificate is assigned to a trust-store-managed slot. This is a + /// write operation and requires trust-store write access. + virtual score::Result AddCertificateToTrustStore(const CryptoResourceId& trust_store, + const CryptoResourceId& cert) = 0; + + /// @brief Removes a certificate from a persistent trust store by SHA-256 fingerprint. + /// + /// This changes trust-store deployment state and requires write access. + virtual score::Result RemoveCertificateFromTrustStore( + const CryptoResourceId& trust_store, + score::cpp::span certificate_fingerprint) = 0; protected: ICertificateManagementContext() = default; @@ -243,4 +254,4 @@ class ICertificateManagementContext : public IContext } // namespace score -#endif // SCORE_CRYPTO_SRC_API_FUTURE_CONTEXTS_I_CERTIFICATE_MANAGEMENT_CONTEXT_HPP +#endif // SCORE_CRYPTO_SRC_API_CONTEXTS_I_CERTIFICATE_MANAGEMENT_CONTEXT_HPP diff --git a/score/crypto/src/api/future/contexts/i_certificate_verification_context.hpp b/score/crypto/src/api/contexts/i_certificate_verification_context.hpp similarity index 53% rename from score/crypto/src/api/future/contexts/i_certificate_verification_context.hpp rename to score/crypto/src/api/contexts/i_certificate_verification_context.hpp index 6dea3ea90..f8059f9a6 100644 --- a/score/crypto/src/api/future/contexts/i_certificate_verification_context.hpp +++ b/score/crypto/src/api/contexts/i_certificate_verification_context.hpp @@ -11,8 +11,8 @@ * SPDX-License-Identifier: Apache-2.0 ********************************************************************************/ -#ifndef SCORE_CRYPTO_SRC_API_FUTURE_CONTEXTS_I_CERTIFICATE_VERIFICATION_CONTEXT_HPP -#define SCORE_CRYPTO_SRC_API_FUTURE_CONTEXTS_I_CERTIFICATE_VERIFICATION_CONTEXT_HPP +#ifndef SCORE_CRYPTO_SRC_API_CONTEXTS_I_CERTIFICATE_VERIFICATION_CONTEXT_HPP +#define SCORE_CRYPTO_SRC_API_CONTEXTS_I_CERTIFICATE_VERIFICATION_CONTEXT_HPP #include "score/crypto/src/api/certificate/cert_types.hpp" #include "score/crypto/src/api/common/types.hpp" @@ -41,19 +41,18 @@ namespace crypto /// auto ctx = crypto_context->CreateCertificateVerificationContext(config).value(); /// ctx->SetCertificate(leaf_cert); /// ctx->SetVerificationTrustStore(system_trust_store); -/// ctx->SetRevocationCheckPolicy(RevocationCheckPolicy::kOcspWithCrlFallback); -/// ctx->SetOcspResponse(ocsp_response_data); +/// ctx->SetRevocationCheckPolicy(RevocationCheckPolicy::kCrlOnly); /// auto result = ctx->Verify(); /// @endcode /// -/// @par Example — chain verification with additional trust anchors +/// @par Example — chain verification with additional untrusted certificates /// @code /// // ext_ca is a kCertificate from ParseCertificate() — not persisted. /// std::array extra = {ext_ca->GetId()}; /// auto ctx = crypto_context->CreateCertificateVerificationContext(config).value(); /// ctx->SetCertificateChain(chain); /// ctx->SetVerificationTrustStore(system_trust_store); -/// ctx->SetAdditionalTrustAnchors(extra); // local to this context, no system store change +/// ctx->SetAdditionalCertificates(extra); // untrusted chain-building inputs /// auto result = ctx->Verify(); /// @endcode class ICertificateVerificationContext : public IContext @@ -93,36 +92,60 @@ class ICertificateVerificationContext : public IContext /// @return std::monostate on success, error if handle is invalid virtual score::Result SetVerificationTrustStore(const CryptoResourceId& trust_store) = 0; - /// @brief Supplies additional trust anchors for this verification, beyond the system trust store. + /// @brief Sets the standalone trusted certificates for this verification context. /// - /// Use this to trust certificates not provisioned in any system trust store — - /// e.g. an external CA received at runtime, a rotation candidate, or a test root. - /// Does not modify the system trust store; these roots are local to this context instance. + /// This mode is mutually exclusive with SetVerificationTrustStore(). Each + /// call replaces the previously configured set, so callers that discover + /// anchors incrementally must collect them before calling this method. /// - /// Accepts both `kCertificate` (parsed, not persisted) and `kCertSlot` handles. - /// The daemon validates each certificate immediately: - /// - Expired certificates cause the whole call to fail. - /// - Certificates already present in the configured system trust store are - /// accepted silently (idempotent union — no duplicate anchors). + /// @param certs Span of certificate handles to treat as trust anchors + /// (type = kCertificate or kCertSlot) + /// @return std::monostate on success, error if any handle is invalid + virtual score::Result SetTrustedCertificates( + score::cpp::span certs) = 0; + + /// @brief Selects the chain termination rule for trust-store verification. /// - /// Replaces any previously set additional anchors on this context (set semantics). + /// The default is ChainTerminationPolicy::kRootRequired. This setting has + /// no effect in standalone trusted-certificate mode. + virtual score::Result SetChainTerminationPolicy(ChainTerminationPolicy policy) = 0; + + /// @brief Supplies additional untrusted certificates for chain building. /// - /// @param anchors Span of certificate handles (type = kCertificate or kCertSlot) - /// @return std::monostate on success, error if any handle is invalid or any certificate has expired - virtual score::Result SetAdditionalTrustAnchors( - score::cpp::span anchors) = 0; - - /// @brief Provides an OCSP response for revocation checking. - /// @param response_data DER-encoded OCSP response - /// @return std::monostate on success, error on parse failure - /// @note The context internally validates the OCSP responder's certificate - /// chain against the configured verification trust store. - virtual score::Result SetOcspResponse(score::cpp::span response_data) = 0; - - /// @brief References an imported CRL for revocation checking. - /// @param crl Handle to a previously imported CRL - /// @return std::monostate on success, error if handle is invalid - virtual score::Result SetCrl(const CryptoResourceId& crl) = 0; + /// Use this for intermediate certificates that are not provisioned in the + /// system trust store, such as an intermediate received with a peer chain. + /// These certificates are local to this context and do not establish trust. + /// + /// Accepts `kCertificate` and `kCertSlot` handles. Certificates already + /// present in the trust store are deduplicated by fingerprint. The daemon + /// uses these objects only as untrusted chain-building inputs; trust is + /// established exclusively by the configured trust store or standalone + /// trusted certificates. + /// + /// Replaces any previously set additional certificates on this context. + /// + /// @param certificates Span of untrusted certificate handles + /// (type = kCertificate or kCertSlot) + /// @return std::monostate on success, or an error if a handle is invalid + virtual score::Result SetAdditionalCertificates( + score::cpp::span certificates) = 0; + + // ---- OCSP (not yet active — IPC implementation pending) ---- +#if 0 + /// @brief Provides one or more OCSP responses for revocation checking. + /// + /// Each entry is a DER-encoded OCSP response. Supplying multiple responses + /// covers chains where both the leaf and one or more intermediates have + /// stapled OCSP responses (e.g. TLS 1.3 certificate_status records). + /// The daemon matches each response to the appropriate certificate in the + /// chain by the certID field embedded in the response; order does not matter. + /// Replaces any previously set responses on this context. + /// + /// @param responses Span of DER-encoded OCSP response byte spans + /// @return std::monostate on success, error if any response fails to parse + virtual score::Result SetOcspResponses( + score::cpp::span> responses) = 0; +#endif // OCSP /// @brief Overrides the verification time. /// @param epoch_seconds Verification time as seconds since Unix epoch @@ -144,6 +167,25 @@ class ICertificateVerificationContext : public IContext /// @note At minimum, a certificate (or chain) and trust anchor must be set. virtual score::Result Verify() = 0; + /// @brief Returns the number of certificates in the verified chain. + /// + /// Valid only after a successful Verify() call. The length is stable between + /// this call and GetVerifiedChain() provided no intervening Verify() is made. + /// + /// @return Number of entries in the chain (leaf to terminating anchor inclusive), + /// or an error if Verify() has not yet succeeded. + virtual score::Result GetVerifiedChainLength() const = 0; + + /// @brief Fills caller-provided buffer with verified chain certificate IDs. + /// + /// Certificates are ordered leaf-first, terminating anchor last. + /// The caller must size @p out to at least GetVerifiedChainLength() entries. + /// + /// @param out Caller-allocated span of CryptoResourceId to fill + /// @return Number of entries written, or an error if @p out is too small + /// or Verify() has not yet succeeded. + virtual score::Result GetVerifiedChain(score::cpp::span out) const = 0; + protected: ICertificateVerificationContext() = default; }; @@ -152,4 +194,4 @@ class ICertificateVerificationContext : public IContext } // namespace score -#endif // SCORE_CRYPTO_SRC_API_FUTURE_CONTEXTS_I_CERTIFICATE_VERIFICATION_CONTEXT_HPP +#endif // SCORE_CRYPTO_SRC_API_CONTEXTS_I_CERTIFICATE_VERIFICATION_CONTEXT_HPP diff --git a/score/crypto/src/api/future/certificate/BUILD b/score/crypto/src/api/future/certificate/BUILD index 877c2b40e..46c8ddd5e 100644 --- a/score/crypto/src/api/future/certificate/BUILD +++ b/score/crypto/src/api/future/certificate/BUILD @@ -17,12 +17,13 @@ load("@rules_cc//cc:defs.bzl", "cc_library") +# cert_types.hpp and i_ocsp_request_export.hpp moved to +# //score/crypto/src/api/certificate:cert_types (active). + # cc_library( # name = "crypto_certificate", # hdrs = [ -# "cert_types.hpp", # "i_csr_export.hpp", -# "i_ocsp_request_export.hpp", # ], # deps = [ # "//score/crypto/src/api/common:crypto_common", diff --git a/score/crypto/src/api/future/config/BUILD b/score/crypto/src/api/future/config/BUILD index bf631ee2c..0697cc05b 100644 --- a/score/crypto/src/api/future/config/BUILD +++ b/score/crypto/src/api/future/config/BUILD @@ -18,12 +18,13 @@ load("@rules_cc//cc:defs.bzl", "cc_library") +# certificate_context_config.hpp and certificate_verification_context_config.hpp +# moved to //score/crypto/src/api/config:cert_context_configs (active). + # cc_library( # name = "future_context_configs", # hdrs = [ # "aead_context_config.hpp", -# "certificate_context_config.hpp", -# "certificate_verification_context_config.hpp", # "cipher_context_config.hpp", # "csr_generation_context_config.hpp", # "random_context_config.hpp", diff --git a/score/crypto/src/api/future/contexts/BUILD b/score/crypto/src/api/future/contexts/BUILD index b425f9caf..b84dfa1f3 100644 --- a/score/crypto/src/api/future/contexts/BUILD +++ b/score/crypto/src/api/future/contexts/BUILD @@ -62,18 +62,18 @@ load("@rules_cc//cc:defs.bzl", "cc_library") # ], # ) -# -- Certificate management + verification + CSR -- +# i_certificate_management_context.hpp and i_certificate_verification_context.hpp +# moved to //score/crypto/src/api/contexts:cert_contexts (active). + +# -- CSR -- # cc_library( -# name = "certificate_contexts", +# name = "csr_generation_context", # hdrs = [ -# "i_certificate_management_context.hpp", -# "i_certificate_verification_context.hpp", # "i_csr_generation_context.hpp", # ], # deps = [ # "//score/crypto/src/api/contexts:context_bases", # "//score/crypto/src/api/common:crypto_common", -# "//score/crypto/src/api/future/certificate:crypto_certificate", # "@score_baselibs//score/result", # ], # ) diff --git a/score/crypto/src/api/future/objects/BUILD b/score/crypto/src/api/future/objects/BUILD index 2b0c6ec0f..6a6bf45e7 100644 --- a/score/crypto/src/api/future/objects/BUILD +++ b/score/crypto/src/api/future/objects/BUILD @@ -17,11 +17,12 @@ load("@rules_cc//cc:defs.bzl", "cc_library") +# i_certificate_object.hpp and i_cert_slot_object.hpp moved to +# //score/crypto/src/api/objects:cert_objects (active). + # cc_library( # name = "future_crypto_objects", # hdrs = [ -# "i_cert_slot_object.hpp", -# "i_certificate_object.hpp", # "i_data_object.hpp", # "i_provider_object.hpp", # "i_secure_object.hpp", diff --git a/score/crypto/src/api/objects/BUILD b/score/crypto/src/api/objects/BUILD index 0b45142c5..1702080ff 100644 --- a/score/crypto/src/api/objects/BUILD +++ b/score/crypto/src/api/objects/BUILD @@ -31,3 +31,19 @@ cc_library( "@score_baselibs//score/result", ], ) + +cc_library( + name = "cert_objects", + hdrs = [ + "i_cert_slot_object.hpp", + "i_certificate_object.hpp", + ], + includes = ["."], + visibility = ["//visibility:public"], + deps = [ + ":crypto_objects", + "//score/crypto/src/api/common:crypto_common", + "@score_baselibs//score/language/futurecpp", + "@score_baselibs//score/result", + ], +) diff --git a/score/crypto/src/api/future/objects/i_cert_slot_object.hpp b/score/crypto/src/api/objects/i_cert_slot_object.hpp similarity index 88% rename from score/crypto/src/api/future/objects/i_cert_slot_object.hpp rename to score/crypto/src/api/objects/i_cert_slot_object.hpp index bd778556f..d6444b5d5 100644 --- a/score/crypto/src/api/future/objects/i_cert_slot_object.hpp +++ b/score/crypto/src/api/objects/i_cert_slot_object.hpp @@ -11,8 +11,8 @@ * SPDX-License-Identifier: Apache-2.0 ********************************************************************************/ -#ifndef SCORE_CRYPTO_SRC_API_FUTURE_OBJECTS_I_CERT_SLOT_OBJECT_HPP -#define SCORE_CRYPTO_SRC_API_FUTURE_OBJECTS_I_CERT_SLOT_OBJECT_HPP +#ifndef SCORE_CRYPTO_SRC_API_OBJECTS_I_CERT_SLOT_OBJECT_HPP +#define SCORE_CRYPTO_SRC_API_OBJECTS_I_CERT_SLOT_OBJECT_HPP #include "score/crypto/src/api/objects/i_crypto_object.hpp" @@ -51,4 +51,4 @@ class ICertSlotObject : public ICryptoObject } // namespace score -#endif // SCORE_CRYPTO_SRC_API_FUTURE_OBJECTS_I_CERT_SLOT_OBJECT_HPP +#endif // SCORE_CRYPTO_SRC_API_OBJECTS_I_CERT_SLOT_OBJECT_HPP diff --git a/score/crypto/src/api/future/objects/i_certificate_object.hpp b/score/crypto/src/api/objects/i_certificate_object.hpp similarity index 95% rename from score/crypto/src/api/future/objects/i_certificate_object.hpp rename to score/crypto/src/api/objects/i_certificate_object.hpp index e3ed4992d..d09a62224 100644 --- a/score/crypto/src/api/future/objects/i_certificate_object.hpp +++ b/score/crypto/src/api/objects/i_certificate_object.hpp @@ -11,8 +11,8 @@ * SPDX-License-Identifier: Apache-2.0 ********************************************************************************/ -#ifndef SCORE_CRYPTO_SRC_API_FUTURE_OBJECTS_I_CERTIFICATE_OBJECT_HPP -#define SCORE_CRYPTO_SRC_API_FUTURE_OBJECTS_I_CERTIFICATE_OBJECT_HPP +#ifndef SCORE_CRYPTO_SRC_API_OBJECTS_I_CERTIFICATE_OBJECT_HPP +#define SCORE_CRYPTO_SRC_API_OBJECTS_I_CERTIFICATE_OBJECT_HPP #include "score/crypto/src/api/objects/i_crypto_object.hpp" #include "score/result/result.h" @@ -105,4 +105,4 @@ class ICertificateObject : public ICryptoObject } // namespace score -#endif // SCORE_CRYPTO_SRC_API_FUTURE_OBJECTS_I_CERTIFICATE_OBJECT_HPP +#endif // SCORE_CRYPTO_SRC_API_OBJECTS_I_CERTIFICATE_OBJECT_HPP From f6830b6950e2ea183ea9366996dd2a299b8a4f87 Mon Sep 17 00:00:00 2001 From: Athul Mallappallil Date: Thu, 30 Jul 2026 22:00:40 +0200 Subject: [PATCH 03/25] Utility fns to Enc/Dec Str to Hex val --- score/crypto/src/daemon/common/BUILD | 1 + score/crypto/src/daemon/common/hex.hpp | 64 ++++++++++++++++++++++++++ 2 files changed, 65 insertions(+) create mode 100644 score/crypto/src/daemon/common/hex.hpp diff --git a/score/crypto/src/daemon/common/BUILD b/score/crypto/src/daemon/common/BUILD index 1cfebd98d..03b571a32 100644 --- a/score/crypto/src/daemon/common/BUILD +++ b/score/crypto/src/daemon/common/BUILD @@ -18,6 +18,7 @@ cc_library( hdrs = [ "actors.hpp", "daemon_error.hpp", + "hex.hpp", "secure_memory.hpp", "types.hpp", ], diff --git a/score/crypto/src/daemon/common/hex.hpp b/score/crypto/src/daemon/common/hex.hpp new file mode 100644 index 000000000..18cc79872 --- /dev/null +++ b/score/crypto/src/daemon/common/hex.hpp @@ -0,0 +1,64 @@ +/******************************************************************************** + * Copyright (c) 2026 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ + +#ifndef SCORE_CRYPTO_SRC_DAEMON_COMMON_HEX_HPP +#define SCORE_CRYPTO_SRC_DAEMON_COMMON_HEX_HPP + +#include "score/crypto/common/types.hpp" + +#include +#include +#include +#include +#include + +namespace score::crypto::daemon::common +{ + +[[nodiscard]] inline std::string EncodeHex(score::crypto::span bytes) +{ + static constexpr char kHex[] = "0123456789abcdef"; + std::string result; + result.reserve(bytes.size() * 2U); + for (const auto byte : bytes) + { + result.push_back(kHex[(byte >> 4U) & 0x0FU]); + result.push_back(kHex[byte & 0x0FU]); + } + return result; +} + +[[nodiscard]] inline std::optional> DecodeHex(const std::string& value) +{ + if ((value.size() % 2U) != 0U) + return std::nullopt; + + const auto nibble = [](char c) -> int { + c = static_cast(std::tolower(static_cast(c))); + return c >= '0' && c <= '9' ? c - '0' : (c >= 'a' && c <= 'f' ? c - 'a' + 10 : -1); + }; + std::vector result(value.size() / 2U); + for (std::size_t i = 0U; i < result.size(); ++i) + { + const int high = nibble(value[2U * i]); + const int low = nibble(value[2U * i + 1U]); + if (high < 0 || low < 0) + return std::nullopt; + result[i] = static_cast((high << 4) | low); + } + return result; +} + +} // namespace score::crypto::daemon::common + +#endif // SCORE_CRYPTO_SRC_DAEMON_COMMON_HEX_HPP From 71e76a312df2f207c2ed2bc257565eaa55e69477 Mon Sep 17 00:00:00 2001 From: Athul Mallappallil Date: Fri, 7 Aug 2026 20:52:18 +0000 Subject: [PATCH 04/25] Pvdr mgr fix and capability selection --- score/crypto/src/daemon/common/types.hpp | 44 ++++++ .../crypto/src/daemon/provider/i_provider.hpp | 33 +++++ .../src/daemon/provider/provider_manager.hpp | 25 ++++ .../daemon/provider/src/provider_manager.cpp | 91 ++++++++++-- .../provider/src/provider_manager_test.cpp | 135 +++++++++++++++++- 5 files changed, 317 insertions(+), 11 deletions(-) diff --git a/score/crypto/src/daemon/common/types.hpp b/score/crypto/src/daemon/common/types.hpp index 9f3bdfdf0..55b112cb2 100644 --- a/score/crypto/src/daemon/common/types.hpp +++ b/score/crypto/src/daemon/common/types.hpp @@ -180,6 +180,50 @@ inline CryptoProviderType CryptoProviderTypeFromString(const std::string& typeSt } } +/** + * @brief Functional capabilities a crypto provider can offer. + * + * Capabilities are orthogonal to CryptoProviderType (HARDWARE/SOFTWARE/...): a + * single provider may offer several at once. ProviderManager uses them to select + * a default provider for a specific functional area (e.g. certificate + * operations) instead of relying on the hardware/software category alone — a + * DEFAULT provider is not guaranteed to support every functional area. + * + * Values are a bitmask so a provider's full capability set fits in one field. + */ +enum class ProviderCapability : std::uint8_t +{ + kNone = 0x00U, ///< No functional capability advertised + kCrypto = 0x01U, ///< Symmetric cipher / hash / MAC handlers (GetCryptoHandlerFactory) + kKeyManagement = 0x02U, ///< Key generation / storage (GetKeyFactory / GetKeySlotHandler) + kCertManagement = 0x04U, ///< Certificate parse / verify / CSR (GetCertFactory) +}; + +/// @brief Bitwise OR for combining provider capabilities. +inline constexpr ProviderCapability operator|(ProviderCapability lhs, ProviderCapability rhs) noexcept +{ + return static_cast(static_cast(lhs) | static_cast(rhs)); +} + +/// @brief Bitwise AND for testing provider capabilities. +inline constexpr ProviderCapability operator&(ProviderCapability lhs, ProviderCapability rhs) noexcept +{ + return static_cast(static_cast(lhs) & static_cast(rhs)); +} + +/// @brief Bitwise OR-assign for accumulating provider capabilities. +inline constexpr ProviderCapability& operator|=(ProviderCapability& lhs, ProviderCapability rhs) noexcept +{ + lhs = lhs | rhs; + return lhs; +} + +/// @brief True when @p caps includes every capability bit in @p required. +inline constexpr bool HasCapability(ProviderCapability caps, ProviderCapability required) noexcept +{ + return (caps & required) == required; +} + } // namespace score::crypto::daemon::common /** diff --git a/score/crypto/src/daemon/provider/i_provider.hpp b/score/crypto/src/daemon/provider/i_provider.hpp index b7dc53b57..bbe001ed8 100644 --- a/score/crypto/src/daemon/provider/i_provider.hpp +++ b/score/crypto/src/daemon/provider/i_provider.hpp @@ -147,6 +147,39 @@ class IProvider { return nullptr; } + + // ----------------------------------------------------------------------- + // Capability advertisement + // ----------------------------------------------------------------------- + + /// @brief Report the functional capabilities this provider offers. + /// + /// The default derives the capability set directly from the capability + /// accessors above — the single source of truth — so a provider that + /// returns a non-null factory automatically advertises the matching + /// capability. Providers whose capability cannot be inferred from an + /// accessor (e.g. a backend that offers certificate operations only through + /// an extension) override this to declare the correct set. + /// + /// Used by ProviderManager::GetProviderForCapability() to pick a default + /// provider for a functional area rather than by hardware/software category. + [[nodiscard]] virtual common::ProviderCapability GetProviderCapabilities() + { + common::ProviderCapability caps = common::ProviderCapability::kNone; + if (GetCryptoHandlerFactory() != nullptr) + { + caps |= common::ProviderCapability::kCrypto; + } + if (GetKeyFactory() != nullptr) + { + caps |= common::ProviderCapability::kKeyManagement; + } + if (GetCertFactory() != nullptr) + { + caps |= common::ProviderCapability::kCertManagement; + } + return caps; + } }; } // namespace score::crypto::daemon::provider diff --git a/score/crypto/src/daemon/provider/provider_manager.hpp b/score/crypto/src/daemon/provider/provider_manager.hpp index 38fead7c8..eb0ef1193 100644 --- a/score/crypto/src/daemon/provider/provider_manager.hpp +++ b/score/crypto/src/daemon/provider/provider_manager.hpp @@ -160,6 +160,31 @@ class ProviderManager */ std::shared_ptr GetProvider(common::CryptoProviderType cryptoType) const; + /** + * @brief Select the preferred initialized provider that offers a capability. + * + * Filters registered providers to those that are initialized and advertise + * @p capability (via IProvider::GetProviderCapabilities()), then chooses + * among them by @p preferenceOrder over CryptoProviderType. Falls back to + * the lowest-id capable provider when none match the preference. + * + * This is the capability-aware counterpart to GetProvider(CryptoProviderType): + * callers that need a functional area (e.g. certificate operations) but do + * not care which specific provider serves it use this instead of the + * category-only default, so a DEFAULT provider that lacks the capability is + * never returned. Most certificate callers rely on this default resolution; + * clients that must pin a specific provider resolve it by name/ID instead. + * + * @param capability The functional capability the provider must offer. + * @param preferenceOrder Category priority among capable providers. Defaults + * to HARDWARE → SOFTWARE; certificate callers pass SOFTWARE first. + * @return The selected provider, or nullptr if none offers the capability. + */ + [[nodiscard]] std::shared_ptr GetProviderForCapability( + common::ProviderCapability capability, + const std::vector& preferenceOrder = {common::CryptoProviderType::HARDWARE, + common::CryptoProviderType::SOFTWARE}) const; + /** * @brief Set a provider as default for a specific crypto provider type * diff --git a/score/crypto/src/daemon/provider/src/provider_manager.cpp b/score/crypto/src/daemon/provider/src/provider_manager.cpp index 78f3eb632..b2f080f0b 100644 --- a/score/crypto/src/daemon/provider/src/provider_manager.cpp +++ b/score/crypto/src/daemon/provider/src/provider_manager.cpp @@ -80,30 +80,65 @@ void ProviderManager::RecordFactoryResult(const std::string& factoryName, Provid common::ProviderName ProviderManager::ResolveDefaultProviderName( const std::vector& preferenceOrder) { - std::unordered_map byType; - common::ProviderName anyName; - for (const auto& [name, entry] : m_providers) + // Prefer providers that initialized successfully so the default maps to a + // usable provider whenever one exists — InitializeAll() has already run by + // the time Initialize() calls this. Registered-but-failed providers are kept + // as a fallback only: if none initialized yet (e.g. all temporarily + // unavailable at startup), the default still resolves to a registered name + // so it can be retried on a later lookup via EnsureProviderInitialized(). + std::unordered_map initializedByType; + std::unordered_map registeredByType; + common::ProviderName anyInitializedName; + common::ProviderName anyRegisteredName; + + // Iterate in numeric-id (registration) order for deterministic selection. + for (common::ProviderId id = 0; id < m_provider_by_id.size(); ++id) { + const auto& entry = m_providers.at(m_name_by_id[id]); if (!entry.instance) { continue; } - byType.emplace(entry.cryptoType, name); - if (anyName.empty()) + registeredByType.emplace(entry.cryptoType, entry.name); + if (anyRegisteredName.empty()) { - anyName = name; + anyRegisteredName = entry.name; + } + if (entry.instance->IsInitialized()) + { + initializedByType.emplace(entry.cryptoType, entry.name); + if (anyInitializedName.empty()) + { + anyInitializedName = entry.name; + } } } + // First choice: preferred type among successfully-initialized providers. for (const auto& preferred : preferenceOrder) { - auto it = byType.find(preferred); - if (it != byType.end()) + const auto it = initializedByType.find(preferred); + if (it != initializedByType.end()) { return it->second; } } - return anyName; + if (!anyInitializedName.empty()) + { + return anyInitializedName; + } + + // Fallback: nothing initialized yet — resolve to a registered provider so a + // temporarily-unavailable provider can still be retried on later lookups. + for (const auto& preferred : preferenceOrder) + { + const auto it = registeredByType.find(preferred); + if (it != registeredByType.end()) + { + return it->second; + } + } + return anyRegisteredName; } bool ProviderManager::BuildTypeMappings( @@ -235,6 +270,44 @@ std::shared_ptr ProviderManager::GetProvider(common::CryptoProviderTy return provider_entry.instance; } +std::shared_ptr ProviderManager::GetProviderForCapability( + common::ProviderCapability capability, + const std::vector& preferenceOrder) const +{ + std::unordered_map> byType; + std::shared_ptr firstCapable; + + // Iterate in numeric-id order so the fallback selection is deterministic. + for (common::ProviderId id = 0; id < m_provider_by_id.size(); ++id) + { + auto& entry = const_cast(m_providers.at(m_name_by_id[id])); + if (!EnsureProviderInitialized(entry)) + { + continue; + } + if (!common::HasCapability(entry.instance->GetProviderCapabilities(), capability)) + { + continue; + } + // First capable provider of each category wins; earlier ids take priority. + byType.emplace(entry.cryptoType, entry.instance); + if (!firstCapable) + { + firstCapable = entry.instance; + } + } + + for (const auto& preferred : preferenceOrder) + { + const auto it = byType.find(preferred); + if (it != byType.end()) + { + return it->second; + } + } + return firstCapable; +} + bool ProviderManager::SetDefaultProviderForType(common::CryptoProviderType cryptoType, common::ProviderId providerId) { // Verify the provider exists by numeric ID and is initialized diff --git a/score/crypto/src/daemon/provider/src/provider_manager_test.cpp b/score/crypto/src/daemon/provider/src/provider_manager_test.cpp index 7cb656dd6..c3daef732 100644 --- a/score/crypto/src/daemon/provider/src/provider_manager_test.cpp +++ b/score/crypto/src/daemon/provider/src/provider_manager_test.cpp @@ -31,8 +31,11 @@ namespace class ConfigurableStubProvider final : public provider::IProvider { public: - ConfigurableStubProvider(const std::string& name, common::ProviderId id, bool fail_init) - : m_name{name}, m_id{id}, m_fail_init{fail_init} + ConfigurableStubProvider(const std::string& name, + common::ProviderId id, + bool fail_init, + common::ProviderCapability capabilities = common::ProviderCapability::kNone) + : m_name{name}, m_id{id}, m_fail_init{fail_init}, m_capabilities{capabilities} { } @@ -65,10 +68,16 @@ class ConfigurableStubProvider final : public provider::IProvider return m_name; } + common::ProviderCapability GetProviderCapabilities() override + { + return m_capabilities; + } + private: std::string m_name; common::ProviderId m_id; bool m_fail_init; + common::ProviderCapability m_capabilities; bool m_initialized{false}; }; } // namespace @@ -186,3 +195,125 @@ TEST(ProviderManagerInitStateTest, FailedProviderRemainsRegisteredButUnavailable EXPECT_TRUE(mgr.GetProviderType("OK_PROVIDER").has_value()); EXPECT_TRUE(mgr.GetProviderType("FAIL_PROVIDER").has_value()); } + +// =========================================================================== +// GetProviderForCapability +// =========================================================================== + +namespace +{ +// SW provider offers crypto + cert; HW provider offers crypto + key management. +provider::ProviderManager::Sptr MakeCapabilityManager() +{ + score::crypto::daemon::config::Config config; + auto mgr = std::make_shared(config.GetProviderInitConfig()); + + mgr->RegisterProvider( + "SW_PROVIDER", + std::make_shared( + "SW_PROVIDER", 0, false, + common::ProviderCapability::kCrypto | common::ProviderCapability::kCertManagement), + common::CryptoProviderType::SOFTWARE); + + mgr->RegisterProvider( + "HW_PROVIDER", + std::make_shared( + "HW_PROVIDER", 1, false, + common::ProviderCapability::kCrypto | common::ProviderCapability::kKeyManagement), + common::CryptoProviderType::HARDWARE); + + mgr->Initialize(); + return mgr; +} +} // namespace + +TEST(ProviderManagerCapabilityTest, ReturnsOnlyCapableProvider) +{ + auto mgr = MakeCapabilityManager(); + // Only the SW provider advertises certificate capability. + auto cert_prov = mgr->GetProviderForCapability(common::ProviderCapability::kCertManagement); + ASSERT_NE(cert_prov, nullptr); + EXPECT_EQ(cert_prov->GetProviderName(), "SW_PROVIDER"); +} + +TEST(ProviderManagerCapabilityTest, PreferenceOrderPicksAmongCapableProviders) +{ + auto mgr = MakeCapabilityManager(); + // Both providers offer crypto; preference decides which is returned. + auto sw_first = mgr->GetProviderForCapability( + common::ProviderCapability::kCrypto, + {common::CryptoProviderType::SOFTWARE, common::CryptoProviderType::HARDWARE}); + ASSERT_NE(sw_first, nullptr); + EXPECT_EQ(sw_first->GetProviderName(), "SW_PROVIDER"); + + auto hw_first = mgr->GetProviderForCapability( + common::ProviderCapability::kCrypto, + {common::CryptoProviderType::HARDWARE, common::CryptoProviderType::SOFTWARE}); + ASSERT_NE(hw_first, nullptr); + EXPECT_EQ(hw_first->GetProviderName(), "HW_PROVIDER"); +} + +TEST(ProviderManagerCapabilityTest, ReturnsNullWhenNoProviderOffersCapability) +{ + score::crypto::daemon::config::Config config; + provider::ProviderManager mgr(config.GetProviderInitConfig()); + mgr.RegisterProvider("SW_PROVIDER", + std::make_shared( + "SW_PROVIDER", 0, false, common::ProviderCapability::kCrypto), + common::CryptoProviderType::SOFTWARE); + mgr.Initialize(); + + EXPECT_EQ(mgr.GetProviderForCapability(common::ProviderCapability::kCertManagement), nullptr); +} + +TEST(ProviderManagerCapabilityTest, FallsBackToCapableProviderOutsidePreference) +{ + auto mgr = MakeCapabilityManager(); + // Key management is only on HW; a SOFTWARE-only preference still finds it + // via the lowest-id capable fallback rather than returning nullptr. + auto key_prov = + mgr->GetProviderForCapability(common::ProviderCapability::kKeyManagement, + {common::CryptoProviderType::SOFTWARE}); + ASSERT_NE(key_prov, nullptr); + EXPECT_EQ(key_prov->GetProviderName(), "HW_PROVIDER"); +} + +TEST(ProviderManagerCapabilityTest, UninitializedProviderIsNotSelected) +{ + score::crypto::daemon::config::Config config; + provider::ProviderManager mgr(config.GetProviderInitConfig()); + // Capable on paper, but initialization fails so it must be skipped. + mgr.RegisterProvider("FAIL_PROVIDER", + std::make_shared( + "FAIL_PROVIDER", 0, true, common::ProviderCapability::kCertManagement), + common::CryptoProviderType::SOFTWARE); + mgr.Initialize(); + + EXPECT_EQ(mgr.GetProviderForCapability(common::ProviderCapability::kCertManagement), nullptr); +} + +// =========================================================================== +// Default provider resolution prefers successfully-initialized providers +// =========================================================================== + +TEST(ProviderManagerDefaultResolutionTest, DefaultSkipsFailedPreferredProvider) +{ + score::crypto::daemon::config::Config config; + provider::ProviderManager mgr(config.GetProviderInitConfig()); + + // Preferred category (HARDWARE) is registered but fails to initialize; + // the SOFTWARE provider initializes successfully. + mgr.RegisterProvider("HW_PROVIDER", + std::make_shared("HW_PROVIDER", 0, /*fail_init=*/true), + common::CryptoProviderType::HARDWARE); + mgr.RegisterProvider("SW_PROVIDER", + std::make_shared("SW_PROVIDER", 1, /*fail_init=*/false), + common::CryptoProviderType::SOFTWARE); + mgr.Initialize(); + + // DEFAULT must resolve to the initialized SOFTWARE provider rather than the + // failed HARDWARE provider that the preference order would otherwise pick. + auto def = mgr.GetProvider(common::CryptoProviderType::DEFAULT); + ASSERT_NE(def, nullptr); + EXPECT_EQ(def->GetProviderName(), "SW_PROVIDER"); +} From 43d19ca5c908abef3cb11943ba823364ff8222e3 Mon Sep 17 00:00:00 2001 From: Athul Mallappallil Date: Tue, 11 Aug 2026 12:52:13 +0000 Subject: [PATCH 05/25] Correction in ResourceType --- score/crypto/docs/architecture/api_description.rst | 4 ++-- score/crypto/docs/architecture/design_decisions.rst | 2 +- score/crypto/docs/architecture/dynamic_architecture.rst | 4 ++-- score/crypto/src/api/common/types.hpp | 8 ++++---- .../api/contexts/i_certificate_verification_context.hpp | 4 ++-- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/score/crypto/docs/architecture/api_description.rst b/score/crypto/docs/architecture/api_description.rst index c5e3b4b4a..da2de27a5 100644 --- a/score/crypto/docs/architecture/api_description.rst +++ b/score/crypto/docs/architecture/api_description.rst @@ -40,8 +40,8 @@ The API uses a two-phase resource identification model: struct CryptoResourceId { uint64_t id; // daemon-assigned, unique per session - ResourceType type; // kProvider, kKeySlot, kCertSlot, kVerificationTrustStore, - // kKey, kCertificate, kCrl, kSecureObject, kDataObject + ResourceType type; // kProvider, kKeySlot, kCertSlot, kCertificateTrustStore, + // kKey, kCertificate, kSecureObject, kDataObject ResourcePersistence persistence; // kPersistent or kEphemeral uint16_t primary_provider; // owning device/provider index (0 = unbound) }; diff --git a/score/crypto/docs/architecture/design_decisions.rst b/score/crypto/docs/architecture/design_decisions.rst index 35361d7ed..432b05f9f 100644 --- a/score/crypto/docs/architecture/design_decisions.rst +++ b/score/crypto/docs/architecture/design_decisions.rst @@ -336,7 +336,7 @@ Scope ^^^^^ Applies to ``kPersistent`` resources only: ``kKeySlot``, ``kCertificate``, -``kCertSlot``, ``kVerificationTrustStore``. Ephemeral (``kKey``) IDs remain session-scoped +``kCertSlot``, ``kCertificateTrustStore``. Ephemeral (``kKey``) IDs remain session-scoped (valid only within the ``IKeyManagementContext`` session that produced them). IPC Schema diff --git a/score/crypto/docs/architecture/dynamic_architecture.rst b/score/crypto/docs/architecture/dynamic_architecture.rst index 0b693bda3..a68be6a1d 100644 --- a/score/crypto/docs/architecture/dynamic_architecture.rst +++ b/score/crypto/docs/architecture/dynamic_architecture.rst @@ -19,7 +19,7 @@ API Dynamic Architecture .. code-block:: rst - + .. comp_arc_dyn:: Dynamic View :id: comp_arc_dyn__crypto__dynamic_view :security: YES @@ -208,7 +208,7 @@ Certificate Verification // Resolve certificate and verification trust store auto cert = ctx->ResolveResource("DeviceCert", ResourceType::kCertSlot).value(); - auto anchor = ctx->ResolveResource("RootCA", ResourceType::kVerificationTrustStore).value(); + auto anchor = ctx->ResolveResource("RootCA", ResourceType::kCertificateTrustStore).value(); // Verify using builder-style context CertificateVerificationContextConfig verify_cfg; diff --git a/score/crypto/src/api/common/types.hpp b/score/crypto/src/api/common/types.hpp index 31f75584f..4e8df63fc 100644 --- a/score/crypto/src/api/common/types.hpp +++ b/score/crypto/src/api/common/types.hpp @@ -60,12 +60,12 @@ enum class ResourceType : uint8_t kProvider, ///< Crypto provider / device kKeySlot, ///< Persistent key storage slot kCertSlot, ///< Persistent certificate storage slot - kVerificationTrustStore, ///< Named group of trusted CA certificates used for certificate chain + kCertificateTrustStore, ///< Named group of trusted CA certificates used for certificate chain ///< verification. kKey, ///< Key material (generated / loaded / derived / imported) - kCertificate, ///< Parsed or stored certificate object - kCrl, ///< Certificate Revocation List — shares the same numeric id - ///< as the issuer certificate resource (differentiated by type field) + kCertificate, ///< Parsed or stored certificate object. + ///< CRLs are not a resource type: they are co-located with the + ///< issuer's certificate slot and never independently resolvable. kSecureObject, ///< Secure storage entry kDataObject ///< Generic data blob }; diff --git a/score/crypto/src/api/contexts/i_certificate_verification_context.hpp b/score/crypto/src/api/contexts/i_certificate_verification_context.hpp index f8059f9a6..108e0838f 100644 --- a/score/crypto/src/api/contexts/i_certificate_verification_context.hpp +++ b/score/crypto/src/api/contexts/i_certificate_verification_context.hpp @@ -84,11 +84,11 @@ class ICertificateVerificationContext : public IContext /// @brief Sets the system trust store to use for certificate chain verification. /// /// The trust store is a manifest-configured named group of persistent certificate - /// slots. Resolve it by name with ResourceType::kVerificationTrustStore. + /// slots. Resolve it by name with ResourceType::kCertificateTrustStore. /// Empty slots in the store are silently skipped at verification time. /// /// @param trust_store Handle to the verification trust store - /// (type = kVerificationTrustStore) + /// (type = kCertificateTrustStore) /// @return std::monostate on success, error if handle is invalid virtual score::Result SetVerificationTrustStore(const CryptoResourceId& trust_store) = 0; From 735893ac220d9e555d1c19639aba790a8451dab7 Mon Sep 17 00:00:00 2001 From: Athul Mallappallil Date: Tue, 11 Aug 2026 13:39:43 +0000 Subject: [PATCH 06/25] Capability selection based on ctx id --- score/crypto/src/daemon/common/hex.hpp | 2 +- .../src/daemon/mediator/src/mediator_impl.cpp | 26 ++++++++++++++- .../crypto/src/daemon/provider/i_provider.hpp | 27 ++++------------ .../provider/pkcs11/pkcs11_provider.hpp | 7 ++++ .../src/daemon/provider/provider_manager.hpp | 32 ++++++++++++------- .../openssl/provider_openssl.cpp | 6 ++++ .../openssl/provider_openssl.hpp | 3 ++ .../daemon/provider/src/provider_manager.cpp | 16 ++++++++++ 8 files changed, 85 insertions(+), 34 deletions(-) diff --git a/score/crypto/src/daemon/common/hex.hpp b/score/crypto/src/daemon/common/hex.hpp index 18cc79872..c97f32eb1 100644 --- a/score/crypto/src/daemon/common/hex.hpp +++ b/score/crypto/src/daemon/common/hex.hpp @@ -14,7 +14,7 @@ #ifndef SCORE_CRYPTO_SRC_DAEMON_COMMON_HEX_HPP #define SCORE_CRYPTO_SRC_DAEMON_COMMON_HEX_HPP -#include "score/crypto/common/types.hpp" +#include "score/crypto/src/common/types.hpp" #include #include diff --git a/score/crypto/src/daemon/mediator/src/mediator_impl.cpp b/score/crypto/src/daemon/mediator/src/mediator_impl.cpp index b4cd5d8ab..589373d2f 100644 --- a/score/crypto/src/daemon/mediator/src/mediator_impl.cpp +++ b/score/crypto/src/daemon/mediator/src/mediator_impl.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -301,6 +302,22 @@ bool MediatorImpl::HandleContextCreationOperation(const score::crypto::daemon::c } } + // Scoped context types encode the capability as a prefix ("CERT:VERIFICATION", "KEY:MANAGEMENT"). + // Unscoped types ("HASH", "MAC") fall back to type-based provider selection. + // To add a new scope: add one entry to kScopeCapability. + static const std::unordered_map kScopeCapability{ + {"CERT", common::ProviderCapability::kCertManagement}, + {"KEY", common::ProviderCapability::kKeyManagement}, + }; + common::ProviderCapability required_capability = common::ProviderCapability::kNone; + const auto colon_pos = context_type.find(':'); + if (colon_pos != std::string_view::npos) + { + const auto it = kScopeCapability.find(context_type.substr(0, colon_pos)); + if (it != kScopeCapability.end()) + required_capability = it->second; + } + // --- Resolve target provider (considers key/slot affinity when available) --- std::shared_ptr provider; if (m_km_service && has_key_binding) @@ -317,6 +334,11 @@ bool MediatorImpl::HandleContextCreationOperation(const score::crypto::daemon::c } provider = m_provider_manager->GetProvider(resolved_id_res.value()); } + else if (required_capability != common::ProviderCapability::kNone + && requested_provider_type == common::CryptoProviderType::DEFAULT) + { + provider = m_provider_manager->GetProviderForCapability(required_capability); + } else { provider = m_provider_manager->GetProvider(requested_provider_type); @@ -414,7 +436,9 @@ bool MediatorImpl::HandleContextCreationOperation(const score::crypto::daemon::c } const std::string_view provider_selection = - has_key_binding ? " (key-affinity resolved)" : " (type-based selection)"; + has_key_binding ? " (key-affinity resolved)" + : required_capability != common::ProviderCapability::kNone ? " (capability-based selection)" + : " (type-based selection)"; score::mw::log::LogVerbose() << "[SCORE_API_MED] CTX_CREATE [" << context_type << "/" << algorithm << "] selected provider: name='" << provider->GetProviderName() << "' id=" << provider->GetProviderId() << provider_selection diff --git a/score/crypto/src/daemon/provider/i_provider.hpp b/score/crypto/src/daemon/provider/i_provider.hpp index bbe001ed8..c418ec559 100644 --- a/score/crypto/src/daemon/provider/i_provider.hpp +++ b/score/crypto/src/daemon/provider/i_provider.hpp @@ -154,31 +154,18 @@ class IProvider /// @brief Report the functional capabilities this provider offers. /// - /// The default derives the capability set directly from the capability - /// accessors above — the single source of truth — so a provider that - /// returns a non-null factory automatically advertises the matching - /// capability. Providers whose capability cannot be inferred from an - /// accessor (e.g. a backend that offers certificate operations only through - /// an extension) override this to declare the correct set. + /// Concrete providers MUST override this and return their full capability set + /// explicitly. The default returns kNone so an unoverridden provider is never + /// selected by GetProviderForCapability() — a silent miss is always preferable + /// to a mis-routed operation. Derivation from accessor returns is intentionally + /// avoided: as capability entry points evolve, heuristic derivation becomes + /// incorrect. /// /// Used by ProviderManager::GetProviderForCapability() to pick a default /// provider for a functional area rather than by hardware/software category. [[nodiscard]] virtual common::ProviderCapability GetProviderCapabilities() { - common::ProviderCapability caps = common::ProviderCapability::kNone; - if (GetCryptoHandlerFactory() != nullptr) - { - caps |= common::ProviderCapability::kCrypto; - } - if (GetKeyFactory() != nullptr) - { - caps |= common::ProviderCapability::kKeyManagement; - } - if (GetCertFactory() != nullptr) - { - caps |= common::ProviderCapability::kCertManagement; - } - return caps; + return common::ProviderCapability::kNone; } }; diff --git a/score/crypto/src/daemon/provider/pkcs11/pkcs11_provider.hpp b/score/crypto/src/daemon/provider/pkcs11/pkcs11_provider.hpp index 500b7265d..d94a41055 100644 --- a/score/crypto/src/daemon/provider/pkcs11/pkcs11_provider.hpp +++ b/score/crypto/src/daemon/provider/pkcs11/pkcs11_provider.hpp @@ -86,6 +86,13 @@ class Pkcs11Provider final : public IProvider, public std::enable_shared_from_th [[nodiscard]] common::ProviderId GetProviderId() const override; [[nodiscard]] const common::ProviderName& GetProviderName() const override; + // --- Capability advertisement --- + + [[nodiscard]] common::ProviderCapability GetProviderCapabilities() override + { + return common::ProviderCapability::kCrypto | common::ProviderCapability::kKeyManagement; + } + // --- Crypto capability --- [[nodiscard]] std::shared_ptr GetCryptoHandlerFactory() override; diff --git a/score/crypto/src/daemon/provider/provider_manager.hpp b/score/crypto/src/daemon/provider/provider_manager.hpp index eb0ef1193..fbcf975c2 100644 --- a/score/crypto/src/daemon/provider/provider_manager.hpp +++ b/score/crypto/src/daemon/provider/provider_manager.hpp @@ -165,25 +165,33 @@ class ProviderManager * * Filters registered providers to those that are initialized and advertise * @p capability (via IProvider::GetProviderCapabilities()), then chooses - * among them by @p preferenceOrder over CryptoProviderType. Falls back to - * the lowest-id capable provider when none match the preference. + * among them using the per-capability default preference order defined in + * ProviderManager. Falls back to the lowest-id capable provider when no + * preferred-category provider is found. * - * This is the capability-aware counterpart to GetProvider(CryptoProviderType): - * callers that need a functional area (e.g. certificate operations) but do - * not care which specific provider serves it use this instead of the - * category-only default, so a DEFAULT provider that lacks the capability is - * never returned. Most certificate callers rely on this default resolution; - * clients that must pin a specific provider resolve it by name/ID instead. + * Per-capability defaults: kCertManagement → SOFTWARE first (parsing/verification + * are inherently software); kKeyManagement and kCrypto → HARDWARE first. + * + * @param capability The functional capability the provider must offer. + * @return The selected provider, or nullptr if none offers the capability. + */ + [[nodiscard]] std::shared_ptr GetProviderForCapability( + common::ProviderCapability capability) const; + + /** + * @brief Select the preferred initialized provider with an explicit category order. + * + * Same as GetProviderForCapability(capability) but lets the caller override + * the preference order. Use this overload only when testing ordering behavior + * or when a specific call site needs a non-default preference. * * @param capability The functional capability the provider must offer. - * @param preferenceOrder Category priority among capable providers. Defaults - * to HARDWARE → SOFTWARE; certificate callers pass SOFTWARE first. + * @param preferenceOrder Category priority among capable providers. * @return The selected provider, or nullptr if none offers the capability. */ [[nodiscard]] std::shared_ptr GetProviderForCapability( common::ProviderCapability capability, - const std::vector& preferenceOrder = {common::CryptoProviderType::HARDWARE, - common::CryptoProviderType::SOFTWARE}) const; + const std::vector& preferenceOrder) const; /** * @brief Set a provider as default for a specific crypto provider type diff --git a/score/crypto/src/daemon/provider/score_provider/openssl/provider_openssl.cpp b/score/crypto/src/daemon/provider/score_provider/openssl/provider_openssl.cpp index f9285ea49..411a80357 100644 --- a/score/crypto/src/daemon/provider/score_provider/openssl/provider_openssl.cpp +++ b/score/crypto/src/daemon/provider/score_provider/openssl/provider_openssl.cpp @@ -68,6 +68,12 @@ std::shared_ptr<::score::crypto::daemon::provider::handler::ICryptoHandlerFactor return std::make_shared(m_factory, GetKeySlotHandler({}), m_keyManagementService); } +common::ProviderCapability OpenSSL::GetProviderCapabilities() +{ + return common::ProviderCapability::kCrypto | common::ProviderCapability::kKeyManagement | + common::ProviderCapability::kCertManagement; +} + std::shared_ptr OpenSSL::GetKeyFactory() { return m_factory; diff --git a/score/crypto/src/daemon/provider/score_provider/openssl/provider_openssl.hpp b/score/crypto/src/daemon/provider/score_provider/openssl/provider_openssl.hpp index 07d82a1d8..9858edbe3 100644 --- a/score/crypto/src/daemon/provider/score_provider/openssl/provider_openssl.hpp +++ b/score/crypto/src/daemon/provider/score_provider/openssl/provider_openssl.hpp @@ -41,6 +41,9 @@ class OpenSSL final : public ::score::crypto::daemon::provider::score_provider:: // --- IProvider lifecycle (OpenSSL-specific) --- void Shutdown() override; + // --- Capability advertisement --- + [[nodiscard]] common::ProviderCapability GetProviderCapabilities() override; + // --- Key management capability --- std::shared_ptr GetKeyFactory() override; std::shared_ptr GetKeySlotHandler( diff --git a/score/crypto/src/daemon/provider/src/provider_manager.cpp b/score/crypto/src/daemon/provider/src/provider_manager.cpp index b2f080f0b..a9771e491 100644 --- a/score/crypto/src/daemon/provider/src/provider_manager.cpp +++ b/score/crypto/src/daemon/provider/src/provider_manager.cpp @@ -270,6 +270,22 @@ std::shared_ptr ProviderManager::GetProvider(common::CryptoProviderTy return provider_entry.instance; } +std::shared_ptr ProviderManager::GetProviderForCapability( + common::ProviderCapability capability) const +{ + using Cap = common::ProviderCapability; + using Cat = common::CryptoProviderType; + // Per-capability defaults: cert operations are software-first; everything else hardware-first. + static const std::unordered_map> kDefaultPref{ + {Cap::kCertManagement, {Cat::SOFTWARE, Cat::HARDWARE}}, + {Cap::kKeyManagement, {Cat::HARDWARE, Cat::SOFTWARE}}, + {Cap::kCrypto, {Cat::HARDWARE, Cat::SOFTWARE}}, + }; + static const std::vector kFallback{Cat::HARDWARE, Cat::SOFTWARE}; + const auto it = kDefaultPref.find(capability); + return GetProviderForCapability(capability, it != kDefaultPref.end() ? it->second : kFallback); +} + std::shared_ptr ProviderManager::GetProviderForCapability( common::ProviderCapability capability, const std::vector& preferenceOrder) const From ec04b5e1391a8fe2a40e3c66ad836ecac73bd75d Mon Sep 17 00:00:00 2001 From: Athul Mallappallil Date: Tue, 11 Aug 2026 20:42:41 +0000 Subject: [PATCH 07/25] Common file io with atomic write --- score/crypto/src/daemon/common/storage/BUILD | 12 ++++ .../src/daemon/common/storage/file_io.cpp | 60 +++++++++++++++++++ .../src/daemon/common/storage/file_io.hpp | 44 ++++++++++++++ .../storage/kv/kv_deployment_writer.cpp | 28 ++++----- .../storage/kv/kv_deployment_writer.hpp | 5 +- 5 files changed, 128 insertions(+), 21 deletions(-) create mode 100644 score/crypto/src/daemon/common/storage/file_io.cpp create mode 100644 score/crypto/src/daemon/common/storage/file_io.hpp diff --git a/score/crypto/src/daemon/common/storage/BUILD b/score/crypto/src/daemon/common/storage/BUILD index a0f30c38e..a37a0059a 100644 --- a/score/crypto/src/daemon/common/storage/BUILD +++ b/score/crypto/src/daemon/common/storage/BUILD @@ -31,6 +31,17 @@ cc_library( ], ) +cc_library( + name = "file_io", + srcs = ["file_io.cpp"], + hdrs = ["file_io.hpp"], + visibility = ["//:__subpackages__"], + deps = [ + "//score/crypto/src/common:common_types", + "//score/crypto/src/daemon/common", + ], +) + cc_library( name = "kv_deployment", srcs = [ @@ -44,6 +55,7 @@ cc_library( visibility = ["//:__subpackages__"], deps = [ ":deployment_iface", + ":file_io", "@score_baselibs//score/mw/log", ], ) diff --git a/score/crypto/src/daemon/common/storage/file_io.cpp b/score/crypto/src/daemon/common/storage/file_io.cpp new file mode 100644 index 000000000..a2ed540da --- /dev/null +++ b/score/crypto/src/daemon/common/storage/file_io.cpp @@ -0,0 +1,60 @@ +/******************************************************************************** + * Copyright (c) 2026 Contributors to the Eclipse Foundation + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ +#include "score/crypto/src/daemon/common/storage/file_io.hpp" + +#include +#include + +namespace score::crypto::daemon::common::storage +{ + +score::crypto::Expected, DaemonErrorCode> +ReadFile(const std::string& path, std::size_t max_size) +{ + std::ifstream input(path, std::ios::binary); + if (!input) + return score::crypto::make_unexpected(DaemonErrorCode::kResourceNotAllocated); + input.seekg(0, std::ios::end); + const auto size = input.tellg(); + if (size <= 0 || static_cast(size) > max_size) + return score::crypto::make_unexpected(DaemonErrorCode::kInvalidArgument); + input.seekg(0, std::ios::beg); + std::vector data(static_cast(size)); + input.read(reinterpret_cast(data.data()), static_cast(data.size())); + if (!input) + return score::crypto::make_unexpected(DaemonErrorCode::kInternalError); + return data; +} + +score::crypto::Expected +WriteFile(const std::string& path, score::crypto::span data) +{ + if (path.empty() || data.empty()) + return score::crypto::make_unexpected(DaemonErrorCode::kInvalidArgument); + std::error_code ec; + std::filesystem::create_directories(std::filesystem::path(path).parent_path(), ec); + if (ec) + return score::crypto::make_unexpected(DaemonErrorCode::kInternalError); + const std::string temporary = path + ".tmp"; + { + std::ofstream output(temporary, std::ios::binary | std::ios::trunc); + if (!output) + return score::crypto::make_unexpected(DaemonErrorCode::kPersistFailed); + output.write(reinterpret_cast(data.data()), + static_cast(data.size())); + output.flush(); + if (!output) + return score::crypto::make_unexpected(DaemonErrorCode::kPersistFailed); + } + std::filesystem::rename(temporary, path, ec); + if (ec) + { + std::filesystem::remove(temporary, ec); + return score::crypto::make_unexpected(DaemonErrorCode::kPersistFailed); + } + return std::monostate{}; +} + +} // namespace score::crypto::daemon::common::storage diff --git a/score/crypto/src/daemon/common/storage/file_io.hpp b/score/crypto/src/daemon/common/storage/file_io.hpp new file mode 100644 index 000000000..185bde989 --- /dev/null +++ b/score/crypto/src/daemon/common/storage/file_io.hpp @@ -0,0 +1,44 @@ +/******************************************************************************** + * Copyright (c) 2026 Contributors to the Eclipse Foundation + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ +#ifndef SCORE_CRYPTO_SRC_DAEMON_COMMON_STORAGE_FILE_IO_HPP +#define SCORE_CRYPTO_SRC_DAEMON_COMMON_STORAGE_FILE_IO_HPP + +#include "score/crypto/src/common/types.hpp" +#include "score/crypto/src/daemon/common/daemon_error.hpp" + +#include +#include +#include +#include + +namespace score::crypto::daemon::common::storage +{ + +/// Read the entire binary contents of @p path into a byte vector. +/// +/// @param path Absolute or relative path to the file. +/// @param max_size Maximum accepted file size in bytes. Returns kInvalidArgument +/// if the file is empty or exceeds this limit. +/// @return Byte vector on success; kResourceNotAllocated if the file cannot be +/// opened, kInvalidArgument if size is out of range, kInternalError on +/// a partial read. +[[nodiscard]] score::crypto::Expected, DaemonErrorCode> +ReadFile(const std::string& path, std::size_t max_size); + +/// Write @p data to @p path atomically via a temporary file and rename. +/// +/// Creates parent directories if they do not exist. Writes to a sibling +/// .tmp first, then renames atomically. The temporary file is removed +/// on rename failure. +/// +/// @return std::monostate on success; kInvalidArgument if path or data is +/// empty, kInternalError if the directory cannot be created, +/// kPersistFailed on write or rename failure. +[[nodiscard]] score::crypto::Expected +WriteFile(const std::string& path, score::crypto::span data); + +} // namespace score::crypto::daemon::common::storage + +#endif // SCORE_CRYPTO_SRC_DAEMON_COMMON_STORAGE_FILE_IO_HPP diff --git a/score/crypto/src/daemon/common/storage/kv/kv_deployment_writer.cpp b/score/crypto/src/daemon/common/storage/kv/kv_deployment_writer.cpp index 72d67a59f..8d5270476 100644 --- a/score/crypto/src/daemon/common/storage/kv/kv_deployment_writer.cpp +++ b/score/crypto/src/daemon/common/storage/kv/kv_deployment_writer.cpp @@ -13,9 +13,9 @@ #include "score/crypto/src/daemon/common/storage/kv/kv_deployment_writer.hpp" -#include "score/mw/log/logging.h" +#include "score/crypto/src/daemon/common/storage/file_io.hpp" -#include +#include namespace score::crypto::daemon::common::storage { @@ -24,29 +24,21 @@ score::crypto::Expected{ + reinterpret_cast(content.data()), content.size()}; + return WriteFile(path, bytes); } } // namespace score::crypto::daemon::common::storage diff --git a/score/crypto/src/daemon/common/storage/kv/kv_deployment_writer.hpp b/score/crypto/src/daemon/common/storage/kv/kv_deployment_writer.hpp index 2ccb65420..086e3680d 100644 --- a/score/crypto/src/daemon/common/storage/kv/kv_deployment_writer.hpp +++ b/score/crypto/src/daemon/common/storage/kv/kv_deployment_writer.hpp @@ -24,7 +24,8 @@ namespace score::crypto::daemon::common::storage /// @brief Writes a DeploymentDescriptor to a key=value text file. /// /// Produces the same section/key=value format that KvDeploymentLoader can read back. -/// Existing file content is replaced (opened with std::ios::trunc). +/// Writes atomically via a temporary sibling file and rename — the existing file +/// is preserved until the new content is fully flushed. class KvDeploymentWriter final : public IDeploymentWriter { public: @@ -32,8 +33,6 @@ class KvDeploymentWriter final : public IDeploymentWriter const std::string& path, const DeploymentDescriptor& descriptor) override; - private: - static constexpr std::string_view kLogPrefix = "[KV_DEPLOYMENT_WRITER_COMMON] "; }; } // namespace score::crypto::daemon::common::storage From 752cea0f15688054798d362dfff941c4e8ec8116 Mon Sep 17 00:00:00 2001 From: Athul Mallappallil Date: Tue, 11 Aug 2026 20:59:40 +0000 Subject: [PATCH 08/25] Formatting fix --- score/crypto/src/api/common/types.hpp | 24 +++++++------- .../i_certificate_management_context.hpp | 6 ++-- .../i_certificate_verification_context.hpp | 5 ++- .../common/storage/deployment_path_utils.hpp | 1 - .../src/daemon/common/storage/file_io.cpp | 23 ++++++++++---- .../src/daemon/common/storage/file_io.hpp | 21 ++++++++++--- .../storage/kv/kv_deployment_writer.cpp | 4 +-- .../storage/kv/kv_deployment_writer.hpp | 1 - score/crypto/src/daemon/key_management/BUILD | 2 +- .../src/daemon/mediator/src/mediator_impl.cpp | 14 ++++----- .../src/daemon/provider/provider_manager.hpp | 3 +- .../daemon/provider/src/provider_manager.cpp | 7 ++--- .../provider/src/provider_manager_test.cpp | 31 +++++++++---------- 13 files changed, 79 insertions(+), 63 deletions(-) diff --git a/score/crypto/src/api/common/types.hpp b/score/crypto/src/api/common/types.hpp index 4e8df63fc..6e4f14ec4 100644 --- a/score/crypto/src/api/common/types.hpp +++ b/score/crypto/src/api/common/types.hpp @@ -57,17 +57,17 @@ using AlgorithmId = FixedCapacityString<64>; /// kKeySlot and kCertSlot identify only persistent storage locations. enum class ResourceType : uint8_t { - kProvider, ///< Crypto provider / device - kKeySlot, ///< Persistent key storage slot - kCertSlot, ///< Persistent certificate storage slot - kCertificateTrustStore, ///< Named group of trusted CA certificates used for certificate chain - ///< verification. - kKey, ///< Key material (generated / loaded / derived / imported) - kCertificate, ///< Parsed or stored certificate object. - ///< CRLs are not a resource type: they are co-located with the - ///< issuer's certificate slot and never independently resolvable. - kSecureObject, ///< Secure storage entry - kDataObject ///< Generic data blob + kProvider, ///< Crypto provider / device + kKeySlot, ///< Persistent key storage slot + kCertSlot, ///< Persistent certificate storage slot + kCertificateTrustStore, ///< Named group of trusted CA certificates used for certificate chain + ///< verification. + kKey, ///< Key material (generated / loaded / derived / imported) + kCertificate, ///< Parsed or stored certificate object. + ///< CRLs are not a resource type: they are co-located with the + ///< issuer's certificate slot and never independently resolvable. + kSecureObject, ///< Secure storage entry + kDataObject ///< Generic data blob }; /// @brief Persistence classification of a crypto resource. @@ -304,7 +304,7 @@ inline constexpr bool HasPermission(KeyOperationPermission granted, KeyOperation struct CertificateSlotInfo { CertificateSlotState state{CertificateSlotState::kEmpty}; - bool has_crl{false}; ///< Whether a CRL is currently associated with the slot + bool has_crl{false}; ///< Whether a CRL is currently associated with the slot }; /// @brief Information about a key slot and its contents. diff --git a/score/crypto/src/api/contexts/i_certificate_management_context.hpp b/score/crypto/src/api/contexts/i_certificate_management_context.hpp index 48491e34f..7fd6a97b3 100644 --- a/score/crypto/src/api/contexts/i_certificate_management_context.hpp +++ b/score/crypto/src/api/contexts/i_certificate_management_context.hpp @@ -237,14 +237,14 @@ class ICertificateManagementContext : public IContext /// The certificate is assigned to a trust-store-managed slot. This is a /// write operation and requires trust-store write access. virtual score::Result AddCertificateToTrustStore(const CryptoResourceId& trust_store, - const CryptoResourceId& cert) = 0; + const CryptoResourceId& cert) = 0; /// @brief Removes a certificate from a persistent trust store by SHA-256 fingerprint. /// /// This changes trust-store deployment state and requires write access. virtual score::Result RemoveCertificateFromTrustStore( - const CryptoResourceId& trust_store, - score::cpp::span certificate_fingerprint) = 0; + const CryptoResourceId& trust_store, + score::cpp::span certificate_fingerprint) = 0; protected: ICertificateManagementContext() = default; diff --git a/score/crypto/src/api/contexts/i_certificate_verification_context.hpp b/score/crypto/src/api/contexts/i_certificate_verification_context.hpp index 108e0838f..8f0834efe 100644 --- a/score/crypto/src/api/contexts/i_certificate_verification_context.hpp +++ b/score/crypto/src/api/contexts/i_certificate_verification_context.hpp @@ -101,8 +101,7 @@ class ICertificateVerificationContext : public IContext /// @param certs Span of certificate handles to treat as trust anchors /// (type = kCertificate or kCertSlot) /// @return std::monostate on success, error if any handle is invalid - virtual score::Result SetTrustedCertificates( - score::cpp::span certs) = 0; + virtual score::Result SetTrustedCertificates(score::cpp::span certs) = 0; /// @brief Selects the chain termination rule for trust-store verification. /// @@ -128,7 +127,7 @@ class ICertificateVerificationContext : public IContext /// (type = kCertificate or kCertSlot) /// @return std::monostate on success, or an error if a handle is invalid virtual score::Result SetAdditionalCertificates( - score::cpp::span certificates) = 0; + score::cpp::span certificates) = 0; // ---- OCSP (not yet active — IPC implementation pending) ---- #if 0 diff --git a/score/crypto/src/daemon/common/storage/deployment_path_utils.hpp b/score/crypto/src/daemon/common/storage/deployment_path_utils.hpp index 2ece49a06..be3fe0e55 100644 --- a/score/crypto/src/daemon/common/storage/deployment_path_utils.hpp +++ b/score/crypto/src/daemon/common/storage/deployment_path_utils.hpp @@ -40,5 +40,4 @@ namespace score::crypto::daemon::common::storage } // namespace score::crypto::daemon::common::storage - #endif // SCORE_CRYPTO_SRC_DAEMON_COMMON_STORAGE_DEPLOYMENT_PATH_UTILS_HPP diff --git a/score/crypto/src/daemon/common/storage/file_io.cpp b/score/crypto/src/daemon/common/storage/file_io.cpp index a2ed540da..1a51d8b85 100644 --- a/score/crypto/src/daemon/common/storage/file_io.cpp +++ b/score/crypto/src/daemon/common/storage/file_io.cpp @@ -1,3 +1,15 @@ +/******************************************************************************** + * Copyright (c) 2026 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ /******************************************************************************** * Copyright (c) 2026 Contributors to the Eclipse Foundation * SPDX-License-Identifier: Apache-2.0 @@ -10,8 +22,8 @@ namespace score::crypto::daemon::common::storage { -score::crypto::Expected, DaemonErrorCode> -ReadFile(const std::string& path, std::size_t max_size) +score::crypto::Expected, DaemonErrorCode> ReadFile(const std::string& path, + std::size_t max_size) { std::ifstream input(path, std::ios::binary); if (!input) @@ -28,8 +40,8 @@ ReadFile(const std::string& path, std::size_t max_size) return data; } -score::crypto::Expected -WriteFile(const std::string& path, score::crypto::span data) +score::crypto::Expected WriteFile(const std::string& path, + score::crypto::span data) { if (path.empty() || data.empty()) return score::crypto::make_unexpected(DaemonErrorCode::kInvalidArgument); @@ -42,8 +54,7 @@ WriteFile(const std::string& path, score::crypto::span data) std::ofstream output(temporary, std::ios::binary | std::ios::trunc); if (!output) return score::crypto::make_unexpected(DaemonErrorCode::kPersistFailed); - output.write(reinterpret_cast(data.data()), - static_cast(data.size())); + output.write(reinterpret_cast(data.data()), static_cast(data.size())); output.flush(); if (!output) return score::crypto::make_unexpected(DaemonErrorCode::kPersistFailed); diff --git a/score/crypto/src/daemon/common/storage/file_io.hpp b/score/crypto/src/daemon/common/storage/file_io.hpp index 185bde989..13e1c03f8 100644 --- a/score/crypto/src/daemon/common/storage/file_io.hpp +++ b/score/crypto/src/daemon/common/storage/file_io.hpp @@ -1,3 +1,15 @@ +/******************************************************************************** + * Copyright (c) 2026 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ /******************************************************************************** * Copyright (c) 2026 Contributors to the Eclipse Foundation * SPDX-License-Identifier: Apache-2.0 @@ -24,8 +36,8 @@ namespace score::crypto::daemon::common::storage /// @return Byte vector on success; kResourceNotAllocated if the file cannot be /// opened, kInvalidArgument if size is out of range, kInternalError on /// a partial read. -[[nodiscard]] score::crypto::Expected, DaemonErrorCode> -ReadFile(const std::string& path, std::size_t max_size); +[[nodiscard]] score::crypto::Expected, DaemonErrorCode> ReadFile(const std::string& path, + std::size_t max_size); /// Write @p data to @p path atomically via a temporary file and rename. /// @@ -36,8 +48,9 @@ ReadFile(const std::string& path, std::size_t max_size); /// @return std::monostate on success; kInvalidArgument if path or data is /// empty, kInternalError if the directory cannot be created, /// kPersistFailed on write or rename failure. -[[nodiscard]] score::crypto::Expected -WriteFile(const std::string& path, score::crypto::span data); +[[nodiscard]] score::crypto::Expected WriteFile( + const std::string& path, + score::crypto::span data); } // namespace score::crypto::daemon::common::storage diff --git a/score/crypto/src/daemon/common/storage/kv/kv_deployment_writer.cpp b/score/crypto/src/daemon/common/storage/kv/kv_deployment_writer.cpp index 8d5270476..38517a959 100644 --- a/score/crypto/src/daemon/common/storage/kv/kv_deployment_writer.cpp +++ b/score/crypto/src/daemon/common/storage/kv/kv_deployment_writer.cpp @@ -36,8 +36,8 @@ score::crypto::Expected{ - reinterpret_cast(content.data()), content.size()}; + const auto bytes = + score::crypto::span{reinterpret_cast(content.data()), content.size()}; return WriteFile(path, bytes); } diff --git a/score/crypto/src/daemon/common/storage/kv/kv_deployment_writer.hpp b/score/crypto/src/daemon/common/storage/kv/kv_deployment_writer.hpp index 086e3680d..153bfa863 100644 --- a/score/crypto/src/daemon/common/storage/kv/kv_deployment_writer.hpp +++ b/score/crypto/src/daemon/common/storage/kv/kv_deployment_writer.hpp @@ -32,7 +32,6 @@ class KvDeploymentWriter final : public IDeploymentWriter [[nodiscard]] score::crypto::Expected Write( const std::string& path, const DeploymentDescriptor& descriptor) override; - }; } // namespace score::crypto::daemon::common::storage diff --git a/score/crypto/src/daemon/key_management/BUILD b/score/crypto/src/daemon/key_management/BUILD index 07dc910e1..1088c0130 100644 --- a/score/crypto/src/daemon/key_management/BUILD +++ b/score/crypto/src/daemon/key_management/BUILD @@ -108,11 +108,11 @@ cc_library( visibility = ["//:__subpackages__"], deps = [ ":key_management_headers", + "//score/crypto/src/api/common:crypto_common", "//score/crypto/src/daemon/common", "//score/crypto/src/daemon/common/storage:kv_deployment", "//score/crypto/src/daemon/data_manager", "//score/crypto/src/daemon/provider:provider_headers", "//score/crypto/src/daemon/provider:provider_manager", - "//score/crypto/src/api/common:crypto_common", ], ) diff --git a/score/crypto/src/daemon/mediator/src/mediator_impl.cpp b/score/crypto/src/daemon/mediator/src/mediator_impl.cpp index 589373d2f..77c7b93ce 100644 --- a/score/crypto/src/daemon/mediator/src/mediator_impl.cpp +++ b/score/crypto/src/daemon/mediator/src/mediator_impl.cpp @@ -307,7 +307,7 @@ bool MediatorImpl::HandleContextCreationOperation(const score::crypto::daemon::c // To add a new scope: add one entry to kScopeCapability. static const std::unordered_map kScopeCapability{ {"CERT", common::ProviderCapability::kCertManagement}, - {"KEY", common::ProviderCapability::kKeyManagement}, + {"KEY", common::ProviderCapability::kKeyManagement}, }; common::ProviderCapability required_capability = common::ProviderCapability::kNone; const auto colon_pos = context_type.find(':'); @@ -334,8 +334,8 @@ bool MediatorImpl::HandleContextCreationOperation(const score::crypto::daemon::c } provider = m_provider_manager->GetProvider(resolved_id_res.value()); } - else if (required_capability != common::ProviderCapability::kNone - && requested_provider_type == common::CryptoProviderType::DEFAULT) + else if (required_capability != common::ProviderCapability::kNone && + requested_provider_type == common::CryptoProviderType::DEFAULT) { provider = m_provider_manager->GetProviderForCapability(required_capability); } @@ -435,10 +435,10 @@ bool MediatorImpl::HandleContextCreationOperation(const score::crypto::daemon::c return false; } - const std::string_view provider_selection = - has_key_binding ? " (key-affinity resolved)" - : required_capability != common::ProviderCapability::kNone ? " (capability-based selection)" - : " (type-based selection)"; + const std::string_view provider_selection = has_key_binding ? " (key-affinity resolved)" + : required_capability != common::ProviderCapability::kNone + ? " (capability-based selection)" + : " (type-based selection)"; score::mw::log::LogVerbose() << "[SCORE_API_MED] CTX_CREATE [" << context_type << "/" << algorithm << "] selected provider: name='" << provider->GetProviderName() << "' id=" << provider->GetProviderId() << provider_selection diff --git a/score/crypto/src/daemon/provider/provider_manager.hpp b/score/crypto/src/daemon/provider/provider_manager.hpp index fbcf975c2..01a596c4b 100644 --- a/score/crypto/src/daemon/provider/provider_manager.hpp +++ b/score/crypto/src/daemon/provider/provider_manager.hpp @@ -175,8 +175,7 @@ class ProviderManager * @param capability The functional capability the provider must offer. * @return The selected provider, or nullptr if none offers the capability. */ - [[nodiscard]] std::shared_ptr GetProviderForCapability( - common::ProviderCapability capability) const; + [[nodiscard]] std::shared_ptr GetProviderForCapability(common::ProviderCapability capability) const; /** * @brief Select the preferred initialized provider with an explicit category order. diff --git a/score/crypto/src/daemon/provider/src/provider_manager.cpp b/score/crypto/src/daemon/provider/src/provider_manager.cpp index a9771e491..bb50a9d38 100644 --- a/score/crypto/src/daemon/provider/src/provider_manager.cpp +++ b/score/crypto/src/daemon/provider/src/provider_manager.cpp @@ -270,16 +270,15 @@ std::shared_ptr ProviderManager::GetProvider(common::CryptoProviderTy return provider_entry.instance; } -std::shared_ptr ProviderManager::GetProviderForCapability( - common::ProviderCapability capability) const +std::shared_ptr ProviderManager::GetProviderForCapability(common::ProviderCapability capability) const { using Cap = common::ProviderCapability; using Cat = common::CryptoProviderType; // Per-capability defaults: cert operations are software-first; everything else hardware-first. static const std::unordered_map> kDefaultPref{ {Cap::kCertManagement, {Cat::SOFTWARE, Cat::HARDWARE}}, - {Cap::kKeyManagement, {Cat::HARDWARE, Cat::SOFTWARE}}, - {Cap::kCrypto, {Cat::HARDWARE, Cat::SOFTWARE}}, + {Cap::kKeyManagement, {Cat::HARDWARE, Cat::SOFTWARE}}, + {Cap::kCrypto, {Cat::HARDWARE, Cat::SOFTWARE}}, }; static const std::vector kFallback{Cat::HARDWARE, Cat::SOFTWARE}; const auto it = kDefaultPref.find(capability); diff --git a/score/crypto/src/daemon/provider/src/provider_manager_test.cpp b/score/crypto/src/daemon/provider/src/provider_manager_test.cpp index c3daef732..e1b53cf3c 100644 --- a/score/crypto/src/daemon/provider/src/provider_manager_test.cpp +++ b/score/crypto/src/daemon/provider/src/provider_manager_test.cpp @@ -211,15 +211,13 @@ provider::ProviderManager::Sptr MakeCapabilityManager() mgr->RegisterProvider( "SW_PROVIDER", std::make_shared( - "SW_PROVIDER", 0, false, - common::ProviderCapability::kCrypto | common::ProviderCapability::kCertManagement), + "SW_PROVIDER", 0, false, common::ProviderCapability::kCrypto | common::ProviderCapability::kCertManagement), common::CryptoProviderType::SOFTWARE); mgr->RegisterProvider( "HW_PROVIDER", std::make_shared( - "HW_PROVIDER", 1, false, - common::ProviderCapability::kCrypto | common::ProviderCapability::kKeyManagement), + "HW_PROVIDER", 1, false, common::ProviderCapability::kCrypto | common::ProviderCapability::kKeyManagement), common::CryptoProviderType::HARDWARE); mgr->Initialize(); @@ -240,15 +238,15 @@ TEST(ProviderManagerCapabilityTest, PreferenceOrderPicksAmongCapableProviders) { auto mgr = MakeCapabilityManager(); // Both providers offer crypto; preference decides which is returned. - auto sw_first = mgr->GetProviderForCapability( - common::ProviderCapability::kCrypto, - {common::CryptoProviderType::SOFTWARE, common::CryptoProviderType::HARDWARE}); + auto sw_first = + mgr->GetProviderForCapability(common::ProviderCapability::kCrypto, + {common::CryptoProviderType::SOFTWARE, common::CryptoProviderType::HARDWARE}); ASSERT_NE(sw_first, nullptr); EXPECT_EQ(sw_first->GetProviderName(), "SW_PROVIDER"); - auto hw_first = mgr->GetProviderForCapability( - common::ProviderCapability::kCrypto, - {common::CryptoProviderType::HARDWARE, common::CryptoProviderType::SOFTWARE}); + auto hw_first = + mgr->GetProviderForCapability(common::ProviderCapability::kCrypto, + {common::CryptoProviderType::HARDWARE, common::CryptoProviderType::SOFTWARE}); ASSERT_NE(hw_first, nullptr); EXPECT_EQ(hw_first->GetProviderName(), "HW_PROVIDER"); } @@ -257,10 +255,10 @@ TEST(ProviderManagerCapabilityTest, ReturnsNullWhenNoProviderOffersCapability) { score::crypto::daemon::config::Config config; provider::ProviderManager mgr(config.GetProviderInitConfig()); - mgr.RegisterProvider("SW_PROVIDER", - std::make_shared( - "SW_PROVIDER", 0, false, common::ProviderCapability::kCrypto), - common::CryptoProviderType::SOFTWARE); + mgr.RegisterProvider( + "SW_PROVIDER", + std::make_shared("SW_PROVIDER", 0, false, common::ProviderCapability::kCrypto), + common::CryptoProviderType::SOFTWARE); mgr.Initialize(); EXPECT_EQ(mgr.GetProviderForCapability(common::ProviderCapability::kCertManagement), nullptr); @@ -271,9 +269,8 @@ TEST(ProviderManagerCapabilityTest, FallsBackToCapableProviderOutsidePreference) auto mgr = MakeCapabilityManager(); // Key management is only on HW; a SOFTWARE-only preference still finds it // via the lowest-id capable fallback rather than returning nullptr. - auto key_prov = - mgr->GetProviderForCapability(common::ProviderCapability::kKeyManagement, - {common::CryptoProviderType::SOFTWARE}); + auto key_prov = mgr->GetProviderForCapability(common::ProviderCapability::kKeyManagement, + {common::CryptoProviderType::SOFTWARE}); ASSERT_NE(key_prov, nullptr); EXPECT_EQ(key_prov->GetProviderName(), "HW_PROVIDER"); } From 656a245bb898a11dc4dbe88c1714d26ff563d2af Mon Sep 17 00:00:00 2001 From: Athul Mallappallil Date: Wed, 12 Aug 2026 14:34:31 +0000 Subject: [PATCH 09/25] Added two more file io fn --- .../src/daemon/common/storage/file_io.cpp | 17 ++++ .../src/daemon/common/storage/file_io.hpp | 14 ++++ .../slot/file_backed_slot_handler.cpp | 79 +++++-------------- .../slot/file_backed_slot_handler.hpp | 9 +-- 4 files changed, 51 insertions(+), 68 deletions(-) diff --git a/score/crypto/src/daemon/common/storage/file_io.cpp b/score/crypto/src/daemon/common/storage/file_io.cpp index 1a51d8b85..e54f7f79f 100644 --- a/score/crypto/src/daemon/common/storage/file_io.cpp +++ b/score/crypto/src/daemon/common/storage/file_io.cpp @@ -68,4 +68,21 @@ score::crypto::Expected WriteFile(const std::st return std::monostate{}; } +bool FileExists(const std::string& path) +{ + std::error_code ec; + return std::filesystem::is_regular_file(path, ec); +} + +score::crypto::Expected RemoveFile(const std::string& path) +{ + if (path.empty()) + return score::crypto::make_unexpected(DaemonErrorCode::kInvalidArgument); + std::error_code ec; + std::filesystem::remove(path, ec); + if (ec) + return score::crypto::make_unexpected(DaemonErrorCode::kPersistFailed); + return std::monostate{}; +} + } // namespace score::crypto::daemon::common::storage diff --git a/score/crypto/src/daemon/common/storage/file_io.hpp b/score/crypto/src/daemon/common/storage/file_io.hpp index 13e1c03f8..6d4483402 100644 --- a/score/crypto/src/daemon/common/storage/file_io.hpp +++ b/score/crypto/src/daemon/common/storage/file_io.hpp @@ -52,6 +52,20 @@ namespace score::crypto::daemon::common::storage const std::string& path, score::crypto::span data); +/// Return true if @p path refers to an existing regular file. +/// +/// Returns false for directories, symlinks to non-existent targets, and any +/// other non-regular-file entries. Errors resolve to false. +[[nodiscard]] bool FileExists(const std::string& path); + +/// Remove the file at @p path. +/// +/// Idempotent: returns success if the file does not exist. +/// +/// @return std::monostate on success or if the file was already absent; +/// kInvalidArgument if path is empty, kPersistFailed on a filesystem error. +[[nodiscard]] score::crypto::Expected RemoveFile(const std::string& path); + } // namespace score::crypto::daemon::common::storage #endif // SCORE_CRYPTO_SRC_DAEMON_COMMON_STORAGE_FILE_IO_HPP diff --git a/score/crypto/src/daemon/key_management/slot/file_backed_slot_handler.cpp b/score/crypto/src/daemon/key_management/slot/file_backed_slot_handler.cpp index 53e27f44c..555ecca22 100644 --- a/score/crypto/src/daemon/key_management/slot/file_backed_slot_handler.cpp +++ b/score/crypto/src/daemon/key_management/slot/file_backed_slot_handler.cpp @@ -14,43 +14,42 @@ #include "score/crypto/src/daemon/key_management/slot/file_backed_slot_handler.hpp" #include "score/crypto/src/daemon/common/secure_memory.hpp" +#include "score/crypto/src/daemon/common/storage/file_io.hpp" #include "score/crypto/src/daemon/key_management/detail/slot_info_builder.hpp" #include "score/crypto/src/daemon/key_management/interfaces/key_management_operations.hpp" #include "score/crypto/src/daemon/key_management/interfaces/key_slot_config.hpp" #include "score/crypto/src/daemon/key_management/slot/deployment_loader.hpp" #include -#include -#include -#include #include namespace score::crypto::daemon::key_management { +namespace +{ +namespace file_io = common::storage; +using Error = common::DaemonErrorCode; +} // namespace FileBackedSlotHandler::FileBackedSlotHandler(IKeyFactory::Sptr factory) : m_factory{std::move(factory)} {} -score::crypto::Expected -FileBackedSlotHandler::LoadKey(const KeySlotConfig& slot) +score::crypto::Expected FileBackedSlotHandler::LoadKey(const KeySlotConfig& slot) { - // Load deployment info to get the key file path. auto deploy_result = DeploymentLoader::Load(slot.deployment_path, slot.deployment_format); if (!deploy_result.has_value()) - { return score::crypto::make_unexpected(deploy_result.error()); - } const auto& deploy_info = deploy_result.value(); const auto path_it = deploy_info.key_properties.find(std::string{deployment_keys::kKeyPath}); - if ((path_it == deploy_info.key_properties.end()) || path_it->second.empty()) - { - return score::crypto::make_unexpected(score::crypto::daemon::common::DaemonErrorCode::kInvalidArgument); - } + if (path_it == deploy_info.key_properties.end() || path_it->second.empty()) + return score::crypto::make_unexpected(Error::kInvalidArgument); - auto read_result = ReadKeyFile(path_it->second); + auto read_result = file_io::ReadFile(path_it->second, kMaxKeyFileSize); if (!read_result.has_value()) { - return score::crypto::make_unexpected(read_result.error()); + const auto file_io_err = read_result.error(); + return score::crypto::make_unexpected(file_io_err == Error::kResourceNotAllocated ? Error::kKeySlotEmpty + : file_io_err); } auto& buffer = read_result.value(); @@ -62,72 +61,32 @@ FileBackedSlotHandler::LoadKey(const KeySlotConfig& slot) req.permissions = slot.allowed_operations; auto import_result = m_factory->ImportKey(req); - - // Securely zeroize regardless of import outcome. common::SecureZeroizeAndClear(buffer); - return import_result; } -score::crypto::Expected -FileBackedSlotHandler::GetSlotState(const KeySlotConfig& slot) +score::crypto::Expected FileBackedSlotHandler::GetSlotState( + const KeySlotConfig& slot) { auto deploy_result = DeploymentLoader::Load(slot.deployment_path, slot.deployment_format); if (!deploy_result.has_value()) - { return score::crypto::KeySlotState::kEmpty; - } const auto& deploy_info = deploy_result.value(); const auto path_it = deploy_info.key_properties.find(std::string{deployment_keys::kKeyPath}); - if ((path_it == deploy_info.key_properties.end()) || path_it->second.empty()) - { + if (path_it == deploy_info.key_properties.end() || path_it->second.empty()) return score::crypto::KeySlotState::kEmpty; - } - std::ifstream file(path_it->second, std::ios::binary); - if (file.good()) - { - return score::crypto::KeySlotState::kOccupied; - } - - return score::crypto::KeySlotState::kEmpty; + return file_io::FileExists(path_it->second) ? score::crypto::KeySlotState::kOccupied + : score::crypto::KeySlotState::kEmpty; } -score::crypto::Expected -FileBackedSlotHandler::GetSlotInfo(const KeySlotConfig& slot) +score::crypto::Expected FileBackedSlotHandler::GetSlotInfo(const KeySlotConfig& slot) { auto state_result = GetSlotState(slot); if (!state_result.has_value()) - { return score::crypto::make_unexpected(state_result.error()); - } return detail::BuildKeySlotInfo(slot, state_result.value()); } -score::crypto::Expected, score::crypto::daemon::common::DaemonErrorCode> -FileBackedSlotHandler::ReadKeyFile(const std::string& file_path) const -{ - std::ifstream file(file_path, std::ios::binary); - if (!file.is_open()) - { - return score::crypto::make_unexpected(score::crypto::daemon::common::DaemonErrorCode::kKeySlotEmpty); - } - - std::vector buffer((std::istreambuf_iterator(file)), std::istreambuf_iterator()); - - if (buffer.empty()) - { - return score::crypto::make_unexpected(score::crypto::daemon::common::DaemonErrorCode::kInvalidArgument); - } - - if (buffer.size() > kMaxKeyFileSize) - { - common::SecureZeroizeAndClear(buffer); - return score::crypto::make_unexpected(score::crypto::daemon::common::DaemonErrorCode::kInvalidArgument); - } - - return buffer; -} - } // namespace score::crypto::daemon::key_management diff --git a/score/crypto/src/daemon/key_management/slot/file_backed_slot_handler.hpp b/score/crypto/src/daemon/key_management/slot/file_backed_slot_handler.hpp index b6cfad295..d6f410ab5 100644 --- a/score/crypto/src/daemon/key_management/slot/file_backed_slot_handler.hpp +++ b/score/crypto/src/daemon/key_management/slot/file_backed_slot_handler.hpp @@ -19,8 +19,6 @@ #include #include -#include -#include namespace score::crypto::daemon::key_management { @@ -70,15 +68,10 @@ class FileBackedSlotHandler final : public IKeySlotHandler GetSlotInfo(const KeySlotConfig& slot) override; private: - [[nodiscard]] score::crypto::Expected, score::crypto::daemon::common::DaemonErrorCode> - ReadKeyFile(const std::string& file_path) const; - IKeyFactory::Sptr m_factory; - /// Maximum key file size to guard against reading unreasonably large files. + /// Maximum accepted key file size (8 KiB). static constexpr std::size_t kMaxKeyFileSize = 8U * 1024U; - - static constexpr std::string_view LOG_PREFIX = "[FILE_BACKED_SLOT_HANDLER]"; }; } // namespace score::crypto::daemon::key_management From 7a8904e1476566290d45bee182aa138c1f5f97f3 Mon Sep 17 00:00:00 2001 From: Athul Mallappallil Date: Wed, 12 Aug 2026 21:46:18 +0000 Subject: [PATCH 10/25] Use baselibs for filesystem IO --- score/crypto/src/daemon/common/storage/BUILD | 1 + .../src/daemon/common/storage/file_io.cpp | 80 +++++++++++-------- .../data_plane/src/base_shm_factory.cpp | 3 +- .../key_management/openssl_key_factory.cpp | 2 +- 4 files changed, 48 insertions(+), 38 deletions(-) diff --git a/score/crypto/src/daemon/common/storage/BUILD b/score/crypto/src/daemon/common/storage/BUILD index a37a0059a..6eecf280d 100644 --- a/score/crypto/src/daemon/common/storage/BUILD +++ b/score/crypto/src/daemon/common/storage/BUILD @@ -39,6 +39,7 @@ cc_library( deps = [ "//score/crypto/src/common:common_types", "//score/crypto/src/daemon/common", + "@score_baselibs//score/filesystem", ], ) diff --git a/score/crypto/src/daemon/common/storage/file_io.cpp b/score/crypto/src/daemon/common/storage/file_io.cpp index e54f7f79f..a08f789c6 100644 --- a/score/crypto/src/daemon/common/storage/file_io.cpp +++ b/score/crypto/src/daemon/common/storage/file_io.cpp @@ -10,14 +10,12 @@ * * SPDX-License-Identifier: Apache-2.0 ********************************************************************************/ -/******************************************************************************** - * Copyright (c) 2026 Contributors to the Eclipse Foundation - * SPDX-License-Identifier: Apache-2.0 - ********************************************************************************/ #include "score/crypto/src/daemon/common/storage/file_io.hpp" -#include -#include +#include "score/filesystem/error.h" +#include "score/filesystem/filestream/file_factory.h" +#include "score/filesystem/filestream/file_stream.h" +#include "score/filesystem/filesystem.h" namespace score::crypto::daemon::common::storage { @@ -25,17 +23,20 @@ namespace score::crypto::daemon::common::storage score::crypto::Expected, DaemonErrorCode> ReadFile(const std::string& path, std::size_t max_size) { - std::ifstream input(path, std::ios::binary); - if (!input) + score::filesystem::FileFactory factory{}; + auto open_result = factory.Open(score::filesystem::Path{path}, std::ios::binary | std::ios::in); + if (!open_result.has_value()) return score::crypto::make_unexpected(DaemonErrorCode::kResourceNotAllocated); - input.seekg(0, std::ios::end); - const auto size = input.tellg(); + + auto& stream = *open_result.value(); + stream.seekg(0, std::ios::end); + const auto size = stream.tellg(); if (size <= 0 || static_cast(size) > max_size) return score::crypto::make_unexpected(DaemonErrorCode::kInvalidArgument); - input.seekg(0, std::ios::beg); + stream.seekg(0, std::ios::beg); std::vector data(static_cast(size)); - input.read(reinterpret_cast(data.data()), static_cast(data.size())); - if (!input) + stream.read(reinterpret_cast(data.data()), static_cast(data.size())); + if (!stream) return score::crypto::make_unexpected(DaemonErrorCode::kInternalError); return data; } @@ -45,42 +46,51 @@ score::crypto::Expected WriteFile(const std::st { if (path.empty() || data.empty()) return score::crypto::make_unexpected(DaemonErrorCode::kInvalidArgument); - std::error_code ec; - std::filesystem::create_directories(std::filesystem::path(path).parent_path(), ec); - if (ec) - return score::crypto::make_unexpected(DaemonErrorCode::kInternalError); - const std::string temporary = path + ".tmp"; + + const score::filesystem::Path target_path{path}; + score::filesystem::StandardFilesystem fs{}; + const auto parent = target_path.ParentPath(); + if (!parent.Empty()) { - std::ofstream output(temporary, std::ios::binary | std::ios::trunc); - if (!output) - return score::crypto::make_unexpected(DaemonErrorCode::kPersistFailed); - output.write(reinterpret_cast(data.data()), static_cast(data.size())); - output.flush(); - if (!output) - return score::crypto::make_unexpected(DaemonErrorCode::kPersistFailed); + if (!fs.CreateDirectories(parent).has_value()) + return score::crypto::make_unexpected(DaemonErrorCode::kInternalError); } - std::filesystem::rename(temporary, path, ec); - if (ec) - { - std::filesystem::remove(temporary, ec); + + score::filesystem::FileFactory factory{}; + auto stream_result = factory.AtomicUpdate(target_path, std::ios::binary | std::ios::trunc); + if (!stream_result.has_value()) + return score::crypto::make_unexpected(DaemonErrorCode::kPersistFailed); + + auto& stream = *stream_result.value(); + stream.write(reinterpret_cast(data.data()), static_cast(data.size())); + stream.flush(); + if (!stream) + // Stream is in a bad state; Close() (called by the destructor) will detect this + // and clean up the temp file rather than renaming it. + return score::crypto::make_unexpected(DaemonErrorCode::kPersistFailed); + + // Close() triggers the atomic rename — check it explicitly to confirm success. + // The destructor calls Close() again on the way out; a second call on an already-closed + // stream returns an error that the destructor ignores, which is safe. + if (!stream_result.value()->Close().has_value()) return score::crypto::make_unexpected(DaemonErrorCode::kPersistFailed); - } return std::monostate{}; } bool FileExists(const std::string& path) { - std::error_code ec; - return std::filesystem::is_regular_file(path, ec); + score::filesystem::StandardFilesystem fs{}; + const auto result = fs.IsRegularFile(score::filesystem::Path{path}); + return result.has_value() && result.value(); } score::crypto::Expected RemoveFile(const std::string& path) { if (path.empty()) return score::crypto::make_unexpected(DaemonErrorCode::kInvalidArgument); - std::error_code ec; - std::filesystem::remove(path, ec); - if (ec) + score::filesystem::StandardFilesystem fs{}; + const auto result = fs.Remove(score::filesystem::Path{path}); + if (!result.has_value() && result.error() != score::filesystem::ErrorCode::kFileOrDirectoryDoesNotExist) return score::crypto::make_unexpected(DaemonErrorCode::kPersistFailed); return std::monostate{}; } diff --git a/score/crypto/src/daemon/data_plane/src/base_shm_factory.cpp b/score/crypto/src/daemon/data_plane/src/base_shm_factory.cpp index 5dffad5f9..6b874497f 100644 --- a/score/crypto/src/daemon/data_plane/src/base_shm_factory.cpp +++ b/score/crypto/src/daemon/data_plane/src/base_shm_factory.cpp @@ -43,8 +43,7 @@ Expected BaseShmFactory::Create(std::strin perm_map[score::os::Acl::Permission::kRead] = {uid}; perm_map[score::os::Acl::Permission::kWrite] = {uid}; - auto handle = ShmFactory::Create( - std::string(name), [](const auto&) noexcept {}, size, perm_map); + auto handle = ShmFactory::Create(std::string(name), [](const auto&) noexcept {}, size, perm_map); if (!handle) { return make_unexpected(common::DaemonErrorCode::kAllocationFailed); diff --git a/score/crypto/src/daemon/provider/score_provider/openssl/key_management/openssl_key_factory.cpp b/score/crypto/src/daemon/provider/score_provider/openssl/key_management/openssl_key_factory.cpp index dd3b1bb7c..9f0ed4e46 100644 --- a/score/crypto/src/daemon/provider/score_provider/openssl/key_management/openssl_key_factory.cpp +++ b/score/crypto/src/daemon/provider/score_provider/openssl/key_management/openssl_key_factory.cpp @@ -26,7 +26,7 @@ namespace score::crypto::daemon::provider::openssl { -OpenSslKeyFactory::OpenSslKeyFactory(common::ProviderId provider_id) : m_provider_id(provider_id){}; +OpenSslKeyFactory::OpenSslKeyFactory(common::ProviderId provider_id) : m_provider_id(provider_id) {}; ::score::crypto::Expected OpenSslKeyFactory::GenerateKey(const key_management::KeyGenerationRequest& request) From 6dca195a5e610f33640590c6b02cc419e1e62fa7 Mon Sep 17 00:00:00 2001 From: Athul Mallappallil Date: Wed, 12 Aug 2026 22:19:47 +0000 Subject: [PATCH 11/25] Minor doc update --- .../key_management_class_diagram.puml | 4 +-- .../architecture/key_management_details.rst | 27 ++++++++++--------- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/score/crypto/docs/architecture/key_management_class_diagram.puml b/score/crypto/docs/architecture/key_management_class_diagram.puml index 2d340d86f..2a26895ee 100644 --- a/score/crypto/docs/architecture/key_management_class_diagram.puml +++ b/score/crypto/docs/architecture/key_management_class_diagram.puml @@ -184,7 +184,7 @@ package "Slot Management" <> #F0F8FF { } ' ==================================================================== -' SLOT DEPLOYMENT (slot/deployment/) +' SLOT DEPLOYMENT (slot/ façades → daemon/common/storage/ implementations) ' ==================================================================== package "Slot Deployment" <> #E8F0FE { @@ -230,7 +230,7 @@ package "Slot Deployment" <> #E8F0FE { class KvDeploymentWriter { + Write(path : string, info : SlotDeploymentInfo) : Expected .. writes [metadata] then [key] sections .. - .. opens with ios::trunc .. + .. delegates to file_io::WriteFile (atomic temp→rename) .. } } diff --git a/score/crypto/docs/architecture/key_management_details.rst b/score/crypto/docs/architecture/key_management_details.rst index 510ba4f5d..d3b55c445 100644 --- a/score/crypto/docs/architecture/key_management_details.rst +++ b/score/crypto/docs/architecture/key_management_details.rst @@ -619,22 +619,23 @@ implements ``IDeploymentLoader`` / ``IDeploymentWriter``: .. code-block:: text - slot/ - deployment_loader.hpp/.cpp ← façade (public API unchanged for all callers) + key_management/slot/ + deployment_loader.hpp/.cpp ← façade (delegates to common/storage/ impls) deployment_writer.hpp/.cpp ← façade - deployment/ - deployment_path_utils.hpp ← IsDeploymentPathSafe() — shared guard - i_deployment_loader.hpp ← pure-virtual interface - i_deployment_writer.hpp ← pure-virtual interface - kv/ - kv_deployment_loader.hpp/.cpp ← current implementation - kv_deployment_writer.hpp/.cpp - json/ ← reserved (add JsonDeploymentLoader when needed) - flatbuffer/ ← reserved + + daemon/common/storage/ ← shared by key_management and cert_management + deployment_path_utils.hpp ← IsDeploymentPathSafe() — shared guard + i_deployment_loader.hpp ← pure-virtual interface + i_deployment_writer.hpp ← pure-virtual interface + kv/ + kv_deployment_loader.hpp/.cpp ← current implementation + kv_deployment_writer.hpp/.cpp ← writes atomically via file_io::WriteFile + json/ ← reserved (add JsonDeploymentLoader when needed) + flatbuffer/ ← reserved To add a new format: implement ``IDeploymentLoader`` / ``IDeploymentWriter`` under -``slot/deployment//``, then add one ``if``-branch in each façade ``.cpp`` -and one dep in ``slot/deployment/BUILD``. No other files change. +``daemon/common/storage//``, then add one ``if``-branch in each façade ``.cpp`` +and one dep in ``daemon/common/storage/BUILD``. No other files change. **Key=value format (``"kv"``) — file layout** From 67989fa6bfcb2abcff3a35a31b7e5e0b698ef3a2 Mon Sep 17 00:00:00 2001 From: Athul Mallappallil Date: Thu, 13 Aug 2026 20:39:57 +0000 Subject: [PATCH 12/25] Make dependancy explicit in keym --- score/crypto/src/daemon/key_management/BUILD | 1 + 1 file changed, 1 insertion(+) diff --git a/score/crypto/src/daemon/key_management/BUILD b/score/crypto/src/daemon/key_management/BUILD index 1088c0130..11978775b 100644 --- a/score/crypto/src/daemon/key_management/BUILD +++ b/score/crypto/src/daemon/key_management/BUILD @@ -110,6 +110,7 @@ cc_library( ":key_management_headers", "//score/crypto/src/api/common:crypto_common", "//score/crypto/src/daemon/common", + "//score/crypto/src/daemon/common/storage:file_io", "//score/crypto/src/daemon/common/storage:kv_deployment", "//score/crypto/src/daemon/data_manager", "//score/crypto/src/daemon/provider:provider_headers", From 3763f70c1a2f37ca07b1f52ba8fba8ae85a3156d Mon Sep 17 00:00:00 2001 From: Athul Mallappallil Date: Fri, 14 Aug 2026 09:55:45 +0000 Subject: [PATCH 13/25] Minor code doc fix --- .../architecture/key_management_class_diagram.puml | 3 ++- score/crypto/src/api/common/types.hpp | 2 -- .../contexts/i_certificate_management_context.hpp | 6 ------ score/crypto/src/api/future/certificate/BUILD | 2 -- score/crypto/src/api/future/config/BUILD | 3 --- score/crypto/src/api/future/contexts/BUILD | 3 --- score/crypto/src/api/future/objects/BUILD | 2 -- .../common/storage/kv/kv_deployment_loader.cpp | 14 +++++++++----- 8 files changed, 11 insertions(+), 24 deletions(-) diff --git a/score/crypto/docs/architecture/key_management_class_diagram.puml b/score/crypto/docs/architecture/key_management_class_diagram.puml index 2a26895ee..c0f4f1c2f 100644 --- a/score/crypto/docs/architecture/key_management_class_diagram.puml +++ b/score/crypto/docs/architecture/key_management_class_diagram.puml @@ -225,12 +225,13 @@ package "Slot Deployment" <> #E8F0FE { + Load(path : string) : Expected .. parses [metadata] / [key] key=value sections .. .. blank lines and # comments ignored .. + .. delegates to file_io::ReadFile (score::filesystem) .. } class KvDeploymentWriter { + Write(path : string, info : SlotDeploymentInfo) : Expected .. writes [metadata] then [key] sections .. - .. delegates to file_io::WriteFile (atomic temp→rename) .. + .. delegates to file_io::WriteFile (atomic write via score::filesystem) .. } } diff --git a/score/crypto/src/api/common/types.hpp b/score/crypto/src/api/common/types.hpp index 6e4f14ec4..dcd4e149a 100644 --- a/score/crypto/src/api/common/types.hpp +++ b/score/crypto/src/api/common/types.hpp @@ -64,8 +64,6 @@ enum class ResourceType : uint8_t ///< verification. kKey, ///< Key material (generated / loaded / derived / imported) kCertificate, ///< Parsed or stored certificate object. - ///< CRLs are not a resource type: they are co-located with the - ///< issuer's certificate slot and never independently resolvable. kSecureObject, ///< Secure storage entry kDataObject ///< Generic data blob }; diff --git a/score/crypto/src/api/contexts/i_certificate_management_context.hpp b/score/crypto/src/api/contexts/i_certificate_management_context.hpp index 7fd6a97b3..6a275f454 100644 --- a/score/crypto/src/api/contexts/i_certificate_management_context.hpp +++ b/score/crypto/src/api/contexts/i_certificate_management_context.hpp @@ -36,7 +36,6 @@ namespace crypto /// @brief Interface for certificate lifecycle management operations. /// -/// Mirrors the structure of IKeyManagementContext for certificates: /// - **Parse** raw bytes into a daemon-backed ICertificateObject with an /// ephemeral resource ID. /// - **SaveCertificate** copies an ephemeral certificate to a persistent slot @@ -45,7 +44,6 @@ namespace crypto /// - **Export / convert** using a two-call pattern: query the required buffer /// size first, then fill the caller-supplied span. /// - **Slot management** and **trust store management** are co-located here. -/// - CRL, OCSP, and CSR operations are defined in future/ and not yet active. /// /// **ParseCertificate lifecycle**: /// @code @@ -213,10 +211,6 @@ class ICertificateManagementContext : public IContext /// @param cert_slot Handle to the slot whose CRL should be removed (type = kCertSlot) /// @return std::monostate on success, error if no CRL is present or access is denied virtual score::Result DeleteCrl(const CryptoResourceId& cert_slot) = 0; - - /// @brief Bulk-deletes expired CRLs across all certificate slots. - /// @return Number of CRLs deleted - virtual score::Result DeleteExpiredCrls() = 0; #endif // CRL management // ---- OCSP (not yet active — IPC implementation pending) ---- diff --git a/score/crypto/src/api/future/certificate/BUILD b/score/crypto/src/api/future/certificate/BUILD index 46c8ddd5e..2cf8d569d 100644 --- a/score/crypto/src/api/future/certificate/BUILD +++ b/score/crypto/src/api/future/certificate/BUILD @@ -17,8 +17,6 @@ load("@rules_cc//cc:defs.bzl", "cc_library") -# cert_types.hpp and i_ocsp_request_export.hpp moved to -# //score/crypto/src/api/certificate:cert_types (active). # cc_library( # name = "crypto_certificate", diff --git a/score/crypto/src/api/future/config/BUILD b/score/crypto/src/api/future/config/BUILD index 0697cc05b..d9b0d65c9 100644 --- a/score/crypto/src/api/future/config/BUILD +++ b/score/crypto/src/api/future/config/BUILD @@ -18,9 +18,6 @@ load("@rules_cc//cc:defs.bzl", "cc_library") -# certificate_context_config.hpp and certificate_verification_context_config.hpp -# moved to //score/crypto/src/api/config:cert_context_configs (active). - # cc_library( # name = "future_context_configs", # hdrs = [ diff --git a/score/crypto/src/api/future/contexts/BUILD b/score/crypto/src/api/future/contexts/BUILD index b84dfa1f3..226c95608 100644 --- a/score/crypto/src/api/future/contexts/BUILD +++ b/score/crypto/src/api/future/contexts/BUILD @@ -62,9 +62,6 @@ load("@rules_cc//cc:defs.bzl", "cc_library") # ], # ) -# i_certificate_management_context.hpp and i_certificate_verification_context.hpp -# moved to //score/crypto/src/api/contexts:cert_contexts (active). - # -- CSR -- # cc_library( # name = "csr_generation_context", diff --git a/score/crypto/src/api/future/objects/BUILD b/score/crypto/src/api/future/objects/BUILD index 6a6bf45e7..b31ce8318 100644 --- a/score/crypto/src/api/future/objects/BUILD +++ b/score/crypto/src/api/future/objects/BUILD @@ -17,8 +17,6 @@ load("@rules_cc//cc:defs.bzl", "cc_library") -# i_certificate_object.hpp and i_cert_slot_object.hpp moved to -# //score/crypto/src/api/objects:cert_objects (active). # cc_library( # name = "future_crypto_objects", diff --git a/score/crypto/src/daemon/common/storage/kv/kv_deployment_loader.cpp b/score/crypto/src/daemon/common/storage/kv/kv_deployment_loader.cpp index eda2e4204..34ec737cc 100644 --- a/score/crypto/src/daemon/common/storage/kv/kv_deployment_loader.cpp +++ b/score/crypto/src/daemon/common/storage/kv/kv_deployment_loader.cpp @@ -13,9 +13,9 @@ #include "score/crypto/src/daemon/common/storage/kv/kv_deployment_loader.hpp" +#include "score/crypto/src/daemon/common/storage/file_io.hpp" #include "score/mw/log/logging.h" -#include #include #include @@ -41,18 +41,22 @@ namespace score::crypto::Expected KvDeploymentLoader::Load( const std::string& path) { - std::ifstream file(path); - if (!file.is_open()) + constexpr std::size_t kMaxDescriptorSize = 64U * 1024U; + auto read_result = ReadFile(path, kMaxDescriptorSize); + if (!read_result.has_value()) { score::mw::log::LogError() << kLogPrefix << "Cannot open: " << path; - return score::crypto::make_unexpected(score::crypto::daemon::common::DaemonErrorCode::kInternalError); + return score::crypto::make_unexpected(read_result.error()); } + const auto& bytes = read_result.value(); + std::istringstream stream{std::string{reinterpret_cast(bytes.data()), bytes.size()}}; + DeploymentDescriptor descriptor; std::string current_section; std::string line; - while (std::getline(file, line)) + while (std::getline(stream, line)) { const std::string trimmed = Trim(line); if (trimmed.empty() || trimmed[0] == '#') From 5cc9b12139ec9ca0747c1f1c447b62d204b247db Mon Sep 17 00:00:00 2001 From: Athul Mallappallil Date: Tue, 18 Aug 2026 22:12:22 +0000 Subject: [PATCH 14/25] Cert APIs update and config entry rename --- .../i_certificate_management_context.hpp | 21 +++++++++++++++++-- .../i_certificate_verification_context.hpp | 4 ++-- score/crypto/src/daemon/common/types.hpp | 4 +++- score/crypto/src/daemon/config/inc/config.hpp | 16 +++++++------- .../slot/config_driven_slot_catalog.cpp | 2 +- 5 files changed, 33 insertions(+), 14 deletions(-) diff --git a/score/crypto/src/api/contexts/i_certificate_management_context.hpp b/score/crypto/src/api/contexts/i_certificate_management_context.hpp index 6a275f454..220234ba6 100644 --- a/score/crypto/src/api/contexts/i_certificate_management_context.hpp +++ b/score/crypto/src/api/contexts/i_certificate_management_context.hpp @@ -233,12 +233,29 @@ class ICertificateManagementContext : public IContext virtual score::Result AddCertificateToTrustStore(const CryptoResourceId& trust_store, const CryptoResourceId& cert) = 0; + /// @brief Removes a certificate from a persistent trust store by cert handle. + /// + /// The certificate must be loaded in the daemon (ephemeral or slot-loaded). + /// The daemon resolves the SHA-256 fingerprint internally from the handle. + /// + /// Normal path: caller has the cert already parsed or loaded from a slot. + /// + /// @param trust_store Handle to the trust store (type = kCertificateTrustStore) + /// @param cert Handle to the certificate to remove (type = kCertificate or kCertSlot) + virtual score::Result RemoveCertificateFromTrustStore(const CryptoResourceId& trust_store, + const CryptoResourceId& cert) = 0; + /// @brief Removes a certificate from a persistent trust store by SHA-256 fingerprint. /// - /// This changes trust-store deployment state and requires write access. + /// The certificate does not need to be loaded in the daemon. Use this when + /// the fingerprint is known from an external source (security bulletin, policy + /// document, trust-store listing) without the cert bytes being available. + /// + /// @param trust_store Handle to the trust store (type = kCertificateTrustStore) + /// @param sha256_fingerprint 32-byte SHA-256 fingerprint of the certificate to remove virtual score::Result RemoveCertificateFromTrustStore( const CryptoResourceId& trust_store, - score::cpp::span certificate_fingerprint) = 0; + score::cpp::span sha256_fingerprint) = 0; protected: ICertificateManagementContext() = default; diff --git a/score/crypto/src/api/contexts/i_certificate_verification_context.hpp b/score/crypto/src/api/contexts/i_certificate_verification_context.hpp index 8f0834efe..db6c7b106 100644 --- a/score/crypto/src/api/contexts/i_certificate_verification_context.hpp +++ b/score/crypto/src/api/contexts/i_certificate_verification_context.hpp @@ -72,13 +72,13 @@ class ICertificateVerificationContext : public IContext /// @brief Sets the leaf certificate to verify. /// @param cert Handle to the certificate to verify /// @return std::monostate on success, error if cert handle is invalid - /// @note Mutually exclusive with SetCertificateChain(). + /// @note Replaces any previously set certificate or chain on this context. virtual score::Result SetCertificate(const CryptoResourceId& cert) = 0; /// @brief Sets a certificate chain to verify (leaf first). /// @param chain Ordered chain of certificate handles (leaf first, root last) /// @return std::monostate on success, error if any handle is invalid - /// @note Mutually exclusive with SetCertificate(). + /// @note Replaces any previously set certificate or chain on this context. virtual score::Result SetCertificateChain(score::cpp::span chain) = 0; /// @brief Sets the system trust store to use for certificate chain verification. diff --git a/score/crypto/src/daemon/common/types.hpp b/score/crypto/src/daemon/common/types.hpp index 55b112cb2..77f435e92 100644 --- a/score/crypto/src/daemon/common/types.hpp +++ b/score/crypto/src/daemon/common/types.hpp @@ -196,7 +196,9 @@ enum class ProviderCapability : std::uint8_t kNone = 0x00U, ///< No functional capability advertised kCrypto = 0x01U, ///< Symmetric cipher / hash / MAC handlers (GetCryptoHandlerFactory) kKeyManagement = 0x02U, ///< Key generation / storage (GetKeyFactory / GetKeySlotHandler) - kCertManagement = 0x04U, ///< Certificate parse / verify / CSR (GetCertFactory) + kCertManagement = 0x04U, ///< Certificate parsing / verification (GetCertParser). + /// Does NOT imply cert-slot storage — slot handlers are + /// selected by name (slot.storage_backend), not by this bit. }; /// @brief Bitwise OR for combining provider capabilities. diff --git a/score/crypto/src/daemon/config/inc/config.hpp b/score/crypto/src/daemon/config/inc/config.hpp index cec1841d4..dd081dc29 100644 --- a/score/crypto/src/daemon/config/inc/config.hpp +++ b/score/crypto/src/daemon/config/inc/config.hpp @@ -272,11 +272,11 @@ class KeyConfig /// /// The daemon's SlotRegistry stores these mappings and resolves them /// transparently during ResolveResource IPC calls. - struct AppResourceEntry + struct AppKeySlotEntry { uint32_t uid; ///< UID of the application that owns this mapping std::string app_resource_id; ///< Application-local resource name - std::string slot_name; ///< Actual slot name registered in the daemon registry + std::string slot_name; ///< Actual key slot name registered in the daemon registry }; KeyConfig() = default; @@ -294,15 +294,15 @@ class KeyConfig } /// @brief Add an application resource mapping entry (called by parser). - void AddAppResourceEntry(AppResourceEntry entry) + void AddAppKeySlotEntry(AppKeySlotEntry entry) { - m_app_resource_entries.push_back(std::move(entry)); + m_app_key_slot_entries.push_back(std::move(entry)); } - /// @brief Get all per-application resource ID mappings. - const std::vector& GetAppResourceEntries() const + /// @brief Get all per-application key slot resource ID mappings. + const std::vector& GetAppKeySlotEntries() const { - return m_app_resource_entries; + return m_app_key_slot_entries; } /// @brief Path to the JSON key slot manifest file (optional). @@ -321,7 +321,7 @@ class KeyConfig private: std::vector m_slot_entries; - std::vector m_app_resource_entries; + std::vector m_app_key_slot_entries; std::string m_manifest_path; }; diff --git a/score/crypto/src/daemon/key_management/slot/config_driven_slot_catalog.cpp b/score/crypto/src/daemon/key_management/slot/config_driven_slot_catalog.cpp index 12037bb92..65f146549 100644 --- a/score/crypto/src/daemon/key_management/slot/config_driven_slot_catalog.cpp +++ b/score/crypto/src/daemon/key_management/slot/config_driven_slot_catalog.cpp @@ -123,7 +123,7 @@ void ConfigDrivenSlotCatalog::Load(SlotRegistry& registry) score::mw::log::LogDebug() << LOG_PREFIX << "Loaded" << entries.size() << " slot(s) from configuration."; // Register per-application resource ID mappings. - for (const auto& mapping : m_key_config.GetAppResourceEntries()) + for (const auto& mapping : m_key_config.GetAppKeySlotEntries()) { registry.RegisterAppResource(mapping.uid, mapping.app_resource_id, mapping.slot_name); } From af7c509fec7cd6a3c25633ddae72a959a68846e0 Mon Sep 17 00:00:00 2001 From: Athul Mallappallil Date: Wed, 19 Aug 2026 07:49:17 +0000 Subject: [PATCH 15/25] Fix name inconsistancy in config --- .../src/daemon/config/crypto_config.fbs | 10 +++--- .../config/src/flatbuffer_config_parser.cpp | 32 +++++++++---------- .../config/src/flatbuffer_config_parser.hpp | 8 ++--- .../config/key_management_test_config.json | 2 +- .../config/integration_test_config.json | 2 +- 5 files changed, 27 insertions(+), 27 deletions(-) diff --git a/score/crypto/src/daemon/config/crypto_config.fbs b/score/crypto/src/daemon/config/crypto_config.fbs index a5f09561a..ed720cddd 100644 --- a/score/crypto/src/daemon/config/crypto_config.fbs +++ b/score/crypto/src/daemon/config/crypto_config.fbs @@ -39,10 +39,10 @@ table KeySlotEntry { deployment_format: string (required); } -/// Per-application resource ID to slot name mapping +/// Per-application resource ID to key slot name mapping /// Applications reference keys by portable application-local names /// (e.g., "signing_key") -table AppResourceEntry { +table AppKeySlotEntry { /// UID of the application that owns this mapping uid: uint32; /// Application-local resource name @@ -51,12 +51,12 @@ table AppResourceEntry { slot_name: string (required); } -/// Key slot config contains all slot and app resource definitions +/// Key slot config contains all slot and app key slot definitions table KeySlotConfig { /// All key slot definitions slot_entries: [KeySlotEntry] (required); - /// All per-app resource mappings - app_resource_entries: [AppResourceEntry] (required); + /// All per-app key slot mappings + app_key_slot_entries: [AppKeySlotEntry] (required); } /// Top-level configuration root_type diff --git a/score/crypto/src/daemon/config/src/flatbuffer_config_parser.cpp b/score/crypto/src/daemon/config/src/flatbuffer_config_parser.cpp index 0f41d670c..6f3f24918 100644 --- a/score/crypto/src/daemon/config/src/flatbuffer_config_parser.cpp +++ b/score/crypto/src/daemon/config/src/flatbuffer_config_parser.cpp @@ -72,8 +72,8 @@ Expected FlatBufferConfigParser::ParseK return make_unexpected(slot_entries_result.error()); } - // Parse app resource entries - auto app_resource_result = ParseAppResourceEntries(key_slot_config, out_config); + // Parse app key slot entries + auto app_resource_result = ParseAppKeySlotEntries(key_slot_config, out_config); if (!app_resource_result.has_value()) { return make_unexpected(app_resource_result.error()); @@ -81,7 +81,7 @@ Expected FlatBufferConfigParser::ParseK score::mw::log::LogDebug() << LOG_PREFIX << "Successfully parsed configuration. Loaded " << out_config.GetSlotEntries().size() << " slot(s) and " - << out_config.GetAppResourceEntries().size() << " app resource mapping(s)."; + << out_config.GetAppKeySlotEntries().size() << " app key slot mapping(s)."; return std::monostate{}; } @@ -220,43 +220,43 @@ Expected FlatBufferConfigParser::ParseF return ParseFromBuffer(buffer.data(), buffer.size(), out_config); } -Expected FlatBufferConfigParser::ParseAppResourceEntries( +Expected FlatBufferConfigParser::ParseAppKeySlotEntries( const KeySlotConfig* key_slot_config, KeyConfig& out_config) { - const auto* app_resource_entries = key_slot_config->app_resource_entries(); - if (!app_resource_entries) + const auto* app_key_slot_entries = key_slot_config->app_key_slot_entries(); + if (!app_key_slot_entries) { - return std::monostate{}; // No app resource entries is not an error + return std::monostate{}; // No app key slot entries is not an error } - for (const auto* entry : *app_resource_entries) + for (const auto* entry : *app_key_slot_entries) { if (!entry) { - score::mw::log::LogError() << LOG_PREFIX << "Null app resource entry encountered - invalid configuration"; + score::mw::log::LogError() << LOG_PREFIX << "Null app key slot entry encountered - invalid configuration"; return make_unexpected(common::DaemonErrorCode::kInternalError); } - KeyConfig::AppResourceEntry resource_entry; - resource_entry.uid = entry->uid(); + KeyConfig::AppKeySlotEntry key_slot_entry; + key_slot_entry.uid = entry->uid(); // All fields below are required per schema - add defensive checks if (!entry->app_resource_id()) { - score::mw::log::LogError() << LOG_PREFIX << "App resource entry missing required field 'app_resource_id'"; + score::mw::log::LogError() << LOG_PREFIX << "App key slot entry missing required field 'app_resource_id'"; return make_unexpected(common::DaemonErrorCode::kInternalError); } - resource_entry.app_resource_id = entry->app_resource_id()->str(); + key_slot_entry.app_resource_id = entry->app_resource_id()->str(); if (!entry->slot_name()) { - score::mw::log::LogError() << LOG_PREFIX << "App resource entry missing required field 'slot_name'"; + score::mw::log::LogError() << LOG_PREFIX << "App key slot entry missing required field 'slot_name'"; return make_unexpected(common::DaemonErrorCode::kInternalError); } - resource_entry.slot_name = entry->slot_name()->str(); + key_slot_entry.slot_name = entry->slot_name()->str(); - out_config.AddAppResourceEntry(std::move(resource_entry)); + out_config.AddAppKeySlotEntry(std::move(key_slot_entry)); } return std::monostate{}; diff --git a/score/crypto/src/daemon/config/src/flatbuffer_config_parser.hpp b/score/crypto/src/daemon/config/src/flatbuffer_config_parser.hpp index 3766d7f4b..4efc26a1d 100644 --- a/score/crypto/src/daemon/config/src/flatbuffer_config_parser.hpp +++ b/score/crypto/src/daemon/config/src/flatbuffer_config_parser.hpp @@ -125,16 +125,16 @@ class FlatBufferConfigParser const keyslot::KeySlotConfig* key_slot_config, KeyConfig& out_config); - /// @brief Parse app resource entries from key slot configuration. + /// @brief Parse app key slot entries from key slot configuration. /// - /// Iterates through app resource entries in the KeySlotConfig and populates - /// KeyConfig with parsed AppResourceEntry objects. + /// Iterates through app key slot entries in the KeySlotConfig and populates + /// KeyConfig with parsed AppKeySlotEntry objects. /// /// @param key_slot_config Pointer to the KeySlotConfig FlatBuffers object /// @param out_config Output KeyConfig object to populate /// @return Success (monostate) on successful parsing, DaemonErrorCode on failure /// @retval kInternalError Invalid entry structure or missing required fields - static Expected ParseAppResourceEntries( + static Expected ParseAppKeySlotEntries( const keyslot::KeySlotConfig* key_slot_config, KeyConfig& out_config); }; diff --git a/score/crypto/tests/key_management/config/key_management_test_config.json b/score/crypto/tests/key_management/config/key_management_test_config.json index 6af995447..fae797185 100644 --- a/score/crypto/tests/key_management/config/key_management_test_config.json +++ b/score/crypto/tests/key_management/config/key_management_test_config.json @@ -33,7 +33,7 @@ "deployment_format": "kv" } ], - "app_resource_entries": [ + "app_key_slot_entries": [ { "uid": 0, "app_resource_id": "test/hmac", diff --git a/score/tests/test_vectors/config/integration_test_config.json b/score/tests/test_vectors/config/integration_test_config.json index 54d039393..01fe8f8df 100644 --- a/score/tests/test_vectors/config/integration_test_config.json +++ b/score/tests/test_vectors/config/integration_test_config.json @@ -53,7 +53,7 @@ "deployment_format" : "kv" } ], - "app_resource_entries": [ + "app_key_slot_entries": [ { "uid": 0, "app_resource_id": "test/hmac", From 7e8aefae85fe79a7322309b08f18c68af467332a Mon Sep 17 00:00:00 2001 From: Athul Mallappallil Date: Tue, 25 Aug 2026 10:21:16 +0000 Subject: [PATCH 16/25] Minor fix on the file write --- score/crypto/src/daemon/common/storage/file_io.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/score/crypto/src/daemon/common/storage/file_io.cpp b/score/crypto/src/daemon/common/storage/file_io.cpp index a08f789c6..bd542842f 100644 --- a/score/crypto/src/daemon/common/storage/file_io.cpp +++ b/score/crypto/src/daemon/common/storage/file_io.cpp @@ -57,7 +57,7 @@ score::crypto::Expected WriteFile(const std::st } score::filesystem::FileFactory factory{}; - auto stream_result = factory.AtomicUpdate(target_path, std::ios::binary | std::ios::trunc); + auto stream_result = factory.AtomicUpdate(target_path, std::ios::out | std::ios::binary | std::ios::trunc); if (!stream_result.has_value()) return score::crypto::make_unexpected(DaemonErrorCode::kPersistFailed); From 4371adf8305e6b0c79a3e11f87e2b38b6f5f2cc7 Mon Sep 17 00:00:00 2001 From: Athul Mallappallil Date: Fri, 28 Aug 2026 10:15:42 +0000 Subject: [PATCH 17/25] API update for cert management --- .../i_certificate_management_context.hpp | 112 +++++++++--- score/crypto/src/api/objects/BUILD | 1 + .../src/api/objects/i_certificate_object.hpp | 14 +- .../src/api/objects/i_trust_store_object.hpp | 165 ++++++++++++++++++ 4 files changed, 263 insertions(+), 29 deletions(-) create mode 100644 score/crypto/src/api/objects/i_trust_store_object.hpp diff --git a/score/crypto/src/api/contexts/i_certificate_management_context.hpp b/score/crypto/src/api/contexts/i_certificate_management_context.hpp index 220234ba6..71e075dc1 100644 --- a/score/crypto/src/api/contexts/i_certificate_management_context.hpp +++ b/score/crypto/src/api/contexts/i_certificate_management_context.hpp @@ -14,7 +14,6 @@ #ifndef SCORE_CRYPTO_SRC_API_CONTEXTS_I_CERTIFICATE_MANAGEMENT_CONTEXT_HPP #define SCORE_CRYPTO_SRC_API_CONTEXTS_I_CERTIFICATE_MANAGEMENT_CONTEXT_HPP -#include "score/crypto/src/api/certificate/i_ocsp_request_export.hpp" #include "score/crypto/src/api/common/crypto_resource_guard.hpp" #include "score/crypto/src/api/common/types.hpp" #include "score/crypto/src/api/contexts/i_context.hpp" @@ -26,6 +25,7 @@ #include #include #include +#include #include namespace score @@ -101,8 +101,7 @@ class ICertificateManagementContext : public IContext /// /// Typical usage: parse → inspect fields → save to slot. /// - /// @param cert CryptoResourceId of the certificate to save (type = kCertificate). - /// Pass the result of ICertificateObject::GetId() directly. + /// @param cert CryptoResourceId of the certificate to save (type = kCertificate or kCertSlot) /// @param target_slot Handle to the target slot (type = kCertSlot) /// @return std::monostate on success, error if slot is occupied or access is denied virtual score::Result SaveCertificate(const CryptoResourceId& cert, @@ -189,18 +188,39 @@ class ICertificateManagementContext : public IContext /// @return Number of certificates deleted virtual score::Result DeleteExpiredCertificates() = 0; - // ---- CRL management (not yet active — IPC implementation pending) ---- -#if 0 + // ---- Persistence — with optional CRL propagation ---- + + /// @brief Copies an ephemeral certificate to a persistent slot, optionally propagating its CRL. + /// + /// When @p with_crl is true the daemon propagates the CRL already held for @p cert: + /// - If a session-scoped CRL was previously associated via ImportCrl() (persist=false), + /// that CRL is used (works for both kCertificate and kCertSlot sources). + /// - Otherwise the CRL is read from @p cert's slot's persistent [crl] section + /// (only applicable when cert is a kCertSlot source). + /// + /// No CRL re-validation occurs — the daemon reuses the CRL it already accepted. + /// + /// @param cert CryptoResourceId of the certificate to save (type = kCertificate or kCertSlot) + /// @param target_slot Handle to the target slot (type = kCertSlot) + /// @param with_crl When true, propagate the associated CRL to the destination slot + virtual score::Result SaveCertificate(const CryptoResourceId& cert, + const CryptoResourceId& target_slot, + bool with_crl) = 0; + + // ---- CRL management ---- + /// @brief Imports a Certificate Revocation List and associates it with its issuer certificate. /// /// The CRL lifecycle follows the lifecycle of @p issuer_cert: /// - kCertSlot + persist=true: CRL written to the slot's [crl] section; write access required. - /// - kCertSlot or kCertificate + persist=false (default): session-scoped; no write access needed. + /// - kCertSlot or kCertificate + persist=false: session-scoped in-memory; no write access needed. + /// Session CRL is consumed by SaveCertificate(with_crl=true) and + /// AddCertificateToTrustStore(with_crl=true) without re-passing raw bytes. /// - /// @param crl_data Encoded CRL data - /// @param format Encoding format of the CRL + /// @param crl_data Encoded CRL data + /// @param format Encoding format of the CRL /// @param issuer_cert Handle to the issuer certificate (type = kCertSlot or kCertificate) - /// @param persist When true, store permanently to the issuer slot (kCertSlot only). + /// @param persist When true, store permanently to the issuer slot (kCertSlot only) /// @return std::monostate on success, error if validation fails or access is denied virtual score::Result ImportCrl(score::cpp::span crl_data, FormatType format, @@ -211,35 +231,37 @@ class ICertificateManagementContext : public IContext /// @param cert_slot Handle to the slot whose CRL should be removed (type = kCertSlot) /// @return std::monostate on success, error if no CRL is present or access is denied virtual score::Result DeleteCrl(const CryptoResourceId& cert_slot) = 0; -#endif // CRL management - // ---- OCSP (not yet active — IPC implementation pending) ---- -#if 0 - /// @brief Constructs an OCSP request for a certificate's revocation status. - /// - /// @param cert Handle to the certificate to check (type = kCertificate or kCertSlot) - /// @param issuer_cert Handle to the issuer certificate - /// @return Export object providing the DER-encoded request and responder URL - virtual score::Result GetOcspRequestData(const CryptoResourceId& cert, - const CryptoResourceId& issuer_cert) = 0; -#endif // OCSP + // ---- OCSP (reserved for future support) ---- + // /// @brief Constructs an OCSP request for a certificate's revocation status. + // /// + // /// @param cert Handle to the certificate to check (type = kCertificate or kCertSlot) + // /// @param issuer_cert Handle to the issuer certificate + // /// @return Export object providing the DER-encoded request and responder URL + // virtual score::Result GetOcspRequestData( + // const CryptoResourceId& cert, + // const CryptoResourceId& issuer_cert) = 0; // ---- Trust-store membership management ---- /// @brief Adds a certificate to a persistent trust store. /// - /// The certificate is assigned to a trust-store-managed slot. This is a - /// write operation and requires trust-store write access. + /// The certificate is assigned to a trust-store-managed exclusive slot. This is a + /// write operation and requires trust-store write access. Idempotent: if the cert + /// is already a member of any type, returns success without allocating a new slot. + /// + /// @param trust_store Handle to the trust store (type = kCertificateTrustStore) + /// @param cert Handle to the certificate to add (type = kCertificate or kCertSlot) + /// @param with_crl When true, propagate the associated CRL to the exclusive slot virtual score::Result AddCertificateToTrustStore(const CryptoResourceId& trust_store, - const CryptoResourceId& cert) = 0; + const CryptoResourceId& cert, + bool with_crl = false) = 0; /// @brief Removes a certificate from a persistent trust store by cert handle. /// /// The certificate must be loaded in the daemon (ephemeral or slot-loaded). /// The daemon resolves the SHA-256 fingerprint internally from the handle. /// - /// Normal path: caller has the cert already parsed or loaded from a slot. - /// /// @param trust_store Handle to the trust store (type = kCertificateTrustStore) /// @param cert Handle to the certificate to remove (type = kCertificate or kCertSlot) virtual score::Result RemoveCertificateFromTrustStore(const CryptoResourceId& trust_store, @@ -248,8 +270,7 @@ class ICertificateManagementContext : public IContext /// @brief Removes a certificate from a persistent trust store by SHA-256 fingerprint. /// /// The certificate does not need to be loaded in the daemon. Use this when - /// the fingerprint is known from an external source (security bulletin, policy - /// document, trust-store listing) without the cert bytes being available. + /// the fingerprint is known from an external source without the cert bytes being available. /// /// @param trust_store Handle to the trust store (type = kCertificateTrustStore) /// @param sha256_fingerprint 32-byte SHA-256 fingerprint of the certificate to remove @@ -257,6 +278,43 @@ class ICertificateManagementContext : public IContext const CryptoResourceId& trust_store, score::cpp::span sha256_fingerprint) = 0; + /// @brief Enables a previously disabled trust store member identified by its slot resource. + /// + /// Use the slot_id from ITrustStoreObject::MemberInfo to obtain the slot handle. + /// + /// @param trust_store Handle to the trust store (type = kCertificateTrustStore) + /// @param slot Handle to the member slot (type = kCertSlot) + virtual score::Result EnableTrustStoreMember(const CryptoResourceId& trust_store, + const CryptoResourceId& slot) = 0; + + /// @brief Disables a trust store member identified by its slot resource. + /// + /// A disabled member is excluded from anchor resolution; it remains in the store + /// and can be re-enabled. Use RemoveCertificateFromTrustStore to permanently remove. + /// + /// Use the slot_id from ITrustStoreObject::MemberInfo to obtain the slot handle. + /// + /// @param trust_store Handle to the trust store (type = kCertificateTrustStore) + /// @param slot Handle to the member slot (type = kCertSlot) + virtual score::Result DisableTrustStoreMember(const CryptoResourceId& trust_store, + const CryptoResourceId& slot) = 0; + + /// @brief Imports a CRL for a trust store exclusive member identified by its slot resource. + /// + /// Only kExclusiveMutable trust store slots are writable through this path. + /// For shared-static or conditional-external members, use ImportCrl directly on the slot. + /// + /// Use the slot_id from ITrustStoreObject::MemberInfo to obtain the slot handle. + /// + /// @param trust_store Handle to the trust store (type = kCertificateTrustStore) + /// @param slot Handle to the exclusive member slot (type = kCertSlot) + /// @param crl_data Encoded CRL bytes + /// @param format Encoding format of the CRL + virtual score::Result ImportCrlForTrustStoreMember(const CryptoResourceId& trust_store, + const CryptoResourceId& slot, + score::cpp::span crl_data, + FormatType format) = 0; + protected: ICertificateManagementContext() = default; }; diff --git a/score/crypto/src/api/objects/BUILD b/score/crypto/src/api/objects/BUILD index 1702080ff..ed7a69117 100644 --- a/score/crypto/src/api/objects/BUILD +++ b/score/crypto/src/api/objects/BUILD @@ -37,6 +37,7 @@ cc_library( hdrs = [ "i_cert_slot_object.hpp", "i_certificate_object.hpp", + "i_trust_store_object.hpp", ], includes = ["."], visibility = ["//visibility:public"], diff --git a/score/crypto/src/api/objects/i_certificate_object.hpp b/score/crypto/src/api/objects/i_certificate_object.hpp index d09a62224..fbea93ecf 100644 --- a/score/crypto/src/api/objects/i_certificate_object.hpp +++ b/score/crypto/src/api/objects/i_certificate_object.hpp @@ -14,14 +14,16 @@ #ifndef SCORE_CRYPTO_SRC_API_OBJECTS_I_CERTIFICATE_OBJECT_HPP #define SCORE_CRYPTO_SRC_API_OBJECTS_I_CERTIFICATE_OBJECT_HPP +#include "score/crypto/src/api/common/types.hpp" #include "score/crypto/src/api/objects/i_crypto_object.hpp" #include "score/result/result.h" #include "score/span.hpp" +#include #include #include #include -#include +#include namespace score { @@ -51,6 +53,8 @@ namespace crypto class ICertificateObject : public ICryptoObject { public: + static constexpr std::size_t kSha256FingerprintSize = 32U; + using Uptr = std::unique_ptr; ~ICertificateObject() override = default; @@ -76,9 +80,15 @@ class ICertificateObject : public ICryptoObject /// @return Algorithm string (e.g., "RSA-2048", "ECDSA-P256", "ML-DSA-65") virtual AlgorithmId GetPublicKeyAlgorithm() const noexcept = 0; - /// @brief Returns the certificate serial number as a hex-encoded string. + /// @brief Returns the certificate serial number as an uppercase hex string (e.g., "01ABCDEF"). virtual std::string GetSerialNumber() const = 0; + /// @brief Returns the SHA-256 fingerprint of the certificate as a 32-byte array. + /// + /// The fingerprint is the SHA-256 digest of the DER-encoded certificate. Together + /// with the issuer DN and serial number it uniquely identifies a certificate. + virtual std::array GetFingerprint() const noexcept = 0; + /// @brief Returns the byte size of the DER-encoded SubjectPublicKeyInfo. /// /// Call this before ExportPublicKey() to determine the required buffer size. diff --git a/score/crypto/src/api/objects/i_trust_store_object.hpp b/score/crypto/src/api/objects/i_trust_store_object.hpp new file mode 100644 index 000000000..3fb2b1c1a --- /dev/null +++ b/score/crypto/src/api/objects/i_trust_store_object.hpp @@ -0,0 +1,165 @@ +/******************************************************************************** + * Copyright (c) 2026 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ + +#ifndef SCORE_CRYPTO_SRC_API_OBJECTS_I_TRUST_STORE_OBJECT_HPP +#define SCORE_CRYPTO_SRC_API_OBJECTS_I_TRUST_STORE_OBJECT_HPP + +#include "score/crypto/src/api/common/types.hpp" +#include "score/crypto/src/api/objects/i_crypto_object.hpp" +#include "score/span.hpp" + +#include +#include +#include +#include +#include +#include + +namespace score +{ + +namespace crypto +{ + +/// @brief Read-only typed view of a named trust store. +/// +/// Provides a point-in-time snapshot of trust store membership: which certificates +/// are present, their membership kind, and their enabled/disabled state. +/// +/// Mutations (add, remove, enable, disable, import CRL) are performed via +/// ICertificateManagementContext — not through this object. +/// +/// Obtained via ICryptoContext::GetTrustStoreObject(). +class ITrustStoreObject : public ICryptoObject +{ + public: + static constexpr std::size_t kSha256FingerprintSize = 32U; + + using Uptr = std::unique_ptr; + + /// @brief Membership kind of a trust store anchor. + enum class MemberKind : uint8_t + { + kSharedStatic = 0U, ///< Externally managed slot; read-only from trust store perspective. + kExclusiveMutable = 1U, ///< Trust-store-owned exclusive slot; mutable via management context. + kConditionalExternal = 2U ///< External slot; disabled after unexpected content change. + }; + + /// @brief Snapshot of a single trust store member. + /// + /// Both slot_id and sha256_fingerprint are provided so callers can: + /// - Use slot_id directly for enable/disable/importCrl operations without a round-trip. + /// - Use sha256_fingerprint for quick identity matching against externally known fingerprints + /// (e.g., from a security bulletin) without loading the full certificate. + /// - Use subject + issuer + serial_number for human-readable identification and logging. + struct MemberInfo + { + CryptoResourceId slot_id{}; ///< kCertSlot resource — use for management ops. + std::array + sha256_fingerprint{}; ///< SHA-256 fingerprint of the member certificate. + std::string subject; ///< RFC 4514 Subject DN (e.g., "CN=Root CA,O=ACME,C=DE"). + std::string issuer; ///< RFC 4514 Issuer DN. + std::string serial_number; ///< Uppercase hex serial (e.g., "01ABCDEF"). + MemberKind kind{MemberKind::kSharedStatic}; ///< Membership type. + bool is_enabled{true}; ///< Whether anchor is active for chain building. + }; + + ~ITrustStoreObject() override = default; + + ITrustStoreObject(const ITrustStoreObject&) = delete; + ITrustStoreObject& operator=(const ITrustStoreObject&) = delete; + ITrustStoreObject(ITrustStoreObject&&) = default; + ITrustStoreObject& operator=(ITrustStoreObject&&) = default; + + /// @brief Returns the point-in-time snapshot of all occupied trust store members. + /// + /// Each entry corresponds to a certificate slot that currently holds a certificate. + /// Empty slots (not yet populated) are omitted. + virtual const std::vector& GetMembers() const noexcept = 0; + + // ---- Non-virtual convenience accessors (operate on GetMembers() locally) ---- + + /// @brief Find the member entry for a given slot resource ID. + /// + /// Matches by id and type only — primary_provider is not compared because + /// MemberInfo slot_id has primary_provider=0 as a placeholder. + /// @returns Pointer to the matching MemberInfo, or nullptr if not a member. + [[nodiscard]] const MemberInfo* FindMember(const CryptoResourceId& slot) const noexcept + { + for (const auto& member : GetMembers()) + { + if (member.slot_id.id == slot.id && member.slot_id.type == slot.type) + { + return &member; + } + } + return nullptr; + } + + /// @brief Find the member with the given SHA-256 fingerprint. + /// + /// @param fingerprint 32-byte fingerprint span. Returns nullptr if its size is not 32. + /// @returns Pointer to the matching MemberInfo, or nullptr if not found. + [[nodiscard]] const MemberInfo* FindMemberByFingerprint(score::cpp::span fingerprint) const noexcept + { + if (fingerprint.size() != kSha256FingerprintSize) + { + return nullptr; + } + for (const auto& member : GetMembers()) + { + if (std::equal(fingerprint.begin(), fingerprint.end(), member.sha256_fingerprint.begin())) + { + return &member; + } + } + return nullptr; + } + + /// @brief Returns the slot IDs of all enabled trust store members. + [[nodiscard]] std::vector GetEnabledMemberSlotIds() const + { + std::vector result; + for (const auto& member : GetMembers()) + { + if (member.is_enabled) + { + result.push_back(member.slot_id); + } + } + return result; + } + + /// @brief Returns the slot IDs of all disabled trust store members. + [[nodiscard]] std::vector GetDisabledMemberSlotIds() const + { + std::vector result; + for (const auto& member : GetMembers()) + { + if (!member.is_enabled) + { + result.push_back(member.slot_id); + } + } + return result; + } + + protected: + ITrustStoreObject() = default; +}; + +} // namespace crypto + +} // namespace score + +#endif // SCORE_CRYPTO_SRC_API_OBJECTS_I_TRUST_STORE_OBJECT_HPP From f493baa2b2fc26f5b96572a9eedae890f4e48927 Mon Sep 17 00:00:00 2001 From: Athul Mallappallil Date: Wed, 9 Sep 2026 12:42:39 +0000 Subject: [PATCH 18/25] Fix coverage workflow --- tools/coverage/BUILD | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tools/coverage/BUILD b/tools/coverage/BUILD index a5ae2a252..e2689d1b3 100644 --- a/tools/coverage/BUILD +++ b/tools/coverage/BUILD @@ -26,6 +26,10 @@ score_coverage_scope( visibility = ["//visibility:private"], deps = [ "//score/crypto/src/api:crypto_stack", + "//score/crypto/src/api/certificate:cert_types", + "//score/crypto/src/api/config:cert_context_configs", + "//score/crypto/src/api/contexts:cert_contexts", + "//score/crypto/src/api/objects:cert_objects", "//score/crypto/src/api/future/common:future_common", "//score/crypto/src/backend:active_pkcs11_backend", "//score/crypto/src/backend:pkcs11_backend_defines", From d48ac0d80c9da16a7a32ed3e665cb34fb03ec30e Mon Sep 17 00:00:00 2001 From: Athul Mallappallil Date: Fri, 18 Sep 2026 16:54:48 +0200 Subject: [PATCH 19/25] Refactor types to common, cert and keys --- score/crypto/src/api/BUILD | 2 + score/crypto/src/api/certificate/BUILD | 4 +- .../crypto/src/api/certificate/cert_types.hpp | 64 --- score/crypto/src/api/common/BUILD | 10 +- .../src/api/common/crypto_resource_guard.hpp | 2 +- .../src/api/common/i_memory_allocator.hpp | 2 +- .../src/api/common/src/i_release_callback.hpp | 2 +- score/crypto/src/api/common/types.hpp | 453 ------------------ score/crypto/src/api/config/BUILD | 2 + .../src/api/config/base_context_config.hpp | 2 +- .../api/config/certificate_context_config.hpp | 6 - ...ertificate_verification_context_config.hpp | 9 +- .../src/api/config/key_operation_params.hpp | 4 +- .../src/api/config/permission_builder.hpp | 2 +- score/crypto/src/api/contexts/BUILD | 7 +- .../i_certificate_management_context.hpp | 3 +- .../i_certificate_verification_context.hpp | 4 +- .../api/contexts/i_key_management_context.hpp | 3 +- .../api/contexts/src/hash_context_impl.cpp | 2 +- .../api/contexts/src/hash_context_impl.hpp | 2 +- .../src/key_management_context_impl.cpp | 3 +- .../src/key_management_context_impl.hpp | 3 +- .../src/api/contexts/src/mac_context_impl.cpp | 2 +- .../src/api/contexts/src/mac_context_impl.hpp | 2 +- score/crypto/src/api/data_plane/BUILD | 1 + .../api/future/config/aead_context_config.hpp | 2 +- .../future/config/cipher_context_config.hpp | 2 +- .../contexts/i_csr_generation_context.hpp | 2 +- score/crypto/src/api/i_crypto_context.hpp | 2 +- .../src/api/objects/i_certificate_object.hpp | 3 +- .../src/api/objects/i_crypto_object.hpp | 2 +- score/crypto/src/api/objects/i_key_object.hpp | 1 + .../src/api/objects/i_key_slot_object.hpp | 1 + .../src/api/objects/i_trust_store_object.hpp | 2 +- .../src/api/src/crypto_context_impl.cpp | 5 +- .../src/api/src/crypto_context_impl.hpp | 2 +- .../src/api/src/provider_type_converter.hpp | 2 +- score/crypto/src/api/types/BUILD | 46 ++ score/crypto/src/api/types/certificate.hpp | 112 +++++ score/crypto/src/api/types/common.hpp | 163 +++++++ score/crypto/src/api/types/key.hpp | 102 ++++ score/crypto/src/backend/BUILD | 2 +- score/crypto/src/daemon/common/BUILD | 1 + score/crypto/src/daemon/config/inc/config.hpp | 10 +- score/crypto/src/daemon/data_plane/BUILD | 1 + score/crypto/src/daemon/key_management/BUILD | 3 + .../daemon/key_management/core/key_entry.hpp | 2 +- .../detail/slot_info_builder.hpp | 3 +- .../interfaces/i_key_factory.hpp | 2 +- .../interfaces/i_key_slot_handler.hpp | 3 +- .../interfaces/key_slot_config.hpp | 3 +- .../key_management/interfaces/key_types.hpp | 3 +- .../nodes/key_slot_data_node.hpp | 3 +- .../slot/access_policy_enforcer.hpp | 3 +- .../slot/file_backed_slot_handler.cpp | 12 +- .../key_management/slot/slot_registry.hpp | 2 +- .../crypto/src/daemon/provider/handler/BUILD | 1 + .../provider/handler/handler_init_params.hpp | 2 +- .../key_management/pkcs11_key_store.cpp | 2 +- .../key_management/pkcs11_key_store.hpp | 2 +- .../operations/mac/pkcs11_mac_context.hpp | 2 +- .../operations/mac/pkcs11_mac_executor.cpp | 2 +- .../operations/mac/pkcs11_mac_executor.hpp | 2 +- .../operations/mac/pkcs11_mac_handler.cpp | 2 +- score/crypto/tests/key_management/BUILD | 1 + .../test_access_policy_enforcer.cpp | 3 +- .../test_key_config_manager.cpp | 3 +- .../test_key_management_context.cpp | 3 +- .../test_openssl_key_handler.cpp | 3 +- .../integration_tests/score_api_mac_test.cpp | 2 +- score/tests/integration_tests/score_demo.cpp | 2 +- tools/coverage/BUILD | 2 +- 72 files changed, 539 insertions(+), 593 deletions(-) delete mode 100644 score/crypto/src/api/certificate/cert_types.hpp delete mode 100644 score/crypto/src/api/common/types.hpp create mode 100644 score/crypto/src/api/types/BUILD create mode 100644 score/crypto/src/api/types/certificate.hpp create mode 100644 score/crypto/src/api/types/common.hpp create mode 100644 score/crypto/src/api/types/key.hpp diff --git a/score/crypto/src/api/BUILD b/score/crypto/src/api/BUILD index 5cf44811d..4d8e1ec9c 100644 --- a/score/crypto/src/api/BUILD +++ b/score/crypto/src/api/BUILD @@ -47,6 +47,8 @@ cc_library( deps = [ "//score/crypto/src/api:operations", "//score/crypto/src/api/common:crypto_common", + "//score/crypto/src/api/types:types", + "//score/crypto/src/api/config:cert_context_configs", "//score/crypto/src/api/config:context_configs", "//score/crypto/src/api/contexts:context_bases", "//score/crypto/src/api/contexts:crypto_contexts", diff --git a/score/crypto/src/api/certificate/BUILD b/score/crypto/src/api/certificate/BUILD index a0e9c52e4..c3047b02d 100644 --- a/score/crypto/src/api/certificate/BUILD +++ b/score/crypto/src/api/certificate/BUILD @@ -14,15 +14,13 @@ load("@rules_cc//cc:defs.bzl", "cc_library") cc_library( - name = "cert_types", + name = "ocsp_export", hdrs = [ - "cert_types.hpp", "i_ocsp_request_export.hpp", ], includes = ["."], visibility = ["//visibility:public"], deps = [ - "//score/crypto/src/api/common:crypto_common", "@score_baselibs//score/language/futurecpp", "@score_baselibs//score/result", ], diff --git a/score/crypto/src/api/certificate/cert_types.hpp b/score/crypto/src/api/certificate/cert_types.hpp deleted file mode 100644 index cd2f697be..000000000 --- a/score/crypto/src/api/certificate/cert_types.hpp +++ /dev/null @@ -1,64 +0,0 @@ -/******************************************************************************** - * Copyright (c) 2026 Contributors to the Eclipse Foundation - * - * See the NOTICE file(s) distributed with this work for additional - * information regarding copyright ownership. - * - * This program and the accompanying materials are made available under the - * terms of the Apache License Version 2.0 which is available at - * https://www.apache.org/licenses/LICENSE-2.0 - * - * SPDX-License-Identifier: Apache-2.0 - ********************************************************************************/ - -#ifndef SCORE_CRYPTO_SRC_API_CERTIFICATE_CERT_TYPES_HPP -#define SCORE_CRYPTO_SRC_API_CERTIFICATE_CERT_TYPES_HPP - -#include "score/crypto/src/api/common/types.hpp" - -#include - -namespace score -{ - -namespace crypto -{ - -/// @brief Result of a certificate verification operation. -enum class CertVerifyResult : uint8_t -{ - kValid, ///< Certificate is valid and trusted - kExpired, ///< Certificate has expired - kNotYetValid, ///< Certificate is not yet valid (future notBefore) - kRevoked, ///< Certificate has been revoked - kNoRootFound, ///< Root CA is not in the trust store - kChainIncomplete, ///< Intermediate certificate missing - kSignatureInvalid, ///< Signature verification failed - kInvalidPurpose, ///< Key usage or extended key usage mismatch - kUnknownAlgorithm, ///< Unsupported or unknown algorithm in certificate - kUnknownError ///< Unspecified verification failure -}; - -/// @brief Controls where certificate-chain verification may terminate. -enum class ChainTerminationPolicy : uint8_t -{ - /// Require a complete path ending at a self-signed trust-store root. - kRootRequired, - /// Permit termination at the first certificate present in the trust store. - kTrustStoreTerminated -}; - -/// @brief Status of an OCSP response. -enum class OcspStatus : uint8_t -{ - kGood, ///< Certificate is not revoked - kRevoked, ///< Certificate has been revoked - kUnknown, ///< Responder does not know the certificate - kError ///< OCSP response could not be parsed or verified -}; - -} // namespace crypto - -} // namespace score - -#endif // SCORE_CRYPTO_SRC_API_CERTIFICATE_CERT_TYPES_HPP diff --git a/score/crypto/src/api/common/BUILD b/score/crypto/src/api/common/BUILD index 77b6993a4..63e81b5e8 100644 --- a/score/crypto/src/api/common/BUILD +++ b/score/crypto/src/api/common/BUILD @@ -13,6 +13,13 @@ load("@rules_cc//cc:defs.bzl", "cc_library") +cc_library( + name = "crypto_common_base", + hdrs = ["fixed_capacity_string.hpp"], + includes = ["."], + visibility = ["//visibility:public"], +) + cc_library( name = "crypto_common", srcs = [ @@ -27,11 +34,12 @@ cc_library( "fixed_capacity_string.hpp", "i_memory.hpp", "i_memory_allocator.hpp", - "types.hpp", ], includes = ["."], visibility = ["//visibility:public"], deps = [ + ":crypto_common_base", + "//score/crypto/src/api/types:common_types", "@score_baselibs//score/language/futurecpp", "@score_baselibs//score/result", ], diff --git a/score/crypto/src/api/common/crypto_resource_guard.hpp b/score/crypto/src/api/common/crypto_resource_guard.hpp index b1a69bfb1..831df0ec9 100644 --- a/score/crypto/src/api/common/crypto_resource_guard.hpp +++ b/score/crypto/src/api/common/crypto_resource_guard.hpp @@ -14,7 +14,7 @@ #ifndef SCORE_CRYPTO_SRC_API_COMMON_CRYPTO_RESOURCE_GUARD_HPP #define SCORE_CRYPTO_SRC_API_COMMON_CRYPTO_RESOURCE_GUARD_HPP -#include "score/crypto/src/api/common/types.hpp" +#include "score/crypto/src/api/types/common.hpp" #include "score/result/result.h" #include diff --git a/score/crypto/src/api/common/i_memory_allocator.hpp b/score/crypto/src/api/common/i_memory_allocator.hpp index 3ceaac56f..941bea398 100644 --- a/score/crypto/src/api/common/i_memory_allocator.hpp +++ b/score/crypto/src/api/common/i_memory_allocator.hpp @@ -15,7 +15,7 @@ #define SCORE_CRYPTO_SRC_API_COMMON_I_MEMORY_ALLOCATOR_HPP #include "score/crypto/src/api/common/i_memory.hpp" -#include "score/crypto/src/api/common/types.hpp" +#include "score/crypto/src/api/types/common.hpp" #include "score/result/result.h" #include diff --git a/score/crypto/src/api/common/src/i_release_callback.hpp b/score/crypto/src/api/common/src/i_release_callback.hpp index abdb6aae7..d76356741 100644 --- a/score/crypto/src/api/common/src/i_release_callback.hpp +++ b/score/crypto/src/api/common/src/i_release_callback.hpp @@ -14,7 +14,7 @@ #ifndef SCORE_CRYPTO_SRC_API_COMMON_SRC_I_RELEASE_CALLBACK_HPP #define SCORE_CRYPTO_SRC_API_COMMON_SRC_I_RELEASE_CALLBACK_HPP -#include "score/crypto/src/api/common/types.hpp" +#include "score/crypto/src/api/types/common.hpp" #include "score/result/result.h" #include diff --git a/score/crypto/src/api/common/types.hpp b/score/crypto/src/api/common/types.hpp deleted file mode 100644 index dcd4e149a..000000000 --- a/score/crypto/src/api/common/types.hpp +++ /dev/null @@ -1,453 +0,0 @@ -/******************************************************************************** - * Copyright (c) 2026 Contributors to the Eclipse Foundation - * - * See the NOTICE file(s) distributed with this work for additional - * information regarding copyright ownership. - * - * This program and the accompanying materials are made available under the - * terms of the Apache License Version 2.0 which is available at - * https://www.apache.org/licenses/LICENSE-2.0 - * - * SPDX-License-Identifier: Apache-2.0 - ********************************************************************************/ - -#ifndef SCORE_CRYPTO_SRC_API_COMMON_TYPES_HPP -#define SCORE_CRYPTO_SRC_API_COMMON_TYPES_HPP - -#include "score/crypto/src/api/common/error_domain.hpp" -#include "score/crypto/src/api/common/fixed_capacity_string.hpp" - -#include -#include -#include -#include - -namespace score -{ - -namespace crypto -{ - -/// @brief Application-defined name for config files (e.g., "KeySlot_42"). -/// Only used at resolution time via ICryptoContext::ResolveResource(). -/// -/// Uses FixedCapacityString<64> — stack-allocated, no heap allocation. -/// Resource names are deployment-time configuration values (bounded, immutable). -/// All observed resource name strings are well under 64 characters. -using ResourceId = FixedCapacityString<64>; - -/// @brief String-based algorithm identifier for extensibility (including PQC). -/// -/// Uses FixedCapacityString<64> — a stack-allocated, non-heap-allocating string -/// that satisfies automotive safety requirements (deterministic memory, no heap -/// fragmentation) while preserving extensibility. New algorithms can be added -/// at the daemon level without modifying the client library — any algorithm name -/// up to 64 characters is accepted at runtime. -/// -/// Examples: "AES-256-CBC", "SHA-256", "ECDSA-P256", "ML-KEM-768", "ML-DSA-65", -/// "SLH-DSA-SHA2-128s", "XMSS-SHA2_10_256" -/// -/// Implicit conversion to std::string_view enables zero-copy interop. -/// Explicit conversion to std::string available for IPC serialization. -using AlgorithmId = FixedCapacityString<64>; - -/// @brief Type of crypto resource managed by the daemon. -/// -/// kKey and kCertificate identify live objects (key material, parsed certs); -/// kKeySlot and kCertSlot identify only persistent storage locations. -enum class ResourceType : uint8_t -{ - kProvider, ///< Crypto provider / device - kKeySlot, ///< Persistent key storage slot - kCertSlot, ///< Persistent certificate storage slot - kCertificateTrustStore, ///< Named group of trusted CA certificates used for certificate chain - ///< verification. - kKey, ///< Key material (generated / loaded / derived / imported) - kCertificate, ///< Parsed or stored certificate object. - kSecureObject, ///< Secure storage entry - kDataObject ///< Generic data blob -}; - -/// @brief Persistence classification of a crypto resource. -enum class ResourcePersistence : uint8_t -{ - kPersistent, ///< Survives context/stack destruction, stored in provider - kEphemeral ///< Auto-cleaned on context/stack destruction -}; - -/// @brief The sole runtime handle for all resolved crypto resources. -/// -/// Applications resolve string-based ResourceId to CryptoResourceId once via -/// ICryptoContext::ResolveResource(), then use this compact struct for all -/// subsequent operations. No string fields — all comparisons are numeric/enum. -/// -/// @note Struct is ~16 bytes with padding, fully numeric, cheap to copy and hash. -struct CryptoResourceId -{ - uint64_t id{0U}; ///< Daemon-assigned, unique per session - ResourceType type{ResourceType::kKeySlot}; ///< Resource classification - ResourcePersistence persistence{ResourcePersistence::kEphemeral}; ///< Lifetime - uint16_t primary_provider{0U}; ///< Daemon-assigned numeric provider index. - ///< Embeds device binding: identifies which - ///< provider/device owns this resource. - ///< 0 = unbound (e.g., trust anchors). - - constexpr bool operator==(const CryptoResourceId& other) const noexcept - { - return (id == other.id) && (type == other.type) && (persistence == other.persistence) && - (primary_provider == other.primary_provider); - } - - constexpr bool operator!=(const CryptoResourceId& other) const noexcept - { - return !(*this == other); - } -}; - -/// @brief Preference for selecting a crypto provider when not explicitly specified. -enum class ProviderType : uint8_t -{ - kDefault, ///< Daemon selects the most appropriate provider - kHardware, ///< Require a hardware provider (HSM/TEE) - kSoftware, ///< Require a software provider (OpenSSL/wolfSSL) - kHardwarePreferred, ///< Prefer hardware, fall back to software - kSoftwarePreferred ///< Prefer software, fall back to hardware -}; - -/// @brief Certificate and key data encoding format. -enum class FormatType : uint8_t -{ - kDer, ///< DER (binary) encoding - kPem ///< PEM (base64-armored) encoding -}; - -/// @brief State of a key slot. -/// -/// Renamed from KeySlotStatus to disambiguate from CertificateStatus. -enum class KeySlotState : uint8_t -{ - kEmpty, ///< Slot contains no key material - kOccupied, ///< Slot contains a key - kLocked ///< Slot is in use and cannot be modified -}; - -/// @brief State of a certificate slot. -/// -/// Certificate slots contain certificate/CRL storage and are not bound to a -/// certificate-operation provider. Provider selection is made by the -/// operation/context that parses or verifies the material. -enum class CertificateSlotState : uint8_t -{ - kEmpty, ///< Slot contains no certificate - kOccupied, ///< Slot contains a certificate - kLocked ///< Slot is in use and cannot be modified -}; - -/// @brief Validity status of a certificate. -enum class CertificateStatus : uint8_t -{ - kValid, ///< Certificate is valid - kRevoked, ///< Certificate has been revoked - kExpired, ///< Certificate has expired - kUnknown ///< Status cannot be determined -}; - -/// @brief Direction for symmetric cipher and AEAD operations. -enum class CipherDirection : uint8_t -{ - kEncrypt, ///< Encryption / sealing direction - kDecrypt ///< Decryption / opening direction -}; - -/// @brief Intended usage mode for MAC and signature contexts. -/// -/// Specifies whether the context will be used to generate (sign) or verify. -/// Used for: -/// - Key permission enforcement (kSign for generation, kVerify for verification). -/// - Provider-specific API selection (e.g. PKCS#11 C_SignInit vs C_VerifyInit). -/// -/// @note CipherDirection covers encrypt/decrypt for symmetric ciphers. -/// OperationMode covers MAC generation/verification and future signature contexts. -enum class OperationMode : uint8_t -{ - kGenerate, ///< MAC generation / signature creation - kVerify ///< MAC verification / signature verification -}; - -/// @brief Type of shared memory to allocate for the data plane. -enum class MemoryType : uint8_t -{ - kDefault, ///< Daemon-managed shared memory, suitable for most providers. - ///< The daemon may copy data into provider-compatible memory internally. - kProviderCompatible ///< Memory directly usable by a specific provider (e.g., DMA-capable - ///< for HW/TEE), enabling true zero-copy from application through - ///< daemon to the crypto device. -}; - -/// @brief Controls the revocation checking strategy in ICertificateVerificationContext. -enum class RevocationCheckPolicy : uint8_t -{ - kNone, ///< No revocation checking - kCrlOnly, ///< Check revocation using CRL only - kOcspOnly, ///< Check revocation using OCSP only - kOcspWithCrlFallback ///< Prefer OCSP, fall back to CRL if OCSP is unavailable -}; - -/// @brief Bitmask defining which cryptographic operations a key is permitted to perform. -/// -/// Key operation permissions enforce the principle of least privilege: a key -/// configured for signing cannot be misused for encryption, and vice versa. -/// Permissions are assigned when a key slot is provisioned (daemon-side -/// configuration) and optionally constrained further at key generation time. -/// -/// The permission model uses a capability-centric bitmask grouped by -/// operation category: -/// - **Data protection** (bits 0–3): encrypt, decrypt, wrap, unwrap -/// - **Authentication** (bits 4–7): sign, verify, mac, agree -/// - **Key lifecycle** (bits 8–10): derive, export, import -/// -/// Composite presets are provided for common deployment patterns. -/// Use bitwise OR to combine individual permissions. -/// -/// @note Permission enforcement is performed by the daemon at context -/// creation time. If a key's permissions do not include the operation -/// requested by the context, the daemon returns -/// CryptoErrorCode::kKeyOperationNotPermitted. -enum class KeyOperationPermission : uint32_t -{ - kNone = 0x0000U, ///< No operations permitted (storage-only key) - - // ---- Data protection (bits 0–3) ---- - kEncrypt = 0x0001U, ///< Symmetric/asymmetric encryption - kDecrypt = 0x0002U, ///< Symmetric/asymmetric decryption - kWrap = 0x0004U, ///< Key wrapping (encrypting another key) - kUnwrap = 0x0008U, ///< Key unwrapping (decrypting a wrapped key) - - // ---- Authentication (bits 4–7) ---- - kSign = 0x0010U, ///< Digital signature generation - kVerify = 0x0020U, ///< Digital signature verification - kMac = 0x0040U, ///< MAC generation and verification - kAgree = 0x0080U, ///< Key agreement (ECDH, ML-KEM decapsulation) - - // ---- Key lifecycle (bits 8–10) ---- - kDerive = 0x0100U, ///< Key derivation (as source key) - kExport = 0x0200U, ///< Export raw key material (for exportable keys) - kImport = 0x0400U, ///< Slot accepts imported key material - - // ---- Composite presets (common deployment patterns) ---- - - /// Data protection: encrypt + decrypt + wrap + unwrap - kDataProtection = 0x000FU, - /// Authentication: sign + verify + mac + agree - kAuthentication = 0x00F0U, - /// Full lifecycle: derive + export + import - kFullLifecycle = 0x0700U, - /// All operations permitted (no restrictions) - kAll = 0x07FFU, -}; - -/// @brief Bitwise OR for combining key operation permissions. -inline constexpr KeyOperationPermission operator|(KeyOperationPermission lhs, KeyOperationPermission rhs) noexcept -{ - return static_cast(static_cast(lhs) | static_cast(rhs)); -} - -/// @brief Bitwise AND for testing key operation permissions. -inline constexpr KeyOperationPermission operator&(KeyOperationPermission lhs, KeyOperationPermission rhs) noexcept -{ - return static_cast(static_cast(lhs) & static_cast(rhs)); -} - -/// @brief Bitwise NOT for inverting key operation permissions. -/// @note Result is masked to valid permission bits (0–10) to prevent undefined states. -inline constexpr KeyOperationPermission operator~(KeyOperationPermission perm) noexcept -{ - constexpr uint32_t kValidBitsMask = 0x07FFU; // Bits 0–10 only - return static_cast((~static_cast(perm)) & kValidBitsMask); -} - -/// @brief Bitwise OR-assign for accumulating key operation permissions. -inline constexpr KeyOperationPermission& operator|=(KeyOperationPermission& lhs, KeyOperationPermission rhs) noexcept -{ - lhs = lhs | rhs; - return lhs; -} - -/// @brief Bitwise AND-assign for masking key operation permissions. -inline constexpr KeyOperationPermission& operator&=(KeyOperationPermission& lhs, KeyOperationPermission rhs) noexcept -{ - lhs = lhs & rhs; - return lhs; -} - -/// @brief Tests whether a permission set includes a specific required permission. -/// @param granted The permission set to test (e.g., from KeySlotInfo) -/// @param required The permission(s) being checked -/// @return true if all bits in required are set in granted -inline constexpr bool HasPermission(KeyOperationPermission granted, KeyOperationPermission required) noexcept -{ - // Only consider defined permission bits (bits 0..10). Mask both operands - // to avoid granting permissions due to out-of-range/invalid bits. - constexpr uint32_t kValidBitsMask = 0x07FFU; // bits 0..10 - const uint32_t g = static_cast(granted) & kValidBitsMask; - const uint32_t r = static_cast(required) & kValidBitsMask; - return (g & r) == r; -} - -/// @brief Lightweight information about certificate-slot storage. -/// -/// Returned by ICertificateManagementContext::GetCertificateSlotInfo(). -/// Certificate-specific details such as subject, issuer, algorithm, and -/// validity are obtained by loading/parsing the certificate. -struct CertificateSlotInfo -{ - CertificateSlotState state{CertificateSlotState::kEmpty}; - bool has_crl{false}; ///< Whether a CRL is currently associated with the slot -}; - -/// @brief Information about a key slot and its contents. -/// -/// Returned by IKeyManagementContext::GetKeySlotInfo(). Exposes device binding, -/// cross-provider compatibility, and permitted operations so applications can -/// make informed decisions. -struct KeySlotInfo -{ - KeySlotState state{KeySlotState::kEmpty}; ///< State of the key slot - AlgorithmId algorithm{}; ///< Algorithm of the stored key (empty if slot is empty) - uint16_t primary_provider{0U}; ///< Provider/device that owns this slot - - /// @brief Secondary providers that can also use keys in this slot. - /// - /// Fixed-capacity array (max 8 providers). Use compatible_provider_count - /// to determine how many entries are valid. - static constexpr std::size_t kMaxCompatibleProviders = 8U; - std::array compatible_providers{}; - std::size_t compatible_provider_count{0U}; - - /// @brief Operations this key slot permits. - /// - /// Defaults to kAll for backward compatibility. When provisioned with - /// restricted permissions, the daemon enforces them at context creation - /// time — creating an encrypt context with a sign-only key returns - /// CryptoErrorCode::kKeyOperationNotPermitted. - KeyOperationPermission permitted_operations{KeyOperationPermission::kAll}; -}; - -/// @brief Human-readable provider metadata. -/// -/// Returned by ICryptoContext::GetProviderInfo(). Maps daemon-assigned numeric -/// provider IDs to descriptive information. -struct ProviderInfo -{ - uint16_t id{0U}; ///< Daemon-assigned provider index - ProviderType type{ProviderType::kDefault}; ///< Provider classification - FixedCapacityString<32> name{}; ///< Human-readable provider name (e.g., "OpenSSL", "SoftHSM") -}; - -/// @brief Cross-provider compatibility information for a resource. -/// -/// Returned by ICryptoContext::QueryProviderCompatibility(). Secondary providers -/// are those that can also use this resource (e.g., a SW-exported key re-importable -/// into another SW provider). Not embedded in CryptoResourceId because the -/// secondary list is variable-length and mutable daemon-side state. -struct ProviderCompatibilityInfo -{ - CryptoResourceId resource{}; ///< The queried resource - uint16_t primary_provider{0U}; ///< Owning provider - - /// @brief Providers that can also use this resource. - /// - /// Fixed-capacity array (max 8 providers). Use secondary_provider_count - /// to determine how many entries are valid. - static constexpr std::size_t kMaxSecondaryProviders = 8U; - std::array secondary_providers{}; - std::size_t secondary_provider_count{0U}; -}; - -/// @brief Capabilities of a specific algorithm as reported by the daemon. -/// -/// Returned by ICryptoContext::QueryCapabilities(). Includes PQC algorithms -/// (e.g., "ML-KEM-768", "ML-DSA-65") when supported by configured providers. -struct AlgorithmCapabilities -{ - AlgorithmId id{}; ///< Algorithm identifier - bool supported{false}; ///< Whether any configured provider supports this algorithm - - /// @brief Supported modes/variants (e.g., "CBC", "GCM", "CTR"). - /// - /// Fixed-capacity array (max 16 modes). Use mode_count to determine - /// how many entries are valid. - static constexpr std::size_t kMaxModes = 16U; - std::array, kMaxModes> modes{}; - std::size_t mode_count{0U}; -}; - -/// @brief Aggregate view of all providers and supported algorithms. -/// -/// Returned by the parameterless ICryptoContext::QueryCapabilities() overload. -/// Provides a complete snapshot of the system's crypto capabilities. -struct SystemCapabilities -{ - /// @brief All configured providers. - /// - /// Fixed-capacity array (max 16 providers). Use provider_count to determine - /// how many entries are valid. - static constexpr std::size_t kMaxProviders = 16U; - std::array providers{}; - std::size_t provider_count{0U}; - - /// @brief All supported algorithms. - /// - /// Fixed-capacity array (max 64 algorithms). Use algorithm_count to determine - /// how many entries are valid. - static constexpr std::size_t kMaxAlgorithms = 64U; - std::array algorithms{}; - std::size_t algorithm_count{0U}; -}; - -/// @brief Single key-value entry for algorithm- or operation-scoped extended parameters. -struct ExtendedParameterEntry -{ - FixedCapacityString<32> key{}; ///< Parameter name (middleware-defined, not provider-defined) - FixedCapacityString<64> value{}; ///< Parameter value -}; - -/// @brief Fixed-capacity key-value map for algorithm- or operation-scoped extended parameters. -/// -/// Provides a forward-compatible extension point in context configs for parameters -/// that are not yet modeled as typed fields (e.g., PQC parameter sets, key-derivation -/// context strings). Keys and their semantics are defined by the **middleware -/// specification** — never by the underlying crypto provider or hardware back-end. -/// -/// Provider-specific tuning (HSM slot indices, PIN policies, vendor flags, etc.) -/// belongs exclusively in the daemon's static configuration and must NOT appear -/// here. Application code using this struct must remain portable across all -/// compliant provider implementations. -/// -/// Max 16 entries. -struct ExtendedParameters -{ - static constexpr std::size_t kMaxEntries = 16U; - std::array entries{}; - std::size_t entry_count{0U}; -}; - -} // namespace crypto - -} // namespace score - -/// @brief std::hash specialization for CryptoResourceId, enabling use in unordered containers. -template <> -struct std::hash -{ - std::size_t operator()(const score::crypto::CryptoResourceId& rid) const noexcept - { - std::size_t h = std::hash{}(rid.id); - h ^= std::hash{}(static_cast(rid.type)) << 1U; - h ^= std::hash{}(static_cast(rid.persistence)) << 2U; - h ^= std::hash{}(rid.primary_provider) << 3U; - return h; - } -}; - -#endif // SCORE_CRYPTO_SRC_API_COMMON_TYPES_HPP diff --git a/score/crypto/src/api/config/BUILD b/score/crypto/src/api/config/BUILD index 1dd33a64e..4b5288625 100644 --- a/score/crypto/src/api/config/BUILD +++ b/score/crypto/src/api/config/BUILD @@ -27,6 +27,7 @@ cc_library( visibility = ["//visibility:public"], deps = [ "//score/crypto/src/api/common:crypto_common", + "//score/crypto/src/api/types:types", ], ) @@ -41,5 +42,6 @@ cc_library( deps = [ ":context_configs", "//score/crypto/src/api/common:crypto_common", + "//score/crypto/src/api/types:types", ], ) diff --git a/score/crypto/src/api/config/base_context_config.hpp b/score/crypto/src/api/config/base_context_config.hpp index efe3cd18f..3ec03ed4e 100644 --- a/score/crypto/src/api/config/base_context_config.hpp +++ b/score/crypto/src/api/config/base_context_config.hpp @@ -14,7 +14,7 @@ #ifndef SCORE_CRYPTO_SRC_API_CONFIG_BASE_CONTEXT_CONFIG_HPP #define SCORE_CRYPTO_SRC_API_CONFIG_BASE_CONTEXT_CONFIG_HPP -#include "score/crypto/src/api/common/types.hpp" +#include "score/crypto/src/api/types/common.hpp" #include #include diff --git a/score/crypto/src/api/config/certificate_context_config.hpp b/score/crypto/src/api/config/certificate_context_config.hpp index 8808c2def..a0b94b39c 100644 --- a/score/crypto/src/api/config/certificate_context_config.hpp +++ b/score/crypto/src/api/config/certificate_context_config.hpp @@ -38,12 +38,6 @@ struct CertificateContextConfig : public BaseContextConfig { // -- Fluent builder -- - CertificateContextConfig& SetAlgorithm(const AlgorithmId& alg) noexcept - { - BaseContextConfig::SetAlgorithm(alg); - return *this; - } - CertificateContextConfig& SetProvider(const CryptoResourceId& prov) noexcept { BaseContextConfig::SetProvider(prov); diff --git a/score/crypto/src/api/config/certificate_verification_context_config.hpp b/score/crypto/src/api/config/certificate_verification_context_config.hpp index 838fd0c75..0eac7dd5f 100644 --- a/score/crypto/src/api/config/certificate_verification_context_config.hpp +++ b/score/crypto/src/api/config/certificate_verification_context_config.hpp @@ -14,8 +14,9 @@ #ifndef SCORE_CRYPTO_SRC_API_CONFIG_CERTIFICATE_VERIFICATION_CONTEXT_CONFIG_HPP #define SCORE_CRYPTO_SRC_API_CONFIG_CERTIFICATE_VERIFICATION_CONTEXT_CONFIG_HPP -#include "score/crypto/src/api/common/types.hpp" #include "score/crypto/src/api/config/base_context_config.hpp" +#include "score/crypto/src/api/types/certificate.hpp" +#include "score/crypto/src/api/types/common.hpp" #include @@ -51,12 +52,6 @@ struct CertificateVerificationContextConfig : public BaseContextConfig // -- Fluent builder -- - CertificateVerificationContextConfig& SetAlgorithm(const AlgorithmId& alg) noexcept - { - BaseContextConfig::SetAlgorithm(alg); - return *this; - } - CertificateVerificationContextConfig& SetProvider(const CryptoResourceId& prov) noexcept { BaseContextConfig::SetProvider(prov); diff --git a/score/crypto/src/api/config/key_operation_params.hpp b/score/crypto/src/api/config/key_operation_params.hpp index 6e56182ac..94c50c0d8 100644 --- a/score/crypto/src/api/config/key_operation_params.hpp +++ b/score/crypto/src/api/config/key_operation_params.hpp @@ -14,7 +14,9 @@ #ifndef SCORE_CRYPTO_SRC_API_CONFIG_KEY_OPERATION_PARAMS_HPP #define SCORE_CRYPTO_SRC_API_CONFIG_KEY_OPERATION_PARAMS_HPP -#include "score/crypto/src/api/common/types.hpp" +#include "score/crypto/src/api/common/error_domain.hpp" +#include "score/crypto/src/api/types/common.hpp" +#include "score/crypto/src/api/types/key.hpp" #include "score/span.hpp" #include diff --git a/score/crypto/src/api/config/permission_builder.hpp b/score/crypto/src/api/config/permission_builder.hpp index 9b3272d8b..12def9a5d 100644 --- a/score/crypto/src/api/config/permission_builder.hpp +++ b/score/crypto/src/api/config/permission_builder.hpp @@ -14,7 +14,7 @@ #ifndef SCORE_CRYPTO_SRC_API_CONFIG_PERMISSION_BUILDER_HPP #define SCORE_CRYPTO_SRC_API_CONFIG_PERMISSION_BUILDER_HPP -#include "score/crypto/src/api/common/types.hpp" +#include "score/crypto/src/api/types/key.hpp" namespace score { diff --git a/score/crypto/src/api/contexts/BUILD b/score/crypto/src/api/contexts/BUILD index 06375baa8..bb3fe3f19 100644 --- a/score/crypto/src/api/contexts/BUILD +++ b/score/crypto/src/api/contexts/BUILD @@ -24,6 +24,7 @@ cc_library( visibility = ["//visibility:public"], deps = [ "//score/crypto/src/api/common:crypto_common", + "//score/crypto/src/api/types:types", "@score_baselibs//score/language/futurecpp", "@score_baselibs//score/result", ], @@ -41,6 +42,7 @@ cc_library( deps = [ ":context_bases", "//score/crypto/src/api/common:crypto_common", + "//score/crypto/src/api/types:types", "//score/crypto/src/api/config:context_configs", "//score/crypto/src/api/objects:crypto_objects", "@score_baselibs//score/language/futurecpp", @@ -58,8 +60,10 @@ cc_library( visibility = ["//visibility:public"], deps = [ ":context_bases", - "//score/crypto/src/api/certificate:cert_types", + "//score/crypto/src/api/types:certificate_types", + "//score/crypto/src/api/certificate:ocsp_export", "//score/crypto/src/api/common:crypto_common", + "//score/crypto/src/api/types:types", "//score/crypto/src/api/config:cert_context_configs", "//score/crypto/src/api/objects:cert_objects", "@score_baselibs//score/language/futurecpp", @@ -86,6 +90,7 @@ cc_library( "//score/crypto/src/api:operations", "//score/crypto/src/api/common:crypto_common", "//score/crypto/src/api/common:release_callback_iface", + "//score/crypto/src/api/types:types", "//score/crypto/src/api/control_plane", "//score/crypto/src/api/data_plane:data_plane_client", ], diff --git a/score/crypto/src/api/contexts/i_certificate_management_context.hpp b/score/crypto/src/api/contexts/i_certificate_management_context.hpp index 71e075dc1..f4c4882f9 100644 --- a/score/crypto/src/api/contexts/i_certificate_management_context.hpp +++ b/score/crypto/src/api/contexts/i_certificate_management_context.hpp @@ -15,9 +15,10 @@ #define SCORE_CRYPTO_SRC_API_CONTEXTS_I_CERTIFICATE_MANAGEMENT_CONTEXT_HPP #include "score/crypto/src/api/common/crypto_resource_guard.hpp" -#include "score/crypto/src/api/common/types.hpp" #include "score/crypto/src/api/contexts/i_context.hpp" #include "score/crypto/src/api/objects/i_certificate_object.hpp" +#include "score/crypto/src/api/types/certificate.hpp" +#include "score/crypto/src/api/types/common.hpp" #include "score/result/result.h" #include "score/span.hpp" diff --git a/score/crypto/src/api/contexts/i_certificate_verification_context.hpp b/score/crypto/src/api/contexts/i_certificate_verification_context.hpp index db6c7b106..c7e69f785 100644 --- a/score/crypto/src/api/contexts/i_certificate_verification_context.hpp +++ b/score/crypto/src/api/contexts/i_certificate_verification_context.hpp @@ -14,9 +14,9 @@ #ifndef SCORE_CRYPTO_SRC_API_CONTEXTS_I_CERTIFICATE_VERIFICATION_CONTEXT_HPP #define SCORE_CRYPTO_SRC_API_CONTEXTS_I_CERTIFICATE_VERIFICATION_CONTEXT_HPP -#include "score/crypto/src/api/certificate/cert_types.hpp" -#include "score/crypto/src/api/common/types.hpp" #include "score/crypto/src/api/contexts/i_context.hpp" +#include "score/crypto/src/api/types/certificate.hpp" +#include "score/crypto/src/api/types/common.hpp" #include "score/result/result.h" #include "score/span.hpp" diff --git a/score/crypto/src/api/contexts/i_key_management_context.hpp b/score/crypto/src/api/contexts/i_key_management_context.hpp index 4592cfa7e..c618cbf4c 100644 --- a/score/crypto/src/api/contexts/i_key_management_context.hpp +++ b/score/crypto/src/api/contexts/i_key_management_context.hpp @@ -15,9 +15,10 @@ #define SCORE_CRYPTO_SRC_API_CONTEXTS_I_KEY_MANAGEMENT_CONTEXT_HPP #include "score/crypto/src/api/common/crypto_resource_guard.hpp" -#include "score/crypto/src/api/common/types.hpp" #include "score/crypto/src/api/config/key_operation_params.hpp" #include "score/crypto/src/api/contexts/i_context.hpp" +#include "score/crypto/src/api/types/common.hpp" +#include "score/crypto/src/api/types/key.hpp" #include "score/result/result.h" #include "score/span.hpp" diff --git a/score/crypto/src/api/contexts/src/hash_context_impl.cpp b/score/crypto/src/api/contexts/src/hash_context_impl.cpp index 479716c77..34044bea6 100644 --- a/score/crypto/src/api/contexts/src/hash_context_impl.cpp +++ b/score/crypto/src/api/contexts/src/hash_context_impl.cpp @@ -14,7 +14,7 @@ #include "score/crypto/src/api/contexts/src/hash_context_impl.hpp" #include "score/crypto/src/api/common/error_domain.hpp" -#include "score/crypto/src/api/common/types.hpp" +#include "score/crypto/src/api/types/common.hpp" #include "score/crypto/src/api/control_plane/i_connection.hpp" #include "score/crypto/src/daemon/common/actors.hpp" diff --git a/score/crypto/src/api/contexts/src/hash_context_impl.hpp b/score/crypto/src/api/contexts/src/hash_context_impl.hpp index 3c117b959..615990d57 100644 --- a/score/crypto/src/api/contexts/src/hash_context_impl.hpp +++ b/score/crypto/src/api/contexts/src/hash_context_impl.hpp @@ -16,8 +16,8 @@ #include "score/crypto/src/api/contexts/i_hash_context.hpp" -#include "score/crypto/src/api/common/types.hpp" #include "score/crypto/src/api/data_plane/i_buffer_transcoder.hpp" +#include "score/crypto/src/api/types/common.hpp" #include "score/crypto/src/api/control_plane/i_connection.hpp" diff --git a/score/crypto/src/api/contexts/src/key_management_context_impl.cpp b/score/crypto/src/api/contexts/src/key_management_context_impl.cpp index bd4e2d5e3..1502062bc 100644 --- a/score/crypto/src/api/contexts/src/key_management_context_impl.cpp +++ b/score/crypto/src/api/contexts/src/key_management_context_impl.cpp @@ -17,8 +17,9 @@ #include "score/crypto/src/api/common/error_domain.hpp" #include "score/crypto/src/api/common/src/crypto_resource_guard_factory.hpp" #include "score/crypto/src/api/common/src/i_release_callback.hpp" -#include "score/crypto/src/api/common/types.hpp" #include "score/crypto/src/api/config/key_operation_params.hpp" +#include "score/crypto/src/api/types/common.hpp" +#include "score/crypto/src/api/types/key.hpp" #include "score/crypto/src/api/control_plane/i_connection.hpp" #include "score/crypto/src/daemon/common/actors.hpp" diff --git a/score/crypto/src/api/contexts/src/key_management_context_impl.hpp b/score/crypto/src/api/contexts/src/key_management_context_impl.hpp index 27fba5478..4a033ccf3 100644 --- a/score/crypto/src/api/contexts/src/key_management_context_impl.hpp +++ b/score/crypto/src/api/contexts/src/key_management_context_impl.hpp @@ -16,9 +16,10 @@ #include "score/crypto/src/api/common/crypto_resource_guard.hpp" #include "score/crypto/src/api/common/src/i_release_callback.hpp" -#include "score/crypto/src/api/common/types.hpp" #include "score/crypto/src/api/config/key_operation_params.hpp" #include "score/crypto/src/api/contexts/i_key_management_context.hpp" +#include "score/crypto/src/api/types/common.hpp" +#include "score/crypto/src/api/types/key.hpp" #include "score/crypto/src/api/control_plane/i_connection.hpp" #include "score/crypto/src/daemon/control_plane/control_protocol.h" diff --git a/score/crypto/src/api/contexts/src/mac_context_impl.cpp b/score/crypto/src/api/contexts/src/mac_context_impl.cpp index f0fd654fc..fe675617f 100644 --- a/score/crypto/src/api/contexts/src/mac_context_impl.cpp +++ b/score/crypto/src/api/contexts/src/mac_context_impl.cpp @@ -14,7 +14,7 @@ #include "score/crypto/src/api/contexts/src/mac_context_impl.hpp" #include "score/crypto/src/api/common/error_domain.hpp" -#include "score/crypto/src/api/common/types.hpp" +#include "score/crypto/src/api/types/common.hpp" #include "score/crypto/src/api/control_plane/i_connection.hpp" #include "score/crypto/src/daemon/common/actors.hpp" diff --git a/score/crypto/src/api/contexts/src/mac_context_impl.hpp b/score/crypto/src/api/contexts/src/mac_context_impl.hpp index 10748adef..2f503c669 100644 --- a/score/crypto/src/api/contexts/src/mac_context_impl.hpp +++ b/score/crypto/src/api/contexts/src/mac_context_impl.hpp @@ -16,8 +16,8 @@ #include "score/crypto/src/api/contexts/i_mac_context.hpp" -#include "score/crypto/src/api/common/types.hpp" #include "score/crypto/src/api/data_plane/i_buffer_transcoder.hpp" +#include "score/crypto/src/api/types/common.hpp" #include "score/crypto/src/api/control_plane/i_connection.hpp" diff --git a/score/crypto/src/api/data_plane/BUILD b/score/crypto/src/api/data_plane/BUILD index d75ce015a..e53c4f5d2 100644 --- a/score/crypto/src/api/data_plane/BUILD +++ b/score/crypto/src/api/data_plane/BUILD @@ -39,6 +39,7 @@ cc_library( visibility = ["//visibility:public"], deps = [ "//score/crypto/src/api/common:crypto_common", + "//score/crypto/src/api/types:types", "//score/crypto/src/api/control_plane", "//score/crypto/src/common:common_types", "//score/crypto/src/daemon/common", diff --git a/score/crypto/src/api/future/config/aead_context_config.hpp b/score/crypto/src/api/future/config/aead_context_config.hpp index b69b9320a..e545f5f48 100644 --- a/score/crypto/src/api/future/config/aead_context_config.hpp +++ b/score/crypto/src/api/future/config/aead_context_config.hpp @@ -14,8 +14,8 @@ #ifndef SCORE_CRYPTO_SRC_API_FUTURE_CONFIG_AEAD_CONTEXT_CONFIG_HPP #define SCORE_CRYPTO_SRC_API_FUTURE_CONFIG_AEAD_CONTEXT_CONFIG_HPP -#include "score/crypto/src/api/common/types.hpp" #include "score/crypto/src/api/config/base_context_config.hpp" +#include "score/crypto/src/api/types/common.hpp" namespace score { diff --git a/score/crypto/src/api/future/config/cipher_context_config.hpp b/score/crypto/src/api/future/config/cipher_context_config.hpp index cb99e2a5b..59c2d853d 100644 --- a/score/crypto/src/api/future/config/cipher_context_config.hpp +++ b/score/crypto/src/api/future/config/cipher_context_config.hpp @@ -15,8 +15,8 @@ #define SCORE_CRYPTO_SRC_API_FUTURE_CONFIG_CIPHER_CONTEXT_CONFIG_HPP #include "score/crypto/src/api/common/crypto_resource_guard.hpp" -#include "score/crypto/src/api/common/types.hpp" #include "score/crypto/src/api/config/base_context_config.hpp" +#include "score/crypto/src/api/types/common.hpp" namespace score { diff --git a/score/crypto/src/api/future/contexts/i_csr_generation_context.hpp b/score/crypto/src/api/future/contexts/i_csr_generation_context.hpp index 2333cf320..75ac8e5aa 100644 --- a/score/crypto/src/api/future/contexts/i_csr_generation_context.hpp +++ b/score/crypto/src/api/future/contexts/i_csr_generation_context.hpp @@ -15,8 +15,8 @@ #define SCORE_CRYPTO_SRC_API_FUTURE_CONTEXTS_I_CSR_GENERATION_CONTEXT_HPP #include "score/crypto/src/api/certificate/i_csr_export.hpp" -#include "score/crypto/src/api/common/types.hpp" #include "score/crypto/src/api/contexts/i_context.hpp" +#include "score/crypto/src/api/types/common.hpp" #include "score/result/result.h" #include diff --git a/score/crypto/src/api/i_crypto_context.hpp b/score/crypto/src/api/i_crypto_context.hpp index 2e614f724..1ff2b6f62 100644 --- a/score/crypto/src/api/i_crypto_context.hpp +++ b/score/crypto/src/api/i_crypto_context.hpp @@ -14,7 +14,7 @@ #ifndef SCORE_CRYPTO_SRC_API_I_CRYPTO_CONTEXT_HPP #define SCORE_CRYPTO_SRC_API_I_CRYPTO_CONTEXT_HPP -#include "score/crypto/src/api/common/types.hpp" +#include "score/crypto/src/api/types/common.hpp" #include "score/result/result.h" #include diff --git a/score/crypto/src/api/objects/i_certificate_object.hpp b/score/crypto/src/api/objects/i_certificate_object.hpp index fbea93ecf..eefdb2ca5 100644 --- a/score/crypto/src/api/objects/i_certificate_object.hpp +++ b/score/crypto/src/api/objects/i_certificate_object.hpp @@ -14,8 +14,9 @@ #ifndef SCORE_CRYPTO_SRC_API_OBJECTS_I_CERTIFICATE_OBJECT_HPP #define SCORE_CRYPTO_SRC_API_OBJECTS_I_CERTIFICATE_OBJECT_HPP -#include "score/crypto/src/api/common/types.hpp" #include "score/crypto/src/api/objects/i_crypto_object.hpp" +#include "score/crypto/src/api/types/certificate.hpp" +#include "score/crypto/src/api/types/common.hpp" #include "score/result/result.h" #include "score/span.hpp" diff --git a/score/crypto/src/api/objects/i_crypto_object.hpp b/score/crypto/src/api/objects/i_crypto_object.hpp index 383e98ec9..764d65e03 100644 --- a/score/crypto/src/api/objects/i_crypto_object.hpp +++ b/score/crypto/src/api/objects/i_crypto_object.hpp @@ -14,7 +14,7 @@ #ifndef SCORE_CRYPTO_SRC_API_OBJECTS_I_CRYPTO_OBJECT_HPP #define SCORE_CRYPTO_SRC_API_OBJECTS_I_CRYPTO_OBJECT_HPP -#include "score/crypto/src/api/common/types.hpp" +#include "score/crypto/src/api/types/common.hpp" #include diff --git a/score/crypto/src/api/objects/i_key_object.hpp b/score/crypto/src/api/objects/i_key_object.hpp index 7f8700d12..6bea23ae3 100644 --- a/score/crypto/src/api/objects/i_key_object.hpp +++ b/score/crypto/src/api/objects/i_key_object.hpp @@ -15,6 +15,7 @@ #define SCORE_CRYPTO_SRC_API_OBJECTS_I_KEY_OBJECT_HPP #include "score/crypto/src/api/objects/i_crypto_object.hpp" +#include "score/crypto/src/api/types/key.hpp" #include #include diff --git a/score/crypto/src/api/objects/i_key_slot_object.hpp b/score/crypto/src/api/objects/i_key_slot_object.hpp index a001ac0d4..06af2dd02 100644 --- a/score/crypto/src/api/objects/i_key_slot_object.hpp +++ b/score/crypto/src/api/objects/i_key_slot_object.hpp @@ -15,6 +15,7 @@ #define SCORE_CRYPTO_SRC_API_OBJECTS_I_KEY_SLOT_OBJECT_HPP #include "score/crypto/src/api/objects/i_crypto_object.hpp" +#include "score/crypto/src/api/types/key.hpp" #include #include diff --git a/score/crypto/src/api/objects/i_trust_store_object.hpp b/score/crypto/src/api/objects/i_trust_store_object.hpp index 3fb2b1c1a..0c6477f22 100644 --- a/score/crypto/src/api/objects/i_trust_store_object.hpp +++ b/score/crypto/src/api/objects/i_trust_store_object.hpp @@ -14,8 +14,8 @@ #ifndef SCORE_CRYPTO_SRC_API_OBJECTS_I_TRUST_STORE_OBJECT_HPP #define SCORE_CRYPTO_SRC_API_OBJECTS_I_TRUST_STORE_OBJECT_HPP -#include "score/crypto/src/api/common/types.hpp" #include "score/crypto/src/api/objects/i_crypto_object.hpp" +#include "score/crypto/src/api/types/common.hpp" #include "score/span.hpp" #include diff --git a/score/crypto/src/api/src/crypto_context_impl.cpp b/score/crypto/src/api/src/crypto_context_impl.cpp index 1afc8e301..6673db782 100644 --- a/score/crypto/src/api/src/crypto_context_impl.cpp +++ b/score/crypto/src/api/src/crypto_context_impl.cpp @@ -14,7 +14,6 @@ #include "score/crypto/src/api/src/crypto_context_impl.hpp" #include "score/crypto/src/api/common/error_domain.hpp" -#include "score/crypto/src/api/common/types.hpp" #include "score/crypto/src/api/config/hash_context_config.hpp" #include "score/crypto/src/api/config/key_management_context_config.hpp" #include "score/crypto/src/api/config/mac_context_config.hpp" @@ -22,6 +21,10 @@ #include "score/crypto/src/api/contexts/src/key_management_context_impl.hpp" #include "score/crypto/src/api/contexts/src/mac_context_impl.hpp" #include "score/crypto/src/api/src/provider_type_converter.hpp" +#include "score/crypto/src/api/types/certificate.hpp" +#include "score/crypto/src/api/types/common.hpp" +#include "score/crypto/src/daemon/common/actors.hpp" +#include "score/crypto/src/daemon/common/types.hpp" #include "score/crypto/src/daemon/control_plane/control_protocol.h" #include "score/crypto/src/api/control_plane/i_connection.hpp" diff --git a/score/crypto/src/api/src/crypto_context_impl.hpp b/score/crypto/src/api/src/crypto_context_impl.hpp index ae84ec686..d85e63e76 100644 --- a/score/crypto/src/api/src/crypto_context_impl.hpp +++ b/score/crypto/src/api/src/crypto_context_impl.hpp @@ -14,9 +14,9 @@ #ifndef SCORE_CRYPTO_SRC_API_SRC_CRYPTO_CONTEXT_IMPL_HPP #define SCORE_CRYPTO_SRC_API_SRC_CRYPTO_CONTEXT_IMPL_HPP -#include "score/crypto/src/api/common/types.hpp" #include "score/crypto/src/api/data_plane/i_buffer_transcoder.hpp" #include "score/crypto/src/api/i_crypto_context.hpp" +#include "score/crypto/src/api/types/common.hpp" #include "score/crypto/src/api/control_plane/i_connection.hpp" #include "score/crypto/src/daemon/control_plane/control_protocol.h" diff --git a/score/crypto/src/api/src/provider_type_converter.hpp b/score/crypto/src/api/src/provider_type_converter.hpp index 5f6372d76..7b7758d53 100644 --- a/score/crypto/src/api/src/provider_type_converter.hpp +++ b/score/crypto/src/api/src/provider_type_converter.hpp @@ -14,7 +14,7 @@ #ifndef SCORE_CRYPTO_SRC_API_SRC_PROVIDER_TYPE_CONVERTER_HPP #define SCORE_CRYPTO_SRC_API_SRC_PROVIDER_TYPE_CONVERTER_HPP -#include "score/crypto/src/api/common/types.hpp" +#include "score/crypto/src/api/types/common.hpp" #include diff --git a/score/crypto/src/api/types/BUILD b/score/crypto/src/api/types/BUILD new file mode 100644 index 000000000..d2a329b27 --- /dev/null +++ b/score/crypto/src/api/types/BUILD @@ -0,0 +1,46 @@ +# ******************************************************************************* +# Copyright (c) 2026 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* + +load("@rules_cc//cc:defs.bzl", "cc_library") + +cc_library( + name = "common_types", + hdrs = ["common.hpp"], + includes = ["."], + visibility = ["//visibility:public"], + deps = ["//score/crypto/src/api/common:crypto_common_base"], +) + +cc_library( + name = "certificate_types", + hdrs = ["certificate.hpp"], + includes = ["."], + visibility = ["//visibility:public"], + deps = [":common_types"], +) + +cc_library( + name = "key_types", + hdrs = ["key.hpp"], + includes = ["."], + visibility = ["//visibility:public"], + deps = [":common_types"], +) + +cc_library( + name = "types", + hdrs = ["common.hpp", "certificate.hpp", "key.hpp"], + includes = ["."], + visibility = ["//visibility:public"], + deps = [":certificate_types", ":key_types"], +) diff --git a/score/crypto/src/api/types/certificate.hpp b/score/crypto/src/api/types/certificate.hpp new file mode 100644 index 000000000..519b83526 --- /dev/null +++ b/score/crypto/src/api/types/certificate.hpp @@ -0,0 +1,112 @@ +/******************************************************************************** + * Copyright (c) 2026 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ + +#ifndef SCORE_CRYPTO_SRC_API_TYPES_CERTIFICATE_HPP +#define SCORE_CRYPTO_SRC_API_TYPES_CERTIFICATE_HPP + +#include "score/crypto/src/api/types/common.hpp" + +#include +#include +#include + +namespace score::crypto +{ + +enum class CertificateSlotState : uint8_t +{ + kEmpty, + kOccupied, + kLocked +}; + +enum class CertificateStatus : uint8_t +{ + kValid, + kRevoked, + kExpired, + kUnknown +}; + +enum class CertVerifyResult : uint8_t +{ + kValid, + kExpired, + kNotYetValid, + kRevoked, + kNoRootFound, + kChainIncomplete, + kSignatureInvalid, + kInvalidPurpose, + kUnknownAlgorithm, + kUnknownError +}; + +enum class ChainTerminationPolicy : uint8_t +{ + kRootRequired, + kTrustStoreTerminated +}; + +enum class OcspStatus : uint8_t +{ + kGood, + kRevoked, + kUnknown, + kError +}; + +enum class RevocationCheckPolicy : uint8_t +{ + kNone, + kCrlOnly, + kOcspOnly, + kOcspWithCrlFallback +}; + +enum class VerificationEvidenceMode : uint8_t +{ + kNone, + kChain, + kChainAndCrl +}; + +struct CrlMetadata +{ + std::array fingerprint{}; + std::array issuer_fingerprint{}; + int64_t this_update{0}; + int64_t next_update{0}; + uint64_t crl_number{0U}; +}; + +struct CrlMetadataWireLayout final +{ + static constexpr std::size_t kFingerprintSize = 32U; + static constexpr std::size_t kCrlFingerprintOffset = 0U; + static constexpr std::size_t kIssuerFingerprintOffset = kCrlFingerprintOffset + kFingerprintSize; + static constexpr std::size_t kThisUpdateOffset = kIssuerFingerprintOffset + kFingerprintSize; + static constexpr std::size_t kNextUpdateOffset = kThisUpdateOffset + sizeof(std::int64_t); + static constexpr std::size_t kCrlNumberOffset = kNextUpdateOffset + sizeof(std::int64_t); + static constexpr std::size_t kEntrySize = kCrlNumberOffset + sizeof(std::uint64_t); +}; + +struct CertificateSlotInfo +{ + CertificateSlotState state{CertificateSlotState::kEmpty}; + bool has_crl{false}; +}; + +} // namespace score::crypto + +#endif // SCORE_CRYPTO_SRC_API_TYPES_CERTIFICATE_HPP diff --git a/score/crypto/src/api/types/common.hpp b/score/crypto/src/api/types/common.hpp new file mode 100644 index 000000000..bd532dfef --- /dev/null +++ b/score/crypto/src/api/types/common.hpp @@ -0,0 +1,163 @@ +/******************************************************************************** + * Copyright (c) 2026 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ + +#ifndef SCORE_CRYPTO_SRC_API_TYPES_COMMON_HPP +#define SCORE_CRYPTO_SRC_API_TYPES_COMMON_HPP + +#include "score/crypto/src/api/common/fixed_capacity_string.hpp" + +#include +#include +#include +#include + +namespace score::crypto +{ + +using ResourceId = FixedCapacityString<64>; +using AlgorithmId = FixedCapacityString<64>; + +enum class ResourceType : uint8_t +{ + kProvider, + kKeySlot, + kCertSlot, + kCertificateTrustStore, + kKey, + kCertificate, + kSecureObject, + kDataObject +}; + +enum class ResourcePersistence : uint8_t +{ + kPersistent, + kEphemeral +}; + +struct CryptoResourceId +{ + uint64_t id{0U}; + ResourceType type{ResourceType::kKeySlot}; + ResourcePersistence persistence{ResourcePersistence::kEphemeral}; + uint16_t primary_provider{0U}; + + constexpr bool operator==(const CryptoResourceId& other) const noexcept + { + return (id == other.id) && (type == other.type) && (persistence == other.persistence) && + (primary_provider == other.primary_provider); + } + + constexpr bool operator!=(const CryptoResourceId& other) const noexcept + { + return !(*this == other); + } +}; + +enum class ProviderType : uint8_t +{ + kDefault, + kHardware, + kSoftware, + kHardwarePreferred, + kSoftwarePreferred +}; + +enum class FormatType : uint8_t +{ + kDer, + kPem +}; + +enum class CipherDirection : uint8_t +{ + kEncrypt, + kDecrypt +}; + +enum class OperationMode : uint8_t +{ + kGenerate, + kVerify +}; + +enum class MemoryType : uint8_t +{ + kDefault, + kProviderCompatible +}; + +struct ProviderInfo +{ + uint16_t id{0U}; + ProviderType type{ProviderType::kDefault}; + FixedCapacityString<32> name{}; +}; + +struct ProviderCompatibilityInfo +{ + CryptoResourceId resource{}; + uint16_t primary_provider{0U}; + static constexpr std::size_t kMaxSecondaryProviders = 8U; + std::array secondary_providers{}; + std::size_t secondary_provider_count{0U}; +}; + +struct AlgorithmCapabilities +{ + AlgorithmId id{}; + bool supported{false}; + static constexpr std::size_t kMaxModes = 16U; + std::array, kMaxModes> modes{}; + std::size_t mode_count{0U}; +}; + +struct SystemCapabilities +{ + static constexpr std::size_t kMaxProviders = 16U; + std::array providers{}; + std::size_t provider_count{0U}; + static constexpr std::size_t kMaxAlgorithms = 64U; + std::array algorithms{}; + std::size_t algorithm_count{0U}; +}; + +struct ExtendedParameterEntry +{ + FixedCapacityString<32> key{}; + FixedCapacityString<64> value{}; +}; + +struct ExtendedParameters +{ + static constexpr std::size_t kMaxEntries = 16U; + std::array entries{}; + std::size_t entry_count{0U}; +}; + +} // namespace score::crypto + +template <> +struct std::hash +{ + std::size_t operator()(const score::crypto::CryptoResourceId& rid) const noexcept + { + std::size_t h = std::hash{}(rid.id); + h ^= std::hash{}(static_cast(rid.type)) << 1U; + h ^= std::hash{}(static_cast(rid.persistence)) << 2U; + h ^= std::hash{}(rid.primary_provider) << 3U; + return h; + } +}; + +#endif // SCORE_CRYPTO_SRC_API_TYPES_COMMON_HPP diff --git a/score/crypto/src/api/types/key.hpp b/score/crypto/src/api/types/key.hpp new file mode 100644 index 000000000..6e3392675 --- /dev/null +++ b/score/crypto/src/api/types/key.hpp @@ -0,0 +1,102 @@ +/******************************************************************************** + * Copyright (c) 2026 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ + +#ifndef SCORE_CRYPTO_SRC_API_TYPES_KEY_HPP +#define SCORE_CRYPTO_SRC_API_TYPES_KEY_HPP + +#include "score/crypto/src/api/types/common.hpp" + +#include +#include +#include + +namespace score::crypto +{ + +enum class KeySlotState : uint8_t +{ + kEmpty, + kOccupied, + kLocked +}; + +enum class KeyOperationPermission : uint32_t +{ + kNone = 0x0000U, + kEncrypt = 0x0001U, + kDecrypt = 0x0002U, + kWrap = 0x0004U, + kUnwrap = 0x0008U, + kSign = 0x0010U, + kVerify = 0x0020U, + kMac = 0x0040U, + kAgree = 0x0080U, + kDerive = 0x0100U, + kExport = 0x0200U, + kImport = 0x0400U, + kDataProtection = 0x000FU, + kAuthentication = 0x00F0U, + kFullLifecycle = 0x0700U, + kAll = 0x07FFU, +}; + +inline constexpr KeyOperationPermission operator|(KeyOperationPermission lhs, KeyOperationPermission rhs) noexcept +{ + return static_cast(static_cast(lhs) | static_cast(rhs)); +} + +inline constexpr KeyOperationPermission operator&(KeyOperationPermission lhs, KeyOperationPermission rhs) noexcept +{ + return static_cast(static_cast(lhs) & static_cast(rhs)); +} + +inline constexpr KeyOperationPermission operator~(KeyOperationPermission perm) noexcept +{ + constexpr uint32_t kValidBitsMask = 0x07FFU; + return static_cast((~static_cast(perm)) & kValidBitsMask); +} + +inline constexpr KeyOperationPermission& operator|=(KeyOperationPermission& lhs, KeyOperationPermission rhs) noexcept +{ + lhs = lhs | rhs; + return lhs; +} + +inline constexpr KeyOperationPermission& operator&=(KeyOperationPermission& lhs, KeyOperationPermission rhs) noexcept +{ + lhs = lhs & rhs; + return lhs; +} + +inline constexpr bool HasPermission(KeyOperationPermission granted, KeyOperationPermission required) noexcept +{ + constexpr uint32_t kValidBitsMask = 0x07FFU; + const uint32_t g = static_cast(granted) & kValidBitsMask; + const uint32_t r = static_cast(required) & kValidBitsMask; + return (g & r) == r; +} + +struct KeySlotInfo +{ + KeySlotState state{KeySlotState::kEmpty}; + AlgorithmId algorithm{}; + uint16_t primary_provider{0U}; + static constexpr std::size_t kMaxCompatibleProviders = 8U; + std::array compatible_providers{}; + std::size_t compatible_provider_count{0U}; + KeyOperationPermission permitted_operations{KeyOperationPermission::kAll}; +}; + +} // namespace score::crypto + +#endif // SCORE_CRYPTO_SRC_API_TYPES_KEY_HPP diff --git a/score/crypto/src/backend/BUILD b/score/crypto/src/backend/BUILD index 756d6b254..140a87457 100644 --- a/score/crypto/src/backend/BUILD +++ b/score/crypto/src/backend/BUILD @@ -77,7 +77,7 @@ config_setting( ":score_crypto_score_backend_enabled": "True", ":score_crypto_score_openssl_enabled": "True", }, - visibility = ["//:__subpackages__"], + visibility = ["//visibility:public"], ) # ============================================================================ diff --git a/score/crypto/src/daemon/common/BUILD b/score/crypto/src/daemon/common/BUILD index 03b571a32..b5888cf68 100644 --- a/score/crypto/src/daemon/common/BUILD +++ b/score/crypto/src/daemon/common/BUILD @@ -25,6 +25,7 @@ cc_library( visibility = ["//:__subpackages__"], deps = [ "//score/crypto/src/api/common:crypto_common", + "//score/crypto/src/api/types:types", "@score_baselibs//score/result", ], ) diff --git a/score/crypto/src/daemon/config/inc/config.hpp b/score/crypto/src/daemon/config/inc/config.hpp index dd081dc29..07373d506 100644 --- a/score/crypto/src/daemon/config/inc/config.hpp +++ b/score/crypto/src/daemon/config/inc/config.hpp @@ -222,15 +222,15 @@ class GeneralConfig /** * @brief Key management configuration section * - * Stores key slot definitions parsed from the daemon's configuration source - * (JSON manifest or flatbuffer). Each entry describes a persistent key slot: + * Stores key slot definitions parsed from the daemon's binary FlatBuffers + * configuration source. Each entry describes a persistent key slot: * its human-readable name, algorithm, owning provider, access policy, and * a deployment path that points to the external deployment descriptor. * * At daemon startup, a ConfigDrivenSlotCatalog reads these entries and calls * SlotRegistry::RegisterSlot() for each one. * - * Example JSON slot entry: + * Example slot entry: * @code * { * "slot_name": "vehicle/hmac-256", @@ -305,7 +305,7 @@ class KeyConfig return m_app_key_slot_entries; } - /// @brief Path to the JSON key slot manifest file (optional). + /// @brief Path to an optional key slot manifest used by catalog tooling. /// /// If non-empty, ConfigDrivenSlotCatalog reads this file during Load(). /// If empty, only the entries added via AddSlotEntry() are used. @@ -395,7 +395,7 @@ class Config bool ParseCommandLine(int argc, char** argv); /** - * @brief Parse configuration (like flatbuffer) + * @brief Parse the binary FlatBuffers configuration * @param none * @return true if parsing succeeded, false on error */ diff --git a/score/crypto/src/daemon/data_plane/BUILD b/score/crypto/src/daemon/data_plane/BUILD index 30a9edbdd..7f7188896 100644 --- a/score/crypto/src/daemon/data_plane/BUILD +++ b/score/crypto/src/daemon/data_plane/BUILD @@ -19,6 +19,7 @@ cc_library( visibility = ["//:__subpackages__"], deps = [ "//score/crypto/src/api/common:crypto_common", + "//score/crypto/src/api/types:types", "//score/crypto/src/common:common_types", "//score/crypto/src/daemon/common", "//score/crypto/src/daemon/data_manager", diff --git a/score/crypto/src/daemon/key_management/BUILD b/score/crypto/src/daemon/key_management/BUILD index 11978775b..2f79db00c 100644 --- a/score/crypto/src/daemon/key_management/BUILD +++ b/score/crypto/src/daemon/key_management/BUILD @@ -33,6 +33,7 @@ cc_library( visibility = ["//:__subpackages__"], deps = [ "//score/crypto/src/api/common:crypto_common", + "//score/crypto/src/api/types:types", "//score/crypto/src/api/config:context_configs", "//score/crypto/src/common:common_types", "//score/crypto/src/daemon/common", @@ -75,6 +76,7 @@ cc_library( deps = [ ":key_handler_iface", "//score/crypto/src/api/common:crypto_common", + "//score/crypto/src/api/types:types", "//score/crypto/src/api/config:context_configs", "//score/crypto/src/daemon/common", "//score/crypto/src/daemon/control_plane:request_handler_hdr", @@ -109,6 +111,7 @@ cc_library( deps = [ ":key_management_headers", "//score/crypto/src/api/common:crypto_common", + "//score/crypto/src/api/types:types", "//score/crypto/src/daemon/common", "//score/crypto/src/daemon/common/storage:file_io", "//score/crypto/src/daemon/common/storage:kv_deployment", diff --git a/score/crypto/src/daemon/key_management/core/key_entry.hpp b/score/crypto/src/daemon/key_management/core/key_entry.hpp index e0f56a5f2..4f9e701da 100644 --- a/score/crypto/src/daemon/key_management/core/key_entry.hpp +++ b/score/crypto/src/daemon/key_management/core/key_entry.hpp @@ -14,7 +14,7 @@ #ifndef SCORE_CRYPTO_SRC_DAEMON_KEY_MANAGEMENT_CORE_KEY_ENTRY_HPP #define SCORE_CRYPTO_SRC_DAEMON_KEY_MANAGEMENT_CORE_KEY_ENTRY_HPP -#include "score/crypto/src/api/common/types.hpp" +#include "score/crypto/src/api/types/common.hpp" #include "score/crypto/src/daemon/data_manager/data_node.hpp" #include "score/crypto/src/daemon/key_management/interfaces/i_key_handler.hpp" #include "score/crypto/src/daemon/key_management/slot/slot_registry.hpp" diff --git a/score/crypto/src/daemon/key_management/detail/slot_info_builder.hpp b/score/crypto/src/daemon/key_management/detail/slot_info_builder.hpp index 202645dfc..a6ef94466 100644 --- a/score/crypto/src/daemon/key_management/detail/slot_info_builder.hpp +++ b/score/crypto/src/daemon/key_management/detail/slot_info_builder.hpp @@ -14,7 +14,8 @@ #ifndef SCORE_CRYPTO_SRC_DAEMON_KEY_MANAGEMENT_DETAIL_SLOT_INFO_BUILDER_HPP #define SCORE_CRYPTO_SRC_DAEMON_KEY_MANAGEMENT_DETAIL_SLOT_INFO_BUILDER_HPP -#include "score/crypto/src/api/common/types.hpp" +#include "score/crypto/src/api/types/common.hpp" +#include "score/crypto/src/api/types/key.hpp" #include "score/crypto/src/daemon/key_management/interfaces/key_slot_config.hpp" namespace score::crypto::daemon::key_management::detail diff --git a/score/crypto/src/daemon/key_management/interfaces/i_key_factory.hpp b/score/crypto/src/daemon/key_management/interfaces/i_key_factory.hpp index 3b3142b9a..791e0a5a3 100644 --- a/score/crypto/src/daemon/key_management/interfaces/i_key_factory.hpp +++ b/score/crypto/src/daemon/key_management/interfaces/i_key_factory.hpp @@ -14,7 +14,7 @@ #ifndef SCORE_CRYPTO_SRC_DAEMON_KEY_MANAGEMENT_INTERFACES_I_KEY_FACTORY_HPP #define SCORE_CRYPTO_SRC_DAEMON_KEY_MANAGEMENT_INTERFACES_I_KEY_FACTORY_HPP -#include "score/crypto/src/api/common/types.hpp" +#include "score/crypto/src/api/types/common.hpp" #include "score/crypto/src/common/types.hpp" #include "score/crypto/src/daemon/common/daemon_error.hpp" #include "score/crypto/src/daemon/key_management/interfaces/i_key_handler.hpp" diff --git a/score/crypto/src/daemon/key_management/interfaces/i_key_slot_handler.hpp b/score/crypto/src/daemon/key_management/interfaces/i_key_slot_handler.hpp index f97c8a770..d15b2d9c8 100644 --- a/score/crypto/src/daemon/key_management/interfaces/i_key_slot_handler.hpp +++ b/score/crypto/src/daemon/key_management/interfaces/i_key_slot_handler.hpp @@ -14,7 +14,8 @@ #ifndef SCORE_CRYPTO_SRC_DAEMON_KEY_MANAGEMENT_INTERFACES_I_KEY_SLOT_HANDLER_HPP #define SCORE_CRYPTO_SRC_DAEMON_KEY_MANAGEMENT_INTERFACES_I_KEY_SLOT_HANDLER_HPP -#include "score/crypto/src/api/common/types.hpp" +#include "score/crypto/src/api/types/common.hpp" +#include "score/crypto/src/api/types/key.hpp" #include "score/crypto/src/common/types.hpp" #include "score/crypto/src/daemon/common/daemon_error.hpp" #include "score/crypto/src/daemon/key_management/interfaces/i_key_handler.hpp" diff --git a/score/crypto/src/daemon/key_management/interfaces/key_slot_config.hpp b/score/crypto/src/daemon/key_management/interfaces/key_slot_config.hpp index a8d8395d4..c935eb892 100644 --- a/score/crypto/src/daemon/key_management/interfaces/key_slot_config.hpp +++ b/score/crypto/src/daemon/key_management/interfaces/key_slot_config.hpp @@ -14,7 +14,8 @@ #ifndef SCORE_CRYPTO_SRC_DAEMON_KEY_MANAGEMENT_INTERFACES_KEY_SLOT_CONFIG_HPP #define SCORE_CRYPTO_SRC_DAEMON_KEY_MANAGEMENT_INTERFACES_KEY_SLOT_CONFIG_HPP -#include "score/crypto/src/api/common/types.hpp" +#include "score/crypto/src/api/types/common.hpp" +#include "score/crypto/src/api/types/key.hpp" #include "score/crypto/src/daemon/common/types.hpp" #include diff --git a/score/crypto/src/daemon/key_management/interfaces/key_types.hpp b/score/crypto/src/daemon/key_management/interfaces/key_types.hpp index 5c4b9a345..5373ee69c 100644 --- a/score/crypto/src/daemon/key_management/interfaces/key_types.hpp +++ b/score/crypto/src/daemon/key_management/interfaces/key_types.hpp @@ -14,8 +14,9 @@ #ifndef SCORE_CRYPTO_SRC_DAEMON_KEY_MANAGEMENT_INTERFACES_KEY_TYPES_HPP #define SCORE_CRYPTO_SRC_DAEMON_KEY_MANAGEMENT_INTERFACES_KEY_TYPES_HPP -#include "score/crypto/src/api/common/types.hpp" #include "score/crypto/src/api/config/key_operation_params.hpp" +#include "score/crypto/src/api/types/common.hpp" +#include "score/crypto/src/api/types/key.hpp" #include "score/crypto/src/daemon/common/types.hpp" #include diff --git a/score/crypto/src/daemon/key_management/nodes/key_slot_data_node.hpp b/score/crypto/src/daemon/key_management/nodes/key_slot_data_node.hpp index 4d546734f..1df88ec7b 100644 --- a/score/crypto/src/daemon/key_management/nodes/key_slot_data_node.hpp +++ b/score/crypto/src/daemon/key_management/nodes/key_slot_data_node.hpp @@ -14,7 +14,8 @@ #ifndef SCORE_CRYPTO_SRC_DAEMON_KEY_MANAGEMENT_NODES_KEY_SLOT_DATA_NODE_HPP #define SCORE_CRYPTO_SRC_DAEMON_KEY_MANAGEMENT_NODES_KEY_SLOT_DATA_NODE_HPP -#include "score/crypto/src/api/common/types.hpp" +#include "score/crypto/src/api/types/common.hpp" +#include "score/crypto/src/api/types/key.hpp" #include "score/crypto/src/daemon/data_manager/data_node.hpp" #include "score/crypto/src/daemon/key_management/slot/slot_registry.hpp" diff --git a/score/crypto/src/daemon/key_management/slot/access_policy_enforcer.hpp b/score/crypto/src/daemon/key_management/slot/access_policy_enforcer.hpp index c92ddcc90..405efcadc 100644 --- a/score/crypto/src/daemon/key_management/slot/access_policy_enforcer.hpp +++ b/score/crypto/src/daemon/key_management/slot/access_policy_enforcer.hpp @@ -14,7 +14,8 @@ #ifndef SCORE_CRYPTO_SRC_DAEMON_KEY_MANAGEMENT_SLOT_ACCESS_POLICY_ENFORCER_HPP #define SCORE_CRYPTO_SRC_DAEMON_KEY_MANAGEMENT_SLOT_ACCESS_POLICY_ENFORCER_HPP -#include "score/crypto/src/api/common/types.hpp" +#include "score/crypto/src/api/types/common.hpp" +#include "score/crypto/src/api/types/key.hpp" #include "score/crypto/src/daemon/common/daemon_error.hpp" #include "score/crypto/src/daemon/common/types.hpp" #include "score/crypto/src/daemon/data_manager/data_node.hpp" diff --git a/score/crypto/src/daemon/key_management/slot/file_backed_slot_handler.cpp b/score/crypto/src/daemon/key_management/slot/file_backed_slot_handler.cpp index 555ecca22..635a2ed97 100644 --- a/score/crypto/src/daemon/key_management/slot/file_backed_slot_handler.cpp +++ b/score/crypto/src/daemon/key_management/slot/file_backed_slot_handler.cpp @@ -70,15 +70,21 @@ score::crypto::Expected FileBackedSlotHandle { auto deploy_result = DeploymentLoader::Load(slot.deployment_path, slot.deployment_format); if (!deploy_result.has_value()) - return score::crypto::KeySlotState::kEmpty; + { + if (deploy_result.error() == Error::kResourceNotAllocated) + return score::crypto::KeySlotState::kEmpty; + return score::crypto::make_unexpected(deploy_result.error()); + } const auto& deploy_info = deploy_result.value(); const auto path_it = deploy_info.key_properties.find(std::string{deployment_keys::kKeyPath}); if (path_it == deploy_info.key_properties.end() || path_it->second.empty()) return score::crypto::KeySlotState::kEmpty; - return file_io::FileExists(path_it->second) ? score::crypto::KeySlotState::kOccupied - : score::crypto::KeySlotState::kEmpty; + const auto exists = file_io::FileExists(path_it->second); + if (!exists) + return score::crypto::make_unexpected(exists.error()); + return exists.value() ? score::crypto::KeySlotState::kOccupied : score::crypto::KeySlotState::kEmpty; } score::crypto::Expected FileBackedSlotHandler::GetSlotInfo(const KeySlotConfig& slot) diff --git a/score/crypto/src/daemon/key_management/slot/slot_registry.hpp b/score/crypto/src/daemon/key_management/slot/slot_registry.hpp index 0e4e98a35..7eacc0e39 100644 --- a/score/crypto/src/daemon/key_management/slot/slot_registry.hpp +++ b/score/crypto/src/daemon/key_management/slot/slot_registry.hpp @@ -14,7 +14,7 @@ #ifndef SCORE_CRYPTO_SRC_DAEMON_KEY_MANAGEMENT_SLOT_SLOT_REGISTRY_HPP #define SCORE_CRYPTO_SRC_DAEMON_KEY_MANAGEMENT_SLOT_SLOT_REGISTRY_HPP -#include "score/crypto/src/api/common/types.hpp" +#include "score/crypto/src/api/types/common.hpp" #include "score/crypto/src/daemon/common/daemon_error.hpp" #include "score/crypto/src/daemon/data_manager/data_node.hpp" #include "score/crypto/src/daemon/key_management/interfaces/key_slot_config.hpp" diff --git a/score/crypto/src/daemon/provider/handler/BUILD b/score/crypto/src/daemon/provider/handler/BUILD index 040b0fdb1..2b4e2af02 100644 --- a/score/crypto/src/daemon/provider/handler/BUILD +++ b/score/crypto/src/daemon/provider/handler/BUILD @@ -22,6 +22,7 @@ cc_library( visibility = ["//:__subpackages__"], deps = [ "//score/crypto/src/api/common:crypto_common", + "//score/crypto/src/api/types:types", "//score/crypto/src/common:common_types", "//score/crypto/src/daemon/common", "//score/crypto/src/daemon/key_management:key_handler_iface", diff --git a/score/crypto/src/daemon/provider/handler/handler_init_params.hpp b/score/crypto/src/daemon/provider/handler/handler_init_params.hpp index 0dba756ce..cc2d4d046 100644 --- a/score/crypto/src/daemon/provider/handler/handler_init_params.hpp +++ b/score/crypto/src/daemon/provider/handler/handler_init_params.hpp @@ -14,7 +14,7 @@ #ifndef SCORE_CRYPTO_SRC_DAEMON_PROVIDER_HANDLER_HANDLER_INIT_PARAMS_HPP #define SCORE_CRYPTO_SRC_DAEMON_PROVIDER_HANDLER_HANDLER_INIT_PARAMS_HPP -#include "score/crypto/src/api/common/types.hpp" +#include "score/crypto/src/api/types/common.hpp" #include "score/crypto/src/daemon/common/types.hpp" #include "score/crypto/src/daemon/key_management/interfaces/i_key_handler.hpp" #include diff --git a/score/crypto/src/daemon/provider/pkcs11/key_management/pkcs11_key_store.cpp b/score/crypto/src/daemon/provider/pkcs11/key_management/pkcs11_key_store.cpp index 01bfab2af..04d685745 100644 --- a/score/crypto/src/daemon/provider/pkcs11/key_management/pkcs11_key_store.cpp +++ b/score/crypto/src/daemon/provider/pkcs11/key_management/pkcs11_key_store.cpp @@ -13,7 +13,7 @@ #include "score/crypto/src/daemon/provider/pkcs11/key_management/pkcs11_key_store.hpp" -#include "score/crypto/src/api/common/types.hpp" +#include "score/crypto/src/api/types/common.hpp" #include "score/crypto/src/common/types.hpp" #include "score/crypto/src/daemon/common/daemon_error.hpp" #include "score/crypto/src/daemon/common/types.hpp" diff --git a/score/crypto/src/daemon/provider/pkcs11/key_management/pkcs11_key_store.hpp b/score/crypto/src/daemon/provider/pkcs11/key_management/pkcs11_key_store.hpp index 56d9dad9a..373476d4f 100644 --- a/score/crypto/src/daemon/provider/pkcs11/key_management/pkcs11_key_store.hpp +++ b/score/crypto/src/daemon/provider/pkcs11/key_management/pkcs11_key_store.hpp @@ -14,7 +14,7 @@ #ifndef SCORE_CRYPTO_SRC_DAEMON_PROVIDER_PKCS11_KEY_MANAGEMENT_PKCS11_KEY_STORE_HPP #define SCORE_CRYPTO_SRC_DAEMON_PROVIDER_PKCS11_KEY_MANAGEMENT_PKCS11_KEY_STORE_HPP -#include "score/crypto/src/api/common/types.hpp" +#include "score/crypto/src/api/types/common.hpp" #include "score/crypto/src/daemon/common/daemon_error.hpp" #include "score/crypto/src/daemon/key_management/interfaces/key_types.hpp" #include "score/crypto/src/daemon/provider/pkcs11/key_management/resolved_key.hpp" diff --git a/score/crypto/src/daemon/provider/pkcs11/operations/mac/pkcs11_mac_context.hpp b/score/crypto/src/daemon/provider/pkcs11/operations/mac/pkcs11_mac_context.hpp index 964a592b5..dc54aa12d 100644 --- a/score/crypto/src/daemon/provider/pkcs11/operations/mac/pkcs11_mac_context.hpp +++ b/score/crypto/src/daemon/provider/pkcs11/operations/mac/pkcs11_mac_context.hpp @@ -14,7 +14,7 @@ #ifndef SCORE_CRYPTO_SRC_DAEMON_PROVIDER_PKCS11_OPERATIONS_MAC_PKCS11_MAC_CONTEXT_HPP #define SCORE_CRYPTO_SRC_DAEMON_PROVIDER_PKCS11_OPERATIONS_MAC_PKCS11_MAC_CONTEXT_HPP -#include "score/crypto/src/api/common/types.hpp" // OperationMode +#include "score/crypto/src/api/types/common.hpp" // OperationMode #include diff --git a/score/crypto/src/daemon/provider/pkcs11/operations/mac/pkcs11_mac_executor.cpp b/score/crypto/src/daemon/provider/pkcs11/operations/mac/pkcs11_mac_executor.cpp index f988509bb..2ccf0cdb2 100644 --- a/score/crypto/src/daemon/provider/pkcs11/operations/mac/pkcs11_mac_executor.cpp +++ b/score/crypto/src/daemon/provider/pkcs11/operations/mac/pkcs11_mac_executor.cpp @@ -12,7 +12,7 @@ ********************************************************************************/ #include "score/crypto/src/daemon/provider/pkcs11/operations/mac/pkcs11_mac_executor.hpp" -#include "score/crypto/src/api/common/types.hpp" +#include "score/crypto/src/api/types/common.hpp" #include "score/crypto/src/daemon/provider/handler/operations/mac_handler_operations.hpp" #include "score/crypto/src/daemon/provider/handler/src/handler_utils.hpp" #include "score/crypto/src/daemon/provider/pkcs11/pkcs11_module.hpp" diff --git a/score/crypto/src/daemon/provider/pkcs11/operations/mac/pkcs11_mac_executor.hpp b/score/crypto/src/daemon/provider/pkcs11/operations/mac/pkcs11_mac_executor.hpp index 1881a2041..171cfb289 100644 --- a/score/crypto/src/daemon/provider/pkcs11/operations/mac/pkcs11_mac_executor.hpp +++ b/score/crypto/src/daemon/provider/pkcs11/operations/mac/pkcs11_mac_executor.hpp @@ -14,7 +14,7 @@ #ifndef SCORE_CRYPTO_SRC_DAEMON_PROVIDER_PKCS11_OPERATIONS_MAC_PKCS11_MAC_EXECUTOR_HPP #define SCORE_CRYPTO_SRC_DAEMON_PROVIDER_PKCS11_OPERATIONS_MAC_PKCS11_MAC_EXECUTOR_HPP -#include "score/crypto/src/api/common/types.hpp" // OperationMode +#include "score/crypto/src/api/types/common.hpp" // OperationMode #include "score/crypto/src/common/types.hpp" #include "score/crypto/src/daemon/common/daemon_error.hpp" #include "score/crypto/src/daemon/common/types.hpp" diff --git a/score/crypto/src/daemon/provider/pkcs11/operations/mac/pkcs11_mac_handler.cpp b/score/crypto/src/daemon/provider/pkcs11/operations/mac/pkcs11_mac_handler.cpp index 09b7a0cd3..250c9b24f 100644 --- a/score/crypto/src/daemon/provider/pkcs11/operations/mac/pkcs11_mac_handler.cpp +++ b/score/crypto/src/daemon/provider/pkcs11/operations/mac/pkcs11_mac_handler.cpp @@ -12,7 +12,7 @@ ********************************************************************************/ #include "score/crypto/src/daemon/provider/pkcs11/operations/mac/pkcs11_mac_handler.hpp" -#include "score/crypto/src/api/common/types.hpp" +#include "score/crypto/src/api/types/common.hpp" #include "score/crypto/src/common/types.hpp" #include "score/crypto/src/daemon/common/algorithm_info.hpp" #include "score/crypto/src/daemon/common/daemon_error.hpp" diff --git a/score/crypto/tests/key_management/BUILD b/score/crypto/tests/key_management/BUILD index a4ffdaa9d..bacdeeb2c 100644 --- a/score/crypto/tests/key_management/BUILD +++ b/score/crypto/tests/key_management/BUILD @@ -64,6 +64,7 @@ cc_test( }), deps = [ "//score/crypto/src/api/common:crypto_common", + "//score/crypto/src/api/types:types", "//score/crypto/src/daemon/common", "//score/crypto/src/daemon/config", "//score/crypto/src/daemon/data_manager", diff --git a/score/crypto/tests/key_management/test_access_policy_enforcer.cpp b/score/crypto/tests/key_management/test_access_policy_enforcer.cpp index 9a056d638..dcf551d39 100644 --- a/score/crypto/tests/key_management/test_access_policy_enforcer.cpp +++ b/score/crypto/tests/key_management/test_access_policy_enforcer.cpp @@ -11,7 +11,8 @@ * SPDX-License-Identifier: Apache-2.0 ********************************************************************************/ -#include "score/crypto/src/api/common/types.hpp" +#include "score/crypto/src/api/types/common.hpp" +#include "score/crypto/src/api/types/key.hpp" #include "score/crypto/src/daemon/key_management/interfaces/key_slot_config.hpp" #include "score/crypto/src/daemon/key_management/slot/access_policy_enforcer.hpp" diff --git a/score/crypto/tests/key_management/test_key_config_manager.cpp b/score/crypto/tests/key_management/test_key_config_manager.cpp index 2dec739ba..6f8adb72b 100644 --- a/score/crypto/tests/key_management/test_key_config_manager.cpp +++ b/score/crypto/tests/key_management/test_key_config_manager.cpp @@ -11,7 +11,8 @@ * SPDX-License-Identifier: Apache-2.0 ********************************************************************************/ -#include "score/crypto/src/api/common/types.hpp" +#include "score/crypto/src/api/types/common.hpp" +#include "score/crypto/src/api/types/key.hpp" #include "score/crypto/src/daemon/config/src/flatbuffer_config_parser.hpp" #include "score/crypto/src/daemon/key_management/interfaces/key_slot_config.hpp" #include "score/crypto/src/daemon/key_management/slot/config_driven_slot_catalog.hpp" diff --git a/score/crypto/tests/key_management/test_key_management_context.cpp b/score/crypto/tests/key_management/test_key_management_context.cpp index dcbbf55fc..e6c5f615a 100644 --- a/score/crypto/tests/key_management/test_key_management_context.cpp +++ b/score/crypto/tests/key_management/test_key_management_context.cpp @@ -20,7 +20,8 @@ /// handler dispatch flow without mocks. #include "score/crypto/src/api/common/error_domain.hpp" -#include "score/crypto/src/api/common/types.hpp" +#include "score/crypto/src/api/types/common.hpp" +#include "score/crypto/src/api/types/key.hpp" #include "score/crypto/src/daemon/common/actors.hpp" #include "score/crypto/src/daemon/config/src/flatbuffer_config_parser.hpp" #include "score/crypto/src/daemon/data_manager/data_manager.hpp" diff --git a/score/crypto/tests/key_management/test_openssl_key_handler.cpp b/score/crypto/tests/key_management/test_openssl_key_handler.cpp index 0b278fc9e..98ecc8a08 100644 --- a/score/crypto/tests/key_management/test_openssl_key_handler.cpp +++ b/score/crypto/tests/key_management/test_openssl_key_handler.cpp @@ -11,7 +11,8 @@ * SPDX-License-Identifier: Apache-2.0 ********************************************************************************/ -#include "score/crypto/src/api/common/types.hpp" +#include "score/crypto/src/api/types/common.hpp" +#include "score/crypto/src/api/types/key.hpp" #include "score/crypto/src/daemon/key_management/interfaces/i_key_factory.hpp" #include "score/crypto/src/daemon/provider/score_provider/openssl/key_management/openssl_key_factory.hpp" #include "score/crypto/src/daemon/provider/score_provider/openssl/key_management/openssl_key_handler.hpp" diff --git a/score/tests/integration_tests/score_api_mac_test.cpp b/score/tests/integration_tests/score_api_mac_test.cpp index 87dc5ee62..31b71bcd0 100644 --- a/score/tests/integration_tests/score_api_mac_test.cpp +++ b/score/tests/integration_tests/score_api_mac_test.cpp @@ -22,7 +22,6 @@ /// - Context reuse via Reset() /// - Automatic key release via CryptoResourceGuard RAII -#include "score/crypto/src/api/common/types.hpp" #include "score/crypto/src/api/config/key_management_context_config.hpp" #include "score/crypto/src/api/config/key_operation_params.hpp" #include "score/crypto/src/api/config/mac_context_config.hpp" @@ -31,6 +30,7 @@ #include "score/crypto/src/api/crypto_stack_factory.hpp" #include "score/crypto/src/api/i_crypto_context.hpp" #include "score/crypto/src/api/i_crypto_stack.hpp" +#include "score/crypto/src/api/types/common.hpp" #include "score/tests/utility/test_utility.hpp" #include diff --git a/score/tests/integration_tests/score_demo.cpp b/score/tests/integration_tests/score_demo.cpp index 017a43816..f8489c07c 100644 --- a/score/tests/integration_tests/score_demo.cpp +++ b/score/tests/integration_tests/score_demo.cpp @@ -25,12 +25,12 @@ /// 4. RAII pattern ensures automatic key zeroization on cleanup #include "score/crypto/src/api/common/error_domain.hpp" -#include "score/crypto/src/api/common/types.hpp" #include "score/crypto/src/api/config/mac_context_config.hpp" #include "score/crypto/src/api/contexts/i_mac_context.hpp" #include "score/crypto/src/api/crypto_stack_factory.hpp" #include "score/crypto/src/api/i_crypto_context.hpp" #include "score/crypto/src/api/i_crypto_stack.hpp" +#include "score/crypto/src/api/types/common.hpp" #include "score/result/result.h" #include "score/tests/utility/test_utility.hpp" diff --git a/tools/coverage/BUILD b/tools/coverage/BUILD index e2689d1b3..fbecbeb89 100644 --- a/tools/coverage/BUILD +++ b/tools/coverage/BUILD @@ -26,7 +26,7 @@ score_coverage_scope( visibility = ["//visibility:private"], deps = [ "//score/crypto/src/api:crypto_stack", - "//score/crypto/src/api/certificate:cert_types", + "//score/crypto/src/api/types:types", "//score/crypto/src/api/config:cert_context_configs", "//score/crypto/src/api/contexts:cert_contexts", "//score/crypto/src/api/objects:cert_objects", From b81ec7d85db2f2e2a12d49699a5eab5ae06fc369 Mon Sep 17 00:00:00 2001 From: Athul Mallappallil Date: Fri, 18 Sep 2026 16:57:13 +0200 Subject: [PATCH 20/25] Separate trust store mgmt ctx --- score/crypto/src/api/config/BUILD | 1 + .../trust_store_management_context_config.hpp | 55 ++++++ score/crypto/src/api/contexts/BUILD | 1 + .../i_certificate_management_context.hpp | 73 -------- .../i_trust_store_management_context.hpp | 171 ++++++++++++++++++ .../src/api/objects/i_trust_store_object.hpp | 2 +- 6 files changed, 229 insertions(+), 74 deletions(-) create mode 100644 score/crypto/src/api/config/trust_store_management_context_config.hpp create mode 100644 score/crypto/src/api/contexts/i_trust_store_management_context.hpp diff --git a/score/crypto/src/api/config/BUILD b/score/crypto/src/api/config/BUILD index 4b5288625..6dbe92095 100644 --- a/score/crypto/src/api/config/BUILD +++ b/score/crypto/src/api/config/BUILD @@ -36,6 +36,7 @@ cc_library( hdrs = [ "certificate_context_config.hpp", "certificate_verification_context_config.hpp", + "trust_store_management_context_config.hpp", ], includes = ["."], visibility = ["//visibility:public"], diff --git a/score/crypto/src/api/config/trust_store_management_context_config.hpp b/score/crypto/src/api/config/trust_store_management_context_config.hpp new file mode 100644 index 000000000..c82367ae6 --- /dev/null +++ b/score/crypto/src/api/config/trust_store_management_context_config.hpp @@ -0,0 +1,55 @@ +/******************************************************************************** + * Copyright (c) 2026 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ + +#ifndef SCORE_CRYPTO_SRC_API_CONFIG_TRUST_STORE_MANAGEMENT_CONTEXT_CONFIG_HPP +#define SCORE_CRYPTO_SRC_API_CONFIG_TRUST_STORE_MANAGEMENT_CONTEXT_CONFIG_HPP + +#include "score/crypto/src/api/config/base_context_config.hpp" + +namespace score +{ + +namespace crypto +{ + +/// @brief Configuration for trust-store management context creation. +/// +/// Provider selection is optional. Trust-store management uses the +/// certificate-management provider capability and the CERT:TRUST_STORE +/// context type. +struct TrustStoreManagementContextConfig : public BaseContextConfig +{ + TrustStoreManagementContextConfig& SetProvider(const CryptoResourceId& prov) noexcept + { + BaseContextConfig::SetProvider(prov); + return *this; + } + + TrustStoreManagementContextConfig& SetProviderType(ProviderType type) noexcept + { + BaseContextConfig::SetProviderType(type); + return *this; + } + + TrustStoreManagementContextConfig& SetExtendedParameter(const std::string& key, const std::string& value) + { + BaseContextConfig::SetExtendedParameter(key, value); + return *this; + } +}; + +} // namespace crypto + +} // namespace score + +#endif // SCORE_CRYPTO_SRC_API_CONFIG_TRUST_STORE_MANAGEMENT_CONTEXT_CONFIG_HPP diff --git a/score/crypto/src/api/contexts/BUILD b/score/crypto/src/api/contexts/BUILD index bb3fe3f19..8b4b6af7c 100644 --- a/score/crypto/src/api/contexts/BUILD +++ b/score/crypto/src/api/contexts/BUILD @@ -55,6 +55,7 @@ cc_library( hdrs = [ "i_certificate_management_context.hpp", "i_certificate_verification_context.hpp", + "i_trust_store_management_context.hpp", ], includes = ["."], visibility = ["//visibility:public"], diff --git a/score/crypto/src/api/contexts/i_certificate_management_context.hpp b/score/crypto/src/api/contexts/i_certificate_management_context.hpp index f4c4882f9..7efabc6f3 100644 --- a/score/crypto/src/api/contexts/i_certificate_management_context.hpp +++ b/score/crypto/src/api/contexts/i_certificate_management_context.hpp @@ -243,79 +243,6 @@ class ICertificateManagementContext : public IContext // const CryptoResourceId& cert, // const CryptoResourceId& issuer_cert) = 0; - // ---- Trust-store membership management ---- - - /// @brief Adds a certificate to a persistent trust store. - /// - /// The certificate is assigned to a trust-store-managed exclusive slot. This is a - /// write operation and requires trust-store write access. Idempotent: if the cert - /// is already a member of any type, returns success without allocating a new slot. - /// - /// @param trust_store Handle to the trust store (type = kCertificateTrustStore) - /// @param cert Handle to the certificate to add (type = kCertificate or kCertSlot) - /// @param with_crl When true, propagate the associated CRL to the exclusive slot - virtual score::Result AddCertificateToTrustStore(const CryptoResourceId& trust_store, - const CryptoResourceId& cert, - bool with_crl = false) = 0; - - /// @brief Removes a certificate from a persistent trust store by cert handle. - /// - /// The certificate must be loaded in the daemon (ephemeral or slot-loaded). - /// The daemon resolves the SHA-256 fingerprint internally from the handle. - /// - /// @param trust_store Handle to the trust store (type = kCertificateTrustStore) - /// @param cert Handle to the certificate to remove (type = kCertificate or kCertSlot) - virtual score::Result RemoveCertificateFromTrustStore(const CryptoResourceId& trust_store, - const CryptoResourceId& cert) = 0; - - /// @brief Removes a certificate from a persistent trust store by SHA-256 fingerprint. - /// - /// The certificate does not need to be loaded in the daemon. Use this when - /// the fingerprint is known from an external source without the cert bytes being available. - /// - /// @param trust_store Handle to the trust store (type = kCertificateTrustStore) - /// @param sha256_fingerprint 32-byte SHA-256 fingerprint of the certificate to remove - virtual score::Result RemoveCertificateFromTrustStore( - const CryptoResourceId& trust_store, - score::cpp::span sha256_fingerprint) = 0; - - /// @brief Enables a previously disabled trust store member identified by its slot resource. - /// - /// Use the slot_id from ITrustStoreObject::MemberInfo to obtain the slot handle. - /// - /// @param trust_store Handle to the trust store (type = kCertificateTrustStore) - /// @param slot Handle to the member slot (type = kCertSlot) - virtual score::Result EnableTrustStoreMember(const CryptoResourceId& trust_store, - const CryptoResourceId& slot) = 0; - - /// @brief Disables a trust store member identified by its slot resource. - /// - /// A disabled member is excluded from anchor resolution; it remains in the store - /// and can be re-enabled. Use RemoveCertificateFromTrustStore to permanently remove. - /// - /// Use the slot_id from ITrustStoreObject::MemberInfo to obtain the slot handle. - /// - /// @param trust_store Handle to the trust store (type = kCertificateTrustStore) - /// @param slot Handle to the member slot (type = kCertSlot) - virtual score::Result DisableTrustStoreMember(const CryptoResourceId& trust_store, - const CryptoResourceId& slot) = 0; - - /// @brief Imports a CRL for a trust store exclusive member identified by its slot resource. - /// - /// Only kExclusiveMutable trust store slots are writable through this path. - /// For shared-static or conditional-external members, use ImportCrl directly on the slot. - /// - /// Use the slot_id from ITrustStoreObject::MemberInfo to obtain the slot handle. - /// - /// @param trust_store Handle to the trust store (type = kCertificateTrustStore) - /// @param slot Handle to the exclusive member slot (type = kCertSlot) - /// @param crl_data Encoded CRL bytes - /// @param format Encoding format of the CRL - virtual score::Result ImportCrlForTrustStoreMember(const CryptoResourceId& trust_store, - const CryptoResourceId& slot, - score::cpp::span crl_data, - FormatType format) = 0; - protected: ICertificateManagementContext() = default; }; diff --git a/score/crypto/src/api/contexts/i_trust_store_management_context.hpp b/score/crypto/src/api/contexts/i_trust_store_management_context.hpp new file mode 100644 index 000000000..9ec3cbeb6 --- /dev/null +++ b/score/crypto/src/api/contexts/i_trust_store_management_context.hpp @@ -0,0 +1,171 @@ +/******************************************************************************** + * Copyright (c) 2026 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ + +#ifndef SCORE_CRYPTO_SRC_API_CONTEXTS_I_TRUST_STORE_MANAGEMENT_CONTEXT_HPP +#define SCORE_CRYPTO_SRC_API_CONTEXTS_I_TRUST_STORE_MANAGEMENT_CONTEXT_HPP + +#include "score/crypto/src/api/contexts/i_context.hpp" +#include "score/crypto/src/api/types/certificate.hpp" +#include "score/crypto/src/api/types/common.hpp" +#include "score/result/result.h" +#include "score/span.hpp" + +#include +#include +#include + +namespace score +{ + +namespace crypto +{ + +/// @brief Interface for trust-store membership curation. +/// +/// A trust store remains a collection of certificate slots owned by +/// `ICertificateManagementContext`; this context owns only the membership +/// and enablement policy on top of it — a distinct client-facing capability +/// under the same certificate-management provider scope (`CERT:TRUST_STORE`). +/// +/// Certificate lifecycle operations (parse, save, export, slot CRL import) +/// remain on `ICertificateManagementContext`. Read-only trust-store +/// inspection remains on `ITrustStoreObject`, obtained via +/// `ICryptoContext::GetTrustStoreObject()`. +class ITrustStoreManagementContext : public IContext +{ + public: + using Uptr = std::unique_ptr; + + ~ITrustStoreManagementContext() override = default; + + ITrustStoreManagementContext(const ITrustStoreManagementContext&) = delete; + ITrustStoreManagementContext& operator=(const ITrustStoreManagementContext&) = delete; + ITrustStoreManagementContext(ITrustStoreManagementContext&&) = default; + ITrustStoreManagementContext& operator=(ITrustStoreManagementContext&&) = default; + + /// @brief Adds a certificate to a persistent trust store. + /// + /// The certificate is assigned to a trust-store-managed exclusive slot. This is a + /// write operation and requires trust-store write access. Idempotent: if the cert + /// is already a member of any type, returns success without allocating a new slot. + /// + /// @param trust_store Handle to the trust store (type = kCertificateTrustStore) + /// @param cert Handle to the certificate to add (type = kCertificate or kCertSlot) + /// @return std::monostate on success, error if the trust store cannot be updated + virtual score::Result AddCertificateToTrustStore(const CryptoResourceId& trust_store, + const CryptoResourceId& cert) = 0; + + /// @brief Adds a certificate and propagates its associated CRL. + /// @param trust_store Handle to the trust store (type = kCertificateTrustStore) + /// @param cert Handle to the certificate to add (type = kCertificate or kCertSlot) + /// The CRL is resolved daemon-side from the certificate resource's + /// session-scoped CRL association (see + /// `ICertificateManagementContext::ImportCrl`) or, failing that, + /// from the source slot's persistent CRL — no raw bytes are passed here. + virtual score::Result AddCertificateToTrustStoreWithCrl(const CryptoResourceId& trust_store, + const CryptoResourceId& cert) = 0; + + /// @brief Removes a certificate from a persistent trust store by cert handle. + /// + /// The certificate must be loaded in the daemon (ephemeral or slot-loaded). + /// The daemon resolves the SHA-256 fingerprint internally from the handle. + /// + /// @param trust_store Handle to the trust store (type = kCertificateTrustStore) + /// @param cert Handle to the certificate to remove (type = kCertificate or kCertSlot) + virtual score::Result RemoveCertificateFromTrustStore(const CryptoResourceId& trust_store, + const CryptoResourceId& cert) = 0; + + /// @brief Removes a certificate from a persistent trust store by SHA-256 fingerprint. + /// + /// The certificate does not need to be loaded in the daemon. Use this when + /// the fingerprint is known from an external source without the cert bytes being available. + /// + /// @param trust_store Handle to the trust store (type = kCertificateTrustStore) + /// @param sha256_fingerprint 32-byte SHA-256 fingerprint of the certificate to remove + virtual score::Result RemoveCertificateFromTrustStore( + const CryptoResourceId& trust_store, + score::cpp::span sha256_fingerprint) = 0; + + /// @brief Enables a disabled trust store member identified by its slot resource. + /// + /// Use the slot_id from ITrustStoreObject::MemberInfo to obtain the slot handle. + /// + /// @param trust_store Handle to the trust store (type = kCertificateTrustStore) + /// @param slot Handle to the member slot (type = kCertSlot) + virtual score::Result EnableTrustStoreMember(const CryptoResourceId& trust_store, + const CryptoResourceId& slot) = 0; + + /// @brief Disables a trust store member identified by its slot resource. + /// + /// A disabled member is excluded from anchor resolution; it remains in the store + /// and can be re-enabled. Use RemoveCertificateFromTrustStore to permanently remove. + /// + /// Use the slot_id from ITrustStoreObject::MemberInfo to obtain the slot handle. + /// + /// @param trust_store Handle to the trust store (type = kCertificateTrustStore) + /// @param slot Handle to the member slot (type = kCertSlot) + virtual score::Result DisableTrustStoreMember(const CryptoResourceId& trust_store, + const CryptoResourceId& slot) = 0; + + /// @brief Acknowledges an unexpected content change on a conditional-external member. + /// + /// A kConditionalExternal member is automatically disabled when its slot content + /// changes without acknowledgement (see ITrustStoreObject::MemberInfo state). This + /// re-baselines the accepted fingerprint to the slot's current content and + /// re-enables the member. Not equivalent to EnableTrustStoreMember: enabling alone + /// does not update the accepted fingerprint, so the member would be disabled again + /// on the next anchor reload if the content is still unacknowledged. + /// + /// Use the slot_id from ITrustStoreObject::MemberInfo to obtain the slot handle. + /// + /// @param trust_store Handle to the trust store (type = kCertificateTrustStore) + /// @param slot Handle to the conditional-external member slot (type = kCertSlot) + virtual score::Result AcknowledgeTrustStoreMemberUpdate(const CryptoResourceId& trust_store, + const CryptoResourceId& slot) = 0; + + /// @brief Imports a CRL for a trust store exclusive member identified by its slot resource. + /// + /// Only kExclusiveMutable trust store slots are writable through this path. + /// For shared-static or conditional-external members, use + /// `ICertificateManagementContext::ImportCrlToSlot` directly on the slot. + /// + /// Use the slot_id from ITrustStoreObject::MemberInfo to obtain the slot handle. + /// + /// @param trust_store Handle to the trust store (type = kCertificateTrustStore) + /// @param slot Handle to the exclusive member slot (type = kCertSlot) + /// @param crl_data Encoded CRL bytes + /// @param format Encoding format of the CRL + virtual score::Result ImportCrlForTrustStoreMember(const CryptoResourceId& trust_store, + const CryptoResourceId& slot, + score::cpp::span crl_data, + FormatType format) = 0; + + /// @brief Deletes the CRL from a trust-store-owned exclusive member. + /// + /// Only kExclusiveMutable members are writable through this path. The + /// trust store's write permission is required. + /// + /// @param trust_store Handle to the trust store (type = kCertificateTrustStore) + /// @param slot Handle to the exclusive member slot (type = kCertSlot) + virtual score::Result DeleteCrlForTrustStoreMember(const CryptoResourceId& trust_store, + const CryptoResourceId& slot) = 0; + + protected: + ITrustStoreManagementContext() = default; +}; + +} // namespace crypto + +} // namespace score + +#endif // SCORE_CRYPTO_SRC_API_CONTEXTS_I_TRUST_STORE_MANAGEMENT_CONTEXT_HPP diff --git a/score/crypto/src/api/objects/i_trust_store_object.hpp b/score/crypto/src/api/objects/i_trust_store_object.hpp index 0c6477f22..9d5757af2 100644 --- a/score/crypto/src/api/objects/i_trust_store_object.hpp +++ b/score/crypto/src/api/objects/i_trust_store_object.hpp @@ -37,7 +37,7 @@ namespace crypto /// are present, their membership kind, and their enabled/disabled state. /// /// Mutations (add, remove, enable, disable, import CRL) are performed via -/// ICertificateManagementContext — not through this object. +/// ITrustStoreManagementContext — not through this object. /// /// Obtained via ICryptoContext::GetTrustStoreObject(). class ITrustStoreObject : public ICryptoObject From d3cf839c019b92b03d2f3412ecc835a5ff6ce164 Mon Sep 17 00:00:00 2001 From: Athul Mallappallil Date: Fri, 18 Sep 2026 16:59:19 +0200 Subject: [PATCH 21/25] Storage refactor --- score/crypto/src/daemon/common/storage/BUILD | 27 +++++ .../common/storage/deployment_descriptor.hpp | 25 +++- .../src/daemon/common/storage/file_io.cpp | 35 +++++- .../src/daemon/common/storage/file_io.hpp | 20 ++-- .../storage/kv/kv_deployment_loader.cpp | 10 +- .../storage/kv/kv_deployment_loader.hpp | 3 + .../tests/test_deployment_descriptor.cpp | 57 +++++++++ .../common/storage/tests/test_file_io.cpp | 81 +++++++++++++ .../tests/test_kv_deployment_loader.cpp | 113 ++++++++++++++++++ 9 files changed, 349 insertions(+), 22 deletions(-) create mode 100644 score/crypto/src/daemon/common/storage/tests/test_deployment_descriptor.cpp create mode 100644 score/crypto/src/daemon/common/storage/tests/test_file_io.cpp create mode 100644 score/crypto/src/daemon/common/storage/tests/test_kv_deployment_loader.cpp diff --git a/score/crypto/src/daemon/common/storage/BUILD b/score/crypto/src/daemon/common/storage/BUILD index 6eecf280d..a9c43b26d 100644 --- a/score/crypto/src/daemon/common/storage/BUILD +++ b/score/crypto/src/daemon/common/storage/BUILD @@ -60,3 +60,30 @@ cc_library( "@score_baselibs//score/mw/log", ], ) + +cc_test( + name = "test_deployment_descriptor", + srcs = ["tests/test_deployment_descriptor.cpp"], + deps = [ + ":deployment_iface", + "@googletest//:gtest_main", + ], +) + +cc_test( + name = "test_file_io", + srcs = ["tests/test_file_io.cpp"], + deps = [ + ":file_io", + "@googletest//:gtest_main", + ], +) + +cc_test( + name = "test_kv_deployment_loader", + srcs = ["tests/test_kv_deployment_loader.cpp"], + deps = [ + ":kv_deployment", + "@googletest//:gtest_main", + ], +) diff --git a/score/crypto/src/daemon/common/storage/deployment_descriptor.hpp b/score/crypto/src/daemon/common/storage/deployment_descriptor.hpp index 4edcb1e4d..2c8812367 100644 --- a/score/crypto/src/daemon/common/storage/deployment_descriptor.hpp +++ b/score/crypto/src/daemon/common/storage/deployment_descriptor.hpp @@ -15,6 +15,7 @@ #define SCORE_CRYPTO_SRC_DAEMON_COMMON_STORAGE_DEPLOYMENT_DESCRIPTOR_HPP #include +#include #include namespace score::crypto::daemon::common::storage @@ -33,18 +34,30 @@ struct DeploymentDescriptor /// @brief Section name -> (key -> value) map. std::unordered_map> sections; - /// @brief Get a value from a section, returning default_val if absent. - [[nodiscard]] const std::string& Get(const std::string& section, - const std::string& key, - const std::string& default_val = kEmptyString) const noexcept + /// @brief Get a value from a section, returning an empty string if absent. + [[nodiscard]] const std::string& Get(const std::string& section, const std::string& key) const noexcept { const auto sit = sections.find(section); if (sit == sections.end()) { - return default_val; + return kEmptyString; } const auto kit = sit->second.find(key); - return (kit != sit->second.end()) ? kit->second : default_val; + return (kit != sit->second.end()) ? kit->second : kEmptyString; + } + + /// @brief Get a value from a section, returning an owning default if absent. + [[nodiscard]] std::string Get(const std::string& section, + const std::string& key, + std::string_view default_val) const + { + const auto sit = sections.find(section); + if (sit == sections.end()) + { + return std::string{default_val}; + } + const auto kit = sit->second.find(key); + return (kit != sit->second.end()) ? kit->second : std::string{default_val}; } /// @brief True if the named section is present (even if empty). diff --git a/score/crypto/src/daemon/common/storage/file_io.cpp b/score/crypto/src/daemon/common/storage/file_io.cpp index bd542842f..5db4c4548 100644 --- a/score/crypto/src/daemon/common/storage/file_io.cpp +++ b/score/crypto/src/daemon/common/storage/file_io.cpp @@ -23,10 +23,21 @@ namespace score::crypto::daemon::common::storage score::crypto::Expected, DaemonErrorCode> ReadFile(const std::string& path, std::size_t max_size) { + const auto exists = FileExists(path); + if (!exists) + return score::crypto::make_unexpected(exists.error()); + if (!*exists) + return score::crypto::make_unexpected(DaemonErrorCode::kResourceNotAllocated); + score::filesystem::FileFactory factory{}; auto open_result = factory.Open(score::filesystem::Path{path}, std::ios::binary | std::ios::in); if (!open_result.has_value()) - return score::crypto::make_unexpected(DaemonErrorCode::kResourceNotAllocated); + { + return score::crypto::make_unexpected(open_result.error() == + score::filesystem::ErrorCode::kFileOrDirectoryDoesNotExist + ? DaemonErrorCode::kResourceNotAllocated + : DaemonErrorCode::kInternalError); + } auto& stream = *open_result.value(); stream.seekg(0, std::ios::end); @@ -77,11 +88,20 @@ score::crypto::Expected WriteFile(const std::st return std::monostate{}; } -bool FileExists(const std::string& path) +score::crypto::Expected FileExists(const std::string& path) { + if (path.empty()) + return score::crypto::make_unexpected(DaemonErrorCode::kInvalidArgument); + score::filesystem::StandardFilesystem fs{}; const auto result = fs.IsRegularFile(score::filesystem::Path{path}); - return result.has_value() && result.value(); + if (!result.has_value()) + { + if (result.error() == score::filesystem::ErrorCode::kFileOrDirectoryDoesNotExist) + return false; + return score::crypto::make_unexpected(DaemonErrorCode::kInternalError); + } + return result.value(); } score::crypto::Expected RemoveFile(const std::string& path) @@ -90,8 +110,15 @@ score::crypto::Expected RemoveFile(const std::s return score::crypto::make_unexpected(DaemonErrorCode::kInvalidArgument); score::filesystem::StandardFilesystem fs{}; const auto result = fs.Remove(score::filesystem::Path{path}); - if (!result.has_value() && result.error() != score::filesystem::ErrorCode::kFileOrDirectoryDoesNotExist) + if (!result.has_value()) + { + const auto status = fs.Status(score::filesystem::Path{path}); + if (status.has_value() && status->Type() == score::filesystem::FileType::kNotFound) + return std::monostate{}; + if (result.error() == score::filesystem::ErrorCode::kFileOrDirectoryDoesNotExist) + return std::monostate{}; return score::crypto::make_unexpected(DaemonErrorCode::kPersistFailed); + } return std::monostate{}; } diff --git a/score/crypto/src/daemon/common/storage/file_io.hpp b/score/crypto/src/daemon/common/storage/file_io.hpp index 6d4483402..844e4db71 100644 --- a/score/crypto/src/daemon/common/storage/file_io.hpp +++ b/score/crypto/src/daemon/common/storage/file_io.hpp @@ -10,10 +10,7 @@ * * SPDX-License-Identifier: Apache-2.0 ********************************************************************************/ -/******************************************************************************** - * Copyright (c) 2026 Contributors to the Eclipse Foundation - * SPDX-License-Identifier: Apache-2.0 - ********************************************************************************/ + #ifndef SCORE_CRYPTO_SRC_DAEMON_COMMON_STORAGE_FILE_IO_HPP #define SCORE_CRYPTO_SRC_DAEMON_COMMON_STORAGE_FILE_IO_HPP @@ -33,9 +30,9 @@ namespace score::crypto::daemon::common::storage /// @param path Absolute or relative path to the file. /// @param max_size Maximum accepted file size in bytes. Returns kInvalidArgument /// if the file is empty or exceeds this limit. -/// @return Byte vector on success; kResourceNotAllocated if the file cannot be -/// opened, kInvalidArgument if size is out of range, kInternalError on -/// a partial read. +/// @return Byte vector on success; kResourceNotAllocated if the file is absent, +/// kInvalidArgument if size is out of range, kInternalError if the file +/// cannot be opened for another reason or on a partial read. [[nodiscard]] score::crypto::Expected, DaemonErrorCode> ReadFile(const std::string& path, std::size_t max_size); @@ -52,11 +49,12 @@ namespace score::crypto::daemon::common::storage const std::string& path, score::crypto::span data); -/// Return true if @p path refers to an existing regular file. +/// Check whether @p path refers to an existing regular file. /// -/// Returns false for directories, symlinks to non-existent targets, and any -/// other non-regular-file entries. Errors resolve to false. -[[nodiscard]] bool FileExists(const std::string& path); +/// Returns false for missing paths, directories, symlinks to non-existent +/// targets, and other non-regular-file entries. Filesystem errors are returned +/// as failures instead of being reported as absence. +[[nodiscard]] score::crypto::Expected FileExists(const std::string& path); /// Remove the file at @p path. /// diff --git a/score/crypto/src/daemon/common/storage/kv/kv_deployment_loader.cpp b/score/crypto/src/daemon/common/storage/kv/kv_deployment_loader.cpp index 34ec737cc..0524bfe36 100644 --- a/score/crypto/src/daemon/common/storage/kv/kv_deployment_loader.cpp +++ b/score/crypto/src/daemon/common/storage/kv/kv_deployment_loader.cpp @@ -79,7 +79,15 @@ score::crypto::Expected + +#include + +namespace score::crypto::daemon::common::storage +{ +namespace +{ + +TEST(DeploymentDescriptorTest, MissingKeyWithoutDefaultReturnsStableEmptyString) +{ + DeploymentDescriptor descriptor; + + const auto& value = descriptor.Get("certificate", "cert_path"); + + EXPECT_TRUE(value.empty()); + EXPECT_EQ(&value, &descriptor.Get("certificate", "cert_path")); +} + +TEST(DeploymentDescriptorTest, ExplicitDefaultReturnsOwningValue) +{ + DeploymentDescriptor descriptor; + + const auto& value = descriptor.Get("certificate", "cert_path", "/default/path"); + + EXPECT_EQ(value, "/default/path"); + static_assert(std::is_same_v); +} + +TEST(DeploymentDescriptorTest, ExistingValueWithoutDefaultReturnsDescriptorValue) +{ + DeploymentDescriptor descriptor; + descriptor.Set("certificate", "cert_path", "/certificate/path"); + + const auto& value = descriptor.Get("certificate", "cert_path"); + + EXPECT_EQ(value, "/certificate/path"); + static_assert(std::is_same_v); +} + +} // namespace +} // namespace score::crypto::daemon::common::storage diff --git a/score/crypto/src/daemon/common/storage/tests/test_file_io.cpp b/score/crypto/src/daemon/common/storage/tests/test_file_io.cpp new file mode 100644 index 000000000..f91e1f987 --- /dev/null +++ b/score/crypto/src/daemon/common/storage/tests/test_file_io.cpp @@ -0,0 +1,81 @@ +/******************************************************************************** + * Copyright (c) 2026 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ + +#include "score/crypto/src/daemon/common/storage/file_io.hpp" + +#include + +#include +#include +#include +#include + +namespace score::crypto::daemon::common::storage +{ +namespace +{ + +std::filesystem::path TestPath(const std::string& suffix) +{ + return std::filesystem::temp_directory_path() / + ("score_crypto_file_io_" + std::to_string(std::chrono::steady_clock::now().time_since_epoch().count()) + + "_" + suffix); +} + +TEST(FileIoTest, MissingFileIsReportedAsAbsent) +{ + const auto path = TestPath("missing"); + + const auto result = FileExists(path.string()); + + ASSERT_TRUE(result.has_value()); + EXPECT_FALSE(result.value()); +} + +TEST(FileIoTest, RegularFileIsReportedAsPresent) +{ + const auto path = TestPath("present"); + { + std::ofstream output{path}; + ASSERT_TRUE(output.is_open()); + output << "data"; + } + + const auto result = FileExists(path.string()); + + ASSERT_TRUE(result.has_value()); + EXPECT_TRUE(result.value()); + std::filesystem::remove(path); +} + +TEST(FileIoTest, MissingFileReadRetainsEmptyResourceMeaning) +{ + const auto path = TestPath("missing_read"); + + const auto result = ReadFile(path.string(), 1024U); + + ASSERT_FALSE(result.has_value()); + EXPECT_EQ(result.error(), DaemonErrorCode::kResourceNotAllocated); +} + +TEST(FileIoTest, RemovingMissingFileIsIdempotent) +{ + const auto path = TestPath("missing_remove"); + + const auto result = RemoveFile(path.string()); + + EXPECT_TRUE(result.has_value()); +} + +} // namespace +} // namespace score::crypto::daemon::common::storage diff --git a/score/crypto/src/daemon/common/storage/tests/test_kv_deployment_loader.cpp b/score/crypto/src/daemon/common/storage/tests/test_kv_deployment_loader.cpp new file mode 100644 index 000000000..029681b22 --- /dev/null +++ b/score/crypto/src/daemon/common/storage/tests/test_kv_deployment_loader.cpp @@ -0,0 +1,113 @@ +/******************************************************************************** + * Copyright (c) 2026 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ + +#include "score/crypto/src/daemon/common/storage/kv/kv_deployment_loader.hpp" + +#include + +#include +#include +#include +#include + +namespace score::crypto::daemon::common::storage +{ +namespace +{ + +std::filesystem::path TestPath(const std::string& suffix) +{ + return std::filesystem::temp_directory_path() / + ("score_crypto_kv_deployment_loader_" + + std::to_string(std::chrono::steady_clock::now().time_since_epoch().count()) + "_" + suffix); +} + +std::string WriteDescriptor(const std::string& suffix, const std::string& content) +{ + const auto path = TestPath(suffix); + std::ofstream output{path}; + output << content; + output.close(); + return path.string(); +} + +TEST(KvDeploymentLoaderTest, ValidDescriptorLoadsSuccessfully) +{ + const auto path = WriteDescriptor("valid", + "[certificate]\n" + "cert_path = /tmp/cert.pem\n" + "cert_format = pem\n" + "\n" + "[crl]\n" + "crl_path = /tmp/cert.crl\n"); + + KvDeploymentLoader loader; + const auto result = loader.Load(path); + + ASSERT_TRUE(result.has_value()); + EXPECT_EQ(result->Get("certificate", "cert_path"), "/tmp/cert.pem"); + EXPECT_EQ(result->Get("certificate", "cert_format"), "pem"); + EXPECT_EQ(result->Get("crl", "crl_path"), "/tmp/cert.crl"); + std::filesystem::remove(path); +} + +TEST(KvDeploymentLoaderTest, DuplicateKeyInSameSectionIsRejected) +{ + const auto path = WriteDescriptor("duplicate", + "[certificate]\n" + "cert_path = /tmp/first.pem\n" + "cert_path = /tmp/second.pem\n"); + + KvDeploymentLoader loader; + const auto result = loader.Load(path); + + ASSERT_FALSE(result.has_value()); + EXPECT_EQ(result.error(), DaemonErrorCode::kInvalidArgument); + std::filesystem::remove(path); +} + +TEST(KvDeploymentLoaderTest, DuplicateKeyWithSurroundingWhitespaceIsRejected) +{ + const auto path = WriteDescriptor("duplicate_whitespace", + "[certificate]\n" + " cert_path = /tmp/first.pem\n" + "cert_path= /tmp/second.pem\n"); + + KvDeploymentLoader loader; + const auto result = loader.Load(path); + + ASSERT_FALSE(result.has_value()); + EXPECT_EQ(result.error(), DaemonErrorCode::kInvalidArgument); + std::filesystem::remove(path); +} + +TEST(KvDeploymentLoaderTest, SameKeyInDifferentSectionsIsAllowed) +{ + const auto path = WriteDescriptor("same_key_different_sections", + "[certificate]\n" + "path = /tmp/cert.pem\n" + "\n" + "[crl]\n" + "path = /tmp/cert.crl\n"); + + KvDeploymentLoader loader; + const auto result = loader.Load(path); + + ASSERT_TRUE(result.has_value()); + EXPECT_EQ(result->Get("certificate", "path"), "/tmp/cert.pem"); + EXPECT_EQ(result->Get("crl", "path"), "/tmp/cert.crl"); + std::filesystem::remove(path); +} + +} // namespace +} // namespace score::crypto::daemon::common::storage From 7acea47cd61ed0bf89afa98ca20daabd37a37ba8 Mon Sep 17 00:00:00 2001 From: Athul Mallappallil Date: Fri, 18 Sep 2026 17:00:03 +0200 Subject: [PATCH 22/25] Mediator provider capability fix --- .../src/daemon/mediator/src/mediator_impl.cpp | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/score/crypto/src/daemon/mediator/src/mediator_impl.cpp b/score/crypto/src/daemon/mediator/src/mediator_impl.cpp index 77c7b93ce..e69d96f5b 100644 --- a/score/crypto/src/daemon/mediator/src/mediator_impl.cpp +++ b/score/crypto/src/daemon/mediator/src/mediator_impl.cpp @@ -351,6 +351,16 @@ bool MediatorImpl::HandleContextCreationOperation(const score::crypto::daemon::c return false; } + if (required_capability != common::ProviderCapability::kNone && + !common::HasCapability(provider->GetProviderCapabilities(), required_capability)) + { + score::mw::log::LogError() + << "[SCORE_API_MED] ERROR - Selected provider lacks required capability for context: " << context_type; + responseBuilder.operation(operation.operationId) + .return_error(score::crypto::CryptoErrorCode::kUnsupportedOperation); + return false; + } + auto crypto_ops = provider->GetCryptoHandlerFactory(); if (crypto_ops == nullptr) { @@ -365,7 +375,8 @@ bool MediatorImpl::HandleContextCreationOperation(const score::crypto::daemon::c { score::mw::log::LogError() << "[SCORE_API_MED] ERROR - Handler or algorithm not supported:" << context_type << "/" << algorithm; - responseBuilder.operation(operation.operationId).return_error(score::crypto::CryptoErrorCode::kInternalError); + responseBuilder.operation(operation.operationId) + .return_error(score::crypto::CryptoErrorCode::kUnsupportedOperation); return false; } From b734df0f9335b6657213ec465bcd262a500e26a4 Mon Sep 17 00:00:00 2001 From: Athul Mallappallil Date: Fri, 18 Sep 2026 17:01:04 +0200 Subject: [PATCH 23/25] Crl inspect and more verify evidence --- .../i_certificate_management_context.hpp | 97 +++++++++---------- .../i_certificate_verification_context.hpp | 70 +++++++------ score/crypto/src/api/objects/BUILD | 2 + .../src/api/objects/i_cert_slot_object.hpp | 3 + .../src/api/objects/i_certificate_object.hpp | 21 ++-- 5 files changed, 105 insertions(+), 88 deletions(-) diff --git a/score/crypto/src/api/contexts/i_certificate_management_context.hpp b/score/crypto/src/api/contexts/i_certificate_management_context.hpp index 7efabc6f3..2521e7b3f 100644 --- a/score/crypto/src/api/contexts/i_certificate_management_context.hpp +++ b/score/crypto/src/api/contexts/i_certificate_management_context.hpp @@ -37,23 +37,21 @@ namespace crypto /// @brief Interface for certificate lifecycle management operations. /// -/// - **Parse** raw bytes into a daemon-backed ICertificateObject with an -/// ephemeral resource ID. -/// - **SaveCertificate** copies an ephemeral certificate to a persistent slot -/// (copy semantics — the ephemeral cert remains valid until the -/// ICertificateObject goes out of scope). +/// - **Parse** raw bytes into a guarded ephemeral certificate resource. +/// - **SaveCertificate** copies an ephemeral certificate to a persistent slot. /// - **Export / convert** using a two-call pattern: query the required buffer /// size first, then fill the caller-supplied span. -/// - **Slot management** and **trust store management** are co-located here. +/// - **Certificate-slot and slot-CRL lifecycle** including loading, saving, +/// clearing, and persistent CRL import. /// /// **ParseCertificate lifecycle**: /// @code /// auto cert = cert_mgmt->ParseCertificate(der_bytes, FormatType::kDer).value(); -/// // cert->GetId() is valid — daemon assigned an ephemeral kCertificate ID. -/// // Inspect before committing: -/// if (cert->GetNotAfter() < current_time) { return Error; } -/// cert_mgmt->SaveCertificate(cert->GetId(), target_slot).value(); -/// // cert goes out of scope → destructor → daemon releases ephemeral copy. +/// auto view = crypto_context->GetCertificateObject(cert).value(); +/// // Inspect the certificate while cert owns the daemon resource. +/// if (view->GetNotAfter() < current_time) { return Error; } +/// cert_mgmt->SaveCertificate(cert, target_slot).value(); +/// // cert goes out of scope → guard releases the ephemeral certificate. /// @endcode class ICertificateManagementContext : public IContext { @@ -73,32 +71,29 @@ class ICertificateManagementContext : public IContext /// /// Sends the raw bytes to the daemon, which validates the certificate /// structure and assigns an ephemeral kCertificate resource ID. - /// The returned ICertificateObject::GetId() is immediately valid. + /// The returned guard owns the ephemeral kCertificate resource. /// /// @param cert_data DER or PEM encoded certificate bytes /// @param format Encoding format of the input data - /// @return ICertificateObject with a daemon-assigned ephemeral ID. - /// Destroying the object releases the ephemeral ID. - virtual score::Result ParseCertificate(score::cpp::span cert_data, - FormatType format) = 0; + /// @return CryptoResourceGuard owning the daemon-assigned ephemeral resource. + virtual score::Result ParseCertificate(score::cpp::span cert_data, + FormatType format) = 0; /// @brief Parses multiple certificates from a PEM bundle or DER chain. /// /// @param cert_data PEM bundle or concatenated certificate data /// @param format Encoding format of the data - /// @return Ordered vector of ICertificateObject (first = leaf/first in bundle). - /// Each object has a daemon-assigned ephemeral ID. - virtual score::Result> ParseCertificates( - score::cpp::span cert_data, - FormatType format) = 0; + /// @return Ordered vector of guards (first = leaf/first in bundle). + /// Each guard owns one daemon-assigned ephemeral resource. + virtual score::Result> ParseCertificates(score::cpp::span cert_data, + FormatType format) = 0; // ---- Persistence ---- /// @brief Copies an ephemeral certificate to a persistent certificate slot. /// - /// Copy semantics: the ephemeral certificate (and its ICertificateObject) - /// remains valid after this call. The object releases the ephemeral copy - /// independently when it is destroyed. + /// Copy semantics: the source guard continues to own the ephemeral + /// certificate after this call. /// /// Typical usage: parse → inspect fields → save to slot. /// @@ -166,10 +161,9 @@ class ICertificateManagementContext : public IContext /// @return std::monostate on success, error if the slot is not found or access is denied virtual score::Result ClearCertificate(const CryptoResourceId& slot) = 0; - /// @brief Queries the occupancy and metadata of a certificate slot. - /// @param slot Handle to the slot (type = kCertSlot) - /// @return CertificateSlotInfo with certificate-slot state and CRL presence - virtual score::Result GetCertificateSlotInfo(const CryptoResourceId& slot) = 0; + /// @brief Loads a certificate from a persistent slot into an ephemeral resource. + /// The returned guard may be reused with multiple certificate contexts. + virtual score::Result LoadCertificate(const CryptoResourceId& slot) = 0; // ---- Key extraction ---- @@ -185,17 +179,13 @@ class ICertificateManagementContext : public IContext virtual score::Result> LoadCertificatePublicKey( const CryptoResourceId& cert) = 0; - /// @brief Bulk-deletes expired certificates from persistent slots. - /// @return Number of certificates deleted - virtual score::Result DeleteExpiredCertificates() = 0; + // ---- Persistence with CRL propagation ---- - // ---- Persistence — with optional CRL propagation ---- - - /// @brief Copies an ephemeral certificate to a persistent slot, optionally propagating its CRL. + /// @brief Copies a certificate to a persistent slot and propagates its CRL. /// - /// When @p with_crl is true the daemon propagates the CRL already held for @p cert: - /// - If a session-scoped CRL was previously associated via ImportCrl() (persist=false), - /// that CRL is used (works for both kCertificate and kCertSlot sources). + /// The daemon propagates the CRL already held for @p cert: + /// - If a session-scoped CRL is associated via ImportCrl() with a + /// kCertificate source, that CRL is used. /// - Otherwise the CRL is read from @p cert's slot's persistent [crl] section /// (only applicable when cert is a kCertSlot source). /// @@ -203,30 +193,35 @@ class ICertificateManagementContext : public IContext /// /// @param cert CryptoResourceId of the certificate to save (type = kCertificate or kCertSlot) /// @param target_slot Handle to the target slot (type = kCertSlot) - /// @param with_crl When true, propagate the associated CRL to the destination slot - virtual score::Result SaveCertificate(const CryptoResourceId& cert, - const CryptoResourceId& target_slot, - bool with_crl) = 0; + virtual score::Result SaveCertificateWithCrl(const CryptoResourceId& cert, + const CryptoResourceId& target_slot) = 0; // ---- CRL management ---- - /// @brief Imports a Certificate Revocation List and associates it with its issuer certificate. + /// @brief Imports a session-scoped CRL for a `kCertificate` resource. /// - /// The CRL lifecycle follows the lifecycle of @p issuer_cert: - /// - kCertSlot + persist=true: CRL written to the slot's [crl] section; write access required. - /// - kCertSlot or kCertificate + persist=false: session-scoped in-memory; no write access needed. - /// Session CRL is consumed by SaveCertificate(with_crl=true) and - /// AddCertificateToTrustStore(with_crl=true) without re-passing raw bytes. + /// The association follows the lifetime of @p issuer_cert. No slot write + /// access is required. The session CRL is consumed by + /// SaveCertificateWithCrl and AddCertificateToTrustStoreWithCrl + /// without re-passing raw bytes. /// /// @param crl_data Encoded CRL data /// @param format Encoding format of the CRL - /// @param issuer_cert Handle to the issuer certificate (type = kCertSlot or kCertificate) - /// @param persist When true, store permanently to the issuer slot (kCertSlot only) + /// @param issuer_cert Handle to a `kCertificate` resource. Obtain one by + /// parsing a certificate or loading it from a slot. /// @return std::monostate on success, error if validation fails or access is denied virtual score::Result ImportCrl(score::cpp::span crl_data, FormatType format, - const CryptoResourceId& issuer_cert, - bool persist = false) = 0; + const CryptoResourceId& issuer_cert) = 0; + + /// @brief Imports a CRL to a persistent certificate slot. + /// @param crl_data Encoded CRL data + /// @param format Encoding format of the CRL + /// @param cert_slot Handle to the certificate slot (type = kCertSlot) + /// @return std::monostate on success, error if validation fails or access is denied + virtual score::Result ImportCrlToSlot(score::cpp::span crl_data, + FormatType format, + const CryptoResourceId& cert_slot) = 0; /// @brief Removes the CRL stored in a certificate slot. /// @param cert_slot Handle to the slot whose CRL should be removed (type = kCertSlot) diff --git a/score/crypto/src/api/contexts/i_certificate_verification_context.hpp b/score/crypto/src/api/contexts/i_certificate_verification_context.hpp index c7e69f785..51d91dd89 100644 --- a/score/crypto/src/api/contexts/i_certificate_verification_context.hpp +++ b/score/crypto/src/api/contexts/i_certificate_verification_context.hpp @@ -48,7 +48,7 @@ namespace crypto /// @par Example — chain verification with additional untrusted certificates /// @code /// // ext_ca is a kCertificate from ParseCertificate() — not persisted. -/// std::array extra = {ext_ca->GetId()}; +/// std::array extra = {ext_ca.Id()}; /// auto ctx = crypto_context->CreateCertificateVerificationContext(config).value(); /// ctx->SetCertificateChain(chain); /// ctx->SetVerificationTrustStore(system_trust_store); @@ -72,13 +72,13 @@ class ICertificateVerificationContext : public IContext /// @brief Sets the leaf certificate to verify. /// @param cert Handle to the certificate to verify /// @return std::monostate on success, error if cert handle is invalid - /// @note Replaces any previously set certificate or chain on this context. + /// @note Replaces the certificate or chain configured on this context. virtual score::Result SetCertificate(const CryptoResourceId& cert) = 0; /// @brief Sets a certificate chain to verify (leaf first). /// @param chain Ordered chain of certificate handles (leaf first, root last) /// @return std::monostate on success, error if any handle is invalid - /// @note Replaces any previously set certificate or chain on this context. + /// @note Replaces the certificate or chain configured on this context. virtual score::Result SetCertificateChain(score::cpp::span chain) = 0; /// @brief Sets the system trust store to use for certificate chain verification. @@ -92,21 +92,23 @@ class ICertificateVerificationContext : public IContext /// @return std::monostate on success, error if handle is invalid virtual score::Result SetVerificationTrustStore(const CryptoResourceId& trust_store) = 0; - /// @brief Sets the standalone trusted certificates for this verification context. + /// @brief Sets explicit trusted certificates for this verification context. /// - /// This mode is mutually exclusive with SetVerificationTrustStore(). Each - /// call replaces the previously configured set, so callers that discover - /// anchors incrementally must collect them before calling this method. + /// When a verification trust store is configured, these certificates are + /// added to the trust-store anchors. Without a trust store, they form the + /// complete standalone trust-anchor set. Each call replaces only the + /// explicitly configured certificates. /// /// @param certs Span of certificate handles to treat as trust anchors /// (type = kCertificate or kCertSlot) /// @return std::monostate on success, error if any handle is invalid virtual score::Result SetTrustedCertificates(score::cpp::span certs) = 0; - /// @brief Selects the chain termination rule for trust-store verification. + /// @brief Selects the chain termination rule for configured-anchor verification. /// - /// The default is ChainTerminationPolicy::kRootRequired. This setting has - /// no effect in standalone trusted-certificate mode. + /// The default is ChainTerminationPolicy::kRootRequired. With + /// kTrustStoreTerminated, verification stops at the first certificate in + /// the effective trust-anchor set, including explicit trusted certificates. virtual score::Result SetChainTerminationPolicy(ChainTerminationPolicy policy) = 0; /// @brief Supplies additional untrusted certificates for chain building. @@ -121,7 +123,7 @@ class ICertificateVerificationContext : public IContext /// established exclusively by the configured trust store or standalone /// trusted certificates. /// - /// Replaces any previously set additional certificates on this context. + /// Replaces the additional certificates configured on this context. /// /// @param certificates Span of untrusted certificate handles /// (type = kCertificate or kCertSlot) @@ -129,7 +131,7 @@ class ICertificateVerificationContext : public IContext virtual score::Result SetAdditionalCertificates( score::cpp::span certificates) = 0; - // ---- OCSP (not yet active — IPC implementation pending) ---- + // ---- OCSP ---- #if 0 /// @brief Provides one or more OCSP responses for revocation checking. /// @@ -138,7 +140,7 @@ class ICertificateVerificationContext : public IContext /// stapled OCSP responses (e.g. TLS 1.3 certificate_status records). /// The daemon matches each response to the appropriate certificate in the /// chain by the certID field embedded in the response; order does not matter. - /// Replaces any previously set responses on this context. + /// Replaces the OCSP responses configured on this context. /// /// @param responses Span of DER-encoded OCSP response byte spans /// @return std::monostate on success, error if any response fails to parse @@ -159,6 +161,10 @@ class ICertificateVerificationContext : public IContext /// @note Overrides the default policy set in the config. virtual score::Result SetRevocationCheckPolicy(RevocationCheckPolicy policy) = 0; + /// @brief Selects which evidence is retained after verification. + /// @note The default is kNone. Configure before Verify(). + virtual score::Result SetEvidenceMode(VerificationEvidenceMode mode) = 0; + // ---- Execution ---- /// @brief Executes the configured certificate verification. @@ -167,23 +173,31 @@ class ICertificateVerificationContext : public IContext virtual score::Result Verify() = 0; /// @brief Returns the number of certificates in the verified chain. - /// - /// Valid only after a successful Verify() call. The length is stable between - /// this call and GetVerifiedChain() provided no intervening Verify() is made. - /// - /// @return Number of entries in the chain (leaf to terminating anchor inclusive), - /// or an error if Verify() has not yet succeeded. - virtual score::Result GetVerifiedChainLength() const = 0; + /// @return Number of certificates, or an error before Verify(). + virtual score::Result GetVerifiedChainCertificateCount() const = 0; - /// @brief Fills caller-provided buffer with verified chain certificate IDs. + /// @brief Returns the encoded size of the verified chain. /// - /// Certificates are ordered leaf-first, terminating anchor last. - /// The caller must size @p out to at least GetVerifiedChainLength() entries. - /// - /// @param out Caller-allocated span of CryptoResourceId to fill - /// @return Number of entries written, or an error if @p out is too small - /// or Verify() has not yet succeeded. - virtual score::Result GetVerifiedChain(score::cpp::span out) const = 0; + /// Certificates are ordered leaf-first. PEM output is a concatenated PEM + /// chain; DER output is concatenated DER certificates in the same order. + virtual score::Result GetVerifiedChainExportSize(FormatType format) const = 0; + + /// @brief Exports the verified chain in leaf-first order. + virtual score::Result ExportVerifiedChain(FormatType format, score::cpp::span out) const = 0; + + /// @brief Returns the encoded size of one certificate in the verified chain. + virtual score::Result GetVerifiedCertificateExportSize(std::size_t index, FormatType format) const = 0; + + /// @brief Exports one certificate from the verified chain. + virtual score::Result ExportVerifiedCertificate(std::size_t index, + FormatType format, + score::cpp::span out) const = 0; + + /// @brief Returns the number of retained CRL evidence entries. + virtual score::Result GetSelectedCrlMetadataCount() const = 0; + + /// @brief Fills caller-provided storage with selected CRL metadata. + virtual score::Result GetSelectedCrlMetadata(score::cpp::span out) const = 0; protected: ICertificateVerificationContext() = default; diff --git a/score/crypto/src/api/objects/BUILD b/score/crypto/src/api/objects/BUILD index ed7a69117..929d9898b 100644 --- a/score/crypto/src/api/objects/BUILD +++ b/score/crypto/src/api/objects/BUILD @@ -27,6 +27,7 @@ cc_library( visibility = ["//visibility:public"], deps = [ "//score/crypto/src/api/common:crypto_common", + "//score/crypto/src/api/types:types", "@score_baselibs//score/language/futurecpp", "@score_baselibs//score/result", ], @@ -44,6 +45,7 @@ cc_library( deps = [ ":crypto_objects", "//score/crypto/src/api/common:crypto_common", + "//score/crypto/src/api/types:types", "@score_baselibs//score/language/futurecpp", "@score_baselibs//score/result", ], diff --git a/score/crypto/src/api/objects/i_cert_slot_object.hpp b/score/crypto/src/api/objects/i_cert_slot_object.hpp index d6444b5d5..24aedd0da 100644 --- a/score/crypto/src/api/objects/i_cert_slot_object.hpp +++ b/score/crypto/src/api/objects/i_cert_slot_object.hpp @@ -43,6 +43,9 @@ class ICertSlotObject : public ICryptoObject /// @brief Whether the certificate slot currently holds a certificate. virtual bool IsOccupied() const noexcept = 0; + /// @brief Whether the slot currently stores a persistent CRL. + virtual bool HasCrl() const noexcept = 0; + protected: ICertSlotObject() = default; }; diff --git a/score/crypto/src/api/objects/i_certificate_object.hpp b/score/crypto/src/api/objects/i_certificate_object.hpp index eefdb2ca5..772d6c6b8 100644 --- a/score/crypto/src/api/objects/i_certificate_object.hpp +++ b/score/crypto/src/api/objects/i_certificate_object.hpp @@ -34,19 +34,16 @@ namespace crypto /// @brief Typed view of a certificate resource. /// -/// The single certificate abstraction used for both ephemeral (parsed from bytes) -/// and persistent (loaded from a slot) certificates. All instances are +/// The single certificate view abstraction used for both ephemeral (parsed from +/// bytes) and persistent (loaded from a slot) certificates. All instances are /// daemon-backed and carry a valid `GetId()` from the moment they are obtained. /// -/// **Lifecycle**: destroying this object releases the daemon-side resource. -/// For ephemeral certificates created by ParseCertificate(), the daemon frees -/// the resource when the last ICertificateObject referring to it is destroyed. -/// For persistent certificates loaded from a slot, the slot and its content -/// are unaffected — only the in-memory view object is released. +/// **Lifecycle**: this object is non-owning. A parsed certificate's +/// CryptoResourceGuard owns the daemon-side resource and must outlive this view. +/// For persistent certificates, the slot owns the stored content. /// /// **Persistence**: use ICertificateManagementContext::SaveCertificate() to -/// copy an ephemeral certificate to a persistent slot. The ephemeral copy -/// remains valid and is released independently when this object is destroyed. +/// copy an ephemeral certificate to a persistent slot. /// /// Provides field access, serial number, public key metadata, and public key /// export. Certificates with PQC keys (ML-DSA, SLH-DSA, XMSS, LMS) may @@ -90,6 +87,12 @@ class ICertificateObject : public ICryptoObject /// with the issuer DN and serial number it uniquely identifies a certificate. virtual std::array GetFingerprint() const noexcept = 0; + /// @brief Returns metadata for the CRL associated with this certificate. + /// + /// The result is empty when no session-scoped or persistent CRL is + /// associated with the certificate. + virtual std::optional GetCrlMetadata() const noexcept = 0; + /// @brief Returns the byte size of the DER-encoded SubjectPublicKeyInfo. /// /// Call this before ExportPublicKey() to determine the required buffer size. From a16d97da0efd70ce36e0aca468b00c2a4b9d7cfb Mon Sep 17 00:00:00 2001 From: Athul Mallappallil Date: Fri, 18 Sep 2026 17:01:33 +0200 Subject: [PATCH 24/25] Doc update --- .../api_certificate_contexts.puml | 56 +++++++++++++++---- .../docs/architecture/api_description.rst | 19 ++++++- .../docs/architecture/api_typed_objects.puml | 2 + .../architecture/configuration_objects.puml | 1 - score/crypto/docs/architecture/interfaces.rst | 19 ++++++- 5 files changed, 79 insertions(+), 18 deletions(-) diff --git a/score/crypto/docs/architecture/api_certificate_contexts.puml b/score/crypto/docs/architecture/api_certificate_contexts.puml index ebb37ff0b..4b8e9109a 100644 --- a/score/crypto/docs/architecture/api_certificate_contexts.puml +++ b/score/crypto/docs/architecture/api_certificate_contexts.puml @@ -30,10 +30,11 @@ package "Context Base" { package "Certificate Management" { interface ICertificateManagementContext { __ Parsing __ - + ParseCertificate(cert_data, format) : Result - + ParseCertificates(cert_data, format) : Result> + + ParseCertificate(cert_data, format) : Result + + ParseCertificates(cert_data, format) : Result> __ Persistence (copy semantics) __ + SaveCertificate(id, slot) : Result + + SaveCertificateWithCrl(id, slot) : Result __ Export __ + GetCertificateExportSize(cert) : Result + ExportCertificate(cert, format, output) : Result @@ -41,21 +42,40 @@ package "Certificate Management" { + ConvertCertificateFormat(input, in_fmt, out_fmt, output) : Result __ Slot Management __ + ClearCertificate(slot) : Result - + GetCertificateSlotInfo(slot) : Result + + LoadCertificate(slot) : Result __ CRL Management __ - + ImportCrl(crl_data, format, issuer_cert, persist) : Result - + DeleteCrl(crl) : Result - + DeleteExpiredCrls() : Result - + DeleteExpiredCertificates() : Result + + ImportCrl(crl_data, format, certificate) : Result + + ImportCrlToSlot(crl_data, format, cert_slot) : Result + + DeleteCrl(cert_slot) : Result __ Key Extraction __ + LoadCertificatePublicKey(cert) : Result> - __ OCSP __ - + GetOcspRequestData(cert, issuer_cert) : Result + __ OCSP (reserved) __ + + GetOcspRequestData(...) : deferred } ICertificateManagementContext --|> IContext : inherits } +' ============================================================ +' Trust-Store Management +' ============================================================ +package "Trust-Store Management" { + interface ITrustStoreManagementContext { + __ Membership __ + + AddCertificateToTrustStoreWithCrl(trust_store, cert) : Result + + RemoveCertificateFromTrustStore(trust_store, cert) : Result + + RemoveCertificateFromTrustStore(trust_store, fingerprint) : Result + + EnableTrustStoreMember(trust_store, slot) : Result + + DisableTrustStoreMember(trust_store, slot) : Result + + AcknowledgeTrustStoreMemberUpdate(trust_store, slot) : Result + __ Member CRL __ + + ImportCrlForTrustStoreMember(trust_store, slot, crl_data, format) : Result + + DeleteCrlForTrustStoreMember(trust_store, slot) : Result + } + + ITrustStoreManagementContext --|> IContext : inherits +} + ' ============================================================ ' Certificate Verification ' ============================================================ @@ -65,13 +85,19 @@ package "Certificate Verification" { + SetCertificate(cert) : Result + SetCertificateChain(chain) : Result + SetVerificationTrustStore(trust_store) : Result - + SetAdditionalTrustAnchors(anchors : span) : Result - + SetOcspResponse(response_data) : Result - + SetCrl(crl) : Result + + SetAdditionalCertificates(certificates : span) : Result + + SetOcspResponses(responses : span) : deferred + SetVerificationTime(epoch_seconds) : Result + SetRevocationCheckPolicy(policy) : Result + + SetEvidenceMode(mode) : Result __ Execution __ + Verify() : Result + + GetVerifiedChainExportSize(format) : Result + + ExportVerifiedChain(format, output) : Result + + GetVerifiedCertificateExportSize(index, format) : Result + + ExportVerifiedCertificate(index, format, output) : Result + + GetSelectedCrlMetadataCount() : Result + + GetSelectedCrlMetadata(out : span) : Result } ICertificateVerificationContext --|> IContext : inherits @@ -111,6 +137,11 @@ package "Configuration" { + SetProviderType(type) : CertificateContextConfig& } + class TrustStoreManagementContextConfig <> { + + SetProvider(prov) : TrustStoreManagementContextConfig& + + SetProviderType(type) : TrustStoreManagementContextConfig& + } + class CertificateVerificationContextConfig <> { + revocation_policy : optional --- @@ -134,6 +165,7 @@ package "Configuration" { ' Relationships ' ============================================================ CertificateContextConfig ..> ICertificateManagementContext : configures +TrustStoreManagementContextConfig ..> ITrustStoreManagementContext : configures CertificateVerificationContextConfig ..> ICertificateVerificationContext : configures CsrGenerationContextConfig ..> ICsrGenerationContext : configures diff --git a/score/crypto/docs/architecture/api_description.rst b/score/crypto/docs/architecture/api_description.rst index da2de27a5..6aff07582 100644 --- a/score/crypto/docs/architecture/api_description.rst +++ b/score/crypto/docs/architecture/api_description.rst @@ -226,6 +226,7 @@ promoting DRY code reuse: ├── IRandomContext (Generate, Seed) ├── IKeyManagementContext (key lifecycle operations) ├── ICertificateManagementContext (certificate lifecycle operations) + ├── ITrustStoreManagementContext (trust-store membership curation) ├── ICertificateVerificationContext (builder-style chain verification) └── ICsrGenerationContext (builder-style CSR generation) @@ -458,10 +459,13 @@ Certificate Lifecycle - **Parsing**: ``ParseCertificate()`` returns an ``ICertificateObject::Uptr`` with field accessors (subject, issuer, serial, validity dates, algorithm). The object is backed by a daemon-assigned ephemeral ``CryptoResourceId``. -- **Persistence**: ``SaveCertificate(id, slot)`` promotes a parsed certificate to a slot +- **Persistence**: ``SaveCertificate(id, slot)`` promotes a parsed certificate to a slot; + ``SaveCertificateWithCrl(id, slot)`` also propagates the associated CRL (copy semantics — the parsed object remains valid after the call) - **Export**: ``GetCertificateExportSize()`` + ``ExportCertificate()`` two-call pattern -- **CRL**: ``ImportCrl()``, ``DeleteCrl()``, ``DeleteExpiredCrls()`` for offline revocation +- **CRL**: ``ImportCrl()`` for session-scoped CRLs on loaded certificates, + ``ImportCrlToSlot()`` and ``DeleteCrl()`` for persistent slot-scoped + revocation, with CRL metadata available for inspection - **Key extraction**: ``LoadCertificatePublicKey()`` extracts the public key as a ``CryptoResourceGuard`` wrapping an ephemeral ``CryptoResourceId`` with ``type == kKey``, following the same guard model as key-producing methods. @@ -469,6 +473,17 @@ Certificate Lifecycle - **OCSP**: ``GetOcspRequestData()`` generates a request; the response is consumed via ``ICertificateVerificationContext::SetOcspResponse()`` +**ITrustStoreManagementContext** handles trust-store membership curation: + +- adding and removing certificate members +- enabling, disabling, and acknowledging member updates +- importing CRLs for trust-store-owned exclusive members +- deleting CRLs from trust-store-owned exclusive members + +It uses ``TrustStoreManagementContextConfig`` and the certificate-management +provider capability, but routes to the distinct ``CERT:TRUST_STORE`` daemon +context. ``ITrustStoreObject`` remains a read-only snapshot interface. + **ICertificateVerificationContext** provides builder-style chain verification: - ``SetCertificate()``, ``SetCertificateChain()``, ``SetVerificationTrustStore()``, ``SetAdditionalTrustAnchors()`` diff --git a/score/crypto/docs/architecture/api_typed_objects.puml b/score/crypto/docs/architecture/api_typed_objects.puml index fc261072c..5cd6a8d3d 100644 --- a/score/crypto/docs/architecture/api_typed_objects.puml +++ b/score/crypto/docs/architecture/api_typed_objects.puml @@ -70,6 +70,7 @@ package "Slot Objects" { interface ICertSlotObject { + IsOccupied() : bool + + HasCrl() : bool } IKeySlotObject --|> ICryptoObject : inherits @@ -86,6 +87,7 @@ package "Certificate Objects" { + GetNotBefore() : int64_t + GetNotAfter() : int64_t + GetPublicKeyAlgorithm() : AlgorithmId + + GetCrlMetadata() : optional } ICertificateObject --|> ICryptoObject : inherits diff --git a/score/crypto/docs/architecture/configuration_objects.puml b/score/crypto/docs/architecture/configuration_objects.puml index 35e2c60e8..b19e22bcf 100644 --- a/score/crypto/docs/architecture/configuration_objects.puml +++ b/score/crypto/docs/architecture/configuration_objects.puml @@ -106,7 +106,6 @@ package "Configuration" { } class CertificateContextConfig <> { - + SetAlgorithm(alg) : CertificateContextConfig& + SetProvider(prov) : CertificateContextConfig& + SetProviderType(type) : CertificateContextConfig& } diff --git a/score/crypto/docs/architecture/interfaces.rst b/score/crypto/docs/architecture/interfaces.rst index d8e5a395c..81ade8acc 100644 --- a/score/crypto/docs/architecture/interfaces.rst +++ b/score/crypto/docs/architecture/interfaces.rst @@ -192,9 +192,8 @@ The public API surface is organized into the following interface groups: (copy semantics — object remains valid after persist), export (``GetCertificateExportSize`` + ``ExportCertificate``), format conversion (``GetConvertedCertificateSize`` + ``ConvertCertificateFormat``), - ``ClearCertificate``, ``GetCertificateSlotInfo``, CRL management - (``ImportCrl``, ``DeleteCrl``, ``DeleteExpiredCrls``, - ``DeleteExpiredCertificates``), + ``ClearCertificate``, CRL management + (``ImportCrl``, ``DeleteCrl``, and CRL metadata inspection), public key extraction (``LoadCertificatePublicKey`` — returns a ``CryptoResourceGuard`` wrapping an ephemeral ``kKey`` resource, following the same guard model as key-producing methods), and OCSP @@ -212,6 +211,20 @@ The public API surface is organized into the following interface groups: certificate, chain, verification trust store, and revocation check policy via fluent setters, then executes verification with ``Verify()``. +.. real_arc_int:: ITrustStoreManagementContext + :id: real_arc_int__crypto__i_trust_store_mgmt_ctx + :version: 1 + :security: YES + :safety: QM + :status: invalid + :language: cpp + + Trust-store membership management. Adds and removes certificate + members, enables or disables members, acknowledges + conditional-member updates, and imports CRLs for exclusive members + managed by the trust store. Read-only inspection is provided + through ``ITrustStoreObject``. + .. real_arc_int:: ICsrGenerationContext :id: real_arc_int__crypto__i_csr_gen_context :version: 1 From 67d87b8cf7a27c5e43b5851a4b3ef2a234e00621 Mon Sep 17 00:00:00 2001 From: Athul Mallappallil Date: Fri, 18 Sep 2026 22:52:07 +0200 Subject: [PATCH 25/25] Trust store object refactor --- .../i_trust_store_management_context.hpp | 10 +- .../src/api/objects/i_certificate_object.hpp | 2 - .../src/api/objects/i_trust_store_object.hpp | 91 ++----------------- .../src/api/src/crypto_context_impl.cpp | 2 +- score/crypto/src/api/types/certificate.hpp | 38 +++++++- 5 files changed, 48 insertions(+), 95 deletions(-) diff --git a/score/crypto/src/api/contexts/i_trust_store_management_context.hpp b/score/crypto/src/api/contexts/i_trust_store_management_context.hpp index 9ec3cbeb6..d9905d8d1 100644 --- a/score/crypto/src/api/contexts/i_trust_store_management_context.hpp +++ b/score/crypto/src/api/contexts/i_trust_store_management_context.hpp @@ -98,7 +98,7 @@ class ITrustStoreManagementContext : public IContext /// @brief Enables a disabled trust store member identified by its slot resource. /// - /// Use the slot_id from ITrustStoreObject::MemberInfo to obtain the slot handle. + /// Use the slot_id from MemberInfo to obtain the slot handle. /// /// @param trust_store Handle to the trust store (type = kCertificateTrustStore) /// @param slot Handle to the member slot (type = kCertSlot) @@ -110,7 +110,7 @@ class ITrustStoreManagementContext : public IContext /// A disabled member is excluded from anchor resolution; it remains in the store /// and can be re-enabled. Use RemoveCertificateFromTrustStore to permanently remove. /// - /// Use the slot_id from ITrustStoreObject::MemberInfo to obtain the slot handle. + /// Use the slot_id from MemberInfo to obtain the slot handle. /// /// @param trust_store Handle to the trust store (type = kCertificateTrustStore) /// @param slot Handle to the member slot (type = kCertSlot) @@ -120,13 +120,13 @@ class ITrustStoreManagementContext : public IContext /// @brief Acknowledges an unexpected content change on a conditional-external member. /// /// A kConditionalExternal member is automatically disabled when its slot content - /// changes without acknowledgement (see ITrustStoreObject::MemberInfo state). This + /// changes without acknowledgement (see MemberInfo state). This /// re-baselines the accepted fingerprint to the slot's current content and /// re-enables the member. Not equivalent to EnableTrustStoreMember: enabling alone /// does not update the accepted fingerprint, so the member would be disabled again /// on the next anchor reload if the content is still unacknowledged. /// - /// Use the slot_id from ITrustStoreObject::MemberInfo to obtain the slot handle. + /// Use the slot_id from MemberInfo to obtain the slot handle. /// /// @param trust_store Handle to the trust store (type = kCertificateTrustStore) /// @param slot Handle to the conditional-external member slot (type = kCertSlot) @@ -139,7 +139,7 @@ class ITrustStoreManagementContext : public IContext /// For shared-static or conditional-external members, use /// `ICertificateManagementContext::ImportCrlToSlot` directly on the slot. /// - /// Use the slot_id from ITrustStoreObject::MemberInfo to obtain the slot handle. + /// Use the slot_id from MemberInfo to obtain the slot handle. /// /// @param trust_store Handle to the trust store (type = kCertificateTrustStore) /// @param slot Handle to the exclusive member slot (type = kCertSlot) diff --git a/score/crypto/src/api/objects/i_certificate_object.hpp b/score/crypto/src/api/objects/i_certificate_object.hpp index 772d6c6b8..4cf72d4ae 100644 --- a/score/crypto/src/api/objects/i_certificate_object.hpp +++ b/score/crypto/src/api/objects/i_certificate_object.hpp @@ -51,8 +51,6 @@ namespace crypto class ICertificateObject : public ICryptoObject { public: - static constexpr std::size_t kSha256FingerprintSize = 32U; - using Uptr = std::unique_ptr; ~ICertificateObject() override = default; diff --git a/score/crypto/src/api/objects/i_trust_store_object.hpp b/score/crypto/src/api/objects/i_trust_store_object.hpp index 9d5757af2..6c49e2ffa 100644 --- a/score/crypto/src/api/objects/i_trust_store_object.hpp +++ b/score/crypto/src/api/objects/i_trust_store_object.hpp @@ -15,14 +15,11 @@ #define SCORE_CRYPTO_SRC_API_OBJECTS_I_TRUST_STORE_OBJECT_HPP #include "score/crypto/src/api/objects/i_crypto_object.hpp" -#include "score/crypto/src/api/types/common.hpp" +#include "score/crypto/src/api/types/certificate.hpp" #include "score/span.hpp" -#include -#include #include #include -#include #include namespace score @@ -43,37 +40,8 @@ namespace crypto class ITrustStoreObject : public ICryptoObject { public: - static constexpr std::size_t kSha256FingerprintSize = 32U; - using Uptr = std::unique_ptr; - /// @brief Membership kind of a trust store anchor. - enum class MemberKind : uint8_t - { - kSharedStatic = 0U, ///< Externally managed slot; read-only from trust store perspective. - kExclusiveMutable = 1U, ///< Trust-store-owned exclusive slot; mutable via management context. - kConditionalExternal = 2U ///< External slot; disabled after unexpected content change. - }; - - /// @brief Snapshot of a single trust store member. - /// - /// Both slot_id and sha256_fingerprint are provided so callers can: - /// - Use slot_id directly for enable/disable/importCrl operations without a round-trip. - /// - Use sha256_fingerprint for quick identity matching against externally known fingerprints - /// (e.g., from a security bulletin) without loading the full certificate. - /// - Use subject + issuer + serial_number for human-readable identification and logging. - struct MemberInfo - { - CryptoResourceId slot_id{}; ///< kCertSlot resource — use for management ops. - std::array - sha256_fingerprint{}; ///< SHA-256 fingerprint of the member certificate. - std::string subject; ///< RFC 4514 Subject DN (e.g., "CN=Root CA,O=ACME,C=DE"). - std::string issuer; ///< RFC 4514 Issuer DN. - std::string serial_number; ///< Uppercase hex serial (e.g., "01ABCDEF"). - MemberKind kind{MemberKind::kSharedStatic}; ///< Membership type. - bool is_enabled{true}; ///< Whether anchor is active for chain building. - }; - ~ITrustStoreObject() override = default; ITrustStoreObject(const ITrustStoreObject&) = delete; @@ -87,72 +55,27 @@ class ITrustStoreObject : public ICryptoObject /// Empty slots (not yet populated) are omitted. virtual const std::vector& GetMembers() const noexcept = 0; - // ---- Non-virtual convenience accessors (operate on GetMembers() locally) ---- + // ---- Convenience accessors (defined in terms of GetMembers()) ---- /// @brief Find the member entry for a given slot resource ID. /// /// Matches by id and type only — primary_provider is not compared because /// MemberInfo slot_id has primary_provider=0 as a placeholder. /// @returns Pointer to the matching MemberInfo, or nullptr if not a member. - [[nodiscard]] const MemberInfo* FindMember(const CryptoResourceId& slot) const noexcept - { - for (const auto& member : GetMembers()) - { - if (member.slot_id.id == slot.id && member.slot_id.type == slot.type) - { - return &member; - } - } - return nullptr; - } + [[nodiscard]] virtual const MemberInfo* FindMember(const CryptoResourceId& slot) const noexcept = 0; /// @brief Find the member with the given SHA-256 fingerprint. /// /// @param fingerprint 32-byte fingerprint span. Returns nullptr if its size is not 32. /// @returns Pointer to the matching MemberInfo, or nullptr if not found. - [[nodiscard]] const MemberInfo* FindMemberByFingerprint(score::cpp::span fingerprint) const noexcept - { - if (fingerprint.size() != kSha256FingerprintSize) - { - return nullptr; - } - for (const auto& member : GetMembers()) - { - if (std::equal(fingerprint.begin(), fingerprint.end(), member.sha256_fingerprint.begin())) - { - return &member; - } - } - return nullptr; - } + [[nodiscard]] virtual const MemberInfo* FindMemberByFingerprint( + score::cpp::span fingerprint) const noexcept = 0; /// @brief Returns the slot IDs of all enabled trust store members. - [[nodiscard]] std::vector GetEnabledMemberSlotIds() const - { - std::vector result; - for (const auto& member : GetMembers()) - { - if (member.is_enabled) - { - result.push_back(member.slot_id); - } - } - return result; - } + [[nodiscard]] virtual std::vector GetEnabledMemberSlotIds() const = 0; /// @brief Returns the slot IDs of all disabled trust store members. - [[nodiscard]] std::vector GetDisabledMemberSlotIds() const - { - std::vector result; - for (const auto& member : GetMembers()) - { - if (!member.is_enabled) - { - result.push_back(member.slot_id); - } - } - return result; - } + [[nodiscard]] virtual std::vector GetDisabledMemberSlotIds() const = 0; protected: ITrustStoreObject() = default; diff --git a/score/crypto/src/api/src/crypto_context_impl.cpp b/score/crypto/src/api/src/crypto_context_impl.cpp index 6673db782..14f5aa67b 100644 --- a/score/crypto/src/api/src/crypto_context_impl.cpp +++ b/score/crypto/src/api/src/crypto_context_impl.cpp @@ -131,7 +131,7 @@ score::Result CryptoContextImpl::ResolveResource(const Resourc .forDataNodeId(m_connection->GetConnectionNodeId()) .operation(score::crypto::daemon::mediator::operations::ResolveResource()) .with_in_string(resource_id) - .with_in_val_uint8(static_cast(type)) + .with_in_val_uint64(static_cast(type)) .build(); if (!control_req_result.has_value()) diff --git a/score/crypto/src/api/types/certificate.hpp b/score/crypto/src/api/types/certificate.hpp index 519b83526..566624b63 100644 --- a/score/crypto/src/api/types/certificate.hpp +++ b/score/crypto/src/api/types/certificate.hpp @@ -19,10 +19,15 @@ #include #include #include +#include namespace score::crypto { +/// Byte length of a SHA-256 digest, shared by every certificate/CRL/trust-store +/// fingerprint field in this domain. +inline constexpr std::size_t kSha256FingerprintSize = 32U; + enum class CertificateSlotState : uint8_t { kEmpty, @@ -83,8 +88,8 @@ enum class VerificationEvidenceMode : uint8_t struct CrlMetadata { - std::array fingerprint{}; - std::array issuer_fingerprint{}; + std::array fingerprint{}; + std::array issuer_fingerprint{}; int64_t this_update{0}; int64_t next_update{0}; uint64_t crl_number{0U}; @@ -92,7 +97,7 @@ struct CrlMetadata struct CrlMetadataWireLayout final { - static constexpr std::size_t kFingerprintSize = 32U; + static constexpr std::size_t kFingerprintSize = kSha256FingerprintSize; static constexpr std::size_t kCrlFingerprintOffset = 0U; static constexpr std::size_t kIssuerFingerprintOffset = kCrlFingerprintOffset + kFingerprintSize; static constexpr std::size_t kThisUpdateOffset = kIssuerFingerprintOffset + kFingerprintSize; @@ -107,6 +112,33 @@ struct CertificateSlotInfo bool has_crl{false}; }; +/// Membership kind of a trust store anchor. +enum class MemberKind : uint8_t +{ + kSharedStatic = 0U, ///< Externally managed slot; read-only from trust store perspective. + kExclusiveMutable = 1U, ///< Trust-store-owned exclusive slot; mutable via management context. + kConditionalExternal = 2U ///< External slot; disabled after unexpected content change. +}; + +/// Snapshot of a single trust store member. +/// +/// Both slot_id and sha256_fingerprint are provided so callers can: +/// - Use slot_id directly for enable/disable/importCrl operations without a round-trip. +/// - Use sha256_fingerprint for quick identity matching against externally known fingerprints +/// (e.g., from a security bulletin) without loading the full certificate. +/// - Use subject + issuer + serial_number for human-readable identification and logging. +struct MemberInfo +{ + CryptoResourceId slot_id{}; ///< kCertSlot resource — use for management ops. + std::array + sha256_fingerprint{}; ///< SHA-256 fingerprint of the member certificate. + std::string subject; ///< RFC 4514 Subject DN (e.g., "CN=Root CA,O=ACME,C=DE"). + std::string issuer; ///< RFC 4514 Issuer DN. + std::string serial_number; ///< Uppercase hex serial (e.g., "01ABCDEF"). + MemberKind kind{MemberKind::kSharedStatic}; ///< Membership type. + bool is_enabled{true}; ///< Whether anchor is active for chain building. +}; + } // namespace score::crypto #endif // SCORE_CRYPTO_SRC_API_TYPES_CERTIFICATE_HPP