Skip to content

Commit f838ae6

Browse files
committed
Tie RSA methods to their engine lifetime
Store each allocated RSA EVP_PKEY_METHOD in its owning ENGINE rather than a shared global pointer. This keeps the callback valid until the ENGINE's final structural reference is released, even if the last PKCS11_CTX is freed while a key still retains an ENGINE reference. OpenSSL then releases the method from its engine teardown path without leaking it or confusing a later libp11 ENGINE instance.
1 parent 2e62cc4 commit f838ae6

1 file changed

Lines changed: 25 additions & 15 deletions

File tree

src/p11_rsa.c

Lines changed: 25 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,8 @@ static int rsa_ex_index = 0;
3333
static RSA_METHOD *pkcs11_rsa_method = NULL;
3434

3535
#if OPENSSL_VERSION_NUMBER >= 0x30000000L && OPENSSL_VERSION_NUMBER < 0x40000000L && !defined(OPENSSL_NO_ENGINE)
36-
static EVP_PKEY_METHOD *pkey_method_rsa = NULL;
3736
static ENGINE *pkey_engine_rsa = NULL;
37+
static int pkey_engine_rsa_ex_index = -1;
3838
#endif /* OpenSSL 3.x with ENGINE support */
3939

4040
static RSA *pkcs11_get1_rsa(PKCS11_OBJECT_private *key)
@@ -247,14 +247,13 @@ static int pkcs11_pkey_engine_meths(ENGINE *engine,
247247
{
248248
static int pkey_nids[] = { EVP_PKEY_RSA, 0 };
249249

250-
(void)engine;
251250
if (!pmeth) {
252251
*nids = pkey_nids;
253252
return 1;
254253
}
255254
if (nid == EVP_PKEY_RSA) {
256-
*pmeth = pkey_method_rsa;
257-
return 1;
255+
*pmeth = ENGINE_get_ex_data(engine, pkey_engine_rsa_ex_index);
256+
return *pmeth != NULL;
258257
}
259258
*pmeth = NULL;
260259
return 0;
@@ -263,24 +262,34 @@ static int pkcs11_pkey_engine_meths(ENGINE *engine,
263262
/* Initialize an ENGINE that selects the RSA method only for libp11 keys. */
264263
static int pkcs11_pkey_method_rsa_new(void)
265264
{
265+
EVP_PKEY_METHOD *pkey_method_rsa;
266+
ENGINE *engine;
267+
266268
if (pkey_engine_rsa)
267269
return 1;
268270

269271
pkey_method_rsa = pkcs11_pkey_method_rsa();
270272
if (!pkey_method_rsa)
271273
return 0;
272-
pkey_engine_rsa = ENGINE_new();
273-
if (!pkey_engine_rsa ||
274-
!ENGINE_set_id(pkey_engine_rsa, "libp11-rsa-key") ||
275-
!ENGINE_set_name(pkey_engine_rsa, "libp11 RSA key method") ||
276-
!ENGINE_set_pkey_meths(pkey_engine_rsa,
277-
pkcs11_pkey_engine_meths)) {
278-
ENGINE_free(pkey_engine_rsa);
279-
pkey_engine_rsa = NULL;
274+
if (pkey_engine_rsa_ex_index < 0)
275+
pkey_engine_rsa_ex_index = ENGINE_get_ex_new_index(0,
276+
"libp11 RSA EVP_PKEY_METHOD", NULL, NULL, NULL);
277+
engine = ENGINE_new();
278+
if (pkey_engine_rsa_ex_index < 0 || !engine ||
279+
!ENGINE_set_id(engine, "libp11-rsa-key") ||
280+
!ENGINE_set_name(engine, "libp11 RSA key method") ||
281+
!ENGINE_set_ex_data(engine, pkey_engine_rsa_ex_index,
282+
pkey_method_rsa)) {
283+
ENGINE_free(engine);
284+
EVP_PKEY_meth_free(pkey_method_rsa);
285+
return 0;
286+
}
287+
if (!ENGINE_set_pkey_meths(engine, pkcs11_pkey_engine_meths)) {
288+
ENGINE_free(engine);
280289
EVP_PKEY_meth_free(pkey_method_rsa);
281-
pkey_method_rsa = NULL;
282290
return 0;
283291
}
292+
pkey_engine_rsa = engine;
284293
return 1;
285294
}
286295
#endif /* OPENSSL_NO_ENGINE */
@@ -301,11 +310,12 @@ void pkcs11_rsa_key_method_free(void)
301310
{
302311
#ifndef OPENSSL_NO_ENGINE
303312
if (pkey_engine_rsa) {
313+
/* OpenSSL frees the method returned by the callback when the
314+
* ENGINE's final structural reference is released. Keep the method
315+
* in ENGINE ex_data so it remains available if keys still hold refs. */
304316
ENGINE_free(pkey_engine_rsa);
305317
pkey_engine_rsa = NULL;
306318
}
307-
/* ENGINE_free() releases the methods cached by the ENGINE. */
308-
pkey_method_rsa = NULL;
309319
#endif /* OPENSSL_NO_ENGINE */
310320
}
311321

0 commit comments

Comments
 (0)