summaryrefslogtreecommitdiff
path: root/Modules/_ssl.c
diff options
context:
space:
mode:
Diffstat (limited to 'Modules/_ssl.c')
-rw-r--r--Modules/_ssl.c966
1 files changed, 740 insertions, 226 deletions
diff --git a/Modules/_ssl.c b/Modules/_ssl.c
index c27073c121..b7b39dd372 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, _PyTime_t timeout);
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,16 @@ 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)
+/* If sock is NULL, use a timeout of 0 second */
+#define GET_SOCKET_TIMEOUT(sock) \
+ ((sock != NULL) ? (sock)->sock_timeout : 0)
/*
* SSL errors.
@@ -419,13 +414,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 +473,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 +491,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 +512,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 +537,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 +550,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 +568,28 @@ 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);
+ _PyTime_t timeout, deadline = 0;
+ int has_timeout;
+
+ if (sock) {
+ if (((PyObject*)sock) == Py_None) {
+ _setSSLError("Underlying socket connection gone",
+ PY_SSL_ERROR_NO_SOCKET, __FILE__, __LINE__);
+ return NULL;
+ }
+ Py_INCREF(sock);
- if (((PyObject*)sock) == Py_None) {
- _setSSLError("Underlying socket connection gone",
- PY_SSL_ERROR_NO_SOCKET, __FILE__, __LINE__);
- return 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);
}
- 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);
+ timeout = GET_SOCKET_TIMEOUT(sock);
+ has_timeout = (timeout > 0);
+ if (has_timeout)
+ deadline = _PyTime_GetMonotonicClock() + timeout;
/* Actually negotiate SSL connection */
/* XXX If SSL_do_handshake() returns 0, it's also a failure. */
@@ -570,15 +598,21 @@ 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 (has_timeout)
+ timeout = deadline - _PyTime_GetMonotonicClock();
+
if (err == SSL_ERROR_WANT_READ) {
- sockstate = check_socket_and_wait_for_timeout(sock, 0);
+ sockstate = PySSL_select(sock, 0, timeout);
} else if (err == SSL_ERROR_WANT_WRITE) {
- sockstate = check_socket_and_wait_for_timeout(sock, 1);
+ sockstate = PySSL_select(sock, 1, timeout);
} else {
sockstate = SOCKET_OPERATION_OK;
}
+
if (sockstate == SOCKET_HAS_TIMED_OUT) {
PyErr_SetString(PySocketModule.timeout_error,
ERRSTR("The handshake operation timed out"));
@@ -595,7 +629,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 +644,7 @@ static PyObject *PySSL_SSLdo_handshake(PySSLSocket *self)
return Py_None;
error:
- Py_DECREF(sock);
+ Py_XDECREF(sock);
return NULL;
}
@@ -779,12 +813,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 +1385,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 +1485,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 +1557,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 +1614,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 +1625,27 @@ static void PySSL_dealloc(PySSLSocket *self)
*/
static int
-check_socket_and_wait_for_timeout(PySocketSockObject *s, int writing)
+PySSL_select(PySocketSockObject *s, int writing, _PyTime_t timeout)
{
+ 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) || (timeout == 0))
return SOCKET_IS_NONBLOCKING;
+ else if (timeout < 0) {
+ if (s->sock_timeout > 0)
+ return SOCKET_HAS_TIMED_OUT;
+ else
+ return SOCKET_IS_BLOCKING;
+ }
/* Guard against closed socket */
if (s->sock_fd < 0)
@@ -1510,46 +1654,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;
-
- /* 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
+ pollfd.fd = s->sock_fd;
+ pollfd.events = writing ? POLLOUT : POLLIN;
- goto normal_return;
- }
-#endif
+ /* timeout is in seconds, poll() uses milliseconds */
+ ms = (int)_PyTime_AsMilliseconds(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(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 +1696,21 @@ static PyObject *PySSL_SSLwrite(PySSLSocket *self, PyObject *args)
int sockstate;
int err;
int nonblocking;
- PySocketSockObject *sock
- = (PySocketSockObject *) PyWeakref_GetObject(self->Socket);
-
- if (((PyObject*)sock) == Py_None) {
- _setSSLError("Underlying socket connection gone",
- PY_SSL_ERROR_NO_SOCKET, __FILE__, __LINE__);
- return NULL;
+ PySocketSockObject *sock = GET_SOCKET(self);
+ _PyTime_t timeout, deadline = 0;
+ int has_timeout;
+
+ 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 +1720,19 @@ 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);
+ }
+
+ timeout = GET_SOCKET_TIMEOUT(sock);
+ has_timeout = (timeout > 0);
+ if (has_timeout)
+ deadline = _PyTime_GetMonotonicClock() + timeout;
- sockstate = check_socket_and_wait_for_timeout(sock, 1);
+ sockstate = PySSL_select(sock, 1, timeout);
if (sockstate == SOCKET_HAS_TIMED_OUT) {
PyErr_SetString(PySocketModule.timeout_error,
"The write operation timed out");
@@ -1602,21 +1746,27 @@ 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 (has_timeout)
+ timeout = deadline - _PyTime_GetMonotonicClock();
+
if (err == SSL_ERROR_WANT_READ) {
- sockstate = check_socket_and_wait_for_timeout(sock, 0);
+ sockstate = PySSL_select(sock, 0, timeout);
} else if (err == SSL_ERROR_WANT_WRITE) {
- sockstate = check_socket_and_wait_for_timeout(sock, 1);
+ sockstate = PySSL_select(sock, 1, timeout);
} else {
sockstate = SOCKET_OPERATION_OK;
}
+
if (sockstate == SOCKET_HAS_TIMED_OUT) {
PyErr_SetString(PySocketModule.timeout_error,
"The write operation timed out");
@@ -1630,7 +1780,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 +1788,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 +1828,18 @@ static PyObject *PySSL_SSLread(PySSLSocket *self, PyObject *args)
int sockstate;
int err;
int nonblocking;
- PySocketSockObject *sock
- = (PySocketSockObject *) PyWeakref_GetObject(self->Socket);
-
- if (((PyObject*)sock) == Py_None) {
- _setSSLError("Underlying socket connection gone",
- PY_SSL_ERROR_NO_SOCKET, __FILE__, __LINE__);
- return NULL;
+ PySocketSockObject *sock = GET_SOCKET(self);
+ _PyTime_t timeout, deadline = 0;
+ int has_timeout;
+
+ 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 +1865,43 @@ 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);
+ }
+
+ timeout = GET_SOCKET_TIMEOUT(sock);
+ has_timeout = (timeout > 0);
+ if (has_timeout)
+ deadline = _PyTime_GetMonotonicClock() + timeout;
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 (has_timeout)
+ timeout = deadline - _PyTime_GetMonotonicClock();
+
if (err == SSL_ERROR_WANT_READ) {
- sockstate = check_socket_and_wait_for_timeout(sock, 0);
+ sockstate = PySSL_select(sock, 0, timeout);
} 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, timeout);
+ } 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 +1910,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 +1928,7 @@ done:
}
error:
- Py_DECREF(sock);
+ Py_XDECREF(sock);
if (!buf_passed)
Py_XDECREF(dest);
else
@@ -1779,21 +1945,29 @@ 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);
+ _PyTime_t timeout, deadline = 0;
+ int has_timeout;
+
+ 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);
- /* 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;
+ /* 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);
}
- 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);
+ timeout = GET_SOCKET_TIMEOUT(sock);
+ has_timeout = (timeout > 0);
+ if (has_timeout)
+ deadline = _PyTime_GetMonotonicClock() + timeout;
while (1) {
PySSL_BEGIN_ALLOW_THREADS
@@ -1809,6 +1983,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;
@@ -1823,14 +1998,18 @@ static PyObject *PySSL_SSLshutdown(PySSLSocket *self)
continue;
}
+ if (has_timeout)
+ timeout = deadline - _PyTime_GetMonotonicClock();
+
/* 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, timeout);
else if (ssl_err == SSL_ERROR_WANT_WRITE)
- sockstate = check_socket_and_wait_for_timeout(sock, 1);
+ sockstate = PySSL_select(sock, 1, timeout);
else
break;
+
if (sockstate == SOCKET_HAS_TIMED_OUT) {
if (ssl_err == SSL_ERROR_WANT_READ)
PyErr_SetString(PySocketModule.timeout_error,
@@ -1851,15 +2030,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 +2050,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 +2082,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 +2105,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 +2218,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 +2289,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 +2319,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 +2352,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 +2368,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 +2413,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 +2500,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 +2537,6 @@ set_verify_flags(PySSLContext *self, PyObject *arg, void *c)
}
return 0;
}
-#endif
static PyObject *
get_options(PySSLContext *self, void *c)
@@ -2750,11 +2995,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 +3042,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 +3184,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 +3419,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 +3429,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 +3502,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 +3863,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 +4248,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 +4260,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 +4411,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 +4476,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 +4619,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 +4639,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();