diff options
Diffstat (limited to 'Modules/_ssl.c')
-rw-r--r-- | Modules/_ssl.c | 918 |
1 files changed, 692 insertions, 226 deletions
diff --git a/Modules/_ssl.c b/Modules/_ssl.c index c27073c..bb838b0 100644 --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -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; @@ -108,6 +109,11 @@ struct py_ssl_library_code { # define HAVE_SNI 0 #endif +/* ALPN added in OpenSSL 1.0.2 */ +#if !defined(LIBRESSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x1000200fL && !defined(OPENSSL_NO_TLSEXT) +# define HAVE_ALPN +#endif + enum py_ssl_error { /* these mirror ssl.h */ PY_SSL_ERROR_NONE, @@ -161,13 +167,6 @@ static unsigned int _ssl_locks_count = 0; #define X509_NAME_MAXLEN 256 -/* RAND_* APIs got added to OpenSSL in 0.9.5 */ -#if OPENSSL_VERSION_NUMBER >= 0x0090500fL -# define HAVE_OPENSSL_RAND 1 -#else -# undef HAVE_OPENSSL_RAND -#endif - /* SSL_CTX_clear_options() and SSL_clear_options() were first added in * OpenSSL 0.9.8m but do not appear in some 0.9.9-dev versions such the * 0.9.9 from "May 2008" that NetBSD 5.0 uses. */ @@ -181,36 +180,18 @@ static unsigned int _ssl_locks_count = 0; * older SSL, but let's be safe */ #define PySSL_CB_MAXLEN 128 -/* SSL_get_finished got added to OpenSSL in 0.9.5 */ -#if OPENSSL_VERSION_NUMBER >= 0x0090500fL -# define HAVE_OPENSSL_FINISHED 1 -#else -# define HAVE_OPENSSL_FINISHED 0 -#endif - -/* ECDH support got added to OpenSSL in 0.9.8 */ -#if OPENSSL_VERSION_NUMBER < 0x0090800fL && !defined(OPENSSL_NO_ECDH) -# define OPENSSL_NO_ECDH -#endif - -/* compression support got added to OpenSSL in 0.9.8 */ -#if OPENSSL_VERSION_NUMBER < 0x0090800fL && !defined(OPENSSL_NO_COMP) -# define OPENSSL_NO_COMP -#endif - -/* X509_VERIFY_PARAM got added to OpenSSL in 0.9.8 */ -#if OPENSSL_VERSION_NUMBER >= 0x0090800fL -# define HAVE_OPENSSL_VERIFY_PARAM -#endif - typedef struct { PyObject_HEAD SSL_CTX *ctx; #ifdef OPENSSL_NPN_NEGOTIATED - char *npn_protocols; + unsigned char *npn_protocols; int npn_protocols_len; #endif +#ifdef HAVE_ALPN + unsigned char *alpn_protocols; + int alpn_protocols_len; +#endif #ifndef OPENSSL_NO_TLSEXT PyObject *set_hostname; #endif @@ -226,20 +207,29 @@ 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); -static int check_socket_and_wait_for_timeout(PySocketSockObject *s, - int writing); +static int PySSL_select(PySocketSockObject *s, int writing); static PyObject *PySSL_peercert(PySSLSocket *self, PyObject *args); 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, @@ -251,11 +241,12 @@ typedef enum { } timeout_state; /* Wrap error strings with filename and line # */ -#define STRINGIFY1(x) #x -#define STRINGIFY2(x) STRINGIFY1(x) #define ERRSTR1(x,y,z) (x ":" y ": " z) -#define ERRSTR(x) ERRSTR1("_ssl.c", STRINGIFY2(__LINE__), x) +#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. @@ -419,13 +410,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(); @@ -479,10 +469,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); @@ -495,6 +487,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 */ @@ -504,8 +508,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; @@ -520,7 +533,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) { BIO_set_nbio(SSL_get_rbio(self->ssl), 1); BIO_set_nbio(SSL_get_wbio(self->ssl), 1); } @@ -533,10 +546,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; } @@ -548,20 +564,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; - } - Py_INCREF(sock); + 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); + /* just in case the blocking state of the socket has been changed */ + nonblocking = (sock->sock_timeout >= 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. */ @@ -570,15 +587,18 @@ static PyObject *PySSL_SSLdo_handshake(PySSLSocket *self) ret = SSL_do_handshake(self->ssl); err = SSL_get_error(self->ssl, ret); PySSL_END_ALLOW_THREADS + if (PyErr_CheckSignals()) goto error; + if (err == SSL_ERROR_WANT_READ) { - sockstate = check_socket_and_wait_for_timeout(sock, 0); + sockstate = PySSL_select(sock, 0); } else if (err == SSL_ERROR_WANT_WRITE) { - sockstate = check_socket_and_wait_for_timeout(sock, 1); + sockstate = PySSL_select(sock, 1); } else { sockstate = SOCKET_OPERATION_OK; } + if (sockstate == SOCKET_HAS_TIMED_OUT) { PyErr_SetString(PySocketModule.timeout_error, ERRSTR("The handshake operation timed out")); @@ -595,7 +615,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__); @@ -610,7 +630,7 @@ static PyObject *PySSL_SSLdo_handshake(PySSLSocket *self) return Py_None; error: - Py_DECREF(sock); + Py_XDECREF(sock); return NULL; } @@ -779,12 +799,7 @@ _get_peer_alt_names (X509 *certificate) { char buf[2048]; char *vptr; int len; - /* Issue #2973: ASN1_item_d2i() API changed in OpenSSL 0.9.6m */ -#if OPENSSL_VERSION_NUMBER >= 0x009060dfL const unsigned char *p; -#else - unsigned char *p; -#endif if (certificate == NULL) return peer_alt_names; @@ -1356,54 +1371,96 @@ If the optional argument is True, returns a DER-encoded copy of the\n\ peer certificate, or None if no certificate was provided. This will\n\ return the certificate even if it wasn't validated."); -static PyObject *PySSL_cipher (PySSLSocket *self) { - - PyObject *retval, *v; - const SSL_CIPHER *current; - char *cipher_name; - char *cipher_protocol; - - if (self->ssl == NULL) - Py_RETURN_NONE; - current = SSL_get_current_cipher(self->ssl); - if (current == NULL) - Py_RETURN_NONE; - - retval = PyTuple_New(3); +static PyObject * +cipher_to_tuple(const SSL_CIPHER *cipher) +{ + const char *cipher_name, *cipher_protocol; + PyObject *v, *retval = PyTuple_New(3); if (retval == NULL) return NULL; - cipher_name = (char *) SSL_CIPHER_get_name(current); + cipher_name = SSL_CIPHER_get_name(cipher); if (cipher_name == NULL) { Py_INCREF(Py_None); PyTuple_SET_ITEM(retval, 0, Py_None); } else { v = PyUnicode_FromString(cipher_name); if (v == NULL) - goto fail0; + goto fail; PyTuple_SET_ITEM(retval, 0, v); } - cipher_protocol = (char *) SSL_CIPHER_get_version(current); + + cipher_protocol = SSL_CIPHER_get_version(cipher); if (cipher_protocol == NULL) { Py_INCREF(Py_None); PyTuple_SET_ITEM(retval, 1, Py_None); } else { v = PyUnicode_FromString(cipher_protocol); if (v == NULL) - goto fail0; + goto fail; PyTuple_SET_ITEM(retval, 1, v); } - v = PyLong_FromLong(SSL_CIPHER_get_bits(current, NULL)); + + v = PyLong_FromLong(SSL_CIPHER_get_bits(cipher, NULL)); if (v == NULL) - goto fail0; + goto fail; PyTuple_SET_ITEM(retval, 2, v); + return retval; - fail0: + fail: Py_DECREF(retval); return NULL; } +static PyObject *PySSL_shared_ciphers(PySSLSocket *self) +{ + SSL_SESSION *sess = SSL_get_session(self->ssl); + STACK_OF(SSL_CIPHER) *ciphers; + int i; + PyObject *res; + + if (!sess || !sess->ciphers) + Py_RETURN_NONE; + ciphers = sess->ciphers; + res = PyList_New(sk_SSL_CIPHER_num(ciphers)); + if (!res) + return NULL; + for (i = 0; i < sk_SSL_CIPHER_num(ciphers); i++) { + PyObject *tup = cipher_to_tuple(sk_SSL_CIPHER_value(ciphers, i)); + if (!tup) { + Py_DECREF(res); + return NULL; + } + PyList_SET_ITEM(res, i, tup); + } + return res; +} + +static PyObject *PySSL_cipher (PySSLSocket *self) +{ + const SSL_CIPHER *current; + + if (self->ssl == NULL) + Py_RETURN_NONE; + current = SSL_get_current_cipher(self->ssl); + if (current == NULL) + Py_RETURN_NONE; + return cipher_to_tuple(current); +} + +static PyObject *PySSL_version(PySSLSocket *self) +{ + const char *version; + + if (self->ssl == NULL) + Py_RETURN_NONE; + version = SSL_get_version(self->ssl); + if (!strcmp(version, "unknown")) + Py_RETURN_NONE; + return PyUnicode_FromString(version); +} + #ifdef OPENSSL_NPN_NEGOTIATED static PyObject *PySSL_selected_npn_protocol(PySSLSocket *self) { const unsigned char *out; @@ -1414,7 +1471,20 @@ static PyObject *PySSL_selected_npn_protocol(PySSLSocket *self) { if (out == NULL) Py_RETURN_NONE; - return PyUnicode_FromStringAndSize((char *) out, outlen); + return PyUnicode_FromStringAndSize((char *)out, outlen); +} +#endif + +#ifdef HAVE_ALPN +static PyObject *PySSL_selected_alpn_protocol(PySSLSocket *self) { + const unsigned char *out; + unsigned int outlen; + + SSL_get0_alpn_selected(self->ssl, &out, &outlen); + + if (out == NULL) + Py_RETURN_NONE; + return PyUnicode_FromStringAndSize((char *)out, outlen); } #endif @@ -1473,6 +1543,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) { @@ -1482,6 +1600,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); } @@ -1491,17 +1611,23 @@ static void PySSL_dealloc(PySSLSocket *self) */ static int -check_socket_and_wait_for_timeout(PySocketSockObject *s, int writing) +PySSL_select(PySocketSockObject *s, int writing) { + int rc; +#ifdef HAVE_POLL + struct pollfd pollfd; + _PyTime_t ms; +#else + int nfds; fd_set fds; struct timeval tv; - int rc; +#endif /* 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)) return SOCKET_IS_NONBLOCKING; + else if (s->sock_timeout < 0) + return SOCKET_IS_BLOCKING; /* Guard against closed socket */ if (s->sock_fd < 0) @@ -1510,46 +1636,36 @@ check_socket_and_wait_for_timeout(PySocketSockObject *s, int writing) /* Prefer poll, if available, since you can poll() any fd * which can't be done with select(). */ #ifdef HAVE_POLL - { - struct pollfd pollfd; - int timeout; + pollfd.fd = s->sock_fd; + pollfd.events = writing ? POLLOUT : POLLIN; - pollfd.fd = s->sock_fd; - pollfd.events = writing ? POLLOUT : POLLIN; - - /* s->sock_timeout is in seconds, timeout in ms */ - timeout = (int)(s->sock_timeout * 1000 + 0.5); - PySSL_BEGIN_ALLOW_THREADS - rc = poll(&pollfd, 1, timeout); - PySSL_END_ALLOW_THREADS - - goto normal_return; - } -#endif + /* s->sock_timeout is in seconds, timeout in ms */ + ms = (int)_PyTime_AsMilliseconds(s->sock_timeout, _PyTime_ROUND_CEILING); + assert(ms <= INT_MAX); + PySSL_BEGIN_ALLOW_THREADS + rc = poll(&pollfd, 1, (int)ms); + PySSL_END_ALLOW_THREADS +#else /* Guard against socket too large for select*/ if (!_PyIsSelectable_fd(s->sock_fd)) return SOCKET_TOO_LARGE_FOR_SELECT; - /* Construct the arguments to select */ - tv.tv_sec = (int)s->sock_timeout; - tv.tv_usec = (int)((s->sock_timeout - tv.tv_sec) * 1e6); + _PyTime_AsTimeval_noraise(s->sock_timeout, &tv, _PyTime_ROUND_CEILING); + FD_ZERO(&fds); FD_SET(s->sock_fd, &fds); - /* See if the socket is ready */ + /* Wait until the socket becomes ready */ PySSL_BEGIN_ALLOW_THREADS + nfds = Py_SAFE_DOWNCAST(s->sock_fd+1, SOCKET_T, int); if (writing) - rc = select(Py_SAFE_DOWNCAST(s->sock_fd+1, SOCKET_T, int), - NULL, &fds, NULL, &tv); + rc = select(nfds, NULL, &fds, NULL, &tv); else - rc = select(Py_SAFE_DOWNCAST(s->sock_fd+1, SOCKET_T, int), - &fds, NULL, NULL, &tv); + rc = select(nfds, &fds, NULL, NULL, &tv); PySSL_END_ALLOW_THREADS - -#ifdef HAVE_POLL -normal_return: #endif + /* Return SOCKET_TIMED_OUT on timeout, SOCKET_OPERATION_OK otherwise (when we are able to write or when there's something to read) */ return rc == 0 ? SOCKET_HAS_TIMED_OUT : SOCKET_OPERATION_OK; @@ -1562,18 +1678,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; } @@ -1583,12 +1700,14 @@ 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); + 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); + sockstate = PySSL_select(sock, 1); if (sockstate == SOCKET_HAS_TIMED_OUT) { PyErr_SetString(PySocketModule.timeout_error, "The write operation timed out"); @@ -1602,21 +1721,24 @@ static PyObject *PySSL_SSLwrite(PySSLSocket *self, PyObject *args) "Underlying socket too large for select()."); goto error; } + do { PySSL_BEGIN_ALLOW_THREADS len = SSL_write(self->ssl, buf.buf, (int)buf.len); err = SSL_get_error(self->ssl, len); PySSL_END_ALLOW_THREADS - if (PyErr_CheckSignals()) { + + if (PyErr_CheckSignals()) goto error; - } + if (err == SSL_ERROR_WANT_READ) { - sockstate = check_socket_and_wait_for_timeout(sock, 0); + sockstate = PySSL_select(sock, 0); } else if (err == SSL_ERROR_WANT_WRITE) { - sockstate = check_socket_and_wait_for_timeout(sock, 1); + sockstate = PySSL_select(sock, 1); } else { sockstate = SOCKET_OPERATION_OK; } + if (sockstate == SOCKET_HAS_TIMED_OUT) { PyErr_SetString(PySocketModule.timeout_error, "The write operation timed out"); @@ -1630,7 +1752,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); @@ -1638,7 +1760,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; } @@ -1678,15 +1800,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; @@ -1712,31 +1835,35 @@ 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); + BIO_set_nbio(SSL_get_rbio(self->ssl), nonblocking); + BIO_set_nbio(SSL_get_wbio(self->ssl), nonblocking); + } do { PySSL_BEGIN_ALLOW_THREADS count = SSL_read(self->ssl, mem, len); err = SSL_get_error(self->ssl, count); PySSL_END_ALLOW_THREADS + if (PyErr_CheckSignals()) goto error; + if (err == SSL_ERROR_WANT_READ) { - sockstate = check_socket_and_wait_for_timeout(sock, 0); + sockstate = PySSL_select(sock, 0); } else if (err == SSL_ERROR_WANT_WRITE) { - sockstate = check_socket_and_wait_for_timeout(sock, 1); - } else if ((err == SSL_ERROR_ZERO_RETURN) && - (SSL_get_shutdown(self->ssl) == - SSL_RECEIVED_SHUTDOWN)) + sockstate = PySSL_select(sock, 1); + } else if (err == SSL_ERROR_ZERO_RETURN && + SSL_get_shutdown(self->ssl) == SSL_RECEIVED_SHUTDOWN) { count = 0; goto done; - } else { - sockstate = SOCKET_OPERATION_OK; } + else + sockstate = SOCKET_OPERATION_OK; + if (sockstate == SOCKET_HAS_TIMED_OUT) { PyErr_SetString(PySocketModule.timeout_error, "The read operation timed out"); @@ -1745,13 +1872,14 @@ static PyObject *PySSL_SSLread(PySSLSocket *self, PyObject *args) break; } } while (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE); + if (count <= 0) { PySSL_SetError(self, count, __FILE__, __LINE__); goto error; } done: - Py_DECREF(sock); + Py_XDECREF(sock); if (!buf_passed) { _PyBytes_Resize(&dest, count); return dest; @@ -1762,7 +1890,7 @@ done: } error: - Py_DECREF(sock); + Py_XDECREF(sock); if (!buf_passed) Py_XDECREF(dest); else @@ -1779,21 +1907,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; - } - Py_INCREF(sock); + 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); + /* Just in case the blocking state of the socket has been changed */ + nonblocking = (sock->sock_timeout >= 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 @@ -1809,6 +1938,7 @@ static PyObject *PySSL_SSLshutdown(PySSLSocket *self) SSL_set_read_ahead(self->ssl, 0); err = SSL_shutdown(self->ssl); PySSL_END_ALLOW_THREADS + /* If err == 1, a secure shutdown with SSL_shutdown() is complete */ if (err > 0) break; @@ -1826,11 +1956,12 @@ static PyObject *PySSL_SSLshutdown(PySSLSocket *self) /* Possibly retry shutdown until timeout or failure */ ssl_err = SSL_get_error(self->ssl, err); if (ssl_err == SSL_ERROR_WANT_READ) - sockstate = check_socket_and_wait_for_timeout(sock, 0); + sockstate = PySSL_select(sock, 0); else if (ssl_err == SSL_ERROR_WANT_WRITE) - sockstate = check_socket_and_wait_for_timeout(sock, 1); + sockstate = PySSL_select(sock, 1); else break; + if (sockstate == SOCKET_HAS_TIMED_OUT) { if (ssl_err == SSL_ERROR_WANT_READ) PyErr_SetString(PySocketModule.timeout_error, @@ -1851,15 +1982,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; } @@ -1869,7 +2002,6 @@ PyDoc_STRVAR(PySSL_SSLshutdown_doc, Does the SSL shutdown handshake with the remote end, and returns\n\ the underlying socket object."); -#if HAVE_OPENSSL_FINISHED static PyObject * PySSL_tls_unique_cb(PySSLSocket *self) { @@ -1902,11 +2034,15 @@ Returns the 'tls-unique' channel binding data, as defined by RFC 5929.\n\ \n\ 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}, + {"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 */ }; @@ -1921,16 +2057,19 @@ static PyMethodDef PySSLMethods[] = { {"peer_certificate", (PyCFunction)PySSL_peercert, METH_VARARGS, PySSL_peercert_doc}, {"cipher", (PyCFunction)PySSL_cipher, METH_NOARGS}, + {"shared_ciphers", (PyCFunction)PySSL_shared_ciphers, METH_NOARGS}, + {"version", (PyCFunction)PySSL_version, METH_NOARGS}, #ifdef OPENSSL_NPN_NEGOTIATED {"selected_npn_protocol", (PyCFunction)PySSL_selected_npn_protocol, METH_NOARGS}, #endif +#ifdef HAVE_ALPN + {"selected_alpn_protocol", (PyCFunction)PySSL_selected_alpn_protocol, METH_NOARGS}, +#endif {"compression", (PyCFunction)PySSL_compression, METH_NOARGS}, {"shutdown", (PyCFunction)PySSL_SSLshutdown, METH_NOARGS, PySSL_SSLshutdown_doc}, -#if HAVE_OPENSSL_FINISHED {"tls_unique_cb", (PyCFunction)PySSL_tls_unique_cb, METH_NOARGS, PySSL_tls_unique_cb_doc}, -#endif {NULL, NULL} }; @@ -2031,6 +2170,9 @@ context_new(PyTypeObject *type, PyObject *args, PyObject *kwds) #ifdef OPENSSL_NPN_NEGOTIATED self->npn_protocols = NULL; #endif +#ifdef HAVE_ALPN + self->alpn_protocols = NULL; +#endif #ifndef OPENSSL_NO_TLSEXT self->set_hostname = NULL; #endif @@ -2099,7 +2241,10 @@ context_dealloc(PySSLContext *self) context_clear(self); SSL_CTX_free(self->ctx); #ifdef OPENSSL_NPN_NEGOTIATED - PyMem_Free(self->npn_protocols); + PyMem_FREE(self->npn_protocols); +#endif +#ifdef HAVE_ALPN + PyMem_FREE(self->alpn_protocols); #endif Py_TYPE(self)->tp_free(self); } @@ -2126,6 +2271,30 @@ set_ciphers(PySSLContext *self, PyObject *args) } #ifdef OPENSSL_NPN_NEGOTIATED +static int +do_protocol_selection(int alpn, unsigned char **out, unsigned char *outlen, + const unsigned char *server_protocols, unsigned int server_protocols_len, + const unsigned char *client_protocols, unsigned int client_protocols_len) +{ + int ret; + if (client_protocols == NULL) { + client_protocols = (unsigned char *)""; + client_protocols_len = 0; + } + if (server_protocols == NULL) { + server_protocols = (unsigned char *)""; + server_protocols_len = 0; + } + + ret = SSL_select_next_proto(out, outlen, + server_protocols, server_protocols_len, + client_protocols, client_protocols_len); + if (alpn && ret != OPENSSL_NPN_NEGOTIATED) + return SSL_TLSEXT_ERR_NOACK; + + return SSL_TLSEXT_ERR_OK; +} + /* this callback gets passed to SSL_CTX_set_next_protos_advertise_cb */ static int _advertiseNPN_cb(SSL *s, @@ -2135,10 +2304,10 @@ _advertiseNPN_cb(SSL *s, PySSLContext *ssl_ctx = (PySSLContext *) args; if (ssl_ctx->npn_protocols == NULL) { - *data = (unsigned char *) ""; + *data = (unsigned char *)""; *len = 0; } else { - *data = (unsigned char *) ssl_ctx->npn_protocols; + *data = ssl_ctx->npn_protocols; *len = ssl_ctx->npn_protocols_len; } @@ -2151,23 +2320,9 @@ _selectNPN_cb(SSL *s, const unsigned char *server, unsigned int server_len, void *args) { - PySSLContext *ssl_ctx = (PySSLContext *) args; - - unsigned char *client = (unsigned char *) ssl_ctx->npn_protocols; - int client_len; - - if (client == NULL) { - client = (unsigned char *) ""; - client_len = 0; - } else { - client_len = ssl_ctx->npn_protocols_len; - } - - SSL_select_next_proto(out, outlen, - server, server_len, - client, client_len); - - return SSL_TLSEXT_ERR_OK; + PySSLContext *ctx = (PySSLContext *)args; + return do_protocol_selection(0, out, outlen, server, server_len, + ctx->npn_protocols, ctx->npn_protocols_len); } #endif @@ -2210,6 +2365,50 @@ _set_npn_protocols(PySSLContext *self, PyObject *args) #endif } +#ifdef HAVE_ALPN +static int +_selectALPN_cb(SSL *s, + const unsigned char **out, unsigned char *outlen, + const unsigned char *client_protocols, unsigned int client_protocols_len, + void *args) +{ + PySSLContext *ctx = (PySSLContext *)args; + return do_protocol_selection(1, (unsigned char **)out, outlen, + ctx->alpn_protocols, ctx->alpn_protocols_len, + client_protocols, client_protocols_len); +} +#endif + +static PyObject * +_set_alpn_protocols(PySSLContext *self, PyObject *args) +{ +#ifdef HAVE_ALPN + Py_buffer protos; + + if (!PyArg_ParseTuple(args, "y*:set_npn_protocols", &protos)) + return NULL; + + PyMem_FREE(self->alpn_protocols); + self->alpn_protocols = PyMem_Malloc(protos.len); + if (!self->alpn_protocols) + return PyErr_NoMemory(); + memcpy(self->alpn_protocols, protos.buf, protos.len); + self->alpn_protocols_len = protos.len; + PyBuffer_Release(&protos); + + if (SSL_CTX_set_alpn_protos(self->ctx, self->alpn_protocols, self->alpn_protocols_len)) + return PyErr_NoMemory(); + SSL_CTX_set_alpn_select_cb(self->ctx, _selectALPN_cb, self); + + PyBuffer_Release(&protos); + Py_RETURN_NONE; +#else + PyErr_SetString(PyExc_NotImplementedError, + "The ALPN extension requires OpenSSL 1.0.2 or later."); + return NULL; +#endif +} + static PyObject * get_verify_mode(PySSLContext *self, void *c) { @@ -2253,7 +2452,6 @@ set_verify_mode(PySSLContext *self, PyObject *arg, void *c) return 0; } -#ifdef HAVE_OPENSSL_VERIFY_PARAM static PyObject * get_verify_flags(PySSLContext *self, void *c) { @@ -2291,7 +2489,6 @@ set_verify_flags(PySSLContext *self, PyObject *arg, void *c) } return 0; } -#endif static PyObject * get_options(PySSLContext *self, void *c) @@ -2750,11 +2947,9 @@ load_dh_params(PySSLContext *self, PyObject *filepath) DH *dh; f = _Py_fopen_obj(filepath, "rb"); - if (f == NULL) { - if (!PyErr_Occurred()) - PyErr_SetFromErrnoWithFilenameObject(PyExc_OSError, filepath); + if (f == NULL) return NULL; - } + errno = 0; PySSL_BEGIN_ALLOW_THREADS dh = PEM_read_DHparams(f, NULL, NULL, NULL); @@ -2799,14 +2994,43 @@ context_wrap_socket(PySSLContext *self, PyObject *args, PyObject *kwds) return NULL; } - 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 (!PyArg_Parse(hostname_obj, "et", "idna", &hostname)) + return NULL; + } + + res = (PyObject *) newPySSLSocket(self, NULL, server_side, hostname, + incoming, outgoing); + + PyMem_Free(hostname); + return res; +} + +static PyObject * session_stats(PySSLContext *self, PyObject *unused) { int r; @@ -2912,11 +3136,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, @@ -3133,10 +3371,8 @@ static PyGetSetDef context_getsetlist[] = { (setter) set_check_hostname, NULL}, {"options", (getter) get_options, (setter) set_options, NULL}, -#ifdef HAVE_OPENSSL_VERIFY_PARAM {"verify_flags", (getter) get_verify_flags, (setter) set_verify_flags, NULL}, -#endif {"verify_mode", (getter) get_verify_mode, (setter) set_verify_mode, NULL}, {NULL}, /* sentinel */ @@ -3145,8 +3381,12 @@ 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_alpn_protocols", (PyCFunction) _set_alpn_protocols, + METH_VARARGS, NULL}, {"_set_npn_protocols", (PyCFunction) _set_npn_protocols, METH_VARARGS, NULL}, {"load_cert_chain", (PyCFunction) load_cert_chain, @@ -3214,25 +3454,246 @@ 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 /* helper routines for seeding the SSL PRNG */ static PyObject * PySSL_RAND_add(PyObject *self, PyObject *args) { - char *buf; + Py_buffer view; + const char *buf; Py_ssize_t len, written; double entropy; - if (!PyArg_ParseTuple(args, "s#d:RAND_add", &buf, &len, &entropy)) + if (!PyArg_ParseTuple(args, "s*d:RAND_add", &view, &entropy)) return NULL; + buf = (const char *)view.buf; + len = view.len; do { written = Py_MIN(len, INT_MAX); RAND_add(buf, (int)written, entropy); buf += written; len -= written; } while (len); + PyBuffer_Release(&view); Py_INCREF(Py_None); return Py_None; } @@ -3354,8 +3815,6 @@ Returns number of bytes read. Raises SSLError if connection to EGD\n\ fails or if it does not provide enough data to seed PRNG."); #endif /* HAVE_RAND_EGD */ -#endif /* HAVE_OPENSSL_RAND */ - PyDoc_STRVAR(PySSL_get_default_verify_paths_doc, "get_default_verify_paths() -> tuple\n\ @@ -3741,7 +4200,6 @@ PySSL_enum_crls(PyObject *self, PyObject *args, PyObject *kwds) static PyMethodDef PySSL_methods[] = { {"_test_decode_cert", PySSL_test_decode_certificate, METH_VARARGS}, -#ifdef HAVE_OPENSSL_RAND {"RAND_add", PySSL_RAND_add, METH_VARARGS, PySSL_RAND_add_doc}, {"RAND_bytes", PySSL_RAND_bytes, METH_VARARGS, @@ -3754,7 +4212,6 @@ static PyMethodDef PySSL_methods[] = { #endif {"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 @@ -3906,6 +4363,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) @@ -3969,6 +4428,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", @@ -4109,11 +4571,7 @@ PyInit__ssl(void) Py_INCREF(r); PyModule_AddObject(m, "HAS_SNI", r); -#if HAVE_OPENSSL_FINISHED r = Py_True; -#else - r = Py_False; -#endif Py_INCREF(r); PyModule_AddObject(m, "HAS_TLS_UNIQUE", r); @@ -4133,6 +4591,14 @@ PyInit__ssl(void) Py_INCREF(r); PyModule_AddObject(m, "HAS_NPN", r); +#ifdef HAVE_ALPN + r = Py_True; +#else + r = Py_False; +#endif + Py_INCREF(r); + PyModule_AddObject(m, "HAS_ALPN", r); + /* Mappings for error codes */ err_codes_to_names = PyDict_New(); err_names_to_codes = PyDict_New(); |