Rename error types and re-export them at the crate top level.

This commit is contained in:
Heiko Schaefer 2021-09-01 23:59:56 +02:00
parent f501c09d2f
commit 316ca7eb3a
19 changed files with 184 additions and 261 deletions

View file

@ -1,19 +1,19 @@
// SPDX-FileCopyrightText: 2021 Heiko Schaefer <heiko@schaefer.name> // SPDX-FileCopyrightText: 2021 Heiko Schaefer <heiko@schaefer.name>
// SPDX-License-Identifier: MIT OR Apache-2.0 // SPDX-License-Identifier: MIT OR Apache-2.0
use anyhow::{Error, Result}; use anyhow::Result;
use std::str::FromStr; use std::str::FromStr;
use std::string::FromUtf8Error; use std::string::FromUtf8Error;
use thiserror::Error; use thiserror;
use sequoia_openpgp::parse::Parse; use sequoia_openpgp::parse::Parse;
use sequoia_openpgp::serialize::SerializeInto; use sequoia_openpgp::serialize::SerializeInto;
use sequoia_openpgp::Cert; use sequoia_openpgp::Cert;
use openpgp_card;
use openpgp_card::algorithm::AlgoSimple; use openpgp_card::algorithm::AlgoSimple;
use openpgp_card::card_do::{KeyGenerationTime, Sex}; use openpgp_card::card_do::{KeyGenerationTime, Sex};
use openpgp_card::errors::{OcErrorStatus, OpenpgpCardError}; use openpgp_card::{CardApp, Error, KeyType, StatusByte};
use openpgp_card::{CardApp, KeyType};
use openpgp_card_sequoia::{ use openpgp_card_sequoia::{
make_cert, public_key_material_to_key, public_to_fingerprint, make_cert, public_key_material_to_key, public_to_fingerprint,
}; };
@ -23,23 +23,23 @@ use crate::util;
#[derive(Debug)] #[derive(Debug)]
pub enum TestResult { pub enum TestResult {
Status(OcErrorStatus), Status(StatusByte),
StatusOk, StatusOk,
Text(String), Text(String),
} }
type TestOutput = Vec<TestResult>; type TestOutput = Vec<TestResult>;
#[derive(Error, Debug)] #[derive(thiserror::Error, Debug)]
pub enum TestError { pub enum TestError {
#[error("Failed to upload key {0} ({1})")] #[error("Failed to upload key {0} ({1})")]
KeyUploadError(String, Error), KeyUploadError(String, anyhow::Error),
#[error(transparent)] #[error(transparent)]
OPGP(#[from] OpenpgpCardError), OPGP(#[from] Error),
#[error(transparent)] #[error(transparent)]
OCard(#[from] OcErrorStatus), OCard(#[from] StatusByte),
#[error(transparent)] #[error(transparent)]
Other(#[from] anyhow::Error), // source and Display delegate to anyhow::Error Other(#[from] anyhow::Error), // source and Display delegate to anyhow::Error
@ -485,8 +485,8 @@ pub fn test_verify(
// try to set name without verify, assert result is not ok! // try to set name without verify, assert result is not ok!
let res = ca.set_name("Notverified<<Hello"); let res = ca.set_name("Notverified<<Hello");
if let Err(OpenpgpCardError::OcStatus(s)) = res { if let Err(Error::CardStatus(s)) = res {
assert_eq!(s, OcErrorStatus::SecurityStatusNotSatisfied); assert_eq!(s, StatusByte::SecurityStatusNotSatisfied);
} else { } else {
panic!("Status should be 'SecurityStatusNotSatisfied'"); panic!("Status should be 'SecurityStatusNotSatisfied'");
} }
@ -494,7 +494,7 @@ pub fn test_verify(
ca.verify_pw3("12345678")?; ca.verify_pw3("12345678")?;
match ca.check_pw3() { match ca.check_pw3() {
Err(OpenpgpCardError::OcStatus(s)) => { Err(Error::CardStatus(s)) => {
// e.g. yubikey5 returns an error status! // e.g. yubikey5 returns an error status!
out.push(TestResult::Status(s)); out.push(TestResult::Status(s));
} }
@ -512,7 +512,7 @@ pub fn test_verify(
ca.verify_pw1("123456")?; ca.verify_pw1("123456")?;
match ca.check_pw3() { match ca.check_pw3() {
Err(OpenpgpCardError::OcStatus(s)) => { Err(Error::CardStatus(s)) => {
// e.g. yubikey5 returns an error status! // e.g. yubikey5 returns an error status!
out.push(TestResult::Status(s)); out.push(TestResult::Status(s));
} }

View file

@ -16,8 +16,7 @@ use openpgp::Cert;
use sequoia_openpgp as openpgp; use sequoia_openpgp as openpgp;
use openpgp_card::crypto_data::Cryptogram; use openpgp_card::crypto_data::Cryptogram;
use openpgp_card::errors::OpenpgpCardError; use openpgp_card::{CardApp, Error};
use openpgp_card::CardApp;
use crate::PublicKey; use crate::PublicKey;
@ -38,7 +37,7 @@ impl<'a> CardDecryptor<'a> {
ca: &'a mut CardApp, ca: &'a mut CardApp,
cert: &Cert, cert: &Cert,
policy: &dyn Policy, policy: &dyn Policy,
) -> Result<CardDecryptor<'a>, OpenpgpCardError> { ) -> Result<CardDecryptor<'a>, Error> {
// Get the fingerprint for the decryption key from the card. // Get the fingerprint for the decryption key from the card.
let ard = ca.get_app_data()?; let ard = ca.get_app_data()?;
let fps = ard.get_fingerprints()?; let fps = ard.get_fingerprints()?;
@ -63,12 +62,12 @@ impl<'a> CardDecryptor<'a> {
let public = keys[0].clone(); let public = keys[0].clone();
Ok(Self { ca, public }) Ok(Self { ca, public })
} else { } else {
Err(OpenpgpCardError::InternalError(anyhow!( Err(Error::InternalError(anyhow!(
"Failed to find a matching (sub)key in cert" "Failed to find a matching (sub)key in cert"
))) )))
} }
} else { } else {
Err(OpenpgpCardError::InternalError(anyhow!( Err(Error::InternalError(anyhow!(
"Failed to get the decryption key's Fingerprint from the card" "Failed to get the decryption key's Fingerprint from the card"
))) )))
} }

View file

@ -7,7 +7,6 @@
use anyhow::{anyhow, Context, Result}; use anyhow::{anyhow, Context, Result};
use std::convert::TryFrom; use std::convert::TryFrom;
use std::convert::TryInto; use std::convert::TryInto;
use std::error::Error;
use std::io; use std::io;
use std::ops::{Deref, DerefMut}; use std::ops::{Deref, DerefMut};
use std::time::SystemTime; use std::time::SystemTime;
@ -41,9 +40,7 @@ use openpgp_card::crypto_data::{
CardUploadableKey, Cryptogram, EccKey, EccType, Hash, PrivateKeyMaterial, CardUploadableKey, Cryptogram, EccKey, EccType, Hash, PrivateKeyMaterial,
PublicKeyMaterial, RSAKey, PublicKeyMaterial, RSAKey,
}; };
use openpgp_card::{ use openpgp_card::{CardApp, CardClientBox, Error, KeyType, Response};
errors::OpenpgpCardError, CardApp, CardClientBox, KeyType, Response,
};
use crate::signer::CardSigner; use crate::signer::CardSigner;
@ -373,7 +370,7 @@ impl CardUploadableKey for SequoiaKey {
ts.into() ts.into()
} }
fn get_fp(&self) -> Result<Fingerprint, OpenpgpCardError> { fn get_fp(&self) -> Result<Fingerprint, Error> {
let fp = self.key.fingerprint(); let fp = self.key.fingerprint();
fp.as_bytes().try_into() fp.as_bytes().try_into()
} }
@ -455,7 +452,7 @@ pub fn upload_from_cert_yolo(
cert: &openpgp::Cert, cert: &openpgp::Cert,
key_type: KeyType, key_type: KeyType,
password: Option<String>, password: Option<String>,
) -> Result<(), Box<dyn Error>> { ) -> Result<(), Box<dyn std::error::Error>> {
let policy = StandardPolicy::new(); let policy = StandardPolicy::new();
// Find all suitable (sub)keys for key_type. // Find all suitable (sub)keys for key_type.
@ -488,7 +485,7 @@ pub fn upload_key(
vka: ValidErasedKeyAmalgamation<SecretParts>, vka: ValidErasedKeyAmalgamation<SecretParts>,
key_type: KeyType, key_type: KeyType,
password: Option<String>, password: Option<String>,
) -> Result<(), OpenpgpCardError> { ) -> Result<(), Error> {
let sqk = SequoiaKey::new(vka, password); let sqk = SequoiaKey::new(vka, password);
oca.upload_key(Box::new(sqk), key_type) oca.upload_key(Box::new(sqk), key_type)
@ -546,7 +543,7 @@ pub fn public_to_fingerprint(
pkm: &PublicKeyMaterial, pkm: &PublicKeyMaterial,
time: KeyGenerationTime, time: KeyGenerationTime,
kt: KeyType, kt: KeyType,
) -> Result<Fingerprint, OpenpgpCardError> { ) -> Result<Fingerprint, Error> {
// Transform PublicKeyMaterial into a Sequoia Key // Transform PublicKeyMaterial into a Sequoia Key
let key = public_key_material_to_key(pkm, kt, time)?; let key = public_key_material_to_key(pkm, kt, time)?;
@ -581,7 +578,7 @@ impl CardBase {
/// Set up connection (cache "application related data") to a /// Set up connection (cache "application related data") to a
/// CardClient, on which the openpgp applet has already been opened. /// CardClient, on which the openpgp applet has already been opened.
pub fn open_card(ccb: CardClientBox) -> Result<Self, OpenpgpCardError> { pub fn open_card(ccb: CardClientBox) -> Result<Self, Error> {
// read and cache "application related data" // read and cache "application related data"
let mut card_app = CardApp::from(ccb); let mut card_app = CardApp::from(ccb);
@ -602,13 +599,11 @@ impl CardBase {
self.card_app.get_app_data() self.card_app.get_app_data()
} }
pub fn get_application_id( pub fn get_application_id(&self) -> Result<ApplicationId, Error> {
&self,
) -> Result<ApplicationId, OpenpgpCardError> {
self.ard.get_application_id() self.ard.get_application_id()
} }
pub fn get_historical(&self) -> Result<Historical, OpenpgpCardError> { pub fn get_historical(&self) -> Result<Historical, Error> {
self.ard.get_historical() self.ard.get_historical()
} }
@ -626,9 +621,7 @@ impl CardBase {
unimplemented!() unimplemented!()
} }
pub fn get_extended_capabilities( pub fn get_extended_capabilities(&self) -> Result<ExtendedCap, Error> {
&self,
) -> Result<ExtendedCap, OpenpgpCardError> {
self.ard.get_extended_capabilities() self.ard.get_extended_capabilities()
} }
@ -641,9 +634,7 @@ impl CardBase {
self.ard.get_pw_status_bytes() self.ard.get_pw_status_bytes()
} }
pub fn get_fingerprints( pub fn get_fingerprints(&self) -> Result<KeySet<Fingerprint>, Error> {
&self,
) -> Result<KeySet<Fingerprint>, OpenpgpCardError> {
self.ard.get_fingerprints() self.ard.get_fingerprints()
} }
@ -730,7 +721,7 @@ impl CardBase {
} }
} }
pub fn check_pw1(&mut self) -> Result<Response, OpenpgpCardError> { pub fn check_pw1(&mut self) -> Result<Response, Error> {
self.card_app.check_pw1() self.card_app.check_pw1()
} }
@ -744,7 +735,7 @@ impl CardBase {
} }
} }
pub fn check_pw3(&mut self) -> Result<Response, OpenpgpCardError> { pub fn check_pw3(&mut self) -> Result<Response, Error> {
self.card_app.check_pw3() self.card_app.check_pw3()
} }
@ -783,10 +774,7 @@ impl DerefMut for CardUser {
impl CardUser { impl CardUser {
/// Decrypt the ciphertext in `dm`, on the card. /// Decrypt the ciphertext in `dm`, on the card.
pub fn decrypt( pub fn decrypt(&mut self, dm: Cryptogram) -> Result<Vec<u8>, Error> {
&mut self,
dm: Cryptogram,
) -> Result<Vec<u8>, OpenpgpCardError> {
self.card_app.decrypt(dm) self.card_app.decrypt(dm)
} }
} }
@ -820,7 +808,7 @@ impl CardSign {
pub fn signature_for_hash( pub fn signature_for_hash(
&mut self, &mut self,
hash: Hash, hash: Hash,
) -> Result<Vec<u8>, OpenpgpCardError> { ) -> Result<Vec<u8>, Error> {
self.card_app.signature_for_hash(hash) self.card_app.signature_for_hash(hash)
} }
} }
@ -847,10 +835,7 @@ impl DerefMut for CardAdmin {
} }
impl CardAdmin { impl CardAdmin {
pub fn set_name( pub fn set_name(&mut self, name: &str) -> Result<Response, Error> {
&mut self,
name: &str,
) -> Result<Response, OpenpgpCardError> {
if name.len() >= 40 { if name.len() >= 40 {
return Err(anyhow!("name too long").into()); return Err(anyhow!("name too long").into());
} }
@ -863,10 +848,7 @@ impl CardAdmin {
self.card_app.set_name(name) self.card_app.set_name(name)
} }
pub fn set_lang( pub fn set_lang(&mut self, lang: &str) -> Result<Response, Error> {
&mut self,
lang: &str,
) -> Result<Response, OpenpgpCardError> {
if lang.len() > 8 { if lang.len() > 8 {
return Err(anyhow!("lang too long").into()); return Err(anyhow!("lang too long").into());
} }
@ -874,14 +856,11 @@ impl CardAdmin {
self.card_app.set_lang(lang) self.card_app.set_lang(lang)
} }
pub fn set_sex(&mut self, sex: Sex) -> Result<Response, OpenpgpCardError> { pub fn set_sex(&mut self, sex: Sex) -> Result<Response, Error> {
self.card_app.set_sex(sex) self.card_app.set_sex(sex)
} }
pub fn set_url( pub fn set_url(&mut self, url: &str) -> Result<Response, Error> {
&mut self,
url: &str,
) -> Result<Response, OpenpgpCardError> {
if url.chars().any(|c| !c.is_ascii()) { if url.chars().any(|c| !c.is_ascii()) {
return Err(anyhow!("Invalid char in url").into()); return Err(anyhow!("Invalid char in url").into());
} }
@ -900,7 +879,7 @@ impl CardAdmin {
&mut self, &mut self,
key: Box<dyn CardUploadableKey>, key: Box<dyn CardUploadableKey>,
key_type: KeyType, key_type: KeyType,
) -> Result<(), OpenpgpCardError> { ) -> Result<(), Error> {
self.card_app.key_import(key, key_type) self.card_app.key_import(key, key_type)
} }
} }

View file

@ -11,8 +11,7 @@ use openpgp::types::{Curve, PublicKeyAlgorithm};
use sequoia_openpgp as openpgp; use sequoia_openpgp as openpgp;
use openpgp_card::crypto_data::Hash; use openpgp_card::crypto_data::Hash;
use openpgp_card::errors::OpenpgpCardError; use openpgp_card::{CardApp, Error};
use openpgp_card::CardApp;
use crate::PublicKey; use crate::PublicKey;
@ -33,7 +32,7 @@ impl<'a> CardSigner<'a> {
ca: &'a mut CardApp, ca: &'a mut CardApp,
cert: &openpgp::Cert, cert: &openpgp::Cert,
policy: &dyn Policy, policy: &dyn Policy,
) -> Result<CardSigner<'a>, OpenpgpCardError> { ) -> Result<CardSigner<'a>, Error> {
// Get the fingerprint for the signing key from the card. // Get the fingerprint for the signing key from the card.
let ard = ca.get_app_data()?; let ard = ca.get_app_data()?;
let fps = ard.get_fingerprints()?; let fps = ard.get_fingerprints()?;
@ -60,12 +59,12 @@ impl<'a> CardSigner<'a> {
Ok(Self::with_pubkey(ca, public)) Ok(Self::with_pubkey(ca, public))
} else { } else {
Err(OpenpgpCardError::InternalError(anyhow!( Err(Error::InternalError(anyhow!(
"Failed to find a matching (sub)key in cert" "Failed to find a matching (sub)key in cert"
))) )))
} }
} else { } else {
Err(OpenpgpCardError::InternalError(anyhow!( Err(Error::InternalError(anyhow!(
"Failed to get the signing key's Fingerprint \ "Failed to get the signing key's Fingerprint \
from the card" from the card"
))) )))

View file

@ -11,10 +11,8 @@ pub mod response;
use anyhow::Result; use anyhow::Result;
use std::convert::TryFrom; use std::convert::TryFrom;
use crate::apdu::command::Command; use crate::apdu::{command::Command, response::RawResponse};
use crate::apdu::response::RawResponse; use crate::{CardClientBox, Error, StatusByte};
use crate::errors::{OcErrorStatus, OpenpgpCardError};
use crate::CardClientBox;
// "Maximum amount of bytes in a short APDU command or response" (from pcsc) // "Maximum amount of bytes in a short APDU command or response" (from pcsc)
const MAX_BUFFER_SIZE: usize = 264; const MAX_BUFFER_SIZE: usize = 264;
@ -34,7 +32,7 @@ pub(crate) fn send_command(
card_client: &mut CardClientBox, card_client: &mut CardClientBox,
cmd: Command, cmd: Command,
expect_reply: bool, expect_reply: bool,
) -> Result<RawResponse, OpenpgpCardError> { ) -> Result<RawResponse, Error> {
let mut resp = RawResponse::try_from(send_command_low_level( let mut resp = RawResponse::try_from(send_command_low_level(
card_client, card_client,
cmd, cmd,
@ -75,7 +73,7 @@ fn send_command_low_level(
card_client: &mut CardClientBox, card_client: &mut CardClientBox,
cmd: Command, cmd: Command,
expect_reply: bool, expect_reply: bool,
) -> Result<Vec<u8>, OpenpgpCardError> { ) -> Result<Vec<u8>, Error> {
let (ext_support, chaining_support, mut max_cmd_bytes, max_rsp_bytes) = let (ext_support, chaining_support, mut max_cmd_bytes, max_rsp_bytes) =
if let Some(caps) = card_client.get_caps() { if let Some(caps) = card_client.get_caps() {
log::debug!("found card caps data!"); log::debug!("found card caps data!");
@ -151,9 +149,8 @@ fn send_command_low_level(
d.to_vec(), d.to_vec(),
); );
let serialized = partial let serialized =
.serialize(ext) partial.serialize(ext).map_err(Error::InternalError)?;
.map_err(OpenpgpCardError::InternalError)?;
log::debug!(" -> chunked APDU command: {:x?}", &serialized); log::debug!(" -> chunked APDU command: {:x?}", &serialized);
@ -162,7 +159,7 @@ fn send_command_low_level(
log::debug!(" <- APDU chunk response: {:x?}", &resp); log::debug!(" <- APDU chunk response: {:x?}", &resp);
if resp.len() < 2 { if resp.len() < 2 {
return Err(OpenpgpCardError::ResponseLength(resp.len())); return Err(Error::ResponseLength(resp.len()));
} }
if !last { if !last {
@ -176,7 +173,7 @@ fn send_command_low_level(
|| (sw1 == 0x68 && sw2 == 0x83)) || (sw1 == 0x68 && sw2 == 0x83))
{ {
// Unexpected status for a non-final chunked response // Unexpected status for a non-final chunked response
return Err(OcErrorStatus::from((sw1, sw2)).into()); return Err(StatusByte::from((sw1, sw2)).into());
} }
// ISO: "If SW1-SW2 is set to '6884', then command // ISO: "If SW1-SW2 is set to '6884', then command
@ -193,7 +190,7 @@ fn send_command_low_level(
// Can't send this command to the card, because it is too long and // Can't send this command to the card, because it is too long and
// the card doesn't support command chaining. // the card doesn't support command chaining.
if serialized.len() > max_cmd_bytes { if serialized.len() > max_cmd_bytes {
return Err(OpenpgpCardError::CommandTooLong(serialized.len())); return Err(Error::CommandTooLong(serialized.len()));
} }
log::debug!(" -> APDU command: {:x?}", &serialized); log::debug!(" -> APDU command: {:x?}", &serialized);

View file

@ -1,7 +1,7 @@
// SPDX-FileCopyrightText: 2021 Heiko Schaefer <heiko@schaefer.name> // SPDX-FileCopyrightText: 2021 Heiko Schaefer <heiko@schaefer.name>
// SPDX-License-Identifier: MIT OR Apache-2.0 // SPDX-License-Identifier: MIT OR Apache-2.0
use crate::errors::{OcErrorStatus, OpenpgpCardError}; use crate::{Error, StatusByte};
use std::convert::TryFrom; use std::convert::TryFrom;
/// Response from the card to a command. /// Response from the card to a command.
@ -35,29 +35,27 @@ pub(crate) struct RawResponse {
} }
impl TryFrom<RawResponse> for Response { impl TryFrom<RawResponse> for Response {
type Error = OpenpgpCardError; type Error = Error;
fn try_from(value: RawResponse) -> Result<Self, Self::Error> { fn try_from(value: RawResponse) -> Result<Self, Self::Error> {
if value.is_ok() { if value.is_ok() {
Ok(Response { data: value.data }) Ok(Response { data: value.data })
} else { } else {
Err(OpenpgpCardError::OcStatus(OcErrorStatus::from( Err(Error::CardStatus(StatusByte::from(value.status())))
value.status(),
)))
} }
} }
} }
impl RawResponse { impl RawResponse {
pub fn check_ok(&self) -> Result<(), OcErrorStatus> { pub fn check_ok(&self) -> Result<(), StatusByte> {
if !self.is_ok() { if !self.is_ok() {
Err(OcErrorStatus::from((self.sw1, self.sw2))) Err(StatusByte::from((self.sw1, self.sw2)))
} else { } else {
Ok(()) Ok(())
} }
} }
pub fn data(&self) -> Result<&[u8], OcErrorStatus> { pub fn data(&self) -> Result<&[u8], StatusByte> {
self.check_ok()?; self.check_ok()?;
Ok(&self.data) Ok(&self.data)
} }
@ -87,15 +85,15 @@ impl RawResponse {
} }
impl TryFrom<Vec<u8>> for RawResponse { impl TryFrom<Vec<u8>> for RawResponse {
type Error = OpenpgpCardError; type Error = Error;
fn try_from(mut data: Vec<u8>) -> Result<Self, Self::Error> { fn try_from(mut data: Vec<u8>) -> Result<Self, Self::Error> {
let sw2 = data let sw2 = data
.pop() .pop()
.ok_or_else(|| OpenpgpCardError::ResponseLength(data.len()))?; .ok_or_else(|| Error::ResponseLength(data.len()))?;
let sw1 = data let sw1 = data
.pop() .pop()
.ok_or_else(|| OpenpgpCardError::ResponseLength(data.len()))?; .ok_or_else(|| Error::ResponseLength(data.len()))?;
Ok(RawResponse { data, sw1, sw2 }) Ok(RawResponse { data, sw1, sw2 })
} }

View file

@ -18,8 +18,8 @@ use crate::card_do::{
use crate::crypto_data::{ use crate::crypto_data::{
CardUploadableKey, Cryptogram, EccType, Hash, PublicKeyMaterial, CardUploadableKey, Cryptogram, EccType, Hash, PublicKeyMaterial,
}; };
use crate::errors::OpenpgpCardError;
use crate::tlv::{tag::Tag, value::Value, Tlv}; use crate::tlv::{tag::Tag, value::Value, Tlv};
use crate::Error;
use crate::{apdu, keys, CardCaps, CardClientBox, KeyType}; use crate::{apdu, keys, CardCaps, CardClientBox, KeyType};
/// Low-level access to OpenPGP card functionality. /// Low-level access to OpenPGP card functionality.
@ -92,7 +92,7 @@ impl CardApp {
// --- select --- // --- select ---
/// Select the OpenPGP card application /// Select the OpenPGP card application
pub fn select(&mut self) -> Result<Response, OpenpgpCardError> { pub fn select(&mut self) -> Result<Response, Error> {
let select_openpgp = commands::select_openpgp(); let select_openpgp = commands::select_openpgp();
apdu::send_command(&mut self.card_client, select_openpgp, false)? apdu::send_command(&mut self.card_client, select_openpgp, false)?
.try_into() .try_into()
@ -207,9 +207,7 @@ impl CardApp {
/// ///
/// Call select_data() before calling this fn, to select a particular /// Call select_data() before calling this fn, to select a particular
/// certificate (if the card supports multiple certificates). /// certificate (if the card supports multiple certificates).
pub fn get_cardholder_certificate( pub fn get_cardholder_certificate(&mut self) -> Result<Response, Error> {
&mut self,
) -> Result<Response, OpenpgpCardError> {
let cmd = commands::get_cardholder_certificate(); let cmd = commands::get_cardholder_certificate();
apdu::send_command(&mut self.card_client, cmd, true)?.try_into() apdu::send_command(&mut self.card_client, cmd, true)?.try_into()
} }
@ -233,7 +231,7 @@ impl CardApp {
&mut self, &mut self,
num: u8, num: u8,
tag: &[u8], tag: &[u8],
) -> Result<Response, OpenpgpCardError> { ) -> Result<Response, Error> {
let tlv = Tlv::new( let tlv = Tlv::new(
[0x60], [0x60],
Value::C(vec![Tlv::new([0x5c], Value::S(tag.to_vec()))]), Value::C(vec![Tlv::new([0x5c], Value::S(tag.to_vec()))]),
@ -308,7 +306,7 @@ impl CardApp {
pub fn verify_pw1_for_signing( pub fn verify_pw1_for_signing(
&mut self, &mut self,
pin: &str, pin: &str,
) -> Result<Response, OpenpgpCardError> { ) -> Result<Response, Error> {
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());
@ -321,19 +319,14 @@ impl CardApp {
/// ///
/// (Note: some cards don't correctly implement this feature, /// (Note: some cards don't correctly implement this feature,
/// e.g. yubikey 5) /// e.g. yubikey 5)
pub fn check_pw1_for_signing( pub fn check_pw1_for_signing(&mut self) -> Result<Response, Error> {
&mut self,
) -> Result<Response, OpenpgpCardError> {
let verify = commands::verify_pw1_81(vec![]); let verify = commands::verify_pw1_81(vec![]);
apdu::send_command(&mut self.card_client, verify, false)?.try_into() apdu::send_command(&mut self.card_client, verify, false)?.try_into()
} }
/// Verify PW1 (user) and set an appropriate access status. /// Verify PW1 (user) and set an appropriate access status.
/// (For operations except signing, mode 82). /// (For operations except signing, mode 82).
pub fn verify_pw1( pub fn verify_pw1(&mut self, pin: &str) -> Result<Response, Error> {
&mut self,
pin: &str,
) -> Result<Response, OpenpgpCardError> {
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());
@ -347,16 +340,13 @@ impl CardApp {
/// ///
/// (Note: some cards don't correctly implement this feature, /// (Note: some cards don't correctly implement this feature,
/// e.g. yubikey 5) /// e.g. yubikey 5)
pub fn check_pw1(&mut self) -> Result<Response, OpenpgpCardError> { pub fn check_pw1(&mut self) -> Result<Response, Error> {
let verify = commands::verify_pw1_82(vec![]); let verify = commands::verify_pw1_82(vec![]);
apdu::send_command(&mut self.card_client, verify, false)?.try_into() apdu::send_command(&mut self.card_client, verify, false)?.try_into()
} }
/// Verify PW3 (admin) and set an appropriate access status. /// Verify PW3 (admin) and set an appropriate access status.
pub fn verify_pw3( pub fn verify_pw3(&mut self, pin: &str) -> Result<Response, Error> {
&mut self,
pin: &str,
) -> Result<Response, OpenpgpCardError> {
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());
@ -369,7 +359,7 @@ impl CardApp {
/// ///
/// (Note: some cards don't correctly implement this feature, /// (Note: some cards don't correctly implement this feature,
/// e.g. yubikey 5) /// e.g. yubikey 5)
pub fn check_pw3(&mut self) -> Result<Response, OpenpgpCardError> { pub fn check_pw3(&mut self) -> Result<Response, Error> {
let verify = commands::verify_pw3(vec![]); let verify = commands::verify_pw3(vec![]);
apdu::send_command(&mut self.card_client, verify, false)?.try_into() apdu::send_command(&mut self.card_client, verify, false)?.try_into()
} }
@ -380,10 +370,7 @@ impl CardApp {
/// ///
/// (This is a convenience wrapper around the low-level pso_decipher /// (This is a convenience wrapper around the low-level pso_decipher
/// operation, it builds the required `data` field from `dm`) /// operation, it builds the required `data` field from `dm`)
pub fn decrypt( pub fn decrypt(&mut self, dm: Cryptogram) -> Result<Vec<u8>, Error> {
&mut self,
dm: Cryptogram,
) -> Result<Vec<u8>, OpenpgpCardError> {
match dm { match dm {
Cryptogram::RSA(message) => { Cryptogram::RSA(message) => {
let mut data = vec![0x0]; let mut data = vec![0x0];
@ -409,10 +396,7 @@ impl CardApp {
/// Run decryption operation on the smartcard (low level operation) /// Run decryption operation on the smartcard (low level operation)
/// (7.2.11 PSO: DECIPHER) /// (7.2.11 PSO: DECIPHER)
fn pso_decipher( fn pso_decipher(&mut self, data: Vec<u8>) -> Result<Vec<u8>, Error> {
&mut self,
data: Vec<u8>,
) -> Result<Vec<u8>, OpenpgpCardError> {
// The OpenPGP card is already connected and PW1 82 has been verified // The OpenPGP card is already connected and PW1 82 has been verified
let dec_cmd = commands::decryption(data); let dec_cmd = commands::decryption(data);
let resp = apdu::send_command(&mut self.card_client, dec_cmd, true)?; let resp = apdu::send_command(&mut self.card_client, dec_cmd, true)?;
@ -431,7 +415,7 @@ impl CardApp {
pub fn signature_for_hash( pub fn signature_for_hash(
&mut self, &mut self,
hash: Hash, hash: Hash,
) -> Result<Vec<u8>, OpenpgpCardError> { ) -> Result<Vec<u8>, Error> {
let data = match hash { let data = match hash {
Hash::SHA256(_) | Hash::SHA384(_) | Hash::SHA512(_) => { Hash::SHA256(_) | Hash::SHA384(_) | Hash::SHA512(_) => {
let tlv = Tlv::new( let tlv = Tlv::new(
@ -466,7 +450,7 @@ impl CardApp {
fn pso_compute_digital_signature( fn pso_compute_digital_signature(
&mut self, &mut self,
data: Vec<u8>, data: Vec<u8>,
) -> Result<Vec<u8>, OpenpgpCardError> { ) -> Result<Vec<u8>, Error> {
let dec_cmd = commands::signature(data); let dec_cmd = commands::signature(data);
let resp = apdu::send_command(&mut self.card_client, dec_cmd, true)?; let resp = apdu::send_command(&mut self.card_client, dec_cmd, true)?;
@ -492,33 +476,24 @@ impl CardApp {
Ok(resp.data()?.to_vec()) Ok(resp.data()?.to_vec())
} }
pub fn set_name( pub fn set_name(&mut self, name: &str) -> Result<Response, Error> {
&mut self,
name: &str,
) -> Result<Response, OpenpgpCardError> {
let put_name = commands::put_name(name.as_bytes().to_vec()); let put_name = commands::put_name(name.as_bytes().to_vec());
apdu::send_command(&mut self.card_client, put_name, false)?.try_into() apdu::send_command(&mut self.card_client, put_name, false)?.try_into()
} }
pub fn set_lang( pub fn set_lang(&mut self, lang: &str) -> Result<Response, Error> {
&mut self,
lang: &str,
) -> Result<Response, OpenpgpCardError> {
let put_lang = commands::put_lang(lang.as_bytes().to_vec()); let put_lang = commands::put_lang(lang.as_bytes().to_vec());
apdu::send_command(self.card_client.borrow_mut(), put_lang, false)? apdu::send_command(self.card_client.borrow_mut(), put_lang, false)?
.try_into() .try_into()
} }
pub fn set_sex(&mut self, sex: Sex) -> Result<Response, OpenpgpCardError> { pub fn set_sex(&mut self, sex: Sex) -> Result<Response, Error> {
let put_sex = commands::put_sex((&sex).into()); let put_sex = commands::put_sex((&sex).into());
apdu::send_command(self.card_client.borrow_mut(), put_sex, false)? apdu::send_command(self.card_client.borrow_mut(), put_sex, false)?
.try_into() .try_into()
} }
pub fn set_url( pub fn set_url(&mut self, url: &str) -> Result<Response, Error> {
&mut self,
url: &str,
) -> Result<Response, OpenpgpCardError> {
let put_url = commands::put_url(url.as_bytes().to_vec()); let put_url = commands::put_url(url.as_bytes().to_vec());
apdu::send_command(&mut self.card_client, put_url, false)?.try_into() apdu::send_command(&mut self.card_client, put_url, false)?.try_into()
} }
@ -527,7 +502,7 @@ impl CardApp {
&mut self, &mut self,
time: KeyGenerationTime, time: KeyGenerationTime,
key_type: KeyType, key_type: KeyType,
) -> Result<Response, OpenpgpCardError> { ) -> Result<Response, Error> {
// Timestamp update // Timestamp update
let time_value: Vec<u8> = time let time_value: Vec<u8> = time
.get() .get()
@ -549,7 +524,7 @@ impl CardApp {
&mut self, &mut self,
fp: Fingerprint, fp: Fingerprint,
key_type: KeyType, key_type: KeyType,
) -> Result<Response, OpenpgpCardError> { ) -> Result<Response, Error> {
let fp_cmd = commands::put_data( let fp_cmd = commands::put_data(
&[key_type.get_fingerprint_put_tag()], &[key_type.get_fingerprint_put_tag()],
fp.as_bytes().to_vec(), fp.as_bytes().to_vec(),
@ -573,7 +548,7 @@ impl CardApp {
&mut self, &mut self,
pw_status: &PWStatus, pw_status: &PWStatus,
long: bool, long: bool,
) -> Result<Response, OpenpgpCardError> { ) -> Result<Response, Error> {
let data = pw_status.serialize_for_put(long); let data = pw_status.serialize_for_put(long);
let cmd = commands::put_pw_status(data); let cmd = commands::put_pw_status(data);
@ -587,7 +562,7 @@ impl CardApp {
pub fn set_cardholder_certificate( pub fn set_cardholder_certificate(
&mut self, &mut self,
data: Vec<u8>, data: Vec<u8>,
) -> Result<Response, OpenpgpCardError> { ) -> Result<Response, Error> {
let cmd = commands::put_cardholder_certificate(data); let cmd = commands::put_cardholder_certificate(data);
apdu::send_command(&mut self.card_client, cmd, false)?.try_into() apdu::send_command(&mut self.card_client, cmd, false)?.try_into()
} }
@ -598,7 +573,7 @@ impl CardApp {
&mut self, &mut self,
key_type: KeyType, key_type: KeyType,
algo: &Algo, algo: &Algo,
) -> Result<Response, OpenpgpCardError> { ) -> Result<Response, Error> {
// FIXME: caching? // FIXME: caching?
let ard = self.get_app_data()?; let ard = self.get_app_data()?;
@ -668,7 +643,7 @@ impl CardApp {
&mut self, &mut self,
key: Box<dyn CardUploadableKey>, key: Box<dyn CardUploadableKey>,
key_type: KeyType, key_type: KeyType,
) -> Result<(), OpenpgpCardError> { ) -> Result<(), Error> {
let algo_list = self.get_algo_info(); let algo_list = self.get_algo_info();
// An error is ok - it's fine if a card doesn't offer a list of // An error is ok - it's fine if a card doesn't offer a list of
@ -689,10 +664,10 @@ impl CardApp {
&PublicKeyMaterial, &PublicKeyMaterial,
KeyGenerationTime, KeyGenerationTime,
KeyType, KeyType,
) -> Result<Fingerprint, OpenpgpCardError>, ) -> Result<Fingerprint, Error>,
key_type: KeyType, key_type: KeyType,
algo: Option<&Algo>, algo: Option<&Algo>,
) -> Result<(PublicKeyMaterial, KeyGenerationTime), OpenpgpCardError> { ) -> Result<(PublicKeyMaterial, KeyGenerationTime), Error> {
keys::gen_key_with_metadata(self, fp_from_pub, key_type, algo) keys::gen_key_with_metadata(self, fp_from_pub, key_type, algo)
} }
@ -707,10 +682,10 @@ impl CardApp {
&PublicKeyMaterial, &PublicKeyMaterial,
KeyGenerationTime, KeyGenerationTime,
KeyType, KeyType,
) -> Result<Fingerprint, OpenpgpCardError>, ) -> Result<Fingerprint, Error>,
key_type: KeyType, key_type: KeyType,
algo: AlgoSimple, algo: AlgoSimple,
) -> Result<(PublicKeyMaterial, KeyGenerationTime), OpenpgpCardError> { ) -> Result<(PublicKeyMaterial, KeyGenerationTime), Error> {
let algo = algo.get_algo(key_type); let algo = algo.get_algo(key_type);
self.generate_key(fp_from_pub, key_type, Some(&algo)) self.generate_key(fp_from_pub, key_type, Some(&algo))
} }
@ -724,7 +699,7 @@ impl CardApp {
pub fn get_pub_key( pub fn get_pub_key(
&mut self, &mut self,
key_type: KeyType, key_type: KeyType,
) -> Result<PublicKeyMaterial, OpenpgpCardError> { ) -> Result<PublicKeyMaterial, Error> {
keys::get_pub_key(self, key_type) keys::get_pub_key(self, key_type)
} }
} }

View file

@ -8,9 +8,8 @@ use nom::{combinator, number::complete as number, sequence};
use std::collections::HashSet; use std::collections::HashSet;
use std::convert::TryFrom; use std::convert::TryFrom;
use crate::card_do::complete; use crate::card_do::{complete, ExtendedCap, Features};
use crate::card_do::{ExtendedCap, Features}; use crate::Error;
use crate::errors::OpenpgpCardError;
fn features(input: &[u8]) -> nom::IResult<&[u8], HashSet<Features>> { fn features(input: &[u8]) -> nom::IResult<&[u8], HashSet<Features>> {
combinator::map(number::u8, |b| { combinator::map(number::u8, |b| {
@ -70,7 +69,7 @@ impl ExtendedCap {
} }
impl TryFrom<&[u8]> for ExtendedCap { impl TryFrom<&[u8]> for ExtendedCap {
type Error = OpenpgpCardError; type Error = Error;
fn try_from(input: &[u8]) -> Result<Self, Self::Error> { fn try_from(input: &[u8]) -> Result<Self, Self::Error> {
let ec = complete(parse(input))?; let ec = complete(parse(input))?;

View file

@ -10,7 +10,7 @@ use std::convert::TryInto;
use std::fmt; use std::fmt;
use crate::card_do::{Fingerprint, KeySet}; use crate::card_do::{Fingerprint, KeySet};
use crate::errors::OpenpgpCardError; use crate::Error;
impl From<[u8; 20]> for Fingerprint { impl From<[u8; 20]> for Fingerprint {
fn from(data: [u8; 20]) -> Self { fn from(data: [u8; 20]) -> Self {
@ -19,7 +19,7 @@ impl From<[u8; 20]> for Fingerprint {
} }
impl TryFrom<&[u8]> for Fingerprint { impl TryFrom<&[u8]> for Fingerprint {
type Error = OpenpgpCardError; type Error = Error;
fn try_from(input: &[u8]) -> Result<Self, Self::Error> { fn try_from(input: &[u8]) -> Result<Self, Self::Error> {
log::trace!( log::trace!(
@ -84,9 +84,7 @@ fn fingerprints(input: &[u8]) -> nom::IResult<&[u8], KeySet<Fingerprint>> {
} }
/// Parse three fingerprints from the card into a KeySet of Fingerprints /// Parse three fingerprints from the card into a KeySet of Fingerprints
pub(crate) fn to_keyset( pub(crate) fn to_keyset(input: &[u8]) -> Result<KeySet<Fingerprint>, Error> {
input: &[u8],
) -> Result<KeySet<Fingerprint>, OpenpgpCardError> {
log::trace!("Fingerprint from input: {:x?}, len {}", input, input.len()); log::trace!("Fingerprint from input: {:x?}, len {}", input, input.len());
// The input may be longer than 3 fingerprint, don't fail if it hasn't // The input may be longer than 3 fingerprint, don't fail if it hasn't
@ -94,5 +92,5 @@ pub(crate) fn to_keyset(
self::fingerprints(input) self::fingerprints(input)
.map(|res| res.1) .map(|res| res.1)
.map_err(|err| anyhow!("Parsing failed: {:?}", err)) .map_err(|err| anyhow!("Parsing failed: {:?}", err))
.map_err(OpenpgpCardError::InternalError) .map_err(Error::InternalError)
} }

View file

@ -4,7 +4,7 @@
//! 6 Historical Bytes //! 6 Historical Bytes
use crate::card_do::{CardCapabilities, CardServiceData, Historical}; use crate::card_do::{CardCapabilities, CardServiceData, Historical};
use crate::errors::OpenpgpCardError; use crate::Error;
use anyhow::{anyhow, Result}; use anyhow::{anyhow, Result};
use std::convert::TryFrom; use std::convert::TryFrom;
@ -78,7 +78,7 @@ impl Historical {
} }
impl TryFrom<&[u8]> for Historical { impl TryFrom<&[u8]> for Historical {
type Error = OpenpgpCardError; type Error = Error;
fn try_from(data: &[u8]) -> Result<Self, Self::Error> { fn try_from(data: &[u8]) -> Result<Self, Self::Error> {
let len = data.len(); let len = data.len();

View file

@ -7,9 +7,8 @@ use anyhow::anyhow;
use chrono::{DateTime, NaiveDateTime, Utc}; use chrono::{DateTime, NaiveDateTime, Utc};
use nom::{combinator, number::complete as number, sequence}; use nom::{combinator, number::complete as number, sequence};
use crate::card_do::KeyGenerationTime; use crate::card_do::{KeyGenerationTime, KeySet};
use crate::card_do::KeySet; use crate::Error;
use crate::errors::OpenpgpCardError;
impl From<KeyGenerationTime> for DateTime<Utc> { impl From<KeyGenerationTime> for DateTime<Utc> {
fn from(kg: KeyGenerationTime) -> Self { fn from(kg: KeyGenerationTime) -> Self {
@ -54,9 +53,7 @@ fn key_generation_set(
)))(input) )))(input)
} }
pub fn from( pub fn from(input: &[u8]) -> Result<KeySet<KeyGenerationTime>, Error> {
input: &[u8],
) -> Result<KeySet<KeyGenerationTime>, OpenpgpCardError> {
// List of generation dates/times of key pairs, binary. // List of generation dates/times of key pairs, binary.
// 4 bytes, Big Endian each for Sig, Dec and Aut. Each // 4 bytes, Big Endian each for Sig, Dec and Aut. Each
// value shall be seconds since Jan 1, 1970. Default // value shall be seconds since Jan 1, 1970. Default
@ -73,5 +70,5 @@ pub fn from(
self::key_generation_set(input) self::key_generation_set(input)
.map(|res| res.1) .map(|res| res.1)
.map_err(|err| anyhow!("Parsing failed: {:?}", err)) .map_err(|err| anyhow!("Parsing failed: {:?}", err))
.map_err(OpenpgpCardError::InternalError) .map_err(Error::InternalError)
} }

View file

@ -3,15 +3,12 @@
//! OpenPGP card data objects (DO) //! OpenPGP card data objects (DO)
use anyhow::{anyhow, Error, Result}; use anyhow::{anyhow, Result};
use std::collections::HashSet; use std::collections::HashSet;
use std::convert::TryFrom; use std::convert::TryFrom;
use std::convert::TryInto; use std::convert::TryInto;
use crate::algorithm::Algo; use crate::{algorithm::Algo, tlv::Tlv, Error, KeyType};
use crate::errors::OpenpgpCardError;
use crate::tlv::Tlv;
use crate::KeyType;
mod algo_attrs; mod algo_attrs;
mod algo_info; mod algo_info;
@ -36,9 +33,7 @@ pub struct ApplicationRelatedData(pub(crate) Tlv);
impl ApplicationRelatedData { impl ApplicationRelatedData {
/// Application identifier (AID), ISO 7816-4 /// Application identifier (AID), ISO 7816-4
pub fn get_application_id( pub fn get_application_id(&self) -> Result<ApplicationId, Error> {
&self,
) -> Result<ApplicationId, OpenpgpCardError> {
// get from cached "application related data" // get from cached "application related data"
let aid = self.0.find(&[0x4f].into()); let aid = self.0.find(&[0x4f].into());
@ -50,7 +45,7 @@ impl ApplicationRelatedData {
} }
/// Historical bytes /// Historical bytes
pub fn get_historical(&self) -> Result<Historical, OpenpgpCardError> { pub fn get_historical(&self) -> Result<Historical, Error> {
// get from cached "application related data" // get from cached "application related data"
let hist = self.0.find(&[0x5f, 0x52].into()); let hist = self.0.find(&[0x5f, 0x52].into());
@ -90,9 +85,7 @@ impl ApplicationRelatedData {
} }
/// Extended Capabilities /// Extended Capabilities
pub fn get_extended_capabilities( pub fn get_extended_capabilities(&self) -> Result<ExtendedCap, Error> {
&self,
) -> Result<ExtendedCap, OpenpgpCardError> {
// get from cached "application related data" // get from cached "application related data"
let ecap = self.0.find(&[0xc0].into()); let ecap = self.0.find(&[0xc0].into());
@ -136,9 +129,7 @@ impl ApplicationRelatedData {
/// Fingerprint, per key type. /// Fingerprint, per key type.
/// Zero bytes indicate a not defined private key. /// Zero bytes indicate a not defined private key.
pub fn get_fingerprints( pub fn get_fingerprints(&self) -> Result<KeySet<Fingerprint>, Error> {
&self,
) -> Result<KeySet<Fingerprint>, OpenpgpCardError> {
// Get from cached "application related data" // Get from cached "application related data"
let fp = self.0.find(&[0xc5].into()); let fp = self.0.find(&[0xc5].into());
@ -156,7 +147,7 @@ impl ApplicationRelatedData {
/// Generation dates/times of key pairs /// Generation dates/times of key pairs
pub fn get_key_generation_times( pub fn get_key_generation_times(
&self, &self,
) -> Result<KeySet<KeyGenerationTime>, OpenpgpCardError> { ) -> Result<KeySet<KeyGenerationTime>, Error> {
let kg = self.0.find(&[0xcd].into()); let kg = self.0.find(&[0xcd].into());
if let Some(kg) = kg { if let Some(kg) = kg {
@ -373,7 +364,9 @@ impl<T> KeySet<T> {
} }
/// nom parsing helper /// nom parsing helper
pub(crate) fn complete<O>(result: nom::IResult<&[u8], O>) -> Result<O, Error> { pub(crate) fn complete<O>(
result: nom::IResult<&[u8], O>,
) -> Result<O, anyhow::Error> {
let (rem, output) = let (rem, output) =
result.map_err(|err| anyhow!("Parsing failed: {:?}", err))?; result.map_err(|err| anyhow!("Parsing failed: {:?}", err))?;
if rem.is_empty() { if rem.is_empty() {

View file

@ -6,10 +6,10 @@
use anyhow::anyhow; use anyhow::anyhow;
use crate::card_do::PWStatus; use crate::card_do::PWStatus;
use crate::errors::OpenpgpCardError; use crate::Error;
impl PWStatus { impl PWStatus {
pub fn try_from(input: &[u8]) -> Result<Self, OpenpgpCardError> { pub fn try_from(input: &[u8]) -> Result<Self, Error> {
if input.len() == 7 { if input.len() == 7 {
let pw1_cds_multi = input[0] == 0x01; let pw1_cds_multi = input[0] == 0x01;
let pw1_pin_block = input[1] & 0x80 != 0; let pw1_pin_block = input[1] & 0x80 != 0;
@ -33,7 +33,7 @@ impl PWStatus {
err_count_pw3, err_count_pw3,
}) })
} else { } else {
Err(OpenpgpCardError::InternalError(anyhow!( Err(Error::InternalError(anyhow!(
"Unexpected length of PW Status Bytes: {}", "Unexpected length of PW Status Bytes: {}",
input.len() input.len()
))) )))

View file

@ -9,7 +9,7 @@ use anyhow::Result;
use crate::algorithm::Algo; use crate::algorithm::Algo;
use crate::card_do::{Fingerprint, KeyGenerationTime}; use crate::card_do::{Fingerprint, KeyGenerationTime};
use crate::errors::OpenpgpCardError; use crate::Error;
/// A hash value that can be signed by the card. /// A hash value that can be signed by the card.
#[non_exhaustive] #[non_exhaustive]
@ -71,7 +71,7 @@ pub trait CardUploadableKey {
fn get_ts(&self) -> KeyGenerationTime; fn get_ts(&self) -> KeyGenerationTime;
/// fingerprint /// fingerprint
fn get_fp(&self) -> Result<Fingerprint, OpenpgpCardError>; fn get_fp(&self) -> Result<Fingerprint, Error>;
} }
/// Algorithm-independent container for private key material to upload to /// Algorithm-independent container for private key material to upload to

View file

@ -3,24 +3,22 @@
//! Error types used by this crate. //! Error types used by this crate.
//! //!
//! [`OpenpgpCardError`] is a wrapper enum for all error types that are used. //! [`Error`] is a wrapper enum for all error types that are used.
//! //!
//! The two main classes of errors are: //! The two main classes of errors are:
//! - [`SmartcardError`], for problems on the reader/smartcard layer //! - [`SmartcardError`], for problems on the reader/smartcard layer
//! - [`OcErrorStatus`], which models error statuses reported by the OpenPGP //! - [`StatusByte`], which models error statuses reported by the OpenPGP
//! card application //! card application
use thiserror::Error; /// Enum wrapper for the different error types of this crate
#[derive(thiserror::Error, Debug)]
/// Enum that wraps the different error types that this crate can return
#[derive(Error, Debug)]
#[non_exhaustive] #[non_exhaustive]
pub enum OpenpgpCardError { pub enum Error {
#[error("Error interacting with smartcard: {0}")] #[error("Error interacting with smartcard: {0}")]
Smartcard(SmartcardError), Smartcard(SmartcardError),
#[error("OpenPGP card error status: {0}")] #[error("OpenPGP card error status: {0}")]
OcStatus(OcErrorStatus), CardStatus(StatusByte),
#[error("Command too long ({0} bytes)")] #[error("Command too long ({0} bytes)")]
CommandTooLong(usize), CommandTooLong(usize),
@ -32,22 +30,22 @@ pub enum OpenpgpCardError {
InternalError(anyhow::Error), InternalError(anyhow::Error),
} }
impl From<OcErrorStatus> for OpenpgpCardError { impl From<StatusByte> for Error {
fn from(oce: OcErrorStatus) -> Self { fn from(oce: StatusByte) -> Self {
OpenpgpCardError::OcStatus(oce) Error::CardStatus(oce)
} }
} }
impl From<anyhow::Error> for OpenpgpCardError { impl From<anyhow::Error> for Error {
fn from(ae: anyhow::Error) -> Self { fn from(ae: anyhow::Error) -> Self {
OpenpgpCardError::InternalError(ae) Error::InternalError(ae)
} }
} }
/// OpenPGP card "Status Byte" errors /// OpenPGP card "Status Byte" errors
#[derive(Error, Debug, PartialEq)] #[derive(thiserror::Error, Debug, PartialEq)]
#[non_exhaustive] #[non_exhaustive]
pub enum OcErrorStatus { pub enum StatusByte {
#[error("Selected file or DO in termination state")] #[error("Selected file or DO in termination state")]
TerminationState, TerminationState,
@ -118,40 +116,40 @@ pub enum OcErrorStatus {
UnknownStatus(u8, u8), UnknownStatus(u8, u8),
} }
impl From<(u8, u8)> for OcErrorStatus { impl From<(u8, u8)> for StatusByte {
fn from(status: (u8, u8)) -> Self { fn from(status: (u8, u8)) -> Self {
match (status.0, status.1) { match (status.0, status.1) {
(0x62, 0x85) => OcErrorStatus::TerminationState, (0x62, 0x85) => StatusByte::TerminationState,
(0x63, 0xC0..=0xCF) => { (0x63, 0xC0..=0xCF) => {
OcErrorStatus::PasswordNotChecked(status.1 & 0xf) StatusByte::PasswordNotChecked(status.1 & 0xf)
} }
(0x64, 0x02..=0x80) => OcErrorStatus::TriggeringByCard(status.1), (0x64, 0x02..=0x80) => StatusByte::TriggeringByCard(status.1),
(0x65, 0x01) => OcErrorStatus::MemoryFailure, (0x65, 0x01) => StatusByte::MemoryFailure,
(0x66, 0x00) => OcErrorStatus::SecurityRelatedIssues, (0x66, 0x00) => StatusByte::SecurityRelatedIssues,
(0x67, 0x00) => OcErrorStatus::WrongLength, (0x67, 0x00) => StatusByte::WrongLength,
(0x68, 0x81) => OcErrorStatus::LogicalChannelNotSupported, (0x68, 0x81) => StatusByte::LogicalChannelNotSupported,
(0x68, 0x82) => OcErrorStatus::SecureMessagingNotSupported, (0x68, 0x82) => StatusByte::SecureMessagingNotSupported,
(0x68, 0x83) => OcErrorStatus::LastCommandOfChainExpected, (0x68, 0x83) => StatusByte::LastCommandOfChainExpected,
(0x68, 0x84) => OcErrorStatus::CommandChainingUnsupported, (0x68, 0x84) => StatusByte::CommandChainingUnsupported,
(0x69, 0x82) => OcErrorStatus::SecurityStatusNotSatisfied, (0x69, 0x82) => StatusByte::SecurityStatusNotSatisfied,
(0x69, 0x83) => OcErrorStatus::AuthenticationMethodBlocked, (0x69, 0x83) => StatusByte::AuthenticationMethodBlocked,
(0x69, 0x85) => OcErrorStatus::ConditionOfUseNotSatisfied, (0x69, 0x85) => StatusByte::ConditionOfUseNotSatisfied,
(0x69, 0x87) => OcErrorStatus::ExpectedSecureMessagingDOsMissing, (0x69, 0x87) => StatusByte::ExpectedSecureMessagingDOsMissing,
(0x69, 0x88) => OcErrorStatus::SMDataObjectsIncorrect, (0x69, 0x88) => StatusByte::SMDataObjectsIncorrect,
(0x6A, 0x80) => OcErrorStatus::IncorrectParametersCommandDataField, (0x6A, 0x80) => StatusByte::IncorrectParametersCommandDataField,
(0x6A, 0x82) => OcErrorStatus::FileOrApplicationNotFound, (0x6A, 0x82) => StatusByte::FileOrApplicationNotFound,
(0x6A, 0x88) => OcErrorStatus::ReferencedDataNotFound, (0x6A, 0x88) => StatusByte::ReferencedDataNotFound,
(0x6B, 0x00) => OcErrorStatus::WrongParametersP1P2, (0x6B, 0x00) => StatusByte::WrongParametersP1P2,
(0x6D, 0x00) => OcErrorStatus::INSNotSupported, (0x6D, 0x00) => StatusByte::INSNotSupported,
(0x6E, 0x00) => OcErrorStatus::CLANotSupported, (0x6E, 0x00) => StatusByte::CLANotSupported,
(0x6F, 0x00) => OcErrorStatus::NoPreciseDiagnosis, (0x6F, 0x00) => StatusByte::NoPreciseDiagnosis,
_ => OcErrorStatus::UnknownStatus(status.0, status.1), _ => StatusByte::UnknownStatus(status.0, status.1),
} }
} }
} }
/// Errors on the smartcard/reader layer /// Errors on the smartcard/reader layer
#[derive(Error, Debug)] #[derive(thiserror::Error, Debug)]
#[non_exhaustive] #[non_exhaustive]
pub enum SmartcardError { pub enum SmartcardError {
#[error("Failed to create a pcsc smartcard context {0}")] #[error("Failed to create a pcsc smartcard context {0}")]

View file

@ -16,8 +16,8 @@ use crate::crypto_data::{
CardUploadableKey, EccKey, EccPub, PrivateKeyMaterial, PublicKeyMaterial, CardUploadableKey, EccKey, EccPub, PrivateKeyMaterial, PublicKeyMaterial,
RSAKey, RSAPub, RSAKey, RSAPub,
}; };
use crate::errors::OpenpgpCardError;
use crate::tlv::{length::tlv_encode_length, value::Value, Tlv}; use crate::tlv::{length::tlv_encode_length, value::Value, Tlv};
use crate::Error;
use crate::{apdu, KeyType}; use crate::{apdu, KeyType};
/// Generate asymmetric key pair on the card. /// Generate asymmetric key pair on the card.
@ -36,10 +36,10 @@ pub(crate) fn gen_key_with_metadata(
&PublicKeyMaterial, &PublicKeyMaterial,
KeyGenerationTime, KeyGenerationTime,
KeyType, KeyType,
) -> Result<Fingerprint, OpenpgpCardError>, ) -> Result<Fingerprint, Error>,
key_type: KeyType, key_type: KeyType,
algo: Option<&Algo>, algo: Option<&Algo>,
) -> Result<(PublicKeyMaterial, KeyGenerationTime), OpenpgpCardError> { ) -> Result<(PublicKeyMaterial, KeyGenerationTime), Error> {
// set algo on card if it's Some // set algo on card if it's Some
if let Some(algo) = algo { if let Some(algo) = algo {
card_app.set_algorithm_attributes(key_type, algo)?; card_app.set_algorithm_attributes(key_type, algo)?;
@ -63,7 +63,7 @@ pub(crate) fn gen_key_with_metadata(
// Store creation timestamp (unix time format, limited to u32) // Store creation timestamp (unix time format, limited to u32)
let ts = time let ts = time
.duration_since(UNIX_EPOCH) .duration_since(UNIX_EPOCH)
.map_err(|e| OpenpgpCardError::InternalError(anyhow!(e)))? .map_err(|e| Error::InternalError(anyhow!(e)))?
.as_secs() as u32; .as_secs() as u32;
let ts = ts.into(); let ts = ts.into();
@ -100,8 +100,7 @@ fn tlv_to_pubkey(tlv: &Tlv, algo: &Algo) -> Result<PublicKeyMaterial> {
(_, _, _) => Err(anyhow!( (_, _, _) => Err(anyhow!(
"Unexpected public key material from card {:?}", "Unexpected public key material from card {:?}",
tlv tlv
) )),
.into()),
} }
} }
@ -112,7 +111,7 @@ fn tlv_to_pubkey(tlv: &Tlv, algo: &Algo) -> Result<PublicKeyMaterial> {
pub(crate) fn generate_asymmetric_key_pair( pub(crate) fn generate_asymmetric_key_pair(
card_app: &mut CardApp, card_app: &mut CardApp,
key_type: KeyType, key_type: KeyType,
) -> Result<Tlv, OpenpgpCardError> { ) -> Result<Tlv, Error> {
// generate key // generate key
let crt = get_crt(key_type)?; let crt = get_crt(key_type)?;
let gen_key_cmd = commands::gen_key(crt.serialize().to_vec()); let gen_key_cmd = commands::gen_key(crt.serialize().to_vec());
@ -136,7 +135,7 @@ pub(crate) fn generate_asymmetric_key_pair(
pub(crate) fn get_pub_key( pub(crate) fn get_pub_key(
card_app: &mut CardApp, card_app: &mut CardApp,
key_type: KeyType, key_type: KeyType,
) -> Result<PublicKeyMaterial, OpenpgpCardError> { ) -> Result<PublicKeyMaterial, Error> {
// algo // algo
let ard = card_app.get_app_data()?; // FIXME: caching let ard = card_app.get_app_data()?; // FIXME: caching
let algo = ard.get_algorithm_attributes(key_type)?; let algo = ard.get_algorithm_attributes(key_type)?;
@ -163,7 +162,7 @@ pub(crate) fn key_import(
key: Box<dyn CardUploadableKey>, key: Box<dyn CardUploadableKey>,
key_type: KeyType, key_type: KeyType,
algo_list: Option<AlgoInfo>, algo_list: Option<AlgoInfo>,
) -> Result<(), OpenpgpCardError> { ) -> Result<(), Error> {
let (algo, key_cmd) = match key.get_key()? { let (algo, key_cmd) = match key.get_key()? {
PrivateKeyMaterial::R(rsa_key) => { PrivateKeyMaterial::R(rsa_key) => {
// RSA bitsize // RSA bitsize
@ -262,7 +261,7 @@ fn get_card_algo_rsa(
algo_list: AlgoInfo, algo_list: AlgoInfo,
key_type: KeyType, key_type: KeyType,
rsa_bits: u16, rsa_bits: u16,
) -> Result<RsaAttrs, OpenpgpCardError> { ) -> Result<RsaAttrs, Error> {
// Find suitable algorithm parameters (from card's list of algorithms). // Find suitable algorithm parameters (from card's list of algorithms).
// FIXME: handle "no list available" (older cards?) // FIXME: handle "no list available" (older cards?)
// (Current algo parameters of the key slot should be used, then (?)) // (Current algo parameters of the key slot should be used, then (?))
@ -323,7 +322,7 @@ fn check_card_algo_ecc(
fn ecc_key_import_cmd( fn ecc_key_import_cmd(
ecc_key: Box<dyn EccKey>, ecc_key: Box<dyn EccKey>,
key_type: KeyType, key_type: KeyType,
) -> Result<Command, OpenpgpCardError> { ) -> Result<Command, Error> {
let scalar_data = ecc_key.get_scalar(); let scalar_data = ecc_key.get_scalar();
let scalar_len = scalar_data.len() as u8; let scalar_len = scalar_data.len() as u8;
@ -348,7 +347,7 @@ fn rsa_key_import_cmd(
key_type: KeyType, key_type: KeyType,
rsa_key: Box<dyn RSAKey>, rsa_key: Box<dyn RSAKey>,
algo_attrs: &RsaAttrs, algo_attrs: &RsaAttrs,
) -> Result<Command, OpenpgpCardError> { ) -> Result<Command, Error> {
// Assemble key command, which contains three sub-TLV: // Assemble key command, which contains three sub-TLV:
// 1) "Control Reference Template" // 1) "Control Reference Template"
@ -411,17 +410,13 @@ fn rsa_key_import_cmd(
} }
/// Get "Control Reference Template" Tlv for `key_type` /// Get "Control Reference Template" Tlv for `key_type`
fn get_crt(key_type: KeyType) -> Result<Tlv, OpenpgpCardError> { fn get_crt(key_type: KeyType) -> Result<Tlv, Error> {
// "Control Reference Template" (0xB8 | 0xB6 | 0xA4) // "Control Reference Template" (0xB8 | 0xB6 | 0xA4)
let tag = match key_type { let tag = match key_type {
KeyType::Decryption => 0xB8, KeyType::Decryption => 0xB8,
KeyType::Signing => 0xB6, KeyType::Signing => 0xB6,
KeyType::Authentication => 0xA4, KeyType::Authentication => 0xA4,
_ => { _ => return Err(Error::InternalError(anyhow!("Unexpected KeyType"))),
return Err(OpenpgpCardError::InternalError(anyhow!(
"Unexpected KeyType"
)))
}
}; };
Ok(Tlv::new([tag], Value::S(vec![]))) Ok(Tlv::new([tag], Value::S(vec![])))
} }

View file

@ -32,12 +32,13 @@ mod apdu;
mod card_app; mod card_app;
pub mod card_do; pub mod card_do;
pub mod crypto_data; pub mod crypto_data;
pub mod errors; mod errors;
mod keys; mod keys;
mod tlv; mod tlv;
pub use crate::apdu::response::Response; pub use crate::apdu::response::Response;
pub use crate::card_app::CardApp; pub use crate::card_app::CardApp;
pub use crate::errors::{Error, SmartcardError, StatusByte};
/// The CardClient trait defines communication with an OpenPGP card via a /// The CardClient trait defines communication with an OpenPGP card via a
/// backend implementation (e.g. the pcsc backend in the crate /// backend implementation (e.g. the pcsc backend in the crate

View file

@ -2,10 +2,11 @@
// SPDX-License-Identifier: MIT OR Apache-2.0 // SPDX-License-Identifier: MIT OR Apache-2.0
use anyhow::{anyhow, Result}; use anyhow::{anyhow, Result};
use pcsc::{Card, Context, Error, Protocols, Scope, ShareMode}; use pcsc::{Card, Context, Protocols, Scope, ShareMode};
use openpgp_card::errors::{OpenpgpCardError, SmartcardError}; use openpgp_card::{
use openpgp_card::{CardApp, CardCaps, CardClient, CardClientBox}; CardApp, CardCaps, CardClient, CardClientBox, Error, SmartcardError,
};
pub struct PcscClient { pub struct PcscClient {
card: Card, card: Card,
@ -51,7 +52,7 @@ impl PcscClient {
let card = let card =
match ctx.connect(reader, ShareMode::Shared, Protocols::ANY) { match ctx.connect(reader, ShareMode::Shared, Protocols::ANY) {
Ok(card) => card, Ok(card) => card,
Err(Error::NoSmartcard) => { Err(pcsc::Error::NoSmartcard) => {
continue; // try next reader continue; // try next reader
} }
Err(err) => { Err(err) => {
@ -94,16 +95,14 @@ impl PcscClient {
} }
/// Try to select the OpenPGP application on a card /// Try to select the OpenPGP application on a card
fn select(card_client: PcscClient) -> Result<CardApp, OpenpgpCardError> { fn select(card_client: PcscClient) -> Result<CardApp, Error> {
let ccb = Box::new(card_client) as CardClientBox; let ccb = Box::new(card_client) as CardClientBox;
let mut ca = CardApp::from(ccb); let mut ca = CardApp::from(ccb);
if ca.select().is_ok() { if ca.select().is_ok() {
Ok(ca) Ok(ca)
} else { } else {
Err(OpenpgpCardError::Smartcard( Err(Error::Smartcard(SmartcardError::SelectOpenPGPCardFailed))
SmartcardError::SelectOpenPGPCardFailed,
))
} }
} }
@ -111,14 +110,14 @@ impl PcscClient {
/// ///
/// If multiple cards are connected, this will effectively be a random /// If multiple cards are connected, this will effectively be a random
/// pick. You should consider using `open_by_ident` instead. /// pick. You should consider using `open_by_ident` instead.
pub fn open_yolo() -> Result<CardClientBox, OpenpgpCardError> { pub fn open_yolo() -> Result<CardClientBox, Error> {
for card in Self::unopened_cards()? { for card in Self::unopened_cards()? {
if let Ok(ca) = Self::select(card) { if let Ok(ca) = Self::select(card) {
return Ok(ca.into()); return Ok(ca.into());
} }
} }
Err(OpenpgpCardError::Smartcard(SmartcardError::CardNotFound( Err(Error::Smartcard(SmartcardError::CardNotFound(
"No OpenPGP card found".to_string(), "No OpenPGP card found".to_string(),
))) )))
} }
@ -128,7 +127,7 @@ impl PcscClient {
fn match_by_ident( fn match_by_ident(
mut ca: CardApp, mut ca: CardApp,
ident: &str, ident: &str,
) -> Result<Option<CardClientBox>, OpenpgpCardError> { ) -> Result<Option<CardClientBox>, Error> {
let ard = ca.get_app_data()?; let ard = ca.get_app_data()?;
let aid = ard.get_application_id()?; let aid = ard.get_application_id()?;
@ -141,9 +140,7 @@ impl PcscClient {
/// Returns the OpenPGP card that matches `ident`, if it is available. /// Returns the OpenPGP card that matches `ident`, if it is available.
/// The OpenPGP application of the `CardClientBox` has been selected. /// The OpenPGP application of the `CardClientBox` has been selected.
pub fn open_by_ident( pub fn open_by_ident(ident: &str) -> Result<CardClientBox, Error> {
ident: &str,
) -> Result<CardClientBox, OpenpgpCardError> {
for card in Self::unopened_cards()? { for card in Self::unopened_cards()? {
if let Ok(ca) = Self::select(card) { if let Ok(ca) = Self::select(card) {
if let Some(matched_card) = if let Some(matched_card) =
@ -154,7 +151,7 @@ impl PcscClient {
} }
} }
Err(OpenpgpCardError::Smartcard(SmartcardError::CardNotFound( Err(Error::Smartcard(SmartcardError::CardNotFound(
ident.to_string(), ident.to_string(),
))) )))
} }
@ -165,7 +162,7 @@ impl CardClient for PcscClient {
let mut resp_buffer = vec![0; buf_size]; let mut resp_buffer = vec![0; buf_size];
let resp = self.card.transmit(cmd, &mut resp_buffer).map_err(|e| { let resp = self.card.transmit(cmd, &mut resp_buffer).map_err(|e| {
OpenpgpCardError::Smartcard(SmartcardError::Error(format!( Error::Smartcard(SmartcardError::Error(format!(
"Transmit failed: {:?}", "Transmit failed: {:?}",
e e
))) )))

View file

@ -13,7 +13,7 @@ use sequoia_ipc::gnupg::{Agent, Context};
use std::sync::Mutex; use std::sync::Mutex;
use tokio::runtime::Runtime; use tokio::runtime::Runtime;
use openpgp_card::errors::OpenpgpCardError; use openpgp_card::Error;
use openpgp_card::{CardCaps, CardClient, CardClientBox}; use openpgp_card::{CardCaps, CardClient, CardClientBox};
lazy_static! { lazy_static! {
@ -108,9 +108,7 @@ impl ScdClient {
/// Create a CardClientBox object that uses an scdaemon instance as its /// Create a CardClientBox object that uses an scdaemon instance as its
/// backend. If multiple cards are available, scdaemon implicitly /// backend. If multiple cards are available, scdaemon implicitly
/// selects one. /// selects one.
pub fn open( pub fn open(agent: Option<Agent>) -> Result<CardClientBox, Error> {
agent: Option<Agent>,
) -> Result<CardClientBox, OpenpgpCardError> {
let card = ScdClient::new(agent, true)?; let card = ScdClient::new(agent, true)?;
Ok(Box::new(card) as CardClientBox) Ok(Box::new(card) as CardClientBox)
} }
@ -120,7 +118,7 @@ impl ScdClient {
pub fn open_by_serial( pub fn open_by_serial(
agent: Option<Agent>, agent: Option<Agent>,
serial: &str, serial: &str,
) -> Result<CardClientBox, OpenpgpCardError> { ) -> Result<CardClientBox, Error> {
let mut card = ScdClient::new(agent, true)?; let mut card = ScdClient::new(agent, true)?;
card.select_card(serial)?; card.select_card(serial)?;