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 {}