summaryrefslogtreecommitdiff
path: root/Modules/_ssl.c
diff options
context:
space:
mode:
Diffstat (limited to 'Modules/_ssl.c')
-rw-r--r--Modules/_ssl.c806
1 files changed, 632 insertions, 174 deletions
diff --git a/Modules/_ssl.c b/Modules/_ssl.c
index 9bd07764bc..8596225cbf 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,10 +207,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 +230,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,
@@ -251,11 +242,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 +411,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 +470,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 +488,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 +509,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 +534,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);
}
@@ -533,10 +547,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 +565,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.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. */
@@ -595,7 +613,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 +628,7 @@ static PyObject *PySSL_SSLdo_handshake(PySSLSocket *self)
return Py_None;
error:
- Py_DECREF(sock);
+ Py_XDECREF(sock);
return NULL;
}
@@ -779,12 +797,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 +1369,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 +1469,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 +1541,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 +1598,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);
}
@@ -1498,10 +1616,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)
@@ -1562,18 +1680,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,10 +1702,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) {
@@ -1630,7 +1751,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 +1759,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 +1799,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,10 +1834,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);
+ }
do {
PySSL_BEGIN_ALLOW_THREADS
@@ -1751,7 +1875,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;
@@ -1762,7 +1886,7 @@ done:
}
error:
- Py_DECREF(sock);
+ Py_XDECREF(sock);
if (!buf_passed)
Py_XDECREF(dest);
else
@@ -1779,21 +1903,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.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
@@ -1851,15 +1976,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 +1996,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 +2028,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 +2051,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 +2164,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 +2235,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 +2265,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 +2298,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 +2314,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 +2359,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 +2446,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 +2483,6 @@ set_verify_flags(PySSLContext *self, PyObject *arg, void *c)
}
return 0;
}
-#endif
static PyObject *
get_options(PySSLContext *self, void *c)
@@ -2799,14 +2990,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 +3132,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 +3367,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 +3377,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,8 +3450,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
/* helper routines for seeding the SSL PRNG */
static PyObject *
@@ -3354,8 +3807,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 +4192,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 +4204,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 +4355,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 +4420,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 +4563,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 +4583,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();