Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 51c8fdcb6c | |||
| aa4dadc22f | |||
| b1abbf9d61 | |||
| ea2b612e8d | |||
| 5945e818ca | |||
| f38fed3bee | |||
| 06948b3dbc | |||
| e951ab6c5e | |||
| 03c86a2b08 | |||
| 2cda1758c1 |
@@ -1,3 +1,12 @@
|
||||
1.0.1 2019-02-11
|
||||
* Reorder milter start and dropping privileges so permissions on Unix socket
|
||||
are correct (LP: 1797720)
|
||||
- Make domain checks case insensitive for determining if signing should be
|
||||
done (LP: #1815311)
|
||||
- Add additional Sendmail configuration information to README from OpenDKIM
|
||||
update based on input from Дилян Палаузов (LP: #1801619)
|
||||
- Add information on Ed25519 key creation to README (LP: #1815313)
|
||||
|
||||
1.0.0 2018-05-11
|
||||
- Minor documentation updates
|
||||
- Deleted reference to obsolete syslog target in unit file
|
||||
|
||||
@@ -1,10 +1,17 @@
|
||||
This is a DKIM signing and verification milter. In theory it has been tested
|
||||
with both Postfix and Sendmail.
|
||||
OVERVIEW
|
||||
========
|
||||
|
||||
This is a DKIM signing and verification milter. It has been tested with both
|
||||
Postfix and Sendmail.
|
||||
|
||||
The configuration file is designed to be compatible with OpenDKIM, but only
|
||||
a subset of OpenDKIM options are supported. If an unsupported option is
|
||||
specified, an error will be raised.
|
||||
|
||||
|
||||
INSTALLATION
|
||||
===========
|
||||
|
||||
This package includes a default configuration file and man pages. For those
|
||||
to be installed when installing using setup.py, the following incantation is
|
||||
required because setuptools developers decided not being able to do this by
|
||||
@@ -12,7 +19,7 @@ default is a feature:
|
||||
|
||||
python setup.py install --single-version-externally-managed --record=/dev/null
|
||||
|
||||
For users of Debian Stable (Debian 9, Codename Squueze), all dependencies are
|
||||
For users of Debian Stable (Debian 9, Codename Squeeze), all dependencies are
|
||||
available in either the main or backports repositories:
|
||||
|
||||
[sudo] apt install python-milter python-nacl python-ipaddress python-dnspython
|
||||
@@ -33,6 +40,48 @@ The milter will work with either pydns (DNS) or dnspython (dns), preferring
|
||||
dnspython is both are available. The dkimpy DKIM module also works with
|
||||
either.
|
||||
|
||||
|
||||
SETUP
|
||||
====
|
||||
|
||||
SIGNING KEYS
|
||||
============
|
||||
|
||||
In order to create DKIM signatures, a private key must be available. Signing
|
||||
keys should be protected (owned by root:root with permissions 600 in a
|
||||
directory that is not world readable). Different keys are required for RSA
|
||||
and (if used) Ed25519.
|
||||
|
||||
RSA
|
||||
===
|
||||
|
||||
Both public and private keys for RSA have standard formats and there are many
|
||||
tools available to create them. Keys must (RFC 8302) have a minimum size of
|
||||
1024 bits and should have a size of at least 2048 bits. The dknewkey script
|
||||
that is provided with dkimpy is one such tool:
|
||||
|
||||
dknewkey exampleprivkey
|
||||
|
||||
will produce both the private key file (.key suffix) and a file with the DKIM
|
||||
public key record to be published DNS (.dns suffix). RSA is the default key
|
||||
type. 2048 bits is the default key size.
|
||||
|
||||
ED25519
|
||||
=======
|
||||
|
||||
There is no standardized non-binary representation for Ed25519 private keys,
|
||||
so in order to generate Ed25519 keys for dkimpy-milter, dkimpy specific tools
|
||||
must be used to be compatible. The same dknewkey script support Ed25519:
|
||||
|
||||
dknewkey --ktype ed25519 anothernewkey
|
||||
|
||||
will provide both the private key file (.key suffix) and a file with the DKIM
|
||||
public key record to be published DNS (.dns suffix). Ed25519 keys do not have
|
||||
variable bit lengths.
|
||||
|
||||
MTA INTEGRATION
|
||||
==============
|
||||
|
||||
Both a systemd unit file and a sysv init file are provided. Both make
|
||||
assumptions about defaults being used, e.g. if a non-standard pidfile name is
|
||||
used, they will need to be updated. The sysv init file is Debian specific and
|
||||
@@ -61,7 +110,8 @@ the following steps:
|
||||
As with all milters, dkimpy-milter needs to be integrated with your MTA of
|
||||
choice (Sendmail or Postfix).
|
||||
|
||||
For Sendmail:
|
||||
SENDMAIL
|
||||
========
|
||||
|
||||
Configuration is very similar to opendkim, but needs some adjustment for
|
||||
dkimpy-milter. Here's an example configuration line to include in your
|
||||
@@ -77,12 +127,64 @@ Milter support should be present by default in most versions of sendmail
|
||||
these days, but if not included in your Sendmail build, see:
|
||||
http://www.elandsys.com/resources/sendmail/milter.html
|
||||
|
||||
For Postfix:
|
||||
ISSUES USING SENDMAIL TO SIGN AND VERIFY
|
||||
========================================
|
||||
|
||||
When using the sendmail MTA in both signing and verifying mode, there are
|
||||
a few issues of which to be aware that might cause operational problems
|
||||
and deserve consideration.
|
||||
|
||||
(a) When the MTA will be used for relaying emails, e.g. delivering to other
|
||||
hosts using the aliases mechanism, it is important not to break
|
||||
signatures inserted by the original sender. This is particularly sensitive
|
||||
particular when the sending domain has published a "reject" DMARC policy.
|
||||
|
||||
By default, sendmail quotes to address header fields when there are no
|
||||
quotes and the display part of the address contains a period or an
|
||||
apostrophe. However, opendkim only sees the raw, unmodified form of
|
||||
the header field, and so the content that gets verified and what gets
|
||||
signed will not be the same, guaranteeing the attached signature is not
|
||||
valid.
|
||||
|
||||
To direct sendmail not to modify the headers, add this to your sendmail.mc:
|
||||
|
||||
conf(`confMUST_QUOTE_CHARS', `')
|
||||
|
||||
(b) As stated in sendmail's KNOWNBUGS file, sendmail truncates header field
|
||||
values longer than 256 characters, which could mean truncating the domain
|
||||
of a long From: header field value and invalidating the signature.
|
||||
You may wish to consider increasing MAXNAME in sendmail/conf.h to mitigate
|
||||
changing the messages and invalidating their signatures. This change
|
||||
requires recompiling sendmail.
|
||||
|
||||
(c) Similar to (a) above, sendmail may wrap very long single-line recipient
|
||||
fields for presentation purposes; for example:
|
||||
|
||||
To: very long name <a@example.org>,anotherloo...ong name b <b@example.org>
|
||||
|
||||
...might be rewritten as:
|
||||
|
||||
To: very long name <a@example.org>,
|
||||
anotherloo...ong name b <b@example.org>
|
||||
|
||||
This rewrite is also done after opendkim has seen the message, meaning
|
||||
the signature opendkim attaches to the message does not match the
|
||||
content it signed. There is not a known configuration change to
|
||||
mitigate this mutation.
|
||||
|
||||
The only known mechanism for dealing with this is to have distinct
|
||||
instances of opendkim do the verifying (inbound) and signing (outbound)
|
||||
so that the version that arrives at the signing instance is already
|
||||
in the rewritten form, guaranteeing the input and output are the same
|
||||
and thus the signature matches the payload.
|
||||
|
||||
POSTFIX
|
||||
=======
|
||||
|
||||
Integration of dkimpy-milter into Postfix is like any milter (See Postfix's
|
||||
README_FILES/MILTER_README). Here's an example master.cf excerpt the talks to
|
||||
two dkimpy-milter instances, one configured for signing and one configured for
|
||||
verification:
|
||||
README_FILES/MILTER_README). Here's an example master.cf excerpt that talks
|
||||
to two dkimpy-milter instances, one configured for signing and one configured
|
||||
for verification:
|
||||
|
||||
smtp inet n - - - - smtpd
|
||||
...
|
||||
@@ -127,14 +229,15 @@ MacroListVerify daemon_name|VERIFYING
|
||||
...
|
||||
|
||||
|
||||
NOTES
|
||||
=====
|
||||
|
||||
The python DKIM library, dkimpy, requires the entire message being signed or
|
||||
verified to be in memory, so dkimpy-milter does not write messages out to a
|
||||
temp file. This may impact performance on low-memory systems.
|
||||
|
||||
This is an initial production release to support interoperability testing with
|
||||
Ed25519 signatures sufficient functionality for basic use. The documented
|
||||
functionality has been implemented and at generally partially tested. It is
|
||||
free of known defects, but is not fully tested in a variety of environments.
|
||||
|
||||
DKIM Ed25519 signatures are still in development, but the specification is
|
||||
technically stable. Version 1.0.0 supports draft-ietf-dcrup-dkim-crypto-09.
|
||||
DKIM with Ed25519 signatures are described in RFC 8463. Version 1.0.0 and
|
||||
later support Ed25519 signing and verification. RFC 8301 removed rsa-sha1
|
||||
from DKIM. dkimpy-milter does not sign with rsa-sha1, but still considers
|
||||
rsa-sha1 signatures as valid for verification because they are still in
|
||||
common use and are not known to be cryptographically broken.
|
||||
|
||||
@@ -39,10 +39,16 @@ MacroListVerify implemented verified
|
||||
SyslogSuccess implemented verified
|
||||
|
||||
1.0.0
|
||||
No additional features planned
|
||||
No additional features
|
||||
|
||||
Plannedataset type support (if needed):
|
||||
db:/.db
|
||||
1.0.1
|
||||
Bug fix only, improved documentation
|
||||
|
||||
1.1.0 (planned)
|
||||
Port to Python 3
|
||||
Subdomain support
|
||||
|
||||
Planned dataset type support (if needed):
|
||||
mdb:
|
||||
|
||||
Considered for near-term feature release
|
||||
@@ -50,7 +56,7 @@ Considered for near-term feature release
|
||||
AlwaysAddARHeader
|
||||
ChangeRootDirectory
|
||||
ClockDrift (requires dkimpy change)
|
||||
DNSTimeout (requires dkmpy change)
|
||||
DNSTimeout (requires dkimpy change)
|
||||
MilterDebug
|
||||
MinimumKeyBits
|
||||
OversignHeaders (may require dkimpy changes)
|
||||
|
||||
+11
-11
@@ -39,7 +39,7 @@ from dkimpy_milter.util import read_keyfile
|
||||
from dkimpy_milter.util import own_socketfile
|
||||
from dkimpy_milter.util import fold
|
||||
|
||||
__version__ = "1.0.0"
|
||||
__version__ = "1.0.1"
|
||||
FWS = re.compile(r'\r?\n[ \t]+')
|
||||
|
||||
|
||||
@@ -131,7 +131,7 @@ class dkimMilter(Milter.Base):
|
||||
if lname == 'from':
|
||||
fname, self.author = parseaddr(val)
|
||||
try:
|
||||
self.fdomain = self.author.split('@')[1]
|
||||
self.fdomain = self.author.split('@')[1].lower()
|
||||
except IndexError as er:
|
||||
self.fdomain = '' # self.author was not a proper email address
|
||||
if (milterconfig.get('Syslog') and
|
||||
@@ -228,7 +228,7 @@ class dkimMilter(Milter.Base):
|
||||
'd={3})'.format(self.getsymval('i'),
|
||||
d.signature_fields.get(b'a'),
|
||||
d.signature_fields.get(b's'),
|
||||
d.domain))
|
||||
d.domain.lower()))
|
||||
if privateEd25519:
|
||||
d = dkim.DKIM(txt)
|
||||
h = d.sign(milterconfig.get('SelectorEd25519'), self.fdomain,
|
||||
@@ -244,7 +244,7 @@ class dkimMilter(Milter.Base):
|
||||
'd={3})'.format(self.getsymval('i'),
|
||||
d.signature_fields.get(b'a'),
|
||||
d.signature_fields.get(b's'),
|
||||
d.domain))
|
||||
d.domain.lower()))
|
||||
except dkim.DKIMException as x:
|
||||
if milterconfig.get('Syslog'):
|
||||
syslog.syslog('DKIM: {0}'.format(x))
|
||||
@@ -292,8 +292,8 @@ class dkimMilter(Milter.Base):
|
||||
'd={3})'.format(self.getsymval('i'),
|
||||
d.signature_fields.get(b'a'),
|
||||
d.signature_fields.get(b's'),
|
||||
d.domain))
|
||||
self.dkim_domain = d.domain
|
||||
d.domain.lower()))
|
||||
self.dkim_domain = d.domain.lower()
|
||||
else:
|
||||
if milterconfig.get('DiagnosticDirectory'):
|
||||
fd, fname = tempfile.mkstemp(".dkim")
|
||||
@@ -303,7 +303,7 @@ class dkimMilter(Milter.Base):
|
||||
syslog.syslog('DKIM: Fail (saved as {0})'
|
||||
.format(fname))
|
||||
else:
|
||||
syslog.syslog('DKIM: Fail ({0})'.format(d.domain))
|
||||
syslog.syslog('DKIM: Fail ({0})'.format(d.domain.lower()))
|
||||
if res:
|
||||
result = 'pass'
|
||||
else:
|
||||
@@ -348,13 +348,13 @@ def main():
|
||||
Milter.set_flags(Milter.CHGHDRS + Milter.ADDHDRS)
|
||||
miltername = 'dkimpy-filter'
|
||||
socketname = milterconfig.get('Socket')
|
||||
own_socketfile(milterconfig)
|
||||
drop_privileges(milterconfig)
|
||||
sys.stdout.flush()
|
||||
Milter.runmilter(miltername, socketname, 240)
|
||||
if milterconfig.get('Syslog'):
|
||||
syslog.syslog('dkimpy-milter started:{0} user:{1}'
|
||||
.format(pid, milterconfig.get('UserID')))
|
||||
sys.stdout.flush()
|
||||
Milter.runmilter(miltername, socketname, 240)
|
||||
own_socketfile(milterconfig)
|
||||
drop_privileges(milterconfig)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
+1
-13
@@ -294,19 +294,7 @@ def _dataset_to_list(dataset):
|
||||
else:
|
||||
return [dataset.strip().strip(',')]
|
||||
if dataset[-3:] == '.db' or dataset[:3] == 'db:':
|
||||
# This is a Sleepycat (Oracle) DB dataset
|
||||
import whichdb # Will need rewriting someday for python3
|
||||
if dataset[-3:] == '.db':
|
||||
dbname = dataset
|
||||
elif dataset[:3] == 'db:':
|
||||
dbname = dataset[3:]
|
||||
else:
|
||||
raise dkim.ParameterError('Unimplmented dataset type: {0}'
|
||||
.format(type(dataset)))
|
||||
if whichdb.whichdb(dbname) != 'dbhash':
|
||||
raise dkim.ParameterError('Unimplmented dataset type: {0}'
|
||||
.format(type(dataset)))
|
||||
#TODO replace this with code to use db maps
|
||||
# This is a Sleepycat (Oracle) DB dataset, which we dont support
|
||||
raise dkim.ParameterError('Unsupported dataset db datase: {0}'
|
||||
.format(type(dataset)))
|
||||
|
||||
|
||||
+5
-4
@@ -127,7 +127,6 @@
|
||||
.rm #[ #] #H #V #F C
|
||||
.\" ========================================================================
|
||||
.\"
|
||||
.IX Title "dkimpy-milter 8"
|
||||
.TH dkimpyy-milter 8
|
||||
.SH NAME
|
||||
.B dkimpy
|
||||
@@ -269,7 +268,7 @@ proposal, and Cisco's
|
||||
.B Internet Identified Mail
|
||||
(IIM) proposal.
|
||||
.SH VERSION
|
||||
This man page covers version 0.9.4 of
|
||||
This man page covers version 1.1.0 of
|
||||
.I dkimpy-milter.
|
||||
.SH COPYRIGHT
|
||||
Copyright (c) 2005-2008, Sendmail, Inc. and its suppliers. All rights
|
||||
@@ -278,7 +277,7 @@ reserved.
|
||||
Copyright (c) 2009-2013, 2015, The Trusted Domain Project.
|
||||
All rights reserved.
|
||||
|
||||
Copyright (c) 2018 Scott Kitterman <scott@kitterman.com>
|
||||
Copyright (c) 2018, 2019 Scott Kitterman <scott@kitterman.com>
|
||||
.SH SEE ALSO
|
||||
.I dkimpy-milter.conf(5), sendmail(8)
|
||||
.P
|
||||
@@ -292,4 +291,6 @@ RFC6376 - DomainKeys Identified Mail
|
||||
.P
|
||||
RFC7601 - Message Header Field for Indicating Message Authentication Status
|
||||
.P
|
||||
draft-ietf-dcrup-dkim-crypto - A new cryptographic signature method for DKIM
|
||||
RFC8301 - Cryptographic Algorithm and Key Usage Update to DomainKeys Identified Mail (DKIM)
|
||||
.P
|
||||
RFC8463 - A New Cryptographic Signature Method for DomainKeys Identified Mail (DKIM)
|
||||
|
||||
@@ -127,16 +127,13 @@
|
||||
.rm #[ #] #H #V #F C
|
||||
.\" ========================================================================
|
||||
.\"
|
||||
.IX Title "dkimpy-milter.conf 5"
|
||||
.TH dkimpy-milter.conf 5 "2018-02-12"
|
||||
.SH "NAME"
|
||||
dkimpy-milter \- Python milter for DKIM signing and validation
|
||||
.SH "VERSION"
|
||||
.IX Header "VERSION"
|
||||
0\.9\.2
|
||||
|
||||
.SH "DESCRIPTION"
|
||||
.IX Header "DESCRIPTION"
|
||||
.I dkimpy-milter(8)
|
||||
implements the
|
||||
.B DKIM
|
||||
@@ -160,18 +157,15 @@ The provided setup.py installs this configuration file in /etc or
|
||||
Command line invocation of parameters as is done by OpenDKIM is not supported.
|
||||
|
||||
.SH "USAGE"
|
||||
.IX Header "USAGE"
|
||||
Usage:
|
||||
dkimpy-milter [/etc/dkimpy-milter.conf]
|
||||
|
||||
.SH "OTHER DOCUMENTATION"
|
||||
.IX Header "OTHER DOCUMENTATION"
|
||||
This documentation assumes you have read Postfix's README_FILES/MILTER_README
|
||||
(or Sendmail equivalent) and are generally familiar with Domain Keys Identified
|
||||
Mail (DKIM). See RFC 6376 for details.
|
||||
|
||||
.SH "SYNOPSIS"
|
||||
.IX Header "SYNOPSIS"
|
||||
|
||||
dkimpy-milter operates with a default installed configuration file and
|
||||
set of default configuration options that are used if the configuration file
|
||||
@@ -181,14 +175,12 @@ files can be used directly. Not all OpenDKIM options are supported. If an
|
||||
unsupported option from OpenDKIM is specified, an error will be raised.
|
||||
|
||||
.SH "DESCRIPTION"
|
||||
.IX Header "DESCRIPTION"
|
||||
|
||||
Configuration options are described here and in the configuration file
|
||||
provided with the package. The provided setup.py installs this configuration
|
||||
file in /etc or /usr/local/etc.
|
||||
|
||||
.SH "OPTIONS"
|
||||
.IX Header "OPTIONS"
|
||||
|
||||
.TP
|
||||
.I AuthservID (string)
|
||||
@@ -441,7 +433,6 @@ unless an alternate
|
||||
is specified.
|
||||
|
||||
.SH "AUTHORS"
|
||||
.IX Header "AUTHORS"
|
||||
\ddkimpy-milter\fR was written by Scott Kitterman <scott@kitterman.com>.
|
||||
It is based on dkimpy-milter.py Copyright (c) 2001-2013 Business Management Systems, Inc.
|
||||
Copyright (c) 2013-2015 Stuart D. Gathman
|
||||
|
||||
Reference in New Issue
Block a user