Use an "ident" to specify a card.

The ident is a combination of manufacturer and serial number.

The OpenPGP card spec stipulates:
"Each OpenPGP application on a card from a manufacturer/personaliser has a unique serial number"
This commit is contained in:
Heiko Schaefer 2021-07-03 18:17:30 +02:00
parent 920da0442b
commit 01fab2d91c
4 changed files with 39 additions and 19 deletions

View file

@ -24,12 +24,12 @@ const TEST_ENC_MSG: &str = "example/encrypted_to_25519.asc";
fn main() -> Result<(), Box<dyn Error>> {
env_logger::init();
// Serial number of the OpenPGP Card that will be used for tests.
let test_card_serial = env::var("TEST_CARD_SERIAL");
// Ident of the OpenPGP Card that will be used for tests.
let test_card_ident = env::var("TEST_CARD_IDENT");
if let Ok(test_card_serial) = test_card_serial {
if let Ok(test_card_ident) = test_card_ident {
println!("** get card");
let oc = CardBase::open_by_serial(&test_card_serial)?;
let oc = CardBase::open_by_ident(&test_card_ident)?;
// card metadata
@ -37,7 +37,7 @@ fn main() -> Result<(), Box<dyn Error>> {
let app_id = oc.get_aid()?;
println!("app id: {:x?}\n\n", app_id);
println!(" serial: {:?}\n\n", app_id.serial());
println!(" ident: {:?}\n\n", app_id.ident());
let eli = oc.get_extended_length_information()?;
println!("extended_length_info: {:?}\n\n", eli);
@ -75,7 +75,7 @@ fn main() -> Result<(), Box<dyn Error>> {
// CAUTION: Write commands ahead!
// Try not to overwrite your production cards.
// ---------------------------------------------
assert_eq!(app_id.serial(), test_card_serial);
assert_eq!(app_id.ident(), test_card_ident);
oc.factory_reset()?;
@ -127,11 +127,11 @@ fn main() -> Result<(), Box<dyn Error>> {
// Open fresh Card for decrypt
// -----------------------------
let oc = CardBase::open_by_serial(&test_card_serial)?;
let oc = CardBase::open_by_ident(&test_card_ident)?;
let app_id = oc.get_aid()?;
// Check that we're still using the expected card
assert_eq!(app_id.serial(), test_card_serial);
assert_eq!(app_id.ident(), test_card_ident);
match oc.verify_pw1("123456") {
Ok(oc_user) => {
@ -160,7 +160,7 @@ fn main() -> Result<(), Box<dyn Error>> {
// -----------------------------
// Open fresh Card for signing
// -----------------------------
let oc = CardBase::open_by_serial(&test_card_serial)?;
let oc = CardBase::open_by_ident(&test_card_ident)?;
// Sign
match oc.verify_pw1_for_signing("123456") {
@ -185,7 +185,7 @@ fn main() -> Result<(), Box<dyn Error>> {
_ => panic!("verify pw1 failed"),
}
} else {
println!("Please set environment variable TEST_CARD_SERIAL.");
println!("Please set environment variable TEST_CARD_IDENT.");
println!();
println!("NOTE: the configured card will get overwritten!");
@ -196,7 +196,7 @@ fn main() -> Result<(), Box<dyn Error>> {
let cards = openpgp_card::CardBase::list_cards()?;
for c in cards {
println!(" '{}'", c.get_aid()?.serial());
println!(" '{}'", c.get_aid()?.ident());
}
}

View file

@ -145,8 +145,8 @@ pub enum SmartcardError {
#[error("No reader found.")]
NoReaderFoundError,
#[error("The requested card was not found.")]
CardNotFound,
#[error("The requested card '{0}' was not found.")]
CardNotFound(String),
#[error("Failed to connect to the card: {0}")]
SmartCardConnectionError(String),

View file

@ -233,8 +233,11 @@ impl CardBase {
Ok(ocs)
}
/// Find an OpenPGP card by serial number, open and return it.
pub fn open_by_serial(serial: &str) -> Result<Self, OpenpgpCardError> {
/// Find an OpenPGP card by "ident", open and return it.
///
/// The ident is constructed as a concatenation of manufacturer
/// id, a colon, and the card serial. Example: "1234:5678ABCD".
pub fn open_by_ident(ident: &str) -> Result<Self, OpenpgpCardError> {
let cards = card::get_cards().map_err(|e| {
OpenpgpCardError::Smartcard(SmartcardError::Error(format!(
"{:?}",
@ -247,14 +250,16 @@ impl CardBase {
if let Ok(opened_card) = res {
let res = opened_card.get_aid();
if let Ok(aid) = res {
if aid.serial() == serial {
if aid.ident() == ident {
return Ok(opened_card);
}
}
}
}
Err(OpenpgpCardError::Smartcard(SmartcardError::CardNotFound))
Err(OpenpgpCardError::Smartcard(SmartcardError::CardNotFound(
ident.to_string(),
)))
}
/// Open connection to some card and select the openpgp applet

View file

@ -55,7 +55,22 @@ impl TryFrom<&[u8]> for ApplicationId {
}
impl ApplicationId {
pub fn serial(&self) -> String {
format!("{:08X}", self.serial)
pub fn serial(&self) -> u32 {
self.serial
}
pub fn manufacturer(&self) -> u16 {
self.manufacturer
}
/// This ident is constructed as the concatenation of manufacturer
/// id, a colon, and the card serial (in hexadecimal representation).
///
/// It is a more easily human-readable, shorter form of the full
/// 16-byte AID ("Application Identifier").
///
/// Example: "1234:5678ABCD".
pub fn ident(&self) -> String {
format!("{:04X}:{:08X}", self.manufacturer, self.serial)
}
}