Update the SSH documentation.
This commit is contained in:
@@ -2,6 +2,8 @@ use base64::DecodeError;
|
||||
use ed25519::ED25519PublicImportError;
|
||||
use std::io;
|
||||
|
||||
/// A whole pile of errors that you can get when parsing an SSH key from
|
||||
/// disk or memory.
|
||||
#[derive(Debug)]
|
||||
pub enum SSHKeyParseError
|
||||
{
|
||||
@@ -49,6 +51,8 @@ impl From<ED25519PublicImportError> for SSHKeyParseError {
|
||||
}
|
||||
}
|
||||
|
||||
/// A much smaller set of errors you can get when rendering an SSH key into
|
||||
/// a file or memory block.
|
||||
#[derive(Debug)]
|
||||
pub enum SSHKeyRenderError {
|
||||
IOError(io::Error),
|
||||
|
||||
@@ -13,6 +13,9 @@ use std::iter::Iterator;
|
||||
const OPENER: &'static str = "-----BEGIN OPENSSH PRIVATE KEY-----\n";
|
||||
const CLOSER: &'static str = "-----END OPENSSH PRIVATE KEY-----";
|
||||
|
||||
/// Given a string defining an ASCII SSH key blob (one that starts with
|
||||
/// "--BEGIN..."), decode the body of the blob and return it as binary
|
||||
/// data.
|
||||
pub fn parse_ssh_private_key_data(s: &str) -> Result<Vec<u8>,SSHKeyParseError>
|
||||
{
|
||||
if s.starts_with(OPENER) {
|
||||
@@ -28,6 +31,8 @@ pub fn parse_ssh_private_key_data(s: &str) -> Result<Vec<u8>,SSHKeyParseError>
|
||||
}
|
||||
}
|
||||
|
||||
/// Once you've figured out the binary data you want to produce for an SSH key
|
||||
/// blob, use this routine to render it into its ASCII encoding.
|
||||
pub fn render_ssh_private_key_data(bytes: &[u8]) -> String
|
||||
{
|
||||
let mut bytestr = encode(bytes);
|
||||
@@ -52,6 +57,7 @@ pub fn render_ssh_private_key_data(bytes: &[u8]) -> String
|
||||
const OPENSSH_MAGIC_HEADER: &'static str = "openssh-key-v1\0";
|
||||
const OPENSSH_MAGIC_HEADER_LEN: usize = 15;
|
||||
|
||||
/// Parse the magic header in an SSH key file.
|
||||
pub fn parse_openssh_header<R: Read>(input: &mut R) -> Result<(),SSHKeyParseError>
|
||||
{
|
||||
let mut limited_input_header = input.take(OPENSSH_MAGIC_HEADER_LEN as u64);
|
||||
@@ -70,6 +76,7 @@ pub fn parse_openssh_header<R: Read>(input: &mut R) -> Result<(),SSHKeyParseErro
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Render the magic header in an SSH key file.
|
||||
pub fn render_openssh_header<O: Write>(output: &mut O) -> Result<(),SSHKeyRenderError>
|
||||
{
|
||||
Ok(output.write_all(OPENSSH_MAGIC_HEADER.as_bytes())?)
|
||||
@@ -77,6 +84,8 @@ pub fn render_openssh_header<O: Write>(output: &mut O) -> Result<(),SSHKeyRender
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/// Parse an unsigned u32 from the SSH key stream. (This does the appropriate
|
||||
/// conversion from network order to native order.)
|
||||
pub fn parse_openssh_u32<I: Read>(input: &mut I) -> Result<u32,SSHKeyParseError>
|
||||
{
|
||||
let mut limited_input_header = input.take(4);
|
||||
@@ -84,6 +93,8 @@ pub fn parse_openssh_u32<I: Read>(input: &mut I) -> Result<u32,SSHKeyParseError>
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
/// Render an unsigned u32 from the SSH key stream. (This does the appropriate
|
||||
/// conversion from network order to native order.)
|
||||
pub fn render_openssh_u32<O: Write>(output: &mut O, val: u32) -> Result<(),SSHKeyRenderError>
|
||||
{
|
||||
Ok(output.write_u32::<BigEndian>(val)?)
|
||||
@@ -91,6 +102,9 @@ pub fn render_openssh_u32<O: Write>(output: &mut O, val: u32) -> Result<(),SSHKe
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/// Parse a string from the SSH key stream. This does some validation to ensure
|
||||
/// that the data being read is actually in a form that Rust will recognize as
|
||||
/// being a valid string.
|
||||
pub fn parse_openssh_string<I: Read>(input: &mut I) -> Result<String,SSHKeyParseError>
|
||||
{
|
||||
let length = parse_openssh_u32(input)?;
|
||||
@@ -100,6 +114,7 @@ pub fn parse_openssh_string<I: Read>(input: &mut I) -> Result<String,SSHKeyParse
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
/// Render a string into the SSH key stream.
|
||||
pub fn render_openssh_string<O: Write>(output: &mut O, v: &str) -> Result<(),SSHKeyRenderError>
|
||||
{
|
||||
let vbytes: Vec<u8> = v.bytes().collect();
|
||||
@@ -116,6 +131,7 @@ pub fn render_openssh_string<O: Write>(output: &mut O, v: &str) -> Result<(),SSH
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/// Read a buffer from the SSH key stream.
|
||||
pub fn parse_openssh_buffer<I: Read>(input: &mut I) -> Result<Vec<u8>,SSHKeyParseError>
|
||||
{
|
||||
let length = parse_openssh_u32(input)?;
|
||||
@@ -125,6 +141,7 @@ pub fn parse_openssh_buffer<I: Read>(input: &mut I) -> Result<Vec<u8>,SSHKeyPars
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
/// Render a buffer into the SSH key stream.
|
||||
pub fn render_openssh_buffer<O: Write>(output: &mut O, b: &[u8]) -> Result<(),SSHKeyRenderError>
|
||||
{
|
||||
if b.len() > 0xFFFFFFFF {
|
||||
@@ -141,6 +158,7 @@ pub fn render_openssh_buffer<O: Write>(output: &mut O, b: &[u8]) -> Result<(),SS
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/// Parse a fixed-width number from the SSH key stream and return it.
|
||||
pub fn parse_openssh_number<I,D>(input: &mut I) -> Result<D,SSHKeyParseError>
|
||||
where
|
||||
I: Read,
|
||||
@@ -151,6 +169,7 @@ pub fn parse_openssh_number<I,D>(input: &mut I) -> Result<D,SSHKeyParseError>
|
||||
Ok(D::from_bytes(&buffer))
|
||||
}
|
||||
|
||||
/// Render a fixed-width number into the SSH key stream.
|
||||
pub fn render_openssh_number<O,D>(output: &mut O, n: &D) -> Result<(),SSHKeyRenderError>
|
||||
where
|
||||
O: Write,
|
||||
|
||||
@@ -2,7 +2,7 @@ mod dsa;
|
||||
mod ecdsa;
|
||||
mod ed25519;
|
||||
mod errors;
|
||||
mod frame;
|
||||
pub mod frame;
|
||||
mod rsa;
|
||||
|
||||
pub use self::errors::{SSHKeyParseError,SSHKeyRenderError};
|
||||
@@ -14,16 +14,35 @@ use std::io::{Cursor,Read,Write};
|
||||
use std::path::Path;
|
||||
use super::KeyPair;
|
||||
|
||||
/// A trait defining keys that can be parsed / rendered by this library. Note
|
||||
/// that you probably don't want to use these routines directly; they're mostly
|
||||
/// used by the internal functions. Perhaps the only reason to use them is to
|
||||
/// implement them, because you've got another kind of key you want to parse that
|
||||
/// isn't already part of the library. (In that case, though ... maybe send a
|
||||
/// patch?)
|
||||
pub trait SSHKey: Sized + KeyPair {
|
||||
/// Return true if the given string is a valid key type identifier for this
|
||||
/// key type. (i.e., "ssh-ed25519" is the identifier for ED25519, and "dss"
|
||||
/// and "ssh-dss" are both valid identifiers for DSA keys.)
|
||||
fn valid_keytype(s: &str) -> bool;
|
||||
|
||||
/// Parse the public blob info within an SSH blob. I strongly recommend
|
||||
/// using the functions in `ssh::frame` for this.
|
||||
fn parse_ssh_public_info<I: Read>(inp: &mut I) -> Result<Self::Public,SSHKeyParseError>;
|
||||
/// Parse the private blob info within an SSH blob. I strongly recommend
|
||||
/// using the functions in `ssh::frame` for this.
|
||||
fn parse_ssh_private_info<I: Read>(inp: &mut I) -> Result<(Self::Private,String),SSHKeyParseError>;
|
||||
|
||||
/// Render the public blob info within an SSH blob. I strongly recommend
|
||||
/// using the functions in `ssh::frame` for this.
|
||||
fn render_ssh_public_info<O: Write>(&self, out: &mut O) -> Result<(),SSHKeyRenderError>;
|
||||
/// Render the private blob info within an SSH blob. I strongly recommend
|
||||
/// using the functions in `ssh::frame` for this.
|
||||
fn render_ssh_private_info<O: Write>(&self, out: &mut O) -> Result<(),SSHKeyRenderError>;
|
||||
}
|
||||
|
||||
/// Decode a string containing a private key into the appropriate key type and
|
||||
/// the comment associated with it, usually an email address or similar.
|
||||
pub fn decode_ssh<KP: SSHKey>(x: &str) -> Result<(KP, String),SSHKeyParseError>
|
||||
{
|
||||
let bytes = parse_ssh_private_key_data(x)?;
|
||||
@@ -61,6 +80,8 @@ pub fn decode_ssh<KP: SSHKey>(x: &str) -> Result<(KP, String),SSHKeyParseError>
|
||||
Ok((KP::new(public, private), comment))
|
||||
}
|
||||
|
||||
/// Decode a string containing a public key into an appropriate key type and
|
||||
/// the comment associated with it, usually an email address or similar.
|
||||
pub fn decode_ssh_pubkey<KP: SSHKey>(s: &str) -> Result<(KP::Public, String),SSHKeyParseError>
|
||||
{
|
||||
let mut splitter = s.split_whitespace();
|
||||
@@ -82,6 +103,8 @@ pub fn decode_ssh_pubkey<KP: SSHKey>(s: &str) -> Result<(KP::Public, String),SSH
|
||||
}
|
||||
}
|
||||
|
||||
/// Load an SSH private key file, returning the appropriate key type and the
|
||||
/// comment associated with it.
|
||||
pub fn load_ssh_keyfile<KP,P>(path: P) -> Result<(KP, String),SSHKeyParseError>
|
||||
where
|
||||
KP: SSHKey,
|
||||
@@ -93,6 +116,7 @@ pub fn load_ssh_keyfile<KP,P>(path: P) -> Result<(KP, String),SSHKeyParseError>
|
||||
decode_ssh(&contents)
|
||||
}
|
||||
|
||||
/// Load all the public keys from a file into memory.
|
||||
pub fn load_ssh_pubkeys<KP,P>(path: P) -> Result<Vec<(KP::Public, String)>,SSHKeyParseError>
|
||||
where
|
||||
KP: SSHKey,
|
||||
@@ -110,6 +134,7 @@ pub fn load_ssh_pubkeys<KP,P>(path: P) -> Result<Vec<(KP::Public, String)>,SSHKe
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
/// Encode a supported key into its ASCII SSH format, with the given comment.
|
||||
pub fn encode_ssh<KP: SSHKey>(x: &KP, comment: &str) -> Result<String,SSHKeyRenderError>
|
||||
{
|
||||
let mut pubkeybin = Vec::with_capacity(8192);
|
||||
@@ -140,6 +165,7 @@ pub fn encode_ssh<KP: SSHKey>(x: &KP, comment: &str) -> Result<String,SSHKeyRend
|
||||
Ok(render_ssh_private_key_data(&binary))
|
||||
}
|
||||
|
||||
/// Encode a supported key into the given file, with the given comment.
|
||||
pub fn write_ssh_keyfile<KP,P>(path: P, x: &KP, comment: &str) -> Result<(),SSHKeyRenderError>
|
||||
where
|
||||
KP: SSHKey,
|
||||
|
||||
Reference in New Issue
Block a user