diff -up Python-2.7.5/Modules/_ssl.c.wrap Python-2.7.5/Modules/_ssl.c
--- Python-2.7.5/Modules/_ssl.c.wrap 2015-06-25 09:09:59.646325880 +0200
+++ Python-2.7.5/Modules/_ssl.c 2015-06-25 10:33:20.349273370 +0200
@@ -224,6 +224,19 @@ typedef struct {
enum py_ssl_server_or_client socket_type;
} PySSLSocket;
+typedef struct {
+ PyObject_HEAD
+ PySocketSockObject *Socket; /* Socket on which we're layered */
+ PySSLContext* ctx;
+ SSL* ssl;
+ X509* peer_cert;
+ char server[X509_NAME_MAXLEN];
+ char issuer[X509_NAME_MAXLEN];
+ int shutdown_seen_zero;
+
+} PySSLObject;
+
+static PyTypeObject PySSL_Type;
static PyTypeObject PySSLContext_Type;
static PyTypeObject PySSLSocket_Type;
@@ -455,6 +468,138 @@ _setSSLError (char *errstr, int errcode,
* SSL objects
*/
+static PyObject *
+context_new_args(PyTypeObject *type, int proto_version);
+
+static PyObject *
+load_cert_chain_args(PySSLContext *self, char *certfile_bytes, char *keyfile_bytes, PyObject *password);
+
+static PyObject *
+set_ciphers_args(PySSLContext *self, const char *cipherlist);
+
+static PyObject *
+load_verify_locations_args(PySSLContext *self, PyObject *cafile, PyObject *capath, PyObject *cadata);
+
+static int
+set_verify_mode_args(PySSLContext *self, int n);
+
+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,
+ PyObject *cacerts_file, const char *ciphers)
+{
+ PySSLObject *self;
+ char *errstr = NULL;
+ SSL_CTX *ctx = NULL;
+
+
+ self = PyObject_New(PySSLObject, &PySSL_Type); /* Create new object */
+ if (self == NULL)
+ return NULL;
+ memset(self->server, '\0', sizeof(char) * X509_NAME_MAXLEN);
+ memset(self->issuer, '\0', sizeof(char) * X509_NAME_MAXLEN);
+
+ self->peer_cert = NULL;
+ self->ssl = NULL;
+ self->ctx = NULL;
+ self->Socket = NULL;
+ self->shutdown_seen_zero = 0;
+
+ /* Make sure the SSL error state is initialized */
+ (void) ERR_get_state();
+ ERR_clear_error();
+
+ 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;
+ }
+
+
+ if ((key_file && !cert_file) || (!key_file && cert_file)) {
+ errstr = ERRSTR("Both the key & certificate files "
+ "must be specified");
+ goto fail;
+ }
+
+
+ PyObject *sslctx = context_new_args(&PySSLContext_Type, proto_version);
+ if ((sslctx != NULL) && (PyObject_TypeCheck(sslctx, &PySSLContext_Type))) {
+#if !HAVE_SNI
+ errstr = ERRSTR("setting a socket's "
+ "context is not supported by your OpenSSL library");
+ goto fail;
+#else
+ self->ctx = (PySSLContext *) sslctx;
+ ctx = self->ctx->ctx;
+#endif
+ } else {
+ errstr = ERRSTR("The value must be a SSLContext");
+ goto fail;
+ }
+
+ if (key_file) {
+ load_cert_chain_args(self->ctx, cert_file, key_file, NULL);
+ }
+
+ if (ciphers != NULL) {
+ set_ciphers_args(self->ctx, ciphers);
+ }
+
+
+
+ if (certreq != PY_SSL_CERT_NONE) {
+ if (cacerts_file == Py_None) {
+ errstr = ERRSTR("No root certificates specified for "
+ "verification of other-side certificates.");
+ goto fail;
+ } else {
+ load_verify_locations_args(self->ctx, cacerts_file, NULL, NULL);
+ }
+ }
+
+ /* ssl compatibility */
+ SSL_CTX_set_options(ctx,
+ SSL_OP_ALL & ~SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS);
+
+ set_verify_mode_args(self->ctx, certreq);
+
+ PySSL_BEGIN_ALLOW_THREADS
+ self->ssl = SSL_new(ctx); /* New ssl struct */
+ PySSL_END_ALLOW_THREADS
+ SSL_set_fd(self->ssl, Sock->sock_fd); /* Set the socket for SSL */
+#ifdef SSL_MODE_AUTO_RETRY
+ SSL_set_mode(self->ssl, SSL_MODE_AUTO_RETRY);
+#endif
+
+ /* 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 */
+ BIO_set_nbio(SSL_get_rbio(self->ssl), 1);
+ BIO_set_nbio(SSL_get_wbio(self->ssl), 1);
+ }
+ PySSL_BEGIN_ALLOW_THREADS
+ if (socket_type == PY_SSL_CLIENT)
+ SSL_set_connect_state(self->ssl);
+ else
+ SSL_set_accept_state(self->ssl);
+ PySSL_END_ALLOW_THREADS
+
+ self->Socket = Sock;
+ Py_INCREF(self->Socket);
+ return self;
+ fail:
+ if (errstr)
+ PyErr_SetString(PySSLErrorObject, errstr);
+ Py_DECREF(self);
+ return NULL;
+}
+
static PySSLSocket *
newPySSLSocket(PySSLContext *sslctx, PySocketSockObject *sock,
enum py_ssl_server_or_client socket_type,
@@ -526,6 +671,47 @@ newPySSLSocket(PySSLContext *sslctx, PyS
}
+
+
+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;
+ PyObject *cacerts_file;
+ const 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(PySSLSocket *self)
@@ -1922,6 +2108,11 @@ static PyMethodDef PySSLMethods[] = {
{NULL, NULL}
};
+static PyObject *PySSL_getattr(PySSLObject *self, char *name)
+{
+ return Py_FindMethod(PySSLMethods, (PyObject *)self, name);
+}
+
static PyTypeObject PySSLSocket_Type = {
PyVarObject_HEAD_INIT(NULL, 0)
"_ssl._SSLSocket", /*tp_name*/
@@ -1956,25 +2147,49 @@ static PyTypeObject PySSLSocket_Type = {
ssl_getsetlist, /*tp_getset*/
};
+static PyTypeObject PySSL_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "ssl.SSLContext", /*tp_name*/
+ sizeof(PySSLObject), /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ /* methods */
+ (destructor)PySSL_dealloc, /*tp_dealloc*/
+ 0, /*tp_print*/
+ (getattrfunc)PySSL_getattr, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ 0, /*tp_repr*/
+ 0, /*tp_as_number*/
+ 0, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+ 0, /*tp_hash*/
+};
+
/*
* _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;
- long options;
- SSL_CTX *ctx = NULL;
if (!PyArg_ParseTupleAndKeywords(
args, kwds, "i:_SSLContext", kwlist,
&proto_version))
return NULL;
+ return context_new_args(type, proto_version);
+}
+static PyObject *
+context_new_args(PyTypeObject *type, int proto_version)
+{
+ SSL_CTX *ctx = NULL;
+ PySSLContext *self;
+ long options;
PySSL_BEGIN_ALLOW_THREADS
if (proto_version == PY_SSL_VERSION_TLS1)
ctx = SSL_CTX_new(TLSv1_method());
@@ -2082,11 +2297,16 @@ context_dealloc(PySSLContext *self)
static PyObject *
set_ciphers(PySSLContext *self, PyObject *args)
{
- int ret;
const char *cipherlist;
if (!PyArg_ParseTuple(args, "s:set_ciphers", &cipherlist))
return NULL;
+ return set_ciphers_args(self, cipherlist);
+ }
+
+static PyObject *
+set_ciphers_args(PySSLContext *self, const char *cipherlist){
+ int ret;
ret = SSL_CTX_set_cipher_list(self->ctx, cipherlist);
if (ret == 0) {
/* Clearing the error queue is necessary on some OpenSSL versions,
@@ -2204,9 +2424,17 @@ get_verify_mode(PySSLContext *self, void
static int
set_verify_mode(PySSLContext *self, PyObject *arg, void *c)
{
- int n, mode;
+ int n;
if (!PyArg_Parse(arg, "i", &n))
return -1;
+ return set_verify_mode_args(self, n);
+ }
+
+static int
+set_verify_mode_args(PySSLContext *self, int n)
+{
+ int mode;
+
if (n == PY_SSL_CERT_NONE)
mode = SSL_VERIFY_NONE;
else if (n == PY_SSL_CERT_OPTIONAL)
@@ -2434,10 +2662,6 @@ load_cert_chain(PySSLContext *self, PyOb
char *kwlist[] = {"certfile", "keyfile", "password", NULL};
PyObject *password = NULL;
char *certfile_bytes = NULL, *keyfile_bytes = NULL;
- pem_password_cb *orig_passwd_cb = self->ctx->default_passwd_callback;
- void *orig_passwd_userdata = self->ctx->default_passwd_callback_userdata;
- _PySSLPasswordInfo pw_info = { NULL, NULL, NULL, 0, 0 };
- int r;
errno = 0;
ERR_clear_error();
@@ -2447,6 +2671,17 @@ load_cert_chain(PySSLContext *self, PyOb
Py_FileSystemDefaultEncoding, &keyfile_bytes,
&password))
return NULL;
+ return load_cert_chain_args(self, certfile_bytes, keyfile_bytes, password);
+ }
+
+static PyObject *
+load_cert_chain_args(PySSLContext *self, char *certfile_bytes, char *keyfile_bytes ,PyObject *password){
+
+ pem_password_cb *orig_passwd_cb = self->ctx->default_passwd_callback;
+ void *orig_passwd_userdata = self->ctx->default_passwd_callback_userdata;
+ _PySSLPasswordInfo pw_info = { NULL, NULL, NULL, 0, 0 };
+ int r;
+
if (password && password != Py_None) {
if (PyCallable_Check(password)) {
pw_info.callable = password;
@@ -2598,22 +2833,27 @@ _add_ca_certs(PySSLContext *self, void *
return retval;
}
-
static PyObject *
load_verify_locations(PySSLContext *self, PyObject *args, PyObject *kwds)
{
char *kwlist[] = {"cafile", "capath", "cadata", NULL};
PyObject *cadata = NULL, *cafile = NULL, *capath = NULL;
- PyObject *cafile_bytes = NULL, *capath_bytes = NULL;
- const char *cafile_buf = NULL, *capath_buf = NULL;
- int r = 0, ok = 1;
-
- errno = 0;
if (!PyArg_ParseTupleAndKeywords(args, kwds,
"|OOO:load_verify_locations", kwlist,
&cafile, &capath, &cadata))
return NULL;
+ return load_verify_locations_args(self, cafile, capath, cadata);
+ }
+
+static PyObject *
+load_verify_locations_args(PySSLContext *self, PyObject *cafile, PyObject *capath, PyObject *cadata)
+{
+ PyObject *cafile_bytes = NULL, *capath_bytes = NULL;
+ const char *cafile_buf = NULL, *capath_buf = NULL;
+ int r = 0, ok = 1;
+
+ errno = 0;
if (cafile == Py_None)
cafile = NULL;
if (capath == Py_None)
@@ -3688,6 +3928,8 @@ PySSL_enum_crls(PyObject *self, PyObject
/* 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