RFC: fully secure SMTP connection for "hg email"

FUJIWARA Katsunori foozy at lares.dti.ne.jp
Tue Mar 19 01:41:47 CDT 2013


At Sun, 17 Mar 2013 13:55:13 -0500,
Kevin Bullock wrote:
> 
> On 17 Mar 2013, at 11:42 AM, FUJIWARA Katsunori wrote:
> 
> > Hi, devels
> > 
> > We can use secure connection to SMTP server by setting "[smtp] tls" to
> > starttls or smtps for "hg email".
> > 
> > But, AFAIK, the certificate of SMTP server isn't verified as same as
> > verification for HTTPS connection at push/pull operations. This may
> > cause man-in-the-middle security problem.
> > 
> > To connect to SMTP server safely via (maybe untrustable) networks, the
> > certificate of it should be verified: e.g. mail transmission via GMail
> > account.
> > 
> > So, I tried to verify the certificate of SMTP server before
> > authentication/transmission step of SMTP, but it seems to be difficult
> > to do so as same as verification for HTTPS connection, because:
> > 
> >  - in smtplib, "ssl.wrap_socket()" is invoked for STARTTLS/SMTPS
> >    without explicit "cert_reqs" argument, so default value
> >    "CERT_NONE" is used for it:
> > 
> >      http://hg.python.org/cpython/file/59292f366b53/Lib/smtplib.py#l635
> >      http://hg.python.org/cpython/file/59292f366b53/Lib/smtplib.py#l874
> 
> It seems like we should be able to do the certificate verification
> when we set up the SMTP connection
> <http://selenic.com/hg/file/tip/mercurial/mail.py#l33>. For the
> SMTPS case, we can pass the certfile parameter to
> smtplib.SMTP_SSL(), and for the STARTTLS case, we can pass it in
> when we call s.starttls().

As far as I tried, "certfile" parameter to "smtplib.SMTP_SSL()" or
"SMTP.starttls()" doesn't work expectedly.

Even when valid cacert file is specified as "certfile" to them,
connection is established with the server using self-signed (= not
valid) certificate.

According to comment of "SMTP.starttls()", SSL socket created with
CERT_NONE seems not to check the certificate of peer.

        If the server supports TLS, this will encrypt the rest of the SMTP
        session. If you provide the keyfile and certfile parameters,
        the identity of the SMTP server and client can be checked. This,
        however, depends on whether the socket module really checks the
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        certificates.
        ^^^^^^^^^^^^

In addition to it, "certfile" parameter to SSLSocket requires
"keyfile", because "certfile" is also used as keyfile (and causes
error in connection step) if "keyfile" is not specified:

        if certfile and not keyfile:
            keyfile = certfile

    http://hg.python.org/cpython/file/59292f366b53/Lib/ssl.py#l268


> That assumes we have the CA certificate bundle configured à la
> web.cacerts (in fact, we should reuse that setting, or rename it and
> deprecate the old one). I'm not clear on how you're suggesting to
> verify it by fingerprint, without monkey-patching smtplib... could
> you elaborate?

IMHO, for monky-patching smtplib, "SMTP_SSL._get_socket()" and
"SMTP.starttls()" should be fully overridden.

Overriding them for just one Python version seems not to be so
difficult.

But I'm not sure that keeping compatibility of monkey-patched them
against any Python versions is reasonable (and good for policy of
Mercurial code) enough.

I also think that the CA certificate bundle should be used, if
possible. "fingerprint" verification is just listed as one of possible
options.

OK, I'll send the patch with monkey-patching on smtplib for
evaluation.

----------------------------------------------------------------------
[FUJIWARA Katsunori]                             foozy at lares.dti.ne.jp


More information about the Mercurial-devel mailing list