redact_crypto/
x509.rs

1use cookie_factory::{GenResult, WriteContext};
2use der::{
3    asn1::{Any, Ia5String},
4    Decodable, DecodeValue, Decoder, Encodable, Length, Sequence, Tag, TagMode, Tagged,
5};
6use spki::{AlgorithmIdentifier, SubjectPublicKeyInfo};
7use std::{
8    convert::{TryFrom, TryInto},
9    io::Write,
10};
11use x509::{
12    der::Oid as OidTrait, AlgorithmIdentifier as AlgorithmIdentifierTrait,
13    SubjectPublicKeyInfo as SubjectPublicKeyInfoTrait,
14};
15
16pub struct Oid(pub Vec<u64>);
17impl AsRef<[u64]> for Oid {
18    fn as_ref(&self) -> &[u64] {
19        &self.0
20    }
21}
22impl OidTrait for Oid {}
23
24pub struct AlgorithmIdentifierWrapper<'a>(pub AlgorithmIdentifier<'a>);
25impl<'a> AlgorithmIdentifierTrait for AlgorithmIdentifierWrapper<'a> {
26    type AlgorithmOid = Oid;
27
28    fn algorithm(&self) -> Self::AlgorithmOid {
29        Oid(self.0.oid.arcs().map(|v| v as u64).collect::<Vec<u64>>())
30    }
31
32    fn parameters<W: std::io::Write>(&self, mut w: WriteContext<W>) -> GenResult<W> {
33        match self.0.parameters {
34            Some(p) => {
35                w.write_all(p.value())?;
36                Ok(w)
37            }
38            None => Ok(w),
39        }
40    }
41}
42
43pub struct SubjectPublicKeyInfoWrapper<'a>(pub SubjectPublicKeyInfo<'a>);
44impl<'a> SubjectPublicKeyInfoTrait for SubjectPublicKeyInfoWrapper<'a> {
45    type AlgorithmId = AlgorithmIdentifierWrapper<'a>;
46    type SubjectPublicKey = &'a [u8];
47
48    fn algorithm_id(&self) -> Self::AlgorithmId {
49        AlgorithmIdentifierWrapper(self.0.algorithm)
50    }
51
52    fn public_key(&self) -> Self::SubjectPublicKey {
53        self.0.subject_public_key
54    }
55}
56
57pub struct DistinguishedName<'a> {
58    pub o: &'a str,
59    pub ou: &'a str,
60    pub cn: &'a str,
61}
62
63#[derive(Clone, Debug, Eq, PartialEq)]
64pub struct GeneralNames<'a> {
65    pub sans: Vec<GeneralName<'a>>,
66}
67
68impl<'a> TryFrom<&'a [&'a str]> for GeneralNames<'a> {
69    type Error = der::Error;
70
71    fn try_from(sans: &'a [&'a str]) -> Result<Self, Self::Error> {
72        let mut valid_strings = vec![];
73        sans.iter().try_for_each(|san| {
74            valid_strings.push(GeneralName::DnsName(Ia5String::new(*san)?));
75            Ok::<_, der::Error>(())
76        })?;
77        Ok(Self {
78            sans: valid_strings,
79        })
80    }
81}
82
83impl<'a> DecodeValue<'a> for GeneralNames<'a> {
84    fn decode_value(decoder: &mut Decoder<'a>, _: Length) -> der::Result<Self> {
85        let mut sans = vec![];
86        while !decoder.is_finished() {
87            let san: GeneralName = decoder.decode()?;
88            sans.push(san);
89        }
90        Ok(Self { sans })
91    }
92}
93
94impl<'a> TryFrom<Any<'a>> for GeneralNames<'a> {
95    type Error = der::Error;
96
97    fn try_from(any: Any<'a>) -> der::Result<GeneralNames<'a>> {
98        any.sequence(|decoder| {
99            let mut sans = vec![];
100            while !decoder.is_finished() {
101                let san: GeneralName = decoder.decode()?;
102                sans.push(san);
103            }
104
105            Ok(Self { sans })
106        })
107    }
108}
109
110impl<'a> Sequence<'a> for GeneralNames<'a> {
111    fn fields<F, T>(&self, field_encoder: F) -> der::Result<T>
112    where
113        F: FnOnce(&[&dyn Encodable]) -> der::Result<T>,
114    {
115        let mut references: Vec<&dyn Encodable> = vec![];
116        for reference in self.sans.iter() {
117            references.push(reference);
118        }
119        field_encoder(references.as_slice())
120    }
121}
122
123#[derive(Clone, Debug, Eq, PartialEq)]
124pub enum GeneralName<'a> {
125    Rfc822Name(Ia5String<'a>),
126    DnsName(Ia5String<'a>),
127}
128
129impl<'a> Decodable<'a> for GeneralName<'a> {
130    fn decode(decoder: &mut Decoder<'a>) -> der::Result<Self> {
131        decoder.any()?.try_into()
132    }
133}
134
135impl<'a> Encodable for GeneralName<'a> {
136    fn encoded_len(&self) -> der::Result<Length> {
137        match self {
138            GeneralName::Rfc822Name(v) => {
139                TryInto::<Length>::try_into(v.as_bytes().len())?.for_tlv()
140            }
141            GeneralName::DnsName(v) => TryInto::<Length>::try_into(v.as_bytes().len())?.for_tlv(),
142        }
143    }
144
145    fn encode(&self, encoder: &mut der::Encoder<'_>) -> der::Result<()> {
146        let (tag_number, value) = match self {
147            GeneralName::Rfc822Name(v) => (0x01.try_into()?, v),
148            GeneralName::DnsName(v) => (0x02.try_into()?, v),
149        };
150        encoder.context_specific(tag_number, TagMode::Implicit, value)
151    }
152}
153
154impl<'a> TryFrom<Any<'a>> for GeneralName<'a> {
155    type Error = der::Error;
156
157    fn try_from(any: Any<'a>) -> Result<Self, Self::Error> {
158        match any.tag() {
159            Tag::ContextSpecific { number, .. } => match number.value() {
160                0x01 => Ok(GeneralName::Rfc822Name(Ia5String::new(any.value())?)),
161                0x02 => Ok(GeneralName::DnsName(Ia5String::new(any.value())?)),
162                _ => Err(der::ErrorKind::TagUnexpected {
163                    expected: None,
164                    actual: any.tag(),
165                }
166                .into()),
167            },
168            actual => Err(der::ErrorKind::TagUnexpected {
169                expected: None,
170                actual,
171            }
172            .into()),
173        }
174    }
175}