Add RSA-PSS padding support to the OpenSSL crypto PMD.

Store PSS-specific parameters (hash, MGF1 hash, and salt length)
in the RSA session, advertise PSS capability, and configure the
OpenSSL EVP context accordingly for sign and verify operations.

Introduce a dedicated RSA-PSS verification path using
EVP_PKEY_verify(), while retaining verify-recover for supported
deterministic padding schemes. Reject unsupported RSA-PSS usage
for non-sign/verify operations.

Signed-off-by: Sucharitha Sarananaga <[email protected]>
---
 drivers/crypto/openssl/openssl_pmd_private.h |   6 +
 drivers/crypto/openssl/rte_openssl_pmd.c     | 314 +++++++++++++++----
 drivers/crypto/openssl/rte_openssl_pmd_ops.c |  27 +-
 3 files changed, 292 insertions(+), 55 deletions(-)

diff --git a/drivers/crypto/openssl/openssl_pmd_private.h 
b/drivers/crypto/openssl/openssl_pmd_private.h
index 8704e1915a..8a6db6066f 100644
--- a/drivers/crypto/openssl/openssl_pmd_private.h
+++ b/drivers/crypto/openssl/openssl_pmd_private.h
@@ -5,6 +5,8 @@
 #ifndef _OPENSSL_PMD_PRIVATE_H_
 #define _OPENSSL_PMD_PRIVATE_H_
 
+#include <rte_common.h>
+
 #include <openssl/evp.h>
 #include <openssl/cmac.h>
 #include <openssl/hmac.h>
@@ -186,6 +188,10 @@ struct __rte_cache_aligned openssl_asym_session {
 
                        uint8_t *label;
                        uint32_t label_len;
+
+                       const EVP_MD *pss_md;
+                       const EVP_MD *pss_mgf1_md;
+                       int pss_saltlen;
                } r;
                struct exp {
                        BIGNUM *exp;
diff --git a/drivers/crypto/openssl/rte_openssl_pmd.c 
b/drivers/crypto/openssl/rte_openssl_pmd.c
index 4fbbb73bfa..1b33470c8f 100644
--- a/drivers/crypto/openssl/rte_openssl_pmd.c
+++ b/drivers/crypto/openssl/rte_openssl_pmd.c
@@ -2327,6 +2327,216 @@ openssl_rsa_set_oaep_params(EVP_PKEY_CTX *ctx,
        return 0;
 }
 
+/**
+ * Configure RSA-PSS padding parameters, including the signature digest,
+ * on an initialized EVP_PKEY_CTX. Must be called after
+ * EVP_PKEY_CTX_set_rsa_padding().
+ *
+ * @return 0 on success, -1 on failure.
+ */
+static int
+openssl_rsa_set_pss_params(EVP_PKEY_CTX *ctx,
+               const struct openssl_asym_session *sess)
+{
+       /*
+        * Tells OpenSSL which hash algorithm was used to create the
+        * input message digest (rte_crypto_rsa_padding::hash), so it
+        * knows the expected digest length and can embed the correct
+        * algorithm identifier while PSS-encoding it. This does not
+        * cause the digest to be (re-)computed here: EVP_PKEY_sign()/
+        * EVP_PKEY_verify() operate on the digest bytes as-is.
+        */
+       if (EVP_PKEY_CTX_set_signature_md(ctx, sess->u.r.pss_md) <= 0)
+               return -1;
+
+       if (EVP_PKEY_CTX_set_rsa_mgf1_md(ctx, sess->u.r.pss_mgf1_md) <= 0)
+               return -1;
+
+       /* pss_saltlen is a literal byte count (0 is valid: no salt) */
+       if (EVP_PKEY_CTX_set_rsa_pss_saltlen(ctx, sess->u.r.pss_saltlen) <= 0)
+               return -1;
+
+       return 0;
+}
+
+/**
+ * Sign a message using RSA-PSS. Per rte_crypto_rsa_op_param::message and
+ * rte_crypto_rsa_padding::hash, the input is a digest already hashed by
+ * the caller with the configured algorithm, not the raw message, so
+ * EVP_PKEY_sign() is used directly on it (no internal re-hashing). This
+ * matches the pattern used for PKCS#1 v1.5/unpadded RSA signing in
+ * process_openssl_rsa_op_evp().
+ *
+ * The OpenSSL PMD does not advertise rte_crypto_rsa_capa::pss_explicit_salt,
+ * so an application-supplied rte_crypto_rsa_op_param::pss_salt is rejected
+ * by the caller before this function is invoked; the salt is always
+ * generated internally by OpenSSL's RNG via EVP_PKEY_sign().
+ *
+ * @return 0 on success, -1 on failure.
+ */
+static int
+openssl_rsa_pss_sign(uint32_t pad, const struct openssl_asym_session *sess,
+               struct rte_crypto_asym_op *op)
+{
+       EVP_PKEY_CTX *ctx = sess->u.r.ctx;
+       size_t outlen = 0;
+
+       if (EVP_PKEY_sign_init(ctx) <= 0)
+               return -1;
+
+       if (EVP_PKEY_CTX_set_rsa_padding(ctx, pad) <= 0)
+               return -1;
+
+       if (openssl_rsa_set_pss_params(ctx, sess) < 0)
+               return -1;
+
+       if (EVP_PKEY_sign(ctx, NULL, &outlen,
+                       op->rsa.message.data, op->rsa.message.length) <= 0)
+               return -1;
+
+       if (outlen == 0 || outlen > op->rsa.sign.length)
+               return -1;
+
+       outlen = op->rsa.sign.length;
+       if (EVP_PKEY_sign(ctx, op->rsa.sign.data, &outlen,
+                       op->rsa.message.data, op->rsa.message.length) <= 0)
+               return -1;
+
+       op->rsa.sign.length = outlen;
+       return 0;
+}
+
+/**
+ * Verify an RSA-PSS signature against a pre-computed message digest.
+ * Per rte_crypto_rsa_op_param::message and rte_crypto_rsa_padding::hash,
+ * the input is already a digest, so EVP_PKEY_verify() is used directly
+ * on it (no internal re-hashing). PSS does not support verify-recover,
+ * so this also gives a direct pass/fail result.
+ *
+ * A signature mismatch (including one caused by OpenSSL rejecting a
+ * malformed signature outright, e.g. wrong size) is a normal outcome,
+ * not a processing error, so it must not fail the enqueue operation.
+ *
+ * @return 0 if the signature is valid, 1 if invalid/mismatched,
+ *         -1 on a setup/processing failure unrelated to the signature.
+ */
+static int
+openssl_rsa_pss_verify(uint32_t pad, const struct openssl_asym_session *sess,
+               struct rte_crypto_asym_op *op)
+{
+       EVP_PKEY_CTX *ctx = sess->u.r.ctx;
+       int ret;
+
+       if (EVP_PKEY_verify_init(ctx) <= 0)
+               return -1;
+
+       if (EVP_PKEY_CTX_set_rsa_padding(ctx, pad) <= 0)
+               return -1;
+
+       if (openssl_rsa_set_pss_params(ctx, sess) < 0)
+               return -1;
+
+       /*
+        * EVP_PKEY_verify() returns 1 for a valid signature, 0 for an
+        * invalid one, and a negative value only for setup/library errors
+        * (see EVP_PKEY_verify(3)); a malformed signature is reported via
+        * a 0 return here too, not a negative one.
+        */
+       ret = EVP_PKEY_verify(ctx,
+                       op->rsa.sign.data, op->rsa.sign.length,
+                       op->rsa.message.data, op->rsa.message.length);
+       if (ret < 0)
+               return -1;
+
+       if (ret == 0) {
+               OPENSSL_LOG(DEBUG, "RSA-PSS signature verification failed");
+               return 1;
+       }
+
+       return 0;
+}
+
+/**
+ * Verify an RSA signature using verify-recover, for deterministic
+ * padding schemes (PKCS#1 v1.5, no padding). Not applicable to PSS,
+ * since OpenSSL does not support recover-mode verification for PSS
+ * (RSA-PSS is a probabilistic scheme and cannot be undone to recover
+ * the original digest).
+ *
+ * A signature mismatch is a normal outcome, not a processing error, so
+ * it must not fail the enqueue operation. Note that EVP_PKEY_verify_recover()
+ * itself can return <= 0 for a mismatch too, e.g. when the signature does not
+ * decode to a validly padded value (OpenSSL then reports it as a hard
+ * "data too large for modulus"/padding error rather than a soft 0 return),
+ * so that case is treated the same as a successful-but-mismatching recover.
+ *
+ * @return 0 if the signature is valid, 1 if invalid/mismatched,
+ *         -1 on a setup/processing failure unrelated to the signature.
+ */
+static int
+openssl_rsa_verify_recover(EVP_PKEY_CTX *ctx, uint32_t pad,
+               struct rte_crypto_asym_op *op)
+{
+       uint8_t *tmp;
+       size_t outlen = 0;
+       int ret;
+
+       if (EVP_PKEY_verify_recover_init(ctx) <= 0)
+               return -1;
+
+       if (EVP_PKEY_CTX_set_rsa_padding(ctx, pad) <= 0)
+               return -1;
+
+       if (EVP_PKEY_verify_recover(ctx, NULL, &outlen,
+                       op->rsa.sign.data,
+                       op->rsa.sign.length) <= 0) {
+               OPENSSL_LOG(ERR, "RSA sign Verification failed");
+               return 1;
+       }
+
+       if ((outlen <= 0) || (outlen != op->rsa.sign.length)) {
+               OPENSSL_LOG(ERR, "RSA sign Verification failed");
+               return 1;
+       }
+
+       tmp = OPENSSL_malloc(outlen);
+       if (tmp == NULL) {
+               OPENSSL_LOG(ERR, "Memory allocation failed");
+               return -1;
+       }
+
+       ret = EVP_PKEY_verify_recover(ctx, tmp, &outlen,
+                       op->rsa.sign.data,
+                       op->rsa.sign.length);
+       if (ret <= 0) {
+               /*
+                * A malformed/corrupted signature can make the underlying
+                * RSA op itself fail (e.g. invalid padding), rather than
+                * just returning a recovered value that fails to compare.
+                * Both cases mean verification failed, not that processing
+                * broke, so still let the op complete successfully.
+                */
+               OPENSSL_free(tmp);
+               OPENSSL_LOG(ERR, "RSA sign Verification failed");
+               return 1;
+       }
+
+       OPENSSL_LOG(DEBUG,
+                       "Length of public_decrypt %zu "
+                       "length of message %zd",
+                       outlen, op->rsa.message.length);
+       if (outlen != op->rsa.message.length ||
+                       CRYPTO_memcmp(tmp, op->rsa.message.data,
+                               op->rsa.message.length) != 0) {
+               OPENSSL_free(tmp);
+               OPENSSL_LOG(ERR, "RSA sign Verification failed");
+               return 1;
+       }
+       OPENSSL_free(tmp);
+
+       return 0;
+}
+
 /* process rsa operations */
 static int
 process_openssl_rsa_op_evp(struct rte_crypto_op *cop,
@@ -2334,7 +2544,6 @@ process_openssl_rsa_op_evp(struct rte_crypto_op *cop,
 {
        struct rte_crypto_asym_op *op = cop->asym;
        uint32_t pad = sess->u.r.pad;
-       uint8_t *tmp;
        size_t outlen = 0;
        int ret = -1;
 
@@ -2352,6 +2561,15 @@ process_openssl_rsa_op_evp(struct rte_crypto_op *cop,
                return ret;
        }
 
+       /* PSS is only valid for sign/verify */
+       if (sess->u.r.pad == RTE_CRYPTO_RSA_PADDING_PSS &&
+               op->rsa.op_type != RTE_CRYPTO_ASYM_OP_SIGN &&
+               op->rsa.op_type != RTE_CRYPTO_ASYM_OP_VERIFY) {
+               OPENSSL_LOG(ERR, "PSS supports sign/verify only");
+               cop->status = RTE_CRYPTO_OP_STATUS_INVALID_ARGS;
+               return ret;
+       }
+
        switch (pad) {
        case RTE_CRYPTO_RSA_PADDING_PKCS1_5:
                pad = RSA_PKCS1_PADDING;
@@ -2362,6 +2580,9 @@ process_openssl_rsa_op_evp(struct rte_crypto_op *cop,
        case RTE_CRYPTO_RSA_PADDING_OAEP:
                pad = RSA_PKCS1_OAEP_PADDING;
                break;
+       case RTE_CRYPTO_RSA_PADDING_PSS:
+               pad = RSA_PKCS1_PSS_PADDING;
+               break;
        default:
                cop->status = RTE_CRYPTO_OP_STATUS_INVALID_ARGS;
                OPENSSL_LOG(ERR,
@@ -2426,70 +2647,55 @@ process_openssl_rsa_op_evp(struct rte_crypto_op *cop,
                break;
 
        case RTE_CRYPTO_ASYM_OP_SIGN:
-               if (EVP_PKEY_sign_init(rsa_ctx) <= 0)
-                       goto err_rsa;
+               if (sess->u.r.pad == RTE_CRYPTO_RSA_PADDING_PSS) {
+                       if (op->rsa.pss_salt.data != NULL) {
+                               OPENSSL_LOG(ERR, "Explicit RSA-PSS salt is not 
supported");
+                               cop->status = RTE_CRYPTO_OP_STATUS_INVALID_ARGS;
+                               return ret;
+                       }
+                       if (openssl_rsa_pss_sign(pad, sess, op) < 0)
+                               goto err_rsa;
+               } else {
+                       if (EVP_PKEY_sign_init(rsa_ctx) <= 0)
+                               goto err_rsa;
 
-               if (EVP_PKEY_CTX_set_rsa_padding(rsa_ctx, pad) <= 0)
-                       goto err_rsa;
+                       if (EVP_PKEY_CTX_set_rsa_padding(rsa_ctx, pad) <= 0)
+                               goto err_rsa;
 
-               if (EVP_PKEY_sign(rsa_ctx, NULL, &outlen,
-                               op->rsa.message.data,
-                               op->rsa.message.length) <= 0)
-                       goto err_rsa;
+                       if (EVP_PKEY_sign(rsa_ctx, NULL, &outlen,
+                                       op->rsa.message.data,
+                                       op->rsa.message.length) <= 0)
+                               goto err_rsa;
 
-               if (outlen <= 0)
-                       goto err_rsa;
+                       if (outlen <= 0)
+                               goto err_rsa;
 
-               if (EVP_PKEY_sign(rsa_ctx, op->rsa.sign.data, &outlen,
-                               op->rsa.message.data,
-                               op->rsa.message.length) <= 0)
-                       goto err_rsa;
-               op->rsa.sign.length = outlen;
+                       if (EVP_PKEY_sign(rsa_ctx, op->rsa.sign.data, &outlen,
+                                       op->rsa.message.data,
+                                       op->rsa.message.length) <= 0)
+                               goto err_rsa;
+                       op->rsa.sign.length = outlen;
+               }
                break;
 
        case RTE_CRYPTO_ASYM_OP_VERIFY:
-               if (EVP_PKEY_verify_recover_init(rsa_ctx) <= 0)
-                       goto err_rsa;
-
-               if (EVP_PKEY_CTX_set_rsa_padding(rsa_ctx, pad) <= 0)
-                       goto err_rsa;
+               if (sess->u.r.pad == RTE_CRYPTO_RSA_PADDING_PSS)
+                       ret = openssl_rsa_pss_verify(pad, sess, op);
+               else
+                       ret = openssl_rsa_verify_recover(rsa_ctx, pad, op);
 
-               if (EVP_PKEY_verify_recover(rsa_ctx, NULL, &outlen,
-                               op->rsa.sign.data,
-                               op->rsa.sign.length) <= 0)
+               if (ret < 0)
                        goto err_rsa;
 
-               if ((outlen <= 0) || (outlen != op->rsa.sign.length))
-                       goto err_rsa;
-
-               tmp = OPENSSL_malloc(outlen);
-               if (tmp == NULL) {
-                       OPENSSL_LOG(ERR, "Memory allocation failed");
-                       goto err_rsa;
-               }
-
-               ret = EVP_PKEY_verify_recover(rsa_ctx, tmp, &outlen,
-                               op->rsa.sign.data,
-                               op->rsa.sign.length);
-               if (ret <= 0) {
-                       /* OpenSSL RSA verification returns one on
-                        * successful verification, otherwise 0. Hence,
-                        * this enqueue operation should succeed even if
-                        * invalid signature has been requested in verify.
-                        */
-                       OPENSSL_free(tmp);
-                       goto err_rsa;
-               }
-
-               OPENSSL_LOG(DEBUG,
-                               "Length of public_decrypt %zu "
-                               "length of message %zd",
-                               outlen, op->rsa.message.length);
-               if (CRYPTO_memcmp(tmp, op->rsa.message.data,
-                               op->rsa.message.length)) {
-                       OPENSSL_LOG(ERR, "RSA sign Verification failed");
+               /*
+                * ret == 1 means the signature did not verify; that is a
+                * normal outcome, so the op still completes (with an error
+                * status) instead of failing the enqueue itself.
+                */
+               if (ret > 0) {
+                       cop->status = RTE_CRYPTO_OP_STATUS_ERROR;
+                       return 0;
                }
-               OPENSSL_free(tmp);
                break;
 
        default:
diff --git a/drivers/crypto/openssl/rte_openssl_pmd_ops.c 
b/drivers/crypto/openssl/rte_openssl_pmd_ops.c
index 2504cfb9f5..efc11339be 100644
--- a/drivers/crypto/openssl/rte_openssl_pmd_ops.c
+++ b/drivers/crypto/openssl/rte_openssl_pmd_ops.c
@@ -741,9 +741,11 @@ static const struct rte_cryptodev_capabilities 
openssl_pmd_capabilities[] = {
                                .increment = 1
                                },
 #if (OPENSSL_VERSION_NUMBER >= 0x30000000L)
+                               /* pss_explicit_salt not supported, defaults to 
false */
                                .pad_types = ((1 << 
RTE_CRYPTO_RSA_PADDING_NONE) |
                                        (1 << RTE_CRYPTO_RSA_PADDING_PKCS1_5) |
-                                       (1 << RTE_CRYPTO_RSA_PADDING_OAEP)),
+                                       (1 << RTE_CRYPTO_RSA_PADDING_OAEP) |
+                                       (1 << RTE_CRYPTO_RSA_PADDING_PSS)),
                                .mgf1_hash_algos = 
(RTE_BIT64(RTE_CRYPTO_AUTH_SHA1) |
                                        RTE_BIT64(RTE_CRYPTO_AUTH_SHA224) |
                                        RTE_BIT64(RTE_CRYPTO_AUTH_SHA256) |
@@ -1324,6 +1326,29 @@ static int openssl_set_asym_session_parameters(
                                asym_session->u.r.label_len = 0;
                                asym_session->u.r.label = NULL;
                        }
+               } else if (xform->rsa.padding.type == 
RTE_CRYPTO_RSA_PADDING_PSS) {
+                       asym_session->u.r.pss_md = 
openssl_get_md(xform->rsa.padding.hash);
+
+                       if (asym_session->u.r.pss_md == NULL) {
+                               OPENSSL_LOG(ERR,
+                                       "Unsupported PSS hash algorithm %u",
+                                       xform->rsa.padding.hash);
+                               goto err_rsa;
+                       }
+
+                       enum rte_crypto_auth_algorithm mgf1 = 
xform->rsa.padding.mgf1hash;
+
+                       if (mgf1 == 0)
+                               mgf1 = xform->rsa.padding.hash;
+
+                       asym_session->u.r.pss_mgf1_md = openssl_get_md(mgf1);
+                       if (asym_session->u.r.pss_mgf1_md == NULL) {
+                               OPENSSL_LOG(ERR,
+                                       "Unsupported PSS MGF1 hash algorithm 
%u", mgf1);
+                               goto err_rsa;
+                       }
+
+                       asym_session->u.r.pss_saltlen = 
xform->rsa.padding.pss_saltlen;
                }
 
                OSSL_PARAM_BLD * param_bld = OSSL_PARAM_BLD_new();
-- 
2.54.0

Reply via email to