dkim 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.travis.yml +9 -0
- data/CHANGELOG.md +9 -0
- data/Gemfile +10 -0
- data/Guardfile +5 -0
- data/README.md +50 -60
- data/bin/dkimsign.rb +0 -0
- data/lib/dkim.rb +3 -8
- data/lib/dkim/interceptor.rb +13 -1
- data/lib/dkim/options.rb +72 -0
- data/lib/dkim/signed_mail.rb +18 -43
- data/lib/dkim/version.rb +1 -1
- data/test/dkim/canonicalization_test.rb +80 -0
- data/test/dkim/dkim_header_test.rb +42 -0
- data/test/dkim/interceptor_test.rb +108 -0
- data/test/dkim/options_test.rb +37 -0
- data/test/dkim/signed_mail_test.rb +66 -0
- data/test/test_helper.rb +34 -4
- metadata +22 -5
- data/test/canonicalization_test.rb +0 -78
data/.travis.yml
ADDED
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,14 @@
|
|
1
1
|
# dkim Changelog
|
2
2
|
|
3
|
+
## 2012.04.15, Version 0.2.0
|
4
|
+
* Warn and strip existing signatures in Dkim::Interceptor
|
5
|
+
* Dkim options can be accessed and modified using new Dkim.options or signed_mail.options hash
|
6
|
+
* Refactoring and better testing
|
7
|
+
* Improved documentation
|
8
|
+
|
9
|
+
## 2011.12.10, Version 0.1.0
|
10
|
+
* Ensure header lines are not folded using Dkim::Interceptor
|
11
|
+
|
3
12
|
## 2011.07.25, Version 0.0.3
|
4
13
|
* add Dkim::Interceptor class for integration with rails and [mail](https://github.com/mikel/mail)
|
5
14
|
|
data/Gemfile
CHANGED
data/Guardfile
ADDED
data/README.md
CHANGED
@@ -1,30 +1,62 @@
|
|
1
1
|
dkim
|
2
2
|
====
|
3
|
-
|
4
3
|
A DKIM signing library in ruby.
|
5
4
|
|
5
|
+
[![Build Status](https://secure.travis-ci.org/jhawthorn/dkim.png?branch=master)](http://travis-ci.org/jhawthorn/dkim)
|
6
|
+
|
7
|
+
[Documentation](http://rubydoc.info/github/jhawthorn/dkim)
|
8
|
+
|
6
9
|
Installation
|
7
10
|
============
|
8
11
|
|
9
12
|
sudo gem install dkim
|
10
13
|
|
11
|
-
|
12
|
-
|
14
|
+
Necessary configuration
|
15
|
+
=======================
|
16
|
+
A private key, a domain, and a selector need to be specified in order to sign messages.
|
17
|
+
|
18
|
+
These can be specified globally
|
19
|
+
|
20
|
+
Dkim::domain = 'example.com'
|
21
|
+
Dkim::selector = 'mail'
|
22
|
+
Dkim::private_key = open('private.pem').read
|
23
|
+
|
24
|
+
Options can be overridden per message.
|
25
|
+
|
26
|
+
Dkim.sign(mail, :selector => 'mail2', :private_key => open('private2.pem').read)
|
27
|
+
|
28
|
+
For more details see {Dkim::Options}
|
29
|
+
|
30
|
+
Usage With Rails
|
31
|
+
================
|
32
|
+
|
33
|
+
Dkim contains `Dkim::Interceptor` which can be used to sign all mail delivered by rails 3 or [mail](https://github.com/mikel/mail).
|
34
|
+
For rails, create an initializer (for example `config/initializers/dkim.rb`) with the following template.
|
35
|
+
|
36
|
+
# Configure dkim globally (see above)
|
37
|
+
Dkim::domain = 'example.com'
|
38
|
+
Dkim::selector = 'mail'
|
39
|
+
Dkim::private_key = open('private.pem').read
|
40
|
+
|
41
|
+
# This will sign all ActionMailer deliveries
|
42
|
+
ActionMailer::Base.register_interceptor(Dkim::Interceptor)
|
43
|
+
|
44
|
+
Standalone Usage
|
45
|
+
================
|
13
46
|
|
14
47
|
Calling `Dkim.sign` on a string representing an email message returns the message with a DKIM signature inserted.
|
15
48
|
|
16
49
|
For example
|
17
50
|
|
18
|
-
mail = <<
|
51
|
+
mail = Dkim.sign(<<EOS)
|
19
52
|
To: someone@example.com
|
20
53
|
From: john@example.com
|
21
54
|
Subject: hi
|
22
|
-
|
55
|
+
|
23
56
|
Howdy
|
24
|
-
|
57
|
+
EOS
|
25
58
|
|
26
59
|
Dkim.sign(mail)
|
27
|
-
|
28
60
|
# =>
|
29
61
|
# To: someone@example.com
|
30
62
|
# From: john@example.com
|
@@ -34,67 +66,25 @@ For example
|
|
34
66
|
# b=0mKnNOkxFGiww63Zu4t46J7eZc3Uak3I9km3IH2Le3XcnSNtWJgxiwBX26IZ5yzcT
|
35
67
|
# VwJzcCnPKCScIJMQ7yfbfXmNsKVIOV6eSUqu1YvJ1fgzlSAXuDEMNFTjoto5rrdA+
|
36
68
|
# BgX849hEY/bWHDl1JJgNpiwtpl4t0Q7M4BVJUd7Lo=
|
37
|
-
#
|
69
|
+
#
|
38
70
|
# Howdy
|
39
71
|
|
40
|
-
|
41
|
-
-----------------------
|
42
|
-
A private key, a domain, and a selector need to be specified in order to sign messages.
|
43
|
-
|
44
|
-
These can be specified globally
|
45
|
-
|
46
|
-
Dkim::domain = 'example.com'
|
47
|
-
Dkim::selector = 'mail'
|
48
|
-
Dkim::private_key = open('private.pem').read
|
72
|
+
More flexibility can be found using {Dkim::SignedMail} directly.
|
49
73
|
|
50
|
-
|
51
|
-
|
52
|
-
Dkim.sign(mail, :selector => 'mail2', :private_key => open('private2.pem').read)
|
53
|
-
|
54
|
-
Additional configuration
|
55
|
-
------------------------
|
74
|
+
Specific configuration
|
75
|
+
========================
|
56
76
|
|
57
|
-
|
58
|
-
|
59
|
-
Dkim::signable_headers = Dkim::DefaultHeaders # Sign only the specified headers
|
60
|
-
Dkim::signing_algorithm = 'rsa-sha256' # can be rsa-sha1 or rsa-sha256 (default)
|
61
|
-
Dkim::header_canonicalization = 'relaxed' # Can be simple or relaxed (default)
|
62
|
-
Dkim::body_canonicalization = 'relaxed' # Can be simple or relaxed (default)
|
63
|
-
|
64
|
-
The defaults should fit most users needs; however, certain use cases will need them to be customized.
|
65
|
-
|
66
|
-
For example, for sending mesages through amazon SES, certain headers should not be signed
|
77
|
+
For sending mesages through Amazon SES, certain headers should not be signed
|
67
78
|
|
68
79
|
Dkim::signable_headers = Dkim::DefaultHeaders - %w{Message-ID Resent-Message-ID Date Return-Path Bounces-To}
|
69
80
|
|
70
|
-
|
81
|
+
Some OpenSSL's don't have sha256 support.
|
82
|
+
RFC 6376 states that signers SHOULD sign using rsa-sha256.
|
83
|
+
For this reason, dkim will *not* use rsa-sha1 as a fallback.
|
71
84
|
If you wish to override this behaviour and use whichever algorithm is available you can use this snippet (**not recommended**).
|
72
85
|
|
73
86
|
Dkim::signing_algorithm = defined?(OpenSSL::Digest::SHA256) ? 'rsa-sha256' : 'rsa-sha1'
|
74
87
|
|
75
|
-
Usage With Rails
|
76
|
-
================
|
77
|
-
|
78
|
-
Dkim contains `Dkim::Interceptor` which can be used to sign all mail delivered by the [mail gem](https://github.com/mikel/mail) or rails 3, which uses mail.
|
79
|
-
For rails, create an initializer (for example `config/initializers/dkim.rb`) with the following template.
|
80
|
-
|
81
|
-
# Configure dkim globally (see above)
|
82
|
-
Dkim::domain = 'example.com'
|
83
|
-
Dkim::selector = 'mail'
|
84
|
-
Dkim::private_key = open('private.pem').read
|
85
|
-
|
86
|
-
# This will sign all ActionMailer deliveries
|
87
|
-
ActionMailer::Base.register_interceptor('Dkim::Interceptor')
|
88
|
-
|
89
|
-
Example executable
|
90
|
-
==================
|
91
|
-
|
92
|
-
The library includes a `dkimsign.rb` executable suitable for testing the library or performing simple signatures.
|
93
|
-
|
94
|
-
`dkimsign.rb DOMAIN SELECTOR KEYFILE [MAILFILE]`
|
95
|
-
|
96
|
-
If MAILFILE is not specified `dkimsign.rb` will read the mail message from standard in.
|
97
|
-
|
98
88
|
Limitations
|
99
89
|
===========
|
100
90
|
|
@@ -108,11 +98,11 @@ Limitations
|
|
108
98
|
Resources
|
109
99
|
=========
|
110
100
|
|
111
|
-
* [RFC
|
101
|
+
* [RFC 6376](http://tools.ietf.org/html/rfc6376)
|
112
102
|
* Inspired by perl's [Mail-DKIM](http://dkimproxy.sourceforge.net/)
|
113
103
|
|
114
|
-
|
115
|
-
|
104
|
+
License
|
105
|
+
=======
|
116
106
|
|
117
107
|
(The MIT License)
|
118
108
|
|
data/bin/dkimsign.rb
CHANGED
File without changes
|
data/lib/dkim.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
|
2
2
|
require 'dkim/signed_mail'
|
3
|
+
require 'dkim/options'
|
3
4
|
require 'dkim/interceptor'
|
4
5
|
|
5
6
|
module Dkim
|
@@ -14,13 +15,7 @@ module Dkim
|
|
14
15
|
List-Post List-Owner List-Archive}
|
15
16
|
|
16
17
|
class << self
|
17
|
-
|
18
|
-
|
19
|
-
attr_reader :private_key
|
20
|
-
def private_key= key
|
21
|
-
key = OpenSSL::PKey::RSA.new(key) if key.is_a?(String)
|
22
|
-
@private_key = key
|
23
|
-
end
|
18
|
+
include Dkim::Options
|
24
19
|
|
25
20
|
def sign message, options={}
|
26
21
|
SignedMail.new(message, options).to_s
|
@@ -28,7 +23,7 @@ module Dkim
|
|
28
23
|
end
|
29
24
|
end
|
30
25
|
|
31
|
-
Dkim::signable_headers = Dkim::DefaultHeaders
|
26
|
+
Dkim::signable_headers = Dkim::DefaultHeaders.dup
|
32
27
|
Dkim::domain = nil
|
33
28
|
Dkim::selector = nil
|
34
29
|
Dkim::signing_algorithm = 'rsa-sha256'
|
data/lib/dkim/interceptor.rb
CHANGED
@@ -3,7 +3,19 @@ module Dkim
|
|
3
3
|
class Interceptor
|
4
4
|
def self.delivering_email(message)
|
5
5
|
require 'mail/dkim_field'
|
6
|
-
|
6
|
+
|
7
|
+
# strip any existing signatures
|
8
|
+
if message['DKIM-Signature']
|
9
|
+
warn "WARNING: Dkim::Interceptor given a message with an existing signature, which it has replaced."
|
10
|
+
warn "If you really want to add a second signature to the message, you should be using the dkim gem directly."
|
11
|
+
message['DKIM-Signature'] = nil
|
12
|
+
end
|
13
|
+
|
14
|
+
# generate new signature
|
15
|
+
dkim_signature = SignedMail.new(message.encoded).dkim_header.value
|
16
|
+
|
17
|
+
# append signature to message
|
18
|
+
message.header.fields << Mail::DkimField.new(dkim_signature)
|
7
19
|
message
|
8
20
|
end
|
9
21
|
end
|
data/lib/dkim/options.rb
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
module Dkim
|
2
|
+
module Options
|
3
|
+
private
|
4
|
+
def self.define_option_method attribute_name
|
5
|
+
define_method(attribute_name){options[attribute_name]}
|
6
|
+
define_method("#{attribute_name}="){|value| options[attribute_name] = value}
|
7
|
+
end
|
8
|
+
public
|
9
|
+
|
10
|
+
# @attribute [rw]
|
11
|
+
# Hash of all options
|
12
|
+
# @return [Hash]
|
13
|
+
def options
|
14
|
+
@options ||= {}
|
15
|
+
end
|
16
|
+
attr_writer :options
|
17
|
+
|
18
|
+
# @attribute [rw]
|
19
|
+
# This corresponds to the t= tag in the dkim header.
|
20
|
+
# The default (nil) is to use the current time at signing.
|
21
|
+
# @return [Time,#to_i] A Time object or seconds since the epoch
|
22
|
+
define_option_method :time
|
23
|
+
|
24
|
+
# @attribute [rw]
|
25
|
+
# The signing algorithm for dkim. Valid values are 'rsa-sha1' and 'rsa-sha256' (default).
|
26
|
+
# This corresponds to the a= tag in the dkim header.
|
27
|
+
# @return [String] signing algorithm
|
28
|
+
define_option_method :signing_algorithm
|
29
|
+
|
30
|
+
# @attribute [rw]
|
31
|
+
# Configures which headers should be signed.
|
32
|
+
# Defaults to {Dkim::DefaultHeaders Dkim::DefaultHeaders}
|
33
|
+
# @return [Array<String>] signable headers
|
34
|
+
define_option_method :signable_headers
|
35
|
+
|
36
|
+
# @attribute [rw]
|
37
|
+
# The domain used for signing.
|
38
|
+
# This corresponds to the d= tag in the dkim header.
|
39
|
+
# @return [String] domain
|
40
|
+
define_option_method :domain
|
41
|
+
|
42
|
+
# @attribute [rw]
|
43
|
+
# Selector used for signing.
|
44
|
+
# This corresponds to the s= tag in the dkim header.
|
45
|
+
# @return [String] selector
|
46
|
+
define_option_method :selector
|
47
|
+
|
48
|
+
# @attribute [rw]
|
49
|
+
# Header canonicalization algorithm.
|
50
|
+
# Valid values are 'simple' and 'relaxed' (default)
|
51
|
+
# This corresponds to the first half of the c= tag in the dkim header.
|
52
|
+
# @return [String] header canonicalization algorithm
|
53
|
+
define_option_method :header_canonicalization
|
54
|
+
|
55
|
+
# @attribute [rw]
|
56
|
+
# Body canonicalization algorithm.
|
57
|
+
# Valid values are 'simple' and 'relaxed' (default)
|
58
|
+
# This corresponds to the second half of the c= tag in the dkim header.
|
59
|
+
# @return [String] body canonicalization algorithm
|
60
|
+
define_option_method :body_canonicalization
|
61
|
+
|
62
|
+
# @attribute [rw]
|
63
|
+
# RSA private key for signing.
|
64
|
+
# Can be assigned either an {OpenSSL::PKey::RSA} private key or a valid PEM format string.
|
65
|
+
# @return [OpenSSL::PKey::RSA] private key
|
66
|
+
define_option_method :private_key
|
67
|
+
def private_key= key
|
68
|
+
key = OpenSSL::PKey::RSA.new(key) if key.is_a?(String)
|
69
|
+
options[:private_key] = key
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
data/lib/dkim/signed_mail.rb
CHANGED
@@ -4,69 +4,44 @@ require 'dkim/body'
|
|
4
4
|
require 'dkim/dkim_header'
|
5
5
|
require 'dkim/header'
|
6
6
|
require 'dkim/header_list'
|
7
|
+
require 'dkim/options'
|
7
8
|
|
8
9
|
module Dkim
|
9
10
|
class SignedMail
|
11
|
+
include Options
|
12
|
+
|
13
|
+
# A new instance of SignedMail
|
14
|
+
#
|
15
|
+
# @param [String,#to_s] message mail message to be signed
|
16
|
+
# @param [Hash] options hash of options for signing. Defaults are taken from {Dkim}. See {Options} for details.
|
10
17
|
def initialize message, options={}
|
11
18
|
message = message.to_s.gsub(/\r?\n/, "\r\n")
|
12
19
|
headers, body = message.split(/\r?\n\r?\n/, 2)
|
13
20
|
@headers = HeaderList.new headers
|
14
21
|
@body = Body.new body
|
15
22
|
|
16
|
-
|
17
|
-
@
|
18
|
-
@selector = options[:selector]
|
19
|
-
@time = options[:time]
|
20
|
-
@signing_algorithm = options[:signing_algorithm]
|
21
|
-
@private_key = options[:private_key]
|
22
|
-
@header_canonicalization = options[:header_canonicalization]
|
23
|
-
@body_canonicalization = options[:body_canonicalization]
|
24
|
-
end
|
25
|
-
|
26
|
-
# options for signatures
|
27
|
-
attr_writer :signing_algorithm, :signable_headers, :domain, :selector, :time, :header_canonicalization, :body_canonicalization
|
28
|
-
|
29
|
-
def private_key= key
|
30
|
-
key = OpenSSL::PKey::RSA.new(key) if key.is_a?(String)
|
31
|
-
@private_key = key
|
32
|
-
end
|
33
|
-
def private_key
|
34
|
-
@private_key || Dkim::private_key
|
35
|
-
end
|
36
|
-
def signing_algorithm
|
37
|
-
@signing_algorithm || Dkim::signing_algorithm
|
38
|
-
end
|
39
|
-
def signable_headers
|
40
|
-
@signable_headers || Dkim::signable_headers
|
41
|
-
end
|
42
|
-
def domain
|
43
|
-
@domain || Dkim::domain
|
44
|
-
end
|
45
|
-
def selector
|
46
|
-
@selector || Dkim::selector
|
47
|
-
end
|
48
|
-
def time
|
49
|
-
@time
|
50
|
-
end
|
51
|
-
def header_canonicalization
|
52
|
-
@header_canonicalization || Dkim::header_canonicalization
|
53
|
-
end
|
54
|
-
def body_canonicalization
|
55
|
-
@body_canonicalization || Dkim::body_canonicalization
|
23
|
+
# default options from Dkim.options
|
24
|
+
@options = Dkim.options.merge(options)
|
56
25
|
end
|
57
26
|
|
27
|
+
# @return [Array<String>] Signed headers of message in their canonical forms
|
58
28
|
def signed_headers
|
59
29
|
(@headers.map(&:relaxed_key) & signable_headers.map(&:downcase)).sort
|
60
30
|
end
|
31
|
+
|
32
|
+
# @return [String] Signed headers of message in their canonical forms
|
61
33
|
def canonical_header
|
62
34
|
headers = signed_headers.map do |key|
|
63
35
|
@headers[key].to_s(header_canonicalization) + "\r\n"
|
64
36
|
end.join
|
65
37
|
end
|
38
|
+
|
39
|
+
# @return [String] Body of message in its canonical form
|
66
40
|
def canonical_body
|
67
41
|
@body.to_s(body_canonicalization)
|
68
42
|
end
|
69
43
|
|
44
|
+
# @return [DkimHeader] Constructed signature for the mail message
|
70
45
|
def dkim_header
|
71
46
|
dkim_header = DkimHeader.new
|
72
47
|
|
@@ -97,8 +72,8 @@ module Dkim
|
|
97
72
|
dkim_header
|
98
73
|
end
|
99
74
|
|
75
|
+
# @return [String] Message combined with calculated dkim header signature
|
100
76
|
def to_s
|
101
|
-
# Return the original message with the calculated header
|
102
77
|
headers = @headers.to_a + [dkim_header]
|
103
78
|
headers.map(&:to_s).join("\r\n") +
|
104
79
|
"\r\n\r\n" +
|
@@ -107,13 +82,13 @@ module Dkim
|
|
107
82
|
|
108
83
|
private
|
109
84
|
def base64_encode data
|
110
|
-
[data].pack('m0
|
85
|
+
[data].pack('m0').gsub("\n",'')
|
111
86
|
end
|
112
87
|
def digest_alg
|
113
88
|
case signing_algorithm
|
114
89
|
when 'rsa-sha1'
|
115
90
|
OpenSSL::Digest::SHA1.new
|
116
|
-
when 'rsa-sha256'
|
91
|
+
when 'rsa-sha256'
|
117
92
|
OpenSSL::Digest::SHA256.new
|
118
93
|
else
|
119
94
|
raise "Unknown digest algorithm: '#{signing_algorithm}'"
|
data/lib/dkim/version.rb
CHANGED
@@ -0,0 +1,80 @@
|
|
1
|
+
|
2
|
+
require 'test_helper'
|
3
|
+
|
4
|
+
module Dkim
|
5
|
+
class CanonicalizationTest < MiniTest::Unit::TestCase
|
6
|
+
# from section 3.4.6 of RFC 6376
|
7
|
+
def setup
|
8
|
+
@input = <<-eos.rfc_format
|
9
|
+
A: <SP> X <CRLF>
|
10
|
+
B <SP> : <SP> Y <HTAB><CRLF>
|
11
|
+
<HTAB> Z <SP><SP><CRLF>
|
12
|
+
<CRLF>
|
13
|
+
<SP> C <SP><CRLF>
|
14
|
+
D <SP><HTAB><SP> E <CRLF>
|
15
|
+
<CRLF>
|
16
|
+
<CRLF>
|
17
|
+
eos
|
18
|
+
@mail = SignedMail.new(@input)
|
19
|
+
@mail.signable_headers = ['A', 'B']
|
20
|
+
end
|
21
|
+
def test_relaxed_header
|
22
|
+
@mail.header_canonicalization = 'relaxed'
|
23
|
+
expected_header = <<-eos.rfc_format
|
24
|
+
a:X <CRLF>
|
25
|
+
b:Y <SP> Z <CRLF>
|
26
|
+
eos
|
27
|
+
assert_equal expected_header, @mail.canonical_header
|
28
|
+
end
|
29
|
+
def test_relaxed_body
|
30
|
+
@mail.body_canonicalization = 'relaxed'
|
31
|
+
expected_body = <<-eos.rfc_format
|
32
|
+
<SP> C <CRLF>
|
33
|
+
D <SP> E <CRLF>
|
34
|
+
eos
|
35
|
+
assert_equal expected_body, @mail.canonical_body
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_simple_header
|
39
|
+
@mail.header_canonicalization = 'simple'
|
40
|
+
expected_header = <<-eos.rfc_format
|
41
|
+
A: <SP> X <CRLF>
|
42
|
+
B <SP> : <SP> Y <HTAB><CRLF>
|
43
|
+
<HTAB> Z <SP><SP><CRLF>
|
44
|
+
eos
|
45
|
+
assert_equal expected_header, @mail.canonical_header
|
46
|
+
end
|
47
|
+
def test_simple_body
|
48
|
+
@mail.body_canonicalization = 'simple'
|
49
|
+
expected_body = <<-eos.rfc_format
|
50
|
+
<SP> C <SP><CRLF>
|
51
|
+
D <SP><HTAB><SP> E <CRLF>
|
52
|
+
eos
|
53
|
+
assert_equal expected_body, @mail.canonical_body
|
54
|
+
end
|
55
|
+
|
56
|
+
# from errata: empty bodies
|
57
|
+
def test_simple_empty_body
|
58
|
+
@mail = SignedMail.new("test: test\r\n\r\n")
|
59
|
+
@mail.body_canonicalization = 'simple'
|
60
|
+
|
61
|
+
assert_equal "\r\n", @mail.canonical_body
|
62
|
+
end
|
63
|
+
|
64
|
+
def test_relaxed_empty_body
|
65
|
+
@mail = SignedMail.new("test: test\r\n\r\n")
|
66
|
+
@mail.body_canonicalization = 'relaxed'
|
67
|
+
|
68
|
+
assert_equal "", @mail.canonical_body
|
69
|
+
end
|
70
|
+
|
71
|
+
def test_relaxed_errata_1384
|
72
|
+
body = "testing<crlf><sp><sp><cr><lf><cr><lf>".rfc_format
|
73
|
+
@mail = SignedMail.new("test: test\r\n\r\n#{body}")
|
74
|
+
@mail.body_canonicalization = 'relaxed'
|
75
|
+
|
76
|
+
assert_equal "testing\r\n", @mail.canonical_body
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
@@ -0,0 +1,42 @@
|
|
1
|
+
|
2
|
+
require 'test_helper'
|
3
|
+
|
4
|
+
module Dkim
|
5
|
+
class DkimHeaderTest < MiniTest::Unit::TestCase
|
6
|
+
def setup
|
7
|
+
@header = DkimHeader.new
|
8
|
+
|
9
|
+
# from Appendix A of RFC 6376
|
10
|
+
@header['v'] = '1'
|
11
|
+
@header['a'] = 'rsa-sha256'
|
12
|
+
@header['s'] = 'brisbane'
|
13
|
+
@header['d'] = 'example.com'
|
14
|
+
@header['c'] = 'simple/simple'
|
15
|
+
@header['q'] = 'dns/txt'
|
16
|
+
@header['i'] = 'joe@football.example.com'
|
17
|
+
@header['h'] = 'Received : From : To : Subject : Date : Message-ID'
|
18
|
+
@header['bh']= '2jUSOH9NhtVGCQWNr9BrIAPreKQjO6Sn7XIkfJVOzv8='
|
19
|
+
@header['b'] = 'AuUoFEfDxTDkHlLXSZEpZj79LICEps6eda7W3deTVFOk4yAUoqOB4nujc7YopdG5dWLSdNg6xNAZpOPr+kHxt1IrE+NahM6L/LbvaHutKVdkLLkpVaVVQPzeRDI009SO2Il5Lu7rDNH6mZckBdrIx0orEtZV4bmp/YzhwvcubU4='
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_correct_format
|
23
|
+
header = @header.to_s
|
24
|
+
|
25
|
+
# result from RFC 6376 minus trailing ';'
|
26
|
+
expected = %{
|
27
|
+
DKIM-Signature: v=1; a=rsa-sha256; s=brisbane; d=example.com;
|
28
|
+
c=simple/simple; q=dns/txt; i=joe@football.example.com;
|
29
|
+
h=Received : From : To : Subject : Date : Message-ID;
|
30
|
+
bh=2jUSOH9NhtVGCQWNr9BrIAPreKQjO6Sn7XIkfJVOzv8=;
|
31
|
+
b=AuUoFEfDxTDkHlLXSZEpZj79LICEps6eda7W3deTVFOk4yAUoqOB
|
32
|
+
4nujc7YopdG5dWLSdNg6xNAZpOPr+kHxt1IrE+NahM6L/LbvaHut
|
33
|
+
KVdkLLkpVaVVQPzeRDI009SO2Il5Lu7rDNH6mZckBdrIx0orEtZV
|
34
|
+
4bmp/YzhwvcubU4=
|
35
|
+
}
|
36
|
+
|
37
|
+
# compare removing whitespace
|
38
|
+
assert_equal expected.gsub(/\s/,''), header.gsub(/\s/,'')
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
@@ -0,0 +1,108 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
require 'mail'
|
4
|
+
|
5
|
+
module Dkim
|
6
|
+
SIGNEDMAIL = <<-eos
|
7
|
+
DKIM-Signature: v=1; a=rsa-sha256; s=brisbane; d=example.com;
|
8
|
+
c=simple/simple; q=dns/txt; i=joe@football.example.com;
|
9
|
+
h=Received : From : To : Subject : Date : Message-ID;
|
10
|
+
bh=2jUSOH9NhtVGCQWNr9BrIAPreKQjO6Sn7XIkfJVOzv8=;
|
11
|
+
b=AuUoFEfDxTDkHlLXSZEpZj79LICEps6eda7W3deTVFOk4yAUoqOB
|
12
|
+
4nujc7YopdG5dWLSdNg6xNAZpOPr+kHxt1IrE+NahM6L/LbvaHut
|
13
|
+
KVdkLLkpVaVVQPzeRDI009SO2Il5Lu7rDNH6mZckBdrIx0orEtZV
|
14
|
+
4bmp/YzhwvcubU4=;
|
15
|
+
Received: from client1.football.example.com [192.0.2.1]
|
16
|
+
by submitserver.example.com with SUBMISSION;
|
17
|
+
Fri, 11 Jul 2003 21:01:54 -0700 (PDT)
|
18
|
+
From: Joe SixPack <joe@football.example.com>
|
19
|
+
To: Suzie Q <suzie@shopping.example.net>
|
20
|
+
Subject: Is dinner ready?
|
21
|
+
Date: Fri, 11 Jul 2003 21:00:37 -0700 (PDT)
|
22
|
+
Message-ID: <20030712040037.46341.5F8J@football.example.com>
|
23
|
+
DKIM-Signature: v=1; a=rsa-sha256; s=brisbane; d=example.com;
|
24
|
+
c=simple/simple; q=dns/txt; i=joe@football.example.com;
|
25
|
+
h=Received : From : To : Subject : Date : Message-ID;
|
26
|
+
bh=2jUSOH9NhtVGCQWNr9BrIAPreKQjO6Sn7XIkfJVOzv8=;
|
27
|
+
b=AuUoFEfDxTDkHlLXSZEpZj79LICEps6eda7W3deTVFOk4yAUoqOB
|
28
|
+
4nujc7YopdG5dWLSdNg6xNAZpOPr+kHxt1IrE+NahM6L/LbvaHut
|
29
|
+
KVdkLLkpVaVVQPzeRDI009SO2Il5Lu7rDNH6mZckBdrIx0orEtZV
|
30
|
+
4bmp/YzhwvcubU4=;
|
31
|
+
|
32
|
+
Hi.
|
33
|
+
|
34
|
+
We lost the game. Are you hungry yet?
|
35
|
+
|
36
|
+
Joe.
|
37
|
+
eos
|
38
|
+
|
39
|
+
class InterceptorTest < MiniTest::Unit::TestCase
|
40
|
+
def setup
|
41
|
+
@original_options = Dkim.options.dup
|
42
|
+
|
43
|
+
mail = EXAMPLEEMAIL.dup
|
44
|
+
|
45
|
+
@mail = Mail.new(mail)
|
46
|
+
end
|
47
|
+
|
48
|
+
def teardown
|
49
|
+
Dkim.options = @original_options
|
50
|
+
end
|
51
|
+
|
52
|
+
def test_header_with_relaxed
|
53
|
+
Dkim.header_canonicalization = 'relaxed'
|
54
|
+
Dkim.body_canonicalization = 'relaxed'
|
55
|
+
Dkim.signing_algorithm = 'rsa-sha256'
|
56
|
+
Interceptor.delivering_email(@mail)
|
57
|
+
dkim_header = @mail['DKIM-Signature']
|
58
|
+
|
59
|
+
assert dkim_header
|
60
|
+
assert_includes dkim_header.to_s, 'rsa-sha256'
|
61
|
+
assert_includes dkim_header.to_s, 's=brisbane'
|
62
|
+
assert_includes dkim_header.to_s, 'd=example.com'
|
63
|
+
assert_includes dkim_header.to_s, 'c=relaxed/relaxed'
|
64
|
+
assert_includes dkim_header.to_s, 'q=dns/txt'
|
65
|
+
assert_includes dkim_header.to_s, 'bh=2jUSOH9NhtVGCQWNr9BrIAPreKQjO6Sn7XIkfJVOzv8='
|
66
|
+
|
67
|
+
# TODO: double check signing of 'b' header
|
68
|
+
end
|
69
|
+
|
70
|
+
def test_header_with_simple
|
71
|
+
Dkim.header_canonicalization = 'simple'
|
72
|
+
Dkim.body_canonicalization = 'simple'
|
73
|
+
Dkim.signing_algorithm = 'rsa-sha256'
|
74
|
+
Interceptor.delivering_email(@mail)
|
75
|
+
dkim_header = @mail['DKIM-Signature']
|
76
|
+
assert dkim_header
|
77
|
+
assert_includes dkim_header.to_s, 'rsa-sha256'
|
78
|
+
assert_includes dkim_header.to_s, 's=brisbane'
|
79
|
+
assert_includes dkim_header.to_s, 'd=example.com'
|
80
|
+
assert_includes dkim_header.to_s, 'c=simple/simple'
|
81
|
+
assert_includes dkim_header.to_s, 'q=dns/txt'
|
82
|
+
assert_includes dkim_header.to_s, 'bh=2jUSOH9NhtVGCQWNr9BrIAPreKQjO6Sn7XIkfJVOzv8='
|
83
|
+
|
84
|
+
# TODO: double check signing of 'b' header
|
85
|
+
end
|
86
|
+
|
87
|
+
def test_strips_exsting_headers
|
88
|
+
warnings = ""
|
89
|
+
klass = Class.new(Interceptor)
|
90
|
+
klass.class.send(:define_method, :warn) do |message|
|
91
|
+
warnings << message << "\n"
|
92
|
+
end
|
93
|
+
@mail = Mail.new(SIGNEDMAIL)
|
94
|
+
|
95
|
+
assert_equal 2, @mail.header.fields.count { |field| field.name =~ /^DKIM-Signature$/i }
|
96
|
+
assert_equal 2, @mail.encoded.scan('DKIM-Signature').count
|
97
|
+
|
98
|
+
klass.delivering_email(@mail)
|
99
|
+
|
100
|
+
# should give a warning
|
101
|
+
assert_includes warnings, 'Interceptor'
|
102
|
+
|
103
|
+
assert_equal 1, @mail.header.fields.count { |field| field.name =~ /^DKIM-Signature$/i }
|
104
|
+
assert_equal 1, @mail.encoded.scan('DKIM-Signature').count
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Dkim
|
2
|
+
class OptionsTest < MiniTest::Unit::TestCase
|
3
|
+
def setup
|
4
|
+
klass = Class.new
|
5
|
+
klass.send :include, Options
|
6
|
+
@options = klass.new
|
7
|
+
end
|
8
|
+
def test_defaults_empty
|
9
|
+
assert_equal({}, @options.options)
|
10
|
+
end
|
11
|
+
|
12
|
+
def test_all_options
|
13
|
+
@options.signing_algorithm = 'abc123'
|
14
|
+
assert_equal({:signing_algorithm => 'abc123'}, @options.options)
|
15
|
+
|
16
|
+
desired_options = {
|
17
|
+
:signing_algorithm => 'abc123',
|
18
|
+
:signable_headers => [],
|
19
|
+
:domain => 'example.net',
|
20
|
+
:selector => 'selector',
|
21
|
+
:time => 'time',
|
22
|
+
:header_canonicalization => 'simple',
|
23
|
+
:body_canonicalization => 'simple'
|
24
|
+
}
|
25
|
+
|
26
|
+
desired_options.each do |key, value|
|
27
|
+
@options.send("#{key}=", value)
|
28
|
+
end
|
29
|
+
|
30
|
+
assert_equal(desired_options, @options.options)
|
31
|
+
|
32
|
+
desired_options.each do |key, value|
|
33
|
+
assert_equal value, @options.send("#{key}")
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
|
2
|
+
require 'test_helper'
|
3
|
+
|
4
|
+
module Dkim
|
5
|
+
class SignedMailTest < MiniTest::Unit::TestCase
|
6
|
+
def setup
|
7
|
+
@mail = EXAMPLEEMAIL.dup
|
8
|
+
end
|
9
|
+
|
10
|
+
def test_defaults
|
11
|
+
signed_mail = SignedMail.new(@mail, :time => Time.at(1234567890))
|
12
|
+
dkim_header = signed_mail.dkim_header
|
13
|
+
|
14
|
+
assert_equal 'rsa-sha256', dkim_header['a']
|
15
|
+
assert_equal 'brisbane', dkim_header['s']
|
16
|
+
assert_equal 'example.com', dkim_header['d']
|
17
|
+
assert_equal 'relaxed/relaxed', dkim_header['c']
|
18
|
+
assert_equal 'dns/txt', dkim_header['q']
|
19
|
+
|
20
|
+
# bh value from RFC 6376
|
21
|
+
assert_equal '2jUSOH9NhtVGCQWNr9BrIAPreKQjO6Sn7XIkfJVOzv8=', dkim_header['bh']
|
22
|
+
assert_equal 'mamSUb17FQSZY2lfkeAsH/DvmpHsXdaFAu6BfbVblGBQ5+2yIPCx+clF5wClVBj97utSZb1WwOM0iup1JL37FI/UG+bxHo+MdGLqbLR63THGEdVF8FVeST4o4EQTWe0H3P/sU2rRZ61+M2SrTS94QkKAgj89QNOG48xSAO9xdfs=', dkim_header['b']
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_overrides
|
26
|
+
options = {
|
27
|
+
:domain => 'example.org',
|
28
|
+
:selector => 'sidney',
|
29
|
+
:time => Time.now,
|
30
|
+
:signing_algorithm => 'rsa-sha1',
|
31
|
+
:header_canonicalization => 'simple',
|
32
|
+
:body_canonicalization => 'simple',
|
33
|
+
:time => Time.at(1234567890)
|
34
|
+
}
|
35
|
+
signed_mail = SignedMail.new(@mail, options)
|
36
|
+
dkim_header = signed_mail.dkim_header
|
37
|
+
|
38
|
+
assert_equal 'rsa-sha1', dkim_header['a']
|
39
|
+
assert_equal 'sidney', dkim_header['s']
|
40
|
+
assert_equal 'example.org', dkim_header['d']
|
41
|
+
assert_equal 'simple/simple', dkim_header['c']
|
42
|
+
assert_equal 'dns/txt', dkim_header['q']
|
43
|
+
assert_equal 'yk6W9pJJilr5MMgeEdSd7J3IaJI=', dkim_header['bh']
|
44
|
+
assert_equal 'sqYGmen+fouyIj83HuJ1v+1x40xp481bLxxcgAWMFsWYEwG05KYl+o0ZWn8jqgd1coKlX29o9iFjcMtZHudT8KpOdcLVYpY3gxzNfEgH79eRz32/ieGgroSK2GoMA/aV1QkxfUZexLUdj9oOX8uaMYXDkj8RGmlEGi+NDz/e4sE=', dkim_header['b']
|
45
|
+
end
|
46
|
+
|
47
|
+
def test_empty_body_hashes
|
48
|
+
@mail = @mail.split("\n\n").first + "\n\n"
|
49
|
+
|
50
|
+
# the following are from RFC 6376 section 3.4.3 and 3.4.4
|
51
|
+
[
|
52
|
+
# [bh, options]
|
53
|
+
['uoq1oCgLlTqpdDX/iUbLy7J1Wic=', {:body_canonicalization => 'simple', :signing_algorithm => 'rsa-sha1' }],
|
54
|
+
['frcCV1k9oG9oKj3dpUqdJg1PxRT2RSN/XKdLCPjaYaY=', {:body_canonicalization => 'simple', :signing_algorithm => 'rsa-sha256'}],
|
55
|
+
['2jmj7l5rSw0yVb/vlWAYkK/YBwk=', {:body_canonicalization => 'relaxed', :signing_algorithm => 'rsa-sha1' }],
|
56
|
+
['47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=', {:body_canonicalization => 'relaxed', :signing_algorithm => 'rsa-sha256'}],
|
57
|
+
].each do |body_hash, options|
|
58
|
+
signed_mail = SignedMail.new(@mail, options)
|
59
|
+
dkim_header = signed_mail.dkim_header
|
60
|
+
|
61
|
+
assert_equal body_hash, dkim_header['bh']
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
data/test/test_helper.rb
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
|
2
|
-
require '
|
2
|
+
require 'minitest/autorun'
|
3
3
|
require 'dkim'
|
4
4
|
|
5
5
|
class String
|
6
|
-
# Parse the format used in
|
6
|
+
# Parse the format used in RFC 6376
|
7
7
|
#
|
8
8
|
# In the following examples, actual whitespace is used only for
|
9
9
|
# clarity. The actual input and output text is designated using
|
@@ -23,7 +23,37 @@ class String
|
|
23
23
|
end
|
24
24
|
end
|
25
25
|
|
26
|
-
# examples used in
|
27
|
-
|
26
|
+
# examples used in RFC 6376
|
27
|
+
EXAMPLEEMAIL = %{
|
28
|
+
From: Joe SixPack <IIVyTowbcT@www.brandonchecketts.com>
|
29
|
+
To: Suzie Q <suzie@shopping.example.net>
|
30
|
+
Subject: Is dinner ready?
|
31
|
+
Date: Fri, 11 Jul 2003 21:00:37 -0700 (PDT)
|
32
|
+
Message-ID: <20030712040037.46341.5F8J@football.example.com>
|
33
|
+
|
34
|
+
Hi.
|
35
|
+
|
36
|
+
We lost the game. Are you hungry yet?
|
28
37
|
|
38
|
+
Joe.}.gsub(/\A\n/,'')
|
39
|
+
|
40
|
+
Dkim::domain = 'example.com'
|
41
|
+
Dkim::selector = 'brisbane'
|
42
|
+
Dkim::private_key = %{
|
43
|
+
-----BEGIN RSA PRIVATE KEY-----
|
44
|
+
MIICXwIBAAKBgQDwIRP/UC3SBsEmGqZ9ZJW3/DkMoGeLnQg1fWn7/zYtIxN2SnFC
|
45
|
+
jxOCKG9v3b4jYfcTNh5ijSsq631uBItLa7od+v/RtdC2UzJ1lWT947qR+Rcac2gb
|
46
|
+
to/NMqJ0fzfVjH4OuKhitdY9tf6mcwGjaNBcWToIMmPSPDdQPNUYckcQ2QIDAQAB
|
47
|
+
AoGBALmn+XwWk7akvkUlqb+dOxyLB9i5VBVfje89Teolwc9YJT36BGN/l4e0l6QX
|
48
|
+
/1//6DWUTB3KI6wFcm7TWJcxbS0tcKZX7FsJvUz1SbQnkS54DJck1EZO/BLa5ckJ
|
49
|
+
gAYIaqlA9C0ZwM6i58lLlPadX/rtHb7pWzeNcZHjKrjM461ZAkEA+itss2nRlmyO
|
50
|
+
n1/5yDyCluST4dQfO8kAB3toSEVc7DeFeDhnC1mZdjASZNvdHS4gbLIA1hUGEF9m
|
51
|
+
3hKsGUMMPwJBAPW5v/U+AWTADFCS22t72NUurgzeAbzb1HWMqO4y4+9Hpjk5wvL/
|
52
|
+
eVYizyuce3/fGke7aRYw/ADKygMJdW8H/OcCQQDz5OQb4j2QDpPZc0Nc4QlbvMsj
|
53
|
+
7p7otWRO5xRa6SzXqqV3+F0VpqvDmshEBkoCydaYwc2o6WQ5EBmExeV8124XAkEA
|
54
|
+
qZzGsIxVP+sEVRWZmW6KNFSdVUpk3qzK0Tz/WjQMe5z0UunY9Ax9/4PVhp/j61bf
|
55
|
+
eAYXunajbBSOLlx4D+TunwJBANkPI5S9iylsbLs6NkaMHV6k5ioHBBmgCak95JGX
|
56
|
+
GMot/L2x0IYyMLAz6oLWh2hm7zwtb0CgOrPo1ke44hFYnfc=
|
57
|
+
-----END RSA PRIVATE KEY-----
|
58
|
+
}
|
29
59
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dkim
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2012-04-16 00:00:00.000000000 Z
|
13
13
|
dependencies: []
|
14
14
|
description: gem for adding DKIM signatures to email messages
|
15
15
|
email:
|
@@ -20,8 +20,10 @@ extensions: []
|
|
20
20
|
extra_rdoc_files: []
|
21
21
|
files:
|
22
22
|
- .gitignore
|
23
|
+
- .travis.yml
|
23
24
|
- CHANGELOG.md
|
24
25
|
- Gemfile
|
26
|
+
- Guardfile
|
25
27
|
- README.md
|
26
28
|
- Rakefile
|
27
29
|
- bin/dkimsign.rb
|
@@ -33,10 +35,15 @@ files:
|
|
33
35
|
- lib/dkim/header.rb
|
34
36
|
- lib/dkim/header_list.rb
|
35
37
|
- lib/dkim/interceptor.rb
|
38
|
+
- lib/dkim/options.rb
|
36
39
|
- lib/dkim/signed_mail.rb
|
37
40
|
- lib/dkim/version.rb
|
38
41
|
- lib/mail/dkim_field.rb
|
39
|
-
- test/canonicalization_test.rb
|
42
|
+
- test/dkim/canonicalization_test.rb
|
43
|
+
- test/dkim/dkim_header_test.rb
|
44
|
+
- test/dkim/interceptor_test.rb
|
45
|
+
- test/dkim/options_test.rb
|
46
|
+
- test/dkim/signed_mail_test.rb
|
40
47
|
- test/test_helper.rb
|
41
48
|
homepage: https://github.com/jhawthorn/dkim
|
42
49
|
licenses: []
|
@@ -50,18 +57,28 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
50
57
|
- - ! '>='
|
51
58
|
- !ruby/object:Gem::Version
|
52
59
|
version: '0'
|
60
|
+
segments:
|
61
|
+
- 0
|
62
|
+
hash: -2701069676603955611
|
53
63
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
54
64
|
none: false
|
55
65
|
requirements:
|
56
66
|
- - ! '>='
|
57
67
|
- !ruby/object:Gem::Version
|
58
68
|
version: '0'
|
69
|
+
segments:
|
70
|
+
- 0
|
71
|
+
hash: -2701069676603955611
|
59
72
|
requirements: []
|
60
73
|
rubyforge_project: dkim
|
61
|
-
rubygems_version: 1.8.
|
74
|
+
rubygems_version: 1.8.17
|
62
75
|
signing_key:
|
63
76
|
specification_version: 3
|
64
77
|
summary: DKIM library in ruby
|
65
78
|
test_files:
|
66
|
-
- test/canonicalization_test.rb
|
79
|
+
- test/dkim/canonicalization_test.rb
|
80
|
+
- test/dkim/dkim_header_test.rb
|
81
|
+
- test/dkim/interceptor_test.rb
|
82
|
+
- test/dkim/options_test.rb
|
83
|
+
- test/dkim/signed_mail_test.rb
|
67
84
|
- test/test_helper.rb
|
@@ -1,78 +0,0 @@
|
|
1
|
-
|
2
|
-
require 'test_helper'
|
3
|
-
|
4
|
-
class CanonicalizationTest < Test::Unit::TestCase
|
5
|
-
# from section 3.4.6 of rfc4871
|
6
|
-
def setup
|
7
|
-
@input = <<-eos.rfc_format
|
8
|
-
A: <SP> X <CRLF>
|
9
|
-
B <SP> : <SP> Y <HTAB><CRLF>
|
10
|
-
<HTAB> Z <SP><SP><CRLF>
|
11
|
-
<CRLF>
|
12
|
-
<SP> C <SP><CRLF>
|
13
|
-
D <SP><HTAB><SP> E <CRLF>
|
14
|
-
<CRLF>
|
15
|
-
<CRLF>
|
16
|
-
eos
|
17
|
-
@mail = Dkim::SignedMail.new(@input)
|
18
|
-
@mail.signable_headers = ['A', 'B']
|
19
|
-
end
|
20
|
-
def test_relaxed_header
|
21
|
-
@mail.header_canonicalization = 'relaxed'
|
22
|
-
expected_header = <<-eos.rfc_format
|
23
|
-
a:X <CRLF>
|
24
|
-
b:Y <SP> Z <CRLF>
|
25
|
-
eos
|
26
|
-
assert_equal expected_header, @mail.canonical_header
|
27
|
-
end
|
28
|
-
def test_relaxed_body
|
29
|
-
@mail.body_canonicalization = 'relaxed'
|
30
|
-
expected_body = <<-eos.rfc_format
|
31
|
-
<SP> C <CRLF>
|
32
|
-
D <SP> E <CRLF>
|
33
|
-
eos
|
34
|
-
assert_equal expected_body, @mail.canonical_body
|
35
|
-
end
|
36
|
-
|
37
|
-
def test_simple_header
|
38
|
-
@mail.header_canonicalization = 'simple'
|
39
|
-
expected_header = <<-eos.rfc_format
|
40
|
-
A: <SP> X <CRLF>
|
41
|
-
B <SP> : <SP> Y <HTAB><CRLF>
|
42
|
-
<HTAB> Z <SP><SP><CRLF>
|
43
|
-
eos
|
44
|
-
assert_equal expected_header, @mail.canonical_header
|
45
|
-
end
|
46
|
-
def test_simple_body
|
47
|
-
@mail.body_canonicalization = 'simple'
|
48
|
-
expected_body = <<-eos.rfc_format
|
49
|
-
<SP> C <SP><CRLF>
|
50
|
-
D <SP><HTAB><SP> E <CRLF>
|
51
|
-
eos
|
52
|
-
assert_equal expected_body, @mail.canonical_body
|
53
|
-
end
|
54
|
-
|
55
|
-
# from errata: empty bodies
|
56
|
-
def test_simple_empty_body
|
57
|
-
@mail = Dkim::SignedMail.new("test: test\r\n\r\n")
|
58
|
-
@mail.body_canonicalization = 'simple'
|
59
|
-
|
60
|
-
assert_equal "\r\n", @mail.canonical_body
|
61
|
-
end
|
62
|
-
|
63
|
-
def test_relaxed_empty_body
|
64
|
-
@mail = Dkim::SignedMail.new("test: test\r\n\r\n")
|
65
|
-
@mail.body_canonicalization = 'relaxed'
|
66
|
-
|
67
|
-
assert_equal "", @mail.canonical_body
|
68
|
-
end
|
69
|
-
|
70
|
-
def test_relaxed_errata_1384
|
71
|
-
body = "testing<crlf><sp><sp><cr><lf><cr><lf>".rfc_format
|
72
|
-
@mail = Dkim::SignedMail.new("test: test\r\n\r\n#{body}")
|
73
|
-
@mail.body_canonicalization = 'relaxed'
|
74
|
-
|
75
|
-
assert_equal "testing\r\n", @mail.canonical_body
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|