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:
parent
920da0442b
commit
01fab2d91c
4 changed files with 39 additions and 19 deletions
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue