diff --git a/src/ssh/dsa.rs b/src/ssh/dsa.rs index ceb7c1b..12fd1a0 100644 --- a/src/ssh/dsa.rs +++ b/src/ssh/dsa.rs @@ -6,10 +6,14 @@ use ssh::frame::*; use ssh::SSHKey; impl SSHKey for DSAKeyPair { + fn valid_keytype(s: &str) -> bool { + (s == "ssh-dss") || (s == "dss") + } + fn parse_ssh_public_info(inp: &mut I) -> Result { let pubkey_type = parse_openssh_string(inp)?; - if pubkey_type != "ssh-dss" { + if !Self::valid_keytype(&pubkey_type) { return Err(SSHKeyParseError::UnknownKeyType(pubkey_type)); } let pubp = parse_openssh_number(inp)?; @@ -29,7 +33,7 @@ impl SSHKey for DSAKeyPair { return Err(SSHKeyParseError::PrivateKeyCorruption); } let privkey_type = parse_openssh_string(inp)?; - if privkey_type != "ssh-dss" { + if !Self::valid_keytype(&privkey_type) { return Err(SSHKeyParseError::InconsistentKeyTypes("ssh-dss".to_string(), privkey_type)); } let privp = parse_openssh_number(inp)?; diff --git a/src/ssh/errors.rs b/src/ssh/errors.rs index 3e649d7..856a173 100644 --- a/src/ssh/errors.rs +++ b/src/ssh/errors.rs @@ -18,7 +18,9 @@ pub enum SSHKeyParseError InconsistentKeyTypes(String,String), InconsistentPublicKeyValue, InvalidPrivateKeyValue, - InvalidPadding + InvalidPadding, + InvalidPublicKeyType, + BrokenPublicKeyLine } impl From for SSHKeyParseError { diff --git a/src/ssh/mod.rs b/src/ssh/mod.rs index 5787676..0606aef 100644 --- a/src/ssh/mod.rs +++ b/src/ssh/mod.rs @@ -4,6 +4,7 @@ mod frame; pub use self::errors::{SSHKeyParseError,SSHKeyRenderError}; +use base64::{decode,encode}; use self::frame::*; use std::fs::File; use std::io::{Cursor,Read,Write}; @@ -11,6 +12,8 @@ use std::path::Path; use super::KeyPair; pub trait SSHKey: Sized + KeyPair { + fn valid_keytype(s: &str) -> bool; + fn parse_ssh_public_info(inp: &mut I) -> Result; fn parse_ssh_private_info(inp: &mut I) -> Result<(Self::Private,String),SSHKeyParseError>; @@ -55,6 +58,27 @@ pub fn decode_ssh(x: &str) -> Result<(KP, String),SSHKeyParseError> Ok((KP::new(public, private), comment)) } +pub fn decode_ssh_pubkey(s: &str) -> Result<(KP::Public, String),SSHKeyParseError> +{ + let mut splitter = s.split_whitespace(); + + match (splitter.next(), splitter.next(), splitter.next(), splitter.next()) { + (Some(keytype), Some(keymaterial), Some(comment), None) => { + if !KP::valid_keytype(keytype) { + return Err(SSHKeyParseError::InvalidPublicKeyType); + } + + let bytes = decode(keymaterial)?; + let mut byte_cursor = Cursor::new(bytes); + let key = KP::parse_ssh_public_info(&mut byte_cursor)?; + + Ok((key, comment.to_string())) + } + _ => + Err(SSHKeyParseError::BrokenPublicKeyLine) + } +} + pub fn load_ssh_keyfile(path: P) -> Result<(KP, String),SSHKeyParseError> where KP: SSHKey, @@ -66,6 +90,23 @@ pub fn load_ssh_keyfile(path: P) -> Result<(KP, String),SSHKeyParseError> decode_ssh(&contents) } +pub fn load_ssh_pubkeys(path: P) -> Result,SSHKeyParseError> + where + KP: SSHKey, + P: AsRef +{ + let mut file = File::open(path)?; + let mut contents = String::new(); + file.read_to_string(&mut contents)?; + let mut result = Vec::new(); + + for line in contents.lines() { + result.push( decode_ssh_pubkey::(line)? ); + } + + Ok(result) +} + pub fn encode_ssh(x: &KP, comment: &str) -> Result { let mut pubkeybin = Vec::with_capacity(8192); @@ -101,7 +142,7 @@ pub fn write_ssh_keyfile(path: P, x: &KP, comment: &str) -> Result<(),SSHK #[cfg(test)] -use dsa::{DSAKeyPair,DSAPublicKey,DSAPrivateKey,L1024N160}; +use dsa::{DSAKeyPair,DSAPublicKey,DSAPrivateKey,DSAPubKey,L1024N160}; #[cfg(test)] use sha2::Sha256; @@ -138,6 +179,20 @@ fn read_dsa_examples() { assert_eq!(keypair.public.y,keypair2.public.y,"failed to reparse key pair (y)"); assert_eq!(keypair.private.x,keypair2.private.x,"failed to reparse key pair (x)"); assert_eq!(comment,comment2,"failed to reparse comment"); + let ppath = format!("testdata/ssh/{}.pub",file); + match load_ssh_pubkeys::,String>(ppath) { + Err(e4) => assert!(false, format!("pubkey error: {:?}", e4)), + Ok(pubkeys) => { + let _ : Vec<(DSAPubKey,String)> = pubkeys; + for (pubkey, comment3) in pubkeys { + assert_eq!(pubkey.params.p, keypair.public.params.p, "public key check (p)"); + assert_eq!(pubkey.params.q, keypair.public.params.q, "public key check (q)"); + assert_eq!(pubkey.params.g, keypair.public.params.g, "public key check (g)"); + assert_eq!(pubkey.y, keypair.public.y, "public key check (y)"); + assert_eq!(comment, comment3, "public key check comment") + } + } + } } } }