[Python-Dev] Simplify and unify SSL verification

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 key_file, cert_file and check_hostname 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 verify_mode=CERT_NONE. Python 3.5 will default
>    to CERT_REQUIRED.

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

> - enforce hostname matching in CERT_OPTIONAL or CERT_REQUIRED 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.get_default_context() 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 check_cert option to SSLContext and a check_cert() 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 check_cert option will support four values:
>
> None (default)
>    use match_hostname() if verify_mode is CERT_OPTIONAL or
>    CERT_REQUIRED
> True
>    always use match_hostname()
> False
>    never use match_hostname()

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.create_connection((hostname, self.port))
>        sock = self.context.wrap_socket(sock,
>                                        server_hostname=hostname)
>        sock.check_cert(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