use crate::error::{Result, Error};
use crate::pubkey::{Privkey, Pubkey};
pub use self::openssh::{
OpensshKeypair, OpensshKeypairNopass,
decode_openssh_pem_keypair, decode_openssh_binary_keypair,
decode_openssh_pem_keypair_nopass, decode_openssh_binary_keypair_nopass,
};
pub use self::pkcs1::{
decode_pkcs1_pem_privkey_nopass, decode_pkcs1_der_privkey,
decode_pkcs1_pem_pubkey, decode_pkcs1_der_pubkey,
};
pub use self::pkcs8::{
decode_pkcs8_pem_privkey, decode_pkcs8_der_privkey, decode_pkcs8_encrypted_der_privkey,
decode_pkcs8_pem_pubkey, decode_pkcs8_der_pubkey,
};
mod openssh;
mod pkcs1;
mod pkcs8;
fn decode_pem(pem_data: &[u8], expected_tag: &'static str) -> Result<Vec<u8>> {
let pem = pem::parse(pem_data).map_err(Error::Pem)?;
if pem.tag() != expected_tag {
return Err(Error::BadPemTag(pem.tag().into(), expected_tag.into()))
}
Ok(pem.into_contents())
}
pub fn decode_pem_privkey(pem_data: &[u8], passphrase: &[u8]) -> Result<Privkey> {
let pem = pem::parse(pem_data).map_err(Error::Pem)?;
match pem.tag() {
"OPENSSH PRIVATE KEY" => decode_openssh_binary_keypair(pem.into_contents().into(), passphrase)
.map(|keypair| keypair.privkey),
"RSA PRIVATE KEY" => decode_pkcs1_der_privkey(pem.contents()).map(Privkey::Rsa),
"PRIVATE KEY" => decode_pkcs8_der_privkey(pem.contents()),
"ENCRYPTED PRIVATE KEY" => decode_pkcs8_encrypted_der_privkey(pem.contents(), passphrase),
_ => Err(Error::UnknownPemTag(pem.tag().into())),
}
}
#[derive(Clone, PartialEq, Eq)]
#[cfg_attr(feature = "debug-less-secure", derive(Debug))]
pub enum DecodedPrivkeyNopass {
Privkey(Privkey),
Pubkey(Pubkey),
Encrypted,
}
impl DecodedPrivkeyNopass {
pub fn privkey(&self) -> Option<&Privkey> {
match self {
Self::Privkey(privkey) => Some(privkey),
Self::Pubkey(_) | Self::Encrypted => None,
}
}
pub fn pubkey(&self) -> Option<Pubkey> {
match self {
Self::Privkey(privkey) => Some(privkey.pubkey()),
Self::Pubkey(pubkey) => Some(pubkey.clone()),
Self::Encrypted => None,
}
}
}
pub fn decode_pem_privkey_nopass(pem_data: &[u8]) -> Result<DecodedPrivkeyNopass> {
let pem = pem::parse(pem_data).map_err(Error::Pem)?;
match pem.tag() {
"OPENSSH PRIVATE KEY" =>
decode_openssh_binary_keypair_nopass(pem.into_contents().into()).map(|keypair| {
match keypair.privkey {
Some(privkey) => DecodedPrivkeyNopass::Privkey(privkey),
None => DecodedPrivkeyNopass::Pubkey(keypair.pubkey),
}
}),
"RSA PRIVATE KEY" => decode_pkcs1_der_privkey(pem.contents())
.map(|privkey| DecodedPrivkeyNopass::Privkey(Privkey::Rsa(privkey))),
"PRIVATE KEY" => decode_pkcs8_der_privkey(pem.contents())
.map(DecodedPrivkeyNopass::Privkey),
"ENCRYPTED PRIVATE KEY" => Ok(DecodedPrivkeyNopass::Encrypted),
_ => Err(Error::UnknownPemTag(pem.tag().into())),
}
}
pub fn decode_pem_pubkey(pem_data: &[u8]) -> Result<Pubkey> {
let pem = pem::parse(pem_data).map_err(Error::Pem)?;
match pem.tag() {
"RSA PUBLIC KEY" => decode_pkcs1_der_pubkey(pem.contents()).map(Pubkey::Rsa),
"PUBLIC KEY" => decode_pkcs8_der_pubkey(pem.contents()),
_ => Err(Error::UnknownPemTag(pem.tag().into())),
}
}