summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMiss Islington (bot) <31488909+miss-islington@users.noreply.github.com>2019-06-30 23:51:40 -0700
committerNed Deily <nad@python.org>2019-07-01 22:27:58 -0400
commit5b45fb0a449543fab6e7b606e51b739cb316d3c4 (patch)
treefaddc0122ba3e2179cd945341d49e6d341be67f8
parent3e24dd52bba863fce4f3c6a34ca9f813666ed181 (diff)
downloadcpython-git-5b45fb0a449543fab6e7b606e51b739cb316d3c4.tar.gz
[3.7] bpo-37428: Don't set PHA verify flag on client side (GH-14421) (GH-14493)
SSLContext.post_handshake_auth = True no longer sets SSL_VERIFY_POST_HANDSHAKE verify flag for client connections. Although the option is documented as ignored for clients, OpenSSL implicitly enables cert chain validation when the flag is set. Signed-off-by: Christian Heimes <christian@python.org> https://bugs.python.org/issue37428 (cherry picked from commit f0f5930ac88482ef896283db5be9b8d508d077db) Co-authored-by: Christian Heimes <christian@python.org> https://bugs.python.org/issue37428
-rw-r--r--Lib/test/test_ssl.py31
-rw-r--r--Misc/NEWS.d/next/Library/2019-06-27-13-27-02.bpo-37428._wcwUd.rst4
-rw-r--r--Modules/_ssl.c43
3 files changed, 61 insertions, 17 deletions
diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py
index 73b6bdf01e..86f790b4a2 100644
--- a/Lib/test/test_ssl.py
+++ b/Lib/test/test_ssl.py
@@ -4437,6 +4437,37 @@ class TestPostHandshakeAuth(unittest.TestCase):
s.write(b'PHA')
self.assertIn(b'WRONG_SSL_VERSION', s.recv(1024))
+ def test_bpo37428_pha_cert_none(self):
+ # verify that post_handshake_auth does not implicitly enable cert
+ # validation.
+ hostname = SIGNED_CERTFILE_HOSTNAME
+ client_context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
+ client_context.post_handshake_auth = True
+ client_context.load_cert_chain(SIGNED_CERTFILE)
+ # no cert validation and CA on client side
+ client_context.check_hostname = False
+ client_context.verify_mode = ssl.CERT_NONE
+
+ server_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
+ server_context.load_cert_chain(SIGNED_CERTFILE)
+ server_context.load_verify_locations(SIGNING_CA)
+ server_context.post_handshake_auth = True
+ server_context.verify_mode = ssl.CERT_REQUIRED
+
+ server = ThreadedEchoServer(context=server_context, chatty=False)
+ with server:
+ with client_context.wrap_socket(socket.socket(),
+ server_hostname=hostname) as s:
+ s.connect((HOST, server.port))
+ s.write(b'HASCERT')
+ self.assertEqual(s.recv(1024), b'FALSE\n')
+ s.write(b'PHA')
+ self.assertEqual(s.recv(1024), b'OK\n')
+ s.write(b'HASCERT')
+ self.assertEqual(s.recv(1024), b'TRUE\n')
+ # server cert has not been validated
+ self.assertEqual(s.getpeercert(), {})
+
def test_main(verbose=False):
if support.verbose:
diff --git a/Misc/NEWS.d/next/Library/2019-06-27-13-27-02.bpo-37428._wcwUd.rst b/Misc/NEWS.d/next/Library/2019-06-27-13-27-02.bpo-37428._wcwUd.rst
new file mode 100644
index 0000000000..2cdce6b24d
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2019-06-27-13-27-02.bpo-37428._wcwUd.rst
@@ -0,0 +1,4 @@
+SSLContext.post_handshake_auth = True no longer sets
+SSL_VERIFY_POST_HANDSHAKE verify flag for client connections. Although the
+option is documented as ignored for clients, OpenSSL implicitly enables cert
+chain validation when the flag is set.
diff --git a/Modules/_ssl.c b/Modules/_ssl.c
index 30c91f5931..e8955eedfa 100644
--- a/Modules/_ssl.c
+++ b/Modules/_ssl.c
@@ -931,6 +931,26 @@ newPySSLSocket(PySSLContext *sslctx, PySocketSockObject *sock,
SSL_set_mode(self->ssl,
SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER | SSL_MODE_AUTO_RETRY);
+#ifdef TLS1_3_VERSION
+ if (sslctx->post_handshake_auth == 1) {
+ if (socket_type == PY_SSL_SERVER) {
+ /* bpo-37428: OpenSSL does not ignore SSL_VERIFY_POST_HANDSHAKE.
+ * Set SSL_VERIFY_POST_HANDSHAKE flag only for server sockets and
+ * only in combination with SSL_VERIFY_PEER flag. */
+ int mode = SSL_get_verify_mode(self->ssl);
+ if (mode & SSL_VERIFY_PEER) {
+ int (*verify_cb)(int, X509_STORE_CTX *) = NULL;
+ verify_cb = SSL_get_verify_callback(self->ssl);
+ mode |= SSL_VERIFY_POST_HANDSHAKE;
+ SSL_set_verify(self->ssl, mode, verify_cb);
+ }
+ } else {
+ /* client socket */
+ SSL_set_post_handshake_auth(self->ssl, 1);
+ }
+ }
+#endif
+
if (server_hostname != NULL) {
if (_ssl_configure_hostname(self, server_hostname) < 0) {
Py_DECREF(self);
@@ -2928,10 +2948,10 @@ _set_verify_mode(PySSLContext *self, enum py_ssl_cert_requirements n)
"invalid value for verify_mode");
return -1;
}
-#ifdef TLS1_3_VERSION
- if (self->post_handshake_auth)
- mode |= SSL_VERIFY_POST_HANDSHAKE;
-#endif
+
+ /* bpo-37428: newPySSLSocket() sets SSL_VERIFY_POST_HANDSHAKE flag for
+ * server sockets and SSL_set_post_handshake_auth() for client. */
+
/* keep current verify cb */
verify_cb = SSL_CTX_get_verify_callback(self->ctx);
SSL_CTX_set_verify(self->ctx, mode, verify_cb);
@@ -3628,8 +3648,6 @@ get_post_handshake_auth(PySSLContext *self, void *c) {
#if TLS1_3_VERSION
static int
set_post_handshake_auth(PySSLContext *self, PyObject *arg, void *c) {
- int (*verify_cb)(int, X509_STORE_CTX *) = NULL;
- int mode = SSL_CTX_get_verify_mode(self->ctx);
if (arg == NULL) {
PyErr_SetString(PyExc_AttributeError, "cannot delete attribute");
return -1;
@@ -3641,17 +3659,8 @@ set_post_handshake_auth(PySSLContext *self, PyObject *arg, void *c) {
}
self->post_handshake_auth = pha;
- /* client-side socket setting, ignored by server-side */
- SSL_CTX_set_post_handshake_auth(self->ctx, pha);
-
- /* server-side socket setting, ignored by client-side */
- verify_cb = SSL_CTX_get_verify_callback(self->ctx);
- if (pha) {
- mode |= SSL_VERIFY_POST_HANDSHAKE;
- } else {
- mode ^= SSL_VERIFY_POST_HANDSHAKE;
- }
- SSL_CTX_set_verify(self->ctx, mode, verify_cb);
+ /* bpo-37428: newPySSLSocket() sets SSL_VERIFY_POST_HANDSHAKE flag for
+ * server sockets and SSL_set_post_handshake_auth() for client. */
return 0;
}