Skip to main content

Modules/_ssl.c

Source:

cpython 3.14 @ ab2d84fe1023/Modules/_ssl.c

_ssl wraps OpenSSL (or LibreSSL) to provide TLS for ssl.SSLSocket and ssl.SSLContext. The Python ssl module (Lib/ssl.py) builds the high-level API on top.

Map

LinesSymbolRole
1-200ConstantsPROTOCOL_TLS_CLIENT, CERT_REQUIRED, OP_NO_SSLv2, etc.
201-600SSLContext typeWraps SSL_CTX * — ca certs, key/cert, options, verify mode
601-1000SSLContext_wrap_socketCreate SSLSocket from a regular socket + context
1001-1500SSLSocket typeWraps SSL * — per-connection state
1501-2000SSLSocket_do_handshakeTLS handshake (blocking or non-blocking)
2001-2500SSLSocket_read, SSLSocket_writeEncrypted read/write
2501-3000SSLSocket_getpeercertParse X.509 certificate into a dict
3001-3500SSLContext_load_cert_chainLoad key+cert from file
3501-4000SSLContext_load_verify_locationsCA bundle loading
4001-5000SNI and hostname checkingSSL_set_tlsext_host_name, match_hostname
5001-6000Error handling_setSSLError — translate OpenSSL errors to Python exceptions

Reading

SSLContext creation

// CPython: Modules/_ssl.c:280 _ssl__SSLContext_impl
static PyObject *
_ssl__SSLContext_impl(PyTypeObject *type, int proto_version)
{
SSL_CTX *ctx = SSL_CTX_new(TLS_method());
/* Set safe defaults */
SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);
SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL);
SSL_CTX_set_default_verify_paths(ctx);
...
}

ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT) also sets check_hostname=True and verify_mode=CERT_REQUIRED in the Python layer.

wrap_socket

// CPython: Modules/_ssl.c:780 _ssl__SSLObject_impl
static PyObject *
_ssl__SSLObject_impl(PyTypeObject *type, PyObject *ctx_arg,
PyObject *sock, int server_side,
PyObject *server_hostname)
{
SSL *ssl = SSL_new(((PySSLContext *)ctx_arg)->ctx);
SSL_set_fd(ssl, PyObject_AsFileDescriptor(sock));
if (server_hostname && !server_side)
SSL_set_tlsext_host_name(ssl, hostname_utf8);
...
}

Handshake

// CPython: Modules/_ssl.c:1180 _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(...);
Py_RETURN_NONE;
}

The handshake loop handles WANT_READ/WANT_WRITE for non-blocking sockets.

read / write

// CPython: Modules/_ssl.c:1620 _ssl__SSLObject_read_impl
static PyObject *
_ssl__SSLObject_read_impl(PySSLObject *self, int len, int group_right_1,
Py_buffer *buffer)
{
Py_BEGIN_ALLOW_THREADS
count = SSL_read(self->ssl, mem, len);
Py_END_ALLOW_THREADS
...
}

Certificate dict

// CPython: Modules/_ssl.c:2700 _decode_certificate
static PyObject *
_decode_certificate(PySSLObject *self)
{
X509 *certificate = SSL_get_peer_certificate(self->ssl);
/* Extract subject, issuer, notBefore, notAfter, subjectAltName */
PyObject *retval = PyDict_New();
PyDict_SetItemString(retval, "subject", parse_X509_name(X509_get_subject_name(certificate)));
PyDict_SetItemString(retval, "notAfter", _PySSL_GetNotAfter(certificate));
...
return retval;
}

ssl.SSLSocket.getpeercert() returns a dict with subject, issuer, notBefore, notAfter, subjectAltName (list of (tag, value) pairs).

gopy notes

ssl in gopy uses Go's crypto/tls package. SSLContext maps to tls.Config. wrap_socket returns an object wrapping tls.Conn. Handshake calls tls.Conn.Handshake(). Certificate parsing uses x509.Certificate fields mapped to the same Python dict structure. CERT_REQUIRED maps to tls.RequireAndVerifyClientCert on the server side and InsecureSkipVerify=false on the client side.