Skip to content

Commit

Permalink
Merge pull request #94 from Nitrokey/rsa-import
Browse files Browse the repository at this point in the history
Rsa import
  • Loading branch information
sosthene-nitrokey committed Nov 18, 2022
2 parents 0293e62 + f5485a2 commit 0de848d
Show file tree
Hide file tree
Showing 12 changed files with 1,548 additions and 107 deletions.
13 changes: 12 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@ hex = { version = "0.4", features = ["serde"] }
[features]
std = []
virtual = ["std", "vpicc"]
rsa2048 = ["trussed/rsa2048"]
rsa4096 = ["rsa2048", "trussed/rsa4096"]
rsa4096-gen = ["rsa4096"]

# used for delog
log-all = []
Expand All @@ -63,9 +66,17 @@ log-warn = []
log-error = []

[patch.crates-io]
trussed = { git = "https://github.com/trussed-dev/trussed" , rev = "6de826f3bcbef247e55fd890d80d9ed6ce9f0abc" }
# trussed = { git = "https://github.com/trussed-dev/trussed" , rev = "6de826f3bcbef247e55fd890d80d9ed6ce9f0abc" }
trussed = { git = "https://github.com/nitrokey/trussed" , branch = "rsa-import" }
littlefs2-sys = { git = "https://github.com/sosthene-nitrokey/littlefs2-sys.git", branch = "bindgen-runtime-feature" }
interchange = { git = "https://github.com/trussed-dev/interchange.git", rev = "fe5633466640e1e9a8c06d9b5dd1d0af08c272af" }
p256-cortex-m4 = { git = "https://github.com/sosthene-nitrokey/p256-cortex-m4.git", branch = "upgrade" }

[package.metadata.docs.rs]
all-features = true

[profile.dev.package.rsa]
opt-level = 2

[profile.dev.package.num-bigint-dig]
opt-level = 2
7 changes: 4 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ FUZZ_DURATION?="0"
.PHONY: check
check:
cargo check --all-features --all-targets --workspace
cargo check --no-default-features
cargo check --no-default-features --all-targets
cargo clippy --all-features --all-targets -- --deny warnings
cargo fmt -- --check
RUSTDOCFLAGS='-Dwarnings' cargo doc --all-features --package opcard
Expand All @@ -24,7 +24,8 @@ fix:

.PHONY: test
test:
cargo test --features virtual
cargo test --features virtual,rsa2048,rsa4096-gen gpg_crypto,sequoia_gen_key
cargo test --features virtual,rsa2048,rsa4096

.PHONY: fuzz
fuzz: fuzz-corpus
Expand All @@ -45,7 +46,7 @@ fuzz-cov:

.PHONY: tarpaulin
tarpaulin:
cargo tarpaulin --features virtual -o Html -o Xml
cargo tarpaulin --features virtual,rsa4096-gen -o Html -o Xml

.PHONY: ci
ci: check tarpaulin
Expand Down
6 changes: 3 additions & 3 deletions src/command/data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1300,15 +1300,15 @@ mod tests {
(DataObject::ExtendedCapabilities, &EXTENDED_CAPABILITIES),
(
DataObject::AlgorithmAttributesSignature,
SignatureAlgorithm::Rsa2k.attributes(),
SignatureAlgorithm::Rsa2048.attributes(),
),
(
DataObject::AlgorithmAttributesDecryption,
DecryptionAlgorithm::Rsa2k.attributes(),
DecryptionAlgorithm::Rsa2048.attributes(),
),
(
DataObject::AlgorithmAttributesAuthentication,
AuthenticationAlgorithm::Rsa2k.attributes(),
AuthenticationAlgorithm::Rsa2048.attributes(),
),
(
DataObject::PwStatusBytes,
Expand Down
154 changes: 133 additions & 21 deletions src/command/gen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

use hex_literal::hex;
use iso7816::Status;
use trussed::types::{KeyId, KeySerialization, Location, StorageAttributes};
use trussed::types::{KeyId, KeySerialization, Location, Mechanism, StorageAttributes};
use trussed::{syscall, try_syscall};

use crate::card::LoadedContext;
Expand Down Expand Up @@ -34,9 +34,14 @@ pub fn sign<const R: usize, T: trussed::Client>(
SignatureAlgorithm::EcDsaP256 => {
gen_ec_key(ctx.lend(), KeyType::Sign, CurveAlgo::EcDsaP256)
}
_ => {
error!("Unimplemented operation");
Err(Status::ConditionsOfUseNotSatisfied)
SignatureAlgorithm::Rsa2048 => {
gen_rsa_key(ctx.lend(), KeyType::Sign, Mechanism::Rsa2048Pkcs)
}
SignatureAlgorithm::Rsa4096 => {
#[cfg(feature = "rsa4096-gen")]
return gen_rsa_key(ctx.lend(), KeyType::Sign, Mechanism::Rsa4096Pkcs);
#[cfg(not(feature = "rsa4096-gen"))]
return Err(Status::FunctionNotSupported);
}
}
}
Expand All @@ -49,9 +54,14 @@ pub fn dec<const R: usize, T: trussed::Client>(
match algo {
DecryptionAlgorithm::X255 => gen_ec_key(ctx.lend(), KeyType::Dec, CurveAlgo::X255),
DecryptionAlgorithm::EcDhP256 => gen_ec_key(ctx.lend(), KeyType::Dec, CurveAlgo::EcDhP256),
_ => {
error!("Unimplemented operation");
Err(Status::ConditionsOfUseNotSatisfied)
DecryptionAlgorithm::Rsa2048 => {
gen_rsa_key(ctx.lend(), KeyType::Dec, Mechanism::Rsa2048Pkcs)
}
DecryptionAlgorithm::Rsa4096 => {
#[cfg(feature = "rsa4096-gen")]
return gen_rsa_key(ctx.lend(), KeyType::Dec, Mechanism::Rsa4096Pkcs);
#[cfg(not(feature = "rsa4096-gen"))]
return Err(Status::FunctionNotSupported);
}
}
}
Expand All @@ -66,13 +76,51 @@ pub fn aut<const R: usize, T: trussed::Client>(
AuthenticationAlgorithm::EcDsaP256 => {
gen_ec_key(ctx.lend(), KeyType::Aut, CurveAlgo::EcDsaP256)
}
_ => {
error!("Unimplemented operation");
Err(Status::ConditionsOfUseNotSatisfied)
AuthenticationAlgorithm::Rsa2048 => {
gen_rsa_key(ctx.lend(), KeyType::Aut, Mechanism::Rsa2048Pkcs)
}
AuthenticationAlgorithm::Rsa4096 => {
#[cfg(feature = "rsa4096-gen")]
return gen_rsa_key(ctx.lend(), KeyType::Aut, Mechanism::Rsa4096Pkcs);
#[cfg(not(feature = "rsa4096-gen"))]
return Err(Status::FunctionNotSupported);
}
}
}

#[cfg(feature = "rsa2048")]
fn gen_rsa_key<const R: usize, T: trussed::Client>(
ctx: LoadedContext<'_, R, T>,
key: KeyType,
mechanism: Mechanism,
) -> Result<(), Status> {
let client = ctx.backend.client_mut();
let key_id = try_syscall!(client.generate_key(
mechanism,
StorageAttributes::new().set_persistence(Location::Internal)
))
.map_err(|_err| {
error!("Failed to generate key: {_err:?}");
Status::UnspecifiedNonpersistentExecutionError
})?
.key;

if let Some((old_key, _)) = ctx
.state
.internal
.set_key_id(key, Some((key_id, KeyOrigin::Generated)), client)
.map_err(|_| Status::UnspecifiedNonpersistentExecutionError)?
{
// Deletion is not a fatal error
try_syscall!(client.delete(old_key))
.inspect_err_stable(|_err| {
error!("Failed to delete old key: {_err:?}");
})
.ok();
}
read_rsa_key(ctx, key_id, mechanism)
}

fn gen_ec_key<const R: usize, T: trussed::Client>(
ctx: LoadedContext<'_, R, T>,
key: KeyType,
Expand Down Expand Up @@ -117,10 +165,8 @@ pub fn read_sign<const R: usize, T: trussed::Client>(
match algo {
SignatureAlgorithm::Ed255 => read_ec_key(ctx.lend(), key_id, CurveAlgo::Ed255),
SignatureAlgorithm::EcDsaP256 => read_ec_key(ctx.lend(), key_id, CurveAlgo::EcDsaP256),
_ => {
error!("Unimplemented operation");
Err(Status::ConditionsOfUseNotSatisfied)
}
SignatureAlgorithm::Rsa2048 => read_rsa_key(ctx.lend(), key_id, Mechanism::Rsa2048Pkcs),
SignatureAlgorithm::Rsa4096 => read_rsa_key(ctx.lend(), key_id, Mechanism::Rsa4096Pkcs),
}
}

Expand All @@ -137,10 +183,8 @@ pub fn read_dec<const R: usize, T: trussed::Client>(
match algo {
DecryptionAlgorithm::X255 => read_ec_key(ctx.lend(), key_id, CurveAlgo::X255),
DecryptionAlgorithm::EcDhP256 => read_ec_key(ctx.lend(), key_id, CurveAlgo::EcDhP256),
_ => {
error!("Unimplemented operation");
Err(Status::ConditionsOfUseNotSatisfied)
}
DecryptionAlgorithm::Rsa2048 => read_rsa_key(ctx.lend(), key_id, Mechanism::Rsa2048Pkcs),
DecryptionAlgorithm::Rsa4096 => read_rsa_key(ctx.lend(), key_id, Mechanism::Rsa4096Pkcs),
}
}

Expand All @@ -157,9 +201,11 @@ pub fn read_aut<const R: usize, T: trussed::Client>(
match algo {
AuthenticationAlgorithm::Ed255 => read_ec_key(ctx.lend(), key_id, CurveAlgo::Ed255),
AuthenticationAlgorithm::EcDsaP256 => read_ec_key(ctx.lend(), key_id, CurveAlgo::EcDsaP256),
_ => {
error!("Unimplemented operation");
Err(Status::ConditionsOfUseNotSatisfied)
AuthenticationAlgorithm::Rsa2048 => {
read_rsa_key(ctx.lend(), key_id, Mechanism::Rsa2048Pkcs)
}
AuthenticationAlgorithm::Rsa4096 => {
read_rsa_key(ctx.lend(), key_id, Mechanism::Rsa4096Pkcs)
}
}
}
Expand Down Expand Up @@ -210,3 +256,69 @@ fn read_ec_key<const R: usize, T: trussed::Client>(
serialize_pub(curve, ctx.lend(), &serialized)?;
ctx.reply.prepend_len(offset)
}

#[cfg(feature = "rsa2048")]
fn read_rsa_key<const R: usize, T: trussed::Client>(
mut ctx: LoadedContext<'_, R, T>,
key_id: KeyId,
mechanism: Mechanism,
) -> Result<(), Status> {
let client = ctx.backend.client_mut();
let public_key = syscall!(client.derive_key(
mechanism,
key_id,
None,
StorageAttributes::new().set_persistence(Location::Volatile)
))
.key;
ctx.reply.expand(KEYGEN_DO_TAG)?;
let offset = ctx.reply.len();

let serialized_n =
try_syscall!(client.serialize_key(mechanism, public_key, KeySerialization::RsaN))
.map_err(|_err| {
error!("Failed to serialize public key N: {_err:?}");
syscall!(client.delete(public_key));
Status::UnspecifiedNonpersistentExecutionError
})?
.serialized_key;
ctx.reply.expand(&[0x81])?;
ctx.reply.append_len(serialized_n.len())?;
ctx.reply.expand(&serialized_n)?;
drop(serialized_n);

let serialized_e =
try_syscall!(client.serialize_key(mechanism, public_key, KeySerialization::RsaE))
.map_err(|_err| {
error!("Failed to serialize public key E: {_err:?}");
syscall!(client.delete(public_key));
Status::UnspecifiedNonpersistentExecutionError
})?
.serialized_key;
ctx.reply.expand(&[0x82])?;
ctx.reply.append_len(serialized_e.len())?;
ctx.reply.expand(&serialized_e)?;

ctx.reply.prepend_len(offset)?;

syscall!(client.delete(public_key));
Ok(())
}

#[cfg(not(feature = "rsa2048"))]
fn gen_rsa_key<const R: usize, T: trussed::Client>(
_ctx: LoadedContext<'_, R, T>,
_key: KeyType,
_mechanism: Mechanism,
) -> Result<(), Status> {
Err(Status::FunctionNotSupported)
}

#[cfg(not(feature = "rsa2048"))]
fn read_rsa_key<const R: usize, T: trussed::Client>(
_ctx: LoadedContext<'_, R, T>,
_key_id: KeyId,
_mechanism: Mechanism,
) -> Result<(), Status> {
Err(Status::FunctionNotSupported)
}
Loading

0 comments on commit 0de848d

Please sign in to comment.