mirror of
https://github.com/python/cpython.git
synced 2025-08-04 08:59:19 +00:00
add support for ALPN (closes #20188)
This commit is contained in:
parent
06140f2e04
commit
cca2732a82
5 changed files with 231 additions and 29 deletions
132
Modules/_ssl.c
132
Modules/_ssl.c
|
@ -109,6 +109,11 @@ struct py_ssl_library_code {
|
|||
# define HAVE_SNI 0
|
||||
#endif
|
||||
|
||||
/* ALPN added in OpenSSL 1.0.2 */
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x1000200fL && !defined(OPENSSL_NO_TLSEXT)
|
||||
# define HAVE_ALPN
|
||||
#endif
|
||||
|
||||
enum py_ssl_error {
|
||||
/* these mirror ssl.h */
|
||||
PY_SSL_ERROR_NONE,
|
||||
|
@ -180,9 +185,13 @@ 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
|
||||
|
@ -1460,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
|
||||
|
||||
|
@ -2053,6 +2075,9 @@ static PyMethodDef PySSLMethods[] = {
|
|||
{"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,
|
||||
|
@ -2159,6 +2184,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
|
||||
|
@ -2218,7 +2246,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);
|
||||
}
|
||||
|
@ -2244,6 +2275,23 @@ set_ciphers(PySSLContext *self, PyObject *args)
|
|||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static int
|
||||
do_protocol_selection(unsigned char **out, unsigned char *outlen,
|
||||
const unsigned char *remote_protocols, unsigned int remote_protocols_len,
|
||||
unsigned char *our_protocols, unsigned int our_protocols_len)
|
||||
{
|
||||
if (our_protocols == NULL) {
|
||||
our_protocols = (unsigned char*)"";
|
||||
our_protocols_len = 0;
|
||||
}
|
||||
|
||||
SSL_select_next_proto(out, outlen,
|
||||
remote_protocols, remote_protocols_len,
|
||||
our_protocols, our_protocols_len);
|
||||
|
||||
return SSL_TLSEXT_ERR_OK;
|
||||
}
|
||||
|
||||
#ifdef OPENSSL_NPN_NEGOTIATED
|
||||
/* this callback gets passed to SSL_CTX_set_next_protos_advertise_cb */
|
||||
static int
|
||||
|
@ -2254,10 +2302,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;
|
||||
}
|
||||
|
||||
|
@ -2270,23 +2318,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(out, outlen, server, server_len,
|
||||
ctx->npn_protocols, ctx->npn_protocols_len);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -2329,6 +2363,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((unsigned char **)out, outlen,
|
||||
client_protocols, client_protocols_len,
|
||||
ctx->alpn_protocols, ctx->alpn_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)
|
||||
{
|
||||
|
@ -3307,6 +3385,8 @@ static struct PyMethodDef context_methods[] = {
|
|||
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,
|
||||
|
@ -4502,6 +4582,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();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue