dkim

package module
v0.1.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 10, 2023 License: MIT Imports: 17 Imported by: 0

README

DKIM verification Go Report Card GoDoc Go

The project was started as a fork of https://github.com/kalloc/dkim

Original plan was just fix few defects and create PR but eventually the project was totally overhauled.

TODO

  • Copied header fields (z=) verification

RFCs

Documentation

Overview

This is a modified copy of go1.11.5 textproto.Reader

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrMissingArcFields      = errors.New("missing arc fields")
	ErrInstanceMismatch      = errors.New("mismatch of arc header instances")
	ErrArcLimit              = errors.New("message over arc-set limit")
	ErrMsgNotSigned          = errors.New("message is not arc signed")
	ErrAMSValidationFailure  = errors.New("most recent ARC-Message-signature did not validate")
	ErrAMSIncludesSealHeader = errors.New("Arc-Message-signature MUST NOT sign ARC-Seal")
)
View Source
var (
	ErrUnacceptableKey      = errors.New("unacceptable key")
	ErrBadSignature         = errors.New("bad signature")
	ErrBodyHashMismatched   = errors.New("body hash mismatched")
	ErrSignatureNotFound    = errors.New("signature not found")
	ErrInputError           = errors.New("input error")
	ErrDomainMismatch       = errors.New("domain mismatch")
	ErrSignatureExpired     = errors.New("signature expired")
	ErrTimestampInFuture    = errors.New("timestamp in the future")
	ErrInvalidSigningEntity = errors.New("invalid signing entity")
	ErrKeyUnavailable       = errors.New("key unavailable")
	ErrTestingMode          = errors.New("domain is testing DKIM")
	ErrKeyRevoked           = errors.New("key revoked")
)
View Source
var (
	// Queries holds implementations of public key queries
	Queries = map[string]PublicKeyQuery{
		// contains filtered or unexported fields
	}
)

Functions

func CanonicalMIMEHeaderKey

func CanonicalMIMEHeaderKey(s string) string

CanonicalMIMEHeaderKey returns the canonical format of the MIME header key s. The canonicalization converts the first letter and any letter following a hyphen to upper case; the rest are converted to lowercase. For example, the canonical key for "accept-encoding" is "Accept-Encoding". MIME header keys are assumed to be ASCII only. If s contains a space or invalid header field bytes, it is returned without modifications.

Types

type AlgorithmID

type AlgorithmID crypto.Hash

func (AlgorithmID) MarshalText

func (id AlgorithmID) MarshalText() ([]byte, error)

type ArcResult

type ArcResult struct {
	// Final result of verification
	Result

	// Result data at each part of the chain until failure
	Chain []ArcSetResult `json:"chain"`
}

type ArcSetResult

type ArcSetResult struct {
	Instance int        `json:"instance"`
	Spf      ResultCode `json:"spf"`
	Dkim     ResultCode `json:"dkim"`
	Dmarc    ResultCode `json:"dmarc"`
	AMSValid bool       `json:"ams-vaild"`
	ASValid  bool       `json:"as-valid"`
	CV       ResultCode `json:"cv"`
}

ArcSetResult holds the result data for verification of a single arc set

type ErrorSource

type ErrorSource uint8
const (
	VerifyError ErrorSource = iota
	SignatureError
	KeyError
)

type KVPair

type KVPair struct {
	Key      string // Original header key as it was read from the message
	Original string // Original unfolded value of the header
	Folded   string // Folded value of the header
}

KVPair holds key-value pair of the message header as it needed for DKIM verification

type MIMEHeader

type MIMEHeader map[string][]KVPair

A MIMEHeader represents the key-value pairs in a mail message header.

func (MIMEHeader) CanonicalizedAndFolded

func (h MIMEHeader) CanonicalizedAndFolded() map[string][]string

CanonicalizedAndFolded converts MIMEHeader into map[string][]string, where key is canonicalized header and values are folded. The map could be used as mail.Headed

type Message

type Message struct {
	Header MIMEHeader
	Body   io.ReadSeeker
}

func ParseMessage

func ParseMessage(s string) (*Message, error)

type PublicKey

type PublicKey struct {
	Raw        string   `json:"raw,omitempty"`        // raw value of the key record
	Version    string   `json:"version,omitempty"`    // 'v' tag value
	KeyType    string   `json:"key_type,omitempty"`   // 'k' tag value
	Data       []byte   `json:"key,omitempty"`        // 'p' tag value
	Algorithms []string `json:"algorithms,omitempty"` // parsed 'h' tag value; [] means "allowing all"
	Services   []string `json:"services,omitempty"`   // parsed 's' tag value; [] is "*"
	Flags      []string `json:"flags,omitempty"`      // parsed 't' tag value
	Notes      string   `json:"notes,omitempty"`      // 'n' tag value
	Testing    bool     `json:"testing"`              // 't' contains 'y'
	Strict     bool     `json:"strict"`               // 't' contains 's'
	// contains filtered or unexported fields
}

PublicKey holds parsed public key

type PublicKeyQuery

type PublicKeyQuery func(*Signature) (*PublicKey, error)

PublicKeyQuery defines API for implementation of "q=".

type Reader

type Reader struct {
	R *bufio.Reader
	// contains filtered or unexported fields
}

A Reader implements convenience methods for reading requests or responses from a text protocol network connection.

func NewReader

func NewReader(r *bufio.Reader) *Reader

NewReader returns a new Reader reading from r.

To avoid denial of service attacks, the provided bufio.Reader should be reading from an io.LimitReader or similar Reader to bound the size of responses.

func (*Reader) ReadLineBytes

func (r *Reader) ReadLineBytes() ([]byte, error)

ReadLineBytes is like ReadLine but returns a []byte instead of a string.

func (*Reader) ReadMIMEHeader

func (r *Reader) ReadMIMEHeader() (MIMEHeader, error)

ReadMIMEHeader reads a MIME-style header from r. The header is a sequence of possibly continued Key: Value lines ending in a blank line. The returned map m maps CanonicalMIMEHeaderKey(key) to a sequence of values in the same order encountered in the input.

For example, consider this input:

my-key: Value 1
Long-Key: Even
       Longer Value
My-Key: Value 2

Given that input, ReadMIMEHeader returns the map:

 map[string][]KVPair{
     "My-Key": {
         {"my-key", "Value 1", "Value 1"},
		    {"My-Key", "Value 2", "Value 2"},
	    },
	    "Long-Key": {
		    {"Long-Key", "Even\n       Longer Value", "Even Longer Value"},
	    },
 }

type Result

type Result struct {
	Order     int                `json:"order"`
	Result    ResultCode         `json:"code"`
	Error     *VerificationError `json:"error,omitempty"`
	Signature *Signature         `json:"signature,omitempty"`
	Key       *PublicKey         `json:"key,omitempty"`
	Timestamp time.Time          `json:"timestamp"`
}

Result holds all details about result of DKIM signature verification

func Verify

func Verify(hdr string, msg *Message, opts ...VerifyOption) ([]*Result, error)

Verify extracts DKIM signature from message, verifies it and returns Result of verification in accordance with RFC6376 (DKIM Signatures)

func (*Result) String

func (r *Result) String() string

String returns textual representation of DKIM verification result. The representation is NOT conformed with RFC7601, but is compilation of values recommended by RFC7601 and form defined for Received-SPF by RFC7208

type ResultCode

type ResultCode uint8

ResultCode presents a signature verification result in a form defined by RFC7601 in 2.7.1. DKIM and DomainKeys

const (
	None ResultCode
	Pass
	Fail
	Policy
	Neutral
	Temperror
	Permerror
)

DKIM Verification Results

func (ResultCode) MarshalText

func (r ResultCode) MarshalText() ([]byte, error)

func (ResultCode) String

func (r ResultCode) String() string

type Signature

type Signature struct {
	Header string `json:"header"` // Header of the signature
	Raw    string `json:"raw"`    // Raw value of the signature

	AlgorithmID    AlgorithmID       `json:"algorithmId"`             // 3 (SHA1) or 5 (SHA256)
	Hash           []byte            `json:"hash"`                    // 'h' tag value
	BodyHash       []byte            `json:"bodyHash"`                // 'bh' tag value
	RelaxedHeader  bool              `json:"relaxedHeader"`           // header canonicalization algorithm
	RelaxedBody    bool              `json:"relaxedBody"`             // body canonicalization algorithm
	SignerDomain   string            `json:"signerDomain"`            // 'd' tag value
	Headers        []string          `json:"headers"`                 // parsed 'h' tag value
	UserIdentifier string            `json:"userId"`                  // 'i' tag value
	ArcInstance    int               `json:"arcInstance"`             // 'i' tag value (only in arc headers)
	Length         int64             `json:"length"`                  // 'l' tag value
	Selector       string            `json:"selector"`                // 's' tag value
	Timestamp      time.Time         `json:"ts"`                      // 't' tag value as time.Time
	Expiration     time.Time         `json:"exp"`                     // 'x' tag value as time.Time
	CopiedHeaders  map[string]string `json:"copiedHeaders,omitempty"` // parsed 'z' tag value

	// Arc related fields
	ArcCV ResultCode `json:"arcCv"` // 'cv' tag, chain validation value for arc seal
	Spf   ResultCode `json:"spf"`   // spf value for ARC-Authentication-Results
	Dmarc ResultCode `json:"dmarc"` // dmarc value for ARC-Authentication-Results
	Dkim  ResultCode `json:"dkim"`  // dkim value for ARC-Authentication-Results
	// contains filtered or unexported fields
}

Signature holds parsed DKIM signature

type VerificationError

type VerificationError struct {
	Err         error       `json:"error"`
	Explanation string      `json:"explanation,omitempty"`
	Source      ErrorSource `json:"source"`
	Tag         string      `json:"tag,omitempty"`
	Value       string      `json:"value,omitempty"`
}

func (*VerificationError) Error

func (e *VerificationError) Error() string

func (*VerificationError) MarshalJSON

func (e *VerificationError) MarshalJSON() ([]byte, error)

type VerifyOption

type VerifyOption func(s *Signature, k *PublicKey, m *Message) (ResultCode, error)

VerifyOption provides way to extend signature verification. Verifiers MAY ignore the DKIM-Signature Header field and return PERMFAIL (unacceptable signature Header) for any other reason, for example, if the signature does not sign Header fields that the Verifier views to be essential. As a case in point, if MIME Header fields are not signed, certain attacks may be possible that the Verifier would prefer to avoid.

func InvalidSigningEntityOption

func InvalidSigningEntityOption(domains ...string) VerifyOption

InvalidSigningEntityOption checks if domain of "i=" equals to "d=". Verifiers MAY ignore the DKIM-Signature Header field if the domain used by the Signer in the "d=" tag is not associated with a valid signing entity. For example, signatures with "d=" values such as "com" and "co.uk" could be ignored. The list of unacceptable domains SHOULD be configurable.

func SignatureTimingOption

func SignatureTimingOption(drift time.Duration) VerifyOption

SignatureTimingOption checks if signature is expired Verifiers MAY ignore the DKIM-Signature Header field and return PERMFAIL (signature expired) if it contains an "x=" tag and the signature has expired.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL