diff --git a/Cargo.toml b/Cargo.toml index 8b668e7..869eae5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -42,6 +42,7 @@ admin-app = { version = "0.1.0", optional = true } apdu-dispatch = { version = "0.1", optional = true } delog = { version = "0.1.7", optional = true } vpicc = { version = "0.1.0", optional = true } +cfg-if = "1.0.0" [dev-dependencies] env_logger = "0.9" diff --git a/src/card.rs b/src/card.rs index 24c2700..f48a194 100644 --- a/src/card.rs +++ b/src/card.rs @@ -3,6 +3,7 @@ #[cfg(feature = "admin-app")] use admin_app::{ResetSignal, ResetSignalAllocation}; +use cfg_if::cfg_if; use hex_literal::hex; use iso7816::Status; use trussed::types::Location; @@ -158,6 +159,38 @@ impl apdu_dispatch::App for Car } } +#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)] +pub enum RsaKeySizes { + Rsa2048, + Rsa3072, + Rsa4096, +} + +impl RsaKeySizes { + fn default_max_gen() -> Self { + cfg_if! { + if #[cfg(feature = "rsa4096-gen")] { + Self::Rsa4096 + } else if #[cfg(feature = "rsa3072-gen")] { + Self::Rsa3072 + } else { + Self::Rsa2048 + } + } + } + fn default_max_import() -> Self { + cfg_if! { + if #[cfg(feature = "rsa4096")] { + Self::Rsa4096 + } else if #[cfg(feature = "rsa3072")] { + Self::Rsa3072 + } else { + Self::Rsa2048 + } + } + } +} + /// Options for the OpenPGP card. #[derive(Clone, Debug)] #[non_exhaustive] @@ -176,6 +209,12 @@ pub struct Options { /// Which trussed storage to use pub storage: Location, + /// Max RSA size allowed to be imported + pub rsa_max_import: RsaKeySizes, + + /// Max RSA size allowed to be generated + pub rsa_max_gen: RsaKeySizes, + /// Flag to signal that the application has had its configuration changed or was factory-resetted by the admin application /// /// Requires the feature-flag admin-app @@ -219,6 +258,8 @@ impl Default for Options { historical_bytes: heapless::Vec::from_slice(&hex!("0031F573C00160009000")).unwrap(), button_available: true, storage: Location::External, + rsa_max_import: RsaKeySizes::default_max_import(), + rsa_max_gen: RsaKeySizes::default_max_gen(), #[cfg(feature = "admin-app")] reset_signal: None, } @@ -301,6 +342,11 @@ mod tests { hex!("D2 76 00 01 24 01 03 04 00 00 00 00 00 00 00 00"), ) } + + #[test] + fn key_sizes() { + assert!(RsaKeySizes::Rsa2048 < RsaKeySizes::Rsa4096); + } } use trussed_staging::wrap_key_to_file::WrapKeyToFileClient; diff --git a/src/command/gen.rs b/src/command/gen.rs index beb7bc0..d08490e 100644 --- a/src/command/gen.rs +++ b/src/command/gen.rs @@ -6,7 +6,7 @@ use iso7816::Status; use trussed::try_syscall; use trussed::types::{KeyId, KeySerialization, Location, Mechanism, StorageAttributes}; -use crate::card::LoadedContext; +use crate::card::{LoadedContext, RsaKeySizes}; use crate::state::KeyOrigin; use crate::types::*; @@ -37,28 +37,25 @@ pub fn sign( gen_ec_key(ctx.lend(), KeyType::Sign, CurveAlgo::EcDsaP256) } SignatureAlgorithm::Rsa2048 => { - #[cfg(feature = "rsa2048-gen")] - return gen_rsa_key(ctx.lend(), KeyType::Sign, Mechanism::Rsa2048Pkcs1v15); - #[cfg(not(feature = "rsa2048-gen"))] - { + if ctx.options.rsa_max_gen >= RsaKeySizes::Rsa2048 { + gen_rsa_key(ctx.lend(), KeyType::Sign, Mechanism::Rsa2048Pkcs1v15) + } else { warn!("Attempt to generate key disabled {:?}", algo); Err(Status::FunctionNotSupported) } } SignatureAlgorithm::Rsa3072 => { - #[cfg(feature = "rsa3072-gen")] - return gen_rsa_key(ctx.lend(), KeyType::Sign, Mechanism::Rsa3072Pkcs1v15); - #[cfg(not(feature = "rsa3072-gen"))] - { + if ctx.options.rsa_max_gen >= RsaKeySizes::Rsa3072 { + gen_rsa_key(ctx.lend(), KeyType::Sign, Mechanism::Rsa3072Pkcs1v15) + } else { warn!("Attempt to generate key disabled {:?}", algo); Err(Status::FunctionNotSupported) } } SignatureAlgorithm::Rsa4096 => { - #[cfg(feature = "rsa4096-gen")] - return gen_rsa_key(ctx.lend(), KeyType::Sign, Mechanism::Rsa4096Pkcs1v15); - #[cfg(not(feature = "rsa4096-gen"))] - { + if ctx.options.rsa_max_gen >= RsaKeySizes::Rsa4096 { + gen_rsa_key(ctx.lend(), KeyType::Sign, Mechanism::Rsa4096Pkcs1v15) + } else { warn!("Attempt to generate key disabled {:?}", algo); Err(Status::FunctionNotSupported) } @@ -75,28 +72,25 @@ pub fn dec( DecryptionAlgorithm::X255 => gen_ec_key(ctx.lend(), KeyType::Dec, CurveAlgo::X255), DecryptionAlgorithm::EcDhP256 => gen_ec_key(ctx.lend(), KeyType::Dec, CurveAlgo::EcDhP256), DecryptionAlgorithm::Rsa2048 => { - #[cfg(feature = "rsa2048-gen")] - return gen_rsa_key(ctx.lend(), KeyType::Dec, Mechanism::Rsa2048Pkcs1v15); - #[cfg(not(feature = "rsa2048-gen"))] - { + if ctx.options.rsa_max_gen >= RsaKeySizes::Rsa2048 { + gen_rsa_key(ctx.lend(), KeyType::Dec, Mechanism::Rsa2048Pkcs1v15) + } else { warn!("Attempt to generate key disabled {:?}", algo); Err(Status::FunctionNotSupported) } } DecryptionAlgorithm::Rsa3072 => { - #[cfg(feature = "rsa3072-gen")] - return gen_rsa_key(ctx.lend(), KeyType::Dec, Mechanism::Rsa3072Pkcs1v15); - #[cfg(not(feature = "rsa3072-gen"))] - { + if ctx.options.rsa_max_gen >= RsaKeySizes::Rsa3072 { + gen_rsa_key(ctx.lend(), KeyType::Dec, Mechanism::Rsa3072Pkcs1v15) + } else { warn!("Attempt to generate key disabled {:?}", algo); Err(Status::FunctionNotSupported) } } DecryptionAlgorithm::Rsa4096 => { - #[cfg(feature = "rsa4096-gen")] - return gen_rsa_key(ctx.lend(), KeyType::Dec, Mechanism::Rsa4096Pkcs1v15); - #[cfg(not(feature = "rsa4096-gen"))] - { + if ctx.options.rsa_max_gen >= RsaKeySizes::Rsa4096 { + gen_rsa_key(ctx.lend(), KeyType::Dec, Mechanism::Rsa4096Pkcs1v15) + } else { warn!("Attempt to generate key disabled {:?}", algo); Err(Status::FunctionNotSupported) } @@ -115,28 +109,25 @@ pub fn aut( gen_ec_key(ctx.lend(), KeyType::Aut, CurveAlgo::EcDsaP256) } AuthenticationAlgorithm::Rsa2048 => { - #[cfg(feature = "rsa2048-gen")] - return gen_rsa_key(ctx.lend(), KeyType::Aut, Mechanism::Rsa2048Pkcs1v15); - #[cfg(not(feature = "rsa2048-gen"))] - { + if ctx.options.rsa_max_gen >= RsaKeySizes::Rsa2048 { + gen_rsa_key(ctx.lend(), KeyType::Aut, Mechanism::Rsa2048Pkcs1v15) + } else { warn!("Attempt to generate key disabled {:?}", algo); Err(Status::FunctionNotSupported) } } AuthenticationAlgorithm::Rsa3072 => { - #[cfg(feature = "rsa3072-gen")] - return gen_rsa_key(ctx.lend(), KeyType::Aut, Mechanism::Rsa3072Pkcs1v15); - #[cfg(not(feature = "rsa3072-gen"))] - { + if ctx.options.rsa_max_gen >= RsaKeySizes::Rsa3072 { + gen_rsa_key(ctx.lend(), KeyType::Aut, Mechanism::Rsa3072Pkcs1v15) + } else { warn!("Attempt to generate key disabled {:?}", algo); Err(Status::FunctionNotSupported) } } AuthenticationAlgorithm::Rsa4096 => { - #[cfg(feature = "rsa4096-gen")] - return gen_rsa_key(ctx.lend(), KeyType::Aut, Mechanism::Rsa4096Pkcs1v15); - #[cfg(not(feature = "rsa4096-gen"))] - { + if ctx.options.rsa_max_gen >= RsaKeySizes::Rsa4096 { + gen_rsa_key(ctx.lend(), KeyType::Aut, Mechanism::Rsa4096Pkcs1v15) + } else { warn!("Attempt to generate key disabled {:?}", algo); Err(Status::FunctionNotSupported) } @@ -144,7 +135,7 @@ pub fn aut( } } -#[cfg(feature = "rsa2048-gen")] +#[cfg(feature = "rsa")] fn gen_rsa_key( mut ctx: LoadedContext<'_, R, T>, key: KeyType, @@ -182,6 +173,14 @@ fn gen_rsa_key( .map_err(|_| Status::UnspecifiedNonpersistentExecutionError)?; read_rsa_key(ctx, pubkey, mechanism) } +#[cfg(not(feature = "rsa"))] +fn gen_rsa_key( + _ctx: LoadedContext<'_, R, T>, + _key: KeyType, + _mechanism: Mechanism, +) -> Result<(), Status> { + Err(Status::FunctionNotSupported) +} fn gen_ec_key( mut ctx: LoadedContext<'_, R, T>, diff --git a/src/command/private_key_template.rs b/src/command/private_key_template.rs index f8534ff..c3cca2a 100644 --- a/src/command/private_key_template.rs +++ b/src/command/private_key_template.rs @@ -5,7 +5,7 @@ use iso7816::Status; use trussed::try_syscall; use trussed::types::{KeyId, KeySerialization, Location, Mechanism, StorageAttributes}; -use crate::card::LoadedContext; +use crate::card::{LoadedContext, RsaKeySizes}; use crate::state::KeyOrigin; use crate::tlv::get_do; use crate::types::*; @@ -43,9 +43,19 @@ pub fn put_sign( let key_id = match attr { SignatureAlgorithm::EcDsaP256 => put_ec(ctx.lend(), CurveAlgo::EcDsaP256)?, SignatureAlgorithm::Ed255 => put_ec(ctx.lend(), CurveAlgo::Ed255)?, - SignatureAlgorithm::Rsa2048 => put_rsa(ctx.lend(), Mechanism::Rsa2048Pkcs1v15)?, - SignatureAlgorithm::Rsa3072 => put_rsa(ctx.lend(), Mechanism::Rsa3072Pkcs1v15)?, - SignatureAlgorithm::Rsa4096 => put_rsa(ctx.lend(), Mechanism::Rsa4096Pkcs1v15)?, + SignatureAlgorithm::Rsa2048 if ctx.options.rsa_max_import >= RsaKeySizes::Rsa2048 => { + put_rsa(ctx.lend(), Mechanism::Rsa2048Pkcs1v15)? + } + SignatureAlgorithm::Rsa3072 if ctx.options.rsa_max_import >= RsaKeySizes::Rsa3072 => { + put_rsa(ctx.lend(), Mechanism::Rsa3072Pkcs1v15)? + } + SignatureAlgorithm::Rsa4096 if ctx.options.rsa_max_import >= RsaKeySizes::Rsa4096 => { + put_rsa(ctx.lend(), Mechanism::Rsa4096Pkcs1v15)? + } + _ => { + warn!("Attempt to import key disabled {:?}", attr); + return Err(Status::FunctionNotSupported); + } } .map(|(private_key, pubkey)| (private_key, (pubkey, KeyOrigin::Imported))); ctx.state @@ -69,9 +79,19 @@ pub fn put_dec( let key_id = match attr { DecryptionAlgorithm::EcDhP256 => put_ec(ctx.lend(), CurveAlgo::EcDhP256)?, DecryptionAlgorithm::X255 => put_ec(ctx.lend(), CurveAlgo::X255)?, - DecryptionAlgorithm::Rsa2048 => put_rsa(ctx.lend(), Mechanism::Rsa2048Pkcs1v15)?, - DecryptionAlgorithm::Rsa3072 => put_rsa(ctx.lend(), Mechanism::Rsa3072Pkcs1v15)?, - DecryptionAlgorithm::Rsa4096 => put_rsa(ctx.lend(), Mechanism::Rsa4096Pkcs1v15)?, + DecryptionAlgorithm::Rsa2048 if ctx.options.rsa_max_import >= RsaKeySizes::Rsa2048 => { + put_rsa(ctx.lend(), Mechanism::Rsa2048Pkcs1v15)? + } + DecryptionAlgorithm::Rsa3072 if ctx.options.rsa_max_import >= RsaKeySizes::Rsa3072 => { + put_rsa(ctx.lend(), Mechanism::Rsa3072Pkcs1v15)? + } + DecryptionAlgorithm::Rsa4096 if ctx.options.rsa_max_import >= RsaKeySizes::Rsa4096 => { + put_rsa(ctx.lend(), Mechanism::Rsa4096Pkcs1v15)? + } + _ => { + warn!("Attempt to import key disabled {:?}", attr); + return Err(Status::FunctionNotSupported); + } } .map(|(private_key, pubkey)| (private_key, (pubkey, KeyOrigin::Imported))); ctx.state @@ -95,9 +115,19 @@ pub fn put_aut( let key_id = match attr { AuthenticationAlgorithm::EcDsaP256 => put_ec(ctx.lend(), CurveAlgo::EcDsaP256)?, AuthenticationAlgorithm::Ed255 => put_ec(ctx.lend(), CurveAlgo::Ed255)?, - AuthenticationAlgorithm::Rsa2048 => put_rsa(ctx.lend(), Mechanism::Rsa2048Pkcs1v15)?, - AuthenticationAlgorithm::Rsa3072 => put_rsa(ctx.lend(), Mechanism::Rsa3072Pkcs1v15)?, - AuthenticationAlgorithm::Rsa4096 => put_rsa(ctx.lend(), Mechanism::Rsa4096Pkcs1v15)?, + AuthenticationAlgorithm::Rsa2048 if ctx.options.rsa_max_import >= RsaKeySizes::Rsa2048 => { + put_rsa(ctx.lend(), Mechanism::Rsa2048Pkcs1v15)? + } + AuthenticationAlgorithm::Rsa3072 if ctx.options.rsa_max_import >= RsaKeySizes::Rsa3072 => { + put_rsa(ctx.lend(), Mechanism::Rsa3072Pkcs1v15)? + } + AuthenticationAlgorithm::Rsa4096 if ctx.options.rsa_max_import >= RsaKeySizes::Rsa4096 => { + put_rsa(ctx.lend(), Mechanism::Rsa4096Pkcs1v15)? + } + _ => { + warn!("Attempt to import key disabled {:?}", attr); + return Err(Status::FunctionNotSupported); + } } .map(|(private_key, public_key)| (private_key, (public_key, KeyOrigin::Imported))); ctx.state