Issue #21965: Add support for in-memory SSL to the ssl module.

Patch by Geert Jansen.
This commit is contained in:
Antoine Pitrou 2014-10-05 20:41:53 +02:00
parent 414e15a88d
commit b1fdf47ff5
5 changed files with 926 additions and 102 deletions

View file

@ -64,6 +64,7 @@ static PySocketModule_APIObject PySocketModule;
#include "openssl/ssl.h"
#include "openssl/err.h"
#include "openssl/rand.h"
#include "openssl/bio.h"
/* SSL error object */
static PyObject *PySSLErrorObject;
@ -226,10 +227,19 @@ typedef struct {
char shutdown_seen_zero;
char handshake_done;
enum py_ssl_server_or_client socket_type;
PyObject *owner; /* Python level "owner" passed to servername callback */
PyObject *server_hostname;
} PySSLSocket;
typedef struct {
PyObject_HEAD
BIO *bio;
int eof_written;
} PySSLMemoryBIO;
static PyTypeObject PySSLContext_Type;
static PyTypeObject PySSLSocket_Type;
static PyTypeObject PySSLMemoryBIO_Type;
static PyObject *PySSL_SSLwrite(PySSLSocket *self, PyObject *args);
static PyObject *PySSL_SSLread(PySSLSocket *self, PyObject *args);
@ -240,6 +250,7 @@ static PyObject *PySSL_cipher(PySSLSocket *self);
#define PySSLContext_Check(v) (Py_TYPE(v) == &PySSLContext_Type)
#define PySSLSocket_Check(v) (Py_TYPE(v) == &PySSLSocket_Type)
#define PySSLMemoryBIO_Check(v) (Py_TYPE(v) == &PySSLMemoryBIO_Type)
typedef enum {
SOCKET_IS_NONBLOCKING,
@ -254,6 +265,9 @@ typedef enum {
#define ERRSTR1(x,y,z) (x ":" y ": " z)
#define ERRSTR(x) ERRSTR1("_ssl.c", Py_STRINGIFY(__LINE__), x)
/* Get the socket from a PySSLSocket, if it has one */
#define GET_SOCKET(obj) ((obj)->Socket ? \
(PySocketSockObject *) PyWeakref_GetObject((obj)->Socket) : NULL)
/*
* SSL errors.
@ -417,13 +431,12 @@ PySSL_SetError(PySSLSocket *obj, int ret, char *filename, int lineno)
case SSL_ERROR_SYSCALL:
{
if (e == 0) {
PySocketSockObject *s
= (PySocketSockObject *) PyWeakref_GetObject(obj->Socket);
PySocketSockObject *s = GET_SOCKET(obj);
if (ret == 0 || (((PyObject *)s) == Py_None)) {
p = PY_SSL_ERROR_EOF;
type = PySSLEOFErrorObject;
errstr = "EOF occurred in violation of protocol";
} else if (ret == -1) {
} else if (s && ret == -1) {
/* underlying BIO reported an I/O error */
Py_INCREF(s);
ERR_clear_error();
@ -477,10 +490,12 @@ _setSSLError (char *errstr, int errcode, char *filename, int lineno) {
static PySSLSocket *
newPySSLSocket(PySSLContext *sslctx, PySocketSockObject *sock,
enum py_ssl_server_or_client socket_type,
char *server_hostname)
char *server_hostname,
PySSLMemoryBIO *inbio, PySSLMemoryBIO *outbio)
{
PySSLSocket *self;
SSL_CTX *ctx = sslctx->ctx;
PyObject *hostname;
long mode;
self = PyObject_New(PySSLSocket, &PySSLSocket_Type);
@ -493,6 +508,18 @@ newPySSLSocket(PySSLContext *sslctx, PySocketSockObject *sock,
self->ctx = sslctx;
self->shutdown_seen_zero = 0;
self->handshake_done = 0;
self->owner = NULL;
if (server_hostname != NULL) {
hostname = PyUnicode_Decode(server_hostname, strlen(server_hostname),
"idna", "strict");
if (hostname == NULL) {
Py_DECREF(self);
return NULL;
}
self->server_hostname = hostname;
} else
self->server_hostname = NULL;
Py_INCREF(sslctx);
/* Make sure the SSL error state is initialized */
@ -502,8 +529,17 @@ newPySSLSocket(PySSLContext *sslctx, 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, Py_SAFE_DOWNCAST(sock->sock_fd, SOCKET_T, int));
SSL_set_app_data(self->ssl, self);
if (sock) {
SSL_set_fd(self->ssl, Py_SAFE_DOWNCAST(sock->sock_fd, SOCKET_T, int));
} else {
/* BIOs are reference counted and SSL_set_bio borrows our reference.
* To prevent a double free in memory_bio_dealloc() we need to take an
* extra reference here. */
CRYPTO_add(&inbio->bio->references, 1, CRYPTO_LOCK_BIO);
CRYPTO_add(&outbio->bio->references, 1, CRYPTO_LOCK_BIO);
SSL_set_bio(self->ssl, inbio->bio, outbio->bio);
}
mode = SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER;
#ifdef SSL_MODE_AUTO_RETRY
mode |= SSL_MODE_AUTO_RETRY;
@ -518,7 +554,7 @@ newPySSLSocket(PySSLContext *sslctx, PySocketSockObject *sock,
/* 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) {
if (sock && sock->sock_timeout >= 0.0) {
BIO_set_nbio(SSL_get_rbio(self->ssl), 1);
BIO_set_nbio(SSL_get_wbio(self->ssl), 1);
}
@ -531,10 +567,13 @@ newPySSLSocket(PySSLContext *sslctx, PySocketSockObject *sock,
PySSL_END_ALLOW_THREADS
self->socket_type = socket_type;
self->Socket = PyWeakref_NewRef((PyObject *) sock, NULL);
if (self->Socket == NULL) {
Py_DECREF(self);
return NULL;
if (sock != NULL) {
self->Socket = PyWeakref_NewRef((PyObject *) sock, NULL);
if (self->Socket == NULL) {
Py_DECREF(self);
Py_XDECREF(self->server_hostname);
return NULL;
}
}
return self;
}
@ -546,20 +585,21 @@ static PyObject *PySSL_SSLdo_handshake(PySSLSocket *self)
int ret;
int err;
int sockstate, nonblocking;
PySocketSockObject *sock
= (PySocketSockObject *) PyWeakref_GetObject(self->Socket);
PySocketSockObject *sock = GET_SOCKET(self);
if (((PyObject*)sock) == Py_None) {
_setSSLError("Underlying socket connection gone",
PY_SSL_ERROR_NO_SOCKET, __FILE__, __LINE__);
return NULL;
if (sock) {
if (((PyObject*)sock) == Py_None) {
_setSSLError("Underlying socket connection gone",
PY_SSL_ERROR_NO_SOCKET, __FILE__, __LINE__);
return NULL;
}
Py_INCREF(sock);
/* just in case the blocking state of the socket has been changed */
nonblocking = (sock->sock_timeout >= 0.0);
BIO_set_nbio(SSL_get_rbio(self->ssl), nonblocking);
BIO_set_nbio(SSL_get_wbio(self->ssl), nonblocking);
}
Py_INCREF(sock);
/* just in case the blocking state of the socket has been changed */
nonblocking = (sock->sock_timeout >= 0.0);
BIO_set_nbio(SSL_get_rbio(self->ssl), nonblocking);
BIO_set_nbio(SSL_get_wbio(self->ssl), nonblocking);
/* Actually negotiate SSL connection */
/* XXX If SSL_do_handshake() returns 0, it's also a failure. */
@ -593,7 +633,7 @@ static PyObject *PySSL_SSLdo_handshake(PySSLSocket *self)
break;
}
} while (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE);
Py_DECREF(sock);
Py_XDECREF(sock);
if (ret < 1)
return PySSL_SetError(self, ret, __FILE__, __LINE__);
@ -608,7 +648,7 @@ static PyObject *PySSL_SSLdo_handshake(PySSLSocket *self)
return Py_None;
error:
Py_DECREF(sock);
Py_XDECREF(sock);
return NULL;
}
@ -1483,6 +1523,54 @@ on the SSLContext to change the certificate information associated with the\n\
SSLSocket before the cryptographic exchange handshake messages\n");
static PyObject *
PySSL_get_server_side(PySSLSocket *self, void *c)
{
return PyBool_FromLong(self->socket_type == PY_SSL_SERVER);
}
PyDoc_STRVAR(PySSL_get_server_side_doc,
"Whether this is a server-side socket.");
static PyObject *
PySSL_get_server_hostname(PySSLSocket *self, void *c)
{
if (self->server_hostname == NULL)
Py_RETURN_NONE;
Py_INCREF(self->server_hostname);
return self->server_hostname;
}
PyDoc_STRVAR(PySSL_get_server_hostname_doc,
"The currently set server hostname (for SNI).");
static PyObject *
PySSL_get_owner(PySSLSocket *self, void *c)
{
PyObject *owner;
if (self->owner == NULL)
Py_RETURN_NONE;
owner = PyWeakref_GetObject(self->owner);
Py_INCREF(owner);
return owner;
}
static int
PySSL_set_owner(PySSLSocket *self, PyObject *value, void *c)
{
Py_XDECREF(self->owner);
self->owner = PyWeakref_NewRef(value, NULL);
if (self->owner == NULL)
return -1;
return 0;
}
PyDoc_STRVAR(PySSL_get_owner_doc,
"The Python-level owner of this object.\
Passed as \"self\" in servername callback.");
static void PySSL_dealloc(PySSLSocket *self)
{
@ -1492,6 +1580,8 @@ static void PySSL_dealloc(PySSLSocket *self)
SSL_free(self->ssl);
Py_XDECREF(self->Socket);
Py_XDECREF(self->ctx);
Py_XDECREF(self->server_hostname);
Py_XDECREF(self->owner);
PyObject_Del(self);
}
@ -1508,10 +1598,10 @@ check_socket_and_wait_for_timeout(PySocketSockObject *s, int writing)
int rc;
/* Nothing to do unless we're in timeout mode (not non-blocking) */
if (s->sock_timeout < 0.0)
return SOCKET_IS_BLOCKING;
else if (s->sock_timeout == 0.0)
if ((s == NULL) || (s->sock_timeout == 0.0))
return SOCKET_IS_NONBLOCKING;
else if (s->sock_timeout < 0.0)
return SOCKET_IS_BLOCKING;
/* Guard against closed socket */
if (s->sock_fd < 0)
@ -1572,18 +1662,19 @@ static PyObject *PySSL_SSLwrite(PySSLSocket *self, PyObject *args)
int sockstate;
int err;
int nonblocking;
PySocketSockObject *sock
= (PySocketSockObject *) PyWeakref_GetObject(self->Socket);
PySocketSockObject *sock = GET_SOCKET(self);
if (((PyObject*)sock) == Py_None) {
_setSSLError("Underlying socket connection gone",
PY_SSL_ERROR_NO_SOCKET, __FILE__, __LINE__);
return NULL;
if (sock != NULL) {
if (((PyObject*)sock) == Py_None) {
_setSSLError("Underlying socket connection gone",
PY_SSL_ERROR_NO_SOCKET, __FILE__, __LINE__);
return NULL;
}
Py_INCREF(sock);
}
Py_INCREF(sock);
if (!PyArg_ParseTuple(args, "y*:write", &buf)) {
Py_DECREF(sock);
Py_XDECREF(sock);
return NULL;
}
@ -1593,10 +1684,12 @@ static PyObject *PySSL_SSLwrite(PySSLSocket *self, PyObject *args)
goto error;
}
/* just in case the blocking state of the socket has been changed */
nonblocking = (sock->sock_timeout >= 0.0);
BIO_set_nbio(SSL_get_rbio(self->ssl), nonblocking);
BIO_set_nbio(SSL_get_wbio(self->ssl), nonblocking);
if (sock != NULL) {
/* just in case the blocking state of the socket has been changed */
nonblocking = (sock->sock_timeout >= 0.0);
BIO_set_nbio(SSL_get_rbio(self->ssl), nonblocking);
BIO_set_nbio(SSL_get_wbio(self->ssl), nonblocking);
}
sockstate = check_socket_and_wait_for_timeout(sock, 1);
if (sockstate == SOCKET_HAS_TIMED_OUT) {
@ -1640,7 +1733,7 @@ static PyObject *PySSL_SSLwrite(PySSLSocket *self, PyObject *args)
}
} while (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE);
Py_DECREF(sock);
Py_XDECREF(sock);
PyBuffer_Release(&buf);
if (len > 0)
return PyLong_FromLong(len);
@ -1648,7 +1741,7 @@ static PyObject *PySSL_SSLwrite(PySSLSocket *self, PyObject *args)
return PySSL_SetError(self, len, __FILE__, __LINE__);
error:
Py_DECREF(sock);
Py_XDECREF(sock);
PyBuffer_Release(&buf);
return NULL;
}
@ -1688,15 +1781,16 @@ static PyObject *PySSL_SSLread(PySSLSocket *self, PyObject *args)
int sockstate;
int err;
int nonblocking;
PySocketSockObject *sock
= (PySocketSockObject *) PyWeakref_GetObject(self->Socket);
PySocketSockObject *sock = GET_SOCKET(self);
if (((PyObject*)sock) == Py_None) {
_setSSLError("Underlying socket connection gone",
PY_SSL_ERROR_NO_SOCKET, __FILE__, __LINE__);
return NULL;
if (sock != NULL) {
if (((PyObject*)sock) == Py_None) {
_setSSLError("Underlying socket connection gone",
PY_SSL_ERROR_NO_SOCKET, __FILE__, __LINE__);
return NULL;
}
Py_INCREF(sock);
}
Py_INCREF(sock);
buf.obj = NULL;
buf.buf = NULL;
@ -1722,10 +1816,12 @@ static PyObject *PySSL_SSLread(PySSLSocket *self, PyObject *args)
}
}
/* just in case the blocking state of the socket has been changed */
nonblocking = (sock->sock_timeout >= 0.0);
BIO_set_nbio(SSL_get_rbio(self->ssl), nonblocking);
BIO_set_nbio(SSL_get_wbio(self->ssl), nonblocking);
if (sock != NULL) {
/* just in case the blocking state of the socket has been changed */
nonblocking = (sock->sock_timeout >= 0.0);
BIO_set_nbio(SSL_get_rbio(self->ssl), nonblocking);
BIO_set_nbio(SSL_get_wbio(self->ssl), nonblocking);
}
/* first check if there are bytes ready to be read */
PySSL_BEGIN_ALLOW_THREADS
@ -1781,7 +1877,7 @@ static PyObject *PySSL_SSLread(PySSLSocket *self, PyObject *args)
}
done:
Py_DECREF(sock);
Py_XDECREF(sock);
if (!buf_passed) {
_PyBytes_Resize(&dest, count);
return dest;
@ -1792,7 +1888,7 @@ done:
}
error:
Py_DECREF(sock);
Py_XDECREF(sock);
if (!buf_passed)
Py_XDECREF(dest);
else
@ -1809,21 +1905,22 @@ static PyObject *PySSL_SSLshutdown(PySSLSocket *self)
{
int err, ssl_err, sockstate, nonblocking;
int zeros = 0;
PySocketSockObject *sock
= (PySocketSockObject *) PyWeakref_GetObject(self->Socket);
PySocketSockObject *sock = GET_SOCKET(self);
/* Guard against closed socket */
if ((((PyObject*)sock) == Py_None) || (sock->sock_fd < 0)) {
_setSSLError("Underlying socket connection gone",
PY_SSL_ERROR_NO_SOCKET, __FILE__, __LINE__);
return NULL;
if (sock != NULL) {
/* Guard against closed socket */
if ((((PyObject*)sock) == Py_None) || (sock->sock_fd < 0)) {
_setSSLError("Underlying socket connection gone",
PY_SSL_ERROR_NO_SOCKET, __FILE__, __LINE__);
return NULL;
}
Py_INCREF(sock);
/* Just in case the blocking state of the socket has been changed */
nonblocking = (sock->sock_timeout >= 0.0);
BIO_set_nbio(SSL_get_rbio(self->ssl), nonblocking);
BIO_set_nbio(SSL_get_wbio(self->ssl), nonblocking);
}
Py_INCREF(sock);
/* Just in case the blocking state of the socket has been changed */
nonblocking = (sock->sock_timeout >= 0.0);
BIO_set_nbio(SSL_get_rbio(self->ssl), nonblocking);
BIO_set_nbio(SSL_get_wbio(self->ssl), nonblocking);
while (1) {
PySSL_BEGIN_ALLOW_THREADS
@ -1881,15 +1978,17 @@ static PyObject *PySSL_SSLshutdown(PySSLSocket *self)
}
if (err < 0) {
Py_DECREF(sock);
Py_XDECREF(sock);
return PySSL_SetError(self, err, __FILE__, __LINE__);
}
else
if (sock)
/* It's already INCREF'ed */
return (PyObject *) sock;
else
Py_RETURN_NONE;
error:
Py_DECREF(sock);
Py_XDECREF(sock);
return NULL;
}
@ -1937,6 +2036,12 @@ If the TLS handshake is not yet complete, None is returned");
static PyGetSetDef ssl_getsetlist[] = {
{"context", (getter) PySSL_get_context,
(setter) PySSL_set_context, PySSL_set_context_doc},
{"server_side", (getter) PySSL_get_server_side, NULL,
PySSL_get_server_side_doc},
{"server_hostname", (getter) PySSL_get_server_hostname, NULL,
PySSL_get_server_hostname_doc},
{"owner", (getter) PySSL_get_owner, (setter) PySSL_set_owner,
PySSL_get_owner_doc},
{NULL}, /* sentinel */
};
@ -2825,13 +2930,48 @@ context_wrap_socket(PySSLContext *self, PyObject *args, PyObject *kwds)
#endif
}
res = (PyObject *) newPySSLSocket(self, sock, server_side,
hostname);
res = (PyObject *) newPySSLSocket(self, sock, server_side, hostname,
NULL, NULL);
if (hostname != NULL)
PyMem_Free(hostname);
return res;
}
static PyObject *
context_wrap_bio(PySSLContext *self, PyObject *args, PyObject *kwds)
{
char *kwlist[] = {"incoming", "outgoing", "server_side",
"server_hostname", NULL};
int server_side;
char *hostname = NULL;
PyObject *hostname_obj = Py_None, *res;
PySSLMemoryBIO *incoming, *outgoing;
/* server_hostname is either None (or absent), or to be encoded
using the idna encoding. */
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!O!i|O:_wrap_bio", kwlist,
&PySSLMemoryBIO_Type, &incoming,
&PySSLMemoryBIO_Type, &outgoing,
&server_side, &hostname_obj))
return NULL;
if (hostname_obj != Py_None) {
#if HAVE_SNI
if (!PyArg_Parse(hostname_obj, "et", "idna", &hostname))
return NULL;
#else
PyErr_SetString(PyExc_ValueError, "server_hostname is not supported "
"by your OpenSSL library");
return NULL;
#endif
}
res = (PyObject *) newPySSLSocket(self, NULL, server_side, hostname,
incoming, outgoing);
PyMem_Free(hostname);
return res;
}
static PyObject *
session_stats(PySSLContext *self, PyObject *unused)
{
@ -2938,11 +3078,25 @@ _servername_callback(SSL *s, int *al, void *args)
ssl = SSL_get_app_data(s);
assert(PySSLSocket_Check(ssl));
ssl_socket = PyWeakref_GetObject(ssl->Socket);
/* The servername callback expects a argument that represents the current
* SSL connection and that has a .context attribute that can be changed to
* identify the requested hostname. Since the official API is the Python
* level API we want to pass the callback a Python level object rather than
* a _ssl.SSLSocket instance. If there's an "owner" (typically an
* SSLObject) that will be passed. Otherwise if there's a socket then that
* will be passed. If both do not exist only then the C-level object is
* passed. */
if (ssl->owner)
ssl_socket = PyWeakref_GetObject(ssl->owner);
else if (ssl->Socket)
ssl_socket = PyWeakref_GetObject(ssl->Socket);
else
ssl_socket = (PyObject *) ssl;
Py_INCREF(ssl_socket);
if (ssl_socket == Py_None) {
if (ssl_socket == Py_None)
goto error;
}
if (servername == NULL) {
result = PyObject_CallFunctionObjArgs(ssl_ctx->set_hostname, ssl_socket,
@ -3171,6 +3325,8 @@ static PyGetSetDef context_getsetlist[] = {
static struct PyMethodDef context_methods[] = {
{"_wrap_socket", (PyCFunction) context_wrap_socket,
METH_VARARGS | METH_KEYWORDS, NULL},
{"_wrap_bio", (PyCFunction) context_wrap_bio,
METH_VARARGS | METH_KEYWORDS, NULL},
{"set_ciphers", (PyCFunction) set_ciphers,
METH_VARARGS, NULL},
{"_set_npn_protocols", (PyCFunction) _set_npn_protocols,
@ -3240,6 +3396,225 @@ static PyTypeObject PySSLContext_Type = {
};
/*
* MemoryBIO objects
*/
static PyObject *
memory_bio_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
char *kwlist[] = {NULL};
BIO *bio;
PySSLMemoryBIO *self;
if (!PyArg_ParseTupleAndKeywords(args, kwds, ":MemoryBIO", kwlist))
return NULL;
bio = BIO_new(BIO_s_mem());
if (bio == NULL) {
PyErr_SetString(PySSLErrorObject,
"failed to allocate BIO");
return NULL;
}
/* Since our BIO is non-blocking an empty read() does not indicate EOF,
* just that no data is currently available. The SSL routines should retry
* the read, which we can achieve by calling BIO_set_retry_read(). */
BIO_set_retry_read(bio);
BIO_set_mem_eof_return(bio, -1);
assert(type != NULL && type->tp_alloc != NULL);
self = (PySSLMemoryBIO *) type->tp_alloc(type, 0);
if (self == NULL) {
BIO_free(bio);
return NULL;
}
self->bio = bio;
self->eof_written = 0;
return (PyObject *) self;
}
static void
memory_bio_dealloc(PySSLMemoryBIO *self)
{
BIO_free(self->bio);
Py_TYPE(self)->tp_free(self);
}
static PyObject *
memory_bio_get_pending(PySSLMemoryBIO *self, void *c)
{
return PyLong_FromLong(BIO_ctrl_pending(self->bio));
}
PyDoc_STRVAR(PySSL_memory_bio_pending_doc,
"The number of bytes pending in the memory BIO.");
static PyObject *
memory_bio_get_eof(PySSLMemoryBIO *self, void *c)
{
return PyBool_FromLong((BIO_ctrl_pending(self->bio) == 0)
&& self->eof_written);
}
PyDoc_STRVAR(PySSL_memory_bio_eof_doc,
"Whether the memory BIO is at EOF.");
static PyObject *
memory_bio_read(PySSLMemoryBIO *self, PyObject *args)
{
int len = -1, avail, nbytes;
PyObject *result;
if (!PyArg_ParseTuple(args, "|i:read", &len))
return NULL;
avail = BIO_ctrl_pending(self->bio);
if ((len < 0) || (len > avail))
len = avail;
result = PyBytes_FromStringAndSize(NULL, len);
if ((result == NULL) || (len == 0))
return result;
nbytes = BIO_read(self->bio, PyBytes_AS_STRING(result), len);
/* There should never be any short reads but check anyway. */
if ((nbytes < len) && (_PyBytes_Resize(&result, len) < 0)) {
Py_DECREF(result);
return NULL;
}
return result;
}
PyDoc_STRVAR(PySSL_memory_bio_read_doc,
"read([len]) -> bytes\n\
\n\
Read up to len bytes from the memory BIO.\n\
\n\
If len is not specified, read the entire buffer.\n\
If the return value is an empty bytes instance, this means either\n\
EOF or that no data is available. Use the \"eof\" property to\n\
distinguish between the two.");
static PyObject *
memory_bio_write(PySSLMemoryBIO *self, PyObject *args)
{
Py_buffer buf;
int nbytes;
if (!PyArg_ParseTuple(args, "y*:write", &buf))
return NULL;
if (buf.len > INT_MAX) {
PyErr_Format(PyExc_OverflowError,
"string longer than %d bytes", INT_MAX);
goto error;
}
if (self->eof_written) {
PyErr_SetString(PySSLErrorObject,
"cannot write() after write_eof()");
goto error;
}
nbytes = BIO_write(self->bio, buf.buf, buf.len);
if (nbytes < 0) {
_setSSLError(NULL, 0, __FILE__, __LINE__);
goto error;
}
PyBuffer_Release(&buf);
return PyLong_FromLong(nbytes);
error:
PyBuffer_Release(&buf);
return NULL;
}
PyDoc_STRVAR(PySSL_memory_bio_write_doc,
"write(b) -> len\n\
\n\
Writes the bytes b into the memory BIO. Returns the number\n\
of bytes written.");
static PyObject *
memory_bio_write_eof(PySSLMemoryBIO *self, PyObject *args)
{
self->eof_written = 1;
/* After an EOF is written, a zero return from read() should be a real EOF
* i.e. it should not be retried. Clear the SHOULD_RETRY flag. */
BIO_clear_retry_flags(self->bio);
BIO_set_mem_eof_return(self->bio, 0);
Py_RETURN_NONE;
}
PyDoc_STRVAR(PySSL_memory_bio_write_eof_doc,
"write_eof()\n\
\n\
Write an EOF marker to the memory BIO.\n\
When all data has been read, the \"eof\" property will be True.");
static PyGetSetDef memory_bio_getsetlist[] = {
{"pending", (getter) memory_bio_get_pending, NULL,
PySSL_memory_bio_pending_doc},
{"eof", (getter) memory_bio_get_eof, NULL,
PySSL_memory_bio_eof_doc},
{NULL}, /* sentinel */
};
static struct PyMethodDef memory_bio_methods[] = {
{"read", (PyCFunction) memory_bio_read,
METH_VARARGS, PySSL_memory_bio_read_doc},
{"write", (PyCFunction) memory_bio_write,
METH_VARARGS, PySSL_memory_bio_write_doc},
{"write_eof", (PyCFunction) memory_bio_write_eof,
METH_NOARGS, PySSL_memory_bio_write_eof_doc},
{NULL, NULL} /* sentinel */
};
static PyTypeObject PySSLMemoryBIO_Type = {
PyVarObject_HEAD_INIT(NULL, 0)
"_ssl.MemoryBIO", /*tp_name*/
sizeof(PySSLMemoryBIO), /*tp_basicsize*/
0, /*tp_itemsize*/
(destructor)memory_bio_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, /*tp_flags*/
0, /*tp_doc*/
0, /*tp_traverse*/
0, /*tp_clear*/
0, /*tp_richcompare*/
0, /*tp_weaklistoffset*/
0, /*tp_iter*/
0, /*tp_iternext*/
memory_bio_methods, /*tp_methods*/
0, /*tp_members*/
memory_bio_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*/
memory_bio_new, /*tp_new*/
};
#ifdef HAVE_OPENSSL_RAND
@ -3927,6 +4302,8 @@ PyInit__ssl(void)
return NULL;
if (PyType_Ready(&PySSLSocket_Type) < 0)
return NULL;
if (PyType_Ready(&PySSLMemoryBIO_Type) < 0)
return NULL;
m = PyModule_Create(&_sslmodule);
if (m == NULL)
@ -3990,6 +4367,9 @@ PyInit__ssl(void)
if (PyDict_SetItemString(d, "_SSLSocket",
(PyObject *)&PySSLSocket_Type) != 0)
return NULL;
if (PyDict_SetItemString(d, "MemoryBIO",
(PyObject *)&PySSLMemoryBIO_Type) != 0)
return NULL;
PyModule_AddIntConstant(m, "SSL_ERROR_ZERO_RETURN",
PY_SSL_ERROR_ZERO_RETURN);
PyModule_AddIntConstant(m, "SSL_ERROR_WANT_READ",