1use 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
23const P256_PARAMS: &[u8] = &[0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07];
25const SECP256K1_PARAMS: &[u8] = &[0x06, 0x05, 0x2b, 0x81, 0x04, 0x00, 0x0a];
27const ED25519_PARAMS: &[u8] = &[0x06, 0x03, 0x2b, 0x65, 0x70];
30const ED25519_NAME_PARAMS: &[u8] = b"\x13\x0cedwards25519";
33pub const STAGING_LABEL_PREFIX: &str = "identity-kit-staging-";
35const RSA_PUBLIC_EXPONENT: &[u8] = &[0x01, 0x00, 0x01];
37const 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#[derive(Debug, Clone, PartialEq, Eq, Hash)]
57#[non_exhaustive]
58pub enum Pkcs11Token {
59 Label(String),
62 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#[derive(Debug, Clone, PartialEq, Eq)]
115#[non_exhaustive]
116pub struct Pkcs11KeyStoreOptions {
117 pub sessions: usize,
122 pub rsa_algorithm: JwsAlgorithm,
130 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 pub fn new() -> Self {
152 Self::default()
153 }
154
155 #[must_use]
157 pub fn sessions(mut self, sessions: usize) -> Self {
158 self.sessions = sessions;
159 self
160 }
161
162 #[must_use]
164 pub fn rsa_algorithm(mut self, alg: JwsAlgorithm) -> Self {
165 self.rsa_algorithm = alg;
166 self
167 }
168
169 #[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#[derive(Debug, thiserror::Error)]
179#[non_exhaustive]
180pub enum Pkcs11Error {
181 #[error("PKCS#11 module `{}`: {source}", module.display())]
183 Module {
184 module: PathBuf,
186 #[source]
188 source: CryptokiError,
189 },
190 #[error("PKCS#11 module has no {0}")]
192 TokenNotFound(Pkcs11Token),
193 #[error("PKCS#11 key store options: {0}")]
195 InvalidOptions(String),
196 #[error("PKCS#11 {function} failed: {source}")]
198 Call {
199 function: &'static str,
201 #[source]
203 source: CryptokiError,
204 },
205 #[error("PKCS#11 module returned a {actual}-byte signature for {alg}, expected {expected}")]
207 SignatureLength {
208 alg: JwsAlgorithm,
210 expected: usize,
212 actual: usize,
214 },
215}
216
217impl Pkcs11Error {
218 fn call(function: &'static str) -> impl FnOnce(CryptokiError) -> KeyStoreError {
220 move |source| KeyStoreError::backend(Self::Call { function, source })
221 }
222
223 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#[derive(Clone)]
292pub struct Pkcs11KeyStore {
293 inner: Arc<Inner>,
294}
295
296struct Inner {
298 module: PathBuf,
299 context: Pkcs11,
300 slot: Slot,
301 token_label: String,
302 pin: Option<AuthPin>,
303 options: Pkcs11KeyStoreOptions,
304 algorithms: Vec<JwsAlgorithm>,
306 key_pair_generation: Vec<MechanismType>,
308 write_protected: bool,
309 pool: Pool,
310 writes: Arc<Mutex<()>>,
312}
313
314struct Pool {
316 state: Mutex<PoolState>,
317 available: Condvar,
319 max: usize,
321}
322
323#[derive(Default)]
324struct PoolState {
325 idle: Vec<Session>,
326 open: usize,
328}
329
330impl Pkcs11KeyStore {
331 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 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 let session = inner.open_session()?;
434 inner.pool.release(session);
435 Ok(Self {
436 inner: Arc::new(inner),
437 })
438 }
439
440 pub fn module(&self) -> &Path {
442 &self.inner.module
443 }
444
445 pub fn slot(&self) -> u64 {
447 self.inner.slot.id()
448 }
449
450 pub fn token_label(&self) -> &str {
452 &self.inner.token_label
453 }
454
455 pub fn options(&self) -> &Pkcs11KeyStoreOptions {
457 &self.inner.options
458 }
459
460 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 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 Ok(()) | Err(CryptokiError::Pkcs11(RvError::UserAlreadyLoggedIn, _)) => {}
570 Err(source) => return Err(Pkcs11Error::call("C_Login")(source)),
571 }
572 }
573 Ok(session)
574 }
575
576 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 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 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 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 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 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 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 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 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 let _ = session.destroy_object(private);
875 let _ = session.destroy_object(public);
876 }
877 labelled
878 }
879}
880
881impl Pool {
882 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 fn release(&self, session: Session) {
910 self.lock().idle.push(session);
911 self.available.notify_one();
912 }
913
914 fn discard(&self, session: Session) {
916 drop(session);
917 self.lock().open -= 1;
918 self.available.notify_one();
919 }
920
921 fn lock(&self) -> MutexGuard<'_, PoolState> {
923 self.state.lock().unwrap_or_else(PoisonError::into_inner)
924 }
925}
926
927static MODULES: Mutex<Vec<(PathBuf, Pkcs11)>> = Mutex::new(Vec::new());
933
934static TOKEN_WRITES: Mutex<Vec<TokenWriteLock>> = Mutex::new(Vec::new());
941
942type TokenWriteLock = ((PathBuf, u64), Arc<Mutex<()>>);
944
945fn 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
960fn 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 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#[derive(Debug, Clone, Copy, PartialEq, Eq)]
985enum KeyKind {
986 Ed25519,
987 P256,
988 Secp256k1,
989 Rsa,
990}
991
992fn 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
1023fn 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
1049fn 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
1066fn 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
1079fn 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
1088fn 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
1128fn 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
1152fn 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
1170fn 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 if length < 0x80 {
1189 return None;
1190 }
1191 (length, content)
1192 };
1193 (content.len() == length).then_some(content)
1194}
1195
1196fn invalid_options(reason: impl Into<String>) -> KeyStoreError {
1198 KeyStoreError::backend(Pkcs11Error::InvalidOptions(reason.into()))
1199}
1200
1201const _: () = {
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 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 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 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 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 assert_eq!(ec_point_bytes(&[0x04, 0x01, 0xaa], kind), Some(&[0xaa][..]));
1270 }
1271 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 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}