From 4d6ed25ed3ebd51f4dd971e817523f28bd16be14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Trojnara?= Date: Mon, 17 Aug 2026 19:40:00 +0200 Subject: [PATCH 1/3] Add extensible EVP_PKEY callbacks Allow callers to install per-context callbacks for EVP_PKEY objects returned by libp11. A callback-type selector permits future key callbacks to use the same registration function without expanding the public API for each event. Keep callback state private to each context so integrations do not introduce process-wide method selection. --- src/libp11-int.h | 6 +++++- src/libp11.exports | 1 + src/libp11.h | 31 ++++++++++++++++++++++++++++++- src/p11_front.c | 33 +++++++++++++++++++++++++++++++-- 4 files changed, 67 insertions(+), 4 deletions(-) diff --git a/src/libp11-int.h b/src/libp11-int.h index 0b7ab81b..27b56de7 100644 --- a/src/libp11-int.h +++ b/src/libp11-int.h @@ -1,7 +1,7 @@ /* libp11, a simple layer on top of PKCS#11 API * Copyright (C) 2005 Olaf Kirch * Copyright (C) 2015-2025 Michał Trojnara - * Copyright © 2025 Mobi - Com Polska Sp. z o.o. + * Copyright © 2025-2026 Mobi - Com Polska Sp. z o.o. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -63,6 +63,8 @@ typedef struct pkcs11_keys PKCS11_keys; typedef struct pkcs11_object_ops PKCS11_OBJECT_ops; typedef struct pkcs11_template_st PKCS11_TEMPLATE; +#define PKCS11_PKEY_CALLBACK_COUNT 2 + /* get private implementations of PKCS11 structures */ /* @@ -81,6 +83,8 @@ struct pkcs11_ctx_private { unsigned int forkid; int initialized; void (*vlog_a)(int, const char *, va_list); /* for the logging callback */ + PKCS11_PKEY_CALLBACK pkey_callbacks[PKCS11_PKEY_CALLBACK_COUNT]; + void *pkey_callback_data[PKCS11_PKEY_CALLBACK_COUNT]; }; struct pkcs11_keys { diff --git a/src/libp11.exports b/src/libp11.exports index a0834ed2..b87643f5 100644 --- a/src/libp11.exports +++ b/src/libp11.exports @@ -1,6 +1,7 @@ PKCS11_CTX_init_args PKCS11_CTX_new_ex PKCS11_CTX_new +PKCS11_CTX_set_pkey_callback PKCS11_CTX_load PKCS11_CTX_unload PKCS11_CTX_free diff --git a/src/libp11.h b/src/libp11.h index 08fd9ad4..cbe45c0d 100644 --- a/src/libp11.h +++ b/src/libp11.h @@ -1,6 +1,6 @@ /* libp11, a simple layer on top of PKCS#11 API * Copyright (C) 2005 Olaf Kirch - * Copyright © 2025 Mobi - Com Polska Sp. z o.o. + * Copyright © 2025-2026 Mobi - Com Polska Sp. z o.o. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -171,6 +171,18 @@ struct PKCS11_kgen_attrs_st { /** PKCS11 ASCII logging callback */ typedef void (*PKCS11_VLOG_A_CB)(int, const char *, va_list); +/** + * Callback invoked for an EVP_PKEY returned by libp11 + * + * The key arguments are borrowed and must not be freed by the callback. + * The callback may modify the EVP_PKEY and must return 0 on success or -1 + * on error. + */ +typedef int (*PKCS11_PKEY_CALLBACK)(PKCS11_KEY *, EVP_PKEY *, void *); + +/** Callback type for PKCS11_get_private_key() */ +#define PKCS11_PKEY_CALLBACK_GET_PRIVATE_KEY 1 + /** * Create a new libp11 context with specified flags * @@ -187,6 +199,23 @@ extern PKCS11_CTX *PKCS11_CTX_new_ex(int flags); */ extern PKCS11_CTX *PKCS11_CTX_new(void); +/** + * Set a callback for EVP_PKEY objects returned by this context + * + * The callback and its user data must remain valid until they are replaced, + * unset, or the context is freed. Callback registration must not be changed + * concurrently with key retrieval. + * + * @param ctx context allocated by PKCS11_CTX_new() + * @param callback_type one of PKCS11_PKEY_CALLBACK_* types + * @param callback callback function, or NULL to unset it + * @param user_data opaque callback data + * @retval 0 success + * @retval -1 unsupported callback type or invalid context + */ +extern int PKCS11_CTX_set_pkey_callback(PKCS11_CTX *ctx, + int callback_type, PKCS11_PKEY_CALLBACK callback, void *user_data); + /** * Specify any private PKCS#11 module initialization args, if necessary * diff --git a/src/p11_front.c b/src/p11_front.c index 6cd6f235..084d69a0 100644 --- a/src/p11_front.c +++ b/src/p11_front.c @@ -1,6 +1,6 @@ /* libp11, a simple layer on top of PKCS#11 API * Copyright (C) 2016-2025 Michał Trojnara - * Copyright © 2025 Mobi - Com Polska Sp. z o.o. + * Copyright © 2025-2026 Mobi - Com Polska Sp. z o.o. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -42,6 +42,22 @@ PKCS11_CTX *PKCS11_CTX_new(void) return pkcs11_CTX_new(0); } +int PKCS11_CTX_set_pkey_callback(PKCS11_CTX *pctx, + int callback_type, PKCS11_PKEY_CALLBACK callback, void *user_data) +{ + PKCS11_CTX_private *ctx; + + if (!pctx || callback_type <= 0 || + callback_type >= PKCS11_PKEY_CALLBACK_COUNT) + return -1; + ctx = pctx->_private; + if (check_fork(ctx) < 0) + return -1; + ctx->pkey_callbacks[callback_type] = callback; + ctx->pkey_callback_data[callback_type] = callback ? user_data : NULL; + return 0; +} + void PKCS11_CTX_init_args(PKCS11_CTX *ctx, const char *init_args) { if (check_fork(ctx->_private) < 0) @@ -255,9 +271,22 @@ int PKCS11_get_key_type(PKCS11_KEY *pkey) EVP_PKEY *PKCS11_get_private_key(PKCS11_KEY *pkey) { PKCS11_OBJECT_private *key = pkey->_private; + PKCS11_CTX_private *ctx = key->slot->ctx; + PKCS11_PKEY_CALLBACK callback; + EVP_PKEY *ret; + if (check_object_fork(key) < 0) return NULL; - return pkcs11_get_key(key, CKO_PRIVATE_KEY); + ret = pkcs11_get_key(key, CKO_PRIVATE_KEY); + if (!ret) + return NULL; + callback = ctx->pkey_callbacks[PKCS11_PKEY_CALLBACK_GET_PRIVATE_KEY]; + if (callback && callback(pkey, ret, + ctx->pkey_callback_data[PKCS11_PKEY_CALLBACK_GET_PRIVATE_KEY])) { + EVP_PKEY_free(ret); + return NULL; + } + return ret; } EVP_PKEY *PKCS11_get_public_key(PKCS11_KEY *pkey) From 970e6b7d64828d32e132750746524035991e8b25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Trojnara?= Date: Mon, 17 Aug 2026 19:43:58 +0200 Subject: [PATCH 2/3] Scope RSA PKEY methods to ENGINE keys Stop registering libp11's RSA EVP_PKEY_METHOD for every RSA key in the process. The global override changes dispatch for unrelated provider-backed software keys and can make their operations fail. Have the ENGINE integration install a per-context key callback instead. The callback attaches that ENGINE only to keys returned through its own libp11 context, preserving native RSA-PSS and parameter-aware OAEP dispatch without introducing ENGINE calls into the libp11 component. --- src/eng_back.c | 24 +++++++++++++++++++- src/eng_front.c | 18 +++++---------- src/engine.h | 4 +++- src/libp11-int.h | 5 ----- src/p11_load.c | 3 --- src/p11_rsa.c | 58 +++++------------------------------------------- src/util.h | 4 +++- src/util_uri.c | 23 ++++++++++++++++++- 8 files changed, 61 insertions(+), 78 deletions(-) diff --git a/src/eng_back.c b/src/eng_back.c index feba3cf4..093498c8 100644 --- a/src/eng_back.c +++ b/src/eng_back.c @@ -3,7 +3,7 @@ * Copyright (c) 2002 Juha Yrjölä * Copyright (c) 2002 Olaf Kirch * Copyright (c) 2003 Kevin Stefanik - * Copyright (c) 2016-2025 Michał Trojnara + * Copyright (c) 2016-2026 Michał Trojnara * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -160,6 +160,28 @@ int ENGINE_CTX_finish(ENGINE_CTX *ctx) return 1; } +/* EVP_PKEY_set1_engine() is required for OpenSSL 1.1.x, + * but otherwise setting pkey->engine breaks OpenSSL 1.0.2 */ +#ifdef EVP_F_EVP_PKEY_SET1_ENGINE +static int set_pkey_engine(PKCS11_KEY *key, EVP_PKEY *pkey, void *user_data) +{ + (void)key; + return EVP_PKEY_set1_engine(pkey, user_data) ? 0 : -1; +} +#endif /* EVP_F_EVP_PKEY_SET1_ENGINE */ + +int ENGINE_CTX_set_pkey_callback(ENGINE_CTX *ctx, ENGINE *engine) +{ +#ifdef EVP_F_EVP_PKEY_SET1_ENGINE + return UTIL_CTX_set_pkey_callback(ctx->util_ctx, + PKCS11_PKEY_CALLBACK_GET_PRIVATE_KEY, set_pkey_engine, engine); +#else + (void)ctx; + (void)engine; + return 1; +#endif /* EVP_F_EVP_PKEY_SET1_ENGINE */ +} + /******************************************************************************/ /* Engine load public/private key */ /******************************************************************************/ diff --git a/src/eng_front.c b/src/eng_front.c index 39ab9f4d..7d5ad888 100644 --- a/src/eng_front.c +++ b/src/eng_front.c @@ -5,7 +5,7 @@ * Portions Copyright (c) 2003 Kevin Stefanik (kstef@mtppi.org) * Copied/modified by Kevin Stefanik (kstef@mtppi.org) for the OpenSC * project 2003. - * Copyright (c) 2016-2025 Michał Trojnara + * Copyright (c) 2016-2026 Michał Trojnara * * Licensed under the OpenSSL license (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -175,12 +175,13 @@ static EVP_PKEY *load_privkey(ENGINE *engine, const char *s_key_id, UI_METHOD *ui_method, void *ui_data) { ENGINE_CTX *ctx; - EVP_PKEY *pkey; ctx = ENGINE_CTX_get(engine); if (!ctx) return 0; - bind_helper_methods(engine); + if (!bind_helper_methods(engine) || + !ENGINE_CTX_set_pkey_callback(ctx, engine)) + return 0; #if OPENSSL_VERSION_NUMBER >= 0x30000000L /* * A workaround for an OpenSSL bug affecting the handling of foreign @@ -207,16 +208,7 @@ static EVP_PKEY *load_privkey(ENGINE *engine, const char *s_key_id, } } #endif - pkey = ENGINE_CTX_load_privkey(ctx, s_key_id, ui_method, ui_data); -#ifdef EVP_F_EVP_PKEY_SET1_ENGINE - /* EVP_PKEY_set1_engine() is required for OpenSSL 1.1.x, - * but otherwise setting pkey->engine breaks OpenSSL 1.0.2 */ - if (pkey && !EVP_PKEY_set1_engine(pkey, engine)) { - EVP_PKEY_free(pkey); - pkey = NULL; - } -#endif /* EVP_F_EVP_PKEY_SET1_ENGINE */ - return pkey; + return ENGINE_CTX_load_privkey(ctx, s_key_id, ui_method, ui_data); } static int engine_ctrl(ENGINE *engine, int cmd, long i, void *p, void (*f) (void)) diff --git a/src/engine.h b/src/engine.h index 374dcea8..2e5923b4 100644 --- a/src/engine.h +++ b/src/engine.h @@ -2,7 +2,7 @@ * Copyright (c) 2001 Markus Friedl * Copyright (c) 2002 Juha Yrjölä * Copyright (c) 2003 Kevin Stefanik - * Copyright (c) 2016-2025 Michał Trojnara + * Copyright (c) 2016-2026 Michał Trojnara * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -84,6 +84,8 @@ int ENGINE_CTX_init(ENGINE_CTX *ctx); int ENGINE_CTX_finish(ENGINE_CTX *ctx); +int ENGINE_CTX_set_pkey_callback(ENGINE_CTX *ctx, ENGINE *engine); + int ENGINE_CTX_ctrl(ENGINE_CTX *ctx, int cmd, long i, void *p, void (*f)(void)); EVP_PKEY *ENGINE_CTX_load_pubkey(ENGINE_CTX *ctx, const char *s_key_id, diff --git a/src/libp11-int.h b/src/libp11-int.h index 27b56de7..24dba11c 100644 --- a/src/libp11-int.h +++ b/src/libp11-int.h @@ -630,11 +630,6 @@ extern void pkcs11_ed_key_method_free(void); extern void pkcs11_xdh_key_method_free(void); #endif /* !defined(OPENSSL_NO_ECX) && OPENSSL_VERSION_NUMBER >= 0x30000000L && OPENSSL_VERSION_NUMBER < 0x40000000L */ -#if OPENSSL_VERSION_NUMBER >= 0x30000000L && OPENSSL_VERSION_NUMBER < 0x40000000L -/* Free the global RSA EVP_PKEY_METHOD */ -extern void pkcs11_rsa_key_method_free(void); -# endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L && OPENSSL_VERSION_NUMBER < 0x40000000L */ - #if OPENSSL_VERSION_NUMBER < 0x100020d0L || defined(LIBRESSL_VERSION_NUMBER) /* Get sign_init and sign callbacks from EVP_PKEY_METHOD */ extern void EVP_PKEY_meth_get_sign(EVP_PKEY_METHOD *pmeth, diff --git a/src/p11_load.c b/src/p11_load.c index bd757827..dfea4035 100644 --- a/src/p11_load.c +++ b/src/p11_load.c @@ -39,9 +39,6 @@ static void libp11_global_free(void) #ifndef OPENSSL_NO_RSA pkcs11_rsa_method_free(); -# if OPENSSL_VERSION_NUMBER >= 0x30000000L && OPENSSL_VERSION_NUMBER < 0x40000000L - pkcs11_rsa_key_method_free(); -# endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L && OPENSSL_VERSION_NUMBER < 0x40000000L */ #endif /* OPENSSL_NO_RSA */ #if !defined(OPENSSL_NO_ECX) && OPENSSL_VERSION_NUMBER >= 0x30000000L && OPENSSL_VERSION_NUMBER < 0x40000000L diff --git a/src/p11_rsa.c b/src/p11_rsa.c index 58a80a2d..4809b256 100644 --- a/src/p11_rsa.c +++ b/src/p11_rsa.c @@ -29,10 +29,6 @@ static int rsa_ex_index = 0; static RSA_METHOD *pkcs11_rsa_method = NULL; -#if OPENSSL_VERSION_NUMBER >= 0x30000000L && OPENSSL_VERSION_NUMBER < 0x40000000L -static EVP_PKEY_METHOD *pkey_method_rsa = NULL; -#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L && OPENSSL_VERSION_NUMBER < 0x40000000L */ - static RSA *pkcs11_get1_rsa(PKCS11_OBJECT_private *key) { EVP_PKEY *evp_key = pkcs11_get_key(key, key->object_class); @@ -235,39 +231,6 @@ void pkcs11_set_ex_data_rsa(RSA *rsa, PKCS11_OBJECT_private *key) RSA_set_ex_data(rsa, rsa_ex_index, key); } -#if OPENSSL_VERSION_NUMBER >= 0x30000000L && OPENSSL_VERSION_NUMBER < 0x40000000L - -/* Global initialize RSA EVP_PKEY_METHOD */ -static int pkcs11_pkey_method_rsa_new(void) -{ - if (pkey_method_rsa) - return 1; /* EVP_PKEY_RSA method already initialized */ - - pkey_method_rsa = pkcs11_pkey_method_rsa(); - if (!pkey_method_rsa) - return 0; - - /* Register the method globally */ - if (!EVP_PKEY_meth_add0(pkey_method_rsa)) { - EVP_PKEY_meth_free(pkey_method_rsa); - pkey_method_rsa = NULL; - return 0; - } - return 1; -} - -void pkcs11_rsa_key_method_free(void) -{ - if (pkey_method_rsa) { - free_pkey_ex_index(); - EVP_PKEY_meth_remove(pkey_method_rsa); - EVP_PKEY_meth_free(pkey_method_rsa); - pkey_method_rsa = NULL; - } -} - -#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L && OPENSSL_VERSION_NUMBER < 0x40000000L */ - /* * Build an EVP_PKEY object */ @@ -285,21 +248,6 @@ static EVP_PKEY *pkcs11_get_evp_key_rsa(PKCS11_OBJECT_private *key) return NULL; } if (key->object_class == CKO_PRIVATE_KEY) { -#if OPENSSL_VERSION_NUMBER >= 0x30000000L -# if OPENSSL_VERSION_NUMBER < 0x40000000L - if ((key->slot->ctx->flags & PKCS11_FLAG_NO_METHODS) == 0) { - /* global initialize RSA EVP_PKEY_METHOD */ - if (!pkcs11_pkey_method_rsa_new()) { - EVP_PKEY_free(pk); - return NULL; - } - alloc_pkey_ex_index(); - pkcs11_set_ex_data_pkey(pk, key); - atexit(pkcs11_rsa_key_method_free); - } -# endif /* OPENSSL_VERSION_NUMBER < 0x40000000L */ -#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ - /* The RSA object owns the reference stored in its ex_data. */ key = pkcs11_object_ref(key); RSA_set_method(rsa, PKCS11_get_rsa_method()); @@ -318,7 +266,11 @@ static EVP_PKEY *pkcs11_get_evp_key_rsa(PKCS11_OBJECT_private *key) #endif pkcs11_set_ex_data_rsa(rsa, key); - EVP_PKEY_set1_RSA(pk, rsa); /* Also increments the rsa ref count */ + if (!EVP_PKEY_set1_RSA(pk, rsa)) { + RSA_free(rsa); + EVP_PKEY_free(pk); + return NULL; + } RSA_free(rsa); /* Drops our reference to it */ return pk; } diff --git a/src/util.h b/src/util.h index a1379e72..e873409d 100644 --- a/src/util.h +++ b/src/util.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025 Michał Trojnara + * Copyright (c) 2025-2026 Michał Trojnara * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -58,6 +58,8 @@ void UTIL_CTX_free(UTIL_CTX *ctx); int UTIL_CTX_set_module(UTIL_CTX *ctx, const char *module); int UTIL_CTX_set_init_args(UTIL_CTX *ctx, const char *init_args); int UTIL_CTX_set_ui_method(UTIL_CTX *ctx, UI_METHOD *ui_method, void *ui_data); +int UTIL_CTX_set_pkey_callback(UTIL_CTX *ctx, int callback_type, + PKCS11_PKEY_CALLBACK callback, void *user_data); int UTIL_CTX_enumerate_slots(UTIL_CTX *ctx); void UTIL_CTX_free_libp11(UTIL_CTX *ctx); diff --git a/src/util_uri.c b/src/util_uri.c index 002e6cdb..7390a540 100644 --- a/src/util_uri.c +++ b/src/util_uri.c @@ -3,7 +3,7 @@ * Copyright (c) 2002 Juha Yrjölä * Copyright (c) 2002 Olaf Kirch * Copyright (c) 2003 Kevin Stefanik - * Copyright (c) 2016-2025 Michał Trojnara + * Copyright (c) 2016-2026 Michał Trojnara * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -53,6 +53,9 @@ struct util_ctx_st { char *init_args; UI_METHOD *ui_method; void *ui_data; + int pkey_callback_type; + PKCS11_PKEY_CALLBACK pkey_callback; + void *pkey_callback_data; /* Logging */ int debug_level; /* level of debug output */ @@ -127,6 +130,18 @@ int UTIL_CTX_set_ui_method(UTIL_CTX *ctx, UI_METHOD *ui_method, void *ui_data) return 1; } +int UTIL_CTX_set_pkey_callback(UTIL_CTX *ctx, int callback_type, + PKCS11_PKEY_CALLBACK callback, void *user_data) +{ + ctx->pkey_callback_type = callback_type; + ctx->pkey_callback = callback; + ctx->pkey_callback_data = callback ? user_data : NULL; + if (ctx->pkcs11_ctx && PKCS11_CTX_set_pkey_callback(ctx->pkcs11_ctx, + callback_type, callback, user_data) < 0) + return 0; + return 1; +} + static int util_ctx_enumerate_slots_unlocked(UTIL_CTX *ctx) { /* PKCS11_update_slots() uses C_GetSlotList() via libp11 */ @@ -173,6 +188,12 @@ static int util_ctx_init_libp11(UTIL_CTX *ctx) PKCS11_set_vlog_a_method(ctx->pkcs11_ctx, ctx->vlog); PKCS11_CTX_init_args(ctx->pkcs11_ctx, ctx->init_args); PKCS11_set_ui_method(ctx->pkcs11_ctx, ctx->ui_method, ctx->ui_data); + if (ctx->pkey_callback && PKCS11_CTX_set_pkey_callback(ctx->pkcs11_ctx, + ctx->pkey_callback_type, ctx->pkey_callback, + ctx->pkey_callback_data) < 0) { + UTIL_CTX_free_libp11(ctx); + return -1; + } if (PKCS11_CTX_load(ctx->pkcs11_ctx, ctx->module) < 0) { UTIL_CTX_log(ctx, LOG_ERR, "Unable to load module %s\n", ctx->module); UTIL_CTX_free_libp11(ctx); From ed5c1fa1d85313a985d5f947c594a712afd3c20f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Trojnara?= Date: Mon, 17 Aug 2026 19:50:15 +0200 Subject: [PATCH 3/3] Test scoped RSA PKEY method dispatch Verify that installing a callback for a PKCS#11 key does not change provider dispatch for software RSA keys created before or afterward. Exercise ENGINE RSA-PSS with both raw-RSA-only and native-PSS-only SoftHSM configurations. Also retrieve a key through PKCS11_get_private_key(), attach key-scoped method dispatch through the new callback API, and require native CKM_RSA_PKCS_PSS when CKM_RSA_X_509 is unavailable. --- .gitignore | 2 + tests/Makefile.am | 5 + tests/pkey-callback.c | 104 +++++++++++ tests/pkey-callback.h | 33 ++++ tests/rsa-pss-direct.c | 311 +++++++++++++++++++++++++++++++++ tests/rsa-software-key.c | 169 ++++++++++++++++++ tests/rsa-software-key.softhsm | 148 ++++++++++++++++ 7 files changed, 772 insertions(+) create mode 100644 tests/pkey-callback.c create mode 100644 tests/pkey-callback.h create mode 100644 tests/rsa-pss-direct.c create mode 100644 tests/rsa-software-key.c create mode 100755 tests/rsa-software-key.softhsm diff --git a/.gitignore b/.gitignore index 1fa37af8..44c01da2 100644 --- a/.gitignore +++ b/.gitignore @@ -82,6 +82,8 @@ tests/evp-sign tests/fork-change-slot tests/rsa-oaep tests/rsa-pss-sign +tests/rsa-software-key +tests/rsa-pss-direct tests/check-privkey tests/dup-key tests/check-privkey-prov diff --git a/tests/Makefile.am b/tests/Makefile.am index 19662201..9ad84a7d 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -21,6 +21,8 @@ check_PROGRAMS = \ rsa-pss-sign-prov \ rsa-oaep \ rsa-oaep-prov \ + rsa-software-key \ + rsa-pss-direct \ check-privkey \ check-privkey-prov \ dup-key \ @@ -46,6 +48,7 @@ dist_check_SCRIPTS = \ rsa-evp-sign.softhsm \ rsa-pss-sign.softhsm \ rsa-oaep.softhsm \ + rsa-software-key.softhsm \ rsa-check-privkey.softhsm \ rsa-cert-store.softhsm \ rsa-keygen.softhsm \ @@ -108,6 +111,8 @@ fork_change_slot_prov_SOURCES = fork-change-slot-prov.c helpers_prov.c dup_key_prov_SOURCES = dup-key-prov.c helpers_prov.c check_privkey_prov_SOURCES = check-privkey-prov.c helpers_prov.c rsa_pss_sign_prov_SOURCES = rsa-pss-sign-prov.c helpers_prov.c +rsa_software_key_SOURCES = rsa-software-key.c pkey-callback.c pkey-callback.h +rsa_pss_direct_SOURCES = rsa-pss-direct.c pkey-callback.c pkey-callback.h rsa_oaep_prov_SOURCES = rsa-oaep-prov.c helpers_prov.c check_all_prov_SOURCES = check-all-prov.c helpers_prov.c ec_derive_prov_SOURCES = ec-derive-prov.c helpers_prov.c diff --git a/tests/pkey-callback.c b/tests/pkey-callback.c new file mode 100644 index 00000000..74576999 --- /dev/null +++ b/tests/pkey-callback.c @@ -0,0 +1,104 @@ +/* + * Copyright © 2026 Mobi - Com Polska Sp. z o.o. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#define OPENSSL_SUPPRESS_DEPRECATED + +#include "pkey-callback.h" + +#include +#include + +#if OPENSSL_VERSION_NUMBER >= 0x30000000L && \ + OPENSSL_VERSION_NUMBER < 0x40000000L && !defined(OPENSSL_NO_ENGINE) +#include + +struct test_pkey_callback_ctx_st { + ENGINE *engine; +}; + +static int set_pkey_engine(PKCS11_KEY *key, EVP_PKEY *pkey, void *user_data) +{ + TEST_PKEY_CALLBACK_CTX *ctx = user_data; + + (void)key; + return EVP_PKEY_set1_engine(pkey, ctx->engine) ? 0 : -1; +} + +int test_pkey_callback_init(PKCS11_CTX *ctx, + TEST_PKEY_CALLBACK_CTX **callback_ctx) +{ + TEST_PKEY_CALLBACK_CTX *cb_ctx; + + if (!ctx || !callback_ctx) + return 0; + *callback_ctx = NULL; + cb_ctx = OPENSSL_zalloc(sizeof(*cb_ctx)); + if (!cb_ctx) + return 0; + cb_ctx->engine = ENGINE_new(); + if (!cb_ctx->engine || + !ENGINE_set_id(cb_ctx->engine, "libp11-test-pkey") || + !ENGINE_set_name(cb_ctx->engine, "libp11 test PKEY methods") || + !ENGINE_set_pkey_meths(cb_ctx->engine, PKCS11_pkey_meths) || + PKCS11_CTX_set_pkey_callback(ctx, + PKCS11_PKEY_CALLBACK_GET_PRIVATE_KEY, + set_pkey_engine, cb_ctx) < 0) { + ENGINE_free(cb_ctx->engine); + OPENSSL_free(cb_ctx); + return 0; + } + *callback_ctx = cb_ctx; + return 1; +} + +void test_pkey_callback_cleanup(PKCS11_CTX *ctx, + TEST_PKEY_CALLBACK_CTX *callback_ctx) +{ + if (!callback_ctx) + return; + if (ctx) + PKCS11_CTX_set_pkey_callback(ctx, + PKCS11_PKEY_CALLBACK_GET_PRIVATE_KEY, NULL, NULL); + ENGINE_free(callback_ctx->engine); + OPENSSL_free(callback_ctx); +} + +#else + +struct test_pkey_callback_ctx_st { + int unused; +}; + +int test_pkey_callback_init(PKCS11_CTX *ctx, + TEST_PKEY_CALLBACK_CTX **callback_ctx) +{ + (void)ctx; + if (callback_ctx) + *callback_ctx = NULL; + return -1; +} + +void test_pkey_callback_cleanup(PKCS11_CTX *ctx, + TEST_PKEY_CALLBACK_CTX *callback_ctx) +{ + (void)ctx; + (void)callback_ctx; +} + +#endif + +/* vim: set noexpandtab: */ diff --git a/tests/pkey-callback.h b/tests/pkey-callback.h new file mode 100644 index 00000000..4ad19104 --- /dev/null +++ b/tests/pkey-callback.h @@ -0,0 +1,33 @@ +/* + * Copyright © 2026 Mobi - Com Polska Sp. z o.o. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef TEST_PKEY_CALLBACK_H +#define TEST_PKEY_CALLBACK_H + +#include + +typedef struct test_pkey_callback_ctx_st TEST_PKEY_CALLBACK_CTX; + +/* Returns 1 on success, 0 on error, or -1 when ENGINE is unavailable. */ +int test_pkey_callback_init(PKCS11_CTX *ctx, + TEST_PKEY_CALLBACK_CTX **callback_ctx); +void test_pkey_callback_cleanup(PKCS11_CTX *ctx, + TEST_PKEY_CALLBACK_CTX *callback_ctx); + +#endif /* TEST_PKEY_CALLBACK_H */ + +/* vim: set noexpandtab: */ diff --git a/tests/rsa-pss-direct.c b/tests/rsa-pss-direct.c new file mode 100644 index 00000000..f83c9217 --- /dev/null +++ b/tests/rsa-pss-direct.c @@ -0,0 +1,311 @@ +/* + * Copyright © 2026 Mobi - Com Polska Sp. z o.o. + * Author: Małgorzata Olszówka + * All rights reserved. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Test RSA-PSS signing with an EVP_PKEY retrieved directly through + * PKCS11_get_private_key(). A per-context callback attaches key-scoped + * ENGINE method dispatch without registering a process-wide method. + */ + +#include + +#include +#include + +#if OPENSSL_VERSION_NUMBER >= 0x30000000L && OPENSSL_VERSION_NUMBER < 0x40000000L && \ + !defined(OPENSSL_NO_ENGINE) && !defined(OPENSSL_NO_RSA) + +#include "pkey-callback.h" + +#include +#include +#include + +#include + +static const unsigned char message[] = + "libp11 direct RSA-PSS signing test"; + +static void error_queue(const char *name) +{ + if (ERR_peek_error() == 0) + return; + + fprintf(stderr, "%s generated errors:\n", name); + ERR_print_errors_fp(stderr); +} + +static int is_rsa_key(EVP_PKEY *pkey) +{ + int type; + + if (pkey == NULL) + return 0; + + type = EVP_PKEY_base_id(pkey); + if (type == EVP_PKEY_RSA) + return 1; + +#ifdef EVP_PKEY_RSA_PSS + if (type == EVP_PKEY_RSA_PSS) + return 1; +#endif + + return 0; +} + + +static int sign_pss(EVP_PKEY *pkey, + const unsigned char *digest, size_t digest_len, + unsigned char **signature, size_t *signature_len) +{ + EVP_PKEY_CTX *ctx = NULL; + unsigned char *buffer = NULL; + size_t buffer_len = 0; + int ret = 0; + + ctx = EVP_PKEY_CTX_new(pkey, NULL); + if (ctx == NULL) + goto end; + + if (EVP_PKEY_sign_init(ctx) <= 0) + goto end; + + if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PSS_PADDING) <= 0) + goto end; + + if (EVP_PKEY_CTX_set_signature_md(ctx, EVP_sha256()) <= 0) + goto end; + + if (EVP_PKEY_CTX_set_rsa_mgf1_md(ctx, EVP_sha256()) <= 0) + goto end; + + if (EVP_PKEY_CTX_set_rsa_pss_saltlen(ctx, RSA_PSS_SALTLEN_DIGEST) <= 0) + goto end; + + if (EVP_PKEY_sign(ctx, NULL, &buffer_len,digest, digest_len) <= 0) + goto end; + + buffer = OPENSSL_malloc(buffer_len); + if (buffer == NULL) + goto end; + + if (EVP_PKEY_sign(ctx, buffer, &buffer_len,digest, digest_len) <= 0) + goto end; + + *signature = buffer; + *signature_len = buffer_len; + buffer = NULL; + + ret = 1; + +end: + if (!ret) + error_queue("RSA-PSS signing"); + + OPENSSL_free(buffer); + EVP_PKEY_CTX_free(ctx); + + return ret; +} + +static int verify_pss(EVP_PKEY *pkey, + const unsigned char *digest, size_t digest_len, + const unsigned char *signature, size_t signature_len) +{ + EVP_PKEY_CTX *ctx = NULL; + int ret = 0; + + ctx = EVP_PKEY_CTX_new(pkey, NULL); + if (ctx == NULL) + goto end; + + if (EVP_PKEY_verify_init(ctx) <= 0) + goto end; + + if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PSS_PADDING) <= 0) + goto end; + + if (EVP_PKEY_CTX_set_signature_md(ctx, EVP_sha256()) <= 0) + goto end; + + if (EVP_PKEY_CTX_set_rsa_mgf1_md(ctx, EVP_sha256()) <= 0) + goto end; + + if (EVP_PKEY_CTX_set_rsa_pss_saltlen(ctx, RSA_PSS_SALTLEN_DIGEST) <= 0) + goto end; + + if (EVP_PKEY_verify(ctx, signature, signature_len, digest, digest_len) != 1) + goto end; + + ret = 1; + +end: + if (!ret) + error_queue("RSA-PSS verification"); + + EVP_PKEY_CTX_free(ctx); + + return ret; +} + +int main(int argc, char *argv[]) +{ + PKCS11_CTX *ctx = NULL; + PKCS11_SLOT *slots = NULL; + PKCS11_SLOT *slot = NULL; + PKCS11_KEY *keys = NULL; + TEST_PKEY_CALLBACK_CTX *callback_ctx = NULL; + EVP_PKEY *pkey = NULL; + unsigned char digest[EVP_MAX_MD_SIZE]; + unsigned char *signature = NULL; + unsigned int digest_len = 0; + unsigned int nslots = 0; + unsigned int nkeys = 0; + size_t signature_len = 0; + const char *pin; + int logged_in = 0; + int module_loaded = 0; + int rc = 1; + + if (argc < 2) { + fprintf(stderr, "usage: %s /path/to/pkcs11-module.so [PIN]\n", + argv[0]); + return 1; + } + + pin = argc >= 3 ? argv[2] : NULL; + + ctx = PKCS11_CTX_new(); + if (ctx == NULL) + goto end; + + if (test_pkey_callback_init(ctx, &callback_ctx) <= 0) { + fprintf(stderr, "PKCS11_CTX_set_pkey_callback failed\n"); + goto end; + } + + if (PKCS11_CTX_load(ctx, argv[1]) < 0) { + fprintf(stderr, "PKCS11_CTX_load failed\n"); + goto end; + } + + module_loaded = 1; + + if (PKCS11_enumerate_slots(ctx, &slots, &nslots) < 0) { + fprintf(stderr, "PKCS11_enumerate_slots failed\n"); + goto end; + } + + slot = PKCS11_find_token(ctx, slots, nslots); + if (slot == NULL || slot->token == NULL) { + fprintf(stderr, "No token available\n"); + goto end; + } + + if (slot->token->loginRequired && pin == NULL) { + fprintf(stderr, "The token requires a PIN\n"); + goto end; + } + + if (pin != NULL) { + if (PKCS11_login(slot, 0, pin) != 0) { + fprintf(stderr, "PKCS11_login failed\n"); + goto end; + } + logged_in = 1; + } + + if (PKCS11_enumerate_keys(slot->token, &keys, &nkeys) < 0) { + fprintf(stderr, "PKCS11_enumerate_keys failed\n"); + goto end; + } + + if (nkeys == 0) { + fprintf(stderr, "No private keys found\n"); + goto end; + } + + pkey = PKCS11_get_private_key(&keys[0]); + if (pkey == NULL) { + fprintf(stderr, "PKCS11_get_private_key failed\n"); + error_queue("PKCS11_get_private_key"); + goto end; + } + + if (!is_rsa_key(pkey)) { + fprintf(stderr, "The private key is not RSA\n"); + goto end; + } + + printf("RSA key size............: %d bits\n", EVP_PKEY_bits(pkey)); + + if (EVP_Digest(message, sizeof(message) - 1, + digest, &digest_len, + EVP_sha256(), NULL) != 1) { + fprintf(stderr, "EVP_Digest failed\n"); + goto end; + } + + if (!sign_pss(pkey, digest, digest_len, &signature, &signature_len)) + goto end; + + printf("RSA-PSS signature.......: %lu bytes\n", + (unsigned long)signature_len); + + /* + * The private EVP_PKEY also contains the RSA public components, + * so the same key can be used for verification. + */ + if (!verify_pss(pkey, digest, digest_len, signature, signature_len)) + goto end; + + printf("RSA-PSS verification....: successful\n"); + printf("Direct libp11 API test...: successful\n"); + + rc = 0; + +end: + OPENSSL_free(signature); + EVP_PKEY_free(pkey); + test_pkey_callback_cleanup(ctx, callback_ctx); + + if (logged_in) + PKCS11_logout(slot); + + if (slots != NULL) + PKCS11_release_all_slots(ctx, slots, nslots); + + if (module_loaded) + PKCS11_CTX_unload(ctx); + + PKCS11_CTX_free(ctx); + + return rc; +} + +#else + +int main(void) +{ + fprintf(stderr, "Skipped: test requires RSA and ENGINE with OpenSSL 3.x\n"); + return 77; +} + +#endif + +/* vim: set noexpandtab: */ diff --git a/tests/rsa-software-key.c b/tests/rsa-software-key.c new file mode 100644 index 00000000..7ec89603 --- /dev/null +++ b/tests/rsa-software-key.c @@ -0,0 +1,169 @@ +/* + * Copyright (C) 2026 OpenSC Project + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include + +#include + +#if OPENSSL_VERSION_NUMBER >= 0x30000000L && OPENSSL_VERSION_NUMBER < 0x40000000L && \ + !defined(OPENSSL_NO_RSA) + +#include "pkey-callback.h" + +#include +#include +#include +#include +#include +#include + +static EVP_PKEY *generate_software_key(void) +{ + EVP_PKEY_CTX *ctx; + EVP_PKEY *key = NULL; + + ctx = EVP_PKEY_CTX_new_from_name(NULL, "RSA", NULL); + if (!ctx) + return NULL; + if (EVP_PKEY_keygen_init(ctx) <= 0 || + EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, 2048) <= 0 || + EVP_PKEY_generate(ctx, &key) <= 0) { + EVP_PKEY_free(key); + key = NULL; + } + EVP_PKEY_CTX_free(ctx); + return key; +} + +static int sign_certificate(EVP_PKEY *key) +{ + static const unsigned char common_name[] = "libp11 software RSA test"; + X509_NAME *name; + X509 *cert; + int ret = 0; + + cert = X509_new(); + if (!cert) + return 0; + name = X509_get_subject_name(cert); + if (!name || !X509_set_version(cert, 2) || + !ASN1_INTEGER_set(X509_get_serialNumber(cert), 1) || + !X509_gmtime_adj(X509_getm_notBefore(cert), 0) || + !X509_gmtime_adj(X509_getm_notAfter(cert), 3600) || + !X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC, + common_name, -1, -1, 0) || + !X509_set_issuer_name(cert, name) || + !X509_set_pubkey(cert, key) || + X509_sign(cert, key, EVP_sha256()) <= 0 || + X509_verify(cert, key) <= 0) + goto cleanup; + ret = 1; + +cleanup: + X509_free(cert); + return ret; +} + +int main(int argc, char **argv) +{ + PKCS11_CTX *ctx = NULL; + PKCS11_SLOT *slots = NULL, *slot; + PKCS11_KEY *keys; + TEST_PKEY_CALLBACK_CTX *callback_ctx = NULL; + EVP_PKEY *software_key = NULL, *new_software_key = NULL; + EVP_PKEY *token_key = NULL; + unsigned int nslots = 0, nkeys = 0; + int callback_status; + int ret = EXIT_FAILURE; + + if (argc != 3) { + fprintf(stderr, "usage: %s [module] [PIN]\n", argv[0]); + return EXIT_FAILURE; + } + + software_key = generate_software_key(); + if (!software_key || !EVP_PKEY_get0_provider(software_key) || + !sign_certificate(software_key)) { + fprintf(stderr, "Initial software RSA operation failed\n"); + goto cleanup; + } + + ctx = PKCS11_CTX_new(); + if (!ctx) { + fprintf(stderr, "Failed to initialize PKCS#11\n"); + goto cleanup; + } + callback_status = test_pkey_callback_init(ctx, &callback_ctx); + if (callback_status == 0 || PKCS11_CTX_load(ctx, argv[1]) < 0 || + PKCS11_enumerate_slots(ctx, &slots, &nslots) < 0) { + fprintf(stderr, "Failed to initialize PKCS#11\n"); + goto cleanup; + } + slot = PKCS11_find_token(ctx, slots, nslots); + if (!slot || PKCS11_login(slot, 0, argv[2]) < 0 || + PKCS11_enumerate_keys(slot->token, &keys, &nkeys) < 0 || + nkeys == 0) { + fprintf(stderr, "Failed to find a PKCS#11 private key\n"); + goto cleanup; + } + token_key = PKCS11_get_private_key(&keys[0]); + if (!token_key) { + fprintf(stderr, "PKCS11_get_private_key failed\n"); + goto cleanup; + } + + /* Loading a token key must not alter a provider-backed key that was + * created earlier, or change how subsequent software keys are created. */ + new_software_key = generate_software_key(); + if (!EVP_PKEY_get0_provider(software_key) || + !sign_certificate(software_key) || !new_software_key || + !EVP_PKEY_get0_provider(new_software_key) || + !sign_certificate(new_software_key)) { + fprintf(stderr, "PKCS#11 key affected an unrelated software RSA key\n"); + goto cleanup; + } + + ret = EXIT_SUCCESS; + +cleanup: + if (ret != EXIT_SUCCESS) + ERR_print_errors_fp(stderr); + EVP_PKEY_free(new_software_key); + EVP_PKEY_free(token_key); + EVP_PKEY_free(software_key); + test_pkey_callback_cleanup(ctx, callback_ctx); + if (slots) + PKCS11_release_all_slots(ctx, slots, nslots); + if (ctx) { + PKCS11_CTX_unload(ctx); + PKCS11_CTX_free(ctx); + } + return ret; +} + +#else + +int main(void) +{ + fprintf(stderr, "Skipped: test requires RSA with OpenSSL 3.x\n"); + return 77; +} + +#endif + +/* vim: set noexpandtab: */ diff --git a/tests/rsa-software-key.softhsm b/tests/rsa-software-key.softhsm new file mode 100755 index 00000000..125e2e53 --- /dev/null +++ b/tests/rsa-software-key.softhsm @@ -0,0 +1,148 @@ +#!/bin/bash + +# Copyright (C) 2026 OpenSC Project +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +outdir="output.$$" + +PRIVATE_KEY="pkcs11:token=libp11-0;id=%01%02%03%04;object=server-key-0;type=private;pin-value=1234" +PUBLIC_KEY="pkcs11:token=libp11-0;id=%01%02%03%04;object=server-key-0;type=public;pin-value=1234" + +# Load common test functions +. "${srcdir}/common.sh" + +# Do the token initialization +init_token "rsa" "1" "libp11" "${ID}" "server-key" "privkey" "pubkey" + +# +# Configure SoftHSM2 to expose raw RSA but not native RSA-PSS. +# +# This forces libp11/OpenSSL to perform PSS encoding in software and +# use CKM_RSA_X_509 for the actual private-key operation. +# +if [[ -n "${SOFTHSM2_CONF}" ]]; then + echo "slots.mechanisms = CKM_RSA_PKCS_KEY_PAIR_GEN,CKM_RSA_X_509" \ + >>"${SOFTHSM2_CONF}" + LD_LIBRARY_PATH="${TEMP_LD_LIBRARY_PATH}" has_mechanism RSA-PKCS-PSS + has_pss=$? + LD_LIBRARY_PATH="${TEMP_LD_LIBRARY_PATH}" has_mechanism RSA-X-509 + has_raw=$? + if [[ $has_pss -eq 0 || $has_raw -ne 0 ]]; then + echo "Failed to configure raw RSA without native RSA-PSS." + exit 1 + fi +fi + +# Load OpenSSL settings +. "${srcdir}/openssl-settings.sh" + +# Restore OpenSSL settings +trap cleanup EXIT + +# +# Test isolation between software and PKCS#11 RSA keys. +# +${WRAPPER} ./rsa-software-key "${MODULE}" "${PIN}" +rc=$? + +if [[ $rc -eq 77 ]]; then + echo "Software RSA key isolation test skipped." + rm -rf "$outdir" + exit 77 +elif [[ $rc -ne 0 ]]; then + echo "Software RSA key isolation test failed." + exit 1 +fi + +# +# Test RSA-PSS through the ENGINE interface. +# +# With the SoftHSM2 configuration above, native CKM_RSA_PKCS_PSS is +# unavailable, so this exercises software PSS encoding over +# CKM_RSA_X_509. +# +${WRAPPER} ./rsa-pss-sign "${PIN}" "${outdir}/engines.cnf" \ + "${PRIVATE_KEY}" "${PUBLIC_KEY}" "${MODULE}" +rc=$? + +if [[ $rc -ne 0 && $rc -ne 77 ]]; then + echo "Raw RSA-PSS ENGINE test failed." + exit 1 +fi +echo + +# +# Configure SoftHSM2 for native RSA-PSS. +# +# CKM_RSA_X_509 is deliberately disabled. Therefore, a successful +# RSA-PSS signature cannot use the software-PSS/raw-RSA fallback. +# +if [[ -n "${SOFTHSM2_CONF}" ]]; then + grep -v '^slots.mechanisms' "${SOFTHSM2_CONF}" \ + >"${SOFTHSM2_CONF}.tmp" + echo "slots.mechanisms = CKM_RSA_PKCS_KEY_PAIR_GEN,CKM_RSA_PKCS_PSS" \ + >>"${SOFTHSM2_CONF}.tmp" + mv "${SOFTHSM2_CONF}.tmp" "${SOFTHSM2_CONF}" + LD_LIBRARY_PATH="${TEMP_LD_LIBRARY_PATH}" has_mechanism RSA-PKCS-PSS + has_pss=$? + LD_LIBRARY_PATH="${TEMP_LD_LIBRARY_PATH}" has_mechanism RSA-X-509 + has_raw=$? + if [[ $has_pss -ne 0 || $has_raw -eq 0 ]]; then + echo "Failed to configure native RSA-PSS without raw RSA." + exit 1 + fi +fi + +# +# Test native RSA-PSS through ENGINE when the ENGINE test is supported. +# +${WRAPPER} ./rsa-pss-sign "${PIN}" "${outdir}/engines.cnf" \ + "${PRIVATE_KEY}" "${PUBLIC_KEY}" "${MODULE}" +rc=$? +if [[ $rc -eq 77 ]]; then + echo "Native RSA-PSS ENGINE test skipped." + exit 77 +elif [[ $rc -ne 0 ]]; then + echo "Native RSA-PSS ENGINE test failed." + exit 1 +fi +echo + +# +# Do not load the pkcs11 ENGINE through the OpenSSL configuration. +# The following test installs a per-context PKEY callback and exercises an +# EVP_PKEY obtained directly through PKCS11_get_private_key(). +# +unset OPENSSL_ENGINES + +# +# Run the direct libp11 API test. +# +# For SoftHSM2, CKM_RSA_X_509 has been disabled above. Therefore a +# successful RSA-PSS signature proves that the native +# CKM_RSA_PKCS_PSS path is functional. +# +${WRAPPER} ./rsa-pss-direct "${MODULE}" "${PIN}" +rc=$? +if [[ $rc -eq 77 ]]; then + echo "Direct RSA-PSS test skipped." + exit 77 +elif [[ $rc -ne 0 ]]; then + echo "Direct RSA-PSS test failed." + exit 1 +fi + +rm -rf "$outdir" +exit 0