use cryptoki::{
context::{CInitializeArgs, CInitializeFlags, Pkcs11},
mechanism::{
Mechanism, MechanismType,
eddsa::{EddsaParams, EddsaSignatureScheme},
rsa::{PkcsMgfType, PkcsPssParams},
},
object::{Attribute, AttributeType, CertificateType, KeyType, ObjectClass},
session::{Session, UserType},
types::AuthPin,
};
use log::{debug, error, info};
use rustls::{
self, OtherError, SignatureAlgorithm, SignatureScheme,
client::ResolvesClientCert,
pki_types::CertificateDer,
sign::{CertifiedKey, Signer, SigningKey},
};
use std::{
ffi::OsStr,
fmt,
sync::{Arc, Mutex},
};
use x509_certificate::X509Certificate;
#[derive(Debug)]
enum PKCS11Error {
CertificateNotFoundError,
KeyHandleNotFoundError,
UnsupportedSignatureSchemeError(SignatureScheme),
SignError(cryptoki::error::Error),
}
impl std::error::Error for PKCS11Error {}
impl fmt::Display for PKCS11Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
PKCS11Error::SignError(err) => write!(f, "{}: {}", self, err),
PKCS11Error::UnsupportedSignatureSchemeError(scheme) => {
write!(f, "{}: {:?}", self, scheme)
}
_ => write!(f, "{}", self),
}
}
}
#[derive(Debug)]
struct PKCS11Signer {
session: Arc<Mutex<Session>>,
scheme: SignatureScheme,
}
impl<'a> TryInto<Mechanism<'a>> for &PKCS11Signer {
type Error = rustls::Error;
fn try_into(self) -> Result<Mechanism<'a>, rustls::Error> {
match self.scheme {
SignatureScheme::ECDSA_NISTP256_SHA256 => Ok(Mechanism::EcdsaSha256),
SignatureScheme::ECDSA_NISTP384_SHA384 => Ok(Mechanism::EcdsaSha384),
SignatureScheme::ECDSA_NISTP521_SHA512 => Ok(Mechanism::EcdsaSha512),
SignatureScheme::RSA_PKCS1_SHA256 => Ok(Mechanism::Sha256RsaPkcs),
SignatureScheme::RSA_PKCS1_SHA384 => Ok(Mechanism::Sha384RsaPkcs),
SignatureScheme::RSA_PKCS1_SHA512 => Ok(Mechanism::Sha512RsaPkcs),
SignatureScheme::RSA_PSS_SHA256 => {
let params = PkcsPssParams {
hash_alg: MechanismType::SHA256_RSA_PKCS, mgf: PkcsMgfType::MGF1_SHA256, s_len: 32.into(),
};
Ok(Mechanism::Sha256RsaPkcsPss(params))
}
SignatureScheme::RSA_PSS_SHA384 => {
let params = PkcsPssParams {
hash_alg: MechanismType::SHA384_RSA_PKCS, mgf: PkcsMgfType::MGF1_SHA384, s_len: 48.into(),
};
Ok(Mechanism::Sha384RsaPkcsPss(params))
}
SignatureScheme::RSA_PSS_SHA512 => {
let params = PkcsPssParams {
hash_alg: MechanismType::SHA512_RSA_PKCS, mgf: PkcsMgfType::MGF1_SHA512, s_len: 64.into(),
};
Ok(Mechanism::Sha384RsaPkcsPss(params))
}
SignatureScheme::ED25519 => Ok(Mechanism::Eddsa(EddsaParams::new(
EddsaSignatureScheme::Ed25519,
))),
unsupported_scheme => Err(rustls::Error::Other(OtherError(Arc::new(
PKCS11Error::UnsupportedSignatureSchemeError(unsupported_scheme),
)))),
}
}
}
impl Into<KeyType> for &PKCS11Signer {
fn into(self) -> KeyType {
match self.scheme {
SignatureScheme::ECDSA_NISTP256_SHA256 => KeyType::EC,
SignatureScheme::ECDSA_NISTP384_SHA384 => KeyType::EC,
_ => KeyType::RSA,
}
}
}
impl Signer for PKCS11Signer {
fn sign(&self, message: &[u8]) -> Result<Vec<u8>, rustls::Error> {
let session = self.session.lock().unwrap();
let key_template = vec![
Attribute::Token(true),
Attribute::Private(true),
Attribute::Sign(true),
Attribute::KeyType(self.into()),
];
let key = session
.find_objects(&key_template)
.unwrap() .into_iter()
.next()
.ok_or(rustls::Error::Other(OtherError(Arc::new(
PKCS11Error::KeyHandleNotFoundError,
))))?;
let mechanism = self.try_into()?;
let mut signed_message = session.sign(&mechanism, key, message).map_err(|err| {
rustls::Error::Other(OtherError(Arc::new(PKCS11Error::SignError(err))))
})?;
let signed_message = match self.into() {
KeyType::EC => signed_message.to_asn1_sig().unwrap(),
_ => signed_message,
};
debug!("{:?}({:02x?})", mechanism, signed_message);
Ok(signed_message)
}
fn scheme(&self) -> SignatureScheme {
self.scheme
}
}
#[derive(Debug)]
struct PKCS11SigningKey {
session: Arc<Mutex<Session>>,
scheme: SignatureScheme,
}
impl Into<SignatureAlgorithm> for &PKCS11SigningKey {
fn into(self) -> SignatureAlgorithm {
match self.scheme {
SignatureScheme::ECDSA_NISTP256_SHA256 => SignatureAlgorithm::ECDSA,
SignatureScheme::ECDSA_NISTP384_SHA384 => SignatureAlgorithm::ECDSA,
SignatureScheme::RSA_PKCS1_SHA256 => SignatureAlgorithm::RSA,
SignatureScheme::RSA_PKCS1_SHA384 => SignatureAlgorithm::RSA,
SignatureScheme::RSA_PSS_SHA256 => SignatureAlgorithm::RSA,
SignatureScheme::RSA_PSS_SHA384 => SignatureAlgorithm::RSA,
_ => SignatureAlgorithm::Unknown(0),
}
}
}
impl SigningKey for PKCS11SigningKey {
fn choose_scheme(&self, offered: &[SignatureScheme]) -> Option<Box<dyn Signer>> {
debug!(
"schemes offered: {:?}, scheme supported: {:?}",
offered, self.scheme
);
if offered.contains(&self.scheme) {
return Some(Box::new(PKCS11Signer {
session: self.session.clone(),
scheme: self.scheme,
}));
}
None
}
fn algorithm(&self) -> SignatureAlgorithm {
debug!("algorithm called!");
self.into()
}
}
#[derive(Debug)]
pub struct PKCS11ClientCertResolver {
chain: Vec<CertificateDer<'static>>,
signing_key: Arc<PKCS11SigningKey>,
}
impl ResolvesClientCert for PKCS11ClientCertResolver {
fn resolve(
&self,
_acceptable_issuers: &[&[u8]],
_sigschemes: &[SignatureScheme],
) -> Option<Arc<CertifiedKey>> {
Some(Arc::new(CertifiedKey {
cert: self.chain.clone(),
key: self.signing_key.clone(),
ocsp: None,
}))
}
fn has_certs(&self) -> bool {
self.chain.len() > 0
}
}
impl PKCS11ClientCertResolver {
pub fn new(pin: Option<&str>, path: &OsStr) -> Result<Self, Box<dyn std::error::Error>> {
let pkcs11client = Pkcs11::new(path)?;
pkcs11client.initialize(CInitializeArgs::new(CInitializeFlags::OS_LOCKING_OK))?;
let slot = pkcs11client.get_slots_with_token()?.remove(0); let session = pkcs11client.open_ro_session(slot)?;
match pin {
Some(pin) => session.login(UserType::User, Some(&AuthPin::new(pin.into())))?,
None => session.login(UserType::User, None)?,
}
let search_template = vec![
Attribute::Class(ObjectClass::CERTIFICATE),
Attribute::CertificateType(CertificateType::X_509),
];
let handle = session.find_objects(&search_template)?.remove(0);
let value = session
.get_attributes(handle, &[AttributeType::Value])?
.remove(0);
let (scheme, chain) = parse_certificate(value)?;
let session = Arc::new(Mutex::new(session));
let signing_key = Arc::new(PKCS11SigningKey { session, scheme });
Ok(Self { chain, signing_key })
}
}
trait ToASN1 {
fn to_asn1_sig(&mut self) -> Result<Vec<u8>, asn1::WriteError>;
}
impl ToASN1 for Vec<u8> {
fn to_asn1_sig(&mut self) -> Result<Vec<u8>, asn1::WriteError> {
let mut mid = self.len() / 2;
if self[0] >> 7 == 1 {
self.insert(0, 0u8);
mid += 1; }
if self[mid] >> 7 == 1 {
self.insert(mid, 0u8);
}
asn1::write(|w| {
w.write_element(&asn1::SequenceWriter::new(&|w: &mut asn1::Writer| {
let r = asn1::BigInt::new(&self[..mid]);
w.write_element(&r)?;
let s = asn1::BigInt::new(&self[mid..]);
w.write_element(&s)?;
Ok(())
}))
})
}
}
fn parse_certificate(
value: Attribute,
) -> Result<(SignatureScheme, Vec<CertificateDer<'static>>), Box<dyn std::error::Error>> {
match value {
Attribute::Value(cert) => {
let x509 = X509Certificate::from_der(&cert).unwrap();
info!(
"CN: {}, Issuer: {}",
x509.subject_common_name().unwrap(),
x509.issuer_common_name().unwrap(),
);
debug!(
"Signature algorithm: {:?}",
x509.signature_algorithm().unwrap(),
);
debug!("Pubkey({:02x})", x509.public_key_data());
let scheme = match x509.signature_algorithm().unwrap() {
x509_certificate::SignatureAlgorithm::RsaSha256 => {
SignatureScheme::RSA_PKCS1_SHA256 }
x509_certificate::SignatureAlgorithm::RsaSha384 => {
SignatureScheme::RSA_PKCS1_SHA384 }
x509_certificate::SignatureAlgorithm::EcdsaSha256 => {
SignatureScheme::ECDSA_NISTP256_SHA256
}
x509_certificate::SignatureAlgorithm::EcdsaSha384 => {
SignatureScheme::ECDSA_NISTP384_SHA384
}
unsupported_scheme => {
error!("Unsupported scheme: {}", unsupported_scheme);
return Err(Box::new(PKCS11Error::UnsupportedSignatureSchemeError(
SignatureScheme::Unknown(0),
)));
}
};
let certificate_der = CertificateDer::from_slice(&cert).into_owned();
Ok((scheme, vec![certificate_der]))
}
_ => Err(Box::new(PKCS11Error::CertificateNotFoundError)),
}
}