dkim

package module
v0.0.0-...-d51ec4f Latest Latest
Warning

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

Go to latest
Published: May 17, 2016 License: MIT Imports: 12 Imported by: 0

README

dkim

Library for signing emails with DKIM.

The purpose of this library is to create a solution for DKIM signing in Go that is fast, simple, and suitable for bulk mail applications.

To create the body hash, the body can be written in chunks, written all at once, or copied from an io.Reader using io.Copy. There is no need to present the complete message or body as a byte slice in memory. At this moment only "simple" body canonicalization is supported, which is efficient and secure. The only prerequisite is that body lines have proper CRLF line terminators.

The create the header hash, a standard mail.Header is used for input. This saves parsing when a mail.Header is already available. At this moment only "relaxed" header canonicalization is supported, which is reliable and most common. Part of the canonicalization is done by mail.ReadMessage or textproto.Reader.ReadMIMEHeader when a mail.Header is created.

Because mail.Header is implemented with a map, the order of headers in the "h=" tag is non-deterministic. Repeated headers are represented as array values in mail.Header and are signed bottom most first. This should be fine, since validators will follow the ordering in the "h=" tag and repeated headers are processed in the same order as they are signed.

The hashing algorithm is considered a global policy and can be changed from SHA256 to SHA1. The headers that are included in the signature can also be changed by modifying a global parameter. For headers that are repeated all instances will be signed.

Using

First create a signing domain from a private key in memory or read it from disk:

domain, err := dkim.ReadDomain("emailfabric.com", "test", "testdata/test.rsa")
if err != nil {
	return
}

You need a mail.Header for the email header and a io.Reader for the email body. You can use mail.ReadMessage to create these:

msg, err := mail.ReadMessage(bytes.NewReader(data))
if err != nil {
	return
}

Creating the signature goes as follows:

sig := dkim.NewSignature(domain)

// step 1
_, err = io.Copy(sig.BodyWriter(), msg.Body)
if err != nil {
	return
}

// step 2
err = sig.SignHeader(msg.Header)
if err != nil {
	return
}

The signature must be prepended to the email header. Just write it before writing the email message:

_, err = sig.WriteTo(writer)
if err != nil {
	return
}

Complete API documentation can be found at GoDoc.

Documentation

Overview

Package dkim is used for signing emails with DKIM.

Index

Constants

This section is empty.

Variables

Hash is the algorithm used for hashing. SHA256 is recommended by the RFC. Change this to crypto.SHA1 if you need to.

View Source
var SignHeaderFields = []string{
	"From",
	"Reply-to",
	"Subject",
	"Date",
	"To",
	"Cc",
	"Resent-Date",
	"Resent-From",
	"Resent-Sender",
	"Resent-To",
	"Resent-Cc",
	"In-Reply-To",
	"References",
	"List-Id",
	"List-Help",
	"List-Unsubscribe",
	"List-Subscribe",
	"List-Post",
	"List-Owner",
	"List-Archive",
}

SignHeaderFields lists the header names to sign. These headers are recommended in RFC 6376 section 5.4.1. The list can be changed at will. This implementation signs each instance, if the header field occurs more than once. The basic rule for choosing fields to include is to select those fields that constitute the "core" of the message content. Note that "From" is required and "DKIM-Signature" is implicitly signed.

Functions

func GenerateKeyPair

func GenerateKeyPair(bits int) (keyPEM []byte, pubB64 string, err error)

GenerateKeyPair returns a new PEM encoded private key and base64 encoded public key.

func ParsePrivateKey

func ParsePrivateKey(keyPEM []byte) (key *rsa.PrivateKey, err error)

ParsePrivateKey returns the private key from a PEM formatted block.

Types

type Domain

type Domain struct {
	Name       string
	Selector   string
	PrivateKey *rsa.PrivateKey
}

Domain used for DKIM signing. Which domain to use for signing is left to the user. Common (and best) practice is to use the same domain as in the Sender: or From: header.

func ReadDomain

func ReadDomain(name, selector, keyfile string) (domain *Domain, err error)

ReadDomain creates a signing domain from name, selector and file with PEM encoded private key.

type Signature

type Signature struct {
	// contains filtered or unexported fields
}

Signature represents DKIM-Signature header field.

func NewSignature

func NewSignature(domain *Domain) *Signature

NewSignature creates a signature signed by the specified domain.

func (*Signature) BodyWriter

func (sig *Signature) BodyWriter() io.Writer

BodyWriter returns a writer that should receive the message body for calculating the body hash in the "bh=" tag. The body should be written before SignHeader is called. It is assumed that the body has proper CRLF line ends.

func (*Signature) SignHeader

func (sig *Signature) SignHeader(header mail.Header) (err error)

SignHeader adds the header fields in SignHeaderFields from the mail.Header to the signature. The header hash is signed with the domain private key and used for the "b=" tag.

func (*Signature) WriteTo

func (sig *Signature) WriteTo(w io.Writer) (n int64, err error)

WriteTo writes the complete DKIM-Signature with trailing CRLF to the writer.

Jump to

Keyboard shortcuts

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