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