From f6c223cd515e5b67c874933ab9f0940451bbcf3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= Date: Thu, 27 Jul 2023 17:29:55 +0200 Subject: [PATCH 1/7] Add se050 test --- Cargo.toml | 8 + src/admin.rs | 78 ++- src/admin/run_tests.rs | 1039 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 1120 insertions(+), 5 deletions(-) create mode 100644 src/admin/run_tests.rs diff --git a/Cargo.toml b/Cargo.toml index 542482d..e71f0dc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,7 +16,13 @@ delog = "0.1" iso7816 = "0.1" trussed = "0.1" +se050 = { version = "0.0.1", optional = true } +embedded-hal = { version = "0.2.7", optional = true } +hex-literal = "0.4.1" + [features] +se050 = ["dep:se050", "embedded-hal"] + log-all = [] log-none = [] log-info = [] @@ -27,3 +33,5 @@ log-error = [] [patch.crates-io] ctaphid-dispatch = { git = "https://github.com/trussed-dev/ctaphid-dispatch.git", rev = "57cb3317878a8593847595319aa03ef17c29ec5b" } trussed = { git = "https://github.com/trussed-dev/trussed.git", rev = "51e68500d7601d04f884f5e95567d14b9018a6cb" } +iso7816 = { git = "https://github.com/sosthene-nitrokey/iso7816.git", rev = "160ca3bbd8e21ec4e4ee1e0748e1eaa53a45c97f"} +se050 = { git = "https://github.com/sosthene-nitrokey/se050-generation.git", rev = "b645ea9de6c53c18a2173ec8d4d1307580c405c3"} diff --git a/src/admin.rs b/src/admin.rs index ba1200a..d46bb52 100644 --- a/src/admin.rs +++ b/src/admin.rs @@ -3,6 +3,10 @@ use apdu_dispatch::{app as apdu, command, response, Command as ApduCommand}; use core::{convert::TryInto, marker::PhantomData, time::Duration}; use ctaphid_dispatch::app::{self as hid, Command as HidCommand, Message}; use ctaphid_dispatch::command::VendorCommand; +#[cfg(feature = "se050")] +use embedded_hal::blocking::delay::DelayUs; +#[cfg(feature = "se050")] +use se050::{se050::Se050, t1::I2CForT1}; use trussed::{interrupt::InterruptFlag, syscall, types::Vec, Client as TrussedClient}; pub const USER_PRESENCE_TIMEOUT_SECS: u32 = 15; @@ -11,6 +15,7 @@ pub const USER_PRESENCE_TIMEOUT_SECS: u32 = 15; // application). The actual application command is stored in the first byte of the packet data. const ADMIN: VendorCommand = VendorCommand::H72; const STATUS: u8 = 0x80; +const TEST_SE050: u8 = 0x81; // For compatibility, old commands are also available directly as separate vendor commands. const UPDATE: VendorCommand = VendorCommand::H51; @@ -25,7 +30,19 @@ const WINK: HidCommand = HidCommand::Wink; // 0x08 const RNG_DATA_LEN: usize = 57; -#[derive(PartialEq)] +mod run_tests; +use run_tests::*; + +/// Trait representing the possible ownership of the SE050 by the admin app. +/// +/// Implemented by `()` and the `Se050` stract +pub trait MaybeSe: RunTests {} + +impl MaybeSe for () {} +#[cfg(feature = "se050")] +impl> MaybeSe for Se050 {} + +#[derive(PartialEq, Debug)] enum Command { Update, Reboot, @@ -35,6 +52,7 @@ enum Command { Locked, Wink, Status, + TestSe050, } impl TryFrom for Command { @@ -51,6 +69,7 @@ impl TryFrom for Command { // Now check the new commands. match command { STATUS => Ok(Command::Status), + TEST_SE050 => Ok(Command::TestSe050), _ => Err(Error::UnsupportedCommand), } } @@ -134,7 +153,7 @@ pub trait Reboot { fn locked() -> bool; } -pub struct App +pub struct App where T: TrussedClient, R: Reboot, @@ -146,6 +165,7 @@ where full_version: &'static str, status: S, boot_interface: PhantomData, + se050: Se050, } impl App @@ -168,9 +188,47 @@ where full_version, status, boot_interface: PhantomData, + se050: (), } } +} +#[cfg(feature = "se050")] +impl App> +where + T: TrussedClient, + R: Reboot, + S: AsRef<[u8]>, + Twi: I2CForT1, + D: DelayUs, +{ + pub fn with_se( + client: T, + uuid: [u8; 16], + version: u32, + full_version: &'static str, + status: S, + se050: Se050, + ) -> Self { + Self { + trussed: client, + uuid, + version, + full_version, + status, + boot_interface: PhantomData, + se050, + } + } +} + +impl App +where + T: TrussedClient, + R: Reboot, + S: AsRef<[u8]>, + Se050: MaybeSe, +{ fn user_present(&mut self) -> bool { let user_present = syscall!(self .trussed @@ -185,6 +243,7 @@ where flag: Option, response: &mut Vec, ) -> Result<(), Error> { + debug_now!("Executing command: {command:?}"); match command { Command::Reboot => R::reboot(), Command::Locked => { @@ -228,16 +287,23 @@ where Command::Status => { response.extend_from_slice(self.status.as_ref()).ok(); } + Command::TestSe050 => { + debug_now!("Running se050 tests"); + if let Err(_err) = self.se050.run_tests(response) { + debug_now!("se050 tests failed: {_err:?}"); + } + } } Ok(()) } } -impl hid::App<'static> for App +impl hid::App<'static> for App where T: TrussedClient, R: Reboot, S: AsRef<[u8]>, + Se: MaybeSe, { fn commands(&self) -> &'static [HidCommand] { &[ @@ -276,11 +342,12 @@ where } } -impl iso7816::App for App +impl iso7816::App for App where T: TrussedClient, R: Reboot, S: AsRef<[u8]>, + Se: MaybeSe, { // Solo management app fn aid(&self) -> iso7816::Aid { @@ -288,11 +355,12 @@ where } } -impl apdu::App<{ command::SIZE }, { response::SIZE }> for App +impl apdu::App<{ command::SIZE }, { response::SIZE }> for App where T: TrussedClient, R: Reboot, S: AsRef<[u8]>, + Se: MaybeSe, { fn select(&mut self, _apdu: &ApduCommand, _reply: &mut response::Data) -> apdu::Result { Ok(()) diff --git a/src/admin/run_tests.rs b/src/admin/run_tests.rs new file mode 100644 index 0000000..7c4ae93 --- /dev/null +++ b/src/admin/run_tests.rs @@ -0,0 +1,1039 @@ +use ctaphid_dispatch::types::Error; + +#[cfg(feature = "se050")] +use embedded_hal::blocking::delay::DelayUs; +use iso7816::Status; +#[cfg(feature = "se050")] +use se050::{ + se050::{ + commands::{ + CreateSession, DeleteAll, DeleteSecureObject, EcdsaSign, EcdsaVerify, GetRandom, + ReadIdList, ReadObject, VerifySessionUserId, WriteBinary, WriteEcKey, WriteUserId, + }, + policies::{ObjectAccessRule, ObjectPolicyFlags, Policy, PolicySet}, + EcCurve, EcDsaSignatureAlgo, ObjectId, P1KeyType, ProcessSessionCmd, Se050Result, + }, + t1::I2CForT1, +}; +use trussed::types::Vec; + +#[cfg(feature = "se050")] +use se050::se050::Se050; + +#[cfg(feature = "se050")] +use hex_literal::hex; + +pub trait RunTests { + fn run_tests(&mut self, _response: &mut Vec) -> Result<(), Error> { + debug_now!("Default run tests"); + Err(Error::InvalidCommand) + } + + fn run_tests_internal( + &mut self, + _response: &mut Vec, + ) -> Result<(), Status> { + Err(Status::NotFound) + } +} + +#[cfg(feature = "se050")] +const BUFFER_LEN: usize = 1024; + +#[cfg(feature = "se050")] +#[derive(Debug)] +#[repr(u8)] +enum Advance { + Enable = 1, + Random1, + Random2, + Random3, + WriteUserId, + CreateSession, + VerifySessionUserId, + DeleteAll, + List, + WriteBinary1, + ReadBinary1, + DeleteBinary1, + WriteBinary2, + ReadBinary2, + DeleteBinary2, + WriteBinary3, + ReadBinary3, + DeleteBinary3, + CreateP256, + ListP256, + GenerateP256, + EcDsaP256, + VerifyP256, + DeleteP256, + CreateP521, + GenerateP521, + EcDsaP521, + VerifyP521, + DeleteP521, + RecreationWriteUserId, + RecreationWriteBinary, + RecreationDeleteAttempt, + RecreationDeleteUserId, + RecreationRecreateUserId, + RecreationCreateSession, + RecreationAuthSession, + RecreationDeleteAttack, + Rsa2048Gen, + Rsa2048Sign, + Rsa2048Verify, + Rsa2048Encrypt, + Rsa2048Decrypt, + Rsa2048Delete, + Rsa3072Gen, + Rsa3072Sign, + Rsa3072Verify, + Rsa3072Encrypt, + Rsa3072Decrypt, + Rsa3072Delete, + Rsa4096Gen, + Rsa4096Sign, + Rsa4096Verify, + Rsa4096Encrypt, + Rsa4096Decrypt, + Rsa4096Delete, + SymmWrite, + SymmEncryptOneShot, + SymmDecryptOneShot, + SymmEncryptCreate, + SymmEncryptInit, + SymmEncryptUpdate1, + SymmEncryptUpdate2, + SymmEncryptFinal, + SymmEncryptDelete, + SymmDecryptCreate, + SymmDecryptInit, + SymmDecryptUpdate1, + SymmDecryptUpdate2, + SymmDecryptFinal, + SymmDecryptDelete, + SymmDelete, + MacWrite, + MacSignOneShot, + MacVerifyOneShot, + MacSignCreate, + MacSignInit, + MacSignUpdate1, + MacSignUpdate2, + MacSignFinal, + MacSignDelete, + MacVerifyCreate, + MacVerifyInit, + MacVerifyUpdate1, + MacVerifyUpdate2, + MacVerifyFinal, + MacVerifyDelete, + MacDelete, +} + +impl RunTests for () {} + +#[cfg(feature = "se050")] +impl> RunTests for Se050 { + fn run_tests(&mut self, response: &mut Vec) -> Result<(), Error> { + debug_now!("Se050 run tests"); + match self.run_tests_internal(response) { + Ok(()) => Ok(()), + Err(err) => { + response.push(0).ok(); + let sw: [u8; 2] = err.into(); + response.extend_from_slice(&sw).ok(); + Ok(()) + } + } + } + fn run_tests_internal( + &mut self, + response: &mut Vec, + ) -> Result<(), Status> { + let atr = self.enable()?; + response + .extend_from_slice(&[ + atr.major, + atr.minor, + atr.patch, + atr.secure_box_major, + atr.secure_box_minor, + ]) + .ok(); + response.push(Advance::Enable as _).ok(); + run_get_random(self, response)?; + run_factory_reset(self, response)?; + run_list(self, response)?; + run_binary(self, response)?; + run_ecc(self, response)?; + run_userid_recreation(self, response)?; + run_rsa2048(self, response)?; + run_rsa3072(self, response)?; + run_rsa4096(self, response)?; + run_symm(self, response)?; + run_mac(self, response)?; + Ok(()) + } +} + +#[cfg(feature = "se050")] +fn run_get_random, const N: usize>( + se050: &mut Se050, + response: &mut Vec, +) -> Result<(), Status> { + let mut buf = [b'a'; BUFFER_LEN]; + let lens = [1, 256, 800]; + let advance = [Advance::Random1, Advance::Random2, Advance::Random3]; + for (len, advance) in lens.into_iter().zip(advance) { + let res = se050.run_command( + &GetRandom { + length: (len as u16).into(), + }, + &mut buf, + )?; + response.push(advance as u8).ok(); + if res.data == &[b'a'; BUFFER_LEN][..len] { + debug!("Failed to get random"); + response.extend_from_slice(&[0, 0, 0]).ok(); + return Ok(()); + } + } + Ok(()) +} + +#[cfg(feature = "se050")] +fn run_factory_reset, const N: usize>( + se050: &mut Se050, + response: &mut Vec, +) -> Result<(), Status> { + let mut buf = [b'a'; BUFFER_LEN]; + let data = &hex!("31323334"); + + se050.run_command( + &WriteUserId { + policy: None, + max_attempts: None, + object_id: ObjectId::FACTORY_RESET, + data, + }, + &mut buf, + )?; + response.push(Advance::WriteUserId as u8).ok(); + let session = se050.run_command( + &CreateSession { + object_id: ObjectId::FACTORY_RESET, + }, + &mut buf, + )?; + response.push(Advance::CreateSession as u8).ok(); + + se050.run_command( + &ProcessSessionCmd { + session_id: session.session_id, + apdu: VerifySessionUserId { user_id: data }, + }, + &mut buf, + )?; + response.push(Advance::VerifySessionUserId as u8).ok(); + + se050.run_command( + &ProcessSessionCmd { + session_id: session.session_id, + apdu: DeleteAll {}, + }, + &mut buf, + )?; + response.push(Advance::DeleteAll as u8).ok(); + Ok(()) +} + +#[cfg(feature = "se050")] +fn run_list, const N: usize>( + se050: &mut Se050, + response: &mut Vec, +) -> Result<(), Status> { + let mut buf = [0; 200]; + se050.run_command( + &ReadIdList { + offset: 0.into(), + filter: se050::se050::SecureObjectFilter::All, + }, + &mut buf, + )?; + response.push(Advance::List as u8).ok(); + Ok(()) +} + +#[cfg(feature = "se050")] +fn run_binary, const N: usize>( + se050: &mut Se050, + response: &mut Vec, +) -> Result<(), Status> { + let mut buf = [b'a'; 400]; + let buf2 = [b'b'; 400]; + let object_id = ObjectId(hex!("01020304")); + let policy = &[Policy { + object_id: ObjectId::INVALID, + access_rule: ObjectAccessRule::from_flags( + ObjectPolicyFlags::ALLOW_DELETE | ObjectPolicyFlags::ALLOW_READ, + ), + }]; + for (((len, advance_write), advance_read), advance_delete) in [1, 255, 300] + .into_iter() + .zip([ + Advance::WriteBinary1, + Advance::WriteBinary2, + Advance::WriteBinary3, + ]) + .zip([ + Advance::ReadBinary1, + Advance::ReadBinary2, + Advance::ReadBinary3, + ]) + .zip([ + Advance::DeleteBinary1, + Advance::DeleteBinary2, + Advance::DeleteBinary3, + ]) + { + se050.run_command( + &WriteBinary { + transient: false, + policy: Some(PolicySet(policy)), + object_id, + offset: None, + file_length: Some(len.into()), + data: Some(&buf2[..len.into()]), + }, + &mut buf, + )?; + response.push(advance_write as u8).ok(); + let res = se050.run_command( + &ReadObject { + object_id, + offset: None, + length: Some(len.into()), + rsa_key_component: None, + }, + &mut buf, + )?; + response.push(advance_read as u8).ok(); + if res.data[..len.into()] != buf2[..len.into()] { + return Err(0x3001.into()); + } + + se050.run_command(&DeleteSecureObject { object_id }, &mut buf)?; + response.push(advance_delete as u8).ok(); + } + Ok(()) +} + +#[cfg(feature = "se050")] +fn run_ecc, const N: usize>( + se050: &mut Se050, + response: &mut Vec, +) -> Result<(), Status> { + use se050::se050::commands::ReadEcCurveList; + + let mut buf = [0; 200]; + let mut buf2 = [0; 200]; + let object_id = ObjectId(hex!("01020304")); + + // *********** P256 *********** // + + se050.create_and_set_curve(EcCurve::NistP256)?; + response.push(Advance::CreateP256 as u8).ok(); + let _res = se050.run_command(&ReadEcCurveList {}, &mut buf)?; + debug_now!("Ec curves list: {:?}", _res); + response.push(Advance::ListP256 as u8).ok(); + se050.run_command( + &WriteEcKey { + transient: false, + is_auth: false, + key_type: Some(P1KeyType::KeyPair), + policy: None, + max_attempts: None, + object_id, + curve: Some(EcCurve::NistP256), + private_key: None, + public_key: None, + }, + &mut buf, + )?; + response.push(Advance::GenerateP256 as u8).ok(); + let res = se050.run_command( + &EcdsaSign { + key_id: object_id, + data: &[52; 32], + algo: EcDsaSignatureAlgo::Sha256, + }, + &mut buf, + )?; + response.push(Advance::EcDsaP256 as u8).ok(); + let res = se050.run_command( + &EcdsaVerify { + key_id: object_id, + data: &[52; 32], + algo: EcDsaSignatureAlgo::Sha256, + signature: res.signature, + }, + &mut buf2, + )?; + if res.result != Se050Result::Success { + return Err(0x3002.into()); + } + response.push(Advance::VerifyP256 as u8).ok(); + se050.run_command(&DeleteSecureObject { object_id }, &mut buf)?; + response.push(Advance::DeleteP256 as u8).ok(); + + // *********** P521 *********** // + + se050.create_and_set_curve(EcCurve::NistP521)?; + response.push(Advance::CreateP521 as u8).ok(); + se050.run_command( + &WriteEcKey { + transient: false, + is_auth: false, + key_type: Some(P1KeyType::KeyPair), + policy: None, + max_attempts: None, + object_id, + curve: Some(EcCurve::NistP521), + private_key: None, + public_key: None, + }, + &mut buf, + )?; + response.push(Advance::GenerateP521 as u8).ok(); + let res = se050.run_command( + &EcdsaSign { + key_id: object_id, + data: &[52; 64], + algo: EcDsaSignatureAlgo::Sha512, + }, + &mut buf, + )?; + response.push(Advance::EcDsaP521 as u8).ok(); + let res = se050.run_command( + &EcdsaVerify { + key_id: object_id, + data: &[52; 64], + algo: EcDsaSignatureAlgo::Sha512, + signature: res.signature, + }, + &mut buf2, + )?; + if res.result != Se050Result::Success { + return Err(0x3003.into()); + } + response.push(Advance::VerifyP521 as u8).ok(); + se050.run_command(&DeleteSecureObject { object_id }, &mut buf)?; + response.push(Advance::DeleteP521 as u8).ok(); + Ok(()) +} + +#[cfg(feature = "se050")] +fn run_userid_recreation, const N: usize>( + se050: &mut Se050, + response: &mut Vec, +) -> Result<(), Status> { + let mut buf = [0; BUFFER_LEN]; + let object_id = ObjectId(hex!("01020304")); + let user_id = ObjectId(hex!("01223344")); + let user_id_good_value = hex!("31323334"); + let user_id_bad_value = hex!("FFFFFFFF"); + let policy_user_id = &[Policy { + object_id: ObjectId::INVALID, + access_rule: ObjectAccessRule::from_flags( + ObjectPolicyFlags::ALLOW_DELETE | ObjectPolicyFlags::ALLOW_WRITE, + ), + }]; + se050.run_command( + &WriteUserId { + policy: Some(PolicySet(policy_user_id)), + max_attempts: None, + object_id: user_id, + data: &user_id_good_value, + }, + &mut buf, + )?; + response.push(Advance::RecreationWriteUserId as u8).ok(); + let policy = &[Policy { + object_id: user_id, + access_rule: ObjectAccessRule::from_flags( + ObjectPolicyFlags::ALLOW_DELETE | ObjectPolicyFlags::ALLOW_READ, + ), + }]; + se050.run_command( + &WriteBinary { + transient: false, + policy: Some(PolicySet(policy)), + object_id, + offset: None, + file_length: Some(2.into()), + data: Some(&[1, 2]), + }, + &mut buf, + )?; + response.push(Advance::RecreationWriteBinary as u8).ok(); + match se050.run_command(&DeleteSecureObject { object_id }, &mut buf) { + Ok(_) => return Err(0x3004.into()), + Err(se050::se050::Error::Status(Status::CommandNotAllowedNoEf)) => {} + Err(_err) => { + debug_now!("Got unexpected error: {_err:?}"); + return Err(0x3007.into()); + } + } + response.push(Advance::RecreationDeleteAttempt as u8).ok(); + se050.run_command(&DeleteSecureObject { object_id: user_id }, &mut buf)?; + response.push(Advance::RecreationDeleteUserId as u8).ok(); + se050.run_command( + &WriteUserId { + policy: None, + max_attempts: None, + object_id: user_id, + data: &user_id_bad_value, + }, + &mut buf, + )?; + response.push(Advance::RecreationRecreateUserId as u8).ok(); + + let session = se050.run_command(&CreateSession { object_id: user_id }, &mut buf)?; + response.push(Advance::RecreationCreateSession as u8).ok(); + + se050.run_command( + &ProcessSessionCmd { + session_id: session.session_id, + apdu: VerifySessionUserId { + user_id: &user_id_bad_value, + }, + }, + &mut buf, + )?; + response.push(Advance::RecreationAuthSession as u8).ok(); + + let attack = se050.run_command( + &ProcessSessionCmd { + session_id: session.session_id, + apdu: DeleteSecureObject { object_id: user_id }, + }, + &mut buf, + ); + + match attack { + Ok(_) => return Err(0x3005.into()), + Err(se050::se050::Error::Status(Status::CommandNotAllowedNoEf)) => {} + Err(_err) => { + debug_now!("Got unexpected error: {_err:?}"); + return Err(0x3006.into()); + } + } + response.push(Advance::RecreationDeleteAttack as u8).ok(); + Ok(()) +} + +#[cfg(feature = "se050")] +fn run_rsa2048, const N: usize>( + se050: &mut Se050, + response: &mut Vec, +) -> Result<(), Status> { + use se050::se050::{ + commands::{GenRsaKey, RsaDecrypt, RsaEncrypt, RsaSign, RsaVerify}, + RsaEncryptionAlgo, RsaSignatureAlgo, + }; + + let mut buf = [0; 1000]; + let mut buf2 = [0; 1000]; + let object_id = ObjectId(hex!("02334455")); + se050.run_command( + &GenRsaKey { + transient: false, + is_auth: false, + policy: None, + max_attempts: None, + object_id, + key_size: Some(2048.into()), + }, + &mut buf, + )?; + response.push(Advance::Rsa2048Gen as u8).ok(); + let res = se050.run_command( + &RsaSign { + key_id: object_id, + data: &[52; 32], + algo: RsaSignatureAlgo::RsaSha256Pkcs1, + }, + &mut buf, + )?; + response.push(Advance::Rsa2048Sign as u8).ok(); + let res = se050.run_command( + &RsaVerify { + key_id: object_id, + data: &[52; 32], + algo: RsaSignatureAlgo::RsaSha256Pkcs1, + signature: res.signature, + }, + &mut buf2, + )?; + response.push(Advance::Rsa2048Verify as u8).ok(); + let res = se050.run_command( + &RsaEncrypt { + key_id: object_id, + plaintext: &[52; 32], + algo: RsaEncryptionAlgo::Pkcs1, + }, + &mut buf2, + )?; + response.push(Advance::Rsa2048Encrypt as u8).ok(); + let res = se050.run_command( + &RsaDecrypt { + key_id: object_id, + algo: RsaEncryptionAlgo::Pkcs1, + ciphertext: res.ciphertext, + }, + &mut buf, + )?; + if res.plaintext != &[52; 32] { + return Err(0x3008.into()); + } + response.push(Advance::Rsa2048Decrypt as u8).ok(); + + se050.run_command(&DeleteSecureObject { object_id }, &mut buf)?; + response.push(Advance::Rsa2048Delete as u8).ok(); + + Ok(()) +} + +#[cfg(feature = "se050")] +fn run_rsa3072, const N: usize>( + se050: &mut Se050, + response: &mut Vec, +) -> Result<(), Status> { + use se050::se050::{ + commands::{GenRsaKey, RsaDecrypt, RsaEncrypt, RsaSign, RsaVerify}, + RsaEncryptionAlgo, RsaSignatureAlgo, + }; + + let mut buf = [0; 1000]; + let mut buf2 = [0; 1000]; + let object_id = ObjectId(hex!("02334455")); + se050.run_command( + &GenRsaKey { + transient: false, + is_auth: false, + policy: None, + max_attempts: None, + object_id, + key_size: Some(3072.into()), + }, + &mut buf, + )?; + response.push(Advance::Rsa3072Gen as u8).ok(); + let res = se050.run_command( + &RsaSign { + key_id: object_id, + data: &[52; 32], + algo: RsaSignatureAlgo::RsaSha256Pkcs1, + }, + &mut buf, + )?; + response.push(Advance::Rsa3072Sign as u8).ok(); + let res = se050.run_command( + &RsaVerify { + key_id: object_id, + data: &[52; 32], + algo: RsaSignatureAlgo::RsaSha256Pkcs1, + signature: res.signature, + }, + &mut buf2, + )?; + response.push(Advance::Rsa3072Verify as u8).ok(); + let res = se050.run_command( + &RsaEncrypt { + key_id: object_id, + plaintext: &[52; 32], + algo: RsaEncryptionAlgo::Pkcs1, + }, + &mut buf2, + )?; + response.push(Advance::Rsa3072Encrypt as u8).ok(); + let res = se050.run_command( + &RsaDecrypt { + key_id: object_id, + algo: RsaEncryptionAlgo::Pkcs1, + ciphertext: res.ciphertext, + }, + &mut buf, + )?; + if res.plaintext != &[52; 32] { + return Err(0x3008.into()); + } + response.push(Advance::Rsa3072Decrypt as u8).ok(); + + se050.run_command(&DeleteSecureObject { object_id }, &mut buf)?; + response.push(Advance::Rsa3072Delete as u8).ok(); + + Ok(()) +} + +#[cfg(feature = "se050")] +fn run_rsa4096, const N: usize>( + se050: &mut Se050, + response: &mut Vec, +) -> Result<(), Status> { + use se050::se050::{ + commands::{GenRsaKey, RsaDecrypt, RsaEncrypt, RsaSign, RsaVerify}, + RsaEncryptionAlgo, RsaSignatureAlgo, + }; + + let mut buf = [0; 1000]; + let mut buf2 = [0; 1000]; + let object_id = ObjectId(hex!("02334455")); + se050.run_command( + &GenRsaKey { + transient: false, + is_auth: false, + policy: None, + max_attempts: None, + object_id, + key_size: Some(4096.into()), + }, + &mut buf, + )?; + response.push(Advance::Rsa4096Gen as u8).ok(); + let res = se050.run_command( + &RsaSign { + key_id: object_id, + data: &[52; 32], + algo: RsaSignatureAlgo::RsaSha256Pkcs1, + }, + &mut buf, + )?; + response.push(Advance::Rsa4096Sign as u8).ok(); + let res = se050.run_command( + &RsaVerify { + key_id: object_id, + data: &[52; 32], + algo: RsaSignatureAlgo::RsaSha256Pkcs1, + signature: res.signature, + }, + &mut buf2, + )?; + response.push(Advance::Rsa4096Verify as u8).ok(); + let res = se050.run_command( + &RsaEncrypt { + key_id: object_id, + plaintext: &[52; 32], + algo: RsaEncryptionAlgo::Pkcs1, + }, + &mut buf2, + )?; + response.push(Advance::Rsa4096Encrypt as u8).ok(); + let res = se050.run_command( + &RsaDecrypt { + key_id: object_id, + algo: RsaEncryptionAlgo::Pkcs1, + ciphertext: res.ciphertext, + }, + &mut buf, + )?; + if res.plaintext != &[52; 32] { + return Err(0x3008.into()); + } + response.push(Advance::Rsa4096Decrypt as u8).ok(); + + se050.run_command(&DeleteSecureObject { object_id }, &mut buf)?; + response.push(Advance::Rsa4096Delete as u8).ok(); + + Ok(()) +} + +#[cfg(feature = "se050")] +fn run_symm, const N: usize>( + se050: &mut Se050, + response: &mut Vec, +) -> Result<(), Status> { + use se050::se050::{ + commands::{ + CipherDecryptInit, CipherEncryptInit, CipherFinal, CipherOneShotDecrypt, + CipherOneShotEncrypt, CipherUpdate, CreateCipherObject, DeleteCryptoObj, WriteSymmKey, + }, + CipherMode, CryptoObjectId, SymmKeyType, + }; + + let mut buf = [0; 1000]; + let mut buf2 = [0; 1000]; + let plaintext_data = [2; 32 * 15]; + let key_id = ObjectId(hex!("03445566")); + let cipher_id = CryptoObjectId(hex!("0123")); + let key = [0x42; 32]; + let iv = [0xFF; 16]; + se050.run_command( + &WriteSymmKey { + transient: true, + is_auth: false, + key_type: SymmKeyType::Aes, + policy: None, + max_attempts: None, + object_id: key_id, + kek_id: None, + value: &key, + }, + &mut buf, + )?; + response.push(Advance::SymmWrite as u8).ok(); + let ciphertext1 = se050.run_command( + &CipherOneShotEncrypt { + key_id, + mode: CipherMode::AesCtr, + plaintext: &plaintext_data, + initialization_vector: Some(&iv), + }, + &mut buf, + )?; + response.push(Advance::SymmEncryptOneShot as u8).ok(); + let plaintext1 = se050.run_command( + &CipherOneShotDecrypt { + key_id, + mode: CipherMode::AesCtr, + ciphertext: &ciphertext1.ciphertext, + initialization_vector: Some(&iv), + }, + &mut buf2, + )?; + response.push(Advance::SymmDecryptOneShot as u8).ok(); + assert_eq!(plaintext1.plaintext, plaintext_data); + se050.run_command( + &CreateCipherObject { + id: cipher_id, + subtype: CipherMode::AesCtr, + }, + &mut buf2, + )?; + response.push(Advance::SymmEncryptCreate as u8).ok(); + se050.run_command( + &CipherEncryptInit { + key_id, + initialization_vector: Some(&iv), + cipher_id, + }, + &mut buf2, + )?; + response.push(Advance::SymmEncryptInit as u8).ok(); + let ciphertext2 = se050.run_command( + &CipherUpdate { + cipher_id, + data: &plaintext_data[0..32 * 10], + }, + &mut buf2, + )?; + response.push(Advance::SymmEncryptUpdate1 as u8).ok(); + let ciphertext3 = se050.run_command( + &CipherUpdate { + cipher_id, + data: &plaintext_data[32 * 10..][..32 * 5], + }, + &mut buf2, + )?; + response.push(Advance::SymmEncryptUpdate2 as u8).ok(); + let ciphertext4 = se050.run_command( + &CipherFinal { + cipher_id, + data: &plaintext_data[32 * 15..], + }, + &mut buf2, + )?; + response.push(Advance::SymmEncryptFinal as u8).ok(); + se050.run_command(&DeleteCryptoObj { id: cipher_id }, &mut buf2)?; + response.push(Advance::SymmEncryptDelete as u8).ok(); + se050.run_command( + &CreateCipherObject { + id: cipher_id, + subtype: CipherMode::AesCtr, + }, + &mut buf2, + )?; + response.push(Advance::SymmDecryptCreate as u8).ok(); + se050.run_command( + &CipherDecryptInit { + key_id, + initialization_vector: Some(&iv), + cipher_id, + }, + &mut buf2, + )?; + response.push(Advance::SymmDecryptInit as u8).ok(); + let ciphertext2 = se050.run_command( + &CipherUpdate { + cipher_id, + data: &ciphertext1.ciphertext[0..32 * 10], + }, + &mut buf2, + )?; + response.push(Advance::SymmDecryptUpdate1 as u8).ok(); + let ciphertext3 = se050.run_command( + &CipherUpdate { + cipher_id, + data: &ciphertext1.ciphertext[32 * 10..][..32 * 5], + }, + &mut buf2, + )?; + response.push(Advance::SymmDecryptUpdate2 as u8).ok(); + let ciphertext4 = se050.run_command( + &CipherFinal { + cipher_id, + data: &ciphertext1.ciphertext[32 * 15..], + }, + &mut buf2, + )?; + response.push(Advance::SymmDecryptFinal as u8).ok(); + se050.run_command(&DeleteCryptoObj { id: cipher_id }, &mut buf2)?; + response.push(Advance::SymmDecryptDelete as u8).ok(); + se050.run_command(&DeleteSecureObject { object_id: key_id }, &mut buf2)?; + response.push(Advance::SymmDelete as u8).ok(); + Ok(()) +} + +#[cfg(feature = "se050")] +fn run_mac, const N: usize>( + se050: &mut Se050, + response: &mut Vec, +) -> Result<(), Status> { + use se050::se050::{ + commands::{ + CreateSignatureObject, DeleteCryptoObj, MacGenerateFinal, MacGenerateInit, + MacOneShotGenerate, MacOneShotValidate, MacUpdate, MacValidateFinal, MacValidateInit, + WriteSymmKey, + }, + CryptoObjectId, MacAlgo, SymmKeyType, + }; + + let mut buf = [0; 1000]; + let mut buf2 = [0; 1000]; + let plaintext_data = [2; 32 * 15]; + let key_id = ObjectId(hex!("03445566")); + let mac_id = CryptoObjectId(hex!("0123")); + let key = [0x42; 32]; + se050.run_command( + &WriteSymmKey { + transient: false, + is_auth: false, + key_type: SymmKeyType::Hmac, + policy: None, + max_attempts: None, + object_id: key_id, + kek_id: None, + value: &key, + }, + &mut buf, + )?; + response.push(Advance::MacWrite as u8).ok(); + let tag1 = se050.run_command( + &MacOneShotGenerate { + key_id, + data: &plaintext_data, + algo: MacAlgo::HmacSha256, + }, + &mut buf, + )?; + response.push(Advance::MacSignOneShot as u8).ok(); + let res = se050.run_command( + &MacOneShotValidate { + key_id, + algo: MacAlgo::HmacSha256, + data: &plaintext_data, + tag: tag1.tag, + }, + &mut buf2, + )?; + response.push(Advance::MacVerifyOneShot as u8).ok(); + if res.result != Se050Result::Success { + return Err(0x6008.into()); + } + se050.run_command( + &CreateSignatureObject { + id: mac_id, + subtype: MacAlgo::HmacSha256, + }, + &mut buf2, + )?; + response.push(Advance::MacSignCreate as u8).ok(); + se050.run_command(&MacGenerateInit { key_id, mac_id }, &mut buf2)?; + response.push(Advance::MacSignInit as u8).ok(); + se050.run_command( + &MacUpdate { + mac_id, + data: &plaintext_data[0..32 * 10], + }, + &mut buf2, + )?; + response.push(Advance::MacSignUpdate1 as u8).ok(); + se050.run_command( + &MacUpdate { + mac_id, + data: &plaintext_data[32 * 10..][..32 * 5], + }, + &mut buf2, + )?; + response.push(Advance::MacSignUpdate2 as u8).ok(); + let tag2 = se050.run_command( + &MacGenerateFinal { + mac_id, + data: &plaintext_data[32 * 15..], + }, + &mut buf2, + )?; + response.push(Advance::MacSignFinal as u8).ok(); + assert_eq!(tag2.tag, tag1.tag); + se050.run_command(&DeleteCryptoObj { id: mac_id }, &mut buf)?; + response.push(Advance::MacSignDelete as u8).ok(); + + se050.run_command( + &CreateSignatureObject { + id: mac_id, + subtype: MacAlgo::HmacSha256, + }, + &mut buf, + )?; + response.push(Advance::MacVerifyCreate as u8).ok(); + se050.run_command(&MacValidateInit { key_id, mac_id }, &mut buf)?; + response.push(Advance::MacVerifyInit as u8).ok(); + se050.run_command( + &MacUpdate { + mac_id, + data: &plaintext_data[0..32 * 10], + }, + &mut buf, + )?; + response.push(Advance::MacVerifyUpdate1 as u8).ok(); + se050.run_command( + &MacUpdate { + mac_id, + data: &plaintext_data[32 * 10..][..32 * 5], + }, + &mut buf, + )?; + response.push(Advance::MacVerifyUpdate2 as u8).ok(); + let res2 = se050.run_command( + &MacValidateFinal { + mac_id, + data: &plaintext_data[32 * 15..], + tag: tag2.tag, + }, + &mut buf, + )?; + if res2.result != Se050Result::Success { + return Err(0x6009.into()); + } + response.push(Advance::MacVerifyFinal as u8).ok(); + + se050.run_command(&DeleteCryptoObj { id: mac_id }, &mut buf)?; + response.push(Advance::MacVerifyDelete as u8).ok(); + + se050.run_command(&DeleteSecureObject { object_id: key_id }, &mut buf2)?; + response.push(Advance::MacDelete as u8).ok(); + Ok(()) +} From c784b0c4758f1e522f7f51933c766495e9b2ae2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= Date: Fri, 28 Jul 2023 16:43:16 +0200 Subject: [PATCH 2/7] Add SE050 free memory reporting --- src/admin/run_tests.rs | 61 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 55 insertions(+), 6 deletions(-) diff --git a/src/admin/run_tests.rs b/src/admin/run_tests.rs index 7c4ae93..8fbace0 100644 --- a/src/admin/run_tests.rs +++ b/src/admin/run_tests.rs @@ -163,6 +163,7 @@ impl> RunTests for Se050 { atr.secure_box_minor, ]) .ok(); + run_free_mem(self, response)?; response.push(Advance::Enable as _).ok(); run_get_random(self, response)?; run_factory_reset(self, response)?; @@ -178,6 +179,43 @@ impl> RunTests for Se050 { Ok(()) } } +#[cfg(feature = "se050")] +fn run_free_mem, const N: usize>( + se050: &mut Se050, + response: &mut Vec, +) -> Result<(), Status> { + use se050::se050::{commands::GetFreeMemory, Memory}; + + let mut buf = [b'a'; BUFFER_LEN]; + let mem = se050.run_command( + &GetFreeMemory { + memory: Memory::Persistent, + }, + &mut buf, + )?; + response + .extend_from_slice(&mem.available.0.to_be_bytes()) + .ok(); + let mem = se050.run_command( + &GetFreeMemory { + memory: Memory::TransientReset, + }, + &mut buf, + )?; + response + .extend_from_slice(&mem.available.0.to_be_bytes()) + .ok(); + let mem = se050.run_command( + &GetFreeMemory { + memory: Memory::TransientDeselect, + }, + &mut buf, + )?; + response + .extend_from_slice(&mem.available.0.to_be_bytes()) + .ok(); + Ok(()) +} #[cfg(feature = "se050")] fn run_get_random, const N: usize>( @@ -447,9 +485,7 @@ fn run_userid_recreation, const N: usize>( let user_id_bad_value = hex!("FFFFFFFF"); let policy_user_id = &[Policy { object_id: ObjectId::INVALID, - access_rule: ObjectAccessRule::from_flags( - ObjectPolicyFlags::ALLOW_DELETE | ObjectPolicyFlags::ALLOW_WRITE, - ), + access_rule: ObjectAccessRule::from_flags(ObjectPolicyFlags::ALLOW_DELETE), }]; se050.run_command( &WriteUserId { @@ -479,7 +515,15 @@ fn run_userid_recreation, const N: usize>( &mut buf, )?; response.push(Advance::RecreationWriteBinary as u8).ok(); - match se050.run_command(&DeleteSecureObject { object_id }, &mut buf) { + match se050.run_command( + &ReadObject { + object_id, + offset: Some(0.into()), + length: Some(2.into()), + rsa_key_component: None, + }, + &mut buf, + ) { Ok(_) => return Err(0x3004.into()), Err(se050::se050::Error::Status(Status::CommandNotAllowedNoEf)) => {} Err(_err) => { @@ -518,13 +562,18 @@ fn run_userid_recreation, const N: usize>( let attack = se050.run_command( &ProcessSessionCmd { session_id: session.session_id, - apdu: DeleteSecureObject { object_id: user_id }, + apdu: ReadObject { + object_id, + offset: Some(0.into()), + length: Some(2.into()), + rsa_key_component: None, + }, }, &mut buf, ); match attack { - Ok(_) => return Err(0x3005.into()), + Ok(_) => {} Err(se050::se050::Error::Status(Status::CommandNotAllowedNoEf)) => {} Err(_err) => { debug_now!("Got unexpected error: {_err:?}"); From a44adb0a3390af2a76784ec06a094854a42b9e93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= Date: Fri, 11 Aug 2023 17:08:26 +0200 Subject: [PATCH 3/7] Add PBKDF2 tests --- Cargo.toml | 6 +- src/admin/run_tests.rs | 219 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 223 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index e71f0dc..42b502d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,9 +19,11 @@ trussed = "0.1" se050 = { version = "0.0.1", optional = true } embedded-hal = { version = "0.2.7", optional = true } hex-literal = "0.4.1" +rand_chacha = { version = "0.3.1", optional = true, default-features = false } [features] -se050 = ["dep:se050", "embedded-hal"] +default = ["se050"] +se050 = ["dep:se050", "embedded-hal", "rand_chacha"] log-all = [] log-none = [] @@ -34,4 +36,4 @@ log-error = [] ctaphid-dispatch = { git = "https://github.com/trussed-dev/ctaphid-dispatch.git", rev = "57cb3317878a8593847595319aa03ef17c29ec5b" } trussed = { git = "https://github.com/trussed-dev/trussed.git", rev = "51e68500d7601d04f884f5e95567d14b9018a6cb" } iso7816 = { git = "https://github.com/sosthene-nitrokey/iso7816.git", rev = "160ca3bbd8e21ec4e4ee1e0748e1eaa53a45c97f"} -se050 = { git = "https://github.com/sosthene-nitrokey/se050-generation.git", rev = "b645ea9de6c53c18a2173ec8d4d1307580c405c3"} +se050 = { git = "https://github.com/sosthene-nitrokey/se050-generation.git", rev = "b4dc057ed7b3e1dda88a8c1314f77048df961b10"} diff --git a/src/admin/run_tests.rs b/src/admin/run_tests.rs index 8fbace0..e7f6891 100644 --- a/src/admin/run_tests.rs +++ b/src/admin/run_tests.rs @@ -131,6 +131,22 @@ enum Advance { MacVerifyFinal, MacVerifyDelete, MacDelete, + AesSessionCreateKey, + AesSessionCreateBinary, + AesSessionCreateSession, + AesSessionAuthenticate, + AesSessionReadBinary, + AesSessionUpdateKey, + AesSessionCloseSession, + AesSessionRecreateSession, + AesSessionReAuthenticate, + AesSessionReadBinary2, + AesSessionDeleteBinary, + AesSessionDeleteKey, + Pbkdf2WritePin, + Pbkdf2Calculate, + Pbkdf2Compare, + Pbkdf2DeletePin, } impl RunTests for () {} @@ -176,6 +192,8 @@ impl> RunTests for Se050 { run_rsa4096(self, response)?; run_symm(self, response)?; run_mac(self, response)?; + run_aes_session(self, response)?; + run_pbkdf(self, response)?; Ok(()) } } @@ -1086,3 +1104,204 @@ fn run_mac, const N: usize>( response.push(Advance::MacDelete as u8).ok(); Ok(()) } + +#[cfg(feature = "se050")] +fn run_aes_session, const N: usize>( + se050: &mut Se050, + response: &mut Vec, +) -> Result<(), Status> { + use rand_chacha::rand_core::SeedableRng; + use se050::se050::{ + commands::{CloseSession, WriteSymmKey}, + SymmKeyType, + }; + + let mut buf = [0; 1024]; + let key = [0x42; 16]; + let key2 = [0x43; 16]; + let key_id = ObjectId(hex!("03445566")); + let bin_id = ObjectId(hex!("03445567")); + let bin_data = hex!("CAFECAFE"); + let key_policy = &[ + Policy { + object_id: key_id, + access_rule: ObjectAccessRule::from_flags(ObjectPolicyFlags::ALLOW_WRITE), + }, + Policy { + object_id: ObjectId::INVALID, + access_rule: ObjectAccessRule::from_flags(ObjectPolicyFlags::ALLOW_DELETE), + }, + ]; + let bin_policy = &[ + Policy { + object_id: key_id, + access_rule: ObjectAccessRule::from_flags(ObjectPolicyFlags::ALLOW_READ), + }, + Policy { + object_id: ObjectId::INVALID, + access_rule: ObjectAccessRule::from_flags(ObjectPolicyFlags::ALLOW_DELETE), + }, + ]; + se050.run_command( + &WriteSymmKey { + transient: false, + is_auth: true, + key_type: SymmKeyType::Aes, + policy: Some(PolicySet(key_policy)), + max_attempts: None, + object_id: key_id, + kek_id: None, + value: &key, + }, + &mut buf, + )?; + response.push(Advance::AesSessionCreateKey as _).ok(); + se050.run_command( + &WriteBinary { + transient: false, + policy: Some(PolicySet(bin_policy)), + object_id: bin_id, + offset: None, + file_length: Some((bin_data.len() as u16).into()), + data: Some(&bin_data), + }, + &mut buf, + )?; + response.push(Advance::AesSessionCreateBinary as _).ok(); + + let session = se050.run_command(&CreateSession { object_id: key_id }, &mut buf)?; + let session_id = session.session_id; + response.push(Advance::AesSessionCreateSession as u8).ok(); + debug_now!("Created session"); + + let mut rng = rand_chacha::ChaCha8Rng::from_seed([0xCA; 32]); + se050.authenticate_aes128_session(session_id, &key, &mut rng)?; + response.push(Advance::AesSessionAuthenticate as u8).ok(); + + let data = se050.run_command( + &ProcessSessionCmd { + session_id, + apdu: ReadObject { + object_id: bin_id, + offset: None, + length: Some((bin_data.len() as u16).into()), + rsa_key_component: None, + }, + }, + &mut buf, + )?; + assert_eq!(data.data, &bin_data); + response.push(Advance::AesSessionReadBinary as _).ok(); + + se050.run_command( + &ProcessSessionCmd { + session_id, + apdu: WriteSymmKey { + transient: false, + is_auth: true, + key_type: SymmKeyType::Aes, + policy: None, + max_attempts: None, + object_id: key_id, + kek_id: None, + value: &key2, + }, + }, + &mut buf, + )?; + response.push(Advance::AesSessionUpdateKey as _).ok(); + + se050.run_command( + &ProcessSessionCmd { + session_id, + apdu: CloseSession {}, + }, + &mut buf, + )?; + response.push(Advance::AesSessionCloseSession as _).ok(); + + let session = se050.run_command(&CreateSession { object_id: key_id }, &mut buf)?; + let session_id = session.session_id; + response.push(Advance::AesSessionRecreateSession as u8).ok(); + debug_now!("Created session"); + + let mut rng = rand_chacha::ChaCha8Rng::from_seed([0xCA; 32]); + se050.authenticate_aes128_session(session_id, &key2, &mut rng)?; + response.push(Advance::AesSessionReAuthenticate as u8).ok(); + + let data = se050.run_command( + &ProcessSessionCmd { + session_id, + apdu: ReadObject { + object_id: bin_id, + offset: None, + length: Some((bin_data.len() as u16).into()), + rsa_key_component: None, + }, + }, + &mut buf, + )?; + assert_eq!(data.data, &bin_data); + response.push(Advance::AesSessionReadBinary2 as _).ok(); + + se050.run_command(&DeleteSecureObject { object_id: bin_id }, &mut buf)?; + response.push(Advance::AesSessionDeleteBinary as _).ok(); + se050.run_command(&DeleteSecureObject { object_id: key_id }, &mut buf)?; + response.push(Advance::AesSessionDeleteKey as _).ok(); + + Ok(()) +} + +#[cfg(feature = "se050")] +fn run_pbkdf, const N: usize>( + se050: &mut Se050, + response: &mut Vec, +) -> Result<(), Status> { + use se050::se050::{ + commands::{Pbkdf2, WriteSymmKey}, + SymmKeyType, + }; + + let mut buf = [0; 1024]; + let pin = b"123456"; + let salt = [0x42; 16]; + let pin_id = ObjectId(hex!("03445566")); + + se050.run_command( + &WriteSymmKey { + transient: true, + is_auth: false, + key_type: SymmKeyType::Hmac, + policy: None, + max_attempts: None, + object_id: pin_id, + kek_id: None, + value: pin, + }, + &mut buf, + )?; + + response.push(Advance::Pbkdf2WritePin as u8).ok(); + + let res = se050.run_command( + &Pbkdf2 { + password: pin_id, + salt: Some(&salt), + iterations: 32.into(), + requested_len: 16.into(), + }, + &mut buf, + )?; + response.push(Advance::Pbkdf2Calculate as u8).ok(); + + if res.data != hex!("685126241d909137ecd3385eaea2725f") { + debug_now!("Got HASH: {:02x?}", res.data); + return Err(Status::CorruptedData); + } + response.push(Advance::Pbkdf2Compare as u8).ok(); + + se050.run_command(&DeleteSecureObject { object_id: pin_id }, &mut buf)?; + response.push(Advance::Pbkdf2DeletePin as u8).ok(); + + Ok(()) +} From 8ab34bf89cdcfcc25f4d2b463de225de28eafc8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= Date: Wed, 16 Aug 2023 10:19:27 +0200 Subject: [PATCH 4/7] Add import-export tests --- Cargo.toml | 2 +- src/admin/run_tests.rs | 139 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 140 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 42b502d..11dbdf4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -36,4 +36,4 @@ log-error = [] ctaphid-dispatch = { git = "https://github.com/trussed-dev/ctaphid-dispatch.git", rev = "57cb3317878a8593847595319aa03ef17c29ec5b" } trussed = { git = "https://github.com/trussed-dev/trussed.git", rev = "51e68500d7601d04f884f5e95567d14b9018a6cb" } iso7816 = { git = "https://github.com/sosthene-nitrokey/iso7816.git", rev = "160ca3bbd8e21ec4e4ee1e0748e1eaa53a45c97f"} -se050 = { git = "https://github.com/sosthene-nitrokey/se050-generation.git", rev = "b4dc057ed7b3e1dda88a8c1314f77048df961b10"} +se050 = { git = "https://github.com/sosthene-nitrokey/se050-generation.git", rev = "b1c9479698ae8afe36d6158a91f988d212d8aaa0"} diff --git a/src/admin/run_tests.rs b/src/admin/run_tests.rs index e7f6891..f4245ba 100644 --- a/src/admin/run_tests.rs +++ b/src/admin/run_tests.rs @@ -147,6 +147,15 @@ enum Advance { Pbkdf2Calculate, Pbkdf2Compare, Pbkdf2DeletePin, + ImportWrite, + ImportCipher, + ImportExport, + ImportDelete, + ImportDeletionWorked, + ImportImport, + ImportCipher2, + ImportComp, + ImportDeleteFinal, } impl RunTests for () {} @@ -194,6 +203,7 @@ impl> RunTests for Se050 { run_mac(self, response)?; run_aes_session(self, response)?; run_pbkdf(self, response)?; + run_export_import(self, response)?; Ok(()) } } @@ -1305,3 +1315,132 @@ fn run_pbkdf, const N: usize>( Ok(()) } + +#[cfg(feature = "se050")] +fn run_export_import, const N: usize>( + se050: &mut Se050, + response: &mut Vec, +) -> Result<(), Status> { + use se050::se050::{ + commands::{CipherOneShotEncrypt, ExportObject, ImportObject, WriteSymmKey}, + CipherMode, RsaKeyComponent, SymmKeyType, + }; + + let mut buf = [0; 128]; + let mut buf2 = [0; 1000]; + let mut buf3 = [0; 1000]; + let plaintext_data = [2; 32]; + let key_id = ObjectId(hex!("03445566")); + let key = [0x42; 32]; + let iv = [0xFF; 16]; + let policy = &[ + Policy { + object_id: ObjectId::INVALID, + access_rule: ObjectAccessRule::from_flags( + ObjectPolicyFlags::ALLOW_WRITE + | ObjectPolicyFlags::ALLOW_ENC + | ObjectPolicyFlags::ALLOW_DELETE + | ObjectPolicyFlags::ALLOW_IMPORT_EXPORT, + ), + }, + Policy { + object_id: ObjectId::INVALID, + access_rule: ObjectAccessRule::from_flags(ObjectPolicyFlags::ALLOW_DELETE), + }, + ]; + se050.run_command( + &WriteSymmKey { + transient: true, + is_auth: false, + key_type: SymmKeyType::Aes, + policy: Some(PolicySet(policy)), + max_attempts: None, + object_id: key_id, + kek_id: None, + value: &key, + }, + &mut buf, + )?; + response.push(Advance::ImportWrite as u8).ok(); + let ciphertext1 = se050.run_command( + &CipherOneShotEncrypt { + key_id, + mode: CipherMode::AesCtr, + plaintext: &plaintext_data, + initialization_vector: Some(&iv), + }, + &mut buf, + )?; + response.push(Advance::ImportCipher as u8).ok(); + + debug_now!("Exporting"); + let exported = se050 + .run_command( + &ExportObject { + object_id: key_id, + rsa_key_component: RsaKeyComponent::Na, + }, + &mut buf2, + ) + .map_err(|_err| { + debug_now!("Got err: {:?}", _err); + _err + })?; + response.push(Advance::ImportExport as u8).ok(); + + se050.enable()?; + response.push(Advance::ImportDelete as u8).ok(); + + let res = se050.run_command( + &CipherOneShotEncrypt { + key_id, + mode: CipherMode::AesCtr, + plaintext: &plaintext_data, + initialization_vector: Some(&iv), + }, + &mut buf3, + ); + if !matches!( + res, + Err(se050::se050::Error::Status( + Status::ConditionsOfUseNotSatisfied, + )) + ) { + return Err((0x3000 + line!() as u16).into()); + } + response.push(Advance::ImportDeletionWorked as u8).ok(); + + debug_now!("Importing"); + se050.run_command( + &ImportObject { + transient: true, + object_id: key_id, + rsa_key_component: None, + serialized_object: exported.data, + }, + &mut buf3, + )?; + response.push(Advance::ImportImport as u8).ok(); + + debug_now!("Encrypting"); + let ciphertext2 = se050.run_command( + &CipherOneShotEncrypt { + key_id, + mode: CipherMode::AesCtr, + plaintext: &plaintext_data, + initialization_vector: Some(&iv), + }, + &mut buf3, + )?; + response.push(Advance::ImportCipher2 as u8).ok(); + + debug_now!("Comparing"); + if ciphertext1.ciphertext != ciphertext2.ciphertext { + return Err((0x3000 + line!() as u16).into()); + } + response.push(Advance::ImportComp as u8).ok(); + + se050.run_command(&DeleteSecureObject { object_id: key_id }, &mut buf3)?; + response.push(Advance::ImportDeleteFinal as u8).ok(); + Ok(()) +} From 2ddb1ad5f74a973779a0c6535c9bb58979f0da1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= Date: Wed, 16 Aug 2023 16:22:16 +0200 Subject: [PATCH 5/7] Use renamed se05x crate --- Cargo.toml | 6 +- src/admin.rs | 24 ++++---- src/admin/run_tests.rs | 123 +++++++++++++++++++++++++---------------- 3 files changed, 90 insertions(+), 63 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 11dbdf4..693c7c7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,14 +16,14 @@ delog = "0.1" iso7816 = "0.1" trussed = "0.1" -se050 = { version = "0.0.1", optional = true } +se05x = { version = "0.0.1", optional = true } embedded-hal = { version = "0.2.7", optional = true } hex-literal = "0.4.1" rand_chacha = { version = "0.3.1", optional = true, default-features = false } [features] default = ["se050"] -se050 = ["dep:se050", "embedded-hal", "rand_chacha"] +se050 = ["dep:se05x", "embedded-hal", "rand_chacha"] log-all = [] log-none = [] @@ -36,4 +36,4 @@ log-error = [] ctaphid-dispatch = { git = "https://github.com/trussed-dev/ctaphid-dispatch.git", rev = "57cb3317878a8593847595319aa03ef17c29ec5b" } trussed = { git = "https://github.com/trussed-dev/trussed.git", rev = "51e68500d7601d04f884f5e95567d14b9018a6cb" } iso7816 = { git = "https://github.com/sosthene-nitrokey/iso7816.git", rev = "160ca3bbd8e21ec4e4ee1e0748e1eaa53a45c97f"} -se050 = { git = "https://github.com/sosthene-nitrokey/se050-generation.git", rev = "b1c9479698ae8afe36d6158a91f988d212d8aaa0"} +se05x = { git = "https://github.com/Nitrokey/se05x.git", rev = "db1ddea25cc382355b4292352652da656abc3005"} diff --git a/src/admin.rs b/src/admin.rs index d46bb52..a6d819a 100644 --- a/src/admin.rs +++ b/src/admin.rs @@ -6,7 +6,7 @@ use ctaphid_dispatch::command::VendorCommand; #[cfg(feature = "se050")] use embedded_hal::blocking::delay::DelayUs; #[cfg(feature = "se050")] -use se050::{se050::Se050, t1::I2CForT1}; +use se05x::{se05x::Se05X, t1::I2CForT1}; use trussed::{interrupt::InterruptFlag, syscall, types::Vec, Client as TrussedClient}; pub const USER_PRESENCE_TIMEOUT_SECS: u32 = 15; @@ -35,12 +35,12 @@ use run_tests::*; /// Trait representing the possible ownership of the SE050 by the admin app. /// -/// Implemented by `()` and the `Se050` stract +/// Implemented by `()` and the `Se05X` stract pub trait MaybeSe: RunTests {} impl MaybeSe for () {} #[cfg(feature = "se050")] -impl> MaybeSe for Se050 {} +impl> MaybeSe for Se05X {} #[derive(PartialEq, Debug)] enum Command { @@ -52,7 +52,7 @@ enum Command { Locked, Wink, Status, - TestSe050, + TestSe05X, } impl TryFrom for Command { @@ -69,7 +69,7 @@ impl TryFrom for Command { // Now check the new commands. match command { STATUS => Ok(Command::Status), - TEST_SE050 => Ok(Command::TestSe050), + TEST_SE050 => Ok(Command::TestSe05X), _ => Err(Error::UnsupportedCommand), } } @@ -153,7 +153,7 @@ pub trait Reboot { fn locked() -> bool; } -pub struct App +pub struct App where T: TrussedClient, R: Reboot, @@ -165,7 +165,7 @@ where full_version: &'static str, status: S, boot_interface: PhantomData, - se050: Se050, + se050: Se05X, } impl App @@ -194,7 +194,7 @@ where } #[cfg(feature = "se050")] -impl App> +impl App> where T: TrussedClient, R: Reboot, @@ -208,7 +208,7 @@ where version: u32, full_version: &'static str, status: S, - se050: Se050, + se050: Se05X, ) -> Self { Self { trussed: client, @@ -222,12 +222,12 @@ where } } -impl App +impl App where T: TrussedClient, R: Reboot, S: AsRef<[u8]>, - Se050: MaybeSe, + Se05X: MaybeSe, { fn user_present(&mut self) -> bool { let user_present = syscall!(self @@ -287,7 +287,7 @@ where Command::Status => { response.extend_from_slice(self.status.as_ref()).ok(); } - Command::TestSe050 => { + Command::TestSe05X => { debug_now!("Running se050 tests"); if let Err(_err) = self.se050.run_tests(response) { debug_now!("se050 tests failed: {_err:?}"); diff --git a/src/admin/run_tests.rs b/src/admin/run_tests.rs index f4245ba..9c007e1 100644 --- a/src/admin/run_tests.rs +++ b/src/admin/run_tests.rs @@ -4,21 +4,21 @@ use ctaphid_dispatch::types::Error; use embedded_hal::blocking::delay::DelayUs; use iso7816::Status; #[cfg(feature = "se050")] -use se050::{ - se050::{ +use se05x::{ + se05x::{ commands::{ CreateSession, DeleteAll, DeleteSecureObject, EcdsaSign, EcdsaVerify, GetRandom, ReadIdList, ReadObject, VerifySessionUserId, WriteBinary, WriteEcKey, WriteUserId, }, policies::{ObjectAccessRule, ObjectPolicyFlags, Policy, PolicySet}, - EcCurve, EcDsaSignatureAlgo, ObjectId, P1KeyType, ProcessSessionCmd, Se050Result, + EcCurve, EcDsaSignatureAlgo, ObjectId, P1KeyType, ProcessSessionCmd, Se05XResult, }, t1::I2CForT1, }; use trussed::types::Vec; #[cfg(feature = "se050")] -use se050::se050::Se050; +use se05x::se05x::Se05X; #[cfg(feature = "se050")] use hex_literal::hex; @@ -161,9 +161,9 @@ enum Advance { impl RunTests for () {} #[cfg(feature = "se050")] -impl> RunTests for Se050 { +impl> RunTests for Se05X { fn run_tests(&mut self, response: &mut Vec) -> Result<(), Error> { - debug_now!("Se050 run tests"); + debug_now!("Se05X run tests"); match self.run_tests_internal(response) { Ok(()) => Ok(()), Err(err) => { @@ -209,10 +209,10 @@ impl> RunTests for Se050 { } #[cfg(feature = "se050")] fn run_free_mem, const N: usize>( - se050: &mut Se050, + se050: &mut Se05X, response: &mut Vec, ) -> Result<(), Status> { - use se050::se050::{commands::GetFreeMemory, Memory}; + use se05x::se05x::{commands::GetFreeMemory, Memory}; let mut buf = [b'a'; BUFFER_LEN]; let mem = se050.run_command( @@ -247,7 +247,7 @@ fn run_free_mem, const N: usize>( #[cfg(feature = "se050")] fn run_get_random, const N: usize>( - se050: &mut Se050, + se050: &mut Se05X, response: &mut Vec, ) -> Result<(), Status> { let mut buf = [b'a'; BUFFER_LEN]; @@ -272,7 +272,7 @@ fn run_get_random, const N: usize>( #[cfg(feature = "se050")] fn run_factory_reset, const N: usize>( - se050: &mut Se050, + se050: &mut Se05X, response: &mut Vec, ) -> Result<(), Status> { let mut buf = [b'a'; BUFFER_LEN]; @@ -318,14 +318,14 @@ fn run_factory_reset, const N: usize>( #[cfg(feature = "se050")] fn run_list, const N: usize>( - se050: &mut Se050, + se050: &mut Se05X, response: &mut Vec, ) -> Result<(), Status> { let mut buf = [0; 200]; se050.run_command( &ReadIdList { offset: 0.into(), - filter: se050::se050::SecureObjectFilter::All, + filter: se05x::se05x::SecureObjectFilter::All, }, &mut buf, )?; @@ -335,7 +335,7 @@ fn run_list, const N: usize>( #[cfg(feature = "se050")] fn run_binary, const N: usize>( - se050: &mut Se050, + se050: &mut Se05X, response: &mut Vec, ) -> Result<(), Status> { let mut buf = [b'a'; 400]; @@ -399,10 +399,10 @@ fn run_binary, const N: usize>( #[cfg(feature = "se050")] fn run_ecc, const N: usize>( - se050: &mut Se050, + se050: &mut Se05X, response: &mut Vec, ) -> Result<(), Status> { - use se050::se050::commands::ReadEcCurveList; + use se05x::se05x::commands::ReadEcCurveList; let mut buf = [0; 200]; let mut buf2 = [0; 200]; @@ -448,7 +448,7 @@ fn run_ecc, const N: usize>( }, &mut buf2, )?; - if res.result != Se050Result::Success { + if res.result != Se05XResult::Success { return Err(0x3002.into()); } response.push(Advance::VerifyP256 as u8).ok(); @@ -492,7 +492,7 @@ fn run_ecc, const N: usize>( }, &mut buf2, )?; - if res.result != Se050Result::Success { + if res.result != Se05XResult::Success { return Err(0x3003.into()); } response.push(Advance::VerifyP521 as u8).ok(); @@ -503,7 +503,7 @@ fn run_ecc, const N: usize>( #[cfg(feature = "se050")] fn run_userid_recreation, const N: usize>( - se050: &mut Se050, + se050: &mut Se05X, response: &mut Vec, ) -> Result<(), Status> { let mut buf = [0; BUFFER_LEN]; @@ -553,7 +553,7 @@ fn run_userid_recreation, const N: usize>( &mut buf, ) { Ok(_) => return Err(0x3004.into()), - Err(se050::se050::Error::Status(Status::CommandNotAllowedNoEf)) => {} + Err(se05x::se05x::Error::Status(Status::CommandNotAllowedNoEf)) => {} Err(_err) => { debug_now!("Got unexpected error: {_err:?}"); return Err(0x3007.into()); @@ -602,7 +602,7 @@ fn run_userid_recreation, const N: usize>( match attack { Ok(_) => {} - Err(se050::se050::Error::Status(Status::CommandNotAllowedNoEf)) => {} + Err(se05x::se05x::Error::Status(Status::CommandNotAllowedNoEf)) => {} Err(_err) => { debug_now!("Got unexpected error: {_err:?}"); return Err(0x3006.into()); @@ -614,10 +614,10 @@ fn run_userid_recreation, const N: usize>( #[cfg(feature = "se050")] fn run_rsa2048, const N: usize>( - se050: &mut Se050, + se050: &mut Se05X, response: &mut Vec, ) -> Result<(), Status> { - use se050::se050::{ + use se05x::se05x::{ commands::{GenRsaKey, RsaDecrypt, RsaEncrypt, RsaSign, RsaVerify}, RsaEncryptionAlgo, RsaSignatureAlgo, }; @@ -655,6 +655,9 @@ fn run_rsa2048, const N: usize>( }, &mut buf2, )?; + if res.result != Se05XResult::Success { + return Err((0x3000 + line!() as u16).into()); + } response.push(Advance::Rsa2048Verify as u8).ok(); let res = se050.run_command( &RsaEncrypt { @@ -673,7 +676,7 @@ fn run_rsa2048, const N: usize>( }, &mut buf, )?; - if res.plaintext != &[52; 32] { + if res.plaintext != [52; 32] { return Err(0x3008.into()); } response.push(Advance::Rsa2048Decrypt as u8).ok(); @@ -686,10 +689,10 @@ fn run_rsa2048, const N: usize>( #[cfg(feature = "se050")] fn run_rsa3072, const N: usize>( - se050: &mut Se050, + se050: &mut Se05X, response: &mut Vec, ) -> Result<(), Status> { - use se050::se050::{ + use se05x::se05x::{ commands::{GenRsaKey, RsaDecrypt, RsaEncrypt, RsaSign, RsaVerify}, RsaEncryptionAlgo, RsaSignatureAlgo, }; @@ -727,6 +730,9 @@ fn run_rsa3072, const N: usize>( }, &mut buf2, )?; + if res.result != Se05XResult::Success { + return Err((0x3000 + line!() as u16).into()); + } response.push(Advance::Rsa3072Verify as u8).ok(); let res = se050.run_command( &RsaEncrypt { @@ -745,7 +751,7 @@ fn run_rsa3072, const N: usize>( }, &mut buf, )?; - if res.plaintext != &[52; 32] { + if res.plaintext != [52; 32] { return Err(0x3008.into()); } response.push(Advance::Rsa3072Decrypt as u8).ok(); @@ -758,10 +764,10 @@ fn run_rsa3072, const N: usize>( #[cfg(feature = "se050")] fn run_rsa4096, const N: usize>( - se050: &mut Se050, + se050: &mut Se05X, response: &mut Vec, ) -> Result<(), Status> { - use se050::se050::{ + use se05x::se05x::{ commands::{GenRsaKey, RsaDecrypt, RsaEncrypt, RsaSign, RsaVerify}, RsaEncryptionAlgo, RsaSignatureAlgo, }; @@ -799,6 +805,9 @@ fn run_rsa4096, const N: usize>( }, &mut buf2, )?; + if res.result != Se05XResult::Success { + return Err((0x3000 + line!() as u16).into()); + } response.push(Advance::Rsa4096Verify as u8).ok(); let res = se050.run_command( &RsaEncrypt { @@ -817,7 +826,7 @@ fn run_rsa4096, const N: usize>( }, &mut buf, )?; - if res.plaintext != &[52; 32] { + if res.plaintext != [52; 32] { return Err(0x3008.into()); } response.push(Advance::Rsa4096Decrypt as u8).ok(); @@ -830,10 +839,10 @@ fn run_rsa4096, const N: usize>( #[cfg(feature = "se050")] fn run_symm, const N: usize>( - se050: &mut Se050, + se050: &mut Se05X, response: &mut Vec, ) -> Result<(), Status> { - use se050::se050::{ + use se05x::se05x::{ commands::{ CipherDecryptInit, CipherEncryptInit, CipherFinal, CipherOneShotDecrypt, CipherOneShotEncrypt, CipherUpdate, CreateCipherObject, DeleteCryptoObj, WriteSymmKey, @@ -876,7 +885,7 @@ fn run_symm, const N: usize>( &CipherOneShotDecrypt { key_id, mode: CipherMode::AesCtr, - ciphertext: &ciphertext1.ciphertext, + ciphertext: ciphertext1.ciphertext, initialization_vector: Some(&iv), }, &mut buf2, @@ -907,6 +916,9 @@ fn run_symm, const N: usize>( }, &mut buf2, )?; + if ciphertext2.data != &ciphertext1.ciphertext[0..32 * 10] { + return Err((0x3000 + line!() as u16).into()); + } response.push(Advance::SymmEncryptUpdate1 as u8).ok(); let ciphertext3 = se050.run_command( &CipherUpdate { @@ -915,6 +927,9 @@ fn run_symm, const N: usize>( }, &mut buf2, )?; + if ciphertext3.data != &ciphertext1.ciphertext[32 * 10..][..32 * 5] { + return Err((0x3000 + line!() as u16).into()); + } response.push(Advance::SymmEncryptUpdate2 as u8).ok(); let ciphertext4 = se050.run_command( &CipherFinal { @@ -923,6 +938,9 @@ fn run_symm, const N: usize>( }, &mut buf2, )?; + if ciphertext4.data != &ciphertext1.ciphertext[32 * 15..] { + return Err((0x3000 + line!() as u16).into()); + } response.push(Advance::SymmEncryptFinal as u8).ok(); se050.run_command(&DeleteCryptoObj { id: cipher_id }, &mut buf2)?; response.push(Advance::SymmEncryptDelete as u8).ok(); @@ -943,29 +961,38 @@ fn run_symm, const N: usize>( &mut buf2, )?; response.push(Advance::SymmDecryptInit as u8).ok(); - let ciphertext2 = se050.run_command( + let plaintext1 = se050.run_command( &CipherUpdate { cipher_id, data: &ciphertext1.ciphertext[0..32 * 10], }, &mut buf2, )?; + if plaintext1.data != &plaintext_data[..32 * 10] { + return Err((0x3000 + line!() as u16).into()); + } response.push(Advance::SymmDecryptUpdate1 as u8).ok(); - let ciphertext3 = se050.run_command( + let plaintext2 = se050.run_command( &CipherUpdate { cipher_id, data: &ciphertext1.ciphertext[32 * 10..][..32 * 5], }, &mut buf2, )?; + if plaintext2.data != &plaintext_data[32 * 10..][..32 * 5] { + return Err((0x3000 + line!() as u16).into()); + } response.push(Advance::SymmDecryptUpdate2 as u8).ok(); - let ciphertext4 = se050.run_command( + let plaintext3 = se050.run_command( &CipherFinal { cipher_id, data: &ciphertext1.ciphertext[32 * 15..], }, &mut buf2, )?; + if plaintext3.data != &plaintext_data[32 * 15..] { + return Err((0x3000 + line!() as u16).into()); + } response.push(Advance::SymmDecryptFinal as u8).ok(); se050.run_command(&DeleteCryptoObj { id: cipher_id }, &mut buf2)?; response.push(Advance::SymmDecryptDelete as u8).ok(); @@ -976,10 +1003,10 @@ fn run_symm, const N: usize>( #[cfg(feature = "se050")] fn run_mac, const N: usize>( - se050: &mut Se050, + se050: &mut Se05X, response: &mut Vec, ) -> Result<(), Status> { - use se050::se050::{ + use se05x::se05x::{ commands::{ CreateSignatureObject, DeleteCryptoObj, MacGenerateFinal, MacGenerateInit, MacOneShotGenerate, MacOneShotValidate, MacUpdate, MacValidateFinal, MacValidateInit, @@ -1027,8 +1054,8 @@ fn run_mac, const N: usize>( &mut buf2, )?; response.push(Advance::MacVerifyOneShot as u8).ok(); - if res.result != Se050Result::Success { - return Err(0x6008.into()); + if res.result != Se05XResult::Success { + return Err((0x3000 + line!() as u16).into()); } se050.run_command( &CreateSignatureObject { @@ -1102,8 +1129,8 @@ fn run_mac, const N: usize>( }, &mut buf, )?; - if res2.result != Se050Result::Success { - return Err(0x6009.into()); + if res2.result != Se05XResult::Success { + return Err((0x3000 + line!() as u16).into()); } response.push(Advance::MacVerifyFinal as u8).ok(); @@ -1117,11 +1144,11 @@ fn run_mac, const N: usize>( #[cfg(feature = "se050")] fn run_aes_session, const N: usize>( - se050: &mut Se050, + se050: &mut Se05X, response: &mut Vec, ) -> Result<(), Status> { use rand_chacha::rand_core::SeedableRng; - use se050::se050::{ + use se05x::se05x::{ commands::{CloseSession, WriteSymmKey}, SymmKeyType, }; @@ -1264,10 +1291,10 @@ fn run_aes_session, const N: usize>( #[cfg(feature = "se050")] fn run_pbkdf, const N: usize>( - se050: &mut Se050, + se050: &mut Se05X, response: &mut Vec, ) -> Result<(), Status> { - use se050::se050::{ + use se05x::se05x::{ commands::{Pbkdf2, WriteSymmKey}, SymmKeyType, }; @@ -1318,10 +1345,10 @@ fn run_pbkdf, const N: usize>( #[cfg(feature = "se050")] fn run_export_import, const N: usize>( - se050: &mut Se050, + se050: &mut Se05X, response: &mut Vec, ) -> Result<(), Status> { - use se050::se050::{ + use se05x::se05x::{ commands::{CipherOneShotEncrypt, ExportObject, ImportObject, WriteSymmKey}, CipherMode, RsaKeyComponent, SymmKeyType, }; @@ -1402,7 +1429,7 @@ fn run_export_import, const N: usize>( ); if !matches!( res, - Err(se050::se050::Error::Status( + Err(se05x::se05x::Error::Status( Status::ConditionsOfUseNotSatisfied, )) ) { From 9d60607a0cb1a665f00bf81b0c30eda57da02461 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= Date: Tue, 22 Aug 2023 14:30:47 +0200 Subject: [PATCH 6/7] Fix typo --- src/admin.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/admin.rs b/src/admin.rs index a6d819a..3f762c4 100644 --- a/src/admin.rs +++ b/src/admin.rs @@ -35,7 +35,7 @@ use run_tests::*; /// Trait representing the possible ownership of the SE050 by the admin app. /// -/// Implemented by `()` and the `Se05X` stract +/// Implemented by `()` and the `Se05X` struct pub trait MaybeSe: RunTests {} impl MaybeSe for () {} From 210af595e3de6f5c79946befa90ff029100f493e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= Date: Wed, 23 Aug 2023 09:56:51 +0200 Subject: [PATCH 7/7] Move se050-specific features to its own module to reduce the need for cfgs --- src/admin/run_tests.rs | 2710 ++++++++++++++++++++-------------------- 1 file changed, 1347 insertions(+), 1363 deletions(-) diff --git a/src/admin/run_tests.rs b/src/admin/run_tests.rs index 9c007e1..86da0a5 100644 --- a/src/admin/run_tests.rs +++ b/src/admin/run_tests.rs @@ -1,28 +1,7 @@ use ctaphid_dispatch::types::Error; - -#[cfg(feature = "se050")] -use embedded_hal::blocking::delay::DelayUs; use iso7816::Status; -#[cfg(feature = "se050")] -use se05x::{ - se05x::{ - commands::{ - CreateSession, DeleteAll, DeleteSecureObject, EcdsaSign, EcdsaVerify, GetRandom, - ReadIdList, ReadObject, VerifySessionUserId, WriteBinary, WriteEcKey, WriteUserId, - }, - policies::{ObjectAccessRule, ObjectPolicyFlags, Policy, PolicySet}, - EcCurve, EcDsaSignatureAlgo, ObjectId, P1KeyType, ProcessSessionCmd, Se05XResult, - }, - t1::I2CForT1, -}; use trussed::types::Vec; -#[cfg(feature = "se050")] -use se05x::se05x::Se05X; - -#[cfg(feature = "se050")] -use hex_literal::hex; - pub trait RunTests { fn run_tests(&mut self, _response: &mut Vec) -> Result<(), Error> { debug_now!("Default run tests"); @@ -37,1437 +16,1442 @@ pub trait RunTests { } } -#[cfg(feature = "se050")] -const BUFFER_LEN: usize = 1024; +impl RunTests for () {} #[cfg(feature = "se050")] -#[derive(Debug)] -#[repr(u8)] -enum Advance { - Enable = 1, - Random1, - Random2, - Random3, - WriteUserId, - CreateSession, - VerifySessionUserId, - DeleteAll, - List, - WriteBinary1, - ReadBinary1, - DeleteBinary1, - WriteBinary2, - ReadBinary2, - DeleteBinary2, - WriteBinary3, - ReadBinary3, - DeleteBinary3, - CreateP256, - ListP256, - GenerateP256, - EcDsaP256, - VerifyP256, - DeleteP256, - CreateP521, - GenerateP521, - EcDsaP521, - VerifyP521, - DeleteP521, - RecreationWriteUserId, - RecreationWriteBinary, - RecreationDeleteAttempt, - RecreationDeleteUserId, - RecreationRecreateUserId, - RecreationCreateSession, - RecreationAuthSession, - RecreationDeleteAttack, - Rsa2048Gen, - Rsa2048Sign, - Rsa2048Verify, - Rsa2048Encrypt, - Rsa2048Decrypt, - Rsa2048Delete, - Rsa3072Gen, - Rsa3072Sign, - Rsa3072Verify, - Rsa3072Encrypt, - Rsa3072Decrypt, - Rsa3072Delete, - Rsa4096Gen, - Rsa4096Sign, - Rsa4096Verify, - Rsa4096Encrypt, - Rsa4096Decrypt, - Rsa4096Delete, - SymmWrite, - SymmEncryptOneShot, - SymmDecryptOneShot, - SymmEncryptCreate, - SymmEncryptInit, - SymmEncryptUpdate1, - SymmEncryptUpdate2, - SymmEncryptFinal, - SymmEncryptDelete, - SymmDecryptCreate, - SymmDecryptInit, - SymmDecryptUpdate1, - SymmDecryptUpdate2, - SymmDecryptFinal, - SymmDecryptDelete, - SymmDelete, - MacWrite, - MacSignOneShot, - MacVerifyOneShot, - MacSignCreate, - MacSignInit, - MacSignUpdate1, - MacSignUpdate2, - MacSignFinal, - MacSignDelete, - MacVerifyCreate, - MacVerifyInit, - MacVerifyUpdate1, - MacVerifyUpdate2, - MacVerifyFinal, - MacVerifyDelete, - MacDelete, - AesSessionCreateKey, - AesSessionCreateBinary, - AesSessionCreateSession, - AesSessionAuthenticate, - AesSessionReadBinary, - AesSessionUpdateKey, - AesSessionCloseSession, - AesSessionRecreateSession, - AesSessionReAuthenticate, - AesSessionReadBinary2, - AesSessionDeleteBinary, - AesSessionDeleteKey, - Pbkdf2WritePin, - Pbkdf2Calculate, - Pbkdf2Compare, - Pbkdf2DeletePin, - ImportWrite, - ImportCipher, - ImportExport, - ImportDelete, - ImportDeletionWorked, - ImportImport, - ImportCipher2, - ImportComp, - ImportDeleteFinal, -} +mod se050_tests { + use super::*; + + use embedded_hal::blocking::delay::DelayUs; + use se05x::{ + se05x::{ + commands::{ + CreateSession, DeleteAll, DeleteSecureObject, EcdsaSign, EcdsaVerify, GetRandom, + ReadIdList, ReadObject, VerifySessionUserId, WriteBinary, WriteEcKey, WriteUserId, + }, + policies::{ObjectAccessRule, ObjectPolicyFlags, Policy, PolicySet}, + EcCurve, EcDsaSignatureAlgo, ObjectId, P1KeyType, ProcessSessionCmd, Se05XResult, + }, + t1::I2CForT1, + }; -impl RunTests for () {} + use se05x::se05x::Se05X; + + use hex_literal::hex; + + const BUFFER_LEN: usize = 1024; + + #[derive(Debug)] + #[repr(u8)] + enum Advance { + Enable = 1, + Random1, + Random2, + Random3, + WriteUserId, + CreateSession, + VerifySessionUserId, + DeleteAll, + List, + WriteBinary1, + ReadBinary1, + DeleteBinary1, + WriteBinary2, + ReadBinary2, + DeleteBinary2, + WriteBinary3, + ReadBinary3, + DeleteBinary3, + CreateP256, + ListP256, + GenerateP256, + EcDsaP256, + VerifyP256, + DeleteP256, + CreateP521, + GenerateP521, + EcDsaP521, + VerifyP521, + DeleteP521, + RecreationWriteUserId, + RecreationWriteBinary, + RecreationDeleteAttempt, + RecreationDeleteUserId, + RecreationRecreateUserId, + RecreationCreateSession, + RecreationAuthSession, + RecreationDeleteAttack, + Rsa2048Gen, + Rsa2048Sign, + Rsa2048Verify, + Rsa2048Encrypt, + Rsa2048Decrypt, + Rsa2048Delete, + Rsa3072Gen, + Rsa3072Sign, + Rsa3072Verify, + Rsa3072Encrypt, + Rsa3072Decrypt, + Rsa3072Delete, + Rsa4096Gen, + Rsa4096Sign, + Rsa4096Verify, + Rsa4096Encrypt, + Rsa4096Decrypt, + Rsa4096Delete, + SymmWrite, + SymmEncryptOneShot, + SymmDecryptOneShot, + SymmEncryptCreate, + SymmEncryptInit, + SymmEncryptUpdate1, + SymmEncryptUpdate2, + SymmEncryptFinal, + SymmEncryptDelete, + SymmDecryptCreate, + SymmDecryptInit, + SymmDecryptUpdate1, + SymmDecryptUpdate2, + SymmDecryptFinal, + SymmDecryptDelete, + SymmDelete, + MacWrite, + MacSignOneShot, + MacVerifyOneShot, + MacSignCreate, + MacSignInit, + MacSignUpdate1, + MacSignUpdate2, + MacSignFinal, + MacSignDelete, + MacVerifyCreate, + MacVerifyInit, + MacVerifyUpdate1, + MacVerifyUpdate2, + MacVerifyFinal, + MacVerifyDelete, + MacDelete, + AesSessionCreateKey, + AesSessionCreateBinary, + AesSessionCreateSession, + AesSessionAuthenticate, + AesSessionReadBinary, + AesSessionUpdateKey, + AesSessionCloseSession, + AesSessionRecreateSession, + AesSessionReAuthenticate, + AesSessionReadBinary2, + AesSessionDeleteBinary, + AesSessionDeleteKey, + Pbkdf2WritePin, + Pbkdf2Calculate, + Pbkdf2Compare, + Pbkdf2DeletePin, + ImportWrite, + ImportCipher, + ImportExport, + ImportDelete, + ImportDeletionWorked, + ImportImport, + ImportCipher2, + ImportComp, + ImportDeleteFinal, + } -#[cfg(feature = "se050")] -impl> RunTests for Se05X { - fn run_tests(&mut self, response: &mut Vec) -> Result<(), Error> { - debug_now!("Se05X run tests"); - match self.run_tests_internal(response) { - Ok(()) => Ok(()), - Err(err) => { - response.push(0).ok(); - let sw: [u8; 2] = err.into(); - response.extend_from_slice(&sw).ok(); - Ok(()) + impl> RunTests for Se05X { + fn run_tests(&mut self, response: &mut Vec) -> Result<(), Error> { + debug_now!("Se05X run tests"); + match self.run_tests_internal(response) { + Ok(()) => Ok(()), + Err(err) => { + response.push(0).ok(); + let sw: [u8; 2] = err.into(); + response.extend_from_slice(&sw).ok(); + Ok(()) + } } } + fn run_tests_internal( + &mut self, + response: &mut Vec, + ) -> Result<(), Status> { + let atr = self.enable()?; + response + .extend_from_slice(&[ + atr.major, + atr.minor, + atr.patch, + atr.secure_box_major, + atr.secure_box_minor, + ]) + .ok(); + run_free_mem(self, response)?; + response.push(Advance::Enable as _).ok(); + run_get_random(self, response)?; + run_factory_reset(self, response)?; + run_list(self, response)?; + run_binary(self, response)?; + run_ecc(self, response)?; + run_userid_recreation(self, response)?; + run_rsa2048(self, response)?; + run_rsa3072(self, response)?; + run_rsa4096(self, response)?; + run_symm(self, response)?; + run_mac(self, response)?; + run_aes_session(self, response)?; + run_pbkdf(self, response)?; + run_export_import(self, response)?; + Ok(()) + } } - fn run_tests_internal( - &mut self, + fn run_free_mem, const N: usize>( + se050: &mut Se05X, response: &mut Vec, ) -> Result<(), Status> { - let atr = self.enable()?; + use se05x::se05x::{commands::GetFreeMemory, Memory}; + + let mut buf = [b'a'; BUFFER_LEN]; + let mem = se050.run_command( + &GetFreeMemory { + memory: Memory::Persistent, + }, + &mut buf, + )?; response - .extend_from_slice(&[ - atr.major, - atr.minor, - atr.patch, - atr.secure_box_major, - atr.secure_box_minor, - ]) + .extend_from_slice(&mem.available.0.to_be_bytes()) + .ok(); + let mem = se050.run_command( + &GetFreeMemory { + memory: Memory::TransientReset, + }, + &mut buf, + )?; + response + .extend_from_slice(&mem.available.0.to_be_bytes()) + .ok(); + let mem = se050.run_command( + &GetFreeMemory { + memory: Memory::TransientDeselect, + }, + &mut buf, + )?; + response + .extend_from_slice(&mem.available.0.to_be_bytes()) .ok(); - run_free_mem(self, response)?; - response.push(Advance::Enable as _).ok(); - run_get_random(self, response)?; - run_factory_reset(self, response)?; - run_list(self, response)?; - run_binary(self, response)?; - run_ecc(self, response)?; - run_userid_recreation(self, response)?; - run_rsa2048(self, response)?; - run_rsa3072(self, response)?; - run_rsa4096(self, response)?; - run_symm(self, response)?; - run_mac(self, response)?; - run_aes_session(self, response)?; - run_pbkdf(self, response)?; - run_export_import(self, response)?; Ok(()) } -} -#[cfg(feature = "se050")] -fn run_free_mem, const N: usize>( - se050: &mut Se05X, - response: &mut Vec, -) -> Result<(), Status> { - use se05x::se05x::{commands::GetFreeMemory, Memory}; - - let mut buf = [b'a'; BUFFER_LEN]; - let mem = se050.run_command( - &GetFreeMemory { - memory: Memory::Persistent, - }, - &mut buf, - )?; - response - .extend_from_slice(&mem.available.0.to_be_bytes()) - .ok(); - let mem = se050.run_command( - &GetFreeMemory { - memory: Memory::TransientReset, - }, - &mut buf, - )?; - response - .extend_from_slice(&mem.available.0.to_be_bytes()) - .ok(); - let mem = se050.run_command( - &GetFreeMemory { - memory: Memory::TransientDeselect, - }, - &mut buf, - )?; - response - .extend_from_slice(&mem.available.0.to_be_bytes()) - .ok(); - Ok(()) -} -#[cfg(feature = "se050")] -fn run_get_random, const N: usize>( - se050: &mut Se05X, - response: &mut Vec, -) -> Result<(), Status> { - let mut buf = [b'a'; BUFFER_LEN]; - let lens = [1, 256, 800]; - let advance = [Advance::Random1, Advance::Random2, Advance::Random3]; - for (len, advance) in lens.into_iter().zip(advance) { - let res = se050.run_command( - &GetRandom { - length: (len as u16).into(), + fn run_get_random, const N: usize>( + se050: &mut Se05X, + response: &mut Vec, + ) -> Result<(), Status> { + let mut buf = [b'a'; BUFFER_LEN]; + let lens = [1, 256, 800]; + let advance = [Advance::Random1, Advance::Random2, Advance::Random3]; + for (len, advance) in lens.into_iter().zip(advance) { + let res = se050.run_command( + &GetRandom { + length: (len as u16).into(), + }, + &mut buf, + )?; + response.push(advance as u8).ok(); + if res.data == &[b'a'; BUFFER_LEN][..len] { + debug!("Failed to get random"); + response.extend_from_slice(&[0, 0, 0]).ok(); + return Ok(()); + } + } + Ok(()) + } + + fn run_factory_reset, const N: usize>( + se050: &mut Se05X, + response: &mut Vec, + ) -> Result<(), Status> { + let mut buf = [b'a'; BUFFER_LEN]; + let data = &hex!("31323334"); + + se050.run_command( + &WriteUserId { + policy: None, + max_attempts: None, + object_id: ObjectId::FACTORY_RESET, + data, + }, + &mut buf, + )?; + response.push(Advance::WriteUserId as u8).ok(); + let session = se050.run_command( + &CreateSession { + object_id: ObjectId::FACTORY_RESET, + }, + &mut buf, + )?; + response.push(Advance::CreateSession as u8).ok(); + + se050.run_command( + &ProcessSessionCmd { + session_id: session.session_id, + apdu: VerifySessionUserId { user_id: data }, }, &mut buf, )?; - response.push(advance as u8).ok(); - if res.data == &[b'a'; BUFFER_LEN][..len] { - debug!("Failed to get random"); - response.extend_from_slice(&[0, 0, 0]).ok(); - return Ok(()); + response.push(Advance::VerifySessionUserId as u8).ok(); + + se050.run_command( + &ProcessSessionCmd { + session_id: session.session_id, + apdu: DeleteAll {}, + }, + &mut buf, + )?; + response.push(Advance::DeleteAll as u8).ok(); + Ok(()) + } + + fn run_list, const N: usize>( + se050: &mut Se05X, + response: &mut Vec, + ) -> Result<(), Status> { + let mut buf = [0; 200]; + se050.run_command( + &ReadIdList { + offset: 0.into(), + filter: se05x::se05x::SecureObjectFilter::All, + }, + &mut buf, + )?; + response.push(Advance::List as u8).ok(); + Ok(()) + } + + fn run_binary, const N: usize>( + se050: &mut Se05X, + response: &mut Vec, + ) -> Result<(), Status> { + let mut buf = [b'a'; 400]; + let buf2 = [b'b'; 400]; + let object_id = ObjectId(hex!("01020304")); + let policy = &[Policy { + object_id: ObjectId::INVALID, + access_rule: ObjectAccessRule::from_flags( + ObjectPolicyFlags::ALLOW_DELETE | ObjectPolicyFlags::ALLOW_READ, + ), + }]; + for (((len, advance_write), advance_read), advance_delete) in [1, 255, 300] + .into_iter() + .zip([ + Advance::WriteBinary1, + Advance::WriteBinary2, + Advance::WriteBinary3, + ]) + .zip([ + Advance::ReadBinary1, + Advance::ReadBinary2, + Advance::ReadBinary3, + ]) + .zip([ + Advance::DeleteBinary1, + Advance::DeleteBinary2, + Advance::DeleteBinary3, + ]) + { + se050.run_command( + &WriteBinary { + transient: false, + policy: Some(PolicySet(policy)), + object_id, + offset: None, + file_length: Some(len.into()), + data: Some(&buf2[..len.into()]), + }, + &mut buf, + )?; + response.push(advance_write as u8).ok(); + let res = se050.run_command( + &ReadObject { + object_id, + offset: None, + length: Some(len.into()), + rsa_key_component: None, + }, + &mut buf, + )?; + response.push(advance_read as u8).ok(); + if res.data[..len.into()] != buf2[..len.into()] { + return Err(0x3001.into()); + } + + se050.run_command(&DeleteSecureObject { object_id }, &mut buf)?; + response.push(advance_delete as u8).ok(); } + Ok(()) } - Ok(()) -} -#[cfg(feature = "se050")] -fn run_factory_reset, const N: usize>( - se050: &mut Se05X, - response: &mut Vec, -) -> Result<(), Status> { - let mut buf = [b'a'; BUFFER_LEN]; - let data = &hex!("31323334"); - - se050.run_command( - &WriteUserId { - policy: None, - max_attempts: None, - object_id: ObjectId::FACTORY_RESET, - data, - }, - &mut buf, - )?; - response.push(Advance::WriteUserId as u8).ok(); - let session = se050.run_command( - &CreateSession { - object_id: ObjectId::FACTORY_RESET, - }, - &mut buf, - )?; - response.push(Advance::CreateSession as u8).ok(); - - se050.run_command( - &ProcessSessionCmd { - session_id: session.session_id, - apdu: VerifySessionUserId { user_id: data }, - }, - &mut buf, - )?; - response.push(Advance::VerifySessionUserId as u8).ok(); - - se050.run_command( - &ProcessSessionCmd { - session_id: session.session_id, - apdu: DeleteAll {}, - }, - &mut buf, - )?; - response.push(Advance::DeleteAll as u8).ok(); - Ok(()) -} + fn run_ecc, const N: usize>( + se050: &mut Se05X, + response: &mut Vec, + ) -> Result<(), Status> { + use se05x::se05x::commands::ReadEcCurveList; -#[cfg(feature = "se050")] -fn run_list, const N: usize>( - se050: &mut Se05X, - response: &mut Vec, -) -> Result<(), Status> { - let mut buf = [0; 200]; - se050.run_command( - &ReadIdList { - offset: 0.into(), - filter: se05x::se05x::SecureObjectFilter::All, - }, - &mut buf, - )?; - response.push(Advance::List as u8).ok(); - Ok(()) -} + let mut buf = [0; 200]; + let mut buf2 = [0; 200]; + let object_id = ObjectId(hex!("01020304")); -#[cfg(feature = "se050")] -fn run_binary, const N: usize>( - se050: &mut Se05X, - response: &mut Vec, -) -> Result<(), Status> { - let mut buf = [b'a'; 400]; - let buf2 = [b'b'; 400]; - let object_id = ObjectId(hex!("01020304")); - let policy = &[Policy { - object_id: ObjectId::INVALID, - access_rule: ObjectAccessRule::from_flags( - ObjectPolicyFlags::ALLOW_DELETE | ObjectPolicyFlags::ALLOW_READ, - ), - }]; - for (((len, advance_write), advance_read), advance_delete) in [1, 255, 300] - .into_iter() - .zip([ - Advance::WriteBinary1, - Advance::WriteBinary2, - Advance::WriteBinary3, - ]) - .zip([ - Advance::ReadBinary1, - Advance::ReadBinary2, - Advance::ReadBinary3, - ]) - .zip([ - Advance::DeleteBinary1, - Advance::DeleteBinary2, - Advance::DeleteBinary3, - ]) - { + // *********** P256 *********** // + + se050.create_and_set_curve(EcCurve::NistP256)?; + response.push(Advance::CreateP256 as u8).ok(); + let _res = se050.run_command(&ReadEcCurveList {}, &mut buf)?; + debug_now!("Ec curves list: {:?}", _res); + response.push(Advance::ListP256 as u8).ok(); se050.run_command( - &WriteBinary { + &WriteEcKey { transient: false, - policy: Some(PolicySet(policy)), + is_auth: false, + key_type: Some(P1KeyType::KeyPair), + policy: None, + max_attempts: None, object_id, - offset: None, - file_length: Some(len.into()), - data: Some(&buf2[..len.into()]), + curve: Some(EcCurve::NistP256), + private_key: None, + public_key: None, }, &mut buf, )?; - response.push(advance_write as u8).ok(); + response.push(Advance::GenerateP256 as u8).ok(); let res = se050.run_command( - &ReadObject { - object_id, - offset: None, - length: Some(len.into()), - rsa_key_component: None, + &EcdsaSign { + key_id: object_id, + data: &[52; 32], + algo: EcDsaSignatureAlgo::Sha256, }, &mut buf, )?; - response.push(advance_read as u8).ok(); - if res.data[..len.into()] != buf2[..len.into()] { - return Err(0x3001.into()); + response.push(Advance::EcDsaP256 as u8).ok(); + let res = se050.run_command( + &EcdsaVerify { + key_id: object_id, + data: &[52; 32], + algo: EcDsaSignatureAlgo::Sha256, + signature: res.signature, + }, + &mut buf2, + )?; + if res.result != Se05XResult::Success { + return Err(0x3002.into()); } - + response.push(Advance::VerifyP256 as u8).ok(); se050.run_command(&DeleteSecureObject { object_id }, &mut buf)?; - response.push(advance_delete as u8).ok(); - } - Ok(()) -} + response.push(Advance::DeleteP256 as u8).ok(); -#[cfg(feature = "se050")] -fn run_ecc, const N: usize>( - se050: &mut Se05X, - response: &mut Vec, -) -> Result<(), Status> { - use se05x::se05x::commands::ReadEcCurveList; - - let mut buf = [0; 200]; - let mut buf2 = [0; 200]; - let object_id = ObjectId(hex!("01020304")); - - // *********** P256 *********** // - - se050.create_and_set_curve(EcCurve::NistP256)?; - response.push(Advance::CreateP256 as u8).ok(); - let _res = se050.run_command(&ReadEcCurveList {}, &mut buf)?; - debug_now!("Ec curves list: {:?}", _res); - response.push(Advance::ListP256 as u8).ok(); - se050.run_command( - &WriteEcKey { - transient: false, - is_auth: false, - key_type: Some(P1KeyType::KeyPair), - policy: None, - max_attempts: None, - object_id, - curve: Some(EcCurve::NistP256), - private_key: None, - public_key: None, - }, - &mut buf, - )?; - response.push(Advance::GenerateP256 as u8).ok(); - let res = se050.run_command( - &EcdsaSign { - key_id: object_id, - data: &[52; 32], - algo: EcDsaSignatureAlgo::Sha256, - }, - &mut buf, - )?; - response.push(Advance::EcDsaP256 as u8).ok(); - let res = se050.run_command( - &EcdsaVerify { - key_id: object_id, - data: &[52; 32], - algo: EcDsaSignatureAlgo::Sha256, - signature: res.signature, - }, - &mut buf2, - )?; - if res.result != Se05XResult::Success { - return Err(0x3002.into()); - } - response.push(Advance::VerifyP256 as u8).ok(); - se050.run_command(&DeleteSecureObject { object_id }, &mut buf)?; - response.push(Advance::DeleteP256 as u8).ok(); - - // *********** P521 *********** // - - se050.create_and_set_curve(EcCurve::NistP521)?; - response.push(Advance::CreateP521 as u8).ok(); - se050.run_command( - &WriteEcKey { - transient: false, - is_auth: false, - key_type: Some(P1KeyType::KeyPair), - policy: None, - max_attempts: None, - object_id, - curve: Some(EcCurve::NistP521), - private_key: None, - public_key: None, - }, - &mut buf, - )?; - response.push(Advance::GenerateP521 as u8).ok(); - let res = se050.run_command( - &EcdsaSign { - key_id: object_id, - data: &[52; 64], - algo: EcDsaSignatureAlgo::Sha512, - }, - &mut buf, - )?; - response.push(Advance::EcDsaP521 as u8).ok(); - let res = se050.run_command( - &EcdsaVerify { - key_id: object_id, - data: &[52; 64], - algo: EcDsaSignatureAlgo::Sha512, - signature: res.signature, - }, - &mut buf2, - )?; - if res.result != Se05XResult::Success { - return Err(0x3003.into()); - } - response.push(Advance::VerifyP521 as u8).ok(); - se050.run_command(&DeleteSecureObject { object_id }, &mut buf)?; - response.push(Advance::DeleteP521 as u8).ok(); - Ok(()) -} + // *********** P521 *********** // -#[cfg(feature = "se050")] -fn run_userid_recreation, const N: usize>( - se050: &mut Se05X, - response: &mut Vec, -) -> Result<(), Status> { - let mut buf = [0; BUFFER_LEN]; - let object_id = ObjectId(hex!("01020304")); - let user_id = ObjectId(hex!("01223344")); - let user_id_good_value = hex!("31323334"); - let user_id_bad_value = hex!("FFFFFFFF"); - let policy_user_id = &[Policy { - object_id: ObjectId::INVALID, - access_rule: ObjectAccessRule::from_flags(ObjectPolicyFlags::ALLOW_DELETE), - }]; - se050.run_command( - &WriteUserId { - policy: Some(PolicySet(policy_user_id)), - max_attempts: None, - object_id: user_id, - data: &user_id_good_value, - }, - &mut buf, - )?; - response.push(Advance::RecreationWriteUserId as u8).ok(); - let policy = &[Policy { - object_id: user_id, - access_rule: ObjectAccessRule::from_flags( - ObjectPolicyFlags::ALLOW_DELETE | ObjectPolicyFlags::ALLOW_READ, - ), - }]; - se050.run_command( - &WriteBinary { - transient: false, - policy: Some(PolicySet(policy)), - object_id, - offset: None, - file_length: Some(2.into()), - data: Some(&[1, 2]), - }, - &mut buf, - )?; - response.push(Advance::RecreationWriteBinary as u8).ok(); - match se050.run_command( - &ReadObject { - object_id, - offset: Some(0.into()), - length: Some(2.into()), - rsa_key_component: None, - }, - &mut buf, - ) { - Ok(_) => return Err(0x3004.into()), - Err(se05x::se05x::Error::Status(Status::CommandNotAllowedNoEf)) => {} - Err(_err) => { - debug_now!("Got unexpected error: {_err:?}"); - return Err(0x3007.into()); + se050.create_and_set_curve(EcCurve::NistP521)?; + response.push(Advance::CreateP521 as u8).ok(); + se050.run_command( + &WriteEcKey { + transient: false, + is_auth: false, + key_type: Some(P1KeyType::KeyPair), + policy: None, + max_attempts: None, + object_id, + curve: Some(EcCurve::NistP521), + private_key: None, + public_key: None, + }, + &mut buf, + )?; + response.push(Advance::GenerateP521 as u8).ok(); + let res = se050.run_command( + &EcdsaSign { + key_id: object_id, + data: &[52; 64], + algo: EcDsaSignatureAlgo::Sha512, + }, + &mut buf, + )?; + response.push(Advance::EcDsaP521 as u8).ok(); + let res = se050.run_command( + &EcdsaVerify { + key_id: object_id, + data: &[52; 64], + algo: EcDsaSignatureAlgo::Sha512, + signature: res.signature, + }, + &mut buf2, + )?; + if res.result != Se05XResult::Success { + return Err(0x3003.into()); } + response.push(Advance::VerifyP521 as u8).ok(); + se050.run_command(&DeleteSecureObject { object_id }, &mut buf)?; + response.push(Advance::DeleteP521 as u8).ok(); + Ok(()) } - response.push(Advance::RecreationDeleteAttempt as u8).ok(); - se050.run_command(&DeleteSecureObject { object_id: user_id }, &mut buf)?; - response.push(Advance::RecreationDeleteUserId as u8).ok(); - se050.run_command( - &WriteUserId { - policy: None, - max_attempts: None, - object_id: user_id, - data: &user_id_bad_value, - }, - &mut buf, - )?; - response.push(Advance::RecreationRecreateUserId as u8).ok(); - - let session = se050.run_command(&CreateSession { object_id: user_id }, &mut buf)?; - response.push(Advance::RecreationCreateSession as u8).ok(); - se050.run_command( - &ProcessSessionCmd { - session_id: session.session_id, - apdu: VerifySessionUserId { - user_id: &user_id_bad_value, + fn run_userid_recreation, const N: usize>( + se050: &mut Se05X, + response: &mut Vec, + ) -> Result<(), Status> { + let mut buf = [0; BUFFER_LEN]; + let object_id = ObjectId(hex!("01020304")); + let user_id = ObjectId(hex!("01223344")); + let user_id_good_value = hex!("31323334"); + let user_id_bad_value = hex!("FFFFFFFF"); + let policy_user_id = &[Policy { + object_id: ObjectId::INVALID, + access_rule: ObjectAccessRule::from_flags(ObjectPolicyFlags::ALLOW_DELETE), + }]; + se050.run_command( + &WriteUserId { + policy: Some(PolicySet(policy_user_id)), + max_attempts: None, + object_id: user_id, + data: &user_id_good_value, }, - }, - &mut buf, - )?; - response.push(Advance::RecreationAuthSession as u8).ok(); - - let attack = se050.run_command( - &ProcessSessionCmd { - session_id: session.session_id, - apdu: ReadObject { + &mut buf, + )?; + response.push(Advance::RecreationWriteUserId as u8).ok(); + let policy = &[Policy { + object_id: user_id, + access_rule: ObjectAccessRule::from_flags( + ObjectPolicyFlags::ALLOW_DELETE | ObjectPolicyFlags::ALLOW_READ, + ), + }]; + se050.run_command( + &WriteBinary { + transient: false, + policy: Some(PolicySet(policy)), + object_id, + offset: None, + file_length: Some(2.into()), + data: Some(&[1, 2]), + }, + &mut buf, + )?; + response.push(Advance::RecreationWriteBinary as u8).ok(); + match se050.run_command( + &ReadObject { object_id, offset: Some(0.into()), length: Some(2.into()), rsa_key_component: None, }, - }, - &mut buf, - ); - - match attack { - Ok(_) => {} - Err(se05x::se05x::Error::Status(Status::CommandNotAllowedNoEf)) => {} - Err(_err) => { - debug_now!("Got unexpected error: {_err:?}"); - return Err(0x3006.into()); + &mut buf, + ) { + Ok(_) => return Err(0x3004.into()), + Err(se05x::se05x::Error::Status(Status::CommandNotAllowedNoEf)) => {} + Err(_err) => { + debug_now!("Got unexpected error: {_err:?}"); + return Err(0x3007.into()); + } } - } - response.push(Advance::RecreationDeleteAttack as u8).ok(); - Ok(()) -} + response.push(Advance::RecreationDeleteAttempt as u8).ok(); + se050.run_command(&DeleteSecureObject { object_id: user_id }, &mut buf)?; + response.push(Advance::RecreationDeleteUserId as u8).ok(); + se050.run_command( + &WriteUserId { + policy: None, + max_attempts: None, + object_id: user_id, + data: &user_id_bad_value, + }, + &mut buf, + )?; + response.push(Advance::RecreationRecreateUserId as u8).ok(); -#[cfg(feature = "se050")] -fn run_rsa2048, const N: usize>( - se050: &mut Se05X, - response: &mut Vec, -) -> Result<(), Status> { - use se05x::se05x::{ - commands::{GenRsaKey, RsaDecrypt, RsaEncrypt, RsaSign, RsaVerify}, - RsaEncryptionAlgo, RsaSignatureAlgo, - }; + let session = se050.run_command(&CreateSession { object_id: user_id }, &mut buf)?; + response.push(Advance::RecreationCreateSession as u8).ok(); - let mut buf = [0; 1000]; - let mut buf2 = [0; 1000]; - let object_id = ObjectId(hex!("02334455")); - se050.run_command( - &GenRsaKey { - transient: false, - is_auth: false, - policy: None, - max_attempts: None, - object_id, - key_size: Some(2048.into()), - }, - &mut buf, - )?; - response.push(Advance::Rsa2048Gen as u8).ok(); - let res = se050.run_command( - &RsaSign { - key_id: object_id, - data: &[52; 32], - algo: RsaSignatureAlgo::RsaSha256Pkcs1, - }, - &mut buf, - )?; - response.push(Advance::Rsa2048Sign as u8).ok(); - let res = se050.run_command( - &RsaVerify { - key_id: object_id, - data: &[52; 32], - algo: RsaSignatureAlgo::RsaSha256Pkcs1, - signature: res.signature, - }, - &mut buf2, - )?; - if res.result != Se05XResult::Success { - return Err((0x3000 + line!() as u16).into()); - } - response.push(Advance::Rsa2048Verify as u8).ok(); - let res = se050.run_command( - &RsaEncrypt { - key_id: object_id, - plaintext: &[52; 32], - algo: RsaEncryptionAlgo::Pkcs1, - }, - &mut buf2, - )?; - response.push(Advance::Rsa2048Encrypt as u8).ok(); - let res = se050.run_command( - &RsaDecrypt { - key_id: object_id, - algo: RsaEncryptionAlgo::Pkcs1, - ciphertext: res.ciphertext, - }, - &mut buf, - )?; - if res.plaintext != [52; 32] { - return Err(0x3008.into()); + se050.run_command( + &ProcessSessionCmd { + session_id: session.session_id, + apdu: VerifySessionUserId { + user_id: &user_id_bad_value, + }, + }, + &mut buf, + )?; + response.push(Advance::RecreationAuthSession as u8).ok(); + + let attack = se050.run_command( + &ProcessSessionCmd { + session_id: session.session_id, + apdu: ReadObject { + object_id, + offset: Some(0.into()), + length: Some(2.into()), + rsa_key_component: None, + }, + }, + &mut buf, + ); + + match attack { + Ok(_) => {} + Err(se05x::se05x::Error::Status(Status::CommandNotAllowedNoEf)) => {} + Err(_err) => { + debug_now!("Got unexpected error: {_err:?}"); + return Err(0x3006.into()); + } + } + response.push(Advance::RecreationDeleteAttack as u8).ok(); + Ok(()) } - response.push(Advance::Rsa2048Decrypt as u8).ok(); - se050.run_command(&DeleteSecureObject { object_id }, &mut buf)?; - response.push(Advance::Rsa2048Delete as u8).ok(); - - Ok(()) -} + fn run_rsa2048, const N: usize>( + se050: &mut Se05X, + response: &mut Vec, + ) -> Result<(), Status> { + use se05x::se05x::{ + commands::{GenRsaKey, RsaDecrypt, RsaEncrypt, RsaSign, RsaVerify}, + RsaEncryptionAlgo, RsaSignatureAlgo, + }; + + let mut buf = [0; 1000]; + let mut buf2 = [0; 1000]; + let object_id = ObjectId(hex!("02334455")); + se050.run_command( + &GenRsaKey { + transient: false, + is_auth: false, + policy: None, + max_attempts: None, + object_id, + key_size: Some(2048.into()), + }, + &mut buf, + )?; + response.push(Advance::Rsa2048Gen as u8).ok(); + let res = se050.run_command( + &RsaSign { + key_id: object_id, + data: &[52; 32], + algo: RsaSignatureAlgo::RsaSha256Pkcs1, + }, + &mut buf, + )?; + response.push(Advance::Rsa2048Sign as u8).ok(); + let res = se050.run_command( + &RsaVerify { + key_id: object_id, + data: &[52; 32], + algo: RsaSignatureAlgo::RsaSha256Pkcs1, + signature: res.signature, + }, + &mut buf2, + )?; + if res.result != Se05XResult::Success { + return Err((0x3000 + line!() as u16).into()); + } + response.push(Advance::Rsa2048Verify as u8).ok(); + let res = se050.run_command( + &RsaEncrypt { + key_id: object_id, + plaintext: &[52; 32], + algo: RsaEncryptionAlgo::Pkcs1, + }, + &mut buf2, + )?; + response.push(Advance::Rsa2048Encrypt as u8).ok(); + let res = se050.run_command( + &RsaDecrypt { + key_id: object_id, + algo: RsaEncryptionAlgo::Pkcs1, + ciphertext: res.ciphertext, + }, + &mut buf, + )?; + if res.plaintext != [52; 32] { + return Err(0x3008.into()); + } + response.push(Advance::Rsa2048Decrypt as u8).ok(); -#[cfg(feature = "se050")] -fn run_rsa3072, const N: usize>( - se050: &mut Se05X, - response: &mut Vec, -) -> Result<(), Status> { - use se05x::se05x::{ - commands::{GenRsaKey, RsaDecrypt, RsaEncrypt, RsaSign, RsaVerify}, - RsaEncryptionAlgo, RsaSignatureAlgo, - }; + se050.run_command(&DeleteSecureObject { object_id }, &mut buf)?; + response.push(Advance::Rsa2048Delete as u8).ok(); - let mut buf = [0; 1000]; - let mut buf2 = [0; 1000]; - let object_id = ObjectId(hex!("02334455")); - se050.run_command( - &GenRsaKey { - transient: false, - is_auth: false, - policy: None, - max_attempts: None, - object_id, - key_size: Some(3072.into()), - }, - &mut buf, - )?; - response.push(Advance::Rsa3072Gen as u8).ok(); - let res = se050.run_command( - &RsaSign { - key_id: object_id, - data: &[52; 32], - algo: RsaSignatureAlgo::RsaSha256Pkcs1, - }, - &mut buf, - )?; - response.push(Advance::Rsa3072Sign as u8).ok(); - let res = se050.run_command( - &RsaVerify { - key_id: object_id, - data: &[52; 32], - algo: RsaSignatureAlgo::RsaSha256Pkcs1, - signature: res.signature, - }, - &mut buf2, - )?; - if res.result != Se05XResult::Success { - return Err((0x3000 + line!() as u16).into()); - } - response.push(Advance::Rsa3072Verify as u8).ok(); - let res = se050.run_command( - &RsaEncrypt { - key_id: object_id, - plaintext: &[52; 32], - algo: RsaEncryptionAlgo::Pkcs1, - }, - &mut buf2, - )?; - response.push(Advance::Rsa3072Encrypt as u8).ok(); - let res = se050.run_command( - &RsaDecrypt { - key_id: object_id, - algo: RsaEncryptionAlgo::Pkcs1, - ciphertext: res.ciphertext, - }, - &mut buf, - )?; - if res.plaintext != [52; 32] { - return Err(0x3008.into()); + Ok(()) } - response.push(Advance::Rsa3072Decrypt as u8).ok(); - se050.run_command(&DeleteSecureObject { object_id }, &mut buf)?; - response.push(Advance::Rsa3072Delete as u8).ok(); - - Ok(()) -} - -#[cfg(feature = "se050")] -fn run_rsa4096, const N: usize>( - se050: &mut Se05X, - response: &mut Vec, -) -> Result<(), Status> { - use se05x::se05x::{ - commands::{GenRsaKey, RsaDecrypt, RsaEncrypt, RsaSign, RsaVerify}, - RsaEncryptionAlgo, RsaSignatureAlgo, - }; - - let mut buf = [0; 1000]; - let mut buf2 = [0; 1000]; - let object_id = ObjectId(hex!("02334455")); - se050.run_command( - &GenRsaKey { - transient: false, - is_auth: false, - policy: None, - max_attempts: None, - object_id, - key_size: Some(4096.into()), - }, - &mut buf, - )?; - response.push(Advance::Rsa4096Gen as u8).ok(); - let res = se050.run_command( - &RsaSign { - key_id: object_id, - data: &[52; 32], - algo: RsaSignatureAlgo::RsaSha256Pkcs1, - }, - &mut buf, - )?; - response.push(Advance::Rsa4096Sign as u8).ok(); - let res = se050.run_command( - &RsaVerify { - key_id: object_id, - data: &[52; 32], - algo: RsaSignatureAlgo::RsaSha256Pkcs1, - signature: res.signature, - }, - &mut buf2, - )?; - if res.result != Se05XResult::Success { - return Err((0x3000 + line!() as u16).into()); - } - response.push(Advance::Rsa4096Verify as u8).ok(); - let res = se050.run_command( - &RsaEncrypt { - key_id: object_id, - plaintext: &[52; 32], - algo: RsaEncryptionAlgo::Pkcs1, - }, - &mut buf2, - )?; - response.push(Advance::Rsa4096Encrypt as u8).ok(); - let res = se050.run_command( - &RsaDecrypt { - key_id: object_id, - algo: RsaEncryptionAlgo::Pkcs1, - ciphertext: res.ciphertext, - }, - &mut buf, - )?; - if res.plaintext != [52; 32] { - return Err(0x3008.into()); - } - response.push(Advance::Rsa4096Decrypt as u8).ok(); - - se050.run_command(&DeleteSecureObject { object_id }, &mut buf)?; - response.push(Advance::Rsa4096Delete as u8).ok(); - - Ok(()) -} + fn run_rsa3072, const N: usize>( + se050: &mut Se05X, + response: &mut Vec, + ) -> Result<(), Status> { + use se05x::se05x::{ + commands::{GenRsaKey, RsaDecrypt, RsaEncrypt, RsaSign, RsaVerify}, + RsaEncryptionAlgo, RsaSignatureAlgo, + }; + + let mut buf = [0; 1000]; + let mut buf2 = [0; 1000]; + let object_id = ObjectId(hex!("02334455")); + se050.run_command( + &GenRsaKey { + transient: false, + is_auth: false, + policy: None, + max_attempts: None, + object_id, + key_size: Some(3072.into()), + }, + &mut buf, + )?; + response.push(Advance::Rsa3072Gen as u8).ok(); + let res = se050.run_command( + &RsaSign { + key_id: object_id, + data: &[52; 32], + algo: RsaSignatureAlgo::RsaSha256Pkcs1, + }, + &mut buf, + )?; + response.push(Advance::Rsa3072Sign as u8).ok(); + let res = se050.run_command( + &RsaVerify { + key_id: object_id, + data: &[52; 32], + algo: RsaSignatureAlgo::RsaSha256Pkcs1, + signature: res.signature, + }, + &mut buf2, + )?; + if res.result != Se05XResult::Success { + return Err((0x3000 + line!() as u16).into()); + } + response.push(Advance::Rsa3072Verify as u8).ok(); + let res = se050.run_command( + &RsaEncrypt { + key_id: object_id, + plaintext: &[52; 32], + algo: RsaEncryptionAlgo::Pkcs1, + }, + &mut buf2, + )?; + response.push(Advance::Rsa3072Encrypt as u8).ok(); + let res = se050.run_command( + &RsaDecrypt { + key_id: object_id, + algo: RsaEncryptionAlgo::Pkcs1, + ciphertext: res.ciphertext, + }, + &mut buf, + )?; + if res.plaintext != [52; 32] { + return Err(0x3008.into()); + } + response.push(Advance::Rsa3072Decrypt as u8).ok(); -#[cfg(feature = "se050")] -fn run_symm, const N: usize>( - se050: &mut Se05X, - response: &mut Vec, -) -> Result<(), Status> { - use se05x::se05x::{ - commands::{ - CipherDecryptInit, CipherEncryptInit, CipherFinal, CipherOneShotDecrypt, - CipherOneShotEncrypt, CipherUpdate, CreateCipherObject, DeleteCryptoObj, WriteSymmKey, - }, - CipherMode, CryptoObjectId, SymmKeyType, - }; + se050.run_command(&DeleteSecureObject { object_id }, &mut buf)?; + response.push(Advance::Rsa3072Delete as u8).ok(); - let mut buf = [0; 1000]; - let mut buf2 = [0; 1000]; - let plaintext_data = [2; 32 * 15]; - let key_id = ObjectId(hex!("03445566")); - let cipher_id = CryptoObjectId(hex!("0123")); - let key = [0x42; 32]; - let iv = [0xFF; 16]; - se050.run_command( - &WriteSymmKey { - transient: true, - is_auth: false, - key_type: SymmKeyType::Aes, - policy: None, - max_attempts: None, - object_id: key_id, - kek_id: None, - value: &key, - }, - &mut buf, - )?; - response.push(Advance::SymmWrite as u8).ok(); - let ciphertext1 = se050.run_command( - &CipherOneShotEncrypt { - key_id, - mode: CipherMode::AesCtr, - plaintext: &plaintext_data, - initialization_vector: Some(&iv), - }, - &mut buf, - )?; - response.push(Advance::SymmEncryptOneShot as u8).ok(); - let plaintext1 = se050.run_command( - &CipherOneShotDecrypt { - key_id, - mode: CipherMode::AesCtr, - ciphertext: ciphertext1.ciphertext, - initialization_vector: Some(&iv), - }, - &mut buf2, - )?; - response.push(Advance::SymmDecryptOneShot as u8).ok(); - assert_eq!(plaintext1.plaintext, plaintext_data); - se050.run_command( - &CreateCipherObject { - id: cipher_id, - subtype: CipherMode::AesCtr, - }, - &mut buf2, - )?; - response.push(Advance::SymmEncryptCreate as u8).ok(); - se050.run_command( - &CipherEncryptInit { - key_id, - initialization_vector: Some(&iv), - cipher_id, - }, - &mut buf2, - )?; - response.push(Advance::SymmEncryptInit as u8).ok(); - let ciphertext2 = se050.run_command( - &CipherUpdate { - cipher_id, - data: &plaintext_data[0..32 * 10], - }, - &mut buf2, - )?; - if ciphertext2.data != &ciphertext1.ciphertext[0..32 * 10] { - return Err((0x3000 + line!() as u16).into()); - } - response.push(Advance::SymmEncryptUpdate1 as u8).ok(); - let ciphertext3 = se050.run_command( - &CipherUpdate { - cipher_id, - data: &plaintext_data[32 * 10..][..32 * 5], - }, - &mut buf2, - )?; - if ciphertext3.data != &ciphertext1.ciphertext[32 * 10..][..32 * 5] { - return Err((0x3000 + line!() as u16).into()); - } - response.push(Advance::SymmEncryptUpdate2 as u8).ok(); - let ciphertext4 = se050.run_command( - &CipherFinal { - cipher_id, - data: &plaintext_data[32 * 15..], - }, - &mut buf2, - )?; - if ciphertext4.data != &ciphertext1.ciphertext[32 * 15..] { - return Err((0x3000 + line!() as u16).into()); - } - response.push(Advance::SymmEncryptFinal as u8).ok(); - se050.run_command(&DeleteCryptoObj { id: cipher_id }, &mut buf2)?; - response.push(Advance::SymmEncryptDelete as u8).ok(); - se050.run_command( - &CreateCipherObject { - id: cipher_id, - subtype: CipherMode::AesCtr, - }, - &mut buf2, - )?; - response.push(Advance::SymmDecryptCreate as u8).ok(); - se050.run_command( - &CipherDecryptInit { - key_id, - initialization_vector: Some(&iv), - cipher_id, - }, - &mut buf2, - )?; - response.push(Advance::SymmDecryptInit as u8).ok(); - let plaintext1 = se050.run_command( - &CipherUpdate { - cipher_id, - data: &ciphertext1.ciphertext[0..32 * 10], - }, - &mut buf2, - )?; - if plaintext1.data != &plaintext_data[..32 * 10] { - return Err((0x3000 + line!() as u16).into()); - } - response.push(Advance::SymmDecryptUpdate1 as u8).ok(); - let plaintext2 = se050.run_command( - &CipherUpdate { - cipher_id, - data: &ciphertext1.ciphertext[32 * 10..][..32 * 5], - }, - &mut buf2, - )?; - if plaintext2.data != &plaintext_data[32 * 10..][..32 * 5] { - return Err((0x3000 + line!() as u16).into()); - } - response.push(Advance::SymmDecryptUpdate2 as u8).ok(); - let plaintext3 = se050.run_command( - &CipherFinal { - cipher_id, - data: &ciphertext1.ciphertext[32 * 15..], - }, - &mut buf2, - )?; - if plaintext3.data != &plaintext_data[32 * 15..] { - return Err((0x3000 + line!() as u16).into()); + Ok(()) } - response.push(Advance::SymmDecryptFinal as u8).ok(); - se050.run_command(&DeleteCryptoObj { id: cipher_id }, &mut buf2)?; - response.push(Advance::SymmDecryptDelete as u8).ok(); - se050.run_command(&DeleteSecureObject { object_id: key_id }, &mut buf2)?; - response.push(Advance::SymmDelete as u8).ok(); - Ok(()) -} -#[cfg(feature = "se050")] -fn run_mac, const N: usize>( - se050: &mut Se05X, - response: &mut Vec, -) -> Result<(), Status> { - use se05x::se05x::{ - commands::{ - CreateSignatureObject, DeleteCryptoObj, MacGenerateFinal, MacGenerateInit, - MacOneShotGenerate, MacOneShotValidate, MacUpdate, MacValidateFinal, MacValidateInit, - WriteSymmKey, - }, - CryptoObjectId, MacAlgo, SymmKeyType, - }; + fn run_rsa4096, const N: usize>( + se050: &mut Se05X, + response: &mut Vec, + ) -> Result<(), Status> { + use se05x::se05x::{ + commands::{GenRsaKey, RsaDecrypt, RsaEncrypt, RsaSign, RsaVerify}, + RsaEncryptionAlgo, RsaSignatureAlgo, + }; + + let mut buf = [0; 1000]; + let mut buf2 = [0; 1000]; + let object_id = ObjectId(hex!("02334455")); + se050.run_command( + &GenRsaKey { + transient: false, + is_auth: false, + policy: None, + max_attempts: None, + object_id, + key_size: Some(4096.into()), + }, + &mut buf, + )?; + response.push(Advance::Rsa4096Gen as u8).ok(); + let res = se050.run_command( + &RsaSign { + key_id: object_id, + data: &[52; 32], + algo: RsaSignatureAlgo::RsaSha256Pkcs1, + }, + &mut buf, + )?; + response.push(Advance::Rsa4096Sign as u8).ok(); + let res = se050.run_command( + &RsaVerify { + key_id: object_id, + data: &[52; 32], + algo: RsaSignatureAlgo::RsaSha256Pkcs1, + signature: res.signature, + }, + &mut buf2, + )?; + if res.result != Se05XResult::Success { + return Err((0x3000 + line!() as u16).into()); + } + response.push(Advance::Rsa4096Verify as u8).ok(); + let res = se050.run_command( + &RsaEncrypt { + key_id: object_id, + plaintext: &[52; 32], + algo: RsaEncryptionAlgo::Pkcs1, + }, + &mut buf2, + )?; + response.push(Advance::Rsa4096Encrypt as u8).ok(); + let res = se050.run_command( + &RsaDecrypt { + key_id: object_id, + algo: RsaEncryptionAlgo::Pkcs1, + ciphertext: res.ciphertext, + }, + &mut buf, + )?; + if res.plaintext != [52; 32] { + return Err(0x3008.into()); + } + response.push(Advance::Rsa4096Decrypt as u8).ok(); - let mut buf = [0; 1000]; - let mut buf2 = [0; 1000]; - let plaintext_data = [2; 32 * 15]; - let key_id = ObjectId(hex!("03445566")); - let mac_id = CryptoObjectId(hex!("0123")); - let key = [0x42; 32]; - se050.run_command( - &WriteSymmKey { - transient: false, - is_auth: false, - key_type: SymmKeyType::Hmac, - policy: None, - max_attempts: None, - object_id: key_id, - kek_id: None, - value: &key, - }, - &mut buf, - )?; - response.push(Advance::MacWrite as u8).ok(); - let tag1 = se050.run_command( - &MacOneShotGenerate { - key_id, - data: &plaintext_data, - algo: MacAlgo::HmacSha256, - }, - &mut buf, - )?; - response.push(Advance::MacSignOneShot as u8).ok(); - let res = se050.run_command( - &MacOneShotValidate { - key_id, - algo: MacAlgo::HmacSha256, - data: &plaintext_data, - tag: tag1.tag, - }, - &mut buf2, - )?; - response.push(Advance::MacVerifyOneShot as u8).ok(); - if res.result != Se05XResult::Success { - return Err((0x3000 + line!() as u16).into()); + se050.run_command(&DeleteSecureObject { object_id }, &mut buf)?; + response.push(Advance::Rsa4096Delete as u8).ok(); + + Ok(()) } - se050.run_command( - &CreateSignatureObject { - id: mac_id, - subtype: MacAlgo::HmacSha256, - }, - &mut buf2, - )?; - response.push(Advance::MacSignCreate as u8).ok(); - se050.run_command(&MacGenerateInit { key_id, mac_id }, &mut buf2)?; - response.push(Advance::MacSignInit as u8).ok(); - se050.run_command( - &MacUpdate { - mac_id, - data: &plaintext_data[0..32 * 10], - }, - &mut buf2, - )?; - response.push(Advance::MacSignUpdate1 as u8).ok(); - se050.run_command( - &MacUpdate { - mac_id, - data: &plaintext_data[32 * 10..][..32 * 5], - }, - &mut buf2, - )?; - response.push(Advance::MacSignUpdate2 as u8).ok(); - let tag2 = se050.run_command( - &MacGenerateFinal { - mac_id, - data: &plaintext_data[32 * 15..], - }, - &mut buf2, - )?; - response.push(Advance::MacSignFinal as u8).ok(); - assert_eq!(tag2.tag, tag1.tag); - se050.run_command(&DeleteCryptoObj { id: mac_id }, &mut buf)?; - response.push(Advance::MacSignDelete as u8).ok(); - - se050.run_command( - &CreateSignatureObject { - id: mac_id, - subtype: MacAlgo::HmacSha256, - }, - &mut buf, - )?; - response.push(Advance::MacVerifyCreate as u8).ok(); - se050.run_command(&MacValidateInit { key_id, mac_id }, &mut buf)?; - response.push(Advance::MacVerifyInit as u8).ok(); - se050.run_command( - &MacUpdate { - mac_id, - data: &plaintext_data[0..32 * 10], - }, - &mut buf, - )?; - response.push(Advance::MacVerifyUpdate1 as u8).ok(); - se050.run_command( - &MacUpdate { - mac_id, - data: &plaintext_data[32 * 10..][..32 * 5], - }, - &mut buf, - )?; - response.push(Advance::MacVerifyUpdate2 as u8).ok(); - let res2 = se050.run_command( - &MacValidateFinal { - mac_id, - data: &plaintext_data[32 * 15..], - tag: tag2.tag, - }, - &mut buf, - )?; - if res2.result != Se05XResult::Success { - return Err((0x3000 + line!() as u16).into()); + + fn run_symm, const N: usize>( + se050: &mut Se05X, + response: &mut Vec, + ) -> Result<(), Status> { + use se05x::se05x::{ + commands::{ + CipherDecryptInit, CipherEncryptInit, CipherFinal, CipherOneShotDecrypt, + CipherOneShotEncrypt, CipherUpdate, CreateCipherObject, DeleteCryptoObj, + WriteSymmKey, + }, + CipherMode, CryptoObjectId, SymmKeyType, + }; + + let mut buf = [0; 1000]; + let mut buf2 = [0; 1000]; + let plaintext_data = [2; 32 * 15]; + let key_id = ObjectId(hex!("03445566")); + let cipher_id = CryptoObjectId(hex!("0123")); + let key = [0x42; 32]; + let iv = [0xFF; 16]; + se050.run_command( + &WriteSymmKey { + transient: true, + is_auth: false, + key_type: SymmKeyType::Aes, + policy: None, + max_attempts: None, + object_id: key_id, + kek_id: None, + value: &key, + }, + &mut buf, + )?; + response.push(Advance::SymmWrite as u8).ok(); + let ciphertext1 = se050.run_command( + &CipherOneShotEncrypt { + key_id, + mode: CipherMode::AesCtr, + plaintext: &plaintext_data, + initialization_vector: Some(&iv), + }, + &mut buf, + )?; + response.push(Advance::SymmEncryptOneShot as u8).ok(); + let plaintext1 = se050.run_command( + &CipherOneShotDecrypt { + key_id, + mode: CipherMode::AesCtr, + ciphertext: ciphertext1.ciphertext, + initialization_vector: Some(&iv), + }, + &mut buf2, + )?; + response.push(Advance::SymmDecryptOneShot as u8).ok(); + assert_eq!(plaintext1.plaintext, plaintext_data); + se050.run_command( + &CreateCipherObject { + id: cipher_id, + subtype: CipherMode::AesCtr, + }, + &mut buf2, + )?; + response.push(Advance::SymmEncryptCreate as u8).ok(); + se050.run_command( + &CipherEncryptInit { + key_id, + initialization_vector: Some(&iv), + cipher_id, + }, + &mut buf2, + )?; + response.push(Advance::SymmEncryptInit as u8).ok(); + let ciphertext2 = se050.run_command( + &CipherUpdate { + cipher_id, + data: &plaintext_data[0..32 * 10], + }, + &mut buf2, + )?; + if ciphertext2.data != &ciphertext1.ciphertext[0..32 * 10] { + return Err((0x3000 + line!() as u16).into()); + } + response.push(Advance::SymmEncryptUpdate1 as u8).ok(); + let ciphertext3 = se050.run_command( + &CipherUpdate { + cipher_id, + data: &plaintext_data[32 * 10..][..32 * 5], + }, + &mut buf2, + )?; + if ciphertext3.data != &ciphertext1.ciphertext[32 * 10..][..32 * 5] { + return Err((0x3000 + line!() as u16).into()); + } + response.push(Advance::SymmEncryptUpdate2 as u8).ok(); + let ciphertext4 = se050.run_command( + &CipherFinal { + cipher_id, + data: &plaintext_data[32 * 15..], + }, + &mut buf2, + )?; + if ciphertext4.data != &ciphertext1.ciphertext[32 * 15..] { + return Err((0x3000 + line!() as u16).into()); + } + response.push(Advance::SymmEncryptFinal as u8).ok(); + se050.run_command(&DeleteCryptoObj { id: cipher_id }, &mut buf2)?; + response.push(Advance::SymmEncryptDelete as u8).ok(); + se050.run_command( + &CreateCipherObject { + id: cipher_id, + subtype: CipherMode::AesCtr, + }, + &mut buf2, + )?; + response.push(Advance::SymmDecryptCreate as u8).ok(); + se050.run_command( + &CipherDecryptInit { + key_id, + initialization_vector: Some(&iv), + cipher_id, + }, + &mut buf2, + )?; + response.push(Advance::SymmDecryptInit as u8).ok(); + let plaintext1 = se050.run_command( + &CipherUpdate { + cipher_id, + data: &ciphertext1.ciphertext[0..32 * 10], + }, + &mut buf2, + )?; + if plaintext1.data != &plaintext_data[..32 * 10] { + return Err((0x3000 + line!() as u16).into()); + } + response.push(Advance::SymmDecryptUpdate1 as u8).ok(); + let plaintext2 = se050.run_command( + &CipherUpdate { + cipher_id, + data: &ciphertext1.ciphertext[32 * 10..][..32 * 5], + }, + &mut buf2, + )?; + if plaintext2.data != &plaintext_data[32 * 10..][..32 * 5] { + return Err((0x3000 + line!() as u16).into()); + } + response.push(Advance::SymmDecryptUpdate2 as u8).ok(); + let plaintext3 = se050.run_command( + &CipherFinal { + cipher_id, + data: &ciphertext1.ciphertext[32 * 15..], + }, + &mut buf2, + )?; + if plaintext3.data != &plaintext_data[32 * 15..] { + return Err((0x3000 + line!() as u16).into()); + } + response.push(Advance::SymmDecryptFinal as u8).ok(); + se050.run_command(&DeleteCryptoObj { id: cipher_id }, &mut buf2)?; + response.push(Advance::SymmDecryptDelete as u8).ok(); + se050.run_command(&DeleteSecureObject { object_id: key_id }, &mut buf2)?; + response.push(Advance::SymmDelete as u8).ok(); + Ok(()) } - response.push(Advance::MacVerifyFinal as u8).ok(); - se050.run_command(&DeleteCryptoObj { id: mac_id }, &mut buf)?; - response.push(Advance::MacVerifyDelete as u8).ok(); + fn run_mac, const N: usize>( + se050: &mut Se05X, + response: &mut Vec, + ) -> Result<(), Status> { + use se05x::se05x::{ + commands::{ + CreateSignatureObject, DeleteCryptoObj, MacGenerateFinal, MacGenerateInit, + MacOneShotGenerate, MacOneShotValidate, MacUpdate, MacValidateFinal, + MacValidateInit, WriteSymmKey, + }, + CryptoObjectId, MacAlgo, SymmKeyType, + }; + + let mut buf = [0; 1000]; + let mut buf2 = [0; 1000]; + let plaintext_data = [2; 32 * 15]; + let key_id = ObjectId(hex!("03445566")); + let mac_id = CryptoObjectId(hex!("0123")); + let key = [0x42; 32]; + se050.run_command( + &WriteSymmKey { + transient: false, + is_auth: false, + key_type: SymmKeyType::Hmac, + policy: None, + max_attempts: None, + object_id: key_id, + kek_id: None, + value: &key, + }, + &mut buf, + )?; + response.push(Advance::MacWrite as u8).ok(); + let tag1 = se050.run_command( + &MacOneShotGenerate { + key_id, + data: &plaintext_data, + algo: MacAlgo::HmacSha256, + }, + &mut buf, + )?; + response.push(Advance::MacSignOneShot as u8).ok(); + let res = se050.run_command( + &MacOneShotValidate { + key_id, + algo: MacAlgo::HmacSha256, + data: &plaintext_data, + tag: tag1.tag, + }, + &mut buf2, + )?; + response.push(Advance::MacVerifyOneShot as u8).ok(); + if res.result != Se05XResult::Success { + return Err((0x3000 + line!() as u16).into()); + } + se050.run_command( + &CreateSignatureObject { + id: mac_id, + subtype: MacAlgo::HmacSha256, + }, + &mut buf2, + )?; + response.push(Advance::MacSignCreate as u8).ok(); + se050.run_command(&MacGenerateInit { key_id, mac_id }, &mut buf2)?; + response.push(Advance::MacSignInit as u8).ok(); + se050.run_command( + &MacUpdate { + mac_id, + data: &plaintext_data[0..32 * 10], + }, + &mut buf2, + )?; + response.push(Advance::MacSignUpdate1 as u8).ok(); + se050.run_command( + &MacUpdate { + mac_id, + data: &plaintext_data[32 * 10..][..32 * 5], + }, + &mut buf2, + )?; + response.push(Advance::MacSignUpdate2 as u8).ok(); + let tag2 = se050.run_command( + &MacGenerateFinal { + mac_id, + data: &plaintext_data[32 * 15..], + }, + &mut buf2, + )?; + response.push(Advance::MacSignFinal as u8).ok(); + assert_eq!(tag2.tag, tag1.tag); + se050.run_command(&DeleteCryptoObj { id: mac_id }, &mut buf)?; + response.push(Advance::MacSignDelete as u8).ok(); - se050.run_command(&DeleteSecureObject { object_id: key_id }, &mut buf2)?; - response.push(Advance::MacDelete as u8).ok(); - Ok(()) -} + se050.run_command( + &CreateSignatureObject { + id: mac_id, + subtype: MacAlgo::HmacSha256, + }, + &mut buf, + )?; + response.push(Advance::MacVerifyCreate as u8).ok(); + se050.run_command(&MacValidateInit { key_id, mac_id }, &mut buf)?; + response.push(Advance::MacVerifyInit as u8).ok(); + se050.run_command( + &MacUpdate { + mac_id, + data: &plaintext_data[0..32 * 10], + }, + &mut buf, + )?; + response.push(Advance::MacVerifyUpdate1 as u8).ok(); + se050.run_command( + &MacUpdate { + mac_id, + data: &plaintext_data[32 * 10..][..32 * 5], + }, + &mut buf, + )?; + response.push(Advance::MacVerifyUpdate2 as u8).ok(); + let res2 = se050.run_command( + &MacValidateFinal { + mac_id, + data: &plaintext_data[32 * 15..], + tag: tag2.tag, + }, + &mut buf, + )?; + if res2.result != Se05XResult::Success { + return Err((0x3000 + line!() as u16).into()); + } + response.push(Advance::MacVerifyFinal as u8).ok(); -#[cfg(feature = "se050")] -fn run_aes_session, const N: usize>( - se050: &mut Se05X, - response: &mut Vec, -) -> Result<(), Status> { - use rand_chacha::rand_core::SeedableRng; - use se05x::se05x::{ - commands::{CloseSession, WriteSymmKey}, - SymmKeyType, - }; + se050.run_command(&DeleteCryptoObj { id: mac_id }, &mut buf)?; + response.push(Advance::MacVerifyDelete as u8).ok(); - let mut buf = [0; 1024]; - let key = [0x42; 16]; - let key2 = [0x43; 16]; - let key_id = ObjectId(hex!("03445566")); - let bin_id = ObjectId(hex!("03445567")); - let bin_data = hex!("CAFECAFE"); - let key_policy = &[ - Policy { - object_id: key_id, - access_rule: ObjectAccessRule::from_flags(ObjectPolicyFlags::ALLOW_WRITE), - }, - Policy { - object_id: ObjectId::INVALID, - access_rule: ObjectAccessRule::from_flags(ObjectPolicyFlags::ALLOW_DELETE), - }, - ]; - let bin_policy = &[ - Policy { - object_id: key_id, - access_rule: ObjectAccessRule::from_flags(ObjectPolicyFlags::ALLOW_READ), - }, - Policy { - object_id: ObjectId::INVALID, - access_rule: ObjectAccessRule::from_flags(ObjectPolicyFlags::ALLOW_DELETE), - }, - ]; - se050.run_command( - &WriteSymmKey { - transient: false, - is_auth: true, - key_type: SymmKeyType::Aes, - policy: Some(PolicySet(key_policy)), - max_attempts: None, - object_id: key_id, - kek_id: None, - value: &key, - }, - &mut buf, - )?; - response.push(Advance::AesSessionCreateKey as _).ok(); - se050.run_command( - &WriteBinary { - transient: false, - policy: Some(PolicySet(bin_policy)), - object_id: bin_id, - offset: None, - file_length: Some((bin_data.len() as u16).into()), - data: Some(&bin_data), - }, - &mut buf, - )?; - response.push(Advance::AesSessionCreateBinary as _).ok(); - - let session = se050.run_command(&CreateSession { object_id: key_id }, &mut buf)?; - let session_id = session.session_id; - response.push(Advance::AesSessionCreateSession as u8).ok(); - debug_now!("Created session"); - - let mut rng = rand_chacha::ChaCha8Rng::from_seed([0xCA; 32]); - se050.authenticate_aes128_session(session_id, &key, &mut rng)?; - response.push(Advance::AesSessionAuthenticate as u8).ok(); - - let data = se050.run_command( - &ProcessSessionCmd { - session_id, - apdu: ReadObject { - object_id: bin_id, - offset: None, - length: Some((bin_data.len() as u16).into()), - rsa_key_component: None, + se050.run_command(&DeleteSecureObject { object_id: key_id }, &mut buf2)?; + response.push(Advance::MacDelete as u8).ok(); + Ok(()) + } + + fn run_aes_session, const N: usize>( + se050: &mut Se05X, + response: &mut Vec, + ) -> Result<(), Status> { + use rand_chacha::rand_core::SeedableRng; + use se05x::se05x::{ + commands::{CloseSession, WriteSymmKey}, + SymmKeyType, + }; + + let mut buf = [0; 1024]; + let key = [0x42; 16]; + let key2 = [0x43; 16]; + let key_id = ObjectId(hex!("03445566")); + let bin_id = ObjectId(hex!("03445567")); + let bin_data = hex!("CAFECAFE"); + let key_policy = &[ + Policy { + object_id: key_id, + access_rule: ObjectAccessRule::from_flags(ObjectPolicyFlags::ALLOW_WRITE), }, - }, - &mut buf, - )?; - assert_eq!(data.data, &bin_data); - response.push(Advance::AesSessionReadBinary as _).ok(); - - se050.run_command( - &ProcessSessionCmd { - session_id, - apdu: WriteSymmKey { + Policy { + object_id: ObjectId::INVALID, + access_rule: ObjectAccessRule::from_flags(ObjectPolicyFlags::ALLOW_DELETE), + }, + ]; + let bin_policy = &[ + Policy { + object_id: key_id, + access_rule: ObjectAccessRule::from_flags(ObjectPolicyFlags::ALLOW_READ), + }, + Policy { + object_id: ObjectId::INVALID, + access_rule: ObjectAccessRule::from_flags(ObjectPolicyFlags::ALLOW_DELETE), + }, + ]; + se050.run_command( + &WriteSymmKey { transient: false, is_auth: true, key_type: SymmKeyType::Aes, - policy: None, + policy: Some(PolicySet(key_policy)), max_attempts: None, object_id: key_id, kek_id: None, - value: &key2, + value: &key, }, - }, - &mut buf, - )?; - response.push(Advance::AesSessionUpdateKey as _).ok(); - - se050.run_command( - &ProcessSessionCmd { - session_id, - apdu: CloseSession {}, - }, - &mut buf, - )?; - response.push(Advance::AesSessionCloseSession as _).ok(); - - let session = se050.run_command(&CreateSession { object_id: key_id }, &mut buf)?; - let session_id = session.session_id; - response.push(Advance::AesSessionRecreateSession as u8).ok(); - debug_now!("Created session"); - - let mut rng = rand_chacha::ChaCha8Rng::from_seed([0xCA; 32]); - se050.authenticate_aes128_session(session_id, &key2, &mut rng)?; - response.push(Advance::AesSessionReAuthenticate as u8).ok(); - - let data = se050.run_command( - &ProcessSessionCmd { - session_id, - apdu: ReadObject { + &mut buf, + )?; + response.push(Advance::AesSessionCreateKey as _).ok(); + se050.run_command( + &WriteBinary { + transient: false, + policy: Some(PolicySet(bin_policy)), object_id: bin_id, offset: None, - length: Some((bin_data.len() as u16).into()), - rsa_key_component: None, + file_length: Some((bin_data.len() as u16).into()), + data: Some(&bin_data), }, - }, - &mut buf, - )?; - assert_eq!(data.data, &bin_data); - response.push(Advance::AesSessionReadBinary2 as _).ok(); + &mut buf, + )?; + response.push(Advance::AesSessionCreateBinary as _).ok(); + + let session = se050.run_command(&CreateSession { object_id: key_id }, &mut buf)?; + let session_id = session.session_id; + response.push(Advance::AesSessionCreateSession as u8).ok(); + debug_now!("Created session"); + + let mut rng = rand_chacha::ChaCha8Rng::from_seed([0xCA; 32]); + se050.authenticate_aes128_session(session_id, &key, &mut rng)?; + response.push(Advance::AesSessionAuthenticate as u8).ok(); + + let data = se050.run_command( + &ProcessSessionCmd { + session_id, + apdu: ReadObject { + object_id: bin_id, + offset: None, + length: Some((bin_data.len() as u16).into()), + rsa_key_component: None, + }, + }, + &mut buf, + )?; + assert_eq!(data.data, &bin_data); + response.push(Advance::AesSessionReadBinary as _).ok(); - se050.run_command(&DeleteSecureObject { object_id: bin_id }, &mut buf)?; - response.push(Advance::AesSessionDeleteBinary as _).ok(); - se050.run_command(&DeleteSecureObject { object_id: key_id }, &mut buf)?; - response.push(Advance::AesSessionDeleteKey as _).ok(); + se050.run_command( + &ProcessSessionCmd { + session_id, + apdu: WriteSymmKey { + transient: false, + is_auth: true, + key_type: SymmKeyType::Aes, + policy: None, + max_attempts: None, + object_id: key_id, + kek_id: None, + value: &key2, + }, + }, + &mut buf, + )?; + response.push(Advance::AesSessionUpdateKey as _).ok(); - Ok(()) -} + se050.run_command( + &ProcessSessionCmd { + session_id, + apdu: CloseSession {}, + }, + &mut buf, + )?; + response.push(Advance::AesSessionCloseSession as _).ok(); + + let session = se050.run_command(&CreateSession { object_id: key_id }, &mut buf)?; + let session_id = session.session_id; + response.push(Advance::AesSessionRecreateSession as u8).ok(); + debug_now!("Created session"); + + let mut rng = rand_chacha::ChaCha8Rng::from_seed([0xCA; 32]); + se050.authenticate_aes128_session(session_id, &key2, &mut rng)?; + response.push(Advance::AesSessionReAuthenticate as u8).ok(); + + let data = se050.run_command( + &ProcessSessionCmd { + session_id, + apdu: ReadObject { + object_id: bin_id, + offset: None, + length: Some((bin_data.len() as u16).into()), + rsa_key_component: None, + }, + }, + &mut buf, + )?; + assert_eq!(data.data, &bin_data); + response.push(Advance::AesSessionReadBinary2 as _).ok(); -#[cfg(feature = "se050")] -fn run_pbkdf, const N: usize>( - se050: &mut Se05X, - response: &mut Vec, -) -> Result<(), Status> { - use se05x::se05x::{ - commands::{Pbkdf2, WriteSymmKey}, - SymmKeyType, - }; + se050.run_command(&DeleteSecureObject { object_id: bin_id }, &mut buf)?; + response.push(Advance::AesSessionDeleteBinary as _).ok(); + se050.run_command(&DeleteSecureObject { object_id: key_id }, &mut buf)?; + response.push(Advance::AesSessionDeleteKey as _).ok(); - let mut buf = [0; 1024]; - let pin = b"123456"; - let salt = [0x42; 16]; - let pin_id = ObjectId(hex!("03445566")); - - se050.run_command( - &WriteSymmKey { - transient: true, - is_auth: false, - key_type: SymmKeyType::Hmac, - policy: None, - max_attempts: None, - object_id: pin_id, - kek_id: None, - value: pin, - }, - &mut buf, - )?; + Ok(()) + } - response.push(Advance::Pbkdf2WritePin as u8).ok(); + fn run_pbkdf, const N: usize>( + se050: &mut Se05X, + response: &mut Vec, + ) -> Result<(), Status> { + use se05x::se05x::{ + commands::{Pbkdf2, WriteSymmKey}, + SymmKeyType, + }; - let res = se050.run_command( - &Pbkdf2 { - password: pin_id, - salt: Some(&salt), - iterations: 32.into(), - requested_len: 16.into(), - }, - &mut buf, - )?; - response.push(Advance::Pbkdf2Calculate as u8).ok(); + let mut buf = [0; 1024]; + let pin = b"123456"; + let salt = [0x42; 16]; + let pin_id = ObjectId(hex!("03445566")); - if res.data != hex!("685126241d909137ecd3385eaea2725f") { - debug_now!("Got HASH: {:02x?}", res.data); - return Err(Status::CorruptedData); - } - response.push(Advance::Pbkdf2Compare as u8).ok(); + se050.run_command( + &WriteSymmKey { + transient: true, + is_auth: false, + key_type: SymmKeyType::Hmac, + policy: None, + max_attempts: None, + object_id: pin_id, + kek_id: None, + value: pin, + }, + &mut buf, + )?; - se050.run_command(&DeleteSecureObject { object_id: pin_id }, &mut buf)?; - response.push(Advance::Pbkdf2DeletePin as u8).ok(); + response.push(Advance::Pbkdf2WritePin as u8).ok(); - Ok(()) -} + let res = se050.run_command( + &Pbkdf2 { + password: pin_id, + salt: Some(&salt), + iterations: 32.into(), + requested_len: 16.into(), + }, + &mut buf, + )?; + response.push(Advance::Pbkdf2Calculate as u8).ok(); -#[cfg(feature = "se050")] -fn run_export_import, const N: usize>( - se050: &mut Se05X, - response: &mut Vec, -) -> Result<(), Status> { - use se05x::se05x::{ - commands::{CipherOneShotEncrypt, ExportObject, ImportObject, WriteSymmKey}, - CipherMode, RsaKeyComponent, SymmKeyType, - }; + if res.data != hex!("685126241d909137ecd3385eaea2725f") { + debug_now!("Got HASH: {:02x?}", res.data); + return Err(Status::CorruptedData); + } + response.push(Advance::Pbkdf2Compare as u8).ok(); - let mut buf = [0; 128]; - let mut buf2 = [0; 1000]; - let mut buf3 = [0; 1000]; - let plaintext_data = [2; 32]; - let key_id = ObjectId(hex!("03445566")); - let key = [0x42; 32]; - let iv = [0xFF; 16]; - let policy = &[ - Policy { - object_id: ObjectId::INVALID, - access_rule: ObjectAccessRule::from_flags( - ObjectPolicyFlags::ALLOW_WRITE - | ObjectPolicyFlags::ALLOW_ENC - | ObjectPolicyFlags::ALLOW_DELETE - | ObjectPolicyFlags::ALLOW_IMPORT_EXPORT, - ), - }, - Policy { - object_id: ObjectId::INVALID, - access_rule: ObjectAccessRule::from_flags(ObjectPolicyFlags::ALLOW_DELETE), - }, - ]; - se050.run_command( - &WriteSymmKey { - transient: true, - is_auth: false, - key_type: SymmKeyType::Aes, - policy: Some(PolicySet(policy)), - max_attempts: None, - object_id: key_id, - kek_id: None, - value: &key, - }, - &mut buf, - )?; - response.push(Advance::ImportWrite as u8).ok(); - let ciphertext1 = se050.run_command( - &CipherOneShotEncrypt { - key_id, - mode: CipherMode::AesCtr, - plaintext: &plaintext_data, - initialization_vector: Some(&iv), - }, - &mut buf, - )?; - response.push(Advance::ImportCipher as u8).ok(); - - debug_now!("Exporting"); - let exported = se050 - .run_command( - &ExportObject { + se050.run_command(&DeleteSecureObject { object_id: pin_id }, &mut buf)?; + response.push(Advance::Pbkdf2DeletePin as u8).ok(); + + Ok(()) + } + + fn run_export_import, const N: usize>( + se050: &mut Se05X, + response: &mut Vec, + ) -> Result<(), Status> { + use se05x::se05x::{ + commands::{CipherOneShotEncrypt, ExportObject, ImportObject, WriteSymmKey}, + CipherMode, RsaKeyComponent, SymmKeyType, + }; + + let mut buf = [0; 128]; + let mut buf2 = [0; 1000]; + let mut buf3 = [0; 1000]; + let plaintext_data = [2; 32]; + let key_id = ObjectId(hex!("03445566")); + let key = [0x42; 32]; + let iv = [0xFF; 16]; + let policy = &[ + Policy { + object_id: ObjectId::INVALID, + access_rule: ObjectAccessRule::from_flags( + ObjectPolicyFlags::ALLOW_WRITE + | ObjectPolicyFlags::ALLOW_ENC + | ObjectPolicyFlags::ALLOW_DELETE + | ObjectPolicyFlags::ALLOW_IMPORT_EXPORT, + ), + }, + Policy { + object_id: ObjectId::INVALID, + access_rule: ObjectAccessRule::from_flags(ObjectPolicyFlags::ALLOW_DELETE), + }, + ]; + se050.run_command( + &WriteSymmKey { + transient: true, + is_auth: false, + key_type: SymmKeyType::Aes, + policy: Some(PolicySet(policy)), + max_attempts: None, object_id: key_id, - rsa_key_component: RsaKeyComponent::Na, + kek_id: None, + value: &key, }, - &mut buf2, - ) - .map_err(|_err| { - debug_now!("Got err: {:?}", _err); - _err - })?; - response.push(Advance::ImportExport as u8).ok(); - - se050.enable()?; - response.push(Advance::ImportDelete as u8).ok(); - - let res = se050.run_command( - &CipherOneShotEncrypt { - key_id, - mode: CipherMode::AesCtr, - plaintext: &plaintext_data, - initialization_vector: Some(&iv), - }, - &mut buf3, - ); - if !matches!( - res, - Err(se05x::se05x::Error::Status( - Status::ConditionsOfUseNotSatisfied, - )) - ) { - return Err((0x3000 + line!() as u16).into()); - } - response.push(Advance::ImportDeletionWorked as u8).ok(); - - debug_now!("Importing"); - se050.run_command( - &ImportObject { - transient: true, - object_id: key_id, - rsa_key_component: None, - serialized_object: exported.data, - }, - &mut buf3, - )?; - response.push(Advance::ImportImport as u8).ok(); - - debug_now!("Encrypting"); - let ciphertext2 = se050.run_command( - &CipherOneShotEncrypt { - key_id, - mode: CipherMode::AesCtr, - plaintext: &plaintext_data, - initialization_vector: Some(&iv), - }, - &mut buf3, - )?; - response.push(Advance::ImportCipher2 as u8).ok(); + &mut buf, + )?; + response.push(Advance::ImportWrite as u8).ok(); + let ciphertext1 = se050.run_command( + &CipherOneShotEncrypt { + key_id, + mode: CipherMode::AesCtr, + plaintext: &plaintext_data, + initialization_vector: Some(&iv), + }, + &mut buf, + )?; + response.push(Advance::ImportCipher as u8).ok(); + + debug_now!("Exporting"); + let exported = se050 + .run_command( + &ExportObject { + object_id: key_id, + rsa_key_component: RsaKeyComponent::Na, + }, + &mut buf2, + ) + .map_err(|_err| { + debug_now!("Got err: {:?}", _err); + _err + })?; + response.push(Advance::ImportExport as u8).ok(); + + se050.enable()?; + response.push(Advance::ImportDelete as u8).ok(); - debug_now!("Comparing"); - if ciphertext1.ciphertext != ciphertext2.ciphertext { - return Err((0x3000 + line!() as u16).into()); - } - response.push(Advance::ImportComp as u8).ok(); + let res = se050.run_command( + &CipherOneShotEncrypt { + key_id, + mode: CipherMode::AesCtr, + plaintext: &plaintext_data, + initialization_vector: Some(&iv), + }, + &mut buf3, + ); + if !matches!( + res, + Err(se05x::se05x::Error::Status( + Status::ConditionsOfUseNotSatisfied, + )) + ) { + return Err((0x3000 + line!() as u16).into()); + } + response.push(Advance::ImportDeletionWorked as u8).ok(); - se050.run_command(&DeleteSecureObject { object_id: key_id }, &mut buf3)?; - response.push(Advance::ImportDeleteFinal as u8).ok(); - Ok(()) + debug_now!("Importing"); + se050.run_command( + &ImportObject { + transient: true, + object_id: key_id, + rsa_key_component: None, + serialized_object: exported.data, + }, + &mut buf3, + )?; + response.push(Advance::ImportImport as u8).ok(); + + debug_now!("Encrypting"); + let ciphertext2 = se050.run_command( + &CipherOneShotEncrypt { + key_id, + mode: CipherMode::AesCtr, + plaintext: &plaintext_data, + initialization_vector: Some(&iv), + }, + &mut buf3, + )?; + response.push(Advance::ImportCipher2 as u8).ok(); + + debug_now!("Comparing"); + if ciphertext1.ciphertext != ciphertext2.ciphertext { + return Err((0x3000 + line!() as u16).into()); + } + response.push(Advance::ImportComp as u8).ok(); + + se050.run_command(&DeleteSecureObject { object_id: key_id }, &mut buf3)?; + response.push(Advance::ImportDeleteFinal as u8).ok(); + Ok(()) + } }