All of lore.kernel.org
 help / color / mirror / Atom feed
From: Simon P <simon.git@le-huit.fr>
To: git@vger.kernel.org
Cc: mhagger@alum.mit.edu, matthieu.moy@grenoble-inp.fr
Subject: [git-multimail] smtplib, check certificate
Date: Thu, 21 Apr 2016 23:44:50 +0200	[thread overview]
Message-ID: <571949D2.10507@le-huit.fr> (raw)

[-- Attachment #1: Type: text/plain, Size: 653 bytes --]

Hi,

It seems that smtplib doesn't check if a certificate is valid (signed by
a trusted CA).

For my personal usage, I patched the starttls code in git-multimail:
only for starttls with smtplib.

This patch is inspired from

https://github.com/graingert/secure-smtplib/blob/master/src/secure_smtplib/__init__.py

It could be easy to add support cert check in for smtps (see
secure_smtplib).

This patch was tested only on git-multimail (v1.2)

It introduces two new options:
  - multimailhook.smtpcheckcert (default false)
  - multimailhook.smtpcacerts (default
                               /etc/ssl/certs/ca-certificates.crt)

Best regards,
Simon P.

[-- Attachment #2: git-multimail-secure-smtplib.patch --]
[-- Type: text/x-patch, Size: 4235 bytes --]

diff --git a/git-multimail/git_multimail.py b/git-multimail/git_multimail.py
index fae5c91..b49ed9d 100755
--- a/git-multimail/git_multimail.py
+++ b/git-multimail/git_multimail.py
@@ -57,6 +57,7 @@ import subprocess
 import shlex
 import optparse
 import smtplib
+import ssl
 import time
 import cgi
 
@@ -1945,6 +1946,7 @@ class SMTPMailer(Mailer):
                  smtpservertimeout=10.0, smtpserverdebuglevel=0,
                  smtpencryption='none',
                  smtpuser='', smtppass='',
+                 smtpcacerts='/etc/ssl/certs/ca-certificates.crt',smtpcheckcert=False
                  ):
         if not envelopesender:
             sys.stderr.write(
@@ -1974,13 +1976,43 @@ class SMTPMailer(Mailer):
             if self.security == 'none':
                 self.smtp = call(smtplib.SMTP, self.smtpserver, timeout=self.smtpservertimeout)
             elif self.security == 'ssl':
+                if smtpcheckcert:
+                    msg = "Checking certificate is not supported for ssl, prefer starttls"
+                    raise smtplib.SMTPException(msg)
                 self.smtp = call(smtplib.SMTP_SSL, self.smtpserver, timeout=self.smtpservertimeout)
             elif self.security == 'tls':
                 if ':' not in self.smtpserver:
                     self.smtpserver += ':587'  # default port for TLS
                 self.smtp = call(smtplib.SMTP, self.smtpserver, timeout=self.smtpservertimeout)
-                self.smtp.ehlo()
-                self.smtp.starttls()
+                if smtpcheckcert:
+                    # inspired form:
+                    #   https://github.com/graingert/secure-smtplib/blob/master/src/secure_smtplib/__init__.py
+                    # but add the path to trusted ca, and force ceritficate verification.
+                    self.smtp.ehlo_or_helo_if_needed()
+                    if not self.smtp.has_extn("starttls"):
+                        msg = "STARTTLS extension not supported by server"
+                        raise smtplib.SMTPException(msg)
+                    (resp, reply) = self.smtp.docmd("STARTTLS")
+                    if resp == 220:
+                        self.smtp.sock = ssl.wrap_socket(
+                            self.smtp.sock,
+                            ca_certs=smtpcacerts,
+                            cert_reqs=ssl.CERT_REQUIRED
+                        )
+                        if not hasattr(self.smtp.sock, "read"):
+                            # using httplib.FakeSocket with Python 2.5.x or earlier
+                            self.smtp.sock.read = self.smtp.sock.recv
+                        self.smtp.file = smtplib.SSLFakeFile(self.smtp.sock)
+                        self.smtp.helo_resp = None
+                        self.smtp.ehlo_resp = None
+                        self.smtp.esmtp_features = {}
+                        self.smtp.does_esmtp = 0
+                    else:
+                        msg = "Wrong answer to the STARTTLS command"
+                        raise smtplib.SMTPException(msg)
+                else:
+                    self.smtp.ehlo()
+                    self.smtp.starttls()
                 self.smtp.ehlo()
             else:
                 sys.stdout.write('*** Error: Control reached an invalid option. ***')
@@ -3500,6 +3532,8 @@ def choose_mailer(config, environment):
         smtpencryption = config.get('smtpencryption', default='none')
         smtpuser = config.get('smtpuser', default='')
         smtppass = config.get('smtppass', default='')
+        smtpcacerts = config.get('smtpcacerts', default='/etc/ssl/certs/ca-certificates.crt')
+        smtpcheckcert = config.get_bool('smtpcheckcert', default='false')
         mailer = SMTPMailer(
             envelopesender=(environment.get_sender() or environment.get_fromaddr()),
             smtpserver=smtpserver, smtpservertimeout=smtpservertimeout,
@@ -3507,6 +3541,8 @@ def choose_mailer(config, environment):
             smtpencryption=smtpencryption,
             smtpuser=smtpuser,
             smtppass=smtppass,
+            smtpcacerts=smtpcacerts,
+            smtpcheckcert=smtpcheckcert
             )
     elif mailer == 'sendmail':
         command = config.get('sendmailcommand')

             reply	other threads:[~2016-04-21 21:53 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-04-21 21:44 Simon P [this message]
2016-04-22  6:05 ` [git-multimail] smtplib, check certificate Matthieu Moy
2016-04-22  6:41   ` Michael Haggerty
2016-04-24 19:14     ` Simon Pontié
2016-04-24 18:20   ` Simon Pontié

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=571949D2.10507@le-huit.fr \
    --to=simon.git@le-huit.fr \
    --cc=git@vger.kernel.org \
    --cc=matthieu.moy@grenoble-inp.fr \
    --cc=mhagger@alum.mit.edu \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.