Full SSH support for RSA.
This commit is contained in:
@@ -5,7 +5,7 @@ mod rsa;
|
||||
|
||||
pub use self::errors::{SSHKeyParseError,SSHKeyRenderError};
|
||||
|
||||
use base64::{decode,encode};
|
||||
use base64::decode;
|
||||
use self::frame::*;
|
||||
use std::fs::File;
|
||||
use std::io::{Cursor,Read,Write};
|
||||
@@ -137,17 +137,12 @@ pub fn write_ssh_keyfile<KP,P>(path: P, x: &KP, comment: &str) -> Result<(),SSHK
|
||||
file.write_all(&bytes)?;
|
||||
file.sync_all()?;
|
||||
Ok(())
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
use cryptonum::unsigned::{U1024};
|
||||
#[cfg(test)]
|
||||
use dsa::{DSAKeyPair,DSAPublicKey,L1024N160};
|
||||
#[cfg(test)]
|
||||
use rsa::{RSAKeyPair,RSAPublicKey,SIGNING_HASH_SHA256};
|
||||
use rsa::{RSAPair,RSAPublic,SIGNING_HASH_SHA256};
|
||||
#[cfg(test)]
|
||||
use sha2::Sha256;
|
||||
|
||||
@@ -210,41 +205,37 @@ fn read_dsa_examples() {
|
||||
#[cfg(test)]
|
||||
#[test]
|
||||
fn read_rsa_examples() {
|
||||
let test_files = ["rsa1024-1", "rsa1024-2", "rsa1024-3"];
|
||||
let test_files = ["rsa1024-1", "rsa1024-2", "rsa1024-3",
|
||||
"rsa2048-1", "rsa2048-2", "rsa2048-3",
|
||||
"rsa3072-1", "rsa3072-2", "rsa3072-3",
|
||||
"rsa4096-1", "rsa4096-2", "rsa4096-3",
|
||||
"rsa8192-1", "rsa8192-2", "rsa8192-3"];
|
||||
|
||||
for file in test_files.iter() {
|
||||
let path = format!("testdata/ssh/{}",file);
|
||||
let mkeypair = load_ssh_keyfile(path);
|
||||
let mkeypair = load_ssh_keyfile::<RSAPair,String>(path);
|
||||
match mkeypair {
|
||||
Err(e) => assert!(false, format!("reading error: {:?}", e)),
|
||||
Ok((keypair, comment)) => {
|
||||
let buffer = [0,1,2,3,4,6,2];
|
||||
let _ : RSAKeyPair<U1024> = keypair;
|
||||
let sig = keypair.private.sign(&SIGNING_HASH_SHA256, &buffer);
|
||||
assert!(keypair.public.verify(&SIGNING_HASH_SHA256, &buffer, &sig));
|
||||
let buffer2 = [0,1,2,3,4,6,5];
|
||||
assert!(!keypair.public.verify(&SIGNING_HASH_SHA256, &buffer2, &sig));
|
||||
let sig = keypair.sign(&SIGNING_HASH_SHA256, &buffer);
|
||||
assert!(keypair.verify(&SIGNING_HASH_SHA256, &buffer, &sig));
|
||||
match encode_ssh(&keypair, &comment) {
|
||||
Err(e2) => assert!(false, format!("render error: {:?}", e2)),
|
||||
Ok(encodedstr) => {
|
||||
match decode_ssh(&encodedstr) {
|
||||
Err(e3) => assert!(false, format!("reparse error: {:?}", e3)),
|
||||
Ok((keypair2,comment2)) => {
|
||||
let _ : RSAKeyPair<U1024> = keypair2;
|
||||
assert_eq!(keypair.public.n,keypair2.public.n,"failed to reparse key pair (n)");
|
||||
assert_eq!(keypair.public.e,keypair2.public.e,"failed to reparse key pair (e)");
|
||||
assert_eq!(keypair.private.nu,keypair2.private.nu,"failed to reparse key pair (n)");
|
||||
assert_eq!(keypair.private.d,keypair2.private.d,"failed to reparse key pair (d)");
|
||||
assert_eq!(keypair,keypair2,"failed to reparse key pair");
|
||||
assert_eq!(comment,comment2,"failed to reparse comment");
|
||||
let ppath = format!("testdata/ssh/{}.pub",file);
|
||||
match load_ssh_pubkeys::<RSAKeyPair<U1024>,String>(ppath) {
|
||||
match load_ssh_pubkeys::<RSAPair,String>(ppath) {
|
||||
Err(e4) => assert!(false, format!("pubkey error: {:?}", e4)),
|
||||
Ok(pubkeys) => {
|
||||
let _ : Vec<(RSAPublicKey<U1024>,String)> = pubkeys;
|
||||
let _ : Vec<(RSAPublic,String)> = pubkeys;
|
||||
for (pubkey, comment3) in pubkeys {
|
||||
assert_eq!(pubkey.n, keypair.public.n, "public key check (n)");
|
||||
assert_eq!(pubkey.e, keypair.public.e, "public key check (e)");
|
||||
assert_eq!(comment, comment3, "public key check comment")
|
||||
assert_eq!(pubkey, keypair.public(), "public key check");
|
||||
assert_eq!(comment, comment3, "public key check comment");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
174
src/ssh/rsa.rs
174
src/ssh/rsa.rs
@@ -1,11 +1,11 @@
|
||||
use cryptonum::unsigned::*;
|
||||
use rsa::{RSAKeyPair,RSAPublicKey,RSAPrivateKey};
|
||||
use rsa::{RSAPair,RSAPublic,RSAPublicKey,RSAPrivate,RSAPrivateKey};
|
||||
use std::io::{Read,Write};
|
||||
use ssh::errors::{SSHKeyParseError,SSHKeyRenderError};
|
||||
use ssh::frame::*;
|
||||
use ssh::SSHKey;
|
||||
|
||||
impl SSHKey for RSAKeyPair<U1024> {
|
||||
impl SSHKey for RSAPair {
|
||||
fn valid_keytype(s: &str) -> bool {
|
||||
(s == "ssh-rsa") || (s == "rsa")
|
||||
}
|
||||
@@ -16,9 +16,45 @@ impl SSHKey for RSAKeyPair<U1024> {
|
||||
if !Self::valid_keytype(&pubkey_type) {
|
||||
return Err(SSHKeyParseError::UnknownKeyType(pubkey_type));
|
||||
}
|
||||
let e = parse_openssh_number(inp)?;
|
||||
let n = parse_openssh_number(inp)?;
|
||||
Ok(RSAPublicKey::<U1024>::new(n, e))
|
||||
// this peaks a little under the cover a bit (it'd be nice to pretend
|
||||
// that we didn't know the number format was the same as the buffer
|
||||
// one), but we need to infer what kind of key this is, and this appears
|
||||
// to be the easiest / fastest way.
|
||||
let mut ebuf = parse_openssh_buffer(inp)?;
|
||||
let mut nbuf = parse_openssh_buffer(inp)?;
|
||||
|
||||
while ebuf[0] == 0 { ebuf.remove(0); }
|
||||
while nbuf[0] == 0 { nbuf.remove(0); }
|
||||
|
||||
if nbuf.len() > (8192 / 8) {
|
||||
let e = U15360::from_bytes(&ebuf);
|
||||
let n = U15360::from_bytes(&nbuf);
|
||||
Ok(RSAPublic::Key15360(RSAPublicKey::<U15360>::new(n, e)))
|
||||
} else if nbuf.len() > (4096 / 8) {
|
||||
let e = U8192::from_bytes(&ebuf);
|
||||
let n = U8192::from_bytes(&nbuf);
|
||||
Ok(RSAPublic::Key8192(RSAPublicKey::<U8192>::new(n, e)))
|
||||
} else if nbuf.len() > (3072 / 8) {
|
||||
let e = U4096::from_bytes(&ebuf);
|
||||
let n = U4096::from_bytes(&nbuf);
|
||||
Ok(RSAPublic::Key4096(RSAPublicKey::<U4096>::new(n, e)))
|
||||
} else if nbuf.len() > (2048 / 8) {
|
||||
let e = U3072::from_bytes(&ebuf);
|
||||
let n = U3072::from_bytes(&nbuf);
|
||||
Ok(RSAPublic::Key3072(RSAPublicKey::<U3072>::new(n, e)))
|
||||
} else if nbuf.len() > (1024 / 8) {
|
||||
let e = U2048::from_bytes(&ebuf);
|
||||
let n = U2048::from_bytes(&nbuf);
|
||||
Ok(RSAPublic::Key2048(RSAPublicKey::<U2048>::new(n, e)))
|
||||
} else if nbuf.len() > (512 / 8) {
|
||||
let e = U1024::from_bytes(&ebuf);
|
||||
let n = U1024::from_bytes(&nbuf);
|
||||
Ok(RSAPublic::Key1024(RSAPublicKey::<U1024>::new(n, e)))
|
||||
} else {
|
||||
let e = U512::from_bytes(&ebuf);
|
||||
let n = U512::from_bytes(&nbuf);
|
||||
Ok(RSAPublic::Key512(RSAPublicKey::<U512>::new(n, e)))
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_ssh_private_info<I: Read>(inp: &mut I) -> Result<(Self::Private,String),SSHKeyParseError>
|
||||
@@ -32,27 +68,88 @@ impl SSHKey for RSAKeyPair<U1024> {
|
||||
if !Self::valid_keytype(&privkey_type) {
|
||||
return Err(SSHKeyParseError::InconsistentKeyTypes("ssh-rsa".to_string(), privkey_type));
|
||||
}
|
||||
let n = parse_openssh_number(inp)?;
|
||||
let _e: U1024 = parse_openssh_number(inp)?;
|
||||
let d = parse_openssh_number(inp)?;
|
||||
let _iqmp: U1024 = parse_openssh_number(inp)?;
|
||||
let _p: U1024 = parse_openssh_number(inp)?;
|
||||
let _q: U1024 = parse_openssh_number(inp)?;
|
||||
let comment = parse_openssh_string(inp)?;
|
||||
|
||||
// See the comment in the public key section.
|
||||
let mut nbuf = parse_openssh_buffer(inp)?;
|
||||
let _ebuf = parse_openssh_buffer(inp)?;
|
||||
let mut dbuf = parse_openssh_buffer(inp)?;
|
||||
let _iqmp = parse_openssh_buffer(inp)?;
|
||||
let _pbuf = parse_openssh_buffer(inp)?;
|
||||
let _qbuf = parse_openssh_buffer(inp)?;
|
||||
let comment = parse_openssh_string(inp)?;
|
||||
for (idx,byte) in inp.bytes().enumerate() {
|
||||
if ((idx+1) as u8) != byte? {
|
||||
return Err(SSHKeyParseError::InvalidPadding);
|
||||
}
|
||||
}
|
||||
|
||||
Ok((RSAPrivateKey::<U1024>::new(n, d), comment))
|
||||
while dbuf[0] == 0 { dbuf.remove(0); }
|
||||
while nbuf[0] == 0 { nbuf.remove(0); }
|
||||
|
||||
if nbuf.len() > (8192 / 8) {
|
||||
let d = U15360::from_bytes(&dbuf);
|
||||
let n = U15360::from_bytes(&nbuf);
|
||||
Ok((RSAPrivate::Key15360(RSAPrivateKey::<U15360>::new(n, d)), comment))
|
||||
} else if nbuf.len() > (4096 / 8) {
|
||||
let d = U8192::from_bytes(&dbuf);
|
||||
let n = U8192::from_bytes(&nbuf);
|
||||
Ok((RSAPrivate::Key8192(RSAPrivateKey::<U8192>::new(n, d)), comment))
|
||||
} else if nbuf.len() > (3072 / 8) {
|
||||
let d = U4096::from_bytes(&dbuf);
|
||||
let n = U4096::from_bytes(&nbuf);
|
||||
Ok((RSAPrivate::Key4096(RSAPrivateKey::<U4096>::new(n, d)), comment))
|
||||
} else if nbuf.len() > (2048 / 8) {
|
||||
let d = U3072::from_bytes(&dbuf);
|
||||
let n = U3072::from_bytes(&nbuf);
|
||||
Ok((RSAPrivate::Key3072(RSAPrivateKey::<U3072>::new(n, d)), comment))
|
||||
} else if nbuf.len() > (1024 / 8) {
|
||||
let d = U2048::from_bytes(&dbuf);
|
||||
let n = U2048::from_bytes(&nbuf);
|
||||
Ok((RSAPrivate::Key2048(RSAPrivateKey::<U2048>::new(n, d)), comment))
|
||||
} else if nbuf.len() > (512 / 8) {
|
||||
let d = U1024::from_bytes(&dbuf);
|
||||
let n = U1024::from_bytes(&nbuf);
|
||||
Ok((RSAPrivate::Key1024(RSAPrivateKey::<U1024>::new(n, d)), comment))
|
||||
} else {
|
||||
let d = U512::from_bytes(&dbuf);
|
||||
let n = U512::from_bytes(&nbuf);
|
||||
Ok((RSAPrivate::Key512(RSAPrivateKey::<U512>::new(n, d)), comment))
|
||||
}
|
||||
}
|
||||
|
||||
fn render_ssh_public_info<O: Write>(&self, out: &mut O) -> Result<(),SSHKeyRenderError>
|
||||
{
|
||||
render_openssh_string(out, "ssh-rsa")?;
|
||||
render_openssh_number(out, &self.public.e)?;
|
||||
render_openssh_number(out, &self.public.n)?;
|
||||
match self {
|
||||
RSAPair::R512(pbl,_) => {
|
||||
render_openssh_number(out, &pbl.e)?;
|
||||
render_openssh_number(out, &pbl.n)?;
|
||||
}
|
||||
RSAPair::R1024(pbl,_) => {
|
||||
render_openssh_number(out, &pbl.e)?;
|
||||
render_openssh_number(out, &pbl.n)?;
|
||||
}
|
||||
RSAPair::R2048(pbl,_) => {
|
||||
render_openssh_number(out, &pbl.e)?;
|
||||
render_openssh_number(out, &pbl.n)?;
|
||||
}
|
||||
RSAPair::R3072(pbl,_) => {
|
||||
render_openssh_number(out, &pbl.e)?;
|
||||
render_openssh_number(out, &pbl.n)?;
|
||||
}
|
||||
RSAPair::R4096(pbl,_) => {
|
||||
render_openssh_number(out, &pbl.e)?;
|
||||
render_openssh_number(out, &pbl.n)?;
|
||||
}
|
||||
RSAPair::R8192(pbl,_) => {
|
||||
render_openssh_number(out, &pbl.e)?;
|
||||
render_openssh_number(out, &pbl.n)?;
|
||||
}
|
||||
RSAPair::R15360(pbl,_) => {
|
||||
render_openssh_number(out, &pbl.e)?;
|
||||
render_openssh_number(out, &pbl.n)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -61,12 +158,47 @@ impl SSHKey for RSAKeyPair<U1024> {
|
||||
render_openssh_u32(out, 0xDEADBEEF)?; // FIXME: Any reason for this to be random?
|
||||
render_openssh_u32(out, 0xDEADBEEF)?; // ditto
|
||||
render_openssh_string(out, "ssh-rsa")?;
|
||||
render_openssh_number(out, &self.public.n)?;
|
||||
render_openssh_number(out, &self.public.e)?;
|
||||
render_openssh_number(out, &self.private.d)?;
|
||||
render_openssh_number(out, &self.private.d)?;
|
||||
render_openssh_number(out, &self.private.d)?;
|
||||
render_openssh_number(out, &self.private.d)?;
|
||||
match self {
|
||||
RSAPair::R512(pbl,prv) => {
|
||||
render_openssh_number(out, &pbl.n)?;
|
||||
render_openssh_number(out, &pbl.e)?;
|
||||
render_openssh_number(out, &prv.d)?;
|
||||
}
|
||||
RSAPair::R1024(pbl,prv) => {
|
||||
render_openssh_number(out, &pbl.n)?;
|
||||
render_openssh_number(out, &pbl.e)?;
|
||||
render_openssh_number(out, &prv.d)?;
|
||||
}
|
||||
RSAPair::R2048(pbl,prv) => {
|
||||
render_openssh_number(out, &pbl.n)?;
|
||||
render_openssh_number(out, &pbl.e)?;
|
||||
render_openssh_number(out, &prv.d)?;
|
||||
}
|
||||
RSAPair::R3072(pbl,prv) => {
|
||||
render_openssh_number(out, &pbl.n)?;
|
||||
render_openssh_number(out, &pbl.e)?;
|
||||
render_openssh_number(out, &prv.d)?;
|
||||
}
|
||||
RSAPair::R4096(pbl,prv) => {
|
||||
render_openssh_number(out, &pbl.n)?;
|
||||
render_openssh_number(out, &pbl.e)?;
|
||||
render_openssh_number(out, &prv.d)?;
|
||||
}
|
||||
RSAPair::R8192(pbl,prv) => {
|
||||
render_openssh_number(out, &pbl.n)?;
|
||||
render_openssh_number(out, &pbl.e)?;
|
||||
render_openssh_number(out, &prv.d)?;
|
||||
}
|
||||
RSAPair::R15360(pbl,prv) => {
|
||||
render_openssh_number(out, &pbl.n)?;
|
||||
render_openssh_number(out, &pbl.e)?;
|
||||
render_openssh_number(out, &prv.d)?;
|
||||
}
|
||||
}
|
||||
/* iqmp */ render_openssh_buffer(out, &vec![])?;
|
||||
/* p */ render_openssh_buffer(out, &vec![])?;
|
||||
/* q */ render_openssh_buffer(out, &vec![])?;
|
||||
|
||||
render_openssh_string(out, comment)?;
|
||||
// add some padding (not quite sure why)
|
||||
let mut i = comment.len();
|
||||
|
||||
Reference in New Issue
Block a user