diff options
-rw-r--r-- | Doc/library/ssl.rst | 6 | ||||
-rw-r--r-- | Lib/test/test_ssl.py | 8 | ||||
-rw-r--r-- | Misc/NEWS | 3 | ||||
-rw-r--r-- | Modules/_ssl.c | 10 |
4 files changed, 24 insertions, 3 deletions
diff --git a/Doc/library/ssl.rst b/Doc/library/ssl.rst index 983c144..bb4ceca 100644 --- a/Doc/library/ssl.rst +++ b/Doc/library/ssl.rst @@ -659,7 +659,8 @@ SSL sockets also have the following additional methods and attributes: .. method:: SSLSocket.getpeercert(binary_form=False) If there is no certificate for the peer on the other end of the connection, - returns ``None``. + return ``None``. If the SSL handshake hasn't been done yet, raise + :exc:`ValueError`. If the ``binary_form`` parameter is :const:`False`, and a certificate was received from the peer, this method returns a :class:`dict` instance. If the @@ -716,6 +717,9 @@ SSL sockets also have the following additional methods and attributes: The returned dictionary includes additional items such as ``issuer`` and ``notBefore``. + .. versionchanged:: 3.4 + :exc:`ValueError` is raised when the handshake isn't done. + .. method:: SSLSocket.cipher() Returns a three-value tuple containing the name of the cipher being used, the diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py index 8915305..2605e68 100644 --- a/Lib/test/test_ssl.py +++ b/Lib/test/test_ssl.py @@ -1588,8 +1588,14 @@ else: context.load_cert_chain(CERTFILE) server = ThreadedEchoServer(context=context, chatty=False) with server: - s = context.wrap_socket(socket.socket()) + s = context.wrap_socket(socket.socket(), + do_handshake_on_connect=False) s.connect((HOST, server.port)) + # getpeercert() raise ValueError while the handshake isn't + # done. + with self.assertRaises(ValueError): + s.getpeercert() + s.do_handshake() cert = s.getpeercert() self.assertTrue(cert, "Can't get peer certificate.") cipher = s.cipher() @@ -15,6 +15,9 @@ Core and Builtins Library ------- +- Issue #19095: SSLSocket.getpeercert() now raises ValueError when the + SSL handshake hasn't been done. + - Issue #4366: Fix building extensions on all platforms when --enable-shared is used. diff --git a/Modules/_ssl.c b/Modules/_ssl.c index e116d3d..3afe893 100644 --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -220,7 +220,8 @@ typedef struct { SSL *ssl; PySSLContext *ctx; /* weakref to SSL context */ X509 *peer_cert; - int shutdown_seen_zero; + char shutdown_seen_zero; + char handshake_done; enum py_ssl_server_or_client socket_type; } PySSLSocket; @@ -485,6 +486,7 @@ newPySSLSocket(PySSLContext *sslctx, PySocketSockObject *sock, self->ssl = NULL; self->Socket = NULL; self->ctx = sslctx; + self->handshake_done = 0; Py_INCREF(sslctx); /* Make sure the SSL error state is initialized */ @@ -590,6 +592,7 @@ static PyObject *PySSL_SSLdo_handshake(PySSLSocket *self) PySSL_BEGIN_ALLOW_THREADS self->peer_cert = SSL_get_peer_certificate(self->ssl); PySSL_END_ALLOW_THREADS + self->handshake_done = 1; Py_INCREF(Py_None); return Py_None; @@ -1153,6 +1156,11 @@ PySSL_peercert(PySSLSocket *self, PyObject *args) if (!PyArg_ParseTuple(args, "|p:peer_certificate", &binary_mode)) return NULL; + if (!self->handshake_done) { + PyErr_SetString(PyExc_ValueError, + "handshake not done yet"); + return NULL; + } if (!self->peer_cert) Py_RETURN_NONE; |