Rename error types and re-export them at the crate top level.
This commit is contained in:
parent
f501c09d2f
commit
316ca7eb3a
19 changed files with 184 additions and 261 deletions
|
@ -1,19 +1,19 @@
|
|||
// SPDX-FileCopyrightText: 2021 Heiko Schaefer <heiko@schaefer.name>
|
||||
// SPDX-License-Identifier: MIT OR Apache-2.0
|
||||
|
||||
use anyhow::{Error, Result};
|
||||
use anyhow::Result;
|
||||
use std::str::FromStr;
|
||||
use std::string::FromUtf8Error;
|
||||
use thiserror::Error;
|
||||
use thiserror;
|
||||
|
||||
use sequoia_openpgp::parse::Parse;
|
||||
use sequoia_openpgp::serialize::SerializeInto;
|
||||
use sequoia_openpgp::Cert;
|
||||
|
||||
use openpgp_card;
|
||||
use openpgp_card::algorithm::AlgoSimple;
|
||||
use openpgp_card::card_do::{KeyGenerationTime, Sex};
|
||||
use openpgp_card::errors::{OcErrorStatus, OpenpgpCardError};
|
||||
use openpgp_card::{CardApp, KeyType};
|
||||
use openpgp_card::{CardApp, Error, KeyType, StatusByte};
|
||||
use openpgp_card_sequoia::{
|
||||
make_cert, public_key_material_to_key, public_to_fingerprint,
|
||||
};
|
||||
|
@ -23,23 +23,23 @@ use crate::util;
|
|||
|
||||
#[derive(Debug)]
|
||||
pub enum TestResult {
|
||||
Status(OcErrorStatus),
|
||||
Status(StatusByte),
|
||||
StatusOk,
|
||||
Text(String),
|
||||
}
|
||||
|
||||
type TestOutput = Vec<TestResult>;
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
#[derive(thiserror::Error, Debug)]
|
||||
pub enum TestError {
|
||||
#[error("Failed to upload key {0} ({1})")]
|
||||
KeyUploadError(String, Error),
|
||||
KeyUploadError(String, anyhow::Error),
|
||||
|
||||
#[error(transparent)]
|
||||
OPGP(#[from] OpenpgpCardError),
|
||||
OPGP(#[from] Error),
|
||||
|
||||
#[error(transparent)]
|
||||
OCard(#[from] OcErrorStatus),
|
||||
OCard(#[from] StatusByte),
|
||||
|
||||
#[error(transparent)]
|
||||
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!
|
||||
let res = ca.set_name("Notverified<<Hello");
|
||||
|
||||
if let Err(OpenpgpCardError::OcStatus(s)) = res {
|
||||
assert_eq!(s, OcErrorStatus::SecurityStatusNotSatisfied);
|
||||
if let Err(Error::CardStatus(s)) = res {
|
||||
assert_eq!(s, StatusByte::SecurityStatusNotSatisfied);
|
||||
} else {
|
||||
panic!("Status should be 'SecurityStatusNotSatisfied'");
|
||||
}
|
||||
|
@ -494,7 +494,7 @@ pub fn test_verify(
|
|||
ca.verify_pw3("12345678")?;
|
||||
|
||||
match ca.check_pw3() {
|
||||
Err(OpenpgpCardError::OcStatus(s)) => {
|
||||
Err(Error::CardStatus(s)) => {
|
||||
// e.g. yubikey5 returns an error status!
|
||||
out.push(TestResult::Status(s));
|
||||
}
|
||||
|
@ -512,7 +512,7 @@ pub fn test_verify(
|
|||
ca.verify_pw1("123456")?;
|
||||
|
||||
match ca.check_pw3() {
|
||||
Err(OpenpgpCardError::OcStatus(s)) => {
|
||||
Err(Error::CardStatus(s)) => {
|
||||
// e.g. yubikey5 returns an error status!
|
||||
out.push(TestResult::Status(s));
|
||||
}
|
||||
|
|
|
@ -16,8 +16,7 @@ use openpgp::Cert;
|
|||
use sequoia_openpgp as openpgp;
|
||||
|
||||
use openpgp_card::crypto_data::Cryptogram;
|
||||
use openpgp_card::errors::OpenpgpCardError;
|
||||
use openpgp_card::CardApp;
|
||||
use openpgp_card::{CardApp, Error};
|
||||
|
||||
use crate::PublicKey;
|
||||
|
||||
|
@ -38,7 +37,7 @@ impl<'a> CardDecryptor<'a> {
|
|||
ca: &'a mut CardApp,
|
||||
cert: &Cert,
|
||||
policy: &dyn Policy,
|
||||
) -> Result<CardDecryptor<'a>, OpenpgpCardError> {
|
||||
) -> Result<CardDecryptor<'a>, Error> {
|
||||
// Get the fingerprint for the decryption key from the card.
|
||||
let ard = ca.get_app_data()?;
|
||||
let fps = ard.get_fingerprints()?;
|
||||
|
@ -63,12 +62,12 @@ impl<'a> CardDecryptor<'a> {
|
|||
let public = keys[0].clone();
|
||||
Ok(Self { ca, public })
|
||||
} else {
|
||||
Err(OpenpgpCardError::InternalError(anyhow!(
|
||||
Err(Error::InternalError(anyhow!(
|
||||
"Failed to find a matching (sub)key in cert"
|
||||
)))
|
||||
}
|
||||
} else {
|
||||
Err(OpenpgpCardError::InternalError(anyhow!(
|
||||
Err(Error::InternalError(anyhow!(
|
||||
"Failed to get the decryption key's Fingerprint from the card"
|
||||
)))
|
||||
}
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
use anyhow::{anyhow, Context, Result};
|
||||
use std::convert::TryFrom;
|
||||
use std::convert::TryInto;
|
||||
use std::error::Error;
|
||||
use std::io;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::time::SystemTime;
|
||||
|
@ -41,9 +40,7 @@ use openpgp_card::crypto_data::{
|
|||
CardUploadableKey, Cryptogram, EccKey, EccType, Hash, PrivateKeyMaterial,
|
||||
PublicKeyMaterial, RSAKey,
|
||||
};
|
||||
use openpgp_card::{
|
||||
errors::OpenpgpCardError, CardApp, CardClientBox, KeyType, Response,
|
||||
};
|
||||
use openpgp_card::{CardApp, CardClientBox, Error, KeyType, Response};
|
||||
|
||||
use crate::signer::CardSigner;
|
||||
|
||||
|
@ -373,7 +370,7 @@ impl CardUploadableKey for SequoiaKey {
|
|||
ts.into()
|
||||
}
|
||||
|
||||
fn get_fp(&self) -> Result<Fingerprint, OpenpgpCardError> {
|
||||
fn get_fp(&self) -> Result<Fingerprint, Error> {
|
||||
let fp = self.key.fingerprint();
|
||||
fp.as_bytes().try_into()
|
||||
}
|
||||
|
@ -455,7 +452,7 @@ pub fn upload_from_cert_yolo(
|
|||
cert: &openpgp::Cert,
|
||||
key_type: KeyType,
|
||||
password: Option<String>,
|
||||
) -> Result<(), Box<dyn Error>> {
|
||||
) -> Result<(), Box<dyn std::error::Error>> {
|
||||
let policy = StandardPolicy::new();
|
||||
|
||||
// Find all suitable (sub)keys for key_type.
|
||||
|
@ -488,7 +485,7 @@ pub fn upload_key(
|
|||
vka: ValidErasedKeyAmalgamation<SecretParts>,
|
||||
key_type: KeyType,
|
||||
password: Option<String>,
|
||||
) -> Result<(), OpenpgpCardError> {
|
||||
) -> Result<(), Error> {
|
||||
let sqk = SequoiaKey::new(vka, password);
|
||||
|
||||
oca.upload_key(Box::new(sqk), key_type)
|
||||
|
@ -546,7 +543,7 @@ pub fn public_to_fingerprint(
|
|||
pkm: &PublicKeyMaterial,
|
||||
time: KeyGenerationTime,
|
||||
kt: KeyType,
|
||||
) -> Result<Fingerprint, OpenpgpCardError> {
|
||||
) -> Result<Fingerprint, Error> {
|
||||
// Transform PublicKeyMaterial into a Sequoia Key
|
||||
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
|
||||
/// 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"
|
||||
let mut card_app = CardApp::from(ccb);
|
||||
|
||||
|
@ -602,13 +599,11 @@ impl CardBase {
|
|||
self.card_app.get_app_data()
|
||||
}
|
||||
|
||||
pub fn get_application_id(
|
||||
&self,
|
||||
) -> Result<ApplicationId, OpenpgpCardError> {
|
||||
pub fn get_application_id(&self) -> Result<ApplicationId, Error> {
|
||||
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()
|
||||
}
|
||||
|
||||
|
@ -626,9 +621,7 @@ impl CardBase {
|
|||
unimplemented!()
|
||||
}
|
||||
|
||||
pub fn get_extended_capabilities(
|
||||
&self,
|
||||
) -> Result<ExtendedCap, OpenpgpCardError> {
|
||||
pub fn get_extended_capabilities(&self) -> Result<ExtendedCap, Error> {
|
||||
self.ard.get_extended_capabilities()
|
||||
}
|
||||
|
||||
|
@ -641,9 +634,7 @@ impl CardBase {
|
|||
self.ard.get_pw_status_bytes()
|
||||
}
|
||||
|
||||
pub fn get_fingerprints(
|
||||
&self,
|
||||
) -> Result<KeySet<Fingerprint>, OpenpgpCardError> {
|
||||
pub fn get_fingerprints(&self) -> Result<KeySet<Fingerprint>, Error> {
|
||||
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()
|
||||
}
|
||||
|
||||
|
@ -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()
|
||||
}
|
||||
|
||||
|
@ -783,10 +774,7 @@ impl DerefMut for CardUser {
|
|||
|
||||
impl CardUser {
|
||||
/// Decrypt the ciphertext in `dm`, on the card.
|
||||
pub fn decrypt(
|
||||
&mut self,
|
||||
dm: Cryptogram,
|
||||
) -> Result<Vec<u8>, OpenpgpCardError> {
|
||||
pub fn decrypt(&mut self, dm: Cryptogram) -> Result<Vec<u8>, Error> {
|
||||
self.card_app.decrypt(dm)
|
||||
}
|
||||
}
|
||||
|
@ -820,7 +808,7 @@ impl CardSign {
|
|||
pub fn signature_for_hash(
|
||||
&mut self,
|
||||
hash: Hash,
|
||||
) -> Result<Vec<u8>, OpenpgpCardError> {
|
||||
) -> Result<Vec<u8>, Error> {
|
||||
self.card_app.signature_for_hash(hash)
|
||||
}
|
||||
}
|
||||
|
@ -847,10 +835,7 @@ impl DerefMut for CardAdmin {
|
|||
}
|
||||
|
||||
impl CardAdmin {
|
||||
pub fn set_name(
|
||||
&mut self,
|
||||
name: &str,
|
||||
) -> Result<Response, OpenpgpCardError> {
|
||||
pub fn set_name(&mut self, name: &str) -> Result<Response, Error> {
|
||||
if name.len() >= 40 {
|
||||
return Err(anyhow!("name too long").into());
|
||||
}
|
||||
|
@ -863,10 +848,7 @@ impl CardAdmin {
|
|||
self.card_app.set_name(name)
|
||||
}
|
||||
|
||||
pub fn set_lang(
|
||||
&mut self,
|
||||
lang: &str,
|
||||
) -> Result<Response, OpenpgpCardError> {
|
||||
pub fn set_lang(&mut self, lang: &str) -> Result<Response, Error> {
|
||||
if lang.len() > 8 {
|
||||
return Err(anyhow!("lang too long").into());
|
||||
}
|
||||
|
@ -874,14 +856,11 @@ impl CardAdmin {
|
|||
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)
|
||||
}
|
||||
|
||||
pub fn set_url(
|
||||
&mut self,
|
||||
url: &str,
|
||||
) -> Result<Response, OpenpgpCardError> {
|
||||
pub fn set_url(&mut self, url: &str) -> Result<Response, Error> {
|
||||
if url.chars().any(|c| !c.is_ascii()) {
|
||||
return Err(anyhow!("Invalid char in url").into());
|
||||
}
|
||||
|
@ -900,7 +879,7 @@ impl CardAdmin {
|
|||
&mut self,
|
||||
key: Box<dyn CardUploadableKey>,
|
||||
key_type: KeyType,
|
||||
) -> Result<(), OpenpgpCardError> {
|
||||
) -> Result<(), Error> {
|
||||
self.card_app.key_import(key, key_type)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,8 +11,7 @@ use openpgp::types::{Curve, PublicKeyAlgorithm};
|
|||
use sequoia_openpgp as openpgp;
|
||||
|
||||
use openpgp_card::crypto_data::Hash;
|
||||
use openpgp_card::errors::OpenpgpCardError;
|
||||
use openpgp_card::CardApp;
|
||||
use openpgp_card::{CardApp, Error};
|
||||
|
||||
use crate::PublicKey;
|
||||
|
||||
|
@ -33,7 +32,7 @@ impl<'a> CardSigner<'a> {
|
|||
ca: &'a mut CardApp,
|
||||
cert: &openpgp::Cert,
|
||||
policy: &dyn Policy,
|
||||
) -> Result<CardSigner<'a>, OpenpgpCardError> {
|
||||
) -> Result<CardSigner<'a>, Error> {
|
||||
// Get the fingerprint for the signing key from the card.
|
||||
let ard = ca.get_app_data()?;
|
||||
let fps = ard.get_fingerprints()?;
|
||||
|
@ -60,12 +59,12 @@ impl<'a> CardSigner<'a> {
|
|||
|
||||
Ok(Self::with_pubkey(ca, public))
|
||||
} else {
|
||||
Err(OpenpgpCardError::InternalError(anyhow!(
|
||||
Err(Error::InternalError(anyhow!(
|
||||
"Failed to find a matching (sub)key in cert"
|
||||
)))
|
||||
}
|
||||
} else {
|
||||
Err(OpenpgpCardError::InternalError(anyhow!(
|
||||
Err(Error::InternalError(anyhow!(
|
||||
"Failed to get the signing key's Fingerprint \
|
||||
from the card"
|
||||
)))
|
||||
|
|
|
@ -11,10 +11,8 @@ pub mod response;
|
|||
use anyhow::Result;
|
||||
use std::convert::TryFrom;
|
||||
|
||||
use crate::apdu::command::Command;
|
||||
use crate::apdu::response::RawResponse;
|
||||
use crate::errors::{OcErrorStatus, OpenpgpCardError};
|
||||
use crate::CardClientBox;
|
||||
use crate::apdu::{command::Command, response::RawResponse};
|
||||
use crate::{CardClientBox, Error, StatusByte};
|
||||
|
||||
// "Maximum amount of bytes in a short APDU command or response" (from pcsc)
|
||||
const MAX_BUFFER_SIZE: usize = 264;
|
||||
|
@ -34,7 +32,7 @@ pub(crate) fn send_command(
|
|||
card_client: &mut CardClientBox,
|
||||
cmd: Command,
|
||||
expect_reply: bool,
|
||||
) -> Result<RawResponse, OpenpgpCardError> {
|
||||
) -> Result<RawResponse, Error> {
|
||||
let mut resp = RawResponse::try_from(send_command_low_level(
|
||||
card_client,
|
||||
cmd,
|
||||
|
@ -75,7 +73,7 @@ fn send_command_low_level(
|
|||
card_client: &mut CardClientBox,
|
||||
cmd: Command,
|
||||
expect_reply: bool,
|
||||
) -> Result<Vec<u8>, OpenpgpCardError> {
|
||||
) -> Result<Vec<u8>, Error> {
|
||||
let (ext_support, chaining_support, mut max_cmd_bytes, max_rsp_bytes) =
|
||||
if let Some(caps) = card_client.get_caps() {
|
||||
log::debug!("found card caps data!");
|
||||
|
@ -151,9 +149,8 @@ fn send_command_low_level(
|
|||
d.to_vec(),
|
||||
);
|
||||
|
||||
let serialized = partial
|
||||
.serialize(ext)
|
||||
.map_err(OpenpgpCardError::InternalError)?;
|
||||
let serialized =
|
||||
partial.serialize(ext).map_err(Error::InternalError)?;
|
||||
|
||||
log::debug!(" -> chunked APDU command: {:x?}", &serialized);
|
||||
|
||||
|
@ -162,7 +159,7 @@ fn send_command_low_level(
|
|||
log::debug!(" <- APDU chunk response: {:x?}", &resp);
|
||||
|
||||
if resp.len() < 2 {
|
||||
return Err(OpenpgpCardError::ResponseLength(resp.len()));
|
||||
return Err(Error::ResponseLength(resp.len()));
|
||||
}
|
||||
|
||||
if !last {
|
||||
|
@ -176,7 +173,7 @@ fn send_command_low_level(
|
|||
|| (sw1 == 0x68 && sw2 == 0x83))
|
||||
{
|
||||
// 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
|
||||
|
@ -193,7 +190,7 @@ fn send_command_low_level(
|
|||
// Can't send this command to the card, because it is too long and
|
||||
// the card doesn't support command chaining.
|
||||
if serialized.len() > max_cmd_bytes {
|
||||
return Err(OpenpgpCardError::CommandTooLong(serialized.len()));
|
||||
return Err(Error::CommandTooLong(serialized.len()));
|
||||
}
|
||||
|
||||
log::debug!(" -> APDU command: {:x?}", &serialized);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// SPDX-FileCopyrightText: 2021 Heiko Schaefer <heiko@schaefer.name>
|
||||
// SPDX-License-Identifier: MIT OR Apache-2.0
|
||||
|
||||
use crate::errors::{OcErrorStatus, OpenpgpCardError};
|
||||
use crate::{Error, StatusByte};
|
||||
use std::convert::TryFrom;
|
||||
|
||||
/// Response from the card to a command.
|
||||
|
@ -35,29 +35,27 @@ pub(crate) struct RawResponse {
|
|||
}
|
||||
|
||||
impl TryFrom<RawResponse> for Response {
|
||||
type Error = OpenpgpCardError;
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(value: RawResponse) -> Result<Self, Self::Error> {
|
||||
if value.is_ok() {
|
||||
Ok(Response { data: value.data })
|
||||
} else {
|
||||
Err(OpenpgpCardError::OcStatus(OcErrorStatus::from(
|
||||
value.status(),
|
||||
)))
|
||||
Err(Error::CardStatus(StatusByte::from(value.status())))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl RawResponse {
|
||||
pub fn check_ok(&self) -> Result<(), OcErrorStatus> {
|
||||
pub fn check_ok(&self) -> Result<(), StatusByte> {
|
||||
if !self.is_ok() {
|
||||
Err(OcErrorStatus::from((self.sw1, self.sw2)))
|
||||
Err(StatusByte::from((self.sw1, self.sw2)))
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn data(&self) -> Result<&[u8], OcErrorStatus> {
|
||||
pub fn data(&self) -> Result<&[u8], StatusByte> {
|
||||
self.check_ok()?;
|
||||
Ok(&self.data)
|
||||
}
|
||||
|
@ -87,15 +85,15 @@ impl RawResponse {
|
|||
}
|
||||
|
||||
impl TryFrom<Vec<u8>> for RawResponse {
|
||||
type Error = OpenpgpCardError;
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(mut data: Vec<u8>) -> Result<Self, Self::Error> {
|
||||
let sw2 = data
|
||||
.pop()
|
||||
.ok_or_else(|| OpenpgpCardError::ResponseLength(data.len()))?;
|
||||
.ok_or_else(|| Error::ResponseLength(data.len()))?;
|
||||
let sw1 = data
|
||||
.pop()
|
||||
.ok_or_else(|| OpenpgpCardError::ResponseLength(data.len()))?;
|
||||
.ok_or_else(|| Error::ResponseLength(data.len()))?;
|
||||
|
||||
Ok(RawResponse { data, sw1, sw2 })
|
||||
}
|
||||
|
|
|
@ -18,8 +18,8 @@ use crate::card_do::{
|
|||
use crate::crypto_data::{
|
||||
CardUploadableKey, Cryptogram, EccType, Hash, PublicKeyMaterial,
|
||||
};
|
||||
use crate::errors::OpenpgpCardError;
|
||||
use crate::tlv::{tag::Tag, value::Value, Tlv};
|
||||
use crate::Error;
|
||||
use crate::{apdu, keys, CardCaps, CardClientBox, KeyType};
|
||||
|
||||
/// Low-level access to OpenPGP card functionality.
|
||||
|
@ -92,7 +92,7 @@ impl CardApp {
|
|||
// --- select ---
|
||||
|
||||
/// 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();
|
||||
apdu::send_command(&mut self.card_client, select_openpgp, false)?
|
||||
.try_into()
|
||||
|
@ -207,9 +207,7 @@ impl CardApp {
|
|||
///
|
||||
/// Call select_data() before calling this fn, to select a particular
|
||||
/// certificate (if the card supports multiple certificates).
|
||||
pub fn get_cardholder_certificate(
|
||||
&mut self,
|
||||
) -> Result<Response, OpenpgpCardError> {
|
||||
pub fn get_cardholder_certificate(&mut self) -> Result<Response, Error> {
|
||||
let cmd = commands::get_cardholder_certificate();
|
||||
apdu::send_command(&mut self.card_client, cmd, true)?.try_into()
|
||||
}
|
||||
|
@ -233,7 +231,7 @@ impl CardApp {
|
|||
&mut self,
|
||||
num: u8,
|
||||
tag: &[u8],
|
||||
) -> Result<Response, OpenpgpCardError> {
|
||||
) -> Result<Response, Error> {
|
||||
let tlv = Tlv::new(
|
||||
[0x60],
|
||||
Value::C(vec![Tlv::new([0x5c], Value::S(tag.to_vec()))]),
|
||||
|
@ -308,7 +306,7 @@ impl CardApp {
|
|||
pub fn verify_pw1_for_signing(
|
||||
&mut self,
|
||||
pin: &str,
|
||||
) -> Result<Response, OpenpgpCardError> {
|
||||
) -> Result<Response, Error> {
|
||||
assert!(pin.len() >= 6); // FIXME: Err
|
||||
|
||||
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,
|
||||
/// e.g. yubikey 5)
|
||||
pub fn check_pw1_for_signing(
|
||||
&mut self,
|
||||
) -> Result<Response, OpenpgpCardError> {
|
||||
pub fn check_pw1_for_signing(&mut self) -> Result<Response, Error> {
|
||||
let verify = commands::verify_pw1_81(vec![]);
|
||||
apdu::send_command(&mut self.card_client, verify, false)?.try_into()
|
||||
}
|
||||
|
||||
/// Verify PW1 (user) and set an appropriate access status.
|
||||
/// (For operations except signing, mode 82).
|
||||
pub fn verify_pw1(
|
||||
&mut self,
|
||||
pin: &str,
|
||||
) -> Result<Response, OpenpgpCardError> {
|
||||
pub fn verify_pw1(&mut self, pin: &str) -> Result<Response, Error> {
|
||||
assert!(pin.len() >= 6); // FIXME: Err
|
||||
|
||||
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,
|
||||
/// 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![]);
|
||||
apdu::send_command(&mut self.card_client, verify, false)?.try_into()
|
||||
}
|
||||
|
||||
/// Verify PW3 (admin) and set an appropriate access status.
|
||||
pub fn verify_pw3(
|
||||
&mut self,
|
||||
pin: &str,
|
||||
) -> Result<Response, OpenpgpCardError> {
|
||||
pub fn verify_pw3(&mut self, pin: &str) -> Result<Response, Error> {
|
||||
assert!(pin.len() >= 8); // FIXME: Err
|
||||
|
||||
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,
|
||||
/// 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![]);
|
||||
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
|
||||
/// operation, it builds the required `data` field from `dm`)
|
||||
pub fn decrypt(
|
||||
&mut self,
|
||||
dm: Cryptogram,
|
||||
) -> Result<Vec<u8>, OpenpgpCardError> {
|
||||
pub fn decrypt(&mut self, dm: Cryptogram) -> Result<Vec<u8>, Error> {
|
||||
match dm {
|
||||
Cryptogram::RSA(message) => {
|
||||
let mut data = vec![0x0];
|
||||
|
@ -409,10 +396,7 @@ impl CardApp {
|
|||
|
||||
/// Run decryption operation on the smartcard (low level operation)
|
||||
/// (7.2.11 PSO: DECIPHER)
|
||||
fn pso_decipher(
|
||||
&mut self,
|
||||
data: Vec<u8>,
|
||||
) -> Result<Vec<u8>, OpenpgpCardError> {
|
||||
fn pso_decipher(&mut self, data: Vec<u8>) -> Result<Vec<u8>, Error> {
|
||||
// The OpenPGP card is already connected and PW1 82 has been verified
|
||||
let dec_cmd = commands::decryption(data);
|
||||
let resp = apdu::send_command(&mut self.card_client, dec_cmd, true)?;
|
||||
|
@ -431,7 +415,7 @@ impl CardApp {
|
|||
pub fn signature_for_hash(
|
||||
&mut self,
|
||||
hash: Hash,
|
||||
) -> Result<Vec<u8>, OpenpgpCardError> {
|
||||
) -> Result<Vec<u8>, Error> {
|
||||
let data = match hash {
|
||||
Hash::SHA256(_) | Hash::SHA384(_) | Hash::SHA512(_) => {
|
||||
let tlv = Tlv::new(
|
||||
|
@ -466,7 +450,7 @@ impl CardApp {
|
|||
fn pso_compute_digital_signature(
|
||||
&mut self,
|
||||
data: Vec<u8>,
|
||||
) -> Result<Vec<u8>, OpenpgpCardError> {
|
||||
) -> Result<Vec<u8>, Error> {
|
||||
let dec_cmd = commands::signature(data);
|
||||
|
||||
let resp = apdu::send_command(&mut self.card_client, dec_cmd, true)?;
|
||||
|
@ -492,33 +476,24 @@ impl CardApp {
|
|||
Ok(resp.data()?.to_vec())
|
||||
}
|
||||
|
||||
pub fn set_name(
|
||||
&mut self,
|
||||
name: &str,
|
||||
) -> Result<Response, OpenpgpCardError> {
|
||||
pub fn set_name(&mut self, name: &str) -> Result<Response, Error> {
|
||||
let put_name = commands::put_name(name.as_bytes().to_vec());
|
||||
apdu::send_command(&mut self.card_client, put_name, false)?.try_into()
|
||||
}
|
||||
|
||||
pub fn set_lang(
|
||||
&mut self,
|
||||
lang: &str,
|
||||
) -> Result<Response, OpenpgpCardError> {
|
||||
pub fn set_lang(&mut self, lang: &str) -> Result<Response, Error> {
|
||||
let put_lang = commands::put_lang(lang.as_bytes().to_vec());
|
||||
apdu::send_command(self.card_client.borrow_mut(), put_lang, false)?
|
||||
.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());
|
||||
apdu::send_command(self.card_client.borrow_mut(), put_sex, false)?
|
||||
.try_into()
|
||||
}
|
||||
|
||||
pub fn set_url(
|
||||
&mut self,
|
||||
url: &str,
|
||||
) -> Result<Response, OpenpgpCardError> {
|
||||
pub fn set_url(&mut self, url: &str) -> Result<Response, Error> {
|
||||
let put_url = commands::put_url(url.as_bytes().to_vec());
|
||||
apdu::send_command(&mut self.card_client, put_url, false)?.try_into()
|
||||
}
|
||||
|
@ -527,7 +502,7 @@ impl CardApp {
|
|||
&mut self,
|
||||
time: KeyGenerationTime,
|
||||
key_type: KeyType,
|
||||
) -> Result<Response, OpenpgpCardError> {
|
||||
) -> Result<Response, Error> {
|
||||
// Timestamp update
|
||||
let time_value: Vec<u8> = time
|
||||
.get()
|
||||
|
@ -549,7 +524,7 @@ impl CardApp {
|
|||
&mut self,
|
||||
fp: Fingerprint,
|
||||
key_type: KeyType,
|
||||
) -> Result<Response, OpenpgpCardError> {
|
||||
) -> Result<Response, Error> {
|
||||
let fp_cmd = commands::put_data(
|
||||
&[key_type.get_fingerprint_put_tag()],
|
||||
fp.as_bytes().to_vec(),
|
||||
|
@ -573,7 +548,7 @@ impl CardApp {
|
|||
&mut self,
|
||||
pw_status: &PWStatus,
|
||||
long: bool,
|
||||
) -> Result<Response, OpenpgpCardError> {
|
||||
) -> Result<Response, Error> {
|
||||
let data = pw_status.serialize_for_put(long);
|
||||
|
||||
let cmd = commands::put_pw_status(data);
|
||||
|
@ -587,7 +562,7 @@ impl CardApp {
|
|||
pub fn set_cardholder_certificate(
|
||||
&mut self,
|
||||
data: Vec<u8>,
|
||||
) -> Result<Response, OpenpgpCardError> {
|
||||
) -> Result<Response, Error> {
|
||||
let cmd = commands::put_cardholder_certificate(data);
|
||||
apdu::send_command(&mut self.card_client, cmd, false)?.try_into()
|
||||
}
|
||||
|
@ -598,7 +573,7 @@ impl CardApp {
|
|||
&mut self,
|
||||
key_type: KeyType,
|
||||
algo: &Algo,
|
||||
) -> Result<Response, OpenpgpCardError> {
|
||||
) -> Result<Response, Error> {
|
||||
// FIXME: caching?
|
||||
let ard = self.get_app_data()?;
|
||||
|
||||
|
@ -668,7 +643,7 @@ impl CardApp {
|
|||
&mut self,
|
||||
key: Box<dyn CardUploadableKey>,
|
||||
key_type: KeyType,
|
||||
) -> Result<(), OpenpgpCardError> {
|
||||
) -> Result<(), Error> {
|
||||
let algo_list = self.get_algo_info();
|
||||
|
||||
// An error is ok - it's fine if a card doesn't offer a list of
|
||||
|
@ -689,10 +664,10 @@ impl CardApp {
|
|||
&PublicKeyMaterial,
|
||||
KeyGenerationTime,
|
||||
KeyType,
|
||||
) -> Result<Fingerprint, OpenpgpCardError>,
|
||||
) -> Result<Fingerprint, Error>,
|
||||
key_type: KeyType,
|
||||
algo: Option<&Algo>,
|
||||
) -> Result<(PublicKeyMaterial, KeyGenerationTime), OpenpgpCardError> {
|
||||
) -> Result<(PublicKeyMaterial, KeyGenerationTime), Error> {
|
||||
keys::gen_key_with_metadata(self, fp_from_pub, key_type, algo)
|
||||
}
|
||||
|
||||
|
@ -707,10 +682,10 @@ impl CardApp {
|
|||
&PublicKeyMaterial,
|
||||
KeyGenerationTime,
|
||||
KeyType,
|
||||
) -> Result<Fingerprint, OpenpgpCardError>,
|
||||
) -> Result<Fingerprint, Error>,
|
||||
key_type: KeyType,
|
||||
algo: AlgoSimple,
|
||||
) -> Result<(PublicKeyMaterial, KeyGenerationTime), OpenpgpCardError> {
|
||||
) -> Result<(PublicKeyMaterial, KeyGenerationTime), Error> {
|
||||
let algo = algo.get_algo(key_type);
|
||||
self.generate_key(fp_from_pub, key_type, Some(&algo))
|
||||
}
|
||||
|
@ -724,7 +699,7 @@ impl CardApp {
|
|||
pub fn get_pub_key(
|
||||
&mut self,
|
||||
key_type: KeyType,
|
||||
) -> Result<PublicKeyMaterial, OpenpgpCardError> {
|
||||
) -> Result<PublicKeyMaterial, Error> {
|
||||
keys::get_pub_key(self, key_type)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,9 +8,8 @@ use nom::{combinator, number::complete as number, sequence};
|
|||
use std::collections::HashSet;
|
||||
use std::convert::TryFrom;
|
||||
|
||||
use crate::card_do::complete;
|
||||
use crate::card_do::{ExtendedCap, Features};
|
||||
use crate::errors::OpenpgpCardError;
|
||||
use crate::card_do::{complete, ExtendedCap, Features};
|
||||
use crate::Error;
|
||||
|
||||
fn features(input: &[u8]) -> nom::IResult<&[u8], HashSet<Features>> {
|
||||
combinator::map(number::u8, |b| {
|
||||
|
@ -70,7 +69,7 @@ impl ExtendedCap {
|
|||
}
|
||||
|
||||
impl TryFrom<&[u8]> for ExtendedCap {
|
||||
type Error = OpenpgpCardError;
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(input: &[u8]) -> Result<Self, Self::Error> {
|
||||
let ec = complete(parse(input))?;
|
||||
|
|
|
@ -10,7 +10,7 @@ use std::convert::TryInto;
|
|||
use std::fmt;
|
||||
|
||||
use crate::card_do::{Fingerprint, KeySet};
|
||||
use crate::errors::OpenpgpCardError;
|
||||
use crate::Error;
|
||||
|
||||
impl From<[u8; 20]> for Fingerprint {
|
||||
fn from(data: [u8; 20]) -> Self {
|
||||
|
@ -19,7 +19,7 @@ impl From<[u8; 20]> for Fingerprint {
|
|||
}
|
||||
|
||||
impl TryFrom<&[u8]> for Fingerprint {
|
||||
type Error = OpenpgpCardError;
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(input: &[u8]) -> Result<Self, Self::Error> {
|
||||
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
|
||||
pub(crate) fn to_keyset(
|
||||
input: &[u8],
|
||||
) -> Result<KeySet<Fingerprint>, OpenpgpCardError> {
|
||||
pub(crate) fn to_keyset(input: &[u8]) -> Result<KeySet<Fingerprint>, Error> {
|
||||
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
|
||||
|
@ -94,5 +92,5 @@ pub(crate) fn to_keyset(
|
|||
self::fingerprints(input)
|
||||
.map(|res| res.1)
|
||||
.map_err(|err| anyhow!("Parsing failed: {:?}", err))
|
||||
.map_err(OpenpgpCardError::InternalError)
|
||||
.map_err(Error::InternalError)
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
//! 6 Historical Bytes
|
||||
|
||||
use crate::card_do::{CardCapabilities, CardServiceData, Historical};
|
||||
use crate::errors::OpenpgpCardError;
|
||||
use crate::Error;
|
||||
use anyhow::{anyhow, Result};
|
||||
use std::convert::TryFrom;
|
||||
|
||||
|
@ -78,7 +78,7 @@ impl Historical {
|
|||
}
|
||||
|
||||
impl TryFrom<&[u8]> for Historical {
|
||||
type Error = OpenpgpCardError;
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(data: &[u8]) -> Result<Self, Self::Error> {
|
||||
let len = data.len();
|
||||
|
|
|
@ -7,9 +7,8 @@ use anyhow::anyhow;
|
|||
use chrono::{DateTime, NaiveDateTime, Utc};
|
||||
use nom::{combinator, number::complete as number, sequence};
|
||||
|
||||
use crate::card_do::KeyGenerationTime;
|
||||
use crate::card_do::KeySet;
|
||||
use crate::errors::OpenpgpCardError;
|
||||
use crate::card_do::{KeyGenerationTime, KeySet};
|
||||
use crate::Error;
|
||||
|
||||
impl From<KeyGenerationTime> for DateTime<Utc> {
|
||||
fn from(kg: KeyGenerationTime) -> Self {
|
||||
|
@ -54,9 +53,7 @@ fn key_generation_set(
|
|||
)))(input)
|
||||
}
|
||||
|
||||
pub fn from(
|
||||
input: &[u8],
|
||||
) -> Result<KeySet<KeyGenerationTime>, OpenpgpCardError> {
|
||||
pub fn from(input: &[u8]) -> Result<KeySet<KeyGenerationTime>, Error> {
|
||||
// List of generation dates/times of key pairs, binary.
|
||||
// 4 bytes, Big Endian each for Sig, Dec and Aut. Each
|
||||
// value shall be seconds since Jan 1, 1970. Default
|
||||
|
@ -73,5 +70,5 @@ pub fn from(
|
|||
self::key_generation_set(input)
|
||||
.map(|res| res.1)
|
||||
.map_err(|err| anyhow!("Parsing failed: {:?}", err))
|
||||
.map_err(OpenpgpCardError::InternalError)
|
||||
.map_err(Error::InternalError)
|
||||
}
|
||||
|
|
|
@ -3,15 +3,12 @@
|
|||
|
||||
//! OpenPGP card data objects (DO)
|
||||
|
||||
use anyhow::{anyhow, Error, Result};
|
||||
use anyhow::{anyhow, Result};
|
||||
use std::collections::HashSet;
|
||||
use std::convert::TryFrom;
|
||||
use std::convert::TryInto;
|
||||
|
||||
use crate::algorithm::Algo;
|
||||
use crate::errors::OpenpgpCardError;
|
||||
use crate::tlv::Tlv;
|
||||
use crate::KeyType;
|
||||
use crate::{algorithm::Algo, tlv::Tlv, Error, KeyType};
|
||||
|
||||
mod algo_attrs;
|
||||
mod algo_info;
|
||||
|
@ -36,9 +33,7 @@ pub struct ApplicationRelatedData(pub(crate) Tlv);
|
|||
|
||||
impl ApplicationRelatedData {
|
||||
/// Application identifier (AID), ISO 7816-4
|
||||
pub fn get_application_id(
|
||||
&self,
|
||||
) -> Result<ApplicationId, OpenpgpCardError> {
|
||||
pub fn get_application_id(&self) -> Result<ApplicationId, Error> {
|
||||
// get from cached "application related data"
|
||||
let aid = self.0.find(&[0x4f].into());
|
||||
|
||||
|
@ -50,7 +45,7 @@ impl ApplicationRelatedData {
|
|||
}
|
||||
|
||||
/// Historical bytes
|
||||
pub fn get_historical(&self) -> Result<Historical, OpenpgpCardError> {
|
||||
pub fn get_historical(&self) -> Result<Historical, Error> {
|
||||
// get from cached "application related data"
|
||||
let hist = self.0.find(&[0x5f, 0x52].into());
|
||||
|
||||
|
@ -90,9 +85,7 @@ impl ApplicationRelatedData {
|
|||
}
|
||||
|
||||
/// Extended Capabilities
|
||||
pub fn get_extended_capabilities(
|
||||
&self,
|
||||
) -> Result<ExtendedCap, OpenpgpCardError> {
|
||||
pub fn get_extended_capabilities(&self) -> Result<ExtendedCap, Error> {
|
||||
// get from cached "application related data"
|
||||
let ecap = self.0.find(&[0xc0].into());
|
||||
|
||||
|
@ -136,9 +129,7 @@ impl ApplicationRelatedData {
|
|||
|
||||
/// Fingerprint, per key type.
|
||||
/// Zero bytes indicate a not defined private key.
|
||||
pub fn get_fingerprints(
|
||||
&self,
|
||||
) -> Result<KeySet<Fingerprint>, OpenpgpCardError> {
|
||||
pub fn get_fingerprints(&self) -> Result<KeySet<Fingerprint>, Error> {
|
||||
// Get from cached "application related data"
|
||||
let fp = self.0.find(&[0xc5].into());
|
||||
|
||||
|
@ -156,7 +147,7 @@ impl ApplicationRelatedData {
|
|||
/// Generation dates/times of key pairs
|
||||
pub fn get_key_generation_times(
|
||||
&self,
|
||||
) -> Result<KeySet<KeyGenerationTime>, OpenpgpCardError> {
|
||||
) -> Result<KeySet<KeyGenerationTime>, Error> {
|
||||
let kg = self.0.find(&[0xcd].into());
|
||||
|
||||
if let Some(kg) = kg {
|
||||
|
@ -373,7 +364,9 @@ impl<T> KeySet<T> {
|
|||
}
|
||||
|
||||
/// 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) =
|
||||
result.map_err(|err| anyhow!("Parsing failed: {:?}", err))?;
|
||||
if rem.is_empty() {
|
||||
|
|
|
@ -6,10 +6,10 @@
|
|||
use anyhow::anyhow;
|
||||
|
||||
use crate::card_do::PWStatus;
|
||||
use crate::errors::OpenpgpCardError;
|
||||
use crate::Error;
|
||||
|
||||
impl PWStatus {
|
||||
pub fn try_from(input: &[u8]) -> Result<Self, OpenpgpCardError> {
|
||||
pub fn try_from(input: &[u8]) -> Result<Self, Error> {
|
||||
if input.len() == 7 {
|
||||
let pw1_cds_multi = input[0] == 0x01;
|
||||
let pw1_pin_block = input[1] & 0x80 != 0;
|
||||
|
@ -33,7 +33,7 @@ impl PWStatus {
|
|||
err_count_pw3,
|
||||
})
|
||||
} else {
|
||||
Err(OpenpgpCardError::InternalError(anyhow!(
|
||||
Err(Error::InternalError(anyhow!(
|
||||
"Unexpected length of PW Status Bytes: {}",
|
||||
input.len()
|
||||
)))
|
||||
|
|
|
@ -9,7 +9,7 @@ use anyhow::Result;
|
|||
|
||||
use crate::algorithm::Algo;
|
||||
use crate::card_do::{Fingerprint, KeyGenerationTime};
|
||||
use crate::errors::OpenpgpCardError;
|
||||
use crate::Error;
|
||||
|
||||
/// A hash value that can be signed by the card.
|
||||
#[non_exhaustive]
|
||||
|
@ -71,7 +71,7 @@ pub trait CardUploadableKey {
|
|||
fn get_ts(&self) -> KeyGenerationTime;
|
||||
|
||||
/// 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
|
||||
|
|
|
@ -3,24 +3,22 @@
|
|||
|
||||
//! 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:
|
||||
//! - [`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
|
||||
|
||||
use thiserror::Error;
|
||||
|
||||
/// Enum that wraps the different error types that this crate can return
|
||||
#[derive(Error, Debug)]
|
||||
/// Enum wrapper for the different error types of this crate
|
||||
#[derive(thiserror::Error, Debug)]
|
||||
#[non_exhaustive]
|
||||
pub enum OpenpgpCardError {
|
||||
pub enum Error {
|
||||
#[error("Error interacting with smartcard: {0}")]
|
||||
Smartcard(SmartcardError),
|
||||
|
||||
#[error("OpenPGP card error status: {0}")]
|
||||
OcStatus(OcErrorStatus),
|
||||
CardStatus(StatusByte),
|
||||
|
||||
#[error("Command too long ({0} bytes)")]
|
||||
CommandTooLong(usize),
|
||||
|
@ -32,22 +30,22 @@ pub enum OpenpgpCardError {
|
|||
InternalError(anyhow::Error),
|
||||
}
|
||||
|
||||
impl From<OcErrorStatus> for OpenpgpCardError {
|
||||
fn from(oce: OcErrorStatus) -> Self {
|
||||
OpenpgpCardError::OcStatus(oce)
|
||||
impl From<StatusByte> for Error {
|
||||
fn from(oce: StatusByte) -> Self {
|
||||
Error::CardStatus(oce)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<anyhow::Error> for OpenpgpCardError {
|
||||
impl From<anyhow::Error> for Error {
|
||||
fn from(ae: anyhow::Error) -> Self {
|
||||
OpenpgpCardError::InternalError(ae)
|
||||
Error::InternalError(ae)
|
||||
}
|
||||
}
|
||||
|
||||
/// OpenPGP card "Status Byte" errors
|
||||
#[derive(Error, Debug, PartialEq)]
|
||||
#[derive(thiserror::Error, Debug, PartialEq)]
|
||||
#[non_exhaustive]
|
||||
pub enum OcErrorStatus {
|
||||
pub enum StatusByte {
|
||||
#[error("Selected file or DO in termination state")]
|
||||
TerminationState,
|
||||
|
||||
|
@ -118,40 +116,40 @@ pub enum OcErrorStatus {
|
|||
UnknownStatus(u8, u8),
|
||||
}
|
||||
|
||||
impl From<(u8, u8)> for OcErrorStatus {
|
||||
impl From<(u8, u8)> for StatusByte {
|
||||
fn from(status: (u8, u8)) -> Self {
|
||||
match (status.0, status.1) {
|
||||
(0x62, 0x85) => OcErrorStatus::TerminationState,
|
||||
(0x62, 0x85) => StatusByte::TerminationState,
|
||||
(0x63, 0xC0..=0xCF) => {
|
||||
OcErrorStatus::PasswordNotChecked(status.1 & 0xf)
|
||||
StatusByte::PasswordNotChecked(status.1 & 0xf)
|
||||
}
|
||||
(0x64, 0x02..=0x80) => OcErrorStatus::TriggeringByCard(status.1),
|
||||
(0x65, 0x01) => OcErrorStatus::MemoryFailure,
|
||||
(0x66, 0x00) => OcErrorStatus::SecurityRelatedIssues,
|
||||
(0x67, 0x00) => OcErrorStatus::WrongLength,
|
||||
(0x68, 0x81) => OcErrorStatus::LogicalChannelNotSupported,
|
||||
(0x68, 0x82) => OcErrorStatus::SecureMessagingNotSupported,
|
||||
(0x68, 0x83) => OcErrorStatus::LastCommandOfChainExpected,
|
||||
(0x68, 0x84) => OcErrorStatus::CommandChainingUnsupported,
|
||||
(0x69, 0x82) => OcErrorStatus::SecurityStatusNotSatisfied,
|
||||
(0x69, 0x83) => OcErrorStatus::AuthenticationMethodBlocked,
|
||||
(0x69, 0x85) => OcErrorStatus::ConditionOfUseNotSatisfied,
|
||||
(0x69, 0x87) => OcErrorStatus::ExpectedSecureMessagingDOsMissing,
|
||||
(0x69, 0x88) => OcErrorStatus::SMDataObjectsIncorrect,
|
||||
(0x6A, 0x80) => OcErrorStatus::IncorrectParametersCommandDataField,
|
||||
(0x6A, 0x82) => OcErrorStatus::FileOrApplicationNotFound,
|
||||
(0x6A, 0x88) => OcErrorStatus::ReferencedDataNotFound,
|
||||
(0x6B, 0x00) => OcErrorStatus::WrongParametersP1P2,
|
||||
(0x6D, 0x00) => OcErrorStatus::INSNotSupported,
|
||||
(0x6E, 0x00) => OcErrorStatus::CLANotSupported,
|
||||
(0x6F, 0x00) => OcErrorStatus::NoPreciseDiagnosis,
|
||||
_ => OcErrorStatus::UnknownStatus(status.0, status.1),
|
||||
(0x64, 0x02..=0x80) => StatusByte::TriggeringByCard(status.1),
|
||||
(0x65, 0x01) => StatusByte::MemoryFailure,
|
||||
(0x66, 0x00) => StatusByte::SecurityRelatedIssues,
|
||||
(0x67, 0x00) => StatusByte::WrongLength,
|
||||
(0x68, 0x81) => StatusByte::LogicalChannelNotSupported,
|
||||
(0x68, 0x82) => StatusByte::SecureMessagingNotSupported,
|
||||
(0x68, 0x83) => StatusByte::LastCommandOfChainExpected,
|
||||
(0x68, 0x84) => StatusByte::CommandChainingUnsupported,
|
||||
(0x69, 0x82) => StatusByte::SecurityStatusNotSatisfied,
|
||||
(0x69, 0x83) => StatusByte::AuthenticationMethodBlocked,
|
||||
(0x69, 0x85) => StatusByte::ConditionOfUseNotSatisfied,
|
||||
(0x69, 0x87) => StatusByte::ExpectedSecureMessagingDOsMissing,
|
||||
(0x69, 0x88) => StatusByte::SMDataObjectsIncorrect,
|
||||
(0x6A, 0x80) => StatusByte::IncorrectParametersCommandDataField,
|
||||
(0x6A, 0x82) => StatusByte::FileOrApplicationNotFound,
|
||||
(0x6A, 0x88) => StatusByte::ReferencedDataNotFound,
|
||||
(0x6B, 0x00) => StatusByte::WrongParametersP1P2,
|
||||
(0x6D, 0x00) => StatusByte::INSNotSupported,
|
||||
(0x6E, 0x00) => StatusByte::CLANotSupported,
|
||||
(0x6F, 0x00) => StatusByte::NoPreciseDiagnosis,
|
||||
_ => StatusByte::UnknownStatus(status.0, status.1),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Errors on the smartcard/reader layer
|
||||
#[derive(Error, Debug)]
|
||||
#[derive(thiserror::Error, Debug)]
|
||||
#[non_exhaustive]
|
||||
pub enum SmartcardError {
|
||||
#[error("Failed to create a pcsc smartcard context {0}")]
|
||||
|
|
|
@ -16,8 +16,8 @@ use crate::crypto_data::{
|
|||
CardUploadableKey, EccKey, EccPub, PrivateKeyMaterial, PublicKeyMaterial,
|
||||
RSAKey, RSAPub,
|
||||
};
|
||||
use crate::errors::OpenpgpCardError;
|
||||
use crate::tlv::{length::tlv_encode_length, value::Value, Tlv};
|
||||
use crate::Error;
|
||||
use crate::{apdu, KeyType};
|
||||
|
||||
/// Generate asymmetric key pair on the card.
|
||||
|
@ -36,10 +36,10 @@ pub(crate) fn gen_key_with_metadata(
|
|||
&PublicKeyMaterial,
|
||||
KeyGenerationTime,
|
||||
KeyType,
|
||||
) -> Result<Fingerprint, OpenpgpCardError>,
|
||||
) -> Result<Fingerprint, Error>,
|
||||
key_type: KeyType,
|
||||
algo: Option<&Algo>,
|
||||
) -> Result<(PublicKeyMaterial, KeyGenerationTime), OpenpgpCardError> {
|
||||
) -> Result<(PublicKeyMaterial, KeyGenerationTime), Error> {
|
||||
// set algo on card if it's Some
|
||||
if let Some(algo) = 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)
|
||||
let ts = time
|
||||
.duration_since(UNIX_EPOCH)
|
||||
.map_err(|e| OpenpgpCardError::InternalError(anyhow!(e)))?
|
||||
.map_err(|e| Error::InternalError(anyhow!(e)))?
|
||||
.as_secs() as u32;
|
||||
|
||||
let ts = ts.into();
|
||||
|
@ -100,8 +100,7 @@ fn tlv_to_pubkey(tlv: &Tlv, algo: &Algo) -> Result<PublicKeyMaterial> {
|
|||
(_, _, _) => Err(anyhow!(
|
||||
"Unexpected public key material from card {:?}",
|
||||
tlv
|
||||
)
|
||||
.into()),
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -112,7 +111,7 @@ fn tlv_to_pubkey(tlv: &Tlv, algo: &Algo) -> Result<PublicKeyMaterial> {
|
|||
pub(crate) fn generate_asymmetric_key_pair(
|
||||
card_app: &mut CardApp,
|
||||
key_type: KeyType,
|
||||
) -> Result<Tlv, OpenpgpCardError> {
|
||||
) -> Result<Tlv, Error> {
|
||||
// generate key
|
||||
let crt = get_crt(key_type)?;
|
||||
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(
|
||||
card_app: &mut CardApp,
|
||||
key_type: KeyType,
|
||||
) -> Result<PublicKeyMaterial, OpenpgpCardError> {
|
||||
) -> Result<PublicKeyMaterial, Error> {
|
||||
// algo
|
||||
let ard = card_app.get_app_data()?; // FIXME: caching
|
||||
let algo = ard.get_algorithm_attributes(key_type)?;
|
||||
|
@ -163,7 +162,7 @@ pub(crate) fn key_import(
|
|||
key: Box<dyn CardUploadableKey>,
|
||||
key_type: KeyType,
|
||||
algo_list: Option<AlgoInfo>,
|
||||
) -> Result<(), OpenpgpCardError> {
|
||||
) -> Result<(), Error> {
|
||||
let (algo, key_cmd) = match key.get_key()? {
|
||||
PrivateKeyMaterial::R(rsa_key) => {
|
||||
// RSA bitsize
|
||||
|
@ -262,7 +261,7 @@ fn get_card_algo_rsa(
|
|||
algo_list: AlgoInfo,
|
||||
key_type: KeyType,
|
||||
rsa_bits: u16,
|
||||
) -> Result<RsaAttrs, OpenpgpCardError> {
|
||||
) -> Result<RsaAttrs, Error> {
|
||||
// Find suitable algorithm parameters (from card's list of algorithms).
|
||||
// FIXME: handle "no list available" (older cards?)
|
||||
// (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(
|
||||
ecc_key: Box<dyn EccKey>,
|
||||
key_type: KeyType,
|
||||
) -> Result<Command, OpenpgpCardError> {
|
||||
) -> Result<Command, Error> {
|
||||
let scalar_data = ecc_key.get_scalar();
|
||||
let scalar_len = scalar_data.len() as u8;
|
||||
|
||||
|
@ -348,7 +347,7 @@ fn rsa_key_import_cmd(
|
|||
key_type: KeyType,
|
||||
rsa_key: Box<dyn RSAKey>,
|
||||
algo_attrs: &RsaAttrs,
|
||||
) -> Result<Command, OpenpgpCardError> {
|
||||
) -> Result<Command, Error> {
|
||||
// Assemble key command, which contains three sub-TLV:
|
||||
|
||||
// 1) "Control Reference Template"
|
||||
|
@ -411,17 +410,13 @@ fn rsa_key_import_cmd(
|
|||
}
|
||||
|
||||
/// 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)
|
||||
let tag = match key_type {
|
||||
KeyType::Decryption => 0xB8,
|
||||
KeyType::Signing => 0xB6,
|
||||
KeyType::Authentication => 0xA4,
|
||||
_ => {
|
||||
return Err(OpenpgpCardError::InternalError(anyhow!(
|
||||
"Unexpected KeyType"
|
||||
)))
|
||||
}
|
||||
_ => return Err(Error::InternalError(anyhow!("Unexpected KeyType"))),
|
||||
};
|
||||
Ok(Tlv::new([tag], Value::S(vec![])))
|
||||
}
|
||||
|
|
|
@ -32,12 +32,13 @@ mod apdu;
|
|||
mod card_app;
|
||||
pub mod card_do;
|
||||
pub mod crypto_data;
|
||||
pub mod errors;
|
||||
mod errors;
|
||||
mod keys;
|
||||
mod tlv;
|
||||
|
||||
pub use crate::apdu::response::Response;
|
||||
pub use crate::card_app::CardApp;
|
||||
pub use crate::errors::{Error, SmartcardError, StatusByte};
|
||||
|
||||
/// The CardClient trait defines communication with an OpenPGP card via a
|
||||
/// backend implementation (e.g. the pcsc backend in the crate
|
||||
|
|
|
@ -2,10 +2,11 @@
|
|||
// SPDX-License-Identifier: MIT OR Apache-2.0
|
||||
|
||||
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::{CardApp, CardCaps, CardClient, CardClientBox};
|
||||
use openpgp_card::{
|
||||
CardApp, CardCaps, CardClient, CardClientBox, Error, SmartcardError,
|
||||
};
|
||||
|
||||
pub struct PcscClient {
|
||||
card: Card,
|
||||
|
@ -51,7 +52,7 @@ impl PcscClient {
|
|||
let card =
|
||||
match ctx.connect(reader, ShareMode::Shared, Protocols::ANY) {
|
||||
Ok(card) => card,
|
||||
Err(Error::NoSmartcard) => {
|
||||
Err(pcsc::Error::NoSmartcard) => {
|
||||
continue; // try next reader
|
||||
}
|
||||
Err(err) => {
|
||||
|
@ -94,16 +95,14 @@ impl PcscClient {
|
|||
}
|
||||
|
||||
/// 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 mut ca = CardApp::from(ccb);
|
||||
if ca.select().is_ok() {
|
||||
Ok(ca)
|
||||
} else {
|
||||
Err(OpenpgpCardError::Smartcard(
|
||||
SmartcardError::SelectOpenPGPCardFailed,
|
||||
))
|
||||
Err(Error::Smartcard(SmartcardError::SelectOpenPGPCardFailed))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -111,14 +110,14 @@ impl PcscClient {
|
|||
///
|
||||
/// If multiple cards are connected, this will effectively be a random
|
||||
/// 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()? {
|
||||
if let Ok(ca) = Self::select(card) {
|
||||
return Ok(ca.into());
|
||||
}
|
||||
}
|
||||
|
||||
Err(OpenpgpCardError::Smartcard(SmartcardError::CardNotFound(
|
||||
Err(Error::Smartcard(SmartcardError::CardNotFound(
|
||||
"No OpenPGP card found".to_string(),
|
||||
)))
|
||||
}
|
||||
|
@ -128,7 +127,7 @@ impl PcscClient {
|
|||
fn match_by_ident(
|
||||
mut ca: CardApp,
|
||||
ident: &str,
|
||||
) -> Result<Option<CardClientBox>, OpenpgpCardError> {
|
||||
) -> Result<Option<CardClientBox>, Error> {
|
||||
let ard = ca.get_app_data()?;
|
||||
let aid = ard.get_application_id()?;
|
||||
|
||||
|
@ -141,9 +140,7 @@ impl PcscClient {
|
|||
|
||||
/// Returns the OpenPGP card that matches `ident`, if it is available.
|
||||
/// The OpenPGP application of the `CardClientBox` has been selected.
|
||||
pub fn open_by_ident(
|
||||
ident: &str,
|
||||
) -> Result<CardClientBox, OpenpgpCardError> {
|
||||
pub fn open_by_ident(ident: &str) -> Result<CardClientBox, Error> {
|
||||
for card in Self::unopened_cards()? {
|
||||
if let Ok(ca) = Self::select(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(),
|
||||
)))
|
||||
}
|
||||
|
@ -165,7 +162,7 @@ impl CardClient for PcscClient {
|
|||
let mut resp_buffer = vec![0; buf_size];
|
||||
|
||||
let resp = self.card.transmit(cmd, &mut resp_buffer).map_err(|e| {
|
||||
OpenpgpCardError::Smartcard(SmartcardError::Error(format!(
|
||||
Error::Smartcard(SmartcardError::Error(format!(
|
||||
"Transmit failed: {:?}",
|
||||
e
|
||||
)))
|
||||
|
|
|
@ -13,7 +13,7 @@ use sequoia_ipc::gnupg::{Agent, Context};
|
|||
use std::sync::Mutex;
|
||||
use tokio::runtime::Runtime;
|
||||
|
||||
use openpgp_card::errors::OpenpgpCardError;
|
||||
use openpgp_card::Error;
|
||||
use openpgp_card::{CardCaps, CardClient, CardClientBox};
|
||||
|
||||
lazy_static! {
|
||||
|
@ -108,9 +108,7 @@ impl ScdClient {
|
|||
/// Create a CardClientBox object that uses an scdaemon instance as its
|
||||
/// backend. If multiple cards are available, scdaemon implicitly
|
||||
/// selects one.
|
||||
pub fn open(
|
||||
agent: Option<Agent>,
|
||||
) -> Result<CardClientBox, OpenpgpCardError> {
|
||||
pub fn open(agent: Option<Agent>) -> Result<CardClientBox, Error> {
|
||||
let card = ScdClient::new(agent, true)?;
|
||||
Ok(Box::new(card) as CardClientBox)
|
||||
}
|
||||
|
@ -120,7 +118,7 @@ impl ScdClient {
|
|||
pub fn open_by_serial(
|
||||
agent: Option<Agent>,
|
||||
serial: &str,
|
||||
) -> Result<CardClientBox, OpenpgpCardError> {
|
||||
) -> Result<CardClientBox, Error> {
|
||||
let mut card = ScdClient::new(agent, true)?;
|
||||
card.select_card(serial)?;
|
||||
|
||||
|
|
Loading…
Reference in a new issue