use crate::cipher::Cipher;
use crate::error::*;
use crate::format::ossh_privkey::*;
use crate::format::ossh_pubkey::*;
use crate::format::parse_keystr;
use crate::format::pem::*;
use crate::format::pkcs8::*;
use digest::Digest;
use md5::Md5;
use openssl::pkey::{Id, PKey, PKeyRef, Private};
use sha2::{Sha256, Sha512};
use std::fmt;
pub mod dsa;
pub mod ecdsa;
pub mod ed25519;
pub mod rsa;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum FingerprintHash {
MD5,
SHA256,
SHA512,
}
impl FingerprintHash {
fn hash(self, data: &[u8]) -> Vec<u8> {
fn digest_hash<D: Digest>(hasher: &mut D, data: &[u8]) -> Vec<u8> {
hasher.input(data);
hasher.result_reset().to_vec()
}
match self {
FingerprintHash::MD5 => digest_hash(&mut Md5::default(), data),
FingerprintHash::SHA256 => digest_hash(&mut Sha256::default(), data),
FingerprintHash::SHA512 => digest_hash(&mut Sha512::default(), data),
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum KeyType {
RSA,
DSA,
ECDSA,
ED25519,
}
#[derive(Debug, PartialEq)]
pub(crate) enum PublicKeyType {
RSA(rsa::RsaPublicKey),
DSA(dsa::DsaPublicKey),
ECDSA(ecdsa::EcDsaPublicKey),
ED25519(ed25519::Ed25519PublicKey),
}
pub(crate) enum KeyPairType {
RSA(rsa::RsaKeyPair),
DSA(dsa::DsaKeyPair),
ECDSA(ecdsa::EcDsaKeyPair),
ED25519(ed25519::Ed25519KeyPair),
}
pub struct PublicKey {
pub(crate) key: PublicKeyType,
comment: String,
}
impl PublicKey {
pub fn from_keystring(keystr: &str) -> OsshResult<Self> {
Ok(parse_ossh_pubkey(keystr)?)
}
pub fn keytype(&self) -> KeyType {
match &self.key {
PublicKeyType::RSA(_) => KeyType::RSA,
PublicKeyType::DSA(_) => KeyType::DSA,
PublicKeyType::ECDSA(_) => KeyType::ECDSA,
PublicKeyType::ED25519(_) => KeyType::ED25519,
}
}
pub fn comment(&self) -> &str {
&self.comment
}
pub fn comment_mut(&mut self) -> &mut String {
&mut self.comment
}
pub fn serialize(&self) -> OsshResult<String> {
serialize_ossh_pubkey(self, &self.comment)
}
fn inner_key(&self) -> &dyn PublicParts {
match &self.key {
PublicKeyType::RSA(key) => key,
PublicKeyType::DSA(key) => key,
PublicKeyType::ECDSA(key) => key,
PublicKeyType::ED25519(key) => key,
}
}
}
impl Key for PublicKey {
fn size(&self) -> usize {
self.inner_key().size()
}
fn keyname(&self) -> &'static str {
self.inner_key().keyname()
}
}
impl PublicParts for PublicKey {
fn blob(&self) -> Result<Vec<u8>, Error> {
self.inner_key().blob()
}
fn fingerprint(&self, hash: FingerprintHash) -> Result<Vec<u8>, Error> {
self.inner_key().fingerprint(hash)
}
fn verify(&self, data: &[u8], sig: &[u8]) -> Result<bool, Error> {
self.inner_key().verify(data, sig)
}
}
impl fmt::Display for PublicKey {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.serialize().unwrap())
}
}
impl From<rsa::RsaPublicKey> for PublicKey {
fn from(inner: rsa::RsaPublicKey) -> PublicKey {
PublicKey {
key: PublicKeyType::RSA(inner),
comment: String::new(),
}
}
}
impl From<dsa::DsaPublicKey> for PublicKey {
fn from(inner: dsa::DsaPublicKey) -> PublicKey {
PublicKey {
key: PublicKeyType::DSA(inner),
comment: String::new(),
}
}
}
impl From<ecdsa::EcDsaPublicKey> for PublicKey {
fn from(inner: ecdsa::EcDsaPublicKey) -> PublicKey {
PublicKey {
key: PublicKeyType::ECDSA(inner),
comment: String::new(),
}
}
}
impl From<ed25519::Ed25519PublicKey> for PublicKey {
fn from(inner: ed25519::Ed25519PublicKey) -> PublicKey {
PublicKey {
key: PublicKeyType::ED25519(inner),
comment: String::new(),
}
}
}
pub struct KeyPair {
pub(crate) key: KeyPairType,
comment: String,
}
impl KeyPair {
pub(crate) fn from_ossl_pkey(pkey: &PKeyRef<Private>) -> OsshResult<Self> {
match pkey.id() {
Id::RSA => {
Ok(rsa::RsaKeyPair::from_ossl_rsa(pkey.rsa()?, rsa::RsaSignature::SHA1)?.into())
}
Id::DSA => Ok(dsa::DsaKeyPair::from_ossl_dsa(pkey.dsa()?).into()),
Id::EC => Ok(ecdsa::EcDsaKeyPair::from_ossl_ec(pkey.ec_key()?)?.into()),
_ => Err(ErrorKind::UnsupportType.into()),
}
}
pub(crate) fn ossl_pkey(&self) -> OsshResult<PKey<Private>> {
match &self.key {
KeyPairType::RSA(key) => Ok(PKey::from_rsa(key.ossl_rsa().to_owned())?),
KeyPairType::DSA(key) => Ok(PKey::from_dsa(key.ossl_dsa().to_owned())?),
KeyPairType::ECDSA(key) => Ok(PKey::from_ec_key(key.ossl_ec().to_owned())?),
_ => Err(ErrorKind::UnsupportType.into()),
}
}
pub fn from_keystr(pem: &str, passphrase: Option<&[u8]>) -> OsshResult<Self> {
Ok(parse_keystr(pem.as_bytes(), passphrase)?)
}
pub fn generate(keytype: KeyType, bits: usize) -> OsshResult<Self> {
Ok(match keytype {
KeyType::RSA => rsa::RsaKeyPair::generate(bits)?.into(),
KeyType::DSA => dsa::DsaKeyPair::generate(bits)?.into(),
KeyType::ECDSA => ecdsa::EcDsaKeyPair::generate(bits)?.into(),
KeyType::ED25519 => ed25519::Ed25519KeyPair::generate(bits)?.into(),
})
}
pub fn keytype(&self) -> KeyType {
match &self.key {
KeyPairType::RSA(_) => KeyType::RSA,
KeyPairType::DSA(_) => KeyType::DSA,
KeyPairType::ECDSA(_) => KeyType::ECDSA,
KeyPairType::ED25519(_) => KeyType::ED25519,
}
}
pub fn serialize_pem(&self, passphrase: Option<&[u8]>) -> OsshResult<String> {
Ok(stringify_pem_privkey(&self, passphrase)?)
}
pub fn serialize_pkcs8(&self, passphrase: Option<&[u8]>) -> OsshResult<String> {
Ok(serialize_pkcs8_privkey(&self, passphrase)?)
}
pub fn serialize_openssh(
&self,
passphrase: Option<&[u8]>,
cipher: Cipher,
) -> OsshResult<String> {
if let Some(passphrase) = passphrase {
Ok(serialize_ossh_privkey(self, passphrase, cipher, 0)?)
} else {
Ok(serialize_ossh_privkey(self, b"", Cipher::Null, 0)?)
}
}
pub fn comment(&self) -> &str {
&self.comment
}
pub fn comment_mut(&mut self) -> &mut String {
&mut self.comment
}
pub fn serialize_publickey(&self) -> OsshResult<String> {
serialize_ossh_pubkey(self, &self.comment)
}
pub fn clone_public_key(&self) -> Result<PublicKey, Error> {
let key = match &self.key {
KeyPairType::RSA(key) => PublicKeyType::RSA(key.clone_public_key()?),
KeyPairType::DSA(key) => PublicKeyType::DSA(key.clone_public_key()?),
KeyPairType::ECDSA(key) => PublicKeyType::ECDSA(key.clone_public_key()?),
KeyPairType::ED25519(key) => PublicKeyType::ED25519(key.clone_public_key()?),
};
Ok(PublicKey {
key,
comment: self.comment.clone(),
})
}
fn inner_key(&self) -> &dyn PrivateParts {
match &self.key {
KeyPairType::RSA(key) => key,
KeyPairType::DSA(key) => key,
KeyPairType::ECDSA(key) => key,
KeyPairType::ED25519(key) => key,
}
}
fn inner_key_pub(&self) -> &dyn PublicParts {
match &self.key {
KeyPairType::RSA(key) => key,
KeyPairType::DSA(key) => key,
KeyPairType::ECDSA(key) => key,
KeyPairType::ED25519(key) => key,
}
}
}
impl Key for KeyPair {
fn size(&self) -> usize {
self.inner_key().size()
}
fn keyname(&self) -> &'static str {
self.inner_key().keyname()
}
}
impl PublicParts for KeyPair {
fn verify(&self, data: &[u8], sig: &[u8]) -> Result<bool, Error> {
self.inner_key_pub().verify(data, sig)
}
fn blob(&self) -> Result<Vec<u8>, Error> {
self.inner_key_pub().blob()
}
}
impl PrivateParts for KeyPair {
fn sign(&self, data: &[u8]) -> Result<Vec<u8>, Error> {
self.inner_key().sign(data)
}
}
impl From<rsa::RsaKeyPair> for KeyPair {
fn from(inner: rsa::RsaKeyPair) -> KeyPair {
KeyPair {
key: KeyPairType::RSA(inner),
comment: String::new(),
}
}
}
impl From<dsa::DsaKeyPair> for KeyPair {
fn from(inner: dsa::DsaKeyPair) -> KeyPair {
KeyPair {
key: KeyPairType::DSA(inner),
comment: String::new(),
}
}
}
impl From<ecdsa::EcDsaKeyPair> for KeyPair {
fn from(inner: ecdsa::EcDsaKeyPair) -> KeyPair {
KeyPair {
key: KeyPairType::ECDSA(inner),
comment: String::new(),
}
}
}
impl From<ed25519::Ed25519KeyPair> for KeyPair {
fn from(inner: ed25519::Ed25519KeyPair) -> KeyPair {
KeyPair {
key: KeyPairType::ED25519(inner),
comment: String::new(),
}
}
}
pub trait Key {
fn size(&self) -> usize;
fn keyname(&self) -> &'static str;
}
pub trait PublicParts: Key {
fn verify(&self, data: &[u8], sig: &[u8]) -> OsshResult<bool>;
fn blob(&self) -> OsshResult<Vec<u8>>;
fn fingerprint(&self, hash: FingerprintHash) -> OsshResult<Vec<u8>> {
let b = self.blob()?;
Ok(hash.hash(&b))
}
}
pub trait PrivateParts: Key {
fn sign(&self, data: &[u8]) -> OsshResult<Vec<u8>>;
}