Add workaround for select_data() on older Yubikey5 firmware versions.
(This breaks API compatibility, but select_data() was so far not used in any published crate)
This commit is contained in:
parent
0885cb0ac9
commit
432edd5a3e
2 changed files with 46 additions and 5 deletions
|
@ -271,6 +271,11 @@ impl<'a> Open<'a> {
|
||||||
self.opt.security_support_template()
|
self.opt.security_support_template()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// SELECT DATA ("select a DO in the current template").
|
||||||
|
pub fn select_data(&mut self, num: u8, tag: &[u8], yk_workaround: bool) -> Result<(), Error> {
|
||||||
|
self.opt.select_data(num, tag, yk_workaround)
|
||||||
|
}
|
||||||
|
|
||||||
/// Get cardholder certificate.
|
/// Get cardholder certificate.
|
||||||
///
|
///
|
||||||
/// Call select_data() before calling this fn to select a particular
|
/// Call select_data() before calling this fn to select a particular
|
||||||
|
|
|
@ -207,9 +207,30 @@ impl<'a> OpenPgpTransaction<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// SELECT DATA ("select a DO in the current template",
|
/// SELECT DATA ("select a DO in the current template").
|
||||||
/// e.g. for cardholder certificate)
|
///
|
||||||
pub fn select_data(&mut self, num: u8, tag: &[u8]) -> Result<Vec<u8>, Error> {
|
/// This command currently only applies to
|
||||||
|
/// [`cardholder_certificate`](OpenPgpTransaction::cardholder_certificate) and
|
||||||
|
/// [`set_cardholder_certificate`](OpenPgpTransaction::set_cardholder_certificate)
|
||||||
|
/// in OpenPGP card.
|
||||||
|
///
|
||||||
|
/// `yk_workaround`: Yubikey 5 up to (and including) firmware version 5.4.3 need a workaround
|
||||||
|
/// for this command. Set to `true` to apply this workaround.
|
||||||
|
/// (When sending the SELECT DATA command as defined in the card spec, without enabling the
|
||||||
|
/// workaround, bad Yubikey firmware versions (<= 5.4.3) return
|
||||||
|
/// [`IncorrectParametersCommandDataField`](StatusBytes::IncorrectParametersCommandDataField))
|
||||||
|
///
|
||||||
|
/// (This library leaves it up to consumers to decide on a strategy for dealing with this
|
||||||
|
/// issue. Possible strategies include:
|
||||||
|
/// - asking the card for its [`firmware_version`](OpenPgpTransaction::firmware_version)
|
||||||
|
/// and using the workaround if version <=5.4.3
|
||||||
|
/// - trying this command first without the workaround, then with workaround if the card
|
||||||
|
/// returns
|
||||||
|
/// [`IncorrectParametersCommandDataField`](StatusBytes::IncorrectParametersCommandDataField)
|
||||||
|
/// - for read operations: using
|
||||||
|
/// [`next_cardholder_certificate`](OpenPgpTransaction::next_cardholder_certificate)
|
||||||
|
/// instead of SELECT DATA)
|
||||||
|
pub fn select_data(&mut self, num: u8, tag: &[u8], yk_workaround: bool) -> Result<(), Error> {
|
||||||
log::info!("OpenPgpTransaction: select_data");
|
log::info!("OpenPgpTransaction: select_data");
|
||||||
|
|
||||||
let tlv = Tlv::new(
|
let tlv = Tlv::new(
|
||||||
|
@ -217,10 +238,25 @@ impl<'a> OpenPgpTransaction<'a> {
|
||||||
Value::C(vec![Tlv::new(Tags::TagList, Value::S(tag.to_vec()))]),
|
Value::C(vec![Tlv::new(Tags::TagList, Value::S(tag.to_vec()))]),
|
||||||
);
|
);
|
||||||
|
|
||||||
let data = tlv.serialize();
|
let mut data = tlv.serialize();
|
||||||
|
|
||||||
|
if yk_workaround {
|
||||||
|
// Workaround for Yubikey 5.
|
||||||
|
// This hack is needed <= 5.4.3 according to ykman sources
|
||||||
|
// (see _select_certificate() in ykman/openpgp.py).
|
||||||
|
|
||||||
|
assert!(data.len() <= 255); // catch blatant misuse: tags are 1-2 bytes long
|
||||||
|
|
||||||
|
data.insert(0, data.len() as u8);
|
||||||
|
}
|
||||||
|
|
||||||
let cmd = commands::select_data(num, data);
|
let cmd = commands::select_data(num, data);
|
||||||
apdu::send_command(self.tx(), cmd, true)?.try_into()
|
|
||||||
|
// Possible response data (Control Parameter = CP) don't need to be evaluated by the
|
||||||
|
// application (See "7.2.5 SELECT DATA")
|
||||||
|
let _ = apdu::send_command(self.tx(), cmd, true)?.try_into()?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- optional private DOs (0101 - 0104) ---
|
// --- optional private DOs (0101 - 0104) ---
|
||||||
|
|
Loading…
Reference in a new issue