diff --git a/Cargo.toml b/Cargo.toml index 7658a864..9b6197bb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -32,6 +32,7 @@ serde = { version = "1.0", default-features = false } subtle = { version = "2.4.1", default-features = false } trussed = "0.1.0" trussed-rsa-alloc = { version = "0.1.0", optional = true } +trussed-staging = { version = "0.1.0", features = ["wrap-key-to-file"]} serde_repr = "0.1" hex-literal = "0.3.4" trussed-auth = "0.2.1" @@ -85,11 +86,11 @@ log-warn = [] log-error = [] [patch.crates-io] -littlefs2 = { git = "https://github.com/Nitrokey/littlefs2", tag = "v0.3.2-nitrokey-2" } p256-cortex-m4 = { git = "https://github.com/Nitrokey/p256-cortex-m4", tag = "v0.1.0-alpha.6-nitrokey-1" } -trussed = { git = "https://github.com/Nitrokey/trussed" , tag = "v0.1.0-nitrokey.9" } -trussed-auth = { git = "https://github.com/trussed-dev/trussed-auth.git", tag= "v0.2.1"} +trussed = { git = "https://github.com/trussed-dev/trussed" , rev = "55ea391367fce4bf5093ff2d3c79041d7aef0485" } +trussed-auth = { git = "https://github.com/trussed-dev/trussed-auth.git", rev = "6beabd125ea57e87bf642e18278fcc2ba224c50c"} trussed-rsa-alloc = { git = "https://github.com/Nitrokey/trussed-rsa-backend", tag = "v0.1.0" } +trussed-staging = { git = "https://github.com/Nitrokey/trussed-staging", rev = "862666b4c6d275a208803e9db4dfdfc33e92b589" } [package.metadata.docs.rs] all-features = true diff --git a/src/backend.rs b/src/backend.rs index 4a0a2131..8e6ff15d 100644 --- a/src/backend.rs +++ b/src/backend.rs @@ -5,30 +5,29 @@ //! //! As this crate is designed to be usable on any platform, it cannot rely on a specific data //! storage and cryptography implementation. Instead, a [`Card`][`crate::Card`] has to be provided -//! with a Backend wrapping a [`trussed::Client`][trussed::Client] +//! with a Backend wrapping a [`crate::card::Client`][crate::card::Client] use core::fmt::Debug; use trussed::try_syscall; -use trussed_auth::AuthClient; use crate::error::Error; /// Backend that provides data storage and cryptography operations. /// Mostly a wrapper around a trussed client #[derive(Clone)] -pub struct Backend { +pub struct Backend { client: T, } -impl Debug for Backend { +impl Debug for Backend { fn fmt(&self, fmt: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { let Self { client: _client } = self; fmt.debug_struct("Backend").finish() } } -impl Backend { +impl Backend { /// Create new backend from a trussed client pub fn new(client: T) -> Self { Self { client } diff --git a/src/card.rs b/src/card.rs index 5a2218a9..1c1c71c9 100644 --- a/src/card.rs +++ b/src/card.rs @@ -25,13 +25,13 @@ pub const PGP_SMARTCARD_VERSION: [u8; 2] = [3, 4]; /// This is the main entry point for this crate. It takes care of the command handling and state /// management. #[derive(Clone, Debug)] -pub struct Card { +pub struct Card { backend: Backend, options: Options, state: State, } -impl Card { +impl Card { /// Creates a new OpenPGP card with the given backend and options. pub fn new(client: T, options: Options) -> Self { let state = State::default(); @@ -73,13 +73,13 @@ impl Card { } } -impl Drop for Card { +impl Drop for Card { fn drop(&mut self) { self.reset() } } -impl iso7816::App for Card { +impl iso7816::App for Card { fn aid(&self) -> iso7816::Aid { // TODO: check truncation length iso7816::Aid::new_truncatable(&self.options.aid(), RID.len()) @@ -87,9 +87,7 @@ impl iso7816::App for Card { } #[cfg(feature = "apdu-dispatch")] -impl apdu_dispatch::App - for Card -{ +impl apdu_dispatch::App for Card { fn select( &mut self, command: &iso7816::Command, @@ -172,7 +170,7 @@ impl Default for Options { } #[derive(Debug)] -pub struct Context<'a, const R: usize, T: trussed::Client + AuthClient> { +pub struct Context<'a, const R: usize, T: Client> { pub backend: &'a mut Backend, pub options: &'a Options, pub state: &'a mut State, @@ -180,7 +178,7 @@ pub struct Context<'a, const R: usize, T: trussed::Client + AuthClient> { pub reply: Reply<'a, R>, } -impl<'a, const R: usize, T: trussed::Client + AuthClient> Context<'a, R, T> { +impl<'a, const R: usize, T: Client> Context<'a, R, T> { pub fn load_state(&mut self) -> Result, Status> { Ok(LoadedContext { state: self @@ -211,7 +209,7 @@ impl<'a, const R: usize, T: trussed::Client + AuthClient> Context<'a, R, T> { #[derive(Debug)] /// Context with the persistent state loaded from flash -pub struct LoadedContext<'a, const R: usize, T: trussed::Client + AuthClient> { +pub struct LoadedContext<'a, const R: usize, T: Client> { pub backend: &'a mut Backend, pub options: &'a Options, pub state: LoadedState<'a>, @@ -219,7 +217,7 @@ pub struct LoadedContext<'a, const R: usize, T: trussed::Client + AuthClient> { pub reply: Reply<'a, R>, } -impl<'a, const R: usize, T: trussed::Client + AuthClient> LoadedContext<'a, R, T> { +impl<'a, const R: usize, T: Client> LoadedContext<'a, R, T> { /// Lend the context /// /// The resulting `LoadedContext` has a shorter lifetime than the original one, meaning that it @@ -248,3 +246,9 @@ mod tests { ) } } + +use trussed_staging::wrap_key_to_file::WrapKeyToFileClient; + +/// Super trait with all trussed extensions required by opcard +pub trait Client: trussed::Client + AuthClient + WrapKeyToFileClient {} +impl Client for C {} diff --git a/src/command.rs b/src/command.rs index 8141ccfc..8900fd6d 100644 --- a/src/command.rs +++ b/src/command.rs @@ -8,7 +8,7 @@ mod pso; use hex_literal::hex; use iso7816::Status; -use trussed_auth::{AuthClient, PinId}; +use trussed_auth::PinId; use crate::card::{Context, LoadedContext, RID}; use crate::error::Error; @@ -55,7 +55,7 @@ impl Command { } } - pub fn exec( + pub fn exec( &self, mut ctx: Context<'_, R, T>, ) -> Result<(), Status> { @@ -336,7 +336,7 @@ impl TryFrom for ManageSecurityEnvironmentMode { } // § 7.2.1 -fn select( +fn select( context: Context<'_, R, T>, ) -> Result<(), Status> { if context.data.starts_with(&RID) { @@ -350,7 +350,7 @@ fn select( } // § 7.2.2 -fn verify( +fn verify( mut ctx: LoadedContext<'_, R, T>, mode: VerifyMode, password: PasswordMode, @@ -401,7 +401,7 @@ fn verify( } // § 7.2.3 -fn change_reference_data( +fn change_reference_data( mut ctx: LoadedContext<'_, R, T>, password: Password, ) -> Result<(), Status> { @@ -438,7 +438,7 @@ fn change_reference_data( } // § 7.2.14 -fn gen_keypair( +fn gen_keypair( context: LoadedContext<'_, R, T>, mode: GenerateAsymmetricKeyPairMode, ) -> Result<(), Status> { @@ -464,7 +464,7 @@ fn gen_keypair( } // § 7.2.16 -fn terminate_df( +fn terminate_df( mut ctx: Context<'_, R, T>, ) -> Result<(), Status> { if let Ok(ctx) = ctx.load_state() { @@ -490,7 +490,7 @@ fn unspecified_delete_error(_err: E) -> Status { Status::UnspecifiedPersistentExecutionError } -fn factory_reset( +fn factory_reset( ctx: Context<'_, R, T>, ) -> Result<(), Status> { ctx.state.volatile.clear(ctx.backend.client_mut()); @@ -521,7 +521,7 @@ fn factory_reset( } // § 7.2.17 -fn activate_file( +fn activate_file( mut ctx: Context<'_, R, T>, ) -> Result<(), Status> { if State::lifecycle(ctx.backend.client_mut(), ctx.options.storage) == LifeCycle::Operational { @@ -542,7 +542,7 @@ fn activate_file( } // § 7.2.4 -fn reset_retry_conter( +fn reset_retry_conter( ctx: LoadedContext<'_, R, T>, mode: ResetRetryCounterMode, ) -> Result<(), Status> { @@ -552,7 +552,7 @@ fn reset_retry_conter( } } -fn reset_retry_conter_with_p3( +fn reset_retry_conter_with_p3( mut ctx: LoadedContext<'_, R, T>, ) -> Result<(), Status> { if ctx.data.len() < MIN_LENGTH_USER_PIN || ctx.data.len() > MAX_PIN_LENGTH { @@ -575,7 +575,7 @@ fn reset_retry_conter_with_p3( }) } -fn reset_retry_conter_with_code( +fn reset_retry_conter_with_code( mut ctx: LoadedContext<'_, R, T>, ) -> Result<(), Status> { let code_len = ctx.state.persistent.reset_code_len().ok_or_else(|| { @@ -626,7 +626,7 @@ fn reset_retry_conter_with_code } // § 7.2.5 -fn select_data( +fn select_data( ctx: Context<'_, R, T>, occurrence: Occurrence, ) -> Result<(), Status> { @@ -643,7 +643,7 @@ fn select_data( } // § 7.2.15 -fn get_challenge( +fn get_challenge( mut ctx: Context<'_, R, T>, expected: usize, ) -> Result<(), Status> { @@ -665,7 +665,7 @@ fn get_challenge( } // § 7.2.18 -fn manage_security_environment( +fn manage_security_environment( ctx: Context<'_, R, T>, mode: ManageSecurityEnvironmentMode, ) -> Result<(), Status> { diff --git a/src/command/data.rs b/src/command/data.rs index b8277af2..4f228d65 100644 --- a/src/command/data.rs +++ b/src/command/data.rs @@ -8,7 +8,6 @@ use trussed::{ syscall, try_syscall, types::{KeyId, KeySerialization, Mechanism}, }; -use trussed_auth::AuthClient; const CHACHA_NONCE_SIZE: usize = 12; const CHACHA_TAG_SIZE: usize = 16; @@ -345,7 +344,7 @@ impl GetDataObject { | Self::DigitalSignatureCounter ) } - fn reply( + fn reply( self, mut context: Context<'_, R, T>, ) -> Result<(), Status> { @@ -451,7 +450,7 @@ const EXTENDED_CAPABILITIES: [u8; 10] = [ ]; // § 7.2.6 -pub fn get_data( +pub fn get_data( mut context: Context<'_, R, T>, mode: GetDataMode, tag: Tag, @@ -482,7 +481,7 @@ pub fn get_data( } // § 7.2.7 -pub fn get_next_data( +pub fn get_next_data( context: Context<'_, R, T>, tag: Tag, ) -> Result<(), Status> { @@ -513,7 +512,7 @@ fn filtered_objects( objects.iter().filter(move |o| !to_filter.contains(o)) } -fn get_constructed_data( +fn get_constructed_data( mut ctx: Context<'_, R, T>, objects: &'static [GetDataObject], ) -> Result<(), Status> { @@ -537,7 +536,7 @@ fn get_constructed_data( Ok(()) } -pub fn historical_bytes( +pub fn historical_bytes( mut ctx: Context<'_, R, T>, ) -> Result<(), Status> { ctx.reply.expand(&ctx.options.historical_bytes)?; @@ -547,7 +546,7 @@ pub fn historical_bytes( Ok(()) } -fn cardholder_cert( +fn cardholder_cert( ctx: Context<'_, R, T>, ) -> Result<(), Status> { let occ = match ctx.state.volatile.cur_do { @@ -562,7 +561,7 @@ fn cardholder_cert( get_arbitrary_do(ctx, to_load) } -fn pw_status_bytes( +fn pw_status_bytes( mut ctx: Context<'_, R, T>, ) -> Result<(), Status> { let status = if let Ok(ctx) = ctx.load_state() { @@ -601,7 +600,7 @@ fn pw_status_bytes( ctx.reply.expand(&status) } -fn algo_info( +fn algo_info( mut ctx: Context<'_, R, T>, ) -> Result<(), Status> { for alg in SignatureAlgorithm::iter_all() { @@ -625,7 +624,7 @@ fn algo_info( Ok(()) } -fn alg_attr_sign( +fn alg_attr_sign( mut ctx: Context<'_, R, T>, ) -> Result<(), Status> { if let Ok(mut ctx) = ctx.load_state() { @@ -637,7 +636,7 @@ fn alg_attr_sign( } } -fn alg_attr_dec( +fn alg_attr_dec( mut ctx: Context<'_, R, T>, ) -> Result<(), Status> { if let Ok(mut ctx) = ctx.load_state() { @@ -650,7 +649,7 @@ fn alg_attr_dec( } } -fn alg_attr_aut( +fn alg_attr_aut( mut ctx: Context<'_, R, T>, ) -> Result<(), Status> { if let Ok(mut ctx) = ctx.load_state() { @@ -663,7 +662,7 @@ fn alg_attr_aut( } } -fn fingerprints( +fn fingerprints( mut ctx: Context<'_, R, T>, ) -> Result<(), Status> { if let Ok(mut ctx) = ctx.load_state() { @@ -674,7 +673,7 @@ fn fingerprints( } } -fn ca_fingerprints( +fn ca_fingerprints( mut ctx: Context<'_, R, T>, ) -> Result<(), Status> { if let Ok(mut ctx) = ctx.load_state() { @@ -685,7 +684,7 @@ fn ca_fingerprints( } } -fn keygen_dates( +fn keygen_dates( mut ctx: Context<'_, R, T>, ) -> Result<(), Status> { if let Ok(mut ctx) = ctx.load_state() { @@ -704,7 +703,7 @@ fn key_info_byte(data: Option) -> u8 { } } -fn key_info( +fn key_info( mut ctx: Context<'_, R, T>, ) -> Result<(), Status> { if let Ok(mut ctx) = ctx.load_state() { @@ -728,7 +727,7 @@ fn key_info( } } -fn uif( +fn uif( mut ctx: Context<'_, R, T>, key: KeyType, ) -> Result<(), Status> { @@ -750,7 +749,7 @@ fn uif( } } -fn cardholder_name( +fn cardholder_name( mut ctx: Context<'_, R, T>, ) -> Result<(), Status> { if let Ok(mut ctx) = ctx.load_state() { @@ -761,7 +760,7 @@ fn cardholder_name( } } -fn cardholder_sex( +fn cardholder_sex( mut ctx: Context<'_, R, T>, ) -> Result<(), Status> { if let Ok(mut ctx) = ctx.load_state() { @@ -773,7 +772,7 @@ fn cardholder_sex( } } -fn language_preferences( +fn language_preferences( mut ctx: Context<'_, R, T>, ) -> Result<(), Status> { if let Ok(mut ctx) = ctx.load_state() { @@ -785,7 +784,7 @@ fn language_preferences( } } -fn signature_counter( +fn signature_counter( mut ctx: Context<'_, R, T>, ) -> Result<(), Status> { // Counter is only on 3 bytes @@ -798,7 +797,7 @@ fn signature_counter( } } -fn get_arbitrary_do( +fn get_arbitrary_do( mut ctx: Context<'_, R, T>, obj: ArbitraryDO, ) -> Result<(), Status> { @@ -818,7 +817,7 @@ fn get_arbitrary_do( ctx.reply.expand(&data) } -fn get_arbitrary_enc_do( +fn get_arbitrary_enc_do( mut ctx: LoadedContext<'_, R, T>, obj: ArbitraryDO, key: KeyId, @@ -845,7 +844,7 @@ fn get_arbitrary_enc_do( } /// Get an arbitrary DO encrypted with the user key -fn get_arbitrary_user_enc_do( +fn get_arbitrary_user_enc_do( ctx: LoadedContext<'_, R, T>, obj: ArbitraryDO, ) -> Result<(), Status> { @@ -856,7 +855,7 @@ fn get_arbitrary_user_enc_do( } /// Get an arbitrary DO encrypted with the admin key -fn get_arbitrary_admin_enc_do( +fn get_arbitrary_admin_enc_do( ctx: LoadedContext<'_, R, T>, obj: ArbitraryDO, ) -> Result<(), Status> { @@ -867,7 +866,7 @@ fn get_arbitrary_admin_enc_do( } // § 7.2.8 -pub fn put_data( +pub fn put_data( mut context: Context<'_, R, T>, mode: PutDataMode, tag: Tag, @@ -949,7 +948,7 @@ impl PutDataObject { } } - fn put_data( + fn put_data( self, mut ctx: Context<'_, R, T>, ) -> Result<(), Status> { @@ -995,7 +994,7 @@ impl PutDataObject { } } -fn put_cardholder_cert( +fn put_cardholder_cert( ctx: Context<'_, R, T>, ) -> Result<(), Status> { let occ = match ctx.state.volatile.cur_do { @@ -1012,7 +1011,7 @@ fn put_cardholder_cert( const AES256_KEY_LEN: usize = 32; -fn put_enc_dec_key( +fn put_enc_dec_key( mut ctx: LoadedContext<'_, R, T>, ) -> Result<(), Status> { if ctx.data.len() != AES256_KEY_LEN { @@ -1045,7 +1044,7 @@ fn put_enc_dec_key( Ok(()) } -fn put_resetting_code( +fn put_resetting_code( mut ctx: LoadedContext<'_, R, T>, ) -> Result<(), Status> { if ctx.data.is_empty() { @@ -1075,7 +1074,7 @@ fn put_resetting_code( }) } -fn put_uif( +fn put_uif( ctx: LoadedContext<'_, R, T>, key: KeyType, ) -> Result<(), Status> { @@ -1105,7 +1104,7 @@ fn put_uif( .map_err(|_| Status::UnspecifiedPersistentExecutionError) } -fn put_status_bytes( +fn put_status_bytes( ctx: LoadedContext<'_, R, T>, ) -> Result<(), Status> { if ctx.data.len() != 4 && ctx.data.len() != 1 { @@ -1135,7 +1134,7 @@ fn put_status_bytes( Ok(()) } -fn put_language_prefs( +fn put_language_prefs( ctx: LoadedContext<'_, R, T>, ) -> Result<(), Status> { let bytes = if ctx.data.len() % 2 == 0 { @@ -1158,7 +1157,7 @@ fn put_language_prefs( .map_err(|_| Status::UnspecifiedPersistentExecutionError) } -fn put_cardholder_sex( +fn put_cardholder_sex( ctx: LoadedContext<'_, R, T>, ) -> Result<(), Status> { if ctx.data.len() != 1 { @@ -1179,7 +1178,7 @@ fn put_cardholder_sex( .map_err(|_| Status::UnspecifiedPersistentExecutionError) } -fn put_cardholder_name( +fn put_cardholder_name( ctx: LoadedContext<'_, R, T>, ) -> Result<(), Status> { let bytes = heapless::Vec::try_from(ctx.data) @@ -1197,7 +1196,7 @@ fn put_cardholder_name( .map_err(|_| Status::UnspecifiedPersistentExecutionError) } -fn put_alg_attributes_sign( +fn put_alg_attributes_sign( ctx: LoadedContext<'_, R, T>, ) -> Result<(), Status> { let alg = SignatureAlgorithm::try_from(ctx.data).map_err(|_| { @@ -1214,7 +1213,7 @@ fn put_alg_attributes_sign( .map_err(|_| Status::UnspecifiedNonpersistentExecutionError) } -fn put_alg_attributes_dec( +fn put_alg_attributes_dec( ctx: LoadedContext<'_, R, T>, ) -> Result<(), Status> { let alg = DecryptionAlgorithm::try_from(ctx.data).map_err(|_| { @@ -1231,7 +1230,7 @@ fn put_alg_attributes_dec( .map_err(|_| Status::UnspecifiedNonpersistentExecutionError) } -fn put_alg_attributes_aut( +fn put_alg_attributes_aut( ctx: LoadedContext<'_, R, T>, ) -> Result<(), Status> { let alg = AuthenticationAlgorithm::try_from(ctx.data).map_err(|_| { @@ -1248,7 +1247,7 @@ fn put_alg_attributes_aut( .map_err(|_| Status::UnspecifiedNonpersistentExecutionError) } -fn put_arbitrary_admin_enc_do( +fn put_arbitrary_admin_enc_do( ctx: LoadedContext<'_, R, T>, obj: ArbitraryDO, ) -> Result<(), Status> { @@ -1257,7 +1256,7 @@ fn put_arbitrary_admin_enc_do( }; put_arbitrary_enc_do(ctx, obj, k) } -fn put_arbitrary_user_enc_do( +fn put_arbitrary_user_enc_do( ctx: LoadedContext<'_, R, T>, obj: ArbitraryDO, ) -> Result<(), Status> { @@ -1267,7 +1266,7 @@ fn put_arbitrary_user_enc_do( put_arbitrary_enc_do(ctx, obj, k) } -fn put_arbitrary_enc_do( +fn put_arbitrary_enc_do( ctx: LoadedContext<'_, R, T>, obj: ArbitraryDO, key: KeyId, @@ -1298,7 +1297,7 @@ fn put_arbitrary_enc_do( .map_err(|_| Status::UnspecifiedPersistentExecutionError) } -fn put_arbitrary_do( +fn put_arbitrary_do( ctx: Context<'_, R, T>, obj: ArbitraryDO, ) -> Result<(), Status> { @@ -1309,7 +1308,7 @@ fn put_arbitrary_do( .map_err(|_| Status::UnspecifiedPersistentExecutionError) } -fn put_fingerprint( +fn put_fingerprint( ctx: LoadedContext<'_, R, T>, for_key: KeyType, ) -> Result<(), Status> { @@ -1325,7 +1324,7 @@ fn put_fingerprint( .map_err(|_| Status::UnspecifiedNonpersistentExecutionError) } -fn put_ca_fingerprint( +fn put_ca_fingerprint( ctx: LoadedContext<'_, R, T>, for_key: KeyType, ) -> Result<(), Status> { @@ -1340,7 +1339,7 @@ fn put_ca_fingerprint( .map_err(|_| Status::UnspecifiedNonpersistentExecutionError) } -fn put_keygen_date( +fn put_keygen_date( ctx: LoadedContext<'_, R, T>, for_key: KeyType, ) -> Result<(), Status> { diff --git a/src/command/gen.rs b/src/command/gen.rs index e96f7080..e27f1ea4 100644 --- a/src/command/gen.rs +++ b/src/command/gen.rs @@ -5,7 +5,6 @@ use hex_literal::hex; use iso7816::Status; use trussed::try_syscall; use trussed::types::{KeyId, KeySerialization, Location, Mechanism, StorageAttributes}; -use trussed_auth::AuthClient; use crate::card::LoadedContext; use crate::state::KeyOrigin; @@ -16,7 +15,7 @@ const KEYGEN_DO_TAG: &[u8] = &hex!("7f49"); #[cfg(feature = "rsa")] use trussed_rsa_alloc::RsaPublicParts; -fn serialize_pub( +fn serialize_pub( algo: CurveAlgo, ctx: LoadedContext<'_, R, T>, public_key: &[u8], @@ -27,7 +26,7 @@ fn serialize_pub( } } -pub fn sign( +pub fn sign( mut ctx: LoadedContext<'_, R, T>, ) -> Result<(), Status> { let algo = ctx.state.persistent.sign_alg(); @@ -67,7 +66,7 @@ pub fn sign( } } -pub fn dec( +pub fn dec( mut ctx: LoadedContext<'_, R, T>, ) -> Result<(), Status> { let algo = ctx.state.persistent.dec_alg(); @@ -105,7 +104,7 @@ pub fn dec( } } -pub fn aut( +pub fn aut( mut ctx: LoadedContext<'_, R, T>, ) -> Result<(), Status> { let algo = ctx.state.persistent.aut_alg(); @@ -146,7 +145,7 @@ pub fn aut( } #[cfg(feature = "rsa2048-gen")] -fn gen_rsa_key( +fn gen_rsa_key( mut ctx: LoadedContext<'_, R, T>, key: KeyType, mechanism: Mechanism, @@ -184,7 +183,7 @@ fn gen_rsa_key( read_rsa_key(ctx, pubkey, mechanism) } -fn gen_ec_key( +fn gen_ec_key( mut ctx: LoadedContext<'_, R, T>, key: KeyType, curve: CurveAlgo, @@ -222,7 +221,7 @@ fn gen_ec_key( read_ec_key(ctx, pubkey, curve) } -pub fn read_sign( +pub fn read_sign( mut ctx: LoadedContext<'_, R, T>, ) -> Result<(), Status> { let key_id = ctx @@ -241,7 +240,7 @@ pub fn read_sign( } } -pub fn read_dec( +pub fn read_dec( mut ctx: LoadedContext<'_, R, T>, ) -> Result<(), Status> { let key_id = ctx @@ -266,7 +265,7 @@ pub fn read_dec( } } -pub fn read_aut( +pub fn read_aut( mut ctx: LoadedContext<'_, R, T>, ) -> Result<(), Status> { let key_id = ctx @@ -291,7 +290,7 @@ pub fn read_aut( } } -fn serialize_p256( +fn serialize_p256( mut ctx: LoadedContext<'_, R, T>, serialized: &[u8], ) -> Result<(), Status> { @@ -301,7 +300,7 @@ fn serialize_p256( ctx.reply.expand(serialized) } -fn serialize_25519( +fn serialize_25519( mut ctx: LoadedContext<'_, R, T>, serialized: &[u8], ) -> Result<(), Status> { @@ -310,7 +309,7 @@ fn serialize_25519( ctx.reply.expand(serialized) } -fn read_ec_key( +fn read_ec_key( mut ctx: LoadedContext<'_, R, T>, public_key: KeyId, curve: CurveAlgo, @@ -330,7 +329,7 @@ fn read_ec_key( } #[cfg(feature = "rsa")] -fn read_rsa_key( +fn read_rsa_key( mut ctx: LoadedContext<'_, R, T>, public_key: KeyId, mechanism: Mechanism, @@ -364,7 +363,7 @@ fn read_rsa_key( } #[cfg(not(feature = "rsa"))] -fn read_rsa_key( +fn read_rsa_key( _ctx: LoadedContext<'_, R, T>, _key_id: KeyId, _mechanism: Mechanism, diff --git a/src/command/private_key_template.rs b/src/command/private_key_template.rs index 6369e9fc..4de5f780 100644 --- a/src/command/private_key_template.rs +++ b/src/command/private_key_template.rs @@ -4,7 +4,6 @@ use iso7816::Status; use trussed::try_syscall; use trussed::types::{KeyId, KeySerialization, Location, Mechanism, StorageAttributes}; -use trussed_auth::AuthClient; use crate::card::LoadedContext; use crate::state::KeyOrigin; @@ -18,7 +17,7 @@ const CONCATENATION_KEY_DATA_DO: u16 = 0x5F48; use trussed_rsa_alloc::RsaImportFormat; // § 4.4.3.12 -pub fn put_private_key_template( +pub fn put_private_key_template( ctx: LoadedContext<'_, R, T>, ) -> Result<(), Status> { let data = get_do(&[PRIVATE_KEY_TEMPLATE_DO], ctx.data).ok_or_else(|| { @@ -37,7 +36,7 @@ pub fn put_private_key_template Ok(()) } -pub fn put_sign( +pub fn put_sign( mut ctx: LoadedContext<'_, R, T>, ) -> Result<(), Status> { let attr = ctx.state.persistent.sign_alg(); @@ -63,7 +62,7 @@ pub fn put_sign( Ok(()) } -pub fn put_dec( +pub fn put_dec( mut ctx: LoadedContext<'_, R, T>, ) -> Result<(), Status> { let attr = ctx.state.persistent.dec_alg(); @@ -89,7 +88,7 @@ pub fn put_dec( Ok(()) } -pub fn put_aut( +pub fn put_aut( mut ctx: LoadedContext<'_, R, T>, ) -> Result<(), Status> { let attr = ctx.state.persistent.aut_alg(); @@ -115,7 +114,7 @@ pub fn put_aut( Ok(()) } -fn put_ec( +fn put_ec( ctx: LoadedContext<'_, R, T>, curve: CurveAlgo, ) -> Result, Status> { @@ -204,7 +203,7 @@ fn parse_rsa_template(data: &[u8]) -> Option { } #[cfg(feature = "rsa")] -fn put_rsa( +fn put_rsa( ctx: LoadedContext<'_, R, T>, mechanism: Mechanism, ) -> Result, Status> { @@ -254,7 +253,7 @@ fn put_rsa( } #[cfg(not(feature = "rsa"))] -fn put_rsa( +fn put_rsa( _ctx: LoadedContext<'_, R, T>, _mechanism: Mechanism, ) -> Result, Status> { diff --git a/src/command/pso.rs b/src/command/pso.rs index ce35b476..25bf8831 100644 --- a/src/command/pso.rs +++ b/src/command/pso.rs @@ -5,14 +5,13 @@ use iso7816::Status; use trussed::types::*; use trussed::{syscall, try_syscall}; -use trussed_auth::AuthClient; use crate::card::LoadedContext; use crate::state::KeyRef; use crate::tlv::get_do; use crate::types::*; -fn check_uif( +fn check_uif( ctx: LoadedContext<'_, R, T>, key: KeyType, ) -> Result<(), Status> { @@ -23,7 +22,7 @@ fn check_uif( } } -fn prompt_uif( +fn prompt_uif( ctx: LoadedContext<'_, R, T>, ) -> Result<(), Status> { let success = ctx @@ -40,7 +39,7 @@ fn prompt_uif( } // § 7.2.10 -pub fn sign( +pub fn sign( mut ctx: LoadedContext<'_, R, T>, ) -> Result<(), Status> { let key_id = @@ -76,7 +75,7 @@ pub fn sign( sign_result } -fn sign_ec( +fn sign_ec( mut ctx: LoadedContext<'_, R, T>, key_id: KeyId, mechanism: Mechanism, @@ -95,7 +94,7 @@ fn sign_ec( ctx.reply.expand(&signature) } -fn sign_rsa( +fn sign_rsa( mut ctx: LoadedContext<'_, R, T>, key_id: KeyId, mechanism: Mechanism, @@ -119,7 +118,7 @@ enum RsaOrEcc { Ecc, } -fn int_aut_key_mecha_uif( +fn int_aut_key_mecha_uif( ctx: LoadedContext<'_, R, T>, ) -> Result<(KeyId, Mechanism, bool, RsaOrEcc), Status> { let (key_type, (mechanism, key_kind)) = match ctx.state.volatile.keyrefs.internal_aut { @@ -168,7 +167,7 @@ fn int_aut_key_mecha_uif( } // § 7.2.13 -pub fn internal_authenticate( +pub fn internal_authenticate( mut ctx: LoadedContext<'_, R, T>, ) -> Result<(), Status> { if !ctx.state.volatile.other_verified() { @@ -187,7 +186,7 @@ pub fn internal_authenticate( } } -fn decipher_key_mecha_uif( +fn decipher_key_mecha_uif( ctx: LoadedContext<'_, R, T>, ) -> Result<(KeyId, Mechanism, bool, RsaOrEcc), Status> { let (key_type, (mechanism, key_kind)) = match ctx.state.volatile.keyrefs.pso_decipher { @@ -228,7 +227,7 @@ fn decipher_key_mecha_uif( } // § 7.2.11 -pub fn decipher( +pub fn decipher( mut ctx: LoadedContext<'_, R, T>, ) -> Result<(), Status> { if !ctx.state.volatile.other_verified() { @@ -253,7 +252,7 @@ pub fn decipher( } } -fn decrypt_rsa( +fn decrypt_rsa( mut ctx: LoadedContext<'_, R, T>, private_key: KeyId, mechanism: Mechanism, @@ -281,7 +280,7 @@ fn decrypt_rsa( ctx.reply.expand(&plaintext) } -fn decrypt_ec( +fn decrypt_ec( mut ctx: LoadedContext<'_, R, T>, private_key: KeyId, mechanism: Mechanism, @@ -360,7 +359,7 @@ fn decrypt_ec( ctx.reply.expand(&data) } -fn decipher_aes( +fn decipher_aes( mut ctx: LoadedContext<'_, R, T>, ) -> Result<(), Status> { let key_id = ctx @@ -393,7 +392,7 @@ fn decipher_aes( ctx.reply.expand(&plaintext) } -pub fn encipher( +pub fn encipher( mut ctx: LoadedContext<'_, R, T>, ) -> Result<(), Status> { let key_id = ctx diff --git a/src/lib.rs b/src/lib.rs index b27f6c10..44a605f8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -8,12 +8,12 @@ //! # Backends //! //! This crate is designed to work on any platform supported by [trussed](https://trussed.dev). -//! Trussed requires a [Client][trussed::Client] implementation for each platform. +//! Trussed requires a [Client][crate::card::Client] implementation for each platform. //! //! # Command handling //! //! The [`Card`] struct is the main entry point for this crate. It depends on a Trussed -//! [`Client`][`trussed::Client`] implementation that provides low-level functionality. The card +//! [`Client`][`crate::card::Client`] implementation that provides low-level functionality. The card //! can be configured using [`Options`]. Its [`Card::handle`] method expects a full APDU command //! and constructs a reply for it. //! @@ -64,5 +64,5 @@ pub mod virt; #[cfg(feature = "vpicc")] pub use self::vpicc::VpiccCard; -pub use card::{Card, Options}; +pub use card::{Card, Client, Options}; pub use state::{DEFAULT_ADMIN_PIN, DEFAULT_USER_PIN}; diff --git a/src/state.rs b/src/state.rs index 82e573c6..5adc4a38 100644 --- a/src/state.rs +++ b/src/state.rs @@ -13,7 +13,6 @@ use trussed::api::reply::Metadata; use trussed::config::MAX_MESSAGE_LENGTH; use trussed::types::{KeyId, Location, Mechanism, PathBuf, StorageAttributes}; use trussed::{syscall, try_syscall}; -use trussed_auth::AuthClient; use crate::command::{Password, PasswordMode}; use crate::error::Error; @@ -170,7 +169,7 @@ pub struct State { impl State { /// Loads the persistent state from flash - pub fn load<'s, T: trussed::Client + AuthClient>( + pub fn load<'s, T: crate::card::Client>( &'s mut self, client: &mut T, storage: Location, @@ -204,17 +203,14 @@ impl State { fn lifecycle_path() -> PathBuf { PathBuf::from(Self::LIFECYCLE_PATH) } - pub fn lifecycle( - client: &mut T, - storage: Location, - ) -> LifeCycle { + pub fn lifecycle(client: &mut T, storage: Location) -> LifeCycle { match try_syscall!(client.entry_metadata(storage, Self::lifecycle_path())) { Ok(Metadata { metadata: Some(_) }) => LifeCycle::Initialization, _ => LifeCycle::Operational, } } - pub fn terminate_df( + pub fn terminate_df( client: &mut T, storage: Location, ) -> Result<(), Status> { @@ -226,7 +222,7 @@ impl State { }) } - pub fn activate_file( + pub fn activate_file( client: &mut T, storage: Location, ) -> Result<(), Status> { @@ -255,7 +251,7 @@ impl<'a> LoadedState<'a> { } } - pub fn verify_pin( + pub fn verify_pin( &mut self, client: &mut T, storage: Location, @@ -305,7 +301,7 @@ impl<'a> LoadedState<'a> { Ok(()) } - pub fn check_pin( + pub fn check_pin( &mut self, client: &mut T, value: &[u8], @@ -321,7 +317,7 @@ impl<'a> LoadedState<'a> { .ok_or(Error::InvalidPin) } - fn get_user_key( + fn get_user_key( &mut self, client: &mut T, storage: Location, @@ -348,7 +344,7 @@ impl<'a> LoadedState<'a> { Ok(user_key) } - fn get_user_key_from_rc( + fn get_user_key_from_rc( &mut self, client: &mut T, storage: Location, @@ -375,7 +371,7 @@ impl<'a> LoadedState<'a> { Ok(user_key) } - pub fn reset_user_code_with_pw3( + pub fn reset_user_code_with_pw3( &mut self, client: &mut T, storage: Location, @@ -388,7 +384,7 @@ impl<'a> LoadedState<'a> { Ok(()) } - pub fn reset_user_code_with_rc( + pub fn reset_user_code_with_rc( &mut self, client: &mut T, storage: Location, @@ -402,7 +398,7 @@ impl<'a> LoadedState<'a> { Ok(()) } - pub fn set_reset_code( + pub fn set_reset_code( &mut self, client: &mut T, storage: Location, @@ -437,7 +433,7 @@ impl<'a> LoadedState<'a> { Ok(()) } - pub fn set_aes_key( + pub fn set_aes_key( &mut self, new: KeyId, client: &mut T, @@ -458,7 +454,7 @@ impl<'a> LoadedState<'a> { } /// New contains (private key, (public key, KeyOrigin)) - pub fn set_key( + pub fn set_key( &mut self, ty: KeyType, new: Option<(KeyId, (KeyId, KeyOrigin))>, @@ -610,10 +606,7 @@ impl Persistent { } } - fn init_pins( - client: &mut T, - location: Location, - ) -> Result<(), Error> { + fn init_pins(client: &mut T, location: Location) -> Result<(), Error> { #[allow(clippy::unwrap_used)] let default_user_pin = Bytes::from_slice(DEFAULT_USER_PIN).unwrap(); #[allow(clippy::unwrap_used)] @@ -653,10 +646,7 @@ impl Persistent { syscall!(client.delete(admin_key)); Ok(()) } - pub fn load( - client: &mut T, - storage: Location, - ) -> Result { + pub fn load(client: &mut T, storage: Location) -> Result { if let Some(data) = load_if_exists(client, storage, &Self::path())? { trussed::cbor_deserialize(&data).map_err(|_err| { error!("failed to deserialize persistent state: {_err}"); @@ -668,7 +658,11 @@ impl Persistent { } } - pub fn save(&self, client: &mut T, storage: Location) -> Result<(), Error> { + pub fn save( + &self, + client: &mut T, + storage: Location, + ) -> Result<(), Error> { let msg = trussed::cbor_serialize_bytes(&self).map_err(|_err| { error!("Failed to serialize: {_err}"); Error::Saving @@ -680,7 +674,7 @@ impl Persistent { Ok(()) } - pub fn remaining_tries( + pub fn remaining_tries( &self, client: &mut T, password: Password, @@ -690,11 +684,7 @@ impl Persistent { .unwrap_or(0) } - pub fn is_locked( - &self, - client: &mut T, - password: Password, - ) -> bool { + pub fn is_locked(&self, client: &mut T, password: Password) -> bool { self.remaining_tries(client, password) == 0 } @@ -712,7 +702,7 @@ impl Persistent { self.reset_code_pin_len.map(Into::into) } - pub fn change_pin( + pub fn change_pin( &mut self, client: &mut T, storage: Location, @@ -727,7 +717,7 @@ impl Persistent { self.set_pin_len(client, storage, new_pin.len(), password) } - fn set_pin_len( + fn set_pin_len( &mut self, client: &mut T, storage: Location, @@ -742,7 +732,7 @@ impl Persistent { self.save(client, storage) } - pub fn remove_reset_code( + pub fn remove_reset_code( &mut self, client: &mut T, storage: Location, @@ -761,7 +751,7 @@ impl Persistent { pub fn set_sign_alg( &mut self, - client: &mut impl trussed::Client, + client: &mut impl crate::card::Client, storage: Location, alg: SignatureAlgorithm, ) -> Result<(), Error> { @@ -779,7 +769,7 @@ impl Persistent { pub fn set_dec_alg( &mut self, - client: &mut impl trussed::Client, + client: &mut impl crate::card::Client, storage: Location, alg: DecryptionAlgorithm, ) -> Result<(), Error> { @@ -797,7 +787,7 @@ impl Persistent { pub fn set_aut_alg( &mut self, - client: &mut impl trussed::Client, + client: &mut impl crate::card::Client, storage: Location, alg: AuthenticationAlgorithm, ) -> Result<(), Error> { @@ -815,7 +805,7 @@ impl Persistent { pub fn set_fingerprints( &mut self, - client: &mut impl trussed::Client, + client: &mut impl crate::card::Client, storage: Location, data: Fingerprints, ) -> Result<(), Error> { @@ -829,7 +819,7 @@ impl Persistent { pub fn set_ca_fingerprints( &mut self, - client: &mut impl trussed::Client, + client: &mut impl crate::card::Client, storage: Location, data: CaFingerprints, ) -> Result<(), Error> { @@ -843,7 +833,7 @@ impl Persistent { pub fn set_keygen_dates( &mut self, - client: &mut impl trussed::Client, + client: &mut impl crate::card::Client, storage: Location, data: KeyGenDates, ) -> Result<(), Error> { @@ -861,7 +851,7 @@ impl Persistent { pub fn set_uif( &mut self, - client: &mut impl trussed::Client, + client: &mut impl crate::card::Client, storage: Location, uif: Uif, key: KeyType, @@ -881,7 +871,7 @@ impl Persistent { pub fn set_pw1_valid_multiple( &mut self, value: bool, - client: &mut impl trussed::Client, + client: &mut impl crate::card::Client, storage: Location, ) -> Result<(), Error> { self.pw1_valid_multiple = value; @@ -895,7 +885,7 @@ impl Persistent { pub fn set_cardholder_name( &mut self, value: Bytes<39>, - client: &mut impl trussed::Client, + client: &mut impl crate::card::Client, storage: Location, ) -> Result<(), Error> { self.cardholder_name = value; @@ -909,7 +899,7 @@ impl Persistent { pub fn set_cardholder_sex( &mut self, value: Sex, - client: &mut impl trussed::Client, + client: &mut impl crate::card::Client, storage: Location, ) -> Result<(), Error> { self.cardholder_sex = value; @@ -923,7 +913,7 @@ impl Persistent { pub fn set_language_preferences( &mut self, value: Bytes<8>, - client: &mut impl trussed::Client, + client: &mut impl crate::card::Client, storage: Location, ) -> Result<(), Error> { self.language_preferences = value; @@ -936,7 +926,7 @@ impl Persistent { pub fn increment_sign_count( &mut self, - client: &mut impl trussed::Client, + client: &mut impl crate::card::Client, storage: Location, ) -> Result<(), Error> { self.sign_count += 1; @@ -958,7 +948,7 @@ impl Persistent { pub fn delete_key( &mut self, ty: KeyType, - client: &mut impl trussed::Client, + client: &mut impl crate::card::Client, storage: Location, ) -> Result<(), Error> { let (key, path) = match ty { @@ -1022,7 +1012,7 @@ impl UserKeys { take(self) } - fn clear(&mut self, client: &mut impl trussed::Client) { + fn clear(&mut self, client: &mut impl crate::card::Client) { for k in [&mut self.sign, &mut self.dec, &mut self.aut, &mut self.aes] .into_iter() .flat_map(Option::take) @@ -1131,7 +1121,7 @@ impl UserVerifiedInner { _ => None, } } - fn clear(&mut self, client: &mut impl trussed::Client) { + fn clear(&mut self, client: &mut impl crate::card::Client) { match self.take() { Self::Other(k, mut cache) | Self::Sign(k, mut cache) @@ -1157,7 +1147,7 @@ impl UserVerifiedInner { } } - fn clear_cached(&mut self, client: &mut impl trussed::Client, ty: KeyType) { + fn clear_cached(&mut self, client: &mut impl crate::card::Client, ty: KeyType) { let Some(cache) = self.cache_mut() else { return; }; @@ -1173,7 +1163,7 @@ impl UserVerifiedInner { } } - fn clear_aes_cached(&mut self, client: &mut impl trussed::Client) { + fn clear_aes_cached(&mut self, client: &mut impl crate::card::Client) { let Some(cache) = self.cache_mut() else { return; }; @@ -1183,14 +1173,14 @@ impl UserVerifiedInner { } } - fn clear_sign(&mut self, client: &mut impl trussed::Client) { + fn clear_sign(&mut self, client: &mut impl crate::card::Client) { match self { Self::Sign(_k, _cache) => self.clear(client), Self::OtherAndSign(k, cache) => *self = Self::Other(*k, cache.take()), _ => {} }; } - fn clear_other(&mut self, client: &mut impl trussed::Client) { + fn clear_other(&mut self, client: &mut impl crate::card::Client) { match self { Self::Other(_k, _cache) => self.clear(client), Self::OtherAndSign(k, cache) => *self = Self::Sign(*k, cache.take()), @@ -1242,14 +1232,14 @@ impl Volatile { self.admin.0 } - pub fn clear_admin(&mut self, client: &mut impl trussed::Client) { + pub fn clear_admin(&mut self, client: &mut impl crate::card::Client) { if let Some(k) = self.admin.0.take() { syscall!(client.delete(k)); } } fn load_or_get_key( - client: &mut impl trussed::Client, + client: &mut impl crate::card::Client, user_kek: KeyId, opt_key: &mut Option, path: &'static str, @@ -1283,7 +1273,7 @@ impl Volatile { pub fn aes_key_id( &mut self, - client: &mut impl trussed::Client, + client: &mut impl crate::card::Client, storage: Location, ) -> Result { match &mut self.user.0 { @@ -1299,7 +1289,7 @@ impl Volatile { /// Returns the requested key pub fn key_id( &mut self, - client: &mut impl trussed::Client, + client: &mut impl crate::card::Client, key: KeyType, storage: Location, ) -> Result { @@ -1343,15 +1333,15 @@ impl Volatile { self.user.0.user_kek() } - pub fn clear(&mut self, client: &mut impl trussed::Client) { + pub fn clear(&mut self, client: &mut impl crate::card::Client) { self.user.0.clear(client); self.clear_admin(client) } - pub fn clear_sign(&mut self, client: &mut impl trussed::Client) { + pub fn clear_sign(&mut self, client: &mut impl crate::card::Client) { self.user.0.clear_sign(client) } - pub fn clear_other(&mut self, client: &mut impl trussed::Client) { + pub fn clear_other(&mut self, client: &mut impl crate::card::Client) { self.user.0.clear_other(client) } } @@ -1416,7 +1406,7 @@ impl ArbitraryDO { pub fn load( self, - client: &mut impl trussed::Client, + client: &mut impl crate::card::Client, storage: Location, ) -> Result, Error> { load_if_exists(client, storage, &self.path()) @@ -1425,7 +1415,7 @@ impl ArbitraryDO { pub fn save( self, - client: &mut impl trussed::Client, + client: &mut impl crate::card::Client, storage: Location, bytes: &[u8], ) -> Result<(), Error> { @@ -1442,7 +1432,7 @@ impl ArbitraryDO { } fn load_if_exists( - client: &mut impl trussed::Client, + client: &mut impl crate::card::Client, location: Location, path: &PathBuf, ) -> Result>, Error> { diff --git a/src/virt.rs b/src/virt.rs index 1c8631f3..e3aafb79 100644 --- a/src/virt.rs +++ b/src/virt.rs @@ -16,12 +16,16 @@ pub mod dispatch { types::{Bytes, Context, Location}, }; use trussed_auth::{AuthBackend, AuthContext, AuthExtension, MAX_HW_KEY_LEN}; + use trussed_staging::{ + wrap_key_to_file::WrapKeyToFileExtension, StagingBackend, StagingContext, + }; #[cfg(feature = "rsa")] use trussed_rsa_alloc::SoftwareRsa; /// Backends used by opcard pub const BACKENDS: &[BackendId] = &[ + BackendId::Custom(Backend::Staging), BackendId::Custom(Backend::Auth), #[cfg(feature = "rsa")] BackendId::Custom(Backend::Rsa), @@ -33,6 +37,8 @@ pub mod dispatch { pub enum Backend { /// trussed-auth Auth, + /// trussed-staging + Staging, /// trussed-rsa-alloc #[cfg(feature = "rsa")] Rsa, @@ -44,12 +50,15 @@ pub mod dispatch { pub enum Extension { /// trussed-auth Auth, + /// wrap_key_to_file + WrapKeyToFile, } impl From for u8 { fn from(extension: Extension) -> Self { match extension { Extension::Auth => 0, + Extension::WrapKeyToFile => 1, } } } @@ -60,6 +69,7 @@ pub mod dispatch { fn try_from(id: u8) -> Result { match id { 0 => Ok(Extension::Auth), + 1 => Ok(Extension::WrapKeyToFile), _ => Err(Error::InternalError), } } @@ -69,12 +79,14 @@ pub mod dispatch { #[derive(Debug)] pub struct Dispatch { auth: AuthBackend, + staging: StagingBackend, } /// Dispatch context for the backends required by opcard #[derive(Default, Debug)] pub struct DispatchContext { auth: AuthContext, + staging: StagingContext, } impl Dispatch { @@ -82,6 +94,7 @@ pub mod dispatch { pub fn new() -> Self { Self { auth: AuthBackend::new(Location::Internal), + staging: StagingBackend::new(), } } @@ -89,6 +102,7 @@ pub mod dispatch { pub fn with_hw_key(hw_key: Bytes) -> Self { Self { auth: AuthBackend::with_hw_key(Location::Internal, hw_key), + staging: StagingBackend::new(), } } } @@ -116,6 +130,12 @@ pub mod dispatch { self.auth .request(&mut ctx.core, &mut ctx.backends.auth, request, resources) } + Backend::Staging => self.staging.request( + &mut ctx.core, + &mut ctx.backends.staging, + request, + resources, + ), #[cfg(feature = "rsa")] Backend::Rsa => SoftwareRsa.request(&mut ctx.core, &mut (), request, resources), } @@ -137,7 +157,18 @@ pub mod dispatch { request, resources, ), + Extension::WrapKeyToFile => Err(Error::RequestNotAvailable), + }, + Backend::Staging => match extension { + Extension::WrapKeyToFile => self.staging.extension_request_serialized( + &mut ctx.core, + &mut ctx.backends.staging, + request, + resources, + ), + Extension::Auth => Err(Error::RequestNotAvailable), }, + #[cfg(feature = "rsa")] Backend::Rsa => Err(Error::RequestNotAvailable), } @@ -149,6 +180,12 @@ pub mod dispatch { const ID: Self::Id = Self::Id::Auth; } + + impl ExtensionId for Dispatch { + type Id = Extension; + + const ID: Self::Id = Self::Id::WrapKeyToFile; + } } use std::path::PathBuf; diff --git a/src/vpicc.rs b/src/vpicc.rs index af9d8039..a675b994 100644 --- a/src/vpicc.rs +++ b/src/vpicc.rs @@ -2,7 +2,6 @@ // SPDX-License-Identifier: LGPL-3.0-only use iso7816::{command::FromSliceError, Command, Status}; -use trussed_auth::AuthClient; use crate::card::Card; @@ -14,13 +13,13 @@ const RESPONSE_LEN: usize = 7609; /// This struct provides a vpicc OpenPGP smart card implementation that can be used with /// `vpicc-rs` and [`vsmartcard`](https://frankmorgner.github.io/vsmartcard/) to emulate the card. #[derive(Clone, Debug)] -pub struct VpiccCard { +pub struct VpiccCard { request_buffer: RequestBuffer, response_buffer: ResponseBuffer, card: Card, } -impl VpiccCard { +impl VpiccCard { /// Creates a new virtual smart card from the given card. pub fn new(card: Card) -> Self { Self { @@ -45,7 +44,7 @@ impl VpiccCard { } } -impl vpicc::VSmartCard for VpiccCard { +impl vpicc::VSmartCard for VpiccCard { fn power_on(&mut self) {} fn power_off(&mut self) { diff --git a/tests/card/mod.rs b/tests/card/mod.rs index 6707c994..20f5109e 100644 --- a/tests/card/mod.rs +++ b/tests/card/mod.rs @@ -21,11 +21,9 @@ const REQUEST_LEN: usize = 7609; const RESPONSE_LEN: usize = 7609; #[derive(Debug)] -pub struct Card( - Arc>>, -); +pub struct Card(Arc>>); -impl Card { +impl Card { pub fn new(client: T) -> Self { Self::with_options(client, Options::default()) } @@ -60,7 +58,7 @@ impl Card { } } -impl CardBackend for Card { +impl CardBackend for Card { fn transaction(&mut self) -> Result, Error> { // TODO: use reference instead of cloning Ok(Box::new(Transaction { @@ -71,12 +69,12 @@ impl CardBackend for Ca } #[derive(Debug)] -pub struct Transaction { +pub struct Transaction { card: Arc>>, buffer: heapless::Vec, } -impl Transaction { +impl Transaction { fn handle(&mut self, command: &[u8]) -> Result<(), Status> { self.buffer.clear(); let command = Command::::try_from(command).map_err(|err| match err { @@ -91,7 +89,7 @@ impl Transaction { } } -impl CardTransaction for Transaction { +impl CardTransaction for Transaction { fn transmit(&mut self, command: &[u8], _buf_size: usize) -> Result, Error> { let status = self.handle(command).err().unwrap_or_default(); let status: [u8; 2] = status.into(); diff --git a/tests/command-response.rs b/tests/command-response.rs index bb216616..026824ca 100644 --- a/tests/command-response.rs +++ b/tests/command-response.rs @@ -7,7 +7,6 @@ use std::borrow::Cow; use hex_literal::hex; use ron::{extensions::Extensions, Options}; use serde::Deserialize; -use trussed_auth::AuthClient; // iso7816::Status doesn't support serde #[derive(Deserialize, Debug, PartialEq, Clone, Copy, Default)] @@ -424,7 +423,7 @@ enum IoCmd { const MATCH_EMPTY: OutputMatcher = OutputMatcher::Len(0); impl IoCmd { - fn run(&self, card: &mut opcard::Card) { + fn run(&self, card: &mut opcard::Card) { match self { Self::FactoryReset { already_failed } => Self::run_factory_reset(*already_failed, card), Self::Select => Self::run_select(card), @@ -477,7 +476,7 @@ impl IoCmd { } } - fn run_bytes( + fn run_bytes( input: &[u8], output: &OutputMatcher, expected_status: Status, @@ -504,7 +503,7 @@ impl IoCmd { } } - fn run_select(card: &mut opcard::Card) { + fn run_select(card: &mut opcard::Card) { Self::run_bytes( &hex!("00 A4 0400 06 D27600012401"), &MATCH_EMPTY, @@ -513,10 +512,7 @@ impl IoCmd { ) } - fn run_factory_reset( - already_failed: u8, - card: &mut opcard::Card, - ) { + fn run_factory_reset(already_failed: u8, card: &mut opcard::Card) { for i in 0..(3 - already_failed) { Self::run_verify( Pin::Pw3, @@ -531,7 +527,7 @@ impl IoCmd { Self::run_bytes(&hex!("00 44 00 00"), &MATCH_EMPTY, Status::Success, card); } - fn run_iodata( + fn run_iodata( input: &str, output: &OutputMatcher, expected_status: Status, @@ -540,7 +536,7 @@ impl IoCmd { Self::run_bytes(&parse_hex(input), output, expected_status, card) } - fn run_put_data( + fn run_put_data( data_object: DataObject, data: &[u8], expected_status: Status, @@ -552,7 +548,7 @@ impl IoCmd { Self::run_bytes(&input, &OutputMatcher::Len(0), expected_status, card) } - fn run_import( + fn run_import( key: &str, key_type: Option, key_kind: &KeyKind, @@ -578,7 +574,7 @@ impl IoCmd { Self::run_bytes(&input, &OutputMatcher::Len(0), expected_status, card) } - fn run_set_attributes( + fn run_set_attributes( key_kind: &KeyKind, key_type: &KeyType, card: &mut opcard::Card, @@ -594,7 +590,7 @@ impl IoCmd { Self::run_bytes(&input, &OutputMatcher::Len(0), Status::Success, card) } - fn run_verify( + fn run_verify( pin: Pin, value: &Option, expected_status: Status, @@ -605,7 +601,7 @@ impl IoCmd { let input = build_command(0x00, 0x20, 0x00, pin as u8, value, 0); Self::run_bytes(&input, &MATCH_EMPTY, expected_status, card) } - fn run_change( + fn run_change( pin: Pin, old_value: &Option, new_value: &Option, @@ -621,7 +617,7 @@ impl IoCmd { Self::run_bytes(&input, &MATCH_EMPTY, expected_status, card) } - fn run_unblock_pin( + fn run_unblock_pin( reset_code: &Option, new_value: &Option, expected_status: Status, @@ -649,7 +645,7 @@ impl IoCmd { } } - fn run_read_key( + fn run_read_key( key_kind: &KeyKind, key_type: &KeyType, public_key: &str, @@ -673,11 +669,7 @@ impl IoCmd { ) } - fn run_sign( - input: &str, - output: &str, - card: &mut opcard::Card, - ) { + fn run_sign(input: &str, output: &str, card: &mut opcard::Card) { let input = build_command(0x00, 0x2A, 0x9E, 0x9A, &parse_hex(input), 0); Self::run_bytes( &input, @@ -687,7 +679,7 @@ impl IoCmd { ) } - fn run_decrypt( + fn run_decrypt( input: &str, output: &str, key_kind: &KeyKind,