Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 34k
Description
Feature or enhancement
Proposal:
Context: Setting multiple curves/groups in the client hello of TLS clients. Enabling OpenSSLv3 providers.
Issue: Function set_ecdh_curve allows only to specify a single curve for an SSL context, which must support the generation of an EC key via OpenSSL function EC_KEY_new_by_curve_name(nid). This makes it impossible that a client offers more than one curve/group in the client hello (if not specified via openssl.cnf) and also is not supported by some OpenSSL providers (e.g. OQS).
Effect: When addressed, this would add the possibility to specify one or several curves (aka 'groups') by a colon separated string of curve names.
Implementation options: Change the existing code to avoid the somewhat cumbersome "string -> NID --> set single group" approach, but rather directly use the string value from the PyObject *name function argument and SSL_CTX_set1_groups_list().
As an alternative, we could add a new function SSLContext.set_ecdh_curves_list() which under the hood would use (for e.g OpenSSL >v3) SSL_CTX_set1_curves_list() (actually the more modernSSL_CTX_set1_groups_list())
I'm fine either way, with a slight preference for the former: It does NOT introduce a new function, which must be maintained going forward. But it isn't 110% guaranteed not to interfere with legacy code.
Preferred Implementation: ==> Code change for changing existing function (tested on v3.11.5):
static PyObject * _ssl__SSLContext_set_ecdh_curve(PySSLContext *self, PyObject *name) /*[clinic end generated code: output=23022c196e40d7d2 input=c2bafb6f6e34726b]*/{PyObject *name_bytes; if (!PyUnicode_FSConverter(name, &name_bytes)) return NULL; assert(PyBytes_Check(name_bytes)); #if OPENSSL_VERSION_MAJOR < 3 int nid; nid = OBJ_sn2nid(PyBytes_AS_STRING(name_bytes)); Py_DECREF(name_bytes); if (nid == 0){PyErr_Format(PyExc_ValueError, "unknown elliptic curve name %R", name); return NULL} EC_KEY *key = EC_KEY_new_by_curve_name(nid); if (key == NULL){_setSSLError(get_state_ctx(self), NULL, 0, __FILE__, __LINE__); return NULL} SSL_CTX_set_tmp_ecdh(self->ctx, key); EC_KEY_free(key); #else int res = SSL_CTX_set1_groups_list(self->ctx, PyBytes_AS_STRING(name_bytes)); Py_DECREF(name_bytes); if (!res){_setSSLError(get_state_ctx(self), NULL, 0, __FILE__, __LINE__); return NULL} #endif Py_RETURN_NONE} Remark: This will also enable to use the OQS OpenSSL provider to achieve a 'quantum-hard' TLS key agreement, e.g. using x25519_kyber768.
Usage: If implemented as above, usage could look like this when using an SSL context:
myContext.set_ecdh_curve('x25519_kyber768:X25519:secp521r1') Has this already been discussed elsewhere?
This is a minor feature, which does not need previous discussion elsewhere
Links to previous discussion of this feature:
This is a follow-up to #77063, an issue raised in 2018 which seemingly is no longer monitored.