pub struct Dkim2Signer<State = NeedDomain> { /* private fields */ }Expand description
DKIM2 message signer (§12).
Built in typestate steps. Dkim2Signer::from_key takes the first
private key, domain sets the signing domain (d=)
and selector sets the selector of the first key,
which yields a Dkim2Signer<Ready>. Only a
ready signer can sign. Optional settings on a ready signer:
additional_key adds an alternative
signature under another selector (|),
hybrid_key adds a signature that must pass
together with the previous one (,), hashes
selects the Message-Instance hash algorithms, flags
sets the f= tag, nonce sets the n= tag and
out_of_band_arrangement allows
signing messages that are not Fully Verified DKIM2 Messages.
The signing methods (sign,
sign_revised,
sign_with_recipe and
sign_with_message_instance)
return a Dkim2Signed holding the header fields to prepend to the
message. A message that already carries DKIM2 header fields is signed only
with the Dkim2Output of a full verification that passed (§12).
§Example
use mail_auth::{
crypto::{Ed25519Key, RsaKey, Sha256},
dkim2::{Dkim2Signer, Flag, Hop},
};
use rustls_pki_types::{PrivateKeyDer, pem::PemObject};
let rsa_key = RsaKey::<Sha256>::from_key_der(PrivateKeyDer::from_pem_slice(rsa_pem.as_bytes())?)?;
let signed = Dkim2Signer::from_key(rsa_key)
.domain("example.com")
.selector("rsa-sel")
.additional_key(Ed25519Key::from_pkcs8_der(ed25519_pkcs8)?, "ed-sel")
.flags([Flag::Feedback])
.sign(
message.as_bytes(),
Hop::real("sender@example.com", ["recipient@example.org"]),
None,
)?;
let signed_message = format!("{}{}", signed.to_header(), message);Implementations§
Source§impl Dkim2Signer<NeedDomain>
impl Dkim2Signer<NeedDomain>
Sourcepub fn from_key(key: impl Into<DkimKey>) -> Dkim2Signer<NeedDomain>
pub fn from_key(key: impl Into<DkimKey>) -> Dkim2Signer<NeedDomain>
Starts a signer with its first private key (RSA-SHA256,
Ed25519-SHA256 or ML-DSA-44). Continue with
domain.
Sourcepub fn domain(self, domain: impl Into<String>) -> Dkim2Signer<NeedSelector>
pub fn domain(self, domain: impl Into<String>) -> Dkim2Signer<NeedSelector>
Sets the signing domain (d=). Its public keys are looked up under
<selector>._domainkey.<domain>. Continue with
selector.
Source§impl Dkim2Signer<Ready>
impl Dkim2Signer<Ready>
Sourcepub fn additional_key(
self,
key: impl Into<DkimKey>,
selector: impl Into<String>,
) -> Self
pub fn additional_key( self, key: impl Into<DkimKey>, selector: impl Into<String>, ) -> Self
Adds another signing key under its own selector as an alternative to the keys added before it.
The key adds a new |-separated group to the s= tag of the same
signature (algorithmic agility, §10.9): the signature passes when
either this key or an earlier group verifies, so a Verifier that does
not implement one of the algorithms can still check the others.
Selectors must be distinct and a signature holds at most eight keys;
signing fails with
Dkim2Error::DuplicateSelector
or Dkim2Error::TooManySelectors
otherwise.
Sourcepub fn hybrid_key(
self,
key: impl Into<DkimKey>,
selector: impl Into<String>,
) -> Self
pub fn hybrid_key( self, key: impl Into<DkimKey>, selector: impl Into<String>, ) -> Self
Adds another signing key under its own selector that must verify together with the key added before it.
The key joins the last |-separated group of the s= tag with a ,
(a “hybrid” signature, §10.9): that group passes only when every key
in it verifies. The same limits as
additional_key apply.
Sourcepub fn hashes(self, hashes: impl IntoIterator<Item = Dkim2Hash>) -> Self
pub fn hashes(self, hashes: impl IntoIterator<Item = Dkim2Hash>) -> Self
Sets the hash algorithms of the Message-Instance header fields this
signer adds (§3.1 and §9.3). They form a single ,-separated group,
so all of them must match. Repeated algorithms are added once; an
empty list keeps the default, SHA-256 only.
Sourcepub fn flags(self, flags: impl IntoIterator<Item = Flag>) -> Self
pub fn flags(self, flags: impl IntoIterator<Item = Flag>) -> Self
Adds flags to the f= tag of the signature (§10.10). Repeated flags
are added once. Flag::Unknown values must be textstrings (letters,
digits, - and _), or signing fails with
Dkim2Error::SignatureSyntax;
unknown values that spell a defined flag are treated as that flag.
The exploded flag is not allowed on the first signature of a
message (§12.5). It is added automatically to a later signature
whose Hop has more than one RCPT TO; a Forwarder that
sends separate copies to several recipients marks each copy’s hop with
Hop::exploded instead.
Sourcepub fn nonce(self, nonce: impl Into<String>) -> Self
pub fn nonce(self, nonce: impl Into<String>) -> Self
Sets the nonce (n= tag, §10.3): an opaque value meaningful only to
the signer, for example a key to match a returned DSN. It must be at
most 64 printable ASCII characters without semicolons; signing fails
with Dkim2Error::SignatureSyntax
otherwise. An empty nonce means no n= tag.
Sourcepub fn out_of_band_arrangement(self) -> Self
pub fn out_of_band_arrangement(self) -> Self
Declares an out-of-band arrangement (§12 and §12.3) that allows this
signer to sign messages that are not Fully Verified DKIM2 Messages,
such as a message whose most recent signature carries nd= for an
imaginary hop made by the same system. Without it, a message that
already has DKIM2 header fields is signed only with a passing full
verification of it. The chain of custody, mf=/d= and exploded
checks still apply.
Source§impl Dkim2Signer<Ready>
impl Dkim2Signer<Ready>
Sourcepub fn sign<'x, M, A, R, I>(
&self,
message: M,
hop: Hop<A, R, I>,
verified: Option<&Dkim2Output<'_>>,
) -> Result<Dkim2Signed>where
M: TryInto<AuthenticatedMessage<'x>, Error = Error>,
A: AsRef<str>,
R: IntoIterator<Item: AsRef<str>>,
I: Into<String>,
pub fn sign<'x, M, A, R, I>(
&self,
message: M,
hop: Hop<A, R, I>,
verified: Option<&Dkim2Output<'_>>,
) -> Result<Dkim2Signed>where
M: TryInto<AuthenticatedMessage<'x>, Error = Error>,
A: AsRef<str>,
R: IntoIterator<Item: AsRef<str>>,
I: Into<String>,
Signs a message whose content has not changed, as an Originator or a Forwarder that does not modify the message.
message is the raw message, including any DKIM2 header fields added
by earlier hops. hop is the next hop the signature binds to.
verified is the Dkim2Output of a full verification of message
that passed (§12): required when the message already has DKIM2 header
fields, unless the signer has an
out_of_band_arrangement; pass
None for a new message. The result always holds a new
DKIM2-Signature, and holds a new Message-Instance (m=1) only if
the message has none yet.
§Errors
Returns Error::Parse if the message cannot be parsed,
Dkim2Error::NotFullyVerified if the validity proof is missing or
does not match the message, Dkim2Error::FromNotAuthentic if the
message is new (or its From changed) and its From domain is not
the signing domain or a subdomain of it (§12.4), Dkim2Error::HeaderHashMismatch or
Dkim2Error::BodyHashMismatch if the message changed since its most
recent Message-Instance (use sign_revised),
Dkim2Error::SignatureSyntax if the signing domain, the nd=
domain or a selector is not an RFC 5321 domain (U-labels are mapped to
A-labels first), Dkim2Error::SignatureTagMissing for a Hop
without RCPT TO addresses, Dkim2Error::SignatureSyntax for an
empty or null RCPT TO address, a chain of custody, mf=/d=, selector,
nonce or exploded flag error for a signature that would not be valid
(§12.2 to §12.5),
Dkim2Error::SequenceOverflow if the next i= would exceed
u32::MAX, or the signing key’s error if signing fails.
Sourcepub fn sign_revised<'x, O, M, A, R, I>(
&self,
original: O,
modified: M,
hop: Hop<A, R, I>,
verified: Option<&Dkim2Output<'_>>,
) -> Result<Dkim2Signed>where
O: TryInto<AuthenticatedMessage<'x>, Error = Error>,
M: TryInto<AuthenticatedMessage<'x>, Error = Error>,
A: AsRef<str>,
R: IntoIterator<Item: AsRef<str>>,
I: Into<String>,
pub fn sign_revised<'x, O, M, A, R, I>(
&self,
original: O,
modified: M,
hop: Hop<A, R, I>,
verified: Option<&Dkim2Output<'_>>,
) -> Result<Dkim2Signed>where
O: TryInto<AuthenticatedMessage<'x>, Error = Error>,
M: TryInto<AuthenticatedMessage<'x>, Error = Error>,
A: AsRef<str>,
R: IntoIterator<Item: AsRef<str>>,
I: Into<String>,
Signs a message whose content changed, as a Reviser.
original is the message as received and verified the passing full
verification of it (see sign). modified is the
message to be sent, which keeps the DKIM2 header fields of
original. The recipe that recreates original from modified is
computed with Recipe::diff. If the signed content changed, the
result holds a new Message-Instance with the next m=, the new
hashes and the recipe; otherwise it holds only the DKIM2-Signature,
as with sign.
§Errors
Same as sign; either message can fail to parse.
§Example
use mail_auth::{
AuthenticatedMessage, MessageAuthenticator,
crypto::Ed25519Key,
dkim2::{Dkim2Signer, Envelope, Hop},
};
let authenticator = MessageAuthenticator::new_cloudflare_tls().unwrap();
let message = AuthenticatedMessage::parse(received).unwrap();
let verified = authenticator
.verify_dkim2(&message, Envelope::new("sender@example.com", ["list@example.org"]))
.await;
let signed = Dkim2Signer::from_key(Ed25519Key::from_pkcs8_der(pkcs8)?)
.domain("example.org")
.selector("ed25519")
.sign_revised(
received,
modified,
Hop::real("list-bounces@example.org", ["member@example.net"]),
Some(&verified),
)?;
let mut outgoing = Vec::new();
signed.write(&mut outgoing);
outgoing.extend_from_slice(modified);Sourcepub fn sign_with_recipe<'x, M, A, R, I>(
&self,
modified: M,
recipe: Recipe,
hop: Hop<A, R, I>,
verified: Option<&Dkim2Output<'_>>,
) -> Result<Dkim2Signed>where
M: TryInto<AuthenticatedMessage<'x>, Error = Error>,
A: AsRef<str>,
R: IntoIterator<Item: AsRef<str>>,
I: Into<String>,
pub fn sign_with_recipe<'x, M, A, R, I>(
&self,
modified: M,
recipe: Recipe,
hop: Hop<A, R, I>,
verified: Option<&Dkim2Output<'_>>,
) -> Result<Dkim2Signed>where
M: TryInto<AuthenticatedMessage<'x>, Error = Error>,
A: AsRef<str>,
R: IntoIterator<Item: AsRef<str>>,
I: Into<String>,
Signs a changed message with a caller-supplied recipe.
recipe recreates the previous revision from modified, which keeps
the DKIM2 header fields of the received message; verified is the
passing full verification of the received message (see
sign). The result holds a new Message-Instance with
the next m=, the hashes of modified and recipe.
§Errors
Same as sign, and Dkim2Error::RecipeSyntax if
recipe fails Recipe::validate.
Sourcepub fn sign_with_message_instance<'x, A, R, I>(
&self,
modified: &AuthenticatedMessage<'x>,
instance: Option<&MessageInstance>,
hop: Hop<A, R, I>,
verified: Option<&Dkim2Output<'_>>,
) -> Result<Dkim2Signed>
pub fn sign_with_message_instance<'x, A, R, I>( &self, modified: &AuthenticatedMessage<'x>, instance: Option<&MessageInstance>, hop: Hop<A, R, I>, verified: Option<&Dkim2Output<'_>>, ) -> Result<Dkim2Signed>
Signs a message with a caller-supplied Message-Instance.
instance is signed as the newest Message-Instance of modified;
with None, only the instances already present are signed. The
returned Dkim2Signed::message_instance is always None: the caller
writes instance to the message itself, next to the returned
DKIM2-Signature. verified is as in sign.
§Errors
Same as sign, except that parsing cannot fail;
Dkim2Error::InstanceSyntax if instance is not numbered one more
than the highest existing m=, Dkim2Error::HeaderHashMismatch or
Dkim2Error::BodyHashMismatch if its hashes do not match
modified, and Dkim2Error::RecipeSyntax if its recipe fails
Recipe::validate.
Auto Trait Implementations§
impl<State> Freeze for Dkim2Signer<State>where
PhantomData<State>: Freeze,
impl<State> RefUnwindSafe for Dkim2Signer<State>where
PhantomData<State>: RefUnwindSafe,
impl<State> Send for Dkim2Signer<State>where
PhantomData<State>: Send,
impl<State> Sync for Dkim2Signer<State>where
PhantomData<State>: Sync,
impl<State> Unpin for Dkim2Signer<State>where
PhantomData<State>: Unpin,
impl<State> UnsafeUnpin for Dkim2Signer<State>where
PhantomData<State>: UnsafeUnpin,
impl<State> UnwindSafe for Dkim2Signer<State>where
PhantomData<State>: UnwindSafe,
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more