Rename structs that represent different verification states of the OpenPGP card.

This commit is contained in:
Heiko Schaefer 2021-07-02 14:21:50 +02:00
parent 3fcb78caa5
commit 920da0442b
7 changed files with 76 additions and 60 deletions

View file

@ -16,13 +16,13 @@ use openpgp::Cert;
use sequoia_openpgp as openpgp; use sequoia_openpgp as openpgp;
use openpgp_card::errors::OpenpgpCardError; use openpgp_card::errors::OpenpgpCardError;
use openpgp_card::{DecryptMe, OpenPGPCardUser}; use openpgp_card::{CardUser, DecryptMe};
use crate::PublicKey; use crate::PublicKey;
pub(crate) struct CardDecryptor<'a> { pub(crate) struct CardDecryptor<'a> {
/// The OpenPGP card (authenticated to allow decryption operations) /// The OpenPGP card (authenticated to allow decryption operations)
ocu: &'a OpenPGPCardUser, ocu: &'a CardUser,
/// The matching public key for the card's decryption key /// The matching public key for the card's decryption key
public: PublicKey, public: PublicKey,
@ -34,7 +34,7 @@ impl<'a> CardDecryptor<'a> {
/// An Error is returned if no match between the card's decryption /// An Error is returned if no match between the card's decryption
/// key and a (sub)key of `cert` can be made. /// key and a (sub)key of `cert` can be made.
pub fn new( pub fn new(
ocu: &'a OpenPGPCardUser, ocu: &'a CardUser,
cert: &Cert, cert: &Cert,
policy: &dyn Policy, policy: &dyn Policy,
) -> Result<CardDecryptor<'a>, OpenpgpCardError> { ) -> Result<CardDecryptor<'a>, OpenpgpCardError> {

View file

@ -21,8 +21,8 @@ use openpgp::serialize::stream::{Message, Signer};
use sequoia_openpgp as openpgp; use sequoia_openpgp as openpgp;
use openpgp_card::{ use openpgp_card::{
errors::OpenpgpCardError, CardUploadableKey, EccKey, EccType, KeyType, errors::OpenpgpCardError, CardAdmin, CardSign, CardUploadableKey,
OpenPGPCardAdmin, OpenPGPCardUser, PrivateKeyMaterial, RSAKey, CardUser, EccKey, EccType, KeyType, PrivateKeyMaterial, RSAKey,
}; };
mod decryptor; mod decryptor;
@ -216,7 +216,7 @@ impl EccKey for SqEccKey {
/// FIXME: picking the (sub)key to upload should probably done with /// FIXME: picking the (sub)key to upload should probably done with
/// more intent. /// more intent.
pub fn upload_from_cert_yolo( pub fn upload_from_cert_yolo(
oca: &OpenPGPCardAdmin, oca: &CardAdmin,
cert: &sequoia_openpgp::Cert, cert: &sequoia_openpgp::Cert,
key_type: KeyType, key_type: KeyType,
password: Option<String>, password: Option<String>,
@ -249,7 +249,7 @@ pub fn upload_from_cert_yolo(
/// ///
/// The caller needs to make sure that `vka` is suitable for `key_type`. /// The caller needs to make sure that `vka` is suitable for `key_type`.
pub fn upload_key( pub fn upload_key(
oca: &OpenPGPCardAdmin, oca: &CardAdmin,
vka: ValidErasedKeyAmalgamation<SecretParts>, vka: ValidErasedKeyAmalgamation<SecretParts>,
key_type: KeyType, key_type: KeyType,
password: Option<String>, password: Option<String>,
@ -260,7 +260,7 @@ pub fn upload_key(
} }
pub fn decrypt( pub fn decrypt(
ocu: &OpenPGPCardUser, ocu: &CardUser,
cert: &sequoia_openpgp::Cert, cert: &sequoia_openpgp::Cert,
msg: Vec<u8>, msg: Vec<u8>,
) -> Result<Vec<u8>> { ) -> Result<Vec<u8>> {
@ -282,7 +282,7 @@ pub fn decrypt(
} }
pub fn sign( pub fn sign(
ocu: &OpenPGPCardUser, ocu: &CardSign,
cert: &sequoia_openpgp::Cert, cert: &sequoia_openpgp::Cert,
input: &mut dyn io::Read, input: &mut dyn io::Read,
) -> Result<String> { ) -> Result<String> {

View file

@ -8,7 +8,7 @@ use anyhow::Result;
use sequoia_openpgp::parse::Parse; use sequoia_openpgp::parse::Parse;
use sequoia_openpgp::Cert; use sequoia_openpgp::Cert;
use openpgp_card::{KeyType, OpenPGPCard}; use openpgp_card::{CardBase, KeyType};
// Filename of test key and test message to use: // Filename of test key and test message to use:
@ -29,7 +29,7 @@ fn main() -> Result<(), Box<dyn Error>> {
if let Ok(test_card_serial) = test_card_serial { if let Ok(test_card_serial) = test_card_serial {
println!("** get card"); println!("** get card");
let oc = OpenPGPCard::open_by_serial(&test_card_serial)?; let oc = CardBase::open_by_serial(&test_card_serial)?;
// card metadata // card metadata
@ -127,13 +127,13 @@ fn main() -> Result<(), Box<dyn Error>> {
// Open fresh Card for decrypt // Open fresh Card for decrypt
// ----------------------------- // -----------------------------
let oc = OpenPGPCard::open_by_serial(&test_card_serial)?; let oc = CardBase::open_by_serial(&test_card_serial)?;
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.serial(), test_card_serial);
match oc.verify_pw1_82("123456") { match oc.verify_pw1("123456") {
Ok(oc_user) => { Ok(oc_user) => {
println!("pw1 82 verify ok"); println!("pw1 82 verify ok");
@ -160,10 +160,10 @@ fn main() -> Result<(), Box<dyn Error>> {
// ----------------------------- // -----------------------------
// Open fresh Card for signing // Open fresh Card for signing
// ----------------------------- // -----------------------------
let oc = OpenPGPCard::open_by_serial(&test_card_serial)?; let oc = CardBase::open_by_serial(&test_card_serial)?;
// Sign // Sign
match oc.verify_pw1_81("123456") { match oc.verify_pw1_for_signing("123456") {
Ok(oc_user) => { Ok(oc_user) => {
println!("pw1 81 verify ok"); println!("pw1 81 verify ok");
@ -194,7 +194,7 @@ fn main() -> Result<(), Box<dyn Error>> {
println!("The following OpenPGP cards are connected to your system:"); println!("The following OpenPGP cards are connected to your system:");
let cards = openpgp_card::OpenPGPCard::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()?.serial());
} }

View file

@ -11,14 +11,14 @@ use openpgp::types::PublicKeyAlgorithm;
use sequoia_openpgp as openpgp; use sequoia_openpgp as openpgp;
use openpgp_card::errors::OpenpgpCardError; use openpgp_card::errors::OpenpgpCardError;
use openpgp_card::CardSign;
use openpgp_card::Hash; use openpgp_card::Hash;
use openpgp_card::OpenPGPCardUser;
use crate::PublicKey; use crate::PublicKey;
pub(crate) struct CardSigner<'a> { pub(crate) struct CardSigner<'a> {
/// The OpenPGP card (authenticated to allow signing operations) /// The OpenPGP card (authenticated to allow signing operations)
ocu: &'a OpenPGPCardUser, ocu: &'a CardSign,
/// The matching public key for the card's signing key /// The matching public key for the card's signing key
public: PublicKey, public: PublicKey,
@ -30,12 +30,12 @@ impl<'a> CardSigner<'a> {
/// An Error is returned if no match between the card's signing /// An Error is returned if no match between the card's signing
/// key and a (sub)key of `cert` can be made. /// key and a (sub)key of `cert` can be made.
pub fn new( pub fn new(
ocu: &'a OpenPGPCardUser, ocs: &'a CardSign,
cert: &openpgp::Cert, cert: &openpgp::Cert,
policy: &dyn Policy, policy: &dyn Policy,
) -> Result<CardSigner<'a>, OpenpgpCardError> { ) -> Result<CardSigner<'a>, OpenpgpCardError> {
// Get the fingerprint for the signing key from the card. // Get the fingerprint for the signing key from the card.
let fps = ocu.get_fingerprints()?; let fps = ocs.get_fingerprints()?;
let fp = fps.signature(); let fp = fps.signature();
if let Some(fp) = fp { if let Some(fp) = fp {
@ -58,7 +58,7 @@ impl<'a> CardSigner<'a> {
let public = keys[0].clone(); let public = keys[0].clone();
Ok(CardSigner { Ok(CardSigner {
ocu, ocu: ocs,
public: public.role_as_unspecified().clone(), public: public.role_as_unspecified().clone(),
}) })
} else { } else {

View file

@ -11,7 +11,7 @@ use std::convert::TryFrom;
use crate::apdu::command::Command; use crate::apdu::command::Command;
use crate::apdu::response::Response; use crate::apdu::response::Response;
use crate::errors::{OcErrorStatus, OpenpgpCardError, SmartcardError}; use crate::errors::{OcErrorStatus, OpenpgpCardError, SmartcardError};
use crate::OpenPGPCard; use crate::CardBase;
#[derive(Clone, Copy, PartialEq)] #[derive(Clone, Copy, PartialEq)]
pub(crate) enum Le { pub(crate) enum Le {
@ -28,7 +28,7 @@ pub(crate) fn send_command(
card: &Card, card: &Card,
cmd: Command, cmd: Command,
ext: Le, ext: Le,
oc: Option<&OpenPGPCard>, oc: Option<&CardBase>,
) -> Result<Response, OpenpgpCardError> { ) -> Result<Response, OpenpgpCardError> {
let mut resp = let mut resp =
Response::try_from(send_command_low_level(&card, cmd, ext, oc)?)?; Response::try_from(send_command_low_level(&card, cmd, ext, oc)?)?;
@ -68,7 +68,7 @@ fn send_command_low_level(
card: &Card, card: &Card,
cmd: Command, cmd: Command,
ext: Le, ext: Le,
oc: Option<&OpenPGPCard>, oc: Option<&CardBase>,
) -> Result<Vec<u8>, OpenpgpCardError> { ) -> Result<Vec<u8>, OpenpgpCardError> {
log::trace!(" -> full APDU command: {:x?}", cmd); log::trace!(" -> full APDU command: {:x?}", cmd);
log::trace!(" serialized: {:x?}", cmd.serialize(ext)); log::trace!(" serialized: {:x?}", cmd.serialize(ext));

View file

@ -12,7 +12,7 @@ use crate::parse::algo_attrs::{Algo, RsaAttrs};
use crate::parse::algo_info::AlgoInfo; use crate::parse::algo_info::AlgoInfo;
use crate::tlv::{tag::Tag, Tlv, TlvEntry}; use crate::tlv::{tag::Tag, Tlv, TlvEntry};
use crate::{ use crate::{
tlv, CardUploadableKey, EccKey, EccType, KeyType, OpenPGPCardAdmin, tlv, CardAdmin, CardUploadableKey, EccKey, EccType, KeyType,
PrivateKeyMaterial, RSAKey, PrivateKeyMaterial, RSAKey,
}; };
@ -20,7 +20,7 @@ use crate::{
/// ///
/// The client needs to make sure that the key is suitable for `key_type`. /// The client needs to make sure that the key is suitable for `key_type`.
pub(crate) fn upload_key( pub(crate) fn upload_key(
oca: &OpenPGPCardAdmin, oca: &CardAdmin,
key: Box<dyn CardUploadableKey>, key: Box<dyn CardUploadableKey>,
key_type: KeyType, key_type: KeyType,
) -> Result<(), OpenpgpCardError> { ) -> Result<(), OpenpgpCardError> {
@ -369,7 +369,7 @@ fn ecc_algo_attrs_cmd(
} }
fn copy_key_to_card( fn copy_key_to_card(
oca: &OpenPGPCardAdmin, oca: &CardAdmin,
key_type: KeyType, key_type: KeyType,
ts: u64, ts: u64,
fp: Vec<u8>, fp: Vec<u8>,

View file

@ -27,6 +27,8 @@ mod key_upload;
mod parse; mod parse;
mod tlv; mod tlv;
/// Container for a hash value.
/// These hash values can be signed by the card.
pub enum Hash<'a> { pub enum Hash<'a> {
SHA256([u8; 0x20]), SHA256([u8; 0x20]),
SHA384([u8; 0x30]), SHA384([u8; 0x30]),
@ -97,6 +99,8 @@ pub trait EccKey {
fn get_type(&self) -> EccType; fn get_type(&self) -> EccType;
} }
/// A marker to distinguish between elliptic curve algorithms (ECDH, ECDSA,
/// EdDSA)
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
pub enum EccType { pub enum EccType {
ECDH, ECDH,
@ -203,9 +207,9 @@ impl KeyType {
} }
} }
/// Representation of an opened OpenPGP card, with default privileges (i.e. /// Representation of an opened OpenPGP card in its basic, freshly opened,
/// no passwords have been verified) /// state (i.e. no passwords have been verified, default privileges apply).
pub struct OpenPGPCard { pub struct CardBase {
card: Card, card: Card,
// Cache of "application related data". // Cache of "application related data".
@ -215,7 +219,7 @@ pub struct OpenPGPCard {
ard: Tlv, ard: Tlv,
} }
impl OpenPGPCard { impl CardBase {
/// Get all cards that can be opened as an OpenPGP card applet /// Get all cards that can be opened as an OpenPGP card applet
pub fn list_cards() -> Result<Vec<Self>> { pub fn list_cards() -> Result<Vec<Self>> {
let cards = card::get_cards().map_err(|err| anyhow!(err))?; let cards = card::get_cards().map_err(|err| anyhow!(err))?;
@ -229,7 +233,7 @@ impl OpenPGPCard {
Ok(ocs) Ok(ocs)
} }
/// Find an OpenPGP card by serial number and return it. /// Find an OpenPGP card by serial number, open and return it.
pub fn open_by_serial(serial: &str) -> Result<Self, OpenpgpCardError> { pub fn open_by_serial(serial: &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!(
@ -547,10 +551,10 @@ impl OpenPGPCard {
Ok(()) Ok(())
} }
pub fn verify_pw1_81( pub fn verify_pw1_for_signing(
self, self,
pin: &str, pin: &str,
) -> Result<OpenPGPCardUser, OpenPGPCard> { ) -> Result<CardSign, CardBase> {
assert!(pin.len() >= 6); // FIXME: Err assert!(pin.len() >= 6); // FIXME: Err
let verify = commands::verify_pw1_81(pin.as_bytes().to_vec()); let verify = commands::verify_pw1_81(pin.as_bytes().to_vec());
@ -559,17 +563,14 @@ impl OpenPGPCard {
if let Ok(resp) = res { if let Ok(resp) = res {
if resp.is_ok() { if resp.is_ok() {
return Ok(OpenPGPCardUser { oc: self }); return Ok(CardSign { oc: self });
} }
} }
Err(self) Err(self)
} }
pub fn verify_pw1_82( pub fn verify_pw1(self, pin: &str) -> Result<CardUser, CardBase> {
self,
pin: &str,
) -> Result<OpenPGPCardUser, OpenPGPCard> {
assert!(pin.len() >= 6); // FIXME: Err assert!(pin.len() >= 6); // FIXME: Err
let verify = commands::verify_pw1_82(pin.as_bytes().to_vec()); let verify = commands::verify_pw1_82(pin.as_bytes().to_vec());
@ -578,17 +579,14 @@ impl OpenPGPCard {
if let Ok(resp) = res { if let Ok(resp) = res {
if resp.is_ok() { if resp.is_ok() {
return Ok(OpenPGPCardUser { oc: self }); return Ok(CardUser { oc: self });
} }
} }
Err(self) Err(self)
} }
pub fn verify_pw3( pub fn verify_pw3(self, pin: &str) -> Result<CardAdmin, CardBase> {
self,
pin: &str,
) -> Result<OpenPGPCardAdmin, OpenPGPCard> {
assert!(pin.len() >= 8); // FIXME: Err assert!(pin.len() >= 8); // FIXME: Err
let verify = commands::verify_pw3(pin.as_bytes().to_vec()); let verify = commands::verify_pw3(pin.as_bytes().to_vec());
@ -597,7 +595,7 @@ impl OpenPGPCard {
if let Ok(resp) = res { if let Ok(resp) = res {
if resp.is_ok() { if resp.is_ok() {
return Ok(OpenPGPCardAdmin { oc: self }); return Ok(CardAdmin { oc: self });
} }
} }
@ -605,22 +603,22 @@ impl OpenPGPCard {
} }
} }
/// An OpenPGP card after successful verification of PW1 (needs to be split /// An OpenPGP card after successful verification of PW1 in mode 82
/// further to model authentication for signing) /// (verification for operations other than signing)
pub struct OpenPGPCardUser { pub struct CardUser {
oc: OpenPGPCard, oc: CardBase,
} }
/// Allow access to fn of OpenPGPCard, through OpenPGPCardUser. /// Allow access to fn of OpenPGPCard, through OpenPGPCardUser.
impl Deref for OpenPGPCardUser { impl Deref for CardUser {
type Target = OpenPGPCard; type Target = CardBase;
fn deref(&self) -> &Self::Target { fn deref(&self) -> &Self::Target {
&self.oc &self.oc
} }
} }
impl OpenPGPCardUser { impl CardUser {
/// Decrypt the ciphertext in `dm`, on the card. /// Decrypt the ciphertext in `dm`, on the card.
pub fn decrypt(&self, dm: DecryptMe) -> Result<Vec<u8>, OpenpgpCardError> { pub fn decrypt(&self, dm: DecryptMe) -> Result<Vec<u8>, OpenpgpCardError> {
match dm { match dm {
@ -660,7 +658,26 @@ impl OpenPGPCardUser {
Ok(resp.data().map(|d| d.to_vec())?) Ok(resp.data().map(|d| d.to_vec())?)
} }
}
/// An OpenPGP card after successful verification of PW1 in mode 81
/// (verification for signing)
pub struct CardSign {
oc: CardBase,
}
/// Allow access to fn of OpenPGPCard, through OpenPGPCardUser.
impl Deref for CardSign {
type Target = CardBase;
fn deref(&self) -> &Self::Target {
&self.oc
}
}
// FIXME: depending on the setting in "PW1 Status byte", only one
// signature can be made after verification for signing
impl CardSign {
/// Sign the message in `hash`, on the card. /// Sign the message in `hash`, on the card.
pub fn signature_for_hash( pub fn signature_for_hash(
&self, &self,
@ -676,8 +693,7 @@ impl OpenPGPCardUser {
TlvEntry::C(vec![ TlvEntry::C(vec![
Tlv( Tlv(
Tag(vec![0x06]), Tag(vec![0x06]),
// unwrapping is // unwrapping is ok, for SHA*
// ok, for SHA*
TlvEntry::S(hash.oid().unwrap().to_vec()), TlvEntry::S(hash.oid().unwrap().to_vec()),
), ),
Tlv(Tag(vec![0x05]), TlvEntry::S(vec![])), Tlv(Tag(vec![0x05]), TlvEntry::S(vec![])),
@ -711,21 +727,21 @@ impl OpenPGPCardUser {
} }
} }
/// An OpenPGP card after successful verification of PW3 /// An OpenPGP card after successful verification of PW3 ("Admin privileges")
pub struct OpenPGPCardAdmin { pub struct CardAdmin {
oc: OpenPGPCard, oc: CardBase,
} }
/// Allow access to fn of OpenPGPCard, through OpenPGPCardAdmin. /// Allow access to fn of OpenPGPCard, through OpenPGPCardAdmin.
impl Deref for OpenPGPCardAdmin { impl Deref for CardAdmin {
type Target = OpenPGPCard; type Target = CardBase;
fn deref(&self) -> &Self::Target { fn deref(&self) -> &Self::Target {
&self.oc &self.oc
} }
} }
impl OpenPGPCardAdmin { impl CardAdmin {
pub(crate) fn card(&self) -> &Card { pub(crate) fn card(&self) -> &Card {
&self.card &self.card
} }