Why sign your email directly on the MTA (here we will talk about Postfix MTA) ? I don’t find a simple webmail client for my email server that include a S/MIME and/or PGP functionality to sign/encrypt outgoing messages.
So I found and change a little bit a script that get the outgoing message on the MTA and sign them with OpenSSL. The steps are:
– A running Postfix server
– Create the user account that will run the signing script and lock the account to prevent logging in:
useradd -M pfsigner
usermod -L pfsigner
– Create the folder /var/spool/signing. This folder will be used to store temporary message header and content
– chmod 700 /var/spool/signing
– chown pfsigner:pfsigner /var/spool/signing
– Edit your /etc/postfix/master.cf . We will add a new TCP port for the smtpd. This port will be used on your mail/webmail client SMTP configuration. Add these lines:
2525 inet n - - - - smtpd -o content_filter=sign:dummy sign unix - n n - 10 pipe flags=Rq user=pfsigner null_sender= argv=/usr/local/bin/sign.sh -f ${sender} -- ${recipient}
– request your certificate using the procedure here and export the certificate+private key to a pfx file
– convert your pfx file to pem (use your email name in the pem filename as shown below). If your email is youremail@yourdomain.com, use the following command:
openssl pkcs12 -in yourcert.pfx -out youremail@yourdomain.com.pem -nodes
– create the folder certs
mkdir -p /usr/local/src/smtp-signer/certs
– copy the certificate to the certs folder created above
– create the script file /usr/local/bin/sign.sh :
#!/bin/sh # SMTP Signer - POSIX Shell Implementation (using sed) USERNAME="pfsigner" SIGN_DIR="/var/spool/sign" CERT_DIR="/usr/local/src/smtp-signer/certs" SENDMAIL="/usr/sbin/sendmail -G -i" OPENSSL="/usr/bin/openssl" CERT_FILE="${CERT_DIR}/$2.pem" E_TEMPFAIL=75 cd ${SIGN_DIR} || { printf "${SIGN_DIR} does not exist" exit ${E_TEMPFAIL} } # TRAP DEFINITION # Number SIG Meaning # 0 0 On exit from shell # 1 SIGHUP Clean tidyup # 2 SIGINT Interrupt # 3 SIGQUIT Quit # 6 SIGABRT Abort # 9 SIGKILL Die Now (cannot be trap'ped) # 14 SIGALRM Alarm Clock # 15 SIGTERM Terminate trap "rm -f in.$$ body.$$ body2.$$ header1.$$ header2.$$ header.$$ signed.$$" 0 1 2 3 15 # Get the outgoing message : header and body cat >in.$$ # get the header and store it in the file header.$$ sed '/^$/q' <in.$$ >header1.$$ sed '$d' <header1.$$ >header.$$ # find the line that begin with Content-type in the header text CONTENT_TYPE=`sed -n '/Content-Type:/p' <header1.$$` printf "\n" >body.$$ sed '1,/^$/ d' <in.$$ >>body.$$ # You can uncomment the following both lines if you want to troubleshoot and see the content of the header and message body in the log file user.log # logger -f header.$$ # logger -f body.$$ # If a certificate exist and the email is not already signed, sign it with openssl if [[ -f "${CERT_FILE}" ]] && [[ $CONTENT_TYPE != *"signed"* ]]; then # Sign mail and relay MSG="Signed mail from $2" CONTENT_TYPE_BODY=`sed -n '/Content-Type/,+1p' header.$$` printf "${CONTENT_TYPE_BODY}\n" > body2.$$ cat body.$$ >>body2.$$ sed '/Content-Type/,+1 d' <header.$$ >header2.$$ # Sign the message body with OpenSSL ${OPENSSL} smime -sign -signer ${CERT_FILE} -in body2.$$ -out signed.$$ sed '/Content-Type/,+1 d' <header.$$ >header2.$$ # Concaetnante header and the signed message and send it using sendmail tool cat header2.$$ signed.$$ | ${SENDMAIL} "$@" else # Relay without signing MSG="Unsigned mail from $2 because message already signed" cat in.$$ | ${SENDMAIL} "$@" fi STATUS=$? if [ "${STATUS}" -eq 0 ]; then LOG_LEVEL="notice" else LOG_LEVEL="err" fi logger -p "mail.${LOG_LEVEL}" -t "sign.sh" "${MSG}" exit ${STATUS}
You can now configure your favorite email client and do not forget to specify port TCP 2525 for the SMTP settings to send your signed emails.
My Powershell script categories
- Active Directory
- Cluster
- Database
- Exchange
- Files and folders
- Hardware
- Network
- Operating System
- PKI
- SCCM
- Service and process
- Tips
- VMWare
Thanks for the excellent script.
Only bug I found: when you add a .JPG to the email (attached file), the signed message doesn’t validate anymore . For example, Outlook 2007 complains about “corrupted message”, or something like this.
regards, JS
Thank you for your comment. I will try to solve this issue. I will keep you informed.
Nico
I have tested successfully that case :
– I send message from webmail client (Rainloop) configured on my custom postfix. Image attached
– I receive successfully the message + attachment on outlook (version 2016 for me)
Probably a problem with the method you have chosen to send your message with attachment…
Hi Nicolas
(en fait, tu parles francais ? )
Merci d’avoir pris du temps pour ce problème. L’envoi des messages avec fichiers attachés fonctionne correctement, et je reçois aussi le message ainsi que le fichier joint, mais il y a un problème au niveau de la signature. Outlook 2007 m’indique que le message a été altéré, et donc le chiffrement ne correspond pas.
J’utilise ton script sur mon postfix personnel, webmail roundcube. La méthode d’attachement du fichier est standard.
Peut-etre que Outlook 2007 est bugué au niveau de la vérification de la signature, et que le bug a été résolu sous 2016 ? Ca me semble très improbable, car d’autres messages signés avec attachement sont correctement validés.
Il n’y a pas de probleme avec l’en-tete ? Je peux t’envoyer les fichiers temporaires (body, header, header1… ) qui sont créés, si besoin
Merci, Julien
Thanks for the excellent script.
Only bug I found: when you add a .JPG to the email (attached file), the signed message doesn’t validate anymore . For example, Outlook 2007 complains about “corrupted message”, or something like this.
regards, JS
Thank you for your comment. I will try to solve this issue. I will keep you informed.
Nico
I have tested successfully that case :
– I send message from webmail client (Rainloop) configured on my custom postfix. Image attached
– I receive successfully the message + attachment on outlook (version 2016 for me)
Probably a problem with the method you have chosen to send your message with attachment…
Hi Nicolas
(en fait, tu parles francais ? )
Merci d’avoir pris du temps pour ce problème. L’envoi des messages avec fichiers attachés fonctionne correctement, et je reçois aussi le message ainsi que le fichier joint, mais il y a un problème au niveau de la signature. Outlook 2007 m’indique que le message a été altéré, et donc le chiffrement ne correspond pas.
J’utilise ton script sur mon postfix personnel, webmail roundcube. La méthode d’attachement du fichier est standard.
Peut-etre que Outlook 2007 est bugué au niveau de la vérification de la signature, et que le bug a été résolu sous 2016 ? Ca me semble très improbable, car d’autres messages signés avec attachement sont correctement validés.
Il n’y a pas de probleme avec l’en-tete ? Je peux t’envoyer les fichiers temporaires (body, header, header1… ) qui sont créés, si besoin
Merci, Julien
Hi,
I can confirm that your script is working correctly with rainloop, but it’s not the case with roundcube.
Regards, Julien
Hello Julien,
Oui je parle bien francais 🙂 Thank you for your feedback… I don’t have a lot of time to test the script with Roundcube… but I will keep you informed when it will be done !
Nico
Hi,
I can confirm that your script is working correctly with rainloop, but it’s not the case with roundcube.
Regards, Julien
1) Your sign.sh has wrong SIGN_DIR? Is it /var/spool/signing?
2). Maybe private key and certificate should not combine together and with different file permissions:
PRIV_KEY_FILE=”${CERT_DIR}/$2-private-nopass.pem”
then
${OPENSSL} smime -sign -signer ${CERT_FILE} -inkey ${PRIV_KEY_FILE} -in body2.$$ -out signed.$$
1) Your sign.sh has wrong SIGN_DIR? Is it /var/spool/signing?
2). Maybe private key and certificate should not combine together and with different file permissions:
PRIV_KEY_FILE=”${CERT_DIR}/$2-private-nopass.pem”
then
${OPENSSL} smime -sign -signer ${CERT_FILE} -inkey ${PRIV_KEY_FILE} -in body2.$$ -out signed.$$