Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions Doc/library/ssl.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2434,6 +2434,23 @@ successful call of :func:`~ssl.RAND_add`, :func:`~ssl.RAND_bytes` or
:func:`~ssl.RAND_pseudo_bytes` is sufficient.


.. ssl-libressl:

LibreSSL support
----------------

LibreSSL is a fork of OpenSSL 1.0.1. The ssl module has limited support for
LibreSSL. Some features are not available when the ssl module is compiled
with LibreSSL.

* LibreSSL >= 2.6.1 no longer supports NPN. The methods
:meth:`SSLContext.set_npn_protocols` and
:meth:`SSLSocket.selected_npn_protocol` are not available.
* :meth:`SSLContext.set_default_verify_paths` ignores the env vars
:envvar:`SSL_CERT_FILE` and :envvar:`SSL_CERT_PATH` although
:func:`get_default_verify_paths` still reports them.


.. seealso::

Class :class:`socket.socket`
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
The ssl module now contains a workaround for missing NPN support in LibreSSL
2.6.1. Upstream has removed NPN without setting OPENSSL_NO_NEXTPROTONEG.
28 changes: 20 additions & 8 deletions Modules/_ssl.c
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,18 @@ static void _PySSLFixErrno(void) {
# define HAVE_ALPN
#endif

/* We cannot rely on OPENSSL_NO_NEXTPROTONEG because LibreSSL 2.6.1 dropped NPN
* support but did not set OPENSSL_NO_NEXTPROTONEG for compatibility reasons.
* The check for TLSEXT_TYPE_next_proto_neg works with OpenSSL 1.0.1+ and LibreSSL.
*/
#ifdef OPENSSL_NO_NEXTPROTONEG
# define HAVE_NPN 0
#elif defined(TLSEXT_TYPE_next_proto_neg)
# define HAVE_NPN 1
#else
# define HAVE_NPN 0
# endif

#ifndef INVALID_SOCKET /* MS defines this */
#define INVALID_SOCKET (-1)
#endif
Expand Down Expand Up @@ -328,7 +340,7 @@ static unsigned int _ssl_locks_count = 0;
typedef struct {
PyObject_HEAD
SSL_CTX *ctx;
#if defined(OPENSSL_NPN_NEGOTIATED) && !defined(OPENSSL_NO_NEXTPROTONEG)
#ifdef HAVE_NPN
unsigned char *npn_protocols;
int npn_protocols_len;
#endif
Expand Down Expand Up @@ -1894,7 +1906,7 @@ _ssl__SSLSocket_version_impl(PySSLSocket *self)
return PyUnicode_FromString(version);
}

#if defined(OPENSSL_NPN_NEGOTIATED) && !defined(OPENSSL_NO_NEXTPROTONEG)
#ifdef HAVE_NPN
/*[clinic input]
_ssl._SSLSocket.selected_npn_protocol
[clinic start generated code]*/
Expand Down Expand Up @@ -2850,7 +2862,7 @@ _ssl__SSLContext_impl(PyTypeObject *type, int proto_version)
self->ctx = ctx;
self->hostflags = X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS;
self->protocol = proto_version;
#if defined(OPENSSL_NPN_NEGOTIATED) && !defined(OPENSSL_NO_NEXTPROTONEG)
#ifdef HAVE_NPN
self->npn_protocols = NULL;
#endif
#ifdef HAVE_ALPN
Expand Down Expand Up @@ -2989,7 +3001,7 @@ context_dealloc(PySSLContext *self)
PyObject_GC_UnTrack(self);
context_clear(self);
SSL_CTX_free(self->ctx);
#if defined(OPENSSL_NPN_NEGOTIATED) && !defined(OPENSSL_NO_NEXTPROTONEG)
#ifdef HAVE_NPN
PyMem_FREE(self->npn_protocols);
#endif
#ifdef HAVE_ALPN
Expand Down Expand Up @@ -3067,7 +3079,7 @@ _ssl__SSLContext_get_ciphers_impl(PySSLContext *self)
#endif


#if defined(OPENSSL_NPN_NEGOTIATED) && !defined(OPENSSL_NO_NEXTPROTONEG) || defined(HAVE_ALPN)
#if defined(HAVE_NPN) || defined(HAVE_ALPN)
static int
do_protocol_selection(int alpn, unsigned char **out, unsigned char *outlen,
const unsigned char *server_protocols, unsigned int server_protocols_len,
Expand All @@ -3093,7 +3105,7 @@ do_protocol_selection(int alpn, unsigned char **out, unsigned char *outlen,
}
#endif

#if defined(OPENSSL_NPN_NEGOTIATED) && !defined(OPENSSL_NO_NEXTPROTONEG)
#ifdef HAVE_NPN
/* this callback gets passed to SSL_CTX_set_next_protos_advertise_cb */
static int
_advertiseNPN_cb(SSL *s,
Expand Down Expand Up @@ -3136,7 +3148,7 @@ _ssl__SSLContext__set_npn_protocols_impl(PySSLContext *self,
Py_buffer *protos)
/*[clinic end generated code: output=72b002c3324390c6 input=319fcb66abf95bd7]*/
{
#if defined(OPENSSL_NPN_NEGOTIATED) && !defined(OPENSSL_NO_NEXTPROTONEG)
#ifdef HAVE_NPN
PyMem_Free(self->npn_protocols);
self->npn_protocols = PyMem_Malloc(protos->len);
if (self->npn_protocols == NULL)
Expand Down Expand Up @@ -5675,7 +5687,7 @@ PyInit__ssl(void)
Py_INCREF(r);
PyModule_AddObject(m, "HAS_ECDH", r);

#if defined(OPENSSL_NPN_NEGOTIATED) && !defined(OPENSSL_NO_NEXTPROTONEG)
#ifdef HAVE_NPN
r = Py_True;
#else
r = Py_False;
Expand Down