use super::keytype::{Curve, KeyType, KeyTypeKind};
use super::error::{Error, ErrorKind};
use super::PublicKey;
use super::reader::Reader;
use std::fs::File;
use std::io::{Read};
use std::path::Path;
#[derive(Debug, PartialEq, Clone)]
pub struct RsaPrivateKey {
pub d: Vec<u8>,
pub n: Vec<u8>,
}
#[derive(Debug, PartialEq, Clone)]
pub struct EcdsaPrivateKey {
pub curve: Curve,
pub key: Vec<u8>,
}
#[derive(Debug, PartialEq, Clone)]
pub struct Ed25519PrivateKey {
pub key: Vec<u8>,
}
#[derive(Debug, PartialEq, Clone)]
pub enum PrivateKeyKind {
Rsa(RsaPrivateKey),
Ecdsa(EcdsaPrivateKey),
Ed25519(Ed25519PrivateKey),
}
#[derive(Debug, PartialEq, Clone)]
pub struct PrivateKey {
pub key_type: KeyType,
pub kind: PrivateKeyKind,
pub pubkey: PublicKey,
pub comment: Option<String>,
}
impl PrivateKey {
pub fn from_path<P: AsRef<Path>>(path: P) -> Result<PrivateKey, Error> {
let mut contents = String::new();
File::open(path)?.read_to_string(&mut contents)?;
PrivateKey::from_string(&contents)
}
pub fn from_string(contents: &str) -> Result<PrivateKey, Error> {
let mut iter = contents.lines();
let header = iter.next().unwrap_or("");
if header != "-----BEGIN OPENSSH PRIVATE KEY-----" {
return Err(Error::with_kind(ErrorKind::InvalidFormat));
}
let mut encoded_key = String::new();
loop {
let part = match iter.next() {
Some(p) => p,
None => return Err(Error::with_kind(ErrorKind::InvalidFormat)),
};
if part == "-----END OPENSSH PRIVATE KEY-----" {
break;
}
encoded_key.push_str(part);
}
let decoded = base64::decode(encoded_key)?;
let mut reader = Reader::new(&decoded);
let k = PrivateKey::from_reader(&mut reader)?;
Ok(k)
}
pub(crate) fn from_reader(reader: &mut Reader) -> Result<PrivateKey, Error> {
let preamble = reader.read_cstring()?;
if preamble != "openssh-key-v1" {
return Err(Error::with_kind(ErrorKind::InvalidFormat));
}
let cipher_name = reader.read_string()?;
let kdf = reader.read_string()?;
if cipher_name != "none" || kdf != "none" {
return Err(Error::with_kind(ErrorKind::EncryptedPrivateKeyNotSupported));
}
reader.read_string()?;
let number_of_keys = reader.read_u32()?;
if number_of_keys != 1 {
return Err(Error::with_kind(ErrorKind::InvalidFormat));
}
let pubkey = reader
.read_bytes()
.and_then(|v| PublicKey::from_bytes(&v))?;
let _remaining_length = reader.read_u32()?;
let c1 = reader.read_u32()?;
let c2 = reader.read_u32()?;
if c1 != c2 {
return Err(Error::with_kind(ErrorKind::InvalidFormat));
}
let key_type = reader.read_string()?;
let kt = KeyType::from_name(&key_type)?;
let kind = match kt.kind {
KeyTypeKind::Ecdsa => {
let identifier = reader.read_string()?;
let curve = Curve::from_identifier(&identifier)?;
let _pubkey = reader.read_bytes()?;
let key = reader.read_bytes()?;
let k = EcdsaPrivateKey {
curve,
key,
};
PrivateKeyKind::Ecdsa(k)
}
_ => return Err(Error::with_kind(ErrorKind::UnknownKeyType(kt.name.to_string()))),
};
Ok(PrivateKey {
key_type: kt,
kind,
pubkey,
comment: None,
})
}
}