From 177bf2e9faf9db85418e791b33c7b02de1d41ac9 Mon Sep 17 00:00:00 2001 From: Stephan Naumann Date: Wed, 17 Jun 2026 17:31:25 +0200 Subject: [PATCH] breaking: change salt algorithm, --- Cargo.lock | 96 +++++++++++---- nix/package.nix | 2 +- tssh-core/Cargo.toml | 1 + tssh-core/src/sqlite/mod.rs | 45 +++++++ tssh-core/src/sqlite/types.rs | 4 + tssh-core/src/tpm/mod.rs | 71 ++++++----- tssh-pkcs11/src/pkcs11/mod.rs | 192 +++++++++++++++++------------- tssh-pkcs11/src/pkcs11/session.rs | 3 +- tssh/src/commandline.rs | 12 +- tssh/src/main.rs | 23 ++-- 10 files changed, 302 insertions(+), 147 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a48555a..315bcb3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -117,6 +117,15 @@ dependencies = [ "generic-array", ] +[[package]] +name = "block-buffer" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2f6c7dbe95a6ed67ad9f18e57daf93a2f034c524b99fd2b76d18fdfeb6660aa" +dependencies = [ + "hybrid-array", +] + [[package]] name = "cfg-if" version = "1.0.4" @@ -140,7 +149,7 @@ version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" dependencies = [ - "crypto-common", + "crypto-common 0.1.7", "inout", ] @@ -207,6 +216,12 @@ version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" +[[package]] +name = "const-oid" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6ef517f0926dd24a1582492c791b6a4818a4d94e789a334894aa15b0d12f55c" + [[package]] name = "cpufeatures" version = "0.2.17" @@ -270,13 +285,22 @@ dependencies = [ "typenum", ] +[[package]] +name = "crypto-common" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce6e4c961d6cd6c9a86db418387425e8bdeaf05b3c8bc1411e6dca4c252f1453" +dependencies = [ + "hybrid-array", +] + [[package]] name = "der" version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" dependencies = [ - "const-oid", + "const-oid 0.9.6", "der_derive", "flagset", "pem-rfc7468", @@ -310,12 +334,23 @@ version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ - "block-buffer", - "const-oid", - "crypto-common", + "block-buffer 0.10.4", + "const-oid 0.9.6", + "crypto-common 0.1.7", "subtle", ] +[[package]] +name = "digest" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1dd6dbb5841937940781866fa1281a1ff7bd3bf827091440879f9994983d5c2" +dependencies = [ + "block-buffer 0.12.1", + "const-oid 0.10.2", + "crypto-common 0.2.2", +] + [[package]] name = "dirs" version = "6.0.0" @@ -364,7 +399,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" dependencies = [ "der", - "digest", + "digest 0.10.7", "elliptic-curve", "rfc6979", "signature", @@ -379,7 +414,7 @@ checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" dependencies = [ "base16ct", "crypto-bigint", - "digest", + "digest 0.10.7", "ff", "generic-array", "group", @@ -578,7 +613,7 @@ version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" dependencies = [ - "digest", + "digest 0.10.7", ] [[package]] @@ -587,6 +622,15 @@ version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f558a64ac9af88b5ba400d99b579451af0d39c6d360980045b91aac966d705e2" +[[package]] +name = "hybrid-array" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9155a582abd142abc056962c29e3ce5ff2ad5469f4246b537ed42c5deba857da" +dependencies = [ + "typenum", +] + [[package]] name = "icu_collections" version = "2.2.0" @@ -928,7 +972,7 @@ dependencies = [ "ecdsa", "elliptic-curve", "primeorder", - "sha2", + "sha2 0.10.9", ] [[package]] @@ -940,7 +984,7 @@ dependencies = [ "ecdsa", "elliptic-curve", "primeorder", - "sha2", + "sha2 0.10.9", ] [[package]] @@ -954,7 +998,7 @@ dependencies = [ "elliptic-curve", "primeorder", "rand_core 0.6.4", - "sha2", + "sha2 0.10.9", ] [[package]] @@ -1261,15 +1305,15 @@ version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8573f03f5883dcaebdfcf4725caa1ecb9c15b2ef50c43a07b816e06799bb12d" dependencies = [ - "const-oid", - "digest", + "const-oid 0.9.6", + "digest 0.10.7", "num-bigint-dig", "num-integer", "num-traits", "pkcs1", "pkcs8", "rand_core 0.6.4", - "sha2", + "sha2 0.10.9", "signature", "spki", "subtle", @@ -1398,7 +1442,18 @@ checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" dependencies = [ "cfg-if", "cpufeatures 0.2.17", - "digest", + "digest 0.10.7", +] + +[[package]] +name = "sha2" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "446ba717509524cb3f22f17ecc096f10f4822d76ab5c0b9822c5f9c284e825f4" +dependencies = [ + "cfg-if", + "cpufeatures 0.3.0", + "digest 0.11.3", ] [[package]] @@ -1416,7 +1471,7 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" dependencies = [ - "digest", + "digest 0.10.7", "rand_core 0.6.4", ] @@ -1466,7 +1521,7 @@ checksum = "eb9242b9ef4108a78e8cd1a2c98e193ef372437f8c22be363075233321dd4a15" dependencies = [ "base64ct", "pem-rfc7468", - "sha2", + "sha2 0.10.9", ] [[package]] @@ -1481,7 +1536,7 @@ dependencies = [ "rand_core 0.6.4", "rsa", "sec1", - "sha2", + "sha2 0.10.9", "signature", "ssh-cipher", "ssh-encoding", @@ -1736,7 +1791,7 @@ checksum = "5c1751ea94b699404cd8c52fe2f1cb6ba811b8a7d26151298b946b3b8424468e" dependencies = [ "bitfield", "cfg-if", - "digest", + "digest 0.10.7", "ecdsa", "elliptic-curve", "enumflags2", @@ -1798,6 +1853,7 @@ dependencies = [ "rusqlite", "serde", "serde_json", + "sha2 0.11.0", "ssh-key", "tracing", "tss-esapi", @@ -2119,7 +2175,7 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1301e935010a701ae5f8655edc0ad17c44bad3ac5ce8c39185f75453b720ae94" dependencies = [ - "const-oid", + "const-oid 0.9.6", "der", "spki", "tls_codec", diff --git a/nix/package.nix b/nix/package.nix index 5fe18a9..18b6a37 100644 --- a/nix/package.nix +++ b/nix/package.nix @@ -31,7 +31,7 @@ rustPlatform.buildRustPackage { name = "tssh-src"; filter = (path: type: baseNameOf path != "nix"); }; - cargoHash = "sha256-pJ/TJPC2RfajnYNs5bV23tFkwKOwBXZ6g+BRBBuRJvU="; + cargoHash = "sha256-udJoulVqWx3pgbnuOiP1+3PYUo+iQvEwZ/nOp9o5etA="; nativeBuildInputs = [ pkg-config diff --git a/tssh-core/Cargo.toml b/tssh-core/Cargo.toml index 8793d86..c9713de 100644 --- a/tssh-core/Cargo.toml +++ b/tssh-core/Cargo.toml @@ -15,6 +15,7 @@ refinery = { version = "0.9.0", features = ["rusqlite"] } rusqlite = "0.37.0" serde = { version = "1.0.228", features = ["derive"] } serde_json = "1.0.149" +sha2 = "0.11.0" ssh-key = "0.6.7" tracing = "0.1.44" tss-esapi = {version = "8.0.0-alpha.2"} diff --git a/tssh-core/src/sqlite/mod.rs b/tssh-core/src/sqlite/mod.rs index ca9fe0f..a2b4c14 100644 --- a/tssh-core/src/sqlite/mod.rs +++ b/tssh-core/src/sqlite/mod.rs @@ -84,6 +84,43 @@ RETURNING id .context("while adding key to DB") } + pub fn get_all_keys(&self) -> Result> { + const STMT: &str = " +SELECT +id, +pkcs11_id, +host, +username, +port, +pub_key, +template, +backup_key_id +FROM KEYS +ORDER BY id ASC +"; + + let mut stmt = self.c.prepare(STMT)?; + + let mut rows = stmt.query([])?; + + let mut ret = Vec::new(); + + while let Some(r) = rows.next()? { + ret.push(DBKey { + id: r.get(0)?, + pkcs11_id: r.get(1)?, + host: r.get(2)?, + username: r.get(3)?, + port: r.get(4)?, + pub_key: r.get(5)?, + template: r.get(6)?, + backup_key: r.get(7)?, + }); + } + + Ok(ret) + } + pub fn get_keys(&self, page: DBPage) -> Result> { const STMT: &str = " SELECT @@ -283,6 +320,10 @@ fn keys() -> Result<()> { .get_keys(DBPage::default()) .context("while getting keys")?; assert!(keys.is_empty()); + + let keys = db.get_all_keys().context("while getting all keys")?; + assert!(keys.is_empty()); + let key = DBKey::generate_random_key(); let ret = db.add_key(key).context("while adding key")?; @@ -290,6 +331,10 @@ fn keys() -> Result<()> { assert_eq!(keys.len(), 1); assert_eq!(keys[0], ret); + let keys = db.get_all_keys()?; + assert_eq!(keys.len(), 1); + assert_eq!(keys[0], ret); + let key = db.get_key_by_pkcs11_id(&ret.pkcs11_id)?; assert_eq!(key, ret); diff --git a/tssh-core/src/sqlite/types.rs b/tssh-core/src/sqlite/types.rs index 9003071..2cfd0a6 100644 --- a/tssh-core/src/sqlite/types.rs +++ b/tssh-core/src/sqlite/types.rs @@ -105,6 +105,10 @@ pub struct DBPage { } impl DBPage { + pub fn new(page: u32, size: u32) -> Self { + Self { page, size } + } + pub fn offset(&self) -> u32 { self.page * self.size } diff --git a/tssh-core/src/tpm/mod.rs b/tssh-core/src/tpm/mod.rs index bf7e948..30eed9e 100644 --- a/tssh-core/src/tpm/mod.rs +++ b/tssh-core/src/tpm/mod.rs @@ -17,6 +17,7 @@ use std::str::FromStr; use anyhow::{Context, Result, bail}; use serde::{Deserialize, Serialize}; +use sha2::{Digest, digest::Output}; use ssh_key::Mpint; use tss_esapi::{ attributes::ObjectAttributes, @@ -79,14 +80,12 @@ impl From for HashingAlgorithm { impl RsaKeyBits { fn generate_salted_public_key(&self, a: &[u8], b: &[u8], c: &[u8]) -> Result { let salt = Salt::new(a, b, c) - .take(self.pubclic_key_bytes()) + .take(self.public_key_bytes()) .collect::>(); - Ok(PublicKeyRsa::from_bytes( - &salt[0..self.pubclic_key_bytes()], - )?) + Ok(PublicKeyRsa::from_bytes(&salt[0..self.public_key_bytes()])?) } - fn pubclic_key_bytes(&self) -> usize { + fn public_key_bytes(&self) -> usize { match self { RsaKeyBits::Rsa1024 => 128, RsaKeyBits::Rsa2048 => 256, @@ -230,6 +229,13 @@ impl Template { Template::ECC(ecc_template) => format!("ECC,{}", ecc_template.curve), } } + + pub fn signature_size(&self) -> usize { + match self { + Template::RSA(rsa_template) => rsa_template.keybits.public_key_bytes(), + Template::ECC(ecc_template) => ecc_template.curve.point_size() * 2, + } + } } impl TryFrom<&str> for Template { @@ -611,7 +617,7 @@ impl TPMContext { &mut self, public: Public, ecc_template: EccTemplate, - bloob: &[u8], + blob: &[u8], ) -> Result> { self.context.set_sessions(( Some(tss_esapi::interface_types::session_handles::AuthSession::Password), @@ -641,7 +647,7 @@ impl TPMContext { unreachable!() }; - let digest = tss_esapi::structures::Digest::from_bytes(bloob).context("can't digest")?; + let digest = tss_esapi::structures::Digest::from_bytes(blob).context("can't digest")?; let fake_hashcheck = TPMT_TK_HASHCHECK { tag: TPM2_ST_HASHCHECK, @@ -666,6 +672,10 @@ impl TPMContext { fake_ticket, )?; + self.context + .flush_context(create_primary_result.key_handle.into()) + .context("while flushing key handle")?; + let Signature::EcDsa(ecc_signature) = sign_result else { unreachable!() }; @@ -705,7 +715,7 @@ impl TPMContext { &mut self, public: Public, rsa_template: RsaTemplate, - bloob: &[u8], + blob: &[u8], ) -> Result> { self.context.set_sessions(( Some(tss_esapi::interface_types::session_handles::AuthSession::Password), @@ -735,7 +745,7 @@ impl TPMContext { unreachable!() }; - let digest = tss_esapi::structures::Digest::from_bytes(bloob).context("can't digest")?; + let digest = tss_esapi::structures::Digest::from_bytes(blob).context("can't digest")?; let fake_hashcheck = TPMT_TK_HASHCHECK { tag: TPM2_ST_HASHCHECK, @@ -760,45 +770,50 @@ impl TPMContext { fake_ticket, )?; + self.context + .flush_context(create_primary_result.key_handle.into()) + .context("while flushing key handle")?; + let Signature::RsaSsa(rsa_signature) = sign_result else { unreachable!() }; Ok(rsa_signature.signature().to_vec()) } - pub fn sign(&mut self, host_template: &HostTemplate, bloob: &[u8]) -> Result> { + pub fn sign(&mut self, host_template: &HostTemplate, blob: &[u8]) -> Result> { let public = Public::try_from(host_template)?; match &host_template.template { - Template::RSA(rsa_template) => self.sign_rsa(public, rsa_template.clone(), bloob), - Template::ECC(ecc_template) => self.sign_ecc(public, ecc_template.clone(), bloob), + Template::RSA(rsa_template) => self.sign_rsa(public, rsa_template.clone(), blob), + Template::ECC(ecc_template) => self.sign_ecc(public, ecc_template.clone(), blob), } } } -pub struct Salt<'a> { - a: std::iter::Cycle>, - b: std::iter::Cycle>, - c: std::iter::Cycle>, +pub struct Salt { + hash: Output, + idx: usize, } -impl<'a> Salt<'a> { - fn new(a: &'a [u8], b: &'a [u8], c: &'a [u8]) -> Self { - Self { - a: a.iter().cycle(), - b: b.iter().cycle(), - c: c.iter().cycle(), - } +impl Salt { + fn new(a: &[u8], b: &[u8], c: &[u8]) -> Self { + let mut hasher = sha2::Sha512::new(); + hasher.update(a); + hasher.update(b); + hasher.update(c); + + let hash = hasher.finalize(); + + Self { hash, idx: 0 } } } -impl<'a> Iterator for Salt<'a> { +impl Iterator for Salt { type Item = u8; fn next(&mut self) -> Option { - let next_a = self.a.next().copied().unwrap_or(17u8); - let next_b = self.b.next().copied().unwrap_or(23u8); - let next_c = self.c.next().copied().unwrap_or(31u8); - Some(next_a ^ next_b ^ next_c) + let ret = self.hash[self.idx % self.hash.len()]; + self.idx = self.idx.wrapping_add(1); + Some(ret) } } diff --git a/tssh-pkcs11/src/pkcs11/mod.rs b/tssh-pkcs11/src/pkcs11/mod.rs index f67d4cb..e2e1373 100644 --- a/tssh-pkcs11/src/pkcs11/mod.rs +++ b/tssh-pkcs11/src/pkcs11/mod.rs @@ -15,13 +15,11 @@ // along with this program. If not, see . non_snake_case, - unused_variables, clippy::missing_safety_doc, clippy::missing_transmute_annotations )] use std::{ - io::Write, ptr::copy_nonoverlapping, sync::{Mutex, MutexGuard, Once, OnceLock}, }; @@ -37,9 +35,9 @@ use pkcs11_sys::{ CK_UNAVAILABLE_INFORMATION, CK_USER_TYPE, CK_UTF8CHAR_PTR, CK_VERSION, CK_VOID_PTR, CKA_ALWAYS_AUTHENTICATE, CKA_EC_POINT, CKA_ECDSA_PARAMS, CKA_ID, CKA_KEY_TYPE, CKA_LABEL, CKA_MODULUS, CKA_PUBLIC_EXPONENT, CKF_HW, CKF_SIGN, CKF_TOKEN_INITIALIZED, CKF_TOKEN_PRESENT, - CKF_USER_PIN_INITIALIZED, CKK_EC, CKK_RSA, CKM_ECDSA, CKM_ECDSA_SHA256, CKM_RSA_PKCS, - CKR_ARGUMENTS_BAD, CKR_ATTRIBUTE_TYPE_INVALID, CKR_BUFFER_TOO_SMALL, CKR_DEVICE_ERROR, - CKR_FUNCTION_NOT_SUPPORTED, CKR_GENERAL_ERROR, CKR_MECHANISM_INVALID, CKR_OK, + CKF_USER_PIN_INITIALIZED, CKK_EC, CKK_RSA, CKM_ECDSA, CKM_RSA_PKCS, CKR_ARGUMENTS_BAD, + CKR_ATTRIBUTE_TYPE_INVALID, CKR_BUFFER_TOO_SMALL, CKR_DEVICE_ERROR, CKR_FUNCTION_NOT_SUPPORTED, + CKR_GENERAL_ERROR, CKR_MECHANISM_INVALID, CKR_OK, }; use tracing_subscriber::EnvFilter; @@ -109,62 +107,56 @@ static FUNCTION_LIST: CK_FUNCTION_LIST = CK_FUNCTION_LIST { C_GetTokenInfo: Some(C_GetTokenInfo), C_GetMechanismList: Some(C_GetMechanismList), C_GetMechanismInfo: Some(C_GetMechanismInfo), - C_InitToken: Some(unsafe { std::mem::transmute(C_FunctionNotSupported as *const ()) }), + C_InitToken: Some(stub_4), C_InitPIN: Some(C_InitPIN), - C_SetPIN: Some(unsafe { std::mem::transmute(C_FunctionNotSupported as *const ()) }), - C_CloseAllSessions: Some(unsafe { std::mem::transmute(C_FunctionNotSupported as *const ()) }), + C_SetPIN: Some(stub_5), + C_CloseAllSessions: Some(stub_1), C_GetSessionInfo: Some(C_GetSessionInfo), - C_GetOperationState: Some(unsafe { std::mem::transmute(C_FunctionNotSupported as *const ()) }), - C_SetOperationState: Some(unsafe { std::mem::transmute(C_FunctionNotSupported as *const ()) }), + C_GetOperationState: Some(stub_3), + C_SetOperationState: Some(stub_5), C_Login: Some(C_Login), - C_Logout: Some(unsafe { std::mem::transmute(C_FunctionNotSupported as *const ()) }), - C_CreateObject: Some(unsafe { std::mem::transmute(C_FunctionNotSupported as *const ()) }), - C_CopyObject: Some(unsafe { std::mem::transmute(C_FunctionNotSupported as *const ()) }), - C_DestroyObject: Some(unsafe { std::mem::transmute(C_FunctionNotSupported as *const ()) }), - C_GetObjectSize: Some(unsafe { std::mem::transmute(C_FunctionNotSupported as *const ()) }), - C_SetAttributeValue: Some(unsafe { std::mem::transmute(C_FunctionNotSupported as *const ()) }), - C_EncryptInit: Some(unsafe { std::mem::transmute(C_FunctionNotSupported as *const ()) }), - C_Encrypt: Some(unsafe { std::mem::transmute(C_FunctionNotSupported as *const ()) }), - C_EncryptUpdate: Some(unsafe { std::mem::transmute(C_FunctionNotSupported as *const ()) }), - C_EncryptFinal: Some(unsafe { std::mem::transmute(C_FunctionNotSupported as *const ()) }), - C_DecryptInit: Some(unsafe { std::mem::transmute(C_FunctionNotSupported as *const ()) }), - C_Decrypt: Some(unsafe { std::mem::transmute(C_FunctionNotSupported as *const ()) }), - C_DecryptUpdate: Some(unsafe { std::mem::transmute(C_FunctionNotSupported as *const ()) }), - C_DecryptFinal: Some(unsafe { std::mem::transmute(C_FunctionNotSupported as *const ()) }), - C_DigestInit: Some(unsafe { std::mem::transmute(C_FunctionNotSupported as *const ()) }), - C_Digest: Some(unsafe { std::mem::transmute(C_FunctionNotSupported as *const ()) }), - C_DigestUpdate: Some(unsafe { std::mem::transmute(C_FunctionNotSupported as *const ()) }), - C_DigestKey: Some(unsafe { std::mem::transmute(C_FunctionNotSupported as *const ()) }), - C_DigestFinal: Some(unsafe { std::mem::transmute(C_FunctionNotSupported as *const ()) }), - C_SignUpdate: Some(unsafe { std::mem::transmute(C_FunctionNotSupported as *const ()) }), - C_SignFinal: Some(unsafe { std::mem::transmute(C_FunctionNotSupported as *const ()) }), - C_SignRecoverInit: Some(unsafe { std::mem::transmute(C_FunctionNotSupported as *const ()) }), - C_SignRecover: Some(unsafe { std::mem::transmute(C_FunctionNotSupported as *const ()) }), - C_VerifyInit: Some(unsafe { std::mem::transmute(C_FunctionNotSupported as *const ()) }), - C_Verify: Some(unsafe { std::mem::transmute(C_FunctionNotSupported as *const ()) }), - C_VerifyUpdate: Some(unsafe { std::mem::transmute(C_FunctionNotSupported as *const ()) }), - C_VerifyFinal: Some(unsafe { std::mem::transmute(C_FunctionNotSupported as *const ()) }), - C_VerifyRecoverInit: Some(unsafe { std::mem::transmute(C_FunctionNotSupported as *const ()) }), - C_VerifyRecover: Some(unsafe { std::mem::transmute(C_FunctionNotSupported as *const ()) }), - C_DigestEncryptUpdate: Some(unsafe { - std::mem::transmute(C_FunctionNotSupported as *const ()) - }), - C_DecryptDigestUpdate: Some(unsafe { - std::mem::transmute(C_FunctionNotSupported as *const ()) - }), - C_SignEncryptUpdate: Some(unsafe { std::mem::transmute(C_FunctionNotSupported as *const ()) }), - C_DecryptVerifyUpdate: Some(unsafe { - std::mem::transmute(C_FunctionNotSupported as *const ()) - }), - C_GenerateKey: Some(unsafe { std::mem::transmute(C_FunctionNotSupported as *const ()) }), - C_GenerateKeyPair: Some(unsafe { std::mem::transmute(C_FunctionNotSupported as *const ()) }), - C_WrapKey: Some(unsafe { std::mem::transmute(C_FunctionNotSupported as *const ()) }), - C_UnwrapKey: Some(unsafe { std::mem::transmute(C_FunctionNotSupported as *const ()) }), - C_DeriveKey: Some(unsafe { std::mem::transmute(C_FunctionNotSupported as *const ()) }), - C_SeedRandom: Some(unsafe { std::mem::transmute(C_FunctionNotSupported as *const ()) }), - C_GenerateRandom: Some(unsafe { std::mem::transmute(C_FunctionNotSupported as *const ()) }), - C_GetFunctionStatus: Some(unsafe { std::mem::transmute(C_FunctionNotSupported as *const ()) }), - C_CancelFunction: Some(unsafe { std::mem::transmute(C_FunctionNotSupported as *const ()) }), + C_Logout: Some(stub_1), + C_CreateObject: Some(stub_4), + C_CopyObject: Some(stub_5), + C_DestroyObject: Some(stub_2), + C_GetObjectSize: Some(stub_3), + C_SetAttributeValue: Some(stub_4), + C_EncryptInit: Some(stub_3), + C_Encrypt: Some(stub_5), + C_EncryptUpdate: Some(stub_5), + C_EncryptFinal: Some(stub_3), + C_DecryptInit: Some(stub_3), + C_Decrypt: Some(stub_5), + C_DecryptUpdate: Some(stub_5), + C_DecryptFinal: Some(stub_3), + C_DigestInit: Some(stub_2), + C_Digest: Some(stub_5), + C_DigestUpdate: Some(stub_3), + C_DigestKey: Some(stub_2), + C_DigestFinal: Some(stub_3), + C_SignUpdate: Some(stub_3), + C_SignFinal: Some(stub_3), + C_SignRecoverInit: Some(stub_3), + C_SignRecover: Some(stub_5), + C_VerifyInit: Some(stub_3), + C_Verify: Some(stub_5), + C_VerifyUpdate: Some(stub_3), + C_VerifyFinal: Some(stub_3), + C_VerifyRecoverInit: Some(stub_3), + C_VerifyRecover: Some(stub_5), + C_DigestEncryptUpdate: Some(stub_5), + C_DecryptDigestUpdate: Some(stub_5), + C_SignEncryptUpdate: Some(stub_5), + C_DecryptVerifyUpdate: Some(stub_5), + C_GenerateKey: Some(stub_5), + C_GenerateKeyPair: Some(stub_8), + C_WrapKey: Some(stub_6), + C_UnwrapKey: Some(stub_8), + C_DeriveKey: Some(stub_6), + C_SeedRandom: Some(stub_3), + C_GenerateRandom: Some(stub_3), + C_GetFunctionStatus: Some(stub_1), + C_CancelFunction: Some(stub_1), C_WaitForSlotEvent: Some(C_WaitForSlotEvent), }; @@ -192,9 +184,8 @@ pub unsafe extern "C" fn C_Initialize(_pInitArgs: CK_VOID_PTR) -> CK_RV { #[named] #[unsafe(no_mangle)] -pub unsafe extern "C" fn C_Finalize(p_reserved: CK_VOID_PTR) -> CK_RV { +pub unsafe extern "C" fn C_Finalize(_p_reserved: CK_VOID_PTR) -> CK_RV { trace!("{} called", function_name!()); - let _ = std::io::stdout().flush(); CKR_OK } @@ -240,7 +231,7 @@ pub unsafe extern "C" fn C_CloseSession(h_session: CK_SESSION_HANDLE) -> CK_RV { #[named] #[unsafe(no_mangle)] pub unsafe extern "C" fn C_GetSlotList( - token_present: CK_BBOOL, + _token_present: CK_BBOOL, pSlotList: CK_SLOT_ID_PTR, pulCount: CK_ULONG_PTR, ) -> CK_RV { @@ -318,11 +309,6 @@ pub unsafe extern "C" fn C_FindObjectsInit( ) -> CK_RV { trace!("{} called with sessionId {h_session}", function_name!()); - let Ok(session) = session::get_sessions().get_state(h_session) else { - error!("there is no session with id {h_session}"); - return CKR_ARGUMENTS_BAD; - }; - let session_state = unsafe { let attributes = std::slice::from_raw_parts(p_template, ul_count as usize); State::FindObjectsInit(FindObjectsInit::new(attributes)) @@ -337,7 +323,7 @@ pub unsafe extern "C" fn C_FindObjectsInit( fn load_objects(find_objects: &mut FindObjects) -> Result<()> { let result = get_db() - .get_keys(tssh_core::sqlite::types::DBPage::default())? //TODO: more results than default page... + .get_all_keys()? .into_iter() .filter(|k| find_objects.criteria.has(k)) .collect::>(); @@ -402,7 +388,7 @@ pub unsafe extern "C" fn C_FindObjects( let out = unsafe { std::slice::from_raw_parts_mut(phObject, amount_to_write) }; - for (i, v) in out.iter_mut().enumerate() { + for v in out.iter_mut() { *v = results.get(*next_index).unwrap().id as u64; *next_index += 1; unsafe { *pulObjectCount += 1 } @@ -776,7 +762,7 @@ pub unsafe extern "C" fn C_GetMechanismList( ) -> CK_RV { trace!("{} called with slot_id {slot_id}", function_name!()); - const SUPPORTED_MECHANISMS: [CK_ULONG; 1] = [CKM_ECDSA_SHA256]; + const SUPPORTED_MECHANISMS: [CK_ULONG; 2] = [CKM_ECDSA, CKM_RSA_PKCS]; if pul_count.is_null() { return CKR_ARGUMENTS_BAD; @@ -829,8 +815,10 @@ pub unsafe extern "C" fn C_GetMechanismInfo( trace!("asking for type {type_}"); - if type_ != CKM_ECDSA_SHA256 { - error!("only type {CKM_ECDSA_SHA256} is supported but asked for type {type_}"); + const SUPPORTED_TYPES: [u64; 2] = [CKM_ECDSA, CKM_RSA_PKCS]; + + if !SUPPORTED_TYPES.contains(&type_) { + error!("only types {SUPPORTED_TYPES:?} is supported but asked for type {type_}"); return CKR_MECHANISM_INVALID; } @@ -923,13 +911,13 @@ pub unsafe extern "C" fn C_SignInit( let mechanism = unsafe { *p_mechanism }; match template { - Template::RSA(rsa_template) => { + Template::RSA(_) => { if mechanism.mechanism != CKM_RSA_PKCS { error!("requested invalid mechanism {}", mechanism.mechanism); return CKR_MECHANISM_INVALID; } } - Template::ECC(_ecc_template) => { + Template::ECC(_) => { if mechanism.mechanism != CKM_ECDSA { error!("requested invalid mechanism {}", mechanism.mechanism); return CKR_MECHANISM_INVALID; @@ -996,6 +984,11 @@ pub unsafe extern "C" fn C_Sign( return CKR_GENERAL_ERROR; }; + if pSignature.is_null() { + unsafe { *pulSignatureLen = template.template.signature_size() as u64 }; + return CKR_OK; + } + let mut tpm = get_tpm(); let data_to_sign = match prepare_data_for_signing(template.template.clone(), data) { @@ -1014,16 +1007,11 @@ pub unsafe extern "C" fn C_Sign( } }; - let Ok(der_sig) = parse_tpm_sign(template.template, &raw_tpm_sig) else { + let Ok(der_sig) = parse_tpm_sign(&template.template, &raw_tpm_sig) else { error!("can't parse raw tpm signature"); return CKR_DEVICE_ERROR; }; - if pSignature.is_null() { - unsafe { *pulSignatureLen = der_sig.len() as u64 }; - return CKR_OK; - } - let provided_len = unsafe { *pulSignatureLen } as usize; if provided_len < der_sig.len() { error!( @@ -1124,13 +1112,13 @@ fn prepare_data_for_signing(template: Template, data: &[u8]) -> anyhow::Result { if data.len() != 51 { - bail!("expected 67 signing bytes") + bail!("expected 51 signing bytes") } Ok(data[19..].to_vec()) } tpm::RsaKeyBits::Rsa4096 => { if data.len() != 83 { - bail!("expected 67 signing bytes") + bail!("expected 83 signing bytes") } Ok(data[19..].to_vec()) } @@ -1139,7 +1127,7 @@ fn prepare_data_for_signing(template: Template, data: &[u8]) -> anyhow::Result Result, Box> { match template { @@ -1149,7 +1137,7 @@ fn parse_tpm_sign( } fn parse_tpm_ecc_sign( - ecc_template: EccTemplate, + ecc_template: &EccTemplate, signature: &[u8], ) -> Result, Box> { match ecc_template.curve { @@ -1160,7 +1148,7 @@ fn parse_tpm_ecc_sign( } fn parse_tpm_rsa_sign( - rsa_template: RsaTemplate, + _rsa_template: &RsaTemplate, signature: &[u8], ) -> Result, Box> { Ok(signature.to_vec()) @@ -1169,3 +1157,39 @@ fn parse_tpm_rsa_sign( fn get_key_from_db(handle: CK_OBJECT_HANDLE) -> Result { get_db().get_key_by_id(handle as i32) } + +unsafe extern "C" fn stub_1(_: A) -> CK_RV { + CKR_FUNCTION_NOT_SUPPORTED +} + +unsafe extern "C" fn stub_2(_: A, _: B) -> CK_RV { + CKR_FUNCTION_NOT_SUPPORTED +} +unsafe extern "C" fn stub_3(_: A, _: B, _: C) -> CK_RV { + CKR_FUNCTION_NOT_SUPPORTED +} + +unsafe extern "C" fn stub_4(_: A, _: B, _: C, _: D) -> CK_RV { + CKR_FUNCTION_NOT_SUPPORTED +} + +unsafe extern "C" fn stub_5(_: A, _: B, _: C, _: D, _: E) -> CK_RV { + CKR_FUNCTION_NOT_SUPPORTED +} + +unsafe extern "C" fn stub_6(_: A, _: B, _: C, _: D, _: E, _: F) -> CK_RV { + CKR_FUNCTION_NOT_SUPPORTED +} + +unsafe extern "C" fn stub_8( + _: A, + _: B, + _: C, + _: D, + _: E, + _: F, + _: G, + _: H, +) -> CK_RV { + CKR_FUNCTION_NOT_SUPPORTED +} diff --git a/tssh-pkcs11/src/pkcs11/session.rs b/tssh-pkcs11/src/pkcs11/session.rs index 6e63b72..02c235d 100644 --- a/tssh-pkcs11/src/pkcs11/session.rs +++ b/tssh-pkcs11/src/pkcs11/session.rs @@ -16,6 +16,7 @@ use anyhow::Result; use pkcs11_sys::{ CK_ATTRIBUTE, CK_OBJECT_HANDLE, CK_SESSION_HANDLE, CKA_CLASS, CKA_ID, CKA_LABEL, CKA_SIGN, + CKO_PRIVATE_KEY, CKO_PUBLIC_KEY, }; use std::{ collections::HashMap, @@ -138,7 +139,7 @@ impl FindObjectsCriteria { } for class in self.classes.iter() { - if *class == 2 || *class == 3 { + if *class == CKO_PUBLIC_KEY || *class == CKO_PRIVATE_KEY { continue; } return false; diff --git a/tssh/src/commandline.rs b/tssh/src/commandline.rs index aacf618..767ff56 100644 --- a/tssh/src/commandline.rs +++ b/tssh/src/commandline.rs @@ -33,12 +33,20 @@ pub enum Commands { Get(GetKey), Delete(DeleteKey), Sync, - List, + List(List), Clear, Include(Include), Check, } +#[derive(Args, Debug)] +pub struct List { + #[arg(long, default_value_t = 0)] + pub page: u32, + #[arg(long, default_value_t = 101)] + pub size: u32, +} + #[derive(Args, Debug)] pub struct Include { #[arg(short, long)] @@ -61,7 +69,7 @@ pub struct AddKey { #[derive(Args, Debug)] pub struct GetKey { - pub user: User, + pub identifier: Identifier, #[arg(long)] pub raw: bool, } diff --git a/tssh/src/main.rs b/tssh/src/main.rs index 99bcf27..e3057a3 100644 --- a/tssh/src/main.rs +++ b/tssh/src/main.rs @@ -52,7 +52,7 @@ fn main() -> anyhow::Result<()> { match commands.command { commandline::Commands::Add(add_key) => handle_add(db, add_key), - commandline::Commands::List => handle_list(db), + commandline::Commands::List(list) => handle_list(db, list), commandline::Commands::Clear => handle_clear(db), commandline::Commands::Get(get_key) => handle_get(db, get_key), commandline::Commands::Sync => handle_sync(db), @@ -122,7 +122,7 @@ fn handle_include(_db: DB, i: commandline::Include) -> Result<()> { } fn handle_sync(db: DB) -> Result<()> { - let entries = db.get_keys(DBPage::default())?; //TODO: all keys.. + let entries = db.get_all_keys()?; //TODO: all keys.. ssh_writer::write(entries, &ensure_dir_env()?) } @@ -170,8 +170,8 @@ fn handle_add(db: DB, add_key: commandline::AddKey) -> Result<()> { Ok(()) } -fn handle_list(db: DB) -> Result<()> { - let keys = db.get_keys(DBPage::default())?; //TODO: size .. +fn handle_list(db: DB, list: commandline::List) -> Result<()> { + let keys = db.get_keys(DBPage::new(list.page, list.size))?; let mut table = Table::new(); @@ -204,11 +204,12 @@ fn handle_list(db: DB) -> Result<()> { } fn handle_get(db: DB, get_key: commandline::GetKey) -> Result<()> { - let key = db.get_key_by_login( - &get_key.user.host, - &get_key.user.username, - get_key.user.port, - )?; + let key = match get_key.identifier { + commandline::Identifier::Id(id) => db.get_key_by_id(id)?, + commandline::Identifier::User(user) => { + db.get_key_by_login(&user.host, &user.username, user.port)? + } + }; if get_key.raw { print!("{}", key.pub_key); @@ -216,8 +217,8 @@ fn handle_get(db: DB, get_key: commandline::GetKey) -> Result<()> { } println!( - "========== Key for {} =========\n\n{}\n", - get_key.user, key.pub_key + "========== Key for {}@{}:{} =========\n\n{}\n", + key.username, key.host, key.port, key.pub_key ); Ok(())