LibCrypto: Use OpenSSL to generate RSA keys

Replace our slow, possibly incorrect RSA key generation with OpenSSL.

This should fix many WPT tests that are timing out because we were too
slow at computing keys.
This commit is contained in:
devgianlu 2024-12-23 18:19:46 +01:00 committed by Ali Mohammad Pur
commit fef1f62ecc
Notes: github-actions[bot] 2025-01-12 00:14:21 +00:00
2 changed files with 46 additions and 11 deletions

View file

@ -104,6 +104,10 @@ public:
}
};
class OpenSSL_PKEY_CTX {
OPENSSL_WRAPPER_CLASS(OpenSSL_PKEY_CTX, EVP_PKEY_CTX, EVP_PKEY_CTX);
};
class OpenSSL_MD_CTX {
OPENSSL_WRAPPER_CLASS(OpenSSL_MD_CTX, EVP_MD_CTX, EVP_MD_CTX);

View file

@ -1,5 +1,6 @@
/*
* Copyright (c) 2020, Ali Mohammad Pur <mpfard@serenityos.org>
* Copyright (c) 2025, Altomani Gianluca <altomanigianluca@gmail.com>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
@ -11,9 +12,15 @@
#include <LibCrypto/ASN1/DER.h>
#include <LibCrypto/ASN1/PEM.h>
#include <LibCrypto/Certificate/Certificate.h>
#include <LibCrypto/OpenSSL.h>
#include <LibCrypto/PK/RSA.h>
#include <LibCrypto/SecureRandom.h>
#include <openssl/core_names.h>
#include <openssl/evp.h>
#include <openssl/param_build.h>
#include <openssl/rsa.h>
namespace Crypto::PK {
ErrorOr<RSA::KeyPairType> RSA::parse_rsa_key(ReadonlyBytes der, bool is_private, Vector<StringView> current_scope)
@ -116,22 +123,46 @@ ErrorOr<RSA::KeyPairType> RSA::parse_rsa_key(ReadonlyBytes der, bool is_private,
ErrorOr<RSA::KeyPairType> RSA::generate_key_pair(size_t bits, IntegerType e)
{
IntegerType p;
IntegerType q;
IntegerType lambda;
auto ctx = TRY(OpenSSL_PKEY_CTX::wrap(EVP_PKEY_CTX_new_from_name(nullptr, "RSA", nullptr)));
do {
p = NumberTheory::random_big_prime(bits / 2);
q = NumberTheory::random_big_prime(bits / 2);
lambda = NumberTheory::LCM(p.minus(1), q.minus(1));
} while (!(NumberTheory::GCD(e, lambda) == 1));
OPENSSL_TRY(EVP_PKEY_keygen_init(ctx.ptr()));
auto n = p.multiplied_by(q);
auto e_bn = TRY(unsigned_big_integer_to_openssl_bignum(e));
auto* params_bld = OPENSSL_TRY_PTR(OSSL_PARAM_BLD_new());
ScopeGuard const free_params_bld = [&] { OSSL_PARAM_BLD_free(params_bld); };
OPENSSL_TRY(OSSL_PARAM_BLD_push_size_t(params_bld, OSSL_PKEY_PARAM_RSA_BITS, bits));
OPENSSL_TRY(OSSL_PARAM_BLD_push_BN(params_bld, OSSL_PKEY_PARAM_RSA_E, e_bn.ptr()));
auto* params = OSSL_PARAM_BLD_to_param(params_bld);
ScopeGuard const free_params = [&] { OSSL_PARAM_free(params); };
OPENSSL_TRY(EVP_PKEY_CTX_set_params(ctx.ptr(), params));
auto key = TRY(OpenSSL_PKEY::create());
auto* key_ptr = key.ptr();
OPENSSL_TRY(EVP_PKEY_generate(ctx.ptr(), &key_ptr));
#define OPENSSL_GET_KEY_PARAM(param, openssl_name) \
auto param##_bn = TRY(OpenSSL_BN::create()); \
auto* param##_bn_ptr = param##_bn.ptr(); \
OPENSSL_TRY(EVP_PKEY_get_bn_param(key.ptr(), openssl_name, &param##_bn_ptr)); \
auto param = TRY(openssl_bignum_to_unsigned_big_integer(param##_bn));
OPENSSL_GET_KEY_PARAM(n, OSSL_PKEY_PARAM_RSA_N);
OPENSSL_GET_KEY_PARAM(d, OSSL_PKEY_PARAM_RSA_D);
OPENSSL_GET_KEY_PARAM(p, OSSL_PKEY_PARAM_RSA_FACTOR1);
OPENSSL_GET_KEY_PARAM(q, OSSL_PKEY_PARAM_RSA_FACTOR2);
OPENSSL_GET_KEY_PARAM(dp, OSSL_PKEY_PARAM_RSA_EXPONENT1);
OPENSSL_GET_KEY_PARAM(dq, OSSL_PKEY_PARAM_RSA_EXPONENT2);
OPENSSL_GET_KEY_PARAM(qinv, OSSL_PKEY_PARAM_RSA_COEFFICIENT1);
#undef OPENSSL_GET_KEY_PARAM
auto d = NumberTheory::ModularInverse(e, lambda);
RSAKeyPair<PublicKeyType, PrivateKeyType> keys {
{ n, e },
{ n, d, e, p, q }
{ n, d, e, p, q, dp, dq, qinv }
};
return keys;
}