diff options
author | Christian Heimes <christian@python.org> | 2021-04-17 18:06:38 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-04-17 18:06:38 (GMT) |
commit | 7f1305ef9ea7234e1a5aacbea17490232e9b7dc2 (patch) | |
tree | b9aa4b5736f61444b4ea0897cfde12a50cf58a54 | |
parent | 76beadb8ff86eb2bb248bf918bfb20c4069932f4 (diff) | |
download | cpython-7f1305ef9ea7234e1a5aacbea17490232e9b7dc2.zip cpython-7f1305ef9ea7234e1a5aacbea17490232e9b7dc2.tar.gz cpython-7f1305ef9ea7234e1a5aacbea17490232e9b7dc2.tar.bz2 |
bpo-42333: Port _ssl extension to multiphase initialization (PEP 489) (GH-23253)
- Introduce sslmodule_slots
- Introduce sslmodulestate
- Use sslmodulestate
- Get rid of PyState_FindModule
- Move new structs and helpers to header file
- Use macros to access state
- Keep a strong ref to socket type
-rw-r--r-- | Misc/NEWS.d/next/Library/2021-04-17-19-31-17.bpo-42333.cgbtZO.rst | 1 | ||||
-rw-r--r-- | Modules/_ssl.c | 752 | ||||
-rw-r--r-- | Modules/_ssl.h | 45 | ||||
-rw-r--r-- | Modules/_ssl/debughelpers.c | 6 | ||||
-rw-r--r-- | Modules/clinic/_ssl.c.h | 20 | ||||
-rw-r--r-- | setup.py | 10 |
6 files changed, 468 insertions, 366 deletions
diff --git a/Misc/NEWS.d/next/Library/2021-04-17-19-31-17.bpo-42333.cgbtZO.rst b/Misc/NEWS.d/next/Library/2021-04-17-19-31-17.bpo-42333.cgbtZO.rst new file mode 100644 index 0000000..da2df1f --- /dev/null +++ b/Misc/NEWS.d/next/Library/2021-04-17-19-31-17.bpo-42333.cgbtZO.rst @@ -0,0 +1 @@ +Port ``_ssl`` extension module to multiphase initialization. diff --git a/Modules/_ssl.c b/Modules/_ssl.c index 92aabcb..376d3bb 100644 --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -25,6 +25,11 @@ #include "Python.h" +/* Include symbols from _socket module */ +#include "socketmodule.h" + +#include "_ssl.h" + /* Redefined below for Windows debug builds after important #includes */ #define _PySSL_FIX_ERRNO @@ -39,10 +44,6 @@ #define PySSL_UNBLOCK_THREADS PySSL_BEGIN_ALLOW_THREADS_S(_save); #define PySSL_END_ALLOW_THREADS PySSL_END_ALLOW_THREADS_S(_save); } -/* Include symbols from _socket module */ -#include "socketmodule.h" - -static PySocketModule_APIObject PySocketModule; #if defined(HAVE_POLL_H) #include <poll.h> @@ -66,24 +67,13 @@ static PySocketModule_APIObject PySocketModule; # error "OPENSSL_THREADS is not defined, Python requires thread-safe OpenSSL" #endif -/* SSL error object */ -static PyObject *PySSLErrorObject; -static PyObject *PySSLCertVerificationErrorObject; -static PyObject *PySSLZeroReturnErrorObject; -static PyObject *PySSLWantReadErrorObject; -static PyObject *PySSLWantWriteErrorObject; -static PyObject *PySSLSyscallErrorObject; -static PyObject *PySSLEOFErrorObject; -/* Error mappings */ -static PyObject *err_codes_to_names; -static PyObject *err_names_to_codes; -static PyObject *lib_codes_to_names; struct py_ssl_error_code { const char *mnemonic; int library, reason; }; + struct py_ssl_library_code { const char *library; int code; @@ -288,6 +278,8 @@ typedef struct { PyObject *msg_cb; PyObject *keylog_filename; BIO *keylog_bio; + /* Cached module state, also used in SSLSocket and SSLSession code. */ + _sslmodulestate *state; } PySSLContext; typedef struct { @@ -329,11 +321,6 @@ typedef struct { PySSLContext *ctx; } PySSLSession; -static PyTypeObject *PySSLContext_Type; -static PyTypeObject *PySSLSocket_Type; -static PyTypeObject *PySSLMemoryBIO_Type; -static PyTypeObject *PySSLSession_Type; - static inline _PySSLError _PySSL_errno(int failed, const SSL *ssl, int retcode) { _PySSLError err = { 0 }; @@ -350,12 +337,12 @@ static inline _PySSLError _PySSL_errno(int failed, const SSL *ssl, int retcode) /*[clinic input] module _ssl -class _ssl._SSLContext "PySSLContext *" "PySSLContext_Type" -class _ssl._SSLSocket "PySSLSocket *" "PySSLSocket_Type" -class _ssl.MemoryBIO "PySSLMemoryBIO *" "PySSLMemoryBIO_Type" -class _ssl.SSLSession "PySSLSession *" "PySSLSession_Type" +class _ssl._SSLContext "PySSLContext *" "get_state_type(type)->PySSLContext_Type" +class _ssl._SSLSocket "PySSLSocket *" "get_state_type(type)->PySSLSocket_Type" +class _ssl.MemoryBIO "PySSLMemoryBIO *" "get_state_type(type)->PySSLMemoryBIO_Type" +class _ssl.SSLSession "PySSLSession *" "get_state_type(type)->PySSLSession_Type" [clinic start generated code]*/ -/*[clinic end generated code: output=da39a3ee5e6b4b0d input=cc4883756da17954]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=d293bed8bae240fd]*/ #include "clinic/_ssl.c.h" @@ -363,9 +350,6 @@ static int PySSL_select(PySocketSockObject *s, int writing, _PyTime_t timeout); static int PySSL_set_owner(PySSLSocket *, PyObject *, void *); static int PySSL_set_session(PySSLSocket *, PyObject *, void *); -#define PySSLSocket_Check(v) Py_IS_TYPE(v, PySSLSocket_Type) -#define PySSLMemoryBIO_Check(v) Py_IS_TYPE(v, PySSLMemoryBIO_Type) -#define PySSLSession_Check(v) Py_IS_TYPE(v, PySSLSession_Type) typedef enum { SOCKET_IS_NONBLOCKING, @@ -443,7 +427,8 @@ static PyType_Spec sslerror_type_spec = { }; static void -fill_and_set_sslerror(PySSLSocket *sslsock, PyObject *type, int ssl_errno, +fill_and_set_sslerror(_sslmodulestate *state, + PySSLSocket *sslsock, PyObject *type, int ssl_errno, const char *errstr, int lineno, unsigned long errcode) { PyObject *err_value = NULL, *reason_obj = NULL, *lib_obj = NULL; @@ -462,7 +447,7 @@ fill_and_set_sslerror(PySSLSocket *sslsock, PyObject *type, int ssl_errno, key = Py_BuildValue("ii", lib, reason); if (key == NULL) goto fail; - reason_obj = PyDict_GetItemWithError(err_codes_to_names, key); + reason_obj = PyDict_GetItemWithError(state->err_codes_to_names, key); Py_DECREF(key); if (reason_obj == NULL && PyErr_Occurred()) { goto fail; @@ -470,7 +455,7 @@ fill_and_set_sslerror(PySSLSocket *sslsock, PyObject *type, int ssl_errno, key = PyLong_FromLong(lib); if (key == NULL) goto fail; - lib_obj = PyDict_GetItemWithError(lib_codes_to_names, key); + lib_obj = PyDict_GetItemWithError(state->lib_codes_to_names, key); Py_DECREF(key); if (lib_obj == NULL && PyErr_Occurred()) { goto fail; @@ -482,7 +467,7 @@ fill_and_set_sslerror(PySSLSocket *sslsock, PyObject *type, int ssl_errno, errstr = "unknown error"; /* verify code for cert validation error */ - if ((sslsock != NULL) && (type == PySSLCertVerificationErrorObject)) { + if ((sslsock != NULL) && (type == state->PySSLCertVerificationErrorObject)) { const char *verify_str = NULL; long verify_code; @@ -554,7 +539,7 @@ fill_and_set_sslerror(PySSLSocket *sslsock, PyObject *type, int ssl_errno, if (_PyObject_SetAttrId(err_value, &PyId_library, lib_obj)) goto fail; - if ((sslsock != NULL) && (type == PySSLCertVerificationErrorObject)) { + if ((sslsock != NULL) && (type == state->PySSLCertVerificationErrorObject)) { /* Only set verify code / message for SSLCertVerificationError */ if (_PyObject_SetAttrId(err_value, &PyId_verify_code, verify_code_obj)) @@ -585,12 +570,17 @@ PySSL_ChainExceptions(PySSLSocket *sslsock) { static PyObject * PySSL_SetError(PySSLSocket *sslsock, int ret, const char *filename, int lineno) { - PyObject *type = PySSLErrorObject; + PyObject *type; char *errstr = NULL; _PySSLError err; enum py_ssl_error p = PY_SSL_ERROR_NONE; unsigned long e = 0; + assert(sslsock != NULL); + + _sslmodulestate *state = get_state_sock(sslsock); + type = state->PySSLErrorObject; + assert(ret <= 0); e = ERR_peek_last_error(); @@ -600,17 +590,17 @@ PySSL_SetError(PySSLSocket *sslsock, int ret, const char *filename, int lineno) switch (err.ssl) { case SSL_ERROR_ZERO_RETURN: errstr = "TLS/SSL connection has been closed (EOF)"; - type = PySSLZeroReturnErrorObject; + type = state->PySSLZeroReturnErrorObject; p = PY_SSL_ERROR_ZERO_RETURN; break; case SSL_ERROR_WANT_READ: errstr = "The operation did not complete (read)"; - type = PySSLWantReadErrorObject; + type = state->PySSLWantReadErrorObject; p = PY_SSL_ERROR_WANT_READ; break; case SSL_ERROR_WANT_WRITE: p = PY_SSL_ERROR_WANT_WRITE; - type = PySSLWantWriteErrorObject; + type = state->PySSLWantWriteErrorObject; errstr = "The operation did not complete (write)"; break; case SSL_ERROR_WANT_X509_LOOKUP: @@ -627,7 +617,7 @@ PySSL_SetError(PySSLSocket *sslsock, int ret, const char *filename, int lineno) PySocketSockObject *s = GET_SOCKET(sslsock); if (ret == 0 || (((PyObject *)s) == Py_None)) { p = PY_SSL_ERROR_EOF; - type = PySSLEOFErrorObject; + type = state->PySSLEOFErrorObject; errstr = "EOF occurred in violation of protocol"; } else if (s && ret == -1) { /* underlying BIO reported an I/O error */ @@ -643,12 +633,12 @@ PySSL_SetError(PySSLSocket *sslsock, int ret, const char *filename, int lineno) } else { p = PY_SSL_ERROR_EOF; - type = PySSLEOFErrorObject; + type = state->PySSLEOFErrorObject; errstr = "EOF occurred in violation of protocol"; } } else { /* possible? */ p = PY_SSL_ERROR_SYSCALL; - type = PySSLSyscallErrorObject; + type = state->PySSLSyscallErrorObject; errstr = "Some I/O error occurred"; } } else { @@ -665,7 +655,7 @@ PySSL_SetError(PySSLSocket *sslsock, int ret, const char *filename, int lineno) } if (ERR_GET_LIB(e) == ERR_LIB_SSL && ERR_GET_REASON(e) == SSL_R_CERTIFICATE_VERIFY_FAILED) { - type = PySSLCertVerificationErrorObject; + type = state->PySSLCertVerificationErrorObject; } break; } @@ -674,20 +664,20 @@ PySSL_SetError(PySSLSocket *sslsock, int ret, const char *filename, int lineno) errstr = "Invalid error code"; } } - fill_and_set_sslerror(sslsock, type, p, errstr, lineno, e); + fill_and_set_sslerror(state, sslsock, type, p, errstr, lineno, e); ERR_clear_error(); PySSL_ChainExceptions(sslsock); return NULL; } static PyObject * -_setSSLError (const char *errstr, int errcode, const char *filename, int lineno) { - +_setSSLError (_sslmodulestate *state, const char *errstr, int errcode, const char *filename, int lineno) +{ if (errstr == NULL) errcode = ERR_peek_last_error(); else errcode = 0; - fill_and_set_sslerror(NULL, PySSLErrorObject, errcode, errstr, lineno, errcode); + fill_and_set_sslerror(state, NULL, state->PySSLErrorObject, errcode, errstr, lineno, errcode); ERR_clear_error(); return NULL; } @@ -734,7 +724,7 @@ _ssl_configure_hostname(PySSLSocket *self, const char* server_hostname) /* Only send SNI extension for non-IP hostnames */ if (ip == NULL) { if (!SSL_set_tlsext_host_name(self->ssl, server_hostname)) { - _setSSLError(NULL, 0, __FILE__, __LINE__); + _setSSLError(get_state_sock(self), NULL, 0, __FILE__, __LINE__); goto error; } } @@ -743,13 +733,13 @@ _ssl_configure_hostname(PySSLSocket *self, const char* server_hostname) if (ip == NULL) { if (!X509_VERIFY_PARAM_set1_host(param, server_hostname, strlen(server_hostname))) { - _setSSLError(NULL, 0, __FILE__, __LINE__); + _setSSLError(get_state_sock(self), NULL, 0, __FILE__, __LINE__); goto error; } } else { if (!X509_VERIFY_PARAM_set1_ip(param, ASN1_STRING_get0_data(ip), ASN1_STRING_length(ip))) { - _setSSLError(NULL, 0, __FILE__, __LINE__); + _setSSLError(get_state_sock(self), NULL, 0, __FILE__, __LINE__); goto error; } } @@ -773,7 +763,7 @@ newPySSLSocket(PySSLContext *sslctx, PySocketSockObject *sock, SSL_CTX *ctx = sslctx->ctx; _PySSLError err = { 0 }; - self = PyObject_New(PySSLSocket, PySSLSocket_Type); + self = PyObject_New(PySSLSocket, get_state_ctx(sslctx)->PySSLSocket_Type); if (self == NULL) return NULL; @@ -797,7 +787,7 @@ newPySSLSocket(PySSLContext *sslctx, PySocketSockObject *sock, PySSL_END_ALLOW_THREADS if (self->ssl == NULL) { Py_DECREF(self); - _setSSLError(NULL, 0, __FILE__, __LINE__); + _setSSLError(get_state_ctx(self), NULL, 0, __FILE__, __LINE__); return NULL; } /* bpo43522 and OpenSSL < 1.1.1l: copy hostflags manually */ @@ -902,7 +892,8 @@ _ssl__SSLSocket_do_handshake_impl(PySSLSocket *self) if (sock) { if (((PyObject*)sock) == Py_None) { - _setSSLError("Underlying socket connection gone", + _setSSLError(get_state_sock(self), + "Underlying socket connection gone", PY_SSL_ERROR_NO_SOCKET, __FILE__, __LINE__); return NULL; } @@ -947,11 +938,11 @@ _ssl__SSLSocket_do_handshake_impl(PySSLSocket *self) ERRSTR("The handshake operation timed out")); goto error; } else if (sockstate == SOCKET_HAS_BEEN_CLOSED) { - PyErr_SetString(PySSLErrorObject, + PyErr_SetString(get_state_sock(self)->PySSLErrorObject, ERRSTR("Underlying socket has been closed.")); goto error; } else if (sockstate == SOCKET_TOO_LARGE_FOR_SELECT) { - PyErr_SetString(PySSLErrorObject, + PyErr_SetString(get_state_sock(self)->PySSLErrorObject, ERRSTR("Underlying socket too large for select().")); goto error; } else if (sockstate == SOCKET_IS_NONBLOCKING) { @@ -972,7 +963,7 @@ error: } static PyObject * -_asn1obj2py(const ASN1_OBJECT *name, int no_name) +_asn1obj2py(_sslmodulestate *state, const ASN1_OBJECT *name, int no_name) { char buf[X509_NAME_MAXLEN]; char *namebuf = buf; @@ -981,7 +972,7 @@ _asn1obj2py(const ASN1_OBJECT *name, int no_name) buflen = OBJ_obj2txt(namebuf, X509_NAME_MAXLEN, name, no_name); if (buflen < 0) { - _setSSLError(NULL, 0, __FILE__, __LINE__); + _setSSLError(state, NULL, 0, __FILE__, __LINE__); return NULL; } /* initial buffer is too small for oid + terminating null byte */ @@ -996,7 +987,7 @@ _asn1obj2py(const ASN1_OBJECT *name, int no_name) } buflen = OBJ_obj2txt(namebuf, buflen + 1, name, no_name); if (buflen < 0) { - _setSSLError(NULL, 0, __FILE__, __LINE__); + _setSSLError(state, NULL, 0, __FILE__, __LINE__); goto done; } } @@ -1016,7 +1007,8 @@ _asn1obj2py(const ASN1_OBJECT *name, int no_name) } static PyObject * -_create_tuple_for_attribute(ASN1_OBJECT *name, ASN1_STRING *value) +_create_tuple_for_attribute(_sslmodulestate *state, + ASN1_OBJECT *name, ASN1_STRING *value) { Py_ssize_t buflen; unsigned char *valuebuf = NULL; @@ -1024,16 +1016,16 @@ _create_tuple_for_attribute(ASN1_OBJECT *name, ASN1_STRING *value) buflen = ASN1_STRING_to_UTF8(&valuebuf, value); if (buflen < 0) { - _setSSLError(NULL, 0, __FILE__, __LINE__); + _setSSLError(state, NULL, 0, __FILE__, __LINE__); return NULL; } - attr = Py_BuildValue("Ns#", _asn1obj2py(name, 0), valuebuf, buflen); + attr = Py_BuildValue("Ns#", _asn1obj2py(state, name, 0), valuebuf, buflen); OPENSSL_free(valuebuf); return attr; } static PyObject * -_create_tuple_for_X509_NAME (X509_NAME *xname) +_create_tuple_for_X509_NAME (_sslmodulestate *state, X509_NAME *xname) { PyObject *dn = NULL; /* tuple which represents the "distinguished name" */ PyObject *rdn = NULL; /* tuple to hold a "relative distinguished name" */ @@ -1085,7 +1077,7 @@ _create_tuple_for_X509_NAME (X509_NAME *xname) /* now add this attribute to the current RDN */ name = X509_NAME_ENTRY_get_object(entry); value = X509_NAME_ENTRY_get_data(entry); - attr = _create_tuple_for_attribute(name, value); + attr = _create_tuple_for_attribute(state, name, value); /* fprintf(stderr, "RDN level %d, attribute %s: %s\n", entry->set, @@ -1132,7 +1124,7 @@ _create_tuple_for_X509_NAME (X509_NAME *xname) } static PyObject * -_get_peer_alt_names (X509 *certificate) { +_get_peer_alt_names (_sslmodulestate *state, X509 *certificate) { /* this code follows the procedure outlined in OpenSSL's crypto/x509v3/v3_prn.c:X509v3_EXT_print() @@ -1156,7 +1148,7 @@ _get_peer_alt_names (X509 *certificate) { /* get a memory buffer */ biobuf = BIO_new(BIO_s_mem()); if (biobuf == NULL) { - PyErr_SetString(PySSLErrorObject, "failed to allocate BIO"); + PyErr_SetString(state->PySSLErrorObject, "failed to allocate BIO"); return NULL; } @@ -1193,7 +1185,7 @@ _get_peer_alt_names (X509 *certificate) { } PyTuple_SET_ITEM(t, 0, v); - v = _create_tuple_for_X509_NAME (name->d.dirn); + v = _create_tuple_for_X509_NAME(state, name->d.dirn); if (v == NULL) { Py_DECREF(t); goto fail; @@ -1252,7 +1244,7 @@ _get_peer_alt_names (X509 *certificate) { len = i2t_ASN1_OBJECT(buf, sizeof(buf)-1, name->d.rid); if (len < 0) { Py_DECREF(t); - _setSSLError(NULL, 0, __FILE__, __LINE__); + _setSSLError(state, NULL, 0, __FILE__, __LINE__); goto fail; } else if (len >= (int)sizeof(buf)) { v = PyUnicode_FromString("<INVALID>"); @@ -1335,7 +1327,7 @@ _get_peer_alt_names (X509 *certificate) { GENERAL_NAME_print(biobuf, name); len = BIO_gets(biobuf, buf, sizeof(buf)-1); if (len < 0) { - _setSSLError(NULL, 0, __FILE__, __LINE__); + _setSSLError(state, NULL, 0, __FILE__, __LINE__); goto fail; } vptr = strchr(buf, ':'); @@ -1511,7 +1503,7 @@ _get_crl_dp(X509 *certificate) { } static PyObject * -_decode_certificate(X509 *certificate) { +_decode_certificate(_sslmodulestate *state, X509 *certificate) { PyObject *retval = NULL; BIO *biobuf = NULL; @@ -1532,6 +1524,7 @@ _decode_certificate(X509 *certificate) { return NULL; peer = _create_tuple_for_X509_NAME( + state, X509_get_subject_name(certificate)); if (peer == NULL) goto fail0; @@ -1542,6 +1535,7 @@ _decode_certificate(X509 *certificate) { Py_DECREF(peer); issuer = _create_tuple_for_X509_NAME( + state, X509_get_issuer_name(certificate)); if (issuer == NULL) goto fail0; @@ -1563,7 +1557,7 @@ _decode_certificate(X509 *certificate) { /* get a memory buffer */ biobuf = BIO_new(BIO_s_mem()); if (biobuf == NULL) { - PyErr_SetString(PySSLErrorObject, "failed to allocate BIO"); + PyErr_SetString(state->PySSLErrorObject, "failed to allocate BIO"); goto fail0; } @@ -1573,7 +1567,7 @@ _decode_certificate(X509 *certificate) { i2a_ASN1_INTEGER(biobuf, serialNumber); len = BIO_gets(biobuf, buf, sizeof(buf)-1); if (len < 0) { - _setSSLError(NULL, 0, __FILE__, __LINE__); + _setSSLError(state, NULL, 0, __FILE__, __LINE__); goto fail1; } sn_obj = PyUnicode_FromStringAndSize(buf, len); @@ -1590,7 +1584,7 @@ _decode_certificate(X509 *certificate) { ASN1_TIME_print(biobuf, notBefore); len = BIO_gets(biobuf, buf, sizeof(buf)-1); if (len < 0) { - _setSSLError(NULL, 0, __FILE__, __LINE__); + _setSSLError(state, NULL, 0, __FILE__, __LINE__); goto fail1; } pnotBefore = PyUnicode_FromStringAndSize(buf, len); @@ -1607,7 +1601,7 @@ _decode_certificate(X509 *certificate) { ASN1_TIME_print(biobuf, notAfter); len = BIO_gets(biobuf, buf, sizeof(buf)-1); if (len < 0) { - _setSSLError(NULL, 0, __FILE__, __LINE__); + _setSSLError(state, NULL, 0, __FILE__, __LINE__); goto fail1; } pnotAfter = PyUnicode_FromStringAndSize(buf, len); @@ -1621,7 +1615,7 @@ _decode_certificate(X509 *certificate) { /* Now look for subjectAltName */ - peer_alt_names = _get_peer_alt_names(certificate); + peer_alt_names = _get_peer_alt_names(state, certificate); if (peer_alt_names == NULL) goto fail1; else if (peer_alt_names != Py_None) { @@ -1680,7 +1674,7 @@ _decode_certificate(X509 *certificate) { } static PyObject * -_certificate_to_der(X509 *certificate) +_certificate_to_der(_sslmodulestate *state, X509 *certificate) { unsigned char *bytes_buf = NULL; int len; @@ -1689,7 +1683,7 @@ _certificate_to_der(X509 *certificate) bytes_buf = NULL; len = i2d_X509(certificate, &bytes_buf); if (len < 0) { - _setSSLError(NULL, 0, __FILE__, __LINE__); + _setSSLError(state, NULL, 0, __FILE__, __LINE__); return NULL; } /* this is actually an immutable bytes sequence */ @@ -1712,27 +1706,28 @@ _ssl__test_decode_cert_impl(PyObject *module, PyObject *path) PyObject *retval = NULL; X509 *x=NULL; BIO *cert; + _sslmodulestate *state = get_ssl_state(module); if ((cert=BIO_new(BIO_s_file())) == NULL) { - PyErr_SetString(PySSLErrorObject, + PyErr_SetString(state->PySSLErrorObject, "Can't malloc memory to read file"); goto fail0; } if (BIO_read_filename(cert, PyBytes_AsString(path)) <= 0) { - PyErr_SetString(PySSLErrorObject, + PyErr_SetString(state->PySSLErrorObject, "Can't open file"); goto fail0; } x = PEM_read_bio_X509(cert, NULL, NULL, NULL); if (x == NULL) { - PyErr_SetString(PySSLErrorObject, + PyErr_SetString(state->PySSLErrorObject, "Error decoding PEM-encoded file"); goto fail0; } - retval = _decode_certificate(x); + retval = _decode_certificate(state, x); X509_free(x); fail0: @@ -1777,13 +1772,13 @@ _ssl__SSLSocket_getpeercert_impl(PySSLSocket *self, int binary_mode) if (binary_mode) { /* return cert in DER-encoded format */ - result = _certificate_to_der(peer_cert); + result = _certificate_to_der(get_state_sock(self), peer_cert); } else { verification = SSL_CTX_get_verify_mode(SSL_get_SSL_CTX(self->ssl)); if ((verification & SSL_VERIFY_PEER) == 0) result = PyDict_New(); else - result = _decode_certificate(peer_cert); + result = _decode_certificate(get_state_sock(self), peer_cert); } X509_free(peer_cert); return result; @@ -2002,7 +1997,7 @@ static PySSLContext *PySSL_get_context(PySSLSocket *self, void *closure) { static int PySSL_set_context(PySSLSocket *self, PyObject *value, void *closure) { - if (PyObject_TypeCheck(value, PySSLContext_Type)) { + if (PyObject_TypeCheck(value, self->ctx->state->PySSLContext_Type)) { Py_INCREF(value); Py_SETREF(self->ctx, (PySSLContext *)value); SSL_set_SSL_CTX(self->ssl, self->ctx->ctx); @@ -2201,7 +2196,8 @@ _ssl__SSLSocket_write_impl(PySSLSocket *self, Py_buffer *b) if (sock != NULL) { if (((PyObject*)sock) == Py_None) { - _setSSLError("Underlying socket connection gone", + _setSSLError(get_state_sock(self), + "Underlying socket connection gone", PY_SSL_ERROR_NO_SOCKET, __FILE__, __LINE__); return NULL; } @@ -2232,11 +2228,11 @@ _ssl__SSLSocket_write_impl(PySSLSocket *self, Py_buffer *b) "The write operation timed out"); goto error; } else if (sockstate == SOCKET_HAS_BEEN_CLOSED) { - PyErr_SetString(PySSLErrorObject, + PyErr_SetString(get_state_sock(self)->PySSLErrorObject, "Underlying socket has been closed."); goto error; } else if (sockstate == SOCKET_TOO_LARGE_FOR_SELECT) { - PyErr_SetString(PySSLErrorObject, + PyErr_SetString(get_state_sock(self)->PySSLErrorObject, "Underlying socket too large for select()."); goto error; } @@ -2267,7 +2263,7 @@ _ssl__SSLSocket_write_impl(PySSLSocket *self, Py_buffer *b) "The write operation timed out"); goto error; } else if (sockstate == SOCKET_HAS_BEEN_CLOSED) { - PyErr_SetString(PySSLErrorObject, + PyErr_SetString(get_state_sock(self)->PySSLErrorObject, "Underlying socket has been closed."); goto error; } else if (sockstate == SOCKET_IS_NONBLOCKING) { @@ -2346,7 +2342,8 @@ _ssl__SSLSocket_read_impl(PySSLSocket *self, int len, int group_right_1, if (sock != NULL) { if (((PyObject*)sock) == Py_None) { - _setSSLError("Underlying socket connection gone", + _setSSLError(get_state_sock(self), + "Underlying socket connection gone", PY_SSL_ERROR_NO_SOCKET, __FILE__, __LINE__); return NULL; } @@ -2472,7 +2469,8 @@ _ssl__SSLSocket_shutdown_impl(PySSLSocket *self) if (sock != NULL) { /* Guard against closed socket */ if ((((PyObject*)sock) == Py_None) || (sock->sock_fd == INVALID_SOCKET)) { - _setSSLError("Underlying socket connection gone", + _setSSLError(get_state_sock(self), + "Underlying socket connection gone", PY_SSL_ERROR_NO_SOCKET, __FILE__, __LINE__); return NULL; } @@ -2541,7 +2539,7 @@ _ssl__SSLSocket_shutdown_impl(PySSLSocket *self) goto error; } else if (sockstate == SOCKET_TOO_LARGE_FOR_SELECT) { - PyErr_SetString(PySSLErrorObject, + PyErr_SetString(get_state_sock(self)->PySSLErrorObject, "Underlying socket too large for select()."); goto error; } @@ -2626,7 +2624,7 @@ _ssl__SSLSocket_verify_client_post_handshake_impl(PySSLSocket *self) #ifdef TLS1_3_VERSION int err = SSL_verify_client_post_handshake(self->ssl); if (err == 0) - return _setSSLError(NULL, 0, __FILE__, __LINE__); + return _setSSLError(get_state_sock(self), NULL, 0, __FILE__, __LINE__); else Py_RETURN_NONE; #else @@ -2698,7 +2696,7 @@ PySSL_get_session(PySSLSocket *self, void *closure) { if (session == NULL) { Py_RETURN_NONE; } - pysess = PyObject_GC_New(PySSLSession, PySSLSession_Type); + pysess = PyObject_GC_New(PySSLSession, self->ctx->state->PySSLSession_Type); if (pysess == NULL) { SSL_SESSION_free(session); return NULL; @@ -2719,7 +2717,7 @@ static int PySSL_set_session(PySSLSocket *self, PyObject *value, SSL_SESSION *session; int result; - if (!PySSLSession_Check(value)) { + if (!Py_IS_TYPE(value, get_state_sock(self)->PySSLSession_Type)) { PyErr_SetString(PyExc_TypeError, "Value is not a SSLSession."); return -1; } @@ -2748,7 +2746,7 @@ static int PySSL_set_session(PySSLSocket *self, PyObject *value, /* free duplicate, SSL_set_session() bumps ref count */ SSL_SESSION_free(session); if (result == 0) { - _setSSLError(NULL, 0, __FILE__, __LINE__); + _setSSLError(get_state_sock(self), NULL, 0, __FILE__, __LINE__); return -1; } return 0; @@ -2821,7 +2819,6 @@ static PyType_Spec PySSLSocket_spec = { PySSLSocket_slots, }; - /* * _SSLContext objects */ @@ -2874,6 +2871,15 @@ _ssl__SSLContext_impl(PyTypeObject *type, int proto_version) X509_VERIFY_PARAM *params; int result; + /* slower approach, walk MRO and get borrowed reference to module. + * _PyType_GetModuleByDef is required for SSLContext subclasses */ + PyObject *module = _PyType_GetModuleByDef(type, &_sslmodule_def); + if (module == NULL) { + PyErr_SetString(PyExc_RuntimeError, + "Cannot find internal module state"); + return NULL; + } + PySSL_BEGIN_ALLOW_THREADS switch(proto_version) { #if defined(SSL3_VERSION) && !defined(OPENSSL_NO_SSL3) @@ -2923,7 +2929,7 @@ _ssl__SSLContext_impl(PyTypeObject *type, int proto_version) return NULL; } if (ctx == NULL) { - _setSSLError(NULL, 0, __FILE__, __LINE__); + _setSSLError(get_ssl_state(module), NULL, 0, __FILE__, __LINE__); return NULL; } @@ -2941,6 +2947,8 @@ _ssl__SSLContext_impl(PyTypeObject *type, int proto_version) self->keylog_bio = NULL; self->alpn_protocols = NULL; self->set_sni_cb = NULL; + self->state = get_ssl_state(module); + /* Don't check host name by default */ if (proto_version == PY_SSL_VERSION_TLS_CLIENT) { self->check_hostname = 1; @@ -2997,7 +3005,7 @@ _ssl__SSLContext_impl(PyTypeObject *type, int proto_version) if (result == 0) { Py_DECREF(self); ERR_clear_error(); - PyErr_SetString(PySSLErrorObject, + PyErr_SetString(get_state_ctx(self)->PySSLErrorObject, "No cipher can be selected."); return NULL; } @@ -3077,7 +3085,7 @@ _ssl__SSLContext_set_ciphers_impl(PySSLContext *self, const char *cipherlist) otherwise the error will be reported again when another SSL call is done. */ ERR_clear_error(); - PyErr_SetString(PySSLErrorObject, + PyErr_SetString(get_state_ctx(self)->PySSLErrorObject, "No cipher can be selected."); return NULL; } @@ -3100,7 +3108,7 @@ _ssl__SSLContext_get_ciphers_impl(PySSLContext *self) ssl = SSL_new(self->ctx); if (ssl == NULL) { - _setSSLError(NULL, 0, __FILE__, __LINE__); + _setSSLError(get_state_ctx(self), NULL, 0, __FILE__, __LINE__); goto exit; } sk = SSL_get_ciphers(ssl); @@ -3209,7 +3217,7 @@ get_verify_mode(PySSLContext *self, void *c) case SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT: return PyLong_FromLong(PY_SSL_CERT_REQUIRED); } - PyErr_SetString(PySSLErrorObject, + PyErr_SetString(get_state_ctx(self)->PySSLErrorObject, "invalid return value from SSL_CTX_get_verify_mode"); return NULL; } @@ -3254,13 +3262,13 @@ set_verify_flags(PySSLContext *self, PyObject *arg, void *c) set = ~flags & new_flags; if (clear) { if (!X509_VERIFY_PARAM_clear_flags(param, clear)) { - _setSSLError(NULL, 0, __FILE__, __LINE__); + _setSSLError(get_state_ctx(self), NULL, 0, __FILE__, __LINE__); return -1; } } if (set) { if (!X509_VERIFY_PARAM_set_flags(param, set)) { - _setSSLError(NULL, 0, __FILE__, __LINE__); + _setSSLError(get_state_ctx(self), NULL, 0, __FILE__, __LINE__); return -1; } } @@ -3675,7 +3683,7 @@ _ssl__SSLContext_load_cert_chain_impl(PySSLContext *self, PyObject *certfile, PyErr_SetFromErrno(PyExc_OSError); } else { - _setSSLError(NULL, 0, __FILE__, __LINE__); + _setSSLError(get_state_ctx(self), NULL, 0, __FILE__, __LINE__); } goto error; } @@ -3696,7 +3704,7 @@ _ssl__SSLContext_load_cert_chain_impl(PySSLContext *self, PyObject *certfile, PyErr_SetFromErrno(PyExc_OSError); } else { - _setSSLError(NULL, 0, __FILE__, __LINE__); + _setSSLError(get_state_ctx(self), NULL, 0, __FILE__, __LINE__); } goto error; } @@ -3704,7 +3712,7 @@ _ssl__SSLContext_load_cert_chain_impl(PySSLContext *self, PyObject *certfile, r = SSL_CTX_check_private_key(self->ctx); PySSL_END_ALLOW_THREADS_S(pw_info.thread_state); if (r != 1) { - _setSSLError(NULL, 0, __FILE__, __LINE__); + _setSSLError(get_state_ctx(self), NULL, 0, __FILE__, __LINE__); goto error; } SSL_CTX_set_default_passwd_cb(self->ctx, orig_passwd_cb); @@ -3745,7 +3753,7 @@ _add_ca_certs(PySSLContext *self, const void *data, Py_ssize_t len, biobuf = BIO_new_mem_buf(data, (int)len); if (biobuf == NULL) { - _setSSLError("Can't allocate buffer", 0, __FILE__, __LINE__); + _setSSLError(get_state_ctx(self), "Can't allocate buffer", 0, __FILE__, __LINE__); return -1; } @@ -3798,7 +3806,7 @@ _add_ca_certs(PySSLContext *self, const void *data, Py_ssize_t len, ERR_clear_error(); retval = 0; } else { - _setSSLError(NULL, 0, __FILE__, __LINE__); + _setSSLError(get_state_ctx(self), NULL, 0, __FILE__, __LINE__); retval = -1; } @@ -3915,7 +3923,7 @@ _ssl__SSLContext_load_verify_locations_impl(PySSLContext *self, PyErr_SetFromErrno(PyExc_OSError); } else { - _setSSLError(NULL, 0, __FILE__, __LINE__); + _setSSLError(get_state_ctx(self), NULL, 0, __FILE__, __LINE__); } goto error; } @@ -3963,13 +3971,13 @@ _ssl__SSLContext_load_dh_params(PySSLContext *self, PyObject *filepath) PyErr_SetFromErrnoWithFilenameObject(PyExc_OSError, filepath); } else { - _setSSLError(NULL, 0, __FILE__, __LINE__); + _setSSLError(get_state_ctx(self), NULL, 0, __FILE__, __LINE__); } return NULL; } if (!SSL_CTX_set_tmp_dh(self->ctx, dh)) { DH_free(dh); - return _setSSLError(NULL, 0, __FILE__, __LINE__); + return _setSSLError(get_state_ctx(self), NULL, 0, __FILE__, __LINE__); } DH_free(dh); Py_RETURN_NONE; @@ -3977,7 +3985,7 @@ _ssl__SSLContext_load_dh_params(PySSLContext *self, PyObject *filepath) /*[clinic input] _ssl._SSLContext._wrap_socket - sock: object(subclass_of="PySocketModule.Sock_Type") + sock: object(subclass_of="get_state_ctx(self)->Sock_Type") server_side: int server_hostname as hostname_obj: object = None * @@ -3990,7 +3998,7 @@ static PyObject * _ssl__SSLContext__wrap_socket_impl(PySSLContext *self, PyObject *sock, int server_side, PyObject *hostname_obj, PyObject *owner, PyObject *session) -/*[clinic end generated code: output=f103f238633940b4 input=957d5006183d1894]*/ +/*[clinic end generated code: output=f103f238633940b4 input=f5916eadbc6eae81]*/ { char *hostname = NULL; PyObject *res; @@ -4013,8 +4021,8 @@ _ssl__SSLContext__wrap_socket_impl(PySSLContext *self, PyObject *sock, /*[clinic input] _ssl._SSLContext._wrap_bio - incoming: object(subclass_of="PySSLMemoryBIO_Type", type="PySSLMemoryBIO *") - outgoing: object(subclass_of="PySSLMemoryBIO_Type", type="PySSLMemoryBIO *") + incoming: object(subclass_of="get_state_ctx(self)->PySSLMemoryBIO_Type", type="PySSLMemoryBIO *") + outgoing: object(subclass_of="get_state_ctx(self)->PySSLMemoryBIO_Type", type="PySSLMemoryBIO *") server_side: int server_hostname as hostname_obj: object = None * @@ -4028,7 +4036,7 @@ _ssl__SSLContext__wrap_bio_impl(PySSLContext *self, PySSLMemoryBIO *incoming, PySSLMemoryBIO *outgoing, int server_side, PyObject *hostname_obj, PyObject *owner, PyObject *session) -/*[clinic end generated code: output=5c5d6d9b41f99332 input=63867b8f3e1a1aa3]*/ +/*[clinic end generated code: output=5c5d6d9b41f99332 input=331edeec9c738382]*/ { char *hostname = NULL; PyObject *res; @@ -4101,7 +4109,7 @@ _ssl__SSLContext_set_default_verify_paths_impl(PySSLContext *self) /*[clinic end generated code: output=0bee74e6e09deaaa input=35f3408021463d74]*/ { if (!SSL_CTX_set_default_verify_paths(self->ctx)) { - _setSSLError(NULL, 0, __FILE__, __LINE__); + _setSSLError(get_state_ctx(self), NULL, 0, __FILE__, __LINE__); return NULL; } Py_RETURN_NONE; @@ -4134,7 +4142,7 @@ _ssl__SSLContext_set_ecdh_curve(PySSLContext *self, PyObject *name) } key = EC_KEY_new_by_curve_name(nid); if (key == NULL) { - _setSSLError(NULL, 0, __FILE__, __LINE__); + _setSSLError(get_state_ctx(self), NULL, 0, __FILE__, __LINE__); return NULL; } SSL_CTX_set_tmp_ecdh(self->ctx, key); @@ -4146,7 +4154,7 @@ static int _servername_callback(SSL *s, int *al, void *args) { int ret; - PySSLContext *ssl_ctx = (PySSLContext *) args; + PySSLContext *sslctx = (PySSLContext *) args; PySSLSocket *ssl; PyObject *result; /* The high-level ssl.SSLSocket object */ @@ -4154,7 +4162,7 @@ _servername_callback(SSL *s, int *al, void *args) const char *servername = SSL_get_servername(s, TLSEXT_NAMETYPE_host_name); PyGILState_STATE gstate = PyGILState_Ensure(); - if (ssl_ctx->set_sni_cb == NULL) { + if (sslctx->set_sni_cb == NULL) { /* remove race condition in this the call back while if removing the * callback is in progress */ PyGILState_Release(gstate); @@ -4162,7 +4170,7 @@ _servername_callback(SSL *s, int *al, void *args) } ssl = SSL_get_app_data(s); - assert(PySSLSocket_Check(ssl)); + assert(Py_IS_TYPE(ssl, get_state_ctx(sslctx)->PySSLSocket_Type)); /* The servername callback expects an argument that represents the current * SSL connection and that has a .context attribute that can be changed to @@ -4184,8 +4192,8 @@ _servername_callback(SSL *s, int *al, void *args) goto error; if (servername == NULL) { - result = PyObject_CallFunctionObjArgs(ssl_ctx->set_sni_cb, ssl_socket, - Py_None, ssl_ctx, NULL); + result = PyObject_CallFunctionObjArgs(sslctx->set_sni_cb, ssl_socket, + Py_None, sslctx, NULL); } else { PyObject *servername_bytes; @@ -4193,7 +4201,7 @@ _servername_callback(SSL *s, int *al, void *args) servername_bytes = PyBytes_FromString(servername); if (servername_bytes == NULL) { - PyErr_WriteUnraisable((PyObject *) ssl_ctx); + PyErr_WriteUnraisable((PyObject *) sslctx); goto error; } /* server_hostname was encoded to an A-label by our caller; put it @@ -4207,14 +4215,14 @@ _servername_callback(SSL *s, int *al, void *args) } Py_DECREF(servername_bytes); result = PyObject_CallFunctionObjArgs( - ssl_ctx->set_sni_cb, ssl_socket, servername_str, - ssl_ctx, NULL); + sslctx->set_sni_cb, ssl_socket, servername_str, + sslctx, NULL); Py_DECREF(servername_str); } Py_DECREF(ssl_socket); if (result == NULL) { - PyErr_WriteUnraisable(ssl_ctx->set_sni_cb); + PyErr_WriteUnraisable(sslctx->set_sni_cb); *al = SSL_AD_HANDSHAKE_FAILURE; ret = SSL_TLSEXT_ERR_ALERT_FATAL; } @@ -4380,9 +4388,9 @@ _ssl__SSLContext_get_ca_certs_impl(PySSLContext *self, int binary_form) continue; } if (binary_form) { - ci = _certificate_to_der(cert); + ci = _certificate_to_der(get_state_ctx(self), cert); } else { - ci = _decode_certificate(cert); + ci = _decode_certificate(get_state_ctx(self), cert); } if (ci == NULL) { goto error; @@ -4495,8 +4503,7 @@ _ssl_MemoryBIO_impl(PyTypeObject *type) bio = BIO_new(BIO_s_mem()); if (bio == NULL) { - PyErr_SetString(PySSLErrorObject, - "failed to allocate BIO"); + PyErr_SetString(PyExc_MemoryError, "failed to allocate BIO"); return NULL; } /* Since our BIO is non-blocking an empty read() does not indicate EOF, @@ -4575,8 +4582,9 @@ _ssl_MemoryBIO_read_impl(PySSLMemoryBIO *self, int len) nbytes = BIO_read(self->bio, PyBytes_AS_STRING(result), len); if (nbytes < 0) { + _sslmodulestate *state = get_state_mbio(self); Py_DECREF(result); - _setSSLError(NULL, 0, __FILE__, __LINE__); + _setSSLError(state, NULL, 0, __FILE__, __LINE__); return NULL; } @@ -4611,14 +4619,18 @@ _ssl_MemoryBIO_write_impl(PySSLMemoryBIO *self, Py_buffer *b) } if (self->eof_written) { - PyErr_SetString(PySSLErrorObject, + PyObject *module = PyType_GetModule(Py_TYPE(self)); + if (module == NULL) + return NULL; + PyErr_SetString(get_ssl_state(module)->PySSLErrorObject, "cannot write() after write_eof()"); return NULL; } nbytes = BIO_write(self->bio, b->buf, (int)b->len); if (nbytes < 0) { - _setSSLError(NULL, 0, __FILE__, __LINE__); + _sslmodulestate *state = get_state_mbio(self); + _setSSLError(state, NULL, 0, __FILE__, __LINE__); return NULL; } @@ -4699,13 +4711,14 @@ static PyObject * PySSLSession_richcompare(PyObject *left, PyObject *right, int op) { int result; + PyTypeObject *sesstype = ((PySSLSession*)left)->ctx->state->PySSLSession_Type; if (left == NULL || right == NULL) { PyErr_BadInternalCall(); return NULL; } - if (!PySSLSession_Check(left) || !PySSLSession_Check(right)) { + if (!Py_IS_TYPE(left, sesstype) || !Py_IS_TYPE(right, sesstype)) { Py_RETURN_NOTIMPLEMENTED; } @@ -4884,7 +4897,7 @@ _ssl_RAND_add_impl(PyObject *module, Py_buffer *view, double entropy) } static PyObject * -PySSL_RAND(int len, int pseudo) +PySSL_RAND(PyObject *module, int len, int pseudo) { int ok; PyObject *bytes; @@ -4916,7 +4929,7 @@ PySSL_RAND(int len, int pseudo) errstr = ERR_reason_error_string(err); v = Py_BuildValue("(ks)", err, errstr); if (v != NULL) { - PyErr_SetObject(PySSLErrorObject, v); + PyErr_SetObject(get_ssl_state(module)->PySSLErrorObject, v); Py_DECREF(v); } return NULL; @@ -4934,7 +4947,7 @@ static PyObject * _ssl_RAND_bytes_impl(PyObject *module, int n) /*[clinic end generated code: output=977da635e4838bc7 input=678ddf2872dfebfc]*/ { - return PySSL_RAND(n, 0); + return PySSL_RAND(module, n, 0); } /*[clinic input] @@ -4952,7 +4965,7 @@ static PyObject * _ssl_RAND_pseudo_bytes_impl(PyObject *module, int n) /*[clinic end generated code: output=b1509e937000e52d input=58312bd53f9bbdd0]*/ { - return PySSL_RAND(n, 1); + return PySSL_RAND(module, n, 1); } /*[clinic input] @@ -5014,7 +5027,7 @@ _ssl_get_default_verify_paths_impl(PyObject *module) } static PyObject* -asn1obj2py(ASN1_OBJECT *obj) +asn1obj2py(_sslmodulestate *state, ASN1_OBJECT *obj) { int nid; const char *ln, *sn; @@ -5026,7 +5039,7 @@ asn1obj2py(ASN1_OBJECT *obj) } sn = OBJ_nid2sn(nid); ln = OBJ_nid2ln(nid); - return Py_BuildValue("issN", nid, sn, ln, _asn1obj2py(obj, 1)); + return Py_BuildValue("issN", nid, sn, ln, _asn1obj2py(state, obj, 1)); } /*[clinic input] @@ -5052,7 +5065,7 @@ _ssl_txt2obj_impl(PyObject *module, const char *txt, int name) PyErr_Format(PyExc_ValueError, "unknown object '%.100s'", txt); return NULL; } - result = asn1obj2py(obj); + result = asn1obj2py(get_ssl_state(module), obj); ASN1_OBJECT_free(obj); return result; } @@ -5081,7 +5094,7 @@ _ssl_nid2obj_impl(PyObject *module, int nid) PyErr_Format(PyExc_ValueError, "unknown NID %i", nid); return NULL; } - result = asn1obj2py(obj); + result = asn1obj2py(get_ssl_state(module), obj); ASN1_OBJECT_free(obj); return result; } @@ -5423,72 +5436,39 @@ static PyMethodDef PySSL_methods[] = { }; -static int -sslmodule_init_types(PyObject *module) -{ - PySSLContext_Type = (PyTypeObject *)PyType_FromModuleAndSpec( - module, &PySSLContext_spec, NULL - ); - if (PySSLContext_Type == NULL) - return -1; - - PySSLSocket_Type = (PyTypeObject *)PyType_FromModuleAndSpec( - module, &PySSLSocket_spec, NULL - ); - if (PySSLSocket_Type == NULL) - return -1; - - PySSLMemoryBIO_Type = (PyTypeObject *)PyType_FromModuleAndSpec( - module, &PySSLMemoryBIO_spec, NULL - ); - if (PySSLMemoryBIO_Type == NULL) - return -1; - - PySSLSession_Type = (PyTypeObject *)PyType_FromModuleAndSpec( - module, &PySSLSession_spec, NULL - ); - if (PySSLSession_Type == NULL) - return -1; - - if (PyModule_AddType(module, PySSLContext_Type)) - return -1; - if (PyModule_AddType(module, PySSLSocket_Type)) - return -1; - if (PyModule_AddType(module, PySSLMemoryBIO_Type)) - return -1; - if (PyModule_AddType(module, PySSLSession_Type)) - return -1; - - return 0; -} +PyDoc_STRVAR(module_doc, +"Implementation module for SSL socket operations. See the socket module\n\ +for documentation."); static int sslmodule_init_exceptions(PyObject *module) { + _sslmodulestate *state = get_ssl_state(module); PyObject *bases = NULL; -#define add_exception(exc, name, doc, base) \ -do { \ - (exc) = PyErr_NewExceptionWithDoc("ssl." name, (doc), (base), NULL); \ - if ((exc) == NULL) goto error; \ - if (PyModule_AddObjectRef(module, name, exc) < 0) goto error; \ +#define add_exception(exc, name, doc, base) \ +do { \ + (exc) = PyErr_NewExceptionWithDoc("ssl." name, (doc), (base), NULL); \ + if ((state) == NULL) goto error; \ + if (PyModule_AddObjectRef(module, name, exc) < 0) goto error; \ } while(0) - PySSLErrorObject = PyType_FromSpecWithBases(&sslerror_type_spec, PyExc_OSError); - if (PySSLErrorObject == NULL) { + state->PySSLErrorObject = PyType_FromSpecWithBases( + &sslerror_type_spec, PyExc_OSError); + if (state->PySSLErrorObject == NULL) { goto error; } - if (PyModule_AddObjectRef(module, "SSLError", PySSLErrorObject) < 0) { + if (PyModule_AddObjectRef(module, "SSLError", state->PySSLErrorObject) < 0) { goto error; } /* ssl.CertificateError used to be a subclass of ValueError */ - bases = PyTuple_Pack(2, PySSLErrorObject, PyExc_ValueError); + bases = PyTuple_Pack(2, state->PySSLErrorObject, PyExc_ValueError); if (bases == NULL) { goto error; } add_exception( - PySSLCertVerificationErrorObject, + state->PySSLCertVerificationErrorObject, "SSLCertVerificationError", SSLCertVerificationError_doc, bases @@ -5496,38 +5476,38 @@ do { \ Py_CLEAR(bases); add_exception( - PySSLZeroReturnErrorObject, + state->PySSLZeroReturnErrorObject, "SSLZeroReturnError", SSLZeroReturnError_doc, - PySSLErrorObject + state->PySSLErrorObject ); add_exception( - PySSLWantWriteErrorObject, + state->PySSLWantWriteErrorObject, "SSLWantWriteError", SSLWantWriteError_doc, - PySSLErrorObject + state->PySSLErrorObject ); add_exception( - PySSLWantReadErrorObject, + state->PySSLWantReadErrorObject, "SSLWantReadError", SSLWantReadError_doc, - PySSLErrorObject + state->PySSLErrorObject ); add_exception( - PySSLSyscallErrorObject, + state->PySSLSyscallErrorObject, "SSLSyscallError", SSLSyscallError_doc, - PySSLErrorObject + state->PySSLErrorObject ); add_exception( - PySSLEOFErrorObject, + state->PySSLEOFErrorObject, "SSLEOFError", SSLEOFError_doc, - PySSLErrorObject + state->PySSLErrorObject ); #undef add_exception @@ -5540,128 +5520,21 @@ do { \ static int sslmodule_init_socketapi(PyObject *module) { - PySocketModule_APIObject *socket_api; + _sslmodulestate *state = get_ssl_state(module); + PySocketModule_APIObject *sockmod = PySocketModule_ImportModuleAndAPI(); - /* Load _socket module and its C API */ - socket_api = PySocketModule_ImportModuleAndAPI(); - if (socket_api == NULL) + if ((sockmod == NULL) || (sockmod->Sock_Type == NULL)) { return -1; - PySocketModule = *socket_api; - - return 0; -} - -static int -sslmodule_init_errorcodes(PyObject *module) -{ - struct py_ssl_error_code *errcode; - struct py_ssl_library_code *libcode; - - /* Mappings for error codes */ - err_codes_to_names = PyDict_New(); - if (err_codes_to_names == NULL) - return -1; - err_names_to_codes = PyDict_New(); - if (err_names_to_codes == NULL) - return -1; - lib_codes_to_names = PyDict_New(); - if (lib_codes_to_names == NULL) - return -1; - - errcode = error_codes; - while (errcode->mnemonic != NULL) { - PyObject *mnemo, *key; - mnemo = PyUnicode_FromString(errcode->mnemonic); - key = Py_BuildValue("ii", errcode->library, errcode->reason); - if (mnemo == NULL || key == NULL) - return -1; - if (PyDict_SetItem(err_codes_to_names, key, mnemo)) - return -1; - if (PyDict_SetItem(err_names_to_codes, mnemo, key)) - return -1; - Py_DECREF(key); - Py_DECREF(mnemo); - errcode++; } - - libcode = library_codes; - while (libcode->library != NULL) { - PyObject *mnemo, *key; - key = PyLong_FromLong(libcode->code); - mnemo = PyUnicode_FromString(libcode->library); - if (key == NULL || mnemo == NULL) - return -1; - if (PyDict_SetItem(lib_codes_to_names, key, mnemo)) - return -1; - Py_DECREF(key); - Py_DECREF(mnemo); - libcode++; - } - - if (PyModule_AddObject(module, "err_codes_to_names", err_codes_to_names)) - return -1; - if (PyModule_AddObject(module, "err_names_to_codes", err_names_to_codes)) - return -1; - if (PyModule_AddObject(module, "lib_codes_to_names", lib_codes_to_names)) - return -1; - - return 0; -} - -static void -parse_openssl_version(unsigned long libver, - unsigned int *major, unsigned int *minor, - unsigned int *fix, unsigned int *patch, - unsigned int *status) -{ - *status = libver & 0xF; - libver >>= 4; - *patch = libver & 0xFF; - libver >>= 8; - *fix = libver & 0xFF; - libver >>= 8; - *minor = libver & 0xFF; - libver >>= 8; - *major = libver & 0xFF; -} - -static int -sslmodule_init_versioninfo(PyObject *m) -{ - PyObject *r; - unsigned long libver; - unsigned int major, minor, fix, patch, status; - - /* OpenSSL version */ - /* SSLeay() gives us the version of the library linked against, - which could be different from the headers version. - */ - libver = OpenSSL_version_num(); - r = PyLong_FromUnsignedLong(libver); - if (r == NULL || PyModule_AddObject(m, "OPENSSL_VERSION_NUMBER", r)) - return -1; - - parse_openssl_version(libver, &major, &minor, &fix, &patch, &status); - r = Py_BuildValue("IIIII", major, minor, fix, patch, status); - if (r == NULL || PyModule_AddObject(m, "OPENSSL_VERSION_INFO", r)) - return -1; - - r = PyUnicode_FromString(OpenSSL_version(OPENSSL_VERSION)); - if (r == NULL || PyModule_AddObject(m, "OPENSSL_VERSION", r)) - return -1; - - libver = OPENSSL_VERSION_NUMBER; - parse_openssl_version(libver, &major, &minor, &fix, &patch, &status); - r = Py_BuildValue("IIIII", major, minor, fix, patch, status); - if (r == NULL || PyModule_AddObject(m, "_OPENSSL_API_VERSION", r)) - return -1; - + state->Sock_Type = sockmod->Sock_Type; + Py_INCREF(state->Sock_Type); return 0; } static int sslmodule_init_constants(PyObject *m) { + PyModule_AddStringConstant(m, "_DEFAULT_CIPHERS", PY_SSL_DEFAULT_CIPHER_STRING); @@ -5905,44 +5778,235 @@ sslmodule_init_constants(PyObject *m) return 0; } -PyDoc_STRVAR(module_doc, -"Implementation module for SSL socket operations. See the socket module\n\ -for documentation."); +static int +sslmodule_init_errorcodes(PyObject *module) +{ + _sslmodulestate *state = get_ssl_state(module); + struct py_ssl_error_code *errcode; + struct py_ssl_library_code *libcode; -static struct PyModuleDef _sslmodule = { - PyModuleDef_HEAD_INIT, - "_ssl", - module_doc, - -1, - PySSL_methods, - NULL, - NULL, - NULL, - NULL + /* Mappings for error codes */ + state->err_codes_to_names = PyDict_New(); + if (state->err_codes_to_names == NULL) + return -1; + state->err_names_to_codes = PyDict_New(); + if (state->err_names_to_codes == NULL) + return -1; + state->lib_codes_to_names = PyDict_New(); + if (state->lib_codes_to_names == NULL) + return -1; + + errcode = error_codes; + while (errcode->mnemonic != NULL) { + PyObject *mnemo, *key; + mnemo = PyUnicode_FromString(errcode->mnemonic); + key = Py_BuildValue("ii", errcode->library, errcode->reason); + if (mnemo == NULL || key == NULL) + return -1; + if (PyDict_SetItem(state->err_codes_to_names, key, mnemo)) + return -1; + if (PyDict_SetItem(state->err_names_to_codes, mnemo, key)) + return -1; + Py_DECREF(key); + Py_DECREF(mnemo); + errcode++; + } + + libcode = library_codes; + while (libcode->library != NULL) { + PyObject *mnemo, *key; + key = PyLong_FromLong(libcode->code); + mnemo = PyUnicode_FromString(libcode->library); + if (key == NULL || mnemo == NULL) + return -1; + if (PyDict_SetItem(state->lib_codes_to_names, key, mnemo)) + return -1; + Py_DECREF(key); + Py_DECREF(mnemo); + libcode++; + } + + if (PyModule_AddObjectRef(module, "err_codes_to_names", state->err_codes_to_names)) + return -1; + if (PyModule_AddObjectRef(module, "err_names_to_codes", state->err_names_to_codes)) + return -1; + if (PyModule_AddObjectRef(module, "lib_codes_to_names", state->lib_codes_to_names)) + return -1; + + return 0; +} + +static void +parse_openssl_version(unsigned long libver, + unsigned int *major, unsigned int *minor, + unsigned int *fix, unsigned int *patch, + unsigned int *status) +{ + *status = libver & 0xF; + libver >>= 4; + *patch = libver & 0xFF; + libver >>= 8; + *fix = libver & 0xFF; + libver >>= 8; + *minor = libver & 0xFF; + libver >>= 8; + *major = libver & 0xFF; +} + +static int +sslmodule_init_versioninfo(PyObject *m) +{ + PyObject *r; + unsigned long libver; + unsigned int major, minor, fix, patch, status; + + /* OpenSSL version */ + /* SSLeay() gives us the version of the library linked against, + which could be different from the headers version. + */ + libver = OpenSSL_version_num(); + r = PyLong_FromUnsignedLong(libver); + if (r == NULL || PyModule_AddObject(m, "OPENSSL_VERSION_NUMBER", r)) + return -1; + + parse_openssl_version(libver, &major, &minor, &fix, &patch, &status); + r = Py_BuildValue("IIIII", major, minor, fix, patch, status); + if (r == NULL || PyModule_AddObject(m, "OPENSSL_VERSION_INFO", r)) + return -1; + + r = PyUnicode_FromString(OpenSSL_version(OPENSSL_VERSION)); + if (r == NULL || PyModule_AddObject(m, "OPENSSL_VERSION", r)) + return -1; + + libver = OPENSSL_VERSION_NUMBER; + parse_openssl_version(libver, &major, &minor, &fix, &patch, &status); + r = Py_BuildValue("IIIII", major, minor, fix, patch, status); + if (r == NULL || PyModule_AddObject(m, "_OPENSSL_API_VERSION", r)) + return -1; + + return 0; +} + +static int +sslmodule_init_types(PyObject *module) +{ + _sslmodulestate *state = get_ssl_state(module); + + state->PySSLContext_Type = (PyTypeObject *)PyType_FromModuleAndSpec( + module, &PySSLContext_spec, NULL + ); + if (state->PySSLContext_Type == NULL) + return -1; + + state->PySSLSocket_Type = (PyTypeObject *)PyType_FromModuleAndSpec( + module, &PySSLSocket_spec, NULL + ); + if (state->PySSLSocket_Type == NULL) + return -1; + + state->PySSLMemoryBIO_Type = (PyTypeObject *)PyType_FromModuleAndSpec( + module, &PySSLMemoryBIO_spec, NULL + ); + if (state->PySSLMemoryBIO_Type == NULL) + return -1; + + state->PySSLSession_Type = (PyTypeObject *)PyType_FromModuleAndSpec( + module, &PySSLSession_spec, NULL + ); + if (state->PySSLSession_Type == NULL) + return -1; + + if (PyModule_AddType(module, state->PySSLContext_Type)) + return -1; + if (PyModule_AddType(module, state->PySSLSocket_Type)) + return -1; + if (PyModule_AddType(module, state->PySSLMemoryBIO_Type)) + return -1; + if (PyModule_AddType(module, state->PySSLSession_Type)) + return -1; + + return 0; +} + +static PyModuleDef_Slot sslmodule_slots[] = { + {Py_mod_exec, sslmodule_init_types}, + {Py_mod_exec, sslmodule_init_exceptions}, + {Py_mod_exec, sslmodule_init_socketapi}, + {Py_mod_exec, sslmodule_init_errorcodes}, + {Py_mod_exec, sslmodule_init_constants}, + {Py_mod_exec, sslmodule_init_versioninfo}, + {0, NULL} }; -PyMODINIT_FUNC -PyInit__ssl(void) +static int +sslmodule_traverse(PyObject *m, visitproc visit, void *arg) { - PyObject *m; + _sslmodulestate *state = get_ssl_state(m); + + Py_VISIT(state->PySSLContext_Type); + Py_VISIT(state->PySSLSocket_Type); + Py_VISIT(state->PySSLMemoryBIO_Type); + Py_VISIT(state->PySSLSession_Type); + Py_VISIT(state->PySSLErrorObject); + Py_VISIT(state->PySSLCertVerificationErrorObject); + Py_VISIT(state->PySSLZeroReturnErrorObject); + Py_VISIT(state->PySSLWantReadErrorObject); + Py_VISIT(state->PySSLWantWriteErrorObject); + Py_VISIT(state->PySSLSyscallErrorObject); + Py_VISIT(state->PySSLEOFErrorObject); + Py_VISIT(state->err_codes_to_names); + Py_VISIT(state->err_names_to_codes); + Py_VISIT(state->lib_codes_to_names); + Py_VISIT(state->Sock_Type); - m = PyModule_Create(&_sslmodule); - if (m == NULL) - return NULL; + return 0; +} - if (sslmodule_init_types(m) != 0) - return NULL; - if (sslmodule_init_exceptions(m) != 0) - return NULL; - if (sslmodule_init_socketapi(m) != 0) - return NULL; - if (sslmodule_init_errorcodes(m) != 0) - return NULL; - if (sslmodule_init_constants(m) != 0) - return NULL; - if (sslmodule_init_versioninfo(m) != 0) - return NULL; +static int +sslmodule_clear(PyObject *m) +{ + _sslmodulestate *state = get_ssl_state(m); + + Py_CLEAR(state->PySSLContext_Type); + Py_CLEAR(state->PySSLSocket_Type); + Py_CLEAR(state->PySSLMemoryBIO_Type); + Py_CLEAR(state->PySSLSession_Type); + Py_CLEAR(state->PySSLErrorObject); + Py_CLEAR(state->PySSLCertVerificationErrorObject); + Py_CLEAR(state->PySSLZeroReturnErrorObject); + Py_CLEAR(state->PySSLWantReadErrorObject); + Py_CLEAR(state->PySSLWantWriteErrorObject); + Py_CLEAR(state->PySSLSyscallErrorObject); + Py_CLEAR(state->PySSLEOFErrorObject); + Py_CLEAR(state->err_codes_to_names); + Py_CLEAR(state->err_names_to_codes); + Py_CLEAR(state->lib_codes_to_names); + Py_CLEAR(state->Sock_Type); + + return 0; +} + +static void +sslmodule_free(void *m) +{ + sslmodule_clear((PyObject *)m); +} - return m; +static struct PyModuleDef _sslmodule_def = { + PyModuleDef_HEAD_INIT, + .m_name = "_ssl", + .m_doc = module_doc, + .m_size = sizeof(_sslmodulestate), + .m_methods = PySSL_methods, + .m_slots = sslmodule_slots, + .m_traverse = sslmodule_traverse, + .m_clear = sslmodule_clear, + .m_free = sslmodule_free +}; + +PyMODINIT_FUNC +PyInit__ssl(void) +{ + return PyModuleDef_Init(&_sslmodule_def); } diff --git a/Modules/_ssl.h b/Modules/_ssl.h new file mode 100644 index 0000000..3fd517b --- /dev/null +++ b/Modules/_ssl.h @@ -0,0 +1,45 @@ +#ifndef Py_SSL_H +#define Py_SSL_H + +/* + * ssl module state + */ +typedef struct { + /* Types */ + PyTypeObject *PySSLContext_Type; + PyTypeObject *PySSLSocket_Type; + PyTypeObject *PySSLMemoryBIO_Type; + PyTypeObject *PySSLSession_Type; + /* SSL error object */ + PyObject *PySSLErrorObject; + PyObject *PySSLCertVerificationErrorObject; + PyObject *PySSLZeroReturnErrorObject; + PyObject *PySSLWantReadErrorObject; + PyObject *PySSLWantWriteErrorObject; + PyObject *PySSLSyscallErrorObject; + PyObject *PySSLEOFErrorObject; + /* Error mappings */ + PyObject *err_codes_to_names; + PyObject *err_names_to_codes; + PyObject *lib_codes_to_names; + /* socket type from module CAPI */ + PyTypeObject *Sock_Type; +} _sslmodulestate; + +static struct PyModuleDef _sslmodule_def; + +Py_LOCAL_INLINE(_sslmodulestate*) +get_ssl_state(PyObject *module) +{ + void *state = PyModule_GetState(module); + assert(state != NULL); + return (_sslmodulestate *)state; +} + +#define get_state_type(type) \ + (get_ssl_state(_PyType_GetModuleByDef(type, &_sslmodule_def))) +#define get_state_ctx(c) (((PySSLContext *)(c))->state) +#define get_state_sock(s) (((PySSLSocket *)(s))->ctx->state) +#define get_state_mbio(b) ((_sslmodulestate *)PyType_GetModuleState(Py_TYPE(b))) + +#endif /* Py_SSL_H */ diff --git a/Modules/_ssl/debughelpers.c b/Modules/_ssl/debughelpers.c index f39372c..03c125e 100644 --- a/Modules/_ssl/debughelpers.c +++ b/Modules/_ssl/debughelpers.c @@ -21,7 +21,7 @@ _PySSL_msg_callback(int write_p, int version, int content_type, threadstate = PyGILState_Ensure(); ssl_obj = (PySSLSocket *)SSL_get_app_data(ssl); - assert(PySSLSocket_Check(ssl_obj)); + assert(Py_IS_TYPE(ssl_obj, get_state_sock(ssl_obj)->PySSLSocket_Type)); if (ssl_obj->ctx->msg_cb == NULL) { PyGILState_Release(threadstate); return; @@ -125,7 +125,7 @@ _PySSL_keylog_callback(const SSL *ssl, const char *line) threadstate = PyGILState_Ensure(); ssl_obj = (PySSLSocket *)SSL_get_app_data(ssl); - assert(PySSLSocket_Check(ssl_obj)); + assert(Py_IS_TYPE(ssl_obj, get_state_sock(ssl_obj)->PySSLSocket_Type)); if (ssl_obj->ctx->keylog_bio == NULL) { return; } @@ -199,7 +199,7 @@ _PySSLContext_set_keylog_filename(PySSLContext *self, PyObject *arg, void *c) { self->keylog_bio = BIO_new_fp(fp, BIO_CLOSE | BIO_FP_TEXT); if (self->keylog_bio == NULL) { - PyErr_SetString(PySSLErrorObject, + PyErr_SetString(get_state_ctx(self)->PySSLErrorObject, "Can't malloc memory for keylog file"); return -1; } diff --git a/Modules/clinic/_ssl.c.h b/Modules/clinic/_ssl.c.h index 74ab5a8..45c3095 100644 --- a/Modules/clinic/_ssl.c.h +++ b/Modules/clinic/_ssl.c.h @@ -374,7 +374,7 @@ _ssl__SSLContext(PyTypeObject *type, PyObject *args, PyObject *kwargs) PyObject *return_value = NULL; int proto_version; - if ((type == PySSLContext_Type) && + if ((type == get_state_type(type)->PySSLContext_Type) && !_PyArg_NoKeywords("_SSLContext", kwargs)) { goto exit; } @@ -619,8 +619,8 @@ _ssl__SSLContext__wrap_socket(PySSLContext *self, PyObject *const *args, Py_ssiz if (!args) { goto exit; } - if (!PyObject_TypeCheck(args[0], PySocketModule.Sock_Type)) { - _PyArg_BadArgument("_wrap_socket", "argument 'sock'", (PySocketModule.Sock_Type)->tp_name, args[0]); + if (!PyObject_TypeCheck(args[0], get_state_ctx(self)->Sock_Type)) { + _PyArg_BadArgument("_wrap_socket", "argument 'sock'", (get_state_ctx(self)->Sock_Type)->tp_name, args[0]); goto exit; } sock = args[0]; @@ -689,13 +689,13 @@ _ssl__SSLContext__wrap_bio(PySSLContext *self, PyObject *const *args, Py_ssize_t if (!args) { goto exit; } - if (!PyObject_TypeCheck(args[0], PySSLMemoryBIO_Type)) { - _PyArg_BadArgument("_wrap_bio", "argument 'incoming'", (PySSLMemoryBIO_Type)->tp_name, args[0]); + if (!PyObject_TypeCheck(args[0], get_state_ctx(self)->PySSLMemoryBIO_Type)) { + _PyArg_BadArgument("_wrap_bio", "argument 'incoming'", (get_state_ctx(self)->PySSLMemoryBIO_Type)->tp_name, args[0]); goto exit; } incoming = (PySSLMemoryBIO *)args[0]; - if (!PyObject_TypeCheck(args[1], PySSLMemoryBIO_Type)) { - _PyArg_BadArgument("_wrap_bio", "argument 'outgoing'", (PySSLMemoryBIO_Type)->tp_name, args[1]); + if (!PyObject_TypeCheck(args[1], get_state_ctx(self)->PySSLMemoryBIO_Type)) { + _PyArg_BadArgument("_wrap_bio", "argument 'outgoing'", (get_state_ctx(self)->PySSLMemoryBIO_Type)->tp_name, args[1]); goto exit; } outgoing = (PySSLMemoryBIO *)args[1]; @@ -850,11 +850,11 @@ _ssl_MemoryBIO(PyTypeObject *type, PyObject *args, PyObject *kwargs) { PyObject *return_value = NULL; - if ((type == PySSLMemoryBIO_Type) && + if ((type == get_state_type(type)->PySSLMemoryBIO_Type) && !_PyArg_NoPositional("MemoryBIO", args)) { goto exit; } - if ((type == PySSLMemoryBIO_Type) && + if ((type == get_state_type(type)->PySSLMemoryBIO_Type) && !_PyArg_NoKeywords("MemoryBIO", kwargs)) { goto exit; } @@ -1324,4 +1324,4 @@ exit: #ifndef _SSL_ENUM_CRLS_METHODDEF #define _SSL_ENUM_CRLS_METHODDEF #endif /* !defined(_SSL_ENUM_CRLS_METHODDEF) */ -/*[clinic end generated code: output=ae3d1851daba6562 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=83e68c77bd96789a input=a9049054013a1b77]*/ @@ -2428,14 +2428,6 @@ class PyBuildExt(build_ext): self.missing.extend(['_ssl', '_hashlib']) return None, None - self.add(Extension( - '_ssl', ['_ssl.c'], - include_dirs=openssl_includes, - library_dirs=openssl_libdirs, - libraries=openssl_libs, - depends=['socketmodule.h', '_ssl/debughelpers.c']) - ) - if openssl_rpath == 'auto': runtime_library_dirs = openssl_libdirs[:] elif not openssl_rpath: @@ -2469,7 +2461,7 @@ class PyBuildExt(build_ext): Extension( '_ssl', ['_ssl.c'], - depends=['socketmodule.h', '_ssl/debughelpers.c'], + depends=['socketmodule.h', '_ssl/debughelpers.c', '_ssl.h'], **openssl_extension_kwargs ) ) |