package dkim

  1. Overview
  2. Docs

Module DkimSource

DKIM signature and verification for emails.

This module implements the DomainKeys Identified Mail (DKIM) protocol as specified by RFC 6376. DKIM allows a sending domain to cryptographically sign outgoing email so that receiving mail servers can verify the message has not been altered in transit and was authorized by the domain owner.

The library processes emails in a single streaming pass for both verification and signing. Memory consumption stays proportional to the size of an input chunk, not the size of the entire message.

Two signature algorithms are supported: RSA and ED25519. Two hash functions are available: SHA1 and SHA256. Both "simple" and "relaxed" canonicalization methods are implemented for headers and body.

Core types

Sourcetype algorithm = [
  1. | `RSA
  2. | `ED25519
]

The signature algorithm used to produce or verify a DKIM signature. RSA is the most widely deployed algorithm. ED25519 is a newer, smaller-key alternative introduced by RFC 8463.

Sourcetype hash = [
  1. | `SHA1
  2. | `SHA256
]

The hash function used when computing the digest of the message headers and body. SHA256 is recommended. SHA1 is supported for compatibility with older signatures but is considered weak.

Sourcetype canonicalization = [
  1. | `Simple
  2. | `Relaxed
]

The canonicalization algorithm applied to headers or body before hashing. `Simple leaves the content untouched (modulo trailing CRLF rules). `Relaxed normalizes whitespace and lowercases header field names, which makes the signature more tolerant of minor modifications by intermediate mail servers.

Sourcetype query = [
  1. | `DNS of [ `TXT ]
]

The method used to retrieve the public key of the signing domain. The only method defined by RFC 6376 is a DNS TXT record query.

Sourcetype hash_algorithm =
  1. | Hash_algorithm : 'k Digestif.hash -> hash_algorithm

An existentially packed hash algorithm from Digestif.

Sourcetype hash_value =
  1. | Hash_value : 'k Digestif.hash * 'k Digestif.t -> hash_value

An existentially packed hash value: a pair of a Digestif hash algorithm and the corresponding digest.

Sourcetype 'a t

A DKIM record, parameterized by whether it carries a cryptographic signature. A value of type signed t was parsed from an existing DKIM-Signature header field and carries both the original signature bytes and the body hash. A value of type unsigned t is one that has been constructed programmatically and is ready to be signed.

Sourceand signed = private string * hash_value

The payload of a signed DKIM record: the raw signature string together with the body hash. The private annotation prevents construction outside this module while still allowing pattern-matching.

Sourceand unsigned

The phantom type for an unsigned DKIM record. Values of this type are created by v and consumed by Sign.signer.

Sourcetype key = [
  1. | `RSA of Mirage_crypto_pk.Rsa.priv
  2. | `ED25519 of Mirage_crypto_ec.Ed25519.priv
]

A private key used for signing. It must match the algorithm declared in the DKIM record: an RSA key for `RSA and an Ed25519 key for `ED25519.

Constructing a DKIM record

Sourceval v : ?version:int -> ?fields:Mrmime.Field_name.t list -> selector:[ `raw ] Domain_name.t -> ?algorithm:algorithm -> ?hash:hash -> ?canonicalization:(canonicalization * canonicalization) -> ?length:int -> ?query:query -> ?timestamp:int64 -> ?expiration:int64 -> [ `raw ] Domain_name.t -> unsigned t

v ~selector domain creates an unsigned DKIM record for the given domain and selector. The selector determines which DNS TXT record (published at selector._domainkey.domain) holds the corresponding public key.

Optional parameters let you override the defaults:

  • version must be 1 (the only version defined by the RFC).
  • fields lists the header field names to include in the signature; it defaults to [From] and From is always included even if omitted.
  • algorithm defaults to `RSA.
  • hash defaults to `SHA256. canonicalization is a pair of (header, body) methods, defaulting to (`Relaxed, `Relaxed).
  • length restricts the number of body octets covered by the signature. (this parameter is not supported)
  • query defaults to `DNS `TXT.
  • timestamp and expiration are Unix timestamps expressed as int64 values.

Accessors

Sourceval fields : 'a t -> Mrmime.Field_name.t list

fields dkim returns the list of header field names that are (or will be) included in the signature.

Sourceval timestamp : 'a t -> int64 option

timestamp dkim returns the signature creation time, if present. The value is a Unix timestamp.

Sourceval expire : 'a t -> int64 option

expire dkim returns the signature expiration time, if present. A verifier should treat the signature as invalid after this time.

Sourceval body : signed t -> string

body dkim returns the raw hash of the canonicalized body as recorded in the signed DKIM record (the bh= tag).

Sourceval domain : 'a t -> [ `raw ] Domain_name.t

domain dkim returns the signing domain identity (the d= tag).

Sourceval selector : 'a t -> [ `raw ] Domain_name.t

selector dkim returns the selector (the s= tag) used to locate the public key in DNS.

Sourceval domain_name : 'a t -> ([ `raw ] Domain_name.t, [> `Msg of string ]) result

domain_name dkim computes the full DNS name used to retrieve the public key: selector._domainkey.domain. Returns an error if the resulting domain name is invalid.

Sourceval canonicalization : 'a t -> canonicalization * canonicalization

canonicalization dkim returns the pair (header_canon, body_canon) of canonicalization algorithms declared in the DKIM record.

Sourceval hash_algorithm : 'a t -> hash_algorithm

hash_algorithm dkim returns the hash algorithm used for digesting.

Sourceval signature_and_hash : 'signed t -> 'signed

signature_and_hash dkim returns the raw signature-and-hash payload carried by the record. For a signed t, this is the pair of the signature bytes and the body hash.

Sourceval algorithm : 'a t -> algorithm

algorithm dkim returns the signature algorithm (RSA or ED25519).

Parsing

Sourceval of_string : string -> (signed t, [> `Msg of string ]) result

of_string str parses a DKIM-Signature header field value from the given string. The string should contain the tag-value list without the field name itself (that is, everything after "DKIM-Signature:").

Sourceval of_unstrctrd : Unstrctrd.t -> (signed t, [> `Msg of string ]) result

of_unstrctrd u parses a DKIM-Signature from an Unstrctrd.t value obtained from the mrmime header parser.

Modifiers

Sourceval with_canonicalization : 'a t -> (canonicalization * canonicalization) -> 'a t

with_canonicalization dkim (hdr, body) returns a copy of dkim with the canonicalization algorithms replaced.

Sourceval with_signature_and_hash : _ t -> 'signed -> 'signed t

with_signature_and_hash dkim payload returns a copy of dkim carrying the given signature-and-hash payload. This is used internally to transition between signed and unsigned states.

Sourceval with_selector : 'a t -> selector:[ `raw ] Domain_name.t -> 'a t

with_selector dkim ~selector returns a copy of dkim with the selector replaced.

Sourceval with_expiration : 'a t -> int64 option -> 'a t

with_expiration dkim exp returns a copy of dkim with the expiration time replaced. Pass None to remove the expiration.

Domain keys

Sourcetype domain_key

A domain key is the public-side record published in DNS. It contains the public key material and metadata (acceptable hash algorithms, service types, flags) that a verifier needs.

Sourceval domain_key_of_string : string -> (domain_key, [> `Msg of string ]) result

domain_key_of_string str parses a domain key from the content of a DNS TXT record. The string is the raw value returned by the DNS resolver.

Sourceval domain_key_of_dkim : key:key -> _ t -> domain_key

domain_key_of_dkim ~key dkim constructs a domain_key from a private key and a DKIM value. The resulting value is what you would publish in DNS so that verifiers can check signatures produced with key.

Sourceval domain_key_to_string : ?with_version:bool -> domain_key -> string

domain_key_to_string ?with_version dk serializes a domain key into the tag-value format expected in a DNS TXT record. with_version writes the domain-key version (by default) to v=DKIM1.

Sourceval equal_domain_key : domain_key -> domain_key -> bool

equal_domain_key a b is true if a and b carry the same public key material and metadata.

Sourceval public_key : domain_key -> string

public_key dk returns the raw DER-encoded public key bytes.

Sourcemodule Canon : sig ... end
Sourcemodule Digest : sig ... end
Sourcemodule Verify : sig ... end
Sourcemodule Encoder : sig ... end
Sourcemodule Sign : sig ... end
Sourcemodule Body : sig ... end

Email body tokenizer for DKIM canonicalization.

Sourcemodule Decoder : sig ... end

Low-level utilities

The following values are exposed for advanced use cases such as building custom DKIM processing pipelines or integrating with other email authentication mechanisms (SPF, DMARC, ARC).

Sourcetype map

An heterogeneous map holding the parsed tag-value pairs of a DKIM-Signature header field.

Sourceval field_dkim_signature : Mrmime.Field_name.t

The DKIM-Signature field name as a Mrmime.Field_name.t value.

Sourceval remove_signature_of_dkim : Unstrctrd.t -> Unstrctrd.t

remove_signature_of_dkim u strips the b=... tag value from the unstructured representation u of a DKIM-Signature header. The b= tag key and its trailing semicolon are preserved; only the signature data between them is removed. This is the transformation required by the RFC before hashing the DKIM-Signature header itself.

Sourceval uniq : Unstrctrd.t -> Unstrctrd.t

uniq u collapses runs of consecutive whitespace in u into a single whitespace element, preserving the first one.

Sourceval trim : Unstrctrd.t -> Unstrctrd.t

trim u strips leading and trailing whitespace from u and collapses internal whitespace to a single space.

Sourceval of_unstrctrd_to_map : Unstrctrd.t -> (map, [> `Msg of string ]) result

of_unstrctrd_to_map u parses the unstructured content of a DKIM-Signature header into a heterogeneous map of tag-value pairs.

Sourceval map_to_t : map -> (signed t, [> `Msg of string ]) result

map_to_t map converts a parsed tag-value map into a typed signed t record. Returns an error if required tags are missing or values are malformed.

Sourceval get_key : string -> map -> string option

get_key name map looks up a tag by its single-character name in the heterogeneous map. Returns None if the tag is absent. This is useful for accessing non-standard or extension tags that are not represented by dedicated accessors.