mail_auth/dkim/
headers.rs1use super::{Algorithm, Canonicalization, HashAlgorithm, Signature};
8use crate::common::headers::{HeaderWriter, Writer};
9use std::fmt::{Display, Formatter};
10
11impl Signature {
12 pub fn write(&self, writer: &mut impl Writer, as_header: bool) {
13 let (header, new_line) = match self.ch {
14 Canonicalization::Relaxed if !as_header => (&b"dkim-signature:"[..], &b" "[..]),
15 _ => (&b"DKIM-Signature: "[..], &b"\r\n\t"[..]),
16 };
17 writer.write(header);
18 writer.write(b"v=1; a=");
19 writer.write(match self.a {
20 Algorithm::RsaSha256 => b"rsa-sha256",
21 Algorithm::RsaSha1 => b"rsa-sha1",
22 Algorithm::Ed25519Sha256 => b"ed25519-sha256",
23 });
24 for (tag, value) in [(&b"; s="[..], &self.s), (&b"; d="[..], &self.d)] {
25 writer.write(tag);
26 writer.write(value.as_bytes());
27 }
28 writer.write(b"; c=");
29 self.ch.serialize_name(writer);
30 writer.write(b"/");
31 self.cb.serialize_name(writer);
32
33 if let Some(atps) = &self.atps {
34 writer.write(b"; atps=");
35 writer.write(atps.as_bytes());
36 writer.write(b"; atpsh=");
37 writer.write(match self.atpsh {
38 Some(HashAlgorithm::Sha256) => b"sha256",
39 Some(HashAlgorithm::Sha1) => b"sha1",
40 _ => b"none",
41 });
42 }
43 if self.r {
44 writer.write(b"; r=y");
45 }
46
47 writer.write(b";");
48 writer.write(new_line);
49
50 let mut bw = 1;
51 for (num, h) in self.h.iter().enumerate() {
52 if bw + h.len() + 1 >= 76 {
53 writer.write(new_line);
54 bw = 1;
55 }
56 if num > 0 {
57 writer.write_len(b":", &mut bw);
58 } else {
59 writer.write_len(b"h=", &mut bw);
60 }
61 writer.write_len(h.as_bytes(), &mut bw);
62 }
63
64 if !self.i.is_empty() {
65 if bw + self.i.len() + 3 >= 76 {
66 writer.write(b";");
67 writer.write(new_line);
68 bw = 1;
69 } else {
70 writer.write_len(b"; ", &mut bw);
71 }
72 writer.write_len(b"i=", &mut bw);
73
74 for &ch in self.i.as_bytes().iter() {
75 match ch {
76 0..=0x20 | b';' | 0x7f..=u8::MAX => {
77 writer.write_len(format!("={ch:02X}").as_bytes(), &mut bw);
78 }
79 _ => {
80 writer.write_len(&[ch], &mut bw);
81 }
82 }
83 if bw >= 76 {
84 writer.write(new_line);
85 bw = 1;
86 }
87 }
88 }
89
90 for (tag, value) in [
91 (&b"t="[..], self.t),
92 (&b"x="[..], self.x),
93 (&b"l="[..], self.l),
94 ] {
95 if value > 0 {
96 let value = value.to_string();
97 writer.write_len(b";", &mut bw);
98 if bw + tag.len() + value.len() >= 76 {
99 writer.write(new_line);
100 bw = 1;
101 } else {
102 writer.write_len(b" ", &mut bw);
103 }
104
105 writer.write_len(tag, &mut bw);
106 writer.write_len(value.as_bytes(), &mut bw);
107 }
108 }
109
110 for (tag, value) in [(&b"; bh="[..], &self.bh), (&b"; b="[..], &self.b)] {
111 writer.write_len(tag, &mut bw);
112 for &byte in value {
113 writer.write_len(&[byte], &mut bw);
114 if bw >= 76 {
115 writer.write(new_line);
116 bw = 1;
117 }
118 }
119 }
120
121 writer.write(b";");
122 if as_header {
123 writer.write(b"\r\n");
124 }
125 }
126}
127
128impl HeaderWriter for Signature {
129 fn write_header(&self, writer: &mut impl Writer) {
130 self.write(writer, true);
131 }
132}
133
134impl Display for Signature {
135 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
136 let mut buf = Vec::new();
137 self.write(&mut buf, false);
138 f.write_str(&String::from_utf8_lossy(&buf))
139 }
140}