pub struct Signer<T> { /* private fields */ }
Expand description
A signer for an email message.
Signer
is the high-level API for signing a message. It implements a
three-phase, staged design that allows processing the message in chunks.
prepare_signing
: first, a number of signing requests together with the message header allow construction of a signerprocess_body_chunk
: then, any number of chunks of the message body are fed to the signing processsign
(async): finally, the initial signing requests are answered by performing signing and returning the results; this is where most of the actual work is done
Compare this with the similar but distinct procedure of
Verifier
.
For convenience, the free function sign
can be used to perform
all stages in one go.
§Examples
The following example shows how to sign a message using the high-level API.
Don’t forget to prepend the formatted DKIM-Signature header(s) to your message when sending it out.
use viadkim::*;
let header = "From: me@example.com\r\n\
To: you@example.org\r\n\
Subject: Re: Thursday 8pm\r\n\
Date: Thu, 22 Jun 2023 14:03:12 +0200\r\n".parse()?;
let body = b"Hey,\r\n\
\r\n\
Ready for tonight? ;)\r\n";
let domain = DomainName::new("example.com")?;
let selector = Selector::new("selector")?;
let algorithm = SigningAlgorithm::Ed25519Sha256;
let signing_key = SigningKey::from_pkcs8_pem(
"-----BEGIN PRIVATE KEY-----\n\
MC4CAQAwBQYDK2VwBCIEIH1M+KJ5Nln5QmygpruhNrykdHC9AwB8B7ACiiWMp/tQ\n\
-----END PRIVATE KEY-----"
)?;
let request = SignRequest::new(domain, selector, algorithm, signing_key);
let mut signer = Signer::prepare_signing(header, [request])?;
let _ = signer.process_body_chunk(body);
let results = signer.sign().await;
let signature = results.into_iter().next().unwrap()?;
assert_eq!(
signature.format_header().to_string(),
"DKIM-Signature: v=1; d=example.com; s=selector; a=ed25519-sha256; c=relaxed;\r\n\
\tt=1687435395; x=1687867395; h=Date:Subject:To:From; bh=1zGfaauQ3vmMhm21CGMC23\r\n\
\taJE1JrOoKsgT/wvw9owzE=; b=neMHc/e6jrqSscL1pc/fTxOU/CjuvYzvnGbTABQvYkzlIvazqp3\r\n\
\tiR7RXUZi0CbOAq13IEUZPc6S0/63cfAO4CA=="
);
See Verifier
for how the above example
message could be verified.
Implementations§
source§impl<T> Signer<T>where
T: AsRef<SigningKey>,
impl<T> Signer<T>where
T: AsRef<SigningKey>,
sourcepub fn prepare_signing<I>(
headers: HeaderFields,
requests: I
) -> Result<Self, RequestError>where
I: IntoIterator<Item = SignRequest<T>>,
pub fn prepare_signing<I>(
headers: HeaderFields,
requests: I
) -> Result<Self, RequestError>where
I: IntoIterator<Item = SignRequest<T>>,
Prepares a message signing process.
§Errors
If the given arguments including any of the requests cannot be used for signing, an error is returned.
sourcepub fn process_body_chunk(&mut self, chunk: &[u8]) -> BodyHasherStance
pub fn process_body_chunk(&mut self, chunk: &[u8]) -> BodyHasherStance
Processes a chunk of the message body.
Clients should pass the message body either whole or in chunks of
arbitrary size to this method in order to calculate the body hash (the
bh= tag). The returned BodyHasherStance
instructs the client how
to proceed if more chunks are outstanding. Note that the given body
chunk is canonicalised and hashed, but not otherwise retained in memory.
Remember that email message bodies generally use CRLF line endings; this is important for correct body hash calculation.
§Examples
let _ = signer.process_body_chunk(b"\
Hello friend!\r
\r
How are you?\r
");
sourcepub async fn sign(self) -> Vec<SigningResult>
pub async fn sign(self) -> Vec<SigningResult>
Performs the actual signing and returns the resulting signatures.
The returned result vector is never empty.