Add OpenSSL asymmetric tests for RSA-PSS sign and verify
operations using SHA-256 with different salt length settings.

Introduce test vectors covering digest-length salt, maximum
supported salt length, and zero-length salt. Update the
OpenSSL asym test suite to validate RSA-PSS functionality
when supported by the device capabilities.

Signed-off-by: Sucharitha Sarananaga <[email protected]>
---
 app/test/test_cryptodev_asym.c             | 307 +++++++++++++++++++++
 app/test/test_cryptodev_rsa_test_vectors.h | 163 +++++++++++
 2 files changed, 470 insertions(+)

diff --git a/app/test/test_cryptodev_asym.c b/app/test/test_cryptodev_asym.c
index ceae029a4a..718b06aefa 100644
--- a/app/test/test_cryptodev_asym.c
+++ b/app/test/test_cryptodev_asym.c
@@ -606,6 +606,307 @@ test_rsa_oaep_labeled_default_mgf1_enc_dec_crt(void)
        return status;
 }
 
+/*
+ * Check that the device supports RSA-PSS padding, the hash used for
+ * the signature digest, and, if explicitly set, the MGF1 hash (this
+ * PMD defaults MGF1 to the same hash as the digest when unset).
+ */
+static int
+rsa_pss_supported(uint8_t dev_id, const struct rte_crypto_rsa_padding *padding)
+{
+       struct rte_cryptodev_asym_capability_idx idx = {
+               .type = RTE_CRYPTO_ASYM_XFORM_RSA,
+       };
+       const struct rte_cryptodev_asymmetric_xform_capability *capa;
+
+       capa = rte_cryptodev_asym_capability_get(dev_id, &idx);
+       if (capa == NULL) {
+               RTE_LOG(INFO, USER1, "RSA capability not reported by device\n");
+               return 0;
+       }
+
+       if (capa->rsa_capa.pad_types != 0 &&
+                       (capa->rsa_capa.pad_types & (1 << 
RTE_CRYPTO_RSA_PADDING_PSS)) == 0) {
+               RTE_LOG(INFO, USER1,
+                       "RSA PSS padding not supported by device. Supported 
pad_types=%#x\n",
+                       capa->rsa_capa.pad_types);
+               return 0;
+       }
+
+       if (!rte_cryptodev_asym_xform_capability_check_hash(capa, 
padding->hash)) {
+               RTE_LOG(INFO, USER1,
+                       "RSA PSS hash %u not supported by device capabilities "
+                       "(supported hash_algos=%#"PRIx64")\n",
+                       padding->hash, capa->hash_algos);
+               return 0;
+       }
+
+       if (padding->mgf1hash != 0 &&
+                       (capa->rsa_capa.mgf1_hash_algos & 
RTE_BIT64(padding->mgf1hash)) == 0) {
+               RTE_LOG(INFO, USER1,
+                       "RSA PSS MGF1 hash %u not supported by device 
capabilities "
+                       "(supported mgf1_hash_algos=%#"PRIx64")\n",
+                       padding->mgf1hash, capa->rsa_capa.mgf1_hash_algos);
+               return 0;
+       }
+
+       return 1;
+}
+
+/*
+ * Sign then verify the freshly-generated signature. Unlike
+ * queue_ops_rsa_sign_verify(), this does not include a
+ * corrupted-signature negative test: RSA-PSS verification does not
+ * support verify-recover, and mismatches are reported via op->status.
+ */
+static int
+queue_ops_rsa_pss_sign_verify(void *sess)
+{
+       struct crypto_testsuite_params_asym *ts_params = &testsuite_params;
+       struct rte_mempool *op_mpool = ts_params->op_mpool;
+       uint8_t dev_id = ts_params->valid_devs[0];
+       struct rte_crypto_op *op, *result_op;
+       struct rte_crypto_asym_op *asym_op;
+       uint8_t output_buf[TEST_DATA_SIZE];
+       int status;
+
+       /* Set up crypto op data structure */
+       op = rte_crypto_op_alloc(op_mpool, RTE_CRYPTO_OP_TYPE_ASYMMETRIC);
+       if (!op) {
+               RTE_LOG(ERR, USER1, "Failed to allocate asymmetric crypto "
+                       "operation struct\n");
+               return TEST_FAILED;
+       }
+
+       asym_op = op->asym;
+
+       /* Compute sign on the test vector */
+       asym_op->rsa.op_type = RTE_CRYPTO_ASYM_OP_SIGN;
+
+       /*
+        * RTE_CRYPTO_RSA_PADDING_PSS expects message to already be a
+        * digest hashed with the algorithm configured in the session's
+        * padding.hash (SHA-256 here), not the raw plaintext.
+        */
+       asym_op->rsa.message.data = rsa_pss_digest_sha256.data;
+       asym_op->rsa.message.length = rsa_pss_digest_sha256.len;
+       asym_op->rsa.sign.length = RTE_DIM(rsa_n);
+       asym_op->rsa.sign.data = output_buf;
+
+       debug_hexdump(stdout, "digest", asym_op->rsa.message.data,
+                     asym_op->rsa.message.length);
+
+       /* Attach asymmetric crypto session to crypto operations */
+       rte_crypto_op_attach_asym_session(op, sess);
+
+       RTE_LOG(DEBUG, USER1, "Process ASYM operation\n");
+
+       /* Process crypto operation */
+       if (rte_cryptodev_enqueue_burst(dev_id, 0, &op, 1) != 1) {
+               RTE_LOG(ERR, USER1, "Error sending packet for sign\n");
+               status = TEST_FAILED;
+               goto error_exit;
+       }
+
+       while (rte_cryptodev_dequeue_burst(dev_id, 0, &result_op, 1) == 0)
+               rte_pause();
+
+       if (result_op == NULL) {
+               RTE_LOG(ERR, USER1, "Failed to process sign op\n");
+               status = TEST_FAILED;
+               goto error_exit;
+       }
+
+       if (result_op->status != RTE_CRYPTO_OP_STATUS_SUCCESS) {
+               RTE_LOG(ERR, USER1, "Failed to process PSS sign op\n");
+               status = TEST_FAILED;
+               goto error_exit;
+       }
+
+       debug_hexdump(stdout, "signed message", asym_op->rsa.sign.data,
+                     asym_op->rsa.sign.length);
+       asym_op = result_op->asym;
+
+       /* Verify sign */
+       asym_op->rsa.op_type = RTE_CRYPTO_ASYM_OP_VERIFY;
+
+       /* Process crypto operation */
+       if (rte_cryptodev_enqueue_burst(dev_id, 0, &op, 1) != 1) {
+               RTE_LOG(ERR, USER1, "Error sending packet for verify\n");
+               status = TEST_FAILED;
+               goto error_exit;
+       }
+
+       while (rte_cryptodev_dequeue_burst(dev_id, 0, &result_op, 1) == 0)
+               rte_pause();
+
+       if (result_op == NULL) {
+               RTE_LOG(ERR, USER1, "Failed to process verify op\n");
+               status = TEST_FAILED;
+               goto error_exit;
+       }
+
+       if (result_op->status != RTE_CRYPTO_OP_STATUS_SUCCESS) {
+               RTE_LOG(ERR, USER1, "Failed to process PSS sign-verify op\n");
+               status = TEST_FAILED;
+               goto error_exit;
+       }
+
+       status = TEST_SUCCESS;
+error_exit:
+
+       rte_crypto_op_free(op);
+
+       return status;
+}
+
+static int
+test_rsa_pss_sign_verify_digest_saltlen(void)
+{
+       struct crypto_testsuite_params_asym *ts_params = &testsuite_params;
+       struct rte_mempool *sess_mpool = ts_params->session_mpool;
+       struct rte_cryptodev_asym_capability_idx idx;
+       uint8_t dev_id = ts_params->valid_devs[0];
+       struct rte_crypto_asym_xform xform;
+       void *sess = NULL;
+       struct rte_cryptodev_info dev_info;
+       int ret, status = TEST_SUCCESS;
+
+       idx.type = RTE_CRYPTO_ASYM_XFORM_RSA;
+       if (rte_cryptodev_asym_capability_get(dev_id, &idx) == NULL)
+               return -ENOTSUP;
+
+       if (!rsa_pss_supported(dev_id, &rsa_pss_xform.rsa.padding)) {
+               RTE_LOG(INFO, USER1, "RSA PSS not supported. Test skipped\n");
+               return TEST_SKIPPED;
+       }
+
+       rte_cryptodev_info_get(dev_id, &dev_info);
+       if (!(dev_info.feature_flags &
+                               RTE_CRYPTODEV_FF_RSA_PRIV_OP_KEY_EXP)) {
+               RTE_LOG(INFO, USER1, "Device doesn't support sign op with "
+                       "exponent key type. Test skipped\n");
+               return TEST_SKIPPED;
+       }
+
+       memcpy(&xform, &rsa_pss_xform, sizeof(rsa_pss_xform));
+       xform.rsa.key_type = RTE_RSA_KEY_TYPE_EXP;
+
+       ret = rte_cryptodev_asym_session_create(dev_id, &xform, sess_mpool, 
&sess);
+       if (ret < 0) {
+               RTE_LOG(ERR, USER1, "Session creation failed for "
+                       "PSS sign_verify (saltlen = digest length)\n");
+               status = (ret == -ENOTSUP) ? TEST_SKIPPED : TEST_FAILED;
+               goto error_exit;
+       }
+
+       status = queue_ops_rsa_pss_sign_verify(sess);
+
+error_exit:
+       rte_cryptodev_asym_session_free(dev_id, sess);
+       TEST_ASSERT_EQUAL(status, 0, "Test failed");
+
+       return status;
+}
+
+static int
+test_rsa_pss_sign_verify_max_saltlen(void)
+{
+       struct crypto_testsuite_params_asym *ts_params = &testsuite_params;
+       struct rte_mempool *sess_mpool = ts_params->session_mpool;
+       struct rte_cryptodev_asym_capability_idx idx;
+       uint8_t dev_id = ts_params->valid_devs[0];
+       struct rte_crypto_asym_xform xform;
+       void *sess = NULL;
+       struct rte_cryptodev_info dev_info;
+       int ret, status = TEST_SUCCESS;
+
+       idx.type = RTE_CRYPTO_ASYM_XFORM_RSA;
+       if (rte_cryptodev_asym_capability_get(dev_id, &idx) == NULL)
+               return -ENOTSUP;
+
+       if (!rsa_pss_supported(dev_id, &rsa_pss_max_salt_xform.rsa.padding)) {
+               RTE_LOG(INFO, USER1, "RSA PSS not supported. Test skipped\n");
+               return TEST_SKIPPED;
+       }
+
+       rte_cryptodev_info_get(dev_id, &dev_info);
+       if (!(dev_info.feature_flags &
+                               RTE_CRYPTODEV_FF_RSA_PRIV_OP_KEY_EXP)) {
+               RTE_LOG(INFO, USER1, "Device doesn't support sign op with "
+                       "exponent key type. Test skipped\n");
+               return TEST_SKIPPED;
+       }
+
+       memcpy(&xform, &rsa_pss_max_salt_xform, sizeof(rsa_pss_max_salt_xform));
+       xform.rsa.key_type = RTE_RSA_KEY_TYPE_EXP;
+
+       ret = rte_cryptodev_asym_session_create(dev_id, &xform, sess_mpool, 
&sess);
+       if (ret < 0) {
+               RTE_LOG(ERR, USER1, "Session creation failed for "
+                       "PSS sign_verify (max saltlen)\n");
+               status = (ret == -ENOTSUP) ? TEST_SKIPPED : TEST_FAILED;
+               goto error_exit;
+       }
+
+       status = queue_ops_rsa_pss_sign_verify(sess);
+
+error_exit:
+       rte_cryptodev_asym_session_free(dev_id, sess);
+       TEST_ASSERT_EQUAL(status, 0, "Test failed");
+
+       return status;
+}
+
+static int
+test_rsa_pss_sign_verify_zero_saltlen(void)
+{
+       struct crypto_testsuite_params_asym *ts_params = &testsuite_params;
+       struct rte_mempool *sess_mpool = ts_params->session_mpool;
+       struct rte_cryptodev_asym_capability_idx idx;
+       uint8_t dev_id = ts_params->valid_devs[0];
+       struct rte_crypto_asym_xform xform;
+       void *sess = NULL;
+       struct rte_cryptodev_info dev_info;
+       int ret, status = TEST_SUCCESS;
+
+       idx.type = RTE_CRYPTO_ASYM_XFORM_RSA;
+       if (rte_cryptodev_asym_capability_get(dev_id, &idx) == NULL)
+               return -ENOTSUP;
+
+       if (!rsa_pss_supported(dev_id, &rsa_pss_zero_salt_xform.rsa.padding)) {
+               RTE_LOG(INFO, USER1, "RSA PSS not supported. Test skipped\n");
+               return TEST_SKIPPED;
+       }
+
+       rte_cryptodev_info_get(dev_id, &dev_info);
+       if (!(dev_info.feature_flags &
+                               RTE_CRYPTODEV_FF_RSA_PRIV_OP_KEY_EXP)) {
+               RTE_LOG(INFO, USER1, "Device doesn't support sign op with "
+                       "exponent key type. Test skipped\n");
+               return TEST_SKIPPED;
+       }
+
+       memcpy(&xform, &rsa_pss_zero_salt_xform, 
sizeof(rsa_pss_zero_salt_xform));
+       xform.rsa.key_type = RTE_RSA_KEY_TYPE_EXP;
+
+       ret = rte_cryptodev_asym_session_create(dev_id, &xform, sess_mpool, 
&sess);
+       if (ret < 0) {
+               RTE_LOG(ERR, USER1, "Session creation failed for "
+                       "PSS sign_verify (zero saltlen)\n");
+               status = (ret == -ENOTSUP) ? TEST_SKIPPED : TEST_FAILED;
+               goto error_exit;
+       }
+
+       status = queue_ops_rsa_pss_sign_verify(sess);
+
+error_exit:
+       rte_cryptodev_asym_session_free(dev_id, sess);
+       TEST_ASSERT_EQUAL(status, 0, "Test failed");
+
+       return status;
+}
+
 static int
 test_rsa_sign_verify(void)
 {
@@ -5705,6 +6006,12 @@ static struct unit_test_suite 
cryptodev_asym_rsa_testsuite = {
                                test_rsa_oaep_labeled_default_mgf1_enc_dec),
                TEST_CASE_ST(ut_setup_asym, ut_teardown_asym,
                                test_rsa_oaep_labeled_default_mgf1_enc_dec_crt),
+               TEST_CASE_ST(ut_setup_asym, ut_teardown_asym,
+                               test_rsa_pss_sign_verify_digest_saltlen),
+               TEST_CASE_ST(ut_setup_asym, ut_teardown_asym,
+                               test_rsa_pss_sign_verify_max_saltlen),
+               TEST_CASE_ST(ut_setup_asym, ut_teardown_asym,
+                               test_rsa_pss_sign_verify_zero_saltlen),
                /* RSA EXP */
                TEST_CASE_NAMED_WITH_DATA(
                        "RSA Encryption (n=128, pt=20, e=3) EXP, Padding: NONE",
diff --git a/app/test/test_cryptodev_rsa_test_vectors.h 
b/app/test/test_cryptodev_rsa_test_vectors.h
index 6835453b6d..f35a83c016 100644
--- a/app/test/test_cryptodev_rsa_test_vectors.h
+++ b/app/test/test_cryptodev_rsa_test_vectors.h
@@ -251,6 +251,23 @@ struct rsa_test_data rsaplaintext = {
        .len = 20
 };
 
+/*
+ * SHA-256 digest of rsaplaintext.data. RTE_CRYPTO_RSA_PADDING_PSS
+ * expects rte_crypto_rsa_op_param::message to already be a digest
+ * hashed with the algorithm configured in rte_crypto_rsa_padding::hash
+ * (SHA-256 for the PSS xforms below), not the raw message, so PSS
+ * sign/verify tests use this instead of rsaplaintext directly.
+ */
+struct rsa_test_data rsa_pss_digest_sha256 = {
+       .data = {
+               0x45, 0x24, 0x54, 0x32, 0x9d, 0x91, 0xda, 0x1b,
+               0xb8, 0x76, 0x0d, 0x9b, 0xdd, 0xea, 0xe5, 0x21,
+               0x30, 0x91, 0x72, 0xb0, 0x9c, 0x23, 0x12, 0x3f,
+               0xb3, 0x43, 0x09, 0x5d, 0xa3, 0x10, 0x78, 0x7c
+       },
+       .len = 32
+};
+
 uint8_t rsa_n[] = {
        0xb3, 0xa1, 0xaf, 0xb7, 0x13, 0x08, 0x00,
        0x0a, 0x35, 0xdc, 0x2b, 0x20, 0x8d, 0xa1, 0xb5,
@@ -538,4 +555,150 @@ struct rte_crypto_asym_xform 
rsa_oaep_labeled_default_mgf1_xform = {
        }
 };
 
+/*
+ * RSA-PSS xforms below all use the same 1024-bit test key (rsa_n, 128
+ * bytes) and SHA-256 (hLen = 32 bytes). For this key/hash combination:
+ *   emBits = modBits - 1 = 1023, emLen = ceil(emBits / 8) = 128
+ *   maxSaltLen = emLen - hLen - 2 = 128 - 32 - 2 = 94
+ * (see RFC 8017 EMSA-PSS-ENCODE, section 9.1.1)
+ */
+
+/** rsa PSS xform (SHA-256, salt length = digest length, QT private key type 
by default) */
+struct rte_crypto_asym_xform rsa_pss_xform = {
+       .next = NULL,
+       .xform_type = RTE_CRYPTO_ASYM_XFORM_RSA,
+       .rsa = {
+               .padding.type = RTE_CRYPTO_RSA_PADDING_PSS,
+               .padding.hash = RTE_CRYPTO_AUTH_SHA256,
+               .padding.pss_saltlen = 32,
+               .n = {
+                       .data = rsa_n,
+                       .length = sizeof(rsa_n)
+               },
+               .e = {
+                       .data = rsa_e,
+                       .length = sizeof(rsa_e)
+               },
+               .qt = {
+                       .p = {
+                               .data = rsa_p,
+                               .length = sizeof(rsa_p)
+                       },
+                       .q = {
+                               .data = rsa_q,
+                               .length = sizeof(rsa_q)
+                       },
+                       .dP = {
+                               .data = rsa_dP,
+                               .length = sizeof(rsa_dP)
+                       },
+                       .dQ = {
+                               .data = rsa_dQ,
+                               .length = sizeof(rsa_dQ)
+                       },
+                       .qInv = {
+                               .data = rsa_qInv,
+                               .length = sizeof(rsa_qInv)
+                       },
+               },
+               .d = {
+                       .data = rsa_d,
+                       .length = sizeof(rsa_d)
+               },
+               .key_type = RTE_RSA_KEY_TYPE_QT
+       }
+};
+
+/** rsa PSS xform with the maximum permissible salt length (94 bytes) */
+struct rte_crypto_asym_xform rsa_pss_max_salt_xform = {
+       .next = NULL,
+       .xform_type = RTE_CRYPTO_ASYM_XFORM_RSA,
+       .rsa = {
+               .padding.type = RTE_CRYPTO_RSA_PADDING_PSS,
+               .padding.hash = RTE_CRYPTO_AUTH_SHA256,
+               .padding.pss_saltlen = 94,
+               .n = {
+                       .data = rsa_n,
+                       .length = sizeof(rsa_n)
+               },
+               .e = {
+                       .data = rsa_e,
+                       .length = sizeof(rsa_e)
+               },
+               .qt = {
+                       .p = {
+                               .data = rsa_p,
+                               .length = sizeof(rsa_p)
+                       },
+                       .q = {
+                               .data = rsa_q,
+                               .length = sizeof(rsa_q)
+                       },
+                       .dP = {
+                               .data = rsa_dP,
+                               .length = sizeof(rsa_dP)
+                       },
+                       .dQ = {
+                               .data = rsa_dQ,
+                               .length = sizeof(rsa_dQ)
+                       },
+                       .qInv = {
+                               .data = rsa_qInv,
+                               .length = sizeof(rsa_qInv)
+                       },
+               },
+               .d = {
+                       .data = rsa_d,
+                       .length = sizeof(rsa_d)
+               },
+               .key_type = RTE_RSA_KEY_TYPE_QT
+       }
+};
+
+/** rsa PSS xform with zero-length salt (deterministic PSS, no randomization) 
*/
+struct rte_crypto_asym_xform rsa_pss_zero_salt_xform = {
+       .next = NULL,
+       .xform_type = RTE_CRYPTO_ASYM_XFORM_RSA,
+       .rsa = {
+               .padding.type = RTE_CRYPTO_RSA_PADDING_PSS,
+               .padding.hash = RTE_CRYPTO_AUTH_SHA256,
+               .padding.pss_saltlen = 0, /* no salt bytes */
+               .n = {
+                       .data = rsa_n,
+                       .length = sizeof(rsa_n)
+               },
+               .e = {
+                       .data = rsa_e,
+                       .length = sizeof(rsa_e)
+               },
+               .qt = {
+                       .p = {
+                               .data = rsa_p,
+                               .length = sizeof(rsa_p)
+                       },
+                       .q = {
+                               .data = rsa_q,
+                               .length = sizeof(rsa_q)
+                       },
+                       .dP = {
+                               .data = rsa_dP,
+                               .length = sizeof(rsa_dP)
+                       },
+                       .dQ = {
+                               .data = rsa_dQ,
+                               .length = sizeof(rsa_dQ)
+                       },
+                       .qInv = {
+                               .data = rsa_qInv,
+                               .length = sizeof(rsa_qInv)
+                       },
+               },
+               .d = {
+                       .data = rsa_d,
+                       .length = sizeof(rsa_d)
+               },
+               .key_type = RTE_RSA_KEY_TYPE_QT
+       }
+};
+
 #endif /* TEST_CRYPTODEV_RSA_TEST_VECTORS_H__ */
-- 
2.54.0

Reply via email to