use crate::error::X509Error;
use crate::x509::AlgorithmIdentifier;
use asn1_rs::{
oid, Any, CheckDerConstraints, Class, DerAutoDerive, Error, FromDer, Oid, OptTaggedExplicit,
OptTaggedParser, Tag,
};
use core::convert::TryFrom;
use oid_registry::*;
#[allow(non_camel_case_types)]
#[derive(Debug, PartialEq)]
pub enum SignatureAlgorithm<'a> {
RSA,
RSASSA_PSS(Box<RsaSsaPssParams<'a>>),
RSAAES_OAEP(Box<RsaAesOaepParams<'a>>),
DSA,
ECDSA,
ED25519,
}
impl<'a, 'b> TryFrom<&'b AlgorithmIdentifier<'a>> for SignatureAlgorithm<'a> {
type Error = X509Error;
fn try_from(value: &'b AlgorithmIdentifier<'a>) -> Result<Self, Self::Error> {
if value.algorithm.starts_with(&oid! {1.2.840.113549.1.1}) {
if value.algorithm == OID_PKCS1_RSASSAPSS {
let params = match value.parameters.as_ref() {
Some(any) => any,
None => return Err(X509Error::InvalidSignatureValue),
};
let params = RsaSsaPssParams::try_from(params)
.map_err(|_| X509Error::InvalidSignatureValue)?;
Ok(SignatureAlgorithm::RSASSA_PSS(Box::new(params)))
} else {
Ok(SignatureAlgorithm::RSA)
}
} else if test_ecdsa_oid(&value.algorithm) {
Ok(SignatureAlgorithm::ECDSA)
} else if value.algorithm.starts_with(&oid! {1.2.840.10040.4}) {
Ok(SignatureAlgorithm::DSA)
} else if value.algorithm == OID_SIG_ED25519 {
Ok(SignatureAlgorithm::ED25519)
} else if value.algorithm == oid! {1.2.840.113549.1.1.7} {
let params = match value.parameters.as_ref() {
Some(any) => any,
None => return Err(X509Error::InvalidSignatureValue),
};
let params =
RsaAesOaepParams::try_from(params).map_err(|_| X509Error::InvalidSignatureValue)?;
Ok(SignatureAlgorithm::RSAAES_OAEP(Box::new(params)))
} else {
if cfg!(debug_assertions) {
eprintln!("bad Signature AlgorithmIdentifier: {}", value.algorithm);
}
Err(X509Error::InvalidSignatureValue)
}
}
}
#[inline]
fn test_ecdsa_oid(oid: &Oid) -> bool {
oid.starts_with(&oid! {1.2.840.10045.4})
}
#[derive(Debug, PartialEq)]
pub struct RsaSsaPssParams<'a> {
hash_alg: Option<AlgorithmIdentifier<'a>>,
mask_gen_algorithm: Option<AlgorithmIdentifier<'a>>,
salt_length: Option<u32>,
trailer_field: Option<u32>,
}
impl<'a> RsaSsaPssParams<'a> {
pub fn hash_algorithm(&self) -> Option<&AlgorithmIdentifier> {
self.hash_alg.as_ref()
}
pub fn hash_algorithm_oid(&self) -> &'a Oid {
const SHA1: &Oid = &OID_HASH_SHA1;
self.hash_alg
.as_ref()
.map(|alg| &alg.algorithm)
.unwrap_or(SHA1)
}
pub fn mask_gen_algorithm_raw(&self) -> Option<&AlgorithmIdentifier> {
self.mask_gen_algorithm.as_ref()
}
pub fn mask_gen_algorithm(&self) -> Result<MaskGenAlgorithm, X509Error> {
match self.mask_gen_algorithm.as_ref() {
Some(alg) => {
let (_, hash) = alg
.parameters()
.and_then(|any| Oid::from_der(any.data).ok())
.ok_or(X509Error::InvalidAlgorithmIdentifier)?;
Ok(MaskGenAlgorithm::new(alg.algorithm.clone(), hash))
}
_ => {
Ok(MaskGenAlgorithm::new(
oid! {1.2.840.113549.1.1.8}, OID_HASH_SHA1,
))
}
}
}
pub fn salt_length(&self) -> u32 {
self.salt_length.unwrap_or(20)
}
pub fn trailer_field(&self) -> u32 {
self.trailer_field.unwrap_or(1)
}
}
impl<'a> TryFrom<Any<'a>> for RsaSsaPssParams<'a> {
type Error = X509Error;
fn try_from(value: Any<'a>) -> Result<Self, Self::Error> {
Self::try_from(&value)
}
}
impl<'a, 'b> TryFrom<&'b Any<'a>> for RsaSsaPssParams<'a> {
type Error = X509Error;
fn try_from(value: &'b Any<'a>) -> Result<Self, Self::Error> {
value.tag().assert_eq(Tag::Sequence)?;
let i = &value.data;
let (i, hash_alg) = OptTaggedParser::new(Class::ContextSpecific, Tag(0))
.parse_der(i, |_, inner| AlgorithmIdentifier::from_der(inner))?;
let (i, mask_gen_algorithm) = OptTaggedParser::new(Class::ContextSpecific, Tag(1))
.parse_der(i, |_, inner| AlgorithmIdentifier::from_der(inner))?;
let (i, salt_length) = OptTaggedExplicit::<_, Error, 2>::from_der(i)?;
let (_, trailer_field) = OptTaggedExplicit::<_, Error, 3>::from_der(i)?;
let params = RsaSsaPssParams {
hash_alg,
mask_gen_algorithm,
salt_length: salt_length.map(|t| t.into_inner()),
trailer_field: trailer_field.map(|t| t.into_inner()),
};
Ok(params)
}
}
impl CheckDerConstraints for RsaSsaPssParams<'_> {
fn check_constraints(any: &Any) -> asn1_rs::Result<()> {
any.header.assert_constructed()?;
Ok(())
}
}
impl DerAutoDerive for RsaSsaPssParams<'_> {}
#[derive(Debug, PartialEq, Eq)]
pub struct MaskGenAlgorithm<'a, 'b> {
pub mgf: Oid<'a>,
pub hash: Oid<'b>,
}
impl<'a, 'b> MaskGenAlgorithm<'a, 'b> {
pub const fn new(mgf: Oid<'a>, hash: Oid<'b>) -> Self {
Self { mgf, hash }
}
}
#[derive(Debug, PartialEq)]
pub struct RsaAesOaepParams<'a> {
hash_alg: Option<AlgorithmIdentifier<'a>>,
mask_gen_alg: Option<AlgorithmIdentifier<'a>>,
p_source_alg: Option<AlgorithmIdentifier<'a>>,
}
impl<'a> RsaAesOaepParams<'a> {
pub const EMPTY: &'static AlgorithmIdentifier<'static> = &AlgorithmIdentifier::new(
oid! {1.2.840.113549.1.1.9}, None,
);
pub fn hash_algorithm(&self) -> Option<&AlgorithmIdentifier> {
self.hash_alg.as_ref()
}
pub fn hash_algorithm_oid(&self) -> &'a Oid {
const SHA1: &Oid = &OID_HASH_SHA1;
self.hash_alg
.as_ref()
.map(|alg| &alg.algorithm)
.unwrap_or(SHA1)
}
pub fn mask_gen_algorithm_raw(&self) -> Option<&AlgorithmIdentifier> {
self.mask_gen_alg.as_ref()
}
pub fn mask_gen_algorithm(&self) -> Result<MaskGenAlgorithm, X509Error> {
match self.mask_gen_alg.as_ref() {
Some(alg) => {
let (_, hash) = alg
.parameters()
.and_then(|any| Oid::from_der(any.data).ok())
.ok_or(X509Error::InvalidAlgorithmIdentifier)?;
Ok(MaskGenAlgorithm::new(alg.algorithm.clone(), hash))
}
_ => {
Ok(MaskGenAlgorithm::new(
oid! {1.2.840.113549.1.1.8}, OID_HASH_SHA1,
))
}
}
}
pub fn p_source_alg(&'a self) -> &'a AlgorithmIdentifier {
self.p_source_alg.as_ref().unwrap_or(Self::EMPTY)
}
}
impl<'a> TryFrom<Any<'a>> for RsaAesOaepParams<'a> {
type Error = X509Error;
fn try_from(value: Any<'a>) -> Result<Self, Self::Error> {
Self::try_from(&value)
}
}
impl<'a, 'b> TryFrom<&'b Any<'a>> for RsaAesOaepParams<'a> {
type Error = X509Error;
fn try_from(value: &'b Any<'a>) -> Result<Self, Self::Error> {
value.tag().assert_eq(Tag::Sequence)?;
let i = &value.data;
let (i, hash_alg) = OptTaggedParser::new(Class::ContextSpecific, Tag(0))
.parse_der(i, |_, inner| AlgorithmIdentifier::from_der(inner))?;
let (i, mask_gen_alg) = OptTaggedParser::new(Class::ContextSpecific, Tag(1))
.parse_der(i, |_, inner| AlgorithmIdentifier::from_der(inner))?;
let (_, p_source_alg) = OptTaggedParser::new(Class::ContextSpecific, Tag(2))
.parse_der(i, |_, inner| AlgorithmIdentifier::from_der(inner))?;
let params = RsaAesOaepParams {
hash_alg,
mask_gen_alg,
p_source_alg,
};
Ok(params)
}
}
impl CheckDerConstraints for RsaAesOaepParams<'_> {
fn check_constraints(any: &Any) -> asn1_rs::Result<()> {
any.header.assert_constructed()?;
Ok(())
}
}
impl DerAutoDerive for RsaAesOaepParams<'_> {}