1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
use crate::error::X509Result;
use crate::traits::FromDer;
use der_parser::der::*;
use der_parser::error::BerError;
use der_parser::oid::Oid;
use nom::{Err, IResult};
use std::collections::HashMap;

#[derive(Clone, Debug, PartialEq)]
pub struct PolicyMappings<'a> {
    pub mappings: Vec<PolicyMapping<'a>>,
}

impl<'a> FromDer<'a> for PolicyMappings<'a> {
    fn from_der(i: &'a [u8]) -> X509Result<'a, Self> {
        parse_policymappings(i).map_err(Err::convert)
    }
}

impl<'a> PolicyMappings<'a> {
    /// Returns a `HashMap` mapping `Oid` to the list of references to `Oid`
    ///
    /// If several names match the same `Oid`, they are merged in the same entry.
    pub fn as_hashmap(&self) -> HashMap<Oid<'a>, Vec<&Oid<'a>>> {
        // create the hashmap and merge entries with same OID
        let mut m: HashMap<Oid, Vec<&_>> = HashMap::new();
        for desc in &self.mappings {
            let PolicyMapping {
                issuer_domain_policy: left,
                subject_domain_policy: right,
            } = desc;
            if let Some(l) = m.get_mut(left) {
                l.push(right);
            } else {
                m.insert(left.clone(), vec![right]);
            }
        }
        m
    }

    /// Returns a `HashMap` mapping `Oid` to the list of `Oid` (consuming the input)
    ///
    /// If several names match the same `Oid`, they are merged in the same entry.
    pub fn into_hashmap(self) -> HashMap<Oid<'a>, Vec<Oid<'a>>> {
        let mut l = self.mappings;
        // create the hashmap and merge entries with same OID
        let mut m: HashMap<Oid, Vec<_>> = HashMap::new();
        for mapping in l.drain(..) {
            let PolicyMapping {
                issuer_domain_policy: left,
                subject_domain_policy: right,
            } = mapping;
            if let Some(general_names) = m.get_mut(&left) {
                general_names.push(right);
            } else {
                m.insert(left, vec![right]);
            }
        }
        m
    }
}

#[derive(Clone, Debug, PartialEq)]
pub struct PolicyMapping<'a> {
    pub issuer_domain_policy: Oid<'a>,
    pub subject_domain_policy: Oid<'a>,
}

impl<'a> PolicyMapping<'a> {
    pub const fn new(issuer_domain_policy: Oid<'a>, subject_domain_policy: Oid<'a>) -> Self {
        PolicyMapping {
            issuer_domain_policy,
            subject_domain_policy,
        }
    }
}

// PolicyMappings ::= SEQUENCE SIZE (1..MAX) OF SEQUENCE {
//  issuerDomainPolicy      CertPolicyId,
//  subjectDomainPolicy     CertPolicyId }
pub(crate) fn parse_policymappings(i: &[u8]) -> IResult<&[u8], PolicyMappings, BerError> {
    fn parse_oid_pair(i: &[u8]) -> IResult<&[u8], Vec<DerObject<'_>>, BerError> {
        // read 2 OID as a SEQUENCE OF OID - length will be checked later
        parse_der_sequence_of_v(parse_der_oid)(i)
    }
    let (ret, pairs) = parse_der_sequence_of_v(parse_oid_pair)(i)?;
    let mut mappings = Vec::new();
    // let mut mappings: HashMap<Oid, Vec<Oid>> = HashMap::new();
    for pair in pairs.iter() {
        if pair.len() != 2 {
            return Err(Err::Failure(BerError::BerValueError));
        }
        let left = pair[0].as_oid_val().map_err(nom::Err::Failure)?;
        let right = pair[1].as_oid_val().map_err(nom::Err::Failure)?;
        // XXX this should go to Validate
        // if left.bytes() == oid!(raw 2.5.29.32.0) || right.bytes() == oid!(raw 2.5.29.32.0) {
        //     // mapping to or from anyPolicy is not allowed
        //     return Err(Err::Failure(BerError::InvalidTag));
        // }
        mappings.push(PolicyMapping::new(left, right));
    }
    Ok((ret, PolicyMappings { mappings }))
}