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>> {
|
fn main() -> Result<(), Box<dyn Error>> {
|
||||||
env_logger::init();
|
env_logger::init();
|
||||||
|
|
||||||
// Serial number of the OpenPGP Card that will be used for tests.
|
// Ident of the OpenPGP Card that will be used for tests.
|
||||||
let test_card_serial = env::var("TEST_CARD_SERIAL");
|
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");
|
println!("** get card");
|
||||||
let oc = CardBase::open_by_serial(&test_card_serial)?;
|
let oc = CardBase::open_by_ident(&test_card_ident)?;
|
||||||
|
|
||||||
// card metadata
|
// card metadata
|
||||||
|
|
||||||
|
@ -37,7 +37,7 @@ fn main() -> Result<(), Box<dyn Error>> {
|
||||||
let app_id = oc.get_aid()?;
|
let app_id = oc.get_aid()?;
|
||||||
|
|
||||||
println!("app id: {:x?}\n\n", app_id);
|
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()?;
|
let eli = oc.get_extended_length_information()?;
|
||||||
println!("extended_length_info: {:?}\n\n", eli);
|
println!("extended_length_info: {:?}\n\n", eli);
|
||||||
|
@ -75,7 +75,7 @@ fn main() -> Result<(), Box<dyn Error>> {
|
||||||
// CAUTION: Write commands ahead!
|
// CAUTION: Write commands ahead!
|
||||||
// Try not to overwrite your production cards.
|
// 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()?;
|
oc.factory_reset()?;
|
||||||
|
|
||||||
|
@ -127,11 +127,11 @@ fn main() -> Result<(), Box<dyn Error>> {
|
||||||
// Open fresh Card for decrypt
|
// 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()?;
|
let app_id = oc.get_aid()?;
|
||||||
|
|
||||||
// Check that we're still using the expected card
|
// 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") {
|
match oc.verify_pw1("123456") {
|
||||||
Ok(oc_user) => {
|
Ok(oc_user) => {
|
||||||
|
@ -160,7 +160,7 @@ fn main() -> Result<(), Box<dyn Error>> {
|
||||||
// -----------------------------
|
// -----------------------------
|
||||||
// Open fresh Card for signing
|
// Open fresh Card for signing
|
||||||
// -----------------------------
|
// -----------------------------
|
||||||
let oc = CardBase::open_by_serial(&test_card_serial)?;
|
let oc = CardBase::open_by_ident(&test_card_ident)?;
|
||||||
|
|
||||||
// Sign
|
// Sign
|
||||||
match oc.verify_pw1_for_signing("123456") {
|
match oc.verify_pw1_for_signing("123456") {
|
||||||
|
@ -185,7 +185,7 @@ fn main() -> Result<(), Box<dyn Error>> {
|
||||||
_ => panic!("verify pw1 failed"),
|
_ => panic!("verify pw1 failed"),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
println!("Please set environment variable TEST_CARD_SERIAL.");
|
println!("Please set environment variable TEST_CARD_IDENT.");
|
||||||
println!();
|
println!();
|
||||||
|
|
||||||
println!("NOTE: the configured card will get overwritten!");
|
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()?;
|
let cards = openpgp_card::CardBase::list_cards()?;
|
||||||
for c in 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.")]
|
#[error("No reader found.")]
|
||||||
NoReaderFoundError,
|
NoReaderFoundError,
|
||||||
|
|
||||||
#[error("The requested card was not found.")]
|
#[error("The requested card '{0}' was not found.")]
|
||||||
CardNotFound,
|
CardNotFound(String),
|
||||||
|
|
||||||
#[error("Failed to connect to the card: {0}")]
|
#[error("Failed to connect to the card: {0}")]
|
||||||
SmartCardConnectionError(String),
|
SmartCardConnectionError(String),
|
||||||
|
|
|
@ -233,8 +233,11 @@ impl CardBase {
|
||||||
Ok(ocs)
|
Ok(ocs)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Find an OpenPGP card by serial number, open and return it.
|
/// Find an OpenPGP card by "ident", open and return it.
|
||||||
pub fn open_by_serial(serial: &str) -> Result<Self, OpenpgpCardError> {
|
///
|
||||||
|
/// 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| {
|
let cards = card::get_cards().map_err(|e| {
|
||||||
OpenpgpCardError::Smartcard(SmartcardError::Error(format!(
|
OpenpgpCardError::Smartcard(SmartcardError::Error(format!(
|
||||||
"{:?}",
|
"{:?}",
|
||||||
|
@ -247,14 +250,16 @@ impl CardBase {
|
||||||
if let Ok(opened_card) = res {
|
if let Ok(opened_card) = res {
|
||||||
let res = opened_card.get_aid();
|
let res = opened_card.get_aid();
|
||||||
if let Ok(aid) = res {
|
if let Ok(aid) = res {
|
||||||
if aid.serial() == serial {
|
if aid.ident() == ident {
|
||||||
return Ok(opened_card);
|
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
|
/// Open connection to some card and select the openpgp applet
|
||||||
|
|
|
@ -55,7 +55,22 @@ impl TryFrom<&[u8]> for ApplicationId {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ApplicationId {
|
impl ApplicationId {
|
||||||
pub fn serial(&self) -> String {
|
pub fn serial(&self) -> u32 {
|
||||||
format!("{:08X}", self.serial)
|
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