Update the SSH documentation.
This commit is contained in:
@@ -2,6 +2,8 @@ use base64::DecodeError;
|
|||||||
use ed25519::ED25519PublicImportError;
|
use ed25519::ED25519PublicImportError;
|
||||||
use std::io;
|
use std::io;
|
||||||
|
|
||||||
|
/// A whole pile of errors that you can get when parsing an SSH key from
|
||||||
|
/// disk or memory.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum SSHKeyParseError
|
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)]
|
#[derive(Debug)]
|
||||||
pub enum SSHKeyRenderError {
|
pub enum SSHKeyRenderError {
|
||||||
IOError(io::Error),
|
IOError(io::Error),
|
||||||
|
|||||||
@@ -13,6 +13,9 @@ use std::iter::Iterator;
|
|||||||
const OPENER: &'static str = "-----BEGIN OPENSSH PRIVATE KEY-----\n";
|
const OPENER: &'static str = "-----BEGIN OPENSSH PRIVATE KEY-----\n";
|
||||||
const CLOSER: &'static str = "-----END OPENSSH PRIVATE KEY-----";
|
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>
|
pub fn parse_ssh_private_key_data(s: &str) -> Result<Vec<u8>,SSHKeyParseError>
|
||||||
{
|
{
|
||||||
if s.starts_with(OPENER) {
|
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
|
pub fn render_ssh_private_key_data(bytes: &[u8]) -> String
|
||||||
{
|
{
|
||||||
let mut bytestr = encode(bytes);
|
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: &'static str = "openssh-key-v1\0";
|
||||||
const OPENSSH_MAGIC_HEADER_LEN: usize = 15;
|
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>
|
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);
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Render the magic header in an SSH key file.
|
||||||
pub fn render_openssh_header<O: Write>(output: &mut O) -> Result<(),SSHKeyRenderError>
|
pub fn render_openssh_header<O: Write>(output: &mut O) -> Result<(),SSHKeyRenderError>
|
||||||
{
|
{
|
||||||
Ok(output.write_all(OPENSSH_MAGIC_HEADER.as_bytes())?)
|
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>
|
pub fn parse_openssh_u32<I: Read>(input: &mut I) -> Result<u32,SSHKeyParseError>
|
||||||
{
|
{
|
||||||
let mut limited_input_header = input.take(4);
|
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)
|
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>
|
pub fn render_openssh_u32<O: Write>(output: &mut O, val: u32) -> Result<(),SSHKeyRenderError>
|
||||||
{
|
{
|
||||||
Ok(output.write_u32::<BigEndian>(val)?)
|
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>
|
pub fn parse_openssh_string<I: Read>(input: &mut I) -> Result<String,SSHKeyParseError>
|
||||||
{
|
{
|
||||||
let length = parse_openssh_u32(input)?;
|
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)
|
Ok(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Render a string into the SSH key stream.
|
||||||
pub fn render_openssh_string<O: Write>(output: &mut O, v: &str) -> Result<(),SSHKeyRenderError>
|
pub fn render_openssh_string<O: Write>(output: &mut O, v: &str) -> Result<(),SSHKeyRenderError>
|
||||||
{
|
{
|
||||||
let vbytes: Vec<u8> = v.bytes().collect();
|
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>
|
pub fn parse_openssh_buffer<I: Read>(input: &mut I) -> Result<Vec<u8>,SSHKeyParseError>
|
||||||
{
|
{
|
||||||
let length = parse_openssh_u32(input)?;
|
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)
|
Ok(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Render a buffer into the SSH key stream.
|
||||||
pub fn render_openssh_buffer<O: Write>(output: &mut O, b: &[u8]) -> Result<(),SSHKeyRenderError>
|
pub fn render_openssh_buffer<O: Write>(output: &mut O, b: &[u8]) -> Result<(),SSHKeyRenderError>
|
||||||
{
|
{
|
||||||
if b.len() > 0xFFFFFFFF {
|
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>
|
pub fn parse_openssh_number<I,D>(input: &mut I) -> Result<D,SSHKeyParseError>
|
||||||
where
|
where
|
||||||
I: Read,
|
I: Read,
|
||||||
@@ -151,6 +169,7 @@ pub fn parse_openssh_number<I,D>(input: &mut I) -> Result<D,SSHKeyParseError>
|
|||||||
Ok(D::from_bytes(&buffer))
|
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>
|
pub fn render_openssh_number<O,D>(output: &mut O, n: &D) -> Result<(),SSHKeyRenderError>
|
||||||
where
|
where
|
||||||
O: Write,
|
O: Write,
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ mod dsa;
|
|||||||
mod ecdsa;
|
mod ecdsa;
|
||||||
mod ed25519;
|
mod ed25519;
|
||||||
mod errors;
|
mod errors;
|
||||||
mod frame;
|
pub mod frame;
|
||||||
mod rsa;
|
mod rsa;
|
||||||
|
|
||||||
pub use self::errors::{SSHKeyParseError,SSHKeyRenderError};
|
pub use self::errors::{SSHKeyParseError,SSHKeyRenderError};
|
||||||
@@ -14,16 +14,35 @@ use std::io::{Cursor,Read,Write};
|
|||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use super::KeyPair;
|
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 {
|
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;
|
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>;
|
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>;
|
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>;
|
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>;
|
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>
|
pub fn decode_ssh<KP: SSHKey>(x: &str) -> Result<(KP, String),SSHKeyParseError>
|
||||||
{
|
{
|
||||||
let bytes = parse_ssh_private_key_data(x)?;
|
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))
|
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>
|
pub fn decode_ssh_pubkey<KP: SSHKey>(s: &str) -> Result<(KP::Public, String),SSHKeyParseError>
|
||||||
{
|
{
|
||||||
let mut splitter = s.split_whitespace();
|
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>
|
pub fn load_ssh_keyfile<KP,P>(path: P) -> Result<(KP, String),SSHKeyParseError>
|
||||||
where
|
where
|
||||||
KP: SSHKey,
|
KP: SSHKey,
|
||||||
@@ -93,6 +116,7 @@ pub fn load_ssh_keyfile<KP,P>(path: P) -> Result<(KP, String),SSHKeyParseError>
|
|||||||
decode_ssh(&contents)
|
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>
|
pub fn load_ssh_pubkeys<KP,P>(path: P) -> Result<Vec<(KP::Public, String)>,SSHKeyParseError>
|
||||||
where
|
where
|
||||||
KP: SSHKey,
|
KP: SSHKey,
|
||||||
@@ -110,6 +134,7 @@ pub fn load_ssh_pubkeys<KP,P>(path: P) -> Result<Vec<(KP::Public, String)>,SSHKe
|
|||||||
Ok(result)
|
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>
|
pub fn encode_ssh<KP: SSHKey>(x: &KP, comment: &str) -> Result<String,SSHKeyRenderError>
|
||||||
{
|
{
|
||||||
let mut pubkeybin = Vec::with_capacity(8192);
|
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))
|
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>
|
pub fn write_ssh_keyfile<KP,P>(path: P, x: &KP, comment: &str) -> Result<(),SSHKeyRenderError>
|
||||||
where
|
where
|
||||||
KP: SSHKey,
|
KP: SSHKey,
|
||||||
|
|||||||
Reference in New Issue
Block a user