Try to use an upcoming python-cryptography feature to avoid some costs

If the key is the wrong number of bits then we don't care about any other
validation results because we're just going to reject it.  So, check that
before applying other validation, if possible.

This is untested since the version of python-cryptography that supports it is
not released yet and I don't feel like setting up a Rust build tool chain at
the moment.
This commit is contained in:
Jean-Paul Calderone 2022-12-14 08:47:05 -05:00
parent 2677f26455
commit 05c7450376
1 changed files with 23 additions and 4 deletions

View File

@ -72,20 +72,39 @@ def create_signing_keypair_from_string(private_key_der):
:returns: 2-tuple of (private_key, public_key) :returns: 2-tuple of (private_key, public_key)
""" """
priv_key = load_der_private_key( load = partial(
load_der_private_key,
private_key_der, private_key_der,
password=None, password=None,
backend=default_backend(), backend=default_backend(),
) )
if not isinstance(priv_key, rsa.RSAPrivateKey):
try:
# Load it once without the potentially expensive OpenSSL validation
# checks. These have superlinear complexity. We *will* run them just
# below - but first we'll apply our own constant-time checks.
unsafe_priv_key = load(unsafe_skip_rsa_key_validation=True)
except TypeError:
# cryptography<39 does not support this parameter, so just load the
# key with validation...
unsafe_priv_key = load()
# But avoid *reloading* it since that will run the expensive
# validation *again*.
load = lambda: unsafe_priv_key
if not isinstance(unsafe_priv_key, rsa.RSAPrivateKey):
raise ValueError( raise ValueError(
"Private Key did not decode to an RSA key" "Private Key did not decode to an RSA key"
) )
if priv_key.key_size != 2048: if unsafe_priv_key.key_size != 2048:
raise ValueError( raise ValueError(
"Private Key must be 2048 bits" "Private Key must be 2048 bits"
) )
return priv_key, priv_key.public_key()
# Now re-load it with OpenSSL's validation applied.
safe_priv_key = load()
return safe_priv_key, safe_priv_key.public_key()
def der_string_from_signing_key(private_key): def der_string_from_signing_key(private_key):