Add SM2 asymmetric algorithm support in openssl PMD. Signed-off-by: Gowrishankar Muthukrishnan <gmuthukri...@marvell.com> --- doc/guides/cryptodevs/features/openssl.ini | 1 + doc/guides/cryptodevs/openssl.rst | 1 + doc/guides/rel_notes/release_23_07.rst | 4 + drivers/crypto/openssl/openssl_pmd_private.h | 7 + drivers/crypto/openssl/rte_openssl_pmd.c | 245 +++++++++++++++++++ drivers/crypto/openssl/rte_openssl_pmd_ops.c | 101 ++++++++ 6 files changed, 359 insertions(+)
diff --git a/doc/guides/cryptodevs/features/openssl.ini b/doc/guides/cryptodevs/features/openssl.ini index 4b0f9b162e..b64c8ec4a5 100644 --- a/doc/guides/cryptodevs/features/openssl.ini +++ b/doc/guides/cryptodevs/features/openssl.ini @@ -65,6 +65,7 @@ DSA = Y Modular Exponentiation = Y Modular Inversion = Y Diffie-hellman = Y +SM2 = Y ; ; Supported Operating systems of the 'openssl' crypto driver. diff --git a/doc/guides/cryptodevs/openssl.rst b/doc/guides/cryptodevs/openssl.rst index 03041ceda1..ff21d21b23 100644 --- a/doc/guides/cryptodevs/openssl.rst +++ b/doc/guides/cryptodevs/openssl.rst @@ -53,6 +53,7 @@ Supported Asymmetric Crypto algorithms: * ``RTE_CRYPTO_ASYM_XFORM_DH`` * ``RTE_CRYPTO_ASYM_XFORM_MODINV`` * ``RTE_CRYPTO_ASYM_XFORM_MODEX`` +* ``RTE_CRYPTO_ASYM_XFORM_SM2`` Installation diff --git a/doc/guides/rel_notes/release_23_07.rst b/doc/guides/rel_notes/release_23_07.rst index b920840038..8868b0bb32 100644 --- a/doc/guides/rel_notes/release_23_07.rst +++ b/doc/guides/rel_notes/release_23_07.rst @@ -59,6 +59,10 @@ New Features Added SM2 algorithm with prime field curve support. +* **Updated OpenSSL crypto driver for SM2 support.** + + Added SM2 algorithm support in asymmetric crypto operations. + Removed Items ------------- diff --git a/drivers/crypto/openssl/openssl_pmd_private.h b/drivers/crypto/openssl/openssl_pmd_private.h index ed6841e460..d7990c8333 100644 --- a/drivers/crypto/openssl/openssl_pmd_private.h +++ b/drivers/crypto/openssl/openssl_pmd_private.h @@ -12,6 +12,7 @@ #include <openssl/rsa.h> #include <openssl/dh.h> #include <openssl/dsa.h> +#include <openssl/ec.h> #if (OPENSSL_VERSION_NUMBER >= 0x30000000L) #include <openssl/provider.h> #include <openssl/core_names.h> @@ -200,6 +201,12 @@ struct openssl_asym_session { OSSL_PARAM_BLD * param_bld; #endif } s; + struct { +#if (OPENSSL_VERSION_NUMBER >= 0x30000000L) + OSSL_PARAM *key_params; + OSSL_PARAM *enc_params; +#endif + } sm2; } u; } __rte_cache_aligned; /** 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 384d262621..25feb88ac3 100644 --- a/drivers/crypto/openssl/rte_openssl_pmd.c +++ b/drivers/crypto/openssl/rte_openssl_pmd.c @@ -13,6 +13,7 @@ #include <openssl/cmac.h> #include <openssl/hmac.h> #include <openssl/evp.h> +#include <openssl/ec.h> #include "openssl_pmd_private.h" #include "compat.h" @@ -2662,6 +2663,234 @@ process_openssl_rsa_op_evp(struct rte_crypto_op *cop, return ret; } + +static int +process_openssl_sm2_op_evp(struct rte_crypto_op *cop, + struct openssl_asym_session *sess) +{ + EVP_PKEY_CTX *kctx = NULL, *sctx = NULL, *cctx = NULL; + OSSL_PARAM *kparams = sess->u.sm2.key_params; + struct rte_crypto_asym_op *op = cop->asym; + EVP_PKEY *pkey = NULL; + int ret = -1; + + cop->status = RTE_CRYPTO_OP_STATUS_ERROR; + + if (!kparams) + return ret; + + switch (op->sm2.op_type) { + case RTE_CRYPTO_ASYM_OP_ENCRYPT: + { + OSSL_PARAM *eparams = sess->u.sm2.enc_params; + size_t output_len; + + kctx = EVP_PKEY_CTX_new_id(EVP_PKEY_SM2, NULL); + if (kctx == NULL || EVP_PKEY_fromdata_init(kctx) <= 0 || + EVP_PKEY_fromdata(kctx, &pkey, EVP_PKEY_KEYPAIR, kparams) <= 0) + goto err_sm2; + + cctx = EVP_PKEY_CTX_new_from_pkey(NULL, pkey, NULL); + if (!cctx) + goto err_sm2; + + if (!EVP_PKEY_encrypt_init(cctx)) + goto err_sm2; + + if (!EVP_PKEY_CTX_set_params(cctx, eparams)) + goto err_sm2; + + if (!EVP_PKEY_encrypt(cctx, op->sm2.cipher.data, &output_len, + op->sm2.message.data, + op->sm2.message.length)) + goto err_sm2; + op->sm2.cipher.length = output_len; + } + break; + case RTE_CRYPTO_ASYM_OP_DECRYPT: + { + OSSL_PARAM *eparams = sess->u.sm2.enc_params; + + kctx = EVP_PKEY_CTX_new_id(EVP_PKEY_SM2, NULL); + if (kctx == NULL + || EVP_PKEY_fromdata_init(kctx) <= 0 + || EVP_PKEY_fromdata(kctx, &pkey, EVP_PKEY_KEYPAIR, kparams) <= 0) + goto err_sm2; + + cctx = EVP_PKEY_CTX_new_from_pkey(NULL, pkey, NULL); + if (!cctx) + goto err_sm2; + + if (!EVP_PKEY_decrypt_init(cctx)) + goto err_sm2; + + if (!EVP_PKEY_CTX_set_params(cctx, eparams)) + goto err_sm2; + + if (!EVP_PKEY_decrypt(cctx, op->sm2.message.data, &op->sm2.message.length, + op->sm2.cipher.data, op->sm2.cipher.length)) + goto err_sm2; + } + break; + case RTE_CRYPTO_ASYM_OP_SIGN: + { + unsigned char signbuf[128] = {0}; + const unsigned char *signptr = signbuf; + EVP_MD_CTX *md_ctx = NULL; + const BIGNUM *r, *s; + ECDSA_SIG *ec_sign; + EVP_MD *check_md; + size_t signlen; + + kctx = EVP_PKEY_CTX_new_from_name(NULL, "SM2", NULL); + if (kctx == NULL || EVP_PKEY_fromdata_init(kctx) <= 0 || + EVP_PKEY_fromdata(kctx, &pkey, EVP_PKEY_KEYPAIR, kparams) <= 0) + goto err_sm2; + + md_ctx = EVP_MD_CTX_new(); + if (!md_ctx) + goto err_sm2; + + sctx = EVP_PKEY_CTX_new_from_pkey(NULL, pkey, NULL); + if (!sctx) + goto err_sm2; + + EVP_MD_CTX_set_pkey_ctx(md_ctx, sctx); + + check_md = EVP_MD_fetch(NULL, "sm3", NULL); + if (!check_md) + goto err_sm2; + + if (!EVP_DigestSignInit(md_ctx, NULL, check_md, NULL, pkey)) + goto err_sm2; + + if (EVP_PKEY_CTX_set1_id(sctx, op->sm2.id.data, op->sm2.id.length) <= 0) + goto err_sm2; + + if (!EVP_DigestSignUpdate(md_ctx, op->sm2.message.data, + op->sm2.message.length)) + goto err_sm2; + + if (!EVP_DigestSignFinal(md_ctx, NULL, &signlen)) + goto err_sm2; + + if (!EVP_DigestSignFinal(md_ctx, signbuf, &signlen)) + goto err_sm2; + + ec_sign = d2i_ECDSA_SIG(NULL, &signptr, signlen); + if (!ec_sign) + goto err_sm2; + + r = ECDSA_SIG_get0_r(ec_sign); + s = ECDSA_SIG_get0_s(ec_sign); + if (!r || !s) + goto err_sm2; + + op->sm2.r.length = BN_num_bytes(r); + op->sm2.s.length = BN_num_bytes(s); + BN_bn2bin(r, op->sm2.r.data); + BN_bn2bin(s, op->sm2.s.data); + + ECDSA_SIG_free(ec_sign); + } + break; + case RTE_CRYPTO_ASYM_OP_VERIFY: + { + unsigned char signbuf[128] = {0}; + EVP_MD_CTX *md_ctx = NULL; + BIGNUM *r = NULL, *s = NULL; + ECDSA_SIG *ec_sign; + EVP_MD *check_md; + size_t signlen; + + kctx = EVP_PKEY_CTX_new_from_name(NULL, "SM2", NULL); + if (kctx == NULL || EVP_PKEY_fromdata_init(kctx) <= 0 || + EVP_PKEY_fromdata(kctx, &pkey, EVP_PKEY_PUBLIC_KEY, kparams) <= 0) + goto err_sm2; + + if (!EVP_PKEY_is_a(pkey, "SM2")) + goto err_sm2; + + md_ctx = EVP_MD_CTX_new(); + if (!md_ctx) + goto err_sm2; + + sctx = EVP_PKEY_CTX_new_from_pkey(NULL, pkey, NULL); + if (!sctx) + goto err_sm2; + + EVP_MD_CTX_set_pkey_ctx(md_ctx, sctx); + + check_md = EVP_MD_fetch(NULL, "sm3", NULL); + if (!check_md) + goto err_sm2; + + if (!EVP_DigestVerifyInit(md_ctx, NULL, check_md, NULL, pkey)) + goto err_sm2; + + if (EVP_PKEY_CTX_set1_id(sctx, op->sm2.id.data, op->sm2.id.length) <= 0) + goto err_sm2; + + if (!EVP_DigestVerifyUpdate(md_ctx, op->sm2.message.data, + op->sm2.message.length)) + goto err_sm2; + + ec_sign = ECDSA_SIG_new(); + if (!ec_sign) + goto err_sm2; + + r = BN_bin2bn(op->sm2.r.data, op->sm2.r.length, r); + s = BN_bin2bn(op->sm2.s.data, op->sm2.s.length, s); + if (!r || !s) + goto err_sm2; + + if (!ECDSA_SIG_set0(ec_sign, r, s)) { + BN_free(r); + BN_free(s); + goto err_sm2; + } + + r = NULL; + s = NULL; + + signlen = i2d_ECDSA_SIG(ec_sign, (unsigned char **)&signbuf); + if (signlen <= 0) + goto err_sm2; + + if (!EVP_DigestVerifyFinal(md_ctx, signbuf, signlen)) + goto err_sm2; + + BN_free(r); + BN_free(s); + ECDSA_SIG_free(ec_sign); + } + break; + default: + /* allow ops with invalid args to be pushed to + * completion queue + */ + cop->status = RTE_CRYPTO_OP_STATUS_INVALID_ARGS; + goto err_sm2; + } + + ret = 0; + cop->status = RTE_CRYPTO_OP_STATUS_SUCCESS; +err_sm2: + if (kctx) + EVP_PKEY_CTX_free(kctx); + + 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, @@ -2761,6 +2990,15 @@ process_openssl_rsa_op(struct rte_crypto_op *cop, return 0; } + +static int +process_openssl_sm2_op(struct rte_crypto_op *cop, + struct openssl_asym_session *sess) +{ + RTE_SET_USED(cop); + RTE_SET_USED(sess); + return -ENOTSUP; +} #endif static int @@ -2809,6 +3047,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_SM2: +#if (OPENSSL_VERSION_NUMBER >= 0x30000000L) + retval = process_openssl_sm2_op_evp(op, sess); +#else + retval = process_openssl_sm2_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 29ad1b9505..7a1e1e8e8c 100644 --- a/drivers/crypto/openssl/rte_openssl_pmd_ops.c +++ b/drivers/crypto/openssl/rte_openssl_pmd_ops.c @@ -1282,6 +1282,102 @@ static int openssl_set_asym_session_parameters( BN_free(pub_key); return -1; } + case RTE_CRYPTO_ASYM_XFORM_SM2: + { +#if (OPENSSL_VERSION_NUMBER >= 0x30000000L) + OSSL_PARAM_BLD *param_bld = NULL; + OSSL_PARAM *params = NULL; + BIGNUM *pkey = NULL; + uint8_t pubkey[64]; + size_t len = 0; + int ret = -1; + + pkey = BN_bin2bn((const unsigned char *)xform->sm2.pkey.data, + xform->sm2.pkey.length, pkey); + + memset(pubkey, 0, RTE_DIM(pubkey)); + pubkey[0] = 0x04; + len += 1; + memcpy(&pubkey[len], xform->sm2.q.x.data, xform->sm2.q.x.length); + len += xform->sm2.q.x.length; + memcpy(&pubkey[len], xform->sm2.q.y.data, xform->sm2.q.y.length); + len += xform->sm2.q.y.length; + + param_bld = OSSL_PARAM_BLD_new(); + if (!param_bld) { + OPENSSL_LOG(ERR, "failed to allocate params\n"); + goto err_sm2; + } + + ret = OSSL_PARAM_BLD_push_utf8_string(param_bld, + OSSL_PKEY_PARAM_GROUP_NAME, "SM2", 0); + if (!ret) { + OPENSSL_LOG(ERR, "failed to push params\n"); + goto err_sm2; + } + + ret = OSSL_PARAM_BLD_push_BN(param_bld, OSSL_PKEY_PARAM_PRIV_KEY, pkey); + if (!ret) { + OPENSSL_LOG(ERR, "failed to push params\n"); + goto err_sm2; + } + + ret = OSSL_PARAM_BLD_push_octet_string(param_bld, OSSL_PKEY_PARAM_PUB_KEY, + pubkey, len); + if (!ret) { + OPENSSL_LOG(ERR, "failed to push params\n"); + goto err_sm2; + } + + params = OSSL_PARAM_BLD_to_param(param_bld); + if (!params) { + OPENSSL_LOG(ERR, "failed to push params\n"); + goto err_sm2; + } + + asym_session->u.sm2.key_params = params; + OSSL_PARAM_BLD_free(param_bld); + + param_bld = OSSL_PARAM_BLD_new(); + if (!param_bld) { + OPENSSL_LOG(ERR, "failed to allocate params\n"); + goto err_sm2; + } + + ret = OSSL_PARAM_BLD_push_utf8_string(param_bld, + OSSL_ASYM_CIPHER_PARAM_DIGEST, "SM3", 0); + if (!ret) { + OPENSSL_LOG(ERR, "failed to push params\n"); + goto err_sm2; + } + + params = OSSL_PARAM_BLD_to_param(param_bld); + if (!params) { + OPENSSL_LOG(ERR, "failed to h params\n"); + goto err_sm2; + } + + asym_session->u.sm2.enc_params = params; + OSSL_PARAM_BLD_free(param_bld); + + asym_session->xfrm_type = RTE_CRYPTO_ASYM_XFORM_SM2; + break; +err_sm2: + if (pkey) + BN_free(pkey); + + if (param_bld) + OSSL_PARAM_BLD_free(param_bld); + + if (asym_session->u.sm2.key_params) + OSSL_PARAM_free(asym_session->u.sm2.key_params); + + if (asym_session->u.sm2.enc_params) + OSSL_PARAM_free(asym_session->u.sm2.enc_params); + + return -1; +#endif + } default: return ret; } @@ -1366,6 +1462,11 @@ static void openssl_reset_asym_session(struct openssl_asym_session *sess) DSA_free(sess->u.s.dsa); #endif break; + case RTE_CRYPTO_ASYM_XFORM_SM2: +#if (OPENSSL_VERSION_NUMBER >= 0x30000000L) + OSSL_PARAM_free(sess->u.sm2.key_params); + OSSL_PARAM_free(sess->u.sm2.enc_params); +#endif default: break; } -- 2.25.1