Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make RSA key size support a runtime configuration #190

Merged
merged 2 commits into from
Nov 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
46 changes: 46 additions & 0 deletions src/card.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -158,6 +159,38 @@ impl<T: Client, const C: usize, const R: usize> apdu_dispatch::App<C, R> 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]
Expand All @@ -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
Expand Down Expand Up @@ -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,
}
Expand Down Expand Up @@ -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;
Expand Down
75 changes: 37 additions & 38 deletions src/command/gen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::*;

Expand Down Expand Up @@ -37,28 +37,25 @@ pub fn sign<const R: usize, T: crate::card::Client>(
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)
}
Expand All @@ -75,28 +72,25 @@ pub fn dec<const R: usize, T: crate::card::Client>(
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)
}
Expand All @@ -115,36 +109,33 @@ pub fn aut<const R: usize, T: crate::card::Client>(
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)
}
}
}
}

#[cfg(feature = "rsa2048-gen")]
#[cfg(feature = "rsa")]
fn gen_rsa_key<const R: usize, T: crate::card::Client>(
mut ctx: LoadedContext<'_, R, T>,
key: KeyType,
Expand Down Expand Up @@ -182,6 +173,14 @@ fn gen_rsa_key<const R: usize, T: crate::card::Client>(
.map_err(|_| Status::UnspecifiedNonpersistentExecutionError)?;
read_rsa_key(ctx, pubkey, mechanism)
}
#[cfg(not(feature = "rsa"))]
fn gen_rsa_key<const R: usize, T: crate::card::Client>(
_ctx: LoadedContext<'_, R, T>,
_key: KeyType,
_mechanism: Mechanism,
) -> Result<(), Status> {
Err(Status::FunctionNotSupported)
}

fn gen_ec_key<const R: usize, T: crate::card::Client>(
mut ctx: LoadedContext<'_, R, T>,
Expand Down
50 changes: 40 additions & 10 deletions src/command/private_key_template.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::*;
Expand Down Expand Up @@ -43,9 +43,19 @@ pub fn put_sign<const R: usize, T: crate::card::Client>(
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
Expand All @@ -69,9 +79,19 @@ pub fn put_dec<const R: usize, T: crate::card::Client>(
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
Expand All @@ -95,9 +115,19 @@ pub fn put_aut<const R: usize, T: crate::card::Client>(
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
Expand Down