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}