This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: server_hostname should only be required when checking host names
Type: behavior Stage: resolved
Components: asyncio Versions: Python 3.7, Python 3.6, Python 2.7
process
Status: closed Resolution: works for me
Dependencies: Superseder:
Assigned To: yselivanov Nosy List: christian.heimes, j1m, kwarunek, r.david.murray, yselivanov
Priority: normal Keywords:

Created on 2016-06-26 15:43 by j1m, last changed 2022-04-11 14:58 by admin. This issue is now closed.

Files
File name Uploaded Description Edit
bpo27391.py christian.heimes, 2017-09-07 14:25
Messages (22)
msg269292 - (view) Author: Jim Fulton (j1m) * (Python committer) Date: 2016-06-26 15:43
If the given ssl context has check_hostname set to False, then the server_hostname shouldn't be required.
msg269311 - (view) Author: R. David Murray (r.david.murray) * (Python committer) Date: 2016-06-26 21:01
Where is it required?
msg269312 - (view) Author: R. David Murray (r.david.murray) * (Python committer) Date: 2016-06-26 21:02
(To clarify: I haven't used the ssl interface enough for it to be obvious to me where the bug is.)
msg269487 - (view) Author: Jim Fulton (j1m) * (Python committer) Date: 2016-06-29 13:34
It's not bug, it's a misfeature, IMO.

If you pass an SSL context and either don't pass a hostname or pass an empty string, then server_hostname is required, even if check_hostname is false for the context.

The fix is trivial. I'd be happy to provide a PR.
msg269499 - (view) Author: R. David Murray (r.david.murray) * (Python committer) Date: 2016-06-29 14:21
You still haven't told me what you are passing the context to that objects to not having server_hostname.  I suppose the asyncio experts would know immediately, so I should probably just leave it to them...or wait for your PR.
msg269503 - (view) Author: Jim Fulton (j1m) * (Python committer) Date: 2016-06-29 14:36
I'm not sure I understand your question.

The documentation for create_connection, https://docs.python.org/3/library/asyncio-eventloop.html#creating-connections states that server_hostname is required if the host is empty. (I'm generalizing "empty" to include None.)

SSL contexts, https://docs.python.org/3/library/ssl.html#ssl-contexts,
have an attribute, check_hostname, which controls whether hostname checking is required. If set to false in a context passed to create_connection, then it makes no sense to require server_hostname under any circumstances.

Note that this is easy to work around by passing an empty string, it just seems pointless to make people do that if you're already controlling this via the SSL context.
msg269506 - (view) Author: Jim Fulton (j1m) * (Python committer) Date: 2016-06-29 14:38
Consider this a suggestion. Do with it what you will. I'm closing this as I don't want to spend more time on it other than creating a PR if requested.
msg269508 - (view) Author: R. David Murray (r.david.murray) * (Python committer) Date: 2016-06-29 14:46
Sorry, I've been having trouble communicating on this ticket.  I thought I'd posetd an apology but I don't see it...I wonder where I did post it?  Bad morning :(.

Anyway, create_connection was what I was asking for.

Reading the docs, I, at least, agree with you, and if it weren't for backward compatibility I'd suggest making the only way to disable host checking be by passing a context with it disabled.  But failing that I don't see any reason to force you to specify a hostname if you've already said you don't want to check hostnames.
msg269509 - (view) Author: Yury Selivanov (yselivanov) * (Python committer) Date: 2016-06-29 14:57
> SSL contexts, https://docs.python.org/3/library/ssl.html#ssl-contexts,
have an attribute, check_hostname, which controls whether hostname checking is required. If set to false in a context passed to create_connection, then it makes no sense to require server_hostname under any circumstances.

This makes sense.  I'm reopening this issue.  Jim, would you be able to submit a PR to github/python/asyncio?
msg269510 - (view) Author: Jim Fulton (j1m) * (Python committer) Date: 2016-06-29 14:59
No need to apologize!  My capitulation was just due to the fact that this isn't a big deal. (My tone probably came across as cranky; sorry)

WRT backward compatibility, I suspect that there's a bit of wiggle here between loop implementations and I doubt this would be noticed. For example, uvloop errors if you pass None for both server_hostname and ssl. <shug>
msg269511 - (view) Author: Jim Fulton (j1m) * (Python committer) Date: 2016-06-29 15:00
OK, sure, I'll make a PR.
msg276527 - (view) Author: Christian Heimes (christian.heimes) * (Python committer) Date: 2016-09-15 08:06
server_hostname is also required for SNI (server name indicator). Virtual hosting depends on the feature. Without SNI TLS extension you'll end up on the wrong vhost or the web server sends you the wrong certificate.

The feature is pretty much required these days.
msg276572 - (view) Author: Yury Selivanov (yselivanov) * (Python committer) Date: 2016-09-15 16:08
> The feature is pretty much required these days.

We have the feature. What Jim was asking is to make server_hostname argument optional when check_hostname is False in the ssl context
msg276573 - (view) Author: Christian Heimes (christian.heimes) * (Python committer) Date: 2016-09-15 16:25
It's a bad idea. An increasing amount of web servers require a TLS SNI extension. I'd rather make server_hostname a required argument for all client-side SSL sockets -- no matter how check_hostname is configured.
msg276574 - (view) Author: Yury Selivanov (yselivanov) * (Python committer) Date: 2016-09-15 16:28
> It's a bad idea.

I thought so too :)  I was actually going to ask you to review this request.  In any case, feel free to close this issue.
msg276614 - (view) Author: Jim Fulton (j1m) * (Python committer) Date: 2016-09-15 20:29
SSL is used for more than just HTTP.  The are applications in which clients have server public keys that they use to authenticate servers rather than using certificate authorities.  For these applications, server host names are irrelevant.  This is why it makes sense to have an option on the SSL context to disable host name checking.  Removing this ability would break some applications.

If the option to check host names is provided as false on the SSL context, it makes no sense to check whether the host name, which isn't going to be used, is not None.  It's just silly, but not a huge deal one way or the other, because there are actually *two* ways to disable host name checking; you can also pass '' as the hostname, which is why this isn't a big deal and why I haven't gotten around to making a PR yet.
msg276682 - (view) Author: Christian Heimes (christian.heimes) * (Python committer) Date: 2016-09-16 07:56
You are still ignoring my remarks about TLS SNI. :)

Python uses server_hostname for two different but related parts of the TLS/SSL.

1) When server_hostname is set, the client sends the hostname to the server during the TLS handshake in the ClientHello message. [1] Without a TLS SNI extension your client may talk to the wrong service. TLS SNI not limited to HTTPS, although HTTPS virtual hosting is the biggest user of SNI. You should only omit the argument if you directly connect to an IP address.

2) Python uses server_hostname to verify that the certificate matches the hostname. Hostname matching can be disabled with a custom SSLContext that has check hostname disabled.
[1] https://en.wikipedia.org/wiki/Server_Name_Indication

server_hostname='' should not bypass hostname verification. That's a bug.
msg276710 - (view) Author: Jim Fulton (j1m) * (Python committer) Date: 2016-09-16 13:12
I'm not ignoring anything AFAICT.

There are applications where server hostname isn't useful (no virtual hosts, client has server's public key).

I'm not positive we're disagreeing, so let me put this another way.

1. If the given SSL context has check_hostname set to False,
   then ``create_connection`` should not not require a value for
   ``server_hostname``, regardless of the value of ``host``.

   Do you agree?

2. If the given SSL context has check_hostname set to True,
   then ``create_connection`` should not accept an empty string
   to disable hostname checks.

   Do you agree? I'm wondering is this is what you're referring to
   as a bug.

   Personally, this only bothers me from a TOOWTDI perspective.
   I can imagine (always a dangerous word :)) people wanting to 
   reuse an SSL context but disable host name checking. In any case,
   "fixing" this would likely be a breaking change.
msg301586 - (view) Author: Christian Heimes (christian.heimes) * (Python committer) Date: 2017-09-07 14:25
Jim, yes I agree. In a matter of fact, the ssl module also agrees with you and behaves like that for a while. I cannot reproduce the problem with either 2.7, 3.5, or 3.6. I have attached an demo script.


check_hostname = True
* server_hostname='www.python.org' OK
* server_hostname='': Exception: check_hostname requires server_hostname
* no server_hostname: Exception: check_hostname requires server_hostname

check_hostname = False
* server_hostname='www.python.org' OK
* server_hostname='' OK
* no server_hostname OK
msg302292 - (view) Author: Krzysztof Warunek (kwarunek) * Date: 2017-09-15 19:35
The case appears in asyncio's create_connection. Actually it's known thing https://github.com/python/cpython/blob/3.6/Lib/asyncio/base_events.py#L699, a workaround mentioned (same as Jim has pointed) is used widely. It seems reasonably at first sight to "fix it", but I consider this requirement (pass '') as a safety check.
msg302341 - (view) Author: Christian Heimes (christian.heimes) * (Python committer) Date: 2017-09-16 14:14
So it's not a problem with the SSL module but rather in asyncio. From the initial report it was not clear to me that it only affects asyncio.

I'm not sure this issue should be fixed at all. As I explained earlier, a hostname is required for both hostname verification and SNI TLS extension. We may allow to omit the parameter with verify_mode=CERT_NONE and check_hostname=False only. In all other cases the server may return a wrong cert or refuse to establish a connection.
msg302366 - (view) Author: Jim Fulton (j1m) * (Python committer) Date: 2017-09-17 14:28
OMG, >1year. :)

This was always a minor issue.  I still think the current asyncio behavior is dumb, but whatever.

FWIW, I tripped on this when adding SSL support to ZEO, which is a client-server *database* protocol used by ZODB, having nothing to do with the Web. In this context, the client and server are well known to each other and share certs.
History
Date User Action Args
2022-04-11 14:58:33adminsetgithub: 71578
2017-09-17 14:28:58j1msetstatus: open -> closed

messages: + msg302366
stage: resolved
2017-09-16 14:14:19christian.heimessetassignee: christian.heimes -> yselivanov
messages: + msg302341
components: - SSL
2017-09-15 19:35:00kwaruneksetstatus: pending -> open
nosy: + kwarunek
messages: + msg302292

2017-09-07 14:25:18christian.heimessetstatus: open -> pending
files: + bpo27391.py
versions: + Python 2.7, - Python 3.5
messages: + msg301586

resolution: works for me
2016-09-16 14:39:41gvanrossumsetnosy: - gvanrossum
2016-09-16 13:12:24j1msetmessages: + msg276710
2016-09-16 07:56:48christian.heimessetmessages: + msg276682
2016-09-15 20:29:06j1msetmessages: + msg276614
2016-09-15 19:02:14vstinnersetnosy: - vstinner
2016-09-15 16:28:04yselivanovsetmessages: + msg276574
2016-09-15 16:25:29christian.heimessetmessages: + msg276573
2016-09-15 16:08:11yselivanovsetmessages: + msg276572
2016-09-15 08:06:51christian.heimessetversions: + Python 3.7, - Python 3.3, Python 3.4
nosy: + christian.heimes

messages: + msg276527

assignee: christian.heimes
components: + SSL
2016-06-29 15:00:20j1msetmessages: + msg269511
2016-06-29 14:59:28j1msetmessages: + msg269510
2016-06-29 14:57:52yselivanovsetstatus: closed -> open

messages: + msg269509
2016-06-29 14:46:32r.david.murraysetmessages: + msg269508
2016-06-29 14:38:45j1msetstatus: open -> closed

messages: + msg269506
2016-06-29 14:36:01j1msetmessages: + msg269503
2016-06-29 14:21:00r.david.murraysetmessages: + msg269499
2016-06-29 13:34:19j1msetmessages: + msg269487
2016-06-26 21:02:54r.david.murraysetmessages: + msg269312
2016-06-26 21:01:45r.david.murraysetnosy: + r.david.murray
messages: + msg269311
2016-06-26 15:43:57j1mcreate