|
|
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 |
}
|