x509_parser/
cri_attributes.rs1use crate::{
2 error::{X509Error, X509Result},
3 extensions::X509Extension,
4};
5
6use asn1_rs::{Error, FromDer, Header, Oid, Sequence, Tag};
7use nom::combinator::{all_consuming, complete};
8use nom::multi::many0;
9use nom::Err;
10use oid_registry::*;
11use std::collections::HashMap;
12
13#[derive(Clone, Debug, PartialEq)]
15pub struct X509CriAttribute<'a> {
16 pub oid: Oid<'a>,
17 pub value: &'a [u8],
18 pub(crate) parsed_attribute: ParsedCriAttribute<'a>,
19}
20
21impl<'a> FromDer<'a, X509Error> for X509CriAttribute<'a> {
22 fn from_der(i: &'a [u8]) -> X509Result<'a, X509CriAttribute<'a>> {
23 Sequence::from_ber_and_then(i, |i| {
24 let (i, oid) = Oid::from_der(i)?;
25 let value_start = i;
26 let (i, hdr) = Header::from_der(i)?;
27 if hdr.tag() != Tag::Set {
28 return Err(Err::Error(Error::BerTypeError));
29 };
30
31 let (i, parsed_attribute) =
32 parser::parse_attribute(i, &oid).map_err(|_| Err::Error(Error::BerValueError))?;
33 let attribute = X509CriAttribute {
34 oid,
35 value: &value_start[..value_start.len() - i.len()],
36 parsed_attribute,
37 };
38 Ok((i, attribute))
39 })
40 .map_err(|_| X509Error::InvalidAttributes.into())
41 }
42}
43
44impl<'a> X509CriAttribute<'a> {
45 #[inline]
47 pub fn parsed_attribute(&self) -> &ParsedCriAttribute<'a> {
48 &self.parsed_attribute
49 }
50}
51
52#[derive(Clone, Debug, PartialEq)]
54pub struct ExtensionRequest<'a> {
55 pub extensions: Vec<X509Extension<'a>>,
56}
57
58impl<'a> FromDer<'a, X509Error> for ExtensionRequest<'a> {
59 fn from_der(i: &'a [u8]) -> X509Result<'a, Self> {
60 parser::parse_extension_request(i).map_err(Err::convert)
61 }
62}
63
64#[derive(Clone, Debug, Eq, PartialEq)]
65pub struct ChallengePassword(pub String);
66
67#[derive(Clone, Debug, PartialEq)]
69pub enum ParsedCriAttribute<'a> {
70 ChallengePassword(ChallengePassword),
71 ExtensionRequest(ExtensionRequest<'a>),
72 UnsupportedAttribute,
73}
74
75pub(crate) mod parser {
76 use crate::cri_attributes::*;
77 use der_parser::der::{
78 parse_der_bmpstring, parse_der_printablestring, parse_der_t61string,
79 parse_der_universalstring, parse_der_utf8string,
80 };
81 use lazy_static::lazy_static;
82 use nom::branch::alt;
83 use nom::combinator::map;
84
85 type AttrParser = fn(&[u8]) -> X509Result<ParsedCriAttribute>;
86
87 lazy_static! {
88 static ref ATTRIBUTE_PARSERS: HashMap<Oid<'static>, AttrParser> = {
89 macro_rules! add {
90 ($m:ident, $oid:ident, $p:ident) => {
91 $m.insert($oid, $p as AttrParser);
92 };
93 }
94
95 let mut m = HashMap::new();
96 add!(m, OID_PKCS9_EXTENSION_REQUEST, parse_extension_request_attr);
97 add!(
98 m,
99 OID_PKCS9_CHALLENGE_PASSWORD,
100 parse_challenge_password_attr
101 );
102 m
103 };
104 }
105
106 pub(crate) fn parse_attribute<'a>(
109 i: &'a [u8],
110 oid: &Oid,
111 ) -> X509Result<'a, ParsedCriAttribute<'a>> {
112 if let Some(parser) = ATTRIBUTE_PARSERS.get(oid) {
113 parser(i)
114 } else {
115 Ok((i, ParsedCriAttribute::UnsupportedAttribute))
116 }
117 }
118
119 pub(super) fn parse_extension_request(i: &[u8]) -> X509Result<ExtensionRequest> {
120 crate::extensions::parse_extension_sequence(i)
121 .map(|(i, extensions)| (i, ExtensionRequest { extensions }))
122 }
123
124 fn parse_extension_request_attr(i: &[u8]) -> X509Result<ParsedCriAttribute> {
125 map(
126 parse_extension_request,
127 ParsedCriAttribute::ExtensionRequest,
128 )(i)
129 }
130
131 pub(super) fn parse_challenge_password(i: &[u8]) -> X509Result<ChallengePassword> {
147 let (rem, obj) = match alt((
148 parse_der_utf8string,
149 parse_der_printablestring,
150 parse_der_universalstring,
151 parse_der_bmpstring,
152 parse_der_t61string, ))(i)
154 {
155 Ok((rem, obj)) => (rem, obj),
156 Err(_) => return Err(Err::Error(X509Error::InvalidAttributes)),
157 };
158 match obj.content.as_str() {
159 Ok(s) => Ok((rem, ChallengePassword(s.to_string()))),
160 Err(_) => Err(Err::Error(X509Error::InvalidAttributes)),
161 }
162 }
163
164 fn parse_challenge_password_attr(i: &[u8]) -> X509Result<ParsedCriAttribute> {
165 map(
166 parse_challenge_password,
167 ParsedCriAttribute::ChallengePassword,
168 )(i)
169 }
170}
171
172pub(crate) fn parse_cri_attributes(i: &[u8]) -> X509Result<Vec<X509CriAttribute>> {
173 let (i, hdr) = Header::from_der(i).map_err(|_| Err::Error(X509Error::InvalidAttributes))?;
174 if hdr.is_contextspecific() && hdr.tag().0 == 0 {
175 all_consuming(many0(complete(X509CriAttribute::from_der)))(i)
176 } else {
177 Err(Err::Error(X509Error::InvalidAttributes))
178 }
179}