From 5c36da78d738d0e5fdb539a758cc15abc47c843b Mon Sep 17 00:00:00 2001 From: Christian Heimes Date: Fri, 20 Nov 2020 09:40:12 +0100 Subject: [PATCH] bpo-42333: Port _ssl extension module to heap types (GH-23392) All types in _ssl module are now heap types. --- .../2020-11-12-18-21-15.bpo-42333.J9vFmV.rst | 1 + Modules/_ssl.c | 682 +++++++++--------- Modules/clinic/_ssl.c.h | 16 +- 3 files changed, 363 insertions(+), 336 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2020-11-12-18-21-15.bpo-42333.J9vFmV.rst diff --git a/Misc/NEWS.d/next/Library/2020-11-12-18-21-15.bpo-42333.J9vFmV.rst b/Misc/NEWS.d/next/Library/2020-11-12-18-21-15.bpo-42333.J9vFmV.rst new file mode 100644 index 00000000000..f8755c76856 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2020-11-12-18-21-15.bpo-42333.J9vFmV.rst @@ -0,0 +1 @@ +Port _ssl extension module to heap types. diff --git a/Modules/_ssl.c b/Modules/_ssl.c index a34313b7854..130dce40eec 100644 --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -487,10 +487,10 @@ typedef struct { PySSLContext *ctx; } PySSLSession; -static PyTypeObject PySSLContext_Type; -static PyTypeObject PySSLSocket_Type; -static PyTypeObject PySSLMemoryBIO_Type; -static PyTypeObject PySSLSession_Type; +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) { @@ -508,12 +508,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 *" "PySSLContext_Type" +class _ssl._SSLSocket "PySSLSocket *" "PySSLSocket_Type" +class _ssl.MemoryBIO "PySSLMemoryBIO *" "PySSLMemoryBIO_Type" +class _ssl.SSLSession "PySSLSession *" "PySSLSession_Type" [clinic start generated code]*/ -/*[clinic end generated code: output=da39a3ee5e6b4b0d input=bdc67fafeeaa8109]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=cc4883756da17954]*/ #include "clinic/_ssl.c.h" @@ -521,9 +521,9 @@ 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) +#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, @@ -587,7 +587,6 @@ SSLError_str(PyOSErrorObject *self) } static PyType_Slot sslerror_type_slots[] = { - {Py_tp_base, NULL}, /* Filled out in module init as it's not a constant */ {Py_tp_doc, (void*)SSLError_doc}, {Py_tp_str, SSLError_str}, {0, 0}, @@ -937,7 +936,7 @@ newPySSLSocket(PySSLContext *sslctx, PySocketSockObject *sock, SSL_CTX *ctx = sslctx->ctx; _PySSLError err = { 0 }; - self = PyObject_New(PySSLSocket, &PySSLSocket_Type); + self = PyObject_New(PySSLSocket, PySSLSocket_Type); if (self == NULL) return NULL; @@ -2194,7 +2193,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, PySSLContext_Type)) { #if !HAVE_SNI PyErr_SetString(PyExc_NotImplementedError, "setting a socket's " "context is not supported by your OpenSSL library"); @@ -2289,6 +2288,7 @@ PySSL_clear(PySSLSocket *self) static void PySSL_dealloc(PySSLSocket *self) { + PyTypeObject *tp = Py_TYPE(self); if (self->ssl) SSL_free(self->ssl); Py_XDECREF(self->Socket); @@ -2296,6 +2296,7 @@ PySSL_dealloc(PySSLSocket *self) Py_XDECREF(self->server_hostname); Py_XDECREF(self->owner); PyObject_Del(self); + Py_DECREF(tp); } /* If the socket has a timeout, do a select()/poll() on the socket. @@ -2895,7 +2896,7 @@ PySSL_get_session(PySSLSocket *self, void *closure) { Py_RETURN_NONE; } #endif - pysess = PyObject_GC_New(PySSLSession, &PySSLSession_Type); + pysess = PyObject_GC_New(PySSLSession, PySSLSession_Type); if (pysess == NULL) { SSL_SESSION_free(session); return NULL; @@ -3008,38 +3009,21 @@ static PyMethodDef PySSLMethods[] = { {NULL, NULL} }; -static PyTypeObject PySSLSocket_Type = { - PyVarObject_HEAD_INIT(NULL, 0) - "_ssl._SSLSocket", /*tp_name*/ - sizeof(PySSLSocket), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - /* methods */ - (destructor)PySSL_dealloc, /*tp_dealloc*/ - 0, /*tp_vectorcall_offset*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - 0, /*tp_as_async*/ - 0, /*tp_repr*/ - 0, /*tp_as_number*/ - 0, /*tp_as_sequence*/ - 0, /*tp_as_mapping*/ - 0, /*tp_hash*/ - 0, /*tp_call*/ - 0, /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT, /*tp_flags*/ - 0, /*tp_doc*/ - (traverseproc) PySSL_traverse, /*tp_traverse*/ - (inquiry) PySSL_clear, /*tp_clear*/ - 0, /*tp_richcompare*/ - 0, /*tp_weaklistoffset*/ - 0, /*tp_iter*/ - 0, /*tp_iternext*/ - PySSLMethods, /*tp_methods*/ - 0, /*tp_members*/ - ssl_getsetlist, /*tp_getset*/ +static PyType_Slot PySSLSocket_slots[] = { + {Py_tp_methods, PySSLMethods}, + {Py_tp_getset, ssl_getsetlist}, + {Py_tp_dealloc, PySSL_dealloc}, + {Py_tp_traverse, PySSL_traverse}, + {Py_tp_clear, PySSL_clear}, + {0, 0}, +}; + +static PyType_Spec PySSLSocket_spec = { + "_ssl._SSLSocket", + sizeof(PySSLSocket), + 0, + Py_TPFLAGS_DEFAULT, + PySSLSocket_slots, }; @@ -3316,6 +3300,7 @@ context_clear(PySSLContext *self) static void context_dealloc(PySSLContext *self) { + PyTypeObject *tp = Py_TYPE(self); /* bpo-31095: UnTrack is needed before calling any callbacks */ PyObject_GC_UnTrack(self); context_clear(self); @@ -3327,6 +3312,7 @@ context_dealloc(PySSLContext *self) PyMem_FREE(self->alpn_protocols); #endif Py_TYPE(self)->tp_free(self); + Py_DECREF(tp); } /*[clinic input] @@ -4366,8 +4352,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="PySSLMemoryBIO_Type", type="PySSLMemoryBIO *") + outgoing: object(subclass_of="PySSLMemoryBIO_Type", type="PySSLMemoryBIO *") server_side: int server_hostname as hostname_obj: object = None * @@ -4381,7 +4367,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=8cf22f4d586ac56a]*/ +/*[clinic end generated code: output=5c5d6d9b41f99332 input=63867b8f3e1a1aa3]*/ { char *hostname = NULL; PyObject *res; @@ -4829,45 +4815,22 @@ static struct PyMethodDef context_methods[] = { {NULL, NULL} /* sentinel */ }; -static PyTypeObject PySSLContext_Type = { - PyVarObject_HEAD_INIT(NULL, 0) - "_ssl._SSLContext", /*tp_name*/ - sizeof(PySSLContext), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - (destructor)context_dealloc, /*tp_dealloc*/ - 0, /*tp_vectorcall_offset*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - 0, /*tp_as_async*/ - 0, /*tp_repr*/ - 0, /*tp_as_number*/ - 0, /*tp_as_sequence*/ - 0, /*tp_as_mapping*/ - 0, /*tp_hash*/ - 0, /*tp_call*/ - 0, /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, /*tp_flags*/ - 0, /*tp_doc*/ - (traverseproc) context_traverse, /*tp_traverse*/ - (inquiry) context_clear, /*tp_clear*/ - 0, /*tp_richcompare*/ - 0, /*tp_weaklistoffset*/ - 0, /*tp_iter*/ - 0, /*tp_iternext*/ - context_methods, /*tp_methods*/ - 0, /*tp_members*/ - context_getsetlist, /*tp_getset*/ - 0, /*tp_base*/ - 0, /*tp_dict*/ - 0, /*tp_descr_get*/ - 0, /*tp_descr_set*/ - 0, /*tp_dictoffset*/ - 0, /*tp_init*/ - 0, /*tp_alloc*/ - _ssl__SSLContext, /*tp_new*/ +static PyType_Slot PySSLContext_slots[] = { + {Py_tp_methods, context_methods}, + {Py_tp_getset, context_getsetlist}, + {Py_tp_new, _ssl__SSLContext}, + {Py_tp_dealloc, context_dealloc}, + {Py_tp_traverse, context_traverse}, + {Py_tp_clear, context_clear}, + {0, 0}, +}; + +static PyType_Spec PySSLContext_spec = { + "_ssl._SSLContext", + sizeof(PySSLContext), + 0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, + PySSLContext_slots, }; @@ -4915,8 +4878,10 @@ _ssl_MemoryBIO_impl(PyTypeObject *type) static void memory_bio_dealloc(PySSLMemoryBIO *self) { + PyTypeObject *tp = Py_TYPE(self); BIO_free(self->bio); Py_TYPE(self)->tp_free(self); + Py_DECREF(tp); } static PyObject * @@ -5054,47 +5019,21 @@ static struct PyMethodDef memory_bio_methods[] = { {NULL, NULL} /* sentinel */ }; -static PyTypeObject PySSLMemoryBIO_Type = { - PyVarObject_HEAD_INIT(NULL, 0) - "_ssl.MemoryBIO", /*tp_name*/ - sizeof(PySSLMemoryBIO), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - (destructor)memory_bio_dealloc, /*tp_dealloc*/ - 0, /*tp_vectorcall_offset*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - 0, /*tp_as_async*/ - 0, /*tp_repr*/ - 0, /*tp_as_number*/ - 0, /*tp_as_sequence*/ - 0, /*tp_as_mapping*/ - 0, /*tp_hash*/ - 0, /*tp_call*/ - 0, /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT, /*tp_flags*/ - 0, /*tp_doc*/ - 0, /*tp_traverse*/ - 0, /*tp_clear*/ - 0, /*tp_richcompare*/ - 0, /*tp_weaklistoffset*/ - 0, /*tp_iter*/ - 0, /*tp_iternext*/ - memory_bio_methods, /*tp_methods*/ - 0, /*tp_members*/ - memory_bio_getsetlist, /*tp_getset*/ - 0, /*tp_base*/ - 0, /*tp_dict*/ - 0, /*tp_descr_get*/ - 0, /*tp_descr_set*/ - 0, /*tp_dictoffset*/ - 0, /*tp_init*/ - 0, /*tp_alloc*/ - _ssl_MemoryBIO, /*tp_new*/ +static PyType_Slot PySSLMemoryBIO_slots[] = { + {Py_tp_methods, memory_bio_methods}, + {Py_tp_getset, memory_bio_getsetlist}, + {Py_tp_new, _ssl_MemoryBIO}, + {Py_tp_dealloc, memory_bio_dealloc}, + {0, 0}, }; +static PyType_Spec PySSLMemoryBIO_spec = { + "_ssl.MemoryBIO", + sizeof(PySSLMemoryBIO), + 0, + Py_TPFLAGS_DEFAULT, + PySSLMemoryBIO_slots, +}; /* * SSL Session object @@ -5103,6 +5042,7 @@ static PyTypeObject PySSLMemoryBIO_Type = { static void PySSLSession_dealloc(PySSLSession *self) { + PyTypeObject *tp = Py_TYPE(self); /* bpo-31095: UnTrack is needed before calling any callbacks */ PyObject_GC_UnTrack(self); Py_XDECREF(self->ctx); @@ -5110,6 +5050,7 @@ PySSLSession_dealloc(PySSLSession *self) SSL_SESSION_free(self->session); } PyObject_GC_Del(self); + Py_DECREF(tp); } static PyObject * @@ -5251,37 +5192,21 @@ static PyGetSetDef PySSLSession_getsetlist[] = { {NULL}, /* sentinel */ }; -static PyTypeObject PySSLSession_Type = { - PyVarObject_HEAD_INIT(NULL, 0) - "_ssl.Session", /*tp_name*/ - sizeof(PySSLSession), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - (destructor)PySSLSession_dealloc, /*tp_dealloc*/ - 0, /*tp_vectorcall_offset*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - 0, /*tp_as_async*/ - 0, /*tp_repr*/ - 0, /*tp_as_number*/ - 0, /*tp_as_sequence*/ - 0, /*tp_as_mapping*/ - 0, /*tp_hash*/ - 0, /*tp_call*/ - 0, /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /*tp_flags*/ - 0, /*tp_doc*/ - (traverseproc)PySSLSession_traverse, /*tp_traverse*/ - (inquiry)PySSLSession_clear, /*tp_clear*/ - PySSLSession_richcompare, /*tp_richcompare*/ - 0, /*tp_weaklistoffset*/ - 0, /*tp_iter*/ - 0, /*tp_iternext*/ - 0, /*tp_methods*/ - 0, /*tp_members*/ - PySSLSession_getsetlist, /*tp_getset*/ +static PyType_Slot PySSLSession_slots[] = { + {Py_tp_getset,PySSLSession_getsetlist}, + {Py_tp_richcompare, PySSLSession_richcompare}, + {Py_tp_dealloc, PySSLSession_dealloc}, + {Py_tp_traverse, PySSLSession_traverse}, + {Py_tp_clear, PySSLSession_clear}, + {0, 0}, +}; + +static PyType_Spec PySSLSession_spec = { + "_ssl.SSLSession", + sizeof(PySSLSession), + 0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, + PySSLSession_slots, }; @@ -5979,23 +5904,195 @@ static int _setup_ssl_threads(void) { #endif /* HAVE_OPENSSL_CRYPTO_LOCK for OpenSSL < 1.1.0 */ -PyDoc_STRVAR(module_doc, -"Implementation module for SSL socket operations. See the socket module\n\ -for documentation."); +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; -static struct PyModuleDef _sslmodule = { - PyModuleDef_HEAD_INIT, - "_ssl", - module_doc, - -1, - PySSL_methods, - NULL, - NULL, - NULL, - NULL -}; + 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; +} + +static int +sslmodule_init_exceptions(PyObject *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; \ +} while(0) + + bases = PyTuple_Pack(1, PyExc_OSError); + if (bases == NULL) { + goto error; + } + PySSLErrorObject = PyType_FromSpecWithBases(&sslerror_type_spec, bases); + Py_CLEAR(bases); + if (PySSLErrorObject == NULL) { + goto error; + } + if (PyModule_AddObjectRef(module, "SSLError", PySSLErrorObject) < 0) { + goto error; + } + + /* ssl.CertificateError used to be a subclass of ValueError */ + bases = PyTuple_Pack(2, PySSLErrorObject, PyExc_ValueError); + if (bases == NULL) { + goto error; + } + add_exception( + PySSLCertVerificationErrorObject, + "SSLCertVerificationError", + SSLCertVerificationError_doc, + bases + ); + Py_CLEAR(bases); + + add_exception( + PySSLZeroReturnErrorObject, + "SSLZeroReturnError", + SSLZeroReturnError_doc, + PySSLErrorObject + ); + + add_exception( + PySSLWantWriteErrorObject, + "SSLWantWriteError", + SSLWantWriteError_doc, + PySSLErrorObject + ); + + add_exception( + PySSLWantReadErrorObject, + "SSLWantReadError", + SSLWantReadError_doc, + PySSLErrorObject + ); + + add_exception( + PySSLSyscallErrorObject, + "SSLSyscallError", + SSLSyscallError_doc, + PySSLErrorObject + ); + + add_exception( + PySSLEOFErrorObject, + "SSLEOFError", + SSLEOFError_doc, + PySSLErrorObject + ); +#undef add_exception + + return 0; + error: + Py_XDECREF(bases); + return -1; +} + +static int +sslmodule_init_socketapi(PyObject *module) +{ + PySocketModule_APIObject *socket_api; + + /* Load _socket module and its C API */ + socket_api = PySocketModule_ImportModuleAndAPI(); + if (socket_api == 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, @@ -6014,113 +6111,43 @@ parse_openssl_version(unsigned long libver, *major = libver & 0xFF; } -PyMODINIT_FUNC -PyInit__ssl(void) +static int +sslmodule_init_versioninfo(PyObject *m) { - PyObject *m, *d, *r, *bases; + PyObject *r; unsigned long libver; unsigned int major, minor, fix, patch, status; - PySocketModule_APIObject *socket_api; - struct py_ssl_error_code *errcode; - struct py_ssl_library_code *libcode; - if (PyType_Ready(&PySSLContext_Type) < 0) - return NULL; - if (PyType_Ready(&PySSLSocket_Type) < 0) - return NULL; - if (PyType_Ready(&PySSLMemoryBIO_Type) < 0) - return NULL; - if (PyType_Ready(&PySSLSession_Type) < 0) - return NULL; + /* 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; - m = PyModule_Create(&_sslmodule); - if (m == NULL) - return NULL; - d = PyModule_GetDict(m); + r = PyUnicode_FromString(OpenSSL_version(OPENSSL_VERSION)); + if (r == NULL || PyModule_AddObject(m, "OPENSSL_VERSION", r)) + return -1; - /* Load _socket module and its C API */ - socket_api = PySocketModule_ImportModuleAndAPI(); - if (!socket_api) - return NULL; - PySocketModule = *socket_api; + 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; -#ifndef OPENSSL_VERSION_1_1 - /* Load all algorithms and initialize cpuid */ - OPENSSL_add_all_algorithms_noconf(); - /* Init OpenSSL */ - SSL_load_error_strings(); - SSL_library_init(); -#endif - -#ifdef HAVE_OPENSSL_CRYPTO_LOCK - /* note that this will start threading if not already started */ - if (!_setup_ssl_threads()) { - return NULL; - } -#elif OPENSSL_VERSION_1_1 - /* OpenSSL 1.1.0 builtin thread support is enabled */ - _ssl_locks_count++; -#endif - - /* Add symbols to module dict */ - sslerror_type_slots[0].pfunc = PyExc_OSError; - PySSLErrorObject = PyType_FromSpec(&sslerror_type_spec); - if (PySSLErrorObject == NULL) - return NULL; - - /* ssl.CertificateError used to be a subclass of ValueError */ - bases = Py_BuildValue("OO", PySSLErrorObject, PyExc_ValueError); - if (bases == NULL) - return NULL; - PySSLCertVerificationErrorObject = PyErr_NewExceptionWithDoc( - "ssl.SSLCertVerificationError", SSLCertVerificationError_doc, - bases, NULL); - Py_DECREF(bases); - PySSLZeroReturnErrorObject = PyErr_NewExceptionWithDoc( - "ssl.SSLZeroReturnError", SSLZeroReturnError_doc, - PySSLErrorObject, NULL); - PySSLWantReadErrorObject = PyErr_NewExceptionWithDoc( - "ssl.SSLWantReadError", SSLWantReadError_doc, - PySSLErrorObject, NULL); - PySSLWantWriteErrorObject = PyErr_NewExceptionWithDoc( - "ssl.SSLWantWriteError", SSLWantWriteError_doc, - PySSLErrorObject, NULL); - PySSLSyscallErrorObject = PyErr_NewExceptionWithDoc( - "ssl.SSLSyscallError", SSLSyscallError_doc, - PySSLErrorObject, NULL); - PySSLEOFErrorObject = PyErr_NewExceptionWithDoc( - "ssl.SSLEOFError", SSLEOFError_doc, - PySSLErrorObject, NULL); - if (PySSLCertVerificationErrorObject == NULL - || PySSLZeroReturnErrorObject == NULL - || PySSLWantReadErrorObject == NULL - || PySSLWantWriteErrorObject == NULL - || PySSLSyscallErrorObject == NULL - || PySSLEOFErrorObject == NULL) - return NULL; - if (PyDict_SetItemString(d, "SSLError", PySSLErrorObject) != 0 - || PyDict_SetItemString(d, "SSLCertVerificationError", - PySSLCertVerificationErrorObject) != 0 - || PyDict_SetItemString(d, "SSLZeroReturnError", PySSLZeroReturnErrorObject) != 0 - || PyDict_SetItemString(d, "SSLWantReadError", PySSLWantReadErrorObject) != 0 - || PyDict_SetItemString(d, "SSLWantWriteError", PySSLWantWriteErrorObject) != 0 - || PyDict_SetItemString(d, "SSLSyscallError", PySSLSyscallErrorObject) != 0 - || PyDict_SetItemString(d, "SSLEOFError", PySSLEOFErrorObject) != 0) - return NULL; - if (PyDict_SetItemString(d, "_SSLContext", - (PyObject *)&PySSLContext_Type) != 0) - return NULL; - if (PyDict_SetItemString(d, "_SSLSocket", - (PyObject *)&PySSLSocket_Type) != 0) - return NULL; - if (PyDict_SetItemString(d, "MemoryBIO", - (PyObject *)&PySSLMemoryBIO_Type) != 0) - return NULL; - if (PyDict_SetItemString(d, "SSLSession", - (PyObject *)&PySSLSession_Type) != 0) - return NULL; + return 0; +} +static int +sslmodule_init_constants(PyObject *m) +{ PyModule_AddStringConstant(m, "_DEFAULT_CIPHERS", PY_SSL_DEFAULT_CIPHER_STRING); @@ -6377,72 +6404,71 @@ PyInit__ssl(void) addbool(m, "HAS_TLSv1_3", 0); #endif - /* Mappings for error codes */ - err_codes_to_names = PyDict_New(); - err_names_to_codes = PyDict_New(); - if (err_codes_to_names == NULL || err_names_to_codes == NULL) + return 0; +} + +static int +sslmodule_legacy(PyObject *module) +{ +#ifndef OPENSSL_VERSION_1_1 + /* Load all algorithms and initialize cpuid */ + OPENSSL_add_all_algorithms_noconf(); + /* Init OpenSSL */ + SSL_load_error_strings(); + SSL_library_init(); +#endif + +#ifdef HAVE_OPENSSL_CRYPTO_LOCK + /* note that this will start threading if not already started */ + if (!_setup_ssl_threads()) { return NULL; - 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 NULL; - if (PyDict_SetItem(err_codes_to_names, key, mnemo)) - return NULL; - if (PyDict_SetItem(err_names_to_codes, mnemo, key)) - return NULL; - Py_DECREF(key); - Py_DECREF(mnemo); - errcode++; } - if (PyModule_AddObject(m, "err_codes_to_names", err_codes_to_names)) - return NULL; - if (PyModule_AddObject(m, "err_names_to_codes", err_names_to_codes)) +#elif OPENSSL_VERSION_1_1 + /* OpenSSL 1.1.0 builtin thread support is enabled */ + _ssl_locks_count++; +#endif + return 0; +} + +PyDoc_STRVAR(module_doc, +"Implementation module for SSL socket operations. See the socket module\n\ +for documentation."); + + +static struct PyModuleDef _sslmodule = { + PyModuleDef_HEAD_INIT, + "_ssl", + module_doc, + -1, + PySSL_methods, + NULL, + NULL, + NULL, + NULL +}; + +PyMODINIT_FUNC +PyInit__ssl(void) +{ + PyObject *m; + + m = PyModule_Create(&_sslmodule); + if (m == NULL) return NULL; - lib_codes_to_names = PyDict_New(); - if (lib_codes_to_names == NULL) + if (sslmodule_init_types(m) != 0) return NULL; - 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 NULL; - if (PyDict_SetItem(lib_codes_to_names, key, mnemo)) - return NULL; - Py_DECREF(key); - Py_DECREF(mnemo); - libcode++; - } - if (PyModule_AddObject(m, "lib_codes_to_names", lib_codes_to_names)) + if (sslmodule_init_exceptions(m) != 0) return NULL; - - /* 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) + if (sslmodule_init_socketapi(m) != 0) return NULL; - if (PyModule_AddObject(m, "OPENSSL_VERSION_NUMBER", r)) + if (sslmodule_init_errorcodes(m) != 0) return NULL; - 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)) + if (sslmodule_init_constants(m) != 0) return NULL; - r = PyUnicode_FromString(OpenSSL_version(OPENSSL_VERSION)); - if (r == NULL || PyModule_AddObject(m, "OPENSSL_VERSION", r)) + if (sslmodule_init_versioninfo(m) != 0) return NULL; - - 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)) + if (sslmodule_legacy(m) != 0) return NULL; return m; diff --git a/Modules/clinic/_ssl.c.h b/Modules/clinic/_ssl.c.h index 2375f83b325..43469d3c358 100644 --- a/Modules/clinic/_ssl.c.h +++ b/Modules/clinic/_ssl.c.h @@ -399,7 +399,7 @@ _ssl__SSLContext(PyTypeObject *type, PyObject *args, PyObject *kwargs) PyObject *return_value = NULL; int proto_version; - if ((type == &PySSLContext_Type) && + if ((type == PySSLContext_Type) && !_PyArg_NoKeywords("_SSLContext", kwargs)) { goto exit; } @@ -754,13 +754,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], PySSLMemoryBIO_Type)) { + _PyArg_BadArgument("_wrap_bio", "argument 'incoming'", (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], PySSLMemoryBIO_Type)) { + _PyArg_BadArgument("_wrap_bio", "argument 'outgoing'", (PySSLMemoryBIO_Type)->tp_name, args[1]); goto exit; } outgoing = (PySSLMemoryBIO *)args[1]; @@ -919,11 +919,11 @@ _ssl_MemoryBIO(PyTypeObject *type, PyObject *args, PyObject *kwargs) { PyObject *return_value = NULL; - if ((type == &PySSLMemoryBIO_Type) && + if ((type == PySSLMemoryBIO_Type) && !_PyArg_NoPositional("MemoryBIO", args)) { goto exit; } - if ((type == &PySSLMemoryBIO_Type) && + if ((type == PySSLMemoryBIO_Type) && !_PyArg_NoKeywords("MemoryBIO", kwargs)) { goto exit; } @@ -1447,4 +1447,4 @@ exit: #ifndef _SSL_ENUM_CRLS_METHODDEF #define _SSL_ENUM_CRLS_METHODDEF #endif /* !defined(_SSL_ENUM_CRLS_METHODDEF) */ -/*[clinic end generated code: output=d4e4f9cdd08819f4 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=2bb53a80040c9b35 input=a9049054013a1b77]*/