370 lines
11 KiB
Diff
370 lines
11 KiB
Diff
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
|
|
|