Skip to content

Commit 0de848d

Browse files
Merge pull request #94 from Nitrokey/rsa-import
Rsa import
2 parents 0293e62 + f5485a2 commit 0de848d

File tree

12 files changed

+1548
-107
lines changed

12 files changed

+1548
-107
lines changed

Cargo.toml

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,9 @@ hex = { version = "0.4", features = ["serde"] }
5353
[features]
5454
std = []
5555
virtual = ["std", "vpicc"]
56+
rsa2048 = ["trussed/rsa2048"]
57+
rsa4096 = ["rsa2048", "trussed/rsa4096"]
58+
rsa4096-gen = ["rsa4096"]
5659

5760
# used for delog
5861
log-all = []
@@ -63,9 +66,17 @@ log-warn = []
6366
log-error = []
6467

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

7075
[package.metadata.docs.rs]
7176
all-features = true
77+
78+
[profile.dev.package.rsa]
79+
opt-level = 2
80+
81+
[profile.dev.package.num-bigint-dig]
82+
opt-level = 2

Makefile

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ FUZZ_DURATION?="0"
1111
.PHONY: check
1212
check:
1313
cargo check --all-features --all-targets --workspace
14-
cargo check --no-default-features
14+
cargo check --no-default-features --all-targets
1515
cargo clippy --all-features --all-targets -- --deny warnings
1616
cargo fmt -- --check
1717
RUSTDOCFLAGS='-Dwarnings' cargo doc --all-features --package opcard
@@ -24,7 +24,8 @@ fix:
2424

2525
.PHONY: test
2626
test:
27-
cargo test --features virtual
27+
cargo test --features virtual,rsa2048,rsa4096-gen gpg_crypto,sequoia_gen_key
28+
cargo test --features virtual,rsa2048,rsa4096
2829

2930
.PHONY: fuzz
3031
fuzz: fuzz-corpus
@@ -45,7 +46,7 @@ fuzz-cov:
4546

4647
.PHONY: tarpaulin
4748
tarpaulin:
48-
cargo tarpaulin --features virtual -o Html -o Xml
49+
cargo tarpaulin --features virtual,rsa4096-gen -o Html -o Xml
4950

5051
.PHONY: ci
5152
ci: check tarpaulin

src/command/data.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1300,15 +1300,15 @@ mod tests {
13001300
(DataObject::ExtendedCapabilities, &EXTENDED_CAPABILITIES),
13011301
(
13021302
DataObject::AlgorithmAttributesSignature,
1303-
SignatureAlgorithm::Rsa2k.attributes(),
1303+
SignatureAlgorithm::Rsa2048.attributes(),
13041304
),
13051305
(
13061306
DataObject::AlgorithmAttributesDecryption,
1307-
DecryptionAlgorithm::Rsa2k.attributes(),
1307+
DecryptionAlgorithm::Rsa2048.attributes(),
13081308
),
13091309
(
13101310
DataObject::AlgorithmAttributesAuthentication,
1311-
AuthenticationAlgorithm::Rsa2k.attributes(),
1311+
AuthenticationAlgorithm::Rsa2048.attributes(),
13121312
),
13131313
(
13141314
DataObject::PwStatusBytes,

src/command/gen.rs

Lines changed: 133 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
use hex_literal::hex;
55
use iso7816::Status;
6-
use trussed::types::{KeyId, KeySerialization, Location, StorageAttributes};
6+
use trussed::types::{KeyId, KeySerialization, Location, Mechanism, StorageAttributes};
77
use trussed::{syscall, try_syscall};
88

99
use crate::card::LoadedContext;
@@ -34,9 +34,14 @@ pub fn sign<const R: usize, T: trussed::Client>(
3434
SignatureAlgorithm::EcDsaP256 => {
3535
gen_ec_key(ctx.lend(), KeyType::Sign, CurveAlgo::EcDsaP256)
3636
}
37-
_ => {
38-
error!("Unimplemented operation");
39-
Err(Status::ConditionsOfUseNotSatisfied)
37+
SignatureAlgorithm::Rsa2048 => {
38+
gen_rsa_key(ctx.lend(), KeyType::Sign, Mechanism::Rsa2048Pkcs)
39+
}
40+
SignatureAlgorithm::Rsa4096 => {
41+
#[cfg(feature = "rsa4096-gen")]
42+
return gen_rsa_key(ctx.lend(), KeyType::Sign, Mechanism::Rsa4096Pkcs);
43+
#[cfg(not(feature = "rsa4096-gen"))]
44+
return Err(Status::FunctionNotSupported);
4045
}
4146
}
4247
}
@@ -49,9 +54,14 @@ pub fn dec<const R: usize, T: trussed::Client>(
4954
match algo {
5055
DecryptionAlgorithm::X255 => gen_ec_key(ctx.lend(), KeyType::Dec, CurveAlgo::X255),
5156
DecryptionAlgorithm::EcDhP256 => gen_ec_key(ctx.lend(), KeyType::Dec, CurveAlgo::EcDhP256),
52-
_ => {
53-
error!("Unimplemented operation");
54-
Err(Status::ConditionsOfUseNotSatisfied)
57+
DecryptionAlgorithm::Rsa2048 => {
58+
gen_rsa_key(ctx.lend(), KeyType::Dec, Mechanism::Rsa2048Pkcs)
59+
}
60+
DecryptionAlgorithm::Rsa4096 => {
61+
#[cfg(feature = "rsa4096-gen")]
62+
return gen_rsa_key(ctx.lend(), KeyType::Dec, Mechanism::Rsa4096Pkcs);
63+
#[cfg(not(feature = "rsa4096-gen"))]
64+
return Err(Status::FunctionNotSupported);
5565
}
5666
}
5767
}
@@ -66,13 +76,51 @@ pub fn aut<const R: usize, T: trussed::Client>(
6676
AuthenticationAlgorithm::EcDsaP256 => {
6777
gen_ec_key(ctx.lend(), KeyType::Aut, CurveAlgo::EcDsaP256)
6878
}
69-
_ => {
70-
error!("Unimplemented operation");
71-
Err(Status::ConditionsOfUseNotSatisfied)
79+
AuthenticationAlgorithm::Rsa2048 => {
80+
gen_rsa_key(ctx.lend(), KeyType::Aut, Mechanism::Rsa2048Pkcs)
81+
}
82+
AuthenticationAlgorithm::Rsa4096 => {
83+
#[cfg(feature = "rsa4096-gen")]
84+
return gen_rsa_key(ctx.lend(), KeyType::Aut, Mechanism::Rsa4096Pkcs);
85+
#[cfg(not(feature = "rsa4096-gen"))]
86+
return Err(Status::FunctionNotSupported);
7287
}
7388
}
7489
}
7590

91+
#[cfg(feature = "rsa2048")]
92+
fn gen_rsa_key<const R: usize, T: trussed::Client>(
93+
ctx: LoadedContext<'_, R, T>,
94+
key: KeyType,
95+
mechanism: Mechanism,
96+
) -> Result<(), Status> {
97+
let client = ctx.backend.client_mut();
98+
let key_id = try_syscall!(client.generate_key(
99+
mechanism,
100+
StorageAttributes::new().set_persistence(Location::Internal)
101+
))
102+
.map_err(|_err| {
103+
error!("Failed to generate key: {_err:?}");
104+
Status::UnspecifiedNonpersistentExecutionError
105+
})?
106+
.key;
107+
108+
if let Some((old_key, _)) = ctx
109+
.state
110+
.internal
111+
.set_key_id(key, Some((key_id, KeyOrigin::Generated)), client)
112+
.map_err(|_| Status::UnspecifiedNonpersistentExecutionError)?
113+
{
114+
// Deletion is not a fatal error
115+
try_syscall!(client.delete(old_key))
116+
.inspect_err_stable(|_err| {
117+
error!("Failed to delete old key: {_err:?}");
118+
})
119+
.ok();
120+
}
121+
read_rsa_key(ctx, key_id, mechanism)
122+
}
123+
76124
fn gen_ec_key<const R: usize, T: trussed::Client>(
77125
ctx: LoadedContext<'_, R, T>,
78126
key: KeyType,
@@ -117,10 +165,8 @@ pub fn read_sign<const R: usize, T: trussed::Client>(
117165
match algo {
118166
SignatureAlgorithm::Ed255 => read_ec_key(ctx.lend(), key_id, CurveAlgo::Ed255),
119167
SignatureAlgorithm::EcDsaP256 => read_ec_key(ctx.lend(), key_id, CurveAlgo::EcDsaP256),
120-
_ => {
121-
error!("Unimplemented operation");
122-
Err(Status::ConditionsOfUseNotSatisfied)
123-
}
168+
SignatureAlgorithm::Rsa2048 => read_rsa_key(ctx.lend(), key_id, Mechanism::Rsa2048Pkcs),
169+
SignatureAlgorithm::Rsa4096 => read_rsa_key(ctx.lend(), key_id, Mechanism::Rsa4096Pkcs),
124170
}
125171
}
126172

@@ -137,10 +183,8 @@ pub fn read_dec<const R: usize, T: trussed::Client>(
137183
match algo {
138184
DecryptionAlgorithm::X255 => read_ec_key(ctx.lend(), key_id, CurveAlgo::X255),
139185
DecryptionAlgorithm::EcDhP256 => read_ec_key(ctx.lend(), key_id, CurveAlgo::EcDhP256),
140-
_ => {
141-
error!("Unimplemented operation");
142-
Err(Status::ConditionsOfUseNotSatisfied)
143-
}
186+
DecryptionAlgorithm::Rsa2048 => read_rsa_key(ctx.lend(), key_id, Mechanism::Rsa2048Pkcs),
187+
DecryptionAlgorithm::Rsa4096 => read_rsa_key(ctx.lend(), key_id, Mechanism::Rsa4096Pkcs),
144188
}
145189
}
146190

@@ -157,9 +201,11 @@ pub fn read_aut<const R: usize, T: trussed::Client>(
157201
match algo {
158202
AuthenticationAlgorithm::Ed255 => read_ec_key(ctx.lend(), key_id, CurveAlgo::Ed255),
159203
AuthenticationAlgorithm::EcDsaP256 => read_ec_key(ctx.lend(), key_id, CurveAlgo::EcDsaP256),
160-
_ => {
161-
error!("Unimplemented operation");
162-
Err(Status::ConditionsOfUseNotSatisfied)
204+
AuthenticationAlgorithm::Rsa2048 => {
205+
read_rsa_key(ctx.lend(), key_id, Mechanism::Rsa2048Pkcs)
206+
}
207+
AuthenticationAlgorithm::Rsa4096 => {
208+
read_rsa_key(ctx.lend(), key_id, Mechanism::Rsa4096Pkcs)
163209
}
164210
}
165211
}
@@ -210,3 +256,69 @@ fn read_ec_key<const R: usize, T: trussed::Client>(
210256
serialize_pub(curve, ctx.lend(), &serialized)?;
211257
ctx.reply.prepend_len(offset)
212258
}
259+
260+
#[cfg(feature = "rsa2048")]
261+
fn read_rsa_key<const R: usize, T: trussed::Client>(
262+
mut ctx: LoadedContext<'_, R, T>,
263+
key_id: KeyId,
264+
mechanism: Mechanism,
265+
) -> Result<(), Status> {
266+
let client = ctx.backend.client_mut();
267+
let public_key = syscall!(client.derive_key(
268+
mechanism,
269+
key_id,
270+
None,
271+
StorageAttributes::new().set_persistence(Location::Volatile)
272+
))
273+
.key;
274+
ctx.reply.expand(KEYGEN_DO_TAG)?;
275+
let offset = ctx.reply.len();
276+
277+
let serialized_n =
278+
try_syscall!(client.serialize_key(mechanism, public_key, KeySerialization::RsaN))
279+
.map_err(|_err| {
280+
error!("Failed to serialize public key N: {_err:?}");
281+
syscall!(client.delete(public_key));
282+
Status::UnspecifiedNonpersistentExecutionError
283+
})?
284+
.serialized_key;
285+
ctx.reply.expand(&[0x81])?;
286+
ctx.reply.append_len(serialized_n.len())?;
287+
ctx.reply.expand(&serialized_n)?;
288+
drop(serialized_n);
289+
290+
let serialized_e =
291+
try_syscall!(client.serialize_key(mechanism, public_key, KeySerialization::RsaE))
292+
.map_err(|_err| {
293+
error!("Failed to serialize public key E: {_err:?}");
294+
syscall!(client.delete(public_key));
295+
Status::UnspecifiedNonpersistentExecutionError
296+
})?
297+
.serialized_key;
298+
ctx.reply.expand(&[0x82])?;
299+
ctx.reply.append_len(serialized_e.len())?;
300+
ctx.reply.expand(&serialized_e)?;
301+
302+
ctx.reply.prepend_len(offset)?;
303+
304+
syscall!(client.delete(public_key));
305+
Ok(())
306+
}
307+
308+
#[cfg(not(feature = "rsa2048"))]
309+
fn gen_rsa_key<const R: usize, T: trussed::Client>(
310+
_ctx: LoadedContext<'_, R, T>,
311+
_key: KeyType,
312+
_mechanism: Mechanism,
313+
) -> Result<(), Status> {
314+
Err(Status::FunctionNotSupported)
315+
}
316+
317+
#[cfg(not(feature = "rsa2048"))]
318+
fn read_rsa_key<const R: usize, T: trussed::Client>(
319+
_ctx: LoadedContext<'_, R, T>,
320+
_key_id: KeyId,
321+
_mechanism: Mechanism,
322+
) -> Result<(), Status> {
323+
Err(Status::FunctionNotSupported)
324+
}

0 commit comments

Comments
 (0)