From 2a0faa35cd977de2c7f62e25f0e0906aafa5ea41 Mon Sep 17 00:00:00 2001 From: Hatter Jiang Date: Wed, 28 Aug 2024 00:51:57 +0800 Subject: [PATCH] feat: add tests, add sshpubkey, sshprivkey, sshcert, sshbase --- src/lib.rs | 6 +++- src/sshbase.rs | 3 ++ src/sshcert.rs | 1 + src/sshprivkey.rs | 1 + src/sshpubkey.rs | 41 ++++++++++++++++++++++++++ src/sshrw.rs | 74 ++++++++++++++++++++++++++++++++++++++++++----- 6 files changed, 117 insertions(+), 9 deletions(-) create mode 100644 src/sshbase.rs create mode 100644 src/sshcert.rs create mode 100644 src/sshprivkey.rs create mode 100644 src/sshpubkey.rs diff --git a/src/lib.rs b/src/lib.rs index 73338c2..feda21c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1 +1,5 @@ -mod sshrw; \ No newline at end of file +mod sshbase; +mod sshrw; +mod sshpubkey; +mod sshprivkey; +mod sshcert; \ No newline at end of file diff --git a/src/sshbase.rs b/src/sshbase.rs new file mode 100644 index 0000000..071d5f9 --- /dev/null +++ b/src/sshbase.rs @@ -0,0 +1,3 @@ +use std::error::Error; + +pub type SshResult = Result>; diff --git a/src/sshcert.rs b/src/sshcert.rs new file mode 100644 index 0000000..e7aefd0 --- /dev/null +++ b/src/sshcert.rs @@ -0,0 +1 @@ +pub struct SshCert {} \ No newline at end of file diff --git a/src/sshprivkey.rs b/src/sshprivkey.rs new file mode 100644 index 0000000..edc5e83 --- /dev/null +++ b/src/sshprivkey.rs @@ -0,0 +1 @@ +pub struct SshPrivateKey {} \ No newline at end of file diff --git a/src/sshpubkey.rs b/src/sshpubkey.rs new file mode 100644 index 0000000..e8a6797 --- /dev/null +++ b/src/sshpubkey.rs @@ -0,0 +1,41 @@ +use crate::sshbase::SshResult; + +pub struct SshPubicKey { + pub algorithm: String, + pub value: SshPubicKeyValue, + pub comment: Option, +} + +pub enum SshPubicKeyValue { + Rsa(SshRsaPublicKeyValue), + Ecdsa(SshEcdsaPublicKeyValue), + Ed25519(SshEd25519PublicKeyValue), +} + +pub struct SshRsaPublicKeyValue { + pub e: Vec, + pub n: Vec, +} + +pub enum SshEcdsaPublicKeyAlgorithm { + Sha2NistP256, + Sha2NistP384, + Sha2NistP521, +} + +pub struct SshEcdsaPublicKeyValue { + pub a: SshEcdsaPublicKeyAlgorithm, + pub p: String, +} + +pub struct SshEd25519PublicKeyValue { + pub p: Vec, +} + +impl SshPubicKey { + pub fn parse(key: &str) -> SshResult { + // TODO ... + + Err("".to_string())? + } +} \ No newline at end of file diff --git a/src/sshrw.rs b/src/sshrw.rs index a1917dd..8a71686 100644 --- a/src/sshrw.rs +++ b/src/sshrw.rs @@ -1,11 +1,7 @@ +use crate::sshbase::SshResult; use base64::Engine; -use std::error::Error; use std::io::{Cursor, Read}; -const ED25519_PK_SZ: u32 = 32; - -pub type SshResult = Result>; - pub struct SshReader { buffer_len: usize, read_len: usize, @@ -43,6 +39,15 @@ impl SshReader { } } + pub fn read_big_num(&mut self) -> SshResult> { + let bn = self.read_string()?; + if bn.len() > 1 && bn[0] == 0 { + Ok(bn[1..].to_vec()) + } else { + Ok(bn) + } + } + pub fn read_left(&mut self) -> SshResult> { self.read_bytes(self.left_bytes() as u32) } @@ -59,12 +64,16 @@ pub struct SshWriter { } impl SshWriter { - pub fn new(bytes: Vec) -> Self { + pub fn new() -> Self { Self { - buffer: bytes, + buffer: vec![], } } + pub fn as_slice(&self) -> &[u8] { + self.buffer.as_slice() + } + pub fn write_bytes(&mut self, bytes: &[u8]) { self.buffer.extend_from_slice(bytes); } @@ -77,6 +86,17 @@ impl SshWriter { self.write_u32(bytes.len() as u32); self.write_bytes(bytes); } + + pub fn write_big_num(&mut self, bn: &[u8]) { + if (bn.len() > 0) && (bn[0] & 0x80 != 0) { + let mut buff = Vec::with_capacity(bn.len() + 1); + buff.push(0_u8); + buff.extend_from_slice(bn); + self.write_string(&buff); + } else { + self.write_string(bn); + } + } } #[test] @@ -93,6 +113,28 @@ k/QQmZ2Nu29OYSWITbWcoeszsC+AmpFa9zhF/TG+iwmRFKlmodyCWU="; let algorithm = ssh_reader.read_string().unwrap(); assert_eq!(b"ssh-rsa", algorithm.as_slice()); + let e = ssh_reader.read_big_num().unwrap(); + let n = ssh_reader.read_big_num().unwrap(); + assert_eq!("010001", hex::encode(&e)); + assert_eq!("bcda85520bae21bb91f76e9772646352f70ee227f9c5f2207a0187e99577403126690ea1ec18b\ +7e38fcf2794981bea6242474bf536130d0d101c67854eff02e72df646dfce2d8296c4bae049b1adb56186af71\ +d3c858a9e5865b8d47434f1aa3246bac8512b27dee23c469325974ad11d6270e63918d93bd672860d03f4ebc9\ +7f1a11f4091c33644da002c7c0de496775bd4dd3048568d506ad56da45f19bfca5d02c918950fe859f4267000\ +44d3288e16288093987c5ea3caa9dfca7e4d67113dccbff29021d908a5d9cdf44accd64c27935c0c386a91fa1\ +3eda8adaf24cfdf5042417ca7964986df48052fa7fde791ff84130e554d49817478f1dcc6670944a09c5e6f7e\ +51181cc1aee084485914e05cca8c5710c586ed8170bfe7398dd39bdba666776503bd0b04771110e990336f31e\ +971771179dbd1308b78a81e5fb77c954c8e7675f0150690e9f46df547228bd7f7e269ea6870a24fd042667636\ +edbd3984962136d67287accec0be026a456bdce117f4c6fa2c264452a59a87720965", hex::encode(&n)); + + assert_eq!(0, ssh_reader.left_bytes()); + + let mut ssh_writer = SshWriter::new(); + ssh_writer.write_string(b"ssh-rsa"); + ssh_writer.write_big_num(&e); + ssh_writer.write_big_num(&n); + + assert_eq!(id_rsa_pub, STANDARD.encode(ssh_writer.as_slice())); + let id_rsa = "b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABlwAAAAdzc2gtcn\ NhAAAAAwEAAQAAAYEAvNqFUguuIbuR926XcmRjUvcO4if5xfIgegGH6ZV3QDEmaQ6h7Bi3\ 44/PJ5SYG+piQkdL9TYTDQ0QHGeFTv8C5y32Rt/OLYKWxLrgSbGttWGGr3HTyFip5YZbjU\ @@ -148,10 +190,19 @@ M9hkSeHxHrJ1+FMK2xNTd+LF17A/WW3YYTBCz8tQvhtgOQDiSk/9Lnc+vFlMF7LN0dwgwl4zIg07h0M= assert_eq!( "04bb03d7aa0f33d86449e1f11eb275f8530adb135377e2c5d7b03f596dd8613042cfcb50be1b603900e24a4\ ffd2e773ebc594c17b2cdd1dc20c25e33220d3b8743", - hex::encode(ecc_key_point)); + hex::encode(&ecc_key_point)); assert_eq!(0, ssh_reader.left_bytes()); + let mut ssh_writer = SshWriter::new(); + ssh_writer.write_string(b"ecdsa-sha2-nistp256"); + let mut ecc_key_blob_writer = SshWriter::new(); + ecc_key_blob_writer.write_string(&ssh_algorithm); + ecc_key_blob_writer.write_string(&ecc_key_point); + ssh_writer.write_bytes(ecc_key_blob_writer.as_slice()); + + assert_eq!(id_ecdsa_pub, STANDARD.encode(ssh_writer.as_slice())); + let id_ecdsa = "b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAaAAAABNlY2RzYS\ 1zaGEyLW5pc3RwMjU2AAAACG5pc3RwMjU2AAAAQQS7A9eqDzPYZEnh8R6ydfhTCtsTU3fi\ xdewP1lt2GEwQs/LUL4bYDkA4kpP/S53PrxZTBeyzdHcIMJeMyINO4dDAAAAuK3kG36t5B\" @@ -170,11 +221,18 @@ fn test_ed25519() { assert_eq!(b"ssh-ed25519", algorithm.as_slice()); let pub_key = ssh_reader.read_string().unwrap(); + assert_eq!(32, pub_key.len()); assert_eq!("4c1c2f991eda6a910d7316337e155b8df633b7e30127ef014513bbb03b42acd6", hex::encode(&pub_key)); assert_eq!(0, ssh_reader.left_bytes()); + let mut ssh_writer = SshWriter::new(); + ssh_writer.write_string(b"ssh-ed25519"); + ssh_writer.write_string(&pub_key); + + assert_eq!(id_ed25519_pub, STANDARD.encode(ssh_writer.as_slice())); + let id_ed25519 = "b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW\ QyNTUxOQAAACBMHC+ZHtpqkQ1zFjN+FVuN9jO34wEn7wFFE7uwO0Ks1gAAAKCwNsNtsDbD\ bQAAAAtzc2gtZWQyNTUxOQAAACBMHC+ZHtpqkQ1zFjN+FVuN9jO34wEn7wFFE7uwO0Ks1g\