From 29096438b67a44533b787eafd5aa168571c5e599 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= Date: Thu, 6 Oct 2022 10:19:15 +0200 Subject: [PATCH 01/47] Update postcard dependency --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index dc58005c732..b7d1199a7b7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,7 +20,7 @@ generic-array = "0.14.4" heapless = { version = "0.7", features = ["serde"] } hex-literal = "0.3.1" nb = "1" -postcard = "0.7.0" +postcard = "1.0.2" rand_core = "0.6" serde = { version = "1.0", default-features = false } zeroize = { version = "1.2", default-features = false, features = ["zeroize_derive"] } From e64e1f1c947a1541db1fdaeca33e03c70c754ee2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= Date: Thu, 6 Oct 2022 10:39:04 +0200 Subject: [PATCH 02/47] Update aes dependency and replace block-modes by cbc --- Cargo.toml | 4 ++-- src/mechanisms/aes256cbc.rs | 24 ++++++++++++------------ tests/aes256cbc.rs | 9 +++++---- 3 files changed, 19 insertions(+), 18 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index b7d1199a7b7..cf01c02421e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,9 +26,9 @@ serde = { version = "1.0", default-features = false } zeroize = { version = "1.2", default-features = false, features = ["zeroize_derive"] } # RustCrypto -aes = { version = "0.7", default-features = false } +aes = { version = "0.8", default-features = false } +cbc = "0.1.2" blake2 = { version = "0.9", default-features = false, optional = true } -block-modes = { version = "0.8", default-features = false } chacha20 = { version = "0.7", default-features = false, features = ["rng"] } chacha20poly1305 = { version = "0.8", default-features = false, features = ["heapless", "reduced-round"] } des = { version = "0.7", optional = true } diff --git a/src/mechanisms/aes256cbc.rs b/src/mechanisms/aes256cbc.rs index d2af12a4ae2..da4c584eaf2 100644 --- a/src/mechanisms/aes256cbc.rs +++ b/src/mechanisms/aes256cbc.rs @@ -13,13 +13,11 @@ impl Encrypt for super::Aes256Cbc { keystore: &mut impl Keystore, request: &request::Encrypt, ) -> Result { - use block_modes::{BlockMode, Cbc}; - // use block_modes::Cbc; use aes::Aes256; - use block_modes::block_padding::ZeroPadding; + use cbc::cipher::{block_padding::ZeroPadding, BlockEncryptMut, KeyIvInit}; + type Aes256CbcEnc = cbc::Encryptor; // TODO: perhaps use NoPadding and have client pad, to emphasize spec-conformance? - type Aes256Cbc = Cbc; let key_id = request.key; let key = keystore.load_key(key::Secrecy::Secret, None, &key_id)?; @@ -34,7 +32,7 @@ impl Encrypt for super::Aes256Cbc { .map_err(|_| Error::InternalError)?; let zero_iv = [0u8; 16]; - let cipher = Aes256Cbc::new_from_slices(&symmetric_key, &zero_iv).unwrap(); + let cipher = Aes256CbcEnc::new_from_slices(&symmetric_key, &zero_iv).unwrap(); // buffer must have enough space for message+padding let mut buffer = request.message.clone(); @@ -47,7 +45,9 @@ impl Encrypt for super::Aes256Cbc { // Encrypt message in-place. // &buffer[..pos] is used as a message and &buffer[pos..] as a reserved space for padding. // The padding space should be big enough for padding, otherwise method will return Err(BlockModeError). - let ciphertext = cipher.encrypt(&mut buffer, l).unwrap(); + let ciphertext = cipher + .encrypt_padded_mut::(&mut buffer, l) + .unwrap(); let ciphertext = Message::from_slice(ciphertext).unwrap(); Ok(reply::Encrypt { @@ -99,13 +99,11 @@ impl Decrypt for super::Aes256Cbc { keystore: &mut impl Keystore, request: &request::Decrypt, ) -> Result { - use block_modes::{BlockMode, Cbc}; - // use block_modes::Cbc; use aes::Aes256; - use block_modes::block_padding::ZeroPadding; + use cbc::cipher::{block_padding::ZeroPadding, BlockDecryptMut, KeyIvInit}; // TODO: perhaps use NoPadding and have client pad, to emphasize spec-conformance? - type Aes256Cbc = Cbc; + type Aes256CbcDec = cbc::Decryptor; let key_id = request.key; let key = keystore.load_key(key::Secrecy::Secret, None, &key_id)?; @@ -120,7 +118,7 @@ impl Decrypt for super::Aes256Cbc { .map_err(|_| Error::InternalError)?; let zero_iv = [0u8; 16]; - let cipher = Aes256Cbc::new_from_slices(&symmetric_key, &zero_iv).unwrap(); + let cipher = Aes256CbcDec::new_from_slices(&symmetric_key, &zero_iv).unwrap(); // buffer must have enough space for message+padding let mut buffer = request.message.clone(); @@ -134,7 +132,9 @@ impl Decrypt for super::Aes256Cbc { // if after decoding message has malformed padding. // hprintln!("encrypted: {:?}", &buffer).ok(); // hprintln!("symmetric key: {:?}", &symmetric_key).ok(); - let plaintext = cipher.decrypt(&mut buffer).unwrap(); + let plaintext = cipher + .decrypt_padded_mut::(&mut buffer) + .unwrap(); // hprintln!("decrypted: {:?}", &plaintext).ok(); let plaintext = Message::from_slice(plaintext).unwrap(); diff --git a/tests/aes256cbc.rs b/tests/aes256cbc.rs index 6fc34510a86..91af2b5b22b 100644 --- a/tests/aes256cbc.rs +++ b/tests/aes256cbc.rs @@ -9,8 +9,7 @@ use trussed::types::Location::*; use trussed::types::{Mechanism, StorageAttributes}; use aes::Aes256; -use block_modes::block_padding::ZeroPadding; -use block_modes::{BlockMode, Cbc}; +use cbc::cipher::{block_padding::ZeroPadding, BlockEncryptMut, KeyIvInit}; use sha2::digest::Digest; #[test] @@ -25,9 +24,11 @@ fn aes256cbc() { let hash = sha2::Sha256::new(); let key_ref = hash.finalize(); - let cipher = Cbc::::new_from_slices(&key_ref, &[0; 16]).unwrap(); + let cipher = cbc::Encryptor::::new_from_slices(&key_ref, &[0; 16]).unwrap(); let mut buffer = [48; 64]; - cipher.encrypt(&mut buffer, 64).unwrap(); + cipher + .encrypt_padded_mut::(&mut buffer, 64) + .unwrap(); assert_ne!(buffer, [48; 64]); assert_eq!(buffer.as_slice(), *ciphertext); From ccbcf68e9b6cf52126232e477e475a47a43bbd1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= Date: Thu, 6 Oct 2022 10:56:50 +0200 Subject: [PATCH 03/47] Update chacha dependency The `rng` feature is replaced by rand_chacha --- Cargo.toml | 5 +++-- src/mechanisms/chacha8poly1305.rs | 8 ++++---- src/service.rs | 4 ++-- src/store/certstore.rs | 2 +- src/store/counterstore.rs | 2 +- src/store/keystore.rs | 2 +- src/tests.rs | 3 ++- src/virt.rs | 2 +- 8 files changed, 15 insertions(+), 13 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index cf01c02421e..52166bc8a01 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,13 +24,14 @@ postcard = "1.0.2" rand_core = "0.6" serde = { version = "1.0", default-features = false } zeroize = { version = "1.2", default-features = false, features = ["zeroize_derive"] } +rand_chacha = { version = "0.3.1", default-features = false } # RustCrypto aes = { version = "0.8", default-features = false } cbc = "0.1.2" blake2 = { version = "0.9", default-features = false, optional = true } -chacha20 = { version = "0.7", default-features = false, features = ["rng"] } -chacha20poly1305 = { version = "0.8", default-features = false, features = ["heapless", "reduced-round"] } +chacha20 = { version = "0.9", default-features = false } +chacha20poly1305 = { version = "0.10", default-features = false, features = ["heapless", "reduced-round"] } des = { version = "0.7", optional = true } hmac = "0.11" sha-1 = { version = "0.9", default-features = false, optional = true } diff --git a/src/mechanisms/chacha8poly1305.rs b/src/mechanisms/chacha8poly1305.rs index 10ee607559a..2c097184633 100644 --- a/src/mechanisms/chacha8poly1305.rs +++ b/src/mechanisms/chacha8poly1305.rs @@ -58,7 +58,7 @@ impl Decrypt for super::Chacha8Poly1305 { keystore: &mut impl Keystore, request: &request::Decrypt, ) -> Result { - use chacha20poly1305::aead::{AeadInPlace, NewAead}; + use chacha20poly1305::aead::{AeadMutInPlace, KeyInit}; use chacha20poly1305::ChaCha8Poly1305; let serialized_material = keystore @@ -77,7 +77,7 @@ impl Decrypt for super::Chacha8Poly1305 { let symmetric_key = &serialized[..32]; - let aead = ChaCha8Poly1305::new(&GenericArray::clone_from_slice(symmetric_key)); + let mut aead = ChaCha8Poly1305::new(&GenericArray::clone_from_slice(symmetric_key)); let mut plaintext = request.message.clone(); let nonce = GenericArray::from_slice(&request.nonce); @@ -107,7 +107,7 @@ impl Encrypt for super::Chacha8Poly1305 { keystore: &mut impl Keystore, request: &request::Encrypt, ) -> Result { - use chacha20poly1305::aead::{AeadInPlace, NewAead}; + use chacha20poly1305::aead::{AeadMutInPlace, KeyInit}; use chacha20poly1305::ChaCha8Poly1305; // load key and nonce @@ -144,7 +144,7 @@ impl Encrypt for super::Chacha8Poly1305 { }; // keep in state? - let aead = ChaCha8Poly1305::new(&GenericArray::clone_from_slice(symmetric_key)); + let mut aead = ChaCha8Poly1305::new(&GenericArray::clone_from_slice(symmetric_key)); let mut ciphertext = request.message.clone(); let tag: [u8; 16] = aead diff --git a/src/service.rs b/src/service.rs index fafc4c3c53f..cb2ec77f6fb 100644 --- a/src/service.rs +++ b/src/service.rs @@ -1,7 +1,7 @@ -use chacha20::ChaCha8Rng; use heapless_bytes::Unsigned; use interchange::Responder; use littlefs2::path::PathBuf; +use rand_chacha::ChaCha8Rng; pub use rand_core::{RngCore, SeedableRng}; use crate::api::*; @@ -635,7 +635,7 @@ impl ServiceResources

{ } // 3. Initialize ChaCha8 construction with our seed. - let mut rng = chacha20::ChaCha8Rng::from_seed(our_seed); + let mut rng = ChaCha8Rng::from_seed(our_seed); // 4. Store freshly drawn seed for next boot. let mut seed_to_store = [0u8; 32]; diff --git a/src/store/certstore.rs b/src/store/certstore.rs index 38637eaeeb5..fc9476a3e29 100644 --- a/src/store/certstore.rs +++ b/src/store/certstore.rs @@ -1,5 +1,5 @@ -use chacha20::ChaCha8Rng; use littlefs2::path::PathBuf; +use rand_chacha::ChaCha8Rng; use crate::{ error::{Error, Result}, diff --git a/src/store/counterstore.rs b/src/store/counterstore.rs index 4db24b623d8..a0922612246 100644 --- a/src/store/counterstore.rs +++ b/src/store/counterstore.rs @@ -1,5 +1,5 @@ -use chacha20::ChaCha8Rng; use littlefs2::path::PathBuf; +use rand_chacha::ChaCha8Rng; use crate::{ error::{Error, Result}, diff --git a/src/store/keystore.rs b/src/store/keystore.rs index aea1c6b6c01..050fa037610 100644 --- a/src/store/keystore.rs +++ b/src/store/keystore.rs @@ -1,5 +1,5 @@ -use chacha20::ChaCha8Rng; use littlefs2::path::PathBuf; +use rand_chacha::ChaCha8Rng; use crate::{ error::{Error, Result}, diff --git a/src/tests.rs b/src/tests.rs index a83d5921bda..c6dbccf93ea 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -14,7 +14,8 @@ pub struct MockRng(ChaCha20); impl MockRng { pub fn new() -> Self { - use chacha20::cipher::NewCipher; + use chacha20::cipher::KeyIvInit; + let key = GenericArray::from_slice(b"an example very very secret key."); let nonce = GenericArray::from_slice(b"secret nonce"); Self(ChaCha20::new(&key, &nonce)) diff --git a/src/virt.rs b/src/virt.rs index 6661c7e84b7..2091a48dba9 100644 --- a/src/virt.rs +++ b/src/virt.rs @@ -8,7 +8,7 @@ mod ui; use std::{path::PathBuf, sync::Mutex}; -use chacha20::ChaCha8Rng; +use rand_chacha::ChaCha8Rng; use rand_core::SeedableRng as _; use crate::{ From 31957a57f726d2d1c024ccc00320794712af4bd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= Date: Thu, 6 Oct 2022 11:05:29 +0200 Subject: [PATCH 04/47] Update des dependency --- Cargo.toml | 2 +- src/mechanisms/tdes.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 52166bc8a01..33fcd9ae44d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -32,7 +32,7 @@ cbc = "0.1.2" blake2 = { version = "0.9", default-features = false, optional = true } chacha20 = { version = "0.9", default-features = false } chacha20poly1305 = { version = "0.10", default-features = false, features = ["heapless", "reduced-round"] } -des = { version = "0.7", optional = true } +des = { version = "0.8", optional = true } hmac = "0.11" sha-1 = { version = "0.9", default-features = false, optional = true } sha2 = { version = "0.9", default-features = false } diff --git a/src/mechanisms/tdes.rs b/src/mechanisms/tdes.rs index 245ad92c627..5734c1ba7af 100644 --- a/src/mechanisms/tdes.rs +++ b/src/mechanisms/tdes.rs @@ -6,7 +6,7 @@ // use cortex_m_semihosting::{dbg, hprintln}; // needed to even get ::new() from des... -use des::cipher::{BlockDecrypt, BlockEncrypt, NewBlockCipher}; +use des::cipher::{BlockDecrypt, BlockEncrypt, KeyInit}; use crate::api::*; use crate::error::Error; From 142d199716d590d418cab80cc0762d9281263963 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= Date: Thu, 6 Oct 2022 11:06:45 +0200 Subject: [PATCH 05/47] Update blake2 dependency --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 33fcd9ae44d..33bb6c00142 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,7 +29,7 @@ rand_chacha = { version = "0.3.1", default-features = false } # RustCrypto aes = { version = "0.8", default-features = false } cbc = "0.1.2" -blake2 = { version = "0.9", default-features = false, optional = true } +blake2 = { version = "0.10", default-features = false, optional = true } chacha20 = { version = "0.9", default-features = false } chacha20poly1305 = { version = "0.10", default-features = false, features = ["heapless", "reduced-round"] } des = { version = "0.8", optional = true } From 0f822857998da1d006e62d98f5a04f0dcb82a6be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= Date: Thu, 6 Oct 2022 11:09:55 +0200 Subject: [PATCH 06/47] Update hmac and sha dependencies --- Cargo.toml | 6 +++--- src/mechanisms/hmacsha1.rs | 4 ++-- src/mechanisms/hmacsha256.rs | 4 ++-- src/mechanisms/hmacsha512.rs | 4 ++-- src/mechanisms/totp.rs | 2 +- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 33bb6c00142..61021d0e854 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,9 +33,9 @@ blake2 = { version = "0.10", default-features = false, optional = true } chacha20 = { version = "0.9", default-features = false } chacha20poly1305 = { version = "0.10", default-features = false, features = ["heapless", "reduced-round"] } des = { version = "0.8", optional = true } -hmac = "0.11" -sha-1 = { version = "0.9", default-features = false, optional = true } -sha2 = { version = "0.9", default-features = false } +hmac = "0.12" +sha-1 = { version = "0.10", default-features = false, optional = true } +sha2 = { version = "0.10", default-features = false } # ours cosey = "0.3" diff --git a/src/mechanisms/hmacsha1.rs b/src/mechanisms/hmacsha1.rs index 7ae3e0f7c3f..f35a20fe505 100644 --- a/src/mechanisms/hmacsha1.rs +++ b/src/mechanisms/hmacsha1.rs @@ -10,7 +10,7 @@ impl DeriveKey for super::HmacSha1 { keystore: &mut impl Keystore, request: &request::DeriveKey, ) -> Result { - use hmac::{Hmac, Mac, NewMac}; + use hmac::{Hmac, Mac}; type HmacSha1 = Hmac; let key_id = request.base_key; @@ -46,7 +46,7 @@ impl DeriveKey for super::HmacSha1 { impl Sign for super::HmacSha1 { #[inline(never)] fn sign(keystore: &mut impl Keystore, request: &request::Sign) -> Result { - use hmac::{Hmac, Mac, NewMac}; + use hmac::{Hmac, Mac}; use sha1::Sha1; type HmacSha1 = Hmac; diff --git a/src/mechanisms/hmacsha256.rs b/src/mechanisms/hmacsha256.rs index 2f2cbce2a2b..591c2033f9d 100644 --- a/src/mechanisms/hmacsha256.rs +++ b/src/mechanisms/hmacsha256.rs @@ -10,7 +10,7 @@ impl DeriveKey for super::HmacSha256 { keystore: &mut impl Keystore, request: &request::DeriveKey, ) -> Result { - use hmac::{Hmac, Mac, NewMac}; + use hmac::{Hmac, Mac}; type HmacSha256 = Hmac; let key_id = request.base_key; @@ -46,7 +46,7 @@ impl DeriveKey for super::HmacSha256 { impl Sign for super::HmacSha256 { #[inline(never)] fn sign(keystore: &mut impl Keystore, request: &request::Sign) -> Result { - use hmac::{Hmac, Mac, NewMac}; + use hmac::{Hmac, Mac}; use sha2::Sha256; type HmacSha256 = Hmac; diff --git a/src/mechanisms/hmacsha512.rs b/src/mechanisms/hmacsha512.rs index a02e4ae0546..561988d19f4 100644 --- a/src/mechanisms/hmacsha512.rs +++ b/src/mechanisms/hmacsha512.rs @@ -10,7 +10,7 @@ impl DeriveKey for super::HmacSha512 { keystore: &mut impl Keystore, request: &request::DeriveKey, ) -> Result { - use hmac::{Hmac, Mac, NewMac}; + use hmac::{Hmac, Mac}; type HmacSha512 = Hmac; let key_id = request.base_key.object_id; @@ -45,7 +45,7 @@ impl DeriveKey for super::HmacSha512 { impl Sign for super::HmacSha512 { #[inline(never)] fn sign(keystore: &mut impl Keystore, request: &request::Sign) -> Result { - use hmac::{Hmac, Mac, NewMac}; + use hmac::{Hmac, Mac}; use sha2::Sha512; type HmacSha512 = Hmac; diff --git a/src/mechanisms/totp.rs b/src/mechanisms/totp.rs index 1a07d3409be..f47569eb3f0 100644 --- a/src/mechanisms/totp.rs +++ b/src/mechanisms/totp.rs @@ -16,7 +16,7 @@ fn hotp_raw(key: &[u8], counter: u64, digits: u32) -> u64 { #[inline(never)] fn hmac_and_truncate(key: &[u8], message: &[u8], digits: u32) -> u64 { - use hmac::{Hmac, Mac, NewMac}; + use hmac::{Hmac, Mac}; // let mut hmac = Hmac::::new(GenericArray::from_slice(key)); let mut hmac = Hmac::::new_from_slice(key).unwrap(); hmac.update(message); From eb7ef0e2d5cbbe4a2d00a046c903ce331c775e2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= Date: Thu, 6 Oct 2022 11:11:00 +0200 Subject: [PATCH 07/47] Update serial_test --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 61021d0e854..3a566287b6b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -50,7 +50,7 @@ serde-indexed = "0.1.0" [dev-dependencies] # Testing -serial_test = { version = "0.6" } +serial_test = { version = "0.9" } entropy = "0.4.0" once_cell = "1.13.0" # Somehow, this is causing a regression. From 6aa1b261e2c653a3448cb2a92c0a50954cebca53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= Date: Thu, 6 Oct 2022 15:11:21 +0200 Subject: [PATCH 08/47] Update p256 dependency --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 3a566287b6b..d46e209fdcb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -44,7 +44,7 @@ cbor-smol = "0.4" heapless-bytes = { version = "0.3.0", features = ["cbor"] } interchange = "0.2.1" littlefs2 = "0.3.1" -p256-cortex-m4 = { version = "0.1.0-alpha.5", features = ["prehash", "sec1-signatures"] } +p256-cortex-m4 = { version = "0.1.0-alpha.6", features = ["prehash", "sec1-signatures"] } salty = { version = "0.2.0", features = ["cose"] } serde-indexed = "0.1.0" From df1d890147d05a1f1905f12a1191ab736e1c5d9e Mon Sep 17 00:00:00 2001 From: alt3r 3go Date: Mon, 1 Nov 2021 16:53:54 +0100 Subject: [PATCH 09/47] WIP: RSA lib integration - part 1 (very first steps, incomplete) Signed-off-by: alt3r 3go --- Cargo.toml | 8 ++ src/config.rs | 10 +- src/key.rs | 7 ++ src/mechanisms.rs | 3 + src/mechanisms/rsa2k.rs | 247 ++++++++++++++++++++++++++++++++++++++++ src/types.rs | 4 + 6 files changed, 278 insertions(+), 1 deletion(-) create mode 100644 src/mechanisms/rsa2k.rs diff --git a/Cargo.toml b/Cargo.toml index d46e209fdcb..90bbf5fc6b1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -37,6 +37,8 @@ hmac = "0.12" sha-1 = { version = "0.10", default-features = false, optional = true } sha2 = { version = "0.10", default-features = false } +rsa = { version = "0.5.0", optional = true } + # ours cosey = "0.3" delog = "0.1.0" @@ -88,6 +90,9 @@ default-mechanisms = [ "tdes", "totp", "trng", + "rsa2k", + "rsa3k", + "rsa4k" ] aes256-cbc = [] chacha8-poly1305 = [] @@ -102,6 +107,9 @@ sha256 = [] tdes = ["des"] totp = ["sha-1"] trng = ["sha-1"] +rsa2k = ["rsa"] +rsa3k = ["rsa"] +rsa4k = ["rsa"] clients-1 = [] clients-2 = [] diff --git a/src/config.rs b/src/config.rs index 4e92fd23093..eb691d71b72 100644 --- a/src/config.rs +++ b/src/config.rs @@ -13,7 +13,7 @@ pub type MAX_OBJECT_HANDLES = consts::U16; pub type MAX_LABEL_LENGTH = consts::U256; pub const MAX_MEDIUM_DATA_LENGTH: usize = 256; pub type MAX_PATH_LENGTH = consts::U256; -pub const MAX_KEY_MATERIAL_LENGTH: usize = 128; +//pub const MAX_KEY_MATERIAL_LENGTH: usize = 128; // must be above + 4 pub const MAX_SERIALIZED_KEY_LENGTH: usize = 132; cfg_if::cfg_if! { @@ -44,7 +44,15 @@ cfg_if::cfg_if! { } } pub const MAX_SHORT_DATA_LENGTH: usize = 128; + +//TODO: Do we want better granularity here? +#[cfg(any(feature = "rsa2k", feature = "rsa3k", feature = "rsa4k"))] +pub const MAX_SIGNATURE_LENGTH: usize = 512; +pub const MAX_KEY_MATERIAL_LENGTH: usize = 2 * 512; //TODO: Assuming (e/d, N) for now +#[cfg(not(any(feature = "rsa2k", feature = "rsa3k", feature = "rsa4k")))] pub const MAX_SIGNATURE_LENGTH: usize = 72; +pub const MAX_KEY_MATERIAL_LENGTH: usize = 128; + pub const MAX_USER_ATTRIBUTE_LENGTH: usize = 256; pub const USER_ATTRIBUTE_NUMBER: u8 = 37; diff --git a/src/key.rs b/src/key.rs index 64910971a7f..bd2128ff85d 100644 --- a/src/key.rs +++ b/src/key.rs @@ -66,6 +66,7 @@ pub enum Kind { Ed255, P256, X255, + Rsa2k, } bitflags::bitflags! { @@ -150,6 +151,9 @@ impl Kind { Kind::Ed255 => 4, Kind::P256 => 5, Kind::X255 => 6, + Kind::Rsa2k => 0x7, + // Kind::Rsa3k => 0xE0, + // Kind::Rsa4k => 0xE1, } } @@ -161,6 +165,9 @@ impl Kind { 4 => Self::Ed255, 5 => Self::P256, 6 => Self::X255, + + 0x7 => Self::Rsa2k, + _ => return Err(Error::InvalidSerializedKey), }) } diff --git a/src/mechanisms.rs b/src/mechanisms.rs index 67089a965e3..1e29994b27c 100644 --- a/src/mechanisms.rs +++ b/src/mechanisms.rs @@ -49,6 +49,9 @@ pub struct P256 {} pub struct P256Prehashed {} mod p256; +pub struct Rsa2k {} +mod rsa2k; + pub struct Sha256 {} mod sha256; diff --git a/src/mechanisms/rsa2k.rs b/src/mechanisms/rsa2k.rs new file mode 100644 index 00000000000..2ea107ade4a --- /dev/null +++ b/src/mechanisms/rsa2k.rs @@ -0,0 +1,247 @@ +use core::convert::{TryFrom, TryInto}; + +use crate::api::*; +// use crate::config::*; +// use crate::debug; +use crate::error::Error; +use crate::service::*; +use crate::types::*; + +#[inline(never)] +fn load_public_key( + keystore: &mut impl Keystore, + key_id: &KeyId, +) -> Result { + let public_bytes: [u8; 256] = keystore + .load_key(key::Secrecy::Public, Some(key::Kind::Rsa2k), &key_id)? + .material + .as_slice() + .try_into() + .map_err(|_| Error::InternalError)?; + + let public_key = + salty::signature::PublicKey::try_from(&public_bytes).map_err(|_| Error::InternalError)?; + + Ok(public_key) +} + +#[inline(never)] +fn load_keypair(keystore: &mut impl Keystore, key_id: &KeyId) -> Result { + let seed: [u8; 32] = keystore + .load_key(key::Secrecy::Secret, Some(key::Kind::Ed255), &key_id)? + .material + .as_slice() + .try_into() + .map_err(|_| Error::InternalError)?; + + let keypair = salty::signature::Keypair::from(&seed); + // hprintln!("seed: {:?}", &seed).ok(); + Ok(keypair) +} + +#[cfg(feature = "ed255")] +impl DeriveKey for super::Ed255 { + #[inline(never)] + fn derive_key( + keystore: &mut impl Keystore, + request: &request::DeriveKey, + ) -> Result { + let base_id = &request.base_key; + let keypair = load_keypair(keystore, base_id)?; + + let public_id = keystore.store_key( + request.attributes.persistence, + key::Secrecy::Public, + key::Kind::Ed255, + keypair.public.as_bytes(), + )?; + + Ok(reply::DeriveKey { key: public_id }) + } +} + +#[cfg(feature = "ed255")] +impl DeserializeKey for super::Ed255 { + #[inline(never)] + fn deserialize_key( + keystore: &mut impl Keystore, + request: &request::DeserializeKey, + ) -> Result { + // - mechanism: Mechanism + // - serialized_key: Message + // - attributes: StorageAttributes + + if request.format != KeySerialization::Raw { + return Err(Error::InternalError); + } + + if request.serialized_key.len() != 32 { + return Err(Error::InvalidSerializedKey); + } + + let serialized_key: [u8; 32] = request.serialized_key[..32].try_into().unwrap(); + let public_key = salty::signature::PublicKey::try_from(&serialized_key) + .map_err(|_| Error::InvalidSerializedKey)?; + + let public_id = keystore.store_key( + request.attributes.persistence, + key::Secrecy::Public, + key::Kind::Ed255, + public_key.as_bytes(), + )?; + + Ok(reply::DeserializeKey { key: public_id }) + } +} + +#[cfg(feature = "ed255")] +impl GenerateKey for super::Ed255 { + #[inline(never)] + fn generate_key( + keystore: &mut impl Keystore, + request: &request::GenerateKey, + ) -> Result { + let mut seed = [0u8; 32]; + keystore.rng().fill_bytes(&mut seed); + + // let keypair = salty::signature::Keypair::from(&seed); + // #[cfg(all(test, feature = "verbose-tests"))] + // println!("ed255 keypair with public key = {:?}", &keypair.public); + + // store keys + let key_id = keystore.store_key( + request.attributes.persistence, + key::Secrecy::Secret, + key::Info::from(key::Kind::Ed255).with_local_flag(), + &seed, + )?; + + // return handle + Ok(reply::GenerateKey { key: key_id }) + } +} + +#[cfg(feature = "ed255")] +impl SerializeKey for super::Ed255 { + #[inline(never)] + fn serialize_key( + keystore: &mut impl Keystore, + request: &request::SerializeKey, + ) -> Result { + let key_id = request.key; + let public_key = load_public_key(keystore, &key_id)?; + + let serialized_key = match request.format { + KeySerialization::Cose => { + let cose_pk = cosey::Ed25519PublicKey { + // x: Bytes::from_slice(public_key.x_coordinate()).unwrap(), + // x: Bytes::from_slice(&buf).unwrap(), + x: Bytes::from_slice(public_key.as_bytes()).unwrap(), + }; + crate::cbor_serialize_bytes(&cose_pk).map_err(|_| Error::CborError)? + } + + KeySerialization::Raw => { + let mut serialized_key = Message::new(); + serialized_key + .extend_from_slice(public_key.as_bytes()) + .map_err(|_| Error::InternalError)?; + // serialized_key.extend_from_slice(&buf).map_err(|_| Error::InternalError)?; + serialized_key + } + + _ => { + return Err(Error::InternalError); + } + }; + + Ok(reply::SerializeKey { serialized_key }) + } +} + +#[cfg(feature = "ed255")] +impl Exists for super::Ed255 { + #[inline(never)] + fn exists( + keystore: &mut impl Keystore, + request: &request::Exists, + ) -> Result { + let key_id = request.key; + + let exists = keystore.exists_key(key::Secrecy::Secret, Some(key::Kind::Ed255), &key_id); + Ok(reply::Exists { exists }) + } +} + +#[cfg(feature = "ed255")] +impl Sign for super::Ed255 { + #[inline(never)] + fn sign(keystore: &mut impl Keystore, request: &request::Sign) -> Result { + // Not so nice, expands to + // `trussed::/home/nicolas/projects/solo-bee/components/trussed/src/mechanisms/ed255.rs:151 + // Ed255::Sign`, i.e. VEERY long + // debug!("trussed::{}:{} Ed255::Sign", file!(), line!()).ok(); + // debug!("trussed: Ed255::Sign").ok(); + // if let SignatureSerialization::Raw = request.format { + // } else { + // return Err(Error::InvalidSerializationFormat); + // } + + let key_id = request.key; + + let keypair = load_keypair(keystore, &key_id)?; + + let native_signature = keypair.sign(&request.message); + let our_signature = Signature::from_slice(&native_signature.to_bytes()).unwrap(); + + // hprintln!("Ed255 signature:").ok(); + // hprintln!("msg: {:?}", &request.message).ok(); + // hprintln!("pk: {:?}", &keypair.public.as_bytes()).ok(); + // hprintln!("sig: {:?}", &our_signature).ok(); + + // return signature + Ok(reply::Sign { + signature: our_signature, + }) + } +} + +#[cfg(feature = "ed255")] +impl Verify for super::Ed255 { + #[inline(never)] + fn verify( + keystore: &mut impl Keystore, + request: &request::Verify, + ) -> Result { + if let SignatureSerialization::Raw = request.format { + } else { + return Err(Error::InvalidSerializationFormat); + } + + if request.signature.len() != salty::constants::SIGNATURE_SERIALIZED_LENGTH { + return Err(Error::WrongSignatureLength); + } + + let key_id = request.key; + let public_key = load_public_key(keystore, &key_id)?; + + let mut signature_array = [0u8; salty::constants::SIGNATURE_SERIALIZED_LENGTH]; + signature_array.copy_from_slice(request.signature.as_ref()); + let salty_signature = salty::signature::Signature::from(&signature_array); + + Ok(reply::Verify { + valid: public_key + .verify(&request.message, &salty_signature) + .is_ok(), + }) + } +} + +#[cfg(not(feature = "ed255"))] +impl DeriveKey for super::Ed255 {} +#[cfg(not(feature = "ed255"))] +impl GenerateKey for super::Ed255 {} +#[cfg(not(feature = "ed255"))] +impl Sign for super::Ed255 {} +#[cfg(not(feature = "ed255"))] +impl Verify for super::Ed255 {} diff --git a/src/types.rs b/src/types.rs index 2b3e047515f..276d5ce21a9 100644 --- a/src/types.rs +++ b/src/types.rs @@ -511,6 +511,10 @@ pub enum Mechanism { X255, /// Used to serialize the output of a diffie-hellman SharedSecret, + //TODO: Do we want to distinguish PKCS_v1.5 vs PSS/OAEP right here? + Rsa2k, + Rsa3k, + Rsa4k, } pub type LongData = Bytes; From 195a2f69f4a0091da6ae4257708c941089ffc59f Mon Sep 17 00:00:00 2001 From: alt3r 3go Date: Sun, 21 Nov 2021 18:38:22 +0100 Subject: [PATCH 10/47] WIP: RSA lib integration - part 2 (more plumbing, still incomplete) Signed-off-by: alt3r 3go --- Cargo.toml | 7 +- src/config.rs | 13 ++-- src/key.rs | 7 +- src/mechanisms.rs | 4 +- src/mechanisms/{rsa2k.rs => rsa2kpkcs.rs} | 80 ++++++++++------------- src/service.rs | 7 ++ src/store/keystore.rs | 4 ++ src/types.rs | 1 + 8 files changed, 64 insertions(+), 59 deletions(-) rename src/mechanisms/{rsa2k.rs => rsa2kpkcs.rs} (77%) diff --git a/Cargo.toml b/Cargo.toml index 90bbf5fc6b1..ebe5bfd9aac 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -36,8 +36,7 @@ des = { version = "0.8", optional = true } hmac = "0.12" sha-1 = { version = "0.10", default-features = false, optional = true } sha2 = { version = "0.10", default-features = false } - -rsa = { version = "0.5.0", optional = true } +rsa = { version = "0.6.0", optional = true } # ours cosey = "0.3" @@ -90,7 +89,7 @@ default-mechanisms = [ "tdes", "totp", "trng", - "rsa2k", + "rsa2k-pkcs", "rsa3k", "rsa4k" ] @@ -107,7 +106,7 @@ sha256 = [] tdes = ["des"] totp = ["sha-1"] trng = ["sha-1"] -rsa2k = ["rsa"] +rsa2k-pkcs = ["rsa"] rsa3k = ["rsa"] rsa4k = ["rsa"] diff --git a/src/config.rs b/src/config.rs index eb691d71b72..ea1524e5332 100644 --- a/src/config.rs +++ b/src/config.rs @@ -45,14 +45,19 @@ cfg_if::cfg_if! { } pub const MAX_SHORT_DATA_LENGTH: usize = 128; -//TODO: Do we want better granularity here? -#[cfg(any(feature = "rsa2k", feature = "rsa3k", feature = "rsa4k"))] +//TODO: Do we want better keylength granularity here? +#[cfg(any(feature = "rsa2k-pkcs", feature = "rsa3k", feature = "rsa4k"))] pub const MAX_SIGNATURE_LENGTH: usize = 512; -pub const MAX_KEY_MATERIAL_LENGTH: usize = 2 * 512; //TODO: Assuming (e/d, N) for now -#[cfg(not(any(feature = "rsa2k", feature = "rsa3k", feature = "rsa4k")))] +#[cfg(any(feature = "rsa2k-pkcs", feature = "rsa3k", feature = "rsa4k"))] +pub const MAX_KEY_MATERIAL_LENGTH: usize = 2 * 512; //TODO: Assuming plain (, N) for now + +#[cfg(not(any(feature = "rsa2k-pkcs", feature = "rsa3k", feature = "rsa4k")))] pub const MAX_SIGNATURE_LENGTH: usize = 72; +#[cfg(not(any(feature = "rsa2k-pkcs", feature = "rsa3k", feature = "rsa4k")))] pub const MAX_KEY_MATERIAL_LENGTH: usize = 128; +// must be MAX_KEY_MATERIAL_LENGTH + 4 +pub const MAX_SERIALIZED_KEY_LENGTH: usize = MAX_KEY_MATERIAL_LENGTH + 4; pub const MAX_USER_ATTRIBUTE_LENGTH: usize = 256; pub const USER_ATTRIBUTE_NUMBER: u8 = 37; diff --git a/src/key.rs b/src/key.rs index bd2128ff85d..246d84e50d0 100644 --- a/src/key.rs +++ b/src/key.rs @@ -152,8 +152,8 @@ impl Kind { Kind::P256 => 5, Kind::X255 => 6, Kind::Rsa2k => 0x7, - // Kind::Rsa3k => 0xE0, - // Kind::Rsa4k => 0xE1, + //Kind::Rsa3k => 0xE0, + //Kind::Rsa4k => 0xE1, } } @@ -167,7 +167,8 @@ impl Kind { 6 => Self::X255, 0x7 => Self::Rsa2k, - + //0xE0 => Kind::Rsa3k, + //0xE1 => Kind::Rsa4k, _ => return Err(Error::InvalidSerializedKey), }) } diff --git a/src/mechanisms.rs b/src/mechanisms.rs index 1e29994b27c..18a74044e14 100644 --- a/src/mechanisms.rs +++ b/src/mechanisms.rs @@ -49,8 +49,8 @@ pub struct P256 {} pub struct P256Prehashed {} mod p256; -pub struct Rsa2k {} -mod rsa2k; +pub struct Rsa2kPkcs {} +mod rsa2kpkcs; pub struct Sha256 {} mod sha256; diff --git a/src/mechanisms/rsa2k.rs b/src/mechanisms/rsa2kpkcs.rs similarity index 77% rename from src/mechanisms/rsa2k.rs rename to src/mechanisms/rsa2kpkcs.rs index 2ea107ade4a..aa184f9af1b 100644 --- a/src/mechanisms/rsa2k.rs +++ b/src/mechanisms/rsa2kpkcs.rs @@ -8,19 +8,17 @@ use crate::service::*; use crate::types::*; #[inline(never)] -fn load_public_key( - keystore: &mut impl Keystore, - key_id: &KeyId, -) -> Result { - let public_bytes: [u8; 256] = keystore +fn load_public_key(keystore: &mut impl Keystore, key_id: &KeyId) -> Result { + //TODO: The key size should better be defined somewhere instead of hardcoding + let public_bytes: [u8; 512] = keystore .load_key(key::Secrecy::Public, Some(key::Kind::Rsa2k), &key_id)? .material .as_slice() .try_into() .map_err(|_| Error::InternalError)?; - let public_key = - salty::signature::PublicKey::try_from(&public_bytes).map_err(|_| Error::InternalError)?; + // let public_key = salty::signature::PublicKey::try_from(&public_bytes).map_err(|_| Error::InternalError)?; + let public_key = rsa::PublicKey::try_from(&public_bytes).map_err(|_| Error::InternalError)?; Ok(public_key) } @@ -28,7 +26,7 @@ fn load_public_key( #[inline(never)] fn load_keypair(keystore: &mut impl Keystore, key_id: &KeyId) -> Result { let seed: [u8; 32] = keystore - .load_key(key::Secrecy::Secret, Some(key::Kind::Ed255), &key_id)? + .load_key(key::Secrecy::Secret, Some(key::Kind::Rsa2k), &key_id)? .material .as_slice() .try_into() @@ -39,8 +37,8 @@ fn load_keypair(keystore: &mut impl Keystore, key_id: &KeyId) -> Result Result { let key_id = request.key; - let exists = keystore.exists_key(key::Secrecy::Secret, Some(key::Kind::Ed255), &key_id); + let exists = keystore.exists_key(key::Secrecy::Secret, Some(key::Kind::Rsa2k), &key_id); Ok(reply::Exists { exists }) } } -#[cfg(feature = "ed255")] -impl Sign for super::Ed255 { +#[cfg(feature = "rsa2k-pkcs")] +impl Sign for super::Rsa2kPkcs { #[inline(never)] fn sign(keystore: &mut impl Keystore, request: &request::Sign) -> Result { - // Not so nice, expands to - // `trussed::/home/nicolas/projects/solo-bee/components/trussed/src/mechanisms/ed255.rs:151 - // Ed255::Sign`, i.e. VEERY long - // debug!("trussed::{}:{} Ed255::Sign", file!(), line!()).ok(); - // debug!("trussed: Ed255::Sign").ok(); - // if let SignatureSerialization::Raw = request.format { - // } else { - // return Err(Error::InvalidSerializationFormat); - // } - let key_id = request.key; let keypair = load_keypair(keystore, &key_id)?; @@ -194,7 +182,7 @@ impl Sign for super::Ed255 { let native_signature = keypair.sign(&request.message); let our_signature = Signature::from_slice(&native_signature.to_bytes()).unwrap(); - // hprintln!("Ed255 signature:").ok(); + // hprintln!("RSA2K-PKCS_v1.5 signature:").ok(); // hprintln!("msg: {:?}", &request.message).ok(); // hprintln!("pk: {:?}", &keypair.public.as_bytes()).ok(); // hprintln!("sig: {:?}", &our_signature).ok(); @@ -206,8 +194,8 @@ impl Sign for super::Ed255 { } } -#[cfg(feature = "ed255")] -impl Verify for super::Ed255 { +#[cfg(feature = "rsa2k-pkcs")] +impl Verify for super::Rsa2kPkcs { #[inline(never)] fn verify( keystore: &mut impl Keystore, @@ -237,11 +225,11 @@ impl Verify for super::Ed255 { } } -#[cfg(not(feature = "ed255"))] -impl DeriveKey for super::Ed255 {} -#[cfg(not(feature = "ed255"))] -impl GenerateKey for super::Ed255 {} -#[cfg(not(feature = "ed255"))] -impl Sign for super::Ed255 {} -#[cfg(not(feature = "ed255"))] -impl Verify for super::Ed255 {} +#[cfg(not(feature = "rsa2k-pkcs"))] +impl DeriveKey for super::Rsa2kPkcs {} +#[cfg(not(feature = "rsa2k-pkcs"))] +impl GenerateKey for super::Rsa2kPkcs {} +#[cfg(not(feature = "rsa2k-pkcs"))] +impl Sign for super::Rsa2kPkcs {} +#[cfg(not(feature = "rsa2k-pkcs"))] +impl Verify for super::Rsa2kPkcs {} diff --git a/src/service.rs b/src/service.rs index cb2ec77f6fb..c137cd1952b 100644 --- a/src/service.rs +++ b/src/service.rs @@ -171,6 +171,7 @@ impl ServiceResources

{ Mechanism::P256 => mechanisms::P256::derive_key(keystore, request), Mechanism::Sha256 => mechanisms::Sha256::derive_key(keystore, request), Mechanism::X255 => mechanisms::X255::derive_key(keystore, request), + Mechanism::Rsa2kPkcs => mechanisms::Rsa2kPkcs::derive_key(keystore, request), _ => Err(Error::MechanismNotAvailable), }.map(Reply::DeriveKey) @@ -182,6 +183,7 @@ impl ServiceResources

{ Mechanism::Ed255 => mechanisms::Ed255::deserialize_key(keystore, request), Mechanism::P256 => mechanisms::P256::deserialize_key(keystore, request), Mechanism::X255 => mechanisms::X255::deserialize_key(keystore, request), + Mechanism::Rsa2kPkcs => mechanisms::Rsa2kPkcs::deserialize_key(keystore, request), _ => Err(Error::MechanismNotAvailable), }.map(Reply::DeserializeKey) @@ -215,6 +217,7 @@ impl ServiceResources

{ Mechanism::P256 => mechanisms::P256::exists(keystore, request), Mechanism::Totp => mechanisms::Totp::exists(keystore, request), Mechanism::X255 => mechanisms::X255::exists(keystore, request), + Mechanism::Rsa2kPkcs => mechanisms::Rsa2kPkcs::exists(keystore, request), _ => Err(Error::MechanismNotAvailable), }.map(Reply::Exists) @@ -226,6 +229,7 @@ impl ServiceResources

{ Mechanism::Ed255 => mechanisms::Ed255::generate_key(keystore, request), Mechanism::P256 => mechanisms::P256::generate_key(keystore, request), Mechanism::X255 => mechanisms::X255::generate_key(keystore, request), + Mechanism::Rsa2kPkcs => mechanisms::Rsa2kPkcs::generate_key(keystore, request), _ => Err(Error::MechanismNotAvailable), }.map(Reply::GenerateKey) }, @@ -438,6 +442,7 @@ impl ServiceResources

{ Mechanism::P256 => mechanisms::P256::serialize_key(keystore, request), Mechanism::X255 => mechanisms::X255::serialize_key(keystore, request), Mechanism::SharedSecret => mechanisms::SharedSecret::serialize_key(keystore, request), + Mechanism::Rsa2kPkcs => mechanisms::Rsa2kPkcs::serialize_key(keystore, request), _ => Err(Error::MechanismNotAvailable), }.map(Reply::SerializeKey) @@ -454,6 +459,7 @@ impl ServiceResources

{ Mechanism::P256 => mechanisms::P256::sign(keystore, request), Mechanism::P256Prehashed => mechanisms::P256Prehashed::sign(keystore, request), Mechanism::Totp => mechanisms::Totp::sign(keystore, request), + Mechanism::Rsa2kPkcs => mechanisms::Rsa2kPkcs::sign(keystore, request), _ => Err(Error::MechanismNotAvailable), }.map(Reply::Sign) @@ -478,6 +484,7 @@ impl ServiceResources

{ Mechanism::Ed255 => mechanisms::Ed255::verify(keystore, request), Mechanism::P256 => mechanisms::P256::verify(keystore, request), + Mechanism::Rsa2kPkcs => mechanisms::Rsa2kPkcs::verify(keystore, request), _ => Err(Error::MechanismNotAvailable), }.map(Reply::Verify) diff --git a/src/store/keystore.rs b/src/store/keystore.rs index 050fa037610..06ab28d1b8b 100644 --- a/src/store/keystore.rs +++ b/src/store/keystore.rs @@ -172,7 +172,11 @@ impl Keystore for ClientKeystore { let location = self.location(secrecy, id).ok_or(Error::NoSuchKey)?; + //TODO: This should better be defined in some way, instead of hardcoding + #[cfg(not(feature = "rsa2k-pkcs"))] let bytes: Bytes<128> = store::read(self.store, location, &path)?; + #[cfg(feature = "rsa2k-pkcs")] + let bytes: Bytes<512> = store::read(self.store, location, &path)?; let key = key::Key::try_deserialize(&bytes)?; diff --git a/src/types.rs b/src/types.rs index 276d5ce21a9..f0fa76e3508 100644 --- a/src/types.rs +++ b/src/types.rs @@ -513,6 +513,7 @@ pub enum Mechanism { SharedSecret, //TODO: Do we want to distinguish PKCS_v1.5 vs PSS/OAEP right here? Rsa2k, + Rsa2kPkcs, Rsa3k, Rsa4k, } From 6c389cd6ad68b83dc1837543b2d9de67a01b647a Mon Sep 17 00:00:00 2001 From: alt3r 3go Date: Sun, 28 Nov 2021 15:18:15 +0100 Subject: [PATCH 11/47] WIP: RSA lib integration - part 3 (RSA2K GenerateKey+test) Signed-off-by: alt3r 3go --- src/client/mechanisms.rs | 15 +++ src/config.rs | 2 +- src/mechanisms/rsa2kpkcs.rs | 250 ++++++++++++++++++------------------ tests/rsa2kpkcs.rs | 19 +++ 4 files changed, 160 insertions(+), 126 deletions(-) create mode 100644 tests/rsa2kpkcs.rs diff --git a/src/client/mechanisms.rs b/src/client/mechanisms.rs index 020b11cfe6c..f7676a54895 100644 --- a/src/client/mechanisms.rs +++ b/src/client/mechanisms.rs @@ -385,6 +385,21 @@ pub trait P256: CryptoClient { } } +#[cfg(feature = "rsa2k-pkcs")] +impl Rsa2kPkcs for ClientImplementation {} + +pub trait Rsa2kPkcs: CryptoClient { + fn generate_rsa2kpkcs_private_key( + &mut self, + persistence: Location, + ) -> ClientResult<'_, reply::GenerateKey, Self> { + self.generate_key( + Mechanism::Rsa2kPkcs, + StorageAttributes::new().set_persistence(persistence), + ) + } +} + #[cfg(feature = "sha256")] impl Sha256 for ClientImplementation {} diff --git a/src/config.rs b/src/config.rs index ea1524e5332..d20d2274516 100644 --- a/src/config.rs +++ b/src/config.rs @@ -49,7 +49,7 @@ pub const MAX_SHORT_DATA_LENGTH: usize = 128; #[cfg(any(feature = "rsa2k-pkcs", feature = "rsa3k", feature = "rsa4k"))] pub const MAX_SIGNATURE_LENGTH: usize = 512; #[cfg(any(feature = "rsa2k-pkcs", feature = "rsa3k", feature = "rsa4k"))] -pub const MAX_KEY_MATERIAL_LENGTH: usize = 2 * 512; //TODO: Assuming plain (, N) for now +pub const MAX_KEY_MATERIAL_LENGTH: usize = 2 * 609; //TODO: We use PKCS#8 DER format, this value found empirically for 2K keys. Need to generalize. #[cfg(not(any(feature = "rsa2k-pkcs", feature = "rsa3k", feature = "rsa4k")))] pub const MAX_SIGNATURE_LENGTH: usize = 72; diff --git a/src/mechanisms/rsa2kpkcs.rs b/src/mechanisms/rsa2kpkcs.rs index aa184f9af1b..abff955204e 100644 --- a/src/mechanisms/rsa2kpkcs.rs +++ b/src/mechanisms/rsa2kpkcs.rs @@ -1,5 +1,7 @@ use core::convert::{TryFrom, TryInto}; +use rsa::{pkcs8::ToPrivateKey, RsaPrivateKey}; + use crate::api::*; // use crate::config::*; // use crate::debug; @@ -7,55 +9,56 @@ use crate::error::Error; use crate::service::*; use crate::types::*; -#[inline(never)] -fn load_public_key(keystore: &mut impl Keystore, key_id: &KeyId) -> Result { - //TODO: The key size should better be defined somewhere instead of hardcoding - let public_bytes: [u8; 512] = keystore - .load_key(key::Secrecy::Public, Some(key::Kind::Rsa2k), &key_id)? - .material - .as_slice() - .try_into() - .map_err(|_| Error::InternalError)?; +// #[inline(never)] +// fn load_public_key(keystore: &mut impl Keystore, key_id: &KeyId) +// -> Result { - // let public_key = salty::signature::PublicKey::try_from(&public_bytes).map_err(|_| Error::InternalError)?; - let public_key = rsa::PublicKey::try_from(&public_bytes).map_err(|_| Error::InternalError)?; +// //TODO: The key size should better be defined somewhere instead of hardcoding +// let public_bytes: [u8; 512] = keystore +// .load_key(key::Secrecy::Public, Some(key::Kind::Rsa2k), &key_id)? +// .material.as_slice() +// .try_into() +// .map_err(|_| Error::InternalError)?; - Ok(public_key) -} +// // let public_key = salty::signature::PublicKey::try_from(&public_bytes).map_err(|_| Error::InternalError)?; +// let public_key = rsa::RsaPublicKey::try_from(&public_bytes).map_err(|_| Error::InternalError)?; -#[inline(never)] -fn load_keypair(keystore: &mut impl Keystore, key_id: &KeyId) -> Result { - let seed: [u8; 32] = keystore - .load_key(key::Secrecy::Secret, Some(key::Kind::Rsa2k), &key_id)? - .material - .as_slice() - .try_into() - .map_err(|_| Error::InternalError)?; - - let keypair = salty::signature::Keypair::from(&seed); - // hprintln!("seed: {:?}", &seed).ok(); - Ok(keypair) -} +// Ok(public_key) +// } -#[cfg(feature = "rsa2k-pkcs")] -impl DeriveKey for super::Rsa2kPkcs { - #[inline(never)] - fn derive_key( - keystore: &mut impl Keystore, - request: &request::DeriveKey, - ) -> Result { - let base_id = &request.base_key; - let keypair = load_keypair(keystore, base_id)?; +// #[inline(never)] +// fn load_keypair(keystore: &mut impl Keystore, key_id: &KeyId) +// -> Result { - let public_id = keystore.store_key( - request.attributes.persistence, - key::Secrecy::Public, - key::Kind::Rsa2k, - keypair.public.as_bytes(), - )?; +// let seed: [u8; 32] = keystore +// .load_key(key::Secrecy::Secret, Some(key::Kind::Rsa2k), &key_id)? +// .material.as_slice() +// .try_into() +// .map_err(|_| Error::InternalError)?; - Ok(reply::DeriveKey { key: public_id }) - } +// let keypair = salty::signature::Keypair::from(&seed); +// // hprintln!("seed: {:?}", &seed).ok(); +// Ok(keypair) +// } + +#[cfg(feature = "rsa2k-pkcs")] +impl DeriveKey for super::Rsa2kPkcs { + // #[inline(never)] + // fn derive_key(keystore: &mut impl Keystore, request: &request::DeriveKey) + // -> Result + // { + // let base_id = &request.base_key; + // let keypair = load_keypair(keystore, base_id)?; + + // let public_id = keystore.store_key( + // request.attributes.persistence, + // key::Secrecy::Public, key::Kind::Rsa2k, + // keypair.public.as_bytes())?; + + // Ok(reply::DeriveKey { + // key: public_id, + // }) + // } } #[cfg(feature = "rsa2k-pkcs")] @@ -99,19 +102,23 @@ impl GenerateKey for super::Rsa2kPkcs { keystore: &mut impl Keystore, request: &request::GenerateKey, ) -> Result { - let mut seed = [0u8; 32]; - keystore.rng().fill_bytes(&mut seed); + // We want an RSA 2K key + let bits = 2048; + + let private_key = RsaPrivateKey::new(keystore.rng(), bits) + .expect("Failed to generate the RSA 2K private key"); + let pk_der = ToPrivateKey::to_pkcs8_der(&private_key) + .expect("Failed to serialize the RSA 2K private key to PKCS#8 DER"); - // let keypair = salty::signature::Keypair::from(&seed); // #[cfg(all(test, feature = "verbose-tests"))] - // println!("rsa2k-pkcs keypair with public key = {:?}", &keypair.public); + // std::println!("rsa2k-pkcs private key = {:?}", &private_key); - // store keys + // store the key let key_id = keystore.store_key( request.attributes.persistence, key::Secrecy::Secret, key::Info::from(key::Kind::Rsa2k).with_local_flag(), - &seed, + pk_der.as_ref(), )?; // return handle @@ -121,40 +128,35 @@ impl GenerateKey for super::Rsa2kPkcs { #[cfg(feature = "rsa2k-pkcs")] impl SerializeKey for super::Rsa2kPkcs { - #[inline(never)] - fn serialize_key( - keystore: &mut impl Keystore, - request: &request::SerializeKey, - ) -> Result { - let key_id = request.key; - let public_key = load_public_key(keystore, &key_id)?; - - let serialized_key = match request.format { - KeySerialization::Cose => { - let cose_pk = cosey::Ed25519PublicKey { - // x: Bytes::from_slice(public_key.x_coordinate()).unwrap(), - // x: Bytes::from_slice(&buf).unwrap(), - x: Bytes::from_slice(public_key.as_bytes()).unwrap(), - }; - crate::cbor_serialize_bytes(&cose_pk).map_err(|_| Error::CborError)? - } - - KeySerialization::Raw => { - let mut serialized_key = Message::new(); - serialized_key - .extend_from_slice(public_key.as_bytes()) - .map_err(|_| Error::InternalError)?; - // serialized_key.extend_from_slice(&buf).map_err(|_| Error::InternalError)?; - serialized_key - } - - _ => { - return Err(Error::InternalError); - } - }; - - Ok(reply::SerializeKey { serialized_key }) - } + // #[inline(never)] + // fn serialize_key(keystore: &mut impl Keystore, request: &request::SerializeKey) + // -> Result + // { + // let key_id = request.key; + // let public_key = load_public_key(keystore, &key_id)?; + + // let serialized_key = match request.format { + // KeySerialization::Cose => { + // let cose_pk = cosey::Ed25519PublicKey { + // // x: Bytes::from_slice(public_key.x_coordinate()).unwrap(), + // // x: Bytes::from_slice(&buf).unwrap(), + // x: Bytes::from_slice(public_key.as_bytes()).unwrap(), + // }; + // crate::cbor_serialize_bytes(&cose_pk).map_err(|_| Error::CborError)? + // } + + // KeySerialization::Raw => { + // let mut serialized_key = Message::new(); + // serialized_key.extend_from_slice(public_key.as_bytes()).map_err(|_| Error::InternalError)?; + // // serialized_key.extend_from_slice(&buf).map_err(|_| Error::InternalError)?; + // serialized_key + // } + + // _ => { return Err(Error::InternalError); } + // }; + + // Ok(reply::SerializeKey { serialized_key }) + // } } #[cfg(feature = "rsa2k-pkcs")] @@ -173,56 +175,54 @@ impl Exists for super::Rsa2kPkcs { #[cfg(feature = "rsa2k-pkcs")] impl Sign for super::Rsa2kPkcs { - #[inline(never)] - fn sign(keystore: &mut impl Keystore, request: &request::Sign) -> Result { - let key_id = request.key; + // #[inline(never)] + // fn sign(keystore: &mut impl Keystore, request: &request::Sign) + // -> Result + // { - let keypair = load_keypair(keystore, &key_id)?; + // let key_id = request.key; - let native_signature = keypair.sign(&request.message); - let our_signature = Signature::from_slice(&native_signature.to_bytes()).unwrap(); + // let keypair = load_keypair(keystore, &key_id)?; - // hprintln!("RSA2K-PKCS_v1.5 signature:").ok(); - // hprintln!("msg: {:?}", &request.message).ok(); - // hprintln!("pk: {:?}", &keypair.public.as_bytes()).ok(); - // hprintln!("sig: {:?}", &our_signature).ok(); + // let native_signature = keypair.sign(&request.message); + // let our_signature = Signature::from_slice(&native_signature.to_bytes()).unwrap(); - // return signature - Ok(reply::Sign { - signature: our_signature, - }) - } + // // hprintln!("RSA2K-PKCS_v1.5 signature:").ok(); + // // hprintln!("msg: {:?}", &request.message).ok(); + // // hprintln!("pk: {:?}", &keypair.public.as_bytes()).ok(); + // // hprintln!("sig: {:?}", &our_signature).ok(); + + // // return signature + // Ok(reply::Sign { signature: our_signature }) + // } } #[cfg(feature = "rsa2k-pkcs")] impl Verify for super::Rsa2kPkcs { - #[inline(never)] - fn verify( - keystore: &mut impl Keystore, - request: &request::Verify, - ) -> Result { - if let SignatureSerialization::Raw = request.format { - } else { - return Err(Error::InvalidSerializationFormat); - } - - if request.signature.len() != salty::constants::SIGNATURE_SERIALIZED_LENGTH { - return Err(Error::WrongSignatureLength); - } - - let key_id = request.key; - let public_key = load_public_key(keystore, &key_id)?; - - let mut signature_array = [0u8; salty::constants::SIGNATURE_SERIALIZED_LENGTH]; - signature_array.copy_from_slice(request.signature.as_ref()); - let salty_signature = salty::signature::Signature::from(&signature_array); - - Ok(reply::Verify { - valid: public_key - .verify(&request.message, &salty_signature) - .is_ok(), - }) - } + // #[inline(never)] + // fn verify(keystore: &mut impl Keystore, request: &request::Verify) + // -> Result + // { + // if let SignatureSerialization::Raw = request.format { + // } else { + // return Err(Error::InvalidSerializationFormat); + // } + + // if request.signature.len() != salty::constants::SIGNATURE_SERIALIZED_LENGTH { + // return Err(Error::WrongSignatureLength); + // } + + // let key_id = request.key; + // let public_key = load_public_key(keystore, &key_id)?; + + // let mut signature_array = [0u8; salty::constants::SIGNATURE_SERIALIZED_LENGTH]; + // signature_array.copy_from_slice(request.signature.as_ref()); + // let salty_signature = salty::signature::Signature::from(&signature_array); + + // Ok(reply::Verify { valid: + // public_key.verify(&request.message, &salty_signature).is_ok() + // }) + // } } #[cfg(not(feature = "rsa2k-pkcs"))] diff --git a/tests/rsa2kpkcs.rs b/tests/rsa2kpkcs.rs new file mode 100644 index 00000000000..57cb2146dc7 --- /dev/null +++ b/tests/rsa2kpkcs.rs @@ -0,0 +1,19 @@ +use generic_array::typenum::assert_type; +use trussed::client::mechanisms::Rsa2kPkcs; +use trussed::syscall; +use trussed::types::KeyId; + +mod client; + +use trussed::types::Location::*; + +#[test] +fn rsa2kpkcs_generate_key() { + client::get(|client| { + let sk = syscall!(client.generate_rsa2kpkcs_private_key(Internal)).key; + + // This assumes we don't really get they key with ID 0 + // TODO: make sure the above always holds + assert_ne!(sk, KeyId::from_special(0)); + }) +} From 5756f27e1688de9324fa987eaac3ce728d616a14 Mon Sep 17 00:00:00 2001 From: alt3r 3go Date: Sun, 12 Dec 2021 15:20:01 +0100 Subject: [PATCH 12/47] WIP: RSA lib integration - part 4 (DeriveKey+test) Signed-off-by: alt3r 3go --- src/client/mechanisms.rs | 13 +++++++ src/config.rs | 3 +- src/mechanisms/rsa2kpkcs.rs | 73 ++++++++++++++++++++++++++----------- src/store/keystore.rs | 6 ++- tests/rsa2kpkcs.rs | 21 +++++++++-- 5 files changed, 88 insertions(+), 28 deletions(-) diff --git a/src/client/mechanisms.rs b/src/client/mechanisms.rs index f7676a54895..d301dcc9505 100644 --- a/src/client/mechanisms.rs +++ b/src/client/mechanisms.rs @@ -398,6 +398,19 @@ pub trait Rsa2kPkcs: CryptoClient { StorageAttributes::new().set_persistence(persistence), ) } + + fn derive_rsa2kpkcs_public_key( + &mut self, + shared_key: KeyId, + persistence: Location, + ) -> ClientResult<'_, reply::DeriveKey, Self> { + self.derive_key( + Mechanism::Rsa2kPkcs, + shared_key, + None, + StorageAttributes::new().set_persistence(persistence), + ) + } } #[cfg(feature = "sha256")] diff --git a/src/config.rs b/src/config.rs index d20d2274516..7368b973fbf 100644 --- a/src/config.rs +++ b/src/config.rs @@ -49,7 +49,8 @@ pub const MAX_SHORT_DATA_LENGTH: usize = 128; #[cfg(any(feature = "rsa2k-pkcs", feature = "rsa3k", feature = "rsa4k"))] pub const MAX_SIGNATURE_LENGTH: usize = 512; #[cfg(any(feature = "rsa2k-pkcs", feature = "rsa3k", feature = "rsa4k"))] -pub const MAX_KEY_MATERIAL_LENGTH: usize = 2 * 609; //TODO: We use PKCS#8 DER format, this value found empirically for 2K keys. Need to generalize. +//TODO: We use PKCS#8 DER format, this value was found empirically for 2K keys. Need to generalize. +pub const MAX_KEY_MATERIAL_LENGTH: usize = 1217; #[cfg(not(any(feature = "rsa2k-pkcs", feature = "rsa3k", feature = "rsa4k")))] pub const MAX_SIGNATURE_LENGTH: usize = 72; diff --git a/src/mechanisms/rsa2kpkcs.rs b/src/mechanisms/rsa2kpkcs.rs index abff955204e..7a77bc23672 100644 --- a/src/mechanisms/rsa2kpkcs.rs +++ b/src/mechanisms/rsa2kpkcs.rs @@ -1,6 +1,9 @@ use core::convert::{TryFrom, TryInto}; -use rsa::{pkcs8::ToPrivateKey, RsaPrivateKey}; +use rsa::{ + pkcs8::{FromPrivateKey, ToPrivateKey, ToPublicKey}, + RsaPrivateKey, RsaPublicKey, +}; use crate::api::*; // use crate::config::*; @@ -43,22 +46,42 @@ use crate::types::*; #[cfg(feature = "rsa2k-pkcs")] impl DeriveKey for super::Rsa2kPkcs { - // #[inline(never)] - // fn derive_key(keystore: &mut impl Keystore, request: &request::DeriveKey) - // -> Result - // { - // let base_id = &request.base_key; - // let keypair = load_keypair(keystore, base_id)?; + #[inline(never)] + fn derive_key( + keystore: &mut impl Keystore, + request: &request::DeriveKey, + ) -> Result { + // Retrieve private key + let base_key_id = &request.base_key; - // let public_id = keystore.store_key( - // request.attributes.persistence, - // key::Secrecy::Public, key::Kind::Rsa2k, - // keypair.public.as_bytes())?; + // std::println!("Loading key: {:?}", base_key_id); - // Ok(reply::DeriveKey { - // key: public_id, - // }) - // } + let priv_key_der = keystore + .load_key(key::Secrecy::Secret, Some(key::Kind::Rsa2k), base_key_id) + .expect("Failed to load an RSA 2K private key with the given ID") + .material; + + // std::println!("Loaded key material: {}", delog::hex_str!(&priv_key_der)); + // std::println!("Key material length is {}", priv_key_der.len()); + + let priv_key = FromPrivateKey::from_pkcs8_der(&priv_key_der) + .expect("Failed to deserialize an RSA 2K private key from PKCS#8 DER"); + + // Derive and store public key + let pub_key_der = RsaPublicKey::from(&priv_key) + .to_public_key_der() + .expect("Failed to derive an RSA 2K public key or to serialize it to PKCS#8 DER"); + + let pub_key_id = keystore.store_key( + request.attributes.persistence, + key::Secrecy::Public, + key::Kind::Rsa2k, + pub_key_der.as_ref(), + )?; + + // Send a reply + Ok(reply::DeriveKey { key: pub_key_id }) + } } #[cfg(feature = "rsa2k-pkcs")] @@ -105,24 +128,30 @@ impl GenerateKey for super::Rsa2kPkcs { // We want an RSA 2K key let bits = 2048; - let private_key = RsaPrivateKey::new(keystore.rng(), bits) - .expect("Failed to generate the RSA 2K private key"); - let pk_der = ToPrivateKey::to_pkcs8_der(&private_key) - .expect("Failed to serialize the RSA 2K private key to PKCS#8 DER"); + let priv_key = RsaPrivateKey::new(keystore.rng(), bits) + .expect("Failed to generate an RSA 2K private key"); + + // std::println!("Stored key material before DER: {:#?}", priv_key); + + let priv_key_der = priv_key + .to_pkcs8_der() + .expect("Failed to serialize an RSA 2K private key to PKCS#8 DER"); + // std::println!("Stored key material after DER: {}", delog::hex_str!(&priv_key_der)); + // std::println!("Key material length is {}", priv_key_der.as_ref().len()); // #[cfg(all(test, feature = "verbose-tests"))] // std::println!("rsa2k-pkcs private key = {:?}", &private_key); // store the key - let key_id = keystore.store_key( + let priv_key_id = keystore.store_key( request.attributes.persistence, key::Secrecy::Secret, key::Info::from(key::Kind::Rsa2k).with_local_flag(), - pk_der.as_ref(), + priv_key_der.as_ref(), )?; // return handle - Ok(reply::GenerateKey { key: key_id }) + Ok(reply::GenerateKey { key: priv_key_id }) } } diff --git a/src/store/keystore.rs b/src/store/keystore.rs index 06ab28d1b8b..33722f0a735 100644 --- a/src/store/keystore.rs +++ b/src/store/keystore.rs @@ -2,6 +2,7 @@ use littlefs2::path::PathBuf; use rand_chacha::ChaCha8Rng; use crate::{ + config::MAX_SERIALIZED_KEY_LENGTH, error::{Error, Result}, key, store::{self, Store}, @@ -172,11 +173,12 @@ impl Keystore for ClientKeystore { let location = self.location(secrecy, id).ok_or(Error::NoSuchKey)?; - //TODO: This should better be defined in some way, instead of hardcoding + //TODO: This should better be defined in some way, instead of hardcoding. + // I've tried referring to MAX_SERIALIZED_KEY_LENGTH, is this a good idea? #[cfg(not(feature = "rsa2k-pkcs"))] let bytes: Bytes<128> = store::read(self.store, location, &path)?; #[cfg(feature = "rsa2k-pkcs")] - let bytes: Bytes<512> = store::read(self.store, location, &path)?; + let bytes: Bytes = store::read(self.store, location, &path)?; let key = key::Key::try_deserialize(&bytes)?; diff --git a/tests/rsa2kpkcs.rs b/tests/rsa2kpkcs.rs index 57cb2146dc7..1b80663cc14 100644 --- a/tests/rsa2kpkcs.rs +++ b/tests/rsa2kpkcs.rs @@ -1,4 +1,3 @@ -use generic_array::typenum::assert_type; use trussed::client::mechanisms::Rsa2kPkcs; use trussed::syscall; use trussed::types::KeyId; @@ -7,13 +6,29 @@ mod client; use trussed::types::Location::*; +// TODO: Looks like the test infra is not supposed to be used with several tests like below - +// right now it randomly fails with SIGSERV on either of the two, when run together, +// but never when run separately. Need to investigate and fix. + #[test] fn rsa2kpkcs_generate_key() { client::get(|client| { let sk = syscall!(client.generate_rsa2kpkcs_private_key(Internal)).key; - // This assumes we don't really get they key with ID 0 - // TODO: make sure the above always holds + // This assumes we don't ever get a key with ID 0 + // TODO: make sure the above always holds or find a better way to check for success assert_ne!(sk, KeyId::from_special(0)); }) } + +#[test] +fn rsa2kpkcs_derive_key() { + client::get(|client| { + let sk = syscall!(client.generate_rsa2kpkcs_private_key(Internal)).key; + let pk = syscall!(client.derive_rsa2kpkcs_public_key(sk, Volatile)).key; + + // This assumes we don't ever get a key with ID 0 + // TODO: make sure the above always holds or find a better way to check for success + assert_ne!(pk, KeyId::from_special(0)); + }) +} From 22478efef49755c06ac4b16cd3f24e5dd7fb3be6 Mon Sep 17 00:00:00 2001 From: alt3r 3go Date: Sun, 19 Dec 2021 20:03:54 +0100 Subject: [PATCH 13/47] WIP: RSA lib integration - part 5 (Exists/{De}SerializeKey+tests) Signed-off-by: alt3r 3go --- src/client/mechanisms.rs | 17 ++++++++ src/config.rs | 11 +++-- src/mechanisms/rsa2kpkcs.rs | 80 +++++++++++++++++++------------------ tests/rsa2kpkcs.rs | 48 ++++++++++++++++++++++ 4 files changed, 115 insertions(+), 41 deletions(-) diff --git a/src/client/mechanisms.rs b/src/client/mechanisms.rs index d301dcc9505..0a0cce625cf 100644 --- a/src/client/mechanisms.rs +++ b/src/client/mechanisms.rs @@ -411,6 +411,23 @@ pub trait Rsa2kPkcs: CryptoClient { StorageAttributes::new().set_persistence(persistence), ) } + + fn serialize_rsa2kpkcs_key( + &mut self, + key: KeyId, + format: KeySerialization, + ) -> ClientResult<'_, reply::SerializeKey, Self> { + self.serialize_key(Mechanism::Rsa2kPkcs, key, format) + } + + fn deserialize_rsa2kpkcs_key<'c>( + &'c mut self, + serialized_key: &[u8], + format: KeySerialization, + attributes: StorageAttributes, + ) -> ClientResult<'c, reply::DeserializeKey, Self> { + self.deserialize_key(Mechanism::Rsa2kPkcs, serialized_key, format, attributes) + } } #[cfg(feature = "sha256")] diff --git a/src/config.rs b/src/config.rs index 7368b973fbf..749eb545750 100644 --- a/src/config.rs +++ b/src/config.rs @@ -8,7 +8,6 @@ use littlefs2::consts; pub type MAX_APPLICATION_NAME_LENGTH = consts::U256; pub const MAX_LONG_DATA_LENGTH: usize = 1024; -pub const MAX_MESSAGE_LENGTH: usize = 1024; pub type MAX_OBJECT_HANDLES = consts::U16; pub type MAX_LABEL_LENGTH = consts::U256; pub const MAX_MEDIUM_DATA_LENGTH: usize = 256; @@ -45,17 +44,23 @@ cfg_if::cfg_if! { } pub const MAX_SHORT_DATA_LENGTH: usize = 128; -//TODO: Do we want better keylength granularity here? +// TODO: Do we want better keylength granularity here? #[cfg(any(feature = "rsa2k-pkcs", feature = "rsa3k", feature = "rsa4k"))] pub const MAX_SIGNATURE_LENGTH: usize = 512; #[cfg(any(feature = "rsa2k-pkcs", feature = "rsa3k", feature = "rsa4k"))] -//TODO: We use PKCS#8 DER format, this value was found empirically for 2K keys. Need to generalize. +// TODO: We use PKCS#8 DER format, this value was found empirically for 2K keys. Need to generalize. pub const MAX_KEY_MATERIAL_LENGTH: usize = 1217; +#[cfg(any(feature = "rsa2k-pkcs", feature = "rsa3k", feature = "rsa4k"))] +// TODO: This is due to the fact that KEY_MATERIAL_LENGTH is now bigger than MESSAGE_LENGTH. +// Double-check this is okay. +pub const MAX_MESSAGE_LENGTH: usize = MAX_KEY_MATERIAL_LENGTH; #[cfg(not(any(feature = "rsa2k-pkcs", feature = "rsa3k", feature = "rsa4k")))] pub const MAX_SIGNATURE_LENGTH: usize = 72; #[cfg(not(any(feature = "rsa2k-pkcs", feature = "rsa3k", feature = "rsa4k")))] pub const MAX_KEY_MATERIAL_LENGTH: usize = 128; +#[cfg(not(any(feature = "rsa2k-pkcs", feature = "rsa3k", feature = "rsa4k")))] +pub const MAX_MESSAGE_LENGTH: usize = 1024; // must be MAX_KEY_MATERIAL_LENGTH + 4 pub const MAX_SERIALIZED_KEY_LENGTH: usize = MAX_KEY_MATERIAL_LENGTH + 4; diff --git a/src/mechanisms/rsa2kpkcs.rs b/src/mechanisms/rsa2kpkcs.rs index 7a77bc23672..565cf7ae0ea 100644 --- a/src/mechanisms/rsa2kpkcs.rs +++ b/src/mechanisms/rsa2kpkcs.rs @@ -99,22 +99,24 @@ impl DeserializeKey for super::Rsa2kPkcs { return Err(Error::InternalError); } - if request.serialized_key.len() != 32 { - return Err(Error::InvalidSerializedKey); - } - - let serialized_key: [u8; 32] = request.serialized_key[..32].try_into().unwrap(); - let public_key = salty::signature::PublicKey::try_from(&serialized_key) + let private_key: RsaPrivateKey = FromPrivateKey::from_pkcs8_der(&request.serialized_key) .map_err(|_| Error::InvalidSerializedKey)?; - let public_id = keystore.store_key( + // We store our keys in PKCS#8 DER format as well + let private_key_der = private_key + .to_pkcs8_der() + .expect("Failed to serialize an RSA 2K private key to PKCS#8 DER"); + + let private_key_id = keystore.store_key( request.attributes.persistence, - key::Secrecy::Public, + key::Secrecy::Secret, key::Kind::Rsa2k, - public_key.as_bytes(), + private_key_der.as_ref(), )?; - Ok(reply::DeserializeKey { key: public_id }) + Ok(reply::DeserializeKey { + key: private_key_id, + }) } } @@ -157,35 +159,37 @@ impl GenerateKey for super::Rsa2kPkcs { #[cfg(feature = "rsa2k-pkcs")] impl SerializeKey for super::Rsa2kPkcs { - // #[inline(never)] - // fn serialize_key(keystore: &mut impl Keystore, request: &request::SerializeKey) - // -> Result - // { - // let key_id = request.key; - // let public_key = load_public_key(keystore, &key_id)?; + #[inline(never)] + fn serialize_key( + keystore: &mut impl Keystore, + request: &request::SerializeKey, + ) -> Result { + let key_id = request.key; - // let serialized_key = match request.format { - // KeySerialization::Cose => { - // let cose_pk = cosey::Ed25519PublicKey { - // // x: Bytes::from_slice(public_key.x_coordinate()).unwrap(), - // // x: Bytes::from_slice(&buf).unwrap(), - // x: Bytes::from_slice(public_key.as_bytes()).unwrap(), - // }; - // crate::cbor_serialize_bytes(&cose_pk).map_err(|_| Error::CborError)? - // } - - // KeySerialization::Raw => { - // let mut serialized_key = Message::new(); - // serialized_key.extend_from_slice(public_key.as_bytes()).map_err(|_| Error::InternalError)?; - // // serialized_key.extend_from_slice(&buf).map_err(|_| Error::InternalError)?; - // serialized_key - // } - - // _ => { return Err(Error::InternalError); } - // }; - - // Ok(reply::SerializeKey { serialized_key }) - // } + // We rely on the fact that we store the keys in the PKCS#8 DER format already + let priv_key_der = keystore + .load_key(key::Secrecy::Secret, Some(key::Kind::Rsa2k), &key_id) + .expect("Failed to load an RSA 2K private key with the given ID") + .material; + + let serialized_key = match request.format { + // TODO: There are "Der" and "Asn1Der" commented out in KeySerialization enum, + // should those be used instead? + KeySerialization::Raw => { + let mut serialized_key = Message::new(); + serialized_key + .extend_from_slice(&priv_key_der) + .map_err(|_| Error::InternalError)?; + serialized_key + } + + _ => { + return Err(Error::InternalError); + } + }; + + Ok(reply::SerializeKey { serialized_key }) + } } #[cfg(feature = "rsa2k-pkcs")] diff --git a/tests/rsa2kpkcs.rs b/tests/rsa2kpkcs.rs index 1b80663cc14..1b207b71c73 100644 --- a/tests/rsa2kpkcs.rs +++ b/tests/rsa2kpkcs.rs @@ -1,10 +1,13 @@ use trussed::client::mechanisms::Rsa2kPkcs; +use trussed::client::CryptoClient; use trussed::syscall; use trussed::types::KeyId; mod client; +use trussed::types::KeySerialization; use trussed::types::Location::*; +use trussed::types::StorageAttributes; // TODO: Looks like the test infra is not supposed to be used with several tests like below - // right now it randomly fails with SIGSERV on either of the two, when run together, @@ -32,3 +35,48 @@ fn rsa2kpkcs_derive_key() { assert_ne!(pk, KeyId::from_special(0)); }) } + +#[test] +fn rsa2kpkcs_exists_key() { + client::get(|client| { + let sk = syscall!(client.generate_rsa2kpkcs_private_key(Internal)).key; + let key_exists = syscall!(client.exists(trussed::types::Mechanism::Rsa2kPkcs, sk)).exists; + + assert!(key_exists); + }) +} + +#[test] +fn rsa2kpkcs_serialize_key() { + client::get(|client| { + let sk = syscall!(client.generate_rsa2kpkcs_private_key(Internal)).key; + + let serialized_key = + syscall!(client.serialize_rsa2kpkcs_key(sk, KeySerialization::Raw)).serialized_key; + + assert!(!serialized_key.is_empty()); + }) +} + +#[test] +fn rsa2kpkcs_deserialize_key() { + client::get(|client| { + let sk = syscall!(client.generate_rsa2kpkcs_private_key(Internal)).key; + let serialized_key = + syscall!(client.serialize_rsa2kpkcs_key(sk, KeySerialization::Raw)).serialized_key; + let location = StorageAttributes { + persistence: Volatile, + }; + + let deserialized_key_id = syscall!(client.deserialize_rsa2kpkcs_key( + &serialized_key, + KeySerialization::Raw, + location + )) + .key; + + // This assumes we don't ever get a key with ID 0 + // TODO: make sure the above always holds or find a better way to check for success + assert_ne!(deserialized_key_id, KeyId::from_special(0)); + }) +} From 485e7807cb0552366282d9c3cae17ea8ebefee6a Mon Sep 17 00:00:00 2001 From: alt3r 3go Date: Sun, 23 Jan 2022 19:04:10 +0100 Subject: [PATCH 14/47] WIP: RSA lib integration - part 6 (Sign/Verify+tests) Signed-off-by: alt3r 3go --- src/client/mechanisms.rs | 28 ++++++++ src/mechanisms/rsa2kpkcs.rs | 125 +++++++++++++++++++++++------------- tests/rsa2kpkcs.rs | 20 ++++++ 3 files changed, 129 insertions(+), 44 deletions(-) diff --git a/src/client/mechanisms.rs b/src/client/mechanisms.rs index 0a0cce625cf..a1966895624 100644 --- a/src/client/mechanisms.rs +++ b/src/client/mechanisms.rs @@ -428,6 +428,34 @@ pub trait Rsa2kPkcs: CryptoClient { ) -> ClientResult<'c, reply::DeserializeKey, Self> { self.deserialize_key(Mechanism::Rsa2kPkcs, serialized_key, format, attributes) } + + fn sign_rsa2kpkcs<'c>( + &'c mut self, + key: KeyId, + message: &[u8], + ) -> ClientResult<'c, reply::Sign, Self> { + self.sign( + Mechanism::Rsa2kPkcs, + key, + message, + SignatureSerialization::Raw, + ) + } + + fn verify_rsa2kpkcs<'c>( + &'c mut self, + key: KeyId, + message: &[u8], + signature: &[u8], + ) -> ClientResult<'c, reply::Verify, Self> { + self.verify( + Mechanism::Rsa2kPkcs, + key, + message, + signature, + SignatureSerialization::Raw, + ) + } } #[cfg(feature = "sha256")] diff --git a/src/mechanisms/rsa2kpkcs.rs b/src/mechanisms/rsa2kpkcs.rs index 565cf7ae0ea..317efd67b62 100644 --- a/src/mechanisms/rsa2kpkcs.rs +++ b/src/mechanisms/rsa2kpkcs.rs @@ -1,8 +1,6 @@ -use core::convert::{TryFrom, TryInto}; - use rsa::{ pkcs8::{FromPrivateKey, ToPrivateKey, ToPublicKey}, - RsaPrivateKey, RsaPublicKey, + PublicKey, RsaPrivateKey, RsaPublicKey, }; use crate::api::*; @@ -208,54 +206,93 @@ impl Exists for super::Rsa2kPkcs { #[cfg(feature = "rsa2k-pkcs")] impl Sign for super::Rsa2kPkcs { - // #[inline(never)] - // fn sign(keystore: &mut impl Keystore, request: &request::Sign) - // -> Result - // { - - // let key_id = request.key; - - // let keypair = load_keypair(keystore, &key_id)?; + #[inline(never)] + fn sign(keystore: &mut impl Keystore, request: &request::Sign) -> Result { + // First, get the key + let key_id = request.key; - // let native_signature = keypair.sign(&request.message); - // let our_signature = Signature::from_slice(&native_signature.to_bytes()).unwrap(); + // We rely on the fact that we store the keys in the PKCS#8 DER format already + let priv_key_der = keystore + .load_key(key::Secrecy::Secret, Some(key::Kind::Rsa2k), &key_id) + .expect("Failed to load an RSA 2K private key with the given ID") + .material; - // // hprintln!("RSA2K-PKCS_v1.5 signature:").ok(); - // // hprintln!("msg: {:?}", &request.message).ok(); - // // hprintln!("pk: {:?}", &keypair.public.as_bytes()).ok(); - // // hprintln!("sig: {:?}", &our_signature).ok(); + let priv_key: RsaPrivateKey = FromPrivateKey::from_pkcs8_der(&priv_key_der) + .expect("Failed to deserialize an RSA 2K private key from PKCS#8 DER"); - // // return signature - // Ok(reply::Sign { signature: our_signature }) - // } + // RSA lib takes in a hash value to sign, not raw data. + // TODO: Do we assume we get digest into this function, or we calculate it ourselves? + // use sha2::digest::Digest; + // let digest_to_sign: [u8; 32] = sha2::Sha256::digest(&request.message).into(); + + // TODO: there's also .sign_blinded(), which is supposed to protect the private key from timing side channels, + // but requires an RNG instance - decide if we want to always use it. + use rsa::hash::Hash; + use rsa::padding::PaddingScheme; + let native_signature = priv_key + .sign( + PaddingScheme::new_pkcs1v15_sign(Some(Hash::SHA2_256)), + &request.message, + ) + .unwrap(); + let our_signature = Signature::from_slice(&native_signature).unwrap(); + + // std::println!("RSA2K-PKCS_v1.5 signature:"); + // std::println!("msg: {:?}", &request.message); + // std::println!("pk: {:?}", &priv_key); + // std::println!("sig: {:?}", &our_signature); + + // return signature + Ok(reply::Sign { + signature: our_signature, + }) + } } #[cfg(feature = "rsa2k-pkcs")] impl Verify for super::Rsa2kPkcs { - // #[inline(never)] - // fn verify(keystore: &mut impl Keystore, request: &request::Verify) - // -> Result - // { - // if let SignatureSerialization::Raw = request.format { - // } else { - // return Err(Error::InvalidSerializationFormat); - // } - - // if request.signature.len() != salty::constants::SIGNATURE_SERIALIZED_LENGTH { - // return Err(Error::WrongSignatureLength); - // } - - // let key_id = request.key; - // let public_key = load_public_key(keystore, &key_id)?; - - // let mut signature_array = [0u8; salty::constants::SIGNATURE_SERIALIZED_LENGTH]; - // signature_array.copy_from_slice(request.signature.as_ref()); - // let salty_signature = salty::signature::Signature::from(&signature_array); - - // Ok(reply::Verify { valid: - // public_key.verify(&request.message, &salty_signature).is_ok() - // }) - // } + #[inline(never)] + fn verify( + keystore: &mut impl Keystore, + request: &request::Verify, + ) -> Result { + if let SignatureSerialization::Raw = request.format { + } else { + return Err(Error::InvalidSerializationFormat); + } + + // TODO: This must not be a hardcoded magic number, need to generalize + if request.signature.len() != 256 { + return Err(Error::WrongSignatureLength); + } + + let key_id = request.key; + + let priv_key_der = keystore + .load_key(key::Secrecy::Secret, Some(key::Kind::Rsa2k), &key_id) + .expect("Failed to load an RSA 2K private key with the given ID") + .material; + + let priv_key = FromPrivateKey::from_pkcs8_der(&priv_key_der) + .expect("Failed to deserialize an RSA 2K private key from PKCS#8 DER"); + + // Get the public key + let pub_key = RsaPublicKey::from(&priv_key); + + use rsa::hash::Hash; + use rsa::padding::PaddingScheme; + let verification_ok = pub_key + .verify( + PaddingScheme::new_pkcs1v15_sign(Some(Hash::SHA2_256)), + &request.message, + &request.signature, + ) + .is_ok(); + + Ok(reply::Verify { + valid: verification_ok, + }) + } } #[cfg(not(feature = "rsa2k-pkcs"))] diff --git a/tests/rsa2kpkcs.rs b/tests/rsa2kpkcs.rs index 1b207b71c73..a7000517221 100644 --- a/tests/rsa2kpkcs.rs +++ b/tests/rsa2kpkcs.rs @@ -80,3 +80,23 @@ fn rsa2kpkcs_deserialize_key() { assert_ne!(deserialized_key_id, KeyId::from_special(0)); }) } + +#[test] +fn rsa2kpkcs_sign_verify() { + client::get(|client| { + let sk = syscall!(client.generate_rsa2kpkcs_private_key(Volatile)).key; + + let message = [1u8, 2u8, 3u8]; + use sha2::digest::Digest; + let digest_to_sign = sha2::Sha256::digest(&message); + let signature = syscall!(client.sign_rsa2kpkcs(sk, &digest_to_sign)).signature; + + // println!("Message: {:?}", &message); + // println!("Digest: {:?}", &digest_to_sign); + // println!("Signature (len={}): {:?}", signature.len(), &signature); + + let verify_ok = syscall!(client.verify_rsa2kpkcs(sk, &digest_to_sign, &signature)).valid; + + assert!(signature.len() == 256 && verify_ok); + }) +} From 1dfe0b688467b4565f8a63dc30ff470eb2905eaf Mon Sep 17 00:00:00 2001 From: alt3r 3go Date: Mon, 11 Jul 2022 12:59:30 +0200 Subject: [PATCH 15/47] WIP: remove unneeded code, mark my TODOs for simpler discovery Signed-off-by: alt3r 3go --- src/config.rs | 8 +++---- src/mechanisms/rsa2kpkcs.rs | 44 +++++-------------------------------- src/store/keystore.rs | 4 ++-- tests/rsa2kpkcs.rs | 12 +++++----- 4 files changed, 18 insertions(+), 50 deletions(-) diff --git a/src/config.rs b/src/config.rs index 749eb545750..850ec4556e6 100644 --- a/src/config.rs +++ b/src/config.rs @@ -44,15 +44,15 @@ cfg_if::cfg_if! { } pub const MAX_SHORT_DATA_LENGTH: usize = 128; -// TODO: Do we want better keylength granularity here? +// TODO:alt3r-3go: Do we want better keylength granularity here? #[cfg(any(feature = "rsa2k-pkcs", feature = "rsa3k", feature = "rsa4k"))] pub const MAX_SIGNATURE_LENGTH: usize = 512; #[cfg(any(feature = "rsa2k-pkcs", feature = "rsa3k", feature = "rsa4k"))] -// TODO: We use PKCS#8 DER format, this value was found empirically for 2K keys. Need to generalize. +// TODO:alt3r-3go: We use PKCS#8 DER format, this value was found empirically for 2K keys. Need to generalize. pub const MAX_KEY_MATERIAL_LENGTH: usize = 1217; #[cfg(any(feature = "rsa2k-pkcs", feature = "rsa3k", feature = "rsa4k"))] -// TODO: This is due to the fact that KEY_MATERIAL_LENGTH is now bigger than MESSAGE_LENGTH. -// Double-check this is okay. +// TODO:alt3r-3go: This is due to the fact that KEY_MATERIAL_LENGTH is now bigger than MESSAGE_LENGTH. +// Double-check this is okay. pub const MAX_MESSAGE_LENGTH: usize = MAX_KEY_MATERIAL_LENGTH; #[cfg(not(any(feature = "rsa2k-pkcs", feature = "rsa3k", feature = "rsa4k")))] diff --git a/src/mechanisms/rsa2kpkcs.rs b/src/mechanisms/rsa2kpkcs.rs index 317efd67b62..d7adf34af1f 100644 --- a/src/mechanisms/rsa2kpkcs.rs +++ b/src/mechanisms/rsa2kpkcs.rs @@ -10,38 +10,6 @@ use crate::error::Error; use crate::service::*; use crate::types::*; -// #[inline(never)] -// fn load_public_key(keystore: &mut impl Keystore, key_id: &KeyId) -// -> Result { - -// //TODO: The key size should better be defined somewhere instead of hardcoding -// let public_bytes: [u8; 512] = keystore -// .load_key(key::Secrecy::Public, Some(key::Kind::Rsa2k), &key_id)? -// .material.as_slice() -// .try_into() -// .map_err(|_| Error::InternalError)?; - -// // let public_key = salty::signature::PublicKey::try_from(&public_bytes).map_err(|_| Error::InternalError)?; -// let public_key = rsa::RsaPublicKey::try_from(&public_bytes).map_err(|_| Error::InternalError)?; - -// Ok(public_key) -// } - -// #[inline(never)] -// fn load_keypair(keystore: &mut impl Keystore, key_id: &KeyId) -// -> Result { - -// let seed: [u8; 32] = keystore -// .load_key(key::Secrecy::Secret, Some(key::Kind::Rsa2k), &key_id)? -// .material.as_slice() -// .try_into() -// .map_err(|_| Error::InternalError)?; - -// let keypair = salty::signature::Keypair::from(&seed); -// // hprintln!("seed: {:?}", &seed).ok(); -// Ok(keypair) -// } - #[cfg(feature = "rsa2k-pkcs")] impl DeriveKey for super::Rsa2kPkcs { #[inline(never)] @@ -171,8 +139,8 @@ impl SerializeKey for super::Rsa2kPkcs { .material; let serialized_key = match request.format { - // TODO: There are "Der" and "Asn1Der" commented out in KeySerialization enum, - // should those be used instead? + // TODO:alt3r-3go: There are "Der" and "Asn1Der" commented out in KeySerialization enum, + // should those be used instead? KeySerialization::Raw => { let mut serialized_key = Message::new(); serialized_key @@ -221,12 +189,12 @@ impl Sign for super::Rsa2kPkcs { .expect("Failed to deserialize an RSA 2K private key from PKCS#8 DER"); // RSA lib takes in a hash value to sign, not raw data. - // TODO: Do we assume we get digest into this function, or we calculate it ourselves? + // TODO:alt3r-3go: Do we assume we get digest into this function, or we calculate it ourselves? // use sha2::digest::Digest; // let digest_to_sign: [u8; 32] = sha2::Sha256::digest(&request.message).into(); - // TODO: there's also .sign_blinded(), which is supposed to protect the private key from timing side channels, - // but requires an RNG instance - decide if we want to always use it. + // TODO:alt3r-3go: There's also .sign_blinded(), which is supposed to protect the private key from timing side channels, + // but requires an RNG instance - decide if we want to always use it. use rsa::hash::Hash; use rsa::padding::PaddingScheme; let native_signature = priv_key @@ -261,7 +229,7 @@ impl Verify for super::Rsa2kPkcs { return Err(Error::InvalidSerializationFormat); } - // TODO: This must not be a hardcoded magic number, need to generalize + // TODO:alt3r-3go: This must not be a hardcoded magic number, need to generalize if request.signature.len() != 256 { return Err(Error::WrongSignatureLength); } diff --git a/src/store/keystore.rs b/src/store/keystore.rs index 33722f0a735..ab864709c9c 100644 --- a/src/store/keystore.rs +++ b/src/store/keystore.rs @@ -173,8 +173,8 @@ impl Keystore for ClientKeystore { let location = self.location(secrecy, id).ok_or(Error::NoSuchKey)?; - //TODO: This should better be defined in some way, instead of hardcoding. - // I've tried referring to MAX_SERIALIZED_KEY_LENGTH, is this a good idea? + //TODO:alt3r-3go: This should better be defined in some way, instead of hardcoding. + // I've tried referring to MAX_SERIALIZED_KEY_LENGTH, is this a good idea? #[cfg(not(feature = "rsa2k-pkcs"))] let bytes: Bytes<128> = store::read(self.store, location, &path)?; #[cfg(feature = "rsa2k-pkcs")] diff --git a/tests/rsa2kpkcs.rs b/tests/rsa2kpkcs.rs index a7000517221..43936835751 100644 --- a/tests/rsa2kpkcs.rs +++ b/tests/rsa2kpkcs.rs @@ -9,9 +9,9 @@ use trussed::types::KeySerialization; use trussed::types::Location::*; use trussed::types::StorageAttributes; -// TODO: Looks like the test infra is not supposed to be used with several tests like below - -// right now it randomly fails with SIGSERV on either of the two, when run together, -// but never when run separately. Need to investigate and fix. +// TODO:alt3r-3go: Looks like the test infra is not supposed to be used with several tests like below - +// right now it randomly fails with SIGSERV on either of the two, when run together, +// but never when run separately. Need to investigate and fix. #[test] fn rsa2kpkcs_generate_key() { @@ -19,7 +19,7 @@ fn rsa2kpkcs_generate_key() { let sk = syscall!(client.generate_rsa2kpkcs_private_key(Internal)).key; // This assumes we don't ever get a key with ID 0 - // TODO: make sure the above always holds or find a better way to check for success + // TODO:alt3r-3go: make sure the above always holds or find a better way to check for success assert_ne!(sk, KeyId::from_special(0)); }) } @@ -31,7 +31,7 @@ fn rsa2kpkcs_derive_key() { let pk = syscall!(client.derive_rsa2kpkcs_public_key(sk, Volatile)).key; // This assumes we don't ever get a key with ID 0 - // TODO: make sure the above always holds or find a better way to check for success + // TODO:alt3r-3go: make sure the above always holds or find a better way to check for success assert_ne!(pk, KeyId::from_special(0)); }) } @@ -76,7 +76,7 @@ fn rsa2kpkcs_deserialize_key() { .key; // This assumes we don't ever get a key with ID 0 - // TODO: make sure the above always holds or find a better way to check for success + // TODO:alt3r-3go: make sure the above always holds or find a better way to check for success assert_ne!(deserialized_key_id, KeyId::from_special(0)); }) } From 56c9c71cb58bb027e812d5526fe0692de7dc45e8 Mon Sep 17 00:00:00 2001 From: alt3r 3go Date: Sun, 17 Jul 2022 13:30:03 +0200 Subject: [PATCH 16/47] WIP: Rebase to current trussed/main, cleanup Signed-off-by: alt3r 3go --- src/config.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/config.rs b/src/config.rs index 850ec4556e6..a438795ed2b 100644 --- a/src/config.rs +++ b/src/config.rs @@ -14,7 +14,7 @@ pub const MAX_MEDIUM_DATA_LENGTH: usize = 256; pub type MAX_PATH_LENGTH = consts::U256; //pub const MAX_KEY_MATERIAL_LENGTH: usize = 128; // must be above + 4 -pub const MAX_SERIALIZED_KEY_LENGTH: usize = 132; +//pub const MAX_SERIALIZED_KEY_LENGTH: usize = 132; cfg_if::cfg_if! { if #[cfg(feature = "clients-12")] { pub type MAX_SERVICE_CLIENTS = consts::U12; From 5cd3b6d27279c2ccca13e803331e1e967955201c Mon Sep 17 00:00:00 2001 From: alt3r 3go Date: Sun, 17 Jul 2022 13:59:07 +0200 Subject: [PATCH 17/47] WIP: update RSA traits after updating to 0.6.0 Signed-off-by: alt3r 3go --- src/mechanisms/rsa2kpkcs.rs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/mechanisms/rsa2kpkcs.rs b/src/mechanisms/rsa2kpkcs.rs index d7adf34af1f..2526b88dd01 100644 --- a/src/mechanisms/rsa2kpkcs.rs +++ b/src/mechanisms/rsa2kpkcs.rs @@ -1,5 +1,5 @@ use rsa::{ - pkcs8::{FromPrivateKey, ToPrivateKey, ToPublicKey}, + pkcs8::{DecodePrivateKey, EncodePrivateKey, EncodePublicKey}, PublicKey, RsaPrivateKey, RsaPublicKey, }; @@ -10,6 +10,10 @@ use crate::error::Error; use crate::service::*; use crate::types::*; +//TODO:alt3r-3go: sign() and verify() are the only two methods that are actually different between -pkcs and -pss. +// Moreover, the key::Kind::Rsa2K could also probably be parametrized, instead of having a dedicated kind +// for each. Overall this means the class structure can probably be simplified - need to decide. + #[cfg(feature = "rsa2k-pkcs")] impl DeriveKey for super::Rsa2kPkcs { #[inline(never)] @@ -30,7 +34,7 @@ impl DeriveKey for super::Rsa2kPkcs { // std::println!("Loaded key material: {}", delog::hex_str!(&priv_key_der)); // std::println!("Key material length is {}", priv_key_der.len()); - let priv_key = FromPrivateKey::from_pkcs8_der(&priv_key_der) + let priv_key = DecodePrivateKey::from_pkcs8_der(&priv_key_der) .expect("Failed to deserialize an RSA 2K private key from PKCS#8 DER"); // Derive and store public key @@ -65,7 +69,7 @@ impl DeserializeKey for super::Rsa2kPkcs { return Err(Error::InternalError); } - let private_key: RsaPrivateKey = FromPrivateKey::from_pkcs8_der(&request.serialized_key) + let private_key: RsaPrivateKey = DecodePrivateKey::from_pkcs8_der(&request.serialized_key) .map_err(|_| Error::InvalidSerializedKey)?; // We store our keys in PKCS#8 DER format as well @@ -185,7 +189,7 @@ impl Sign for super::Rsa2kPkcs { .expect("Failed to load an RSA 2K private key with the given ID") .material; - let priv_key: RsaPrivateKey = FromPrivateKey::from_pkcs8_der(&priv_key_der) + let priv_key: RsaPrivateKey = DecodePrivateKey::from_pkcs8_der(&priv_key_der) .expect("Failed to deserialize an RSA 2K private key from PKCS#8 DER"); // RSA lib takes in a hash value to sign, not raw data. @@ -241,7 +245,7 @@ impl Verify for super::Rsa2kPkcs { .expect("Failed to load an RSA 2K private key with the given ID") .material; - let priv_key = FromPrivateKey::from_pkcs8_der(&priv_key_der) + let priv_key = DecodePrivateKey::from_pkcs8_der(&priv_key_der) .expect("Failed to deserialize an RSA 2K private key from PKCS#8 DER"); // Get the public key From fcdf318e69052feb200e3199b3c98914fd391980 Mon Sep 17 00:00:00 2001 From: alt3r 3go Date: Sun, 31 Jul 2022 15:57:39 +0200 Subject: [PATCH 18/47] WIP: Address review comments - 1 In a separate commit for better visibility. Removed addressed TODOs, reworded those that should stay for later (magic numbers), rebased to the latest "main". Signed-off-by: alt3r 3go --- Cargo.toml | 6 ++-- src/client/mechanisms.rs | 2 +- src/config.rs | 18 +++++------ src/mechanisms.rs | 3 +- src/mechanisms/{rsa2kpkcs.rs => rsa2k.rs} | 39 +++++++++-------------- src/store/keystore.rs | 6 ++-- src/types.rs | 7 ++-- tests/rsa2kpkcs.rs | 7 +--- 8 files changed, 36 insertions(+), 52 deletions(-) rename src/mechanisms/{rsa2kpkcs.rs => rsa2k.rs} (84%) diff --git a/Cargo.toml b/Cargo.toml index ebe5bfd9aac..75d753de2fb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -89,9 +89,7 @@ default-mechanisms = [ "tdes", "totp", "trng", - "rsa2k-pkcs", - "rsa3k", - "rsa4k" + "rsa2k" ] aes256-cbc = [] chacha8-poly1305 = [] @@ -106,7 +104,7 @@ sha256 = [] tdes = ["des"] totp = ["sha-1"] trng = ["sha-1"] -rsa2k-pkcs = ["rsa"] +rsa2k = ["rsa"] rsa3k = ["rsa"] rsa4k = ["rsa"] diff --git a/src/client/mechanisms.rs b/src/client/mechanisms.rs index a1966895624..7715f165fc0 100644 --- a/src/client/mechanisms.rs +++ b/src/client/mechanisms.rs @@ -385,7 +385,7 @@ pub trait P256: CryptoClient { } } -#[cfg(feature = "rsa2k-pkcs")] +#[cfg(feature = "rsa2k")] impl Rsa2kPkcs for ClientImplementation {} pub trait Rsa2kPkcs: CryptoClient { diff --git a/src/config.rs b/src/config.rs index a438795ed2b..2e7109358fd 100644 --- a/src/config.rs +++ b/src/config.rs @@ -44,22 +44,20 @@ cfg_if::cfg_if! { } pub const MAX_SHORT_DATA_LENGTH: usize = 128; -// TODO:alt3r-3go: Do we want better keylength granularity here? -#[cfg(any(feature = "rsa2k-pkcs", feature = "rsa3k", feature = "rsa4k"))] +#[cfg(any(feature = "rsa2k", feature = "rsa3k", feature = "rsa4k"))] pub const MAX_SIGNATURE_LENGTH: usize = 512; -#[cfg(any(feature = "rsa2k-pkcs", feature = "rsa3k", feature = "rsa4k"))] -// TODO:alt3r-3go: We use PKCS#8 DER format, this value was found empirically for 2K keys. Need to generalize. +#[cfg(any(feature = "rsa2k", feature = "rsa3k", feature = "rsa4k"))] +// TODO: We use PKCS#8 DER format, this value was found empirically for 2K keys. Need to generalize. pub const MAX_KEY_MATERIAL_LENGTH: usize = 1217; -#[cfg(any(feature = "rsa2k-pkcs", feature = "rsa3k", feature = "rsa4k"))] -// TODO:alt3r-3go: This is due to the fact that KEY_MATERIAL_LENGTH is now bigger than MESSAGE_LENGTH. -// Double-check this is okay. +#[cfg(any(feature = "rsa2k", feature = "rsa3k", feature = "rsa4k"))] +// This is due to the fact that KEY_MATERIAL_LENGTH is bigger than MESSAGE_LENGTH for RSA. pub const MAX_MESSAGE_LENGTH: usize = MAX_KEY_MATERIAL_LENGTH; -#[cfg(not(any(feature = "rsa2k-pkcs", feature = "rsa3k", feature = "rsa4k")))] +#[cfg(not(any(feature = "rsa2k", feature = "rsa3k", feature = "rsa4k")))] pub const MAX_SIGNATURE_LENGTH: usize = 72; -#[cfg(not(any(feature = "rsa2k-pkcs", feature = "rsa3k", feature = "rsa4k")))] +#[cfg(not(any(feature = "rsa2k", feature = "rsa3k", feature = "rsa4k")))] pub const MAX_KEY_MATERIAL_LENGTH: usize = 128; -#[cfg(not(any(feature = "rsa2k-pkcs", feature = "rsa3k", feature = "rsa4k")))] +#[cfg(not(any(feature = "rsa2k", feature = "rsa3k", feature = "rsa4k")))] pub const MAX_MESSAGE_LENGTH: usize = 1024; // must be MAX_KEY_MATERIAL_LENGTH + 4 diff --git a/src/mechanisms.rs b/src/mechanisms.rs index 18a74044e14..d79a9819198 100644 --- a/src/mechanisms.rs +++ b/src/mechanisms.rs @@ -50,7 +50,8 @@ pub struct P256Prehashed {} mod p256; pub struct Rsa2kPkcs {} -mod rsa2kpkcs; +// Later on we'll add: "pub struct Rsa2kPss {}" and so on +mod rsa2k; pub struct Sha256 {} mod sha256; diff --git a/src/mechanisms/rsa2kpkcs.rs b/src/mechanisms/rsa2k.rs similarity index 84% rename from src/mechanisms/rsa2kpkcs.rs rename to src/mechanisms/rsa2k.rs index 2526b88dd01..ef8d56f71f5 100644 --- a/src/mechanisms/rsa2kpkcs.rs +++ b/src/mechanisms/rsa2k.rs @@ -10,11 +10,7 @@ use crate::error::Error; use crate::service::*; use crate::types::*; -//TODO:alt3r-3go: sign() and verify() are the only two methods that are actually different between -pkcs and -pss. -// Moreover, the key::Kind::Rsa2K could also probably be parametrized, instead of having a dedicated kind -// for each. Overall this means the class structure can probably be simplified - need to decide. - -#[cfg(feature = "rsa2k-pkcs")] +#[cfg(feature = "rsa2k")] impl DeriveKey for super::Rsa2kPkcs { #[inline(never)] fn derive_key( @@ -54,7 +50,7 @@ impl DeriveKey for super::Rsa2kPkcs { } } -#[cfg(feature = "rsa2k-pkcs")] +#[cfg(feature = "rsa2k")] impl DeserializeKey for super::Rsa2kPkcs { #[inline(never)] fn deserialize_key( @@ -72,7 +68,7 @@ impl DeserializeKey for super::Rsa2kPkcs { let private_key: RsaPrivateKey = DecodePrivateKey::from_pkcs8_der(&request.serialized_key) .map_err(|_| Error::InvalidSerializedKey)?; - // We store our keys in PKCS#8 DER format as well + // We store our keys in PKCS#8 DER format let private_key_der = private_key .to_pkcs8_der() .expect("Failed to serialize an RSA 2K private key to PKCS#8 DER"); @@ -90,7 +86,7 @@ impl DeserializeKey for super::Rsa2kPkcs { } } -#[cfg(feature = "rsa2k-pkcs")] +#[cfg(feature = "rsa2k")] impl GenerateKey for super::Rsa2kPkcs { #[inline(never)] fn generate_key( @@ -127,7 +123,7 @@ impl GenerateKey for super::Rsa2kPkcs { } } -#[cfg(feature = "rsa2k-pkcs")] +#[cfg(feature = "rsa2k")] impl SerializeKey for super::Rsa2kPkcs { #[inline(never)] fn serialize_key( @@ -143,8 +139,6 @@ impl SerializeKey for super::Rsa2kPkcs { .material; let serialized_key = match request.format { - // TODO:alt3r-3go: There are "Der" and "Asn1Der" commented out in KeySerialization enum, - // should those be used instead? KeySerialization::Raw => { let mut serialized_key = Message::new(); serialized_key @@ -162,7 +156,7 @@ impl SerializeKey for super::Rsa2kPkcs { } } -#[cfg(feature = "rsa2k-pkcs")] +#[cfg(feature = "rsa2k")] impl Exists for super::Rsa2kPkcs { #[inline(never)] fn exists( @@ -176,7 +170,7 @@ impl Exists for super::Rsa2kPkcs { } } -#[cfg(feature = "rsa2k-pkcs")] +#[cfg(feature = "rsa2k")] impl Sign for super::Rsa2kPkcs { #[inline(never)] fn sign(keystore: &mut impl Keystore, request: &request::Sign) -> Result { @@ -193,12 +187,9 @@ impl Sign for super::Rsa2kPkcs { .expect("Failed to deserialize an RSA 2K private key from PKCS#8 DER"); // RSA lib takes in a hash value to sign, not raw data. - // TODO:alt3r-3go: Do we assume we get digest into this function, or we calculate it ourselves? - // use sha2::digest::Digest; - // let digest_to_sign: [u8; 32] = sha2::Sha256::digest(&request.message).into(); + // We assume we get digest into this function, too. - // TODO:alt3r-3go: There's also .sign_blinded(), which is supposed to protect the private key from timing side channels, - // but requires an RNG instance - decide if we want to always use it. + // TODO: Consider using .sign_blinded(), which is supposed to protect the private key from timing side channels use rsa::hash::Hash; use rsa::padding::PaddingScheme; let native_signature = priv_key @@ -221,7 +212,7 @@ impl Sign for super::Rsa2kPkcs { } } -#[cfg(feature = "rsa2k-pkcs")] +#[cfg(feature = "rsa2k")] impl Verify for super::Rsa2kPkcs { #[inline(never)] fn verify( @@ -233,7 +224,7 @@ impl Verify for super::Rsa2kPkcs { return Err(Error::InvalidSerializationFormat); } - // TODO:alt3r-3go: This must not be a hardcoded magic number, need to generalize + // TODO: This must not be a hardcoded magic number, convert when a common mechanism is available if request.signature.len() != 256 { return Err(Error::WrongSignatureLength); } @@ -267,11 +258,11 @@ impl Verify for super::Rsa2kPkcs { } } -#[cfg(not(feature = "rsa2k-pkcs"))] +#[cfg(not(feature = "rsa2k"))] impl DeriveKey for super::Rsa2kPkcs {} -#[cfg(not(feature = "rsa2k-pkcs"))] +#[cfg(not(feature = "rsa2k"))] impl GenerateKey for super::Rsa2kPkcs {} -#[cfg(not(feature = "rsa2k-pkcs"))] +#[cfg(not(feature = "rsa2k"))] impl Sign for super::Rsa2kPkcs {} -#[cfg(not(feature = "rsa2k-pkcs"))] +#[cfg(not(feature = "rsa2k"))] impl Verify for super::Rsa2kPkcs {} diff --git a/src/store/keystore.rs b/src/store/keystore.rs index ab864709c9c..7a483b97002 100644 --- a/src/store/keystore.rs +++ b/src/store/keystore.rs @@ -173,11 +173,9 @@ impl Keystore for ClientKeystore { let location = self.location(secrecy, id).ok_or(Error::NoSuchKey)?; - //TODO:alt3r-3go: This should better be defined in some way, instead of hardcoding. - // I've tried referring to MAX_SERIALIZED_KEY_LENGTH, is this a good idea? - #[cfg(not(feature = "rsa2k-pkcs"))] + #[cfg(not(feature = "rsa2k"))] let bytes: Bytes<128> = store::read(self.store, location, &path)?; - #[cfg(feature = "rsa2k-pkcs")] + #[cfg(feature = "rsa2k")] let bytes: Bytes = store::read(self.store, location, &path)?; let key = key::Key::try_deserialize(&bytes)?; diff --git a/src/types.rs b/src/types.rs index f0fa76e3508..9d939c4e6af 100644 --- a/src/types.rs +++ b/src/types.rs @@ -514,8 +514,11 @@ pub enum Mechanism { //TODO: Do we want to distinguish PKCS_v1.5 vs PSS/OAEP right here? Rsa2k, Rsa2kPkcs, - Rsa3k, - Rsa4k, + Rsa2kPss, + Rsa3kPkcs, + Rsa3kPss, + Rsa4kPkcs, + Rsa4kPss, } pub type LongData = Bytes; diff --git a/tests/rsa2kpkcs.rs b/tests/rsa2kpkcs.rs index 43936835751..a9492212294 100644 --- a/tests/rsa2kpkcs.rs +++ b/tests/rsa2kpkcs.rs @@ -9,9 +9,7 @@ use trussed::types::KeySerialization; use trussed::types::Location::*; use trussed::types::StorageAttributes; -// TODO:alt3r-3go: Looks like the test infra is not supposed to be used with several tests like below - -// right now it randomly fails with SIGSERV on either of the two, when run together, -// but never when run separately. Need to investigate and fix. +// Tests below can be run on a PC using the "virt" feature #[test] fn rsa2kpkcs_generate_key() { @@ -19,7 +17,6 @@ fn rsa2kpkcs_generate_key() { let sk = syscall!(client.generate_rsa2kpkcs_private_key(Internal)).key; // This assumes we don't ever get a key with ID 0 - // TODO:alt3r-3go: make sure the above always holds or find a better way to check for success assert_ne!(sk, KeyId::from_special(0)); }) } @@ -31,7 +28,6 @@ fn rsa2kpkcs_derive_key() { let pk = syscall!(client.derive_rsa2kpkcs_public_key(sk, Volatile)).key; // This assumes we don't ever get a key with ID 0 - // TODO:alt3r-3go: make sure the above always holds or find a better way to check for success assert_ne!(pk, KeyId::from_special(0)); }) } @@ -76,7 +72,6 @@ fn rsa2kpkcs_deserialize_key() { .key; // This assumes we don't ever get a key with ID 0 - // TODO:alt3r-3go: make sure the above always holds or find a better way to check for success assert_ne!(deserialized_key_id, KeyId::from_special(0)); }) } From 0ae49ceb70ba5ac6a189c3267757d684617dec89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= Date: Thu, 6 Oct 2022 10:07:42 +0200 Subject: [PATCH 19/47] Fix test with latest main --- tests/rsa2kpkcs.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/rsa2kpkcs.rs b/tests/rsa2kpkcs.rs index a9492212294..1895ee4894b 100644 --- a/tests/rsa2kpkcs.rs +++ b/tests/rsa2kpkcs.rs @@ -60,9 +60,7 @@ fn rsa2kpkcs_deserialize_key() { let sk = syscall!(client.generate_rsa2kpkcs_private_key(Internal)).key; let serialized_key = syscall!(client.serialize_rsa2kpkcs_key(sk, KeySerialization::Raw)).serialized_key; - let location = StorageAttributes { - persistence: Volatile, - }; + let location = StorageAttributes::new().set_persistence(Volatile); let deserialized_key_id = syscall!(client.deserialize_rsa2kpkcs_key( &serialized_key, From 9266f6ff69f9452bb4553aecdb09e84993b611e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= Date: Fri, 7 Oct 2022 15:02:50 +0200 Subject: [PATCH 20/47] RSA: Serialiaze only public keys with E and N serialization formats --- src/mechanisms/p256.rs | 1 + src/mechanisms/rsa2k.rs | 31 ++++++++++++++++++++++++------- src/types.rs | 4 ++++ 3 files changed, 29 insertions(+), 7 deletions(-) diff --git a/src/mechanisms/p256.rs b/src/mechanisms/p256.rs index 21d27282eab..f9182af7632 100644 --- a/src/mechanisms/p256.rs +++ b/src/mechanisms/p256.rs @@ -240,6 +240,7 @@ impl SerializeKey for super::P256 { .map_err(|_| Error::InternalError)?; serialized_key } + _ => return Err(Error::InvalidSerializationFormat), }; Ok(reply::SerializeKey { serialized_key }) diff --git a/src/mechanisms/rsa2k.rs b/src/mechanisms/rsa2k.rs index ef8d56f71f5..6aeb21d4222 100644 --- a/src/mechanisms/rsa2k.rs +++ b/src/mechanisms/rsa2k.rs @@ -1,6 +1,6 @@ use rsa::{ - pkcs8::{DecodePrivateKey, EncodePrivateKey, EncodePublicKey}, - PublicKey, RsaPrivateKey, RsaPublicKey, + pkcs8::{DecodePrivateKey, DecodePublicKey, EncodePrivateKey, EncodePublicKey}, + PublicKey, PublicKeyParts, RsaPrivateKey, RsaPublicKey, }; use crate::api::*; @@ -133,20 +133,37 @@ impl SerializeKey for super::Rsa2kPkcs { let key_id = request.key; // We rely on the fact that we store the keys in the PKCS#8 DER format already - let priv_key_der = keystore - .load_key(key::Secrecy::Secret, Some(key::Kind::Rsa2k), &key_id) - .expect("Failed to load an RSA 2K private key with the given ID") + let pub_key_der = keystore + .load_key(key::Secrecy::Public, Some(key::Kind::Rsa2k), &key_id) + .expect("Failed to load an RSA 2K public key with the given ID") .material; let serialized_key = match request.format { KeySerialization::Raw => { let mut serialized_key = Message::new(); serialized_key - .extend_from_slice(&priv_key_der) + .extend_from_slice(&pub_key_der) .map_err(|_| Error::InternalError)?; serialized_key } - + KeySerialization::RsaN => { + let key: RsaPublicKey = DecodePublicKey::from_public_key_der(&pub_key_der) + .expect("Failed to parse key"); + let mut serialized_n = Message::new(); + serialized_n + .extend_from_slice(&key.n().to_bytes_be()) + .map_err(|_| Error::InternalError)?; + serialized_n + } + KeySerialization::RsaE => { + let key: RsaPublicKey = DecodePublicKey::from_public_key_der(&pub_key_der) + .expect("Failed to parse key"); + let mut serialized_e = Message::new(); + serialized_e + .extend_from_slice(&key.e().to_bytes_be()) + .map_err(|_| Error::InternalError)?; + serialized_e + } _ => { return Err(Error::InternalError); } diff --git a/src/types.rs b/src/types.rs index 9d939c4e6af..cce69fa8da0 100644 --- a/src/types.rs +++ b/src/types.rs @@ -535,6 +535,10 @@ pub enum KeySerialization { EcdhEsHkdf256, Raw, Sec1, + /// RSA Public key modulus + RsaN, + /// RSA Public key exponent + RsaE, } pub type Signature = Bytes; From dd7ec6250e9585f6c916db71b2fec4945517415e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= Date: Fri, 7 Oct 2022 16:12:33 +0200 Subject: [PATCH 21/47] Add logging --- src/mechanisms/rsa2k.rs | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/mechanisms/rsa2k.rs b/src/mechanisms/rsa2k.rs index 6aeb21d4222..ebc424addb6 100644 --- a/src/mechanisms/rsa2k.rs +++ b/src/mechanisms/rsa2k.rs @@ -143,7 +143,10 @@ impl SerializeKey for super::Rsa2kPkcs { let mut serialized_key = Message::new(); serialized_key .extend_from_slice(&pub_key_der) - .map_err(|_| Error::InternalError)?; + .map_err(|_err| { + error!("Failed to write public key {_err:?}"); + Error::InternalError + })?; serialized_key } KeySerialization::RsaN => { @@ -152,7 +155,10 @@ impl SerializeKey for super::Rsa2kPkcs { let mut serialized_n = Message::new(); serialized_n .extend_from_slice(&key.n().to_bytes_be()) - .map_err(|_| Error::InternalError)?; + .map_err(|_err| { + error!("Failed to write public key {_err:?}"); + Error::InternalError + })?; serialized_n } KeySerialization::RsaE => { @@ -161,7 +167,10 @@ impl SerializeKey for super::Rsa2kPkcs { let mut serialized_e = Message::new(); serialized_e .extend_from_slice(&key.e().to_bytes_be()) - .map_err(|_| Error::InternalError)?; + .map_err(|_err| { + error!("Failed to write public key {_err:?}"); + Error::InternalError + })?; serialized_e } _ => { From 70f1576df6dfcb4a19a86d214cdb139bb3aa31e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= Date: Fri, 7 Oct 2022 16:54:12 +0200 Subject: [PATCH 22/47] Fix max key material length --- src/config.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/config.rs b/src/config.rs index 2e7109358fd..669529e8030 100644 --- a/src/config.rs +++ b/src/config.rs @@ -48,7 +48,7 @@ pub const MAX_SHORT_DATA_LENGTH: usize = 128; pub const MAX_SIGNATURE_LENGTH: usize = 512; #[cfg(any(feature = "rsa2k", feature = "rsa3k", feature = "rsa4k"))] // TODO: We use PKCS#8 DER format, this value was found empirically for 2K keys. Need to generalize. -pub const MAX_KEY_MATERIAL_LENGTH: usize = 1217; +pub const MAX_KEY_MATERIAL_LENGTH: usize = 1218; #[cfg(any(feature = "rsa2k", feature = "rsa3k", feature = "rsa4k"))] // This is due to the fact that KEY_MATERIAL_LENGTH is bigger than MESSAGE_LENGTH for RSA. pub const MAX_MESSAGE_LENGTH: usize = MAX_KEY_MATERIAL_LENGTH; From 400df2d1c1a45a2fd7f964d55c0423cd14495563 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= Date: Mon, 10 Oct 2022 11:04:50 +0200 Subject: [PATCH 23/47] Add decryption support --- src/mechanisms/rsa2k.rs | 39 +++++++++++++++++++++++++++++++++++++++ src/service.rs | 1 + 2 files changed, 40 insertions(+) diff --git a/src/mechanisms/rsa2k.rs b/src/mechanisms/rsa2k.rs index ebc424addb6..604a274c6ca 100644 --- a/src/mechanisms/rsa2k.rs +++ b/src/mechanisms/rsa2k.rs @@ -284,6 +284,43 @@ impl Verify for super::Rsa2kPkcs { } } +#[cfg(feature = "rsa2k")] +impl Decrypt for super::Rsa2kPkcs { + #[inline(never)] + fn decrypt( + keystore: &mut impl Keystore, + request: &request::Decrypt, + ) -> Result { + use rsa::padding::PaddingScheme; + + // First, get the key + let key_id = request.key; + + // We rely on the fact that we store the keys in the PKCS#8 DER format already + let priv_key_der = keystore + .load_key(key::Secrecy::Secret, Some(key::Kind::Rsa2k), &key_id) + .expect("Failed to load an RSA 2K private key with the given ID") + .material; + + let priv_key: RsaPrivateKey = DecodePrivateKey::from_pkcs8_der(&priv_key_der) + .expect("Failed to deserialize an RSA 2K private key from PKCS#8 DER"); + + let res = priv_key + .decrypt(PaddingScheme::PKCS1v15Encrypt, &request.message) + .map_err(|_err| { + warn!("Failed to decrypt: {_err}"); + Error::FunctionFailed + })?; + + Ok(reply::Decrypt { + plaintext: Some(Bytes::from_slice(&res).map_err(|_| { + error!("Failed type conversion"); + Error::InternalError + })?), + }) + } +} + #[cfg(not(feature = "rsa2k"))] impl DeriveKey for super::Rsa2kPkcs {} #[cfg(not(feature = "rsa2k"))] @@ -292,3 +329,5 @@ impl GenerateKey for super::Rsa2kPkcs {} impl Sign for super::Rsa2kPkcs {} #[cfg(not(feature = "rsa2k"))] impl Verify for super::Rsa2kPkcs {} +#[cfg(not(feature = "rsa2k"))] +impl Decrypt for super::Rsa2kPkcs {} diff --git a/src/service.rs b/src/service.rs index c137cd1952b..d0243251052 100644 --- a/src/service.rs +++ b/src/service.rs @@ -155,6 +155,7 @@ impl ServiceResources

{ Mechanism::Aes256Cbc => mechanisms::Aes256Cbc::decrypt(keystore, request), Mechanism::Chacha8Poly1305 => mechanisms::Chacha8Poly1305::decrypt(keystore, request), Mechanism::Tdes => mechanisms::Tdes::decrypt(keystore, request), + Mechanism::Rsa2kPkcs => mechanisms::Rsa2kPkcs::decrypt(keystore, request), _ => Err(Error::MechanismNotAvailable), }.map(Reply::Decrypt) From de72d3e7ce662d6847a2e9ae1d8b799ff2fd7373 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= Date: Mon, 10 Oct 2022 11:05:33 +0200 Subject: [PATCH 24/47] Deserialize public key rather than private keys --- src/mechanisms/rsa2k.rs | 14 ++++++-------- tests/rsa2kpkcs.rs | 6 ++++-- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/mechanisms/rsa2k.rs b/src/mechanisms/rsa2k.rs index 604a274c6ca..5ca5a10dd3d 100644 --- a/src/mechanisms/rsa2k.rs +++ b/src/mechanisms/rsa2k.rs @@ -65,24 +65,22 @@ impl DeserializeKey for super::Rsa2kPkcs { return Err(Error::InternalError); } - let private_key: RsaPrivateKey = DecodePrivateKey::from_pkcs8_der(&request.serialized_key) + let pub_key: RsaPublicKey = DecodePublicKey::from_public_key_der(&request.serialized_key) .map_err(|_| Error::InvalidSerializedKey)?; // We store our keys in PKCS#8 DER format - let private_key_der = private_key - .to_pkcs8_der() + let pub_key_der = pub_key + .to_public_key_der() .expect("Failed to serialize an RSA 2K private key to PKCS#8 DER"); - let private_key_id = keystore.store_key( + let pub_key_id = keystore.store_key( request.attributes.persistence, key::Secrecy::Secret, key::Kind::Rsa2k, - private_key_der.as_ref(), + pub_key_der.as_ref(), )?; - Ok(reply::DeserializeKey { - key: private_key_id, - }) + Ok(reply::DeserializeKey { key: pub_key_id }) } } diff --git a/tests/rsa2kpkcs.rs b/tests/rsa2kpkcs.rs index 1895ee4894b..12b583cc18f 100644 --- a/tests/rsa2kpkcs.rs +++ b/tests/rsa2kpkcs.rs @@ -46,9 +46,10 @@ fn rsa2kpkcs_exists_key() { fn rsa2kpkcs_serialize_key() { client::get(|client| { let sk = syscall!(client.generate_rsa2kpkcs_private_key(Internal)).key; + let pk = syscall!(client.derive_rsa2kpkcs_public_key(sk, Volatile)).key; let serialized_key = - syscall!(client.serialize_rsa2kpkcs_key(sk, KeySerialization::Raw)).serialized_key; + syscall!(client.serialize_rsa2kpkcs_key(pk, KeySerialization::Raw)).serialized_key; assert!(!serialized_key.is_empty()); }) @@ -58,8 +59,9 @@ fn rsa2kpkcs_serialize_key() { fn rsa2kpkcs_deserialize_key() { client::get(|client| { let sk = syscall!(client.generate_rsa2kpkcs_private_key(Internal)).key; + let pk = syscall!(client.derive_rsa2kpkcs_public_key(sk, Volatile)).key; let serialized_key = - syscall!(client.serialize_rsa2kpkcs_key(sk, KeySerialization::Raw)).serialized_key; + syscall!(client.serialize_rsa2kpkcs_key(pk, KeySerialization::Raw)).serialized_key; let location = StorageAttributes::new().set_persistence(Volatile); let deserialized_key_id = syscall!(client.deserialize_rsa2kpkcs_key( From 183ac33a5a4b035a6be50f93ec0139155a43c07f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= Date: Mon, 10 Oct 2022 15:08:31 +0200 Subject: [PATCH 25/47] Use None as the hash --- src/mechanisms/rsa2k.rs | 9 ++------- tests/rsa2kpkcs.rs | 13 ++++++++++--- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/mechanisms/rsa2k.rs b/src/mechanisms/rsa2k.rs index 5ca5a10dd3d..82ee061ee15 100644 --- a/src/mechanisms/rsa2k.rs +++ b/src/mechanisms/rsa2k.rs @@ -214,13 +214,9 @@ impl Sign for super::Rsa2kPkcs { // We assume we get digest into this function, too. // TODO: Consider using .sign_blinded(), which is supposed to protect the private key from timing side channels - use rsa::hash::Hash; use rsa::padding::PaddingScheme; let native_signature = priv_key - .sign( - PaddingScheme::new_pkcs1v15_sign(Some(Hash::SHA2_256)), - &request.message, - ) + .sign(PaddingScheme::new_pkcs1v15_sign(None), &request.message) .unwrap(); let our_signature = Signature::from_slice(&native_signature).unwrap(); @@ -266,11 +262,10 @@ impl Verify for super::Rsa2kPkcs { // Get the public key let pub_key = RsaPublicKey::from(&priv_key); - use rsa::hash::Hash; use rsa::padding::PaddingScheme; let verification_ok = pub_key .verify( - PaddingScheme::new_pkcs1v15_sign(Some(Hash::SHA2_256)), + PaddingScheme::new_pkcs1v15_sign(None), &request.message, &request.signature, ) diff --git a/tests/rsa2kpkcs.rs b/tests/rsa2kpkcs.rs index 12b583cc18f..9d36d7dd78d 100644 --- a/tests/rsa2kpkcs.rs +++ b/tests/rsa2kpkcs.rs @@ -80,10 +80,16 @@ fn rsa2kpkcs_deserialize_key() { fn rsa2kpkcs_sign_verify() { client::get(|client| { let sk = syscall!(client.generate_rsa2kpkcs_private_key(Volatile)).key; - + let hash_prefix = [ + 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, + 0x01, 0x05, 0x00, 0x04, 0x20, + ]; let message = [1u8, 2u8, 3u8]; use sha2::digest::Digest; - let digest_to_sign = sha2::Sha256::digest(&message); + let digest_to_sign: Vec = sha2::Sha256::digest(&message) + .into_iter() + .chain(hash_prefix) + .collect(); let signature = syscall!(client.sign_rsa2kpkcs(sk, &digest_to_sign)).signature; // println!("Message: {:?}", &message); @@ -92,6 +98,7 @@ fn rsa2kpkcs_sign_verify() { let verify_ok = syscall!(client.verify_rsa2kpkcs(sk, &digest_to_sign, &signature)).valid; - assert!(signature.len() == 256 && verify_ok); + assert_eq!(signature.len(), 256); + assert!(verify_ok); }) } From 70decec05bd261b4b73f90319be5c20cc39e5370 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= Date: Mon, 10 Oct 2022 15:54:02 +0200 Subject: [PATCH 26/47] Fix max serialized key length --- src/config.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/config.rs b/src/config.rs index 669529e8030..cb99406d1fb 100644 --- a/src/config.rs +++ b/src/config.rs @@ -47,8 +47,8 @@ pub const MAX_SHORT_DATA_LENGTH: usize = 128; #[cfg(any(feature = "rsa2k", feature = "rsa3k", feature = "rsa4k"))] pub const MAX_SIGNATURE_LENGTH: usize = 512; #[cfg(any(feature = "rsa2k", feature = "rsa3k", feature = "rsa4k"))] -// TODO: We use PKCS#8 DER format, this value was found empirically for 2K keys. Need to generalize. -pub const MAX_KEY_MATERIAL_LENGTH: usize = 1218; +// FIXME: Value from https://stackoverflow.com/questions/5403808/private-key-length-bytes for RSA2K Private key +pub const MAX_KEY_MATERIAL_LENGTH: usize = 1232; #[cfg(any(feature = "rsa2k", feature = "rsa3k", feature = "rsa4k"))] // This is due to the fact that KEY_MATERIAL_LENGTH is bigger than MESSAGE_LENGTH for RSA. pub const MAX_MESSAGE_LENGTH: usize = MAX_KEY_MATERIAL_LENGTH; From 4afba61e740d877f9da7188cdc739a1545568edb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= Date: Wed, 12 Oct 2022 15:48:09 +0200 Subject: [PATCH 27/47] Add Pkcs8Der serialzation format --- src/mechanisms/rsa2k.rs | 4 ++-- src/types.rs | 1 + tests/rsa2kpkcs.rs | 6 +++--- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/mechanisms/rsa2k.rs b/src/mechanisms/rsa2k.rs index 82ee061ee15..8dd54f72b14 100644 --- a/src/mechanisms/rsa2k.rs +++ b/src/mechanisms/rsa2k.rs @@ -61,7 +61,7 @@ impl DeserializeKey for super::Rsa2kPkcs { // - serialized_key: Message // - attributes: StorageAttributes - if request.format != KeySerialization::Raw { + if request.format != KeySerialization::Pkcs8Der { return Err(Error::InternalError); } @@ -137,7 +137,7 @@ impl SerializeKey for super::Rsa2kPkcs { .material; let serialized_key = match request.format { - KeySerialization::Raw => { + KeySerialization::Pkcs8Der => { let mut serialized_key = Message::new(); serialized_key .extend_from_slice(&pub_key_der) diff --git a/src/types.rs b/src/types.rs index cce69fa8da0..aada76e8cc4 100644 --- a/src/types.rs +++ b/src/types.rs @@ -539,6 +539,7 @@ pub enum KeySerialization { RsaN, /// RSA Public key exponent RsaE, + Pkcs8Der, } pub type Signature = Bytes; diff --git a/tests/rsa2kpkcs.rs b/tests/rsa2kpkcs.rs index 9d36d7dd78d..6e788a74ed2 100644 --- a/tests/rsa2kpkcs.rs +++ b/tests/rsa2kpkcs.rs @@ -49,7 +49,7 @@ fn rsa2kpkcs_serialize_key() { let pk = syscall!(client.derive_rsa2kpkcs_public_key(sk, Volatile)).key; let serialized_key = - syscall!(client.serialize_rsa2kpkcs_key(pk, KeySerialization::Raw)).serialized_key; + syscall!(client.serialize_rsa2kpkcs_key(pk, KeySerialization::Pkcs8Der)).serialized_key; assert!(!serialized_key.is_empty()); }) @@ -61,12 +61,12 @@ fn rsa2kpkcs_deserialize_key() { let sk = syscall!(client.generate_rsa2kpkcs_private_key(Internal)).key; let pk = syscall!(client.derive_rsa2kpkcs_public_key(sk, Volatile)).key; let serialized_key = - syscall!(client.serialize_rsa2kpkcs_key(pk, KeySerialization::Raw)).serialized_key; + syscall!(client.serialize_rsa2kpkcs_key(pk, KeySerialization::Pkcs8Der)).serialized_key; let location = StorageAttributes::new().set_persistence(Volatile); let deserialized_key_id = syscall!(client.deserialize_rsa2kpkcs_key( &serialized_key, - KeySerialization::Raw, + KeySerialization::Pkcs8Der, location )) .key; From c46a766cf4320994a07a0ad96de99c005c0578b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= Date: Wed, 12 Oct 2022 16:40:33 +0200 Subject: [PATCH 28/47] Fix rsa deserialization secrecy --- src/mechanisms/rsa2k.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mechanisms/rsa2k.rs b/src/mechanisms/rsa2k.rs index 8dd54f72b14..b1b998b2fad 100644 --- a/src/mechanisms/rsa2k.rs +++ b/src/mechanisms/rsa2k.rs @@ -75,7 +75,7 @@ impl DeserializeKey for super::Rsa2kPkcs { let pub_key_id = keystore.store_key( request.attributes.persistence, - key::Secrecy::Secret, + key::Secrecy::Public, key::Kind::Rsa2k, pub_key_der.as_ref(), )?; From 7f23c4a2571bf9ddbaaad1642f589fa9d5d7081e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= Date: Fri, 14 Oct 2022 10:12:49 +0200 Subject: [PATCH 29/47] Rename rsa with full bit size rsa2k -> rsa2048 rsa3k -> rsa3072 rsa4k -> rsa4096 --- Cargo.toml | 8 +-- src/client/mechanisms.rs | 30 +++++----- src/config.rs | 14 ++--- src/key.rs | 14 ++--- src/mechanisms.rs | 6 +- src/mechanisms/{rsa2k.rs => rsa2048.rs} | 74 ++++++++++++------------- src/service.rs | 16 +++--- src/store/keystore.rs | 4 +- src/types.rs | 14 ++--- tests/{rsa2kpkcs.rs => rsa2048pkcs.rs} | 46 +++++++-------- 10 files changed, 114 insertions(+), 112 deletions(-) rename src/mechanisms/{rsa2k.rs => rsa2048.rs} (88%) rename tests/{rsa2kpkcs.rs => rsa2048pkcs.rs} (57%) diff --git a/Cargo.toml b/Cargo.toml index 75d753de2fb..774f423d35c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -89,7 +89,7 @@ default-mechanisms = [ "tdes", "totp", "trng", - "rsa2k" + "rsa2048" ] aes256-cbc = [] chacha8-poly1305 = [] @@ -104,9 +104,9 @@ sha256 = [] tdes = ["des"] totp = ["sha-1"] trng = ["sha-1"] -rsa2k = ["rsa"] -rsa3k = ["rsa"] -rsa4k = ["rsa"] +rsa2048 = ["rsa"] +rsa3072 = ["rsa"] +rsa4096 = ["rsa"] clients-1 = [] clients-2 = [] diff --git a/src/client/mechanisms.rs b/src/client/mechanisms.rs index 7715f165fc0..c76c2917d52 100644 --- a/src/client/mechanisms.rs +++ b/src/client/mechanisms.rs @@ -385,71 +385,71 @@ pub trait P256: CryptoClient { } } -#[cfg(feature = "rsa2k")] -impl Rsa2kPkcs for ClientImplementation {} +#[cfg(feature = "rsa2048")] +impl Rsa2048Pkcs for ClientImplementation {} -pub trait Rsa2kPkcs: CryptoClient { - fn generate_rsa2kpkcs_private_key( +pub trait Rsa2048Pkcs: CryptoClient { + fn generate_rsa2048pkcs_private_key( &mut self, persistence: Location, ) -> ClientResult<'_, reply::GenerateKey, Self> { self.generate_key( - Mechanism::Rsa2kPkcs, + Mechanism::Rsa2048Pkcs, StorageAttributes::new().set_persistence(persistence), ) } - fn derive_rsa2kpkcs_public_key( + fn derive_rsa2048pkcs_public_key( &mut self, shared_key: KeyId, persistence: Location, ) -> ClientResult<'_, reply::DeriveKey, Self> { self.derive_key( - Mechanism::Rsa2kPkcs, + Mechanism::Rsa2048Pkcs, shared_key, None, StorageAttributes::new().set_persistence(persistence), ) } - fn serialize_rsa2kpkcs_key( + fn serialize_rsa2048pkcs_key( &mut self, key: KeyId, format: KeySerialization, ) -> ClientResult<'_, reply::SerializeKey, Self> { - self.serialize_key(Mechanism::Rsa2kPkcs, key, format) + self.serialize_key(Mechanism::Rsa2048Pkcs, key, format) } - fn deserialize_rsa2kpkcs_key<'c>( + fn deserialize_rsa2048pkcs_key<'c>( &'c mut self, serialized_key: &[u8], format: KeySerialization, attributes: StorageAttributes, ) -> ClientResult<'c, reply::DeserializeKey, Self> { - self.deserialize_key(Mechanism::Rsa2kPkcs, serialized_key, format, attributes) + self.deserialize_key(Mechanism::Rsa2048Pkcs, serialized_key, format, attributes) } - fn sign_rsa2kpkcs<'c>( + fn sign_rsa2048pkcs<'c>( &'c mut self, key: KeyId, message: &[u8], ) -> ClientResult<'c, reply::Sign, Self> { self.sign( - Mechanism::Rsa2kPkcs, + Mechanism::Rsa2048Pkcs, key, message, SignatureSerialization::Raw, ) } - fn verify_rsa2kpkcs<'c>( + fn verify_rsa2048pkcs<'c>( &'c mut self, key: KeyId, message: &[u8], signature: &[u8], ) -> ClientResult<'c, reply::Verify, Self> { self.verify( - Mechanism::Rsa2kPkcs, + Mechanism::Rsa2048Pkcs, key, message, signature, diff --git a/src/config.rs b/src/config.rs index cb99406d1fb..1b3e9ed0de1 100644 --- a/src/config.rs +++ b/src/config.rs @@ -44,20 +44,20 @@ cfg_if::cfg_if! { } pub const MAX_SHORT_DATA_LENGTH: usize = 128; -#[cfg(any(feature = "rsa2k", feature = "rsa3k", feature = "rsa4k"))] +#[cfg(any(feature = "rsa2048", feature = "rsa3072", feature = "rsa4096"))] pub const MAX_SIGNATURE_LENGTH: usize = 512; -#[cfg(any(feature = "rsa2k", feature = "rsa3k", feature = "rsa4k"))] -// FIXME: Value from https://stackoverflow.com/questions/5403808/private-key-length-bytes for RSA2K Private key +#[cfg(any(feature = "rsa2048", feature = "rsa3072", feature = "rsa4096"))] +// FIXME: Value from https://stackoverflow.com/questions/5403808/private-key-length-bytes for Rsa2048 Private key pub const MAX_KEY_MATERIAL_LENGTH: usize = 1232; -#[cfg(any(feature = "rsa2k", feature = "rsa3k", feature = "rsa4k"))] +#[cfg(any(feature = "rsa2048", feature = "rsa3072", feature = "rsa4096"))] // This is due to the fact that KEY_MATERIAL_LENGTH is bigger than MESSAGE_LENGTH for RSA. pub const MAX_MESSAGE_LENGTH: usize = MAX_KEY_MATERIAL_LENGTH; -#[cfg(not(any(feature = "rsa2k", feature = "rsa3k", feature = "rsa4k")))] +#[cfg(not(any(feature = "rsa2048", feature = "rsa3072", feature = "rsa4096")))] pub const MAX_SIGNATURE_LENGTH: usize = 72; -#[cfg(not(any(feature = "rsa2k", feature = "rsa3k", feature = "rsa4k")))] +#[cfg(not(any(feature = "rsa2048", feature = "rsa3072", feature = "rsa4096")))] pub const MAX_KEY_MATERIAL_LENGTH: usize = 128; -#[cfg(not(any(feature = "rsa2k", feature = "rsa3k", feature = "rsa4k")))] +#[cfg(not(any(feature = "rsa2048", feature = "rsa3072", feature = "rsa4096")))] pub const MAX_MESSAGE_LENGTH: usize = 1024; // must be MAX_KEY_MATERIAL_LENGTH + 4 diff --git a/src/key.rs b/src/key.rs index 246d84e50d0..b173c14bd8b 100644 --- a/src/key.rs +++ b/src/key.rs @@ -66,7 +66,7 @@ pub enum Kind { Ed255, P256, X255, - Rsa2k, + Rsa2048, } bitflags::bitflags! { @@ -151,9 +151,9 @@ impl Kind { Kind::Ed255 => 4, Kind::P256 => 5, Kind::X255 => 6, - Kind::Rsa2k => 0x7, - //Kind::Rsa3k => 0xE0, - //Kind::Rsa4k => 0xE1, + Kind::Rsa2048 => 0x7, + //Kind::Rsa3072 => 0xE0, + //Kind::Rsa4096 => 0xE1, } } @@ -166,9 +166,9 @@ impl Kind { 5 => Self::P256, 6 => Self::X255, - 0x7 => Self::Rsa2k, - //0xE0 => Kind::Rsa3k, - //0xE1 => Kind::Rsa4k, + 0x7 => Self::Rsa2048, + //0xE0 => Kind::Rsa3072, + //0xE1 => Kind::Rsa4096, _ => return Err(Error::InvalidSerializedKey), }) } diff --git a/src/mechanisms.rs b/src/mechanisms.rs index d79a9819198..619cef77831 100644 --- a/src/mechanisms.rs +++ b/src/mechanisms.rs @@ -49,9 +49,9 @@ pub struct P256 {} pub struct P256Prehashed {} mod p256; -pub struct Rsa2kPkcs {} -// Later on we'll add: "pub struct Rsa2kPss {}" and so on -mod rsa2k; +pub struct Rsa2048Pkcs {} +// Later on we'll add: "pub struct Rsa2048Pss {}" and so on +mod rsa2048; pub struct Sha256 {} mod sha256; diff --git a/src/mechanisms/rsa2k.rs b/src/mechanisms/rsa2048.rs similarity index 88% rename from src/mechanisms/rsa2k.rs rename to src/mechanisms/rsa2048.rs index b1b998b2fad..b595ca04ecb 100644 --- a/src/mechanisms/rsa2k.rs +++ b/src/mechanisms/rsa2048.rs @@ -10,8 +10,8 @@ use crate::error::Error; use crate::service::*; use crate::types::*; -#[cfg(feature = "rsa2k")] -impl DeriveKey for super::Rsa2kPkcs { +#[cfg(feature = "rsa2048")] +impl DeriveKey for super::Rsa2048Pkcs { #[inline(never)] fn derive_key( keystore: &mut impl Keystore, @@ -23,7 +23,7 @@ impl DeriveKey for super::Rsa2kPkcs { // std::println!("Loading key: {:?}", base_key_id); let priv_key_der = keystore - .load_key(key::Secrecy::Secret, Some(key::Kind::Rsa2k), base_key_id) + .load_key(key::Secrecy::Secret, Some(key::Kind::Rsa2048), base_key_id) .expect("Failed to load an RSA 2K private key with the given ID") .material; @@ -41,7 +41,7 @@ impl DeriveKey for super::Rsa2kPkcs { let pub_key_id = keystore.store_key( request.attributes.persistence, key::Secrecy::Public, - key::Kind::Rsa2k, + key::Kind::Rsa2048, pub_key_der.as_ref(), )?; @@ -50,8 +50,8 @@ impl DeriveKey for super::Rsa2kPkcs { } } -#[cfg(feature = "rsa2k")] -impl DeserializeKey for super::Rsa2kPkcs { +#[cfg(feature = "rsa2048")] +impl DeserializeKey for super::Rsa2048Pkcs { #[inline(never)] fn deserialize_key( keystore: &mut impl Keystore, @@ -76,7 +76,7 @@ impl DeserializeKey for super::Rsa2kPkcs { let pub_key_id = keystore.store_key( request.attributes.persistence, key::Secrecy::Public, - key::Kind::Rsa2k, + key::Kind::Rsa2048, pub_key_der.as_ref(), )?; @@ -84,8 +84,8 @@ impl DeserializeKey for super::Rsa2kPkcs { } } -#[cfg(feature = "rsa2k")] -impl GenerateKey for super::Rsa2kPkcs { +#[cfg(feature = "rsa2048")] +impl GenerateKey for super::Rsa2048Pkcs { #[inline(never)] fn generate_key( keystore: &mut impl Keystore, @@ -106,13 +106,13 @@ impl GenerateKey for super::Rsa2kPkcs { // std::println!("Stored key material after DER: {}", delog::hex_str!(&priv_key_der)); // std::println!("Key material length is {}", priv_key_der.as_ref().len()); // #[cfg(all(test, feature = "verbose-tests"))] - // std::println!("rsa2k-pkcs private key = {:?}", &private_key); + // std::println!("rsa2048-pkcs private key = {:?}", &private_key); // store the key let priv_key_id = keystore.store_key( request.attributes.persistence, key::Secrecy::Secret, - key::Info::from(key::Kind::Rsa2k).with_local_flag(), + key::Info::from(key::Kind::Rsa2048).with_local_flag(), priv_key_der.as_ref(), )?; @@ -121,8 +121,8 @@ impl GenerateKey for super::Rsa2kPkcs { } } -#[cfg(feature = "rsa2k")] -impl SerializeKey for super::Rsa2kPkcs { +#[cfg(feature = "rsa2048")] +impl SerializeKey for super::Rsa2048Pkcs { #[inline(never)] fn serialize_key( keystore: &mut impl Keystore, @@ -132,7 +132,7 @@ impl SerializeKey for super::Rsa2kPkcs { // We rely on the fact that we store the keys in the PKCS#8 DER format already let pub_key_der = keystore - .load_key(key::Secrecy::Public, Some(key::Kind::Rsa2k), &key_id) + .load_key(key::Secrecy::Public, Some(key::Kind::Rsa2048), &key_id) .expect("Failed to load an RSA 2K public key with the given ID") .material; @@ -180,8 +180,8 @@ impl SerializeKey for super::Rsa2kPkcs { } } -#[cfg(feature = "rsa2k")] -impl Exists for super::Rsa2kPkcs { +#[cfg(feature = "rsa2048")] +impl Exists for super::Rsa2048Pkcs { #[inline(never)] fn exists( keystore: &mut impl Keystore, @@ -189,13 +189,13 @@ impl Exists for super::Rsa2kPkcs { ) -> Result { let key_id = request.key; - let exists = keystore.exists_key(key::Secrecy::Secret, Some(key::Kind::Rsa2k), &key_id); + let exists = keystore.exists_key(key::Secrecy::Secret, Some(key::Kind::Rsa2048), &key_id); Ok(reply::Exists { exists }) } } -#[cfg(feature = "rsa2k")] -impl Sign for super::Rsa2kPkcs { +#[cfg(feature = "rsa2048")] +impl Sign for super::Rsa2048Pkcs { #[inline(never)] fn sign(keystore: &mut impl Keystore, request: &request::Sign) -> Result { // First, get the key @@ -203,7 +203,7 @@ impl Sign for super::Rsa2kPkcs { // We rely on the fact that we store the keys in the PKCS#8 DER format already let priv_key_der = keystore - .load_key(key::Secrecy::Secret, Some(key::Kind::Rsa2k), &key_id) + .load_key(key::Secrecy::Secret, Some(key::Kind::Rsa2048), &key_id) .expect("Failed to load an RSA 2K private key with the given ID") .material; @@ -220,7 +220,7 @@ impl Sign for super::Rsa2kPkcs { .unwrap(); let our_signature = Signature::from_slice(&native_signature).unwrap(); - // std::println!("RSA2K-PKCS_v1.5 signature:"); + // std::println!("Rsa2048-PKCS_v1.5 signature:"); // std::println!("msg: {:?}", &request.message); // std::println!("pk: {:?}", &priv_key); // std::println!("sig: {:?}", &our_signature); @@ -232,8 +232,8 @@ impl Sign for super::Rsa2kPkcs { } } -#[cfg(feature = "rsa2k")] -impl Verify for super::Rsa2kPkcs { +#[cfg(feature = "rsa2048")] +impl Verify for super::Rsa2048Pkcs { #[inline(never)] fn verify( keystore: &mut impl Keystore, @@ -252,7 +252,7 @@ impl Verify for super::Rsa2kPkcs { let key_id = request.key; let priv_key_der = keystore - .load_key(key::Secrecy::Secret, Some(key::Kind::Rsa2k), &key_id) + .load_key(key::Secrecy::Secret, Some(key::Kind::Rsa2048), &key_id) .expect("Failed to load an RSA 2K private key with the given ID") .material; @@ -277,8 +277,8 @@ impl Verify for super::Rsa2kPkcs { } } -#[cfg(feature = "rsa2k")] -impl Decrypt for super::Rsa2kPkcs { +#[cfg(feature = "rsa2048")] +impl Decrypt for super::Rsa2048Pkcs { #[inline(never)] fn decrypt( keystore: &mut impl Keystore, @@ -291,7 +291,7 @@ impl Decrypt for super::Rsa2kPkcs { // We rely on the fact that we store the keys in the PKCS#8 DER format already let priv_key_der = keystore - .load_key(key::Secrecy::Secret, Some(key::Kind::Rsa2k), &key_id) + .load_key(key::Secrecy::Secret, Some(key::Kind::Rsa2048), &key_id) .expect("Failed to load an RSA 2K private key with the given ID") .material; @@ -314,13 +314,13 @@ impl Decrypt for super::Rsa2kPkcs { } } -#[cfg(not(feature = "rsa2k"))] -impl DeriveKey for super::Rsa2kPkcs {} -#[cfg(not(feature = "rsa2k"))] -impl GenerateKey for super::Rsa2kPkcs {} -#[cfg(not(feature = "rsa2k"))] -impl Sign for super::Rsa2kPkcs {} -#[cfg(not(feature = "rsa2k"))] -impl Verify for super::Rsa2kPkcs {} -#[cfg(not(feature = "rsa2k"))] -impl Decrypt for super::Rsa2kPkcs {} +#[cfg(not(feature = "rsa2048"))] +impl DeriveKey for super::Rsa2048Pkcs {} +#[cfg(not(feature = "rsa2048"))] +impl GenerateKey for super::Rsa2048Pkcs {} +#[cfg(not(feature = "rsa2048"))] +impl Sign for super::Rsa2048Pkcs {} +#[cfg(not(feature = "rsa2048"))] +impl Verify for super::Rsa2048Pkcs {} +#[cfg(not(feature = "rsa2048"))] +impl Decrypt for super::Rsa2048Pkcs {} diff --git a/src/service.rs b/src/service.rs index d0243251052..049e427f151 100644 --- a/src/service.rs +++ b/src/service.rs @@ -155,7 +155,7 @@ impl ServiceResources

{ Mechanism::Aes256Cbc => mechanisms::Aes256Cbc::decrypt(keystore, request), Mechanism::Chacha8Poly1305 => mechanisms::Chacha8Poly1305::decrypt(keystore, request), Mechanism::Tdes => mechanisms::Tdes::decrypt(keystore, request), - Mechanism::Rsa2kPkcs => mechanisms::Rsa2kPkcs::decrypt(keystore, request), + Mechanism::Rsa2048Pkcs => mechanisms::Rsa2048Pkcs::decrypt(keystore, request), _ => Err(Error::MechanismNotAvailable), }.map(Reply::Decrypt) @@ -172,7 +172,7 @@ impl ServiceResources

{ Mechanism::P256 => mechanisms::P256::derive_key(keystore, request), Mechanism::Sha256 => mechanisms::Sha256::derive_key(keystore, request), Mechanism::X255 => mechanisms::X255::derive_key(keystore, request), - Mechanism::Rsa2kPkcs => mechanisms::Rsa2kPkcs::derive_key(keystore, request), + Mechanism::Rsa2048Pkcs => mechanisms::Rsa2048Pkcs::derive_key(keystore, request), _ => Err(Error::MechanismNotAvailable), }.map(Reply::DeriveKey) @@ -184,7 +184,7 @@ impl ServiceResources

{ Mechanism::Ed255 => mechanisms::Ed255::deserialize_key(keystore, request), Mechanism::P256 => mechanisms::P256::deserialize_key(keystore, request), Mechanism::X255 => mechanisms::X255::deserialize_key(keystore, request), - Mechanism::Rsa2kPkcs => mechanisms::Rsa2kPkcs::deserialize_key(keystore, request), + Mechanism::Rsa2048Pkcs => mechanisms::Rsa2048Pkcs::deserialize_key(keystore, request), _ => Err(Error::MechanismNotAvailable), }.map(Reply::DeserializeKey) @@ -218,7 +218,7 @@ impl ServiceResources

{ Mechanism::P256 => mechanisms::P256::exists(keystore, request), Mechanism::Totp => mechanisms::Totp::exists(keystore, request), Mechanism::X255 => mechanisms::X255::exists(keystore, request), - Mechanism::Rsa2kPkcs => mechanisms::Rsa2kPkcs::exists(keystore, request), + Mechanism::Rsa2048Pkcs => mechanisms::Rsa2048Pkcs::exists(keystore, request), _ => Err(Error::MechanismNotAvailable), }.map(Reply::Exists) @@ -230,7 +230,7 @@ impl ServiceResources

{ Mechanism::Ed255 => mechanisms::Ed255::generate_key(keystore, request), Mechanism::P256 => mechanisms::P256::generate_key(keystore, request), Mechanism::X255 => mechanisms::X255::generate_key(keystore, request), - Mechanism::Rsa2kPkcs => mechanisms::Rsa2kPkcs::generate_key(keystore, request), + Mechanism::Rsa2048Pkcs => mechanisms::Rsa2048Pkcs::generate_key(keystore, request), _ => Err(Error::MechanismNotAvailable), }.map(Reply::GenerateKey) }, @@ -443,7 +443,7 @@ impl ServiceResources

{ Mechanism::P256 => mechanisms::P256::serialize_key(keystore, request), Mechanism::X255 => mechanisms::X255::serialize_key(keystore, request), Mechanism::SharedSecret => mechanisms::SharedSecret::serialize_key(keystore, request), - Mechanism::Rsa2kPkcs => mechanisms::Rsa2kPkcs::serialize_key(keystore, request), + Mechanism::Rsa2048Pkcs => mechanisms::Rsa2048Pkcs::serialize_key(keystore, request), _ => Err(Error::MechanismNotAvailable), }.map(Reply::SerializeKey) @@ -460,7 +460,7 @@ impl ServiceResources

{ Mechanism::P256 => mechanisms::P256::sign(keystore, request), Mechanism::P256Prehashed => mechanisms::P256Prehashed::sign(keystore, request), Mechanism::Totp => mechanisms::Totp::sign(keystore, request), - Mechanism::Rsa2kPkcs => mechanisms::Rsa2kPkcs::sign(keystore, request), + Mechanism::Rsa2048Pkcs => mechanisms::Rsa2048Pkcs::sign(keystore, request), _ => Err(Error::MechanismNotAvailable), }.map(Reply::Sign) @@ -485,7 +485,7 @@ impl ServiceResources

{ Mechanism::Ed255 => mechanisms::Ed255::verify(keystore, request), Mechanism::P256 => mechanisms::P256::verify(keystore, request), - Mechanism::Rsa2kPkcs => mechanisms::Rsa2kPkcs::verify(keystore, request), + Mechanism::Rsa2048Pkcs => mechanisms::Rsa2048Pkcs::verify(keystore, request), _ => Err(Error::MechanismNotAvailable), }.map(Reply::Verify) diff --git a/src/store/keystore.rs b/src/store/keystore.rs index 7a483b97002..7793a47fd73 100644 --- a/src/store/keystore.rs +++ b/src/store/keystore.rs @@ -173,9 +173,9 @@ impl Keystore for ClientKeystore { let location = self.location(secrecy, id).ok_or(Error::NoSuchKey)?; - #[cfg(not(feature = "rsa2k"))] + #[cfg(not(feature = "rsa2048"))] let bytes: Bytes<128> = store::read(self.store, location, &path)?; - #[cfg(feature = "rsa2k")] + #[cfg(feature = "rsa2048")] let bytes: Bytes = store::read(self.store, location, &path)?; let key = key::Key::try_deserialize(&bytes)?; diff --git a/src/types.rs b/src/types.rs index aada76e8cc4..bbdd98f3a5a 100644 --- a/src/types.rs +++ b/src/types.rs @@ -512,13 +512,13 @@ pub enum Mechanism { /// Used to serialize the output of a diffie-hellman SharedSecret, //TODO: Do we want to distinguish PKCS_v1.5 vs PSS/OAEP right here? - Rsa2k, - Rsa2kPkcs, - Rsa2kPss, - Rsa3kPkcs, - Rsa3kPss, - Rsa4kPkcs, - Rsa4kPss, + Rsa2048, + Rsa2048Pkcs, + Rsa2048Pss, + Rsa3072Pkcs, + Rsa3072Pss, + Rsa4096Pkcs, + Rsa4096Pss, } pub type LongData = Bytes; diff --git a/tests/rsa2kpkcs.rs b/tests/rsa2048pkcs.rs similarity index 57% rename from tests/rsa2kpkcs.rs rename to tests/rsa2048pkcs.rs index 6e788a74ed2..69a16e739b8 100644 --- a/tests/rsa2kpkcs.rs +++ b/tests/rsa2048pkcs.rs @@ -1,4 +1,4 @@ -use trussed::client::mechanisms::Rsa2kPkcs; +use trussed::client::mechanisms::Rsa2048Pkcs; use trussed::client::CryptoClient; use trussed::syscall; use trussed::types::KeyId; @@ -12,9 +12,9 @@ use trussed::types::StorageAttributes; // Tests below can be run on a PC using the "virt" feature #[test] -fn rsa2kpkcs_generate_key() { +fn rsa2048pkcs_generate_key() { client::get(|client| { - let sk = syscall!(client.generate_rsa2kpkcs_private_key(Internal)).key; + let sk = syscall!(client.generate_rsa2048pkcs_private_key(Internal)).key; // This assumes we don't ever get a key with ID 0 assert_ne!(sk, KeyId::from_special(0)); @@ -22,10 +22,10 @@ fn rsa2kpkcs_generate_key() { } #[test] -fn rsa2kpkcs_derive_key() { +fn rsa2048pkcs_derive_key() { client::get(|client| { - let sk = syscall!(client.generate_rsa2kpkcs_private_key(Internal)).key; - let pk = syscall!(client.derive_rsa2kpkcs_public_key(sk, Volatile)).key; + let sk = syscall!(client.generate_rsa2048pkcs_private_key(Internal)).key; + let pk = syscall!(client.derive_rsa2048pkcs_public_key(sk, Volatile)).key; // This assumes we don't ever get a key with ID 0 assert_ne!(pk, KeyId::from_special(0)); @@ -33,38 +33,40 @@ fn rsa2kpkcs_derive_key() { } #[test] -fn rsa2kpkcs_exists_key() { +fn rsa2048pkcs_exists_key() { client::get(|client| { - let sk = syscall!(client.generate_rsa2kpkcs_private_key(Internal)).key; - let key_exists = syscall!(client.exists(trussed::types::Mechanism::Rsa2kPkcs, sk)).exists; + let sk = syscall!(client.generate_rsa2048pkcs_private_key(Internal)).key; + let key_exists = syscall!(client.exists(trussed::types::Mechanism::Rsa2048Pkcs, sk)).exists; assert!(key_exists); }) } #[test] -fn rsa2kpkcs_serialize_key() { +fn rsa2048pkcs_serialize_key() { client::get(|client| { - let sk = syscall!(client.generate_rsa2kpkcs_private_key(Internal)).key; - let pk = syscall!(client.derive_rsa2kpkcs_public_key(sk, Volatile)).key; + let sk = syscall!(client.generate_rsa2048pkcs_private_key(Internal)).key; + let pk = syscall!(client.derive_rsa2048pkcs_public_key(sk, Volatile)).key; let serialized_key = - syscall!(client.serialize_rsa2kpkcs_key(pk, KeySerialization::Pkcs8Der)).serialized_key; + syscall!(client.serialize_rsa2048pkcs_key(pk, KeySerialization::Pkcs8Der)) + .serialized_key; assert!(!serialized_key.is_empty()); }) } #[test] -fn rsa2kpkcs_deserialize_key() { +fn rsa2048pkcs_deserialize_key() { client::get(|client| { - let sk = syscall!(client.generate_rsa2kpkcs_private_key(Internal)).key; - let pk = syscall!(client.derive_rsa2kpkcs_public_key(sk, Volatile)).key; + let sk = syscall!(client.generate_rsa2048pkcs_private_key(Internal)).key; + let pk = syscall!(client.derive_rsa2048pkcs_public_key(sk, Volatile)).key; let serialized_key = - syscall!(client.serialize_rsa2kpkcs_key(pk, KeySerialization::Pkcs8Der)).serialized_key; + syscall!(client.serialize_rsa2048pkcs_key(pk, KeySerialization::Pkcs8Der)) + .serialized_key; let location = StorageAttributes::new().set_persistence(Volatile); - let deserialized_key_id = syscall!(client.deserialize_rsa2kpkcs_key( + let deserialized_key_id = syscall!(client.deserialize_rsa2048pkcs_key( &serialized_key, KeySerialization::Pkcs8Der, location @@ -77,9 +79,9 @@ fn rsa2kpkcs_deserialize_key() { } #[test] -fn rsa2kpkcs_sign_verify() { +fn rsa2048pkcs_sign_verify() { client::get(|client| { - let sk = syscall!(client.generate_rsa2kpkcs_private_key(Volatile)).key; + let sk = syscall!(client.generate_rsa2048pkcs_private_key(Volatile)).key; let hash_prefix = [ 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20, @@ -90,13 +92,13 @@ fn rsa2kpkcs_sign_verify() { .into_iter() .chain(hash_prefix) .collect(); - let signature = syscall!(client.sign_rsa2kpkcs(sk, &digest_to_sign)).signature; + let signature = syscall!(client.sign_rsa2048pkcs(sk, &digest_to_sign)).signature; // println!("Message: {:?}", &message); // println!("Digest: {:?}", &digest_to_sign); // println!("Signature (len={}): {:?}", signature.len(), &signature); - let verify_ok = syscall!(client.verify_rsa2kpkcs(sk, &digest_to_sign, &signature)).valid; + let verify_ok = syscall!(client.verify_rsa2048pkcs(sk, &digest_to_sign, &signature)).valid; assert_eq!(signature.len(), 256); assert!(verify_ok); From 5292134a7bd3b1b7e196ea5f0f5b6297fd0b98d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= Date: Fri, 14 Oct 2022 11:11:10 +0200 Subject: [PATCH 30/47] Remove RSA std dependency --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 774f423d35c..1ccf6c542d8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -36,7 +36,7 @@ des = { version = "0.8", optional = true } hmac = "0.12" sha-1 = { version = "0.10", default-features = false, optional = true } sha2 = { version = "0.10", default-features = false } -rsa = { version = "0.6.0", optional = true } +rsa = { version = "0.6.0", optional = true, default-features = false } # ours cosey = "0.3" From d8a5cae364c7ae72faaba118622eafef0c43bdae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= Date: Mon, 14 Nov 2022 15:51:32 +0100 Subject: [PATCH 31/47] Restore old Message length Fido-authenticator depended on its length. This commit restores the old length changes only the length of the (de)serialize_key methods to minimize breakage --- src/api.rs | 4 ++-- src/client.rs | 2 +- src/config.rs | 2 +- src/mechanisms/ed255.rs | 2 +- src/mechanisms/p256.rs | 4 ++-- src/mechanisms/rsa2048.rs | 6 +++--- src/mechanisms/shared_secret.rs | 2 +- src/mechanisms/x255.rs | 2 +- src/types.rs | 1 + 9 files changed, 13 insertions(+), 12 deletions(-) diff --git a/src/api.rs b/src/api.rs index 9f0ff021024..67400864b02 100644 --- a/src/api.rs +++ b/src/api.rs @@ -167,7 +167,7 @@ pub mod request { DeserializeKey: - mechanism: Mechanism - - serialized_key: Message + - serialized_key: SerializedKey - format: KeySerialization - attributes: StorageAttributes @@ -436,7 +436,7 @@ pub mod reply { - bytes: Message SerializeKey: - - serialized_key: Message + - serialized_key: SerializedKey Sign: - signature: Signature diff --git a/src/client.rs b/src/client.rs index b93e2a1c18f..0bbef239927 100644 --- a/src/client.rs +++ b/src/client.rs @@ -382,7 +382,7 @@ pub trait CryptoClient: PollClient { attributes: StorageAttributes, ) -> ClientResult<'c, reply::DeserializeKey, Self> { let serialized_key = - Message::from_slice(serialized_key).map_err(|_| ClientError::DataTooLarge)?; + SerializedKey::from_slice(serialized_key).map_err(|_| ClientError::DataTooLarge)?; let r = self.request(request::DeserializeKey { mechanism, serialized_key, diff --git a/src/config.rs b/src/config.rs index 1b3e9ed0de1..f1745035c93 100644 --- a/src/config.rs +++ b/src/config.rs @@ -51,7 +51,7 @@ pub const MAX_SIGNATURE_LENGTH: usize = 512; pub const MAX_KEY_MATERIAL_LENGTH: usize = 1232; #[cfg(any(feature = "rsa2048", feature = "rsa3072", feature = "rsa4096"))] // This is due to the fact that KEY_MATERIAL_LENGTH is bigger than MESSAGE_LENGTH for RSA. -pub const MAX_MESSAGE_LENGTH: usize = MAX_KEY_MATERIAL_LENGTH; +pub const MAX_MESSAGE_LENGTH: usize = 1024; #[cfg(not(any(feature = "rsa2048", feature = "rsa3072", feature = "rsa4096")))] pub const MAX_SIGNATURE_LENGTH: usize = 72; diff --git a/src/mechanisms/ed255.rs b/src/mechanisms/ed255.rs index 0cf47adf1c9..6d3325d0873 100644 --- a/src/mechanisms/ed255.rs +++ b/src/mechanisms/ed255.rs @@ -142,7 +142,7 @@ impl SerializeKey for super::Ed255 { } KeySerialization::Raw => { - let mut serialized_key = Message::new(); + let mut serialized_key = SerializedKey::new(); serialized_key .extend_from_slice(public_key.as_bytes()) .map_err(|_| Error::InternalError)?; diff --git a/src/mechanisms/p256.rs b/src/mechanisms/p256.rs index f9182af7632..a147237e7f2 100644 --- a/src/mechanisms/p256.rs +++ b/src/mechanisms/p256.rs @@ -224,7 +224,7 @@ impl SerializeKey for super::P256 { crate::cbor_serialize_bytes(&cose_pk).map_err(|_| Error::CborError)? } KeySerialization::Raw => { - let mut serialized_key = Message::new(); + let mut serialized_key = SerializedKey::new(); serialized_key .extend_from_slice(&public_key.x()) .map_err(|_| Error::InternalError)?; @@ -234,7 +234,7 @@ impl SerializeKey for super::P256 { serialized_key } KeySerialization::Sec1 => { - let mut serialized_key = Message::new(); + let mut serialized_key = SerializedKey::new(); serialized_key .extend_from_slice(&public_key.to_compressed_sec1_bytes()) .map_err(|_| Error::InternalError)?; diff --git a/src/mechanisms/rsa2048.rs b/src/mechanisms/rsa2048.rs index b595ca04ecb..7656627febd 100644 --- a/src/mechanisms/rsa2048.rs +++ b/src/mechanisms/rsa2048.rs @@ -138,7 +138,7 @@ impl SerializeKey for super::Rsa2048Pkcs { let serialized_key = match request.format { KeySerialization::Pkcs8Der => { - let mut serialized_key = Message::new(); + let mut serialized_key = SerializedKey::new(); serialized_key .extend_from_slice(&pub_key_der) .map_err(|_err| { @@ -150,7 +150,7 @@ impl SerializeKey for super::Rsa2048Pkcs { KeySerialization::RsaN => { let key: RsaPublicKey = DecodePublicKey::from_public_key_der(&pub_key_der) .expect("Failed to parse key"); - let mut serialized_n = Message::new(); + let mut serialized_n = SerializedKey::new(); serialized_n .extend_from_slice(&key.n().to_bytes_be()) .map_err(|_err| { @@ -162,7 +162,7 @@ impl SerializeKey for super::Rsa2048Pkcs { KeySerialization::RsaE => { let key: RsaPublicKey = DecodePublicKey::from_public_key_der(&pub_key_der) .expect("Failed to parse key"); - let mut serialized_e = Message::new(); + let mut serialized_e = SerializedKey::new(); serialized_e .extend_from_slice(&key.e().to_bytes_be()) .map_err(|_err| { diff --git a/src/mechanisms/shared_secret.rs b/src/mechanisms/shared_secret.rs index 7c42b0f684b..b33a1bdddec 100644 --- a/src/mechanisms/shared_secret.rs +++ b/src/mechanisms/shared_secret.rs @@ -22,7 +22,7 @@ impl SerializeKey for super::SharedSecret { if !key.flags.contains(key::Flags::SERIALIZABLE) { return Err(Error::InvalidSerializedKey); }; - let mut serialized_key = Message::new(); + let mut serialized_key = SerializedKey::new(); serialized_key.extend_from_slice(&key.material).unwrap(); Ok(reply::SerializeKey { serialized_key }) diff --git a/src/mechanisms/x255.rs b/src/mechanisms/x255.rs index 4178c15a758..c646c89f72d 100644 --- a/src/mechanisms/x255.rs +++ b/src/mechanisms/x255.rs @@ -149,7 +149,7 @@ impl SerializeKey for super::X255 { let key_id = request.key; let public_key = load_public_key(keystore, &key_id)?; - let mut serialized_key = Message::new(); + let mut serialized_key = SerializedKey::new(); match request.format { KeySerialization::Raw => { serialized_key diff --git a/src/types.rs b/src/types.rs index bbdd98f3a5a..2f86ee30d50 100644 --- a/src/types.rs +++ b/src/types.rs @@ -526,6 +526,7 @@ pub type MediumData = Bytes; pub type ShortData = Bytes; pub type Message = Bytes; +pub type SerializedKey = Bytes; #[derive(Copy, Clone, Eq, PartialEq, Debug, Serialize, Deserialize)] pub enum KeySerialization { From 40422066b5d9c3dd35863584360f80400cab2f1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= Date: Thu, 13 Oct 2022 17:32:46 +0200 Subject: [PATCH 32/47] WIP: Add RSA key import --- Cargo.toml | 7 +-- src/api.rs | 2 +- src/client.rs | 2 +- src/lib.rs | 4 ++ src/mechanisms.rs | 1 + src/mechanisms/rsa2048.rs | 106 ++++++++++++++++++++++++++++++++++++++ src/service.rs | 1 + src/types.rs | 2 + 8 files changed, 120 insertions(+), 5 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 1ccf6c542d8..07774adaafa 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -104,9 +104,10 @@ sha256 = [] tdes = ["des"] totp = ["sha-1"] trng = ["sha-1"] -rsa2048 = ["rsa"] -rsa3072 = ["rsa"] -rsa4096 = ["rsa"] +rsa2048 = ["rsa", "alloc"] +rsa3072 = ["rsa", "alloc"] +rsa4096 = ["rsa", "alloc"] +alloc = [] clients-1 = [] clients-2 = [] diff --git a/src/api.rs b/src/api.rs index 67400864b02..ffc209332d3 100644 --- a/src/api.rs +++ b/src/api.rs @@ -275,7 +275,7 @@ pub mod request { UnsafeInjectKey: - mechanism: Mechanism // -> implies key type - - raw_key: ShortData + - raw_key: Message - attributes: StorageAttributes - format: KeySerialization diff --git a/src/client.rs b/src/client.rs index 0bbef239927..ed7ff2f4d29 100644 --- a/src/client.rs +++ b/src/client.rs @@ -527,7 +527,7 @@ pub trait CryptoClient: PollClient { ) -> ClientResult<'_, reply::UnsafeInjectKey, Self> { let r = self.request(request::UnsafeInjectKey { mechanism, - raw_key: ShortData::from_slice(raw_key).unwrap(), + raw_key: Message::from_slice(raw_key).unwrap(), attributes: StorageAttributes::new().set_persistence(persistence), format, })?; diff --git a/src/lib.rs b/src/lib.rs index 9072ed50715..0f609f10c21 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -17,6 +17,10 @@ extern crate delog; generate_macros!(); +#[cfg(feature = "alloc")] +#[macro_use] +extern crate alloc; + pub use interchange::Interchange; pub mod api; diff --git a/src/mechanisms.rs b/src/mechanisms.rs index 619cef77831..3690ada9fae 100644 --- a/src/mechanisms.rs +++ b/src/mechanisms.rs @@ -52,6 +52,7 @@ mod p256; pub struct Rsa2048Pkcs {} // Later on we'll add: "pub struct Rsa2048Pss {}" and so on mod rsa2048; +pub use rsa2048::RsaPrivateKeyFormat; pub struct Sha256 {} mod sha256; diff --git a/src/mechanisms/rsa2048.rs b/src/mechanisms/rsa2048.rs index 7656627febd..ea83003aa4f 100644 --- a/src/mechanisms/rsa2048.rs +++ b/src/mechanisms/rsa2048.rs @@ -2,6 +2,7 @@ use rsa::{ pkcs8::{DecodePrivateKey, DecodePublicKey, EncodePrivateKey, EncodePublicKey}, PublicKey, PublicKeyParts, RsaPrivateKey, RsaPublicKey, }; +use serde::{Deserialize, Serialize}; use crate::api::*; // use crate::config::*; @@ -314,6 +315,109 @@ impl Decrypt for super::Rsa2048Pkcs { } } +fn unsafe_inject_pkcs_key( + keystore: &mut impl Keystore, + request: &request::UnsafeInjectKey, +) -> Result { + let private_key: RsaPrivateKey = DecodePrivateKey::from_pkcs8_der(&request.raw_key) + .map_err(|_| Error::InvalidSerializedKey)?; + + // We store our keys in PKCS#8 DER format + let private_key_der = private_key + .to_pkcs8_der() + .expect("Failed to serialize an RSA 2K private key to PKCS#8 DER"); + + let private_key_id = keystore.store_key( + request.attributes.persistence, + key::Secrecy::Secret, + key::Kind::Rsa2048, + private_key_der.as_ref(), + )?; + + Ok(reply::UnsafeInjectKey { + key: private_key_id, + }) +} + +/// Data format for RSA Private key serialization in [KeySerialization::Raw](crate::types::KeySerialization::Raw) +/// format in [unsafe_inject_key](crate::client::CryptoClient::unsafe_inject_key) +/// +/// Serialized using [postcard_serialize_bytes](crate::postcard_serialize_bytes). All data are big endian large integers +#[derive(Debug, Deserialize, Serialize)] +pub struct RsaPrivateKeyFormat<'d> { + pub e: &'d [u8], + pub p: &'d [u8], + pub q: &'d [u8], + pub qinv: &'d [u8], + pub dp: &'d [u8], + pub dq: &'d [u8], + pub n: &'d [u8], +} + +#[cfg(feature = "rsa2048")] +fn unsafe_inject_openpgp_key( + keystore: &mut impl Keystore, + request: &request::UnsafeInjectKey, +) -> Result { + use rsa::BigUint; + let data: RsaPrivateKeyFormat<'_> = + crate::postcard_deserialize(&request.raw_key).map_err(|_err| { + error!("Failed to deserialize rsa key: {_err:?}"); + Error::InvalidSerializedKey + })?; + let e = BigUint::from_bytes_be(data.e); + let p = BigUint::from_bytes_be(data.p); + let q = BigUint::from_bytes_be(data.q); + // let dp = BigUint::from_bytes_be(data.dp); + // let dq = BigUint::from_bytes_be(data.dq); + let phi = (&p - 1u64) * (&q - 1u64); + + let d = e.modpow(&(&phi - 1u64), &phi); + + // todo check bit size + let private_key = + RsaPrivateKey::from_components(BigUint::from_bytes_be(data.n), e, d, vec![p, q]); + private_key.validate().map_err(|_err| { + warn!("Bad private key: {_err:?}"); + Error::InvalidSerializedKey + })?; + if private_key.size() != 2048 { + warn!("Bad key size: {}", private_key.size()); + return Err(Error::InvalidSerializedKey); + } + + // We store our keys in PKCS#8 DER format + let private_key_der = private_key + .to_pkcs8_der() + .expect("Failed to serialize an RSA 2K private key to PKCS#8 DER"); + + let private_key_id = keystore.store_key( + request.attributes.persistence, + key::Secrecy::Secret, + key::Kind::Rsa2048, + private_key_der.as_ref(), + )?; + + Ok(reply::UnsafeInjectKey { + key: private_key_id, + }) +} + +#[cfg(feature = "rsa2048")] +impl UnsafeInjectKey for super::Rsa2048Pkcs { + #[inline(never)] + fn unsafe_inject_key( + keystore: &mut impl Keystore, + request: &request::UnsafeInjectKey, + ) -> Result { + match request.format { + KeySerialization::Pkcs8Der => unsafe_inject_pkcs_key(keystore, request), + KeySerialization::OpenPgpRsa => unsafe_inject_openpgp_key(keystore, request), + _ => Err(Error::InvalidSerializationFormat), + } + } +} + #[cfg(not(feature = "rsa2048"))] impl DeriveKey for super::Rsa2048Pkcs {} #[cfg(not(feature = "rsa2048"))] @@ -324,3 +428,5 @@ impl Sign for super::Rsa2048Pkcs {} impl Verify for super::Rsa2048Pkcs {} #[cfg(not(feature = "rsa2048"))] impl Decrypt for super::Rsa2048Pkcs {} +#[cfg(not(feature = "rsa2048"))] +impl UnsafeInjectKey for super::Rsa2048Pkcs {} diff --git a/src/service.rs b/src/service.rs index 049e427f151..a3d5fd444a9 100644 --- a/src/service.rs +++ b/src/service.rs @@ -258,6 +258,7 @@ impl ServiceResources

{ Mechanism::SharedSecret => mechanisms::SharedSecret::unsafe_inject_key(keystore, request), Mechanism::Aes256Cbc => mechanisms::Aes256Cbc::unsafe_inject_key(keystore, request), Mechanism::Tdes => mechanisms::Tdes::unsafe_inject_key(keystore, request), + Mechanism::Rsa2048Pkcs => mechanisms::Rsa2048Pkcs::unsafe_inject_key(keystore, request), _ => Err(Error::MechanismNotAvailable) }.map(Reply::UnsafeInjectKey) }, diff --git a/src/types.rs b/src/types.rs index 2f86ee30d50..488f097287a 100644 --- a/src/types.rs +++ b/src/types.rs @@ -536,6 +536,8 @@ pub enum KeySerialization { EcdhEsHkdf256, Raw, Sec1, + /// RSA OpenPGP private key import format + OpenPgpRsa, /// RSA Public key modulus RsaN, /// RSA Public key exponent From 9d9dd18395d3740263b784a33da200b6c156ac7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= Date: Fri, 14 Oct 2022 08:47:16 +0200 Subject: [PATCH 33/47] Add rsa import support --- Cargo.toml | 9 +++++---- src/mechanisms/rsa2048.rs | 12 ++++++++++-- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 07774adaafa..70ea1d0df9a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -36,7 +36,8 @@ des = { version = "0.8", optional = true } hmac = "0.12" sha-1 = { version = "0.10", default-features = false, optional = true } sha2 = { version = "0.10", default-features = false } -rsa = { version = "0.6.0", optional = true, default-features = false } +rsa = { version = "0.6.0", optional = true , default-features = false } +num-bigint-dig = { version = "0.8.1", optional = true , default-features = false} # ours cosey = "0.3" @@ -104,9 +105,9 @@ sha256 = [] tdes = ["des"] totp = ["sha-1"] trng = ["sha-1"] -rsa2048 = ["rsa", "alloc"] -rsa3072 = ["rsa", "alloc"] -rsa4096 = ["rsa", "alloc"] +rsa2048 = ["rsa", "alloc", "num-bigint-dig"] +rsa3072 = ["rsa", "alloc", "num-bigint-dig"] +rsa4096 = ["rsa", "alloc", "num-bigint-dig"] alloc = [] clients-1 = [] diff --git a/src/mechanisms/rsa2048.rs b/src/mechanisms/rsa2048.rs index ea83003aa4f..68fb0683377 100644 --- a/src/mechanisms/rsa2048.rs +++ b/src/mechanisms/rsa2048.rs @@ -1,3 +1,4 @@ +use num_bigint_dig::traits::ModInverse; use rsa::{ pkcs8::{DecodePrivateKey, DecodePublicKey, EncodePrivateKey, EncodePublicKey}, PublicKey, PublicKeyParts, RsaPrivateKey, RsaPublicKey, @@ -372,7 +373,14 @@ fn unsafe_inject_openpgp_key( // let dq = BigUint::from_bytes_be(data.dq); let phi = (&p - 1u64) * (&q - 1u64); - let d = e.modpow(&(&phi - 1u64), &phi); + let d = e + .clone() + .mod_inverse(&phi) + .and_then(|int| int.to_biguint()) + .ok_or_else(|| { + warn!("Failed inverse"); + Error::InvalidSerializedKey + })?; // todo check bit size let private_key = @@ -381,7 +389,7 @@ fn unsafe_inject_openpgp_key( warn!("Bad private key: {_err:?}"); Error::InvalidSerializedKey })?; - if private_key.size() != 2048 { + if private_key.size() * 8 != 2048 { warn!("Bad key size: {}", private_key.size()); return Err(Error::InvalidSerializedKey); } From 4bc3394978a030494d0961970e9d5a6c2768a97c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= Date: Fri, 14 Oct 2022 09:09:01 +0200 Subject: [PATCH 34/47] Remove the requirement for N in rsa key import --- src/mechanisms/rsa2048.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/mechanisms/rsa2048.rs b/src/mechanisms/rsa2048.rs index 68fb0683377..3f3596bac97 100644 --- a/src/mechanisms/rsa2048.rs +++ b/src/mechanisms/rsa2048.rs @@ -352,7 +352,6 @@ pub struct RsaPrivateKeyFormat<'d> { pub qinv: &'d [u8], pub dp: &'d [u8], pub dq: &'d [u8], - pub n: &'d [u8], } #[cfg(feature = "rsa2048")] @@ -383,8 +382,7 @@ fn unsafe_inject_openpgp_key( })?; // todo check bit size - let private_key = - RsaPrivateKey::from_components(BigUint::from_bytes_be(data.n), e, d, vec![p, q]); + let private_key = RsaPrivateKey::from_components(&p * &q, e, d, vec![p, q]); private_key.validate().map_err(|_err| { warn!("Bad private key: {_err:?}"); Error::InvalidSerializedKey From 45d57e7beabfab839890e0519292663b7e8b2059 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= Date: Fri, 14 Oct 2022 09:17:48 +0200 Subject: [PATCH 35/47] Improve naming --- src/mechanisms.rs | 1 - src/mechanisms/rsa2048.rs | 19 ++----------------- src/types.rs | 18 +++++++++++++++++- 3 files changed, 19 insertions(+), 19 deletions(-) diff --git a/src/mechanisms.rs b/src/mechanisms.rs index 3690ada9fae..619cef77831 100644 --- a/src/mechanisms.rs +++ b/src/mechanisms.rs @@ -52,7 +52,6 @@ mod p256; pub struct Rsa2048Pkcs {} // Later on we'll add: "pub struct Rsa2048Pss {}" and so on mod rsa2048; -pub use rsa2048::RsaPrivateKeyFormat; pub struct Sha256 {} mod sha256; diff --git a/src/mechanisms/rsa2048.rs b/src/mechanisms/rsa2048.rs index 3f3596bac97..c2a11f0804a 100644 --- a/src/mechanisms/rsa2048.rs +++ b/src/mechanisms/rsa2048.rs @@ -3,7 +3,6 @@ use rsa::{ pkcs8::{DecodePrivateKey, DecodePublicKey, EncodePrivateKey, EncodePublicKey}, PublicKey, PublicKeyParts, RsaPrivateKey, RsaPublicKey, }; -use serde::{Deserialize, Serialize}; use crate::api::*; // use crate::config::*; @@ -340,27 +339,13 @@ fn unsafe_inject_pkcs_key( }) } -/// Data format for RSA Private key serialization in [KeySerialization::Raw](crate::types::KeySerialization::Raw) -/// format in [unsafe_inject_key](crate::client::CryptoClient::unsafe_inject_key) -/// -/// Serialized using [postcard_serialize_bytes](crate::postcard_serialize_bytes). All data are big endian large integers -#[derive(Debug, Deserialize, Serialize)] -pub struct RsaPrivateKeyFormat<'d> { - pub e: &'d [u8], - pub p: &'d [u8], - pub q: &'d [u8], - pub qinv: &'d [u8], - pub dp: &'d [u8], - pub dq: &'d [u8], -} - #[cfg(feature = "rsa2048")] fn unsafe_inject_openpgp_key( keystore: &mut impl Keystore, request: &request::UnsafeInjectKey, ) -> Result { use rsa::BigUint; - let data: RsaPrivateKeyFormat<'_> = + let data: RsaCrtImportFormat<'_> = crate::postcard_deserialize(&request.raw_key).map_err(|_err| { error!("Failed to deserialize rsa key: {_err:?}"); Error::InvalidSerializedKey @@ -418,7 +403,7 @@ impl UnsafeInjectKey for super::Rsa2048Pkcs { ) -> Result { match request.format { KeySerialization::Pkcs8Der => unsafe_inject_pkcs_key(keystore, request), - KeySerialization::OpenPgpRsa => unsafe_inject_openpgp_key(keystore, request), + KeySerialization::RsaCrt => unsafe_inject_openpgp_key(keystore, request), _ => Err(Error::InvalidSerializationFormat), } } diff --git a/src/types.rs b/src/types.rs index 488f097287a..a953223a3ff 100644 --- a/src/types.rs +++ b/src/types.rs @@ -537,7 +537,9 @@ pub enum KeySerialization { Raw, Sec1, /// RSA OpenPGP private key import format - OpenPgpRsa, + /// + /// Corresponds to [RsaCrtImportFormat](RsaCrtImportFormat) + RsaCrt, /// RSA Public key modulus RsaN, /// RSA Public key exponent @@ -556,3 +558,17 @@ pub enum SignatureSerialization { } pub type UserAttribute = Bytes; + +/// Data format for RSA Private key serialization in [KeySerialization::Raw](crate::types::KeySerialization::Raw) +/// format in [unsafe_inject_key](crate::client::CryptoClient::unsafe_inject_key) +/// +/// Serialized using [postcard_serialize_bytes](crate::postcard_serialize_bytes). All data are big endian large integers +#[derive(Debug, Deserialize, Serialize)] +pub struct RsaCrtImportFormat<'d> { + pub e: &'d [u8], + pub p: &'d [u8], + pub q: &'d [u8], + pub qinv: &'d [u8], + pub dp: &'d [u8], + pub dq: &'d [u8], +} From 3ce826065cac35f39b516c8b922bbdfbffb6ff55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= Date: Fri, 14 Oct 2022 10:05:05 +0200 Subject: [PATCH 36/47] Fix RSA capitalisation in logs --- src/mechanisms/rsa2048.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mechanisms/rsa2048.rs b/src/mechanisms/rsa2048.rs index c2a11f0804a..6aa98e7dccb 100644 --- a/src/mechanisms/rsa2048.rs +++ b/src/mechanisms/rsa2048.rs @@ -347,7 +347,7 @@ fn unsafe_inject_openpgp_key( use rsa::BigUint; let data: RsaCrtImportFormat<'_> = crate::postcard_deserialize(&request.raw_key).map_err(|_err| { - error!("Failed to deserialize rsa key: {_err:?}"); + error!("Failed to deserialize RSA key: {_err:?}"); Error::InvalidSerializedKey })?; let e = BigUint::from_bytes_be(data.e); From b585d9bbbc453045f70fc02688f881803cd76350 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= Date: Wed, 16 Nov 2022 10:26:22 +0100 Subject: [PATCH 37/47] Remove RSA from default mechanism As RSA requires an allocator, it should no be enabled by default --- Cargo.toml | 1 - src/mechanisms/rsa2048.rs | 768 +++++++++++++++++++------------------- tests/rsa2048pkcs.rs | 2 + 3 files changed, 392 insertions(+), 379 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 70ea1d0df9a..0805803d1ca 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -90,7 +90,6 @@ default-mechanisms = [ "tdes", "totp", "trng", - "rsa2048" ] aes256-cbc = [] chacha8-poly1305 = [] diff --git a/src/mechanisms/rsa2048.rs b/src/mechanisms/rsa2048.rs index 6aa98e7dccb..68949a3ec1a 100644 --- a/src/mechanisms/rsa2048.rs +++ b/src/mechanisms/rsa2048.rs @@ -1,423 +1,435 @@ -use num_bigint_dig::traits::ModInverse; -use rsa::{ - pkcs8::{DecodePrivateKey, DecodePublicKey, EncodePrivateKey, EncodePublicKey}, - PublicKey, PublicKeyParts, RsaPrivateKey, RsaPublicKey, -}; - -use crate::api::*; -// use crate::config::*; -// use crate::debug; -use crate::error::Error; -use crate::service::*; -use crate::types::*; - #[cfg(feature = "rsa2048")] -impl DeriveKey for super::Rsa2048Pkcs { - #[inline(never)] - fn derive_key( - keystore: &mut impl Keystore, - request: &request::DeriveKey, - ) -> Result { - // Retrieve private key - let base_key_id = &request.base_key; - - // std::println!("Loading key: {:?}", base_key_id); +mod implementation { + use super::super::Rsa2048Pkcs; + use num_bigint_dig::traits::ModInverse; + use rsa::{ + pkcs8::{DecodePrivateKey, DecodePublicKey, EncodePrivateKey, EncodePublicKey}, + PublicKey, PublicKeyParts, RsaPrivateKey, RsaPublicKey, + }; + + use crate::api::*; + // use crate::config::*; + // use crate::debug; + use crate::error::Error; + use crate::service::*; + use crate::types::*; + + impl DeriveKey for Rsa2048Pkcs { + #[inline(never)] + fn derive_key( + keystore: &mut impl Keystore, + request: &request::DeriveKey, + ) -> Result { + // Retrieve private key + let base_key_id = &request.base_key; + + // std::println!("Loading key: {:?}", base_key_id); + + let priv_key_der = keystore + .load_key(key::Secrecy::Secret, Some(key::Kind::Rsa2048), base_key_id) + .expect("Failed to load an RSA 2K private key with the given ID") + .material; + + // std::println!("Loaded key material: {}", delog::hex_str!(&priv_key_der)); + // std::println!("Key material length is {}", priv_key_der.len()); + + let priv_key = DecodePrivateKey::from_pkcs8_der(&priv_key_der) + .expect("Failed to deserialize an RSA 2K private key from PKCS#8 DER"); + + // Derive and store public key + let pub_key_der = RsaPublicKey::from(&priv_key) + .to_public_key_der() + .expect("Failed to derive an RSA 2K public key or to serialize it to PKCS#8 DER"); + + let pub_key_id = keystore.store_key( + request.attributes.persistence, + key::Secrecy::Public, + key::Kind::Rsa2048, + pub_key_der.as_ref(), + )?; + + // Send a reply + Ok(reply::DeriveKey { key: pub_key_id }) + } + } - let priv_key_der = keystore - .load_key(key::Secrecy::Secret, Some(key::Kind::Rsa2048), base_key_id) - .expect("Failed to load an RSA 2K private key with the given ID") - .material; + #[cfg(feature = "rsa2048")] + impl DeserializeKey for Rsa2048Pkcs { + #[inline(never)] + fn deserialize_key( + keystore: &mut impl Keystore, + request: &request::DeserializeKey, + ) -> Result { + // - mechanism: Mechanism + // - serialized_key: Message + // - attributes: StorageAttributes + + if request.format != KeySerialization::Pkcs8Der { + return Err(Error::InternalError); + } - // std::println!("Loaded key material: {}", delog::hex_str!(&priv_key_der)); - // std::println!("Key material length is {}", priv_key_der.len()); + let pub_key: RsaPublicKey = + DecodePublicKey::from_public_key_der(&request.serialized_key) + .map_err(|_| Error::InvalidSerializedKey)?; - let priv_key = DecodePrivateKey::from_pkcs8_der(&priv_key_der) - .expect("Failed to deserialize an RSA 2K private key from PKCS#8 DER"); + // We store our keys in PKCS#8 DER format + let pub_key_der = pub_key + .to_public_key_der() + .expect("Failed to serialize an RSA 2K private key to PKCS#8 DER"); - // Derive and store public key - let pub_key_der = RsaPublicKey::from(&priv_key) - .to_public_key_der() - .expect("Failed to derive an RSA 2K public key or to serialize it to PKCS#8 DER"); + let pub_key_id = keystore.store_key( + request.attributes.persistence, + key::Secrecy::Public, + key::Kind::Rsa2048, + pub_key_der.as_ref(), + )?; - let pub_key_id = keystore.store_key( - request.attributes.persistence, - key::Secrecy::Public, - key::Kind::Rsa2048, - pub_key_der.as_ref(), - )?; - - // Send a reply - Ok(reply::DeriveKey { key: pub_key_id }) + Ok(reply::DeserializeKey { key: pub_key_id }) + } } -} -#[cfg(feature = "rsa2048")] -impl DeserializeKey for super::Rsa2048Pkcs { - #[inline(never)] - fn deserialize_key( - keystore: &mut impl Keystore, - request: &request::DeserializeKey, - ) -> Result { - // - mechanism: Mechanism - // - serialized_key: Message - // - attributes: StorageAttributes - - if request.format != KeySerialization::Pkcs8Der { - return Err(Error::InternalError); + #[cfg(feature = "rsa2048")] + impl GenerateKey for Rsa2048Pkcs { + #[inline(never)] + fn generate_key( + keystore: &mut impl Keystore, + request: &request::GenerateKey, + ) -> Result { + // We want an RSA 2K key + let bits = 2048; + + let priv_key = RsaPrivateKey::new(keystore.rng(), bits) + .expect("Failed to generate an RSA 2K private key"); + + // std::println!("Stored key material before DER: {:#?}", priv_key); + + let priv_key_der = priv_key + .to_pkcs8_der() + .expect("Failed to serialize an RSA 2K private key to PKCS#8 DER"); + + // std::println!("Stored key material after DER: {}", delog::hex_str!(&priv_key_der)); + // std::println!("Key material length is {}", priv_key_der.as_ref().len()); + // #[cfg(all(test, feature = "verbose-tests"))] + // std::println!("rsa2048-pkcs private key = {:?}", &private_key); + + // store the key + let priv_key_id = keystore.store_key( + request.attributes.persistence, + key::Secrecy::Secret, + key::Info::from(key::Kind::Rsa2048).with_local_flag(), + priv_key_der.as_ref(), + )?; + + // return handle + Ok(reply::GenerateKey { key: priv_key_id }) } - - let pub_key: RsaPublicKey = DecodePublicKey::from_public_key_der(&request.serialized_key) - .map_err(|_| Error::InvalidSerializedKey)?; - - // We store our keys in PKCS#8 DER format - let pub_key_der = pub_key - .to_public_key_der() - .expect("Failed to serialize an RSA 2K private key to PKCS#8 DER"); - - let pub_key_id = keystore.store_key( - request.attributes.persistence, - key::Secrecy::Public, - key::Kind::Rsa2048, - pub_key_der.as_ref(), - )?; - - Ok(reply::DeserializeKey { key: pub_key_id }) } -} - -#[cfg(feature = "rsa2048")] -impl GenerateKey for super::Rsa2048Pkcs { - #[inline(never)] - fn generate_key( - keystore: &mut impl Keystore, - request: &request::GenerateKey, - ) -> Result { - // We want an RSA 2K key - let bits = 2048; - let priv_key = RsaPrivateKey::new(keystore.rng(), bits) - .expect("Failed to generate an RSA 2K private key"); - - // std::println!("Stored key material before DER: {:#?}", priv_key); - - let priv_key_der = priv_key - .to_pkcs8_der() - .expect("Failed to serialize an RSA 2K private key to PKCS#8 DER"); - - // std::println!("Stored key material after DER: {}", delog::hex_str!(&priv_key_der)); - // std::println!("Key material length is {}", priv_key_der.as_ref().len()); - // #[cfg(all(test, feature = "verbose-tests"))] - // std::println!("rsa2048-pkcs private key = {:?}", &private_key); + #[cfg(feature = "rsa2048")] + impl SerializeKey for Rsa2048Pkcs { + #[inline(never)] + fn serialize_key( + keystore: &mut impl Keystore, + request: &request::SerializeKey, + ) -> Result { + let key_id = request.key; + + // We rely on the fact that we store the keys in the PKCS#8 DER format already + let pub_key_der = keystore + .load_key(key::Secrecy::Public, Some(key::Kind::Rsa2048), &key_id) + .expect("Failed to load an RSA 2K public key with the given ID") + .material; + + let serialized_key = match request.format { + KeySerialization::Pkcs8Der => { + let mut serialized_key = SerializedKey::new(); + serialized_key + .extend_from_slice(&pub_key_der) + .map_err(|_err| { + error!("Failed to write public key {_err:?}"); + Error::InternalError + })?; + serialized_key + } + KeySerialization::RsaN => { + let key: RsaPublicKey = DecodePublicKey::from_public_key_der(&pub_key_der) + .expect("Failed to parse key"); + let mut serialized_n = SerializedKey::new(); + serialized_n + .extend_from_slice(&key.n().to_bytes_be()) + .map_err(|_err| { + error!("Failed to write public key {_err:?}"); + Error::InternalError + })?; + serialized_n + } + KeySerialization::RsaE => { + let key: RsaPublicKey = DecodePublicKey::from_public_key_der(&pub_key_der) + .expect("Failed to parse key"); + let mut serialized_e = SerializedKey::new(); + serialized_e + .extend_from_slice(&key.e().to_bytes_be()) + .map_err(|_err| { + error!("Failed to write public key {_err:?}"); + Error::InternalError + })?; + serialized_e + } + _ => { + return Err(Error::InternalError); + } + }; + + Ok(reply::SerializeKey { serialized_key }) + } + } - // store the key - let priv_key_id = keystore.store_key( - request.attributes.persistence, - key::Secrecy::Secret, - key::Info::from(key::Kind::Rsa2048).with_local_flag(), - priv_key_der.as_ref(), - )?; + #[cfg(feature = "rsa2048")] + impl Exists for Rsa2048Pkcs { + #[inline(never)] + fn exists( + keystore: &mut impl Keystore, + request: &request::Exists, + ) -> Result { + let key_id = request.key; + + let exists = + keystore.exists_key(key::Secrecy::Secret, Some(key::Kind::Rsa2048), &key_id); + Ok(reply::Exists { exists }) + } + } - // return handle - Ok(reply::GenerateKey { key: priv_key_id }) + #[cfg(feature = "rsa2048")] + impl Sign for Rsa2048Pkcs { + #[inline(never)] + fn sign( + keystore: &mut impl Keystore, + request: &request::Sign, + ) -> Result { + // First, get the key + let key_id = request.key; + + // We rely on the fact that we store the keys in the PKCS#8 DER format already + let priv_key_der = keystore + .load_key(key::Secrecy::Secret, Some(key::Kind::Rsa2048), &key_id) + .expect("Failed to load an RSA 2K private key with the given ID") + .material; + + let priv_key: RsaPrivateKey = DecodePrivateKey::from_pkcs8_der(&priv_key_der) + .expect("Failed to deserialize an RSA 2K private key from PKCS#8 DER"); + + // RSA lib takes in a hash value to sign, not raw data. + // We assume we get digest into this function, too. + + // TODO: Consider using .sign_blinded(), which is supposed to protect the private key from timing side channels + use rsa::padding::PaddingScheme; + let native_signature = priv_key + .sign(PaddingScheme::new_pkcs1v15_sign(None), &request.message) + .unwrap(); + let our_signature = Signature::from_slice(&native_signature).unwrap(); + + // std::println!("Rsa2048-PKCS_v1.5 signature:"); + // std::println!("msg: {:?}", &request.message); + // std::println!("pk: {:?}", &priv_key); + // std::println!("sig: {:?}", &our_signature); + + // return signature + Ok(reply::Sign { + signature: our_signature, + }) + } } -} -#[cfg(feature = "rsa2048")] -impl SerializeKey for super::Rsa2048Pkcs { - #[inline(never)] - fn serialize_key( - keystore: &mut impl Keystore, - request: &request::SerializeKey, - ) -> Result { - let key_id = request.key; - - // We rely on the fact that we store the keys in the PKCS#8 DER format already - let pub_key_der = keystore - .load_key(key::Secrecy::Public, Some(key::Kind::Rsa2048), &key_id) - .expect("Failed to load an RSA 2K public key with the given ID") - .material; - - let serialized_key = match request.format { - KeySerialization::Pkcs8Der => { - let mut serialized_key = SerializedKey::new(); - serialized_key - .extend_from_slice(&pub_key_der) - .map_err(|_err| { - error!("Failed to write public key {_err:?}"); - Error::InternalError - })?; - serialized_key - } - KeySerialization::RsaN => { - let key: RsaPublicKey = DecodePublicKey::from_public_key_der(&pub_key_der) - .expect("Failed to parse key"); - let mut serialized_n = SerializedKey::new(); - serialized_n - .extend_from_slice(&key.n().to_bytes_be()) - .map_err(|_err| { - error!("Failed to write public key {_err:?}"); - Error::InternalError - })?; - serialized_n + #[cfg(feature = "rsa2048")] + impl Verify for Rsa2048Pkcs { + #[inline(never)] + fn verify( + keystore: &mut impl Keystore, + request: &request::Verify, + ) -> Result { + if let SignatureSerialization::Raw = request.format { + } else { + return Err(Error::InvalidSerializationFormat); } - KeySerialization::RsaE => { - let key: RsaPublicKey = DecodePublicKey::from_public_key_der(&pub_key_der) - .expect("Failed to parse key"); - let mut serialized_e = SerializedKey::new(); - serialized_e - .extend_from_slice(&key.e().to_bytes_be()) - .map_err(|_err| { - error!("Failed to write public key {_err:?}"); - Error::InternalError - })?; - serialized_e - } - _ => { - return Err(Error::InternalError); + + // TODO: This must not be a hardcoded magic number, convert when a common mechanism is available + if request.signature.len() != 256 { + return Err(Error::WrongSignatureLength); } - }; - Ok(reply::SerializeKey { serialized_key }) - } -} + let key_id = request.key; -#[cfg(feature = "rsa2048")] -impl Exists for super::Rsa2048Pkcs { - #[inline(never)] - fn exists( - keystore: &mut impl Keystore, - request: &request::Exists, - ) -> Result { - let key_id = request.key; + let priv_key_der = keystore + .load_key(key::Secrecy::Secret, Some(key::Kind::Rsa2048), &key_id) + .expect("Failed to load an RSA 2K private key with the given ID") + .material; - let exists = keystore.exists_key(key::Secrecy::Secret, Some(key::Kind::Rsa2048), &key_id); - Ok(reply::Exists { exists }) - } -} + let priv_key = DecodePrivateKey::from_pkcs8_der(&priv_key_der) + .expect("Failed to deserialize an RSA 2K private key from PKCS#8 DER"); -#[cfg(feature = "rsa2048")] -impl Sign for super::Rsa2048Pkcs { - #[inline(never)] - fn sign(keystore: &mut impl Keystore, request: &request::Sign) -> Result { - // First, get the key - let key_id = request.key; - - // We rely on the fact that we store the keys in the PKCS#8 DER format already - let priv_key_der = keystore - .load_key(key::Secrecy::Secret, Some(key::Kind::Rsa2048), &key_id) - .expect("Failed to load an RSA 2K private key with the given ID") - .material; - - let priv_key: RsaPrivateKey = DecodePrivateKey::from_pkcs8_der(&priv_key_der) - .expect("Failed to deserialize an RSA 2K private key from PKCS#8 DER"); - - // RSA lib takes in a hash value to sign, not raw data. - // We assume we get digest into this function, too. - - // TODO: Consider using .sign_blinded(), which is supposed to protect the private key from timing side channels - use rsa::padding::PaddingScheme; - let native_signature = priv_key - .sign(PaddingScheme::new_pkcs1v15_sign(None), &request.message) - .unwrap(); - let our_signature = Signature::from_slice(&native_signature).unwrap(); - - // std::println!("Rsa2048-PKCS_v1.5 signature:"); - // std::println!("msg: {:?}", &request.message); - // std::println!("pk: {:?}", &priv_key); - // std::println!("sig: {:?}", &our_signature); - - // return signature - Ok(reply::Sign { - signature: our_signature, - }) - } -} + // Get the public key + let pub_key = RsaPublicKey::from(&priv_key); -#[cfg(feature = "rsa2048")] -impl Verify for super::Rsa2048Pkcs { - #[inline(never)] - fn verify( - keystore: &mut impl Keystore, - request: &request::Verify, - ) -> Result { - if let SignatureSerialization::Raw = request.format { - } else { - return Err(Error::InvalidSerializationFormat); - } + use rsa::padding::PaddingScheme; + let verification_ok = pub_key + .verify( + PaddingScheme::new_pkcs1v15_sign(None), + &request.message, + &request.signature, + ) + .is_ok(); - // TODO: This must not be a hardcoded magic number, convert when a common mechanism is available - if request.signature.len() != 256 { - return Err(Error::WrongSignatureLength); + Ok(reply::Verify { + valid: verification_ok, + }) } + } - let key_id = request.key; - - let priv_key_der = keystore - .load_key(key::Secrecy::Secret, Some(key::Kind::Rsa2048), &key_id) - .expect("Failed to load an RSA 2K private key with the given ID") - .material; + #[cfg(feature = "rsa2048")] + impl Decrypt for Rsa2048Pkcs { + #[inline(never)] + fn decrypt( + keystore: &mut impl Keystore, + request: &request::Decrypt, + ) -> Result { + use rsa::padding::PaddingScheme; + + // First, get the key + let key_id = request.key; + + // We rely on the fact that we store the keys in the PKCS#8 DER format already + let priv_key_der = keystore + .load_key(key::Secrecy::Secret, Some(key::Kind::Rsa2048), &key_id) + .expect("Failed to load an RSA 2K private key with the given ID") + .material; + + let priv_key: RsaPrivateKey = DecodePrivateKey::from_pkcs8_der(&priv_key_der) + .expect("Failed to deserialize an RSA 2K private key from PKCS#8 DER"); + + let res = priv_key + .decrypt(PaddingScheme::PKCS1v15Encrypt, &request.message) + .map_err(|_err| { + warn!("Failed to decrypt: {_err}"); + Error::FunctionFailed + })?; + + Ok(reply::Decrypt { + plaintext: Some(Bytes::from_slice(&res).map_err(|_| { + error!("Failed type conversion"); + Error::InternalError + })?), + }) + } + } - let priv_key = DecodePrivateKey::from_pkcs8_der(&priv_key_der) - .expect("Failed to deserialize an RSA 2K private key from PKCS#8 DER"); + #[cfg(feature = "rsa2048")] + fn unsafe_inject_pkcs_key( + keystore: &mut impl Keystore, + request: &request::UnsafeInjectKey, + ) -> Result { + let private_key: RsaPrivateKey = DecodePrivateKey::from_pkcs8_der(&request.raw_key) + .map_err(|_| Error::InvalidSerializedKey)?; - // Get the public key - let pub_key = RsaPublicKey::from(&priv_key); + // We store our keys in PKCS#8 DER format + let private_key_der = private_key + .to_pkcs8_der() + .expect("Failed to serialize an RSA 2K private key to PKCS#8 DER"); - use rsa::padding::PaddingScheme; - let verification_ok = pub_key - .verify( - PaddingScheme::new_pkcs1v15_sign(None), - &request.message, - &request.signature, - ) - .is_ok(); + let private_key_id = keystore.store_key( + request.attributes.persistence, + key::Secrecy::Secret, + key::Kind::Rsa2048, + private_key_der.as_ref(), + )?; - Ok(reply::Verify { - valid: verification_ok, + Ok(reply::UnsafeInjectKey { + key: private_key_id, }) } -} -#[cfg(feature = "rsa2048")] -impl Decrypt for super::Rsa2048Pkcs { - #[inline(never)] - fn decrypt( + #[cfg(feature = "rsa2048")] + fn unsafe_inject_openpgp_key( keystore: &mut impl Keystore, - request: &request::Decrypt, - ) -> Result { - use rsa::padding::PaddingScheme; - - // First, get the key - let key_id = request.key; - - // We rely on the fact that we store the keys in the PKCS#8 DER format already - let priv_key_der = keystore - .load_key(key::Secrecy::Secret, Some(key::Kind::Rsa2048), &key_id) - .expect("Failed to load an RSA 2K private key with the given ID") - .material; - - let priv_key: RsaPrivateKey = DecodePrivateKey::from_pkcs8_der(&priv_key_der) - .expect("Failed to deserialize an RSA 2K private key from PKCS#8 DER"); - - let res = priv_key - .decrypt(PaddingScheme::PKCS1v15Encrypt, &request.message) - .map_err(|_err| { - warn!("Failed to decrypt: {_err}"); - Error::FunctionFailed + request: &request::UnsafeInjectKey, + ) -> Result { + use rsa::BigUint; + let data: RsaCrtImportFormat<'_> = + crate::postcard_deserialize(&request.raw_key).map_err(|_err| { + error!("Failed to deserialize RSA key: {_err:?}"); + Error::InvalidSerializedKey + })?; + let e = BigUint::from_bytes_be(data.e); + let p = BigUint::from_bytes_be(data.p); + let q = BigUint::from_bytes_be(data.q); + // let dp = BigUint::from_bytes_be(data.dp); + // let dq = BigUint::from_bytes_be(data.dq); + let phi = (&p - 1u64) * (&q - 1u64); + + let d = e + .clone() + .mod_inverse(&phi) + .and_then(|int| int.to_biguint()) + .ok_or_else(|| { + warn!("Failed inverse"); + Error::InvalidSerializedKey })?; - Ok(reply::Decrypt { - plaintext: Some(Bytes::from_slice(&res).map_err(|_| { - error!("Failed type conversion"); - Error::InternalError - })?), - }) - } -} - -fn unsafe_inject_pkcs_key( - keystore: &mut impl Keystore, - request: &request::UnsafeInjectKey, -) -> Result { - let private_key: RsaPrivateKey = DecodePrivateKey::from_pkcs8_der(&request.raw_key) - .map_err(|_| Error::InvalidSerializedKey)?; - - // We store our keys in PKCS#8 DER format - let private_key_der = private_key - .to_pkcs8_der() - .expect("Failed to serialize an RSA 2K private key to PKCS#8 DER"); - - let private_key_id = keystore.store_key( - request.attributes.persistence, - key::Secrecy::Secret, - key::Kind::Rsa2048, - private_key_der.as_ref(), - )?; - - Ok(reply::UnsafeInjectKey { - key: private_key_id, - }) -} - -#[cfg(feature = "rsa2048")] -fn unsafe_inject_openpgp_key( - keystore: &mut impl Keystore, - request: &request::UnsafeInjectKey, -) -> Result { - use rsa::BigUint; - let data: RsaCrtImportFormat<'_> = - crate::postcard_deserialize(&request.raw_key).map_err(|_err| { - error!("Failed to deserialize RSA key: {_err:?}"); - Error::InvalidSerializedKey - })?; - let e = BigUint::from_bytes_be(data.e); - let p = BigUint::from_bytes_be(data.p); - let q = BigUint::from_bytes_be(data.q); - // let dp = BigUint::from_bytes_be(data.dp); - // let dq = BigUint::from_bytes_be(data.dq); - let phi = (&p - 1u64) * (&q - 1u64); - - let d = e - .clone() - .mod_inverse(&phi) - .and_then(|int| int.to_biguint()) - .ok_or_else(|| { - warn!("Failed inverse"); + // todo check bit size + let private_key = RsaPrivateKey::from_components(&p * &q, e, d, vec![p, q]); + private_key.validate().map_err(|_err| { + warn!("Bad private key: {_err:?}"); Error::InvalidSerializedKey })?; + if private_key.size() * 8 != 2048 { + warn!("Bad key size: {}", private_key.size()); + return Err(Error::InvalidSerializedKey); + } - // todo check bit size - let private_key = RsaPrivateKey::from_components(&p * &q, e, d, vec![p, q]); - private_key.validate().map_err(|_err| { - warn!("Bad private key: {_err:?}"); - Error::InvalidSerializedKey - })?; - if private_key.size() * 8 != 2048 { - warn!("Bad key size: {}", private_key.size()); - return Err(Error::InvalidSerializedKey); - } + // We store our keys in PKCS#8 DER format + let private_key_der = private_key + .to_pkcs8_der() + .expect("Failed to serialize an RSA 2K private key to PKCS#8 DER"); - // We store our keys in PKCS#8 DER format - let private_key_der = private_key - .to_pkcs8_der() - .expect("Failed to serialize an RSA 2K private key to PKCS#8 DER"); - - let private_key_id = keystore.store_key( - request.attributes.persistence, - key::Secrecy::Secret, - key::Kind::Rsa2048, - private_key_der.as_ref(), - )?; - - Ok(reply::UnsafeInjectKey { - key: private_key_id, - }) -} + let private_key_id = keystore.store_key( + request.attributes.persistence, + key::Secrecy::Secret, + key::Kind::Rsa2048, + private_key_der.as_ref(), + )?; -#[cfg(feature = "rsa2048")] -impl UnsafeInjectKey for super::Rsa2048Pkcs { - #[inline(never)] - fn unsafe_inject_key( - keystore: &mut impl Keystore, - request: &request::UnsafeInjectKey, - ) -> Result { - match request.format { - KeySerialization::Pkcs8Der => unsafe_inject_pkcs_key(keystore, request), - KeySerialization::RsaCrt => unsafe_inject_openpgp_key(keystore, request), - _ => Err(Error::InvalidSerializationFormat), + Ok(reply::UnsafeInjectKey { + key: private_key_id, + }) + } + + #[cfg(feature = "rsa2048")] + impl UnsafeInjectKey for Rsa2048Pkcs { + #[inline(never)] + fn unsafe_inject_key( + keystore: &mut impl Keystore, + request: &request::UnsafeInjectKey, + ) -> Result { + match request.format { + KeySerialization::Pkcs8Der => unsafe_inject_pkcs_key(keystore, request), + KeySerialization::RsaCrt => unsafe_inject_openpgp_key(keystore, request), + _ => Err(Error::InvalidSerializationFormat), + } } } } #[cfg(not(feature = "rsa2048"))] -impl DeriveKey for super::Rsa2048Pkcs {} -#[cfg(not(feature = "rsa2048"))] -impl GenerateKey for super::Rsa2048Pkcs {} -#[cfg(not(feature = "rsa2048"))] -impl Sign for super::Rsa2048Pkcs {} -#[cfg(not(feature = "rsa2048"))] -impl Verify for super::Rsa2048Pkcs {} -#[cfg(not(feature = "rsa2048"))] -impl Decrypt for super::Rsa2048Pkcs {} -#[cfg(not(feature = "rsa2048"))] -impl UnsafeInjectKey for super::Rsa2048Pkcs {} +mod non_implementations { + + use super::super::Rsa2048Pkcs; + use crate::service::*; + impl DeriveKey for Rsa2048Pkcs {} + impl GenerateKey for Rsa2048Pkcs {} + impl Sign for Rsa2048Pkcs {} + impl Verify for Rsa2048Pkcs {} + impl Decrypt for Rsa2048Pkcs {} + impl UnsafeInjectKey for Rsa2048Pkcs {} + impl DeserializeKey for Rsa2048Pkcs {} + impl SerializeKey for Rsa2048Pkcs {} + impl Exists for Rsa2048Pkcs {} +} diff --git a/tests/rsa2048pkcs.rs b/tests/rsa2048pkcs.rs index 69a16e739b8..f3380ebe887 100644 --- a/tests/rsa2048pkcs.rs +++ b/tests/rsa2048pkcs.rs @@ -1,3 +1,5 @@ +#![cfg(feature = "rsa2048")] + use trussed::client::mechanisms::Rsa2048Pkcs; use trussed::client::CryptoClient; use trussed::syscall; From dec0247e34f776cf5fceac8ff9b73cac62eca353 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= Date: Thu, 17 Nov 2022 11:42:15 +0100 Subject: [PATCH 38/47] Add support for RSA 4096 bits --- Cargo.toml | 6 + src/client/mechanisms.rs | 73 +++++++ src/config.rs | 4 +- src/key.rs | 5 +- src/mechanisms.rs | 4 + src/mechanisms/rsa4096.rs | 435 ++++++++++++++++++++++++++++++++++++++ src/service.rs | 9 + src/store/keystore.rs | 4 +- tests/rsa4096pkcs.rs | 107 ++++++++++ 9 files changed, 641 insertions(+), 6 deletions(-) create mode 100644 src/mechanisms/rsa4096.rs create mode 100644 tests/rsa4096pkcs.rs diff --git a/Cargo.toml b/Cargo.toml index 0805803d1ca..b6e5cd6710f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -129,3 +129,9 @@ test-attestation-cert-ids = [] [package.metadata.docs.rs] features = ["virt"] rustdoc-args = ["--cfg", "docsrs"] + +[profile.dev.package.rsa] +opt-level = 2 + +[profile.dev.package.num-bigint-dig] +opt-level = 2 diff --git a/src/client/mechanisms.rs b/src/client/mechanisms.rs index c76c2917d52..9b43e03acb3 100644 --- a/src/client/mechanisms.rs +++ b/src/client/mechanisms.rs @@ -458,6 +458,79 @@ pub trait Rsa2048Pkcs: CryptoClient { } } +#[cfg(feature = "rsa4096")] +impl Rsa4096Pkcs for ClientImplementation {} + +pub trait Rsa4096Pkcs: CryptoClient { + fn generate_rsa4096pkcs_private_key( + &mut self, + persistence: Location, + ) -> ClientResult<'_, reply::GenerateKey, Self> { + self.generate_key( + Mechanism::Rsa4096Pkcs, + StorageAttributes::new().set_persistence(persistence), + ) + } + + fn derive_rsa4096pkcs_public_key( + &mut self, + shared_key: KeyId, + persistence: Location, + ) -> ClientResult<'_, reply::DeriveKey, Self> { + self.derive_key( + Mechanism::Rsa4096Pkcs, + shared_key, + None, + StorageAttributes::new().set_persistence(persistence), + ) + } + + fn serialize_rsa4096pkcs_key( + &mut self, + key: KeyId, + format: KeySerialization, + ) -> ClientResult<'_, reply::SerializeKey, Self> { + self.serialize_key(Mechanism::Rsa4096Pkcs, key, format) + } + + fn deserialize_rsa4096pkcs_key<'c>( + &'c mut self, + serialized_key: &[u8], + format: KeySerialization, + attributes: StorageAttributes, + ) -> ClientResult<'c, reply::DeserializeKey, Self> { + self.deserialize_key(Mechanism::Rsa4096Pkcs, serialized_key, format, attributes) + } + + fn sign_rsa4096pkcs<'c>( + &'c mut self, + key: KeyId, + message: &[u8], + ) -> ClientResult<'c, reply::Sign, Self> { + self.sign( + Mechanism::Rsa4096Pkcs, + key, + message, + SignatureSerialization::Raw, + ) + } + + fn verify_rsa4096pkcs<'c>( + &'c mut self, + key: KeyId, + message: &[u8], + signature: &[u8], + ) -> ClientResult<'c, reply::Verify, Self> { + self.verify( + Mechanism::Rsa4096Pkcs, + key, + message, + signature, + SignatureSerialization::Raw, + ) + } +} + #[cfg(feature = "sha256")] impl Sha256 for ClientImplementation {} diff --git a/src/config.rs b/src/config.rs index f1745035c93..454bef1fae5 100644 --- a/src/config.rs +++ b/src/config.rs @@ -45,10 +45,10 @@ cfg_if::cfg_if! { pub const MAX_SHORT_DATA_LENGTH: usize = 128; #[cfg(any(feature = "rsa2048", feature = "rsa3072", feature = "rsa4096"))] -pub const MAX_SIGNATURE_LENGTH: usize = 512; +pub const MAX_SIGNATURE_LENGTH: usize = 512 * 2; #[cfg(any(feature = "rsa2048", feature = "rsa3072", feature = "rsa4096"))] // FIXME: Value from https://stackoverflow.com/questions/5403808/private-key-length-bytes for Rsa2048 Private key -pub const MAX_KEY_MATERIAL_LENGTH: usize = 1232; +pub const MAX_KEY_MATERIAL_LENGTH: usize = 1232 * 2; #[cfg(any(feature = "rsa2048", feature = "rsa3072", feature = "rsa4096"))] // This is due to the fact that KEY_MATERIAL_LENGTH is bigger than MESSAGE_LENGTH for RSA. pub const MAX_MESSAGE_LENGTH: usize = 1024; diff --git a/src/key.rs b/src/key.rs index b173c14bd8b..fcd02ad2b1e 100644 --- a/src/key.rs +++ b/src/key.rs @@ -67,6 +67,7 @@ pub enum Kind { P256, X255, Rsa2048, + Rsa4096, } bitflags::bitflags! { @@ -153,7 +154,7 @@ impl Kind { Kind::X255 => 6, Kind::Rsa2048 => 0x7, //Kind::Rsa3072 => 0xE0, - //Kind::Rsa4096 => 0xE1, + Kind::Rsa4096 => 0x8, } } @@ -168,7 +169,7 @@ impl Kind { 0x7 => Self::Rsa2048, //0xE0 => Kind::Rsa3072, - //0xE1 => Kind::Rsa4096, + 0x8 => Kind::Rsa4096, _ => return Err(Error::InvalidSerializedKey), }) } diff --git a/src/mechanisms.rs b/src/mechanisms.rs index 619cef77831..f48e483757d 100644 --- a/src/mechanisms.rs +++ b/src/mechanisms.rs @@ -53,6 +53,10 @@ pub struct Rsa2048Pkcs {} // Later on we'll add: "pub struct Rsa2048Pss {}" and so on mod rsa2048; +pub struct Rsa4096Pkcs {} +// Later on we'll add: "pub struct Rsa4096Pss {}" and so on +mod rsa4096; + pub struct Sha256 {} mod sha256; diff --git a/src/mechanisms/rsa4096.rs b/src/mechanisms/rsa4096.rs new file mode 100644 index 00000000000..c3f2283e6b7 --- /dev/null +++ b/src/mechanisms/rsa4096.rs @@ -0,0 +1,435 @@ +#[cfg(feature = "rsa4096")] +mod implementation { + use super::super::Rsa4096Pkcs; + use num_bigint_dig::traits::ModInverse; + use rsa::{ + pkcs8::{DecodePrivateKey, DecodePublicKey, EncodePrivateKey, EncodePublicKey}, + PublicKey, PublicKeyParts, RsaPrivateKey, RsaPublicKey, + }; + + use crate::api::*; + // use crate::config::*; + // use crate::debug; + use crate::error::Error; + use crate::service::*; + use crate::types::*; + + impl DeriveKey for Rsa4096Pkcs { + #[inline(never)] + fn derive_key( + keystore: &mut impl Keystore, + request: &request::DeriveKey, + ) -> Result { + // Retrieve private key + let base_key_id = &request.base_key; + + // std::println!("Loading key: {:?}", base_key_id); + + let priv_key_der = keystore + .load_key(key::Secrecy::Secret, Some(key::Kind::Rsa4096), base_key_id) + .expect("Failed to load an RSA 4096 bit private key with the given ID") + .material; + + // std::println!("Loaded key material: {}", delog::hex_str!(&priv_key_der)); + // std::println!("Key material length is {}", priv_key_der.len()); + + let priv_key = DecodePrivateKey::from_pkcs8_der(&priv_key_der) + .expect("Failed to deserialize an RSA 4096 bit private key from PKCS#8 DER"); + + // Derive and store public key + let pub_key_der = RsaPublicKey::from(&priv_key).to_public_key_der().expect( + "Failed to derive an RSA 4096 bit public key or to serialize it to PKCS#8 DER", + ); + + let pub_key_id = keystore.store_key( + request.attributes.persistence, + key::Secrecy::Public, + key::Kind::Rsa4096, + pub_key_der.as_ref(), + )?; + + // Send a reply + Ok(reply::DeriveKey { key: pub_key_id }) + } + } + + #[cfg(feature = "rsa4096")] + impl DeserializeKey for Rsa4096Pkcs { + #[inline(never)] + fn deserialize_key( + keystore: &mut impl Keystore, + request: &request::DeserializeKey, + ) -> Result { + // - mechanism: Mechanism + // - serialized_key: Message + // - attributes: StorageAttributes + + if request.format != KeySerialization::Pkcs8Der { + return Err(Error::InternalError); + } + + let pub_key: RsaPublicKey = + DecodePublicKey::from_public_key_der(&request.serialized_key) + .map_err(|_| Error::InvalidSerializedKey)?; + + // We store our keys in PKCS#8 DER format + let pub_key_der = pub_key + .to_public_key_der() + .expect("Failed to serialize an RSA 2K private key to PKCS#8 DER"); + + let pub_key_id = keystore.store_key( + request.attributes.persistence, + key::Secrecy::Public, + key::Kind::Rsa4096, + pub_key_der.as_ref(), + )?; + + Ok(reply::DeserializeKey { key: pub_key_id }) + } + } + + #[cfg(feature = "rsa4096")] + impl GenerateKey for Rsa4096Pkcs { + #[inline(never)] + fn generate_key( + keystore: &mut impl Keystore, + request: &request::GenerateKey, + ) -> Result { + // We want an RSA 4096 key + let bits = 4096; + + let priv_key = RsaPrivateKey::new(keystore.rng(), bits) + .expect("Failed to generate an RSA 4096 private key"); + + // std::println!("Stored key material before DER: {:#?}", priv_key); + + let priv_key_der = priv_key + .to_pkcs8_der() + .expect("Failed to serialize an RSA 4096 private key to PKCS#8 DER"); + + // std::println!("Stored key material after DER: {}", delog::hex_str!(&priv_key_der)); + // std::println!("Key material length is {}", priv_key_der.as_ref().len()); + // #[cfg(all(test, feature = "verbose-tests"))] + // std::println!("rsa4096-pkcs private key = {:?}", &private_key); + + // store the key + let priv_key_id = keystore.store_key( + request.attributes.persistence, + key::Secrecy::Secret, + key::Info::from(key::Kind::Rsa4096).with_local_flag(), + priv_key_der.as_ref(), + )?; + + // return handle + Ok(reply::GenerateKey { key: priv_key_id }) + } + } + + #[cfg(feature = "rsa4096")] + impl SerializeKey for Rsa4096Pkcs { + #[inline(never)] + fn serialize_key( + keystore: &mut impl Keystore, + request: &request::SerializeKey, + ) -> Result { + let key_id = request.key; + + // We rely on the fact that we store the keys in the PKCS#8 DER format already + let pub_key_der = keystore + .load_key(key::Secrecy::Public, Some(key::Kind::Rsa4096), &key_id) + .expect("Failed to load an RSA 2K public key with the given ID") + .material; + + let serialized_key = match request.format { + KeySerialization::Pkcs8Der => { + let mut serialized_key = SerializedKey::new(); + serialized_key + .extend_from_slice(&pub_key_der) + .map_err(|_err| { + error!("Failed to write public key {_err:?}"); + Error::InternalError + })?; + serialized_key + } + KeySerialization::RsaN => { + let key: RsaPublicKey = DecodePublicKey::from_public_key_der(&pub_key_der) + .expect("Failed to parse key"); + let mut serialized_n = SerializedKey::new(); + serialized_n + .extend_from_slice(&key.n().to_bytes_be()) + .map_err(|_err| { + error!("Failed to write public key {_err:?}"); + Error::InternalError + })?; + serialized_n + } + KeySerialization::RsaE => { + let key: RsaPublicKey = DecodePublicKey::from_public_key_der(&pub_key_der) + .expect("Failed to parse key"); + let mut serialized_e = SerializedKey::new(); + serialized_e + .extend_from_slice(&key.e().to_bytes_be()) + .map_err(|_err| { + error!("Failed to write public key {_err:?}"); + Error::InternalError + })?; + serialized_e + } + _ => { + return Err(Error::InternalError); + } + }; + + Ok(reply::SerializeKey { serialized_key }) + } + } + + #[cfg(feature = "rsa4096")] + impl Exists for Rsa4096Pkcs { + #[inline(never)] + fn exists( + keystore: &mut impl Keystore, + request: &request::Exists, + ) -> Result { + let key_id = request.key; + + let exists = + keystore.exists_key(key::Secrecy::Secret, Some(key::Kind::Rsa4096), &key_id); + Ok(reply::Exists { exists }) + } + } + + #[cfg(feature = "rsa4096")] + impl Sign for Rsa4096Pkcs { + #[inline(never)] + fn sign( + keystore: &mut impl Keystore, + request: &request::Sign, + ) -> Result { + // First, get the key + let key_id = request.key; + + // We rely on the fact that we store the keys in the PKCS#8 DER format already + let priv_key_der = keystore + .load_key(key::Secrecy::Secret, Some(key::Kind::Rsa4096), &key_id) + .expect("Failed to load an RSA 2K private key with the given ID") + .material; + + let priv_key: RsaPrivateKey = DecodePrivateKey::from_pkcs8_der(&priv_key_der) + .expect("Failed to deserialize an RSA 2K private key from PKCS#8 DER"); + + // RSA lib takes in a hash value to sign, not raw data. + // We assume we get digest into this function, too. + + // TODO: Consider using .sign_blinded(), which is supposed to protect the private key from timing side channels + use rsa::padding::PaddingScheme; + let native_signature = priv_key + .sign(PaddingScheme::new_pkcs1v15_sign(None), &request.message) + .unwrap(); + let our_signature = Signature::from_slice(&native_signature).unwrap(); + + // std::println!("Rsa4096-PKCS_v1.5 signature:"); + // std::println!("msg: {:?}", &request.message); + // std::println!("pk: {:?}", &priv_key); + // std::println!("sig: {:?}", &our_signature); + + // return signature + Ok(reply::Sign { + signature: our_signature, + }) + } + } + + #[cfg(feature = "rsa4096")] + impl Verify for Rsa4096Pkcs { + #[inline(never)] + fn verify( + keystore: &mut impl Keystore, + request: &request::Verify, + ) -> Result { + if let SignatureSerialization::Raw = request.format { + } else { + return Err(Error::InvalidSerializationFormat); + } + + // TODO: This must not be a hardcoded magic number, convert when a common mechanism is available + if request.signature.len() != 512 { + return Err(Error::WrongSignatureLength); + } + + let key_id = request.key; + + let priv_key_der = keystore + .load_key(key::Secrecy::Secret, Some(key::Kind::Rsa4096), &key_id) + .expect("Failed to load an RSA 4096 bit private key with the given ID") + .material; + + let priv_key = DecodePrivateKey::from_pkcs8_der(&priv_key_der) + .expect("Failed to deserialize an RSA 4096 bit private key from PKCS#8 DER"); + + // Get the public key + let pub_key = RsaPublicKey::from(&priv_key); + + use rsa::padding::PaddingScheme; + let verification_ok = pub_key + .verify( + PaddingScheme::new_pkcs1v15_sign(None), + &request.message, + &request.signature, + ) + .is_ok(); + + Ok(reply::Verify { + valid: verification_ok, + }) + } + } + + #[cfg(feature = "rsa4096")] + impl Decrypt for Rsa4096Pkcs { + #[inline(never)] + fn decrypt( + keystore: &mut impl Keystore, + request: &request::Decrypt, + ) -> Result { + use rsa::padding::PaddingScheme; + + // First, get the key + let key_id = request.key; + + // We rely on the fact that we store the keys in the PKCS#8 DER format already + let priv_key_der = keystore + .load_key(key::Secrecy::Secret, Some(key::Kind::Rsa4096), &key_id) + .expect("Failed to load an RSA 2K private key with the given ID") + .material; + + let priv_key: RsaPrivateKey = DecodePrivateKey::from_pkcs8_der(&priv_key_der) + .expect("Failed to deserialize an RSA 2K private key from PKCS#8 DER"); + + let res = priv_key + .decrypt(PaddingScheme::PKCS1v15Encrypt, &request.message) + .map_err(|_err| { + warn!("Failed to decrypt: {_err}"); + Error::FunctionFailed + })?; + + Ok(reply::Decrypt { + plaintext: Some(Bytes::from_slice(&res).map_err(|_| { + error!("Failed type conversion"); + Error::InternalError + })?), + }) + } + } + + #[cfg(feature = "rsa4096")] + fn unsafe_inject_pkcs_key( + keystore: &mut impl Keystore, + request: &request::UnsafeInjectKey, + ) -> Result { + let private_key: RsaPrivateKey = DecodePrivateKey::from_pkcs8_der(&request.raw_key) + .map_err(|_| Error::InvalidSerializedKey)?; + + // We store our keys in PKCS#8 DER format + let private_key_der = private_key + .to_pkcs8_der() + .expect("Failed to serialize an RSA 2K private key to PKCS#8 DER"); + + let private_key_id = keystore.store_key( + request.attributes.persistence, + key::Secrecy::Secret, + key::Kind::Rsa4096, + private_key_der.as_ref(), + )?; + + Ok(reply::UnsafeInjectKey { + key: private_key_id, + }) + } + + #[cfg(feature = "rsa4096")] + fn unsafe_inject_openpgp_key( + keystore: &mut impl Keystore, + request: &request::UnsafeInjectKey, + ) -> Result { + use rsa::BigUint; + let data: RsaCrtImportFormat<'_> = + crate::postcard_deserialize(&request.raw_key).map_err(|_err| { + error!("Failed to deserialize RSA key: {_err:?}"); + Error::InvalidSerializedKey + })?; + let e = BigUint::from_bytes_be(data.e); + let p = BigUint::from_bytes_be(data.p); + let q = BigUint::from_bytes_be(data.q); + // let dp = BigUint::from_bytes_be(data.dp); + // let dq = BigUint::from_bytes_be(data.dq); + let phi = (&p - 1u64) * (&q - 1u64); + + let d = e + .clone() + .mod_inverse(&phi) + .and_then(|int| int.to_biguint()) + .ok_or_else(|| { + warn!("Failed inverse"); + Error::InvalidSerializedKey + })?; + + // todo check bit size + let private_key = RsaPrivateKey::from_components(&p * &q, e, d, vec![p, q]); + private_key.validate().map_err(|_err| { + warn!("Bad private key: {_err:?}"); + Error::InvalidSerializedKey + })?; + if private_key.size() * 8 != 4096 { + warn!("Bad key size: {}", private_key.size()); + return Err(Error::InvalidSerializedKey); + } + + // We store our keys in PKCS#8 DER format + let private_key_der = private_key + .to_pkcs8_der() + .expect("Failed to serialize an RSA 2K private key to PKCS#8 DER"); + + let private_key_id = keystore.store_key( + request.attributes.persistence, + key::Secrecy::Secret, + key::Kind::Rsa4096, + private_key_der.as_ref(), + )?; + + Ok(reply::UnsafeInjectKey { + key: private_key_id, + }) + } + + #[cfg(feature = "rsa4096")] + impl UnsafeInjectKey for Rsa4096Pkcs { + #[inline(never)] + fn unsafe_inject_key( + keystore: &mut impl Keystore, + request: &request::UnsafeInjectKey, + ) -> Result { + match request.format { + KeySerialization::Pkcs8Der => unsafe_inject_pkcs_key(keystore, request), + KeySerialization::RsaCrt => unsafe_inject_openpgp_key(keystore, request), + _ => Err(Error::InvalidSerializationFormat), + } + } + } +} + +#[cfg(not(feature = "rsa4096"))] +mod non_implementations { + + use super::super::Rsa4096Pkcs; + use crate::service::*; + impl DeriveKey for Rsa4096Pkcs {} + impl GenerateKey for Rsa4096Pkcs {} + impl Sign for Rsa4096Pkcs {} + impl Verify for Rsa4096Pkcs {} + impl Decrypt for Rsa4096Pkcs {} + impl UnsafeInjectKey for Rsa4096Pkcs {} + impl DeserializeKey for Rsa4096Pkcs {} + impl SerializeKey for Rsa4096Pkcs {} + impl Exists for Rsa4096Pkcs {} +} diff --git a/src/service.rs b/src/service.rs index a3d5fd444a9..dc881c3f352 100644 --- a/src/service.rs +++ b/src/service.rs @@ -156,6 +156,7 @@ impl ServiceResources

{ Mechanism::Chacha8Poly1305 => mechanisms::Chacha8Poly1305::decrypt(keystore, request), Mechanism::Tdes => mechanisms::Tdes::decrypt(keystore, request), Mechanism::Rsa2048Pkcs => mechanisms::Rsa2048Pkcs::decrypt(keystore, request), + Mechanism::Rsa4096Pkcs => mechanisms::Rsa4096Pkcs::decrypt(keystore, request), _ => Err(Error::MechanismNotAvailable), }.map(Reply::Decrypt) @@ -173,6 +174,7 @@ impl ServiceResources

{ Mechanism::Sha256 => mechanisms::Sha256::derive_key(keystore, request), Mechanism::X255 => mechanisms::X255::derive_key(keystore, request), Mechanism::Rsa2048Pkcs => mechanisms::Rsa2048Pkcs::derive_key(keystore, request), + Mechanism::Rsa4096Pkcs => mechanisms::Rsa4096Pkcs::derive_key(keystore, request), _ => Err(Error::MechanismNotAvailable), }.map(Reply::DeriveKey) @@ -185,6 +187,7 @@ impl ServiceResources

{ Mechanism::P256 => mechanisms::P256::deserialize_key(keystore, request), Mechanism::X255 => mechanisms::X255::deserialize_key(keystore, request), Mechanism::Rsa2048Pkcs => mechanisms::Rsa2048Pkcs::deserialize_key(keystore, request), + Mechanism::Rsa4096Pkcs => mechanisms::Rsa4096Pkcs::deserialize_key(keystore, request), _ => Err(Error::MechanismNotAvailable), }.map(Reply::DeserializeKey) @@ -219,6 +222,7 @@ impl ServiceResources

{ Mechanism::Totp => mechanisms::Totp::exists(keystore, request), Mechanism::X255 => mechanisms::X255::exists(keystore, request), Mechanism::Rsa2048Pkcs => mechanisms::Rsa2048Pkcs::exists(keystore, request), + Mechanism::Rsa4096Pkcs => mechanisms::Rsa4096Pkcs::exists(keystore, request), _ => Err(Error::MechanismNotAvailable), }.map(Reply::Exists) @@ -231,6 +235,7 @@ impl ServiceResources

{ Mechanism::P256 => mechanisms::P256::generate_key(keystore, request), Mechanism::X255 => mechanisms::X255::generate_key(keystore, request), Mechanism::Rsa2048Pkcs => mechanisms::Rsa2048Pkcs::generate_key(keystore, request), + Mechanism::Rsa4096Pkcs => mechanisms::Rsa4096Pkcs::generate_key(keystore, request), _ => Err(Error::MechanismNotAvailable), }.map(Reply::GenerateKey) }, @@ -259,6 +264,7 @@ impl ServiceResources

{ Mechanism::Aes256Cbc => mechanisms::Aes256Cbc::unsafe_inject_key(keystore, request), Mechanism::Tdes => mechanisms::Tdes::unsafe_inject_key(keystore, request), Mechanism::Rsa2048Pkcs => mechanisms::Rsa2048Pkcs::unsafe_inject_key(keystore, request), + Mechanism::Rsa4096Pkcs => mechanisms::Rsa4096Pkcs::unsafe_inject_key(keystore, request), _ => Err(Error::MechanismNotAvailable) }.map(Reply::UnsafeInjectKey) }, @@ -445,6 +451,7 @@ impl ServiceResources

{ Mechanism::X255 => mechanisms::X255::serialize_key(keystore, request), Mechanism::SharedSecret => mechanisms::SharedSecret::serialize_key(keystore, request), Mechanism::Rsa2048Pkcs => mechanisms::Rsa2048Pkcs::serialize_key(keystore, request), + Mechanism::Rsa4096Pkcs => mechanisms::Rsa4096Pkcs::serialize_key(keystore, request), _ => Err(Error::MechanismNotAvailable), }.map(Reply::SerializeKey) @@ -462,6 +469,7 @@ impl ServiceResources

{ Mechanism::P256Prehashed => mechanisms::P256Prehashed::sign(keystore, request), Mechanism::Totp => mechanisms::Totp::sign(keystore, request), Mechanism::Rsa2048Pkcs => mechanisms::Rsa2048Pkcs::sign(keystore, request), + Mechanism::Rsa4096Pkcs => mechanisms::Rsa4096Pkcs::sign(keystore, request), _ => Err(Error::MechanismNotAvailable), }.map(Reply::Sign) @@ -487,6 +495,7 @@ impl ServiceResources

{ Mechanism::Ed255 => mechanisms::Ed255::verify(keystore, request), Mechanism::P256 => mechanisms::P256::verify(keystore, request), Mechanism::Rsa2048Pkcs => mechanisms::Rsa2048Pkcs::verify(keystore, request), + Mechanism::Rsa4096Pkcs => mechanisms::Rsa4096Pkcs::verify(keystore, request), _ => Err(Error::MechanismNotAvailable), }.map(Reply::Verify) diff --git a/src/store/keystore.rs b/src/store/keystore.rs index 7793a47fd73..b9f61091ccb 100644 --- a/src/store/keystore.rs +++ b/src/store/keystore.rs @@ -173,9 +173,9 @@ impl Keystore for ClientKeystore { let location = self.location(secrecy, id).ok_or(Error::NoSuchKey)?; - #[cfg(not(feature = "rsa2048"))] + #[cfg(not(any(feature = "rsa2048", feature = "rsa3072", feature = "rsa4096")))] let bytes: Bytes<128> = store::read(self.store, location, &path)?; - #[cfg(feature = "rsa2048")] + #[cfg(any(feature = "rsa2048", feature = "rsa3072", feature = "rsa4096"))] let bytes: Bytes = store::read(self.store, location, &path)?; let key = key::Key::try_deserialize(&bytes)?; diff --git a/tests/rsa4096pkcs.rs b/tests/rsa4096pkcs.rs new file mode 100644 index 00000000000..e6342a4750f --- /dev/null +++ b/tests/rsa4096pkcs.rs @@ -0,0 +1,107 @@ +#![cfg(feature = "rsa4096")] + +use trussed::client::mechanisms::Rsa4096Pkcs; +use trussed::client::CryptoClient; +use trussed::syscall; +use trussed::types::KeyId; + +mod client; + +use trussed::types::KeySerialization; +use trussed::types::Location::*; +use trussed::types::StorageAttributes; + +use hex_literal::hex; + +// Tests below can be run on a PC using the "virt" feature + +#[test] +fn rsa4096pkcs_generate_key() { + client::get(|client| { + let sk = syscall!(client.generate_rsa4096pkcs_private_key(Internal)).key; + + // This assumes we don't ever get a key with ID 0 + assert_ne!(sk, KeyId::from_special(0)); + }) +} + +#[test] +fn rsa4096pkcs_derive_key() { + client::get(|client| { + let sk = syscall!(client.generate_rsa4096pkcs_private_key(Internal)).key; + let pk = syscall!(client.derive_rsa4096pkcs_public_key(sk, Volatile)).key; + + // This assumes we don't ever get a key with ID 0 + assert_ne!(pk, KeyId::from_special(0)); + }) +} + +#[test] +fn rsa4096pkcs_exists_key() { + client::get(|client| { + let sk = syscall!(client.generate_rsa4096pkcs_private_key(Internal)).key; + let key_exists = syscall!(client.exists(trussed::types::Mechanism::Rsa4096Pkcs, sk)).exists; + + assert!(key_exists); + }) +} + +#[test] +fn rsa4096pkcs_serialize_key() { + client::get(|client| { + let sk = syscall!(client.generate_rsa4096pkcs_private_key(Internal)).key; + let pk = syscall!(client.derive_rsa4096pkcs_public_key(sk, Volatile)).key; + + let serialized_key = + syscall!(client.serialize_rsa4096pkcs_key(pk, KeySerialization::Pkcs8Der)) + .serialized_key; + + assert!(!serialized_key.is_empty()); + }) +} + +#[test] +fn rsa4096pkcs_deserialize_key() { + client::get(|client| { + let sk = syscall!(client.generate_rsa4096pkcs_private_key(Internal)).key; + let pk = syscall!(client.derive_rsa4096pkcs_public_key(sk, Volatile)).key; + let serialized_key = + syscall!(client.serialize_rsa4096pkcs_key(pk, KeySerialization::Pkcs8Der)) + .serialized_key; + let location = StorageAttributes::new().set_persistence(Volatile); + + let deserialized_key_id = syscall!(client.deserialize_rsa4096pkcs_key( + &serialized_key, + KeySerialization::Pkcs8Der, + location + )) + .key; + + // This assumes we don't ever get a key with ID 0 + assert_ne!(deserialized_key_id, KeyId::from_special(0)); + }) +} + +#[test] +fn rsa4096pkcs_sign_verify() { + client::get(|client| { + let sk = syscall!(client.generate_rsa4096pkcs_private_key(Volatile)).key; + let hash_prefix = hex!("3051 300d 0609 608648016503040203 0500 0440"); + let message = [1u8, 2u8, 3u8]; + use sha2::digest::Digest; + let digest_to_sign: Vec = sha2::Sha512::digest(&message) + .into_iter() + .chain(hash_prefix) + .collect(); + let signature = syscall!(client.sign_rsa4096pkcs(sk, &digest_to_sign)).signature; + + // println!("Message: {:?}", &message); + // println!("Digest: {:?}", &digest_to_sign); + // println!("Signature (len={}): {:?}", signature.len(), &signature); + + let verify_ok = syscall!(client.verify_rsa4096pkcs(sk, &digest_to_sign, &signature)).valid; + + assert_eq!(signature.len(), 512); + assert!(verify_ok); + }) +} From 4fd0c0675b192c4de974b943c0a247ec35592739 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= Date: Thu, 17 Nov 2022 15:52:11 +0100 Subject: [PATCH 39/47] Add tests for RSA key import --- src/api.rs | 2 +- src/client.rs | 2 +- tests/rsa2048pkcs.rs | 70 ++++++++++++++++++++++++++++++++++++++++--- tests/rsa4096pkcs.rs | 71 +++++++++++++++++++++++++++++++++++++++++--- 4 files changed, 135 insertions(+), 10 deletions(-) diff --git a/src/api.rs b/src/api.rs index ffc209332d3..e169ef4fb79 100644 --- a/src/api.rs +++ b/src/api.rs @@ -275,7 +275,7 @@ pub mod request { UnsafeInjectKey: - mechanism: Mechanism // -> implies key type - - raw_key: Message + - raw_key: SerializedKey - attributes: StorageAttributes - format: KeySerialization diff --git a/src/client.rs b/src/client.rs index ed7ff2f4d29..7d31498dc29 100644 --- a/src/client.rs +++ b/src/client.rs @@ -527,7 +527,7 @@ pub trait CryptoClient: PollClient { ) -> ClientResult<'_, reply::UnsafeInjectKey, Self> { let r = self.request(request::UnsafeInjectKey { mechanism, - raw_key: Message::from_slice(raw_key).unwrap(), + raw_key: SerializedKey::from_slice(raw_key).unwrap(), attributes: StorageAttributes::new().set_persistence(persistence), format, })?; diff --git a/tests/rsa2048pkcs.rs b/tests/rsa2048pkcs.rs index f3380ebe887..da3effadc28 100644 --- a/tests/rsa2048pkcs.rs +++ b/tests/rsa2048pkcs.rs @@ -4,13 +4,22 @@ use trussed::client::mechanisms::Rsa2048Pkcs; use trussed::client::CryptoClient; use trussed::syscall; use trussed::types::KeyId; +use trussed::Bytes; mod client; use trussed::types::KeySerialization; use trussed::types::Location::*; +use trussed::types::Mechanism; +use trussed::types::RsaCrtImportFormat; use trussed::types::StorageAttributes; +use hex_literal::hex; +use num_bigint_dig::BigUint; +use rsa::hash::Hash; +use rsa::padding::PaddingScheme; +use rsa::{PublicKey, RsaPrivateKey}; + // Tests below can be run on a PC using the "virt" feature #[test] @@ -84,10 +93,7 @@ fn rsa2048pkcs_deserialize_key() { fn rsa2048pkcs_sign_verify() { client::get(|client| { let sk = syscall!(client.generate_rsa2048pkcs_private_key(Volatile)).key; - let hash_prefix = [ - 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, - 0x01, 0x05, 0x00, 0x04, 0x20, - ]; + let hash_prefix = hex!("3031 300d 0609 608648016503040201 0500 0420"); let message = [1u8, 2u8, 3u8]; use sha2::digest::Digest; let digest_to_sign: Vec = sha2::Sha256::digest(&message) @@ -106,3 +112,59 @@ fn rsa2048pkcs_sign_verify() { assert!(verify_ok); }) } + +#[test] +fn rsa2048pkcs_inject() { + client::get(|client| { + let n = hex!("b43f96eee6abf0e71d81244f9adcc049c379f22a40d99e0a921fca08c1a83695f2060eeebc52823e8fa59f61156e42119758c3937c848a69e13a4a3ee23f35bb923a63b7d0cec6092957ff038b58c63339f300fb0d6dfc3d239fb8ef2caafbb40ca98fbd795e6ab5128a6e880b72a0637bfb197ea6697cd045c648d2a55f0f0e181d6bb50e56f297c8da164a3b04fab69e66107a7767e3a2c1df5e655c40db3e76e469e6db71b2d4edd73d48eee894d3c6c8e966bc2153256b014bc63a8f02c59a06b89004903ec4887ac916e2f7c5077b93eef17e914bb07add9dced384946f89d99ba48b28eedcc511ce359d2b2bce8052181f229033b6f2b1a905a55b33bd"); + let e = hex!("010001"); + let d = hex!("0ac47db4b9ccedb030c00536482f05c1a24ec79ba4921b71d036dbefd7f9bf81079b3b0b21eedfdef2dfd6fc8ab63276308f59e79699a85718e04d8d2220da89e0fb61f79a1eb00fde0b66ad848682188f4ea7f15765099b71645a3cd773436407199dff989f7e4a60d82a303056e1a3efc51949ca9124a6a0746ee73e7fc63b5c9df7e15be95b3f83dbb81a3a95284b52ca584fd058e9dbe74285b85b13688225c72cfc4c636950553aa31670de8dac45abac75e8872ee623f6cb0974c1915600bfc8e5c60e38101ae558ab3400d540b1db36b5eb6d9a0674ddbb814b69258ef15a0a3d07d557856a30af72d5c8ebc26d8cb067be783a5aea564afba4e28181"); + let p1 = hex!("ccefc3c11c7a0ed08aa3994c7ebe4ec9fabd1d83ff20c0e203ab1f230ae1ca158b6b6e82661f6ba179acb8ce5eca858abaf1987660748b78f00fc14bfb8fe1569fa7ac71276ce8cc1e1e9679fdfb589e538f6ccdab3b3fe26121a2d0f8d5721daea8104f61569f5f634fcd4c202788e46c1e39295d29b07a410ed4d023577fe1"); + let p2 = hex!("e1290bd8c19fbd77eb271fd081a96af60cc33a9e8b0fffb751b1ed557d8653f39bce97a4733f7725f2b26050317fc816698c3d8ba8b2a3198f167c6708fbb96d45b6c1ff6a1e4b07752f6f316a60d8559904466e3ad04b7d9cf56efda9dfeaaadb74caa0079933c7d063ee80ea4bca73c4e0a20dd7b61a6886666359cec59f5d"); + + let dp = hex!("962ea2faf2be73fad98e987a196ba75b97175df8ec4f796a681bd03ea2ebe267357bae497b434d61d144054e9ee2b5487c452e6099c0eeb0dae400d888eae0ccd5455036c018ace560b133bf04a45c45f2a069b0b2ea419fc96497e7a262f134d558ae532dd7080624464801a092b85c04eb85224df68e30995aa01443c20ca1"); + let dq = hex!("7577a39d970e8e9b948c19d5feff733520dd6da4af2a4e9fc6384c78b07f37273ddf1f50056c53edf15b4c522a30df238a374718a88f61f600a79b8969af6242f6feece122ece0f9e812323196ad25d02a7f877b14a5fcec70c9bef909fa2f04aa6f9912ba441c369faab31080abbfd87c1b3190853c95347901cbcd5bc9d065"); + let qinv = hex!("95de753d794227b41134152b071cf490efe78af52e5667cb18119b8a61c1523ecd0c8f38a8b73e64aea5ea098c15f838d995848d364d32cfca7c2e91934b9db04f97703f63125b7245de3eee91b9811131781906e940a60ec28fc754a7e610872311d15101371420590ee616561b9dcbe29a1b70d68d66de81220e0cab723e46"); + let raw = RsaPrivateKey::from_components( + BigUint::from_bytes_be(&n), + BigUint::from_bytes_be(&e), + BigUint::from_bytes_be(&d), + vec![BigUint::from_bytes_be(&p1), BigUint::from_bytes_be(&p2)], + ); + let pk = raw.to_public_key(); + + let request = RsaCrtImportFormat { + e: &e, + p: &p1, + q: &p2, + qinv: &qinv, + dp: &dp, + dq: &dq, + }; + let data: Bytes<2048> = trussed::postcard_serialize_bytes(&request).unwrap(); + let sk = syscall!(client.unsafe_inject_key( + Mechanism::Rsa2048Pkcs, + &data, + Volatile, + KeySerialization::RsaCrt + )) + .key; + + let hash_prefix = hex!("3031 300d 0609 608648016503040201 0500 0420"); + let message = [1u8, 2u8, 3u8]; + use sha2::digest::Digest; + let digest = sha2::Sha256::digest(&message); + let digest_to_sign: Vec = hash_prefix.into_iter().chain(digest).collect(); + + let signature = syscall!(client.sign_rsa2048pkcs(sk, &digest_to_sign)).signature; + assert!(pk + .verify( + PaddingScheme::PKCS1v15Sign { + hash: Some(Hash::SHA2_256) + }, + &digest, + &signature + ) + .is_ok()); + }); +} diff --git a/tests/rsa4096pkcs.rs b/tests/rsa4096pkcs.rs index e6342a4750f..868abd23108 100644 --- a/tests/rsa4096pkcs.rs +++ b/tests/rsa4096pkcs.rs @@ -4,14 +4,21 @@ use trussed::client::mechanisms::Rsa4096Pkcs; use trussed::client::CryptoClient; use trussed::syscall; use trussed::types::KeyId; +use trussed::Bytes; mod client; use trussed::types::KeySerialization; use trussed::types::Location::*; +use trussed::types::Mechanism; +use trussed::types::RsaCrtImportFormat; use trussed::types::StorageAttributes; use hex_literal::hex; +use num_bigint_dig::BigUint; +use rsa::hash::Hash; +use rsa::padding::PaddingScheme; +use rsa::{PublicKey, RsaPrivateKey}; // Tests below can be run on a PC using the "virt" feature @@ -89,10 +96,8 @@ fn rsa4096pkcs_sign_verify() { let hash_prefix = hex!("3051 300d 0609 608648016503040203 0500 0440"); let message = [1u8, 2u8, 3u8]; use sha2::digest::Digest; - let digest_to_sign: Vec = sha2::Sha512::digest(&message) - .into_iter() - .chain(hash_prefix) - .collect(); + let digest = sha2::Sha512::digest(&message); + let digest_to_sign: Vec = hash_prefix.into_iter().chain(digest).collect(); let signature = syscall!(client.sign_rsa4096pkcs(sk, &digest_to_sign)).signature; // println!("Message: {:?}", &message); @@ -105,3 +110,61 @@ fn rsa4096pkcs_sign_verify() { assert!(verify_ok); }) } + +#[test] +fn rsa4096pkcs_inject() { + client::get(|client| { + let n = hex!("adc511a420f48ffcb2c62f1a5113fe4e7f3efa20b0c6e711b93aca7e5ad662ba089ac27e9a1ae4cda8032d0b1ec8e3f719f6d3a04e1572a35caec922b439d53324b020d07e3ff70de2fb53409d26af1034b8f8fbf3776b1decd515af1298d98a671e3b2fd871f1b38c8917ed15c8732f96f75166df782d190913653a21da5d0647abc63c5b157910c455a4ac10d8ca3123ccdb98baf947e3a9ab9bff34fa9b0a19ab61f82c560ca46bad10391e49ef2bf5f01f198db12225338d68b0b18eaab962686e6a445b943952981fdf4c6f8135b6e86b1658d930df7fc2288c178401784a90977d1cf4444b401dabe2ebc6448979f74930aab7933a2fadc4c7b96c2fc65e85b2c49f0fa48381928ba64466b7c13303f8fa4b4afd5ad98e9d0990211a2b80caf6b071301e63d9f46b5d52016ec239e983efc1f6a0cd39a1fb9ae91483cc63f1467d13550802aab45ee03223ab1c13bdd82d79c4575f1bc4179ee9d7183534dd27b0a240497b951338fd29f863ff769140a4251219e61ef1ec8274d48431b58f7201c9069499488ac6c9e13e1ed790df14987760ef568a9fae55fd14e4e85232a345e265fb0ace01a0dc10a5390f67c9dba1de7d90b5b542eaaa370d935e153c97e82fe5108d9065991ad65181b2a2136d1474f91b3b85167cd3c04bdc6d144c4034b96b6be93b33c6d14bb511ffc04659cf807cbfd5039f68fb2ebe8ae9"); + let e = hex!("010001"); + let d = hex!("974447d9127f12a0ad976c0582b2dedbc255363422eee2d340e576c48b9ab892ad4edb248e4dff032fd0a3f35c37108b5864cf506ae8acc49cb7e28b7d4c22d5c48835e8891e7197fb114125ac27b2996eebde82a52c3d68ed7388cec067a267a2e06431803fa061e662a91b4fad10e84a88bca9cabab8b7647927d37508bb95edea1045161d19288960ec5a84c7d32af7b92b28470b1d93876dc5fc61480e92ba49c09ce32b7d11dc51e91f6fc87895522057524d4ff7235f3f27f5387bb30e7225ea88433d5d489127b0071868b097ebc363052f0ed2469cd68da9760709a887705b0f249756"); + + let p1 = hex!("cb4b267410739733134e5c7d21f042db821d3bf1e20b036de71cb40f175b3ddc8a164155223c5fec1df598fd5c314e9bc622c9c01fb3c70b1712b9f77d2ed6de5e9fe5b6dbfd789cedff5acff7d2bf0587bc071d43552f671e5392f69f7b16820bc2bec80b28f1eb42bbf2b99bd31eab59c479d2cd66550a7cf8d000b1c0e9c82460791a722bcd1945e134180b94ebf52026f0ee731cc63c38958f2fa5049ddac4cf55f57240f98afc51ff21a3379b16eba3974bb70623ec06afe6cd2d26041611c7b3b799090103fc0df8973aa1919a2ae65ccd1f484ccc5da4975ace0e96a2c3c0001c9b293b908d5585da5c0bb61ff5c17c20a0bd946a8df4fb7dd98cb44d"); + let p2 = hex!("dad263cb9b3c236859da7ecc6ec5f2154404dedf07cf39c7fd80ec2206384e906f001cf42ca690ab59a2aa73a2c78dfa4d5874a182ac92d7bd15161da7582fef30871b60afefee476944e32b41c482f71ceb6c476a5fccb2f65d8d382674a94b5abb4127bc4d8361bffbe8358f577875a0e0e8e1a975b00d8c3509a6566a1a2cd32d42a744b6785806566453903ebe420c6ea9a7eb2becc68cee40b81bee5e9957ccb7a3297545811e72b1b4e73b985ff30aff9abfb04c81b4937d8312f856098f15cf81c66ea2c6d94459ce25d4364e7d8c2aeaa6eace5b3054c976a8eb292fde2839503fb4444ba133c58fd1de38a995001af6af42661bcc6f18b1081c6f0d"); + let qinv = hex!("a9d2a72964e107db09dce8d345e35487b9f0e6eed1bceb64ed07d8580c0cacdb0641805083787109ae99fe705b426522b837953f05e9a204a277cebdde3e9d8a3e4e4e98f76764615f8028bb1a849cc125c7b11bc881ce08dd8fff72f1fda92fb893d79fc85555af021ad0d4c22f32dbfaacfaa3fd58d397fcb0904b267218374fa1b7ee7b06e6417aeeff428559b252c89fa41427506de6333d96b9ceac62648bb9743f7b4860c66a5e7fab0183ab7600887d947073e6b546adab857481943e3bcd3f88a98ae0febeaeddd71bce34514a8d1a9ebdba00e523f68dc28195cc7a4a1df133dd3d1866a97292fad735776b458750022fb1f4c79e7a3dbcb8bed893"); + + let dp = hex!("69dac6ba16bae99719cd6ad169739e8c8812cadce753cec4525c1ad1e4da88baa658724a6f1a3ae44ab150a95471043a8e901cb7628a8cf1146196ddec9c101c17ef7080a7ca331c9bbca43fb80e4f93049b7ea4d923a91c2ba95ed3f634f48260b755f9f9fda702566c61360e927edcc0505312d60b1beaeb29efbcfcd1b3a9986f777fb2c565f56bf298da906549fc0872de6f7b17178dd1f4e66aeba51cc1064be3b97b75a3baa029de0c58dda26eebe1f1ece5ef579315e44fecb43ea050119007df68db4c6113c4fe95585d3ae0a8c7ecb88e3a6a6adbb3d16fe1edacb831ef6edf7657a10162e68e5d26229f01c348ad669bec3b34c49834bfd220b6dd"); + let dq = hex!("62beaa3609193c492cb302a13223b5388f773b339e0c8f60862f155fcd3abf8941ede522f2bb3f7173838a33a07338c888faafb6ea8701c4c518ace038d1fcdf8d208ae438c0a6e026cae55071df41d24d84975a2ad08c48fe0ffd58275261cb156886e06d82f514b953edd7ad95a5503f86fed0466e4b41f1d14547809b64b071a36cfe9a6d552533c6ec8321068f48b2df8543b7461d150427c7a0cd49e5fa80ba6aec001b618000c37519d376fb2de139475b07c180e4cf1df7779ca9dff9744e3d53acbde44aa364cab9d22c4f4d602e4e7791574843b22db0b41149fd4e128c4840c45e8eab2a5578838c0b21bab4f8553298a7f7f7f76af2d3807b8449"); + + let raw = RsaPrivateKey::from_components( + BigUint::from_bytes_be(&n), + BigUint::from_bytes_be(&e), + BigUint::from_bytes_be(&d), + vec![BigUint::from_bytes_be(&p1), BigUint::from_bytes_be(&p2)], + ); + let pk = raw.to_public_key(); + + let request = RsaCrtImportFormat { + e: &e, + p: &p1, + q: &p2, + qinv: &qinv, + dp: &dp, + dq: &dq, + }; + let data: Bytes<2048> = trussed::postcard_serialize_bytes(&request).unwrap(); + let sk = syscall!(client.unsafe_inject_key( + Mechanism::Rsa4096Pkcs, + &data, + Volatile, + KeySerialization::RsaCrt + )) + .key; + + let hash_prefix = hex!("3051 300d 0609 608648016503040203 0500 0440"); + let message = [1u8, 2u8, 3u8]; + use sha2::digest::Digest; + let digest = sha2::Sha512::digest(&message); + let digest_to_sign: Vec = hash_prefix.into_iter().chain(digest).collect(); + + let signature = syscall!(client.sign_rsa4096pkcs(sk, &digest_to_sign)).signature; + assert!(pk + .verify( + PaddingScheme::PKCS1v15Sign { + hash: Some(Hash::SHA2_512) + }, + &digest, + &signature + ) + .is_ok()); + }); +} From fa7610cfc6f8115a87f9251c9318ecc55a4bb27a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= Date: Thu, 17 Nov 2022 15:58:12 +0100 Subject: [PATCH 40/47] Fix bad import --- src/store/keystore.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/store/keystore.rs b/src/store/keystore.rs index b9f61091ccb..9e49a78dc0c 100644 --- a/src/store/keystore.rs +++ b/src/store/keystore.rs @@ -173,9 +173,6 @@ impl Keystore for ClientKeystore { let location = self.location(secrecy, id).ok_or(Error::NoSuchKey)?; - #[cfg(not(any(feature = "rsa2048", feature = "rsa3072", feature = "rsa4096")))] - let bytes: Bytes<128> = store::read(self.store, location, &path)?; - #[cfg(any(feature = "rsa2048", feature = "rsa3072", feature = "rsa4096"))] let bytes: Bytes = store::read(self.store, location, &path)?; let key = key::Key::try_deserialize(&bytes)?; From 0a4a26955785d75dd8cd6b5f761ff6548e753c9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= Date: Thu, 17 Nov 2022 16:09:03 +0100 Subject: [PATCH 41/47] Fix key length --- src/config.rs | 2 +- tests/interchange_size.rs | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 tests/interchange_size.rs diff --git a/src/config.rs b/src/config.rs index 454bef1fae5..b42f5dd116e 100644 --- a/src/config.rs +++ b/src/config.rs @@ -48,7 +48,7 @@ pub const MAX_SHORT_DATA_LENGTH: usize = 128; pub const MAX_SIGNATURE_LENGTH: usize = 512 * 2; #[cfg(any(feature = "rsa2048", feature = "rsa3072", feature = "rsa4096"))] // FIXME: Value from https://stackoverflow.com/questions/5403808/private-key-length-bytes for Rsa2048 Private key -pub const MAX_KEY_MATERIAL_LENGTH: usize = 1232 * 2; +pub const MAX_KEY_MATERIAL_LENGTH: usize = 1160 * 2 + 72; #[cfg(any(feature = "rsa2048", feature = "rsa3072", feature = "rsa4096"))] // This is due to the fact that KEY_MATERIAL_LENGTH is bigger than MESSAGE_LENGTH for RSA. pub const MAX_MESSAGE_LENGTH: usize = 1024; diff --git a/tests/interchange_size.rs b/tests/interchange_size.rs new file mode 100644 index 00000000000..f7cf84fe089 --- /dev/null +++ b/tests/interchange_size.rs @@ -0,0 +1,12 @@ +#![cfg(any(feature = "rsa2048", feature = "rsa3072", feature = "rsa4096"))] + +use std::mem::size_of; + +use trussed::api::{Reply, Request}; + +// Used to keep track +#[test] +#[ignore] +fn interchange_size() { + assert_eq!((size_of::(), size_of::()), (2408, 2416)); +} From 65a83bc353579c7d01f11191798ef94178697499 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= Date: Wed, 30 Nov 2022 11:52:21 +0100 Subject: [PATCH 42/47] Revert "Update postcard dependency" This reverts commit 29096438b67a44533b787eafd5aa168571c5e599. The update breaks the format and causes loss of existing U2F keys --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index b6e5cd6710f..820d470f4d6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,7 +20,7 @@ generic-array = "0.14.4" heapless = { version = "0.7", features = ["serde"] } hex-literal = "0.3.1" nb = "1" -postcard = "1.0.2" +postcard = "0.7.0" rand_core = "0.6" serde = { version = "1.0", default-features = false } zeroize = { version = "1.2", default-features = false, features = ["zeroize_derive"] } From ccdbf9929a538ebb6c48a785a76ea91a1b17b707 Mon Sep 17 00:00:00 2001 From: Robin Krahl Date: Thu, 1 Dec 2022 10:44:54 +0100 Subject: [PATCH 43/47] Relax key kind check in derive_key for hmacsha256 In #38 [0], we restricted the operations for the hmacsha256 mechanism to symmetric and shared keys. This breaks fido-authenticator because it uses hmacsha256 derive_key on EC keys [1]. This patch relaxes the restrictions to allow all key kinds. [0] https://github.com/trussed-dev/trussed/pull/38 [1] https://github.com/solokeys/fido-authenticator/issues/21 --- src/mechanisms/hmacsha256.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/mechanisms/hmacsha256.rs b/src/mechanisms/hmacsha256.rs index 591c2033f9d..d1dcbd4073d 100644 --- a/src/mechanisms/hmacsha256.rs +++ b/src/mechanisms/hmacsha256.rs @@ -16,7 +16,9 @@ impl DeriveKey for super::HmacSha256 { let key_id = request.base_key; let key = keystore.load_key(key::Secrecy::Secret, None, &key_id)?; if !matches!(key.kind, key::Kind::Symmetric(..) | key::Kind::Shared(..)) { - return Err(Error::WrongKeyKind); + // We have to disable this check for compatibility with fido-authenticator, see: + // https://github.com/solokeys/fido-authenticator/issues/21 + warn!("derive_key for hmacsha256 called with invalid key kind ({:?})", key.kind); } let shared_secret = key.material; From eb4060e037fe6d3e1f61d4df12da7c4bea6797a6 Mon Sep 17 00:00:00 2001 From: Robin Krahl Date: Wed, 14 Dec 2022 14:06:44 +0100 Subject: [PATCH 44/47] Drop firmwares check from CI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For our fork, we don’t need to check compatibility with solokeys. And the nitrokey-3-firmware check isn’t active anyway. --- .github/workflows/firmwares.yml | 72 --------------------------------- 1 file changed, 72 deletions(-) delete mode 100644 .github/workflows/firmwares.yml diff --git a/.github/workflows/firmwares.yml b/.github/workflows/firmwares.yml deleted file mode 100644 index 90fff70d4e8..00000000000 --- a/.github/workflows/firmwares.yml +++ /dev/null @@ -1,72 +0,0 @@ -name: CI - -on: - pull_request: - branches: [main] - push: - branches: [main] - -jobs: - firmwares: - runs-on: ubuntu-latest - - steps: - - name: Checkout repository - uses: actions/checkout@v2 - with: - path: trussed - - - name: Checkout solokeys/solo2 - run: git clone https://github.com/solokeys/solo2 solo2 - - - name: Checkout Nitrokey/nitrokey-3-firmware - run: git clone https://github.com/Nitrokey/nitrokey-3-firmware nk3 - - - name: Install littlefs2-sys/micro-ecc-sys build dependencies - shell: bash - run: | - apt-get update && apt-get install sudo - env && pwd && sudo apt-get update -y -qq && sudo apt-get install -y -qq llvm libc6-dev-i386 libclang-dev clang git - - - uses: fiam/arm-none-eabi-gcc@v1 - with: - release: "10-2020-q4" - - - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: stable - target: thumbv8m.main-none-eabi - override: true - components: llvm-tools-preview - - - - name: cargo install cargo-binutils - uses: actions-rs/install@v0.1 - with: - crate: cargo-binutils - version: latest - use-tool-cache: true - - - name: cargo install flip-link - uses: actions-rs/install@v0.1 - with: - crate: flip-link - version: latest - use-tool-cache: true - - - name: Patch solo2 trussed-dependency - run: | - echo "[patch.crates-io]" >> solo2/runners/lpc55/Cargo.toml - echo "trussed = { path = '../../../trussed' }" >> solo2/runners/lpc55/Cargo.toml - - # - name: Patch Nk3 trussed-dependency -> currently not, as we already patch trussed - # run: | - # echo "[patch.crates-io]" >> nk3/runners/lpc55/Cargo.toml - # echo "trussed = { git = 'https://github.com/trussed-dev/trussed' }" >> nk3/runners/lpc55/Cargo.toml - - - name: Build Solo2 Firmware - run: make build-release -C solo2/runners/lpc55 - - - name: Build Nitrokey-3 Firmware - run: make -C nk3/runners/lpc55 From e0d6a62fea87638e5ac865f3333c9d378cc860a9 Mon Sep 17 00:00:00 2001 From: Robin Krahl Date: Wed, 14 Dec 2022 14:20:16 +0100 Subject: [PATCH 45/47] Fix aes256cbc test --- tests/aes256cbc.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/aes256cbc.rs b/tests/aes256cbc.rs index 91af2b5b22b..9310dfa21a0 100644 --- a/tests/aes256cbc.rs +++ b/tests/aes256cbc.rs @@ -30,7 +30,7 @@ fn aes256cbc() { .encrypt_padded_mut::(&mut buffer, 64) .unwrap(); assert_ne!(buffer, [48; 64]); - assert_eq!(buffer.as_slice(), *ciphertext); + assert_eq!(buffer.as_slice(), ciphertext.as_slice()); let plaintext = syscall!(client.decrypt(Mechanism::Aes256Cbc, key, &ciphertext, &[], &[], &[])) From 0ee76914276e3c29a94feadff79563cb012d9540 Mon Sep 17 00:00:00 2001 From: Robin Krahl Date: Thu, 15 Dec 2022 14:00:20 +0100 Subject: [PATCH 46/47] Patch littlefs2 dependency This is required for compatibility with nitrokey-3-firmware. --- Cargo.toml | 4 +++- src/virt/store.rs | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 820d470f4d6..cbb82f47fd3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -123,8 +123,10 @@ clients-11 = [] clients-12 = [] test-attestation-cert-ids = [] -# [patch.crates-io] + +[patch.crates-io] # interchange = { git = "https://github.com/trussed-dev/interchange", branch = "main" } +littlefs2 = { git = "https://github.com/Nitrokey/littlefs2", tag = "v0.3.2-nitrokey-1" } [package.metadata.docs.rs] features = ["virt"] diff --git a/src/virt/store.rs b/src/virt/store.rs index 19de6f49292..a0b82f4f3a0 100644 --- a/src/virt/store.rs +++ b/src/virt/store.rs @@ -47,7 +47,7 @@ impl Storage for FilesystemStorage { // TODO: This can't actually be changed currently // type ATTRBYTES_MAX = U1022; - fn read(&self, offset: usize, buffer: &mut [u8]) -> LfsResult { + fn read(&mut self, offset: usize, buffer: &mut [u8]) -> LfsResult { let mut file = File::open(&self.0).unwrap(); file.seek(SeekFrom::Start(offset as _)).unwrap(); let bytes_read = file.read(buffer).unwrap(); From 85d78dcac6784e1faccd06beee275d9f3a4977f9 Mon Sep 17 00:00:00 2001 From: Markus Meissner Date: Mon, 6 Feb 2023 15:19:40 +0100 Subject: [PATCH 47/47] virt: adapt to trussed-dev/littlefs2#24 --- src/virt/store.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/virt/store.rs b/src/virt/store.rs index 1f5c28fb96e..dbddd53e792 100644 --- a/src/virt/store.rs +++ b/src/virt/store.rs @@ -5,7 +5,7 @@ use std::{ path::PathBuf, }; -use generic_array::typenum::{U16, U512}; +use generic_array::typenum::{U8, U16, U512}; use littlefs2::{const_ram_storage, driver::Storage, fs::Allocation}; use crate::{ @@ -53,7 +53,7 @@ impl Storage for FilesystemStorage { const BLOCK_CYCLES: isize = -1; type CACHE_SIZE = U512; - type LOOKAHEADWORDS_SIZE = U16; + type LOOKAHEAD_SIZE = U8; // TODO: This can't actually be changed currently // type FILENAME_MAX_PLUS_ONE = U256; // type PATH_MAX_PLUS_ONE = U256;