1use super::{ChainValidation, Results, Seal, Signature};
8use crate::common::parse::*;
9use crate::{
10 Error,
11 common::{crypto::Algorithm, parse::TagParser},
12 dkim::{Canonicalization, parse::SignatureParser},
13};
14use mail_parser::decoders::base64::base64_decode_stream;
15
16pub(crate) const CV: u64 = (b'c' as u64) | ((b'v' as u64) << 8);
17
18impl Signature {
19 #[allow(clippy::while_let_on_iterator)]
20 pub fn parse(header: &'_ [u8]) -> crate::Result<Self> {
21 let mut signature = Signature {
22 a: Algorithm::RsaSha256,
23 d: "".into(),
24 s: "".into(),
25 b: Vec::with_capacity(0),
26 bh: Vec::with_capacity(0),
27 h: Vec::with_capacity(0),
28 z: Vec::with_capacity(0),
29 l: 0,
30 x: 0,
31 t: 0,
32 i: 0,
33 ch: Canonicalization::Simple,
34 cb: Canonicalization::Simple,
35 };
36 let header_len = header.len();
37 let mut header = header.iter();
38
39 while let Some(key) = header.key() {
40 match key {
41 I => {
42 signature.i = header.number().unwrap_or(0) as u32;
43 if !(1..=50).contains(&signature.i) {
44 return Err(Error::ArcInvalidInstance(signature.i));
45 }
46 }
47 A => {
48 signature.a = header.algorithm()?;
49 }
50 B => {
51 signature.b =
52 base64_decode_stream(&mut header, header_len, b';').ok_or(Error::Base64)?
53 }
54 BH => {
55 signature.bh =
56 base64_decode_stream(&mut header, header_len, b';').ok_or(Error::Base64)?
57 }
58 C => {
59 let (ch, cb) = header.canonicalization(Canonicalization::Simple)?;
60 signature.ch = ch;
61 signature.cb = cb;
62 }
63 D => signature.d = header.text(true),
64 H => signature.h = header.items(),
65 L => signature.l = header.number().unwrap_or(0),
66 S => signature.s = header.text(true),
67 T => signature.t = header.number().unwrap_or(0),
68 X => signature.x = header.number().unwrap_or(0),
69 Z => signature.z = header.headers_qp(),
70 _ => header.ignore(),
71 }
72 }
73
74 if !signature.d.is_empty()
75 && !signature.s.is_empty()
76 && !signature.b.is_empty()
77 && !signature.bh.is_empty()
78 && !signature.h.is_empty()
79 {
80 Ok(signature)
81 } else {
82 Err(Error::MissingParameters)
83 }
84 }
85}
86
87impl Seal {
88 #[allow(clippy::while_let_on_iterator)]
89 pub fn parse(header: &'_ [u8]) -> crate::Result<Self> {
90 let mut seal = Seal {
91 a: Algorithm::RsaSha256,
92 d: "".into(),
93 s: "".into(),
94 b: Vec::with_capacity(0),
95 t: 0,
96 i: 0,
97 cv: ChainValidation::None,
98 };
99 let header_len = header.len();
100 let mut header = header.iter();
101 let mut cv = None;
102
103 while let Some(key) = header.key() {
104 match key {
105 I => {
106 seal.i = header.number().unwrap_or(0) as u32;
107 }
108 A => {
109 seal.a = header.algorithm()?;
110 }
111 B => {
112 seal.b =
113 base64_decode_stream(&mut header, header_len, b';').ok_or(Error::Base64)?
114 }
115 D => seal.d = header.text(true),
116 S => seal.s = header.text(true),
117 T => seal.t = header.number().unwrap_or(0),
118 CV => {
119 match header.next_skip_whitespaces().unwrap_or(0) {
120 b'n' | b'N' if header.match_bytes(b"one") => {
121 cv = ChainValidation::None.into();
122 }
123 b'f' | b'F' if header.match_bytes(b"ail") => {
124 cv = ChainValidation::Fail.into();
125 }
126 b'p' | b'P' if header.match_bytes(b"ass") => {
127 cv = ChainValidation::Pass.into();
128 }
129 _ => return Err(Error::ArcInvalidCV),
130 }
131 if !header.seek_tag_end() {
132 return Err(Error::ArcInvalidCV);
133 }
134 }
135 H => {
136 return Err(Error::ArcHasHeaderTag);
137 }
138 _ => header.ignore(),
139 }
140 }
141 seal.cv = cv.ok_or(Error::ArcInvalidCV)?;
142
143 if !(1..=50).contains(&seal.i) {
144 Err(Error::ArcInvalidInstance(seal.i))
145 } else if !seal.d.is_empty() && !seal.s.is_empty() && !seal.b.is_empty() {
146 Ok(seal)
147 } else {
148 Err(Error::MissingParameters)
149 }
150 }
151}
152
153impl Results {
154 #[allow(clippy::while_let_on_iterator)]
155 pub fn parse(header: &'_ [u8]) -> crate::Result<Self> {
156 let mut results = Results { i: 0 };
157 let mut header = header.iter();
158
159 while let Some(key) = header.key() {
160 match key {
161 I => {
162 results.i = header.number().unwrap_or(0) as u32;
163 break;
164 }
165 _ => header.ignore(),
166 }
167 }
168
169 if (1..=50).contains(&results.i) {
170 Ok(results)
171 } else {
172 Err(Error::ArcInvalidInstance(results.i))
173 }
174 }
175}