Skip to content

Commit 66dc33b

Browse files
authored
bpo-29334: Fix ssl.getpeercert for auto-handshake (#1769)
Drop handshake_done and peer_cert members from PySSLSocket struct. The peer certificate can be acquired from *SSL directly. SSL_get_peer_certificate() does not trigger any network activity. Instead of manually tracking the handshake state, simply use SSL_is_init_finished(). In combination these changes fix auto-handshake for non-blocking MemoryBIO connections. Signed-off-by: Christian Heimes <[email protected]>
1 parent e0918ec commit 66dc33b

File tree

1 file changed

+11
-19
lines changed

1 file changed

+11
-19
lines changed

Modules/_ssl.c

Lines changed: 11 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -298,9 +298,7 @@ typedef struct {
298298
PyObject *Socket; /* weakref to socket on which we're layered */
299299
SSL *ssl;
300300
PySSLContext *ctx; /* weakref to SSL context */
301-
X509 *peer_cert;
302301
char shutdown_seen_zero;
303-
char handshake_done;
304302
enum py_ssl_server_or_client socket_type;
305303
PyObject *owner; /* Python level "owner" passed to servername callback */
306304
PyObject *server_hostname;
@@ -595,12 +593,10 @@ newPySSLSocket(PySSLContext *sslctx, PySocketSockObject *sock,
595593
if (self == NULL)
596594
return NULL;
597595

598-
self->peer_cert = NULL;
599596
self->ssl = NULL;
600597
self->Socket = NULL;
601598
self->ctx = sslctx;
602599
self->shutdown_seen_zero = 0;
603-
self->handshake_done = 0;
604600
self->owner = NULL;
605601
self->server_hostname = NULL;
606602
if (server_hostname != NULL) {
@@ -748,13 +744,6 @@ _ssl__SSLSocket_do_handshake_impl(PySSLSocket *self)
748744
if (ret < 1)
749745
return PySSL_SetError(self, ret, __FILE__, __LINE__);
750746

751-
if (self->peer_cert)
752-
X509_free (self->peer_cert);
753-
PySSL_BEGIN_ALLOW_THREADS
754-
self->peer_cert = SSL_get_peer_certificate(self->ssl);
755-
PySSL_END_ALLOW_THREADS
756-
self->handshake_done = 1;
757-
758747
Py_RETURN_NONE;
759748

760749
error:
@@ -1506,25 +1495,30 @@ _ssl__SSLSocket_peer_certificate_impl(PySSLSocket *self, int binary_mode)
15061495
/*[clinic end generated code: output=f0dc3e4d1d818a1d input=8281bd1d193db843]*/
15071496
{
15081497
int verification;
1498+
X509 *peer_cert;
1499+
PyObject *result;
15091500

1510-
if (!self->handshake_done) {
1501+
if (!SSL_is_init_finished(self->ssl)) {
15111502
PyErr_SetString(PyExc_ValueError,
15121503
"handshake not done yet");
15131504
return NULL;
15141505
}
1515-
if (!self->peer_cert)
1506+
peer_cert = SSL_get_peer_certificate(self->ssl);
1507+
if (peer_cert == NULL)
15161508
Py_RETURN_NONE;
15171509

15181510
if (binary_mode) {
15191511
/* return cert in DER-encoded format */
1520-
return _certificate_to_der(self->peer_cert);
1512+
result = _certificate_to_der(peer_cert);
15211513
} else {
15221514
verification = SSL_CTX_get_verify_mode(SSL_get_SSL_CTX(self->ssl));
15231515
if ((verification & SSL_VERIFY_PEER) == 0)
1524-
return PyDict_New();
1516+
result = PyDict_New();
15251517
else
1526-
return _decode_certificate(self->peer_cert);
1518+
result = _decode_certificate(peer_cert);
15271519
}
1520+
X509_free(peer_cert);
1521+
return result;
15281522
}
15291523

15301524
static PyObject *
@@ -1845,8 +1839,6 @@ Passed as \"self\" in servername callback.");
18451839

18461840
static void PySSL_dealloc(PySSLSocket *self)
18471841
{
1848-
if (self->peer_cert) /* Possible not to have one? */
1849-
X509_free (self->peer_cert);
18501842
if (self->ssl)
18511843
SSL_free(self->ssl);
18521844
Py_XDECREF(self->Socket);
@@ -2442,7 +2434,7 @@ static int PySSL_set_session(PySSLSocket *self, PyObject *value,
24422434
"Cannot set session for server-side SSLSocket.");
24432435
return -1;
24442436
}
2445-
if (self->handshake_done) {
2437+
if (SSL_is_init_finished(self->ssl)) {
24462438
PyErr_SetString(PyExc_ValueError,
24472439
"Cannot set session after handshake.");
24482440
return -1;

0 commit comments

Comments
 (0)