Blame SOURCES/00326-do-not-set-PHA-verify-flag-on-client-side.patch

b9ffd2
diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py
b9ffd2
index 883201f..cf4d84d 100644
b9ffd2
--- a/Lib/test/test_ssl.py
b9ffd2
+++ b/Lib/test/test_ssl.py
b9ffd2
@@ -3891,6 +3891,37 @@ class TestPostHandshakeAuth(unittest.TestCase):
b9ffd2
                 s.write(b'PHA')
b9ffd2
                 self.assertIn(b'WRONG_SSL_VERSION', s.recv(1024))
b9ffd2
 
b9ffd2
+    def test_bpo37428_pha_cert_none(self):
b9ffd2
+        # verify that post_handshake_auth does not implicitly enable cert
b9ffd2
+        # validation.
b9ffd2
+        hostname = 'localhost'
b9ffd2
+        client_context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
b9ffd2
+        client_context.post_handshake_auth = True
b9ffd2
+        client_context.load_cert_chain(SIGNED_CERTFILE)
b9ffd2
+        # no cert validation and CA on client side
b9ffd2
+        client_context.check_hostname = False
b9ffd2
+        client_context.verify_mode = ssl.CERT_NONE
b9ffd2
+
b9ffd2
+        server_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
b9ffd2
+        server_context.load_cert_chain(SIGNED_CERTFILE)
b9ffd2
+        server_context.load_verify_locations(SIGNING_CA)
b9ffd2
+        server_context.post_handshake_auth = True
b9ffd2
+        server_context.verify_mode = ssl.CERT_REQUIRED
b9ffd2
+
b9ffd2
+        server = ThreadedEchoServer(context=server_context, chatty=False)
b9ffd2
+        with server:
b9ffd2
+            with client_context.wrap_socket(socket.socket(),
b9ffd2
+                                            server_hostname=hostname) as s:
b9ffd2
+                s.connect((HOST, server.port))
b9ffd2
+                s.write(b'HASCERT')
b9ffd2
+                self.assertEqual(s.recv(1024), b'FALSE\n')
b9ffd2
+                s.write(b'PHA')
b9ffd2
+                self.assertEqual(s.recv(1024), b'OK\n')
b9ffd2
+                s.write(b'HASCERT')
b9ffd2
+                self.assertEqual(s.recv(1024), b'TRUE\n')
b9ffd2
+                # server cert has not been validated
b9ffd2
+                self.assertEqual(s.getpeercert(), {})
b9ffd2
+
b9ffd2
 
b9ffd2
 def test_main(verbose=False):
b9ffd2
     if support.verbose:
b9ffd2
diff --git a/Modules/_ssl.c b/Modules/_ssl.c
b9ffd2
index ec366f0..9bf1cde 100644
b9ffd2
--- a/Modules/_ssl.c
b9ffd2
+++ b/Modules/_ssl.c
b9ffd2
@@ -732,6 +732,26 @@ newPySSLSocket(PySSLContext *sslctx, PySocketSockObject *sock,
b9ffd2
 #endif
b9ffd2
     SSL_set_mode(self->ssl, mode);
b9ffd2
 
b9ffd2
+#ifdef TLS1_3_VERSION
b9ffd2
+    if (sslctx->post_handshake_auth == 1) {
b9ffd2
+        if (socket_type == PY_SSL_SERVER) {
b9ffd2
+            /* bpo-37428: OpenSSL does not ignore SSL_VERIFY_POST_HANDSHAKE.
b9ffd2
+             * Set SSL_VERIFY_POST_HANDSHAKE flag only for server sockets and
b9ffd2
+             * only in combination with SSL_VERIFY_PEER flag. */
b9ffd2
+            int mode = SSL_get_verify_mode(self->ssl);
b9ffd2
+            if (mode & SSL_VERIFY_PEER) {
b9ffd2
+                int (*verify_cb)(int, X509_STORE_CTX *) = NULL;
b9ffd2
+                verify_cb = SSL_get_verify_callback(self->ssl);
b9ffd2
+                mode |= SSL_VERIFY_POST_HANDSHAKE;
b9ffd2
+                SSL_set_verify(self->ssl, mode, verify_cb);
b9ffd2
+            }
b9ffd2
+        } else {
b9ffd2
+            /* client socket */
b9ffd2
+            SSL_set_post_handshake_auth(self->ssl, 1);
b9ffd2
+        }
b9ffd2
+    }
b9ffd2
+#endif
b9ffd2
+
b9ffd2
 #if HAVE_SNI
b9ffd2
     if (server_hostname != NULL) {
b9ffd2
 /* Don't send SNI for IP addresses. We cannot simply use inet_aton() and
b9ffd2
@@ -2765,10 +2785,10 @@ _set_verify_mode(PySSLContext *self, enum py_ssl_cert_requirements n)
b9ffd2
                         "invalid value for verify_mode");
b9ffd2
         return -1;
b9ffd2
     }
b9ffd2
-#ifdef TLS1_3_VERSION
b9ffd2
-    if (self->post_handshake_auth)
b9ffd2
-        mode |= SSL_VERIFY_POST_HANDSHAKE;
b9ffd2
-#endif
b9ffd2
+
b9ffd2
+    /* bpo-37428: newPySSLSocket() sets SSL_VERIFY_POST_HANDSHAKE flag for
b9ffd2
+     * server sockets and SSL_set_post_handshake_auth() for client. */
b9ffd2
+
b9ffd2
     /* keep current verify cb */
b9ffd2
     verify_cb = SSL_CTX_get_verify_callback(self->ctx);
b9ffd2
     SSL_CTX_set_verify(self->ctx, mode, verify_cb);
b9ffd2
@@ -3346,8 +3366,6 @@ get_post_handshake_auth(PySSLContext *self, void *c) {
b9ffd2
 #if TLS1_3_VERSION
b9ffd2
 static int
b9ffd2
 set_post_handshake_auth(PySSLContext *self, PyObject *arg, void *c) {
b9ffd2
-    int (*verify_cb)(int, X509_STORE_CTX *) = NULL;
b9ffd2
-    int mode = SSL_CTX_get_verify_mode(self->ctx);
b9ffd2
     int pha = PyObject_IsTrue(arg);
b9ffd2
 
b9ffd2
     if (pha == -1) {
b9ffd2
@@ -3355,17 +3373,8 @@ set_post_handshake_auth(PySSLContext *self, PyObject *arg, void *c) {
b9ffd2
     }
b9ffd2
     self->post_handshake_auth = pha;
b9ffd2
 
b9ffd2
-    /* client-side socket setting, ignored by server-side */
b9ffd2
-    SSL_CTX_set_post_handshake_auth(self->ctx, pha);
b9ffd2
-
b9ffd2
-    /* server-side socket setting, ignored by client-side */
b9ffd2
-    verify_cb = SSL_CTX_get_verify_callback(self->ctx);
b9ffd2
-    if (pha) {
b9ffd2
-        mode |= SSL_VERIFY_POST_HANDSHAKE;
b9ffd2
-    } else {
b9ffd2
-        mode ^= SSL_VERIFY_POST_HANDSHAKE;
b9ffd2
-    }
b9ffd2
-    SSL_CTX_set_verify(self->ctx, mode, verify_cb);
b9ffd2
+    /* bpo-37428: newPySSLSocket() sets SSL_VERIFY_POST_HANDSHAKE flag for
b9ffd2
+     * server sockets and SSL_set_post_handshake_auth() for client. */
b9ffd2
 
b9ffd2
     return 0;
b9ffd2
 }