diff -r 23f8a511050a Doc/library/ssl.rst --- a/Doc/library/ssl.rst Sat Nov 22 14:41:21 2014 -0800 +++ b/Doc/library/ssl.rst Sun Nov 23 15:45:50 2014 -0500 @@ -680,8 +680,7 @@ .. data:: HAS_SNI Whether the OpenSSL library has built-in support for the *Server Name - Indication* extension (as defined in :rfc:`4366`). When true, you can - use the *server_hostname* argument to :meth:`SSLContext.wrap_socket`. + Indication* extension (as defined in :rfc:`4366`). .. versionadded:: 3.2 @@ -1259,11 +1258,12 @@ On client connections, the optional parameter *server_hostname* specifies the hostname of the service which we are connecting to. This allows a single server to host multiple SSL-based services with distinct certificates, - quite similarly to HTTP virtual hosts. Specifying *server_hostname* - will raise a :exc:`ValueError` if the OpenSSL library doesn't have support - for it (that is, if :data:`HAS_SNI` is :const:`False`). Specifying - *server_hostname* will also raise a :exc:`ValueError` if *server_side* - is true. + quite similarly to HTTP virtual hosts. Specifying *server_hostname* will + raise a :exc:`ValueError` if *server_side* is true. + + .. versionchanged:: 3.5 + Always allow a server_hostname to be passed, even if OpenSSL does not + have SNI. .. method:: SSLContext.wrap_bio(incoming, outgoing, server_side=False, \ server_hostname=None) diff -r 23f8a511050a Lib/ssl.py --- a/Lib/ssl.py Sat Nov 22 14:41:21 2014 -0800 +++ b/Lib/ssl.py Sun Nov 23 15:45:50 2014 -0500 @@ -354,9 +354,14 @@ def wrap_bio(self, incoming, outgoing, server_side=False, server_hostname=None): - sslobj = self._wrap_bio(incoming, outgoing, server_side=server_side, - server_hostname=server_hostname) - return SSLObject(sslobj) + if HAS_SNI: + sslobj = self._wrap_bio(incoming, outgoing, + server_side=server_side, + server_hostname=server_hostname) + else: + sslobj = self._wrap_bio(incoming, outgoing, + server_side=server_side) + return SSLObject(sslobj, server_hostname=server_hostname) def set_npn_protocols(self, npn_protocols): protos = bytearray() @@ -501,10 +506,11 @@ * The ``do_handshake_on_connect`` and ``suppress_ragged_eofs`` machinery. """ - def __init__(self, sslobj, owner=None): + def __init__(self, sslobj, owner=None, server_hostname=None): self._sslobj = sslobj # Note: _sslobj takes a weak reference to owner self._sslobj.owner = owner or self + self._server_hostname = server_hostname @property def context(self): @@ -524,7 +530,7 @@ def server_hostname(self): """The currently set server hostname (for SNI), or ``None`` if no server hostame is set.""" - return self._sslobj.server_hostname + return self._sslobj.server_hostname or self._server_hostname def read(self, len=0, buffer=None): """Read up to 'len' bytes from the SSL object and return them. @@ -655,12 +661,8 @@ raise ValueError("server_hostname can only be specified " "in client mode") if self._context.check_hostname and not server_hostname: - if HAS_SNI: - raise ValueError("check_hostname requires server_hostname") - else: - raise ValueError("check_hostname requires server_hostname, " - "but it's not supported by your OpenSSL " - "library") + raise ValueError("check_hostname requires server_hostname") + self.server_side = server_side self.server_hostname = server_hostname self.do_handshake_on_connect = do_handshake_on_connect @@ -694,9 +696,14 @@ if connected: # create the SSL object try: - sslobj = self._context._wrap_socket(self, server_side, - server_hostname) - self._sslobj = SSLObject(sslobj, owner=self) + if HAS_SNI: + sslobj = self._context._wrap_socket(self, server_side, + server_hostname) + else: + sslobj = self._context._wrap_socket(self, server_side) + self._sslobj = SSLObject(sslobj, + owner=self, + server_hostname=server_hostname) if do_handshake_on_connect: timeout = self.gettimeout() if timeout == 0.0: @@ -936,8 +943,14 @@ # connected at the time of the call. We connect it, then wrap it. if self._connected: raise ValueError("attempt to connect already-connected SSLSocket!") - sslobj = self.context._wrap_socket(self, False, self.server_hostname) - self._sslobj = SSLObject(sslobj, owner=self) + if HAS_SNI: + sslobj = self.context._wrap_socket(self, False, + self.server_hostname) + else: + sslobj = self.context._wrap_socket(self, False) + self._sslobj = SSLObject(sslobj, + owner=self, + server_hostname=self.server_hostname) try: if connect_ex: rc = socket.connect_ex(self, addr)