package dkim
import "github.com/emersion/go-msgauth/dkim"
Package dkim creates and verifies DKIM signatures, as specified in RFC 6376.
FAQ
Why can't I verify a net/mail.Message directly? A net/mail.Message header is already parsed, and whitespace characters (especially continuation lines) are removed. Thus, the signature computed from the parsed header is not the same as the one computed from the raw header.
How can I publish my public key? You have to add a TXT record to your DNS zone. See RFC 6376 appendix C. You can use the dkim-keygen tool included in go-msgauth to generate the key and the TXT record.
Index ¶
- Variables
- func IsPermFail(err error) bool
- func IsTempFail(err error) bool
- func Sign(w io.Writer, r io.Reader, options *SignOptions) error
- type Canonicalization
- type QueryMethod
- type SignOptions
- type Signer
- func NewSigner(options *SignOptions) (*Signer, error)
- func (s *Signer) Close() error
- func (s *Signer) Signature() string
- func (s *Signer) Write(b []byte) (n int, err error)
- type Verification
- func Verify(r io.Reader) ([]*Verification, error)
- func VerifyWithOptions(r io.Reader, options *VerifyOptions) ([]*Verification, error)
- type VerifyOptions
Examples ¶
Variables ¶
ErrTooManySignatures is returned by Verify when the message exceeds the maximum number of signatures.
Functions ¶
func IsPermFail ¶
IsPermFail returns true if the error returned by Verify is a permanent failure. A permanent failure is for instance a missing required field or a malformed header.
func IsTempFail ¶
IsTempFail returns true if the error returned by Verify is a temporary failure.
func Sign ¶
Sign signs a message. It reads it from r and writes the signed version to w.
Code:play
Example¶
package main
import (
"bytes"
"crypto"
"log"
"strings"
"github.com/emersion/go-msgauth/dkim"
)
var (
mailString string
privateKey crypto.Signer
)
func main() {
r := strings.NewReader(mailString)
options := &dkim.SignOptions{
Domain: "example.org",
Selector: "brisbane",
Signer: privateKey,
}
var b bytes.Buffer
if err := dkim.Sign(&b, r, options); err != nil {
log.Fatal(err)
}
}
Types ¶
type Canonicalization ¶
type Canonicalization string
Canonicalization is a canonicalization algorithm.
const ( CanonicalizationSimple Canonicalization = "simple" CanonicalizationRelaxed = "relaxed" )
type QueryMethod ¶
type QueryMethod string
QueryMethod is a DKIM query method.
const ( // DNS TXT resource record (RR) lookup algorithm QueryMethodDNSTXT QueryMethod = "dns/txt" )
type SignOptions ¶
type SignOptions struct { // The SDID claiming responsibility for an introduction of a message into the // mail stream. Hence, the SDID value is used to form the query for the public // key. The SDID MUST correspond to a valid DNS name under which the DKIM key // record is published. // // This can't be empty. Domain string // The selector subdividing the namespace for the domain. // // This can't be empty. Selector string // The Agent or User Identifier (AUID) on behalf of which the SDID is taking // responsibility. // // This is optional. Identifier string // The key used to sign the message. // // Supported Signer.Public() values are *rsa.PublicKey and // ed25519.PublicKey. Signer crypto.Signer // The hash algorithm used to sign the message. If zero, a default hash will // be chosen. // // The only supported hash algorithm is crypto.SHA256. Hash crypto.Hash // Header and body canonicalization algorithms. // // If empty, CanonicalizationSimple is used. HeaderCanonicalization Canonicalization BodyCanonicalization Canonicalization // A list of header fields to include in the signature. If nil, all headers // will be included. If not nil, "From" MUST be in the list. // // See RFC 6376 section 5.4.1 for recommended header fields. HeaderKeys []string // The expiration time. A zero value means no expiration. Expiration time.Time // A list of query methods used to retrieve the public key. // // If nil, it is implicitly defined as QueryMethodDNSTXT. QueryMethods []QueryMethod }
SignOptions is used to configure Sign. Domain, Selector and Signer are mandatory.
type Signer ¶
type Signer struct {
// contains filtered or unexported fields
}
Signer generates a DKIM signature.
The whole message header and body must be written to the Signer. Close should always be called (either after the whole message has been written, or after an error occurred and the signer won't be used anymore). Close may return an error in case signing fails.
After a successful Close, Signature can be called to retrieve the DKIM-Signature header field that the caller should prepend to the message.
func NewSigner ¶
func NewSigner(options *SignOptions) (*Signer, error)
NewSigner creates a new signer. It returns an error if SignOptions is invalid.
func (*Signer) Close ¶
Close implements io.WriteCloser. The error return by Close must be checked.
func (*Signer) Signature ¶
Signature returns the whole DKIM-Signature header field. It can only be called after a successful Signer.Close call.
The returned value contains both the header field name, its value and the final CRLF.
func (*Signer) Write ¶
Write implements io.WriteCloser.
type Verification ¶
type Verification struct { // The SDID claiming responsibility for an introduction of a message into the // mail stream. Domain string // The Agent or User Identifier (AUID) on behalf of which the SDID is taking // responsibility. Identifier string // The list of signed header fields. HeaderKeys []string // The time that this signature was created. If unknown, it's set to zero. Time time.Time // The expiration time. If the signature doesn't expire, it's set to zero. Expiration time.Time // Err is nil if the signature is valid. Err error }
A Verification is produced by Verify when it checks if one signature is valid. If the signature is valid, Err is nil.
func Verify ¶
func Verify(r io.Reader) ([]*Verification, error)
Verify checks if a message's signatures are valid. It returns one verification per signature.
There is no guarantee that the reader will be completely consumed.
Code:play
Example¶
package main
import (
"crypto"
"log"
"strings"
"github.com/emersion/go-msgauth/dkim"
)
var mailString string
func main() {
r := strings.NewReader(mailString)
verifications, err := dkim.Verify(r)
if err != nil {
log.Fatal(err)
}
for _, v := range verifications {
if v.Err == nil {
log.Println("Valid signature for:", v.Domain)
} else {
log.Println("Invalid signature for:", v.Domain, v.Err)
}
}
}
func VerifyWithOptions ¶
func VerifyWithOptions(r io.Reader, options *VerifyOptions) ([]*Verification, error)
VerifyWithOptions performs the same task as Verify, but allows specifying verification options.
type VerifyOptions ¶
type VerifyOptions struct { // LookupTXT returns the DNS TXT records for the given domain name. If nil, // net.LookupTXT is used. LookupTXT func(domain string) ([]string, error) // MaxVerifications controls the maximum number of signature verifications // to perform. If more signatures are present, the first MaxVerifications // signatures are verified, the rest are ignored and ErrTooManySignatures // is returned. If zero, there is no maximum. MaxVerifications int }
VerifyOptions allows to customize the default signature verification behavior.
Source Files ¶
canonical.go dkim.go header.go query.go sign.go verify.go
- Version
- v0.6.8 (latest)
- Published
- Jan 5, 2024
- Platform
- linux/amd64
- Imports
- 21 packages
- Last checked
- 6 days ago –
Tools for package owners.