Changes to cron, register-handler, settings and templates:

- Cron now notifies user what happened (key successfully added/deleted or error)
- More options to customize templates
- Separating concepts in settings (S/MIME, templates)
- Register-handler now only informs on failed PGP submissions (reduce mails to user and false positive mails)
This commit is contained in:
fkrone 2015-01-31 16:08:12 +01:00
parent f5976060c8
commit f7e3b16069
10 changed files with 70 additions and 38 deletions

View File

@ -1,5 +1,7 @@
# gpg-mailgate # gpg-mailgate
**Please note: This fork is currently WIP. It is not recommended for use at the moment.**
gpg-mailgate is a content filter for Postfix that automatically encrypts unencrypted incoming email using PGP or S/MIME for select recipients. gpg-mailgate is a content filter for Postfix that automatically encrypts unencrypted incoming email using PGP or S/MIME for select recipients.
For installation instructions, please refer to the included INSTALL file. For installation instructions, please refer to the included INSTALL file.
@ -18,7 +20,7 @@ This is forked from the original project at http://code.google.com/p/gpg-mailgat
# Authors # Authors
This is a combined work of many developers and contributor:s This is a combined work of many developers and contributors:
* mcmaster <mcmaster@aphrodite.hurricanelabs.rsoc> * mcmaster <mcmaster@aphrodite.hurricanelabs.rsoc>
* Igor Rzegocki <ajgon@irgon.com> - [GitHub](https://github.com/ajgon/gpg-mailgate) * Igor Rzegocki <ajgon@irgon.com> - [GitHub](https://github.com/ajgon/gpg-mailgate)
@ -37,5 +39,6 @@ This is a combined work of many developers and contributor:s
* clean up code * clean up code
* rewrite templates for register-handler * rewrite templates for register-handler
* rewrite and improve installation instructions * rewrite and improve installation instructions
* rewrite readme of gpg-mailgate-web in markdown
* rename from gpg-mailgate to openpgp-s-mime-mailgate or something..... * rename from gpg-mailgate to openpgp-s-mime-mailgate or something.....
* even more magical stuff * even more magical stuff

View File

@ -0,0 +1 @@
Your PGP key has been deleted from our gateway. From now on you will receive mails from us unencrypted.

View File

@ -0,0 +1,3 @@
Your PGP key could not be validated. Please try again with a valid key.
Any valid keys from you submitted to the gateway before are now deleted.

View File

@ -0,0 +1 @@
Your PGP key has been imported successfully. Don't be worried if this mail is not encrypted. The following mails will be encrypted.

View File

@ -23,7 +23,9 @@ from ConfigParser import RawConfigParser
import GnuPG import GnuPG
import MySQLdb import MySQLdb
import smtplib import smtplib
import markdown
from email.MIMEText import MIMEText from email.MIMEText import MIMEText
from email.mime.multipart import MIMEMultipart
def appendLog(msg): def appendLog(msg):
if cfg.has_key('logging') and cfg['logging'].has_key('file'): if cfg.has_key('logging') and cfg['logging'].has_key('file'):
@ -31,15 +33,20 @@ def appendLog(msg):
log.write(msg + "\n") log.write(msg + "\n")
log.close() log.close()
def send_msg( mailsubject, mailbody, recipients = None ): def send_msg( mailsubject, messagefile, recipients = None ):
msg = MIMEText(mailbody) mailbody = file( cfg['cron']['mail_templates'] + "/" + messagefile).read()
msg["From"] = cfg['smime']['register_email'] msg = MIMEMultipart("alternative")
msg["From"] = cfg['cron']['notification_email']
msg["To"] = recipients msg["To"] = recipients
msg["Subject"] = mailsubject msg["Subject"] = mailsubject
msg.attach(MIMEText(mailbody, 'plain'))
msg.attach(MIMEText(markdown.markdown(mailbody), 'html'))
relay = ("127.0.0.1", 10028) relay = ("127.0.0.1", 10028)
smtp = smtplib.SMTP(relay[0], relay[1]) smtp = smtplib.SMTP(relay[0], relay[1])
smtp.sendmail( cfg['smime']['register_email'], recipients, msg.as_string() ) smtp.sendmail( cfg['cron']['notification_email'], recipients, msg.as_string() )
# Read configuration from /etc/gpg-mailgate.conf # Read configuration from /etc/gpg-mailgate.conf
_cfg = RawConfigParser() _cfg = RawConfigParser()
@ -69,15 +76,18 @@ if cfg.has_key('database') and cfg['database'].has_key('enabled') and cfg['datab
GnuPG.add_key(cfg['gpg']['keyhome'], row[0]) # import the key to gpg GnuPG.add_key(cfg['gpg']['keyhome'], row[0]) # import the key to gpg
cursor.execute("UPDATE gpgmw_keys SET status = 1 WHERE id = %s", (row[1],)) # mark key as accepted cursor.execute("UPDATE gpgmw_keys SET status = 1 WHERE id = %s", (row[1],)) # mark key as accepted
appendLog('Imported key from <' + row[2] + '>') appendLog('Imported key from <' + row[2] + '>')
send_msg( "PGP key registration successful", "Your PGP key has been imported successfully. Don't be worried if this mail is not encrypted. The following mails will be encrypted.", row[2] ) if cfg['cron'].has_key('send_email') and cfg['cron']['send_email'] == 'yes':
send_msg( "PGP key registration successful", "registrationSuccess.md", row[2] )
else: else:
cursor.execute("DELETE FROM gpgmw_keys WHERE id = %s", (row[1],)) # delete key cursor.execute("DELETE FROM gpgmw_keys WHERE id = %s", (row[1],)) # delete key
appendLog('Import confirmation failed for <' + row[2] + '>') appendLog('Import confirmation failed for <' + row[2] + '>')
send_msg( "PGP key registration failed", "Your PGP key could not be validated. Please try again with a valid key.", row[2] ) if cfg['cron'].has_key('send_email') and cfg['cron']['send_email'] == 'yes':
send_msg( "PGP key registration failed", "registrationError.md", row[2] )
else: else:
# delete key so we don't continue processing it # delete key so we don't continue processing it
cursor.execute("DELETE FROM gpgmw_keys WHERE id = %s", (row[1],)) cursor.execute("DELETE FROM gpgmw_keys WHERE id = %s", (row[1],))
send_msg( "PGP key deleted", "Your PGP key has been deleted from our gateway. From now on you will receive mails from us unencrypted.", row[2]) if cfg['cron'].has_key('send_email') and cfg['cron']['send_email'] == 'yes':
send_msg( "PGP key deleted", "keyDeleted.md", row[2])
connection.commit() connection.commit()

View File

@ -16,8 +16,19 @@ keyhome = /var/gpg/.gnupg
[smime] [smime]
# the directory for the S/MIME certificate files # the directory for the S/MIME certificate files
cert_path = /var/smime/certs cert_path = /var/smime/certs
[mailregister]
# settings for the register-handler
register_email = register@yourdomain.tld register_email = register@yourdomain.tld
mail_templates = /var/smime/templates mail_templates = /var/gpgmailgate/register_templates
# URL to webpanel. The server should be able to reach it
webpanel_url = http://yourdomain.tld
[cron]
# settings for the gpgmw cron job
send_email = yes
notification_email = gpg-mailgate@yourdomain.tld
mail_templates = /var/gpgmailgate/cron_templates
[logging] [logging]
# For logging to syslog. 'file = syslog', otherwise use path to the file. # For logging to syslog. 'file = syslog', otherwise use path to the file.

View File

@ -45,10 +45,11 @@ if __name__ == "__main__":
sign_type = 'smime' sign_type = 'smime'
sign_part = msg_part sign_part = msg_part
break break
elif msg_part.get_content_type().lower() == "application/pgp-keys": # This may cause that a non ASCII-armored key will be seen as valid. Other solution is not that efficient though
sign_type = 'pgp' #elif msg_part.get_content_type().lower() == "application/pgp-keys":
sign_part = msg_part.get_payload() # sign_type = 'pgp'
break # sign_part = msg_part.get_payload()
# break
elif "-----BEGIN PGP PUBLIC KEY BLOCK-----" in msg_part.get_payload() and "-----END PGP PUBLIC KEY BLOCK-----" in msg_part.get_payload(): elif "-----BEGIN PGP PUBLIC KEY BLOCK-----" in msg_part.get_payload() and "-----END PGP PUBLIC KEY BLOCK-----" in msg_part.get_payload():
msg_content = msg_part.get_payload() msg_content = msg_part.get_payload()
start = msg_content.find("-----BEGIN PGP PUBLIC KEY BLOCK-----") start = msg_content.find("-----BEGIN PGP PUBLIC KEY BLOCK-----")
@ -60,16 +61,16 @@ if __name__ == "__main__":
if sign_part == None: if sign_part == None:
log("Unable to find PKCS7 signature or public PGP key in registration email") log("Unable to find PKCS7 signature or public PGP key in registration email")
failure_msg = file( cfg['smime']['mail_templates'] + "/registrationError.md").read() failure_msg = file( cfg['mailregister']['mail_templates'] + "/registrationError.md").read()
msg = MIMEMultipart("alternative") msg = MIMEMultipart("alternative")
msg["From"] = cfg['smime']['register_email'] msg["From"] = cfg['mailregister']['register_email']
msg["To"] = from_addr msg["To"] = from_addr
msg["Subject"] = "S/MIME / OpenPGP registration failed" msg["Subject"] = "S/MIME / OpenPGP registration failed"
msg.attach(MIMEText(failure_msg, 'plain')) msg.attach(MIMEText(failure_msg, 'plain'))
msg.attach(MIMEText(markdown.markdown(failure_msg), 'html')) msg.attach(MIMEText(markdown.markdown(failure_msg), 'html'))
send_msg(msg, cfg['smime']['register_email'], [from_addr]) send_msg(msg, cfg['mailregister']['register_email'], [from_addr])
sys.exit(0) sys.exit(0)
if sign_type == 'smime': if sign_type == 'smime':
@ -94,26 +95,29 @@ if __name__ == "__main__":
signing_cert.save(os.path.join(CERT_PATH, from_addr)) signing_cert.save(os.path.join(CERT_PATH, from_addr))
elif sign_type == 'pgp':
# send POST to localost on port 11371 which points to our HTTP registration page
sig = sign_part
payload = {'email': from_addr, 'key': sig}
r = requests.post("http://127.0.0.1:11371", data=payload)
# format in user-specific data # format in user-specific data
success_msg = file(cfg['smime']['mail_templates']+"/registrationSuccess.md").read() # sending success mail only for S/MIME as GPGMW handles this on its own
success_msg = file(cfg['mailregister']['mail_templates']+"/registrationSuccess.md").read()
success_msg = success_msg.replace("[:FROMADDRESS:]",from_addr) success_msg = success_msg.replace("[:FROMADDRESS:]",from_addr)
msg = MIMEMultipart("alternative") msg = MIMEMultipart("alternative")
msg["From"] = cfg['smime']['register_email'] msg["From"] = cfg['mailregister']['register_email']
msg["To"] = from_addr msg["To"] = from_addr
msg["Subject"] = "S/MIME / OpenPGP key registration succeeded" msg["Subject"] = "S/MIME certificate registration succeeded"
msg.attach(MIMEText(success_msg, 'plain')) msg.attach(MIMEText(success_msg, 'plain'))
msg.attach(MIMEText(markdown.markdown(success_msg), 'html')) msg.attach(MIMEText(markdown.markdown(success_msg), 'html'))
log("Registration succeeded") send_msg(msg, cfg['mailregister']['register_email'], [from_addr])
send_msg(msg, cfg['smime']['register_email'], [from_addr])
log("S/MIME Registration succeeded")
elif sign_type == 'pgp':
# send POST to gpg-mailgate webpanel
sig = sign_part
payload = {'email': from_addr, 'key': sig}
r = requests.post(cfg['mailregister']['webpanel_url'], data=payload)
log("PGP registration is handed over to GPGMW")
# except: # except:
# log("Registration exception") # log("Registration exception")
# sys.exit(0) # sys.exit(0)

View File

@ -0,0 +1,4 @@
Could not register a S/MIME certificate or PGP key.
For S/MIME make sure your message is signed.
For PGP make sure you attach your ASCII-armored public key to the email.

View File

@ -1,3 +1 @@
Registration was a success. A signature was found in your message, and your S/MIME certificate was saved. Registration was a success. A signature was found in your message, and your S/MIME certificate was saved.
Mailencrypt.net keeps no logs of message content or metadata (such as To, From, or IP address).

View File

@ -1,3 +0,0 @@
The mailencrypt registration attempt failed. Most likely, the message was not signed, or a application/pkcs7-signature section could not be found.
Be sure that you're sending your email with signing turned on.