Skip to main content

confium_store_pkcs11/
instance.rs

1//! One open PKCS#11-backed keystore connection.
2//!
3//! [`Pkcs11Instance`] carries the resolved [`Config`], the live
4//! [`cryptoki`] client, and the open R/W [`Session`](cryptoki::session::Session)
5//! established by [`crate::backend::Pkcs11Backend::open`].
6//!
7//! ## Status
8//!
9//! The storage operations on [`StoreInstance`](confium_store::backend::StoreInstance)
10//! return [`NotImplemented`](confium_store::error::Error::NotImplemented)
11//! in this skeleton. The session plumbing (module load, initialize,
12//! slot resolve, open session, login) is wired for real — so a future
13//! revision fills the stubs against an already-authenticated session
14//! without touching the open path.
15
16use std::ffi::c_void;
17
18use confium_store::backend::{Compartment, StoreInstance};
19use confium_store::error::Result;
20
21use crate::backend::not_implemented;
22use crate::config::Config;
23
24/// One open PKCS#11-backed keystore connection.
25///
26/// Owns the `cryptoki` client and the live session. Both are
27/// `Send + Sync` (the underlying PKCS#11 module was initialised with
28/// `CKF_OS_LOCKING_OK`), so the trait object is sound without a manual
29/// `unsafe impl`.
30pub struct Pkcs11Instance {
31    /// Resolved configuration parsed from `Options` at open time.
32    pub config: Config,
33
34    /// The `cryptoki` client. Held for the lifetime of the instance so
35    /// `C_Finalize` runs on drop and so future operations that need a
36    /// fresh session (e.g. for parallel `C_FindObjects`) can open one.
37    #[allow(dead_code)]
38    client: cryptoki::context::Pkcs11,
39
40    /// The logged-in R/W session. Storage operations issue
41    /// `C_FindObjects` / `C_CreateObject` against this handle.
42    #[allow(dead_code)]
43    session: cryptoki::session::Session,
44}
45
46impl Pkcs11Instance {
47    /// Construct an instance from already-established primitives.
48    /// Called by [`crate::backend::Pkcs11Backend::open`] after the
49    /// session is open and (optionally) logged in.
50    pub(crate) fn new(
51        config: Config,
52        client: cryptoki::context::Pkcs11,
53        session: cryptoki::session::Session,
54    ) -> Self {
55        Self {
56            config,
57            client,
58            session,
59        }
60    }
61}
62
63impl StoreInstance for Pkcs11Instance {
64    fn put_secret(
65        &mut self,
66        _module: &str,
67        _app: &str,
68        _key_id: &str,
69        _key: *mut c_void,
70    ) -> Result<()> {
71        // Skeleton: create a CKO_SECRET_KEY object scoped by the
72        // (module, app, key_id) triple — typically as application
73        // attributes (`CKA_APPLICATION` / a custom `CKA_LABEL`). The
74        // wired-up revision issues `C_CreateObject` against
75        // `self.session`.
76        Err(not_implemented())
77    }
78
79    fn get_secret(&self, _module: &str, _app: &str, _key_id: &str) -> Result<*mut c_void> {
80        // Skeleton: `C_FindObjects` for the matching object and return
81        // its object handle as the opaque `*mut c_void`.
82        Err(not_implemented())
83    }
84
85    fn put_public(
86        &mut self,
87        _module: &str,
88        _app: &str,
89        _identity: &str,
90        _key: *mut c_void,
91        _sig: &[u8],
92    ) -> Result<()> {
93        // Skeleton: store the public key as a CKO_PUBLIC_KEY object
94        // and the detached signature as a sibling attribute (or a
95        // separate data object linked by `CKA_APPLICATION`).
96        Err(not_implemented())
97    }
98
99    fn get_public(
100        &self,
101        _module: &str,
102        _app: &str,
103        _identity: &str,
104    ) -> Result<(*mut c_void, Vec<u8>)> {
105        Err(not_implemented())
106    }
107
108    fn enumerate(
109        &self,
110        _module: &str,
111        _app: &str,
112        _compartment: Compartment,
113    ) -> Result<Vec<(*mut c_void, String)>> {
114        // Skeleton: enumerate the matching objects via a
115        // `C_FindObjects` template search, returning each object
116        // handle paired with its label / identity string.
117        Err(not_implemented())
118    }
119}
120
121// SAFETY: `cryptoki::context::Pkcs11` and `cryptoki::session::Session`
122// are `Send` per upstream; `cryptoki::session::Session` is not marked
123// `Sync` upstream (the crate conservatively refuses to claim it), but
124// the underlying PKCS#11 module initialised with `CKF_OS_LOCKING_OK`
125// is thread-safe per the PKCS#11 v2.40 specification, and the
126// `StoreInstance` trait only ever hands out `&self` for read-side
127// operations (`get_*`, `enumerate`) — the cryptoki `Session` read
128// methods take `&self` and internally serialise through the module's
129// own locking. `Config` is plain owned data. The manual `Sync` impl
130// therefore preserves soundness for the trait object.
131unsafe impl Sync for Pkcs11Instance {}