use bit_vec::BitVec;
use yasna::{ASN1Error, ASN1ErrorKind, ASN1Result, BERDecodable, BERReader, DERWriter, Tag};
use crate::{
types::{AlgorithmIdentifierOwned, DerAnyOwned},
DerWrite,
};
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub enum ProofOfPossession {
RaVerified(()),
Signature(PopoSigningKey),
KeyEncipherment(POPOPrivKey),
KeyAgreement(POPOPrivKey),
}
impl ProofOfPossession {
const TAG_RA_VERIFIED: u64 = 0;
const TAG_SIGNATURE: u64 = 1;
const TAG_KEY_ENCIPHERMENT: u64 = 2;
const TAG_KEY_AGREEMENT: u64 = 3;
fn tag(&self) -> Tag {
match self {
ProofOfPossession::RaVerified(_) => Tag::context(Self::TAG_RA_VERIFIED),
ProofOfPossession::Signature(_) => Tag::context(Self::TAG_SIGNATURE),
ProofOfPossession::KeyEncipherment(_) => Tag::context(Self::TAG_KEY_ENCIPHERMENT),
ProofOfPossession::KeyAgreement(_) => Tag::context(Self::TAG_KEY_AGREEMENT),
}
}
}
impl DerWrite for ProofOfPossession {
fn write(&self, writer: DERWriter) {
match self {
ProofOfPossession::RaVerified(()) => writer.write_tagged_implicit(self.tag(), |w| w.write_null()),
ProofOfPossession::Signature(key) => writer.write_tagged_implicit(self.tag(), |w| key.write(w)),
ProofOfPossession::KeyEncipherment(key) => writer.write_tagged_implicit(self.tag(), |w| key.write(w)),
ProofOfPossession::KeyAgreement(key) => writer.write_tagged_implicit(self.tag(), |w| key.write(w)),
}
}
}
impl BERDecodable for ProofOfPossession {
fn decode_ber(reader: BERReader) -> ASN1Result<Self> {
let tag_number = reader.lookahead_tag()?.tag_number;
reader.read_tagged_implicit(Tag::context(tag_number), |r| match tag_number {
Self::TAG_RA_VERIFIED => Ok(ProofOfPossession::RaVerified(r.read_null()?)),
Self::TAG_SIGNATURE => Ok(ProofOfPossession::Signature(PopoSigningKey::decode_ber(r)?)),
Self::TAG_KEY_ENCIPHERMENT => Ok(ProofOfPossession::KeyEncipherment(POPOPrivKey::decode_ber(r)?)),
Self::TAG_KEY_AGREEMENT => Ok(ProofOfPossession::KeyAgreement(POPOPrivKey::decode_ber(r)?)),
_ => Err(ASN1Error::new(ASN1ErrorKind::Invalid)),
})
}
}
type POPOPrivKey = DerAnyOwned;
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub struct PopoSigningKey {
pub poposk_input: Option<PopoSigningKeyInput>,
pub alg_id: AlgorithmIdentifierOwned,
pub signature: BitVec,
}
impl PopoSigningKey {
const TAG_POPOSK_INPUT: u64 = 0;
}
impl DerWrite for PopoSigningKey {
fn write(&self, writer: DERWriter) {
writer.write_sequence(|writer| {
if let Some(poposk_input) = self.poposk_input.as_ref() {
writer
.next()
.write_tagged_implicit(Tag::context(Self::TAG_POPOSK_INPUT), |w| poposk_input.write(w))
};
self.alg_id.write(writer.next());
self.signature.write(writer.next());
});
}
}
impl BERDecodable for PopoSigningKey {
fn decode_ber(reader: BERReader) -> ASN1Result<Self> {
reader.read_sequence(|reader| {
let poposk_input: Option<PopoSigningKeyInput> = reader.read_optional(|reader| {
let tag_number = reader.lookahead_tag()?.tag_number;
reader.read_tagged_implicit(Tag::context(tag_number), |reader| match tag_number {
Self::TAG_POPOSK_INPUT => Ok(PopoSigningKeyInput::decode_ber(reader)?),
_ => Err(ASN1Error::new(ASN1ErrorKind::Invalid)),
})
})?;
let alg_id = AlgorithmIdentifierOwned::decode_ber(reader.next())?;
let signature = BitVec::decode_ber(reader.next())?;
Ok(PopoSigningKey {
poposk_input,
alg_id,
signature,
})
})
}
}
pub type PopoSigningKeyInput = DerAnyOwned;