x509-parser 0.9.2

Parser for the X.509 v3 format (RFC 5280 certificates)
Documentation
use crate::{
    error::{X509Error, X509Result},
    extensions::X509Extension,
};

use der_parser::der::{
    der_read_element_header, parse_der_oid, parse_der_sequence_defined_g, DerTag,
};
use der_parser::error::BerError;
use der_parser::oid::Oid;
use nom::combinator::map_res;
use nom::Err;
use oid_registry::*;
use std::collections::HashMap;

/// Attributes for Certification Request
#[derive(Debug, PartialEq)]
pub struct X509CriAttribute<'a> {
    pub oid: Oid<'a>,
    pub value: &'a [u8],
    pub(crate) parsed_attribute: ParsedCriAttribute<'a>,
}

impl<'a> X509CriAttribute<'a> {
    pub fn from_der(i: &'a [u8]) -> X509Result<X509CriAttribute> {
        parse_der_sequence_defined_g(|i, _| {
            let (i, oid) = map_res(parse_der_oid, |x| x.as_oid_val())(i)?;
            let value_start = i;
            let (i, hdr) = der_read_element_header(i)?;
            if hdr.tag != DerTag::Set {
                return Err(Err::Error(BerError::BerTypeError));
            };

            let (i, parsed_attribute) = crate::cri_attributes::parser::parse_attribute(i, &oid)?;
            let ext = X509CriAttribute {
                oid,
                value: &value_start[..value_start.len() - i.len()],
                parsed_attribute,
            };
            Ok((i, ext))
        })(i)
        .map_err(|_| X509Error::InvalidAttributes.into())
    }
}

/// Section 3.1 of rfc 5272
#[derive(Debug, PartialEq)]
pub struct ExtensionRequest<'a> {
    pub extensions: HashMap<Oid<'a>, X509Extension<'a>>,
}

/// Attributes for Certification Request
#[derive(Debug, PartialEq)]
pub enum ParsedCriAttribute<'a> {
    ExtensionRequest(ExtensionRequest<'a>),
    UnsupportedAttribute,
}

pub(crate) mod parser {
    use crate::cri_attributes::*;
    use der_parser::error::BerError;
    use der_parser::{oid::Oid, *};
    use lazy_static::lazy_static;
    use nom::{Err, IResult};

    type AttrParser = fn(&[u8]) -> IResult<&[u8], ParsedCriAttribute, BerError>;

    lazy_static! {
        static ref ATTRIBUTE_PARSERS: HashMap<Oid<'static>, AttrParser> = {
            macro_rules! add {
                ($m:ident, $oid:ident, $p:ident) => {
                    $m.insert($oid, $p as AttrParser);
                };
            }

            let mut m = HashMap::new();
            add!(m, OID_PKCS9_EXTENSION_REQUEST, parse_extension_request);
            m
        };
    }

    // look into the parser map if the extension is known, and parse it
    // otherwise, leave it as UnsupportedExtension
    pub(crate) fn parse_attribute<'a>(
        i: &'a [u8],
        oid: &Oid,
    ) -> IResult<&'a [u8], ParsedCriAttribute<'a>, BerError> {
        if let Some(parser) = ATTRIBUTE_PARSERS.get(oid) {
            parser(i)
        } else {
            Ok((i, ParsedCriAttribute::UnsupportedAttribute))
        }
    }

    fn parse_extension_request(i: &[u8]) -> IResult<&[u8], ParsedCriAttribute, BerError> {
        crate::extensions::parse_extension_sequence(i)
            .and_then(|(i, extensions)| {
                crate::extensions::extensions_sequence_to_map(i, extensions)
            })
            .map(|(i, extensions)| {
                (
                    i,
                    ParsedCriAttribute::ExtensionRequest(ExtensionRequest { extensions }),
                )
            })
            .map_err(|_| Err::Error(BerError::BerTypeError))
    }
}

fn attributes_sequence_to_map<'a>(
    i: &'a [u8],
    v: Vec<X509CriAttribute<'a>>,
) -> X509Result<'a, HashMap<Oid<'a>, X509CriAttribute<'a>>> {
    let mut attributes = HashMap::new();
    for attr in v.into_iter() {
        if attributes.insert(attr.oid.clone(), attr).is_some() {
            // duplicate attributes are not allowed
            return Err(Err::Failure(X509Error::DuplicateAttributes));
        }
    }
    Ok((i, attributes))
}

pub(crate) fn parse_cri_attributes(i: &[u8]) -> X509Result<HashMap<Oid, X509CriAttribute>> {
    let (i, hdr) = der_read_element_header(i).or(Err(Err::Error(X509Error::InvalidAttributes)))?;
    if i.is_empty() {
        return Ok((i, HashMap::new()));
    }
    (0..hdr.structured)
        .into_iter()
        .try_fold((i, Vec::new()), |(i, mut attrs), _| {
            let (rem, attr) = X509CriAttribute::from_der(i)?;
            attrs.push(attr);
            Ok((rem, attrs))
        })
        .and_then(|(i, attrs)| attributes_sequence_to_map(i, attrs))
}