Component Architecture#

Crypto Architecture
status: draft
security: YES
safety: QM
version: 1
Component Request Dummy
status: draft
version: 1

Overview#

The score::crypto module provides a provider-agnostic C++ (>=17) middleware interface for cryptographic operations, key management, certificate lifecycle, and shared memory allocation. It follows a client-daemon architecture where the client library communicates with a daemon process over IPC.

The API is organized around a single runtime handle type — CryptoResourceId — that encapsulates a daemon-assigned 64-bit identifier, resource type, persistence semantics, and owning provider index. Applications resolve human-readable string identifiers to CryptoResourceId handles once, then use these compact numeric handles for all subsequent operations.

Key design principles:

  • Provider-agnostic: Operations work identically across hardware (HSM, TEE) and software (OpenSSL, SoftHSM) providers

  • PQC-ready: AlgorithmId uses strings for extensibility, supporting ML-KEM, ML-DSA, SLH-DSA, XMSS, LMS, and SHAKE algorithms

  • Ephemeral-by-default keys: All key generation produces ephemeral keys; explicit PersistKey() promotes to persistent storage

  • Zero-copy data plane: Provider-compatible shared memory enables zero-copy from application through daemon to crypto device

  • Backward-compatible extensibility: All configs use default constructors with fluent builders; new optional fields never break existing callers

Requirements Linked to Component Architecture#

No needs passed the filters

Architecture Details

Static Architecture#

The components are designed to cover the expectations from the feature architecture (i.e. if already exists a definition it should be taken over and enriched).

.. comp:: Crypto
   :id: comp__crypto
   :security: YES
   :safety: QM
   :status: invalid
   :implements:
../../../../_images/component_overview.png

Provider Layer#

The provider layer decouples the daemon from concrete cryptographic library implementations through two complementary abstractions:

IProvider

The single entry-point into one cryptographic back-end (e.g. OpenSSL, a PKCS#11 token). Exposes GetCryptoHandlerFactory(), GetKeyFactory(), and GetKeySlotHandler(). Lifecycle is managed by ProviderManager.

IProviderFactory

A pure-virtual factory interface with a single method ProviderFactoryResult CreateAndRegister(ProviderManager&). Concrete implementations encapsulate the construction and registration of one or more related IProvider instances. ProviderManagerFactory invokes backend factories independently and records each structured result; ProviderManager does not own concrete factories.

ScoreProviderFactory

Top-level factory for the score interface family. Accepts a vector of ScoreProviderEntry values in a complete ScoreProviderFactoryConfig snapshot (default: single OpenSSL entry). CreateAndRegister() resolves each configured implementation tag against the active compile-time backend adapters and registers the resulting provider under its configured name and type.

Pkcs11ProviderFactory

Accepts a complete Pkcs11ProviderFactoryConfig snapshot containing the parsed Pkcs11TokenEntry values. The daemon bootstrapper passes this snapshot when constructing the factory:

  Pkcs11ProviderFactoryConfig factory_config{
     config.GetPkcs11Config().GetConfig()};
  auto factory = std::make_unique<Pkcs11ProviderFactory>(
     std::move(factory_config));
auto result = factory->CreateAndRegister(manager);

CreateAndRegister creates a single shared Pkcs11Module (so C_Initialize is invoked exactly once regardless of token count), then constructs and registers one Pkcs11Provider per entry as CryptoProviderType::HARDWARE.

The factory performs the Pkcs11TokenEntry to Pkcs11ProviderConfig conversion internally (filling labels, PIN, and cleanup strategy). This keeps the conversion within the PKCS#11 subsystem and keeps PKCS#11 implementation details out of the daemon bootstrapper.

Multi-token coexistence: multiple Pkcs11TokenEntry entries in Pkcs11Config produce one Pkcs11Provider per token. All providers from the same factory share a single Pkcs11Module (C_Initialize / C_Finalize is called once), but each provider maintains its own session pools, TokenAuthGuard, and Pkcs11KeyStore. Login state and key registrations are fully isolated. This design supports scenarios such as separate SoftHSM slots for different trust domains within the same process.

For session lifecycle details see PKCS#11 Session Management in the key management details.

ProviderManager

Aggregates all registered providers and routes requests by ProviderId or CryptoProviderType. ProviderManagerFactory registers providers first. ProviderManager::Initialize() then makes the initial initialization pass and builds type mappings. Provider lookups retry unavailable providers under synchronization, using the original stable ProviderId.

Dynamic Architecture#

The typical interaction sequence between Application, Client Library, and Crypto Daemon:

See API Dynamic Architecture for detailed usage flows including pre-deployed key paths, ephemeral key generation, context reuse, PQC signing, certificate verification, and timeout configuration.

Interfaces#

See Interfaces for the full interface descriptions.

Design Decisions#

See Design Decisions for the full design decision records.