#[cfg(test)]
mod signature_hash_algorithm_test;
use std::fmt;
use crate::crypto::*;
use crate::error::*;
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum HashAlgorithm {
Md2 = 0, Md5 = 1, Sha1 = 2, Sha224 = 3,
Sha256 = 4,
Sha384 = 5,
Sha512 = 6,
Ed25519 = 8,
Unsupported,
}
impl From<u8> for HashAlgorithm {
fn from(val: u8) -> Self {
match val {
0 => HashAlgorithm::Md2,
1 => HashAlgorithm::Md5,
2 => HashAlgorithm::Sha1,
3 => HashAlgorithm::Sha224,
4 => HashAlgorithm::Sha256,
5 => HashAlgorithm::Sha384,
6 => HashAlgorithm::Sha512,
8 => HashAlgorithm::Ed25519,
_ => HashAlgorithm::Unsupported,
}
}
}
impl fmt::Display for HashAlgorithm {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
HashAlgorithm::Md2 => write!(f, "md2"),
HashAlgorithm::Md5 => write!(f, "md5"), HashAlgorithm::Sha1 => write!(f, "sha-1"), HashAlgorithm::Sha224 => write!(f, "sha-224"), HashAlgorithm::Sha256 => write!(f, "sha-256"), HashAlgorithm::Sha384 => write!(f, "sha-384"), HashAlgorithm::Sha512 => write!(f, "sha-512"), HashAlgorithm::Ed25519 => write!(f, "null"), _ => write!(f, "unknown or unsupported hash algorithm"),
}
}
}
impl HashAlgorithm {
pub(crate) fn insecure(&self) -> bool {
matches!(
*self,
HashAlgorithm::Md2 | HashAlgorithm::Md5 | HashAlgorithm::Sha1
)
}
pub(crate) fn invalid(&self) -> bool {
matches!(*self, HashAlgorithm::Md2)
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum SignatureAlgorithm {
Rsa = 1,
Ecdsa = 3,
Ed25519 = 7,
Unsupported,
}
impl From<u8> for SignatureAlgorithm {
fn from(val: u8) -> Self {
match val {
1 => SignatureAlgorithm::Rsa,
3 => SignatureAlgorithm::Ecdsa,
7 => SignatureAlgorithm::Ed25519,
_ => SignatureAlgorithm::Unsupported,
}
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct SignatureHashAlgorithm {
pub hash: HashAlgorithm,
pub signature: SignatureAlgorithm,
}
impl SignatureHashAlgorithm {
pub(crate) fn is_compatible(&self, private_key: &CryptoPrivateKey) -> bool {
match &private_key.kind {
CryptoPrivateKeyKind::Ed25519(_) => self.signature == SignatureAlgorithm::Ed25519,
CryptoPrivateKeyKind::Ecdsa256(_) => self.signature == SignatureAlgorithm::Ecdsa,
CryptoPrivateKeyKind::Rsa256(_) => self.signature == SignatureAlgorithm::Rsa,
}
}
}
pub(crate) fn default_signature_schemes() -> Vec<SignatureHashAlgorithm> {
vec![
SignatureHashAlgorithm {
hash: HashAlgorithm::Sha256,
signature: SignatureAlgorithm::Ecdsa,
},
SignatureHashAlgorithm {
hash: HashAlgorithm::Sha384,
signature: SignatureAlgorithm::Ecdsa,
},
SignatureHashAlgorithm {
hash: HashAlgorithm::Sha512,
signature: SignatureAlgorithm::Ecdsa,
},
SignatureHashAlgorithm {
hash: HashAlgorithm::Sha256,
signature: SignatureAlgorithm::Rsa,
},
SignatureHashAlgorithm {
hash: HashAlgorithm::Sha384,
signature: SignatureAlgorithm::Rsa,
},
SignatureHashAlgorithm {
hash: HashAlgorithm::Sha512,
signature: SignatureAlgorithm::Rsa,
},
SignatureHashAlgorithm {
hash: HashAlgorithm::Ed25519,
signature: SignatureAlgorithm::Ed25519,
},
]
}
pub(crate) fn select_signature_scheme(
sigs: &[SignatureHashAlgorithm],
private_key: &CryptoPrivateKey,
) -> Result<SignatureHashAlgorithm> {
for ss in sigs {
if ss.is_compatible(private_key) {
return Ok(*ss);
}
}
Err(Error::ErrNoAvailableSignatureSchemes)
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum SignatureScheme {
Pkcs1WithSha256 = 0x0401,
Pkcs1WithSha384 = 0x0501,
Pkcs1WithSha512 = 0x0601,
PssWithSha256 = 0x0804,
PssWithSha384 = 0x0805,
PssWithSha512 = 0x0806,
EcdsaWithP256AndSha256 = 0x0403,
EcdsaWithP384AndSha384 = 0x0503,
EcdsaWithP521AndSha512 = 0x0603,
Ed25519 = 0x0807,
Pkcs1WithSha1 = 0x0201,
EcdsaWithSha1 = 0x0203,
}
pub(crate) fn parse_signature_schemes(
sigs: &[u16],
insecure_hashes: bool,
) -> Result<Vec<SignatureHashAlgorithm>> {
if sigs.is_empty() {
return Ok(default_signature_schemes());
}
let mut out = vec![];
for ss in sigs {
let sig: SignatureAlgorithm = ((*ss & 0xFF) as u8).into();
if sig == SignatureAlgorithm::Unsupported {
return Err(Error::ErrInvalidSignatureAlgorithm);
}
let h: HashAlgorithm = (((*ss >> 8) & 0xFF) as u8).into();
if h == HashAlgorithm::Unsupported || h.invalid() {
return Err(Error::ErrInvalidHashAlgorithm);
}
if h.insecure() && !insecure_hashes {
continue;
}
out.push(SignatureHashAlgorithm {
hash: h,
signature: sig,
})
}
if out.is_empty() {
Err(Error::ErrNoAvailableSignatureSchemes)
} else {
Ok(out)
}
}