[v2,2/6] crypto/openssl: support EDDSA

Message ID 20240905133933.741-2-gmuthukrishn@marvell.com (mailing list archive)
State Superseded
Delegated to: akhil goyal
Headers
Series [v2,1/6] cryptodev: add EDDSA asymmetric crypto algorithm |

Checks

Context Check Description
ci/checkpatch warning coding style issues

Commit Message

Gowrishankar Muthukrishnan Sept. 5, 2024, 1:39 p.m. UTC
Support EDDSA crypto algorithm in OpenSSL PMD.

Signed-off-by: Gowrishankar Muthukrishnan <gmuthukrishn@marvell.com>
---
 drivers/crypto/openssl/openssl_pmd_private.h |  13 ++
 drivers/crypto/openssl/rte_openssl_pmd.c     | 223 +++++++++++++++++++
 drivers/crypto/openssl/rte_openssl_pmd_ops.c | 131 +++++++++++
 3 files changed, 367 insertions(+)
  

Comments

Jack Bond-Preston Sept. 9, 2024, 9:56 a.m. UTC | #1
Hi,

On 05/09/2024 14:39, Gowrishankar Muthukrishnan wrote:
> Support EDDSA crypto algorithm in OpenSSL PMD.
> 
> Signed-off-by: Gowrishankar Muthukrishnan <gmuthukrishn@marvell.com>
> ---
>   drivers/crypto/openssl/openssl_pmd_private.h |  13 ++
>   drivers/crypto/openssl/rte_openssl_pmd.c     | 223 +++++++++++++++++++
>   drivers/crypto/openssl/rte_openssl_pmd_ops.c | 131 +++++++++++
>   3 files changed, 367 insertions(+)
<snip>
> +	ctx = BN_CTX_new();
> +	if (!ctx)
> +		goto err_ecfpm;
> +
<snip>
> +
> +err_ecfpm:
> +	BN_CTX_free(ctx);
> +	BN_free(n);
> +	return ret;
> +}
<snip>
> +
> +			md_ctx = EVP_MD_CTX_new();
> +			if (!md_ctx)
> +				goto err_eddsa;
> +
<snip>
> +	cop->status = RTE_CRYPTO_OP_STATUS_SUCCESS;
> +err_eddsa:
> +	OSSL_PARAM_BLD_free(iparam_bld);
> +
> +	if (sctx)
> +		EVP_PKEY_CTX_free(sctx);
> +
> +	if (cctx)
> +		EVP_PKEY_CTX_free(cctx);
> +
> +	if (pkey)
> +		EVP_PKEY_free(pkey);
> +
> +	return ret;
<etc..>

This (allocating and freeing ctxs for every operation) has pretty bad 
performance, refer to 
https://patches.dpdk.org/project/dpdk/cover/20240703134552.1439633-1-jack.bond-preston@foss.arm.com/ 
for more information.

I suppose for an initial implementation this could be ok - it's correct, 
just slow.

Cheers,
Jack
  

Patch

diff --git a/drivers/crypto/openssl/openssl_pmd_private.h b/drivers/crypto/openssl/openssl_pmd_private.h
index a50e4d4918..a613988dbe 100644
--- a/drivers/crypto/openssl/openssl_pmd_private.h
+++ b/drivers/crypto/openssl/openssl_pmd_private.h
@@ -231,10 +231,23 @@  struct __rte_cache_aligned openssl_asym_session {
 #endif
 		} s;
 		struct {
+			uint8_t curve_id;
+#if (OPENSSL_VERSION_NUMBER >= 0x30000000L)
+			EC_GROUP * group;
+			BIGNUM *priv_key;
+#endif
+		} ec;
+		struct {
 #if (OPENSSL_VERSION_NUMBER >= 0x30000000L)
 			OSSL_PARAM * params;
 #endif
 		} sm2;
+		struct {
+			uint8_t curve_id;
+#if (OPENSSL_VERSION_NUMBER >= 0x30000000L)
+			OSSL_PARAM * params;
+#endif
+		} eddsa;
 	} u;
 };
 /** Set and validate OPENSSL crypto session parameters */
diff --git a/drivers/crypto/openssl/rte_openssl_pmd.c b/drivers/crypto/openssl/rte_openssl_pmd.c
index 101111e85b..cbc10b27d4 100644
--- a/drivers/crypto/openssl/rte_openssl_pmd.c
+++ b/drivers/crypto/openssl/rte_openssl_pmd.c
@@ -2849,6 +2849,45 @@  process_openssl_rsa_op_evp(struct rte_crypto_op *cop,
 
 }
 
+static int
+process_openssl_ecfpm_op_evp(struct rte_crypto_op *cop,
+		struct openssl_asym_session *sess)
+{
+	const EC_GROUP *ecgrp = sess->u.ec.group;
+	EC_POINT *ecpt = NULL;
+	BN_CTX *ctx = NULL;
+	BIGNUM *n = NULL;
+	int ret = -1;
+
+	n = BN_bin2bn((const unsigned char *)
+			cop->asym->ecpm.scalar.data,
+			cop->asym->ecpm.scalar.length,
+			BN_new());
+
+	ctx = BN_CTX_new();
+	if (!ctx)
+		goto err_ecfpm;
+
+	if (!EC_POINT_mul(ecgrp, ecpt, n, NULL, NULL, ctx))
+		goto err_ecfpm;
+
+	if (cop->asym->flags & RTE_CRYPTO_ASYM_FLAG_PUB_KEY_COMPRESSED) {
+		unsigned char *buf = cop->asym->ecpm.r.x.data;
+		size_t sz;
+
+		sz = EC_POINT_point2oct(ecgrp, ecpt, POINT_CONVERSION_COMPRESSED, buf, 0, ctx);
+		if (!sz)
+			goto err_ecfpm;
+
+		cop->asym->ecpm.r.x.length = sz;
+	}
+
+err_ecfpm:
+	BN_CTX_free(ctx);
+	BN_free(n);
+	return ret;
+}
+
 static int
 process_openssl_sm2_op_evp(struct rte_crypto_op *cop,
 		struct openssl_asym_session *sess)
@@ -3074,6 +3113,158 @@  process_openssl_sm2_op_evp(struct rte_crypto_op *cop,
 	return ret;
 }
 
+static int
+process_openssl_eddsa_op_evp(struct rte_crypto_op *cop,
+		struct openssl_asym_session *sess)
+{
+	static const char * const instance[] = {"Ed25519", "Ed25519ctx", "Ed25519ph",
+						"Ed448", "Ed448ph"};
+	EVP_PKEY_CTX *kctx = NULL, *sctx = NULL, *cctx = NULL;
+	const uint8_t curve_id = sess->u.eddsa.curve_id;
+	struct rte_crypto_asym_op *op = cop->asym;
+	OSSL_PARAM *params = sess->u.eddsa.params;
+	OSSL_PARAM_BLD *iparam_bld = NULL;
+	OSSL_PARAM *iparams = NULL;
+	uint8_t signbuf[128] = {0};
+	EVP_MD_CTX *md_ctx = NULL;
+	EVP_PKEY *pkey = NULL;
+	size_t signlen;
+	int ret = -1;
+
+	cop->status = RTE_CRYPTO_OP_STATUS_ERROR;
+
+	iparam_bld = OSSL_PARAM_BLD_new();
+	if (!iparam_bld)
+		goto err_eddsa;
+
+	if (op->eddsa.instance == RTE_CRYPTO_EDCURVE_25519CTX) {
+		OSSL_PARAM_BLD_push_octet_string(iparam_bld, "context-string",
+			op->eddsa.context.data, op->eddsa.context.length);
+
+	}
+
+	OSSL_PARAM_BLD_push_utf8_string(iparam_bld, "instance",
+		instance[op->eddsa.instance], strlen(instance[op->eddsa.instance]));
+
+	iparams = OSSL_PARAM_BLD_to_param(iparam_bld);
+	if (!iparams)
+		goto err_eddsa;
+
+	switch (op->eddsa.op_type) {
+	case RTE_CRYPTO_ASYM_OP_SIGN:
+		{
+			if (curve_id == RTE_CRYPTO_EC_GROUP_ED25519)
+				kctx = EVP_PKEY_CTX_new_from_name(NULL, "ED25519", NULL);
+			else
+				kctx = EVP_PKEY_CTX_new_from_name(NULL, "ED448", NULL);
+
+			if (kctx == NULL || EVP_PKEY_fromdata_init(kctx) <= 0 ||
+				EVP_PKEY_fromdata(kctx, &pkey, EVP_PKEY_KEYPAIR, params) <= 0)
+				goto err_eddsa;
+
+			md_ctx = EVP_MD_CTX_new();
+			if (!md_ctx)
+				goto err_eddsa;
+
+			sctx = EVP_PKEY_CTX_new_from_pkey(NULL, pkey, NULL);
+			if (!sctx)
+				goto err_eddsa;
+
+			EVP_MD_CTX_set_pkey_ctx(md_ctx, sctx);
+
+#if (OPENSSL_VERSION_NUMBER >= 0x30300000L)
+			if (!EVP_DigestSignInit_ex(md_ctx, NULL, NULL, NULL, NULL, pkey, iparams))
+				goto err_eddsa;
+#else
+			if (op->eddsa.instance == RTE_CRYPTO_EDCURVE_25519 ||
+				op->eddsa.instance == RTE_CRYPTO_EDCURVE_448) {
+				if (!EVP_DigestSignInit(md_ctx, NULL, NULL, NULL, pkey))
+					goto err_eddsa;
+			} else
+				goto err_eddsa;
+#endif
+
+			if (!EVP_DigestSign(md_ctx, NULL, &signlen, op->eddsa.message.data,
+					op->eddsa.message.length))
+				goto err_eddsa;
+
+			if (signlen > RTE_DIM(signbuf))
+				goto err_eddsa;
+
+			if (!EVP_DigestSign(md_ctx, signbuf, &signlen, op->eddsa.message.data,
+					op->eddsa.message.length))
+				goto err_eddsa;
+
+			memcpy(op->eddsa.sign.data, &signbuf[0], signlen);
+			op->eddsa.sign.length = signlen;
+		}
+		break;
+	case RTE_CRYPTO_ASYM_OP_VERIFY:
+		{
+			if (curve_id == RTE_CRYPTO_EC_GROUP_ED25519)
+				kctx = EVP_PKEY_CTX_new_from_name(NULL, "ED25519", NULL);
+			else
+				kctx = EVP_PKEY_CTX_new_from_name(NULL, "ED448", NULL);
+
+			if (kctx == NULL || EVP_PKEY_fromdata_init(kctx) <= 0 ||
+				EVP_PKEY_fromdata(kctx, &pkey, EVP_PKEY_PUBLIC_KEY, params) <= 0)
+				goto err_eddsa;
+
+			md_ctx = EVP_MD_CTX_new();
+			if (!md_ctx)
+				goto err_eddsa;
+
+			sctx = EVP_PKEY_CTX_new_from_pkey(NULL, pkey, NULL);
+			if (!sctx)
+				goto err_eddsa;
+
+			EVP_MD_CTX_set_pkey_ctx(md_ctx, sctx);
+
+#if (OPENSSL_VERSION_NUMBER >= 0x30300000L)
+			if (!EVP_DigestVerifyInit_ex(md_ctx, NULL, NULL, NULL, NULL, pkey, iparams))
+				goto err_eddsa;
+#else
+			if (op->eddsa.instance == RTE_CRYPTO_EDCURVE_25519 ||
+				op->eddsa.instance == RTE_CRYPTO_EDCURVE_448) {
+				if (!EVP_DigestVerifyInit(md_ctx, NULL, NULL, NULL, pkey))
+					goto err_eddsa;
+			} else
+				goto err_eddsa;
+#endif
+
+			signlen = op->eddsa.sign.length;
+			memcpy(&signbuf[0], op->eddsa.sign.data, op->eddsa.sign.length);
+
+			ret = EVP_DigestVerify(md_ctx, signbuf, signlen, op->eddsa.message.data,
+					op->eddsa.message.length);
+			if (ret == 0)
+				goto err_eddsa;
+		}
+		break;
+	default:
+		/* allow ops with invalid args to be pushed to
+		 * completion queue
+		 */
+		cop->status = RTE_CRYPTO_OP_STATUS_INVALID_ARGS;
+		goto err_eddsa;
+	}
+
+	ret = 0;
+	cop->status = RTE_CRYPTO_OP_STATUS_SUCCESS;
+err_eddsa:
+	OSSL_PARAM_BLD_free(iparam_bld);
+
+	if (sctx)
+		EVP_PKEY_CTX_free(sctx);
+
+	if (cctx)
+		EVP_PKEY_CTX_free(cctx);
+
+	if (pkey)
+		EVP_PKEY_free(pkey);
+
+	return ret;
+}
 #else
 static int
 process_openssl_rsa_op(struct rte_crypto_op *cop,
@@ -3174,6 +3365,15 @@  process_openssl_rsa_op(struct rte_crypto_op *cop,
 	return 0;
 }
 
+static int
+process_openssl_ecfpm_op(struct rte_crypto_op *cop,
+		struct openssl_asym_session *sess)
+{
+	RTE_SET_USED(cop);
+	RTE_SET_USED(sess);
+	return -ENOTSUP;
+}
+
 static int
 process_openssl_sm2_op(struct rte_crypto_op *cop,
 		struct openssl_asym_session *sess)
@@ -3182,6 +3382,15 @@  process_openssl_sm2_op(struct rte_crypto_op *cop,
 	RTE_SET_USED(sess);
 	return -ENOTSUP;
 }
+
+static int
+process_openssl_eddsa_op(struct rte_crypto_op *cop,
+		struct openssl_asym_session *sess)
+{
+	RTE_SET_USED(cop);
+	RTE_SET_USED(sess);
+	return -ENOTSUP;
+}
 #endif
 
 static int
@@ -3230,6 +3439,13 @@  process_asym_op(struct openssl_qp *qp, struct rte_crypto_op *op,
 				process_openssl_dsa_verify_op(op, sess);
 		else
 			op->status = RTE_CRYPTO_OP_STATUS_INVALID_ARGS;
+#endif
+		break;
+	case RTE_CRYPTO_ASYM_XFORM_ECFPM:
+#if (OPENSSL_VERSION_NUMBER >= 0x30000000L)
+		retval = process_openssl_ecfpm_op_evp(op, sess);
+#else
+		retval = process_openssl_ecfpm_op(op, sess);
 #endif
 		break;
 	case RTE_CRYPTO_ASYM_XFORM_SM2:
@@ -3237,6 +3453,13 @@  process_asym_op(struct openssl_qp *qp, struct rte_crypto_op *op,
 		retval = process_openssl_sm2_op_evp(op, sess);
 #else
 		retval = process_openssl_sm2_op(op, sess);
+#endif
+		break;
+	case RTE_CRYPTO_ASYM_XFORM_EDDSA:
+#if (OPENSSL_VERSION_NUMBER >= 0x30000000L)
+		retval = process_openssl_eddsa_op_evp(op, sess);
+#else
+		retval = process_openssl_eddsa_op(op, sess);
 #endif
 		break;
 	default:
diff --git a/drivers/crypto/openssl/rte_openssl_pmd_ops.c b/drivers/crypto/openssl/rte_openssl_pmd_ops.c
index 1bbb855a59..bc41717e83 100644
--- a/drivers/crypto/openssl/rte_openssl_pmd_ops.c
+++ b/drivers/crypto/openssl/rte_openssl_pmd_ops.c
@@ -593,6 +593,16 @@  static const struct rte_cryptodev_capabilities openssl_pmd_capabilities[] = {
 		},
 		}
 	},
+	{	/* ECFPM */
+		.op = RTE_CRYPTO_OP_TYPE_ASYMMETRIC,
+		{.asym = {
+			.xform_capa = {
+				.xform_type = RTE_CRYPTO_ASYM_XFORM_ECFPM,
+				.op_types = 0
+				}
+			}
+		}
+	},
 	{	/* SM2 */
 		.op = RTE_CRYPTO_OP_TYPE_ASYMMETRIC,
 		{.asym = {
@@ -610,6 +620,20 @@  static const struct rte_cryptodev_capabilities openssl_pmd_capabilities[] = {
 		}
 		}
 	},
+	{	/* EDDSA */
+		.op = RTE_CRYPTO_OP_TYPE_ASYMMETRIC,
+		{.asym = {
+			.xform_capa = {
+				.xform_type = RTE_CRYPTO_ASYM_XFORM_EDDSA,
+				.hash_algos = (1 << RTE_CRYPTO_AUTH_SHA512 |
+					       1 << RTE_CRYPTO_AUTH_SHAKE_256),
+				.op_types =
+				((1<<RTE_CRYPTO_ASYM_OP_SIGN) |
+				 (1 << RTE_CRYPTO_ASYM_OP_VERIFY)),
+			}
+		}
+		}
+	},
 
 	RTE_CRYPTODEV_END_OF_CAPABILITIES_LIST()
 };
@@ -1356,6 +1380,47 @@  static int openssl_set_asym_session_parameters(
 		BN_free(pub_key);
 		return -1;
 	}
+	case RTE_CRYPTO_ASYM_XFORM_ECFPM:
+	{
+#if (OPENSSL_VERSION_NUMBER >= 0x30000000L)
+		EC_GROUP *ecgrp = NULL;
+
+		asym_session->xfrm_type = xform->xform_type;
+
+		switch (xform->ec.curve_id) {
+		case RTE_CRYPTO_EC_GROUP_SECP192R1:
+			ecgrp = EC_GROUP_new_by_curve_name(NID_secp192k1);
+			break;
+		case RTE_CRYPTO_EC_GROUP_SECP224R1:
+			ecgrp = EC_GROUP_new_by_curve_name(NID_secp224r1);
+			break;
+		case RTE_CRYPTO_EC_GROUP_SECP256R1:
+			ecgrp = EC_GROUP_new_by_curve_name(NID_secp256k1);
+			break;
+		case RTE_CRYPTO_EC_GROUP_SECP384R1:
+			ecgrp = EC_GROUP_new_by_curve_name(NID_secp384r1);
+			break;
+		case RTE_CRYPTO_EC_GROUP_SECP521R1:
+			ecgrp = EC_GROUP_new_by_curve_name(NID_secp521r1);
+			break;
+		case RTE_CRYPTO_EC_GROUP_ED25519:
+			ecgrp = EC_GROUP_new_by_curve_name(NID_ED25519);
+			break;
+		case RTE_CRYPTO_EC_GROUP_ED448:
+			ecgrp = EC_GROUP_new_by_curve_name(NID_ED448);
+			break;
+		default:
+			break;
+		}
+
+		asym_session->u.ec.curve_id = xform->ec.curve_id;
+		asym_session->u.ec.group = ecgrp;
+		break;
+#else
+		OPENSSL_LOG(WARNING, "ECFPM unsupported for OpenSSL Version < 3.0");
+		return -ENOTSUP;
+#endif
+	}
 	case RTE_CRYPTO_ASYM_XFORM_SM2:
 	{
 #if (OPENSSL_VERSION_NUMBER >= 0x30000000L)
@@ -1440,6 +1505,66 @@  static int openssl_set_asym_session_parameters(
 #else
 		OPENSSL_LOG(WARNING, "SM2 unsupported for OpenSSL Version < 3.0");
 		return -ENOTSUP;
+#endif
+	}
+	case RTE_CRYPTO_ASYM_XFORM_EDDSA:
+	{
+#if (OPENSSL_VERSION_NUMBER >= 0x30000000L)
+		OSSL_PARAM_BLD *param_bld = NULL;
+		OSSL_PARAM *params = NULL;
+		int ret = -1;
+
+		asym_session->u.eddsa.curve_id = xform->ec.curve_id;
+
+		param_bld = OSSL_PARAM_BLD_new();
+		if (!param_bld) {
+			OPENSSL_LOG(ERR, "failed to allocate params\n");
+			goto err_eddsa;
+		}
+
+		ret = OSSL_PARAM_BLD_push_utf8_string(param_bld,
+			  OSSL_PKEY_PARAM_GROUP_NAME, "ED25519", sizeof("ED25519"));
+		if (!ret) {
+			OPENSSL_LOG(ERR, "failed to push params\n");
+			goto err_eddsa;
+		}
+
+		ret = OSSL_PARAM_BLD_push_octet_string(param_bld, OSSL_PKEY_PARAM_PRIV_KEY,
+				xform->ec.pkey.data, xform->ec.pkey.length);
+		if (!ret) {
+			OPENSSL_LOG(ERR, "failed to push params\n");
+			goto err_eddsa;
+		}
+
+		ret = OSSL_PARAM_BLD_push_octet_string(param_bld, OSSL_PKEY_PARAM_PUB_KEY,
+				xform->ec.q.x.data, xform->ec.q.x.length);
+		if (!ret) {
+			OPENSSL_LOG(ERR, "failed to push params\n");
+			goto err_eddsa;
+		}
+
+		params = OSSL_PARAM_BLD_to_param(param_bld);
+		if (!params) {
+			OPENSSL_LOG(ERR, "failed to push params\n");
+			goto err_eddsa;
+		}
+
+		asym_session->u.eddsa.params = params;
+		OSSL_PARAM_BLD_free(param_bld);
+
+		asym_session->xfrm_type = RTE_CRYPTO_ASYM_XFORM_EDDSA;
+		break;
+err_eddsa:
+		if (param_bld)
+			OSSL_PARAM_BLD_free(param_bld);
+
+		if (asym_session->u.eddsa.params)
+			OSSL_PARAM_free(asym_session->u.eddsa.params);
+
+		return -1;
+#else
+		OPENSSL_LOG(WARNING, "EDDSA unsupported for OpenSSL Version < 3.0");
+		return -ENOTSUP;
 #endif
 	}
 	default:
@@ -1538,6 +1663,12 @@  static void openssl_reset_asym_session(struct openssl_asym_session *sess)
 #if (OPENSSL_VERSION_NUMBER >= 0x30000000L)
 		OSSL_PARAM_free(sess->u.sm2.params);
 #endif
+		break;
+	case RTE_CRYPTO_ASYM_XFORM_EDDSA:
+#if (OPENSSL_VERSION_NUMBER >= 0x30000000L)
+		OSSL_PARAM_free(sess->u.eddsa.params);
+#endif
+		break;
 	default:
 		break;
 	}