summaryrefslogtreecommitdiffstats
path: root/Modules/_ssl.c
diff options
context:
space:
mode:
Diffstat (limited to 'Modules/_ssl.c')
-rw-r--r--Modules/_ssl.c751
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;