[Python-Dev] Verification of SSL cert and hostname made easy (original) (raw)
Guido van Rossum guido at python.org
Sat Nov 30 23:16:05 CET 2013
- Previous message: [Python-Dev] Verification of SSL cert and hostname made easy
- Next message: [Python-Dev] Verification of SSL cert and hostname made easy
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
Sounds good.
Is another change for asyncio needed?
On Sat, Nov 30, 2013 at 1:54 PM, Nick Coghlan <ncoghlan at gmail.com> wrote:
On 1 Dec 2013 04:32, "Christian Heimes" <christian at python.org> wrote: > > Hi, > > Larry has granted me a special pardon to add an outstanding fix for SSL, > http://bugs.python.org/issue19509 . Right now most stdlib modules > (ftplib, imaplib, nntplib, poplib, smtplib) neither support server name > indication (SNI) nor check the subject name of the peer's certificate > properly. The second issue is a major loop-hole because it allows > man-in-the-middle attack despite CERTREQUIRED. > > With CERTREQUIRED OpenSSL verifies that the peer's certificate is > directly or indirectly signed by a trusted root certification authority. > With Python 3.4 the ssl module is able to use/load the system's trusted > root certs on all major systems (Linux, Mac, BSD, Windows). On Linux and > BSD it requires a properly configured system openssl to locate the root > certs. This usually works out of the box. On Mac Apple's openssl build > is able to use the keychain API of OSX. I have added code for Windows' > system store. > > SSL socket code usually looks like this: > > context = ssl.SSLContext(ssl.PROTOCOLTLSv1) > context.verifymode = ssl.CERTREQUIRED > # new, by default it loads certs trusted for Purpose.SERVERAUTH > context.loaddefaultcerts() > > sock = socket.createconnection(("example.net", 443)) > sslsock = context.wrapsocket(sock) > > SSLContext.wrapsocket() wraps an ordinary socket into a SSLSocket. With > verifymode = CERTREQUIRED OpenSSL ensures that the peer's SSL > certificate is signed by a trusted root CA. In this example one very > important step is missing. The peer may return ANY signed certificate > for ANY hostname. These lines do NOT check that the certificate's > information match "example.net". An attacker can use any arbitrary > certificate (e.g. for "www.evil.net"), get it signed and abuse it for > MitM attacks on "mail.python.org". > http://docs.python.org/3/library/ssl.html#ssl.matchhostname must be > used to verify the cert. It's easy to forget it... > > > I have thought about multiple ways to fix the issue. At first I added a > new argument "checkhostname" to all affected modules and implemented > the check manually. For every module I had to modify several places for > SSL and STARTTLS and add / change about 10 lines. The extra lines are > required to properly shutdown and close the connection when the cert > doesn't match the hostname. I don't like the solution because it's > tedious. Every 3rd party author has to copy the same code, too. > > Then I came up with a better solution: > > context = ssl.SSLContext(ssl.PROTOCOLTLSv1) > context.verifymode = ssl.CERTREQUIRED > context.loaddefaultcerts() > context.checkhostname = True # <-- NEW_ _> > sock = socket.createconnection(("example.net", 443)) > # serverhostname is already used for SNI > sslsock = context.wrapsocket(sock, serverhostname="example.net") > > > This fix requires only a new SSLContext attribute and a small > modification to SSLSocket.dohandshake(): > > if self.context.checkhostname: > try: > matchhostname(self.getpeercert(), self.serverhostname) > except Exception: > self.shutdown(SHUTRDWR) > self.close() > raise > > > Pros: > > * matchhostname() is done in one central place > * the cert is matched as early as possible > * no extra arguments for APIs, a context object is enough > * library developers just have to add serverhostname to get SNI and > hostname checks at the same time > * users of libraries can configure cert verification and checking on the > same object > * missing checks will not pass silently > > Cons: > > * Doesn't work with OpenSSL < 0.9.8f (released 2007) because older_ _> versions lack SNI support. The ssl module raises an exception for > serverhostname if SNI is not supported. > > > The default settings for all stdlib modules will still be verifymode = > CERTNONE and checkhostname = False for maximum backward compatibility. > Python 3.4 comes with a new function ssl.createdefaultcontext() that > returns a new context with best practice settings and loaded root CA > certs. The settings are TLS 1.0, no weak and insecure ciphers (no MD5, > no RC4), no compression (CRIME attack), CERTREQUIRED and checkhostname > = True (for client side only). > > http://bugs.python.org/issue19509 has a working patch for ftplib. > > Comments? If Larry is OK with it as RM (and it sounds like he is), +1 from me as well.
-- --Guido van Rossum (python.org/~guido) -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://mail.python.org/pipermail/python-dev/attachments/20131130/1879d6cc/attachment.html>
- Previous message: [Python-Dev] Verification of SSL cert and hostname made easy
- Next message: [Python-Dev] Verification of SSL cert and hostname made easy
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]