1use super::{ArcSet, ChainValidation, Seal, Signature};
8use crate::{
9 AuthenticationResults,
10 common::{
11 crypto::Algorithm,
12 headers::{HeaderWriter, Writer},
13 },
14 dkim::Canonicalization,
15};
16
17impl Signature {
18 pub(crate) fn write(&self, writer: &mut impl Writer, as_header: bool) {
19 let (header, new_line) = match self.ch {
20 Canonicalization::Relaxed if !as_header => (&b"arc-message-signature:"[..], &b" "[..]),
21 _ => (&b"ARC-Message-Signature: "[..], &b"\r\n\t"[..]),
22 };
23 writer.write(header);
24 writer.write(b"i=");
25 writer.write(self.i.to_string().as_bytes());
26 writer.write(b"; a=");
27 writer.write(match self.a {
28 Algorithm::RsaSha256 => b"rsa-sha256",
29 Algorithm::RsaSha1 => b"rsa-sha1",
30 Algorithm::Ed25519Sha256 => b"ed25519-sha256",
31 });
32 for (tag, value) in [(&b"; s="[..], &self.s), (&b"; d="[..], &self.d)] {
33 writer.write(tag);
34 writer.write(value.as_bytes());
35 }
36 writer.write(b"; c=");
37 self.ch.serialize_name(writer);
38 writer.write(b"/");
39 self.cb.serialize_name(writer);
40
41 writer.write(b";");
42 writer.write(new_line);
43
44 let mut bw = 1;
45 for (num, h) in self.h.iter().enumerate() {
46 if bw + h.len() + 1 >= 76 {
47 writer.write(new_line);
48 bw = 1;
49 }
50 if num > 0 {
51 writer.write_len(b":", &mut bw);
52 } else {
53 writer.write_len(b"h=", &mut bw);
54 }
55 writer.write_len(h.as_bytes(), &mut bw);
56 }
57
58 for (tag, value) in [
59 (&b"t="[..], self.t),
60 (&b"x="[..], self.x),
61 (&b"l="[..], self.l),
62 ] {
63 if value > 0 {
64 let value = value.to_string();
65 writer.write_len(b";", &mut bw);
66 if bw + tag.len() + value.len() >= 76 {
67 writer.write(new_line);
68 bw = 1;
69 } else {
70 writer.write_len(b" ", &mut bw);
71 }
72
73 writer.write_len(tag, &mut bw);
74 writer.write_len(value.as_bytes(), &mut bw);
75 }
76 }
77
78 for (tag, value) in [(&b"; bh="[..], &self.bh), (&b"; b="[..], &self.b)] {
79 writer.write_len(tag, &mut bw);
80 for &byte in value {
81 writer.write_len(&[byte], &mut bw);
82 if bw >= 76 {
83 writer.write(new_line);
84 bw = 1;
85 }
86 }
87 }
88
89 writer.write(b";");
90 if as_header {
91 writer.write(b"\r\n");
92 }
93 }
94}
95
96impl Seal {
97 pub(crate) fn write(&self, writer: &mut impl Writer, as_header: bool) {
98 let (header, new_line) = if !as_header {
99 (&b"arc-seal:"[..], &b" "[..])
100 } else {
101 (&b"ARC-Seal: "[..], &b"\r\n\t"[..])
102 };
103
104 writer.write(header);
105 writer.write(b"i=");
106 writer.write(self.i.to_string().as_bytes());
107 writer.write(b"; a=");
108 writer.write(match self.a {
109 Algorithm::RsaSha256 => b"rsa-sha256",
110 Algorithm::RsaSha1 => b"rsa-sha1",
111 Algorithm::Ed25519Sha256 => b"ed25519-sha256",
112 });
113 for (tag, value) in [(&b"; s="[..], &self.s), (&b"; d="[..], &self.d)] {
114 writer.write(tag);
115 writer.write(value.as_bytes());
116 }
117 writer.write(b"; cv=");
118 writer.write(match self.cv {
119 ChainValidation::None => b"none",
120 ChainValidation::Fail => b"fail",
121 ChainValidation::Pass => b"pass",
122 });
123
124 writer.write(b";");
125 writer.write(new_line);
126
127 let mut bw = 1;
128 if self.t > 0 {
129 writer.write_len(b"t=", &mut bw);
130 writer.write_len(self.t.to_string().as_bytes(), &mut bw);
131 writer.write_len(b"; ", &mut bw);
132 }
133
134 writer.write_len(b"b=", &mut bw);
135 for &byte in &self.b {
136 writer.write_len(&[byte], &mut bw);
137 if bw >= 76 {
138 writer.write(new_line);
139 bw = 1;
140 }
141 }
142
143 writer.write(b";");
144 if as_header {
145 writer.write(b"\r\n");
146 }
147 }
148}
149
150impl AuthenticationResults<'_> {
151 pub(crate) fn write(&self, writer: &mut impl Writer, i: u32, as_header: bool) {
152 writer.write(if !as_header {
153 b"arc-authentication-results:"
154 } else {
155 b"ARC-Authentication-Results: "
156 });
157 writer.write(b"i=");
158 writer.write(i.to_string().as_bytes());
159 writer.write(b"; ");
160 writer.write(self.hostname.as_bytes());
161 if !as_header {
162 let mut last_is_space = false;
163 for &ch in self.auth_results.as_bytes() {
164 if !ch.is_ascii_whitespace() {
165 if last_is_space {
166 writer.write(b" ");
167 last_is_space = false;
168 }
169 writer.write(&[ch]);
170 } else {
171 last_is_space = true;
172 }
173 }
174 } else {
175 writer.write(self.auth_results.as_bytes());
176 }
177 writer.write(b"\r\n");
178 }
179}
180
181impl HeaderWriter for ArcSet<'_> {
182 fn write_header(&self, writer: &mut impl Writer) {
183 self.seal.write(writer, true);
184 self.signature.write(writer, true);
185 self.results.write(writer, self.seal.i, true);
186 }
187}