From df8dab733a8795e896acfd459b2b9adc9607e831 Mon Sep 17 00:00:00 2001
From: Huaxin Lu <luhuaxin1@huawei.com>
Date: Mon, 7 Nov 2022 11:46:33 +0800
Subject: [PATCH 1/2] shim cryptlib support sm2 signature verify

Co-authored-by: Yusong Gao <gaoyusong2@huawei.com>
Signed-off-by: Yusong Gao <gaoyusong2@huawei.com>
Signed-off-by: Huaxin Lu <luhuaxin1@huawei.com>
---
 Cryptlib/Hash/CryptSm3.c                   | 231 +++++++++++++++++++++
 Cryptlib/Include/openssl/crypto.h          |  10 +
 Cryptlib/Include/openssl/ec.h              |  20 ++
 Cryptlib/Include/openssl/ecdsa.h           |   7 +
 Cryptlib/Include/openssl/err.h             |   6 +
 Cryptlib/Include/openssl/evp.h             |  27 ++-
 Cryptlib/Include/openssl/obj_mac.h         |  33 +++
 Cryptlib/Include/openssl/opensslconf.h     |   7 +-
 Cryptlib/Include/openssl/x509.h            |   7 +
 Cryptlib/Library/BaseCryptLib.h            | 111 ++++++++++
 Cryptlib/Makefile                          |   6 +
 Cryptlib/OpenSSL/Makefile                  |  38 +++-
 Cryptlib/OpenSSL/crypto/asn1/a_sign.c      |  11 +-
 Cryptlib/OpenSSL/crypto/asn1/ameth_lib.c   |   8 +-
 Cryptlib/OpenSSL/crypto/asn1/x_req.c       |  13 ++
 Cryptlib/OpenSSL/crypto/asn1/x_x509.c      |   6 +
 Cryptlib/OpenSSL/crypto/bn/bn_lib.c        |   3 -
 Cryptlib/OpenSSL/crypto/err/err.c          |   1 +
 Cryptlib/OpenSSL/crypto/evp/c_alld.c       |   3 +
 Cryptlib/OpenSSL/crypto/evp/digest.c       |  62 +++++-
 Cryptlib/OpenSSL/crypto/evp/evp_lib.c      |  24 +++
 Cryptlib/OpenSSL/crypto/evp/evp_locl.h     |  10 +
 Cryptlib/OpenSSL/crypto/evp/m_sigver.c     |  17 ++
 Cryptlib/OpenSSL/crypto/evp/p_lib.c        |  44 ++++
 Cryptlib/OpenSSL/crypto/evp/pmeth_lib.c    |  16 +-
 Cryptlib/OpenSSL/crypto/mem.c              |  18 ++
 Cryptlib/OpenSSL/crypto/o_str.c            |  87 ++++++++
 Cryptlib/OpenSSL/crypto/objects/obj_dat.h  |  46 +++-
 Cryptlib/OpenSSL/crypto/objects/obj_xref.h |   2 +
 Cryptlib/OpenSSL/crypto/pkcs7/pk7_doit.c   |  34 ++-
 Cryptlib/OpenSSL/crypto/x509/x_all.c       | 145 +++++++++++++
 Cryptlib/Pk/CryptPkcs7Verify.c             |   5 +
 32 files changed, 1020 insertions(+), 38 deletions(-)
 create mode 100644 Cryptlib/Hash/CryptSm3.c

diff --git a/Cryptlib/Hash/CryptSm3.c b/Cryptlib/Hash/CryptSm3.c
new file mode 100644
index 0000000..84d7acc
--- /dev/null
+++ b/Cryptlib/Hash/CryptSm3.c
@@ -0,0 +1,231 @@
+/** @file
+  SM3 Digest Wrapper Implementation over OpenSSL.
+
+Copyright (c) 2009 - 2016, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "InternalCryptLib.h"
+#include <openssl/sm3.h>
+
+/**
+  Retrieves the size, in bytes, of the context buffer required for SM3 hash operations.
+
+  @return  The size, in bytes, of the context buffer required for SM3 hash operations.
+
+**/
+UINTN
+EFIAPI
+Sm3GetContextSize (
+  VOID
+  )
+{
+  //
+  // Retrieves OpenSSL SM3 Context Size
+  //
+  return (UINTN) (sizeof (SM3_CTX));
+}
+
+/**
+  Initializes user-supplied memory pointed by Sm3Context as SM3 hash context for
+  subsequent use.
+
+  If Sm3Context is NULL, then return FALSE.
+
+  @param[out]  Sm3Context  Pointer to SM3 context being initialized.
+
+  @retval TRUE   SM3 context initialization succeeded.
+  @retval FALSE  SM3 context initialization failed.
+
+**/
+BOOLEAN
+EFIAPI
+Sm3Init (
+  OUT  VOID  *Sm3Context
+  )
+{
+  //
+  // Check input parameters.
+  //
+  if (Sm3Context == NULL) {
+    return FALSE;
+  }
+
+  //
+  // OpenSSL SM3 Context Initialization
+  //
+  return (BOOLEAN) (sm3_init ((SM3_CTX *) Sm3Context));
+}
+
+/**
+  Makes a copy of an existing SM3 context.
+
+  If Sm3Context is NULL, then return FALSE.
+  If NewSm3Context is NULL, then return FALSE.
+
+  @param[in]  Sm3Context     Pointer to SM3 context being copied.
+  @param[out] NewSm3Context  Pointer to new SM3 context.
+
+  @retval TRUE   SM3 context copy succeeded.
+  @retval FALSE  SM3 context copy failed.
+
+**/
+BOOLEAN
+EFIAPI
+Sm3Duplicate (
+  IN   CONST VOID  *Sm3Context,
+  OUT  VOID        *NewSm3Context
+  )
+{
+  //
+  // Check input parameters.
+  //
+  if (Sm3Context == NULL || NewSm3Context == NULL) {
+    return FALSE;
+  }
+
+  CopyMem (NewSm3Context, (void *)Sm3Context, sizeof (SM3_CTX));
+
+  return TRUE;
+}
+
+/**
+  Digests the input data and updates SM3 context.
+
+  This function performs SM3 digest on a data buffer of the specified size.
+  It can be called multiple times to compute the digest of long or discontinuous data streams.
+  SM3 context should be already correctly initialized by Sm3Init(), and should not be finalized
+  by Sm3Final(). Behavior with invalid context is undefined.
+
+  If Sm3Context is NULL, then return FALSE.
+
+  @param[in, out]  Sm3Context  Pointer to the SM3 context.
+  @param[in]       Data           Pointer to the buffer containing the data to be hashed.
+  @param[in]       DataSize       Size of Data buffer in bytes.
+
+  @retval TRUE   SM3 data digest succeeded.
+  @retval FALSE  SM3 data digest failed.
+
+**/
+BOOLEAN
+EFIAPI
+Sm3Update (
+  IN OUT  VOID        *Sm3Context,
+  IN      CONST VOID  *Data,
+  IN      UINTN       DataSize
+  )
+{
+  //
+  // Check input parameters.
+  //
+  if (Sm3Context == NULL) {
+    return FALSE;
+  }
+
+  //
+  // Check invalid parameters, in case that only DataLength was checked in OpenSSL
+  //
+  if (Data == NULL && DataSize != 0) {
+    return FALSE;
+  }
+
+  //
+  // OpenSSL SM3 Hash Update
+  //
+  return (BOOLEAN) (sm3_update ((SM3_CTX *) Sm3Context, Data, DataSize));
+}
+
+/**
+  Completes computation of the SM3 digest value.
+
+  This function completes SM3 hash computation and retrieves the digest value into
+  the specified memory. After this function has been called, the SM3 context cannot
+  be used again.
+  SM3 context should be already correctly initialized by Sm3Init(), and should not be
+  finalized by Sm3Final(). Behavior with invalid SM3 context is undefined.
+
+  If Sm3Context is NULL, then return FALSE.
+  If HashValue is NULL, then return FALSE.
+
+  @param[in, out]  Sm3Context  Pointer to the SM3 context.
+  @param[out]      HashValue      Pointer to a buffer that receives the SM3 digest
+                                  value (32 bytes).
+
+  @retval TRUE   SM3 digest computation succeeded.
+  @retval FALSE  SM3 digest computation failed.
+
+**/
+BOOLEAN
+EFIAPI
+Sm3Final (
+  IN OUT  VOID   *Sm3Context,
+  OUT     UINT8  *HashValue
+  )
+{
+  //
+  // Check input parameters.
+  //
+  if (Sm3Context == NULL || HashValue == NULL) {
+    return FALSE;
+  }
+
+  //
+  // OpenSSL SM3 Hash Finalization
+  //
+  return (BOOLEAN) (sm3_final (HashValue, (SM3_CTX *) Sm3Context));
+}
+
+/**
+  Computes the SM3 message digest of a input data buffer.
+
+  This function performs the SM3 message digest of a given data buffer, and places
+  the digest value into the specified memory.
+
+  If this interface is not supported, then return FALSE.
+
+  @param[in]   Data        Pointer to the buffer containing the data to be hashed.
+  @param[in]   DataSize    Size of Data buffer in bytes.
+  @param[out]  HashValue   Pointer to a buffer that receives the SM3 digest
+                           value (32 bytes).
+
+  @retval TRUE   SM3 digest computation succeeded.
+  @retval FALSE  SM3 digest computation failed.
+  @retval FALSE  This interface is not supported.
+
+**/
+BOOLEAN
+EFIAPI
+Sm3HashAll (
+  IN   CONST VOID  *Data,
+  IN   UINTN       DataSize,
+  OUT  UINT8       *HashValue
+  )
+{
+  //
+  // Check input parameters.
+  //
+  if (HashValue == NULL) {
+    return FALSE;
+  }
+  if (Data == NULL && DataSize != 0) {
+    return FALSE;
+  }
+
+  //
+  // OpenSSL SM3 Hash Computation.
+  //
+
+  SM3_CTX c;
+  sm3_init(&c);
+  sm3_update(&c, Data, DataSize);
+  sm3_final(HashValue, &c);
+
+  return TRUE;
+}
diff --git a/Cryptlib/Include/openssl/crypto.h b/Cryptlib/Include/openssl/crypto.h
index e201a12..b0fbe1c 100644
--- a/Cryptlib/Include/openssl/crypto.h
+++ b/Cryptlib/Include/openssl/crypto.h
@@ -380,6 +380,7 @@ int CRYPTO_is_mem_check_on(void);
 # define is_MemCheck_on() CRYPTO_is_mem_check_on()
 
 # define OPENSSL_malloc(num)     CRYPTO_malloc((int)num,OPENSSL_FILE,OPENSSL_LINE)
+# define OPENSSL_zalloc(num)     CRYPTO_zalloc((int)num,OPENSSL_FILE,OPENSSL_LINE)
 # define OPENSSL_strdup(str)     CRYPTO_strdup((str),OPENSSL_FILE,OPENSSL_LINE)
 # define OPENSSL_realloc(addr,num) \
         CRYPTO_realloc((char *)addr,(int)num,OPENSSL_FILE,OPENSSL_LINE)
@@ -389,6 +390,8 @@ int CRYPTO_is_mem_check_on(void);
         CRYPTO_remalloc((char **)addr,(int)num,OPENSSL_FILE,OPENSSL_LINE)
 # define OPENSSL_freeFunc        CRYPTO_free
 # define OPENSSL_free(addr)      CRYPTO_free(addr)
+# define OPENSSL_clear_free(addr, num) \
+	CRYPTO_clear_free(addr,num,OPENSSL_FILE,OPENSSL_LINE)
 
 # define OPENSSL_malloc_locked(num) \
         CRYPTO_malloc_locked((int)num,OPENSSL_FILE,OPENSSL_LINE)
@@ -399,6 +402,8 @@ unsigned long SSLeay(void);
 
 int OPENSSL_issetugid(void);
 
+unsigned char *OPENSSL_hexstr2buf(const char *str, long *len);
+
 /* An opaque type representing an implementation of "ex_data" support */
 typedef struct st_CRYPTO_EX_DATA_IMPL CRYPTO_EX_DATA_IMPL;
 /* Return an opaque pointer to the current "ex_data" implementation */
@@ -533,12 +538,14 @@ void CRYPTO_get_mem_debug_functions(void (**m)
 void *CRYPTO_malloc_locked(int num, const char *file, int line);
 void CRYPTO_free_locked(void *ptr);
 void *CRYPTO_malloc(int num, const char *file, int line);
+void *CRYPTO_zalloc(int num, const char *file, int line);
 char *CRYPTO_strdup(const char *str, const char *file, int line);
 void CRYPTO_free(void *ptr);
 void *CRYPTO_realloc(void *addr, int num, const char *file, int line);
 void *CRYPTO_realloc_clean(void *addr, int old_num, int num, const char *file,
                            int line);
 void *CRYPTO_remalloc(void *addr, int num, const char *file, int line);
+void CRYPTO_clear_free(void *ptr, int num, const char *file, int line);
 
 void OPENSSL_cleanse(void *ptr, size_t len);
 
@@ -651,10 +658,13 @@ void ERR_load_CRYPTO_strings(void);
 # define CRYPTO_F_INT_DUP_EX_DATA                         106
 # define CRYPTO_F_INT_FREE_EX_DATA                        107
 # define CRYPTO_F_INT_NEW_EX_DATA                         108
+# define CRYPTO_F_OPENSSL_HEXSTR2BUF                      118
 
 /* Reason codes. */
 # define CRYPTO_R_FIPS_MODE_NOT_SUPPORTED                 101
 # define CRYPTO_R_NO_DYNLOCK_CREATE_CALLBACK              100
+# define CRYPTO_R_ILLEGAL_HEX_DIGIT                       102
+# define CRYPTO_R_ODD_NUMBER_OF_DIGITS                    103
 
 #ifdef  __cplusplus
 }
diff --git a/Cryptlib/Include/openssl/ec.h b/Cryptlib/Include/openssl/ec.h
index 81e6faf..e315025 100644
--- a/Cryptlib/Include/openssl/ec.h
+++ b/Cryptlib/Include/openssl/ec.h
@@ -254,6 +254,12 @@ BN_MONT_CTX *EC_GROUP_get_mont_data(const EC_GROUP *group);
  */
 int EC_GROUP_get_order(const EC_GROUP *group, BIGNUM *order, BN_CTX *ctx);
 
+/** Gets the order of an EC_GROUP
+ *  \param  group  EC_GROUP object
+ *  \return the group order
+ */
+const BIGNUM *EC_GROUP_get0_order(const EC_GROUP *group);
+
 /** Gets the cofactor of a EC_GROUP
  *  \param  group     EC_GROUP object
  *  \param  cofactor  BIGNUM to which the cofactor is copied
@@ -1053,6 +1059,17 @@ int EC_KEY_print_fp(FILE *fp, const EC_KEY *key, int off);
         EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_EC, \
                                 EVP_PKEY_OP_DERIVE, \
                                 EVP_PKEY_CTRL_GET_EC_KDF_UKM, 0, (void *)p)
+# define EVP_PKEY_CTX_set1_id(ctx, id, id_len) \
+        EVP_PKEY_CTX_ctrl(ctx, -1, -1, \
+                                EVP_PKEY_CTRL_SET1_ID, (int)id_len, (void*)(id))
+
+# define EVP_PKEY_CTX_get1_id(ctx, id) \
+        EVP_PKEY_CTX_ctrl(ctx, -1, -1, \
+                                EVP_PKEY_CTRL_GET1_ID, 0, (void*)(id))
+
+# define EVP_PKEY_CTX_get1_id_len(ctx, id_len) \
+        EVP_PKEY_CTX_ctrl(ctx, -1, -1, \
+                                EVP_PKEY_CTRL_GET1_ID_LEN, 0, (void*)(id_len))
 
 # define EVP_PKEY_CTRL_EC_PARAMGEN_CURVE_NID             (EVP_PKEY_ALG_CTRL + 1)
 # define EVP_PKEY_CTRL_EC_PARAM_ENC                      (EVP_PKEY_ALG_CTRL + 2)
@@ -1064,6 +1081,9 @@ int EC_KEY_print_fp(FILE *fp, const EC_KEY *key, int off);
 # define EVP_PKEY_CTRL_GET_EC_KDF_OUTLEN                 (EVP_PKEY_ALG_CTRL + 8)
 # define EVP_PKEY_CTRL_EC_KDF_UKM                        (EVP_PKEY_ALG_CTRL + 9)
 # define EVP_PKEY_CTRL_GET_EC_KDF_UKM                    (EVP_PKEY_ALG_CTRL + 10)
+# define EVP_PKEY_CTRL_SET1_ID                           (EVP_PKEY_ALG_CTRL + 11)
+# define EVP_PKEY_CTRL_GET1_ID                           (EVP_PKEY_ALG_CTRL + 12)
+# define EVP_PKEY_CTRL_GET1_ID_LEN                       (EVP_PKEY_ALG_CTRL + 13)
 /* KDF types */
 # define EVP_PKEY_ECDH_KDF_NONE                          1
 # define EVP_PKEY_ECDH_KDF_X9_62                         2
diff --git a/Cryptlib/Include/openssl/ecdsa.h b/Cryptlib/Include/openssl/ecdsa.h
index a6f0930..e51d924 100644
--- a/Cryptlib/Include/openssl/ecdsa.h
+++ b/Cryptlib/Include/openssl/ecdsa.h
@@ -90,6 +90,13 @@ ECDSA_SIG *ECDSA_SIG_new(void);
  */
 void ECDSA_SIG_free(ECDSA_SIG *sig);
 
+/** Accessor for r and s fields of ECDSA_SIG
+ *  \param  sig  pointer to ECDSA_SIG structure
+ *  \param  pr   pointer to BIGNUM pointer for r (may be NULL)
+ *  \param  ps   pointer to BIGNUM pointer for s (may be NULL)
+ */
+void ECDSA_SIG_get0(const ECDSA_SIG *sig, const BIGNUM **pr, const BIGNUM **ps);
+
 /** DER encode content of ECDSA_SIG object (note: this function modifies *pp
  *  (*pp += length of the DER encoded signature)).
  *  \param  sig  pointer to the ECDSA_SIG object
diff --git a/Cryptlib/Include/openssl/err.h b/Cryptlib/Include/openssl/err.h
index 5a01980..c8286e1 100644
--- a/Cryptlib/Include/openssl/err.h
+++ b/Cryptlib/Include/openssl/err.h
@@ -197,6 +197,8 @@ typedef struct err_state_st {
 # define ERR_LIB_TS              47
 # define ERR_LIB_HMAC            48
 # define ERR_LIB_JPAKE           49
+# define ERR_LIB_SM2             53
+
 
 # define ERR_LIB_USER            128
 
@@ -233,6 +235,7 @@ typedef struct err_state_st {
 # define TSerr(f,r) ERR_PUT_error(ERR_LIB_TS,(f),(r),OPENSSL_FILE,OPENSSL_LINE)
 # define HMACerr(f,r) ERR_PUT_error(ERR_LIB_HMAC,(f),(r),OPENSSL_FILE,OPENSSL_LINE)
 # define JPAKEerr(f,r) ERR_PUT_error(ERR_LIB_JPAKE,(f),(r),OPENSSL_FILE,OPENSSL_LINE)
+# define SM2err(f,r) ERR_PUT_error(ERR_LIB_SM2,(f),(r),OPENSSL_FILE,OPENSSL_LINE)
 
 /*
  * Borland C seems too stupid to be able to shift and do longs in the
@@ -304,6 +307,9 @@ typedef struct err_state_st {
 # define ERR_R_PASSED_NULL_PARAMETER             (3|ERR_R_FATAL)
 # define ERR_R_INTERNAL_ERROR                    (4|ERR_R_FATAL)
 # define ERR_R_DISABLED                          (5|ERR_R_FATAL)
+# define ERR_R_INIT_FAIL                         (6|ERR_R_FATAL)
+# define ERR_R_PASSED_INVALID_ARGUMENT           (7)
+# define ERR_R_OPERATION_FAIL                    (8|ERR_R_FATAL)
 
 /*
  * 99 is the maximum possible ERR_R_... code, higher values are reserved for
diff --git a/Cryptlib/Include/openssl/evp.h b/Cryptlib/Include/openssl/evp.h
index 376f260..26e8f04 100644
--- a/Cryptlib/Include/openssl/evp.h
+++ b/Cryptlib/Include/openssl/evp.h
@@ -115,6 +115,7 @@
 # define EVP_PKEY_DH     NID_dhKeyAgreement
 # define EVP_PKEY_DHX    NID_dhpublicnumber
 # define EVP_PKEY_EC     NID_X9_62_id_ecPublicKey
+# define EVP_PKEY_SM2    NID_sm2
 # define EVP_PKEY_HMAC   NID_hmac
 # define EVP_PKEY_CMAC   NID_cmac
 
@@ -122,6 +123,12 @@
 extern "C" {
 #endif
 
+/*
+ * Don't free up md_ctx->pctx in EVP_MD_CTX_reset, use the reserved flag
+ * values in evp.h
+ */
+#define EVP_MD_CTX_FLAG_KEEP_PKEY_CTX   0x0400
+
 /*
  * Type needs to be a bit field Sub-type needs to be for variations on the
  * method, as in, can it do arbitrary encryption....
@@ -526,6 +533,9 @@ const EVP_MD *EVP_MD_CTX_md(const EVP_MD_CTX *ctx);
 # define EVP_MD_CTX_block_size(e)        EVP_MD_block_size(EVP_MD_CTX_md(e))
 # define EVP_MD_CTX_type(e)              EVP_MD_type(EVP_MD_CTX_md(e))
 
+void EVP_MD_CTX_set_pkey_ctx(EVP_MD_CTX *ctx, EVP_PKEY_CTX *pctx);
+void *EVP_MD_CTX_md_data(const EVP_MD_CTX *ctx);
+
 int EVP_CIPHER_nid(const EVP_CIPHER *cipher);
 # define EVP_CIPHER_name(e)              OBJ_nid2sn(EVP_CIPHER_nid(e))
 int EVP_CIPHER_block_size(const EVP_CIPHER *cipher);
@@ -583,6 +593,9 @@ int EVP_Cipher(EVP_CIPHER_CTX *c,
 # define EVP_delete_digest_alias(alias) \
         OBJ_NAME_remove(alias,OBJ_NAME_TYPE_MD_METH|OBJ_NAME_ALIAS);
 
+EVP_MD_CTX *EVP_MD_CTX_new(void);
+int EVP_MD_CTX_reset(EVP_MD_CTX *ctx);
+void EVP_MD_CTX_free(EVP_MD_CTX *ctx);
 void EVP_MD_CTX_init(EVP_MD_CTX *ctx);
 int EVP_MD_CTX_cleanup(EVP_MD_CTX *ctx);
 EVP_MD_CTX *EVP_MD_CTX_create(void);
@@ -666,6 +679,10 @@ int EVP_DigestVerifyInit(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx,
 int EVP_DigestVerifyFinal(EVP_MD_CTX *ctx,
                           const unsigned char *sig, size_t siglen);
 
+int EVP_DigestVerify(EVP_MD_CTX *ctx, const unsigned char *sigret,
+                            size_t siglen, const unsigned char *tbs,
+                            size_t tbslen);
+
 int EVP_OpenInit(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *type,
                  const unsigned char *ek, int ekl, const unsigned char *iv,
                  EVP_PKEY *priv);
@@ -741,6 +758,9 @@ const EVP_MD *EVP_ripemd160(void);
 # ifndef OPENSSL_NO_WHIRLPOOL
 const EVP_MD *EVP_whirlpool(void);
 # endif
+# ifndef OPENSSL_NO_SM3
+const EVP_MD *EVP_sm3(void);
+# endif
 const EVP_CIPHER *EVP_enc_null(void); /* does nothing :-) */
 # ifndef OPENSSL_NO_DES
 const EVP_CIPHER *EVP_des_ecb(void);
@@ -954,10 +974,15 @@ int EVP_PKEY_base_id(const EVP_PKEY *pkey);
 int EVP_PKEY_bits(EVP_PKEY *pkey);
 int EVP_PKEY_size(EVP_PKEY *pkey);
 int EVP_PKEY_set_type(EVP_PKEY *pkey, int type);
+int EVP_PKEY_set_alias_type(EVP_PKEY *pkey, int type);
 int EVP_PKEY_set_type_str(EVP_PKEY *pkey, const char *str, int len);
 int EVP_PKEY_assign(EVP_PKEY *pkey, int type, void *key);
 void *EVP_PKEY_get0(EVP_PKEY *pkey);
 
+# ifndef OPENSSL_NO_SM2
+int EVP_PKEY_is_sm2(EVP_PKEY *pkey);
+# endif
+
 # ifndef OPENSSL_NO_RSA
 struct rsa_st;
 int EVP_PKEY_set1_RSA(EVP_PKEY *pkey, struct rsa_st *key);
@@ -976,6 +1001,7 @@ struct dh_st *EVP_PKEY_get1_DH(EVP_PKEY *pkey);
 # ifndef OPENSSL_NO_EC
 struct ec_key_st;
 int EVP_PKEY_set1_EC_KEY(EVP_PKEY *pkey, struct ec_key_st *key);
+struct ec_key_st *EVP_PKEY_get0_EC_KEY(EVP_PKEY *pkey);
 struct ec_key_st *EVP_PKEY_get1_EC_KEY(EVP_PKEY *pkey);
 # endif
 
@@ -1268,7 +1294,6 @@ int EVP_PKEY_paramgen(EVP_PKEY_CTX *ctx, EVP_PKEY **ppkey);
 int EVP_PKEY_keygen_init(EVP_PKEY_CTX *ctx);
 int EVP_PKEY_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY **ppkey);
 
-void EVP_PKEY_CTX_set_cb(EVP_PKEY_CTX *ctx, EVP_PKEY_gen_cb *cb);
 EVP_PKEY_gen_cb *EVP_PKEY_CTX_get_cb(EVP_PKEY_CTX *ctx);
 
 int EVP_PKEY_CTX_get_keygen_info(EVP_PKEY_CTX *ctx, int idx);
diff --git a/Cryptlib/Include/openssl/obj_mac.h b/Cryptlib/Include/openssl/obj_mac.h
index 779c309..91b75e0 100644
--- a/Cryptlib/Include/openssl/obj_mac.h
+++ b/Cryptlib/Include/openssl/obj_mac.h
@@ -4192,3 +4192,36 @@
 #define LN_jurisdictionCountryName              "jurisdictionCountryName"
 #define NID_jurisdictionCountryName             957
 #define OBJ_jurisdictionCountryName             1L,3L,6L,1L,4L,1L,311L,60L,2L,1L,3L
+
+#define SN_ISO_CN               "ISO-CN"
+#define LN_ISO_CN               "ISO CN Member Body"
+#define NID_ISO_CN              958
+#define OBJ_ISO_CN              OBJ_member_body,156L
+
+#define SN_oscca                "oscca"
+#define NID_oscca               959
+#define OBJ_oscca               OBJ_ISO_CN,10197L
+
+#define SN_sm_scheme            "sm-scheme"
+#define NID_sm_scheme           960
+#define OBJ_sm_scheme           OBJ_oscca,1L
+
+#define SN_sm2          "SM2"
+#define LN_sm2          "sm2"
+#define NID_sm2         961
+#define OBJ_sm2         OBJ_sm_scheme,301L
+
+#define SN_sm3          "SM3"
+#define LN_sm3          "sm3"
+#define NID_sm3         962
+#define OBJ_sm3         OBJ_sm_scheme,401L
+
+#define SN_sm3WithRSAEncryption         "RSA-SM3"
+#define LN_sm3WithRSAEncryption         "sm3WithRSAEncryption"
+#define NID_sm3WithRSAEncryption                963
+#define OBJ_sm3WithRSAEncryption                OBJ_sm_scheme,504L
+
+#define SN_SM2_with_SM3         "SM2-SM3"
+#define LN_SM2_with_SM3         "SM2-with-SM3"
+#define NID_SM2_with_SM3                964
+#define OBJ_SM2_with_SM3                OBJ_sm_scheme,501L
diff --git a/Cryptlib/Include/openssl/opensslconf.h b/Cryptlib/Include/openssl/opensslconf.h
index 4a36e9f..12ec552 100644
--- a/Cryptlib/Include/openssl/opensslconf.h
+++ b/Cryptlib/Include/openssl/opensslconf.h
@@ -41,8 +41,8 @@ extern "C" {
 #ifndef OPENSSL_NO_DYNAMIC_ENGINE
 # define OPENSSL_NO_DYNAMIC_ENGINE
 #endif
-#ifndef OPENSSL_NO_EC
-# define OPENSSL_NO_EC
+#ifndef OPENSSL_NO_EC2M
+# define OPENSSL_NO_EC2M
 #endif
 #ifndef OPENSSL_NO_EC_NISTP_64_GCC_128
 # define OPENSSL_NO_EC_NISTP_64_GCC_128
@@ -50,9 +50,6 @@ extern "C" {
 #ifndef OPENSSL_NO_ECDH
 # define OPENSSL_NO_ECDH
 #endif
-#ifndef OPENSSL_NO_ECDSA
-# define OPENSSL_NO_ECDSA
-#endif
 #ifndef OPENSSL_NO_ENGINE
 # define OPENSSL_NO_ENGINE
 #endif
diff --git a/Cryptlib/Include/openssl/x509.h b/Cryptlib/Include/openssl/x509.h
index 6fa28eb..eda456b 100644
--- a/Cryptlib/Include/openssl/x509.h
+++ b/Cryptlib/Include/openssl/x509.h
@@ -237,6 +237,9 @@ typedef struct X509_req_st {
     X509_ALGOR *sig_alg;
     ASN1_BIT_STRING *signature;
     int references;
+# ifndef OPENSSL_NO_SM2
+    ASN1_OCTET_STRING *sm2_id;
+# endif
 } X509_REQ;
 
 typedef struct x509_cinf_st {
@@ -296,6 +299,10 @@ struct x509_st {
     unsigned char sha1_hash[SHA_DIGEST_LENGTH];
 # endif
     X509_CERT_AUX *aux;
+    volatile int ex_cached;
+# ifndef OPENSSL_NO_SM2
+    ASN1_OCTET_STRING *sm2_id;
+# endif
 } /* X509 */ ;
 
 DECLARE_STACK_OF(X509)
diff --git a/Cryptlib/Library/BaseCryptLib.h b/Cryptlib/Library/BaseCryptLib.h
index 2df8bd2..a7fea2c 100644
--- a/Cryptlib/Library/BaseCryptLib.h
+++ b/Cryptlib/Library/BaseCryptLib.h
@@ -52,6 +52,11 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 ///
 #define SHA512_DIGEST_SIZE  64
 
+///
+/// SM3 digest size in bytes
+///
+#define SM3_DIGEST_SIZE  32
+
 ///
 /// TDES block size in bytes
 ///
@@ -893,6 +898,112 @@ Sha512HashAll (
   OUT  UINT8       *HashValue
   );
 
+/**
+  Retrieves the size, in bytes, of the context buffer required for SM3 hash operations.
+  @return  The size, in bytes, of the context buffer required for SM3 hash operations.
+**/
+UINTN
+EFIAPI
+Sm3GetContextSize (
+  VOID
+  );
+
+/**
+  Initializes user-supplied memory pointed by Sm3Context as SM3 hash context for
+  subsequent use.
+  If Sm3Context is NULL, then return FALSE.
+  @param[out]  Sm3Context  Pointer to SM3 context being initialized.
+  @retval TRUE   SM3 context initialization succeeded.
+  @retval FALSE  SM3 context initialization failed.
+**/
+BOOLEAN
+EFIAPI
+Sm3Init (
+  OUT  VOID  *Sm3Context
+  );
+
+/**
+  Makes a copy of an existing SM3 context.
+  If Sm3Context is NULL, then return FALSE.
+  If NewSm3Context is NULL, then return FALSE.
+  If this interface is not supported, then return FALSE.
+  @param[in]  Sm3Context     Pointer to SM3 context being copied.
+  @param[out] NewSm3Context  Pointer to new SM3 context.
+  @retval TRUE   SM3 context copy succeeded.
+  @retval FALSE  SM3 context copy failed.
+  @retval FALSE  This interface is not supported.
+**/
+BOOLEAN
+EFIAPI
+Sm3Duplicate (
+  IN   CONST VOID  *Sm3Context,
+  OUT  VOID        *NewSm3Context
+  );
+
+/**
+  Digests the input data and updates SM3 context.
+  This function performs SM3 digest on a data buffer of the specified size.
+  It can be called multiple times to compute the digest of long or discontinuous data streams.
+  SM3 context should be already correctly initialized by Sm3Init(), and should not be finalied
+  by Sm3Final(). Behavior with invalid context is undefined.
+  If Sm3Context is NULL, then return FALSE.
+  @param[in, out]  Sm3Context     Pointer to the SM3 context.
+  @param[in]       Data           Pointer to the buffer containing the data to be hashed.
+  @param[in]       DataSize       Size of Data buffer in bytes.
+  @retval TRUE   SM3 data digest succeeded.
+  @retval FALSE  SM3 data digest failed.
+**/
+BOOLEAN
+EFIAPI
+Sm3Update (
+  IN OUT  VOID        *Sm3Context,
+  IN      CONST VOID  *Data,
+  IN      UINTN       DataSize
+  );
+
+/**
+  Completes computation of the SM3 digest value.
+  This function completes SM3 hash computation and retrieves the digest value into
+  the specified memory. After this function has been called, the SM3 context cannot
+  be used again.
+  SM3 context should be already correctly initialized by Sm3Init(), and should not be
+  finalized by Sm3Final(). Behavior with invalid SM3 context is undefined.
+  If Sm3Context is NULL, then return FALSE.
+  If HashValue is NULL, then return FALSE.
+  @param[in, out]  Sm3Context     Pointer to the SM3 context.
+  @param[out]      HashValue      Pointer to a buffer that receives the SM3 digest
+                                  value (32 bytes).
+  @retval TRUE   SM3 digest computation succeeded.
+  @retval FALSE  SM3 digest computation failed.
+**/
+BOOLEAN
+EFIAPI
+Sm3Final (
+  IN OUT  VOID   *Sm3Context,
+  OUT     UINT8  *HashValue
+  );
+
+/**
+  Computes the SM3 message digest of a input data buffer.
+  This function performs the SM3 message digest of a given data buffer, and places
+  the digest value into the specified memory.
+  If this interface is not supported, then return FALSE.
+  @param[in]   Data        Pointer to the buffer containing the data to be hashed.
+  @param[in]   DataSize    Size of Data buffer in bytes.
+  @param[out]  HashValue   Pointer to a buffer that receives the SM3 digest
+                           value (32 bytes).
+  @retval TRUE   SM3 digest computation succeeded.
+  @retval FALSE  SM3 digest computation failed.
+  @retval FALSE  This interface is not supported.
+**/
+BOOLEAN
+EFIAPI
+Sm3HashAll (
+  IN   CONST VOID  *Data,
+  IN   UINTN       DataSize,
+  OUT  UINT8       *HashValue
+  );
+
 //=====================================================================================
 //    MAC (Message Authentication Code) Primitive
 //=====================================================================================
diff --git a/Cryptlib/Makefile b/Cryptlib/Makefile
index 89fd5cd..c95a960 100644
--- a/Cryptlib/Makefile
+++ b/Cryptlib/Makefile
@@ -66,6 +66,12 @@ OBJS		=   Hash/CryptMd4Null.o \
 		    SysCall/BaseMemAllocation.o \
 		    SysCall/BaseStrings.o
 
+ifdef ENABLE_SHIM_SM
+OBJS		+=  Hash/CryptSm3.o
+else
+DEFINES		+= -DOPENSSL_NO_SM3
+endif
+
 all: $(TARGET)
 
 libcryptlib.a: $(OBJS)
diff --git a/Cryptlib/OpenSSL/Makefile b/Cryptlib/OpenSSL/Makefile
index 795f471..4923ac3 100644
--- a/Cryptlib/OpenSSL/Makefile
+++ b/Cryptlib/OpenSSL/Makefile
@@ -459,7 +459,43 @@ OBJS		= crypto/cryptlib.o \
 		  crypto/ocsp/ocsp_err.o \
 		  crypto/cmac/cmac.o \
 		  crypto/cmac/cm_ameth.o \
-		  crypto/cmac/cm_pmeth.o \
+		  crypto/cmac/cm_pmeth.o
+
+ifdef ENABLE_SHIM_SM
+OBJS		+=crypto/ec/ec_ameth.o \
+		  crypto/ec/ec_cvt.o \
+		  crypto/ec/eck_prn.o \
+		  crypto/ec/ec_oct.o \
+		  crypto/ec/ecp_smpl.o \
+		  crypto/ec/ec_asn1.o \
+		  crypto/ec/ec_err.o \
+		  crypto/ec/ec_pmeth.o \
+		  crypto/ec/ec_check.o \
+		  crypto/ec/ec_lib.o \
+		  crypto/ec/ecp_mont.o \
+		  crypto/ec/ecp_oct.o \
+		  crypto/ec/ec_curve.o \
+		  crypto/ec/ec_key.o \
+		  crypto/ec/ec_mult.o \
+		  crypto/ec/ecp_nist.o \
+		  crypto/ec/ec_print.o \
+		  crypto/ecdsa/ecs_asn1.o \
+		  crypto/ecdsa/ecs_err.o \
+		  crypto/ecdsa/ecs_lib.o \
+		  crypto/ecdsa/ecs_ossl.o \
+		  crypto/ecdsa/ecs_sign.o \
+		  crypto/ecdsa/ecs_vrf.o \
+		  crypto/sm3/sm3.o \
+		  crypto/sm3/m_sm3.o \
+		  crypto/sm2/sm2_err.o \
+		  crypto/sm2/sm2_pmeth.o \
+		  crypto/sm2/sm2_sign.o
+else
+DEFINES		+=-DOPENSSL_NO_EC \
+		  -DOPENSSL_NO_ECDSA \
+		  -DOPENSSL_NO_SM2 \
+		  -DOPENSSL_NO_SM3
+endif
 
 all: $(TARGET)
 
diff --git a/Cryptlib/OpenSSL/crypto/asn1/a_sign.c b/Cryptlib/OpenSSL/crypto/asn1/a_sign.c
index 51c6a0c..68a2ae6 100644
--- a/Cryptlib/OpenSSL/crypto/asn1/a_sign.c
+++ b/Cryptlib/OpenSSL/crypto/asn1/a_sign.c
@@ -238,7 +238,7 @@ int ASN1_item_sign_ctx(const ASN1_ITEM *it,
     unsigned char *buf_in = NULL, *buf_out = NULL;
     size_t inl = 0, outl = 0, outll = 0;
     int signid, paramtype;
-    int rv;
+    int rv, pkey_id;
 
     type = EVP_MD_CTX_md(ctx);
     pkey = EVP_PKEY_CTX_get0_pkey(ctx->pctx);
@@ -268,10 +268,17 @@ int ASN1_item_sign_ctx(const ASN1_ITEM *it,
 
     if (rv == 2) {
         if (type->flags & EVP_MD_FLAG_PKEY_METHOD_SIGNATURE) {
+
+            pkey_id =
+#ifndef OPENSSL_NO_SM2
+            EVP_PKEY_id(pkey) == NID_sm2 ? NID_sm2 :
+#endif
+            pkey->ameth->pkey_id;
+
             if (!pkey->ameth ||
                 !OBJ_find_sigid_by_algs(&signid,
                                         EVP_MD_nid(type),
-                                        pkey->ameth->pkey_id)) {
+                                        pkey_id)) {
                 ASN1err(ASN1_F_ASN1_ITEM_SIGN_CTX,
                         ASN1_R_DIGEST_AND_KEY_TYPE_NOT_SUPPORTED);
                 return 0;
diff --git a/Cryptlib/OpenSSL/crypto/asn1/ameth_lib.c b/Cryptlib/OpenSSL/crypto/asn1/ameth_lib.c
index 43ddebb..db3d27d 100644
--- a/Cryptlib/OpenSSL/crypto/asn1/ameth_lib.c
+++ b/Cryptlib/OpenSSL/crypto/asn1/ameth_lib.c
@@ -64,6 +64,7 @@
 # include <openssl/engine.h>
 #endif
 #include "asn1_locl.h"
+#include <openssl/evp.h>
 
 extern const EVP_PKEY_ASN1_METHOD rsa_asn1_meths[];
 extern const EVP_PKEY_ASN1_METHOD dsa_asn1_meths[];
@@ -72,6 +73,8 @@ extern const EVP_PKEY_ASN1_METHOD dhx_asn1_meth;
 extern const EVP_PKEY_ASN1_METHOD eckey_asn1_meth;
 extern const EVP_PKEY_ASN1_METHOD hmac_asn1_meth;
 extern const EVP_PKEY_ASN1_METHOD cmac_asn1_meth;
+extern const EVP_PKEY_ASN1_METHOD sm2_asn1_meth;
+
 
 /* Keep this sorted in type order !! */
 static const EVP_PKEY_ASN1_METHOD *standard_methods[] = {
@@ -97,7 +100,10 @@ static const EVP_PKEY_ASN1_METHOD *standard_methods[] = {
     &cmac_asn1_meth,
 #endif
 #ifndef OPENSSL_NO_DH
-    &dhx_asn1_meth
+    &dhx_asn1_meth,
+#endif
+#ifndef OPENSSL_NO_SM2
+    &sm2_asn1_meth,
 #endif
 };
 
diff --git a/Cryptlib/OpenSSL/crypto/asn1/x_req.c b/Cryptlib/OpenSSL/crypto/asn1/x_req.c
index ae293aa..575564e 100644
--- a/Cryptlib/OpenSSL/crypto/asn1/x_req.c
+++ b/Cryptlib/OpenSSL/crypto/asn1/x_req.c
@@ -114,3 +114,16 @@ ASN1_SEQUENCE_ref(X509_REQ, 0, CRYPTO_LOCK_X509_REQ) = {
 IMPLEMENT_ASN1_FUNCTIONS(X509_REQ)
 
 IMPLEMENT_ASN1_DUP_FUNCTION(X509_REQ)
+
+#ifndef OPENSSL_NO_SM2
+void X509_REQ_set0_sm2_id(X509_REQ *x, ASN1_OCTET_STRING *sm2_id)
+{
+    ASN1_OCTET_STRING_free(x->sm2_id);
+    x->sm2_id = sm2_id;
+}
+
+ASN1_OCTET_STRING *X509_REQ_get0_sm2_id(X509_REQ *x)
+{
+    return x->sm2_id;
+}
+#endif
diff --git a/Cryptlib/OpenSSL/crypto/asn1/x_x509.c b/Cryptlib/OpenSSL/crypto/asn1/x_x509.c
index aada4a8..8969918 100644
--- a/Cryptlib/OpenSSL/crypto/asn1/x_x509.c
+++ b/Cryptlib/OpenSSL/crypto/asn1/x_x509.c
@@ -98,6 +98,9 @@ static int x509_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it,
 #ifndef OPENSSL_NO_RFC3779
         ret->rfc3779_addr = NULL;
         ret->rfc3779_asid = NULL;
+#endif
+#ifndef OPENSSL_NO_SM2
+        ret->sm2_id = NULL;
 #endif
         ret->aux = NULL;
         ret->crldp = NULL;
@@ -123,6 +126,9 @@ static int x509_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it,
         sk_IPAddressFamily_pop_free(ret->rfc3779_addr, IPAddressFamily_free);
         ASIdentifiers_free(ret->rfc3779_asid);
 #endif
+#ifndef OPENSSL_NO_SM2
+        ASN1_OCTET_STRING_free(ret->sm2_id);
+#endif
 
         if (ret->name != NULL)
             OPENSSL_free(ret->name);
diff --git a/Cryptlib/OpenSSL/crypto/bn/bn_lib.c b/Cryptlib/OpenSSL/crypto/bn/bn_lib.c
index 2671f35..10b78f5 100644
--- a/Cryptlib/OpenSSL/crypto/bn/bn_lib.c
+++ b/Cryptlib/OpenSSL/crypto/bn/bn_lib.c
@@ -496,9 +496,6 @@ BIGNUM *BN_copy(BIGNUM *a, const BIGNUM *b)
     if (bn_wexpand(a, b->top) == NULL)
         return (NULL);
 
-    if (!a || !b || !a->d || !b->d)
-        return (NULL);
-
 #if 1
     A = a->d;
     B = b->d;
diff --git a/Cryptlib/OpenSSL/crypto/err/err.c b/Cryptlib/OpenSSL/crypto/err/err.c
index e225145..aac5956 100644
--- a/Cryptlib/OpenSSL/crypto/err/err.c
+++ b/Cryptlib/OpenSSL/crypto/err/err.c
@@ -155,6 +155,7 @@ static ERR_STRING_DATA ERR_str_libraries[] = {
     {ERR_PACK(ERR_LIB_FIPS, 0, 0), "FIPS routines"},
     {ERR_PACK(ERR_LIB_CMS, 0, 0), "CMS routines"},
     {ERR_PACK(ERR_LIB_HMAC, 0, 0), "HMAC routines"},
+    {ERR_PACK(ERR_LIB_SM2, 0, 0), "SM2 routines"},
     {0, NULL},
 };
 
diff --git a/Cryptlib/OpenSSL/crypto/evp/c_alld.c b/Cryptlib/OpenSSL/crypto/evp/c_alld.c
index fdbe3ee..6cad383 100644
--- a/Cryptlib/OpenSSL/crypto/evp/c_alld.c
+++ b/Cryptlib/OpenSSL/crypto/evp/c_alld.c
@@ -111,4 +111,7 @@ void OpenSSL_add_all_digests(void)
 #ifndef OPENSSL_NO_WHIRLPOOL
     EVP_add_digest(EVP_whirlpool());
 #endif
+#ifndef OPENSSL_NO_SM3
+    EVP_add_digest(EVP_sm3());
+#endif
 }
diff --git a/Cryptlib/OpenSSL/crypto/evp/digest.c b/Cryptlib/OpenSSL/crypto/evp/digest.c
index 4db1796..ffc03ef 100644
--- a/Cryptlib/OpenSSL/crypto/evp/digest.c
+++ b/Cryptlib/OpenSSL/crypto/evp/digest.c
@@ -122,6 +122,48 @@
 # include "evp_locl.h"
 #endif
 
+/* This call frees resources associated with the context */
+int EVP_MD_CTX_reset(EVP_MD_CTX *ctx)
+{
+    if (ctx == NULL)
+        return 1;
+
+    /*
+     * Don't assume ctx->md_data was cleaned in EVP_Digest_Final, because
+     * sometimes only copies of the context are ever finalised.
+     */
+    if (ctx->digest && ctx->digest->cleanup
+        && !EVP_MD_CTX_test_flags(ctx, EVP_MD_CTX_FLAG_CLEANED))
+        ctx->digest->cleanup(ctx);
+    if (ctx->digest && ctx->digest->ctx_size && ctx->md_data
+        && !EVP_MD_CTX_test_flags(ctx, EVP_MD_CTX_FLAG_REUSE)) {
+        OPENSSL_clear_free(ctx->md_data, ctx->digest->ctx_size);
+    }
+    /*
+     * pctx should be freed by the user of EVP_MD_CTX
+     * if EVP_MD_CTX_FLAG_KEEP_PKEY_CTX is set
+     */
+    if (!EVP_MD_CTX_test_flags(ctx, EVP_MD_CTX_FLAG_KEEP_PKEY_CTX))
+        EVP_PKEY_CTX_free(ctx->pctx);
+#ifndef OPENSSL_NO_ENGINE
+    ENGINE_finish(ctx->engine);
+#endif
+    OPENSSL_cleanse(ctx, sizeof(*ctx));
+
+    return 1;
+}
+
+EVP_MD_CTX *EVP_MD_CTX_new(void)
+{
+    return OPENSSL_zalloc(sizeof(EVP_MD_CTX));
+}
+
+void EVP_MD_CTX_free(EVP_MD_CTX *ctx)
+{
+    EVP_MD_CTX_reset(ctx);
+    OPENSSL_free(ctx);
+}
+
 void EVP_MD_CTX_init(EVP_MD_CTX *ctx)
 {
     memset(ctx, '\0', sizeof *ctx);
@@ -139,7 +181,7 @@ EVP_MD_CTX *EVP_MD_CTX_create(void)
 
 int EVP_DigestInit(EVP_MD_CTX *ctx, const EVP_MD *type)
 {
-    EVP_MD_CTX_init(ctx);
+    EVP_MD_CTX_reset(ctx);
     return EVP_DigestInit_ex(ctx, type, NULL);
 }
 
@@ -264,7 +306,7 @@ int EVP_DigestFinal(EVP_MD_CTX *ctx, unsigned char *md, unsigned int *size)
 {
     int ret;
     ret = EVP_DigestFinal_ex(ctx, md, size);
-    EVP_MD_CTX_cleanup(ctx);
+    EVP_MD_CTX_reset(ctx);
     return ret;
 }
 
@@ -291,7 +333,7 @@ int EVP_DigestFinal_ex(EVP_MD_CTX *ctx, unsigned char *md, unsigned int *size)
 
 int EVP_MD_CTX_copy(EVP_MD_CTX *out, const EVP_MD_CTX *in)
 {
-    EVP_MD_CTX_init(out);
+    EVP_MD_CTX_reset(out);
     return EVP_MD_CTX_copy_ex(out, in);
 }
 
@@ -315,9 +357,19 @@ int EVP_MD_CTX_copy_ex(EVP_MD_CTX *out, const EVP_MD_CTX *in)
         EVP_MD_CTX_set_flags(out, EVP_MD_CTX_FLAG_REUSE);
     } else
         tmp_buf = NULL;
-    EVP_MD_CTX_cleanup(out);
+    EVP_MD_CTX_reset(out);
     memcpy(out, in, sizeof *out);
 
+    /* copied EVP_MD_CTX should free the copied EVP_PKEY_CTX */
+    EVP_MD_CTX_clear_flags(out, EVP_MD_CTX_FLAG_KEEP_PKEY_CTX);
+
+    /* Null these variables, since they are getting fixed up
+     * properly below.  Anything else may cause a memleak and/or
+     * double free if any of the memory allocations below fail
+     */
+    out->md_data = NULL;
+    out->pctx = NULL;
+
     if (in->md_data && out->digest->ctx_size) {
         if (tmp_buf)
             out->md_data = tmp_buf;
@@ -336,7 +388,7 @@ int EVP_MD_CTX_copy_ex(EVP_MD_CTX *out, const EVP_MD_CTX *in)
     if (in->pctx) {
         out->pctx = EVP_PKEY_CTX_dup(in->pctx);
         if (!out->pctx) {
-            EVP_MD_CTX_cleanup(out);
+            EVP_MD_CTX_reset(out);
             return 0;
         }
     }
diff --git a/Cryptlib/OpenSSL/crypto/evp/evp_lib.c b/Cryptlib/OpenSSL/crypto/evp/evp_lib.c
index 7e0bab9..24da25d 100644
--- a/Cryptlib/OpenSSL/crypto/evp/evp_lib.c
+++ b/Cryptlib/OpenSSL/crypto/evp/evp_lib.c
@@ -389,3 +389,27 @@ int EVP_CIPHER_CTX_test_flags(const EVP_CIPHER_CTX *ctx, int flags)
 {
     return (ctx->flags & flags);
 }
+
+void *EVP_MD_CTX_md_data(const EVP_MD_CTX *ctx)
+{
+	return ctx->md_data;
+}
+
+void EVP_MD_CTX_set_pkey_ctx(EVP_MD_CTX *ctx, EVP_PKEY_CTX *pctx)
+{
+    /*
+     * it's reasonable to set NULL pctx (a.k.a clear the ctx->pctx), so
+     * we have to deal with the cleanup job here.
+     */
+    if (!EVP_MD_CTX_test_flags(ctx, EVP_MD_CTX_FLAG_KEEP_PKEY_CTX))
+        EVP_PKEY_CTX_free(ctx->pctx);
+
+    ctx->pctx = pctx;
+
+    if (pctx != NULL) {
+        /* make sure pctx is not freed when destroying EVP_MD_CTX */
+        EVP_MD_CTX_set_flags(ctx, EVP_MD_CTX_FLAG_KEEP_PKEY_CTX);
+    } else {
+        EVP_MD_CTX_clear_flags(ctx, EVP_MD_CTX_FLAG_KEEP_PKEY_CTX);
+    }
+}
diff --git a/Cryptlib/OpenSSL/crypto/evp/evp_locl.h b/Cryptlib/OpenSSL/crypto/evp/evp_locl.h
index 2bb709a..1d179ef 100644
--- a/Cryptlib/OpenSSL/crypto/evp/evp_locl.h
+++ b/Cryptlib/OpenSSL/crypto/evp/evp_locl.h
@@ -324,6 +324,16 @@ struct evp_pkey_method_st {
     int (*derive) (EVP_PKEY_CTX *ctx, unsigned char *key, size_t *keylen);
     int (*ctrl) (EVP_PKEY_CTX *ctx, int type, int p1, void *p2);
     int (*ctrl_str) (EVP_PKEY_CTX *ctx, const char *type, const char *value);
+    int (*digestsign) (EVP_MD_CTX *ctx, unsigned char *sig, size_t *siglen,
+                       const unsigned char *tbs, size_t tbslen);
+    int (*digestverify) (EVP_MD_CTX *ctx, const unsigned char *sig,
+                         size_t siglen, const unsigned char *tbs,
+                         size_t tbslen);
+    int (*check) (EVP_PKEY *pkey);
+    int (*public_check) (EVP_PKEY *pkey);
+    int (*param_check) (EVP_PKEY *pkey);
+
+    int (*digest_custom) (EVP_PKEY_CTX *ctx, EVP_MD_CTX *mctx);
 } /* EVP_PKEY_METHOD */ ;
 
 void evp_pkey_set_cb_translate(BN_GENCB *cb, EVP_PKEY_CTX *ctx);
diff --git a/Cryptlib/OpenSSL/crypto/evp/m_sigver.c b/Cryptlib/OpenSSL/crypto/evp/m_sigver.c
index 4492d20..771b659 100644
--- a/Cryptlib/OpenSSL/crypto/evp/m_sigver.c
+++ b/Cryptlib/OpenSSL/crypto/evp/m_sigver.c
@@ -110,6 +110,13 @@ static int do_sigver_init(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx,
         return 1;
     if (!EVP_DigestInit_ex(ctx, type, e))
         return 0;
+    /*
+     * This indicates the current algorithm requires
+     * special treatment before hashing the tbs-message.
+     */
+    if (ctx->pctx->pmeth->digest_custom != NULL)
+        return ctx->pctx->pmeth->digest_custom(ctx->pctx, ctx);
+
     return 1;
 }
 
@@ -201,3 +208,13 @@ int EVP_DigestVerifyFinal(EVP_MD_CTX *ctx, const unsigned char *sig,
         return r;
     return EVP_PKEY_verify(ctx->pctx, sig, siglen, md, mdlen);
 }
+
+int EVP_DigestVerify(EVP_MD_CTX *ctx, const unsigned char *sigret,
+                     size_t siglen, const unsigned char *tbs, size_t tbslen)
+{
+    if (ctx->pctx->pmeth->digestverify != NULL)
+        return ctx->pctx->pmeth->digestverify(ctx, sigret, siglen, tbs, tbslen);
+    if (EVP_DigestVerifyUpdate(ctx, tbs, tbslen) <= 0)
+        return -1;
+    return EVP_DigestVerifyFinal(ctx, sigret, siglen);
+}
diff --git a/Cryptlib/OpenSSL/crypto/evp/p_lib.c b/Cryptlib/OpenSSL/crypto/evp/p_lib.c
index 545d04f..c95d038 100644
--- a/Cryptlib/OpenSSL/crypto/evp/p_lib.c
+++ b/Cryptlib/OpenSSL/crypto/evp/p_lib.c
@@ -259,6 +259,24 @@ int EVP_PKEY_set_type_str(EVP_PKEY *pkey, const char *str, int len)
     return pkey_set_type(pkey, EVP_PKEY_NONE, str, len);
 }
 
+int EVP_PKEY_set_alias_type(EVP_PKEY *pkey, int type)
+{
+    if (pkey->type == type) {
+        return 1; /* it already is that type */
+    }
+
+    /*
+     * The application is requesting to alias this to a different pkey type,
+     * but not one that resolves to the base type.
+     */
+    if (EVP_PKEY_type(type) != EVP_PKEY_base_id(pkey)) {
+        return 0;
+    }
+
+    pkey->type = type;
+    return 1;
+}
+
 int EVP_PKEY_assign(EVP_PKEY *pkey, int type, void *key)
 {
     if (pkey == NULL || !EVP_PKEY_set_type(pkey, type))
@@ -272,6 +290,24 @@ void *EVP_PKEY_get0(EVP_PKEY *pkey)
     return pkey->pkey.ptr;
 }
 
+# ifndef OPENSSL_NO_SM2
+int EVP_PKEY_is_sm2(EVP_PKEY *pkey)
+{
+    EC_KEY *eckey;
+    const EC_GROUP *group;
+    if (pkey == NULL) {
+        return 0;
+    }
+    if (EVP_PKEY_id(pkey) == EVP_PKEY_EC
+        && (eckey = EVP_PKEY_get1_EC_KEY(pkey)) != NULL
+        && (group = EC_KEY_get0_group(eckey)) != NULL
+        && EC_GROUP_get_curve_name(group) == NID_sm2) {
+            return 1;
+    }
+    return EVP_PKEY_id(pkey) == EVP_PKEY_SM2;
+}
+# endif
+
 #ifndef OPENSSL_NO_RSA
 int EVP_PKEY_set1_RSA(EVP_PKEY *pkey, RSA *key)
 {
@@ -322,6 +358,14 @@ int EVP_PKEY_set1_EC_KEY(EVP_PKEY *pkey, EC_KEY *key)
     return ret;
 }
 
+EC_KEY *EVP_PKEY_get0_EC_KEY(EVP_PKEY *pkey)
+{
+    if (EVP_PKEY_base_id(pkey) != EVP_PKEY_EC) {
+        return NULL;
+    }
+    return pkey->pkey.ec;
+}
+
 EC_KEY *EVP_PKEY_get1_EC_KEY(EVP_PKEY *pkey)
 {
     if (pkey->type != EVP_PKEY_EC) {
diff --git a/Cryptlib/OpenSSL/crypto/evp/pmeth_lib.c b/Cryptlib/OpenSSL/crypto/evp/pmeth_lib.c
index d066862..8e52917 100644
--- a/Cryptlib/OpenSSL/crypto/evp/pmeth_lib.c
+++ b/Cryptlib/OpenSSL/crypto/evp/pmeth_lib.c
@@ -75,7 +75,7 @@ STACK_OF(EVP_PKEY_METHOD) *app_pkey_methods = NULL;
 
 extern const EVP_PKEY_METHOD rsa_pkey_meth, dh_pkey_meth, dsa_pkey_meth;
 extern const EVP_PKEY_METHOD ec_pkey_meth, hmac_pkey_meth, cmac_pkey_meth;
-extern const EVP_PKEY_METHOD dhx_pkey_meth;
+extern const EVP_PKEY_METHOD dhx_pkey_meth, sm2_pkey_meth;
 
 static const EVP_PKEY_METHOD *standard_methods[] = {
 #ifndef OPENSSL_NO_RSA
@@ -95,7 +95,10 @@ static const EVP_PKEY_METHOD *standard_methods[] = {
     &cmac_pkey_meth,
 #endif
 #ifndef OPENSSL_NO_DH
-    &dhx_pkey_meth
+    &dhx_pkey_meth,
+#endif
+#ifndef OPENSSL_NO_SM2
+    &sm2_pkey_meth,
 #endif
 };
 
@@ -135,9 +138,9 @@ static EVP_PKEY_CTX *int_ctx_new(EVP_PKEY *pkey, ENGINE *e, int id)
     EVP_PKEY_CTX *ret;
     const EVP_PKEY_METHOD *pmeth;
     if (id == -1) {
-        if (!pkey || !pkey->ameth)
+        if (!pkey)
             return NULL;
-        id = pkey->ameth->pkey_id;
+        id = pkey->type;
     }
 #ifndef OPENSSL_NO_ENGINE
     if (pkey && pkey->engine)
@@ -365,6 +368,10 @@ int EVP_PKEY_CTX_ctrl(EVP_PKEY_CTX *ctx, int keytype, int optype,
     if ((keytype != -1) && (ctx->pmeth->pkey_id != keytype))
         return -1;
 
+/* Skip the operation checks since this is called in a very early stage */
+    if (ctx->pmeth->digest_custom != NULL)
+        goto doit;
+
     if (ctx->operation == EVP_PKEY_OP_UNDEFINED) {
         EVPerr(EVP_F_EVP_PKEY_CTX_CTRL, EVP_R_NO_OPERATION_SET);
         return -1;
@@ -375,6 +382,7 @@ int EVP_PKEY_CTX_ctrl(EVP_PKEY_CTX *ctx, int keytype, int optype,
         return -1;
     }
 
+doit:
     ret = ctx->pmeth->ctrl(ctx, cmd, p1, p2);
 
     if (ret == -2)
diff --git a/Cryptlib/OpenSSL/crypto/mem.c b/Cryptlib/OpenSSL/crypto/mem.c
index 06c3960..ae5a165 100644
--- a/Cryptlib/OpenSSL/crypto/mem.c
+++ b/Cryptlib/OpenSSL/crypto/mem.c
@@ -456,3 +456,21 @@ long CRYPTO_get_mem_debug_options(void)
         return get_debug_options_func();
     return 0;
 }
+
+void *CRYPTO_zalloc(int num, const char *file, int line)
+{
+    void *ret = CRYPTO_malloc(num, file, line);
+
+    if (ret != NULL)
+        memset(ret, 0, num);
+    return ret;
+}
+
+void CRYPTO_clear_free(void *str, int num, const char *file, int line)
+{
+    if (str == NULL)
+        return;
+    if (num)
+        OPENSSL_cleanse(str, num);
+    CRYPTO_free(str);
+}
diff --git a/Cryptlib/OpenSSL/crypto/o_str.c b/Cryptlib/OpenSSL/crypto/o_str.c
index 7e61cde..c46c631 100644
--- a/Cryptlib/OpenSSL/crypto/o_str.c
+++ b/Cryptlib/OpenSSL/crypto/o_str.c
@@ -60,6 +60,8 @@
 #include <ctype.h>
 #include <e_os.h>
 #include "o_str.h"
+#include "openssl/crypto.h"
+#include "openssl/err.h"
 
 #if !defined(OPENSSL_IMPLEMENTS_strncasecmp) && \
     !defined(OPENSSL_SYSNAME_WIN32) && !defined(OPENSSL_SYSNAME_WINCE) && \
@@ -114,3 +116,88 @@ int OPENSSL_memcmp(const void *v1, const void *v2, size_t n)
 
     return ret;
 }
+
+int OPENSSL_hexchar2int(unsigned char c)
+{
+#ifdef CHARSET_EBCDIC
+    c = os_toebcdic[c];
+#endif
+
+    switch (c) {
+    case '0':
+        return 0;
+    case '1':
+        return 1;
+    case '2':
+        return 2;
+    case '3':
+        return 3;
+    case '4':
+          return 4;
+    case '5':
+          return 5;
+    case '6':
+          return 6;
+    case '7':
+          return 7;
+    case '8':
+          return 8;
+    case '9':
+          return 9;
+    case 'a': case 'A':
+          return 0x0A;
+    case 'b': case 'B':
+          return 0x0B;
+    case 'c': case 'C':
+          return 0x0C;
+    case 'd': case 'D':
+          return 0x0D;
+    case 'e': case 'E':
+          return 0x0E;
+    case 'f': case 'F':
+          return 0x0F;
+    }
+    return -1;
+}
+
+/*
+ * Give a string of hex digits convert to a buffer
+ */
+unsigned char *OPENSSL_hexstr2buf(const char *str, long *len)
+{
+    unsigned char *hexbuf, *q;
+    unsigned char ch, cl;
+    int chi, cli;
+    const unsigned char *p;
+    size_t s;
+
+    s = strlen(str);
+    if ((hexbuf = OPENSSL_malloc(s >> 1)) == NULL) {
+        CRYPTOerr(CRYPTO_F_OPENSSL_HEXSTR2BUF, ERR_R_MALLOC_FAILURE);
+        return NULL;
+    }
+    for (p = (const unsigned char *)str, q = hexbuf; *p; ) {
+        ch = *p++;
+        if (ch == ':')
+            continue;
+        cl = *p++;
+        if (!cl) {
+            CRYPTOerr(CRYPTO_F_OPENSSL_HEXSTR2BUF,
+                      CRYPTO_R_ODD_NUMBER_OF_DIGITS);
+            OPENSSL_free(hexbuf);
+            return NULL;
+        }
+        cli = OPENSSL_hexchar2int(cl);
+        chi = OPENSSL_hexchar2int(ch);
+        if (cli < 0 || chi < 0) {
+            OPENSSL_free(hexbuf);
+            CRYPTOerr(CRYPTO_F_OPENSSL_HEXSTR2BUF, CRYPTO_R_ILLEGAL_HEX_DIGIT);
+            return NULL;
+        }
+        *q++ = (unsigned char)((chi << 4) | cli);
+    }
+
+    if (len)
+        *len = q - hexbuf;
+    return hexbuf;
+}
diff --git a/Cryptlib/OpenSSL/crypto/objects/obj_dat.h b/Cryptlib/OpenSSL/crypto/objects/obj_dat.h
index b7e3cf2..30ea261 100644
--- a/Cryptlib/OpenSSL/crypto/objects/obj_dat.h
+++ b/Cryptlib/OpenSSL/crypto/objects/obj_dat.h
@@ -62,12 +62,12 @@
  * [including the GNU Public Licence.]
  */
 
-#define NUM_NID 958
-#define NUM_SN 951
-#define NUM_LN 951
-#define NUM_OBJ 890
+#define NUM_NID 965
+#define NUM_SN 958
+#define NUM_LN 958
+#define NUM_OBJ 897
 
-static const unsigned char lvalues[6255]={
+static const unsigned char lvalues[6301]={
 0x2A,0x86,0x48,0x86,0xF7,0x0D,               /* [  0] OBJ_rsadsi */
 0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,          /* [  6] OBJ_pkcs */
 0x2A,0x86,0x48,0x86,0xF7,0x0D,0x02,0x02,     /* [ 13] OBJ_md2 */
@@ -952,6 +952,13 @@ static const unsigned char lvalues[6255]={
 0x2B,0x06,0x01,0x04,0x01,0x82,0x37,0x3C,0x02,0x01,0x01,/* [6221] OBJ_jurisdictionLocalityName */
 0x2B,0x06,0x01,0x04,0x01,0x82,0x37,0x3C,0x02,0x01,0x02,/* [6232] OBJ_jurisdictionStateOrProvinceName */
 0x2B,0x06,0x01,0x04,0x01,0x82,0x37,0x3C,0x02,0x01,0x03,/* [6243] OBJ_jurisdictionCountryName */
+0x2A,0x81,0x1C,                              /* [6254] OBJ_ISO_CN */
+0x2A,0x81,0x1C,0xCF,0x55,                    /* [6257] OBJ_oscca */
+0x2A,0x81,0x1C,0xCF,0x55,0x01,               /* [6262] OBJ_sm_scheme */
+0x2A,0x81,0x1C,0xCF,0x55,0x01,0x82,0x2D,     /* [6268] OBJ_sm2 */
+0x2A,0x81,0x1C,0xCF,0x55,0x01,0x83,0x11,     /* [6276] OBJ_sm3 */
+0x2A,0x81,0x1C,0xCF,0x55,0x01,0x83,0x78,     /* [6284] OBJ_sm3WithRSAEncryption */
+0x2A,0x81,0x1C,0xCF,0x55,0x01,0x83,0x75,     /* [6292] OBJ_SM2_with_SM3 */
 };
 
 static const ASN1_OBJECT nid_objs[NUM_NID]={
@@ -2514,6 +2521,14 @@ static const ASN1_OBJECT nid_objs[NUM_NID]={
 	NID_jurisdictionStateOrProvinceName,11,&(lvalues[6232]),0},
 {"jurisdictionC","jurisdictionCountryName",
 	NID_jurisdictionCountryName,11,&(lvalues[6243]),0},
+{"ISO-CN","ISO CN Member Body",NID_ISO_CN,3,&(lvalues[6254]),0},
+{"oscca","oscca",NID_oscca,5,&(lvalues[6257]),0},
+{"sm-scheme","sm-scheme",NID_sm_scheme,6,&(lvalues[6262]),0},
+{"SM2","sm2",NID_sm2,8,&(lvalues[6268]),0},
+{"SM3","sm3",NID_sm3,8,&(lvalues[6276]),0},
+{"RSA-SM3","sm3WithRSAEncryption",NID_sm3WithRSAEncryption,8,
+	&(lvalues[6284]),0},
+{"SM2-SM3","SM2-with-SM3",NID_SM2_with_SM3,8,&(lvalues[6292]),0},
 };
 
 static const unsigned int sn_objs[NUM_SN]={
@@ -2615,6 +2630,7 @@ static const unsigned int sn_objs[NUM_SN]={
 36,	/* "IDEA-ECB" */
 46,	/* "IDEA-OFB" */
 181,	/* "ISO" */
+958,	/* "ISO-CN" */
 183,	/* "ISO-US" */
 645,	/* "ITU-T" */
 646,	/* "JOINT-ISO-ITU-T" */
@@ -2685,6 +2701,10 @@ static const unsigned int sn_objs[NUM_SN]={
 668,	/* "RSA-SHA256" */
 669,	/* "RSA-SHA384" */
 670,	/* "RSA-SHA512" */
+963,	/* "RSA-SM3" */
+961,	/* "SM2" */
+964,	/* "SM2-SM3" */
+962,	/* "SM3" */
 919,	/* "RSAES-OAEP" */
 912,	/* "RSASSA-PSS" */
 777,	/* "SEED-CBC" */
@@ -3176,6 +3196,7 @@ static const unsigned int sn_objs[NUM_SN]={
 77,	/* "nsSslServerName" */
 681,	/* "onBasis" */
 491,	/* "organizationalStatus" */
+959,	/* "oscca" */
 475,	/* "otherMailbox" */
 876,	/* "owner" */
 489,	/* "pagerTelephoneNumber" */
@@ -3422,6 +3443,7 @@ static const unsigned int sn_objs[NUM_SN]={
 52,	/* "signingTime" */
 454,	/* "simpleSecurityObject" */
 496,	/* "singleLevelQuality" */
+960,	/* "sm-scheme" */
 387,	/* "snmpv2" */
 660,	/* "street" */
 85,	/* "subjectAltName" */
@@ -3519,6 +3541,7 @@ static const unsigned int ln_objs[NUM_LN]={
 294,	/* "IPSec End System" */
 295,	/* "IPSec Tunnel" */
 296,	/* "IPSec User" */
+958,	/* "ISO CN Member Body" */
 182,	/* "ISO Member Body" */
 183,	/* "ISO US Member Body" */
 667,	/* "Independent" */
@@ -3573,6 +3596,7 @@ static const unsigned int ln_objs[NUM_LN]={
  2,	/* "RSA Data Security, Inc. PKCS" */
 188,	/* "S/MIME" */
 167,	/* "S/MIME Capabilities" */
+964,    /* "SM2-with-SM3" */
 387,	/* "SNMPv2" */
 512,	/* "Secure Electronic Transactions" */
 386,	/* "Security" */
@@ -4105,6 +4129,7 @@ static const unsigned int ln_objs[NUM_LN]={
 17,	/* "organizationName" */
 491,	/* "organizationalStatus" */
 18,	/* "organizationalUnitName" */
+959,	/* "oscca" */
 475,	/* "otherMailbox" */
 876,	/* "owner" */
 935,	/* "pSpecified" */
@@ -4379,6 +4404,10 @@ static const unsigned int ln_objs[NUM_LN]={
 52,	/* "signingTime" */
 454,	/* "simpleSecurityObject" */
 496,	/* "singleLevelQuality" */
+960,	/* "sm-scheme" */
+961,	/* "sm2" */
+962,	/* "sm3" */
+963,	/* "sm3WithRSAEncryption" */
 16,	/* "stateOrProvinceName" */
 660,	/* "streetAddress" */
 498,	/* "subtreeMaximumQuality" */
@@ -4444,6 +4473,7 @@ static const unsigned int obj_objs[NUM_OBJ]={
 512,	/* OBJ_id_set                       2 23 42 */
 678,	/* OBJ_wap                          2 23 43 */
 435,	/* OBJ_pss                          0 9 2342 */
+958,	/* OBJ_ISO_CN                       1 2 156 */
 183,	/* OBJ_ISO_US                       1 2 840 */
 381,	/* OBJ_iana                         1 3 6 1 */
 677,	/* OBJ_certicom_arc                 1 3 132 */
@@ -4659,6 +4689,7 @@ static const unsigned int obj_objs[NUM_OBJ]={
 637,	/* OBJ_set_brand_Diners             2 23 42 8 30 */
 638,	/* OBJ_set_brand_AmericanExpress    2 23 42 8 34 */
 639,	/* OBJ_set_brand_JCB                2 23 42 8 35 */
+959,	/* OBJ_oscca                        1 2 156 10197 */
 805,	/* OBJ_cryptopro                    1 2 643 2 2 */
 806,	/* OBJ_cryptocom                    1 2 643 2 9 */
 184,	/* OBJ_X9_57                        1 2 840 10040 */
@@ -4733,6 +4764,7 @@ static const unsigned int obj_objs[NUM_OBJ]={
 745,	/* OBJ_wap_wsg_idm_ecid_wtls12      2 23 43 1 4 12 */
 804,	/* OBJ_whirlpool                    1 0 10118 3 0 55 */
 124,	/* OBJ_rle_compression              1 1 1 1 666 1 */
+960,	/* OBJ_sm_scheme                    1 2 156 10197 1 */
 773,	/* OBJ_kisa                         1 2 410 200004 */
 807,	/* OBJ_id_GostR3411_94_with_GostR3410_2001 1 2 643 2 2 3 */
 808,	/* OBJ_id_GostR3411_94_with_GostR3410_94 1 2 643 2 2 4 */
@@ -4836,6 +4868,10 @@ static const unsigned int obj_objs[NUM_OBJ]={
 768,	/* OBJ_camellia_256_ofb128          0 3 4401 5 3 1 9 43 */
 759,	/* OBJ_camellia_256_cfb128          0 3 4401 5 3 1 9 44 */
 437,	/* OBJ_pilot                        0 9 2342 19200300 100 */
+961,	/* OBJ_sm2                          1 2 156 10197 1 301 */
+962,	/* OBJ_sm3                          1 2 156 10197 1 401 */
+964,	/* OBJ_SM2_with_SM3                 1 2 156 10197 1 501 */
+963,	/* OBJ_sm3WithRSAEncryption         1 2 156 10197 1 504 */
 776,	/* OBJ_seed_ecb                     1 2 410 200004 1 3 */
 777,	/* OBJ_seed_cbc                     1 2 410 200004 1 4 */
 779,	/* OBJ_seed_cfb128                  1 2 410 200004 1 5 */
diff --git a/Cryptlib/OpenSSL/crypto/objects/obj_xref.h b/Cryptlib/OpenSSL/crypto/objects/obj_xref.h
index e453e99..cf08a14 100644
--- a/Cryptlib/OpenSSL/crypto/objects/obj_xref.h
+++ b/Cryptlib/OpenSSL/crypto/objects/obj_xref.h
@@ -56,6 +56,7 @@ static const nid_triple sigoid_srt[] = {
      NID_dh_cofactor_kdf},
     {NID_dhSinglePass_cofactorDH_sha512kdf_scheme, NID_sha512,
      NID_dh_cofactor_kdf},
+    {NID_SM2_with_SM3, NID_sm3, NID_sm2},
 };
 
 static const nid_triple *const sigoid_srt_xref[] = {
@@ -96,4 +97,5 @@ static const nid_triple *const sigoid_srt_xref[] = {
     &sigoid_srt[26],
     &sigoid_srt[27],
     &sigoid_srt[28],
+    &sigoid_srt[40],
 };
diff --git a/Cryptlib/OpenSSL/crypto/pkcs7/pk7_doit.c b/Cryptlib/OpenSSL/crypto/pkcs7/pk7_doit.c
index dd6c73f..846fcf8 100644
--- a/Cryptlib/OpenSSL/crypto/pkcs7/pk7_doit.c
+++ b/Cryptlib/OpenSSL/crypto/pkcs7/pk7_doit.c
@@ -1036,10 +1036,10 @@ int PKCS7_signatureVerify(BIO *bio, PKCS7 *p7, PKCS7_SIGNER_INFO *si,
     ASN1_OCTET_STRING *os;
     EVP_MD_CTX mdc_tmp, *mdc;
     int ret = 0, i;
-    int md_type;
+    int md_type, is_sm2 = 0;
     STACK_OF(X509_ATTRIBUTE) *sk;
     BIO *btmp;
-    EVP_PKEY *pkey;
+    EVP_PKEY *pkey = NULL;
 
     EVP_MD_CTX_init(&mdc_tmp);
 
@@ -1074,6 +1074,18 @@ int PKCS7_signatureVerify(BIO *bio, PKCS7 *p7, PKCS7_SIGNER_INFO *si,
         btmp = BIO_next(btmp);
     }
 
+#ifndef OPENSSL_NO_SM2
+    pkey = X509_get_pubkey(x509);
+    if (!pkey)
+        goto err;
+
+    if (EVP_PKEY_is_sm2(pkey)) {
+        is_sm2 = 1;
+        if (!EVP_PKEY_set_alias_type(pkey, EVP_PKEY_SM2))
+            goto err;
+    }
+#endif
+
     /*
      * mdc is the digest ctx that we want, unless there are attributes, in
      * which case the digest is the signed attributes
@@ -1114,7 +1126,12 @@ int PKCS7_signatureVerify(BIO *bio, PKCS7 *p7, PKCS7_SIGNER_INFO *si,
             goto err;
         }
 
-        if (!EVP_VerifyInit_ex(&mdc_tmp, EVP_get_digestbynid(md_type), NULL))
+        ret = is_sm2 ? EVP_DigestVerifyInit(&mdc_tmp, NULL, EVP_get_digestbynid(md_type), NULL, pkey) :
+                       EVP_VerifyInit_ex(&mdc_tmp, EVP_get_digestbynid(md_type), NULL);
+        if (!ret)
+            goto err;
+
+        if (!EVP_DigestVerifyInit(&mdc_tmp, NULL, EVP_get_digestbynid(md_type), NULL, pkey))
             goto err;
 
         alen = ASN1_item_i2d((ASN1_VALUE *)sk, &abuf,
@@ -1131,14 +1148,8 @@ int PKCS7_signatureVerify(BIO *bio, PKCS7 *p7, PKCS7_SIGNER_INFO *si,
     }
 
     os = si->enc_digest;
-    pkey = X509_get_pubkey(x509);
-    if (!pkey) {
-        ret = -1;
-        goto err;
-    }
-
-    i = EVP_VerifyFinal(&mdc_tmp, os->data, os->length, pkey);
-    EVP_PKEY_free(pkey);
+    i = is_sm2 ? EVP_DigestVerifyFinal(&mdc_tmp, os->data, os->length) :
+                 EVP_VerifyFinal(&mdc_tmp, os->data, os->length, pkey);
     if (i <= 0) {
         PKCS7err(PKCS7_F_PKCS7_SIGNATUREVERIFY, PKCS7_R_SIGNATURE_FAILURE);
         ret = -1;
@@ -1146,6 +1157,7 @@ int PKCS7_signatureVerify(BIO *bio, PKCS7 *p7, PKCS7_SIGNER_INFO *si,
     } else
         ret = 1;
  err:
+    EVP_PKEY_free(pkey);
     EVP_MD_CTX_cleanup(&mdc_tmp);
     return (ret);
 }
diff --git a/Cryptlib/OpenSSL/crypto/x509/x_all.c b/Cryptlib/OpenSSL/crypto/x509/x_all.c
index 0f26c54..59a41e3 100644
--- a/Cryptlib/OpenSSL/crypto/x509/x_all.c
+++ b/Cryptlib/OpenSSL/crypto/x509/x_all.c
@@ -71,16 +71,161 @@
 # include <openssl/dsa.h>
 #endif
 
+#ifndef OPENSSL_NO_SM2
+
+# include "openssl/asn1.h"
+# include "openssl/evp.h"
+# include "crypto/asn1/asn1_locl.h"
+
+static int common_verify_sm2(void *data, EVP_PKEY *pkey,
+                             int mdnid, int pknid, int req)
+{
+    X509 *x = NULL;
+    X509_REQ *r = NULL;
+    EVP_MD_CTX *ctx = NULL;
+    unsigned char *buf_in = NULL;
+    int ret = -1, inl = 0;
+    size_t inll = 0;
+    EVP_PKEY_CTX *pctx = NULL;
+    const EVP_MD *type = EVP_get_digestbynid(mdnid);
+    ASN1_BIT_STRING *signature = NULL;
+    ASN1_OCTET_STRING *sm2_id = NULL;
+    ASN1_VALUE *tbv = NULL;
+
+    if (type == NULL) {
+        goto err;
+    }
+
+    if (pkey == NULL) {
+        return -1;
+    }
+
+    if (req == 1) {
+        r = (X509_REQ *)data;
+        signature = r->signature;
+        sm2_id = r->sm2_id;
+        tbv = (ASN1_VALUE *)&r->req_info;
+    } else {
+        x = (X509 *)data;
+        signature = x->signature;
+        sm2_id = x->sm2_id;
+        tbv = (ASN1_VALUE *)x->cert_info;
+    }
+
+    if (signature->type == V_ASN1_BIT_STRING && signature->flags & 0x7) {
+        return -1;
+    }
+
+    ctx = EVP_MD_CTX_new();
+    if (ctx == NULL)
+        goto err;
+
+    /* Check public key OID matches public key type */
+    if (EVP_PKEY_type(pknid) != pkey->ameth->pkey_id) {
+        goto err;
+    }
+
+    if (!EVP_PKEY_set_alias_type(pkey, EVP_PKEY_SM2)) {
+        ret = 0;
+        goto err;
+    }
+
+    pctx = EVP_PKEY_CTX_new(pkey, NULL);
+    if (pctx == NULL) {
+        ret = 0;
+        goto err;
+    }
+    /* NOTE: we tolerate no actual ID, to provide maximum flexibility */
+    if (sm2_id != NULL
+            && EVP_PKEY_CTX_set1_id(pctx, sm2_id->data, sm2_id->length) != 1) {
+        ret = 0;
+        goto err;
+    }
+
+    EVP_MD_CTX_set_pkey_ctx(ctx, pctx);
+    if (!EVP_DigestVerifyInit(ctx, NULL, type, NULL, pkey)) {
+        ret = 0;
+        goto err;
+    }
+
+    inl = ASN1_item_i2d(tbv, &buf_in,
+                        req == 1 ?
+                        ASN1_ITEM_rptr(X509_REQ_INFO) :
+                        ASN1_ITEM_rptr(X509_CINF));
+    if (inl <= 0) {
+        goto err;
+    }
+    if (buf_in == NULL) {
+        goto err;
+    }
+    inll = inl;
+
+    ret = EVP_DigestVerify(ctx, signature->data,
+                           (size_t)signature->length, buf_in, inl);
+    if (ret <= 0) {
+        goto err;
+    }
+    ret = 1;
+ err:
+    OPENSSL_cleanse(buf_in, inll);
+    EVP_MD_CTX_free(ctx);
+    EVP_PKEY_CTX_free(pctx);
+    return ret;
+}
+
+static int x509_verify_sm2(X509 *x, EVP_PKEY *pkey, int mdnid, int pknid)
+{
+    return common_verify_sm2(x, pkey, mdnid, pknid, 0);
+}
+
+static int x509_req_verify_sm2(X509_REQ *x, EVP_PKEY *pkey,
+                               int mdnid, int pknid)
+{
+    return common_verify_sm2(x, pkey, mdnid, pknid, 1);
+}
+
+#endif
+
+
+
 int X509_verify(X509 *a, EVP_PKEY *r)
 {
+#ifndef OPENSSL_NO_SM2
+    int mdnid, pknid;
+#endif
     if (X509_ALGOR_cmp(a->sig_alg, a->cert_info->signature))
         return 0;
+
+#ifndef OPENSSL_NO_SM2
+    /* Convert signature OID into digest and public key OIDs */
+    if (!OBJ_find_sigid_algs(OBJ_obj2nid(a->sig_alg->algorithm),
+                             &mdnid, &pknid)) {
+        return 0;
+    }
+
+    if (pknid == NID_sm2)
+        return x509_verify_sm2(a, r, mdnid, pknid);
+#endif
+
     return (ASN1_item_verify(ASN1_ITEM_rptr(X509_CINF), a->sig_alg,
                              a->signature, a->cert_info, r));
 }
 
 int X509_REQ_verify(X509_REQ *a, EVP_PKEY *r)
 {
+#ifndef OPENSSL_NO_SM2
+    int mdnid, pknid;
+
+    /* Convert signature OID into digest and public key OIDs */
+    if (!OBJ_find_sigid_algs(OBJ_obj2nid(a->sig_alg->algorithm),
+                             &mdnid, &pknid)) {
+        return 0;
+    }
+
+    if (pknid == NID_sm2)
+        return x509_req_verify_sm2(a, r, mdnid, pknid);
+#endif
+
     return (ASN1_item_verify(ASN1_ITEM_rptr(X509_REQ_INFO),
                              a->sig_alg, a->signature, a->req_info, r));
 }
diff --git a/Cryptlib/Pk/CryptPkcs7Verify.c b/Cryptlib/Pk/CryptPkcs7Verify.c
index c189384..7fa8c41 100644
--- a/Cryptlib/Pk/CryptPkcs7Verify.c
+++ b/Cryptlib/Pk/CryptPkcs7Verify.c
@@ -878,6 +878,11 @@ Pkcs7Verify (
   if (EVP_add_digest (EVP_sha512 ()) == 0) {
     return FALSE;
   }
+#ifndef OPENSSL_NO_SM3
+  if (EVP_add_digest (EVP_sm3 ()) == 0) {
+    return FALSE;
+  }
+#endif
   if (EVP_add_digest_alias (SN_sha1WithRSAEncryption, SN_sha1WithRSA) == 0) {
     return FALSE;
   }
-- 
2.33.0

