openpgp-card-sequoia: Transaction::to_*_card() methods
Allow more ergonomic switching to User/Sign/Admin states by directly providing a PIN, while also allowing a `None` parameter if verification has already happened.
This commit is contained in:
parent
8d5b1c0563
commit
212e7f335f
5 changed files with 88 additions and 34 deletions
|
@ -24,9 +24,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||
|
||||
let pin = std::fs::read(pin_file)?;
|
||||
|
||||
transaction.verify_user(&pin)?;
|
||||
|
||||
let mut user = transaction.user_card().unwrap();
|
||||
let mut user = transaction.to_user_card(&pin)?;
|
||||
|
||||
let p = StandardPolicy::new();
|
||||
|
||||
|
|
|
@ -23,9 +23,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||
|
||||
let pin = std::fs::read(pin_file)?;
|
||||
|
||||
transaction.verify_user_for_signing(&pin)?;
|
||||
|
||||
let mut sign = transaction.signing_card().unwrap();
|
||||
let mut sign = transaction.to_signing_card(&pin)?;
|
||||
let s = sign.signer(&|| println!("Touch confirmation needed for signing"))?;
|
||||
|
||||
let stdout = std::io::stdout();
|
||||
|
|
|
@ -100,7 +100,7 @@ fn main() -> Result<(), Box<dyn Error>> {
|
|||
println!("has user (pw1/82) been verified yet? {check:x?}");
|
||||
|
||||
// Use Admin access to card
|
||||
let mut admin = transaction.admin_card().expect("just verified");
|
||||
let mut admin = transaction.to_admin_card(None).expect("just verified");
|
||||
|
||||
println!();
|
||||
|
||||
|
@ -160,7 +160,7 @@ fn main() -> Result<(), Box<dyn Error>> {
|
|||
|
||||
// Use User access to card
|
||||
let mut user = transaction
|
||||
.user_card()
|
||||
.to_user_card(None)
|
||||
.expect("We just validated, this should not fail");
|
||||
|
||||
let _cert = Cert::from_file(TEST_KEY_PATH)?;
|
||||
|
@ -191,7 +191,7 @@ fn main() -> Result<(), Box<dyn Error>> {
|
|||
println!("verify for sign (pw1/81) ok\n");
|
||||
|
||||
// Use Sign access to card
|
||||
let mut sign = transaction.signing_card().expect("just verified");
|
||||
let mut sign = transaction.to_signing_card(None).expect("just verified");
|
||||
|
||||
let _cert = Cert::from_file(TEST_KEY_PATH)?;
|
||||
|
||||
|
|
|
@ -69,9 +69,8 @@
|
|||
//! let mut card = Card::<Open>::open_by_ident(cards, "abcd:01234567")?;
|
||||
//! let mut transaction = card.transaction()?;
|
||||
//!
|
||||
//! // Get authorization for user access to the card with password
|
||||
//! transaction.verify_user(b"123456")?;
|
||||
//! let mut user = transaction.user_card().expect("This should not fail");
|
||||
//! // Get user access to the card (and authorize with the user pin)
|
||||
//! let mut user = transaction.to_user_card("123456")?;
|
||||
//!
|
||||
//! // Get decryptor
|
||||
//! let decryptor = user.decryptor(&|| println!("Touch confirmation needed for decryption"));
|
||||
|
@ -104,9 +103,8 @@
|
|||
//! let mut card = Card::<Open>::open_by_ident(cards, "abcd:01234567")?;
|
||||
//! let mut transaction = card.transaction()?;
|
||||
//!
|
||||
//! // Get authorization for signing access to the card with password
|
||||
//! transaction.verify_user_for_signing(b"123456")?;
|
||||
//! let mut user = transaction.signing_card().expect("This should not fail");
|
||||
//! // Get signing access to the card (and authorize with the user pin)
|
||||
//! let mut user = transaction.to_signing_card("123456")?;
|
||||
//!
|
||||
//! // Get signer
|
||||
//! let signer = user.signer(&|| println!("Touch confirmation needed for signing"));
|
||||
|
@ -130,9 +128,8 @@
|
|||
//! let mut card = Card::<Open>::open_by_ident(cards, "abcd:01234567")?;
|
||||
//! let mut transaction = card.transaction()?;
|
||||
//!
|
||||
//! // Get authorization for admin access to the card with password
|
||||
//! transaction.verify_admin(b"12345678")?;
|
||||
//! let mut admin = transaction.admin_card().expect("This should not fail");
|
||||
//! // Get admin access to the card (and authorize with the admin pin)
|
||||
//! let mut admin = transaction.to_admin_card("12345678")?;
|
||||
//!
|
||||
//! // Set the Name and URL fields on the card
|
||||
//! admin.set_name("Alice Adams")?;
|
||||
|
@ -174,6 +171,36 @@ pub mod util;
|
|||
/// Shorthand for Sequoia public key data (a single public (sub)key)
|
||||
pub type PublicKey = Key<key::PublicParts, key::UnspecifiedRole>;
|
||||
|
||||
/// Optional PIN, used as a parameter to `Card<Transaction>::into_*_card`.
|
||||
///
|
||||
/// Effectively acts like a `Option<&[u8]>`, but with a number of `From`
|
||||
/// implementations for convenience.
|
||||
pub struct OptionalPin<'p>(Option<&'p [u8]>);
|
||||
|
||||
impl<'p> From<Option<&'p [u8]>> for OptionalPin<'p> {
|
||||
fn from(value: Option<&'p [u8]>) -> Self {
|
||||
OptionalPin(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'p> From<&'p str> for OptionalPin<'p> {
|
||||
fn from(value: &'p str) -> Self {
|
||||
OptionalPin(Some(value.as_bytes()))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'p> From<&'p Vec<u8>> for OptionalPin<'p> {
|
||||
fn from(value: &'p Vec<u8>) -> Self {
|
||||
OptionalPin(Some(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'p, const S: usize> From<&'p [u8; S]> for OptionalPin<'p> {
|
||||
fn from(value: &'p [u8; S]) -> Self {
|
||||
OptionalPin(Some(value))
|
||||
}
|
||||
}
|
||||
|
||||
/// Representation of an OpenPGP card.
|
||||
///
|
||||
/// A card transitions between `State`s by starting a transaction (that groups together a number
|
||||
|
@ -362,22 +389,55 @@ impl<'a> Card<Transaction<'a>> {
|
|||
}
|
||||
|
||||
/// Get a view of the card authenticated for "User" commands.
|
||||
pub fn user_card<'b>(&'b mut self) -> Option<Card<User<'a, 'b>>> {
|
||||
Some(Card::<User> {
|
||||
///
|
||||
/// If `pin` is not None, `verify_user` is called with that pin.
|
||||
pub fn to_user_card<'b, 'p, P>(&'b mut self, pin: P) -> Result<Card<User<'a, 'b>>, Error>
|
||||
where
|
||||
P: Into<OptionalPin<'p>>,
|
||||
{
|
||||
let pin: OptionalPin = pin.into();
|
||||
|
||||
if let Some(pin) = pin.0 {
|
||||
self.verify_user(pin)?;
|
||||
}
|
||||
|
||||
Ok(Card::<User> {
|
||||
state: User { tx: self },
|
||||
})
|
||||
}
|
||||
|
||||
/// Get a view of the card authenticated for Signing.
|
||||
pub fn signing_card<'b>(&'b mut self) -> Option<Card<Sign<'a, 'b>>> {
|
||||
Some(Card::<Sign> {
|
||||
///
|
||||
/// If `pin` is not None, `verify_user_for_signing` is called with that pin.
|
||||
pub fn to_signing_card<'b, 'p, P>(&'b mut self, pin: P) -> Result<Card<Sign<'a, 'b>>, Error>
|
||||
where
|
||||
P: Into<OptionalPin<'p>>,
|
||||
{
|
||||
let pin: OptionalPin = pin.into();
|
||||
|
||||
if let Some(pin) = pin.0 {
|
||||
self.verify_user_for_signing(pin)?;
|
||||
}
|
||||
|
||||
Ok(Card::<Sign> {
|
||||
state: Sign { tx: self },
|
||||
})
|
||||
}
|
||||
|
||||
/// Get a view of the card authenticated for "Admin" commands.
|
||||
pub fn admin_card<'b>(&'b mut self) -> Option<Card<Admin<'a, 'b>>> {
|
||||
Some(Card::<Admin> {
|
||||
///
|
||||
/// If `pin` is not None, `verify_admin` is called with that pin.
|
||||
pub fn to_admin_card<'b, 'p, P>(&'b mut self, pin: P) -> Result<Card<Admin<'a, 'b>>, Error>
|
||||
where
|
||||
P: Into<OptionalPin<'p>>,
|
||||
{
|
||||
let pin: OptionalPin = pin.into();
|
||||
|
||||
if let Some(pin) = pin.0 {
|
||||
self.verify_admin(pin)?;
|
||||
}
|
||||
|
||||
Ok(Card::<Admin> {
|
||||
state: Admin { tx: self },
|
||||
})
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
use std::convert::TryFrom;
|
||||
use std::convert::TryInto;
|
||||
|
||||
use anyhow::{anyhow, Result};
|
||||
use anyhow::Result;
|
||||
use openpgp_card::algorithm::{Algo, Curve};
|
||||
use openpgp_card::card_do::{Fingerprint, KeyGenerationTime};
|
||||
use openpgp_card::crypto_data::{CardUploadableKey, PublicKeyMaterial};
|
||||
|
@ -58,16 +58,14 @@ pub fn make_cert(
|
|||
} else {
|
||||
open.verify_user_for_signing_pinpad(pinpad_prompt)?;
|
||||
}
|
||||
if let Some(mut sign) = open.signing_card() {
|
||||
// Card-backed signer for bindings
|
||||
let mut card_signer = sign.signer_from_public(key_sig.clone(), touch_prompt);
|
||||
let mut sign = open.to_signing_card(None)?;
|
||||
|
||||
// Make signature, return it
|
||||
let s = op(&mut card_signer)?;
|
||||
Ok(s)
|
||||
} else {
|
||||
Err(anyhow!("Failed to open card for signing"))
|
||||
}
|
||||
// Card-backed signer for bindings
|
||||
let mut card_signer = sign.signer_from_public(key_sig.clone(), touch_prompt);
|
||||
|
||||
// Make signature, return it
|
||||
let s = op(&mut card_signer)?;
|
||||
Ok::<Signature, anyhow::Error>(s)
|
||||
};
|
||||
|
||||
// 1) use the signing key as primary key
|
||||
|
|
Loading…
Reference in a new issue