commit 81074c20f3dcc19e24b211c8f736afe87972a657 Author: David Fifield david@bamsoftware.com Date: Tue Sep 11 10:50:10 2012 -0700
Verify TLS certificate, and trust only Google's CA. --- flashproxy-reg-email | 52 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 files changed, 50 insertions(+), 2 deletions(-)
diff --git a/flashproxy-reg-email b/flashproxy-reg-email index 7dc1d84..f57bc58 100755 --- a/flashproxy-reg-email +++ b/flashproxy-reg-email @@ -5,7 +5,9 @@ import os import re import smtplib import socket +import ssl import sys +import tempfile
DEFAULT_REMOTE_ADDRESS = "" DEFAULT_REMOTE_PORT = 9000 @@ -18,6 +20,35 @@ DEFAULT_SMTP_PORT = 25 EHLO_FQDN = "[127.0.0.1]" FROM_EMAIL_ADDRESS = "nobody@localhost"
+# We trust no other CA certificate than this. +# +# To find the certificate to copy here, +# $ strace openssl s_client -connect gmail-smtp-in.l.google.com:25 -starttls smtp -verify 10 -CApath /etc/ssl/certs 2>&1 | grep /etc/ssl/certs +# stat("/etc/ssl/certs/XXXXXXXX.0", {st_mode=S_IFREG|0644, st_size=YYYY, ...}) = 0 +CA_CERTS = """\ +subject=/C=US/O=Equifax/OU=Equifax Secure Certificate Authority +issuer=/C=US/O=Equifax/OU=Equifax Secure Certificate Authority +-----BEGIN CERTIFICATE----- +MIIDIDCCAomgAwIBAgIENd70zzANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJV +UzEQMA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2Vy +dGlmaWNhdGUgQXV0aG9yaXR5MB4XDTk4MDgyMjE2NDE1MVoXDTE4MDgyMjE2NDE1 +MVowTjELMAkGA1UEBhMCVVMxEDAOBgNVBAoTB0VxdWlmYXgxLTArBgNVBAsTJEVx +dWlmYXggU2VjdXJlIENlcnRpZmljYXRlIEF1dGhvcml0eTCBnzANBgkqhkiG9w0B +AQEFAAOBjQAwgYkCgYEAwV2xWGcIYu6gmi0fCG2RFGiYCh7+2gRvE4RiIcPRfM6f +BeC4AfBONOziipUEZKzxa1NfBbPLZ4C/QgKO/t0BCezhABRP/PvwDN1Dulsr4R+A +cJkVV5MW8Q+XarfCaCMczE1ZMKxRHjuvK9buY0V7xdlfUNLjUA86iOe/FP3gx7kC +AwEAAaOCAQkwggEFMHAGA1UdHwRpMGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEQ +MA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2VydGlm +aWNhdGUgQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMBoGA1UdEAQTMBGBDzIwMTgw +ODIyMTY0MTUxWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUSOZo+SvSspXXR9gj +IBBPM5iQn9QwHQYDVR0OBBYEFEjmaPkr0rKV10fYIyAQTzOYkJ/UMAwGA1UdEwQF +MAMBAf8wGgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUA +A4GBAFjOKer89961zgK5F7WF0bnj4JXMJTENAKaSbn+2kmOeUJXRmm/kEd5jhW6Y +7qj/WsjTVbJmcVfewCHrPSqnI0kBBIZCe/zuf6IWUrVnZ9NA2zsmWLIodz2uFHdh +1voqZiegDfqnc1zqcPGUIWVEX/r87yloqaKHee9570+sB3c4 +-----END CERTIFICATE----- +""" + class options(object): remote_addr = None email_addr = None @@ -127,8 +158,25 @@ if options.debug: smtp.set_debuglevel(1)
try: - smtp.starttls() - smtp.ehlo() + ca_certs_file = tempfile.NamedTemporaryFile(prefix="flashproxy-reg-email-", suffix=".crt", delete=True) + try: + ca_certs_file.write(CA_CERTS) + ca_certs_file.flush() + # We roll our own initial EHLO/STARTTLS because smtplib.SMTP.starttls + # doesn't allow enough certificate validation. + code, msg = smtp.docmd("EHLO", EHLO_FQDN) + if code != 250: + raise ValueError("Got code %d after EHLO" % code) + code, msg = smtp.docmd("STARTTLS") + if code != 220: + raise ValueError("Got code %d after STARTTLS" % code) + smtp.sock = ssl.wrap_socket(smtp.sock, cert_reqs=ssl.CERT_REQUIRED, + ca_certs=ca_certs_file.name) + smtp.file = smtp.sock.makefile() + finally: + ca_certs_file.close() + + smtp.ehlo(EHLO_FQDN)
if not options.remote_addr[0]: # Grep the EHLO response for our public IP address.