Skip to content

Commit 1e8b4ab

Browse files
committed
bpo-31399: Only expose useful hostflags
Remove all hostflags except for NO_PARTIAL_WILDCARDS and NEVER_CHECK_SUBJECT. The other flags aren't that useful at the moment. Don't support OpenSSL special mode with a leading dot, e.g. ".example.org" matches "www.example.org". It's not standard conform. Signed-off-by: Christian Heimes <[email protected]>
1 parent a48ae16 commit 1e8b4ab

File tree

4 files changed

+32
-47
lines changed

4 files changed

+32
-47
lines changed

Doc/library/ssl.rst

Lines changed: 6 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -431,11 +431,12 @@ Certificate handling
431431
of the certificate, is now supported.
432432

433433
.. versionchanged:: 3.7
434-
The function is no longer used. Hostname matching is now performed
435-
by OpenSSL.
434+
The function is no longer used to TLS connections. Hostname matching
435+
is now performed by OpenSSL.
436436

437437
Allow wildcard when it is the leftmost and the only character
438-
in that segment.
438+
in that segment. Partial wildcards like ``www*.example.com`` are no
439+
longer supported.
439440

440441
.. deprecated:: 3.7
441442

@@ -599,31 +600,15 @@ Constants
599600

600601
.. versionadded:: 3.7
601602

602-
.. attribute:: HostFlags.HOSTFLAG_ALWAYS_CHECK_SUBJECT
603-
604-
Consider subject CN even if the certificate contains at least one subject
605-
alternative name. This flag violates :rfc:`6125`.
606-
607-
.. attribute:: HostFlags.HOSTFLAG_NO_WILDCARDS
608-
609-
Don't support wildcard certificate, e.g. ``*.example.org``.
610-
611603
.. attribute:: HostFlags.HOSTFLAG_NO_PARTIAL_WILDCARDS
612604

613605
Dont' support wildcard certificate with partial matches, e.g.
614606
``www*.example.org``.
615607

616-
.. attribute:: HostFlags.HOSTFLAG_MULTI_LABEL_WILDCARDS
617-
618-
Wildcards match multiple labels, e.g. ``www.subdomain.example.org``
619-
matches ``*.example.org`` This flag violates :rfc:`6125`.
620-
621-
.. attribute:: HostFlags.HOSTFLAG_SINGLE_LABEL_SUBDOMAINS
622-
623608
.. attribute:: HostFlags.HOSTFLAG_NEVER_CHECK_SUBJECT
624609

625610
Ignore subject CN even if the certificate has no subject alternative
626-
names.
611+
name extension.
627612

628613
.. note:: The flag is not available when the ssl module is compiled
629614
with OpenSSL 1.0.2 or LibreSSL.
@@ -1781,8 +1766,7 @@ to speed up repeated connections from the same clients.
17811766
.. attribute:: SSLContext.host_flags
17821767

17831768
The flags for validating host names. By default
1784-
:data:`HostFlags.HOSTFLAG_SINGLE_LABEL_SUBDOMAINS` and
1785-
:data:`HostFlags.HOSTFLAG_NO_PARTIAL_WILDCARDS` are set.
1769+
:data:`HostFlags.HOSTFLAG_NO_PARTIAL_WILDCARDS` is set.
17861770

17871771
.. versionadded:: 3.7
17881772

Lib/asyncio/sslproto.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -590,7 +590,6 @@ def _on_handshake_complete(self, handshake_exc):
590590
raise handshake_exc
591591

592592
peercert = sslobj.getpeercert()
593-
# Since 3.7, the hostname is matched by OpenSSL during handshake.
594593
except BaseException as exc:
595594
if self._loop.get_debug():
596595
if isinstance(exc, ssl.CertificateError):

Lib/test/test_ssl.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1511,6 +1511,16 @@ def test_bad_idna_in_server_hostname(self):
15111511
ctx.wrap_bio(ssl.MemoryBIO(), ssl.MemoryBIO(),
15121512
server_hostname="xn--.com")
15131513

1514+
def test_bad_server_hostname(self):
1515+
ctx = ssl.create_default_context()
1516+
with self.assertRaises(ValueError):
1517+
ctx.wrap_bio(ssl.MemoryBIO(), ssl.MemoryBIO(),
1518+
server_hostname="")
1519+
with self.assertRaises(ValueError):
1520+
ctx.wrap_bio(ssl.MemoryBIO(), ssl.MemoryBIO(),
1521+
server_hostname=".example.org")
1522+
1523+
15141524
class MemoryBIOTests(unittest.TestCase):
15151525

15161526
def test_read_write(self):

Modules/_ssl.c

Lines changed: 16 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -713,17 +713,30 @@ _ssl_configure_hostname(PySSLSocket *self, const char* server_hostname)
713713
int retval = -1;
714714
ASN1_OCTET_STRING *ip;
715715
PyObject *hostname;
716+
size_t len;
716717

717718
assert(server_hostname);
718719

720+
/* Disable OpenSSL's special mode with leading dot in hostname:
721+
* When name starts with a dot (e.g ".example.com"), it will be
722+
* matched by a certificate valid for any sub-domain of name.
723+
*/
724+
len = strlen(server_hostname);
725+
if (len == 0 || *server_hostname == '.') {
726+
PyErr_SetString(
727+
PyExc_ValueError,
728+
"server_hostname cannot be an empty string or start with a "
729+
"leading dot.");
730+
return retval;
731+
}
732+
719733
/* inet_pton is not available on all platforms. */
720734
ip = a2i_IPADDRESS(server_hostname);
721735
if (ip == NULL) {
722736
ERR_clear_error();
723737
}
724738

725-
hostname = PyUnicode_Decode(server_hostname, strlen(server_hostname),
726-
"idna", "strict");
739+
hostname = PyUnicode_Decode(server_hostname, len, "idna", "strict");
727740
if (hostname == NULL) {
728741
goto error;
729742
}
@@ -2811,10 +2824,7 @@ _ssl__SSLContext_impl(PyTypeObject *type, int proto_version)
28112824
return NULL;
28122825
}
28132826
self->ctx = ctx;
2814-
self->hostflags = (
2815-
X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS |
2816-
X509_CHECK_FLAG_SINGLE_LABEL_SUBDOMAINS
2817-
);
2827+
self->hostflags = X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS;
28182828
#if defined(OPENSSL_NPN_NEGOTIATED) && !defined(OPENSSL_NO_NEXTPROTONEG)
28192829
self->npn_protocols = NULL;
28202830
#endif
@@ -5564,30 +5574,12 @@ PyInit__ssl(void)
55645574
SSL_OP_NO_COMPRESSION);
55655575
#endif
55665576

5567-
#ifdef X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT
5568-
PyModule_AddIntConstant(m, "HOSTFLAG_ALWAYS_CHECK_SUBJECT",
5569-
X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT);
5570-
#endif
55715577
#ifdef X509_CHECK_FLAG_NEVER_CHECK_SUBJECT
55725578
PyModule_AddIntConstant(m, "HOSTFLAG_NEVER_CHECK_SUBJECT",
55735579
X509_CHECK_FLAG_NEVER_CHECK_SUBJECT);
55745580
#endif
5575-
#ifdef X509_CHECK_FLAG_NO_WILDCARDS
5576-
PyModule_AddIntConstant(m, "HOSTFLAG_NO_WILDCARDS",
5577-
X509_CHECK_FLAG_NO_WILDCARDS);
5578-
#endif
5579-
#ifdef X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS
55805581
PyModule_AddIntConstant(m, "HOSTFLAG_NO_PARTIAL_WILDCARDS",
55815582
X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS);
5582-
#endif
5583-
#ifdef X509_CHECK_FLAG_MULTI_LABEL_WILDCARDS
5584-
PyModule_AddIntConstant(m, "HOSTFLAG_MULTI_LABEL_WILDCARDS",
5585-
X509_CHECK_FLAG_MULTI_LABEL_WILDCARDS);
5586-
#endif
5587-
#ifdef X509_CHECK_FLAG_SINGLE_LABEL_SUBDOMAINS
5588-
PyModule_AddIntConstant(m, "HOSTFLAG_SINGLE_LABEL_SUBDOMAINS",
5589-
X509_CHECK_FLAG_SINGLE_LABEL_SUBDOMAINS);
5590-
#endif
55915583

55925584
#if HAVE_SNI
55935585
r = Py_True;

0 commit comments

Comments
 (0)