Module: MailAuth::Dkim
- Defined in:
- lib/mailauth/dkim.rb,
lib/mailauth/dkim/signer.rb,
lib/mailauth/dkim/algorithm.rb,
lib/mailauth/dkim/public_key.rb,
lib/mailauth/dkim/canonicalization.rb
Overview
RFC 6376. Verifies the DKIM-Signature headers on a message against the public keys their domains publish, and signs outgoing messages with the private ones.
Defined Under Namespace
Modules: Algorithm, Canonicalization, PublicKey Classes: Malformed, Signer, Verification
Constant Summary collapse
- CRLF =
"\r\n".b
- HASHES =
{ "sha1" => OpenSSL::Digest::SHA1, "sha256" => OpenSSL::Digest::SHA256 }.freeze
- SIGNING_ALGORITHMS =
%w[ rsa ed25519 ].freeze
- KEY_TYPES =
What OpenSSL calls a key, mapped to what a= calls it.
{ "rsaEncryption" => "rsa", "ED25519" => "ed25519" }.freeze
- CANONICALIZATIONS =
%w[ simple relaxed ].freeze
- REQUIRED_TAGS =
%w[ v a b bh d h s ].freeze
- TAG_NAME =
RFC 6376 §3.2: ALPHA *ALNUMPUNC.
/\A[a-zA-Z][a-zA-Z0-9_]*\z/n- MINIMUM_RSA_BITS =
Shorter RSA keys are factorable cheaply enough to prove nothing.
1024- ED25519_SPKI_PREFIX =
ed25519 keys travel as 32 raw bytes (RFC 8463 §3), so we put back the SubjectPublicKeyInfo wrapper OpenSSL insists on before reading one.
[ "302a300506032b6570032100" ].pack("H*")
Class Method Summary collapse
-
.parse_tags(text) ⇒ Object
RFC 6376 §3.2.
- .sign(raw, domain:, selector:, key:, headers: nil, oversign: Signer::OVERSIGNED_HEADERS, expires_in: nil, now: Time.now) ⇒ Object
- .verify(message, resolver: Resolver.new, now: Time.now) ⇒ Object
Class Method Details
.parse_tags(text) ⇒ Object
RFC 6376 §3.2. A malformed tag name, a repeated one, or an empty entry invalidates the whole list rather than the one tag: reading the rest would take a forged tag as read beside the one silently dropped. Values fold across lines, so callers strip whitespace themselves on the tags where it matters.
57 58 59 60 61 62 63 64 65 66 67 68 69 |
# File 'lib/mailauth/dkim.rb', line 57 def self.(text) specs = text.split(";", -1) specs.pop if specs.last&.strip&.empty? # the tag-list's optional trailing ";" specs.each_with_object({}) do |spec, | name, value = spec.split("=", 2) name = name.to_s.strip return nil unless value && name.match?(TAG_NAME) && !.key?(name) [name] = value.strip end end |
.sign(raw, domain:, selector:, key:, headers: nil, oversign: Signer::OVERSIGNED_HEADERS, expires_in: nil, now: Time.now) ⇒ Object
48 49 50 |
# File 'lib/mailauth/dkim.rb', line 48 def self.sign(raw, domain:, selector:, key:, headers: nil, oversign: Signer::OVERSIGNED_HEADERS, expires_in: nil, now: Time.now) Signer.new(raw, domain:, selector:, key:, headers:, oversign:, expires_in:, now:). end |
.verify(message, resolver: Resolver.new, now: Time.now) ⇒ Object
39 40 41 42 43 44 45 46 |
# File 'lib/mailauth/dkim.rb', line 39 def self.verify(, resolver: Resolver.new, now: Time.now) signatures = .fields_named("dkim-signature").map do |field| Verification.new(, field, resolver:, now:).result end signatures << Signature.new(status: Status::NONE, comment: "message not signed") if signatures.empty? DkimResult.new(signatures:) end |