synta-certificate 0.2.6

X.509 certificate structures for synta ASN.1 library
Documentation
//! PKCS#11 token management trait and associated data types.
//!
//! The [`TokenManager`] trait abstracts over the five management operations
//! that FreeIPA's IPAThinCA requires.  The concrete implementation backed by
//! the `cryptoki` crate lives in [`crate::pkcs11_mgmt`].

use super::{BackendPrivateKey, KeySpec, PrivateKeyError};
use crate::pkcs11_uri::Pkcs11Uri;

/// Information about a PKCS#11 slot / token, as returned by [`TokenManager::list_slots`].
#[non_exhaustive]
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct SlotInfo {
    /// The PKCS#11 slot ID (`CK_SLOT_ID`).
    pub slot_id: u64,
    /// Token label (`CKA_LABEL` on the `CKO_TOKEN` object), space-padding stripped.
    pub token_label: String,
    /// Manufacturer ID field from `CK_TOKEN_INFO`, space-padding stripped.
    pub manufacturer_id: String,
    /// Model field from `CK_TOKEN_INFO`, space-padding stripped.
    pub model: String,
    /// Serial number field from `CK_TOKEN_INFO`, space-padding stripped.
    pub serial_number: String,
    /// Subset of `CKF_*` flag bits synthesised from `CK_TOKEN_INFO` boolean fields.
    ///
    /// Only four bits are captured:
    /// - `0x0000_0002` (`CKF_WRITE_PROTECTED`) — token is read-only
    /// - `0x0000_0004` (`CKF_LOGIN_REQUIRED`) — a PIN must be supplied before accessing objects
    /// - `0x0000_0100` (`CKF_PROTECTED_AUTHENTICATION_PATH`) — PIN entry is via a physical keypad
    /// - `0x0000_0400` (`CKF_TOKEN_INITIALIZED`) — token has been initialised
    ///
    /// All other bits are zero; use the individual `cryptoki::slot::TokenInfo` methods when
    /// access to the full flags word is required.
    pub flags: u64,
}

/// Information about a private key object stored on a PKCS#11 token.
#[non_exhaustive]
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Pkcs11KeyInfo {
    /// Object label (`CKA_LABEL`).
    pub label: String,
    /// Raw `CKA_ID` bytes; may be empty if the token does not set this attribute.
    pub id: Vec<u8>,
    /// Human-readable key type: `"RSA"`, `"EC"`, `"Ed"`, `"ML-DSA"`, `"ML-KEM"`, or `"Unknown"`.
    pub key_type: String,
    /// RSA modulus length in bits, derived from `CKA_MODULUS`.
    ///
    /// `0` for all non-RSA key types (EC, Ed25519, Ed448, ML-DSA, ML-KEM), because
    /// those types do not expose `CKA_MODULUS`.
    pub key_bits: u32,
}

/// PKCS#11 token management operations.
///
/// Implemented by [`crate::pkcs11_mgmt::Pkcs11Manager`], which dynamically loads
/// the system PKCS#11 module (e.g. `p11-kit-proxy.so`) via the `cryptoki` crate.
pub trait TokenManager {
    /// List all slots that currently have a token present and initialised.
    fn list_slots(&self) -> Result<Vec<SlotInfo>, PrivateKeyError>;

    /// Return `true` if a private-key object matching the URI's `object` label
    /// exists on the token named by the URI's `token` attribute.
    ///
    /// Requires `token=` and `object=` in the URI.  Authenticates with
    /// `uri.attrs.pin_value` if present.
    fn find_key(&self, uri: &Pkcs11Uri) -> Result<bool, PrivateKeyError>;

    /// List all private-key objects on the named token.
    ///
    /// `pin` is optional; pass `None` when the token does not require a PIN or
    /// when the PIN has already been entered through a protected authentication path.
    fn list_keys(
        &self,
        token_name: &str,
        pin: Option<&str>,
    ) -> Result<Vec<Pkcs11KeyInfo>, PrivateKeyError>;

    /// Destroy the private-key and the matching public-key object identified by
    /// the URI's `object` label from the token named by the URI's `token` attribute.
    ///
    /// Both `CKO_PRIVATE_KEY` and `CKO_PUBLIC_KEY` objects with the given label are
    /// destroyed.  Requires `token=` and `object=` in the URI.  Authenticates with
    /// `uri.attrs.pin_value` if present.
    fn delete_key(&self, uri: &Pkcs11Uri) -> Result<(), PrivateKeyError>;

    /// Generate a key pair on the token and return a handle to the private key.
    ///
    /// Both key objects are stored persistently on the token (`CKA_TOKEN = true`).
    /// Requires `token=` (slot selection) and `object=` (key label) in the URI.
    /// Authenticates with `uri.attrs.pin_value` if present.
    ///
    /// After the PKCS#11 session that generated the key is closed, the key is
    /// loaded back through the active crypto backend so that the returned
    /// [`BackendPrivateKey`] carries a fully populated SPKI and can be used for
    /// signing immediately without a second token look-up.
    ///
    /// `extractable` controls whether `CKA_EXTRACTABLE` is set on the private-key
    /// object.  Pass `false` (the default) for hardware-resident keys that must
    /// not leave the token.  Pass `true` only when the caller explicitly requires
    /// the ability to export the private key material later (e.g. for software
    /// tokens used in backup scenarios).
    fn generate_key_pair_in_token(
        &self,
        spec: &KeySpec,
        uri: &Pkcs11Uri,
        extractable: bool,
    ) -> Result<BackendPrivateKey, PrivateKeyError>;
}