use chrono::{DateTime, TimeZone, Utc};
use nom::{be_u16, be_u32, be_u8};
use num_traits::FromPrimitive;
use crate::crypto::ecc_curve::ecc_curve_from_oid;
use crate::crypto::{HashAlgorithm, PublicKeyAlgorithm, SymmetricKeyAlgorithm};
use crate::types::{mpi, KeyVersion, Mpi, MpiRef, PublicParams};
#[inline]
fn to_owned(mref: MpiRef<'_>) -> Mpi {
mref.to_owned()
}
#[rustfmt::skip]
named!(ecdsa<PublicParams>, do_parse!(
len: be_u8
>> curve: map_opt!(take!(len), ecc_curve_from_oid)
>> p: mpi
>> (PublicParams::ECDSA {
curve,
p: p.to_owned(),
})
));
#[rustfmt::skip]
named!(eddsa<PublicParams>, do_parse!(
len: be_u8
>> curve: map_opt!(take!(len), ecc_curve_from_oid)
>> q: mpi
>> (PublicParams::EdDSA {
curve,
q: q.to_owned(),
})
));
#[rustfmt::skip]
named!(ecdh<PublicParams>, do_parse!(
len: be_u8
>> curve: map_opt!(take!(len), ecc_curve_from_oid)
>> p: mpi
>> _len2: be_u8
>> tag!(&[1][..])
>> hash: map_opt!(be_u8, HashAlgorithm::from_u8)
>> alg_sym: map_opt!(be_u8, SymmetricKeyAlgorithm::from_u8)
>> (PublicParams::ECDH {
curve,
p: p.to_owned(),
hash,
alg_sym,
})
));
#[rustfmt::skip]
named!(elgamal<PublicParams>, do_parse!(
p: map!(mpi, to_owned)
>> g: map!(mpi, to_owned)
>> y: map!(mpi, to_owned)
>> (PublicParams::Elgamal{ p, g, y })
));
#[rustfmt::skip]
named!(dsa<PublicParams>, do_parse!(
p: map!(mpi, to_owned)
>> q: map!(mpi, to_owned)
>> g: map!(mpi, to_owned)
>> y: map!(mpi, to_owned)
>> (PublicParams::DSA { p, q, g, y })
));
#[rustfmt::skip]
named!(rsa<PublicParams>, do_parse!(
n: map!(mpi, to_owned)
>> e: map!(mpi, to_owned)
>> (PublicParams::RSA { n, e })
));
named_args!(pub parse_pub_fields(typ: PublicKeyAlgorithm) <PublicParams>, switch!(
value!(typ),
PublicKeyAlgorithm::RSA |
PublicKeyAlgorithm::RSAEncrypt |
PublicKeyAlgorithm::RSASign => call!(rsa) |
PublicKeyAlgorithm::DSA => call!(dsa) |
PublicKeyAlgorithm::ECDSA => call!(ecdsa) |
PublicKeyAlgorithm::ECDH => call!(ecdh) |
PublicKeyAlgorithm::Elgamal |
PublicKeyAlgorithm::ElgamalSign => call!(elgamal) |
PublicKeyAlgorithm::EdDSA => call!(eddsa)
));
named_args!(new_public_key_parser<'a>(key_ver: &'a KeyVersion) <(KeyVersion, PublicKeyAlgorithm, DateTime<Utc>, Option<u16>, PublicParams)>, do_parse!(
created_at: map!(be_u32, |v| Utc.timestamp(i64::from(v), 0))
>> alg: map_opt!(be_u8, PublicKeyAlgorithm::from_u8)
>> params: call!(parse_pub_fields, alg)
>> (*key_ver, alg, created_at, None, params)
));
named_args!(old_public_key_parser<'a>(key_ver: &'a KeyVersion) <(KeyVersion, PublicKeyAlgorithm, DateTime<Utc>, Option<u16>, PublicParams)>, do_parse!(
created_at: map!(be_u32, |v| Utc.timestamp(i64::from(v), 0))
>> exp: be_u16
>> alg: map_opt!(be_u8, PublicKeyAlgorithm::from_u8)
>> params: call!(parse_pub_fields, alg)
>> (*key_ver, alg, created_at, Some(exp), params)
));
#[rustfmt::skip]
named!(pub parse<(KeyVersion, PublicKeyAlgorithm, DateTime<Utc>, Option<u16>, PublicParams)>, do_parse!(
key_ver: map_opt!(be_u8, KeyVersion::from_u8)
>> key: switch!(value!(&key_ver),
&KeyVersion::V2 => call!(
old_public_key_parser, &key_ver
) |
&KeyVersion::V3 => call!(
old_public_key_parser, &key_ver
) |
&KeyVersion::V4 => call!(
new_public_key_parser, &key_ver
)
)
>> (key)
));