Compare commits

..

4 Commits

Author SHA1 Message Date
Arnaud 0e244e16f0 Fix docstring for Certificate::generate_self_signed (#632)
CI / check (push) Has been cancelled
CI / test (sudo apt-get install libpcsclite-dev, ubuntu-latest, 1.85.0) (push) Has been cancelled
CI / test (sudo apt-get install libpcsclite-dev, ubuntu-latest, stable) (push) Has been cancelled
CI / test (true, macos-latest, 1.85.0) (push) Has been cancelled
CI / test (true, macos-latest, stable) (push) Has been cancelled
CI / test (true, windows-latest, 1.85.0) (push) Has been cancelled
CI / test (true, windows-latest, stable) (push) Has been cancelled
CI / rustfmt (push) Has been cancelled
CI / clippy (push) Has been cancelled
2026-05-11 12:37:50 -06:00
Robin Lambertz ba51f6ad16 Implement PrehashSigner on yubikey::Signer. (#656)
Co-authored-by: roblabla <robin@harfanglab.fr>
2026-05-11 12:37:15 -06:00
Johannes Herforth ca2615eef8 Improve compatibility with ISO 7816-compliant PIV devices (#663) 2026-05-11 12:36:36 -06:00
Robin Lambertz 6c12c7b187 Switch from doc_auto_cfg to doc_cfg (#669)
doc_auto_cfg got removed and folded into the doc_cfg feature flag.
2026-05-09 14:36:05 -06:00
4 changed files with 63 additions and 7 deletions
+22 -2
View File
@@ -114,11 +114,31 @@ impl Apdu {
self self
} }
/// Transmit this APDU using the given card transaction /// Transmit this APDU using the given card transaction.
///
/// Handles ISO 7816-4 `SW1=61` (bytes remaining) responses by issuing
/// [`Ins::GetResponseApdu`] commands until all response data is collected.
pub fn transmit(&self, txn: &Transaction<'_>, recv_len: usize) -> Result<Response> { pub fn transmit(&self, txn: &Transaction<'_>, recv_len: usize) -> Result<Response> {
trace!(">>> {:?}", self); trace!(">>> {:?}", self);
let response = Response::from(txn.transmit(&self.to_bytes(), recv_len)?); let mut response = Response::from(txn.transmit(&self.to_bytes(), recv_len)?);
trace!("<<< {:?}", &response); trace!("<<< {:?}", &response);
if let StatusWords::BytesRemaining { .. } = response.status_words() {
let mut data = response.data().to_vec();
let mut sw = response.status_words();
while let StatusWords::BytesRemaining { .. } = sw {
let next = Response::from(
txn.transmit(&Apdu::new(Ins::GetResponseApdu).to_bytes(), recv_len)?,
);
trace!("<<< {:?}", &next);
data.extend_from_slice(next.data());
sw = next.status_words();
}
response = Response::new(sw, data);
}
Ok(response) Ok(response)
} }
+33 -3
View File
@@ -96,9 +96,8 @@ impl Certificate {
/// Creates a new self-signed certificate for the given key. Writes the resulting /// Creates a new self-signed certificate for the given key. Writes the resulting
/// certificate to the slot before returning it. /// certificate to the slot before returning it.
/// ///
/// `extensions` is optional; if empty, no extensions will be included. Due to the /// `extensions` is a required argument; users who do not have any extensions
/// need for an `O: Oid` type parameter, users who do not have any extensions should /// should set the `extensions` argument to `|_| Ok(())`.
/// use the workaround `let extensions: &[x509_cert::Extension<'_, &[u64]>] = &[];`.
pub fn generate_self_signed<F, KT: yubikey_signer::KeyType>( pub fn generate_self_signed<F, KT: yubikey_signer::KeyType>(
yubikey: &mut YubiKey, yubikey: &mut YubiKey,
key: SlotId, key: SlotId,
@@ -309,6 +308,10 @@ pub mod yubikey_signer {
/// Prepare buffer before submitting it for signature /// Prepare buffer before submitting it for signature
fn prepare(input: &[u8]) -> SigResult<Vec<u8>>; fn prepare(input: &[u8]) -> SigResult<Vec<u8>>;
/// Prepare a prehashed message before submitting it for signature
fn prepare_prehash(hashed: &[u8]) -> SigResult<Vec<u8>>;
/// Read back the signature from the device /// Read back the signature from the device
fn read_signature(input: &[u8]) -> SigResult<Self::Signature>; fn read_signature(input: &[u8]) -> SigResult<Self::Signature>;
} }
@@ -340,6 +343,10 @@ pub mod yubikey_signer {
Ok(Sha256::digest(input).to_vec()) Ok(Sha256::digest(input).to_vec())
} }
fn prepare_prehash(hashed: &[u8]) -> SigResult<Vec<u8>> {
Ok(hashed.to_vec())
}
fn read_signature(input: &[u8]) -> SigResult<Self::Signature> { fn read_signature(input: &[u8]) -> SigResult<Self::Signature> {
Self::Signature::from_bytes(input) Self::Signature::from_bytes(input)
} }
@@ -356,6 +363,10 @@ pub mod yubikey_signer {
Ok(Sha384::digest(input).to_vec()) Ok(Sha384::digest(input).to_vec())
} }
fn prepare_prehash(hashed: &[u8]) -> SigResult<Vec<u8>> {
Ok(hashed.to_vec())
}
fn read_signature(input: &[u8]) -> SigResult<Self::Signature> { fn read_signature(input: &[u8]) -> SigResult<Self::Signature> {
Self::Signature::from_bytes(input) Self::Signature::from_bytes(input)
} }
@@ -415,7 +426,10 @@ pub mod yubikey_signer {
fn prepare(input: &[u8]) -> SigResult<Vec<u8>> { fn prepare(input: &[u8]) -> SigResult<Vec<u8>> {
let hashed = Sha256::digest(input).to_vec(); let hashed = Sha256::digest(input).to_vec();
Self::prepare_prehash(&hashed)
}
fn prepare_prehash(hashed: &[u8]) -> SigResult<Vec<u8>> {
OctetString::new(hashed) OctetString::new(hashed)
.map_err(|e| e.into()) .map_err(|e| e.into())
.and_then(Self::emsa_pkcs1_1_5) .and_then(Self::emsa_pkcs1_1_5)
@@ -515,4 +529,20 @@ pub mod yubikey_signer {
Ok(out) Ok(out)
} }
} }
impl<KT: KeyType> signature::hazmat::PrehashSigner<KT::Signature> for Signer<'_, KT> {
fn sign_prehash(&self, hashed: &[u8]) -> SigResult<KT::Signature> {
let data = KT::prepare_prehash(hashed)?;
let out = sign_data(
&mut self.yubikey.borrow_mut(),
&data,
KT::ALGORITHM,
self.key,
)
.map_err(signature::Error::from_source)?;
let out = KT::read_signature(&out)?;
Ok(out)
}
}
} }
+1 -1
View File
@@ -2,7 +2,7 @@
#![doc( #![doc(
html_logo_url = "https://raw.githubusercontent.com/iqlusioninc/yubikey.rs/main/img/logo-sq.png" html_logo_url = "https://raw.githubusercontent.com/iqlusioninc/yubikey.rs/main/img/logo-sq.png"
)] )]
#![cfg_attr(docsrs, feature(doc_auto_cfg))] #![cfg_attr(docsrs, feature(doc_cfg))]
#![forbid(unsafe_code)] #![forbid(unsafe_code)]
#![warn( #![warn(
clippy::mod_module_files, clippy::mod_module_files,
+7 -1
View File
@@ -599,7 +599,13 @@ impl Key {
}; };
if !buf.is_empty() { if !buf.is_empty() {
let cert = Certificate::from_bytes(buf)?; let cert = match Certificate::from_bytes(buf) {
Ok(c) => c,
Err(e) => {
debug!("error parsing certificate in slot {:?}: {}", slot, e);
continue;
}
};
keys.push(Key { slot, cert }); keys.push(Key { slot, cert });
} }
} }