Skip to content

Commit

Permalink
Make YubiKey::open() more robust (#504)
Browse files Browse the repository at this point in the history
On systems with a physical card-reader, the previous implementation falsely
reports "multiple YubiKeys detected!", even if only one YubiKey is connected.
This change attempts to actually open each reader as a YubiKey, and only
reports "multiple YubiKeys" if it can actually open more than one.

Additionally, this change avoids resetting the YubiKeys in case we find more
than one.
  • Loading branch information
hko-s authored Aug 15, 2023
1 parent 9932d05 commit 485d49a
Showing 1 changed file with 28 additions and 11 deletions.
39 changes: 28 additions & 11 deletions src/yubikey.rs
Original file line number Diff line number Diff line change
Expand Up @@ -178,27 +178,44 @@ impl fmt::Debug for YubiKey {
impl YubiKey {
/// Open a connection to a YubiKey.
///
/// Returns an error if there is more than one YubiKey detected.
/// Returns an error if more than one YubiKey is detected (or none at all).
///
/// NOTE: If multiple YubiKeys are connected, but we are only able to
/// open one of them (e.g. because the other one is in use, and the
/// connection doesn't allow sharing), the YubiKey that we were able to
/// open is returned.
///
/// If you need to operate in environments with more than one YubiKey
/// attached to the same system, use [`YubiKey::open_by_serial`] or
/// [`yubikey::reader::Context`][`Context`] to select from the available
/// PC/SC readers.
pub fn open() -> Result<Self> {
let mut readers = Context::open()?;
let mut reader_iter = readers.iter()?;
let mut yubikey: Option<Self> = None;

if let Some(reader) = reader_iter.next() {
if reader_iter.next().is_some() {
error!("multiple YubiKeys detected!");
return Err(Error::PcscError { inner: None });
let mut readers = Context::open()?;
for reader in readers.iter()? {
if let Ok(yk_found) = reader.open() {
if let Some(yk_stored) = yubikey {
// We found two YubiKeys, so we won't use either.
// Don't reset them.
let _ = yk_stored.disconnect(pcsc::Disposition::LeaveCard);
let _ = yk_found.disconnect(pcsc::Disposition::LeaveCard);

error!("multiple YubiKeys detected!");
return Err(Error::PcscError { inner: None });
} else {
yubikey = Some(yk_found);
}
}

return reader.open();
}

error!("no YubiKey detected!");
Err(Error::NotFound)
if let Some(yubikey) = yubikey {
// We found exactly one YubiKey that we could open, so we return it.
Ok(yubikey)
} else {
error!("no YubiKey detected!");
Err(Error::NotFound)
}
}

/// Open a YubiKey with a specific serial number.
Expand Down

0 comments on commit 485d49a

Please sign in to comment.