body canonicalization
This commit is contained in:
35
dkim.go
35
dkim.go
@@ -2,11 +2,17 @@ package dkim
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
//"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
CRLF = "\r\n"
|
||||||
|
)
|
||||||
|
|
||||||
// sigOptions represents signing options
|
// sigOptions represents signing options
|
||||||
type sigOptions struct {
|
type sigOptions struct {
|
||||||
|
|
||||||
@@ -128,6 +134,9 @@ func Sign(email *bytes.Reader, options sigOptions) (*bytes.Reader, error) {
|
|||||||
|
|
||||||
func canonicalize(emailReader *bytes.Reader, options sigOptions) (headers, body []byte, err error) {
|
func canonicalize(emailReader *bytes.Reader, options sigOptions) (headers, body []byte, err error) {
|
||||||
var email []byte
|
var email []byte
|
||||||
|
body = []byte{}
|
||||||
|
rxReduceWS := regexp.MustCompile(`[ \t]+`)
|
||||||
|
|
||||||
email, err = ioutil.ReadAll(emailReader)
|
email, err = ioutil.ReadAll(emailReader)
|
||||||
emailReader.Seek(0, 0)
|
emailReader.Seek(0, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -136,21 +145,37 @@ func canonicalize(emailReader *bytes.Reader, options sigOptions) (headers, body
|
|||||||
|
|
||||||
parts := bytes.SplitN(email, []byte{13, 10, 13, 10}, 2)
|
parts := bytes.SplitN(email, []byte{13, 10, 13, 10}, 2)
|
||||||
|
|
||||||
|
if len(parts) != 2 {
|
||||||
|
return headers, body, ErrBadMailFormat
|
||||||
|
}
|
||||||
|
|
||||||
|
// Empty body
|
||||||
|
if len(parts[1]) == 0 {
|
||||||
|
parts[1] = []byte{13, 10}
|
||||||
|
}
|
||||||
|
|
||||||
canonicalizations := strings.Split(options.Canonicalization, "/")
|
canonicalizations := strings.Split(options.Canonicalization, "/")
|
||||||
// canonicalyze body
|
// canonicalyze body
|
||||||
if canonicalizations[1] == "simple" {
|
if canonicalizations[1] == "simple" {
|
||||||
body = bytes.TrimRight(parts[1], "\r\n")
|
body = bytes.TrimRight(parts[1], "\r\n")
|
||||||
body = append(body, []byte{13, 10}...)
|
body = append(body, []byte{13, 10}...)
|
||||||
} else {
|
} else {
|
||||||
for _, line := range bytes.Split(parts[1], []byte{10}) {
|
parts[1] = rxReduceWS.ReplaceAll(parts[1], []byte(" "))
|
||||||
println(line)
|
for _, line := range bytes.SplitAfter(parts[1], []byte{10}) {
|
||||||
|
line = bytes.TrimRight(line, " \r\n")
|
||||||
|
// Ignore all whitespace at the end of lines. Implementations
|
||||||
|
// MUST NOT remove the CRLF at the end of the line.
|
||||||
|
if len(line) != 0 {
|
||||||
|
body = append(body, line...)
|
||||||
|
body = append(body, []byte{13, 10}...)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return
|
||||||
|
|
||||||
println(string(parts[0]))
|
/*println(string(parts[0]))
|
||||||
println("\r\n")
|
println("\r\n")
|
||||||
println(string(parts[1]))
|
println(string(parts[1]))
|
||||||
println(string(body))
|
println(string(body))*/
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
54
dkim_test.go
54
dkim_test.go
@@ -31,17 +31,32 @@ kS5vLkzRI84eiJrm3+IieUqIIicsO+WYxQs+JgVx5XhpPjX4SQjHtwEC2xKkWnEv
|
|||||||
selector = "test"
|
selector = "test"
|
||||||
)
|
)
|
||||||
|
|
||||||
var email = `Received: (qmail 28277 invoked from network); 1 May 2015 09:43:37 -0000
|
var email = "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
|
"Received: (qmail 21323 invoked from network); 1 May 2015 09:48:39 -0000" + CRLF +
|
||||||
MIME-Version: 1.0
|
"MIME-Version: 1.0" + CRLF +
|
||||||
Date: Fri, 1 May 2015 11:48:37 +0200
|
"Date: Fri, 1 May 2015 11:48:37 +0200" + CRLF +
|
||||||
Message-ID: <CADu37kTXBeNkJdXc4bSF8DbJnXmNjkLbnswK6GzG_2yn7U7P6w@tmail.io>
|
"Message-ID: <CADu37kTXBeNkJdXc4bSF8DbJnXmNjkLbnswK6GzG_2yn7U7P6w@tmail.io>" + CRLF +
|
||||||
Subject: Test DKIM
|
"Subject: Test DKIM" + CRLF +
|
||||||
From: =?UTF-8?Q?St=C3=A9phane_Depierrepont?= <toorop@tmail.io>
|
"From: =?UTF-8?Q?St=C3=A9phane_Depierrepont?= <toorop@tmail.io>" + CRLF +
|
||||||
To: =?UTF-8?Q?St=C3=A9phane_Depierrepont?= <toorop@toorop.fr>
|
"To: =?UTF-8?Q?St=C3=A9phane_Depierrepont?= <toorop@toorop.fr>" + CRLF +
|
||||||
Content-Type: text/plain; charset=UTF-8` + "\r\n\r\n" + `Hello world
|
"Content-Type: text/plain; charset=UTF-8" + CRLF + CRLF +
|
||||||
--
|
"Hello world" + CRLF +
|
||||||
Toorop` + "\r\n\r\n\r\n\r\n\r\n\r\n\r\n"
|
"line with trailing space " + CRLF +
|
||||||
|
"line with space " + CRLF +
|
||||||
|
"-- " + CRLF +
|
||||||
|
"Toorop " + CRLF + CRLF + CRLF + CRLF + CRLF + CRLF
|
||||||
|
|
||||||
|
var bodySimple = "Hello world" + CRLF +
|
||||||
|
"line with trailing space " + CRLF +
|
||||||
|
"line with space " + CRLF +
|
||||||
|
"-- " + CRLF +
|
||||||
|
"Toorop " + CRLF
|
||||||
|
|
||||||
|
var bodyRelaxed = "Hello world" + CRLF +
|
||||||
|
"line with trailing space" + CRLF +
|
||||||
|
"line with space" + CRLF +
|
||||||
|
"--" + CRLF +
|
||||||
|
"Toorop" + CRLF
|
||||||
|
|
||||||
func Test_NewSigOptions(t *testing.T) {
|
func Test_NewSigOptions(t *testing.T) {
|
||||||
options := NewSigOptions()
|
options := NewSigOptions()
|
||||||
@@ -107,3 +122,20 @@ func Test_Sign(t *testing.T) {
|
|||||||
emailReader, err := Sign(emailReader, options)
|
emailReader, err := Sign(emailReader, options)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Test_canonicalize(t *testing.T) {
|
||||||
|
emailReader := bytes.NewReader([]byte(email))
|
||||||
|
options := NewSigOptions()
|
||||||
|
// simple/simple
|
||||||
|
options.Canonicalization = "simple/simple"
|
||||||
|
_, body, err := canonicalize(emailReader, options)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, []byte(bodySimple), body)
|
||||||
|
|
||||||
|
// relaxed/relaxed
|
||||||
|
options.Canonicalization = "relaxed/relaxed"
|
||||||
|
_, body, err = canonicalize(emailReader, options)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, []byte(bodyRelaxed), body)
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
@@ -21,5 +21,8 @@ var (
|
|||||||
ErrSignBadCanonicalization = errors.New("bad Canonicalization parameter")
|
ErrSignBadCanonicalization = errors.New("bad Canonicalization parameter")
|
||||||
|
|
||||||
// Bad algorithm
|
// Bad algorithm
|
||||||
ErrSignBadAlgo = errors.New("bar algorithm. Only rsa-sha1 or rsa-sha256 are permitted")
|
ErrSignBadAlgo = errors.New("bad algorithm. Only rsa-sha1 or rsa-sha256 are permitted")
|
||||||
|
|
||||||
|
// ErrBadMailFormat
|
||||||
|
ErrBadMailFormat = errors.New("bad mail formart")
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user