diff options
Diffstat (limited to 'Modules/_ssl.c')
-rw-r--r-- | Modules/_ssl.c | 751 |
1 files changed, 672 insertions, 79 deletions
diff --git a/Modules/_ssl.c b/Modules/_ssl.c index cd6640f..3eb03a7 100644 --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -45,6 +45,70 @@ #endif +/* Include symbols from _socket module */ +#include "socketmodule.h" + +static PySocketModule_APIObject PySocketModule; + +#if defined(HAVE_POLL_H) +#include <poll.h> +#elif defined(HAVE_SYS_POLL_H) +#include <sys/poll.h> +#endif + +/* Include OpenSSL header files */ +#include "openssl/rsa.h" +#include "openssl/crypto.h" +#include "openssl/x509.h" +#include "openssl/x509v3.h" +#include "openssl/pem.h" +#include "openssl/ssl.h" +#include "openssl/err.h" +#include "openssl/rand.h" + +/* SSL error object */ +static PyObject *PySSLErrorObject; +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; +}; + +/* Include generated data (error codes) */ +#include "_ssl_data.h" + +/* Openssl comes with TLSv1.1 and TLSv1.2 between 1.0.0h and 1.0.1 + http://www.openssl.org/news/changelog.html + */ +#if OPENSSL_VERSION_NUMBER >= 0x10001000L +# define HAVE_TLSv1_2 1 +#else +# define HAVE_TLSv1_2 0 +#endif + +/* SNI support (client- and server-side) appeared in OpenSSL 1.0.0. + * This includes the SSL_set_SSL_CTX() function. + */ +#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME +# define HAVE_SNI 1 +#else +# define HAVE_SNI 0 +#endif + enum py_ssl_error { /* these mirror ssl.h */ PY_SSL_ERROR_NONE, @@ -78,55 +142,14 @@ enum py_ssl_version { #endif PY_SSL_VERSION_SSL3=1, PY_SSL_VERSION_SSL23, +#if HAVE_TLSv1_2 + PY_SSL_VERSION_TLS1, + PY_SSL_VERSION_TLS1_1, + PY_SSL_VERSION_TLS1_2 +#else PY_SSL_VERSION_TLS1 -}; - -struct py_ssl_error_code { - const char *mnemonic; - int library, reason; -}; - -struct py_ssl_library_code { - const char *library; - int code; -}; - -/* Include symbols from _socket module */ -#include "socketmodule.h" - -static PySocketModule_APIObject PySocketModule; - -#if defined(HAVE_POLL_H) -#include <poll.h> -#elif defined(HAVE_SYS_POLL_H) -#include <sys/poll.h> #endif - -/* Include OpenSSL header files */ -#include "openssl/rsa.h" -#include "openssl/crypto.h" -#include "openssl/x509.h" -#include "openssl/x509v3.h" -#include "openssl/pem.h" -#include "openssl/ssl.h" -#include "openssl/err.h" -#include "openssl/rand.h" - -/* Include generated data (error codes) */ -#include "_ssl_data.h" - -/* SSL error object */ -static PyObject *PySSLErrorObject; -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; +}; #ifdef WITH_THREAD @@ -186,12 +209,16 @@ typedef struct { char *npn_protocols; int npn_protocols_len; #endif +#ifndef OPENSSL_NO_TLSEXT + PyObject *set_hostname; +#endif } PySSLContext; typedef struct { PyObject_HEAD PyObject *Socket; /* weakref to socket on which we're layered */ SSL *ssl; + PySSLContext *ctx; /* weakref to SSL context */ X509 *peer_cert; int shutdown_seen_zero; enum py_ssl_server_or_client socket_type; @@ -442,11 +469,13 @@ _setSSLError (char *errstr, int errcode, char *filename, int lineno) { */ static PySSLSocket * -newPySSLSocket(SSL_CTX *ctx, PySocketSockObject *sock, +newPySSLSocket(PySSLContext *sslctx, PySocketSockObject *sock, enum py_ssl_server_or_client socket_type, char *server_hostname) { PySSLSocket *self; + SSL_CTX *ctx = sslctx->ctx; + long mode; self = PyObject_New(PySSLSocket, &PySSLSocket_Type); if (self == NULL) @@ -455,6 +484,8 @@ newPySSLSocket(SSL_CTX *ctx, PySocketSockObject *sock, self->peer_cert = NULL; self->ssl = NULL; self->Socket = NULL; + self->ctx = sslctx; + Py_INCREF(sslctx); /* Make sure the SSL error state is initialized */ (void) ERR_get_state(); @@ -463,12 +494,15 @@ newPySSLSocket(SSL_CTX *ctx, PySocketSockObject *sock, PySSL_BEGIN_ALLOW_THREADS self->ssl = SSL_new(ctx); PySSL_END_ALLOW_THREADS + SSL_set_app_data(self->ssl,self); SSL_set_fd(self->ssl, sock->sock_fd); + mode = SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER; #ifdef SSL_MODE_AUTO_RETRY - SSL_set_mode(self->ssl, SSL_MODE_AUTO_RETRY); + mode |= SSL_MODE_AUTO_RETRY; #endif + SSL_set_mode(self->ssl, mode); -#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME +#if HAVE_SNI if (server_hostname != NULL) SSL_set_tlsext_host_name(self->ssl, server_hostname); #endif @@ -1050,6 +1084,24 @@ _decode_certificate(X509 *certificate) { return NULL; } +static PyObject * +_certificate_to_der(X509 *certificate) +{ + unsigned char *bytes_buf = NULL; + int len; + PyObject *retval; + + bytes_buf = NULL; + len = i2d_X509(certificate, &bytes_buf); + if (len < 0) { + _setSSLError(NULL, 0, __FILE__, __LINE__); + return NULL; + } + /* this is actually an immutable bytes sequence */ + retval = PyBytes_FromStringAndSize((const char *) bytes_buf, len); + OPENSSL_free(bytes_buf); + return retval; +} static PyObject * PySSL_test_decode_certificate (PyObject *mod, PyObject *args) { @@ -1095,8 +1147,6 @@ PySSL_test_decode_certificate (PyObject *mod, PyObject *args) { static PyObject * PySSL_peercert(PySSLSocket *self, PyObject *args) { - PyObject *retval = NULL; - int len; int verification; int binary_mode = 0; @@ -1108,21 +1158,7 @@ PySSL_peercert(PySSLSocket *self, PyObject *args) if (binary_mode) { /* return cert in DER-encoded format */ - - unsigned char *bytes_buf = NULL; - - bytes_buf = NULL; - len = i2d_X509(self->peer_cert, &bytes_buf); - if (len < 0) { - PySSL_SetError(self, len, __FILE__, __LINE__); - return NULL; - } - /* this is actually an immutable bytes sequence */ - retval = PyBytes_FromStringAndSize - ((const char *) bytes_buf, len); - OPENSSL_free(bytes_buf); - return retval; - + return _certificate_to_der(self->peer_cert); } else { verification = SSL_CTX_get_verify_mode(SSL_get_SSL_CTX(self->ssl)); if ((verification & SSL_VERIFY_PEER) == 0) @@ -1225,6 +1261,43 @@ static PyObject *PySSL_compression(PySSLSocket *self) { #endif } +static PySSLContext *PySSL_get_context(PySSLSocket *self, void *closure) { + Py_INCREF(self->ctx); + return self->ctx; +} + +static int PySSL_set_context(PySSLSocket *self, PyObject *value, + void *closure) { + + 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"); + return -1; +#else + Py_INCREF(value); + Py_DECREF(self->ctx); + self->ctx = (PySSLContext *) value; + SSL_set_SSL_CTX(self->ssl, self->ctx->ctx); +#endif + } else { + PyErr_SetString(PyExc_TypeError, "The value must be a SSLContext"); + return -1; + } + + return 0; +} + +PyDoc_STRVAR(PySSL_set_context_doc, +"_setter_context(ctx)\n\ +\ +This changes the context associated with the SSLSocket. This is typically\n\ +used from within a callback function set by the set_servername_callback\n\ +on the SSLContext to change the certificate information associated with the\n\ +SSLSocket before the cryptographic exchange handshake messages\n"); + + + static void PySSL_dealloc(PySSLSocket *self) { if (self->peer_cert) /* Possible not to have one? */ @@ -1232,6 +1305,7 @@ static void PySSL_dealloc(PySSLSocket *self) if (self->ssl) SSL_free(self->ssl); Py_XDECREF(self->Socket); + Py_XDECREF(self->ctx); PyObject_Del(self); } @@ -1672,6 +1746,12 @@ If the TLS handshake is not yet complete, None is returned"); #endif /* HAVE_OPENSSL_FINISHED */ +static PyGetSetDef ssl_getsetlist[] = { + {"context", (getter) PySSL_get_context, + (setter) PySSL_set_context, PySSL_set_context_doc}, + {NULL}, /* sentinel */ +}; + static PyMethodDef PySSLMethods[] = { {"do_handshake", (PyCFunction)PySSL_SSLdo_handshake, METH_NOARGS}, {"write", (PyCFunction)PySSL_SSLwrite, METH_VARARGS, @@ -1726,6 +1806,8 @@ static PyTypeObject PySSLSocket_Type = { 0, /*tp_iter*/ 0, /*tp_iternext*/ PySSLMethods, /*tp_methods*/ + 0, /*tp_members*/ + ssl_getsetlist, /*tp_getset*/ }; @@ -1749,6 +1831,12 @@ context_new(PyTypeObject *type, PyObject *args, PyObject *kwds) PySSL_BEGIN_ALLOW_THREADS if (proto_version == PY_SSL_VERSION_TLS1) ctx = SSL_CTX_new(TLSv1_method()); +#if HAVE_TLSv1_2 + else if (proto_version == PY_SSL_VERSION_TLS1_1) + ctx = SSL_CTX_new(TLSv1_1_method()); + else if (proto_version == PY_SSL_VERSION_TLS1_2) + ctx = SSL_CTX_new(TLSv1_2_method()); +#endif else if (proto_version == PY_SSL_VERSION_SSL3) ctx = SSL_CTX_new(SSLv3_method()); #ifndef OPENSSL_NO_SSL2 @@ -1782,6 +1870,9 @@ context_new(PyTypeObject *type, PyObject *args, PyObject *kwds) #ifdef OPENSSL_NPN_NEGOTIATED self->npn_protocols = NULL; #endif +#ifndef OPENSSL_NO_TLSEXT + self->set_hostname = NULL; +#endif /* Defaults */ SSL_CTX_set_verify(self->ctx, SSL_VERIFY_NONE, NULL); SSL_CTX_set_options(self->ctx, @@ -1795,9 +1886,28 @@ context_new(PyTypeObject *type, PyObject *args, PyObject *kwds) return (PyObject *)self; } +static int +context_traverse(PySSLContext *self, visitproc visit, void *arg) +{ +#ifndef OPENSSL_NO_TLSEXT + Py_VISIT(self->set_hostname); +#endif + return 0; +} + +static int +context_clear(PySSLContext *self) +{ +#ifndef OPENSSL_NO_TLSEXT + Py_CLEAR(self->set_hostname); +#endif + return 0; +} + static void context_dealloc(PySSLContext *self) { + context_clear(self); SSL_CTX_free(self->ctx); #ifdef OPENSSL_NPN_NEGOTIATED PyMem_Free(self->npn_protocols); @@ -2021,8 +2131,8 @@ _pwinfo_set(_PySSLPasswordInfo *pw_info, PyObject* password, goto error; } - free(pw_info->password); - pw_info->password = malloc(size); + PyMem_Free(pw_info->password); + pw_info->password = PyMem_Malloc(size); if (!pw_info->password) { PyErr_SetString(PyExc_MemoryError, "unable to allocate password buffer"); @@ -2166,13 +2276,13 @@ load_cert_chain(PySSLContext *self, PyObject *args, PyObject *kwds) } SSL_CTX_set_default_passwd_cb(self->ctx, orig_passwd_cb); SSL_CTX_set_default_passwd_cb_userdata(self->ctx, orig_passwd_userdata); - free(pw_info.password); + PyMem_Free(pw_info.password); Py_RETURN_NONE; error: SSL_CTX_set_default_passwd_cb(self->ctx, orig_passwd_cb); SSL_CTX_set_default_passwd_cb_userdata(self->ctx, orig_passwd_userdata); - free(pw_info.password); + PyMem_Free(pw_info.password); Py_XDECREF(keyfile_bytes); Py_XDECREF(certfile_bytes); return NULL; @@ -2288,7 +2398,7 @@ context_wrap_socket(PySSLContext *self, PyObject *args, PyObject *kwds) &sock, &server_side, "idna", &hostname)) return NULL; -#ifndef SSL_CTRL_SET_TLSEXT_HOSTNAME +#if !HAVE_SNI PyMem_Free(hostname); PyErr_SetString(PyExc_ValueError, "server_hostname is not supported " "by your OpenSSL library"); @@ -2296,7 +2406,7 @@ context_wrap_socket(PySSLContext *self, PyObject *args, PyObject *kwds) #endif } - res = (PyObject *) newPySSLSocket(self->ctx, sock, server_side, + res = (PyObject *) newPySSLSocket(self, sock, server_side, hostname); if (hostname != NULL) PyMem_Free(hostname); @@ -2381,6 +2491,248 @@ set_ecdh_curve(PySSLContext *self, PyObject *name) } #endif +#if HAVE_SNI && !defined(OPENSSL_NO_TLSEXT) +static int +_servername_callback(SSL *s, int *al, void *args) +{ + int ret; + PySSLContext *ssl_ctx = (PySSLContext *) args; + PySSLSocket *ssl; + PyObject *servername_o; + PyObject *servername_idna; + PyObject *result; + /* The high-level ssl.SSLSocket object */ + PyObject *ssl_socket; + const char *servername = SSL_get_servername(s, TLSEXT_NAMETYPE_host_name); +#ifdef WITH_THREAD + PyGILState_STATE gstate = PyGILState_Ensure(); +#endif + + if (ssl_ctx->set_hostname == NULL) { + /* remove race condition in this the call back while if removing the + * callback is in progress */ +#ifdef WITH_THREAD + PyGILState_Release(gstate); +#endif + return SSL_TLSEXT_ERR_OK; + } + + ssl = SSL_get_app_data(s); + assert(PySSLSocket_Check(ssl)); + ssl_socket = PyWeakref_GetObject(ssl->Socket); + Py_INCREF(ssl_socket); + if (ssl_socket == Py_None) { + goto error; + } + + if (servername == NULL) { + result = PyObject_CallFunctionObjArgs(ssl_ctx->set_hostname, ssl_socket, + Py_None, ssl_ctx, NULL); + } + else { + servername_o = PyBytes_FromString(servername); + if (servername_o == NULL) { + PyErr_WriteUnraisable((PyObject *) ssl_ctx); + goto error; + } + servername_idna = PyUnicode_FromEncodedObject(servername_o, "idna", NULL); + if (servername_idna == NULL) { + PyErr_WriteUnraisable(servername_o); + Py_DECREF(servername_o); + goto error; + } + Py_DECREF(servername_o); + result = PyObject_CallFunctionObjArgs(ssl_ctx->set_hostname, ssl_socket, + servername_idna, ssl_ctx, NULL); + Py_DECREF(servername_idna); + } + Py_DECREF(ssl_socket); + + if (result == NULL) { + PyErr_WriteUnraisable(ssl_ctx->set_hostname); + *al = SSL_AD_HANDSHAKE_FAILURE; + ret = SSL_TLSEXT_ERR_ALERT_FATAL; + } + else { + if (result != Py_None) { + *al = (int) PyLong_AsLong(result); + if (PyErr_Occurred()) { + PyErr_WriteUnraisable(result); + *al = SSL_AD_INTERNAL_ERROR; + } + ret = SSL_TLSEXT_ERR_ALERT_FATAL; + } + else { + ret = SSL_TLSEXT_ERR_OK; + } + Py_DECREF(result); + } + +#ifdef WITH_THREAD + PyGILState_Release(gstate); +#endif + return ret; + +error: + Py_DECREF(ssl_socket); + *al = SSL_AD_INTERNAL_ERROR; + ret = SSL_TLSEXT_ERR_ALERT_FATAL; +#ifdef WITH_THREAD + PyGILState_Release(gstate); +#endif + return ret; +} +#endif + +PyDoc_STRVAR(PySSL_set_servername_callback_doc, +"set_servername_callback(method)\n\ +\n\ +This sets a callback that will be called when a server name is provided by\n\ +the SSL/TLS client in the SNI extension.\n\ +\n\ +If the argument is None then the callback is disabled. The method is called\n\ +with the SSLSocket, the server name as a string, and the SSLContext object.\n\ +See RFC 6066 for details of the SNI extension."); + +static PyObject * +set_servername_callback(PySSLContext *self, PyObject *args) +{ +#if HAVE_SNI && !defined(OPENSSL_NO_TLSEXT) + PyObject *cb; + + if (!PyArg_ParseTuple(args, "O", &cb)) + return NULL; + + Py_CLEAR(self->set_hostname); + if (cb == Py_None) { + SSL_CTX_set_tlsext_servername_callback(self->ctx, NULL); + } + else { + if (!PyCallable_Check(cb)) { + SSL_CTX_set_tlsext_servername_callback(self->ctx, NULL); + PyErr_SetString(PyExc_TypeError, + "not a callable object"); + return NULL; + } + Py_INCREF(cb); + self->set_hostname = cb; + SSL_CTX_set_tlsext_servername_callback(self->ctx, _servername_callback); + SSL_CTX_set_tlsext_servername_arg(self->ctx, self); + } + Py_RETURN_NONE; +#else + PyErr_SetString(PyExc_NotImplementedError, + "The TLS extension servername callback, " + "SSL_CTX_set_tlsext_servername_callback, " + "is not in the current OpenSSL library."); + return NULL; +#endif +} + +PyDoc_STRVAR(PySSL_get_stats_doc, +"cert_store_stats() -> {'crl': int, 'x509_ca': int, 'x509': int}\n\ +\n\ +Returns quantities of loaded X.509 certificates. X.509 certificates with a\n\ +CA extension and certificate revocation lists inside the context's cert\n\ +store.\n\ +NOTE: Certificates in a capath directory aren't loaded unless they have\n\ +been used at least once."); + +static PyObject * +cert_store_stats(PySSLContext *self) +{ + X509_STORE *store; + X509_OBJECT *obj; + int x509 = 0, crl = 0, pkey = 0, ca = 0, i; + + store = SSL_CTX_get_cert_store(self->ctx); + for (i = 0; i < sk_X509_OBJECT_num(store->objs); i++) { + obj = sk_X509_OBJECT_value(store->objs, i); + switch (obj->type) { + case X509_LU_X509: + x509++; + if (X509_check_ca(obj->data.x509)) { + ca++; + } + break; + case X509_LU_CRL: + crl++; + break; + case X509_LU_PKEY: + pkey++; + break; + default: + /* Ignore X509_LU_FAIL, X509_LU_RETRY, X509_LU_PKEY. + * As far as I can tell they are internal states and never + * stored in a cert store */ + break; + } + } + return Py_BuildValue("{sisisi}", "x509", x509, "crl", crl, + "x509_ca", ca); +} + +PyDoc_STRVAR(PySSL_get_ca_certs_doc, +"get_ca_certs([der=False]) -> list of loaded certificate\n\ +\n\ +Returns a list of dicts with information of loaded CA certs. If the\n\ +optional argument is True, returns a DER-encoded copy of the CA certificate.\n\ +NOTE: Certificates in a capath directory aren't loaded unless they have\n\ +been used at least once."); + +static PyObject * +get_ca_certs(PySSLContext *self, PyObject *args) +{ + X509_STORE *store; + PyObject *ci = NULL, *rlist = NULL; + int i; + int binary_mode = 0; + + if (!PyArg_ParseTuple(args, "|p:get_ca_certs", &binary_mode)) { + return NULL; + } + + if ((rlist = PyList_New(0)) == NULL) { + return NULL; + } + + store = SSL_CTX_get_cert_store(self->ctx); + for (i = 0; i < sk_X509_OBJECT_num(store->objs); i++) { + X509_OBJECT *obj; + X509 *cert; + + obj = sk_X509_OBJECT_value(store->objs, i); + if (obj->type != X509_LU_X509) { + /* not a x509 cert */ + continue; + } + /* CA for any purpose */ + cert = obj->data.x509; + if (!X509_check_ca(cert)) { + continue; + } + if (binary_mode) { + ci = _certificate_to_der(cert); + } else { + ci = _decode_certificate(cert); + } + if (ci == NULL) { + goto error; + } + if (PyList_Append(rlist, ci) == -1) { + goto error; + } + Py_CLEAR(ci); + } + return rlist; + + error: + Py_XDECREF(ci); + Py_XDECREF(rlist); + return NULL; +} + + static PyGetSetDef context_getsetlist[] = { {"options", (getter) get_options, (setter) set_options, NULL}, @@ -2410,6 +2762,12 @@ static struct PyMethodDef context_methods[] = { {"set_ecdh_curve", (PyCFunction) set_ecdh_curve, METH_O, NULL}, #endif + {"set_servername_callback", (PyCFunction) set_servername_callback, + METH_VARARGS, PySSL_set_servername_callback_doc}, + {"cert_store_stats", (PyCFunction) cert_store_stats, + METH_NOARGS, PySSL_get_stats_doc}, + {"get_ca_certs", (PyCFunction) get_ca_certs, + METH_VARARGS, PySSL_get_ca_certs_doc}, {NULL, NULL} /* sentinel */ }; @@ -2433,10 +2791,10 @@ static PyTypeObject PySSLContext_Type = { 0, /*tp_getattro*/ 0, /*tp_setattro*/ 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, /*tp_flags*/ 0, /*tp_doc*/ - 0, /*tp_traverse*/ - 0, /*tp_clear*/ + (traverseproc) context_traverse, /*tp_traverse*/ + (inquiry) context_clear, /*tp_clear*/ 0, /*tp_richcompare*/ 0, /*tp_weaklistoffset*/ 0, /*tp_iter*/ @@ -2647,7 +3005,169 @@ PySSL_RAND_atfork(void) #endif /* HAVE_OPENSSL_RAND */ +PyDoc_STRVAR(PySSL_get_default_verify_paths_doc, +"get_default_verify_paths() -> tuple\n\ +\n\ +Return search paths and environment vars that are used by SSLContext's\n\ +set_default_verify_paths() to load default CAs. The values are\n\ +'cert_file_env', 'cert_file', 'cert_dir_env', 'cert_dir'."); + +static PyObject * +PySSL_get_default_verify_paths(PyObject *self) +{ + PyObject *ofile_env = NULL; + PyObject *ofile = NULL; + PyObject *odir_env = NULL; + PyObject *odir = NULL; + +#define convert(info, target) { \ + const char *tmp = (info); \ + target = NULL; \ + if (!tmp) { Py_INCREF(Py_None); target = Py_None; } \ + else if ((target = PyUnicode_DecodeFSDefault(tmp)) == NULL) { \ + target = PyBytes_FromString(tmp); } \ + if (!target) goto error; \ + } while(0) + + convert(X509_get_default_cert_file_env(), ofile_env); + convert(X509_get_default_cert_file(), ofile); + convert(X509_get_default_cert_dir_env(), odir_env); + convert(X509_get_default_cert_dir(), odir); +#undef convert + + return Py_BuildValue("NNNN", ofile_env, ofile, odir_env, odir); + + error: + Py_XDECREF(ofile_env); + Py_XDECREF(ofile); + Py_XDECREF(odir_env); + Py_XDECREF(odir); + return NULL; +} +#ifdef _MSC_VER +PyDoc_STRVAR(PySSL_enum_cert_store_doc, +"enum_cert_store(store_name, cert_type='certificate') -> []\n\ +\n\ +Retrieve certificates from Windows' cert store. store_name may be one of\n\ +'CA', 'ROOT' or 'MY'. The system may provide more cert storages, too.\n\ +cert_type must be either 'certificate' or 'crl'.\n\ +The function returns a list of (bytes, encoding_type) tuples. The\n\ +encoding_type flag can be interpreted with X509_ASN_ENCODING or\n\ +PKCS_7_ASN_ENCODING."); + +static PyObject * +PySSL_enum_cert_store(PyObject *self, PyObject *args, PyObject *kwds) +{ + char *kwlist[] = {"store_name", "cert_type", NULL}; + char *store_name; + char *cert_type = "certificate"; + HCERTSTORE hStore = NULL; + PyObject *result = NULL; + PyObject *tup = NULL, *cert = NULL, *enc = NULL; + int ok = 1; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|s:enum_cert_store", + kwlist, &store_name, &cert_type)) { + return NULL; + } + + if ((strcmp(cert_type, "certificate") != 0) && + (strcmp(cert_type, "crl") != 0)) { + return PyErr_Format(PyExc_ValueError, + "cert_type must be 'certificate' or 'crl', " + "not %.100s", cert_type); + } + + if ((result = PyList_New(0)) == NULL) { + return NULL; + } + + if ((hStore = CertOpenSystemStore(NULL, store_name)) == NULL) { + Py_DECREF(result); + return PyErr_SetFromWindowsErr(GetLastError()); + } + + if (strcmp(cert_type, "certificate") == 0) { + PCCERT_CONTEXT pCertCtx = NULL; + while (pCertCtx = CertEnumCertificatesInStore(hStore, pCertCtx)) { + cert = PyBytes_FromStringAndSize((const char*)pCertCtx->pbCertEncoded, + pCertCtx->cbCertEncoded); + if (!cert) { + ok = 0; + break; + } + if ((enc = PyLong_FromLong(pCertCtx->dwCertEncodingType)) == NULL) { + ok = 0; + break; + } + if ((tup = PyTuple_New(2)) == NULL) { + ok = 0; + break; + } + PyTuple_SET_ITEM(tup, 0, cert); cert = NULL; + PyTuple_SET_ITEM(tup, 1, enc); enc = NULL; + + if (PyList_Append(result, tup) < 0) { + ok = 0; + break; + } + Py_CLEAR(tup); + } + if (pCertCtx) { + /* loop ended with an error, need to clean up context manually */ + CertFreeCertificateContext(pCertCtx); + } + } else { + PCCRL_CONTEXT pCrlCtx = NULL; + while (pCrlCtx = CertEnumCRLsInStore(hStore, pCrlCtx)) { + cert = PyBytes_FromStringAndSize((const char*)pCrlCtx->pbCrlEncoded, + pCrlCtx->cbCrlEncoded); + if (!cert) { + ok = 0; + break; + } + if ((enc = PyLong_FromLong(pCrlCtx->dwCertEncodingType)) == NULL) { + ok = 0; + break; + } + if ((tup = PyTuple_New(2)) == NULL) { + ok = 0; + break; + } + PyTuple_SET_ITEM(tup, 0, cert); cert = NULL; + PyTuple_SET_ITEM(tup, 1, enc); enc = NULL; + + if (PyList_Append(result, tup) < 0) { + ok = 0; + break; + } + Py_CLEAR(tup); + } + if (pCrlCtx) { + /* loop ended with an error, need to clean up context manually */ + CertFreeCRLContext(pCrlCtx); + } + } + + /* In error cases cert, enc and tup may not be NULL */ + Py_XDECREF(cert); + Py_XDECREF(enc); + Py_XDECREF(tup); + + if (!CertCloseStore(hStore, 0)) { + /* This error case might shadow another exception.*/ + Py_DECREF(result); + return PyErr_SetFromWindowsErr(GetLastError()); + } + if (ok) { + return result; + } else { + Py_DECREF(result); + return NULL; + } +} +#endif /* List of functions exported by this module. */ @@ -2666,6 +3186,12 @@ static PyMethodDef PySSL_methods[] = { {"RAND_status", (PyCFunction)PySSL_RAND_status, METH_NOARGS, PySSL_RAND_status_doc}, #endif + {"get_default_verify_paths", (PyCFunction)PySSL_get_default_verify_paths, + METH_NOARGS, PySSL_get_default_verify_paths_doc}, +#ifdef _MSC_VER + {"enum_cert_store", (PyCFunction)PySSL_enum_cert_store, + METH_VARARGS | METH_KEYWORDS, PySSL_enum_cert_store_doc}, +#endif {NULL, NULL} /* Sentinel */ }; @@ -2727,7 +3253,7 @@ static int _setup_ssl_threads(void) { if (_ssl_locks == NULL) { _ssl_locks_count = CRYPTO_num_locks(); _ssl_locks = (PyThread_type_lock *) - malloc(sizeof(PyThread_type_lock) * _ssl_locks_count); + PyMem_Malloc(sizeof(PyThread_type_lock) * _ssl_locks_count); if (_ssl_locks == NULL) return 0; memset(_ssl_locks, 0, @@ -2739,7 +3265,7 @@ static int _setup_ssl_threads(void) { for (j = 0; j < i; j++) { PyThread_free_lock(_ssl_locks[j]); } - free(_ssl_locks); + PyMem_Free(_ssl_locks); return 0; } } @@ -2894,6 +3420,63 @@ PyInit__ssl(void) PyModule_AddIntConstant(m, "CERT_REQUIRED", PY_SSL_CERT_REQUIRED); +#ifdef _MSC_VER + /* Windows dwCertEncodingType */ + PyModule_AddIntMacro(m, X509_ASN_ENCODING); + PyModule_AddIntMacro(m, PKCS_7_ASN_ENCODING); +#endif + + /* Alert Descriptions from ssl.h */ + /* note RESERVED constants no longer intended for use have been removed */ + /* http://www.iana.org/assignments/tls-parameters/tls-parameters.xml#tls-parameters-6 */ + +#define ADD_AD_CONSTANT(s) \ + PyModule_AddIntConstant(m, "ALERT_DESCRIPTION_"#s, \ + SSL_AD_##s) + + ADD_AD_CONSTANT(CLOSE_NOTIFY); + ADD_AD_CONSTANT(UNEXPECTED_MESSAGE); + ADD_AD_CONSTANT(BAD_RECORD_MAC); + ADD_AD_CONSTANT(RECORD_OVERFLOW); + ADD_AD_CONSTANT(DECOMPRESSION_FAILURE); + ADD_AD_CONSTANT(HANDSHAKE_FAILURE); + ADD_AD_CONSTANT(BAD_CERTIFICATE); + ADD_AD_CONSTANT(UNSUPPORTED_CERTIFICATE); + ADD_AD_CONSTANT(CERTIFICATE_REVOKED); + ADD_AD_CONSTANT(CERTIFICATE_EXPIRED); + ADD_AD_CONSTANT(CERTIFICATE_UNKNOWN); + ADD_AD_CONSTANT(ILLEGAL_PARAMETER); + ADD_AD_CONSTANT(UNKNOWN_CA); + ADD_AD_CONSTANT(ACCESS_DENIED); + ADD_AD_CONSTANT(DECODE_ERROR); + ADD_AD_CONSTANT(DECRYPT_ERROR); + ADD_AD_CONSTANT(PROTOCOL_VERSION); + ADD_AD_CONSTANT(INSUFFICIENT_SECURITY); + ADD_AD_CONSTANT(INTERNAL_ERROR); + ADD_AD_CONSTANT(USER_CANCELLED); + ADD_AD_CONSTANT(NO_RENEGOTIATION); + /* Not all constants are in old OpenSSL versions */ +#ifdef SSL_AD_UNSUPPORTED_EXTENSION + ADD_AD_CONSTANT(UNSUPPORTED_EXTENSION); +#endif +#ifdef SSL_AD_CERTIFICATE_UNOBTAINABLE + ADD_AD_CONSTANT(CERTIFICATE_UNOBTAINABLE); +#endif +#ifdef SSL_AD_UNRECOGNIZED_NAME + ADD_AD_CONSTANT(UNRECOGNIZED_NAME); +#endif +#ifdef SSL_AD_BAD_CERTIFICATE_STATUS_RESPONSE + ADD_AD_CONSTANT(BAD_CERTIFICATE_STATUS_RESPONSE); +#endif +#ifdef SSL_AD_BAD_CERTIFICATE_HASH_VALUE + ADD_AD_CONSTANT(BAD_CERTIFICATE_HASH_VALUE); +#endif +#ifdef SSL_AD_UNKNOWN_PSK_IDENTITY + ADD_AD_CONSTANT(UNKNOWN_PSK_IDENTITY); +#endif + +#undef ADD_AD_CONSTANT + /* protocol versions */ #ifndef OPENSSL_NO_SSL2 PyModule_AddIntConstant(m, "PROTOCOL_SSLv2", @@ -2905,6 +3488,12 @@ PyInit__ssl(void) PY_SSL_VERSION_SSL23); PyModule_AddIntConstant(m, "PROTOCOL_TLSv1", PY_SSL_VERSION_TLS1); +#if HAVE_TLSv1_2 + PyModule_AddIntConstant(m, "PROTOCOL_TLSv1_1", + PY_SSL_VERSION_TLS1_1); + PyModule_AddIntConstant(m, "PROTOCOL_TLSv1_2", + PY_SSL_VERSION_TLS1_2); +#endif /* protocol options */ PyModule_AddIntConstant(m, "OP_ALL", @@ -2912,6 +3501,10 @@ PyInit__ssl(void) PyModule_AddIntConstant(m, "OP_NO_SSLv2", SSL_OP_NO_SSLv2); PyModule_AddIntConstant(m, "OP_NO_SSLv3", SSL_OP_NO_SSLv3); PyModule_AddIntConstant(m, "OP_NO_TLSv1", SSL_OP_NO_TLSv1); +#if HAVE_TLSv1_2 + PyModule_AddIntConstant(m, "OP_NO_TLSv1_1", SSL_OP_NO_TLSv1_1); + PyModule_AddIntConstant(m, "OP_NO_TLSv1_2", SSL_OP_NO_TLSv1_2); +#endif PyModule_AddIntConstant(m, "OP_CIPHER_SERVER_PREFERENCE", SSL_OP_CIPHER_SERVER_PREFERENCE); PyModule_AddIntConstant(m, "OP_SINGLE_DH_USE", SSL_OP_SINGLE_DH_USE); @@ -2923,7 +3516,7 @@ PyInit__ssl(void) SSL_OP_NO_COMPRESSION); #endif -#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME +#if HAVE_SNI r = Py_True; #else r = Py_False; |