blob: 410bf45d545d34081d8fca3efc937d69d469f50c [file] [log] [blame]
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))
}