add SM2 sign function for openssl engine

Signed-off-by: wangyoukang <wangyoukang@xfusion.com>
This commit is contained in:
wangyoukang 2023-08-01 16:09:12 +08:00
parent 5ad629c747
commit 5c2ac1811c
2 changed files with 380 additions and 5 deletions

View File

@ -0,0 +1,369 @@
From a2d613ade54068d7ea44ecce9718023ca53eefde Mon Sep 17 00:00:00 2001
From: guowentao <guowentao@xfusion.com>
Date: Fri, 16 Jun 2023 11:39:29 +0800
Subject: [PATCH] add SM2 sign function for openssl engine
Signed-off-by: guowentao <guowentao@xfusion.com>
---
src/tpm2-tss-engine-common.h | 1 +
src/tpm2-tss-engine-ecc.c | 8 ++
src/tpm2-tss-engine-err.h | 1 +
src/tpm2-tss-engine-sm2.c | 241 +++++++++++++++++++++++++++++++++++
src/tpm2-tss-engine.c | 7 +-
5 files changed, 257 insertions(+), 1 deletion(-)
diff --git a/src/tpm2-tss-engine-common.h b/src/tpm2-tss-engine-common.h
index 14c98a0..e15e9bd 100755
--- a/src/tpm2-tss-engine-common.h
+++ b/src/tpm2-tss-engine-common.h
@@ -51,6 +51,7 @@ extern char *tcti_nameconf;
int init_ecc(ENGINE *e);
int init_rand(ENGINE *e);
int init_rsa(ENGINE *e);
+int init_sm2(ENGINE *e);
TSS2_RC esys_ctx_init (ESYS_CONTEXT **esys_ctx);
diff --git a/src/tpm2-tss-engine-ecc.c b/src/tpm2-tss-engine-ecc.c
index c1c5864..ec1882f 100644
--- a/src/tpm2-tss-engine-ecc.c
+++ b/src/tpm2-tss-engine-ecc.c
@@ -300,6 +300,9 @@ populate_ecc(EC_KEY *key)
case TPM2_ECC_NIST_P384:
nid = EC_curve_nist2nid("P-384");
break;
+ case TPM2_ECC_SM2_P256:
+ nid = NID_sm2;
+ break;
default:
nid = -1;
}
@@ -393,6 +396,11 @@ tpm2tss_ecc_makekey(TPM2_DATA *tpm2Data)
goto error;
}
+ if (!tpm2tss_sm2_setappdata(eckey, tpm2Data)) {
+ ERR(tpm2tss_ecc_makekey, TPM2TSS_R_GENERAL_FAILURE);
+ goto error;
+ }
+
if (!populate_ecc(eckey))
goto error;
diff --git a/src/tpm2-tss-engine-err.h b/src/tpm2-tss-engine-err.h
index e6a7219..f9e0513 100644
--- a/src/tpm2-tss-engine-err.h
+++ b/src/tpm2-tss-engine-err.h
@@ -98,6 +98,7 @@ void ERR_error(int function, int reason, const char *file, int line);
/* tpm2-tss-engine-rsa.c */
#define TPM2TSS_F_tpm2tss_sm2_genkey 144
#define TPM2TSS_F_populate_sm2 145
+#define TPM2TSS_F_tpm_pkey_sm2_sign 146
/* Reason codes */
#define TPM2TSS_R_TPM2DATA_READ_FAILED 100
diff --git a/src/tpm2-tss-engine-sm2.c b/src/tpm2-tss-engine-sm2.c
index 679b36c..8a3908f 100644
--- a/src/tpm2-tss-engine-sm2.c
+++ b/src/tpm2-tss-engine-sm2.c
@@ -43,6 +43,10 @@
static int ec_sm2_key_app_data = -1;
+static int (*sm2_pkey_orig_sign)(EVP_PKEY_CTX * ctx, unsigned char * sig, size_t * siglen, const unsigned char * tbs, size_t tbslen);
+static int (*sm2_pkey_orig_verify)(EVP_PKEY_CTX * ctx, const unsigned char * sig, size_t siglen, const unsigned char * tbs, size_t tbslen);
+static int (*sm2_pkey_orig_digest_custom)(EVP_PKEY_CTX *ctx, EVP_MD_CTX *mctx);
+
static TPM2B_DATA allOutsideInfo = {
.size = 0,
};
@@ -84,6 +88,181 @@ static TPM2B_PUBLIC keyEcTemplate = {
}
};
+static int
+tpm_pkey_sm2_sign(EVP_PKEY_CTX *ctx, unsigned char *sig, size_t *siglen,
+ const unsigned char *tbs, size_t tbslen)
+{
+ DBG("[%s][IN] ctx:%p sig:%p siglen:%ld tbs:%p tbslen:%ld\n", __func__, ctx, sig, *siglen, tbs, tbslen);
+ ECDSA_SIG *s = NULL;
+ int sigleni;
+ BIGNUM *bns = NULL, *bnr = NULL;
+
+ EVP_PKEY *pkey = EVP_PKEY_CTX_get0_pkey(ctx);
+ EC_KEY *eckey = EVP_PKEY_get0_EC_KEY(pkey);
+ const int sig_sz = ECDSA_size(eckey);
+ TPM2_DATA *tpm2Data = tpm2tss_sm2_getappdata(eckey);
+ TPM2_ALG_ID hash_alg;
+
+ /* If this is not a TPM2 key, fall through to software functions */
+ if (tpm2Data == NULL) {
+ DBG("origin sign funciton is called\n");
+ sm2_pkey_orig_sign(ctx, sig, siglen, tbs, tbslen);
+ }
+ DBG("tbs content (size=%ld):\n", tbslen);
+ DBGBUF(tbs, (int)tbslen);
+
+ TSS2_RC r = -1;
+ ESYS_CONTEXT *esys_ctx = NULL;
+ ESYS_TR keyHandle = ESYS_TR_NONE;
+ TPMT_SIGNATURE *sig_tpm = NULL;
+
+ TPMT_TK_HASHCHECK validation = { .tag = TPM2_ST_HASHCHECK,
+ .hierarchy = TPM2_RH_NULL,
+ .digest.size = 0 };
+
+ TPMT_SIG_SCHEME inScheme = { .scheme = TPM2_ALG_SM2 };
+
+ if (sig_sz <= 0) {
+ return 0;
+ }
+
+ if (sig == NULL) {
+ *siglen = (size_t)sig_sz;
+ DBG("siglen is %ld\n", *siglen);
+ return 1;
+ }
+
+ if (*siglen < (size_t)sig_sz) {
+ DBG("error:SM2_F_PKEY_SM2_SIGN, SM2_R_BUFFER_TOO_SMALL");
+ return 0;
+ }
+ /*
+ * ECDSA signatures truncate the incoming hash to fit the curve,
+ * and the signature mechanism is the same regardless of the
+ * hash being used.
+ *
+ * The TPM bizarrely wants to be told the hash algorithm, and
+ * either it or the TSS will validate that the digest length
+ * matches the hash that it's told, despite it having no business
+ * caring about such things.
+ *
+ * So, we can truncate the digest any pretend it's any smaller
+ * digest that the TPM actually does support, as long as that
+ * digest is larger than the size of the curve.
+ */
+ int curve_len = (EC_GROUP_order_bits(EC_KEY_get0_group(eckey)) + 7) / 8;
+ /* If we couldn't work it out, don't truncate */
+ if (!curve_len)
+ curve_len = tbslen;
+ if (tbslen == SHA256_DIGEST_LENGTH ||
+ (curve_len <= SHA256_DIGEST_LENGTH && tbslen > SHA256_DIGEST_LENGTH)) {
+ hash_alg = TPM2_ALG_SM3_256;
+ inScheme.details.ecdsa.hashAlg = hash_alg;
+ tbslen = SHA256_DIGEST_LENGTH;
+ } else {
+ ERR(tpm_pkey_sm2_sign, TPM2TSS_R_PADDING_UNKNOWN);
+ goto error;
+ }
+ DBG("hash alg is %d\n", hash_alg);
+ TPM2B_DIGEST digest = { .size = tbslen };
+ if (digest.size > sizeof(digest.buffer)) {
+ ERR(ecdsa_sign, TPM2TSS_R_DIGEST_TOO_LARGE);
+ goto error;
+ }
+ memcpy(&digest.buffer[0], tbs, tbslen);
+
+ r = init_tpm_key(&esys_ctx, &keyHandle, tpm2Data);
+ ERRchktss(tpm_pkey_sm2_sign, r, goto error);
+
+ r = Esys_Sign(esys_ctx, keyHandle,
+ ESYS_TR_PASSWORD, ESYS_TR_NONE, ESYS_TR_NONE,
+ &digest, &inScheme, &validation, &sig_tpm);
+ ERRchktss(tpm_pkey_sm2_sign, r, goto error);
+
+ s = ECDSA_SIG_new();
+ if (s == NULL) {
+ ERR(ecdsa_sign, ERR_R_MALLOC_FAILURE);
+ goto error;
+ }
+
+ bns = BN_bin2bn(&sig_tpm->signature.ecdsa.signatureS.buffer[0],
+ sig_tpm->signature.ecdsa.signatureS.size, NULL);
+ bnr = BN_bin2bn(&sig_tpm->signature.ecdsa.signatureR.buffer[0],
+ sig_tpm->signature.ecdsa.signatureR.size, NULL);
+ if (!bns || !bnr) {
+ ERR(tpm_pkey_sm2_sign, ERR_R_MALLOC_FAILURE);
+ goto error;
+ }
+
+ ECDSA_SIG_set0(s, bnr, bns);
+
+ #ifndef NDEBUG
+ unsigned char *sig_debug = sig;
+ #endif
+ sigleni = i2d_ECDSA_SIG(s, &sig);
+ if (sigleni < 0) {
+ ERR(tpm_pkey_sm2_sign, ERR_R_MALLOC_FAILURE);
+ goto error;
+ }
+ *siglen = (unsigned int)sigleni;
+ DBG("sig content (size=%ld):\n", *siglen);
+ DBGBUF(sig_debug, *siglen);
+ DBG("[%s][OUT] ctx:%p sig:%p siglen:%ld tbs:%p tbslen:%ld\n", __func__, ctx, sig, *siglen, tbs, tbslen);
+
+ goto out;
+error:
+ r = -1;
+out:
+ if (keyHandle != ESYS_TR_NONE) {
+ if (tpm2Data->privatetype == KEY_TYPE_HANDLE) {
+ Esys_TR_Close(esys_ctx, &keyHandle);
+ } else {
+ Esys_FlushContext(esys_ctx, keyHandle);
+ }
+ }
+ if (r != TSS2_RC_SUCCESS && s != NULL) {
+ if (bns)
+ BN_free(bns);
+ if (bnr)
+ BN_free(bnr);
+ }
+ if (r != TSS2_RC_SUCCESS) {
+ if (s)
+ ECDSA_SIG_free(s);
+ r = -1;
+ }
+
+ esys_ctx_free(&esys_ctx);
+ return (r == TSS2_RC_SUCCESS) ? 1 : r;
+}
+
+static int
+tpm_pkey_sm2_verify(EVP_PKEY_CTX * ctx, const unsigned char * sig, size_t siglen, const unsigned char * tbs, size_t tbslen)
+{
+ int ret = 0;
+ DBG("[%s] ctx:%p sig:%p siglen:%ld tbs:%p tbslen:%ld\n", __func__, ctx, sig, siglen, tbs, tbslen);
+ DBG("tbs content (size=%ld):\n", tbslen);
+ DBGBUF(tbs, (int)tbslen);
+ DBG("sig content (size=%ld):\n", siglen);
+ DBGBUF(sig, siglen);
+ if(sm2_pkey_orig_verify != NULL)
+ ret = sm2_pkey_orig_verify(ctx, sig, siglen, tbs, tbslen);
+ DBG("[%s] ret is %d\n", __func__, ret);
+ return ret;
+}
+
+/* called for digest & sign init, after message digest algorithm set */
+static int
+tpm_pkey_sm2_digest_custom(EVP_PKEY_CTX *ctx, EVP_MD_CTX *mctx)
+{
+ DBG("[%s] ctx:%p mctx:%p \n", __func__, ctx, mctx);
+ int ret = 0;
+ if(sm2_pkey_orig_digest_custom != NULL)
+ ret = sm2_pkey_orig_digest_custom(ctx, mctx);
+ DBG("[%s] ret is %d\n", __func__, ret);
+ return ret;
+}
+
/** Retrieve app data
*
* Since the ECC api (opposed to the RSA api) does not provide a standardized
@@ -96,6 +275,11 @@ static TPM2B_PUBLIC keyEcTemplate = {
TPM2_DATA *
tpm2tss_sm2_getappdata(EC_KEY *key)
{
+ if (ec_sm2_key_app_data == -1) {
+ DBG("Module uninitialized\n");
+ return NULL;
+ }
+
return EC_KEY_get_ex_data(key, ec_sm2_key_app_data);
}
@@ -112,6 +296,11 @@ tpm2tss_sm2_getappdata(EC_KEY *key)
int
tpm2tss_sm2_setappdata(EC_KEY *key, TPM2_DATA *tpm2Data)
{
+ if (ec_sm2_key_app_data == -1) {
+ DBG("Module uninitialized\n");
+ return 0;
+ }
+
return EC_KEY_set_ex_data(key, ec_sm2_key_app_data, tpm2Data);
}
@@ -182,6 +371,23 @@ populate_sm2(EC_KEY *key)
return 1;
}
+static void
+free_sm2_appdata(void *parent, void *ptr, CRYPTO_EX_DATA *ad, int idx,
+ long argl, void *argp)
+{
+ TPM2_DATA *tpm2Data = ptr;
+
+ (void)parent;
+ (void)ad;
+ (void)idx;
+ (void)argl;
+ (void)argp;
+
+ if (!ptr)
+ return;
+
+ OPENSSL_free(tpm2Data);
+}
/** Generate a tpm2tss sm2 key object.
*
@@ -287,3 +493,38 @@ tpm2tss_sm2_genkey(EC_KEY *key, TPMI_ECC_CURVE curve, const char *password,
return (r == TSS2_RC_SUCCESS);
}
+int
+init_sm2(ENGINE *e)
+{
+ (void)(e);
+
+ if (ec_sm2_key_app_data == -1)
+ ec_sm2_key_app_data = EC_KEY_get_ex_new_index(0, NULL, NULL, NULL, free_sm2_appdata);
+
+ EVP_PKEY_METHOD *pkey_sm2_methods;
+
+ pkey_sm2_methods = EVP_PKEY_meth_new(EVP_PKEY_SM2, 0);
+ if (pkey_sm2_methods == NULL)
+ return 0;
+
+ const EVP_PKEY_METHOD *pkey_orig_sm2_methods =
+ EVP_PKEY_meth_find(EVP_PKEY_SM2);
+ if (pkey_orig_sm2_methods == NULL)
+ return 0;
+ EVP_PKEY_meth_copy(pkey_sm2_methods, pkey_orig_sm2_methods);
+ /*
+ * save originals since we only override some of the pkey
+ * functionality, rather than reimplementing all of it
+ */
+ EVP_PKEY_meth_get_sign(pkey_sm2_methods, NULL, &sm2_pkey_orig_sign);
+ EVP_PKEY_meth_get_verify(pkey_sm2_methods, NULL, &sm2_pkey_orig_verify);
+ EVP_PKEY_meth_get_digest_custom((EVP_PKEY_METHOD *)pkey_orig_sm2_methods, &sm2_pkey_orig_digest_custom);
+
+ EVP_PKEY_meth_set_sign(pkey_sm2_methods, NULL, tpm_pkey_sm2_sign);
+ EVP_PKEY_meth_set_verify(pkey_sm2_methods, NULL, tpm_pkey_sm2_verify);
+ EVP_PKEY_meth_set_digest_custom(pkey_sm2_methods, tpm_pkey_sm2_digest_custom);
+ EVP_PKEY_meth_add0(pkey_sm2_methods);
+
+ return 1;
+}
+
diff --git a/src/tpm2-tss-engine.c b/src/tpm2-tss-engine.c
index 824f538..8a5fb52 100644
--- a/src/tpm2-tss-engine.c
+++ b/src/tpm2-tss-engine.c
@@ -293,7 +293,12 @@ init_engine(ENGINE *e) {
ERR(init_engine, TPM2TSS_R_SUBINIT_FAILED);
return rc;
}
-
+
+ rc = init_sm2(e);
+ if (rc != 1) {
+ ERR(init_engine, TPM2TSS_R_SUBINIT_FAILED);
+ return rc;
+ }
initialized = 1;
return 1;
}
--
2.27.0

View File

@ -1,6 +1,6 @@
Name: tpm2-tss-engine Name: tpm2-tss-engine
Version: 1.1.0 Version: 1.1.0
Release: 1.u2 Release: 1.u3
Summary: OpenSSL Engine for TPM2 devices using the tpm2-tss software stack Summary: OpenSSL Engine for TPM2 devices using the tpm2-tss software stack
License: BSD License: BSD
@ -9,6 +9,7 @@ Source0: https://github.com/tpm2-software/tpm2-tss-engine/releases/downlo
Patch10001: 0001-add-bootstrap-for-source-code-compilation.patch Patch10001: 0001-add-bootstrap-for-source-code-compilation.patch
Patch10002: 0002-add-SM2-genkey-function.patch Patch10002: 0002-add-SM2-genkey-function.patch
Patch10003: 0003-add-SM2-sign-function-for-openssl-engine.patch
BuildRequires: make BuildRequires: make
BuildRequires: autoconf BuildRequires: autoconf
@ -85,13 +86,18 @@ uses the tpm2-tss software stack
%changelog %changelog
* Tue Aug 1 2023 wangyoukang<wangyoukang@xfusio.com> - 1.1.0-1.u2 * Tue Aug 1 2023 wangyoukang<wangyoukang@xfusion.com> - 1.1.0-1.u3
- Type:bugfix - Type:req
- CVE:
- DESC: add SM2 sign function for openssl engine
* Tue Aug 1 2023 wangyoukang<wangyoukang@xfusion.com> - 1.1.0-1.u2
- Type:req
- CVE: - CVE:
- DESC: add SM2 genkey function - DESC: add SM2 genkey function
* Tue Aug 1 2023 wangyoukang<wangyoukang@xfusio.com> - 1.1.0-1.u1 * Tue Aug 1 2023 wangyoukang<wangyoukang@xfusion.com> - 1.1.0-1.u1
- Type:bugfix - Type:req
- CVE: - CVE:
- DESC: add bootstratp for source code compilation - DESC: add bootstratp for source code compilation