[Python-Dev] Simplify and unify SSL verification (original) (raw)

Antoine Pitrou solipsis at pitrou.net
Thu Nov 7 21:45:39 CET 2013


Le 07/11/2013 19:13, Christian Heimes a écrit :

Hi,

I'd like to simplify, unify and tighten SSL handling and verification code in Python 3.5. Therefore I propose to deprecate some features for Python 3.4. SSLContext objects are going to be the central instance for configuration. In order to archive the goal I propose to - deprecate the keyfile, certfile and checkhostname arguments in various in favor of context. Python 3.5 will no longer have these arguments in http.client, smtplib etc.

I'm in favour but I think 3.5 is too early. Keep in mind SSLContext is quite young.

- deprecate implicit verifymode=CERTNONE. Python 3.5 will default to CERTREQUIRED.

-0.9. This breaks compatibility and doesn't achieve anything, since there's no reliable story for CA certs.

- enforce hostname matching in CERTOPTIONAL or CERTREQUIRED mode by default in Python 3.5.

Service matching is an application protocol level thing, it isn't strictly part of SSL. I'd feel warmer if you removed the "by default" part.

- add ssl.getdefaultcontext() to acquire a default SSLContext object if the context argument is None. (Python 3.4)

I think I'm against it, for two reasons:

  1. It will in the long term create compatibility and/or security issues (we'll have to keep fragile legacy settings if we want to avoid breaking existing uses of the default context)

  2. SSLContexts are mutable, which means some code can affect other code's behaviour without even knowing. It's a recipe for subtle bugs and security issues.

Applications and/or higher-level libraries should be smart enough to choose their own security preferences, and it's the better place to do so anyway.

- add checkcert option to SSLContext and a checkcert() function to SSLSocket in order to unify certificate validation and hostname matching. (Python 3.4)

The check_cert() function wouldn't achieve anything besides calling match_hostname(), right?

I'm against calling it check_cert(), it's too generic and only induces confusion.

The SSLContext's checkcert option will support four values:

None (default) use matchhostname() if verifymode is CERTOPTIONAL or CERTREQUIRED True always use matchhostname() False never use matchhostname()

What is the hostname that the cert is matched against?

callable function: call func(sslsock, hostname, initiator, **kwargs) The initiator argument is the object that has initiated the SSL connection, e.g. http.client.HTTPSConnection object. sslsock.context points to its SSLContext object

Where does the "hostname" come from?

And why is there an "initiator" object? Personally I prefer to avoid passing opaque user data, since the caller can use a closure anyway. And what are the **kwargs?

A connect method may look like this:

def connect(self): hostname = self.hostname s = socket.createconnection((hostname, self.port)) sock = self.context.wrapsocket(sock, serverhostname=hostname) sock.checkcert(hostname, initiator=self)

So what does this bring compared to the statu quo? I thought at least sock.check_cert() would be called automatically, but if you have to call it yourself it starts looking pointless, IMO.

Regards

Antoine.



More information about the Python-Dev mailing list