Skip to main content

identity_kit/keys/
pkcs11.rs

1//! `Pkcs11KeyStore`: keys in a PKCS#11 token, an HSM or a software token such as SoftHSM2.
2
3use core::fmt;
4use std::error::Error;
5use std::path::{Path, PathBuf};
6use std::sync::atomic::{AtomicU64, Ordering};
7use std::sync::{Arc, Condvar, Mutex, MutexGuard, PoisonError};
8
9use cryptoki::context::{CInitializeArgs, CInitializeFlags, Pkcs11};
10use cryptoki::error::{Error as CryptokiError, RvError};
11use cryptoki::mechanism::eddsa::{EddsaParams, EddsaSignatureScheme};
12use cryptoki::mechanism::rsa::{PkcsMgfType, PkcsPssParams};
13use cryptoki::mechanism::{Mechanism, MechanismType};
14use cryptoki::object::{Attribute, AttributeType, KeyType as CkKeyType, ObjectClass, ObjectHandle};
15use cryptoki::session::{Session, UserType};
16use cryptoki::slot::Slot;
17use cryptoki::types::AuthPin;
18use sha2::{Digest as _, Sha256};
19
20use super::{KeyId, KeySpec, KeyStore, KeyStoreCapabilities, KeyStoreError};
21use crate::jose::{Jwk, JwsAlgorithm, KeyType, normalize_ecdsa_signature};
22
23/// DER `OBJECT IDENTIFIER` 1.2.840.10045.3.1.7 (`prime256v1`), the `CKA_EC_PARAMS` of a P-256 key.
24const P256_PARAMS: &[u8] = &[0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07];
25/// DER `OBJECT IDENTIFIER` 1.3.132.0.10 (`secp256k1`).
26const SECP256K1_PARAMS: &[u8] = &[0x06, 0x05, 0x2b, 0x81, 0x04, 0x00, 0x0a];
27/// DER `OBJECT IDENTIFIER` 1.3.101.112 (`id-Ed25519`, RFC 8410), the `CKA_EC_PARAMS` this store
28/// writes for an Ed25519 key.
29const ED25519_PARAMS: &[u8] = &[0x06, 0x03, 0x2b, 0x65, 0x70];
30/// DER `PrintableString "edwards25519"`, the other `CKA_EC_PARAMS` form PKCS #11 v3.1 §2.3.3
31/// allows for Ed25519 and the one `pkcs11-tool` writes.
32const ED25519_NAME_PARAMS: &[u8] = b"\x13\x0cedwards25519";
33/// The label a key pair carries between its generation and its thumbprint being known.
34pub const STAGING_LABEL_PREFIX: &str = "identity-kit-staging-";
35/// The RSA public exponent of generated keys, 65537.
36const RSA_PUBLIC_EXPONENT: &[u8] = &[0x01, 0x00, 0x01];
37/// The DER `DigestInfo` prefix for SHA-256 (RFC 8017 §9.2, note 1): `CKM_RSA_PKCS` takes the
38/// whole `DigestInfo`, so the store builds it around the hash it computes.
39const SHA256_DIGEST_INFO_PREFIX: &[u8] = &[
40    0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05,
41    0x00, 0x04, 0x20,
42];
43
44/// Which token of a PKCS#11 module a [`Pkcs11KeyStore`] uses.
45///
46/// `&str`, `String` and `u64` convert into it.
47///
48/// # Examples
49///
50/// ```
51/// use identity_kit::keys::Pkcs11Token;
52///
53/// assert_eq!(Pkcs11Token::from("issuer"), Pkcs11Token::Label("issuer".to_owned()));
54/// assert_eq!(Pkcs11Token::from(2_108_653_770), Pkcs11Token::Slot(2_108_653_770));
55/// ```
56#[derive(Debug, Clone, PartialEq, Eq, Hash)]
57#[non_exhaustive]
58pub enum Pkcs11Token {
59    /// The token whose label (`CK_TOKEN_INFO.label`, as set when the token was initialized)
60    /// is this string. Trailing blanks are ignored on both sides.
61    Label(String),
62    /// The token in the slot with this id. Slot ids are assigned by the module; SoftHSM2
63    /// assigns a new one whenever a token is initialized, so a label is usually the better
64    /// choice.
65    Slot(u64),
66}
67
68impl From<&str> for Pkcs11Token {
69    fn from(label: &str) -> Self {
70        Self::Label(label.to_owned())
71    }
72}
73
74impl From<String> for Pkcs11Token {
75    fn from(label: String) -> Self {
76        Self::Label(label)
77    }
78}
79
80impl From<u64> for Pkcs11Token {
81    fn from(slot: u64) -> Self {
82        Self::Slot(slot)
83    }
84}
85
86impl fmt::Display for Pkcs11Token {
87    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
88        match self {
89            Self::Label(label) => write!(f, "token `{label}`"),
90            Self::Slot(slot) => write!(f, "slot {slot}"),
91        }
92    }
93}
94
95/// How a [`Pkcs11KeyStore`] uses its token.
96///
97/// # Examples
98///
99/// ```
100/// use identity_kit::jose::JwsAlgorithm;
101/// use identity_kit::keys::Pkcs11KeyStoreOptions;
102///
103/// let options = Pkcs11KeyStoreOptions::new()
104///     .sessions(2)
105///     .rsa_algorithm(JwsAlgorithm::PS256)
106///     .algorithms([JwsAlgorithm::ES256, JwsAlgorithm::PS256]);
107/// assert_eq!(options.sessions, 2);
108/// assert_eq!(options.rsa_algorithm, JwsAlgorithm::PS256);
109/// assert_eq!(
110///     options.algorithms,
111///     Some(vec![JwsAlgorithm::ES256, JwsAlgorithm::PS256])
112/// );
113/// ```
114#[derive(Debug, Clone, PartialEq, Eq)]
115#[non_exhaustive]
116pub struct Pkcs11KeyStoreOptions {
117    /// How many sessions the store keeps open at most, `4` by default.
118    ///
119    /// Sessions are opened as needed, logged in and reused; an operation waits for a session
120    /// when all of them are in use. At least `1`.
121    pub sessions: usize,
122    /// The algorithm RSA keys sign with, `RS256` by default: `RS256` (`CKM_RSA_PKCS`) or
123    /// `PS256` (`CKM_RSA_PKCS_PSS`).
124    ///
125    /// A PKCS#11 RSA key does not record which padding it is for, and a key signs with one
126    /// algorithm only, so the store settles it for all RSA keys of the token: the public JWK
127    /// of every RSA key carries this `alg`, `sign` accepts only this algorithm for an RSA key
128    /// and `generate` makes RSA keys for it.
129    pub rsa_algorithm: JwsAlgorithm,
130    /// The algorithms the store offers, out of those the module signs with; `None` for all of
131    /// them.
132    ///
133    /// The store derives what it can sign with from the module's mechanism list (see
134    /// [`Pkcs11KeyStore`]); this narrows that list, for a module whose `CKM_ECDSA` cannot take
135    /// secp256k1 for instance. Algorithms the module does not sign with are left out.
136    pub algorithms: Option<Vec<JwsAlgorithm>>,
137}
138
139impl Default for Pkcs11KeyStoreOptions {
140    fn default() -> Self {
141        Self {
142            sessions: 4,
143            rsa_algorithm: JwsAlgorithm::RS256,
144            algorithms: None,
145        }
146    }
147}
148
149impl Pkcs11KeyStoreOptions {
150    /// The defaults: four sessions, `RS256` for RSA keys, every algorithm the module signs with.
151    pub fn new() -> Self {
152        Self::default()
153    }
154
155    /// Sets [`sessions`](Self::sessions).
156    #[must_use]
157    pub fn sessions(mut self, sessions: usize) -> Self {
158        self.sessions = sessions;
159        self
160    }
161
162    /// Sets [`rsa_algorithm`](Self::rsa_algorithm).
163    #[must_use]
164    pub fn rsa_algorithm(mut self, alg: JwsAlgorithm) -> Self {
165        self.rsa_algorithm = alg;
166        self
167    }
168
169    /// Sets [`algorithms`](Self::algorithms).
170    #[must_use]
171    pub fn algorithms(mut self, algorithms: impl IntoIterator<Item = JwsAlgorithm>) -> Self {
172        self.algorithms = Some(algorithms.into_iter().collect());
173        self
174    }
175}
176
177/// What went wrong with the PKCS#11 module, carried as [`KeyStoreError::Backend`].
178#[derive(Debug, thiserror::Error)]
179#[non_exhaustive]
180pub enum Pkcs11Error {
181    /// The module could not be loaded or initialized.
182    #[error("PKCS#11 module `{}`: {source}", module.display())]
183    Module {
184        /// The module's path.
185        module: PathBuf,
186        /// What the module reported.
187        #[source]
188        source: CryptokiError,
189    },
190    /// No slot of the module holds the requested token.
191    #[error("PKCS#11 module has no {0}")]
192    TokenNotFound(Pkcs11Token),
193    /// An option is not usable.
194    #[error("PKCS#11 key store options: {0}")]
195    InvalidOptions(String),
196    /// A PKCS#11 function failed.
197    #[error("PKCS#11 {function} failed: {source}")]
198    Call {
199        /// The operation, as `C_...` names it.
200        function: &'static str,
201        /// What the module reported.
202        #[source]
203        source: CryptokiError,
204    },
205    /// The module returned a signature of another length than the algorithm's JWS form has.
206    #[error("PKCS#11 module returned a {actual}-byte signature for {alg}, expected {expected}")]
207    SignatureLength {
208        /// The algorithm.
209        alg: JwsAlgorithm,
210        /// The length the JWS form has.
211        expected: usize,
212        /// The length the module returned.
213        actual: usize,
214    },
215}
216
217impl Pkcs11Error {
218    /// Wraps the error of the PKCS#11 function `function` as [`KeyStoreError::Backend`].
219    fn call(function: &'static str) -> impl FnOnce(CryptokiError) -> KeyStoreError {
220        move |source| KeyStoreError::backend(Self::Call { function, source })
221    }
222
223    /// Whether the session the error came from is unusable from now on.
224    fn closes_session(&self) -> bool {
225        matches!(
226            self,
227            Self::Call {
228                source: CryptokiError::Pkcs11(
229                    RvError::SessionHandleInvalid
230                        | RvError::SessionClosed
231                        | RvError::DeviceRemoved
232                        | RvError::DeviceError
233                        | RvError::TokenNotPresent,
234                    _
235                ),
236                ..
237            }
238        )
239    }
240}
241
242/// A [`KeyStore`] over a token of a PKCS#11 module: an HSM, a smart card or a software token
243/// such as SoftHSM2.
244///
245/// The key id is the object label (`CKA_LABEL`): a key is the private key object and the
246/// public key object that share a label. Keys are referenced by label, so a label must name one
247/// key; the store refuses a label that names several.
248///
249/// Signing happens in the module. The store hashes in-process and signs the hash with
250/// `CKM_ECDSA` (ES256, ES256K), `CKM_RSA_PKCS` over a SHA-256 `DigestInfo` (RS256) or
251/// `CKM_RSA_PKCS_PSS` with SHA-256, MGF1-SHA-256 and a 32-byte salt (PS256); EdDSA signs the
252/// message itself with `CKM_EDDSA`. ECDSA signatures come back as raw `r || s`, the JWS form.
253///
254/// What the store signs with is read from the module's mechanism list when it is opened:
255/// `EdDSA` when the module has `CKM_EDDSA`, `ES256` and (feature `secp256k1`) `ES256K` when it
256/// has `CKM_ECDSA`, and [`rsa_algorithm`](Pkcs11KeyStoreOptions::rsa_algorithm) when it has the
257/// matching RSA mechanism. [`Pkcs11KeyStoreOptions::algorithms`] narrows the list. The store
258/// generates and deletes keys unless the token is write-protected; a generated key is an
259/// Ed25519, P-256, secp256k1 or RSA (65537) key pair stored on the token, the private key
260/// sensitive and not extractable. The key id of a generated key is the spec's label when set
261/// and the RFC 7638 thumbprint of the public key otherwise; such a key is generated under a
262/// label starting with [`STAGING_LABEL_PREFIX`] and relabelled once its thumbprint is known,
263/// so a generation interrupted in between leaves a key with that prefix on the token, to be
264/// removed with the module's tools.
265///
266/// The module's functions block, so every operation runs on `tokio`'s blocking thread pool;
267/// the store needs a `tokio` runtime. It keeps a pool of logged-in sessions
268/// ([`Pkcs11KeyStoreOptions::sessions`]) and an operation that finds all of them busy waits
269/// for one. A module is loaded and initialized when the first store on it is opened, shared
270/// by every later store on the same path, and never finalized or unloaded before the process
271/// ends. The PIN is kept in memory for logging in
272/// new sessions and zeroized when the store is dropped.
273///
274/// # Examples
275///
276/// ```no_run
277/// # tokio::runtime::Builder::new_current_thread().build()?.block_on(async {
278/// use identity_kit::jose::{JwsAlgorithm, KeyType};
279/// use identity_kit::keys::{KeySpec, KeyStore, Pkcs11KeyStore};
280///
281/// let store = Pkcs11KeyStore::open("/usr/lib/softhsm/libsofthsm2.so", "issuer", Some("1234"))?;
282/// let key = store
283///     .generate(KeySpec::new(KeyType::P256, JwsAlgorithm::ES256).with_label("issuer-2026"))
284///     .await?;
285/// let signature = store.sign(&key, JwsAlgorithm::ES256, b"payload").await?;
286/// assert_eq!(signature.len(), 64);
287/// # Ok::<(), Box<dyn std::error::Error>>(())
288/// # })?;
289/// # Ok::<(), Box<dyn std::error::Error>>(())
290/// ```
291#[derive(Clone)]
292pub struct Pkcs11KeyStore {
293    inner: Arc<Inner>,
294}
295
296/// The state behind the `Arc`, so that blocking tasks can own a reference to it.
297struct Inner {
298    module: PathBuf,
299    context: Pkcs11,
300    slot: Slot,
301    token_label: String,
302    pin: Option<AuthPin>,
303    options: Pkcs11KeyStoreOptions,
304    /// The algorithms the store signs with.
305    algorithms: Vec<JwsAlgorithm>,
306    /// The key pair generation mechanisms the module has.
307    key_pair_generation: Vec<MechanismType>,
308    write_protected: bool,
309    pool: Pool,
310    /// Held while this store generates or deletes a key; see [`TOKEN_WRITES`].
311    writes: Arc<Mutex<()>>,
312}
313
314/// The logged-in sessions.
315struct Pool {
316    state: Mutex<PoolState>,
317    /// Signalled when a session is returned or given up.
318    available: Condvar,
319    /// The most sessions open at once.
320    max: usize,
321}
322
323#[derive(Default)]
324struct PoolState {
325    idle: Vec<Session>,
326    /// Sessions open, idle or in use.
327    open: usize,
328}
329
330impl Pkcs11KeyStore {
331    /// Opens `token` of the PKCS#11 module at `module` with the default options.
332    ///
333    /// Loads the module, initializes it if needed, finds the token, reads its mechanism list and
334    /// opens one session, logging in as the user with `pin` when given. A token that needs no
335    /// login, or one with a protected authentication path, is opened with `None`. This blocks
336    /// while it talks to the module.
337    ///
338    /// PKCS#11 logs the application in, not the session: when the process is logged in to the
339    /// token already (through another store, say), the module reports that instead of checking
340    /// `pin`, and a wrong PIN goes unnoticed until the process logs out.
341    ///
342    /// # Errors
343    ///
344    /// [`KeyStoreError::Backend`] carrying a [`Pkcs11Error`]: the module does not load, the token
345    /// is not there, the PIN is wrong, or the options are not usable.
346    pub fn open(
347        module: impl AsRef<Path>,
348        token: impl Into<Pkcs11Token>,
349        pin: Option<&str>,
350    ) -> Result<Self, KeyStoreError> {
351        Self::open_with(module, token, pin, Pkcs11KeyStoreOptions::default())
352    }
353
354    /// Opens `token` of the PKCS#11 module at `module` as `options` say.
355    ///
356    /// # Errors
357    ///
358    /// As [`Pkcs11KeyStore::open`].
359    pub fn open_with(
360        module: impl AsRef<Path>,
361        token: impl Into<Pkcs11Token>,
362        pin: Option<&str>,
363        options: Pkcs11KeyStoreOptions,
364    ) -> Result<Self, KeyStoreError> {
365        let module = module.as_ref().to_path_buf();
366        let token = token.into();
367        if options.sessions == 0 {
368            return Err(invalid_options("`sessions` must be at least 1"));
369        }
370        if !matches!(
371            options.rsa_algorithm,
372            JwsAlgorithm::RS256 | JwsAlgorithm::PS256
373        ) {
374            return Err(invalid_options(format!(
375                "`rsa_algorithm` must be RS256 or PS256, not {}",
376                options.rsa_algorithm
377            )));
378        }
379
380        let context = load_module(&module)?;
381
382        let (slot, token_label, write_protected) = find_token(&context, &token)?;
383        let mechanisms = context
384            .get_mechanism_list(slot)
385            .map_err(Pkcs11Error::call("C_GetMechanismList"))?;
386        let mut algorithms = Vec::new();
387        if mechanisms.contains(&MechanismType::EDDSA) {
388            algorithms.push(JwsAlgorithm::EdDSA);
389        }
390        if mechanisms.contains(&MechanismType::ECDSA) {
391            algorithms.push(JwsAlgorithm::ES256);
392            #[cfg(feature = "secp256k1")]
393            algorithms.push(JwsAlgorithm::ES256K);
394        }
395        let rsa_mechanism = match options.rsa_algorithm {
396            JwsAlgorithm::PS256 => MechanismType::RSA_PKCS_PSS,
397            _ => MechanismType::RSA_PKCS,
398        };
399        if mechanisms.contains(&rsa_mechanism) {
400            algorithms.push(options.rsa_algorithm);
401        }
402        if let Some(wanted) = &options.algorithms {
403            algorithms.retain(|alg| wanted.contains(alg));
404        }
405        let key_pair_generation = [
406            MechanismType::ECC_EDWARDS_KEY_PAIR_GEN,
407            MechanismType::ECC_KEY_PAIR_GEN,
408            MechanismType::RSA_PKCS_KEY_PAIR_GEN,
409        ]
410        .into_iter()
411        .filter(|mechanism| mechanisms.contains(mechanism))
412        .collect();
413
414        let writes = token_writes(&module, slot.id());
415        let inner = Inner {
416            writes,
417            module,
418            context,
419            slot,
420            token_label,
421            pin: pin.map(|pin| AuthPin::from(pin.to_owned())),
422            pool: Pool {
423                state: Mutex::new(PoolState::default()),
424                available: Condvar::new(),
425                max: options.sessions,
426            },
427            options,
428            algorithms,
429            key_pair_generation,
430            write_protected,
431        };
432        // Open and log in one session now, so that a wrong PIN fails here and not on first use.
433        let session = inner.open_session()?;
434        inner.pool.release(session);
435        Ok(Self {
436            inner: Arc::new(inner),
437        })
438    }
439
440    /// The module's path.
441    pub fn module(&self) -> &Path {
442        &self.inner.module
443    }
444
445    /// The id of the slot the token is in.
446    pub fn slot(&self) -> u64 {
447        self.inner.slot.id()
448    }
449
450    /// The token's label.
451    pub fn token_label(&self) -> &str {
452        &self.inner.token_label
453    }
454
455    /// The options the store was opened with.
456    pub fn options(&self) -> &Pkcs11KeyStoreOptions {
457        &self.inner.options
458    }
459
460    /// Runs `f` on the blocking pool with a reference to the store's state.
461    async fn blocking<T, F>(&self, f: F) -> Result<T, KeyStoreError>
462    where
463        T: Send + 'static,
464        F: FnOnce(&Inner) -> Result<T, KeyStoreError> + Send + 'static,
465    {
466        let inner = Arc::clone(&self.inner);
467        match tokio::task::spawn_blocking(move || f(&inner)).await {
468            Ok(result) => result,
469            Err(e) if e.is_panic() => std::panic::resume_unwind(e.into_panic()),
470            Err(e) => Err(KeyStoreError::backend(e)),
471        }
472    }
473}
474
475impl fmt::Debug for Pkcs11KeyStore {
476    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
477        f.debug_struct("Pkcs11KeyStore")
478            .field("module", &self.inner.module)
479            .field("slot", &self.inner.slot.id())
480            .field("token_label", &self.inner.token_label)
481            .field("algorithms", &self.inner.algorithms)
482            .field("options", &self.inner.options)
483            .finish_non_exhaustive()
484    }
485}
486
487#[async_trait::async_trait]
488impl KeyStore for Pkcs11KeyStore {
489    fn capabilities(&self) -> KeyStoreCapabilities {
490        let capabilities =
491            KeyStoreCapabilities::new(self.inner.algorithms.iter().copied()).remote();
492        if self.inner.write_protected {
493            capabilities
494        } else {
495            capabilities.with_generate().with_delete()
496        }
497    }
498
499    async fn public_jwk(&self, key: &KeyId) -> Result<Jwk, KeyStoreError> {
500        let key = key.clone();
501        self.blocking(move |inner| inner.with_session(|session| inner.public_jwk(session, &key)))
502            .await
503    }
504
505    async fn sign(
506        &self,
507        key: &KeyId,
508        alg: JwsAlgorithm,
509        data: &[u8],
510    ) -> Result<Vec<u8>, KeyStoreError> {
511        let key = key.clone();
512        let data = data.to_vec();
513        self.blocking(move |inner| {
514            inner.with_session(|session| inner.sign(session, &key, alg, &data))
515        })
516        .await
517    }
518
519    async fn exists(&self, key: &KeyId) -> Result<bool, KeyStoreError> {
520        let key = key.clone();
521        self.blocking(move |inner| {
522            inner.with_session(|session| {
523                Ok(find_key(session, ObjectClass::PRIVATE_KEY, &key)?.is_some())
524            })
525        })
526        .await
527    }
528
529    async fn generate(&self, spec: KeySpec) -> Result<KeyId, KeyStoreError> {
530        if self.inner.write_protected {
531            return Err(KeyStoreError::Unsupported("generate"));
532        }
533        self.blocking(move |inner| {
534            let _writing = inner.writes.lock().unwrap_or_else(PoisonError::into_inner);
535            inner.with_session(|session| inner.generate(session, &spec))
536        })
537        .await
538    }
539
540    async fn delete(&self, key: &KeyId) -> Result<(), KeyStoreError> {
541        if self.inner.write_protected {
542            return Err(KeyStoreError::Unsupported("delete"));
543        }
544        let key = key.clone();
545        self.blocking(move |inner| {
546            let _writing = inner.writes.lock().unwrap_or_else(PoisonError::into_inner);
547            inner.with_session(|session| delete(session, &key))
548        })
549        .await
550    }
551}
552
553impl Inner {
554    /// Opens a session on the token and logs in when the store has a PIN.
555    ///
556    /// A write-protected token refuses read/write sessions (`CKR_TOKEN_WRITE_PROTECTED`), and
557    /// signing needs none, so such a token gets read-only sessions.
558    fn open_session(&self) -> Result<Session, KeyStoreError> {
559        let session = if self.write_protected {
560            self.context.open_ro_session(self.slot)
561        } else {
562            self.context.open_rw_session(self.slot)
563        }
564        .map_err(Pkcs11Error::call("C_OpenSession"))?;
565        if let Some(pin) = &self.pin {
566            match session.login(UserType::User, Some(pin)) {
567                // The login state is the application's, not the session's: once one session
568                // of this process is logged in, so are the others.
569                Ok(()) | Err(CryptokiError::Pkcs11(RvError::UserAlreadyLoggedIn, _)) => {}
570                Err(source) => return Err(Pkcs11Error::call("C_Login")(source)),
571            }
572        }
573        Ok(session)
574    }
575
576    /// Runs `f` with a session from the pool, opening one if none is idle and fewer than the
577    /// maximum are open, and waiting otherwise. A session an error made unusable is dropped
578    /// instead of returned.
579    fn with_session<T>(
580        &self,
581        f: impl FnOnce(&Session) -> Result<T, KeyStoreError>,
582    ) -> Result<T, KeyStoreError> {
583        let session = self.pool.acquire(|| self.open_session())?;
584        let result = f(&session);
585        let dead = matches!(
586            &result,
587            Err(KeyStoreError::Backend(e))
588                if e.downcast_ref::<Pkcs11Error>().is_some_and(Pkcs11Error::closes_session)
589        );
590        if dead {
591            self.pool.discard(session);
592        } else {
593            self.pool.release(session);
594        }
595        result
596    }
597
598    /// The algorithm a key of `kind` signs with.
599    fn algorithm_of(&self, kind: KeyKind) -> JwsAlgorithm {
600        match kind {
601            KeyKind::Ed25519 => JwsAlgorithm::EdDSA,
602            KeyKind::P256 => JwsAlgorithm::ES256,
603            KeyKind::Secp256k1 => JwsAlgorithm::ES256K,
604            KeyKind::Rsa => self.options.rsa_algorithm,
605        }
606    }
607
608    /// [`KeyStore::public_jwk`] on `session`.
609    fn public_jwk(&self, session: &Session, key: &KeyId) -> Result<Jwk, KeyStoreError> {
610        let Some(public) = find_key(session, ObjectClass::PUBLIC_KEY, key)? else {
611            return Err(
612                if find_key(session, ObjectClass::PRIVATE_KEY, key)?.is_some() {
613                    KeyStoreError::InvalidKey {
614                        key: key.clone(),
615                        reason: "the token has no public key object with this label".to_owned(),
616                    }
617                } else {
618                    KeyStoreError::NotFound(key.clone())
619                },
620            );
621        };
622        self.public_jwk_of(session, key, public)
623    }
624
625    /// The public JWK of the public key object `public`, with `kid` and `alg` set.
626    fn public_jwk_of(
627        &self,
628        session: &Session,
629        key: &KeyId,
630        public: ObjectHandle,
631    ) -> Result<Jwk, KeyStoreError> {
632        let kind = key_kind(session, key, public)?;
633        let invalid = |reason: String| KeyStoreError::InvalidKey {
634            key: key.clone(),
635            reason,
636        };
637        let jwk = match kind {
638            KeyKind::Rsa => {
639                let attributes = session
640                    .get_attributes(
641                        public,
642                        &[AttributeType::Modulus, AttributeType::PublicExponent],
643                    )
644                    .map_err(Pkcs11Error::call("C_GetAttributeValue"))?;
645                let mut modulus = None;
646                let mut exponent = None;
647                for attribute in attributes {
648                    match attribute {
649                        Attribute::Modulus(n) => modulus = Some(n),
650                        Attribute::PublicExponent(e) => exponent = Some(e),
651                        _ => {}
652                    }
653                }
654                let (Some(n), Some(e)) = (modulus, exponent) else {
655                    return Err(invalid(
656                        "the public key object has no modulus or public exponent".to_owned(),
657                    ));
658                };
659                Jwk::from_rsa_public(&n, &e).map_err(|e| invalid(e.to_string()))?
660            }
661            KeyKind::Ed25519 | KeyKind::P256 | KeyKind::Secp256k1 => {
662                let point = ec_point(session, key, public, kind)?;
663                match kind {
664                    KeyKind::Ed25519 => {
665                        Jwk::from_ed25519_public(&point).map_err(|e| invalid(e.to_string()))?
666                    }
667                    KeyKind::P256 => {
668                        Jwk::from_p256_public(&point).map_err(|e| invalid(e.to_string()))?
669                    }
670                    #[cfg(feature = "secp256k1")]
671                    KeyKind::Secp256k1 => {
672                        Jwk::from_secp256k1_public(&point).map_err(|e| invalid(e.to_string()))?
673                    }
674                    #[cfg(not(feature = "secp256k1"))]
675                    KeyKind::Secp256k1 => {
676                        return Err(invalid(
677                            "secp256k1 keys need the `secp256k1` feature".to_owned(),
678                        ));
679                    }
680                    KeyKind::Rsa => unreachable!("matched above"),
681                }
682            }
683        };
684        Ok(jwk
685            .with_kid(key.as_str())
686            .with_alg(self.algorithm_of(kind).as_str()))
687    }
688
689    /// [`KeyStore::sign`] on `session`.
690    fn sign(
691        &self,
692        session: &Session,
693        key: &KeyId,
694        alg: JwsAlgorithm,
695        data: &[u8],
696    ) -> Result<Vec<u8>, KeyStoreError> {
697        let private = find_key(session, ObjectClass::PRIVATE_KEY, key)?
698            .ok_or_else(|| KeyStoreError::NotFound(key.clone()))?;
699        let kind = key_kind(session, key, private)?;
700        let key_alg = self.algorithm_of(kind);
701        if alg != key_alg {
702            return Err(KeyStoreError::AlgorithmMismatch {
703                key: key.clone(),
704                key_alg,
705                requested: alg,
706            });
707        }
708        if !self.algorithms.contains(&alg) {
709            return Err(KeyStoreError::UnsupportedAlgorithm(alg));
710        }
711        let signature = match kind {
712            KeyKind::Ed25519 => session
713                .sign(
714                    &Mechanism::Eddsa(EddsaParams::new(EddsaSignatureScheme::Pure)),
715                    private,
716                    data,
717                )
718                .map_err(Pkcs11Error::call("C_Sign"))?,
719            KeyKind::P256 => session
720                .sign(&Mechanism::Ecdsa, private, &Sha256::digest(data))
721                .map_err(Pkcs11Error::call("C_Sign"))?,
722            KeyKind::Secp256k1 => {
723                let signature = session
724                    .sign(&Mechanism::Ecdsa, private, &Sha256::digest(data))
725                    .map_err(Pkcs11Error::call("C_Sign"))?;
726                // A module may return either of the two equivalent `s` values; `k256`, like
727                // Bitcoin, accepts only the lower one. A signature that cannot be normalized is
728                // returned as is, for the length check that follows.
729                normalize_ecdsa_signature(alg, &signature).unwrap_or(signature)
730            }
731            KeyKind::Rsa if alg == JwsAlgorithm::PS256 => {
732                let params = PkcsPssParams {
733                    hash_alg: MechanismType::SHA256,
734                    mgf: PkcsMgfType::MGF1_SHA256,
735                    s_len: 32.into(),
736                };
737                session
738                    .sign(
739                        &Mechanism::RsaPkcsPss(params),
740                        private,
741                        &Sha256::digest(data),
742                    )
743                    .map_err(Pkcs11Error::call("C_Sign"))?
744            }
745            KeyKind::Rsa => {
746                let mut digest_info = SHA256_DIGEST_INFO_PREFIX.to_vec();
747                digest_info.extend_from_slice(&Sha256::digest(data));
748                session
749                    .sign(&Mechanism::RsaPkcs, private, &digest_info)
750                    .map_err(Pkcs11Error::call("C_Sign"))?
751            }
752        };
753        if let Some(expected) = match kind {
754            KeyKind::Ed25519 | KeyKind::P256 | KeyKind::Secp256k1 => Some(64),
755            KeyKind::Rsa => None,
756        } && signature.len() != expected
757        {
758            return Err(KeyStoreError::backend(Pkcs11Error::SignatureLength {
759                alg,
760                expected,
761                actual: signature.len(),
762            }));
763        }
764        Ok(signature)
765    }
766
767    /// [`KeyStore::generate`] on `session`.
768    fn generate(&self, session: &Session, spec: &KeySpec) -> Result<KeyId, KeyStoreError> {
769        spec.validate()?;
770        if !self.algorithms.contains(&spec.alg) {
771            return Err(KeyStoreError::UnsupportedAlgorithm(spec.alg));
772        }
773        let (mechanism, generation, mut public_template) = match spec.key_type {
774            KeyType::Ed25519 => (
775                Mechanism::EccEdwardsKeyPairGen,
776                MechanismType::ECC_EDWARDS_KEY_PAIR_GEN,
777                vec![
778                    Attribute::KeyType(CkKeyType::EC_EDWARDS),
779                    Attribute::EcParams(ED25519_PARAMS.to_vec()),
780                ],
781            ),
782            KeyType::P256 => (
783                Mechanism::EccKeyPairGen,
784                MechanismType::ECC_KEY_PAIR_GEN,
785                vec![
786                    Attribute::KeyType(CkKeyType::EC),
787                    Attribute::EcParams(P256_PARAMS.to_vec()),
788                ],
789            ),
790            KeyType::Secp256k1 => (
791                Mechanism::EccKeyPairGen,
792                MechanismType::ECC_KEY_PAIR_GEN,
793                vec![
794                    Attribute::KeyType(CkKeyType::EC),
795                    Attribute::EcParams(SECP256K1_PARAMS.to_vec()),
796                ],
797            ),
798            KeyType::Rsa2048 | KeyType::Rsa4096 => {
799                let bits: cryptoki::types::Ulong = match spec.key_type {
800                    KeyType::Rsa4096 => 4096.into(),
801                    _ => 2048.into(),
802                };
803                (
804                    Mechanism::RsaPkcsKeyPairGen,
805                    MechanismType::RSA_PKCS_KEY_PAIR_GEN,
806                    vec![
807                        Attribute::KeyType(CkKeyType::RSA),
808                        Attribute::ModulusBits(bits),
809                        Attribute::PublicExponent(RSA_PUBLIC_EXPONENT.to_vec()),
810                    ],
811                )
812            }
813        };
814        if !self.key_pair_generation.contains(&generation) {
815            return Err(KeyStoreError::UnsupportedKeyType(spec.key_type));
816        }
817        public_template.extend([
818            Attribute::Token(true),
819            Attribute::Private(false),
820            Attribute::Verify(true),
821        ]);
822        let mut private_template = vec![
823            Attribute::Token(true),
824            Attribute::Private(true),
825            Attribute::Sensitive(true),
826            Attribute::Extractable(false),
827            Attribute::Sign(true),
828        ];
829        if let Some(label) = &spec.label {
830            let id = KeyId::new(label.as_str());
831            if find_key(session, ObjectClass::PRIVATE_KEY, &id)?.is_some()
832                || find_key(session, ObjectClass::PUBLIC_KEY, &id)?.is_some()
833            {
834                return Err(KeyStoreError::AlreadyExists(id));
835            }
836            public_template.extend(label_attributes(label));
837            private_template.extend(label_attributes(label));
838        } else {
839            // The key id will be the thumbprint, known only once the key exists; until then
840            // the objects carry a staging label, so that a key left behind by an interrupted
841            // generation can be recognized and removed.
842            let staging = staging_label();
843            public_template.extend(label_attributes(&staging));
844            private_template.extend(label_attributes(&staging));
845        }
846
847        let (public, private) = session
848            .generate_key_pair(&mechanism, &public_template, &private_template)
849            .map_err(Pkcs11Error::call("C_GenerateKeyPair"))?;
850        if let Some(label) = &spec.label {
851            return Ok(KeyId::new(label.as_str()));
852        }
853        // No label: the key id is the thumbprint of the public key, so label both objects with
854        // it now that the key exists. A key that cannot be labelled is not kept.
855        let labelled = self
856            .public_jwk_of(session, &KeyId::new(""), public)
857            .and_then(|jwk| {
858                jwk.thumbprint_sha256()
859                    .map_err(|e| KeyStoreError::InvalidKey {
860                        key: KeyId::new(""),
861                        reason: e.to_string(),
862                    })
863            })
864            .and_then(|thumbprint| {
865                let attributes = label_attributes(&thumbprint);
866                session
867                    .update_attributes(public, &attributes)
868                    .and_then(|()| session.update_attributes(private, &attributes))
869                    .map_err(Pkcs11Error::call("C_SetAttributeValue"))?;
870                Ok(KeyId::new(thumbprint))
871            });
872        if labelled.is_err() {
873            // Best effort: the error being returned is the one that matters.
874            let _ = session.destroy_object(private);
875            let _ = session.destroy_object(public);
876        }
877        labelled
878    }
879}
880
881impl Pool {
882    /// A session from the pool: an idle one, else a new one from `open` while fewer than the
883    /// maximum are open, else the next one returned.
884    fn acquire(
885        &self,
886        open: impl FnOnce() -> Result<Session, KeyStoreError>,
887    ) -> Result<Session, KeyStoreError> {
888        let mut state = self.lock();
889        loop {
890            if let Some(session) = state.idle.pop() {
891                return Ok(session);
892            }
893            if state.open < self.max {
894                state.open += 1;
895                drop(state);
896                return open().inspect_err(|_| {
897                    self.lock().open -= 1;
898                    self.available.notify_one();
899                });
900            }
901            state = self
902                .available
903                .wait(state)
904                .unwrap_or_else(PoisonError::into_inner);
905        }
906    }
907
908    /// Returns a usable session to the pool.
909    fn release(&self, session: Session) {
910        self.lock().idle.push(session);
911        self.available.notify_one();
912    }
913
914    /// Drops an unusable session, making room for a new one.
915    fn discard(&self, session: Session) {
916        drop(session);
917        self.lock().open -= 1;
918        self.available.notify_one();
919    }
920
921    /// The pool's state, poison or not.
922    fn lock(&self) -> MutexGuard<'_, PoolState> {
923        self.state.lock().unwrap_or_else(PoisonError::into_inner)
924    }
925}
926
927/// The modules loaded so far, by canonical path, each initialized once.
928///
929/// A PKCS#11 library must be initialized once per process, and unloading one that is still
930/// initialized is unsafe, so a loaded module stays loaded and initialized until the process
931/// ends; a store on a module loaded already shares the context.
932static MODULES: Mutex<Vec<(PathBuf, Pkcs11)>> = Mutex::new(Vec::new());
933
934/// One lock per token of the process, held while a key is generated or deleted.
935///
936/// Generation and deletion are provisioning, not the signing path, and serializing them
937/// process-wide costs nothing there; SoftHSM2's file object store fails
938/// (`CKR_GENERAL_ERROR`) when objects are created and destroyed from several sessions at
939/// once, which would otherwise make it unusable for tests that provision in parallel.
940static TOKEN_WRITES: Mutex<Vec<TokenWriteLock>> = Mutex::new(Vec::new());
941
942/// A token, as (canonical module path, slot id), and its write lock.
943type TokenWriteLock = ((PathBuf, u64), Arc<Mutex<()>>);
944
945/// The write lock of the token in `slot` of the module at `module` (canonical path).
946fn token_writes(module: &Path, slot: u64) -> Arc<Mutex<()>> {
947    let key = (
948        std::fs::canonicalize(module).unwrap_or_else(|_| module.to_path_buf()),
949        slot,
950    );
951    let mut locks = TOKEN_WRITES.lock().unwrap_or_else(PoisonError::into_inner);
952    if let Some((_, lock)) = locks.iter().find(|(k, _)| *k == key) {
953        return Arc::clone(lock);
954    }
955    let lock = Arc::new(Mutex::new(()));
956    locks.push((key, Arc::clone(&lock)));
957    lock
958}
959
960/// The initialized context for the module at `module`, loading it on first use.
961fn load_module(module: &Path) -> Result<Pkcs11, KeyStoreError> {
962    let key = std::fs::canonicalize(module).unwrap_or_else(|_| module.to_path_buf());
963    let mut modules = MODULES.lock().unwrap_or_else(PoisonError::into_inner);
964    if let Some((_, context)) = modules.iter().find(|(path, _)| *path == key) {
965        return Ok(context.clone());
966    }
967    let failed = |source| {
968        KeyStoreError::backend(Pkcs11Error::Module {
969            module: module.to_path_buf(),
970            source,
971        })
972    };
973    let context = Pkcs11::new(module).map_err(failed)?;
974    // The application itself may have initialized the module through another handle.
975    match context.initialize(CInitializeArgs::new(CInitializeFlags::OS_LOCKING_OK)) {
976        Ok(()) | Err(CryptokiError::Pkcs11(RvError::CryptokiAlreadyInitialized, _)) => {}
977        Err(source) => return Err(failed(source)),
978    }
979    modules.push((key, context.clone()));
980    Ok(context)
981}
982
983/// The kinds of key the store signs with.
984#[derive(Debug, Clone, Copy, PartialEq, Eq)]
985enum KeyKind {
986    Ed25519,
987    P256,
988    Secp256k1,
989    Rsa,
990}
991
992/// Finds the slot holding `token`, with the token's label and whether it is write-protected.
993fn find_token(
994    context: &Pkcs11,
995    token: &Pkcs11Token,
996) -> Result<(Slot, String, bool), KeyStoreError> {
997    let not_found = || KeyStoreError::backend(Pkcs11Error::TokenNotFound(token.clone()));
998    let slots = context
999        .get_slots_with_token()
1000        .map_err(Pkcs11Error::call("C_GetSlotList"))?;
1001    for slot in slots {
1002        let matches = match token {
1003            Pkcs11Token::Slot(id) => slot.id() == *id,
1004            Pkcs11Token::Label(_) => true,
1005        };
1006        if !matches {
1007            continue;
1008        }
1009        let info = context
1010            .get_token_info(slot)
1011            .map_err(Pkcs11Error::call("C_GetTokenInfo"))?;
1012        let label = info.label().trim_end().to_owned();
1013        if let Pkcs11Token::Label(wanted) = token
1014            && label != wanted.trim_end()
1015        {
1016            continue;
1017        }
1018        return Ok((slot, label, info.write_protected()));
1019    }
1020    Err(not_found())
1021}
1022
1023/// The one object of `class` labelled `key`, if any.
1024fn find_key(
1025    session: &Session,
1026    class: ObjectClass,
1027    key: &KeyId,
1028) -> Result<Option<ObjectHandle>, KeyStoreError> {
1029    let template = [
1030        Attribute::Class(class),
1031        Attribute::Label(key.as_str().as_bytes().to_vec()),
1032    ];
1033    let objects = session
1034        .find_objects(&template)
1035        .map_err(Pkcs11Error::call("C_FindObjects"))?;
1036    match objects.as_slice() {
1037        [] => Ok(None),
1038        [object] => Ok(Some(*object)),
1039        several => Err(KeyStoreError::InvalidKey {
1040            key: key.clone(),
1041            reason: format!(
1042                "the label names {} objects of the same class",
1043                several.len()
1044            ),
1045        }),
1046    }
1047}
1048
1049/// Destroys the private and the public key object labelled `key`.
1050///
1051/// Both are attempted even when the first fails, so a failure leaves as little of the key on
1052/// the token as it can; the first error is returned.
1053fn delete(session: &Session, key: &KeyId) -> Result<(), KeyStoreError> {
1054    let private = find_key(session, ObjectClass::PRIVATE_KEY, key)?;
1055    let public = find_key(session, ObjectClass::PUBLIC_KEY, key)?;
1056    if private.is_none() && public.is_none() {
1057        return Err(KeyStoreError::NotFound(key.clone()));
1058    }
1059    let mut destroyed = Ok(());
1060    for object in [private, public].into_iter().flatten() {
1061        destroyed = destroyed.and(session.destroy_object(object));
1062    }
1063    destroyed.map_err(Pkcs11Error::call("C_DestroyObject"))
1064}
1065
1066/// A label for a key pair that is being generated without a label, unique within the process
1067/// and unlikely to repeat across processes.
1068fn staging_label() -> String {
1069    static COUNTER: AtomicU64 = AtomicU64::new(0);
1070    let nanos = std::time::SystemTime::now()
1071        .duration_since(std::time::UNIX_EPOCH)
1072        .map_or(0, |since| since.as_nanos() as u64);
1073    format!(
1074        "{STAGING_LABEL_PREFIX}{nanos:016x}-{:x}",
1075        COUNTER.fetch_add(1, Ordering::Relaxed)
1076    )
1077}
1078
1079/// `CKA_LABEL` and `CKA_ID`, both set to `label` so that tools pairing the objects of a key by
1080/// id (`pkcs11-tool`, for one) see one key.
1081fn label_attributes(label: &str) -> [Attribute; 2] {
1082    [
1083        Attribute::Label(label.as_bytes().to_vec()),
1084        Attribute::Id(label.as_bytes().to_vec()),
1085    ]
1086}
1087
1088/// What kind of key the object `object` is, from `CKA_KEY_TYPE` and `CKA_EC_PARAMS`.
1089fn key_kind(
1090    session: &Session,
1091    key: &KeyId,
1092    object: ObjectHandle,
1093) -> Result<KeyKind, KeyStoreError> {
1094    let attributes = session
1095        .get_attributes(object, &[AttributeType::KeyType, AttributeType::EcParams])
1096        .map_err(Pkcs11Error::call("C_GetAttributeValue"))?;
1097    let mut key_type = None;
1098    let mut params = None;
1099    for attribute in attributes {
1100        match attribute {
1101            Attribute::KeyType(t) => key_type = Some(t),
1102            Attribute::EcParams(p) => params = Some(p),
1103            _ => {}
1104        }
1105    }
1106    let invalid = |reason: &str| KeyStoreError::InvalidKey {
1107        key: key.clone(),
1108        reason: reason.to_owned(),
1109    };
1110    match key_type {
1111        Some(CkKeyType::RSA) => Ok(KeyKind::Rsa),
1112        Some(CkKeyType::EC) => match params.as_deref() {
1113            Some(P256_PARAMS) => Ok(KeyKind::P256),
1114            Some(SECP256K1_PARAMS) => Ok(KeyKind::Secp256k1),
1115            Some(_) => Err(invalid("the curve is not P-256 or secp256k1")),
1116            None => Err(invalid("the EC key has no CKA_EC_PARAMS")),
1117        },
1118        Some(CkKeyType::EC_EDWARDS) => match params.as_deref() {
1119            Some(ED25519_PARAMS | ED25519_NAME_PARAMS) => Ok(KeyKind::Ed25519),
1120            Some(_) => Err(invalid("the Edwards curve is not Ed25519")),
1121            None => Err(invalid("the Edwards key has no CKA_EC_PARAMS")),
1122        },
1123        Some(_) => Err(invalid("the key type is not RSA, EC or EC_EDWARDS")),
1124        None => Err(invalid("the object has no CKA_KEY_TYPE")),
1125    }
1126}
1127
1128/// The public point of the EC public key object `object`, a key of `kind`: the content of its
1129/// `CKA_EC_POINT`, a DER `OCTET STRING` holding the uncompressed SEC1 point (P-256, secp256k1)
1130/// or the 32-byte public key (Ed25519), or that content bare, as some modules store it.
1131fn ec_point(
1132    session: &Session,
1133    key: &KeyId,
1134    object: ObjectHandle,
1135    kind: KeyKind,
1136) -> Result<Vec<u8>, KeyStoreError> {
1137    let attributes = session
1138        .get_attributes(object, &[AttributeType::EcPoint])
1139        .map_err(Pkcs11Error::call("C_GetAttributeValue"))?;
1140    let invalid = |reason: &str| KeyStoreError::InvalidKey {
1141        key: key.clone(),
1142        reason: reason.to_owned(),
1143    };
1144    let Some(Attribute::EcPoint(encoded)) = attributes.into_iter().next() else {
1145        return Err(invalid("the public key object has no CKA_EC_POINT"));
1146    };
1147    ec_point_bytes(&encoded, kind)
1148        .map(<[u8]>::to_vec)
1149        .ok_or_else(|| invalid("CKA_EC_POINT is neither a DER OCTET STRING nor a bare point"))
1150}
1151
1152/// The point in a `CKA_EC_POINT` value: the content of the DER `OCTET STRING` the attribute
1153/// should be, or the value itself when it is not one but is a point of the size `kind` has.
1154///
1155/// A DER content of the right size wins, so that a bare value which happens to parse as DER
1156/// (a 32-byte key starting `04 1e`) is still read correctly whenever its content would not fit.
1157fn ec_point_bytes(encoded: &[u8], kind: KeyKind) -> Option<&[u8]> {
1158    let fits = |point: &[u8]| match kind {
1159        KeyKind::Ed25519 => point.len() == 32,
1160        KeyKind::P256 | KeyKind::Secp256k1 => point.len() == 65 && point[0] == 0x04,
1161        KeyKind::Rsa => false,
1162    };
1163    match der_octet_string(encoded) {
1164        Some(content) if fits(content) => Some(content),
1165        _ if fits(encoded) => Some(encoded),
1166        other => other,
1167    }
1168}
1169
1170/// The content of a DER `OCTET STRING` that spans exactly `der`.
1171fn der_octet_string(der: &[u8]) -> Option<&[u8]> {
1172    let (&0x04, rest) = der.split_first()? else {
1173        return None;
1174    };
1175    let (&first, rest) = rest.split_first()?;
1176    let (length, content) = if first < 0x80 {
1177        (usize::from(first), rest)
1178    } else {
1179        let length_bytes = usize::from(first & 0x7f);
1180        if length_bytes == 0 || length_bytes > 2 || rest.len() < length_bytes {
1181            return None;
1182        }
1183        let (length, content) = rest.split_at(length_bytes);
1184        let length = length
1185            .iter()
1186            .fold(0usize, |n, &b| (n << 8) | usize::from(b));
1187        // DER uses the shortest form: long form only from 128 up.
1188        if length < 0x80 {
1189            return None;
1190        }
1191        (length, content)
1192    };
1193    (content.len() == length).then_some(content)
1194}
1195
1196/// [`Pkcs11Error::InvalidOptions`] as a [`KeyStoreError`].
1197fn invalid_options(reason: impl Into<String>) -> KeyStoreError {
1198    KeyStoreError::backend(Pkcs11Error::InvalidOptions(reason.into()))
1199}
1200
1201// `Pkcs11Error` is what `Backend` carries, so it must be sendable between threads.
1202const _: () = {
1203    const fn assert_send_sync<T: Send + Sync + Error + 'static>() {}
1204    assert_send_sync::<Pkcs11Error>();
1205};
1206
1207#[cfg(test)]
1208mod tests {
1209    use super::*;
1210
1211    #[test]
1212    fn der_octet_strings_decode() {
1213        // Short form, as every EC point of this crate's curves uses.
1214        assert_eq!(
1215            der_octet_string(&[0x04, 0x02, 0xaa, 0xbb]),
1216            Some(&[0xaa, 0xbb][..])
1217        );
1218        assert_eq!(der_octet_string(&[0x04, 0x00]), Some(&[][..]));
1219        // Long form.
1220        let mut long = vec![0x04, 0x81, 0x80];
1221        long.extend(std::iter::repeat_n(7u8, 128));
1222        assert_eq!(der_octet_string(&long), Some(&long[3..]));
1223        let mut longer = vec![0x04, 0x82, 0x01, 0x00];
1224        longer.extend(std::iter::repeat_n(7u8, 256));
1225        assert_eq!(der_octet_string(&longer), Some(&longer[4..]));
1226
1227        // Not an OCTET STRING, truncated, trailing bytes, non-minimal length.
1228        assert_eq!(der_octet_string(&[0x03, 0x01, 0xaa]), None);
1229        assert_eq!(der_octet_string(&[0x04]), None);
1230        assert_eq!(der_octet_string(&[0x04, 0x03, 0xaa, 0xbb]), None);
1231        assert_eq!(der_octet_string(&[0x04, 0x01, 0xaa, 0xbb]), None);
1232        assert_eq!(der_octet_string(&[0x04, 0x81, 0x01, 0xaa]), None);
1233        assert_eq!(der_octet_string(&[0x04, 0x80]), None);
1234        assert_eq!(
1235            der_octet_string(&[0x04, 0x83, 0x00, 0x00, 0x01, 0xaa]),
1236            None
1237        );
1238        assert_eq!(der_octet_string(&[]), None);
1239    }
1240
1241    #[test]
1242    fn ec_points_are_read_wrapped_or_bare() {
1243        let ed25519 = [7u8; 32];
1244        let mut wrapped = vec![0x04, 0x20];
1245        wrapped.extend_from_slice(&ed25519);
1246        assert_eq!(
1247            ec_point_bytes(&wrapped, KeyKind::Ed25519),
1248            Some(&ed25519[..])
1249        );
1250        assert_eq!(
1251            ec_point_bytes(&ed25519, KeyKind::Ed25519),
1252            Some(&ed25519[..])
1253        );
1254        // A bare key that happens to parse as DER: its DER content is 30 bytes, which does
1255        // not fit, so the bare reading wins.
1256        let mut tricky = vec![0x04, 0x1e];
1257        tricky.extend_from_slice(&[9u8; 30]);
1258        assert_eq!(ec_point_bytes(&tricky, KeyKind::Ed25519), Some(&tricky[..]));
1259
1260        let mut sec1 = vec![0x04];
1261        sec1.extend_from_slice(&[1u8; 64]);
1262        let mut wrapped = vec![0x04, 0x41];
1263        wrapped.extend_from_slice(&sec1);
1264        for kind in [KeyKind::P256, KeyKind::Secp256k1] {
1265            assert_eq!(ec_point_bytes(&wrapped, kind), Some(&sec1[..]));
1266            assert_eq!(ec_point_bytes(&sec1, kind), Some(&sec1[..]));
1267            // The wrong size for the kind: the DER content is handed on for the key
1268            // constructor to refuse.
1269            assert_eq!(ec_point_bytes(&[0x04, 0x01, 0xaa], kind), Some(&[0xaa][..]));
1270        }
1271        // A compressed point is not accepted bare, and nothing that is not DER is.
1272        let mut compressed = vec![0x02];
1273        compressed.extend_from_slice(&[1u8; 64]);
1274        assert_eq!(ec_point_bytes(&compressed, KeyKind::P256), None);
1275        assert_eq!(ec_point_bytes(&[0x05, 0x01, 0xaa], KeyKind::P256), None);
1276        assert_eq!(ec_point_bytes(&ed25519, KeyKind::Rsa), None);
1277    }
1278
1279    #[test]
1280    fn staging_labels_are_distinct() {
1281        let a = staging_label();
1282        let b = staging_label();
1283        assert!(a.starts_with(STAGING_LABEL_PREFIX) && b.starts_with(STAGING_LABEL_PREFIX));
1284        assert_ne!(a, b);
1285        assert!(a.len() <= 64, "fits the usual label limits: {a}");
1286    }
1287
1288    #[test]
1289    fn the_digest_info_prefix_is_the_one_of_rfc_8017() {
1290        // RFC 8017 §9.2, note 1: SHA-256's DigestInfo is this prefix followed by the 32-byte hash.
1291        let mut digest_info = SHA256_DIGEST_INFO_PREFIX.to_vec();
1292        digest_info.extend_from_slice(&[0u8; 32]);
1293        assert_eq!(digest_info.len(), 51);
1294        assert_eq!(digest_info[1], 0x31, "SEQUENCE length covers the rest");
1295        assert_eq!(
1296            &digest_info[4..13],
1297            &[0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04]
1298        );
1299        assert_eq!(&digest_info[13..15], &[0x02, 0x01], "id-sha256");
1300        assert_eq!(
1301            &digest_info[17..19],
1302            &[0x04, 0x20],
1303            "OCTET STRING of 32 bytes"
1304        );
1305    }
1306
1307    #[test]
1308    fn tokens_convert_and_display() {
1309        assert_eq!(Pkcs11Token::from("a"), Pkcs11Token::Label("a".to_owned()));
1310        assert_eq!(
1311            Pkcs11Token::from("a".to_owned()),
1312            Pkcs11Token::Label("a".to_owned())
1313        );
1314        assert_eq!(Pkcs11Token::from(7), Pkcs11Token::Slot(7));
1315        assert_eq!(Pkcs11Token::from("a").to_string(), "token `a`");
1316        assert_eq!(Pkcs11Token::from(7).to_string(), "slot 7");
1317    }
1318
1319    #[test]
1320    fn options_default_and_build() {
1321        let options = Pkcs11KeyStoreOptions::new();
1322        assert_eq!(options, Pkcs11KeyStoreOptions::default());
1323        assert_eq!(options.sessions, 4);
1324        assert_eq!(options.rsa_algorithm, JwsAlgorithm::RS256);
1325        assert_eq!(options.algorithms, None);
1326        let options = options
1327            .sessions(1)
1328            .rsa_algorithm(JwsAlgorithm::PS256)
1329            .algorithms([JwsAlgorithm::EdDSA]);
1330        assert_eq!(options.sessions, 1);
1331        assert_eq!(options.rsa_algorithm, JwsAlgorithm::PS256);
1332        assert_eq!(options.algorithms, Some(vec![JwsAlgorithm::EdDSA]));
1333    }
1334
1335    #[test]
1336    fn bad_options_are_refused_before_the_module_loads() {
1337        let no_sessions = Pkcs11KeyStore::open_with(
1338            "/nonexistent/module.so",
1339            "token",
1340            None,
1341            Pkcs11KeyStoreOptions::new().sessions(0),
1342        )
1343        .unwrap_err();
1344        assert_eq!(
1345            no_sessions.to_string(),
1346            "key store backend error: PKCS#11 key store options: `sessions` must be at least 1"
1347        );
1348        let wrong_rsa = Pkcs11KeyStore::open_with(
1349            "/nonexistent/module.so",
1350            "token",
1351            None,
1352            Pkcs11KeyStoreOptions::new().rsa_algorithm(JwsAlgorithm::ES256),
1353        )
1354        .unwrap_err();
1355        assert_eq!(
1356            wrong_rsa.to_string(),
1357            "key store backend error: PKCS#11 key store options: `rsa_algorithm` must be RS256 or PS256, not ES256"
1358        );
1359    }
1360
1361    #[test]
1362    fn a_missing_module_is_reported_with_its_path() {
1363        let error = Pkcs11KeyStore::open("/nonexistent/module.so", "token", None).unwrap_err();
1364        let KeyStoreError::Backend(source) = &error else {
1365            panic!("expected Backend, got {error:?}");
1366        };
1367        let pkcs11 = source.downcast_ref::<Pkcs11Error>().expect("a Pkcs11Error");
1368        assert!(
1369            matches!(pkcs11, Pkcs11Error::Module { module, .. } if module == Path::new("/nonexistent/module.so"))
1370        );
1371        assert!(
1372            error
1373                .to_string()
1374                .starts_with("key store backend error: PKCS#11 module `/nonexistent/module.so`: "),
1375            "{error}"
1376        );
1377        assert!(pkcs11.source().is_some());
1378    }
1379
1380    #[test]
1381    fn errors_that_close_a_session_are_known() {
1382        let call = |rv| Pkcs11Error::Call {
1383            function: "C_Sign",
1384            source: CryptokiError::Pkcs11(rv, cryptoki::context::Function::Sign),
1385        };
1386        assert!(call(RvError::SessionHandleInvalid).closes_session());
1387        assert!(call(RvError::DeviceRemoved).closes_session());
1388        assert!(!call(RvError::KeyHandleInvalid).closes_session());
1389        assert!(!Pkcs11Error::TokenNotFound(Pkcs11Token::Slot(1)).closes_session());
1390        assert_eq!(
1391            Pkcs11Error::SignatureLength {
1392                alg: JwsAlgorithm::ES256,
1393                expected: 64,
1394                actual: 70
1395            }
1396            .to_string(),
1397            "PKCS#11 module returned a 70-byte signature for ES256, expected 64"
1398        );
1399    }
1400}