Bug fixes for RSA/Ed25519 signing (now works), syslog fixes, update TODO verification status
This commit is contained in:
@@ -1,14 +1,14 @@
|
|||||||
TODO
|
TODO
|
||||||
|
|
||||||
0.9.1 (Alpha)
|
0.9.1 (Alpha)
|
||||||
Sign rsa/ed25519 implemented
|
Sign rsa/ed25519 implemented verified
|
||||||
Verify rsa/ed25519 implemented
|
Verify rsa/ed25519 implemented
|
||||||
Domain implemented
|
Domain implemented verified
|
||||||
KeyFile implemented
|
KeyFile implemented verified
|
||||||
KeyFileEd25519 implemented
|
KeyFileEd25519 implemented verified
|
||||||
Mode implemented
|
Mode implemented
|
||||||
PidFile implemented verified
|
PidFile implemented verified
|
||||||
Selector implemented
|
Selector implemented verified
|
||||||
Socket implemented verified
|
Socket implemented verified
|
||||||
Syslog implemented partly tested
|
Syslog implemented partly tested
|
||||||
UMask implemented
|
UMask implemented
|
||||||
|
|||||||
+26
-21
@@ -45,13 +45,13 @@ FWS = re.compile(r'\r?\n[ \t]+')
|
|||||||
class dkimMilter(Milter.Base):
|
class dkimMilter(Milter.Base):
|
||||||
"Milter to check and sign DKIM. Each connection gets its own instance."
|
"Milter to check and sign DKIM. Each connection gets its own instance."
|
||||||
|
|
||||||
def __init__(self, milterconfig, privatersa=False, privateed25519=False):
|
def __init__(self):
|
||||||
self.mailfrom = None
|
self.mailfrom = None
|
||||||
self.id = Milter.uniqueID()
|
self.id = Milter.uniqueID()
|
||||||
# we don't want config used to change during a connection
|
# we don't want config used to change during a connection
|
||||||
self.conf = milterconfig
|
self.conf = milterconfig
|
||||||
self.privatersa = privatersa
|
self.privatersa = privateRSA
|
||||||
self.privateed25519 = privateed25519
|
self.privateed25519 = privateEd25519
|
||||||
self.fp = None
|
self.fp = None
|
||||||
|
|
||||||
@Milter.noreply
|
@Milter.noreply
|
||||||
@@ -71,7 +71,7 @@ class dkimMilter(Milter.Base):
|
|||||||
else:
|
else:
|
||||||
connecttype = 'EXTERNAL'
|
connecttype = 'EXTERNAL'
|
||||||
if milterconfig.get('Syslog'):
|
if milterconfig.get('Syslog'):
|
||||||
syslog.syslog("connect from %s at %s %s" % (hostname,hostaddr,connecttype))
|
syslog.syslog("connect from {0} at {1} {2}".format(hostname,hostaddr,connecttype))
|
||||||
return Milter.CONTINUE
|
return Milter.CONTINUE
|
||||||
|
|
||||||
# multiple messages can be received on a single connection
|
# multiple messages can be received on a single connection
|
||||||
@@ -80,7 +80,7 @@ class dkimMilter(Milter.Base):
|
|||||||
@Milter.noreply
|
@Milter.noreply
|
||||||
def envfrom(self,f,*str):
|
def envfrom(self,f,*str):
|
||||||
if milterconfig.get('Syslog'):
|
if milterconfig.get('Syslog'):
|
||||||
syslog.syslog("mail from",f,str)
|
syslog.syslog("mail from: {0} {1}".format(f,str))
|
||||||
self.fp = StringIO.StringIO()
|
self.fp = StringIO.StringIO()
|
||||||
self.mailfrom = f
|
self.mailfrom = f
|
||||||
t = parse_addr(f)
|
t = parse_addr(f)
|
||||||
@@ -114,12 +114,12 @@ class dkimMilter(Milter.Base):
|
|||||||
lname = name.lower()
|
lname = name.lower()
|
||||||
if lname == 'dkim-signature':
|
if lname == 'dkim-signature':
|
||||||
if milterconfig.get('Syslog'):
|
if milterconfig.get('Syslog'):
|
||||||
syslog.syslog("%s: %s" % (name,val))
|
syslog.syslog("{0}: {1}".format(name,val))
|
||||||
self.has_dkim += 1
|
self.has_dkim += 1
|
||||||
if lname == 'from':
|
if lname == 'from':
|
||||||
fname,self.author = parseaddr(val)
|
fname,self.author = parseaddr(val)
|
||||||
if milterconfig.get('Syslog'):
|
if milterconfig.get('Syslog'):
|
||||||
syslog.syslog("%s: %s" % (name,val))
|
syslog.syslog("{0}: {1}".format(name,val))
|
||||||
elif lname == 'authentication-results':
|
elif lname == 'authentication-results':
|
||||||
self.arheaders.append(val)
|
self.arheaders.append(val)
|
||||||
if self.fp:
|
if self.fp:
|
||||||
@@ -150,14 +150,14 @@ class dkimMilter(Milter.Base):
|
|||||||
if ar.authserv_id == self.receiver:
|
if ar.authserv_id == self.receiver:
|
||||||
self.chgheader('authentication-results',i,'')
|
self.chgheader('authentication-results',i,'')
|
||||||
if milterconfig.get('Syslog'):
|
if milterconfig.get('Syslog'):
|
||||||
syslog.syslog('REMOVE: ',val)
|
syslog.syslog('REMOVE: {0}'.format(val))
|
||||||
# Check or sign DKIM
|
# Check or sign DKIM
|
||||||
self.fp.seek(0)
|
self.fp.seek(0)
|
||||||
if self.internal_connection or conf.get('Mode') == 's' or conf.get('Mode') == 'sv':
|
if self.internal_connection or milterconfig.get('Mode') == 's' or milterconfig.get('Mode') == 'sv':
|
||||||
txt = self.fp.read()
|
txt = self.fp.read()
|
||||||
self.sign_dkim(txt)
|
self.sign_dkim(txt)
|
||||||
result = None
|
result = None
|
||||||
if self.has_dkim and (conf.get('Mode') == 'v' or conf.get('Mode') == 'sv'):
|
if self.has_dkim and (milterconfig.get('Mode') == 'v' or milterconfig.get('Mode') == 'sv'):
|
||||||
txt = self.fp.read()
|
txt = self.fp.read()
|
||||||
self.check_dkim(txt)
|
self.check_dkim(txt)
|
||||||
else:
|
else:
|
||||||
@@ -175,22 +175,23 @@ class dkimMilter(Milter.Base):
|
|||||||
conf = self.conf
|
conf = self.conf
|
||||||
try:
|
try:
|
||||||
d = dkim.DKIM(txt)
|
d = dkim.DKIM(txt)
|
||||||
h = d.sign(conf.get('Selector'),conf.get('Domain'), self.privatersa,
|
h = d.sign(milterconfig.get('Selector'),milterconfig.get('Domain'), privateRSA,
|
||||||
canonicalize=('relaxed','simple'))
|
canonicalize=('relaxed','simple'))
|
||||||
name,val = h.split(': ',1)
|
name,val = h.split(': ',1)
|
||||||
self.addheader(name,val.strip().replace('\r\n','\n'),0)
|
self.addheader(name,val.strip().replace('\r\n','\n'),0)
|
||||||
if self.privateed25519:
|
if privateEd25519:
|
||||||
d = dkim.DKIM(txt)
|
d = dkim.DKIM(txt)
|
||||||
h = d.sign(conf.get('SelectorEd25519'),conf.get('Domain'), self.privateed25519,
|
h = d.sign(milterconfig.get('SelectorEd25519'),milterconfig.get('Domain'), privateEd25519,
|
||||||
canonicalize=('relaxed','simple'))
|
canonicalize=('relaxed','simple'), signature_algorithm='ed25519-sha256')
|
||||||
name,val = h.split(': ',1)
|
name,val = h.split(': ',1)
|
||||||
self.addheader(name,val.strip().replace('\r\n','\n'),0)
|
self.addheader(name,val.strip().replace('\r\n','\n'),0)
|
||||||
except dkim.DKIMException as x:
|
except dkim.DKIMException as x:
|
||||||
if milterconfig.get('Syslog'):
|
if milterconfig.get('Syslog'):
|
||||||
syslog.syslog('DKIM: %s'%x)
|
syslog.syslog('DKIM: {0}'.format(x))
|
||||||
except Exception as x:
|
except Exception as x:
|
||||||
if milterconfig.get('Syslog'):
|
if milterconfig.get('Syslog'):
|
||||||
syslog.syslog("sign_dkim: %s",x,exc_info=True)
|
syslog.syslog("sign_dkim: {0}".format(x))
|
||||||
|
raise
|
||||||
|
|
||||||
def check_dkim(self,txt):
|
def check_dkim(self,txt):
|
||||||
res = False
|
res = False
|
||||||
@@ -206,23 +207,23 @@ class dkimMilter(Milter.Base):
|
|||||||
except dkim.DKIMException as x:
|
except dkim.DKIMException as x:
|
||||||
self.dkim_comment = str(x)
|
self.dkim_comment = str(x)
|
||||||
if milterconfig.get('Syslog'):
|
if milterconfig.get('Syslog'):
|
||||||
syslog.syslog('DKIM: %s'%x)
|
syslog.syslog('DKIM: {0}'.format(x))
|
||||||
except Exception as x:
|
except Exception as x:
|
||||||
self.dkim_comment = str(x)
|
self.dkim_comment = str(x)
|
||||||
if milterconfig.get('Syslog'):
|
if milterconfig.get('Syslog'):
|
||||||
syslog.syslog("check_dkim: %s",x,exc_info=True)
|
syslog.syslog("check_dkim: {0}".format(x))
|
||||||
self.header_i = d.signature_fields.get(b'i')
|
self.header_i = d.signature_fields.get(b'i')
|
||||||
self.header_d = d.signature_fields.get(b'd')
|
self.header_d = d.signature_fields.get(b'd')
|
||||||
if res:
|
if res:
|
||||||
if milterconfig.get('Syslog'):
|
if milterconfig.get('Syslog'):
|
||||||
syslog.syslog('DKIM: Pass (%s)'%d.domain)
|
syslog.syslog('DKIM: Pass ({0})'.format(d.domain))
|
||||||
self.dkim_domain = d.domain
|
self.dkim_domain = d.domain
|
||||||
else:
|
else:
|
||||||
fd,fname = tempfile.mkstemp(".dkim")
|
fd,fname = tempfile.mkstemp(".dkim")
|
||||||
with os.fdopen(fd,"w+b") as fp:
|
with os.fdopen(fd,"w+b") as fp:
|
||||||
fp.write(txt)
|
fp.write(txt)
|
||||||
if milterconfig.get('Syslog'):
|
if milterconfig.get('Syslog'):
|
||||||
syslog.syslog('DKIM: Fail (saved as %s)'%fname)
|
syslog.syslog('DKIM: Fail (saved as {0})'.format(fname))
|
||||||
if res:
|
if res:
|
||||||
result = 'pass'
|
result = 'pass'
|
||||||
else:
|
else:
|
||||||
@@ -235,6 +236,10 @@ class dkimMilter(Milter.Base):
|
|||||||
return
|
return
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
# Ugh, but there's no easy way around this.
|
||||||
|
global milterconfig
|
||||||
|
global privateRSA
|
||||||
|
global privateEd25519
|
||||||
privateRSA = False
|
privateRSA = False
|
||||||
privateEd25519 = False
|
privateEd25519 = False
|
||||||
configFile = '/etc/dkimpy-milter.conf'
|
configFile = '/etc/dkimpy-milter.conf'
|
||||||
@@ -255,7 +260,7 @@ def main():
|
|||||||
drop_privileges(milterconfig)
|
drop_privileges(milterconfig)
|
||||||
if milterconfig.get('Syslog'):
|
if milterconfig.get('Syslog'):
|
||||||
syslog.syslog('dkimpy-milter started. user: {0}'.format(milterconfig.get('UserID')))
|
syslog.syslog('dkimpy-milter started. user: {0}'.format(milterconfig.get('UserID')))
|
||||||
Milter.factory = dkimMilter(milterconfig, privatersa=privateRSA, privateed25519=privateEd25519)
|
Milter.factory = dkimMilter
|
||||||
Milter.set_flags(Milter.CHGHDRS + Milter.ADDHDRS)
|
Milter.set_flags(Milter.CHGHDRS + Milter.ADDHDRS)
|
||||||
miltername = 'dkimpy-filter'
|
miltername = 'dkimpy-filter'
|
||||||
socketname = milterconfig.get('Socket')
|
socketname = milterconfig.get('Socket')
|
||||||
|
|||||||
@@ -107,9 +107,11 @@ def _readConfigFile(path, configData = None, configGlobal = {}):
|
|||||||
'UserID' : 'str',
|
'UserID' : 'str',
|
||||||
'Domain' : 'str',
|
'Domain' : 'str',
|
||||||
'KeyFile' : 'str',
|
'KeyFile' : 'str',
|
||||||
'KeyFileEd25119' : 'str',
|
'KeyFileEd25519' : 'str',
|
||||||
'Selector' : 'str',
|
'Selector' : 'str',
|
||||||
'Canonicalization' : 'str'
|
'SelectorEd25519': 'str',
|
||||||
|
'Canonicalization' : 'str',
|
||||||
|
'CanonicalizationEd25519' : 'str'
|
||||||
}
|
}
|
||||||
|
|
||||||
# check to see if it's a file
|
# check to see if it's a file
|
||||||
|
|||||||
@@ -103,10 +103,13 @@ def read_keyfile(milterconfig, keytype):
|
|||||||
keyfile = milterconfig.get('KeyFileEd25519')
|
keyfile = milterconfig.get('KeyFileEd25519')
|
||||||
try:
|
try:
|
||||||
f = open(keyfile, 'r')
|
f = open(keyfile, 'r')
|
||||||
key = f.readlines
|
keylist = f.readlines()
|
||||||
except IOError as e:
|
except IOError as e:
|
||||||
if milterconfig.get('Syslog'):
|
if milterconfig.get('Syslog'):
|
||||||
syslog.syslog('Unable to read keyfile {0}. IOError: {1}'.format(keyfile, e))
|
syslog.syslog('Unable to read keyfile {0}. IOError: {1}'.format(keyfile, e))
|
||||||
raise
|
raise
|
||||||
f.close()
|
f.close()
|
||||||
|
key = ''
|
||||||
|
for line in keylist:
|
||||||
|
key += line
|
||||||
return key
|
return key
|
||||||
|
|||||||
@@ -133,7 +133,7 @@
|
|||||||
dkimpy-milter \- Python milter for DKIM signing and validation
|
dkimpy-milter \- Python milter for DKIM signing and validation
|
||||||
.SH "VERSION"
|
.SH "VERSION"
|
||||||
.IX Header "VERSION"
|
.IX Header "VERSION"
|
||||||
0\.
|
0\.9\.1
|
||||||
|
|
||||||
.SH "DESCRIPTION"
|
.SH "DESCRIPTION"
|
||||||
.IX Header "DESCRIPTION"
|
.IX Header "DESCRIPTION"
|
||||||
|
|||||||
Reference in New Issue
Block a user