verify 1
This commit is contained in:
91
dkim.go
91
dkim.go
@@ -68,14 +68,14 @@ type sigOptions struct {
|
||||
SignatureExpireIn uint64
|
||||
|
||||
// CopiedHeaderFileds
|
||||
CopiedHeaderFileds []string
|
||||
CopiedHeaderFields []string
|
||||
}
|
||||
|
||||
// NewSigOption returns new sigoption with some defaults value
|
||||
func NewSigOptions() sigOptions {
|
||||
return sigOptions{
|
||||
Version: 1,
|
||||
Canonicalization: "relaxed/simple",
|
||||
Canonicalization: "simple/simple",
|
||||
Algo: "rsa-sha256",
|
||||
Headers: []string{"from"},
|
||||
BodyLength: 0,
|
||||
@@ -111,18 +111,9 @@ func Sign(email *[]byte, options sigOptions) error {
|
||||
}
|
||||
|
||||
// Canonicalization
|
||||
options.Canonicalization = strings.ToLower(options.Canonicalization)
|
||||
p := strings.Split(options.Canonicalization, "/")
|
||||
if len(p) > 2 {
|
||||
return ErrSignBadCanonicalization
|
||||
}
|
||||
if len(p) == 1 {
|
||||
options.Canonicalization = options.Canonicalization + "/simple"
|
||||
}
|
||||
for _, c := range p {
|
||||
if c != "simple" && c != "relaxed" {
|
||||
return ErrSignBadCanonicalization
|
||||
}
|
||||
options.Canonicalization, err = validateCanonicalization(strings.ToLower(options.Canonicalization))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Algo
|
||||
@@ -146,7 +137,7 @@ func Sign(email *[]byte, options sigOptions) error {
|
||||
}
|
||||
|
||||
// Normalize
|
||||
headers, body, err := canonicalize(email, options)
|
||||
headers, body, err := canonicalize(email, options.Canonicalization, options.Headers)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -179,7 +170,7 @@ func Sign(email *[]byte, options sigOptions) error {
|
||||
|
||||
// Get dkim header base
|
||||
dkimHeader := NewDkimHeaderBySigOptions(options)
|
||||
dHeader := dkimHeader.GetHeaderBase(bodyHash)
|
||||
dHeader := dkimHeader.GetHeaderBaseForSigning(bodyHash)
|
||||
|
||||
canonicalizations := strings.Split(options.Canonicalization, "/")
|
||||
dHeaderCanonicalized, err := canonicalizeHeader(dHeader, canonicalizations[0])
|
||||
@@ -214,8 +205,35 @@ func Sign(email *[]byte, options sigOptions) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// verify verifies an email an return
|
||||
// state: SUCCESS or PERMFAIL or TEMPFAIL or NOTSIGNED
|
||||
// msg: a complementary message (if needed)
|
||||
// error: if an error occurs during verification
|
||||
func Verify(email *[]byte) (state, msg string, err error) {
|
||||
// parse email
|
||||
dkimHeader, err := NewFromEmail(email)
|
||||
if err != nil {
|
||||
if err == ErrDkimHeaderNotFound {
|
||||
return "NOTSIGNED", ErrDkimHeaderNotFound.Error(), nil
|
||||
} else {
|
||||
return "PERMFAIL", err.Error(), err
|
||||
}
|
||||
}
|
||||
println(dkimHeader)
|
||||
|
||||
// // Normalize
|
||||
headers, body, err := canonicalize(email, dkimHeader.MessageCanonicalization, dkimHeader.Headers)
|
||||
if err != nil {
|
||||
return "PERMFAIL", err.Error(), err
|
||||
}
|
||||
|
||||
// HERE
|
||||
|
||||
return "SUCCESS", "", nil
|
||||
}
|
||||
|
||||
// canonicalize returns canonicalized version of header and body
|
||||
func canonicalize(email *[]byte, options sigOptions) (headers, body []byte, err error) {
|
||||
func canonicalize(email *[]byte, cano string, h []string) (headers, body []byte, err error) {
|
||||
body = []byte{}
|
||||
rxReduceWS := regexp.MustCompile(`[ \t]+`)
|
||||
|
||||
@@ -231,7 +249,7 @@ func canonicalize(email *[]byte, options sigOptions) (headers, body []byte, err
|
||||
parts[1] = []byte{13, 10}
|
||||
}
|
||||
|
||||
canonicalizations := strings.Split(options.Canonicalization, "/")
|
||||
canonicalizations := strings.Split(cano, "/")
|
||||
|
||||
// canonicalyze header
|
||||
headersList := list.New()
|
||||
@@ -258,7 +276,7 @@ func canonicalize(email *[]byte, options sigOptions) (headers, body []byte, err
|
||||
var match *list.Element
|
||||
headersToKeepList := list.New()
|
||||
|
||||
for _, headerToKeep := range options.Headers {
|
||||
for _, headerToKeep := range h {
|
||||
match = nil
|
||||
headerToKeepToLower := strings.ToLower(headerToKeep)
|
||||
for e := headersList.Front(); e != nil; e = e.Next() {
|
||||
@@ -323,7 +341,7 @@ func canonicalize(email *[]byte, options sigOptions) (headers, body []byte, err
|
||||
|
||||
// canonicalizeHeader returns canonicalized version of header
|
||||
func canonicalizeHeader(header string, algo string) (string, error) {
|
||||
rxReduceWS := regexp.MustCompile(`[ \t]+`)
|
||||
//rxReduceWS := regexp.MustCompile(`[ \t]+`)
|
||||
if algo == "simple" {
|
||||
// The "simple" header canonicalization algorithm does not change header
|
||||
// fields in any way. Header fields MUST be presented to the signing or
|
||||
@@ -360,11 +378,36 @@ func canonicalizeHeader(header string, algo string) (string, error) {
|
||||
}
|
||||
k := strings.ToLower(kv[0])
|
||||
k = strings.TrimSpace(k)
|
||||
v := strings.Replace(kv[1], "\n", "", -1)
|
||||
v = strings.Replace(v, "\r", "", -1)
|
||||
v = rxReduceWS.ReplaceAllString(v, " ")
|
||||
v = strings.TrimSpace(v)
|
||||
v := removeFWS(kv[1])
|
||||
//v = rxReduceWS.ReplaceAllString(v, " ")
|
||||
//v = strings.TrimSpace(v)
|
||||
return k + ":" + v + CRLF, nil
|
||||
}
|
||||
return header, ErrSignBadCanonicalization
|
||||
}
|
||||
|
||||
// removeFWS removes all FWS from string
|
||||
func removeFWS(in string) string {
|
||||
rxReduceWS := regexp.MustCompile(`[ \t]+`)
|
||||
out := strings.Replace(in, "\n", "", -1)
|
||||
out = strings.Replace(out, "\r", "", -1)
|
||||
out = rxReduceWS.ReplaceAllString(out, " ")
|
||||
return strings.TrimSpace(out)
|
||||
}
|
||||
|
||||
// validateCanonicalization validate canonicalization (c flag)
|
||||
func validateCanonicalization(cano string) (string, error) {
|
||||
p := strings.Split(cano, "/")
|
||||
if len(p) > 2 {
|
||||
return "", ErrSignBadCanonicalization
|
||||
}
|
||||
if len(p) == 1 {
|
||||
cano = cano + "/simple"
|
||||
}
|
||||
for _, c := range p {
|
||||
if c != "simple" && c != "relaxed" {
|
||||
return "", ErrSignBadCanonicalization
|
||||
}
|
||||
}
|
||||
return cano, nil
|
||||
}
|
||||
|
||||
172
dkimHeader.go
172
dkimHeader.go
@@ -1,7 +1,12 @@
|
||||
package dkim
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/mail"
|
||||
"net/textproto"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
@@ -180,7 +185,16 @@ type DkimHeader struct {
|
||||
// in the "z=" tag. Copied header field values are for diagnostic
|
||||
// use.
|
||||
// tag z
|
||||
CopiedHeaderFileds []string
|
||||
CopiedHeaderFields []string
|
||||
|
||||
// HeaderMailFromDomain store the raw email address of the header Mail From
|
||||
// used for verifying in case of multiple DKIM header (we will prioritise
|
||||
// header with d = mail from domain)
|
||||
//HeaderMailFromDomain string
|
||||
|
||||
// RawForsign represents the raw part (with non canonicalization) of the header
|
||||
// used for computint sig in verify process
|
||||
RawForSign string
|
||||
}
|
||||
|
||||
// NewDkimHeaderBySigOptions return a new DkimHeader initioalized with sigOptions value
|
||||
@@ -201,13 +215,165 @@ func NewDkimHeaderBySigOptions(options sigOptions) *DkimHeader {
|
||||
if options.SignatureExpireIn > 0 {
|
||||
h.SignatureExpiration = time.Now().Add(time.Duration(options.SignatureExpireIn) * time.Second)
|
||||
}
|
||||
h.CopiedHeaderFileds = options.CopiedHeaderFileds
|
||||
h.CopiedHeaderFields = options.CopiedHeaderFields
|
||||
return h
|
||||
}
|
||||
|
||||
// NewFromEmail return a new DkimHeader by parsing an email
|
||||
// Note: according to RFC 6376 an email can have multiple DKIM Header
|
||||
// in this case we return the last inserted or the last with d== mail from
|
||||
func NewFromEmail(email *[]byte) (*DkimHeader, error) {
|
||||
m, err := mail.ReadMessage(bytes.NewReader(*email))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// DKIM header ?
|
||||
if len(m.Header[textproto.CanonicalMIMEHeaderKey("DKIM-Signature")]) == 0 {
|
||||
return nil, ErrDkimHeaderNotFound
|
||||
}
|
||||
|
||||
// Get mail from domain
|
||||
mailFromDomain := ""
|
||||
mailfrom, err := mail.ParseAddress(m.Header.Get(textproto.CanonicalMIMEHeaderKey("From")))
|
||||
if err != nil {
|
||||
if err.Error() != "mail: no address" {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
t := strings.SplitAfter(mailfrom.Address, "@")
|
||||
if len(t) > 1 {
|
||||
mailFromDomain = strings.ToLower(t[1])
|
||||
}
|
||||
}
|
||||
|
||||
var keep *DkimHeader
|
||||
var keepErr error
|
||||
for _, dk := range m.Header[textproto.CanonicalMIMEHeaderKey("DKIM-Signature")] {
|
||||
parsed, err := parseDkHeader(dk)
|
||||
// if malformed dkim header try next
|
||||
if err != nil {
|
||||
keepErr = err
|
||||
continue
|
||||
}
|
||||
// Keep first dkim headers
|
||||
if keep == nil {
|
||||
keep = parsed
|
||||
}
|
||||
// if d flag == domain keep this header and return
|
||||
if mailFromDomain == parsed.Domain {
|
||||
return parsed, nil
|
||||
}
|
||||
}
|
||||
if keep == nil {
|
||||
return nil, keepErr
|
||||
}
|
||||
return keep, nil
|
||||
}
|
||||
|
||||
func parseDkHeader(header string) (dkh *DkimHeader, err error) {
|
||||
dkh = new(DkimHeader)
|
||||
|
||||
t := strings.LastIndex(header, "b=")
|
||||
if t == -1 {
|
||||
return nil, ErrDkimHeaderBTagNotFound
|
||||
}
|
||||
dkh.RawForSign = header[0 : t+2]
|
||||
// Mandatory
|
||||
mandatoryFlags := make(map[string]bool, 7) //(b'v', b'a', b'b', b'bh', b'd', b'h', b's')
|
||||
mandatoryFlags["v"] = false
|
||||
mandatoryFlags["a"] = false
|
||||
mandatoryFlags["b"] = false
|
||||
mandatoryFlags["bh"] = false
|
||||
mandatoryFlags["d"] = false
|
||||
mandatoryFlags["h"] = false
|
||||
mandatoryFlags["s"] = false
|
||||
|
||||
// default values
|
||||
dkh.MessageCanonicalization = "simple/simple"
|
||||
dkh.QueryMethods = []string{"dns/txt"}
|
||||
|
||||
fs := strings.Split(header, ";")
|
||||
for _, f := range fs {
|
||||
flagData := strings.SplitN(f, "=", 2)
|
||||
flag := strings.ToLower(strings.TrimSpace(flagData[0]))
|
||||
data := strings.TrimSpace(flagData[1])
|
||||
switch flag {
|
||||
case "v":
|
||||
if data != "1" {
|
||||
return nil, ErrDkimVersionUnsuported
|
||||
}
|
||||
dkh.Version = data
|
||||
mandatoryFlags["v"] = true
|
||||
case "a":
|
||||
dkh.Algorithm = strings.ToLower(data)
|
||||
if dkh.Algorithm != "rsa-sha1" && dkh.Algorithm != "rsa-sha256" {
|
||||
return nil, ErrSignBadAlgo
|
||||
}
|
||||
mandatoryFlags["a"] = true
|
||||
case "b":
|
||||
dkh.SignatureData = removeFWS(data)
|
||||
mandatoryFlags["b"] = true
|
||||
case "bh":
|
||||
dkh.BodyHash = removeFWS(data)
|
||||
mandatoryFlags["bh"] = true
|
||||
case "d":
|
||||
dkh.Domain = strings.ToLower(data)
|
||||
mandatoryFlags["d"] = true
|
||||
case "h":
|
||||
data = strings.ToLower(data)
|
||||
dkh.Headers = strings.Split(data, ":")
|
||||
mandatoryFlags["h"] = true
|
||||
case "s":
|
||||
dkh.Selector = strings.ToLower(data)
|
||||
mandatoryFlags["s"] = true
|
||||
case "c":
|
||||
dkh.MessageCanonicalization, err = validateCanonicalization(strings.ToLower(data))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
case "i":
|
||||
dkh.Auid = data
|
||||
case "l":
|
||||
ui, err := strconv.ParseUint(data, 10, 32)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dkh.BodyLength = uint(ui)
|
||||
case "q":
|
||||
dkh.QueryMethods = strings.Split(data, ":")
|
||||
case "t":
|
||||
ts, err := strconv.ParseInt(data, 10, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dkh.SignatureTimestamp = time.Unix(ts, 0)
|
||||
|
||||
case "x":
|
||||
ts, err := strconv.ParseInt(data, 10, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dkh.SignatureExpiration = time.Unix(ts, 0)
|
||||
case "z":
|
||||
dkh.CopiedHeaderFields = strings.Split(data, "|")
|
||||
}
|
||||
}
|
||||
|
||||
// All mandatory flags are in ?
|
||||
for f, p := range mandatoryFlags {
|
||||
if !p {
|
||||
return nil, errors.New("missing '" + f + "' flag in DKIM header")
|
||||
}
|
||||
}
|
||||
|
||||
return dkh, nil
|
||||
|
||||
}
|
||||
|
||||
// GetHeaderBase return base header for signers
|
||||
// Todo: some refactoring needed...
|
||||
func (d *DkimHeader) GetHeaderBase(bodyHash string) string {
|
||||
func (d *DkimHeader) GetHeaderBaseForSigning(bodyHash string) string {
|
||||
h := "DKIM-Signature: v=" + d.Version + "; a=" + d.Algorithm + "; q=" + strings.Join(d.QueryMethods, ":") + "; c=" + d.MessageCanonicalization + ";" + CRLF + TAB
|
||||
subh := "s=" + d.Selector + ";"
|
||||
if len(subh)+len(d.Domain)+4 > MaxHeaderLineLength {
|
||||
|
||||
82
dkim_test.go
82
dkim_test.go
@@ -52,6 +52,23 @@ var emailBase = "Received: (qmail 28277 invoked from network); 1 May 2015 09:43:
|
||||
"-- " + CRLF +
|
||||
"Toorop" + CRLF + CRLF + CRLF + CRLF + CRLF + CRLF
|
||||
|
||||
var emailBaseNoFrom = "Received: (qmail 28277 invoked from network); 1 May 2015 09:43:37 -0000" + CRLF +
|
||||
"Received: (qmail 21323 invoked from network); 1 May 2015 09:48:39 -0000" + CRLF +
|
||||
"Received: from mail483.ha.ovh.net (b6.ovh.net [213.186.33.56])" + CRLF +
|
||||
" by mo51.mail-out.ovh.net (Postfix) with SMTP id A6E22FF8934" + CRLF +
|
||||
" for <toorop@toorop.fr>; Mon, 4 May 2015 14:00:47 +0200 (CEST)" + CRLF +
|
||||
"MIME-Version: 1.0" + CRLF +
|
||||
"Date: Fri, 1 May 2015 11:48:37 +0200" + CRLF +
|
||||
"Message-ID: <CADu37kTXBeNkJdXc4bSF8DbJnXmNjkLbnswK6GzG_2yn7U7P6w@tmail.io>" + CRLF +
|
||||
"Subject: Test DKIM" + CRLF +
|
||||
"To: =?UTF-8?Q?St=C3=A9phane_Depierrepont?= <toorop@toorop.fr>" + CRLF +
|
||||
"Content-Type: text/plain; charset=UTF-8" + CRLF + CRLF +
|
||||
"Hello world" + CRLF +
|
||||
"line with trailing space " + CRLF +
|
||||
"line with space " + CRLF +
|
||||
"-- " + CRLF +
|
||||
"Toorop" + CRLF + CRLF + CRLF + CRLF + CRLF + CRLF
|
||||
|
||||
var headerSimple = "From: =?UTF-8?Q?St=C3=A9phane_Depierrepont?= <toorop@tmail.io>" + CRLF +
|
||||
"Date: Fri, 1 May 2015 11:48:37 +0200" + CRLF +
|
||||
"MIME-Version: 1.0" + CRLF +
|
||||
@@ -94,10 +111,44 @@ var signedSimpleSimple = "DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=simple
|
||||
" AKF2TcTLZ++1nalq+djU+/aP4KYQd4RWWFBjkxDzvCH4bvB1M5AGp4Qz9ldmdMQBWOvvSp" + CRLF +
|
||||
" DIpJW4XNA/uqLSswtjCYbJsSg9Ywv1o=" + CRLF + emailBase
|
||||
|
||||
var signedNoFrom = "DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=simple/simple;" + CRLF +
|
||||
" s=test; d=tmail.io; l=5; h=from:date:mime-version:received:received;" + CRLF +
|
||||
" bh=GF+NsyJx/iX1Yab8k4suJkMG7DBO2lGAB9F2SCY4GWk=;" + CRLF +
|
||||
" b=SoEhlu1Emm2ASqo8jMhz6FIf2nNHt3ouY4Av/pFFEkQ048RqUFP437ap7RbtL2wh0N3Kkm" + CRLF +
|
||||
" AKF2TcTLZ++1nalq+djU+/aP4KYQd4RWWFBjkxDzvCH4bvB1M5AGp4Qz9ldmdMQBWOvvSp" + CRLF +
|
||||
" DIpJW4XNA/uqLSswtjCYbJsSg9Ywv1o=" + CRLF + emailBaseNoFrom
|
||||
|
||||
var signedMissingFlag = "DKIM-Signature: v=1; q=dns/txt; c=simple/simple;" + CRLF +
|
||||
" s=test; d=tmail.io; l=5; h=from:date:mime-version:received:received;" + CRLF +
|
||||
" bh=GF+NsyJx/iX1Yab8k4suJkMG7DBO2lGAB9F2SCY4GWk=;" + CRLF +
|
||||
" b=SoEhlu1Emm2ASqo8jMhz6FIf2nNHt3ouY4Av/pFFEkQ048RqUFP437ap7RbtL2wh0N3Kkm" + CRLF +
|
||||
" AKF2TcTLZ++1nalq+djU+/aP4KYQd4RWWFBjkxDzvCH4bvB1M5AGp4Qz9ldmdMQBWOvvSp" + CRLF +
|
||||
" DIpJW4XNA/uqLSswtjCYbJsSg9Ywv1o=" + CRLF + emailBase
|
||||
|
||||
var signedBadAlgo = "DKIM-Signature: v=1; a=rsa-shasha; q=dns/txt; c=simple/simple;" + CRLF +
|
||||
" s=test; d=tmail.io; l=5; h=from:date:mime-version:received:received;" + CRLF +
|
||||
" bh=GF+NsyJx/iX1Yab8k4suJkMG7DBO2lGAB9F2SCY4GWk=;" + CRLF +
|
||||
" b=SoEhlu1Emm2ASqo8jMhz6FIf2nNHt3ouY4Av/pFFEkQ048RqUFP437ap7RbtL2wh0N3Kkm" + CRLF +
|
||||
" AKF2TcTLZ++1nalq+djU+/aP4KYQd4RWWFBjkxDzvCH4bvB1M5AGp4Qz9ldmdMQBWOvvSp" + CRLF +
|
||||
" DIpJW4XNA/uqLSswtjCYbJsSg9Ywv1o=" + CRLF + emailBase
|
||||
|
||||
var signedDouble = "DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=simple/simple;" + CRLF +
|
||||
" s=test; d=tmail.io; l=5; h=from:date:mime-version:received:received;" + CRLF +
|
||||
" bh=GF+NsyJx/iX1Yab8k4suJkMG7DBO2lGAB9F2SCY4GWk=;" + CRLF +
|
||||
" b=SoEhlu1Emm2ASqo8jMhz6FIf2nNHt3ouY4Av/pFFEkQ048RqUFP437ap7RbtL2wh0N3Kkm" + CRLF +
|
||||
" AKF2TcTLZ++1nalq+djU+/aP4KYQd4RWWFBjkxDzvCH4bvB1M5AGp4Qz9ldmdMQBWOvvSp" + CRLF +
|
||||
" DIpJW4XNA/uqLSswtjCYbJsSg9Ywv1o=" + CRLF +
|
||||
"DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed;" + CRLF +
|
||||
" s=test; d=tmail.io; l=5; h=from:date:mime-version:received:received;" + CRLF +
|
||||
" bh=GF+NsyJx/iX1Yab8k4suJkMG7DBO2lGAB9F2SCY4GWk=;" + CRLF +
|
||||
" b=byhiFWd0lAM1sqD1tl8S1DZtKNqgiEZp8jrGds6RRydnZkdX9rCPeL0Q5MYWBQ/JmQrml5" + CRLF +
|
||||
" pIghLwl/EshDBmNy65O6qO8pSSGgZmM3T7SRLMloex8bnrBJ4KSYcHV46639gVEWcBOKW0" + CRLF +
|
||||
" h1djZu2jaTuxGeJzlFVtw3Arf2B93cc=" + CRLF + emailBase
|
||||
|
||||
func Test_NewSigOptions(t *testing.T) {
|
||||
options := NewSigOptions()
|
||||
assert.Equal(t, "rsa-sha256", options.Algo)
|
||||
assert.Equal(t, "relaxed/simple", options.Canonicalization)
|
||||
assert.Equal(t, "simple/simple", options.Canonicalization)
|
||||
}
|
||||
|
||||
/*func Test_SignConfig(t *testing.T) {
|
||||
@@ -203,3 +254,32 @@ func Test_Sign(t *testing.T) {
|
||||
assert.Equal(t, []byte(signedSimpleSimple), emailSimple)
|
||||
|
||||
}
|
||||
|
||||
func Test_Verify(t *testing.T) {
|
||||
// no DKIM header
|
||||
email := []byte(emailBase)
|
||||
status, msg, err := Verify(&email)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "NOTSIGNED", status)
|
||||
assert.Equal(t, ErrDkimHeaderNotFound.Error(), msg)
|
||||
|
||||
// No From
|
||||
email = []byte(signedNoFrom)
|
||||
status, msg, err = Verify(&email)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "SUCCESS", status)
|
||||
|
||||
// missing mandatory 'a' flag
|
||||
email = []byte(signedMissingFlag)
|
||||
status, msg, err = Verify(&email)
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "PERMFAIL", status)
|
||||
assert.Equal(t, "missing 'a' flag in DKIM header", msg)
|
||||
|
||||
// missing bad algo
|
||||
email = []byte(signedBadAlgo)
|
||||
status, msg, err = Verify(&email)
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "PERMFAIL", status)
|
||||
assert.Equal(t, ErrSignBadAlgo.Error(), msg)
|
||||
}
|
||||
|
||||
11
errors.go
11
errors.go
@@ -34,4 +34,15 @@ var (
|
||||
|
||||
// ErrBadDKimTagLBodyTooShort
|
||||
ErrBadDKimTagLBodyTooShort = errors.New("bad tag l or bodyLength option. Body length < l value")
|
||||
|
||||
// ErrDkimHeaderNotFound when there's no DKIM-Signature header in an email we have to verify
|
||||
ErrDkimHeaderNotFound = errors.New("no DKIM-Signature header field found ")
|
||||
|
||||
// ErrDkimHeaderBTagNotFound when there's no b tag
|
||||
ErrDkimHeaderBTagNotFound = errors.New("no tag 'b' found in dkim header")
|
||||
|
||||
ErrDkimHeaderMissingTagV = errors.New("no tag 'v' found in dkim header")
|
||||
|
||||
// Version not supported
|
||||
ErrDkimVersionUnsuported = errors.New("unsuported DKIM version")
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user