Return errors from YubiKey::open_by_serial that indicate a key may exist (#477)

* Return errors from `YubiKey::open_by_serial` that indicate a key may exist

The only such error at the moment is `pcsc::Error::SharingViolation`, which
indicates a transient failure to access a specific reader that could have
been the one we needed (and so a future retry might succeed).

Closes iqlusioninc/yubikey.rs#458.

* Avoid resetting unused devices in YubiKey::open_by_serial

We only connect to readers so that we can determine their serial. We
now try to ensure that the order in which we connect to them doesn't
have an effect on their state after we are done.
This commit is contained in:
str4d
2023-02-12 17:22:05 +00:00
committed by GitHub
parent d55079f9a6
commit 0809f300b7
+23 -2
View File
@@ -205,19 +205,40 @@ impl YubiKey {
pub fn open_by_serial(serial: Serial) -> Result<Self> { pub fn open_by_serial(serial: Serial) -> Result<Self> {
let mut readers = Context::open()?; let mut readers = Context::open()?;
let mut open_error = None;
for reader in readers.iter()? { for reader in readers.iter()? {
let yubikey = match reader.open() { let yubikey = match reader.open() {
Ok(yk) => yk, Ok(yk) => yk,
Err(_) => continue, Err(e) => {
// Save the first error we see that indicates we might have been able
// to find a matching YubiKey.
if open_error.is_none() {
if let Error::PcscError {
inner: Some(pcsc::Error::SharingViolation),
} = e
{
open_error = Some(e);
}
}
continue;
}
}; };
if serial == yubikey.serial() { if serial == yubikey.serial() {
return Ok(yubikey); return Ok(yubikey);
} else {
// We didn't want this YubiKey; don't reset it.
let _ = yubikey.disconnect(pcsc::Disposition::LeaveCard);
} }
} }
Err(if let Some(e) = open_error {
e
} else {
error!("no YubiKey detected with serial: {}", serial); error!("no YubiKey detected with serial: {}", serial);
Err(Error::NotFound) Error::NotFound
})
} }
/// Reconnect to a YubiKey. /// Reconnect to a YubiKey.