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

Rsa import #94

Merged
merged 21 commits into from
Nov 18, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
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
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