macro_rules! impl_algorithm_serializers {
($alg:ident) => {
impl ::serde::Serialize for $alg {
fn serialize<S: ::serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
serializer.serialize_u8(self.to_u8())
}
}
impl<'de> ::serde::Deserialize<'de> for $alg {
fn deserialize<D: ::serde::de::Deserializer<'de>>(
deserializer: D,
) -> Result<$alg, D::Error> {
use serde::de::{self, Visitor};
use std::fmt;
struct AlgorithmVisitor;
impl<'de> Visitor<'de> for AlgorithmVisitor {
type Value = $alg;
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str("an unsigned tag byte")
}
fn visit_u8<E: de::Error>(self, value: u8) -> Result<$alg, E> {
$alg::from_u8(value).or_else(|e| Err(E::custom(format!("{}", e))))
}
}
deserializer.deserialize_u8(AlgorithmVisitor)
}
}
};
}
mod error;
pub use self::error::{AlgorithmError, AlgorithmErrorKind};
mod asymmetric;
mod authentication;
mod ecdsa;
mod hmac;
mod kex;
mod mgf;
mod opaque;
mod rsa;
mod template;
mod wrap;
mod yubico_otp;
pub use self::{
asymmetric::AsymmetricAlg, authentication::AuthenticationAlg, ecdsa::EcdsaAlg, hmac::HmacAlg,
kex::KexAlg, mgf::MgfAlg, opaque::OpaqueAlg, rsa::RsaAlg, template::TemplateAlg, wrap::WrapAlg,
yubico_otp::YubicoOtpAlg,
};
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[repr(u8)]
#[allow(non_camel_case_types)]
pub enum Algorithm {
Asymmetric(AsymmetricAlg),
Auth(AuthenticationAlg),
Ecdsa(EcdsaAlg),
Hmac(HmacAlg),
Kex(KexAlg),
Mgf(MgfAlg),
Opaque(OpaqueAlg),
Rsa(RsaAlg),
Template(TemplateAlg),
Wrap(WrapAlg),
YubicoOtp(YubicoOtpAlg),
}
impl Algorithm {
pub fn from_u8(byte: u8) -> Result<Self, AlgorithmError> {
Ok(match byte {
0x01..=0x08 | 0x19..=0x1c => Algorithm::Rsa(RsaAlg::from_u8(byte)?),
0x09..=0x12 | 0x2e | 0x2f => Algorithm::Asymmetric(AsymmetricAlg::from_u8(byte)?),
0x13..=0x16 => Algorithm::Hmac(HmacAlg::from_u8(byte)?),
0x17 | 0x2b..=0x2d => Algorithm::Ecdsa(EcdsaAlg::from_u8(byte)?),
0x18 => Algorithm::Kex(KexAlg::from_u8(byte)?),
0x1d | 0x29 | 0x2a => Algorithm::Wrap(WrapAlg::from_u8(byte)?),
0x1e | 0x1f => Algorithm::Opaque(OpaqueAlg::from_u8(byte)?),
0x20..=0x23 => Algorithm::Mgf(MgfAlg::from_u8(byte)?),
0x24 => Algorithm::Template(TemplateAlg::from_u8(byte)?),
0x25 | 0x27 | 0x28 => Algorithm::YubicoOtp(YubicoOtpAlg::from_u8(byte)?),
0x26 => Algorithm::Auth(AuthenticationAlg::from_u8(byte)?),
_ => fail!(
AlgorithmErrorKind::TagInvalid,
"unknown algorithm ID: 0x{:02x}",
byte
),
})
}
pub fn to_u8(self) -> u8 {
match self {
Algorithm::Asymmetric(alg) => alg.to_u8(),
Algorithm::Auth(alg) => alg.to_u8(),
Algorithm::Ecdsa(alg) => alg.to_u8(),
Algorithm::Hmac(alg) => alg.to_u8(),
Algorithm::Kex(alg) => alg.to_u8(),
Algorithm::Mgf(alg) => alg.to_u8(),
Algorithm::Opaque(alg) => alg.to_u8(),
Algorithm::YubicoOtp(alg) => alg.to_u8(),
Algorithm::Rsa(alg) => alg.to_u8(),
Algorithm::Template(alg) => alg.to_u8(),
Algorithm::Wrap(alg) => alg.to_u8(),
}
}
pub fn asymmetric(self) -> Option<AsymmetricAlg> {
match self {
Algorithm::Asymmetric(alg) => Some(alg),
_ => None,
}
}
pub fn auth(self) -> Option<AuthenticationAlg> {
match self {
Algorithm::Auth(alg) => Some(alg),
_ => None,
}
}
pub fn ecdsa(self) -> Option<EcdsaAlg> {
match self {
Algorithm::Ecdsa(alg) => Some(alg),
_ => None,
}
}
pub fn hmac(self) -> Option<HmacAlg> {
match self {
Algorithm::Hmac(alg) => Some(alg),
_ => None,
}
}
pub fn kex(self) -> Option<KexAlg> {
match self {
Algorithm::Kex(alg) => Some(alg),
_ => None,
}
}
pub fn mgf(self) -> Option<MgfAlg> {
match self {
Algorithm::Mgf(alg) => Some(alg),
_ => None,
}
}
pub fn opaque(self) -> Option<OpaqueAlg> {
match self {
Algorithm::Opaque(alg) => Some(alg),
_ => None,
}
}
pub fn otp(self) -> Option<YubicoOtpAlg> {
match self {
Algorithm::YubicoOtp(alg) => Some(alg),
_ => None,
}
}
pub fn rsa(self) -> Option<RsaAlg> {
match self {
Algorithm::Rsa(alg) => Some(alg),
_ => None,
}
}
pub fn template(self) -> Option<TemplateAlg> {
match self {
Algorithm::Template(alg) => Some(alg),
_ => None,
}
}
pub fn wrap(self) -> Option<WrapAlg> {
match self {
Algorithm::Wrap(alg) => Some(alg),
_ => None,
}
}
}
impl_algorithm_serializers!(Algorithm);
#[cfg(test)]
mod tests {
use super::*;
const ALGORITHM_MAPPING: &[(u8, Algorithm)] = &[
(0x01, Algorithm::Rsa(RsaAlg::PKCS1_SHA1)),
(0x02, Algorithm::Rsa(RsaAlg::PKCS1_SHA256)),
(0x03, Algorithm::Rsa(RsaAlg::PKCS1_SHA384)),
(0x04, Algorithm::Rsa(RsaAlg::PKCS1_SHA512)),
(0x05, Algorithm::Rsa(RsaAlg::PSS_SHA1)),
(0x06, Algorithm::Rsa(RsaAlg::PSS_SHA256)),
(0x07, Algorithm::Rsa(RsaAlg::PSS_SHA384)),
(0x08, Algorithm::Rsa(RsaAlg::PSS_SHA512)),
(0x09, Algorithm::Asymmetric(AsymmetricAlg::RSA_2048)),
(0x0a, Algorithm::Asymmetric(AsymmetricAlg::RSA_3072)),
(0x0b, Algorithm::Asymmetric(AsymmetricAlg::RSA_4096)),
(0x0c, Algorithm::Asymmetric(AsymmetricAlg::EC_P256)),
(0x0d, Algorithm::Asymmetric(AsymmetricAlg::EC_P384)),
(0x0e, Algorithm::Asymmetric(AsymmetricAlg::EC_P521)),
(0x0f, Algorithm::Asymmetric(AsymmetricAlg::EC_K256)),
(0x10, Algorithm::Asymmetric(AsymmetricAlg::EC_BP256)),
(0x11, Algorithm::Asymmetric(AsymmetricAlg::EC_BP384)),
(0x12, Algorithm::Asymmetric(AsymmetricAlg::EC_BP512)),
(0x13, Algorithm::Hmac(HmacAlg::SHA1)),
(0x14, Algorithm::Hmac(HmacAlg::SHA256)),
(0x15, Algorithm::Hmac(HmacAlg::SHA384)),
(0x16, Algorithm::Hmac(HmacAlg::SHA512)),
(0x17, Algorithm::Ecdsa(EcdsaAlg::SHA1)),
(0x18, Algorithm::Kex(KexAlg::ECDH)),
(0x19, Algorithm::Rsa(RsaAlg::OAEP_SHA1)),
(0x1a, Algorithm::Rsa(RsaAlg::OAEP_SHA256)),
(0x1b, Algorithm::Rsa(RsaAlg::OAEP_SHA384)),
(0x1c, Algorithm::Rsa(RsaAlg::OAEP_SHA512)),
(0x1d, Algorithm::Wrap(WrapAlg::AES128_CCM)),
(0x1e, Algorithm::Opaque(OpaqueAlg::DATA)),
(0x1f, Algorithm::Opaque(OpaqueAlg::X509_CERTIFICATE)),
(0x20, Algorithm::Mgf(MgfAlg::SHA1)),
(0x21, Algorithm::Mgf(MgfAlg::SHA256)),
(0x22, Algorithm::Mgf(MgfAlg::SHA384)),
(0x23, Algorithm::Mgf(MgfAlg::SHA512)),
(0x24, Algorithm::Template(TemplateAlg::SSH)),
(0x25, Algorithm::YubicoOtp(YubicoOtpAlg::AES128)),
(0x26, Algorithm::Auth(AuthenticationAlg::YUBICO_AES)),
(0x27, Algorithm::YubicoOtp(YubicoOtpAlg::AES192)),
(0x28, Algorithm::YubicoOtp(YubicoOtpAlg::AES256)),
(0x29, Algorithm::Wrap(WrapAlg::AES192_CCM)),
(0x2a, Algorithm::Wrap(WrapAlg::AES256_CCM)),
(0x2b, Algorithm::Ecdsa(EcdsaAlg::SHA256)),
(0x2c, Algorithm::Ecdsa(EcdsaAlg::SHA384)),
(0x2d, Algorithm::Ecdsa(EcdsaAlg::SHA512)),
(0x2e, Algorithm::Asymmetric(AsymmetricAlg::Ed25519)),
(0x2f, Algorithm::Asymmetric(AsymmetricAlg::EC_P224)),
];
#[test]
fn test_from_u8() {
for (tag, alg) in ALGORITHM_MAPPING {
assert_eq!(*alg, Algorithm::from_u8(*tag).unwrap());
}
}
#[test]
fn test_to_u8() {
for (tag, alg) in ALGORITHM_MAPPING {
assert_eq!(*tag, alg.to_u8());
}
}
}