diff options
Diffstat (limited to 'Modules/_ssl.c')
-rw-r--r-- | Modules/_ssl.c | 535 |
1 files changed, 349 insertions, 186 deletions
diff --git a/Modules/_ssl.c b/Modules/_ssl.c index 9ab184b..96d79b3 100644 --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -115,23 +115,29 @@ static unsigned int _ssl_locks_count = 0; typedef struct { PyObject_HEAD - PyObject *Socket; /* weakref to socket on which we're layered */ - SSL_CTX* ctx; - SSL* ssl; - X509* peer_cert; - int shutdown_seen_zero; + SSL_CTX *ctx; +} PySSLContext; -} PySSLObject; +typedef struct { + PyObject_HEAD + PyObject *Socket; /* weakref to socket on which we're layered */ + SSL *ssl; + X509 *peer_cert; + int shutdown_seen_zero; +} PySSLSocket; + +static PyTypeObject PySSLContext_Type; +static PyTypeObject PySSLSocket_Type; -static PyTypeObject PySSL_Type; -static PyObject *PySSL_SSLwrite(PySSLObject *self, PyObject *args); -static PyObject *PySSL_SSLread(PySSLObject *self, PyObject *args); +static PyObject *PySSL_SSLwrite(PySSLSocket *self, PyObject *args); +static PyObject *PySSL_SSLread(PySSLSocket *self, PyObject *args); static int check_socket_and_wait_for_timeout(PySocketSockObject *s, int writing); -static PyObject *PySSL_peercert(PySSLObject *self, PyObject *args); -static PyObject *PySSL_cipher(PySSLObject *self); +static PyObject *PySSL_peercert(PySSLSocket *self, PyObject *args); +static PyObject *PySSL_cipher(PySSLSocket *self); -#define PySSLObject_Check(v) (Py_TYPE(v) == &PySSL_Type) +#define PySSLContext_Check(v) (Py_TYPE(v) == &PySSLContext_Type) +#define PySSLSocket_Check(v) (Py_TYPE(v) == &PySSLSocket_Type) typedef enum { SOCKET_IS_NONBLOCKING, @@ -154,7 +160,7 @@ typedef enum { */ static PyObject * -PySSL_SetError(PySSLObject *obj, int ret, char *filename, int lineno) +PySSL_SetError(PySSLSocket *obj, int ret, char *filename, int lineno) { PyObject *v; char buf[2048]; @@ -258,126 +264,28 @@ _setSSLError (char *errstr, int errcode, char *filename, int lineno) { return NULL; } -static PySSLObject * -newPySSLObject(PySocketSockObject *Sock, char *key_file, char *cert_file, - enum py_ssl_server_or_client socket_type, - enum py_ssl_cert_requirements certreq, - enum py_ssl_version proto_version, - char *cacerts_file, char *ciphers) +static PySSLSocket * +newPySSLSocket(SSL_CTX *ctx, PySocketSockObject *sock, + enum py_ssl_server_or_client socket_type) { - PySSLObject *self; - char *errstr = NULL; - int ret; - int verification_mode; + PySSLSocket *self; - self = PyObject_New(PySSLObject, &PySSL_Type); /* Create new object */ + self = PyObject_New(PySSLSocket, &PySSLSocket_Type); if (self == NULL) return NULL; + self->peer_cert = NULL; self->ssl = NULL; - self->ctx = NULL; self->Socket = NULL; /* Make sure the SSL error state is initialized */ (void) ERR_get_state(); ERR_clear_error(); - if ((key_file && !cert_file) || (!key_file && cert_file)) { - errstr = ERRSTR("Both the key & certificate files " - "must be specified"); - goto fail; - } - - if ((socket_type == PY_SSL_SERVER) && - ((key_file == NULL) || (cert_file == NULL))) { - errstr = ERRSTR("Both the key & certificate files " - "must be specified for server-side operation"); - goto fail; - } - - PySSL_BEGIN_ALLOW_THREADS - if (proto_version == PY_SSL_VERSION_TLS1) - self->ctx = SSL_CTX_new(TLSv1_method()); /* Set up context */ - else if (proto_version == PY_SSL_VERSION_SSL3) - self->ctx = SSL_CTX_new(SSLv3_method()); /* Set up context */ - else if (proto_version == PY_SSL_VERSION_SSL2) - self->ctx = SSL_CTX_new(SSLv2_method()); /* Set up context */ - else if (proto_version == PY_SSL_VERSION_SSL23) - self->ctx = SSL_CTX_new(SSLv23_method()); /* Set up context */ - PySSL_END_ALLOW_THREADS - - if (self->ctx == NULL) { - errstr = ERRSTR("Invalid SSL protocol variant specified."); - goto fail; - } - - if (ciphers != NULL) { - ret = SSL_CTX_set_cipher_list(self->ctx, ciphers); - if (ret == 0) { - errstr = ERRSTR("No cipher can be selected."); - goto fail; - } - } - - if (certreq != PY_SSL_CERT_NONE) { - if (cacerts_file == NULL) { - errstr = ERRSTR("No root certificates specified for " - "verification of other-side certificates."); - goto fail; - } else { - PySSL_BEGIN_ALLOW_THREADS - ret = SSL_CTX_load_verify_locations(self->ctx, - cacerts_file, - NULL); - PySSL_END_ALLOW_THREADS - if (ret != 1) { - _setSSLError(NULL, 0, __FILE__, __LINE__); - goto fail; - } - } - } - if (key_file) { - PySSL_BEGIN_ALLOW_THREADS - ret = SSL_CTX_use_PrivateKey_file(self->ctx, key_file, - SSL_FILETYPE_PEM); - PySSL_END_ALLOW_THREADS - if (ret != 1) { - _setSSLError(NULL, ret, __FILE__, __LINE__); - goto fail; - } - - PySSL_BEGIN_ALLOW_THREADS - ret = SSL_CTX_use_certificate_chain_file(self->ctx, - cert_file); - PySSL_END_ALLOW_THREADS - if (ret != 1) { - /* - fprintf(stderr, "ret is %d, errcode is %lu, %lu, with file \"%s\"\n", - ret, ERR_peek_error(), ERR_peek_last_error(), cert_file); - */ - if (ERR_peek_last_error() != 0) { - _setSSLError(NULL, ret, __FILE__, __LINE__); - goto fail; - } - } - } - - /* ssl compatibility */ - SSL_CTX_set_options(self->ctx, SSL_OP_ALL); - - verification_mode = SSL_VERIFY_NONE; - if (certreq == PY_SSL_CERT_OPTIONAL) - verification_mode = SSL_VERIFY_PEER; - else if (certreq == PY_SSL_CERT_REQUIRED) - verification_mode = (SSL_VERIFY_PEER | - SSL_VERIFY_FAIL_IF_NO_PEER_CERT); - SSL_CTX_set_verify(self->ctx, verification_mode, - NULL); /* set verify lvl */ - PySSL_BEGIN_ALLOW_THREADS - self->ssl = SSL_new(self->ctx); /* New ssl struct */ + self->ssl = SSL_new(ctx); PySSL_END_ALLOW_THREADS - SSL_set_fd(self->ssl, Sock->sock_fd); /* Set the socket for SSL */ + SSL_set_fd(self->ssl, sock->sock_fd); #ifdef SSL_MODE_AUTO_RETRY SSL_set_mode(self->ssl, SSL_MODE_AUTO_RETRY); #endif @@ -385,8 +293,7 @@ newPySSLObject(PySocketSockObject *Sock, char *key_file, char *cert_file, /* If the socket is in non-blocking mode or timeout mode, set the BIO * to non-blocking mode (blocking is the default) */ - if (Sock->sock_timeout >= 0.0) { - /* Set both the read and write BIO's to non-blocking mode */ + if (sock->sock_timeout >= 0.0) { BIO_set_nbio(SSL_get_rbio(self->ssl), 1); BIO_set_nbio(SSL_get_wbio(self->ssl), 1); } @@ -398,57 +305,13 @@ newPySSLObject(PySocketSockObject *Sock, char *key_file, char *cert_file, SSL_set_accept_state(self->ssl); PySSL_END_ALLOW_THREADS - self->Socket = PyWeakref_NewRef((PyObject *) Sock, Py_None); + self->Socket = PyWeakref_NewRef((PyObject *) sock, NULL); return self; - fail: - if (errstr) - PyErr_SetString(PySSLErrorObject, errstr); - Py_DECREF(self); - return NULL; -} - -static PyObject * -PySSL_sslwrap(PyObject *self, PyObject *args) -{ - PySocketSockObject *Sock; - int server_side = 0; - int verification_mode = PY_SSL_CERT_NONE; - int protocol = PY_SSL_VERSION_SSL23; - char *key_file = NULL; - char *cert_file = NULL; - char *cacerts_file = NULL; - char *ciphers = NULL; - - if (!PyArg_ParseTuple(args, "O!i|zziizz:sslwrap", - PySocketModule.Sock_Type, - &Sock, - &server_side, - &key_file, &cert_file, - &verification_mode, &protocol, - &cacerts_file, &ciphers)) - return NULL; - - /* - fprintf(stderr, - "server_side is %d, keyfile %p, certfile %p, verify_mode %d, " - "protocol %d, certs %p\n", - server_side, key_file, cert_file, verification_mode, - protocol, cacerts_file); - */ - - return (PyObject *) newPySSLObject(Sock, key_file, cert_file, - server_side, verification_mode, - protocol, cacerts_file, - ciphers); } -PyDoc_STRVAR(ssl_doc, -"sslwrap(socket, server_side, [keyfile, certfile, certs_mode, protocol,\n" -" cacertsfile, ciphers]) -> sslobject"); - /* SSL object methods */ -static PyObject *PySSL_SSLdo_handshake(PySSLObject *self) +static PyObject *PySSL_SSLdo_handshake(PySSLSocket *self) { int ret; int err; @@ -986,7 +849,7 @@ PySSL_test_decode_certificate (PyObject *mod, PyObject *args) { static PyObject * -PySSL_peercert(PySSLObject *self, PyObject *args) +PySSL_peercert(PySSLSocket *self, PyObject *args) { PyObject *retval = NULL; int len; @@ -1017,8 +880,7 @@ PySSL_peercert(PySSLObject *self, PyObject *args) return retval; } else { - - verification = SSL_CTX_get_verify_mode(self->ctx); + verification = SSL_CTX_get_verify_mode(SSL_get_SSL_CTX(self->ssl)); if ((verification & SSL_VERIFY_PEER) == 0) return PyDict_New(); else @@ -1038,7 +900,7 @@ If the optional argument is True, returns a DER-encoded copy of the\n\ peer certificate, or None if no certificate was provided. This will\n\ return the certificate even if it wasn't validated."); -static PyObject *PySSL_cipher (PySSLObject *self) { +static PyObject *PySSL_cipher (PySSLSocket *self) { PyObject *retval, *v; SSL_CIPHER *current; @@ -1084,14 +946,12 @@ static PyObject *PySSL_cipher (PySSLObject *self) { return NULL; } -static void PySSL_dealloc(PySSLObject *self) +static void PySSL_dealloc(PySSLSocket *self) { if (self->peer_cert) /* Possible not to have one? */ X509_free (self->peer_cert); if (self->ssl) SSL_free(self->ssl); - if (self->ctx) - SSL_CTX_free(self->ctx); Py_XDECREF(self->Socket); PyObject_Del(self); } @@ -1166,7 +1026,7 @@ normal_return: return rc == 0 ? SOCKET_HAS_TIMED_OUT : SOCKET_OPERATION_OK; } -static PyObject *PySSL_SSLwrite(PySSLObject *self, PyObject *args) +static PyObject *PySSL_SSLwrite(PySSLSocket *self, PyObject *args) { Py_buffer buf; int len; @@ -1250,7 +1110,7 @@ PyDoc_STRVAR(PySSL_SSLwrite_doc, Writes the string s into the SSL object. Returns the number\n\ of bytes written."); -static PyObject *PySSL_SSLpending(PySSLObject *self) +static PyObject *PySSL_SSLpending(PySSLSocket *self) { int count = 0; @@ -1269,7 +1129,7 @@ PyDoc_STRVAR(PySSL_SSLpending_doc, Returns the number of already decrypted bytes available for read,\n\ pending on the connection.\n"); -static PyObject *PySSL_SSLread(PySSLObject *self, PyObject *args) +static PyObject *PySSL_SSLread(PySSLSocket *self, PyObject *args) { PyObject *dest = NULL; Py_buffer buf; @@ -1392,7 +1252,7 @@ PyDoc_STRVAR(PySSL_SSLread_doc, \n\ Read up to len bytes from the SSL socket."); -static PyObject *PySSL_SSLshutdown(PySSLObject *self) +static PyObject *PySSL_SSLshutdown(PySSLSocket *self) { int err, ssl_err, sockstate, nonblocking; int zeros = 0; @@ -1497,10 +1357,10 @@ static PyMethodDef PySSLMethods[] = { {NULL, NULL} }; -static PyTypeObject PySSL_Type = { +static PyTypeObject PySSLSocket_Type = { PyVarObject_HEAD_INIT(NULL, 0) - "ssl.SSLContext", /*tp_name*/ - sizeof(PySSLObject), /*tp_basicsize*/ + "_ssl._SSLSocket", /*tp_name*/ + sizeof(PySSLSocket), /*tp_basicsize*/ 0, /*tp_itemsize*/ /* methods */ (destructor)PySSL_dealloc, /*tp_dealloc*/ @@ -1529,6 +1389,306 @@ static PyTypeObject PySSL_Type = { PySSLMethods, /*tp_methods*/ }; + +/* + * _SSLContext objects + */ + +static PyObject * +context_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + char *kwlist[] = {"protocol", NULL}; + PySSLContext *self; + int proto_version = PY_SSL_VERSION_SSL23; + SSL_CTX *ctx = NULL; + + if (!PyArg_ParseTupleAndKeywords( + args, kwds, "i:_SSLContext", kwlist, + &proto_version)) + return NULL; + + PySSL_BEGIN_ALLOW_THREADS + if (proto_version == PY_SSL_VERSION_TLS1) + ctx = SSL_CTX_new(TLSv1_method()); + else if (proto_version == PY_SSL_VERSION_SSL3) + ctx = SSL_CTX_new(SSLv3_method()); + else if (proto_version == PY_SSL_VERSION_SSL2) + ctx = SSL_CTX_new(SSLv2_method()); + else if (proto_version == PY_SSL_VERSION_SSL23) + ctx = SSL_CTX_new(SSLv23_method()); + else + proto_version = -1; + PySSL_END_ALLOW_THREADS + + if (proto_version == -1) { + PyErr_SetString(PyExc_ValueError, + "invalid protocol version"); + return NULL; + } + if (ctx == NULL) { + PyErr_SetString(PySSLErrorObject, + "failed to allocate SSL context"); + return NULL; + } + + assert(type != NULL && type->tp_alloc != NULL); + self = (PySSLContext *) type->tp_alloc(type, 0); + if (self == NULL) { + SSL_CTX_free(ctx); + return NULL; + } + self->ctx = ctx; + /* Defaults */ + SSL_CTX_set_verify(self->ctx, SSL_VERIFY_NONE, NULL); + SSL_CTX_set_options(self->ctx, SSL_OP_ALL); + + return (PyObject *)self; +} + +static void +context_dealloc(PySSLContext *self) +{ + SSL_CTX_free(self->ctx); + Py_TYPE(self)->tp_free(self); +} + +static PyObject * +set_ciphers(PySSLContext *self, PyObject *args) +{ + int ret; + const char *cipherlist; + + if (!PyArg_ParseTuple(args, "s:set_ciphers", &cipherlist)) + return NULL; + ret = SSL_CTX_set_cipher_list(self->ctx, cipherlist); + if (ret == 0) { + PyErr_SetString(PySSLErrorObject, + "No cipher can be selected."); + return NULL; + } + Py_RETURN_NONE; +} + +static PyObject * +get_verify_mode(PySSLContext *self, void *c) +{ + switch (SSL_CTX_get_verify_mode(self->ctx)) { + case SSL_VERIFY_NONE: + return PyLong_FromLong(PY_SSL_CERT_NONE); + case SSL_VERIFY_PEER: + return PyLong_FromLong(PY_SSL_CERT_OPTIONAL); + case SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT: + return PyLong_FromLong(PY_SSL_CERT_REQUIRED); + } + PyErr_SetString(PySSLErrorObject, + "invalid return value from SSL_CTX_get_verify_mode"); + return NULL; +} + +static int +set_verify_mode(PySSLContext *self, PyObject *arg, void *c) +{ + int n, mode; + if (!PyArg_Parse(arg, "i", &n)) + return -1; + if (n == PY_SSL_CERT_NONE) + mode = SSL_VERIFY_NONE; + else if (n == PY_SSL_CERT_OPTIONAL) + mode = SSL_VERIFY_PEER; + else if (n == PY_SSL_CERT_REQUIRED) + mode = SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT; + else { + PyErr_SetString(PyExc_ValueError, + "invalid value for verify_mode"); + return -1; + } + SSL_CTX_set_verify(self->ctx, mode, NULL); + return 0; +} + +static PyObject * +load_cert_chain(PySSLContext *self, PyObject *args, PyObject *kwds) +{ + char *kwlist[] = {"certfile", "keyfile", NULL}; + PyObject *certfile, *keyfile = NULL; + PyObject *certfile_bytes = NULL, *keyfile_bytes = NULL; + int r; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, + "O|O:load_cert_chain", kwlist, + &certfile, &keyfile)) + return NULL; + if (keyfile == Py_None) + keyfile = NULL; + if (!PyUnicode_FSConverter(certfile, &certfile_bytes)) { + PyErr_SetString(PyExc_TypeError, + "certfile should be a valid filesystem path"); + return NULL; + } + if (keyfile && !PyUnicode_FSConverter(keyfile, &keyfile_bytes)) { + PyErr_SetString(PyExc_TypeError, + "keyfile should be a valid filesystem path"); + goto error; + } + PySSL_BEGIN_ALLOW_THREADS + r = SSL_CTX_use_certificate_chain_file(self->ctx, + PyBytes_AS_STRING(certfile_bytes)); + PySSL_END_ALLOW_THREADS + if (r != 1) { + _setSSLError(NULL, 0, __FILE__, __LINE__); + goto error; + } + PySSL_BEGIN_ALLOW_THREADS + r = SSL_CTX_use_RSAPrivateKey_file(self->ctx, + PyBytes_AS_STRING(keyfile ? keyfile_bytes : certfile_bytes), + SSL_FILETYPE_PEM); + PySSL_END_ALLOW_THREADS + Py_XDECREF(keyfile_bytes); + Py_XDECREF(certfile_bytes); + if (r != 1) { + _setSSLError(NULL, 0, __FILE__, __LINE__); + return NULL; + } + PySSL_BEGIN_ALLOW_THREADS + r = SSL_CTX_check_private_key(self->ctx); + PySSL_END_ALLOW_THREADS + if (r != 1) { + _setSSLError(NULL, 0, __FILE__, __LINE__); + return NULL; + } + Py_RETURN_NONE; + +error: + Py_XDECREF(keyfile_bytes); + Py_XDECREF(certfile_bytes); + return NULL; +} + +static PyObject * +load_verify_locations(PySSLContext *self, PyObject *args, PyObject *kwds) +{ + char *kwlist[] = {"cafile", "capath", NULL}; + PyObject *cafile = NULL, *capath = NULL; + PyObject *cafile_bytes = NULL, *capath_bytes = NULL; + const char *cafile_buf = NULL, *capath_buf = NULL; + int r; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, + "|OO:load_verify_locations", kwlist, + &cafile, &capath)) + return NULL; + if (cafile == Py_None) + cafile = NULL; + if (capath == Py_None) + capath = NULL; + if (cafile == NULL && capath == NULL) { + PyErr_SetString(PyExc_TypeError, + "cafile and capath cannot be both omitted"); + return NULL; + } + if (cafile && !PyUnicode_FSConverter(cafile, &cafile_bytes)) { + PyErr_SetString(PyExc_TypeError, + "cafile should be a valid filesystem path"); + return NULL; + } + if (capath && !PyUnicode_FSConverter(capath, &capath_bytes)) { + Py_DECREF(cafile_bytes); + PyErr_SetString(PyExc_TypeError, + "capath should be a valid filesystem path"); + return NULL; + } + if (cafile) + cafile_buf = PyBytes_AS_STRING(cafile_bytes); + if (capath) + capath_buf = PyBytes_AS_STRING(capath_bytes); + PySSL_BEGIN_ALLOW_THREADS + r = SSL_CTX_load_verify_locations(self->ctx, cafile_buf, capath_buf); + PySSL_END_ALLOW_THREADS + Py_XDECREF(cafile_bytes); + Py_XDECREF(capath_bytes); + if (r != 1) { + _setSSLError(NULL, 0, __FILE__, __LINE__); + return NULL; + } + Py_RETURN_NONE; +} + +static PyObject * +context_wrap_socket(PySSLContext *self, PyObject *args, PyObject *kwds) +{ + char *kwlist[] = {"sock", "server_side", NULL}; + PySocketSockObject *sock; + int server_side = 0; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!i:_wrap_socket", kwlist, + PySocketModule.Sock_Type, + &sock, &server_side)) + return NULL; + + return (PyObject *) newPySSLSocket(self->ctx, sock, server_side); +} + +static PyGetSetDef context_getsetlist[] = { + {"verify_mode", (getter) get_verify_mode, + (setter) set_verify_mode, NULL}, + {NULL}, /* sentinel */ +}; + +static struct PyMethodDef context_methods[] = { + {"_wrap_socket", (PyCFunction) context_wrap_socket, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"set_ciphers", (PyCFunction) set_ciphers, + METH_VARARGS, NULL}, + {"load_cert_chain", (PyCFunction) load_cert_chain, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"load_verify_locations", (PyCFunction) load_verify_locations, + METH_VARARGS | METH_KEYWORDS, NULL}, + {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_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_reserved*/ + 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, /*tp_flags*/ + 0, /*tp_doc*/ + 0, /*tp_traverse*/ + 0, /*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*/ + context_new, /*tp_new*/ +}; + + + #ifdef HAVE_OPENSSL_RAND /* helper routines for seeding the SSL PRNG */ @@ -1598,8 +1758,6 @@ fails or if it does provide enough data to seed PRNG."); /* List of functions exported by this module. */ static PyMethodDef PySSL_methods[] = { - {"sslwrap", PySSL_sslwrap, - METH_VARARGS, ssl_doc}, {"_test_decode_cert", PySSL_test_decode_certificate, METH_VARARGS}, #ifdef HAVE_OPENSSL_RAND @@ -1708,7 +1866,9 @@ PyInit__ssl(void) unsigned int major, minor, fix, patch, status; PySocketModule_APIObject *socket_api; - if (PyType_Ready(&PySSL_Type) < 0) + if (PyType_Ready(&PySSLContext_Type) < 0) + return NULL; + if (PyType_Ready(&PySSLSocket_Type) < 0) return NULL; m = PyModule_Create(&_sslmodule); @@ -1741,8 +1901,11 @@ PyInit__ssl(void) return NULL; if (PyDict_SetItemString(d, "SSLError", PySSLErrorObject) != 0) return NULL; - if (PyDict_SetItemString(d, "SSLType", - (PyObject *)&PySSL_Type) != 0) + if (PyDict_SetItemString(d, "_SSLContext", + (PyObject *)&PySSLContext_Type) != 0) + return NULL; + if (PyDict_SetItemString(d, "_SSLSocket", + (PyObject *)&PySSLSocket_Type) != 0) return NULL; PyModule_AddIntConstant(m, "SSL_ERROR_ZERO_RETURN", PY_SSL_ERROR_ZERO_RETURN); |