From 9bde6956efaa8581dd93c6fbec08bd83d2d67a57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= Date: Thu, 23 Jan 2025 17:48:54 +0100 Subject: [PATCH] Add RSA3072 algorithm --- Cargo.toml | 2 +- src/lib.rs | 13 +++++++-- src/piv_types.rs | 20 ++++++++++--- src/vpicc.rs | 1 + tests/command_response.ron | 60 +++++++++++++++++++++++++++++++++++++- tests/command_response.rs | 8 ++++- 6 files changed, 94 insertions(+), 10 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 010726c..3a70984 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,7 +29,7 @@ log = "0.4" heapless-bytes = "0.3.0" subtle = { version = "2", default-features = false } # TODO: only enable rsa features when needed -trussed-core = { version = "0.1.0-rc.1", features = ["aes256-cbc", "chacha8-poly1305", "crypto-client", "ed255", "filesystem-client", "p256", "p384", "rsa2048", "rsa4096", "shared-secret", "tdes", "x255"] } +trussed-core = { version = "0.1.0-rc.1", features = ["aes256-cbc", "chacha8-poly1305", "crypto-client", "ed255", "filesystem-client", "p256", "p384", "rsa2048", "rsa3072", "rsa4096", "shared-secret", "tdes", "x255"] } trussed-rsa-alloc = { version = "0.2.1", features = ["raw"], optional = true } trussed-chunked = "0.2.0" trussed-hpke = "0.2.0" diff --git a/src/lib.rs b/src/lib.rs index 0f30f4f..2f4e7f3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -925,7 +925,9 @@ impl LoadedAuthenticator<'_, T> { reply.prepend_len(offset)?; } #[cfg(feature = "rsa")] - AsymmetricAlgorithms::Rsa2048 | AsymmetricAlgorithms::Rsa4096 => { + AsymmetricAlgorithms::Rsa2048 + | AsymmetricAlgorithms::Rsa3072 + | AsymmetricAlgorithms::Rsa4096 => { use trussed_rsa_alloc::RsaPublicParts; reply.expand(&[0x7F, 0x49])?; let offset = reply.len(); @@ -1079,13 +1081,18 @@ impl LoadedAuthenticator<'_, T> { match (algo, key) { // TODO: document Here we do not exactly follow the Yubico extensions to fit better with our RSA backend requirements #[cfg(feature = "rsa")] - (AsymmetricAlgorithms::Rsa2048, AsymmetricKeyReference::PivAuthentication) => { + ( + AsymmetricAlgorithms::Rsa2048 + | AsymmetricAlgorithms::Rsa3072 + | AsymmetricAlgorithms::Rsa4096, + AsymmetricKeyReference::PivAuthentication, + ) => { use trussed_rsa_alloc::RsaImportFormat; let p = tlv::get_do(&[0x01], data).ok_or(Status::IncorrectDataParameter)?; let q = tlv::get_do(&[0x02], data).ok_or(Status::IncorrectDataParameter)?; let e = tlv::get_do(&[0x03], data).ok_or(Status::IncorrectDataParameter)?; let id = syscall!(self.trussed.unsafe_inject_key( - Mechanism::Rsa2048Raw, + algo.key_mechanism(), &RsaImportFormat { e, p, q }.serialize().map_err(|_err| { error!("Failed rsa import serialization: {_err:?}"); Status::UnspecifiedNonpersistentExecutionError diff --git a/src/piv_types.rs b/src/piv_types.rs index 5126c5e..ccbc847 100644 --- a/src/piv_types.rs +++ b/src/piv_types.rs @@ -115,6 +115,7 @@ enum_u8! { Aes256 = 0xC, P256 = 0x11, P384 = 0x14, + Rsa3072 = 0x05, // // non-standard! in piv-go though! // Ed255_prev = 0x22, @@ -122,8 +123,7 @@ enum_u8! { // https://globalplatform.org/wp-content/uploads/2014/03/GPC_ISO_Framework_v1.0.pdf#page=15 P521 = 0x15, // non-standard! - Rsa3072 = 0xE0, - Rsa4096 = 0xE1, + Rsa4096 = 0x16, Ed25519 = 0xE2, X25519 = 0xE3, Ed448 = 0xE4, @@ -144,6 +144,8 @@ crate::container::enum_subset! { #[cfg(feature = "rsa")] Rsa2048, #[cfg(feature = "rsa")] + Rsa3072, + #[cfg(feature = "rsa")] Rsa4096, P256, @@ -173,6 +175,8 @@ impl AsymmetricAlgorithms { #[cfg(feature = "rsa")] Self::Rsa2048 => Mechanism::Rsa2048Raw, #[cfg(feature = "rsa")] + Self::Rsa3072 => Mechanism::Rsa3072Raw, + #[cfg(feature = "rsa")] Self::Rsa4096 => Mechanism::Rsa4096Raw, Self::P256 => Mechanism::P256, Self::P384 => Mechanism::P384, @@ -195,6 +199,8 @@ impl AsymmetricAlgorithms { #[cfg(feature = "rsa")] Self::Rsa2048 => Mechanism::Rsa2048Raw, #[cfg(feature = "rsa")] + Self::Rsa3072 => Mechanism::Rsa3072Raw, + #[cfg(feature = "rsa")] Self::Rsa4096 => Mechanism::Rsa4096Raw, Self::P256 => Mechanism::P256Prehashed, Self::P384 => Mechanism::P384Prehashed, @@ -207,6 +213,8 @@ impl AsymmetricAlgorithms { #[cfg(feature = "rsa")] Self::Rsa2048 => 256, #[cfg(feature = "rsa")] + Self::Rsa3072 => 384, + #[cfg(feature = "rsa")] Self::Rsa4096 => 512, Self::P256 => 32, Self::P384 => 48, @@ -216,7 +224,7 @@ impl AsymmetricAlgorithms { pub fn sign_serialization(self) -> SignatureSerialization { match self { #[cfg(feature = "rsa")] - Self::Rsa2048 | Self::Rsa4096 => SignatureSerialization::Raw, + Self::Rsa2048 | Self::Rsa3072 | Self::Rsa4096 => SignatureSerialization::Raw, Self::P256 => SignatureSerialization::Asn1Der, Self::P384 => SignatureSerialization::Asn1Der, } @@ -226,7 +234,9 @@ impl AsymmetricAlgorithms { #[cfg(feature = "rsa")] return matches!( self, - AsymmetricAlgorithms::Rsa2048 | AsymmetricAlgorithms::Rsa4096 + AsymmetricAlgorithms::Rsa2048 + | AsymmetricAlgorithms::Rsa3072 + | AsymmetricAlgorithms::Rsa4096 ); #[cfg(not(feature = "rsa"))] return false; @@ -251,6 +261,7 @@ crate::container::enum_subset! { #[derive(Debug,Deserialize,Serialize)] pub enum RsaAlgorithms: Algorithms { Rsa2048, + Rsa3072, Rsa4096, } } @@ -259,6 +270,7 @@ impl RsaAlgorithms { pub fn mechanism(self) -> Mechanism { match self { Self::Rsa2048 => Mechanism::Rsa2048Raw, + Self::Rsa3072 => Mechanism::Rsa3072Raw, Self::Rsa4096 => Mechanism::Rsa4096Raw, } } diff --git a/src/vpicc.rs b/src/vpicc.rs index af618bb..63ff199 100644 --- a/src/vpicc.rs +++ b/src/vpicc.rs @@ -31,6 +31,7 @@ impl VpiccCard { } fn handle(&mut self, request: &[u8]) -> (&[u8], Status) { + log::debug!("{:02x?} request", request); parse_command(request) .and_then(|command| self.request_buffer.handle(command)) .map(|command| { diff --git a/tests/command_response.ron b/tests/command_response.ron index 8bc116f..d2678d9 100644 --- a/tests/command_response.ron +++ b/tests/command_response.ron @@ -394,7 +394,7 @@ ] ), IoTest( - name: "RSA signature value", + name: "RSA 2048 bit signature value", uuid_config: WithBoth("00112233445566778899AABBCCDDEEFF"), cmd_resp: [ AuthenticateManagement( @@ -425,6 +425,64 @@ ) ] ), + IoTest( + name: "RSA 3072 signature value", + uuid_config: WithBoth("00112233445566778899AABBCCDDEEFF"), + cmd_resp: [ + AuthenticateManagement( + mutual: false, + key: ( + algorithm: Tdes, + key: "0102030405060708 0102030405060708 0102030405060708" + ) + ), + ImportRsaKey( + p: "d669e08e7586b2dae421e717f74138f24e469d64b272b3c76bfcb437c99fdda060af53f3d9d455deec8681f89fc55602eee5ec645d9e813748b044b77d73be7860bf793468ae0eac9990245e975662bbc3a80064b85b8d4980ccd0d746e2c06271e66371ffc76798811fc66e8d708792db92ac3a310df5326045aadb7faf74aa65b75332fe51633bc77f36571989584819efd75e0f1b2fceb4bd32676ff6fdddb71434b2d15763a2788af9b73bdb85701bd7e3314f5c0f9442f11fbe698d41ef", + q: "f19fb71ecddd8fce1e405a282b6577485bf9f25e9dd9ef3f73421bcde0f212c630d6033088fb0d8298e7b2a457eb25d7d9994bf5601be14f9eb9e014109bb5a36361bba4122a35ece0e3d92168b32826de5d4209b2ebcf49a84586ea888d71fa89deec64dde6b8cb6a0a4c4d6e0099a6a8b168cc702341d59649e0c7ce4ca59c4b08bc8658e6ec52b4b9c951e1f9234ca081216b6a3cd8a1492069d22b28197c8c8bfc532c037577617ad02a5cbd515e2b7354adb4ad62a9398dd316f712328b", + e: "010001", + ), + VerifyApplicationPin(), + Sign( + algo: 0x07, + key_reference: 0x9A, + data: "011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111", + output: Data(" + 7c 82 0184 + 82 820180 + 8381de65f2583fa2b6e77e4b6cedb9e8b87d6374aef1dc9cd25f09af0ea49b08df11e4421d3ac0fc24c5718bcb7473d3bd9c3b8b4d7e7b957caf0ceb98442e04c65d7b7a430a0d3f82b62771abdfe47e7e385e2a68b2c799c3c6d8847a4c7fd32f1ef6660c61fd5e73cd75884cc582dc9e13dacea59b23bb318c2d193a0fb1115888c0e3cc1605428d683644c66119b1508dcffa08069dab530153489ccb43bec74bb43d1a1b89ca29ae7635d951a144bd1634e38021e0d251f4ce0f7f0ca8c82b83677dbe9b905ff465b311a297943382e120f0fc6c6b6c89998389a14c98507c7d3bdda978f7e356d27dd427028ca8f1d1a3aaea869b4b5d8273d93d52445959b9321e71bc8f2df43fb27dde1d7e54737e659bf436ddb3f100339bb9d8d12d7a3e4601d272152cc10d2053f62750af1c9337fb3778df71c8f5002787bc2c57c651d55ff374ed0da8489c1eddc8ed185193673f9fa343f2d53c883575371316e82dc53104ef8e5cf178ebc66cb0b102cc132b55c768f3809996532d0f36c791 + "), + ) + ] + ), + IoTest( + name: "RSA 4096 signature value", + uuid_config: WithBoth("00112233445566778899AABBCCDDEEFF"), + cmd_resp: [ + AuthenticateManagement( + key: ( + algorithm: Tdes, + key: "0102030405060708 0102030405060708 0102030405060708" + ), + mutual: false, + ), + ImportRsaKey( + p: "c4e56357f7910f2bcf5095dfbda9485adcd416c7dd5c794be72c4667397f05c840b0cd89f04c4ef12f7bcbf7bfad8c9ef96d695fa6fe4322b7fec913cf3d0976260c22d86f11c01af214d518bdb1c9260bf55e92c838fe60712fac04d0c2beae68a063b81cdc3f3afed2df32146a6d04a63ddb7885e4fe1880f710bae2ca5711e5883834559a331a1e5a8fad9a397f2fa064f36db9aa522d3816aa378c91940473cc1f347b6e0ae21182ba2939fee1f9824678b72a15cc35ebf27899b42494b09d26d0d5efa6fd4ad380b88c64c0687287d902c9a0546f1d06416992853cdcbb9e080dc0989b72514513da9f6dd332fdc46347f4a70b558cc6c6431e308dbfb7", + q: "cb100ef4dd07f17f4ceae3017aeb5cd6a63ef8bd048d181ff8e02dc45857ea1954513340c90db5fe67fcbac1d5dbe681f3ceb26bbc72e4720854ef17e8a340e270c3217c9f61f0734ec3600e3f9b24a648d7b8547117d16107ff1d1413ccc8e858cadbda8264b84fd7bd1fde14d285248d608083e2b40b328c58cfb37f37b6e9f4c416c972c3c6abee6bcccb34975fa5b335c7ba98b846f954e55cfcaba9f3dd9ab84e2b31c7e54967480bfced52c14d5a3a56235ee53f5c1aa994ee5e314bb2bb75ae3266e7e42cc6eb2229e911d95d483659371af5ba001381f278d063e082c99bf238daec1dcd8af07641c6e9bd8d8ea04dfe68d9c1833c9701d820a5cdd3", + e: "010001", + ), + VerifyApplicationPin(), + Sign( + algo: 0x07, + key_reference: 0x9A, + data: "0111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111", + output: Data(" + 7c 82 0204 + 82 820200 + 5b89c77459c1d0d8c6c0a0c0628cde7d76aca80340fce8ec27dc80adecca8e16968c921972d95071a8f1b10c260b81242c119bd0fbe091675952b26d0877fe4e82975aae901c4b8f26ebe965df40abfb9fa1782b4dfde1c0dd6e278d0575695d5f2523af5de01ac2f26abcbac0e2956a02799f7905cba2f223f2e609b079b841b428e90e610e24cd284d039413977d48ae7ca522a2070f7e0dbdeac0b812b4d46392d4085dbf527a7560231199627d84b8569ea1b54a19f4144914a20e2ce32d6915c1db7bcc5559deed24f6bc6683b05afedd384a34a7b1ae51af2b391e8d6f7d5075b5a0bd4b0e13336d834956288341c30808d150b799a8f9f5e2a2c50d9569ebd6f3e06b411931e7286699b4cd409598d0ead0a7a77486143996e92cdb7cdfa9c3777501e25940fe6a280080f377a2552a552f8e009cc4bc1d24cf2c3941a01c09d07a1117bae9637ed749fc0a4d98dd59451061d7c4af323265324a770adf92c63e0a0bc67ef1b326534d047a6683c0491c13f983e320fc2f398f4215ab01a9ac024b31aabf488ace1750d8eb0f6f411c5a8a62b2468ba7ad0c11f1ff108a7bbb8fc5a655a7dffd977eb0377fb6ffc9a2bf6e850e11d2762b6e72f80b44e03dd208071f2f7673566ba3853d3b04759c59b53a8c4138862f55702d25014f4bb2eb1cf2b2d047605f6b4a3f09b55212562bbb9cd35d5c3b3b9a543de3189f + "), + ) + ] + ), IoTest( name: "Protected DOS", uuid_config: WithBoth("00112233445566778899AABBCCDDEEFF"), diff --git a/tests/command_response.rs b/tests/command_response.rs index cd7abb4..c5732e9 100644 --- a/tests/command_response.rs +++ b/tests/command_response.rs @@ -458,8 +458,14 @@ impl IoCmd { .into_iter() .flatten() .collect(); + let algo = match p.len() { + 128 => 0x07, + 192 => 0x05, + 256 => 0x16, + _ => panic!("Invalid RSA key size"), + }; Self::run_bytes( - &build_command(0x00, 0xFE, 0x07, 0x9A, &data, 0), + &build_command(0x00, 0xFE, algo, 0x9A, &data, 0), &MATCH_EMPTY, expected_status, card,