nzcp 1.0.2

An implementation of NZ COVID verification, New Zealand's proof of COVID-19 vaccination solution
Documentation
use std::fmt;

use serde::{
    de::{self, Error, Visitor},
    Deserialize, Deserializer,
};

use super::signature::SignatureAlgorithm;

const KID_KEY: u8 = 4;
const ALG_KEY: u8 = 1;

#[derive(Debug, PartialEq, Eq)]
pub struct ProtectedHeaders<'a> {
    pub kid: &'a str,
    pub algorithm: SignatureAlgorithm,
}

struct ProtectedHeadersVisitor;

impl<'de> Visitor<'de> for ProtectedHeadersVisitor {
    type Value = ProtectedHeaders<'de>;

    fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
        formatter.write_str("COSE protected headers")
    }

    fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
    where
        A: de::MapAccess<'de>,
    {
        let mut kid = None;
        let mut algorithm = None;

        while let Some(key) = map.next_key()? {
            match key {
                KID_KEY => kid = Some(map.next_value()?),
                ALG_KEY => algorithm = Some(map.next_value::<i8>()?.try_into().map_err(A::Error::custom)?),
                _ => return Err(A::Error::unknown_field(&format!("{}", key), &["4 (kid)", "1 (alg)"])),
            }
        }

        match (kid, algorithm) {
            (Some(kid), Some(algorithm)) => Ok(ProtectedHeaders { kid, algorithm }),
            (_, None) => Err(A::Error::missing_field("1 (alg)")),
            (None, _) => Err(A::Error::missing_field("4 (kid)")),
        }
    }
}

impl<'de: 'a, 'a> Deserialize<'de> for ProtectedHeaders<'a> {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        deserializer.deserialize_map(ProtectedHeadersVisitor)
    }
}