From 8d83d00b87954d91ce876ebfec58293b160caccb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C5=8Dan?= Date: Mon, 16 Mar 2026 03:16:03 -0600 Subject: [PATCH] fix: generate_key() error-path resource leaks on OpenSSL 3.x Replace CHECK_OPEN_SSL (which croaks/longjmps) with THROW/goto err pattern in the OpenSSL 3.x code path. Previously, if any EVP call failed after BN_new(e) or EVP_PKEY_CTX_new_from_name(ctx), both resources would leak because croak() skips cleanup. Changes: - Move BIGNUM *e to PREINIT for goto label visibility - Initialize ctx=NULL and add error flag for THROW macro - Replace 5x CHECK_OPEN_SSL with THROW, add err: cleanup block - Cleanup frees e and ctx on both success and error paths - NULL-after-free prevents double-free from later CHECK_OPEN_SSL Pre-3.x paths unchanged (single-resource, no leak risk). Co-Authored-By: Claude Opus 4.6 --- RSA.xs | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/RSA.xs b/RSA.xs index af12460..a193106 100644 --- a/RSA.xs +++ b/RSA.xs @@ -521,11 +521,12 @@ generate_key(proto, bitsSV, exponent = 65537) unsigned long exponent; PREINIT: EVP_PKEY* rsa = NULL; + BIGNUM *e = NULL; #if OPENSSL_VERSION_NUMBER >= 0x30000000L - EVP_PKEY_CTX *ctx; + EVP_PKEY_CTX *ctx = NULL; + int error = 0; #endif CODE: - BIGNUM *e; e = BN_new(); BN_set_word(e, exponent); #if OPENSSL_VERSION_NUMBER < 0x00908000L @@ -545,21 +546,18 @@ generate_key(proto, bitsSV, exponent = 65537) #endif #if OPENSSL_VERSION_NUMBER >= 0x30000000L ctx = EVP_PKEY_CTX_new_from_name(NULL, "RSA", NULL); - - if (!ctx - || EVP_PKEY_keygen_init(ctx) != 1 - || EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, SvIV(bitsSV)) <= 0 - || EVP_PKEY_CTX_set1_rsa_keygen_pubexp(ctx, e) <= 0 - || EVP_PKEY_generate(ctx, &rsa) != 1 - || rsa == NULL) - { - BN_free(e); - EVP_PKEY_CTX_free(ctx); - croakSsl(__FILE__, __LINE__); - } - + THROW(ctx); + THROW(EVP_PKEY_keygen_init(ctx) == 1); + THROW(EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, SvIV(bitsSV)) > 0); + THROW(EVP_PKEY_CTX_set1_rsa_keygen_pubexp(ctx, e) > 0); + THROW(EVP_PKEY_generate(ctx, &rsa) == 1); +err: BN_free(e); + e = NULL; EVP_PKEY_CTX_free(ctx); + ctx = NULL; + if (error) + croakSsl(__FILE__, __LINE__); #endif CHECK_OPEN_SSL(rsa); RETVAL = make_rsa_obj(proto, rsa);