From c5c51408180a8a44f60dca9f3a6bb5e2c52c672b Mon Sep 17 00:00:00 2001 From: olszomal Date: Mon, 18 May 2026 08:51:04 +0200 Subject: [PATCH 1/7] tests: improve RSA interoperability and coverage Add PKCS#11 interoperability tests for: - RSA PKCS#1 v1.5 signing - RSA_NO_PADDING sign/verifyrecover - RSA PKCS#1 v1.5 encrypt/decrypt - RSA OAEP encrypt/decrypt --- tests/pkcs11-uri-without-token.softhsm | 175 +++++++++++-- .../provider-pkcs11-uri-without-token.softhsm | 229 ++++++++++++++++-- tests/rsa-oaep-prov.c | 12 +- tests/rsa-oaep.c | 3 + 4 files changed, 376 insertions(+), 43 deletions(-) diff --git a/tests/pkcs11-uri-without-token.softhsm b/tests/pkcs11-uri-without-token.softhsm index 24fb0dd0..1baa39f9 100755 --- a/tests/pkcs11-uri-without-token.softhsm +++ b/tests/pkcs11-uri-without-token.softhsm @@ -52,23 +52,145 @@ fi trap cleanup EXIT # Run the test -# Generate signature without specifying the token in the PKCS#11 URI + +#### Encrypt/decrypt RSA_PKCS1_OAEP_PADDING (CKM_RSA_PKCS_OAEP) #### + +# Encrypt file with RSA public key using OAEP +# OpenSSL defaults RSA-OAEP to SHA1 for oaep_md +${OPENSSL} pkeyutl -engine pkcs11 -keyform engine \ + -inkey ${PUBLIC_KEY} \ + -encrypt -pubin \ + -pkeyopt rsa_padding_mode:oaep \ + -out "${outdir}/encrypted.bin" -in "${outdir}/in.txt" +if [[ $? -ne 0 ]]; then + echo "Failed to encrypt file with RSA public key using OAEP" + exit 1 +fi +echo + +# Decrypt file with RSA private key using OAEP +# SoftHSM currently supports RSA-OAEP only with SHA-1/MGF1-SHA1 +${OPENSSL} pkeyutl -engine pkcs11 -keyform engine \ + -inkey ${PRIVATE_KEY} \ + -decrypt \ + -pkeyopt rsa_padding_mode:oaep \ + -pkeyopt rsa_oaep_md:sha1 \ + -pkeyopt rsa_mgf1_md:sha1 \ + -out "${outdir}/decrypted.bin" -in "${outdir}/encrypted.bin" +if [[ $? -ne 0 ]]; then + echo "Failed to decrypt file with RSA private key using OAEP" + exit 1 +fi + +cmp "${outdir}/in.txt" "${outdir}/decrypted.bin" +if [[ $? -ne 0 ]]; then + echo "Decrypted OAEP data does not match input" + exit 1 +fi +echo + + +#### Encrypt/decrypt RSA_PKCS1_PADDING (CKM_RSA_PKCS) #### + +# Encrypt file with RSA public key using PKCS#1 v1.5 padding +${OPENSSL} pkeyutl -engine pkcs11 -keyform engine \ + -inkey ${PUBLIC_KEY} \ + -encrypt -pubin \ + -pkeyopt rsa_padding_mode:pkcs1 \ + -out "${outdir}/encrypted.bin" -in "${outdir}/in.txt" +if [[ $? -ne 0 ]]; then + echo "Failed to encrypt file with RSA public key using PKCS#1 padding" + exit 1 +fi +echo + +# Decrypt file with RSA private key using PKCS#1 v1.5 padding +${OPENSSL} pkeyutl -engine pkcs11 -keyform engine \ + -inkey ${PRIVATE_KEY} \ + -decrypt \ + -pkeyopt rsa_padding_mode:pkcs1 \ + -out "${outdir}/decrypted.bin" -in "${outdir}/encrypted.bin" +if [[ $? -ne 0 ]]; then + echo "Failed to decrypt file with RSA private key using PKCS#1 padding" + exit 1 +fi + +cmp "${outdir}/in.txt" "${outdir}/decrypted.bin" +if [[ $? -ne 0 ]]; then + echo "Decrypted PKCS#1 data does not match input" + exit 1 +fi +echo + + +#### Sign/verifyrecover RSA_NO_PADDING (CKM_RSA_X_509) #### + +# Prepare raw input accepted by pkeyutl without -rawin +printf "secret" > "${outdir}/raw.bin" +truncate -s 64 "${outdir}/raw.bin" + +# Sign raw input data without padding +${WRAPPER} ${OPENSSL} pkeyutl -engine pkcs11 -keyform engine \ + -inkey ${PRIVATE_KEY} \ + -sign -pkeyopt rsa_padding_mode:none \ + -out "${outdir}/signature.bin" -in "${outdir}/raw.bin" +if [[ $? -ne 0 ]]; then + echo "Failed to generate signature using PKCS#11 URI ${PRIVATE_KEY}" + exit 1 +fi +echo + +# Verify raw RSA signature using the public key +${OPENSSL} pkeyutl -engine pkcs11 -keyform engine \ + -inkey ${PUBLIC_KEY} \ + -verifyrecover -pubin -pkeyopt rsa_padding_mode:none \ + -in "${outdir}/signature.bin" -out "${outdir}/recovered.bin" +if [[ $? -ne 0 ]]; then + echo "Failed to verifyrecover RSA_NO_PADDING signature using PKCS#11 URI ${PUBLIC_KEY}" + exit 1 +fi + +# RSA_NO_PADDING operates on the input as a big-endian integer. +# During verifyrecover(), OpenSSL returns the full RSA modulus-sized block, +# left-padded with zeros. The original input therefore appears right-aligned +# at the end of the recovered buffer, so compare only the trailing bytes. +cmp "${outdir}/raw.bin" <(tail -c 64 "${outdir}/recovered.bin") +if [[ $? -ne 0 ]]; then + echo "Recovered RSA_NO_PADDING block does not match input" + exit 1 +fi +echo + + +#### Sign/verify RSA_PKCS1_PADDING (CKM_RSA_PKCS) without digest #### + +# Compute the SHA-256 binary digest of the input file +${OPENSSL} dgst -sha256 -binary -out "${outdir}/hash.bin" "${outdir}/in.txt" + +# Sign the input data without specifying the token in the PKCS#11 URI ${WRAPPER} ${OPENSSL} pkeyutl -engine pkcs11 -keyform engine \ - -inkey ${PRIVATE_KEY} -sign -out "${outdir}/signature.bin" \ - -in "${outdir}/in.txt" + -inkey ${PRIVATE_KEY} \ + -sign \ + -out "${outdir}/signature.bin" -in "${outdir}/hash.bin" if [[ $? -ne 0 ]]; then echo "Failed to generate signature using PKCS#11 URI ${PRIVATE_KEY}" exit 1 fi +echo -# Verify the signature without specifying the token in the PKCS#11 URI -${OPENSSL} pkeyutl -engine pkcs11 -keyform engine -pubin \ - -inkey ${PUBLIC_KEY} -verify -sigfile "${outdir}/signature.bin" \ - -in "${outdir}/in.txt" +# Verify RSA signature using the public key without specifying the token +${OPENSSL} pkeyutl -engine pkcs11 -keyform engine \ + -inkey ${PUBLIC_KEY} \ + -verify -pubin \ + -sigfile "${outdir}/signature.bin" -in "${outdir}/hash.bin" if [[ $? -ne 0 ]]; then echo "Failed to verify signature using PKCS#11 URI ${PUBLIC_KEY}" exit 1 fi +echo + + +#### Sign/verify RSA_PKCS1_PADDING (CKM_RSA_PKCS) with implicit SHA256 digest #### if ! ${OPENSSL} pkeyutl -help 2>&1 | grep -q -- "-rawin"; then echo "Skipping RSA-PSS raw test: -rawin not supported" @@ -76,22 +198,47 @@ if ! ${OPENSSL} pkeyutl -help 2>&1 | grep -q -- "-rawin"; then exit 0 # Success fi -# Compute the SHA-256 binary digest of the input file -${OPENSSL} dgst -sha256 -binary -out "${outdir}/hash.bin" "${outdir}/in.txt" +# Sign the input data without specifying the token in the PKCS#11 URI (raw input) +${OPENSSL} pkeyutl -engine pkcs11 -keyform engine \ + -inkey ${PRIVATE_KEY} \ + -sign -rawin \ + -out "${outdir}/signature.bin" -in "${outdir}/in.txt" +if [[ $? -ne 0 ]]; then + echo "Failed to generate signature using PKCS#11 URI ${PRIVATE_KEY}" + exit 1 +fi +echo + +# Verify RSA signature using the public key +${OPENSSL} pkeyutl -engine pkcs11 -keyform engine \ + -inkey ${PUBLIC_KEY} \ + -verify -pubin -rawin \ + -sigfile "${outdir}/signature.bin" -in "${outdir}/in.txt" +if [[ $? -ne 0 ]]; then + echo "Failed to verify signature using PKCS#11 URI ${PUBLIC_KEY}" + exit 1 +fi +echo + + +#### Sign/verify RSA_PKCS1_PSS_PADDING (CKM_RSA_PKCS_PSS) with implicit SHA256 digest #### # Sign the SHA-256 digest with an RSA key using RSA-PSS (raw input) ${OPENSSL} pkeyutl -engine pkcs11 -keyform engine \ - -inkey ${PRIVATE_KEY} -sign -rawin -pkeyopt rsa_padding_mode:pss \ - -out "${outdir}/signature.bin" -in "${outdir}/hash.bin" + -inkey ${PRIVATE_KEY} \ + -sign -rawin -pkeyopt rsa_padding_mode:pss \ + -out "${outdir}/signature.bin" -in "${outdir}/in.txt" if [[ $? -ne 0 ]]; then echo "Failed to sign a digest using RSA-PSS" exit 1 fi +echo # Verify the signature with an RSA public key using RSA-PSS (raw input) -${OPENSSL} pkeyutl -engine pkcs11 -keyform engine -pubin \ - -inkey ${PUBLIC_KEY} -verify -rawin -pkeyopt rsa_padding_mode:pss \ - -sigfile "${outdir}/signature.bin" -in "${outdir}/hash.bin" +${OPENSSL} pkeyutl -engine pkcs11 -keyform engine \ + -inkey ${PUBLIC_KEY} \ + -verify -pubin -rawin -pkeyopt rsa_padding_mode:pss \ + -sigfile "${outdir}/signature.bin" -in "${outdir}/in.txt" if [[ $? -ne 0 ]]; then echo "Failed to verify signature using PKCS#11 URI ${PUBLIC_KEY_ANY}" exit 1 diff --git a/tests/provider-pkcs11-uri-without-token.softhsm b/tests/provider-pkcs11-uri-without-token.softhsm index 12ad3000..38aae038 100755 --- a/tests/provider-pkcs11-uri-without-token.softhsm +++ b/tests/provider-pkcs11-uri-without-token.softhsm @@ -55,67 +55,244 @@ echo "secret" >"${outdir}/in.txt" trap cleanup EXIT # Run the test -# Generate signature without specifying the token in the PKCS#11 URI -# + # Use "?provider=pkcs11prov" to prefer pkcs11prov but allow fallback to default. # Signing may require algorithms not provided by pkcs11prov (e.g. DRBG/RAND), # so a strict "provider=pkcs11prov" would fail to fetch them. + +#### Encrypt/decrypt RSA_PKCS1_OAEP_PADDING (CKM_RSA_PKCS_OAEP) #### + +# Encrypt file with RSA public key using OAEP +# OpenSSL defaults RSA-OAEP to SHA1 for oaep_md +${OPENSSL} pkeyutl -provider pkcs11prov -provider default \ + -propquery "?provider=pkcs11prov" \ + -inkey ${PUBLIC_KEY} \ + -encrypt -pubin \ + -pkeyopt rsa_padding_mode:oaep \ + -out "${outdir}/encrypted.bin" -in "${outdir}/in.txt" +if [[ $? -ne 0 ]]; then + echo "Failed to encrypt file with RSA public key using OAEP" + exit 1 +fi +echo + +# Decrypt file with RSA private key using OAEP +# SoftHSM currently supports RSA-OAEP only with SHA-1/MGF1-SHA1 +${OPENSSL} pkeyutl -provider pkcs11prov -provider default \ + -propquery "?provider=pkcs11prov" \ + -inkey ${PRIVATE_KEY} \ + -decrypt \ + -pkeyopt rsa_padding_mode:oaep \ + -pkeyopt rsa_oaep_md:sha1 \ + -pkeyopt rsa_mgf1_md:sha1 \ + -out "${outdir}/decrypted.bin" -in "${outdir}/encrypted.bin" +if [[ $? -ne 0 ]]; then + echo "Failed to decrypt file with RSA private key using OAEP" + exit 1 +fi + +cmp "${outdir}/in.txt" "${outdir}/decrypted.bin" +if [[ $? -ne 0 ]]; then + echo "Decrypted OAEP data does not match input" + exit 1 +fi +echo + + +#### Encrypt/decrypt RSA_PKCS1_PADDING (CKM_RSA_PKCS) #### + +# Encrypt file with RSA public key using PKCS#1 v1.5 padding +${OPENSSL} pkeyutl -provider pkcs11prov -provider default \ + -propquery "?provider=pkcs11prov" \ + -inkey ${PUBLIC_KEY} \ + -encrypt -pubin \ + -pkeyopt rsa_padding_mode:pkcs1 \ + -out "${outdir}/encrypted.bin" -in "${outdir}/in.txt" +if [[ $? -ne 0 ]]; then + echo "Failed to encrypt file with RSA public key using PKCS#1 padding" + exit 1 +fi +echo + +# Decrypt file with RSA private key using PKCS#1 v1.5 padding +${OPENSSL} pkeyutl -provider pkcs11prov -provider default \ + -propquery "?provider=pkcs11prov" \ + -inkey ${PRIVATE_KEY} \ + -decrypt \ + -pkeyopt rsa_padding_mode:pkcs1 \ + -out "${outdir}/decrypted.bin" -in "${outdir}/encrypted.bin" +if [[ $? -ne 0 ]]; then + echo "Failed to decrypt file with RSA private key using PKCS#1 padding" + exit 1 +fi + +cmp "${outdir}/in.txt" "${outdir}/decrypted.bin" +if [[ $? -ne 0 ]]; then + echo "Decrypted PKCS#1 data does not match input" + exit 1 +fi +echo + + +#### Sign/verifyrecover RSA_NO_PADDING (CKM_RSA_X_509) #### + +# Prepare raw input accepted by pkeyutl without -rawin +printf "secret" > "${outdir}/raw.bin" +truncate -s 64 "${outdir}/raw.bin" + +# Sign raw input data without padding +${WRAPPER} ${OPENSSL} pkeyutl -provider pkcs11prov -provider default \ + -propquery "?provider=pkcs11prov" \ + -inkey ${PRIVATE_KEY} \ + -sign -pkeyopt rsa_padding_mode:none \ + -out "${outdir}/signature.bin" -in "${outdir}/raw.bin" +if [[ $? -ne 0 ]]; then + echo "Failed to generate RSA_NO_PADDING signature using PKCS#11 URI ${PRIVATE_KEY}" + exit 1 +fi +echo + +# Verify raw RSA signature using the public key +${OPENSSL} pkeyutl -provider pkcs11prov -provider default \ + -propquery "provider=pkcs11prov" \ + -inkey ${PUBLIC_KEY} \ + -verifyrecover -pubin -pkeyopt rsa_padding_mode:none \ + -in "${outdir}/signature.bin" -out "${outdir}/recovered.bin" +if [[ $? -ne 0 ]]; then + echo "Failed to verifyrecover RSA_NO_PADDING signature using PKCS#11 URI ${PUBLIC_KEY}" + exit 1 +fi + +# RSA_NO_PADDING operates on the input as a big-endian integer. +# During verifyrecover(), OpenSSL returns the full RSA modulus-sized block, +# left-padded with zeros. The original input therefore appears right-aligned +# at the end of the recovered buffer, so compare only the trailing bytes. +cmp "${outdir}/raw.bin" <(tail -c 64 "${outdir}/recovered.bin") +if [[ $? -ne 0 ]]; then + echo "Recovered RSA_NO_PADDING block does not match input" + exit 1 +fi +echo + + +#### Sign/verify RSA_PKCS1_PADDING (CKM_RSA_PKCS) without digest #### + +# Compute the SHA-256 binary digest of the input file +${OPENSSL} dgst -sha256 -binary -out "${outdir}/hash.bin" "${outdir}/in.txt" + +# Sign the input data without specifying the token in the PKCS#11 URI ${WRAPPER} ${OPENSSL} pkeyutl -provider pkcs11prov -provider default \ -propquery "?provider=pkcs11prov" \ - -inkey ${PRIVATE_KEY} -sign -out "${outdir}/signature.bin" \ - -in "${outdir}/in.txt" + -inkey ${PRIVATE_KEY} \ + -sign \ + -out "${outdir}/signature.bin" -in "${outdir}/hash.bin" if [[ $? -ne 0 ]]; then echo "Failed to generate signature using PKCS#11 URI ${PRIVATE_KEY}" exit 1 fi +echo -# Verify the signature using the public key without specifying the token -${OPENSSL} pkeyutl -provider pkcs11prov -provider default -pubin \ +# Verify RSA signature using the public key without specifying the token +${OPENSSL} pkeyutl -provider pkcs11prov -provider default \ -propquery "provider=pkcs11prov" \ - -inkey ${PUBLIC_KEY} -verify -sigfile "${outdir}/signature.bin" \ - -in "${outdir}/in.txt" + -inkey ${PUBLIC_KEY} \ + -verify -pubin \ + -sigfile "${outdir}/signature.bin" -in "${outdir}/hash.bin" if [[ $? -ne 0 ]]; then echo "Failed to verify signature using PKCS#11 URI ${PUBLIC_KEY}" exit 1 fi +echo -# Verify the signature using a certificate without specifying the token -# -# Use "?provider=pkcs11prov" to prefer pkcs11prov but allow fallback to default. -# This enables default provider decoders (e.g. for SubjectPublicKeyInfo (SPKI)) -# to construct EVP_PKEY from X509 when pkcs11prov does not implement them. -${OPENSSL} pkeyutl -provider pkcs11prov -provider default -certin \ +# Verify the signature using a certificate via rsa_verify_directly() +${OPENSSL} pkeyutl -provider pkcs11prov -provider default \ + -propquery "?provider=pkcs11prov" \ + -inkey ${CERTIFICATE} \ + -verify -certin \ + -sigfile "${outdir}/signature.bin" -in "${outdir}/hash.bin" +if [[ $? -ne 0 ]]; then + echo "Failed to verify signature using PKCS#11 URI ${CERTIFICATE}" + exit 1 +fi +echo + + +#### Sign/verify RSA_PKCS1_PADDING (CKM_RSA_PKCS) with implicit SHA256 digest #### + +# Sign the input data without specifying the token in the PKCS#11 URI (raw input) +${OPENSSL} pkeyutl -provider pkcs11prov -provider default \ + -propquery "?provider=pkcs11prov" \ + -inkey ${PRIVATE_KEY} \ + -sign -rawin \ + -out "${outdir}/signature.bin" -in "${outdir}/in.txt" +if [[ $? -ne 0 ]]; then + echo "Failed to generate signature using PKCS#11 URI ${PRIVATE_KEY}" + exit 1 +fi +echo + +# Verify RSA signature using the public key +${OPENSSL} pkeyutl -provider pkcs11prov -provider default \ -propquery "?provider=pkcs11prov" \ - -inkey ${PUBLIC_KEY} -verify -sigfile "${outdir}/signature.bin" \ - -in "${outdir}/in.txt" + -inkey ${PUBLIC_KEY} \ + -verify -pubin -rawin -digest SHA256 \ + -sigfile "${outdir}/signature.bin" -in "${outdir}/in.txt" if [[ $? -ne 0 ]]; then echo "Failed to verify signature using PKCS#11 URI ${PUBLIC_KEY}" exit 1 fi +echo -# Compute the SHA-256 binary digest of the input file -${OPENSSL} dgst -sha256 -binary -out "${outdir}/hash.bin" "${outdir}/in.txt" +# Verify the signature using a certificate via rsa_verify_directly() +${OPENSSL} pkeyutl -provider pkcs11prov -provider default \ + -propquery "?provider=pkcs11prov" \ + -inkey ${CERTIFICATE} \ + -verify -certin -rawin -digest SHA256 \ + -sigfile "${outdir}/signature.bin" -in "${outdir}/in.txt" +if [[ $? -ne 0 ]]; then + echo "Failed to verify signature using PKCS#11 URI ${CERTIFICATE}" + exit 1 +fi +echo -# Sign the SHA-256 digest with an RSA key using RSA-PSS (raw input) + +#### Sign/verify RSA_PKCS1_PSS_PADDING (CKM_RSA_PKCS_PSS) with implicit SHA256 digest #### + +# Sign the input data with an RSA key using RSA-PSS (raw input) ${OPENSSL} pkeyutl -provider pkcs11prov -provider default \ -propquery "?provider=pkcs11prov" \ - -inkey ${PRIVATE_KEY} -sign -rawin -pkeyopt rsa_padding_mode:pss \ - -out "${outdir}/signature.bin" -in "${outdir}/hash.bin" + -inkey ${PRIVATE_KEY} \ + -sign -rawin -pkeyopt rsa_padding_mode:pss \ + -out "${outdir}/signature.bin" -in "${outdir}/in.txt" if [[ $? -ne 0 ]]; then echo "Failed to sign a digest using RSA-PSS" exit 1 fi +echo -# Verify the signature with an RSA public key using RSA-PSS (raw input) -${OPENSSL} pkeyutl -provider pkcs11prov -provider default -pubin \ - -propquery "provider=pkcs11prov" \ - -inkey ${PUBLIC_KEY} -verify -rawin -pkeyopt rsa_padding_mode:pss \ - -sigfile "${outdir}/signature.bin" -in "${outdir}/hash.bin" +# Verify the signature with an RSA public key using RSA-PSS +${OPENSSL} pkeyutl -provider pkcs11prov -provider default \ + -propquery "?provider=pkcs11prov" \ + -inkey ${PUBLIC_KEY} \ + -verify -pubin -rawin -digest SHA256 -pkeyopt rsa_padding_mode:pss \ + -sigfile "${outdir}/signature.bin" -in "${outdir}/in.txt" if [[ $? -ne 0 ]]; then echo "Failed to verify signature using PKCS#11 URI ${PUBLIC_KEY}" exit 1 fi +echo + +# Verify the signature using a certificate via rsa_verify_directly() +${OPENSSL} pkeyutl -provider pkcs11prov -provider default \ + -propquery "?provider=pkcs11prov" \ + -inkey ${CERTIFICATE} \ + -verify -certin -rawin -digest SHA256 -pkeyopt rsa_padding_mode:pss \ + -sigfile "${outdir}/signature.bin" -in "${outdir}/in.txt" +if [[ $? -ne 0 ]]; then + echo "Failed to verify signature using PKCS#11 URI ${CERTIFICATE}" + exit 1 +fi rm -rf "$outdir" diff --git a/tests/rsa-oaep-prov.c b/tests/rsa-oaep-prov.c index b0934833..ad08bf69 100644 --- a/tests/rsa-oaep-prov.c +++ b/tests/rsa-oaep-prov.c @@ -86,9 +86,12 @@ int main(int argc, char **argv) display_openssl_errors(); goto cleanup; } - /* EME-OAEP as defined in PKCS #1 v2.0 with SHA-1, MGF1 and an empty encoding parameter (OAEP label) */ - if (EVP_PKEY_CTX_set_rsa_padding(pkey_ctx, RSA_PKCS1_OAEP_PADDING) <= 0) { - fprintf(stderr, "Could not set padding\n"); + /* EME-OAEP with SHA-1, MGF1-SHA1 and no OAEP label */ + if (EVP_PKEY_CTX_set_rsa_padding(pkey_ctx, RSA_PKCS1_OAEP_PADDING) <= 0 || + EVP_PKEY_CTX_set_rsa_oaep_md(pkey_ctx, EVP_sha1()) <= 0 || + EVP_PKEY_CTX_set_rsa_mgf1_md(pkey_ctx, EVP_sha1()) <= 0 || + EVP_PKEY_CTX_set0_rsa_oaep_label(pkey_ctx, NULL, 0) <= 0) { + fprintf(stderr, "Could not configure OAEP parameters\n"); display_openssl_errors(); goto cleanup; } @@ -112,6 +115,9 @@ int main(int argc, char **argv) display_openssl_errors(); goto cleanup; } + + /* SoftHSM currently supports RSA-OAEP only with SHA-1/MGF1-SHA1 + * and does not support non-empty OAEP labels (pSourceData). */ if (EVP_PKEY_CTX_set_rsa_padding(pkey_ctx, RSA_PKCS1_OAEP_PADDING) <= 0) { fprintf(stderr, "Could not set padding\n"); display_openssl_errors(); diff --git a/tests/rsa-oaep.c b/tests/rsa-oaep.c index f4399fcb..274ac226 100644 --- a/tests/rsa-oaep.c +++ b/tests/rsa-oaep.c @@ -179,6 +179,7 @@ int main(int argc, char **argv) exit(1); } + /* EME-OAEP with SHA-1, MGF1-SHA1 and no OAEP label */ if (EVP_PKEY_CTX_set_rsa_padding(pkey_ctx, RSA_PKCS1_OAEP_PADDING) <= 0) { fprintf(stderr, "Could not set padding\n"); display_openssl_errors(__LINE__); @@ -212,6 +213,8 @@ int main(int argc, char **argv) exit(1); } + /* SoftHSM currently supports RSA-OAEP only with SHA-1/MGF1-SHA1 + * and does not support non-empty OAEP labels (pSourceData). */ if (EVP_PKEY_CTX_set_rsa_padding(pkey_ctx, RSA_PKCS1_OAEP_PADDING) <= 0) { fprintf(stderr, "Could not set padding\n"); display_openssl_errors(__LINE__); From bc0660661b8139c97ef45052b4ea76199578d967 Mon Sep 17 00:00:00 2001 From: olszomal Date: Mon, 18 May 2026 09:13:58 +0200 Subject: [PATCH 2/7] provider: improve RSA signing and decrypt handling --- NEWS | 1 + src/libp11-int.h | 6 +-- src/libp11.h | 3 +- src/p11_front.c | 6 +-- src/p11_key.c | 6 +-- src/p11_pkey.c | 22 +++------ src/p11_rsa.c | 9 ++-- src/provider.c | 101 +++++++++++++++---------------------- src/provider_helpers.c | 110 +++++++++++++++++++++++------------------ src/provider_helpers.h | 3 +- 10 files changed, 126 insertions(+), 141 deletions(-) diff --git a/NEWS b/NEWS index effe7df9..ecae25fb 100644 --- a/NEWS +++ b/NEWS @@ -2,6 +2,7 @@ NEWS for Libp11 -- History of user visible changes New in 0.4.19; unreleased * Define LIBP11_VERSION_NUMBER (Michał Trojnara) +* Added PKCS#11 provider support for OpenSSL 4.x. (Małgorzata Olszówka) New in 0.4.18; 2026-02-16; Michał Trojnara * Support for RSA-PSS and RSA-OAEP using keys retrieved using the diff --git a/src/libp11-int.h b/src/libp11-int.h index 59285103..e8c4bb42 100644 --- a/src/libp11-int.h +++ b/src/libp11-int.h @@ -383,8 +383,8 @@ extern int pkcs11_sign(int type, /* Sign input data using RSA private key via PKCS#11 mechanism */ extern int pkcs11_evp_pkey_rsa_sign(PKCS11_OBJECT_private *key, EVP_PKEY *pkey, - const char *mdname, const int pad_mode, const int salt_len, - const char *mgf1_mdname, unsigned char *oaep_label, const int oaep_labellen, + const char *mdname, const int pad_mode, + const int salt_len, const char *mgf1_mdname, unsigned char *sig, size_t *siglen, const unsigned char *tbs, size_t tbslen); @@ -409,7 +409,7 @@ extern int pkcs11_evp_pkey_rsa_decrypt(PKCS11_OBJECT_private *key, EVP_PKEY *pke const char *mdname, const int pad_mode, const char *mgf1_mdname, unsigned char *oaep_label, const int oaep_labellen, unsigned char *out, size_t *outlen, - size_t *outsize, const unsigned char *in, size_t inlen); + const unsigned char *in, size_t inlen); /* This function has never been implemented */ extern int pkcs11_verify(int type, diff --git a/src/libp11.h b/src/libp11.h index bba8c3f9..a1628920 100644 --- a/src/libp11.h +++ b/src/libp11.h @@ -537,7 +537,6 @@ extern int PKCS11_verify(int type, /* Perform a private-key operation using a PKCS#11-backed EVP_PKEY */ extern int PKCS11_evp_pkey_sign(EVP_PKEY *pkey, int type, const char *mdname, const int pad_mode, const int salt_len, const char *mgf1_mdname, - unsigned char *oaep_label, const int oaep_labellen, unsigned char *sig, size_t *siglen, const unsigned char *tbs, size_t tbslen); @@ -546,7 +545,7 @@ extern int PKCS11_evp_pkey_decrypt(EVP_PKEY *pk, int type, const char *mdname, const int pad_mode, const char *mgf1_mdname, unsigned char *oaep_label, const int oaep_labellen, unsigned char *sig, size_t *siglen, - size_t *outsize, const unsigned char *in, size_t inlen); + const unsigned char *in, size_t inlen); #endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ /* Encrypts data using the private key */ diff --git a/src/p11_front.c b/src/p11_front.c index b3a713a9..6f4b787b 100644 --- a/src/p11_front.c +++ b/src/p11_front.c @@ -551,7 +551,6 @@ int PKCS11_sign(int type, const unsigned char *m, unsigned int m_len, #if OPENSSL_VERSION_NUMBER >= 0x30000000L int PKCS11_evp_pkey_sign(EVP_PKEY *pk, int type, const char *mdname, const int pad_mode, const int pss_saltlen, const char *mgf1_mdname, - unsigned char *oaep_label, const int oaep_labellen, unsigned char *sig, size_t *siglen, const unsigned char *tbs, size_t tbslen) { @@ -569,7 +568,6 @@ int PKCS11_evp_pkey_sign(EVP_PKEY *pk, int type, const char *mdname, case EVP_PKEY_RSA: return pkcs11_evp_pkey_rsa_sign(key, pk, mdname, pad_mode, pss_saltlen, mgf1_mdname, - oaep_label, oaep_labellen, sig, siglen, tbs, tbslen); #ifndef OPENSSL_NO_EC case EVP_PKEY_EC: @@ -589,7 +587,7 @@ int PKCS11_evp_pkey_decrypt(EVP_PKEY *pk, int type, const char *mdname, const int pad_mode, const char *mgf1_mdname, unsigned char *oaep_label, const int oaep_labellen, unsigned char *out, size_t *outlen, - size_t *outsize, const unsigned char *in, size_t inlen) + const unsigned char *in, size_t inlen) { PKCS11_OBJECT_private *key; PKCS11_KEY *pkey = pkcs11_get_pkcs11_key(pk); @@ -607,7 +605,7 @@ int PKCS11_evp_pkey_decrypt(EVP_PKEY *pk, int type, const char *mdname, return pkcs11_evp_pkey_rsa_decrypt(key, pk, mdname, pad_mode, mgf1_mdname, oaep_label, oaep_labellen, - out, outlen, outsize, in, inlen); + out, outlen, in, inlen); default: return -2; /* type not supported */ } diff --git a/src/p11_key.c b/src/p11_key.c index 3c1f0328..ccf68a64 100644 --- a/src/p11_key.c +++ b/src/p11_key.c @@ -1257,8 +1257,7 @@ static int pkcs11_try_pkey_rsa_sign(EVP_PKEY_CTX *evp_pkey_ctx, mgf1_mdname = EVP_MD_name(mgf1_md); return pkcs11_evp_pkey_rsa_sign(key, pkey, mdname, padding, - salt_len, mgf1_mdname, NULL, 0, - sig, siglen, tbs, tbslen); + salt_len, mgf1_mdname, sig, siglen, tbs, tbslen); } /* Attempt to decrypt using the PKCS#11-backed RSA implementation */ @@ -1269,7 +1268,6 @@ static int pkcs11_try_pkey_rsa_decrypt(EVP_PKEY_CTX *evp_pkey_ctx, EVP_PKEY *pkey; RSA *rsa; int padding; - CK_ULONG outsize = (CK_ULONG)*outlen; PKCS11_OBJECT_private *key; PKCS11_SLOT_private *slot; CK_SESSION_HANDLE session; @@ -1329,7 +1327,7 @@ static int pkcs11_try_pkey_rsa_decrypt(EVP_PKEY_CTX *evp_pkey_ctx, mgf1_mdname = EVP_MD_name(mgf1_md); return pkcs11_evp_pkey_rsa_decrypt(key, pkey, mdname, padding, mgf1_mdname, - oaep_label, oaep_labellen, out, outlen, &outsize, in, inlen); + oaep_label, oaep_labellen, out, outlen, in, inlen); } static int pkcs11_pkey_rsa_sign(EVP_PKEY_CTX *evp_pkey_ctx, diff --git a/src/p11_pkey.c b/src/p11_pkey.c index 077f3b9f..595c2e05 100644 --- a/src/p11_pkey.c +++ b/src/p11_pkey.c @@ -408,8 +408,8 @@ static int pkcs11_sign_with_mechanism(PKCS11_OBJECT_private *key, * Returns 1 on success or -1 on failure. */ int pkcs11_evp_pkey_rsa_sign(PKCS11_OBJECT_private *key, EVP_PKEY *pkey, - const char *mdname, const int pad_mode, const int salt_len, - const char *mgf1_mdname, unsigned char *oaep_label, const int oaep_labellen, + const char *mdname, const int pad_mode, + const int salt_len, const char *mgf1_mdname, unsigned char *sig, size_t *siglen, const unsigned char *tbs, size_t tbslen) { @@ -429,9 +429,8 @@ int pkcs11_evp_pkey_rsa_sign(PKCS11_OBJECT_private *key, EVP_PKEY *pkey, if (ctx == NULL) return -1; - if (pkcs11_set_rsa_mechanism(&mechanism, &pss_params, NULL, - ctx, pkey, pad_mode, salt_len, mdname, mgf1_mdname, - oaep_label, oaep_labellen) < 0) + if (pkcs11_set_rsa_mechanism(&mechanism, &pss_params, NULL, ctx, pkey, + pad_mode, salt_len, mdname, mgf1_mdname, NULL, 0) < 0) return -1; if (pkcs11_sign_with_mechanism(key, &mechanism, sig, siglen, @@ -554,7 +553,7 @@ int pkcs11_evp_pkey_rsa_decrypt(PKCS11_OBJECT_private *key, EVP_PKEY *pkey, const char *mdname, const int pad_mode, const char *mgf1_mdname, unsigned char *oaep_label, const int oaep_labellen, unsigned char *out, size_t *outlen, - size_t *outsize, const unsigned char *in, size_t inlen) + const unsigned char *in, size_t inlen) { CK_MECHANISM mechanism; PKCS11_SLOT_private *slot; @@ -579,17 +578,12 @@ int pkcs11_evp_pkey_rsa_decrypt(PKCS11_OBJECT_private *key, EVP_PKEY *pkey, if (oaep_labellen > 0) pkcs11_log(ctx, LOG_WARNING, "OAEP label may not be supported by PKCS#11 token\n"); - if (pkcs11_set_rsa_mechanism(&mechanism, NULL, &oaep_params, - ctx, pkey, pad_mode, 0, mdname, mgf1_mdname, - oaep_label, oaep_labellen) < 0) + if (pkcs11_set_rsa_mechanism(&mechanism, NULL, &oaep_params, ctx, pkey, + pad_mode, 0, mdname, mgf1_mdname, oaep_label, oaep_labellen) < 0) return -1; /* caller-provided output buffer size */ - if (outsize != NULL) - ck_outlen = (CK_ULONG)*outsize; - else - ck_outlen = (CK_ULONG)*outlen; - + ck_outlen = (CK_ULONG)*outlen; ck_inlen = (CK_ULONG)inlen; if (pkcs11_get_session(slot, 0, &session)) diff --git a/src/p11_rsa.c b/src/p11_rsa.c index 72f7b06a..2a739fea 100644 --- a/src/p11_rsa.c +++ b/src/p11_rsa.c @@ -86,10 +86,9 @@ int pkcs11_private_encrypt(int flen, return -1; siglen = pkcs11_get_key_size(key); - if (!pkcs11_evp_pkey_rsa_sign(key, NULL, NULL, padding, + if (pkcs11_evp_pkey_rsa_sign(key, NULL, NULL, padding, 0, NULL, /* unsupported PSS parameters */ - NULL, 0, /* unsupported oaep_label */ - to, &siglen, from, flen)) + to, &siglen, from, flen) <= 0) return -1; return (int)siglen; @@ -123,9 +122,9 @@ int pkcs11_private_decrypt(int flen, * PKCS#11 "source data" respectively. * https://www.openssl.org/docs/man3.0/man3/RSA_private_decrypt.html */ outlen = flen; - if (!pkcs11_evp_pkey_rsa_decrypt(key, NULL, "SHA1", padding, "SHA1", + if (pkcs11_evp_pkey_rsa_decrypt(key, NULL, "SHA1", padding, "SHA1", NULL, 0, /* unsupported oaep_label */ - to, &outlen, 0, from, flen)) + to, &outlen, from, flen) <= 0) return -1; return (int)outlen; diff --git a/src/provider.c b/src/provider.c index 5d1d909a..4c747648 100644 --- a/src/provider.c +++ b/src/provider.c @@ -266,6 +266,8 @@ static int provider_init(const OSSL_CORE_HANDLE *handle, const OSSL_DISPATCH *in *out = provider_functions; *ctx = prov_ctx; + ERR_load_P11_strings(); + return 1; err: @@ -289,6 +291,7 @@ static void provider_teardown(void *ctx) return; PROVIDER_CTX_destroy(prov_ctx); + ERR_unload_P11_strings(); ERR_clear_error(); } @@ -462,9 +465,13 @@ static int keymgmt_match(const void *provkey1, const void *provkey2, int selecti key_checked = p11_public_equal(keydata1, keydata2); } if (!key_checked && (selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY)) { - /* validate whether the private keys match, not covered by tests */ - //key_checked = keydata1->is_private && keydata2->is_private && private_match(keydata1, keydata2); - /* TODO */ + /* validate whether the private keys match, not covered by tests + * TODO + * key_checked = p11_keydata_is_private(keydata1) && + * p11_keydata_is_private(keydata2) && + * p11_private_equal(keydata1, keydata2); + */ + key_checked = 0; } ok = ok && key_checked; } @@ -568,7 +575,6 @@ static const OSSL_PARAM *keymgmt_export_types(int selection) static int keymgmt_get_params(void *provkey, OSSL_PARAM params[]) { P11_KEYDATA *keydata = (P11_KEYDATA *)provkey; - const OSSL_PARAM *key_params; const OSSL_PARAM *pub; OSSL_PARAM *p; int bits, secbits; @@ -584,7 +590,6 @@ static int keymgmt_get_params(void *provkey, OSSL_PARAM params[]) #if OPENSSL_VERSION_NUMBER >= 0x30600000L category = p11_keydata_get_security_category(keydata); #endif /* OPENSSL_VERSION_NUMBER >= 0x30600000L */ - key_params = p11_keydata_get_params(keydata); /* EVP_PKEY_get_bits(), not covered by tests */ p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_BITS); @@ -610,13 +615,25 @@ static int keymgmt_get_params(void *provkey, OSSL_PARAM params[]) /* EVP_PKEY_get1_encoded_public_key(), not covered by tests */ p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY); - if (p != NULL && - p11_keydata_get_type(keydata) == EVP_PKEY_EC && key_params != NULL) { + if (p != NULL && p11_keydata_get_type(keydata) == EVP_PKEY_EC) { + const OSSL_PARAM *key_params = p11_keydata_get_params(keydata); + + if (key_params == NULL) + return 0; + pub = OSSL_PARAM_locate_const(key_params, OSSL_PKEY_PARAM_PUB_KEY); if (pub != NULL && pub->data != NULL && !OSSL_PARAM_set_octet_string(p, pub->data, pub->data_size)) return 0; } + + /* EVP_PKEY_get_default_digest_nid(), "pkeyutl -sign -rawin" + * For signature algorithms like RSA, DSA and ECDSA, the default + * digest algorithm is SHA256. */ + p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_DEFAULT_DIGEST); + if (p != NULL && !OSSL_PARAM_set_utf8_string(p, "SHA256")) + return 0; + return 1; } @@ -631,6 +648,7 @@ static const OSSL_PARAM *keymgmt_gettable_params(void *provctx) OSSL_PARAM_int(OSSL_PKEY_PARAM_SECURITY_CATEGORY, NULL), #endif /* OPENSSL_VERSION_NUMBER >= 0x30600000L */ OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY, NULL, 0), + OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_DEFAULT_DIGEST, NULL, 0), OSSL_PARAM_END }; (void)provctx; @@ -701,7 +719,6 @@ static int signature_sign(void *ctx, unsigned char *sig, size_t *siglen, { P11_SIGNATURE_CTX *sig_ctx = (P11_SIGNATURE_CTX *)ctx; size_t need; - int rv; if (sig_ctx == NULL || siglen == NULL || tbs == NULL) return 0; @@ -720,17 +737,14 @@ static int signature_sign(void *ctx, unsigned char *sig, size_t *siglen, } /* do the signing using your PKCS#11 layer */ - rv = PKCS11_evp_pkey_sign( + return PKCS11_evp_pkey_sign( p11_signature_ctx_get_evp_pkey(sig_ctx), p11_signature_ctx_get_type(sig_ctx), p11_signature_ctx_get_mdname(sig_ctx), p11_signature_ctx_get_pad_mode(sig_ctx), p11_signature_ctx_get_pss_saltlen(sig_ctx), p11_signature_ctx_get_mgf1_mdname(sig_ctx), - NULL, 0, sig, siglen, tbs, tbslen); - - return (rv > 0); } /* @@ -846,7 +860,7 @@ static int signature_digest_sign_final(void *ctx, unsigned char *sig, EVP_MD_CTX *mdctx; unsigned char md[EVP_MAX_MD_SIZE]; unsigned int mdlen = 0; - size_t need, rv; + size_t need; if (sig_ctx == NULL || siglen == NULL) return 0; @@ -887,17 +901,14 @@ static int signature_digest_sign_final(void *ctx, unsigned char *sig, if (EVP_DigestFinal_ex(mdctx, md, &mdlen) != 1) return 0; - rv = PKCS11_evp_pkey_sign( + return PKCS11_evp_pkey_sign( p11_signature_ctx_get_evp_pkey(sig_ctx), p11_signature_ctx_get_type(sig_ctx), p11_signature_ctx_get_mdname(sig_ctx), p11_signature_ctx_get_pad_mode(sig_ctx), p11_signature_ctx_get_pss_saltlen(sig_ctx), p11_signature_ctx_get_mgf1_mdname(sig_ctx), - NULL, 0, sig, siglen, md, (size_t)mdlen); - - return (rv > 0); } /* @@ -913,7 +924,6 @@ static int signature_digest_sign(void *ctx, unsigned char *sig, size_t *siglen, const char *mdname; const EVP_MD *mdalg; size_t need; - int rv; if (sig_ctx == NULL || siglen == NULL || tbs == NULL) return 0; @@ -936,13 +946,11 @@ static int signature_digest_sign(void *ctx, unsigned char *sig, size_t *siglen, case EVP_PKEY_ED25519: case EVP_PKEY_ED448: /* EdDSA signs the message directly */ - rv = PKCS11_evp_pkey_sign( + return PKCS11_evp_pkey_sign( p11_signature_ctx_get_evp_pkey(sig_ctx), p11_signature_ctx_get_type(sig_ctx), NULL, 0, 0, NULL, - NULL, 0, sig, siglen, tbs, tbslen); - return (rv > 0); case EVP_PKEY_RSA: case EVP_PKEY_RSA_PSS: @@ -958,16 +966,14 @@ static int signature_digest_sign(void *ctx, unsigned char *sig, size_t *siglen, if (EVP_Digest(tbs, tbslen, md, &mdlen, mdalg, NULL) != 1) return 0; - rv = PKCS11_evp_pkey_sign( + return PKCS11_evp_pkey_sign( p11_signature_ctx_get_evp_pkey(sig_ctx), p11_signature_ctx_get_type(sig_ctx), p11_signature_ctx_get_mdname(sig_ctx), p11_signature_ctx_get_pad_mode(sig_ctx), p11_signature_ctx_get_pss_saltlen(sig_ctx), p11_signature_ctx_get_mgf1_mdname(sig_ctx), - NULL, 0, sig, siglen, md, (size_t)mdlen); - return (rv > 0); default: return 0; @@ -1148,7 +1154,6 @@ static int signature_get_ctx_params(void *vctx, OSSL_PARAM params[]) OSSL_PARAM *p; const char *mdname; const char *mgf1_mdname; - const char *pad_mode_str; int pad_mode; int pss_saltlen; @@ -1177,9 +1182,9 @@ static int signature_get_ctx_params(void *vctx, OSSL_PARAM params[]) if (!OSSL_PARAM_set_int(p, pad_mode)) return 0; } else if (p->data_type == OSSL_PARAM_UTF8_STRING) { - pad_mode_str = p11_signature_pad_mode_to_string(pad_mode); - if (pad_mode_str == NULL || - !OSSL_PARAM_set_utf8_string(p, pad_mode_str)) + const char *padding = p11_pad_mode_to_string(pad_mode); + + if (padding == NULL || !OSSL_PARAM_set_utf8_string(p, padding)) return 0; } } @@ -1356,16 +1361,7 @@ static int asym_cipher_encrypt_init(void *ctx, void *provkey, const OSSL_PARAM p static int asym_cipher_encrypt(void *ctx, unsigned char *out, size_t *outlen, size_t outsize, const unsigned char *in, size_t inlen) { - P11_ASYM_CIPHER_CTX *asym_ctx = (P11_ASYM_CIPHER_CTX *)ctx; - int rv; - - if (asym_ctx == NULL) - return 0; - - rv = p11_asym_cipher_ctx_encrypt(asym_ctx, out, outlen, outsize, in, inlen); - if (rv <= 0) - return 0; - return 1; + return p11_asym_cipher_ctx_encrypt(ctx, out, outlen, outsize, in, inlen); } /* Initialize decryption operation with key */ @@ -1380,7 +1376,6 @@ static int asym_cipher_decrypt(void *ctx, unsigned char *out, size_t *outlen, { P11_ASYM_CIPHER_CTX *asym_ctx = (P11_ASYM_CIPHER_CTX *)ctx; size_t need; - int rv; if (asym_ctx == NULL || outlen == NULL || in == NULL) return 0; @@ -1402,7 +1397,9 @@ static int asym_cipher_decrypt(void *ctx, unsigned char *out, size_t *outlen, return 0; /* buffer too small */ } - rv = PKCS11_evp_pkey_decrypt( + *outlen = outsize; /* available signature buffer size */ + + return PKCS11_evp_pkey_decrypt( p11_asym_cipher_ctx_get_evp_pkey(asym_ctx), p11_asym_cipher_ctx_get_type(asym_ctx), p11_asym_cipher_ctx_get_oaep_mdname(asym_ctx), @@ -1410,8 +1407,7 @@ static int asym_cipher_decrypt(void *ctx, unsigned char *out, size_t *outlen, p11_asym_cipher_ctx_get_mgf1_mdname(asym_ctx), p11_asym_cipher_ctx_get_oaep_label(asym_ctx), p11_asym_cipher_ctx_get_oaep_labellen(asym_ctx), - out, outlen, &outsize, in, inlen); - return (rv > 0); + out, outlen, in, inlen); } /* Get asymmetric cipher context parameters. */ @@ -1419,7 +1415,6 @@ static int asym_cipher_get_ctx_params(void *vctx, OSSL_PARAM params[]) { P11_ASYM_CIPHER_CTX *asym_ctx = (P11_ASYM_CIPHER_CTX *)vctx; OSSL_PARAM *p; - const char *pad_mode_str = NULL; const char *oaep_mdname; const char *mgf1_mdname; int pad_mode; @@ -1441,21 +1436,6 @@ static int asym_cipher_get_ctx_params(void *vctx, OSSL_PARAM params[]) if (mgf1_mdname == NULL) mgf1_mdname = oaep_mdname; - switch (pad_mode) { - case RSA_NO_PADDING: - pad_mode_str = OSSL_PKEY_RSA_PAD_MODE_NONE; - break; - case RSA_PKCS1_PADDING: - pad_mode_str = OSSL_PKEY_RSA_PAD_MODE_PKCSV15; - break; - case RSA_PKCS1_OAEP_PADDING: - pad_mode_str = OSSL_PKEY_RSA_PAD_MODE_OAEP; - break; - default: - pad_mode_str = NULL; - break; - } - /* EVP_PKEY_CTX_get_rsa_padding(), not covered by tests */ p = OSSL_PARAM_locate(params, OSSL_ASYM_CIPHER_PARAM_PAD_MODE); if (p != NULL) { @@ -1463,8 +1443,9 @@ static int asym_cipher_get_ctx_params(void *vctx, OSSL_PARAM params[]) if (!OSSL_PARAM_set_int(p, pad_mode)) return 0; } else if (p->data_type == OSSL_PARAM_UTF8_STRING) { - if (pad_mode_str == NULL || - !OSSL_PARAM_set_utf8_string(p, pad_mode_str)) + const char *padding = p11_pad_mode_to_string(pad_mode); + + if (padding == NULL || !OSSL_PARAM_set_utf8_string(p, padding)) return 0; } } diff --git a/src/provider_helpers.c b/src/provider_helpers.c index 03711445..c53cd8ce 100644 --- a/src/provider_helpers.c +++ b/src/provider_helpers.c @@ -140,7 +140,7 @@ struct p11_signature_ctx { struct p11_asym_cipher_ctx { PROVIDER_CTX *prov_ctx; P11_KEYDATA *keydata; - int pad_mode; /* RSA_NO_PADDING, RSA_PKCS1_PADDING, RSA_PKCS1_OAEP_PADDING */ + int pad_mode; /* RSA_PKCS1_OAEP_PADDING */ char *oaep_mdname; /* optional, default = SHA1 in many PKCS#11/OpenSSL flows */ char *mgf1_mdname; /* optional, default = oaep_mdname */ unsigned char *oaep_label; @@ -173,6 +173,7 @@ static int octet_equal(const OSSL_PARAM *a, const OSSL_PARAM *b); #endif /* OPENSSL_NO_ECX */ static void p11_keydata_clear_pubdata(P11_KEYDATA *keydata); static int p11_dup_param_blob(const OSSL_PARAM *p, unsigned char **out, size_t *out_len); +static int p11_keydata_get_pub(const P11_KEYDATA *keydata, unsigned char **buf, size_t *len); /******************************************************************************/ @@ -550,23 +551,6 @@ const char *p11_keydata_get_name(P11_KEYDATA *keydata) return keydata->name; } -/* Get stored raw public key data. */ -int p11_keydata_get_pub(const P11_KEYDATA *keydata, unsigned char **buf, size_t *len) -{ - const P11_PUB_KEY *pubkey; - - if (keydata == NULL || buf == NULL || len == NULL) - return 0; - - pubkey = keydata->pubkey; - if (pubkey == NULL || pubkey->pub == NULL || pubkey->pub_len == 0) - return 0; - - *buf = pubkey->pub; - *len = pubkey->pub_len; - return 1; -} - /* Return whether keydata represents a private key. */ int p11_keydata_is_private(const P11_KEYDATA *keydata) { @@ -980,7 +964,6 @@ int p11_signature_ctx_verify(P11_SIGNATURE_CTX *sig_ctx, EVP_PKEY_CTX *pctx = NULL; EVP_MD_CTX *mdctx = NULL; const EVP_MD *sig_md = NULL; - const char *mgf1_name = NULL; int ok = 0; if (sig_ctx == NULL || sig_ctx->keydata == NULL || sig == NULL || tbs == NULL) @@ -1018,7 +1001,25 @@ int p11_signature_ctx_verify(P11_SIGNATURE_CTX *sig_ctx, goto end; switch (sig_ctx->pad_mode) { - case RSA_PKCS1_PSS_PADDING: + case RSA_PKCS1_PADDING: + /* For PKCS#1 v1.5 signatures the digest is optional. + * If not set, the input is treated as raw data. */ + if (sig_ctx->mdname != NULL) { + sig_md = EVP_get_digestbyname(sig_ctx->mdname); + if (sig_md == NULL) + goto end; + + if (EVP_PKEY_CTX_set_signature_md(pctx, sig_md) <= 0) + goto end; + } + break; + case RSA_PKCS1_PSS_PADDING: { + const EVP_MD *mgf1_md; + const char *mgf1_name; + + /* RSASSA-PSS requires an explicit digest algorithm. + * The digest is used for both the message hash and, + * unless overridden, the MGF1 hash function. */ if (sig_ctx->mdname == NULL) goto end; @@ -1031,23 +1032,20 @@ int p11_signature_ctx_verify(P11_SIGNATURE_CTX *sig_ctx, mgf1_name = (sig_ctx->mgf1_mdname != NULL) ? sig_ctx->mgf1_mdname : sig_ctx->mdname; + + mgf1_md = EVP_get_digestbyname(mgf1_name); + if (mgf1_md == NULL) + goto end; - if (mgf1_name != NULL) { - const EVP_MD *mgf1_md = EVP_get_digestbyname(mgf1_name); - - if (mgf1_md == NULL) - goto end; - - if (EVP_PKEY_CTX_set_rsa_mgf1_md(pctx, mgf1_md) <= 0) - goto end; - } + if (EVP_PKEY_CTX_set_rsa_mgf1_md(pctx, mgf1_md) <= 0) + goto end; if (EVP_PKEY_CTX_set_rsa_pss_saltlen(pctx, (int)sig_ctx->pss_saltlen) <= 0) goto end; - break; - case RSA_PKCS1_PADDING: + break; + } case RSA_NO_PADDING: /* not covered by tests */ case RSA_X931_PADDING: /* not covered by tests */ break; @@ -1212,21 +1210,6 @@ EVP_MD_CTX *p11_signature_ctx_get_mdctx(P11_SIGNATURE_CTX *sig_ctx) return sig_ctx->mdctx; } -/* Convert RSA padding mode to its string representation. */ -const char *p11_signature_pad_mode_to_string(int pad_mode) -{ - switch (pad_mode) { - case RSA_PKCS1_PADDING: - return OSSL_PKEY_RSA_PAD_MODE_PKCSV15; - case RSA_PKCS1_PSS_PADDING: - return OSSL_PKEY_RSA_PAD_MODE_PSS; - case RSA_NO_PADDING: - return OSSL_PKEY_RSA_PAD_MODE_NONE; - default: - return NULL; - } -} - /* Convert RSA-PSS salt length value to its string representation. */ const char *p11_signature_pss_saltlen_to_string(int saltlen) { @@ -1246,6 +1229,23 @@ const char *p11_signature_pss_saltlen_to_string(int saltlen) } } +/* Convert RSA padding mode to its string representation. */ +const char *p11_pad_mode_to_string(int pad_mode) +{ + switch (pad_mode) { + case RSA_PKCS1_PADDING: + return OSSL_PKEY_RSA_PAD_MODE_PKCSV15; + case RSA_PKCS1_PSS_PADDING: + return OSSL_PKEY_RSA_PAD_MODE_PSS; + case RSA_NO_PADDING: + return OSSL_PKEY_RSA_PAD_MODE_NONE; + case RSA_PKCS1_OAEP_PADDING: + return OSSL_PKEY_RSA_PAD_MODE_OAEP; + default: + return NULL; + } +} + /******************************************************************************/ /* ASYM CIPHER helper functions */ @@ -1386,7 +1386,7 @@ int p11_asym_cipher_ctx_encrypt(P11_ASYM_CIPHER_CTX *asym_ctx, if (pub == NULL) return 0; - pctx = EVP_PKEY_CTX_new_from_pkey(NULL, pub, "provider=default"); + pctx = EVP_PKEY_CTX_new(pub, NULL); if (pctx == NULL) goto end; @@ -2295,5 +2295,21 @@ static int p11_dup_param_blob(const OSSL_PARAM *p, unsigned char **out, size_t * return 1; } +/* Get stored raw public key data. */ +static int p11_keydata_get_pub(const P11_KEYDATA *keydata, unsigned char **buf, size_t *len) +{ + const P11_PUB_KEY *pubkey; + + if (keydata == NULL || buf == NULL || len == NULL) + return 0; + + pubkey = keydata->pubkey; + if (pubkey == NULL || pubkey->pub == NULL || pubkey->pub_len == 0) + return 0; + + *buf = pubkey->pub; + *len = pubkey->pub_len; + return 1; +} /* vim: set noexpandtab: */ diff --git a/src/provider_helpers.h b/src/provider_helpers.h index 27023a7d..2402ad0b 100644 --- a/src/provider_helpers.h +++ b/src/provider_helpers.h @@ -81,7 +81,6 @@ int p11_keydata_up_ref(P11_KEYDATA *keydata); void p11_keydata_free(P11_KEYDATA *keydata); P11_KEYDATA *p11_keydata_from_evp_pkey(PROVIDER_CTX *ctx, EVP_PKEY *pkey, int is_private); const char *p11_keydata_get_name(P11_KEYDATA *keydata); -int p11_keydata_get_pub(const P11_KEYDATA *keydata, unsigned char **buf, size_t *len); int p11_keydata_is_private(const P11_KEYDATA *keydata); #if OPENSSL_VERSION_NUMBER >= 0x30600000L int p11_keydata_get_security_category(const P11_KEYDATA *keydata); @@ -129,8 +128,8 @@ int p11_signature_ctx_set_mgf1_mdname(P11_SIGNATURE_CTX *sig_ctx, const char *md const char *p11_signature_ctx_get_mgf1_mdname(const P11_SIGNATURE_CTX *sig_ctx); EVP_MD_CTX *p11_signature_ctx_get_mdctx(P11_SIGNATURE_CTX *sig_ctx); -const char *p11_signature_pad_mode_to_string(int pad_mode); const char *p11_signature_pss_saltlen_to_string(int saltlen); +const char *p11_pad_mode_to_string(int pad_mode); /******************************************************************************/ From caef7e482392b90aa54c2a831fcde3d08b3e87c7 Mon Sep 17 00:00:00 2001 From: olszomal Date: Mon, 18 May 2026 09:50:01 +0200 Subject: [PATCH 3/7] provider: add DigestInfo encoding for RSA PKCS#1 v1.5 signatures --- src/p11_pkey.c | 104 +++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 92 insertions(+), 12 deletions(-) diff --git a/src/p11_pkey.c b/src/p11_pkey.c index 595c2e05..c5f396b1 100644 --- a/src/p11_pkey.c +++ b/src/p11_pkey.c @@ -388,20 +388,81 @@ static int pkcs11_sign_with_mechanism(PKCS11_OBJECT_private *key, return rv; } +/* Build ASN.1 DigestInfo for PKCS#1 v1.5 signing. */ +static int pkcs11_build_digestinfo(const char *mdname, + const unsigned char *dgst, size_t dgstlen, + unsigned char **out, size_t *outlen) +{ + const EVP_MD *md; + X509_SIG *x509_sig = NULL; + X509_ALGOR *alg = NULL; + ASN1_OCTET_STRING *digest = NULL; + unsigned char *p; + int len; + + if (mdname == NULL || dgst == NULL || out == NULL || outlen == NULL) + return 0; + + *out = NULL; + *outlen = 0; + + md = EVP_get_digestbyname(mdname); + if (md == NULL) + return 0; + + if (EVP_MD_size(md) <= 0 || dgstlen != (size_t)EVP_MD_size(md)) + return 0; + + x509_sig = X509_SIG_new(); + if (x509_sig == NULL) + return 0; + + X509_SIG_getm(x509_sig, &alg, &digest); + + if (!X509_ALGOR_set0(alg, OBJ_nid2obj(EVP_MD_type(md)), V_ASN1_NULL, NULL)) + goto err; + + if (!ASN1_OCTET_STRING_set(digest, dgst, (int)dgstlen)) + goto err; + + len = i2d_X509_SIG(x509_sig, NULL); + if (len <= 0) + goto err; + + *out = OPENSSL_malloc((size_t)len); + if (*out == NULL) + goto err; + + p = *out; + len = i2d_X509_SIG(x509_sig, &p); + if (len <= 0) + goto err; + + *outlen = (size_t)len; + X509_SIG_free(x509_sig); + return 1; + +err: + OPENSSL_free(*out); + *out = NULL; + *outlen = 0; + X509_SIG_free(x509_sig); + return 0; +} + /* * Sign input data with an RSA private key using a PKCS#11 token. * - * For RSA_PKCS1_PADDING, RSA_PKCS1_PSS_PADDING and RSA_X931_PADDING, - * the input must be the message digest. + * For RSA_PKCS1_PADDING, if mdname is set, the input must be the message + * digest and is wrapped in an ASN.1 DigestInfo structure before signing with + * CKM_RSA_PKCS. If mdname is not set, the input is signed directly. * - * For RSA_PKCS1_PADDING, the token performs PKCS#1 v1.5 DigestInfo - * encoding internally based on the selected digest algorithm. + * For RSA_PKCS1_PSS_PADDING, the input must be the message digest. The digest + * algorithm, MGF1 digest and salt length are passed separately in + * CK_RSA_PKCS_PSS_PARAMS. * - * For RSA_PKCS1_PSS_PADDING, the digest algorithm, MGF1 digest and - * salt length are passed separately in CK_RSA_PKCS_PSS_PARAMS. - * - * For RSA_X931_PADDING, the token applies X9.31 signature formatting - * based on the provided digest. + * For RSA_X931_PADDING, if the digest type is set it is used to format the + * block data otherwise the first byte is used to specify the X9.31 digest ID. * * For RSA_NO_PADDING, the input is passed to the token unchanged. * @@ -417,6 +478,11 @@ int pkcs11_evp_pkey_rsa_sign(PKCS11_OBJECT_private *key, EVP_PKEY *pkey, PKCS11_SLOT_private *slot; PKCS11_CTX_private *ctx; CK_RSA_PKCS_PSS_PARAMS pss_params; + const unsigned char *sign_tbs = tbs; + size_t sign_tbslen = tbslen; + unsigned char *digestinfo = NULL; + size_t digestinfo_len = 0; + int ret = -1; if (key == NULL || sig == NULL || siglen == NULL || tbs == NULL) return -1; @@ -433,11 +499,25 @@ int pkcs11_evp_pkey_rsa_sign(PKCS11_OBJECT_private *key, EVP_PKEY *pkey, pad_mode, salt_len, mdname, mgf1_mdname, NULL, 0) < 0) return -1; + if (pad_mode == RSA_PKCS1_PADDING && mdname != NULL) { + /* Build ASN.1 DigestInfo for PKCS#1 v1.5 signing. */ + if (!pkcs11_build_digestinfo(mdname, tbs, tbslen, + &digestinfo, &digestinfo_len)) + goto end; + + sign_tbs = digestinfo; + sign_tbslen = digestinfo_len; + } + if (pkcs11_sign_with_mechanism(key, &mechanism, sig, siglen, - tbs, tbslen) != CKR_OK) - return -1; + sign_tbs, sign_tbslen) != CKR_OK) + goto end; - return 1; + ret = 1; + +end: + OPENSSL_free(digestinfo); + return ret; } #ifndef OPENSSL_NO_EC From 470b9aa05c5e8b875d230aaf60840e7c36e5888b Mon Sep 17 00:00:00 2001 From: olszomal Date: Mon, 18 May 2026 13:14:52 +0200 Subject: [PATCH 4/7] provider: add RSA verify-recover support --- src/provider.c | 23 +++++ src/provider_helpers.c | 199 +++++++++++++++++++++++++++++------------ src/provider_helpers.h | 4 + 3 files changed, 169 insertions(+), 57 deletions(-) diff --git a/src/provider.c b/src/provider.c index 4c747648..d35d871a 100644 --- a/src/provider.c +++ b/src/provider.c @@ -81,6 +81,8 @@ PROVIDER_FN(signature_sign_init); PROVIDER_FN(signature_sign); PROVIDER_FN(signature_verify_init); PROVIDER_FN(signature_verify); +PROVIDER_FN(signature_verify_recover_init); +PROVIDER_FN(signature_verify_recover); PROVIDER_FN(signature_digest_sign_init); PROVIDER_FN(signature_digest_sign_update); PROVIDER_FN(signature_digest_sign_final); @@ -152,6 +154,8 @@ static const OSSL_DISPATCH signature_functions[] = { {OSSL_FUNC_SIGNATURE_SIGN, (void (*)(void))signature_sign}, {OSSL_FUNC_SIGNATURE_VERIFY_INIT, (void (*)(void))signature_verify_init}, {OSSL_FUNC_SIGNATURE_VERIFY, (void (*)(void))signature_verify}, + {OSSL_FUNC_SIGNATURE_VERIFY_RECOVER_INIT, (void (*)(void))signature_verify_recover_init}, + {OSSL_FUNC_SIGNATURE_VERIFY_RECOVER, (void (*)(void))signature_verify_recover}, {OSSL_FUNC_SIGNATURE_DIGEST_SIGN_INIT, (void (*)(void))signature_digest_sign_init}, {OSSL_FUNC_SIGNATURE_DIGEST_SIGN_UPDATE, (void (*)(void))signature_digest_sign_update}, {OSSL_FUNC_SIGNATURE_DIGEST_SIGN_FINAL, (void (*)(void))signature_digest_sign_final}, @@ -769,6 +773,25 @@ static int signature_verify(void *ctx, return p11_signature_ctx_verify(ctx, sig, siglen, tbs, tbslen); } +/* + * Initialize signature recovery verification operation with key. + * Used via EVP_PKEY_verify_recover_init(). + */ +int signature_verify_recover_init(void *ctx, void *keydata, const OSSL_PARAM params[]) +{ + return p11_signature_ctx_init(ctx, keydata, params); +} + +/* + * Recover signed data from signature. + * Used after signature_verify_recover_init() and via EVP_PKEY_verify_recover(). + */ +int signature_verify_recover(void *ctx, unsigned char *rout, size_t *routlen, + size_t routsize, const unsigned char *sig, size_t siglen) +{ + return p11_signature_ctx_verifyrecover(ctx, rout, routlen, routsize, sig, siglen); +} + /* * Initialize the signing context. * For Ed25519/Ed448, mdname is ignored and one-shot DigestSign is used. diff --git a/src/provider_helpers.c b/src/provider_helpers.c index c53cd8ce..5d3d80cd 100644 --- a/src/provider_helpers.c +++ b/src/provider_helpers.c @@ -174,6 +174,8 @@ static int octet_equal(const OSSL_PARAM *a, const OSSL_PARAM *b); static void p11_keydata_clear_pubdata(P11_KEYDATA *keydata); static int p11_dup_param_blob(const OSSL_PARAM *p, unsigned char **out, size_t *out_len); static int p11_keydata_get_pub(const P11_KEYDATA *keydata, unsigned char **buf, size_t *len); +static int p11_signature_ctx_setup_rsa_verify(P11_SIGNATURE_CTX *sig_ctx, + EVP_PKEY_CTX *pctx); /******************************************************************************/ @@ -963,7 +965,6 @@ int p11_signature_ctx_verify(P11_SIGNATURE_CTX *sig_ctx, EVP_PKEY *pub = NULL; EVP_PKEY_CTX *pctx = NULL; EVP_MD_CTX *mdctx = NULL; - const EVP_MD *sig_md = NULL; int ok = 0; if (sig_ctx == NULL || sig_ctx->keydata == NULL || sig == NULL || tbs == NULL) @@ -984,10 +985,13 @@ int p11_signature_ctx_verify(P11_SIGNATURE_CTX *sig_ctx, if (EVP_DigestVerifyInit(mdctx, NULL, NULL, NULL, pub) <= 0) goto end; - ok = EVP_DigestVerify(mdctx, sig, siglen, tbs, tbslen); - ok = (ok == 1); + if (EVP_DigestVerify(mdctx, sig, siglen, tbs, tbslen) <= 0) + goto end; + + ok = 1; break; #endif /* OPENSSL_NO_ECX */ + case EVP_PKEY_RSA: case EVP_PKEY_RSA_PSS: pctx = EVP_PKEY_CTX_new(pub, NULL); @@ -997,62 +1001,15 @@ int p11_signature_ctx_verify(P11_SIGNATURE_CTX *sig_ctx, if (EVP_PKEY_verify_init(pctx) <= 0) goto end; - if (EVP_PKEY_CTX_set_rsa_padding(pctx, sig_ctx->pad_mode) <= 0) + if (!p11_signature_ctx_setup_rsa_verify(sig_ctx, pctx)) goto end; - switch (sig_ctx->pad_mode) { - case RSA_PKCS1_PADDING: - /* For PKCS#1 v1.5 signatures the digest is optional. - * If not set, the input is treated as raw data. */ - if (sig_ctx->mdname != NULL) { - sig_md = EVP_get_digestbyname(sig_ctx->mdname); - if (sig_md == NULL) - goto end; - - if (EVP_PKEY_CTX_set_signature_md(pctx, sig_md) <= 0) - goto end; - } - break; - case RSA_PKCS1_PSS_PADDING: { - const EVP_MD *mgf1_md; - const char *mgf1_name; - - /* RSASSA-PSS requires an explicit digest algorithm. - * The digest is used for both the message hash and, - * unless overridden, the MGF1 hash function. */ - if (sig_ctx->mdname == NULL) - goto end; - - sig_md = EVP_get_digestbyname(sig_ctx->mdname); - if (sig_md == NULL) - goto end; - - if (EVP_PKEY_CTX_set_signature_md(pctx, sig_md) <= 0) - goto end; - - mgf1_name = (sig_ctx->mgf1_mdname != NULL) - ? sig_ctx->mgf1_mdname : sig_ctx->mdname; - - mgf1_md = EVP_get_digestbyname(mgf1_name); - if (mgf1_md == NULL) - goto end; - - if (EVP_PKEY_CTX_set_rsa_mgf1_md(pctx, mgf1_md) <= 0) - goto end; - - if (EVP_PKEY_CTX_set_rsa_pss_saltlen(pctx, - (int)sig_ctx->pss_saltlen) <= 0) - goto end; + if (EVP_PKEY_verify(pctx, sig, siglen, tbs, tbslen) <= 0) + goto end; - break; - } - case RSA_NO_PADDING: /* not covered by tests */ - case RSA_X931_PADDING: /* not covered by tests */ - break; - } - ok = EVP_PKEY_verify(pctx, sig, siglen, tbs, tbslen); - ok = (ok == 1); + ok = 1; break; + #ifndef OPENSSL_NO_EC case EVP_PKEY_EC: pctx = EVP_PKEY_CTX_new(pub, NULL); @@ -1062,8 +1019,10 @@ int p11_signature_ctx_verify(P11_SIGNATURE_CTX *sig_ctx, if (EVP_PKEY_verify_init(pctx) <= 0) goto end; - ok = EVP_PKEY_verify(pctx, sig, siglen, tbs, tbslen); - ok = (ok == 1); + if (EVP_PKEY_verify(pctx, sig, siglen, tbs, tbslen) <= 0) + goto end; + + ok = 1; break; #endif /* OPENSSL_NO_EC */ default: @@ -1077,6 +1036,62 @@ int p11_signature_ctx_verify(P11_SIGNATURE_CTX *sig_ctx, return ok; } +/* + * Recover signed data using a temporary public key copy in the default provider. + * Applicable only to signature schemes that support signature recovery (such as RSA). + */ +int p11_signature_ctx_verifyrecover(P11_SIGNATURE_CTX *sig_ctx, + unsigned char *rout, size_t *routlen, size_t routsize, + const unsigned char *sig, size_t siglen) +{ + EVP_PKEY *pub; + EVP_PKEY_CTX *pctx; + int ok = 0; + + if (sig_ctx == NULL || sig_ctx->keydata == NULL || routlen == NULL || sig == NULL) + return 0; + + if (sig_ctx->keydata->type != EVP_PKEY_RSA) + return 0; + + /* RSASSA-PSS does not support signature recovery */ + if (sig_ctx->pad_mode == RSA_PKCS1_PSS_PADDING) + return 0; + + pub = pubkey_from_params_default(sig_ctx->keydata); + if (pub == NULL) + return 0; + + pctx = EVP_PKEY_CTX_new(pub, NULL); + if (pctx == NULL) + goto end; + + if (EVP_PKEY_verify_recover_init(pctx) <= 0) + goto end; + + if (!p11_signature_ctx_setup_rsa_verify(sig_ctx, pctx)) + goto end; + + if (rout == NULL) { + if (EVP_PKEY_verify_recover(pctx, NULL, routlen, sig, siglen) <= 0) + goto end; + + ok = 1; + goto end; + } + + *routlen = routsize; + if (EVP_PKEY_verify_recover(pctx, rout, routlen, sig, siglen) <= 0) + goto end; + + ok = 1; + +end: + EVP_PKEY_CTX_free(pctx); + EVP_PKEY_free(pub); + return ok; +} + /* Return EVP_PKEY associated with signature context. */ EVP_PKEY *p11_signature_ctx_get_evp_pkey(const P11_SIGNATURE_CTX *sig_ctx) { @@ -2312,4 +2327,74 @@ static int p11_keydata_get_pub(const P11_KEYDATA *keydata, unsigned char **buf, return 1; } +/* + * Configure RSA verification parameters on an EVP_PKEY_CTX. + * Supports PKCS#1 v1.5, RSA-PSS, X9.31 and raw RSA modes. + */ +static int p11_signature_ctx_setup_rsa_verify(P11_SIGNATURE_CTX *sig_ctx, + EVP_PKEY_CTX *pctx) +{ + const EVP_MD *sig_md = NULL; + + if (sig_ctx == NULL || pctx == NULL) + return 0; + + if (EVP_PKEY_CTX_set_rsa_padding(pctx, sig_ctx->pad_mode) <= 0) + return 0; + + switch (sig_ctx->pad_mode) { + case RSA_PKCS1_PADDING: + /* + * For PKCS#1 v1.5 signatures the digest is optional. + * If not set, the input is treated as raw data. + */ + if (sig_ctx->mdname != NULL) { + sig_md = EVP_get_digestbyname(sig_ctx->mdname); + if (sig_md == NULL) + return 0; + + if (EVP_PKEY_CTX_set_signature_md(pctx, sig_md) <= 0) + return 0; + } + break; + case RSA_PKCS1_PSS_PADDING: { + const EVP_MD *mgf1_md; + const char *mgf1_name; + + if (sig_ctx->mdname == NULL) + return 0; + + sig_md = EVP_get_digestbyname(sig_ctx->mdname); + if (sig_md == NULL) + return 0; + + if (EVP_PKEY_CTX_set_signature_md(pctx, sig_md) <= 0) + return 0; + + mgf1_name = sig_ctx->mgf1_mdname != NULL + ? sig_ctx->mgf1_mdname : sig_ctx->mdname; + + mgf1_md = EVP_get_digestbyname(mgf1_name); + if (mgf1_md == NULL) + return 0; + + if (EVP_PKEY_CTX_set_rsa_mgf1_md(pctx, mgf1_md) <= 0) + return 0; + + if (EVP_PKEY_CTX_set_rsa_pss_saltlen(pctx, + (int)sig_ctx->pss_saltlen) <= 0) + return 0; + + break; + } + case RSA_NO_PADDING: + case RSA_X931_PADDING: + break; + default: + return 0; + } + + return 1; +} + /* vim: set noexpandtab: */ diff --git a/src/provider_helpers.h b/src/provider_helpers.h index 2402ad0b..1857cee6 100644 --- a/src/provider_helpers.h +++ b/src/provider_helpers.h @@ -111,6 +111,10 @@ int p11_signature_ctx_verify(P11_SIGNATURE_CTX *sig_ctx, const unsigned char *sig, size_t siglen, const unsigned char *tbs, size_t tbslen); +int p11_signature_ctx_verifyrecover(P11_SIGNATURE_CTX *sig_ctx, + unsigned char *rout, size_t *routlen, size_t routsize, + const unsigned char *sig, size_t siglen); + EVP_PKEY *p11_signature_ctx_get_evp_pkey(const P11_SIGNATURE_CTX *sig_ctx); size_t p11_signature_ctx_get_sigsize(const P11_SIGNATURE_CTX *sig_ctx); int p11_signature_ctx_get_type(const P11_SIGNATURE_CTX *sig_ctx); From 98e23c9aaa3e7d688686dfca1adadc7b0f1b21e2 Mon Sep 17 00:00:00 2001 From: olszomal Date: Mon, 18 May 2026 14:43:21 +0200 Subject: [PATCH 5/7] provider: add X9.31 digest encoding for RSA signatures --- src/p11_pkey.c | 85 +++++++++++++++++++++++++++++++++++------- src/provider_helpers.c | 4 +- 2 files changed, 74 insertions(+), 15 deletions(-) diff --git a/src/p11_pkey.c b/src/p11_pkey.c index c5f396b1..cd6226f1 100644 --- a/src/p11_pkey.c +++ b/src/p11_pkey.c @@ -256,6 +256,9 @@ static int pkcs11_set_rsa_mechanism(CK_MECHANISM *mechanism, mechanism->mechanism = CKM_RSA_X_509; break; case RSA_X931_PADDING: + /* RSA_X931_PADDING uses the legacy ANSI X9.31 signature format. + * This deprecated mode is not supported by SoftHSM or YubiKey + * PKCS#11 modules (no CKM_RSA_X9_31 support). */ mechanism->mechanism = CKM_RSA_X9_31; break; case RSA_PKCS1_PSS_PADDING: @@ -450,6 +453,44 @@ static int pkcs11_build_digestinfo(const char *mdname, return 0; } +/* Build digest || X9.31 hash ID for RSA_X931_PADDING signing. */ +static int pkcs11_build_x931_digest(const char *mdname, + const unsigned char *dgst, size_t dgstlen, + unsigned char **out, size_t *outlen) +{ + const EVP_MD *md; + int md_size; + int hash_id; + + if (mdname == NULL || dgst == NULL || out == NULL || outlen == NULL) + return 0; + + *out = NULL; + *outlen = 0; + + md = EVP_get_digestbyname(mdname); + if (md == NULL) + return 0; + + md_size = EVP_MD_size(md); + if (md_size <= 0 || dgstlen != (size_t)md_size) + return 0; + + hash_id = RSA_X931_hash_id(EVP_MD_type(md)); + if (hash_id == -1) + return 0; + + *out = OPENSSL_malloc(dgstlen + 1); + if (*out == NULL) + return 0; + + memcpy(*out, dgst, dgstlen); + (*out)[dgstlen] = (unsigned char)hash_id; + *outlen = dgstlen + 1; + + return 1; +} + /* * Sign input data with an RSA private key using a PKCS#11 token. * @@ -461,8 +502,9 @@ static int pkcs11_build_digestinfo(const char *mdname, * algorithm, MGF1 digest and salt length are passed separately in * CK_RSA_PKCS_PSS_PARAMS. * - * For RSA_X931_PADDING, if the digest type is set it is used to format the - * block data otherwise the first byte is used to specify the X9.31 digest ID. + * For RSA_X931_PADDING, if mdname is set, append the X9.31 hash + * identifier to the digest before passing it to CKM_RSA_X9_31. + * If mdname is not set, the input is expected to contain the hash ID. * * For RSA_NO_PADDING, the input is passed to the token unchanged. * @@ -480,8 +522,8 @@ int pkcs11_evp_pkey_rsa_sign(PKCS11_OBJECT_private *key, EVP_PKEY *pkey, CK_RSA_PKCS_PSS_PARAMS pss_params; const unsigned char *sign_tbs = tbs; size_t sign_tbslen = tbslen; - unsigned char *digestinfo = NULL; - size_t digestinfo_len = 0; + unsigned char *encoded = NULL; + size_t encoded_len = 0; int ret = -1; if (key == NULL || sig == NULL || siglen == NULL || tbs == NULL) @@ -499,14 +541,31 @@ int pkcs11_evp_pkey_rsa_sign(PKCS11_OBJECT_private *key, EVP_PKEY *pkey, pad_mode, salt_len, mdname, mgf1_mdname, NULL, 0) < 0) return -1; - if (pad_mode == RSA_PKCS1_PADDING && mdname != NULL) { - /* Build ASN.1 DigestInfo for PKCS#1 v1.5 signing. */ - if (!pkcs11_build_digestinfo(mdname, tbs, tbslen, - &digestinfo, &digestinfo_len)) - goto end; - - sign_tbs = digestinfo; - sign_tbslen = digestinfo_len; + switch (pad_mode) { + case RSA_PKCS1_PADDING: + if (mdname != NULL) { + /* Build ASN.1 DigestInfo for PKCS#1 v1.5 signing */ + if (!pkcs11_build_digestinfo(mdname, + tbs, tbslen, &encoded, &encoded_len)) + goto end; + + sign_tbs = encoded; + sign_tbslen = encoded_len; + } + break; + case RSA_X931_PADDING: + if (mdname != NULL) { + /* Append X9.31 hash identifier to the digest */ + if (!pkcs11_build_x931_digest(mdname, + tbs, tbslen, &encoded, &encoded_len)) + goto end; + + sign_tbs = encoded; + sign_tbslen = encoded_len; + } + break; + default: + break; } if (pkcs11_sign_with_mechanism(key, &mechanism, sig, siglen, @@ -516,7 +575,7 @@ int pkcs11_evp_pkey_rsa_sign(PKCS11_OBJECT_private *key, EVP_PKEY *pkey, ret = 1; end: - OPENSSL_free(digestinfo); + OPENSSL_free(encoded); return ret; } diff --git a/src/provider_helpers.c b/src/provider_helpers.c index 5d3d80cd..12e4d80e 100644 --- a/src/provider_helpers.c +++ b/src/provider_helpers.c @@ -2344,8 +2344,9 @@ static int p11_signature_ctx_setup_rsa_verify(P11_SIGNATURE_CTX *sig_ctx, switch (sig_ctx->pad_mode) { case RSA_PKCS1_PADDING: + case RSA_X931_PADDING: /* - * For PKCS#1 v1.5 signatures the digest is optional. + * For PKCS#1 v1.5 and X9.31 signatures the digest is optional. * If not set, the input is treated as raw data. */ if (sig_ctx->mdname != NULL) { @@ -2388,7 +2389,6 @@ static int p11_signature_ctx_setup_rsa_verify(P11_SIGNATURE_CTX *sig_ctx, break; } case RSA_NO_PADDING: - case RSA_X931_PADDING: break; default: return 0; From 96ded1cd7635aea6ccb5de6e745dd1c62048ed00 Mon Sep 17 00:00:00 2001 From: olszomal Date: Tue, 19 May 2026 11:50:47 +0200 Subject: [PATCH 6/7] Refactor PKCS#11 RSA decrypt handling and logging --- src/p11_pkey.c | 101 +++++++++++++++++++++++++++++++++++-------------- 1 file changed, 72 insertions(+), 29 deletions(-) diff --git a/src/p11_pkey.c b/src/p11_pkey.c index cd6226f1..a6e99bef 100644 --- a/src/p11_pkey.c +++ b/src/p11_pkey.c @@ -216,8 +216,8 @@ static int pkcs11_oaep_param(CK_RSA_PKCS_OAEP_PARAMS *oaep_params, if (mgf1_md == NULL) return -1; - pkcs11_log(pctx, LOG_DEBUG, "oaep_md=%s mdf1_md=%s\n", - EVP_MD_name(oaep_md), EVP_MD_name(mgf1_md)); + pkcs11_log(pctx, LOG_DEBUG, "oaep_md=%s mdf1_md=%s oaep_labellen=%d\n", + EVP_MD_name(oaep_md), EVP_MD_name(mgf1_md), oaep_labellen); /* fill the CK_RSA_PKCS_OAEP_PARAMS structure */ memset(oaep_params, 0, sizeof(CK_RSA_PKCS_OAEP_PARAMS)); @@ -391,6 +391,74 @@ static int pkcs11_sign_with_mechanism(PKCS11_OBJECT_private *key, return rv; } +/* + * Execute a PKCS#11 decryption operation using the specified mechanism. + * Returns: CKR_OK on success or PKCS#11 error code on failure. + */ +static int pkcs11_decrypt_with_mechanism(PKCS11_OBJECT_private *key, + CK_MECHANISM *mechanism, + unsigned char *out, size_t *outlen, + const unsigned char *in, size_t inlen) +{ + int rv = CKR_GENERAL_ERROR; + PKCS11_SLOT_private *slot; + PKCS11_CTX_private *ctx; + CK_SESSION_HANDLE session; + CK_ULONG ck_outlen; + CK_ULONG ck_inlen; + + if (key == NULL || mechanism == NULL || outlen == NULL || in == NULL) + return CKR_ARGUMENTS_BAD; + + slot = key->slot; + if (slot == NULL) + return CKR_GENERAL_ERROR; + + ctx = slot->ctx; + if (ctx == NULL) + return CKR_GENERAL_ERROR; + +#ifdef DEBUG + pkcs11_log(ctx, LOG_DEBUG, "%s:%d pkcs11_decrypt_with_mechanism() " + "%s out=%p *outlen=%lu in=%p inlen=%lu\n", + __FILE__, __LINE__, + pkcs11_mechanism_name(mechanism), out, *outlen, in, inlen); +#endif + + ck_outlen = (CK_ULONG)*outlen; + ck_inlen = (CK_ULONG)inlen; + + if (pkcs11_get_session(slot, 0, &session)) + return CKR_GENERAL_ERROR; + + rv = CRYPTOKI_call(ctx, C_DecryptInit(session, mechanism, key->object)); + if (rv != CKR_OK) { + pkcs11_log(ctx, LOG_DEBUG, "%s:%d C_DecryptInit rv=%d\n", + __FILE__, __LINE__, rv); + goto end; + } + + if (key->always_authenticate == CK_TRUE) { + rv = pkcs11_authenticate(key, session); + if (rv != CKR_OK) + goto end; + } + + rv = CRYPTOKI_call(ctx, + C_Decrypt(session, (CK_BYTE_PTR)in, ck_inlen, out, &ck_outlen)); + if (rv != CKR_OK) { + pkcs11_log(ctx, LOG_DEBUG, "%s:%d C_Decrypt rv=%d\n", + __FILE__, __LINE__, rv); + goto end; + } + + *outlen = (size_t)ck_outlen; + +end: + pkcs11_put_session(slot, session); + return rv; +} + /* Build ASN.1 DigestInfo for PKCS#1 v1.5 signing. */ static int pkcs11_build_digestinfo(const char *mdname, const unsigned char *dgst, size_t dgstlen, @@ -697,10 +765,7 @@ int pkcs11_evp_pkey_rsa_decrypt(PKCS11_OBJECT_private *key, EVP_PKEY *pkey, CK_MECHANISM mechanism; PKCS11_SLOT_private *slot; PKCS11_CTX_private *ctx; - CK_SESSION_HANDLE session; CK_RSA_PKCS_OAEP_PARAMS oaep_params; - CK_ULONG ck_outlen; - CK_ULONG ck_inlen; int rv; if (key == NULL || outlen == NULL || in == NULL) @@ -721,33 +786,11 @@ int pkcs11_evp_pkey_rsa_decrypt(PKCS11_OBJECT_private *key, EVP_PKEY *pkey, pad_mode, 0, mdname, mgf1_mdname, oaep_label, oaep_labellen) < 0) return -1; - /* caller-provided output buffer size */ - ck_outlen = (CK_ULONG)*outlen; - ck_inlen = (CK_ULONG)inlen; - - if (pkcs11_get_session(slot, 0, &session)) - return -1; - - rv = CRYPTOKI_call(ctx, C_DecryptInit(session, &mechanism, key->object)); + rv = pkcs11_decrypt_with_mechanism(key, &mechanism, out, outlen, + in, inlen); if (rv != CKR_OK) - pkcs11_log(ctx, LOG_DEBUG, "%s:%d C_DecryptInit rv=%d\n", - __FILE__, __LINE__, rv); - else if (rv == CKR_OK && key->always_authenticate == CK_TRUE) - rv = pkcs11_authenticate(key, session); - - if (rv == CKR_OK) - rv = CRYPTOKI_call(ctx, - C_Decrypt(session, (CK_BYTE_PTR)in, ck_inlen, out, &ck_outlen)); - - pkcs11_put_session(slot, session); - - if (rv != CKR_OK) { - pkcs11_log(ctx, LOG_DEBUG, "%s:%d C_Decrypt rv=%d\n", - __FILE__, __LINE__, rv); return -1; - } - *outlen = (size_t)ck_outlen; return (int)*outlen; } From 46d2397765b1bf53e1abfa83f6dabd6d68e2c4b4 Mon Sep 17 00:00:00 2001 From: olszomal Date: Tue, 19 May 2026 11:51:11 +0200 Subject: [PATCH 7/7] Restore RSA PKCS#1 v1.5 private key decryption support This fixes a regression introduced in 4e3ba09fdd8, which unintentionally removed RSA_PKCS1_PADDING decrypt support while refactoring OAEP handling. --- src/p11_key.c | 50 ++++++++++++++++++++++++++++++-------------------- 1 file changed, 30 insertions(+), 20 deletions(-) diff --git a/src/p11_key.c b/src/p11_key.c index ccf68a64..26b98b8b 100644 --- a/src/p11_key.c +++ b/src/p11_key.c @@ -1272,9 +1272,9 @@ static int pkcs11_try_pkey_rsa_decrypt(EVP_PKEY_CTX *evp_pkey_ctx, PKCS11_SLOT_private *slot; CK_SESSION_HANDLE session; const EVP_MD *md, *mgf1_md; - const char *mdname, *mgf1_mdname; + const char *mdname = NULL, *mgf1_mdname = NULL; unsigned char *oaep_label = NULL; - int oaep_labellen; + int oaep_labellen = 0; /* RSA method has EVP_PKEY_FLAG_AUTOARGLEN set. OpenSSL core will handle * the size inquiry internally. */ @@ -1300,22 +1300,6 @@ static int pkcs11_try_pkey_rsa_decrypt(EVP_PKEY_CTX *evp_pkey_ctx, if (EVP_PKEY_CTX_get_rsa_padding(evp_pkey_ctx, &padding) <= 0) return -1; - if (padding != RSA_PKCS1_OAEP_PADDING) - return -1; /* unsupported */ - - /* retrieve OAEP parameters */ - if (EVP_PKEY_CTX_get_rsa_oaep_md(evp_pkey_ctx, &md) <= 0) - return -1; - - if (EVP_PKEY_CTX_get_rsa_mgf1_md(evp_pkey_ctx, &mgf1_md) <= 0) - return -1; - - oaep_labellen = EVP_PKEY_CTX_get0_rsa_oaep_label(evp_pkey_ctx, &oaep_label); - if (oaep_labellen < 0) { - oaep_labellen = 0; - oaep_label = NULL; - } - slot = key->slot; if (!slot) return -1; @@ -1323,8 +1307,34 @@ static int pkcs11_try_pkey_rsa_decrypt(EVP_PKEY_CTX *evp_pkey_ctx, if (pkcs11_get_session(slot, 0, &session)) return -1; - mdname = EVP_MD_name(md); - mgf1_mdname = EVP_MD_name(mgf1_md); + switch (padding) { + case RSA_PKCS1_PADDING: + break; + + case RSA_PKCS1_OAEP_PADDING: + /* retrieve OAEP parameters */ + if (EVP_PKEY_CTX_get_rsa_oaep_md(evp_pkey_ctx, &md) <= 0 || + md == NULL) + return -1; + + if (EVP_PKEY_CTX_get_rsa_mgf1_md(evp_pkey_ctx, &mgf1_md) <= 0 || + mgf1_md == NULL) + return -1; + + mdname = EVP_MD_name(md); + mgf1_mdname = EVP_MD_name(mgf1_md); + + oaep_labellen = EVP_PKEY_CTX_get0_rsa_oaep_label(evp_pkey_ctx, + &oaep_label); + if (oaep_labellen < 0) { + oaep_labellen = 0; + oaep_label = NULL; + } + break; + + default: + return -1; + } return pkcs11_evp_pkey_rsa_decrypt(key, pkey, mdname, padding, mgf1_mdname, oaep_label, oaep_labellen, out, outlen, in, inlen);