Skip to main content

Modules/_ssl.c (part 8)

Source:

cpython 3.14 @ ab2d84fe1023/Modules/_ssl.c

This annotation covers the TLS handshake and I/O. See modules_ssl7_detail for SSLContext.__init__, certificate loading, and hostname verification.

Map

LinesSymbolRole
1-80SSLContext.wrap_socketCreate an SSLSocket from a plain socket
81-180SSLSocket.do_handshakePerform the TLS handshake
181-280SSLSocket.readDecrypt and return data
281-380SSLSocket.writeEncrypt and send data
381-500Non-blocking I/OSSL_ERROR_WANT_READ / SSL_ERROR_WANT_WRITE handling

Reading

SSLContext.wrap_socket

// CPython: Modules/_ssl.c:3420 _ssl__SSLContext_wrap_socket_impl
static PyObject *
_ssl__SSLContext_wrap_socket_impl(PySSLContext *self, PyObject *sock,
int server_side, ...)
{
/* Create OpenSSL SSL object from the context */
SSL *ssl = SSL_new(self->ctx);
SSL_set_fd(ssl, PyObject_AsFileDescriptor(sock));
if (server_side)
SSL_set_accept_state(ssl);
else
SSL_set_connect_state(ssl);
return newPySSLSocket(self, sock, ssl, ...);
}

wrap_socket associates an OpenSSL SSL object with the underlying socket's file descriptor. server_side determines whether SSL_accept or SSL_connect is used during the handshake.

SSLSocket.do_handshake

// CPython: Modules/_ssl.c:1780 _ssl__SSLObject_do_handshake_impl
static PyObject *
_ssl__SSLObject_do_handshake_impl(PySSLObject *self)
{
int ret;
do {
Py_BEGIN_ALLOW_THREADS
ret = SSL_do_handshake(self->ssl);
Py_END_ALLOW_THREADS
err = SSL_get_error(self->ssl, ret);
} while (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE);
if (ret < 1) {
return _setSSLError(get_state_sock(self), NULL, 0, __FILE__, __LINE__);
}
Py_RETURN_NONE;
}

The handshake loop handles WANT_READ/WANT_WRITE for non-blocking sockets by retrying. The GIL is released during the OpenSSL call.

SSLSocket.read

// CPython: Modules/_ssl.c:1860 _ssl__SSLObject_read_impl
static PyObject *
_ssl__SSLObject_read_impl(PySSLObject *self, int len, int group_right_1,
Py_buffer *buffer)
{
int count;
Py_BEGIN_ALLOW_THREADS
count = SSL_read(self->ssl, mem, len);
Py_END_ALLOW_THREADS
err = SSL_get_error(self->ssl, count);
if (err == SSL_ERROR_ZERO_RETURN)
count = 0; /* clean shutdown */
else if (count < 0)
return _setSSLError(...);
return PyBytes_FromStringAndSize(mem, count);
}

SSL_read decrypts data from the OpenSSL buffer. SSL_ERROR_ZERO_RETURN indicates a clean TLS close_notify, which maps to an empty bytes return rather than an exception.

gopy notes

SSLContext.wrap_socket is module/ssl.ContextWrapSocket in module/ssl/module.go using Go's crypto/tls. do_handshake calls tls.Conn.Handshake(). read and write call tls.Conn.Read/Write. Non-blocking behavior is handled via Go's net.Conn timeout mechanism.