added additional/optional S/MIME encryption
This commit is contained in:
parent
73f22775a5
commit
fc4dcb55fe
1 changed files with 69 additions and 4 deletions
|
@ -28,6 +28,13 @@ import GnuPG
|
|||
import smtplib
|
||||
import sys
|
||||
import syslog
|
||||
import traceback
|
||||
import email.utils
|
||||
import os
|
||||
|
||||
# imports for S/MIME
|
||||
from M2Crypto import BIO, Rand, SMIME, X509
|
||||
from email.mime.message import MIMEMessage
|
||||
|
||||
# Read configuration from /etc/gpg-mailgate.conf
|
||||
_cfg = RawConfigParser()
|
||||
|
@ -49,6 +56,10 @@ def log(msg):
|
|||
|
||||
verbose=cfg.has_key('logging') and cfg['logging'].has_key('verbose') and cfg['logging']['verbose'] == 'yes'
|
||||
|
||||
passthrough_emails = file("/etc/postfix/passthrough_emails.cf").read().split()
|
||||
|
||||
CERT_PATH = cfg['smime']['cert_path']+"/"
|
||||
|
||||
# Read e-mail from stdin
|
||||
raw = sys.stdin.read()
|
||||
raw_message = email.message_from_string( raw )
|
||||
|
@ -61,7 +72,7 @@ def send_msg( message, recipients = None ):
|
|||
log("Sending email to: <%s>" % '> <'.join( recipients ))
|
||||
relay = (cfg['relay']['host'], int(cfg['relay']['port']))
|
||||
smtp = smtplib.SMTP(relay[0], relay[1])
|
||||
smtp.sendmail( from_addr, recipients, message.as_string() )
|
||||
smtp.sendmail( from_addr, recipients, message )
|
||||
|
||||
def encrypt_payload( payload, gpg_to_cmdline ):
|
||||
raw_payload = payload.get_payload(decode=True)
|
||||
|
@ -105,6 +116,17 @@ def get_msg( message ):
|
|||
if not message.is_multipart():
|
||||
return message.get_payload()
|
||||
return '\n\n'.join( [str(m) for m in message.get_payload()] )
|
||||
|
||||
def get_cert_for_email(to_addr):
|
||||
simple_path = os.path.join(CERT_PATH, to_addr)
|
||||
if os.path.exists(simple_path): return (simple_path, to_addr)
|
||||
# support foo+ignore@bar.com -> foo@bar.com
|
||||
multi_email = re.match('^([^\+]+)\+([^@]+)@(.*)$', to_addr)
|
||||
if multi_email:
|
||||
fixed_up_email = "%s@%s"%(multi_email.group(1), multi_email.group(3))
|
||||
log("Multi-email %s converted to %s"%(to_addr, fixed_up_email))
|
||||
return get_cert_for_email(fixed_up_email)
|
||||
return None
|
||||
|
||||
keys = GnuPG.public_keys( cfg['gpg']['keyhome'] )
|
||||
gpg_to = list()
|
||||
|
@ -125,11 +147,11 @@ if gpg_to == list():
|
|||
raw_message['X-GPG-Mailgate'] = 'Not encrypted, public key not found'
|
||||
if verbose:
|
||||
log("No encrypted recipients.")
|
||||
send_msg( raw_message )
|
||||
send_msg( raw_message.as_string() )
|
||||
exit()
|
||||
|
||||
if ungpg_to != list():
|
||||
send_msg( raw_message, ungpg_to )
|
||||
send_msg( raw_message.as_string(), ungpg_to )
|
||||
|
||||
log("Encrypting email to: %s" % ' '.join( map(lambda x: x[0], gpg_to) ))
|
||||
|
||||
|
@ -145,4 +167,47 @@ for rcpt in gpg_to:
|
|||
encrypted_payloads = encrypt_all_payloads( raw_message, gpg_to_cmdline )
|
||||
raw_message.set_payload( encrypted_payloads )
|
||||
|
||||
send_msg( raw_message, gpg_to_smtp )
|
||||
did_passthru = False
|
||||
if len(to_addrs) == 1:
|
||||
for pt_email in passthrough_emails:
|
||||
if pt_email.lower() == email.utils.parseaddr(to_addrs[0])[1].lower():
|
||||
did_passthru = True
|
||||
send_msg(raw_message.as_string(), gpg_to_smtp)
|
||||
break
|
||||
|
||||
if not did_passthru:
|
||||
s = SMIME.SMIME()
|
||||
sk = X509.X509_Stack()
|
||||
|
||||
normalized_recipient = []
|
||||
|
||||
for addr in to_addrs:
|
||||
addr_addr = email.utils.parseaddr(addr)[1].lower()
|
||||
cert_and_email = get_cert_for_email(addr_addr)
|
||||
if cert_and_email:
|
||||
(to_cert, normal_email) = cert_and_email
|
||||
log("Found cert "+to_cert+" for "+addr+": "+normal_email)
|
||||
normalized_recipient.append((email.utils.parseaddr(addr)[0], normal_email))
|
||||
x509 = X509.load_cert(to_cert, format=X509.FORMAT_PEM)
|
||||
sk.push(x509)
|
||||
|
||||
if len(normalized_recipient):
|
||||
s.set_x509_stack(sk)
|
||||
s.set_cipher(SMIME.Cipher('aes_192_cbc'))
|
||||
p7 = s.encrypt( BIO.MemoryBuffer(raw_message.as_string()) )
|
||||
|
||||
# Output p7 in mail-friendly format.
|
||||
out = BIO.MemoryBuffer()
|
||||
out.write('From: '+from_addr+'\n')
|
||||
to_list = ",".join([email.utils.formataddr(x) for x in normalized_recipient])
|
||||
out.write('To: '+to_list+'\n')
|
||||
if raw_message['Subject']:
|
||||
out.write('Subject: '+raw_message['Subject']+'\n')
|
||||
s.write(out, p7)
|
||||
|
||||
log("Sending message from "+from_addr+" to "+str(to_addrs))
|
||||
raw_msg = out.read()
|
||||
send_msg(raw_msg, gpg_to_smtp)
|
||||
else:
|
||||
log("Unable to find valid S/MIME recipient")
|
||||
send_msg( raw_message.as_string(), gpg_to_smtp )
|
||||
|
|
Loading…
Reference in a new issue