From 43e9a26a1fe0cb7d67d47d68441e0438101395e9 Mon Sep 17 00:00:00 2001 From: wangyoukang Date: Tue, 1 Aug 2023 15:56:19 +0800 Subject: [PATCH] add SM2 sign function for openssl engine Signed-off-by: wangyoukang --- ...SM2-sign-function-for-openssl-engine.patch | 369 ++++++++++++++++++ tpm2-tss-engine.spec | 8 +- 2 files changed, 376 insertions(+), 1 deletion(-) create mode 100644 0003-add-SM2-sign-function-for-openssl-engine.patch diff --git a/0003-add-SM2-sign-function-for-openssl-engine.patch b/0003-add-SM2-sign-function-for-openssl-engine.patch new file mode 100644 index 0000000..12b89e5 --- /dev/null +++ b/0003-add-SM2-sign-function-for-openssl-engine.patch @@ -0,0 +1,369 @@ +From a2d613ade54068d7ea44ecce9718023ca53eefde Mon Sep 17 00:00:00 2001 +From: guowentao +Date: Fri, 16 Jun 2023 11:39:29 +0800 +Subject: [PATCH] add SM2 sign function for openssl engine + +Signed-off-by: guowentao +--- + 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 + diff --git a/tpm2-tss-engine.spec b/tpm2-tss-engine.spec index 0ddc106..455cfe3 100644 --- a/tpm2-tss-engine.spec +++ b/tpm2-tss-engine.spec @@ -1,6 +1,6 @@ Name: tpm2-tss-engine Version: 1.1.0 -Release: 1.u2 +Release: 1.u3 Summary: OpenSSL Engine for TPM2 devices using the tpm2-tss software stack 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 Patch10002: 0002-add-SM2-genkey-function.patch +Patch10003: 0003-add-SM2-sign-function-for-openssl-engine.patch BuildRequires: make BuildRequires: autoconf @@ -85,6 +86,11 @@ uses the tpm2-tss software stack %changelog +* Tue Aug 1 2023 wangyoukang - 1.1.0-1.u3 +- Type:bugfix +- CVE: +- DESC: add SM2 sign function for openssl engine + * Tue Aug 1 2023 wangyoukang - 1.1.0-1.u2 - Type:bugfix - CVE: -- Gitee