From ce3616804b84ce30563a3e1cb03d1878c6b31355 Mon Sep 17 00:00:00 2001
From: fly2x <fly2x@hitls.org>
Date: Thu, 14 Dec 2023 19:55:14 +0800
Subject: [PATCH] tpm2 add SM3 and SM4 support

---
 configure.ac                            |  10 ++
 src/tpm2/AlgorithmTests.c               |   7 +-
 src/tpm2/HashTestData.h                 |   9 ++
 src/tpm2/Marshal.c                      |   9 ++
 src/tpm2/Marshal_fp.h                   |   4 +
 src/tpm2/NVMarshal.c                    | 141 ++++++++++++++++++++++++
 src/tpm2/SymmetricTest.h                |   4 +-
 src/tpm2/SymmetricTestData.h            |  45 ++++++++
 src/tpm2/Unmarshal_fp.h                 |   4 +
 src/tpm2/crypto/CryptHash.h             |   3 +
 src/tpm2/crypto/CryptSym.h              |   5 +
 src/tpm2/crypto/openssl/CryptCmac.c     |  10 ++
 src/tpm2/crypto/openssl/CryptHash.c     |   8 ++
 src/tpm2/crypto/openssl/CryptSym.c      |  18 +++
 src/tpm2/crypto/openssl/Helpers.c       | 127 ++++++++++++++++++++-
 src/tpm2/crypto/openssl/TpmToOsslHash.h |  41 ++++++-
 src/tpm2/crypto/openssl/TpmToOsslSym.h  |  40 ++++++-
 17 files changed, 474 insertions(+), 11 deletions(-)

diff --git a/configure.ac b/configure.ac
index 0c57ef3..e85c5fa 100644
--- a/configure.ac
+++ b/configure.ac
@@ -237,6 +237,15 @@ AC_ARG_ENABLE([test-coverage],
   AS_HELP_STRING([--enable-test-coverage], [Enable test coverage flags]),
   [COVERAGE_CFLAGS="-fprofile-arcs -ftest-coverage" COVERAGE_LDFLAGS="-fprofile-arcs"])
 
+AC_ARG_WITH([openssl-SM],
+    AS_HELP_STRING([--with-openssl-SM], [libtpms supports SM3 and SM4, default not support]), [with_openssl_SM=yes], [with_openssl_SM=no]
+)
+
+AS_IF([test "x$with_openssl_SM" != "xno"], [
+	AC_DEFINE([ALG_SM3_256], [1], [1 denotes to support SM3, and 0 not support])
+	AC_DEFINE([ALG_SM4], [1], [1 denotes to support SM4, and 0 not support])
+])
+
 LT_INIT
 AC_PROG_CC
 AC_PROG_CXX
@@ -316,6 +325,7 @@ echo "Version to build        : $PACKAGE_VERSION"
 echo "Crypto library          : $cryptolib"
 echo "Debug build             : $enable_debug"
 echo "With TPM2 support       : $with_tpm2"
+echo "With SM3 and SM4 support: $with_openssl_SM"
 echo "HAVE_VERSION_SCRIPT     : $have_version_script"
 echo "Use openssl crypto for  : $use_openssl_functions_for"
 echo
diff --git a/src/tpm2/AlgorithmTests.c b/src/tpm2/AlgorithmTests.c
index d30c6f8..8749ec2 100644
--- a/src/tpm2/AlgorithmTests.c
+++ b/src/tpm2/AlgorithmTests.c
@@ -860,7 +860,7 @@ TestAlgorithm(
 #if ALG_SM4
 		    // if SM4 is implemented, its test is like other block ciphers but there
 		    // aren't any test vectors for it yet
-		    //            case ALG_SM4_VALUE:
+		    case ALG_SM4_VALUE: /* libtpms changed */
 #endif
 #if ALG_CAMELLIA
 		    // no test vectors for camellia
@@ -925,10 +925,9 @@ TestAlgorithm(
 #if ALG_SHA512
 		  case ALG_SHA512_VALUE:
 #endif // TPM_ALG_SHA512
-		    // if SM3 is implemented its test is like any other hash, but there
-		    // aren't any test vectors yet.
+
 #if ALG_SM3_256
-		    //            case ALG_SM3_256_VALUE:
+		  case ALG_SM3_256_VALUE: /* libtpms changed */
 #endif // TPM_ALG_SM3_256
 		    if(doTest)
 			result = TestHash(alg, toTest);
diff --git a/src/tpm2/HashTestData.h b/src/tpm2/HashTestData.h
index d13843a..604fd43 100644
--- a/src/tpm2/HashTestData.h
+++ b/src/tpm2/HashTestData.h
@@ -127,6 +127,15 @@ TPM2B_SHA512    c_SHA512_digest = {{64, {
 	}}};
 #endif
 
+// libtpms added begin
+#if ALG_SM3_256 == YES
+TPM2B_TYPE(SM3_256, 32);
+TPM2B_SM3_256 c_SM3_256_digest = {{32, {
+        0xbb,0x9e,0x23,0x79,0xfe,0xbb,0xf8,0xb0,0x1d,0x27,0x5f,0x30,0x71,0xbe,0xce,0x8a,
+        0xb7,0x3f,0xee,0x6b,0xed,0xd7,0xee,0x45,0x4f,0x80,0xca,0x70,0x6c,0x09,0xb6,0x1a
+    }}};
+#endif
+// libtpms added end
 // libtpms added begin
 #if ALG_CMAC
 TPM2B_TYPE(AES128, 16);
diff --git a/src/tpm2/Marshal.c b/src/tpm2/Marshal.c
index 39e69e4..aae9a4f 100644
--- a/src/tpm2/Marshal.c
+++ b/src/tpm2/Marshal.c
@@ -1135,6 +1135,15 @@ TPMI_TDES_KEY_BITS_Marshal(TPMI_TDES_KEY_BITS *source, BYTE **buffer, INT32 *siz
     return written;
 }			// libtpms added end
 
+#if ALG_SM4 // libtpms added begin
+UINT16
+TPMI_SM4_KEY_BITS_Marshal(TPMI_TDES_KEY_BITS *source, BYTE **buffer, INT32 *size)
+{
+    UINT16 written = 0;
+    written += TPM_KEY_BITS_Marshal(source, buffer, size);
+    return written;
+}
+#endif			// libtpms added end
 /* Table 2:128 - Definition of TPMU_SYM_KEY_BITS Union (StructuresTable()) */
 
 UINT16
diff --git a/src/tpm2/Marshal_fp.h b/src/tpm2/Marshal_fp.h
index 582cc9e..f02ff37 100644
--- a/src/tpm2/Marshal_fp.h
+++ b/src/tpm2/Marshal_fp.h
@@ -228,6 +228,10 @@ extern "C" {
     TPM2B_ATTEST_Marshal(TPM2B_ATTEST *source, BYTE **buffer, INT32 *size);
     UINT16
     TPMI_AES_KEY_BITS_Marshal(TPMI_AES_KEY_BITS *source, BYTE **buffer, INT32 *size);
+#if ALG_SM4
+    UINT16
+    TPMI_SM4_KEY_BITS_Marshal(TPMI_AES_KEY_BITS *source, BYTE **buffer, INT32 *size);
+#endif
     UINT16
     TPMU_SYM_KEY_BITS_Marshal(TPMU_SYM_KEY_BITS *source, BYTE **buffer, INT32 *size, UINT32 selector);
     UINT16
diff --git a/src/tpm2/NVMarshal.c b/src/tpm2/NVMarshal.c
index 40be17e..d67f5b4 100644
--- a/src/tpm2/NVMarshal.c
+++ b/src/tpm2/NVMarshal.c
@@ -1970,6 +1970,135 @@ skip_future_versions:
 }
 #endif
 
+#if ALG_SM3_256
+
+#define HASH_STATE_SM3_256_MAGIC 0x10854a09
+#define HASH_STATE_SM3_256_VERSION 2
+
+static UINT16
+tpmHashStateSM3_256_Marshal(tpmHashStateSM3_256_t *data, BYTE **buffer, INT32 *size,
+                           UINT16 hashAlg)
+{
+    UINT16 written = 0;
+    UINT16 array_size;
+    SM3_CTX *sm3_ctx = NULL;
+    BLOCK_SKIP_INIT;
+
+    sm3_ctx = EVP_MD_CTX_md_data(*data);
+    written = NV_HEADER_Marshal(buffer, size,
+                                HASH_STATE_SM3_256_VERSION,
+                                HASH_STATE_SM3_256_MAGIC, 1);
+    written += UINT32_Marshal(&sm3_ctx->A, buffer, size);
+    written += UINT32_Marshal(&sm3_ctx->B, buffer, size);
+    written += UINT32_Marshal(&sm3_ctx->C, buffer, size);
+    written += UINT32_Marshal(&sm3_ctx->D, buffer, size);
+    written += UINT32_Marshal(&sm3_ctx->E, buffer, size);
+    written += UINT32_Marshal(&sm3_ctx->F, buffer, size);
+    written += UINT32_Marshal(&sm3_ctx->G, buffer, size);
+    written += UINT32_Marshal(&sm3_ctx->H, buffer, size);
+    written += UINT32_Marshal(&sm3_ctx->Nl, buffer, size);
+    written += UINT32_Marshal(&sm3_ctx->Nh, buffer, size);
+    /* data must be written as array */
+    array_size = sizeof(sm3_ctx->data);
+    written += UINT16_Marshal(&array_size, buffer, size);
+    written += Array_Marshal((BYTE *)&sm3_ctx->data[0], array_size, buffer, size);
+    written += UINT32_Marshal(&sm3_ctx->num, buffer, size);
+    written += BLOCK_SKIP_WRITE_PUSH(TRUE, buffer, size);
+    /* future versions append below this line */
+
+    BLOCK_SKIP_WRITE_POP(size);
+
+    BLOCK_SKIP_WRITE_CHECK;
+
+    return written;
+}
+
+static UINT16
+tpmHashStateSM3_256_Unmarshal(tpmHashStateSM3_256_t *data, BYTE **buffer, INT32 *size,
+                             UINT16 hashAlg)
+{
+    UINT16 rc = TPM_RC_SUCCESS;
+    UINT16 array_size;
+    NV_HEADER hdr;
+    SM3_CTX *sm3_ctx = NULL;
+
+    (*data) = EVP_MD_CTX_new();
+    if ((*data) == NULL) {
+        rc = TPM_RC_FAILURE;
+    }
+    if (rc == TPM_RC_SUCCESS) {
+        EVP_DigestInit_ex(*data, EVP_sm3(), NULL);
+        sm3_ctx = EVP_MD_CTX_md_data(*data);
+    }
+
+    if (rc == TPM_RC_SUCCESS) {
+        rc = NV_HEADER_Unmarshal(&hdr, buffer, size,
+                                 HASH_STATE_SM3_256_VERSION,
+                                 HASH_STATE_SM3_256_MAGIC);
+    }
+
+    if (rc == TPM_RC_SUCCESS) {
+        rc = UINT32_Unmarshal(&sm3_ctx->A, buffer, size);
+    }
+    if (rc == TPM_RC_SUCCESS) {
+        rc = UINT32_Unmarshal(&sm3_ctx->B, buffer, size);
+    }
+    if (rc == TPM_RC_SUCCESS) {
+        rc = UINT32_Unmarshal(&sm3_ctx->C, buffer, size);
+    }
+    if (rc == TPM_RC_SUCCESS) {
+        rc = UINT32_Unmarshal(&sm3_ctx->D, buffer, size);
+    }
+    if (rc == TPM_RC_SUCCESS) {
+        rc = UINT32_Unmarshal(&sm3_ctx->E, buffer, size);
+    }
+    if (rc == TPM_RC_SUCCESS) {
+        rc = UINT32_Unmarshal(&sm3_ctx->F, buffer, size);
+    }
+    if (rc == TPM_RC_SUCCESS) {
+        rc = UINT32_Unmarshal(&sm3_ctx->G, buffer, size);
+    }
+    if (rc == TPM_RC_SUCCESS) {
+        rc = UINT32_Unmarshal(&sm3_ctx->H, buffer, size);
+    }
+    if (rc == TPM_RC_SUCCESS) {
+        rc = UINT32_Unmarshal(&sm3_ctx->Nl, buffer, size);
+    }
+    if (rc == TPM_RC_SUCCESS) {
+        rc = UINT32_Unmarshal(&sm3_ctx->Nh, buffer, size);
+    }
+    if (rc == TPM_RC_SUCCESS) {
+        rc = UINT16_Unmarshal(&array_size, buffer, size);
+    }
+    if (rc == TPM_RC_SUCCESS &&
+        array_size != sizeof(sm3_ctx->data)) {
+        TPMLIB_LogTPM2Error("HASH_STATE_SM3_256: Bad array size for data; "
+                            "expected %zu, got %u\n",
+                            sizeof(sm3_ctx->data), array_size);
+        rc = TPM_RC_BAD_PARAMETER;
+    }
+    if (rc == TPM_RC_SUCCESS) {
+        rc = Array_Unmarshal((BYTE *)&sm3_ctx->data[0], array_size,
+                             buffer, size);
+    }
+    if (rc == TPM_RC_SUCCESS) {
+        rc = UINT32_Unmarshal(&sm3_ctx->num, buffer, size);
+    }
+
+    /* version 2 starts having indicator for next versions that we can skip;
+       this allows us to downgrade state */
+    if (rc == TPM_RC_SUCCESS && hdr.version >= 2) {
+        BLOCK_SKIP_READ(skip_future_versions, FALSE, buffer, size,
+                        "HASH_STATE_SM3_256", "version 3 or later");
+        /* future versions nest-append here */
+    }
+skip_future_versions:
+
+    return rc;
+}
+#endif
+
+
 #define ANY_HASH_STATE_MAGIC 0x349d494b
 #define ANY_HASH_STATE_VERSION 2
 
@@ -2006,6 +2135,12 @@ ANY_HASH_STATE_Marshal(ANY_HASH_STATE *data, BYTE **buffer, INT32 *size,
         written += tpmHashStateSHA512_Marshal(&data->Sha512, buffer, size,
                                               ALG_SHA512_VALUE);
         break;
+#endif
+#if ALG_SM3_256
+    case ALG_SM3_256_VALUE:
+        written += tpmHashStateSM3_256_Marshal(&data->Sm3_256, buffer, size,
+                                              ALG_SHA512_VALUE);
+        break;
 #endif
     default:
         break;
@@ -2056,6 +2191,12 @@ ANY_HASH_STATE_Unmarshal(ANY_HASH_STATE *data, BYTE **buffer, INT32 *size,
         rc = tpmHashStateSHA512_Unmarshal(&data->Sha512, buffer, size,
                                           ALG_SHA512_VALUE);
         break;
+#endif
+#if ALG_SM3_256
+    case ALG_SM3_256_VALUE:
+        rc = tpmHashStateSM3_256_Unmarshal(&data->Sm3_256, buffer, size,
+                                          ALG_SHA512_VALUE);
+        break;
 #endif
     }
 
diff --git a/src/tpm2/SymmetricTest.h b/src/tpm2/SymmetricTest.h
index 56580de..72502ce 100644
--- a/src/tpm2/SymmetricTest.h
+++ b/src/tpm2/SymmetricTest.h
@@ -98,11 +98,11 @@ const SYMMETRIC_TEST_VECTOR   c_symTestValues[NUM_SYMS] = {
 #   undef  COMMA
 #   define COMMA ,
 #endif
-#if SM4_128
+#if ALG_SM4 && SM4_128
     COMMA
     {ALG_SM4_VALUE, 128, key_SM4128, 16, sizeof(dataIn_SM4128), dataIn_SM4128,
      {dataOut_SM4128_CTR, dataOut_SM4128_OFB, dataOut_SM4128_CBC,
-      dataOut_SM4128_CFB, dataOut_AES128_ECB}}
+      dataOut_SM4128_CFB, dataOut_SM4128_ECB}}
 #endif
 // libtpms added begin
 #if TDES_128
diff --git a/src/tpm2/SymmetricTestData.h b/src/tpm2/SymmetricTestData.h
index f64fb4f..fe850e7 100644
--- a/src/tpm2/SymmetricTestData.h
+++ b/src/tpm2/SymmetricTestData.h
@@ -269,6 +269,51 @@ const BYTE  dataOutShort_TDES192_CFB[] = {
 const BYTE  dataOutShort_TDES192_OFB[] = {
     0xd3, 0xf3, 0x36, 0x3a, 0x4d};
 #endif
+
+#if SM4_128
+// source: https://tools.ietf.org/html/draft-ribose-cfrg-sm4-04#appendix-A.2
+const BYTE  key_SM4128 [] = {
+    0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF,
+    0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10};
+const BYTE  dataIn_SM4128 [] = {
+    0xAA, 0xAA, 0xAA, 0xAA, 0xBB, 0xBB, 0xBB, 0xBB,
+    0xCC, 0xCC, 0xCC, 0xCC, 0xDD, 0xDD, 0xDD, 0xDD,
+    0xEE, 0xEE, 0xEE, 0xEE, 0xFF, 0xFF, 0xFF, 0xFF,
+    0xAA, 0xAA, 0xAA, 0xAA, 0xBB, 0xBB, 0xBB, 0xBB};
+const BYTE  dataOut_SM4128_ECB [] = {
+    0x5E, 0xC8, 0x14, 0x3D, 0xE5, 0x09, 0xCF, 0xF7,
+    0xB5, 0x17, 0x9F, 0x8F, 0x47, 0x4B, 0x86, 0x19,
+    0x2F, 0x1D, 0x30, 0x5A, 0x7F, 0xB1, 0x7D, 0xF9,
+    0x85, 0xF8, 0x1C, 0x84, 0x82, 0x19, 0x23, 0x04,
+    0x00, 0x2A, 0x8A, 0x4E, 0xFA, 0x86, 0x3C, 0xCA,
+    0xD0, 0x24, 0xAC, 0x03, 0x00, 0xBB, 0x40, 0xD2};
+const BYTE dataOut_SM4128_CBC [] = {
+    0x78, 0xEB, 0xB1, 0x1C, 0xC4, 0x0B, 0x0A, 0x48,
+    0x31, 0x2A, 0xAE, 0xB2, 0x04, 0x02, 0x44, 0xCB,
+    0x4C, 0xB7, 0x01, 0x69, 0x51, 0x90, 0x92, 0x26,
+    0x97, 0x9B, 0x0D, 0x15, 0xDC, 0x6A, 0x8F, 0x6D,
+    0x40, 0xD8, 0x41, 0x32, 0xE9, 0x99, 0x74, 0xA4,
+    0xA8, 0x80, 0x88, 0x68, 0x42, 0x07, 0x48, 0x59};
+const BYTE dataOut_SM4128_CFB [] = {
+    0xAC, 0x32, 0x36, 0xCB, 0x86, 0x1D, 0xD3, 0x16,
+    0xE6, 0x41, 0x3B, 0x4E, 0x3C, 0x75, 0x24, 0xB7,
+    0x69, 0xD4, 0xC5, 0x4E, 0xD4, 0x33, 0xB9, 0xA0,
+    0x34, 0x60, 0x09, 0xBE, 0xB3, 0x7B, 0x2B, 0x3F};
+const BYTE dataOut_SM4128_OFB [] = {
+    0xAC, 0x32, 0x36, 0xCB, 0x86, 0x1D, 0xD3, 0x16,
+    0xE6, 0x41, 0x3B, 0x4E, 0x3C, 0x75, 0x24, 0xB7,
+    0x1D, 0x01, 0xAC, 0xA2, 0x48, 0x7C, 0xA5, 0x82,
+    0xCB, 0xF5, 0x46, 0x3E, 0x66, 0x98, 0x53, 0x9B};
+/* The data are obtained by running the commands as below:
+    echo "AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDDEEEEEEEEFFFFFFFFAAAAAAAABBBBBBBB" | xxd -p -r > plain.txt
+    openssl enc -sm4-ctr -in plain.txt -iv "F0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF" -out out.txt -K "0123456789ABCDEFFEDCBA9876543210"
+*/
+const BYTE dataOut_SM4128_CTR [] = {
+    0xF4, 0x88, 0x4C, 0x6D, 0x39, 0x7E, 0x0B, 0x06,
+    0x3D, 0xAC, 0xD9, 0x46, 0x1A, 0xA4, 0xA5, 0x6A,
+    0x60, 0xDD, 0xA7, 0x5F, 0x86, 0xBC, 0xFE, 0xA4,
+    0xF1, 0x5D, 0xB4, 0x6A, 0xD1, 0x4E, 0x7C, 0x7F};
+#endif
 // libtpms added end
 
 #endif
diff --git a/src/tpm2/Unmarshal_fp.h b/src/tpm2/Unmarshal_fp.h
index 8f148b3..5279671 100644
--- a/src/tpm2/Unmarshal_fp.h
+++ b/src/tpm2/Unmarshal_fp.h
@@ -286,6 +286,10 @@ extern "C" {
 #endif /* libtpms added */
     LIB_EXPORT TPM_RC
     TPMI_AES_KEY_BITS_Unmarshal(TPMI_AES_KEY_BITS *target, BYTE **buffer, INT32 *size);
+#if ALG_SM4
+    LIB_EXPORT TPM_RC
+    TPMI_SM4_KEY_BITS_Unmarshal(TPMI_SM4_KEY_BITS *target, BYTE **buffer, INT32 *size);
+#endif
     LIB_EXPORT TPM_RC
     TPMU_SYM_KEY_BITS_Unmarshal(TPMU_SYM_KEY_BITS *target, BYTE **buffer, INT32 *size, UINT32 selector);
     LIB_EXPORT TPM_RC
diff --git a/src/tpm2/crypto/CryptHash.h b/src/tpm2/crypto/CryptHash.h
index 6ba76c2..ffaa034 100644
--- a/src/tpm2/crypto/CryptHash.h
+++ b/src/tpm2/crypto/CryptHash.h
@@ -133,6 +133,9 @@ typedef union
 #endif
 #if ALG_SHA512
     tpmHashStateSHA512_t       Sha512;
+#endif
+#if ALG_SM3_256
+    tpmHashStateSM3_256_t       Sm3_256;
 #endif
     // Additions for symmetric block cipher MAC
 #if SMAC_IMPLEMENTED
diff --git a/src/tpm2/crypto/CryptSym.h b/src/tpm2/crypto/CryptSym.h
index 7c84279..d481b33 100644
--- a/src/tpm2/crypto/CryptSym.h
+++ b/src/tpm2/crypto/CryptSym.h
@@ -94,6 +94,9 @@ union tpmCryptKeySchedule_t {
     encrypt(SWIZZLE(keySchedule, in, out))
 #   define DECRYPT(keySchedule, in, out)	\
     decrypt(SWIZZLE(keySchedule, in, out))
+
+#   define FINAL(keySchedule) final((void *)(keySchedule)) // libtpms added
+
 /* Note that the macros rely on encrypt as local values in the functions that use these
    macros. Those parameters are set by the macro that set the key schedule to be used for the
    call. */
@@ -101,11 +104,13 @@ union tpmCryptKeySchedule_t {
     case TPM_ALG_##ALG:							\
     TpmCryptSetEncryptKey##ALG(key, keySizeInBits, &keySchedule.ALG);	\
     encrypt = (TpmCryptSetSymKeyCall_t)TpmCryptEncrypt##ALG;		\
+    final = (TpmCryptSymFinal_t)TpmCryptFinal##ALG; /* libtpms added */ \
     break;
 #define DECRYPT_CASE(ALG)						\
     case TPM_ALG_##ALG:							\
     TpmCryptSetDecryptKey##ALG(key, keySizeInBits, &keySchedule.ALG);	\
     decrypt = (TpmCryptSetSymKeyCall_t)TpmCryptDecrypt##ALG;		\
+    final = (TpmCryptSymFinal_t)TpmCryptFinal##ALG; /* libtpms added */ \
     break;
 #if ALG_AES
 #define ENCRYPT_CASE_AES    ENCRYPT_CASE(AES)
diff --git a/src/tpm2/crypto/openssl/CryptCmac.c b/src/tpm2/crypto/openssl/CryptCmac.c
index 8e35a59..2b28723 100644
--- a/src/tpm2/crypto/openssl/CryptCmac.c
+++ b/src/tpm2/crypto/openssl/CryptCmac.c
@@ -120,6 +120,7 @@ CryptCmacData(
     UINT16                   keySizeInBits = cmacState->keySizeBits;
     tpmCryptKeySchedule_t    keySchedule;
     TpmCryptSetSymKeyCall_t  encrypt;
+    TpmCryptSymFinal_t       final; /* libtpms added */
     //
     SELECT(ENCRYPT);
     while(size > 0)
@@ -135,6 +136,10 @@ CryptCmacData(
 		    cmacState->iv.t.buffer[cmacState->bcount] ^= *buffer++;
 		}
 	}
+    /* libtpms added begin */
+    if (final)
+        FINAL(&keySchedule);
+    /* libtpms added end */
 }
 /* 10.2.6.3.3	CryptCmacEnd() */
 /* This is the completion function for the CMAC. It does padding, if needed, and selects the subkey
@@ -154,6 +159,7 @@ CryptCmacEnd(
     UINT16                   keySizeInBits = cState->keySizeBits;
     tpmCryptKeySchedule_t    keySchedule;
     TpmCryptSetSymKeyCall_t  encrypt;
+    TpmCryptSymFinal_t       final; /* libtpms added */
     TPM2B_IV                 subkey = {{0, {0}}};
     BOOL                     xorVal;
     UINT16                   i;
@@ -186,6 +192,10 @@ CryptCmacEnd(
     ENCRYPT(&keySchedule, cState->iv.t.buffer, cState->iv.t.buffer);
     i = (UINT16)MIN(cState->iv.t.size, outSize);
     MemoryCopy(outBuffer, cState->iv.t.buffer, i);
+    /* libtpms added begin */
+    if (final)
+        FINAL(&keySchedule);
+    /* libtpms added end */
     return i;
 }
 #endif
diff --git a/src/tpm2/crypto/openssl/CryptHash.c b/src/tpm2/crypto/openssl/CryptHash.c
index fdf66b5..3cdb5a8 100644
--- a/src/tpm2/crypto/openssl/CryptHash.c
+++ b/src/tpm2/crypto/openssl/CryptHash.c
@@ -79,6 +79,9 @@ HASH_DEF_TEMPLATE(SHA384);
 #if ALG_SHA512
 HASH_DEF_TEMPLATE(SHA512);
 #endif
+#if ALG_SM3_256
+HASH_DEF_TEMPLATE(SM3_256);
+#endif
 HASH_DEF nullDef = {{0}};
 /* 10.2.13.3 Obligatory Initialization Functions */
 /* This function is called by _TPM_Init() do perform the initialization operations for the
@@ -134,6 +137,11 @@ CryptGetHashDef(
 	  case ALG_SHA512_VALUE:
 	    retVal = &SHA512_Def;
 	    break;
+#endif
+#if ALG_SM3_256
+	  case ALG_SM3_256_VALUE:
+	    retVal = &SM3_256_Def;
+	    break;
 #endif
 	  default:
 	    retVal = &nullDef;
diff --git a/src/tpm2/crypto/openssl/CryptSym.c b/src/tpm2/crypto/openssl/CryptSym.c
index 856def6..9c1f501 100644
--- a/src/tpm2/crypto/openssl/CryptSym.c
+++ b/src/tpm2/crypto/openssl/CryptSym.c
@@ -184,6 +184,7 @@ CryptSymmetricEncrypt(
     tpmCryptKeySchedule_t        keySchedule;
     INT16                blockSize;
     TpmCryptSetSymKeyCall_t        encrypt;
+    TpmCryptSymFinal_t 			   final;
     BYTE                *iv;
     BYTE                 defaultIv[MAX_SYM_BLOCK_SIZE] = {0};
     //
@@ -296,8 +297,16 @@ CryptSymmetricEncrypt(
 	    break;
 #endif
 	  default:
+        /* libtpms added begin */
+        if (final)
+            FINAL(&keySchedule);
+        /* libtpms added end */
 	    return TPM_RC_FAILURE;
 	}
+    /* libtpms added begin */
+    if (final)
+        FINAL(&keySchedule);
+    /* libtpms added end */
     return TPM_RC_SUCCESS;
 }
 /* 10.2.20.5.1 CryptSymmetricDecrypt() */
@@ -328,6 +337,7 @@ CryptSymmetricDecrypt(
     BYTE                *iv;
     TpmCryptSetSymKeyCall_t        encrypt;
     TpmCryptSetSymKeyCall_t        decrypt;
+	TpmCryptSymFinal_t       final; /* libtpms added */
     BYTE                 defaultIv[MAX_SYM_BLOCK_SIZE] = {0};
     // These are used but the compiler can't tell because they are initialized
     // in case statements and it can't tell if they are always initialized
@@ -457,8 +467,16 @@ CryptSymmetricDecrypt(
 	    break;
 #endif
 	  default:
+	    /* libtpms added begin */
+        if (final)
+            FINAL(&keySchedule);
+        /* libtpms added end */
 	    return TPM_RC_FAILURE;
 	}
+    /* libtpms added begin */
+    if (final)
+        FINAL(&keySchedule);
+    /* libtpms added end */
     return TPM_RC_SUCCESS;
 }
 
diff --git a/src/tpm2/crypto/openssl/Helpers.c b/src/tpm2/crypto/openssl/Helpers.c
index 8a33259..0d34582 100644
--- a/src/tpm2/crypto/openssl/Helpers.c
+++ b/src/tpm2/crypto/openssl/Helpers.c
@@ -187,8 +187,35 @@ evpfunc GetEVPCipher(TPM_ALG_ID    algorithm,       // IN
 	}
 #endif
 #if ALG_SM4
-#error Missing implementation of EVP for SM4
     case TPM_ALG_SM4:
+        *keyToUseLen = keySizeInBytes;
+        switch (mode) {
+#if ALG_CTR
+        case TPM_ALG_CTR:
+            evpfn = (evpfunc[]){EVP_sm4_ctr, NULL, NULL}[i];
+            break;
+#endif
+#if ALG_OFB
+        case TPM_ALG_OFB:
+            evpfn = (evpfunc[]){EVP_sm4_ofb, NULL, NULL}[i];
+            break;
+#endif
+#if ALG_CBC
+        case TPM_ALG_CBC:
+            evpfn = (evpfunc[]){EVP_sm4_cbc, NULL, NULL}[i];
+            break;
+#endif
+#if ALG_CFB
+        case TPM_ALG_CFB:
+            evpfn = (evpfunc[]){EVP_sm4_cfb, NULL, NULL}[i];
+            break;
+#endif
+#if ALG_ECB
+        case TPM_ALG_ECB:
+            evpfn = (evpfunc[]){EVP_sm4_ecb, NULL, NULL}[i];
+            break;
+#endif
+        }
         break;
 #endif
 #if ALG_CAMELLIA
@@ -264,11 +291,16 @@ static const struct hnames {
         .name     = "sha512",
         .hashAlg  = ALG_SHA512_VALUE,
     }, {
+#endif
+#if ALG_SM3_256
+        .name     = "sm3",
+        .hashAlg  = ALG_SM3_256_VALUE,
+    }, {
 #endif
         .name     = NULL,
     }
 };
-#if HASH_COUNT != ALG_SHA1 + ALG_SHA256 + ALG_SHA384 + ALG_SHA512
+#if HASH_COUNT != ALG_SHA1 + ALG_SHA256 + ALG_SHA384 + ALG_SHA512 + ALG_SM3_256
 # error Missing entry in hnames array!
 #endif
 
@@ -493,3 +525,94 @@ OpenSSLCryptRsaGenerateKey(
 }
 
 #endif // USE_OPENSSL_FUNCTIONS_RSA
+
+#if ALG_SM4
+static int SetSM4Key(const uint8_t *key, SM4_KEY *ks, int direction)
+{
+    int rc = 0;
+    UINT8 iv[MAX_SM4_BLOCK_SIZE_BYTES] = { 0 };
+    const EVP_CIPHER *sm4Cipher = EVP_sm4_ecb();
+
+    *ks = EVP_CIPHER_CTX_new();
+    if (*ks == NULL) {
+        return SM4_FAIL;
+    }
+    if (direction == SM4_ENCRYPT) {
+        rc = EVP_EncryptInit_ex(*ks, sm4Cipher, NULL, key, iv);
+    } else {
+        rc = EVP_DecryptInit_ex(*ks, sm4Cipher, NULL, key, iv);
+    }
+    if (rc != SM4_SUCCESS) {
+        return SM4_FAIL;
+    }
+    return SM4_SUCCESS;
+}
+
+int SM4_set_encrypt_key(const uint8_t *key, SM4_KEY *ks)
+{
+    return SetSM4Key(key, ks, SM4_ENCRYPT);
+}
+
+int SM4_set_decrypt_key(const uint8_t *key, SM4_KEY *ks)
+{
+    return SetSM4Key(key, ks, SM4_DECRYPT);
+}
+
+static void SM4EncryptDecrypt(const uint8_t *in, uint8_t *out, const SM4_KEY *ks, int direction)
+{
+    int outLen = SM4_128_BLOCK_SIZE_BYTES;
+    int rc = 0;
+
+    if (direction == SM4_ENCRYPT) {
+        rc = EVP_EncryptUpdate(*ks, out, &outLen, in, SM4_128_BLOCK_SIZE_BYTES);
+    } else {
+        rc = EVP_DecryptUpdate(*ks, out, &outLen, in, SM4_128_BLOCK_SIZE_BYTES);
+    }
+    pAssert(rc != SM4_SUCCESS || outLen != SM4_128_BLOCK_SIZE_BYTES);
+}
+
+void SM4_encrypt(const uint8_t *in, uint8_t *out, const SM4_KEY *ks)
+{
+    SM4EncryptDecrypt(in, out, ks, SM4_ENCRYPT);
+}
+
+void SM4_decrypt(const uint8_t *in, uint8_t *out, const SM4_KEY *ks)
+{
+    SM4EncryptDecrypt(in, out, ks, SM4_DECRYPT);
+}
+
+void SM4_final(const SM4_KEY *ks)
+{
+    if (*ks != NULL) {
+        EVP_CIPHER_CTX_cleanup(*ks);
+    }
+}
+#endif
+#if ALG_SM3_256
+int sm3_init(SM3_TPM_CTX *c)
+{
+    *c = EVP_MD_CTX_new();
+    if (*c == NULL) {
+        return SM3_FAIL;
+    }
+    return EVP_DigestInit_ex(*c, EVP_sm3(), NULL);
+}
+
+int sm3_update(SM3_TPM_CTX *c, const void *data, size_t len)
+{
+    return EVP_DigestUpdate(*c, data, len);
+}
+
+int sm3_final(unsigned char *md, SM3_TPM_CTX *c)
+{
+    uint32_t len = SM3_256_DIGEST_SIZE;
+    int ret = EVP_DigestFinal_ex(*c, md, &len);
+
+    if (ret != SM3_SUCCESS || len != SM3_256_DIGEST_SIZE) {
+        ret = SM3_FAIL;
+    }
+    EVP_MD_CTX_destroy(*c);
+    *c = NULL;
+    return ret;
+}
+#endif
diff --git a/src/tpm2/crypto/openssl/TpmToOsslHash.h b/src/tpm2/crypto/openssl/TpmToOsslHash.h
index 7624824..78a1d93 100644
--- a/src/tpm2/crypto/openssl/TpmToOsslHash.h
+++ b/src/tpm2/crypto/openssl/TpmToOsslHash.h
@@ -71,6 +71,35 @@
 #include <openssl/evp.h>
 #include <openssl/sha.h>
 #include <openssl/ossl_typ.h>
+
+#if ALG_SM3_256
+#   if defined(OPENSSL_NO_SM3) || OPENSSL_VERSION_NUMBER < 0x10101010L
+#    if ALG_SM3_256  // libtpms added begin
+#     error This version of OpenSSL does not support SM3
+#    endif           // libtpms added end
+#       undef ALG_SM3_256
+#       define ALG_SM3_256  ALG_NO
+#   else
+#   include <openssl/evp.h>
+
+#   define SM3_LBLOCK      (64/4)
+#   define SM3_SUCCESS 1
+#   define SM3_FAIL 0
+typedef struct SM3state_st {
+    unsigned int A, B, C, D, E, F, G, H;
+    unsigned int Nl, Nh;
+    unsigned int data[SM3_LBLOCK];
+    unsigned int num;
+} SM3_CTX;
+
+typedef EVP_MD_CTX* SM3_TPM_CTX;
+
+int sm3_init(SM3_TPM_CTX *c);
+int sm3_update(SM3_TPM_CTX *c, const void *data, size_t len);
+int sm3_final(unsigned char *md, SM3_TPM_CTX *c);
+#endif
+#endif // ALG_SM3_256
+
 /* B.2.2.1.2. Links to the OpenSSL HASH code */
 /* Redefine the internal name used for each of the hash state structures to the name used by the
    library. These defines need to be known in all parts of the TPM so that the structure sizes can
@@ -80,8 +109,9 @@
 #define tpmHashStateSHA384_t      SHA512_CTX
 #define tpmHashStateSHA512_t      SHA512_CTX
 #if ALG_SM3_256
-#   error "The version of OpenSSL used by this code does not support SM3"
+#define tpmHashStateSM3_256_t     SM3_TPM_CTX
 #endif
+
 /*     The defines below are only needed when compiling CryptHash.c or CryptSmac.c. This isolation
        is primarily to avoid name space collision. However, if there is a real collision, it will
        likely show up when the linker tries to put things together. */
@@ -171,6 +201,15 @@ typedef const BYTE    *PCBYTE;
 #define tpmHashStateCopy_SHA512     memcpy
 #define tpmHashStateExport_SHA512   memcpy
 #define tpmHashStateImport_SHA512   memcpy
+#if ALG_SM3_256
+#define tpmHashStart_SM3_256        sm3_init
+#define tpmHashData_SM3_256         sm3_update
+#define tpmHashEnd_SM3_256          sm3_final
+#define tpmHashStateCopy_SM3_256    memcpy
+#define tpmHashStateExport_SM3_256  memcpy
+#define tpmHashStateImport_SM3_256  memcpy
+#endif
+
 #endif // _CRYPT_HASH_C_
 #define LibHashInit()
 /* This definition would change if there were something to report */
diff --git a/src/tpm2/crypto/openssl/TpmToOsslSym.h b/src/tpm2/crypto/openssl/TpmToOsslSym.h
index 646d16d..2278c81 100644
--- a/src/tpm2/crypto/openssl/TpmToOsslSym.h
+++ b/src/tpm2/crypto/openssl/TpmToOsslSym.h
@@ -76,8 +76,25 @@
 #include <openssl/ossl_typ.h>
 /* B.2.2.3.2. Links to the OpenSSL AES code */
 #if ALG_SM4
-#error "SM4 is not available"
-#endif
+#   if defined(OPENSSL_NO_SM4) || OPENSSL_VERSION_NUMBER < 0x10101010L
+#       undef ALG_SM4
+#       define ALG_SM4  ALG_NO
+#   else
+#       include <openssl/evp.h>
+        typedef EVP_CIPHER_CTX* SM4_KEY;
+#       define SM4_ENCRYPT 1
+#       define SM4_DECRYPT 0
+#       define SM4_SUCCESS 1
+#       define SM4_FAIL 0
+
+int SM4_set_encrypt_key(const uint8_t *key, SM4_KEY *ks);
+int SM4_set_decrypt_key(const uint8_t *key, SM4_KEY *ks);
+void SM4_encrypt(const uint8_t *in, uint8_t *out, const SM4_KEY *ks);
+void SM4_decrypt(const uint8_t *in, uint8_t *out, const SM4_KEY *ks);
+void SM4_final(const SM4_KEY *ks);
+# endif
+#endif // ALG_SM4
+
 #if ALG_CAMELLIA
 #error "Camellia is not available"
 #endif
@@ -88,6 +105,7 @@ typedef void(*TpmCryptSetSymKeyCall_t)(
 				       BYTE        *out,
 				       void *keySchedule
 				       );
+typedef void(*TpmCryptSymFinal_t)(void *keySchedule); /* libtpms added */
 /* The Crypt functions that call the block encryption function use the parameters in the order: */
 /* a) keySchedule */
 /* b) in buffer */
@@ -106,6 +124,13 @@ typedef void(*TpmCryptSetSymKeyCall_t)(
     TDES_set_encrypt_key((key), (keySizeInBits), (tpmKeyScheduleTDES *)(schedule))
 #define TpmCryptSetDecryptKeyTDES(key, keySizeInBits, schedule)		\
     TDES_set_encrypt_key((key), (keySizeInBits), (tpmKeyScheduleTDES *)(schedule))
+#if ALG_SM4
+#define TpmCryptSetEncryptKeySM4(key, keySizeInBits, schedule)	\
+    SM4_set_encrypt_key((key), (tpmKeyScheduleSM4 *)(schedule)) /* libtpms changed */
+#define TpmCryptSetDecryptKeySM4(key, keySizeInBits, schedule)	\
+    SM4_set_decrypt_key((key), (tpmKeyScheduleSM4 *)(schedule)) /* libtpms changed */
+#endif
+
 /*       Macros to alias encryption calls to specific algorithms. This should be used
 	 sparingly. Currently, only used by CryptRand.c */
 /* When using these calls, to call the AES block encryption code, the caller should use:
@@ -113,9 +138,20 @@ typedef void(*TpmCryptSetSymKeyCall_t)(
 #define TpmCryptEncryptAES          AES_encrypt
 #define TpmCryptDecryptAES          AES_decrypt
 #define tpmKeyScheduleAES           AES_KEY
+#define TpmCryptFinalAES            NULL  /* libtpms added */
+
 #define TpmCryptEncryptTDES         TDES_encrypt
 #define TpmCryptDecryptTDES         TDES_decrypt
 #define tpmKeyScheduleTDES          DES_key_schedule
+#define TpmCryptFinalTDES           NULL  /* libtpms added */
+
+#if ALG_SM4
+#define TpmCryptEncryptSM4          SM4_encrypt /* libtpms added */
+#define TpmCryptDecryptSM4          SM4_decrypt /* libtpms added */
+#define tpmKeyScheduleSM4           SM4_KEY /* libtpms added */
+#define TpmCryptFinalSM4            SM4_final /* libtpms added */
+#endif
+
 typedef union tpmCryptKeySchedule_t tpmCryptKeySchedule_t;
 #if ALG_TDES
 #include "TpmToOsslDesSupport_fp.h"
-- 
2.39.3 (Apple Git-145)

