body canonicalization

This commit is contained in:
Stéphane Depierrepont aka Toorop
2015-05-04 12:33:01 +02:00
parent d870a49fe7
commit 3c7c1e2829
3 changed files with 77 additions and 17 deletions

35
dkim.go
View File

@@ -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
} }

View File

@@ -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)
}

View File

@@ -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")
) )