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