From 897ef4d611facba29cde86fac6d161984d524da4 Mon Sep 17 00:00:00 2001
From: s_c_c <shichuchao@huawei.com>
Date: Mon, 27 Jun 2022 10:28:38 +0800
Subject: [PATCH] Support TLCP protocol

TLCP_method(), TLCP_server_method(), TLCP_client_method() are the GM version-specific methods for TLCP protocol.
Valid TLCP ciphersuite names are ECDHE-SM4-CBC-SM3 and ECC-SM4-CBC-SM3. Additionally enable-tlcp(argument to Configure) was required.
---
 Configure                                     |   7 +-
 apps/s_client.c                               |  60 +-
 crypto/dh/dh_err.c                            |   8 +-
 crypto/dsa/dsa_err.c                          |   8 +-
 crypto/err/openssl.txt                        |  34 +-
 crypto/evp/evp_err.c                          |   6 +-
 crypto/evp/p_lib.c                            |  18 +
 crypto/rsa/rsa_err.c                          |  23 +-
 crypto/sm2/build.info                         |   2 +-
 crypto/sm2/sm2_err.c                          |   4 +-
 crypto/sm2/sm2_kep.c                          | 254 ++++++
 crypto/sm2/sm2_pmeth.c                        |   4 +
 doc/man1/s_client.pod                         |   9 +
 doc/man3/EVP_PKEY_set1_RSA.pod                |   9 +-
 doc/man3/SSL_CTX_new.pod                      |  19 +-
 doc/man3/SSL_CTX_set_options.pod              |   4 +-
 doc/man3/SSL_CTX_use_certificate.pod          |  56 +-
 doc/man7/ssl.pod                              |  40 +
 include/crypto/sm2.h                          |   1 +
 include/crypto/sm2err.h                       |  12 +-
 include/openssl/dherr.h                       |  15 +-
 include/openssl/dsaerr.h                      |  18 +-
 include/openssl/evp.h                         |   4 +
 include/openssl/evperr.h                      |  17 +-
 include/openssl/rsaerr.h                      |  32 +-
 include/openssl/sm2.h                         |  20 +
 include/openssl/ssl.h                         |  71 ++
 include/openssl/sslerr.h                      |  33 +-
 include/openssl/tls1.h                        |  20 +
 include/openssl/x509.h                        |   4 +
 include/openssl/x509err.h                     |   4 +-
 ssl/methods.c                                 |  36 +
 ssl/record/ssl3_record.c                      |   4 +
 ssl/s3_lib.c                                  | 126 +++
 ssl/ssl_asn1.c                                |   3 +-
 ssl/ssl_cert.c                                |  18 +
 ssl/ssl_cert_table.h                          |   6 +-
 ssl/ssl_ciph.c                                |  46 +-
 ssl/ssl_err.c                                 |  54 +-
 ssl/ssl_lib.c                                 |  81 +-
 ssl/ssl_local.h                               |  69 +-
 ssl/ssl_rsa.c                                 | 541 +++++++++++++
 ssl/ssl_sess.c                                |   3 +
 ssl/ssl_stat.c                                |  28 +
 ssl/statem/extensions.c                       |   6 +-
 ssl/statem/extensions_clnt.c                  |   3 +
 ssl/statem/extensions_srvr.c                  |   6 +-
 ssl/statem/statem.c                           |   4 +
 ssl/statem/statem_clnt.c                      | 434 ++++++++++
 ssl/statem/statem_lib.c                       | 182 ++++-
 ssl/statem/statem_srvr.c                      | 445 ++++++++++-
 ssl/t1_enc.c                                  |  84 ++
 ssl/t1_lib.c                                  | 130 ++-
 test/build.info                               |   6 +-
 test/ciphername_test.c                        |   3 +
 test/recipes/85-test_tlcp.t                   |  34 +
 .../85-test_tlcp_data/ecdsa-client-cert.pem   |  12 +
 .../85-test_tlcp_data/ecdsa-client-key.pem    |   5 +
 .../85-test_tlcp_data/ecdsa-root-cert.pem     |  14 +
 .../85-test_tlcp_data/ecdsa-server-cert.pem   |  12 +
 .../85-test_tlcp_data/ecdsa-server-key.pem    |   5 +
 .../85-test_tlcp_data/sm2-client-enc-cert.pem |  12 +
 .../85-test_tlcp_data/sm2-client-enc-key.pem  |   5 +
 .../85-test_tlcp_data/sm2-client-sig-cert.pem |  12 +
 .../85-test_tlcp_data/sm2-client-sig-key.pem  |   5 +
 .../85-test_tlcp_data/sm2-root-cert.pem       |  14 +
 .../85-test_tlcp_data/sm2-server-enc-cert.pem |  12 +
 .../85-test_tlcp_data/sm2-server-enc-key.pem  |   5 +
 .../85-test_tlcp_data/sm2-server-sig-cert.pem |  12 +
 .../85-test_tlcp_data/sm2-server-sig-key.pem  |   5 +
 test/sm2_internal_test.c                      | 111 +++
 test/tlcptest.c                               | 746 ++++++++++++++++++
 util/libcrypto.num                            |   2 +
 util/libssl.num                               |  17 +
 74 files changed, 4065 insertions(+), 109 deletions(-)
 create mode 100644 crypto/sm2/sm2_kep.c
 create mode 100644 include/openssl/sm2.h
 create mode 100644 test/recipes/85-test_tlcp.t
 create mode 100644 test/recipes/85-test_tlcp_data/ecdsa-client-cert.pem
 create mode 100644 test/recipes/85-test_tlcp_data/ecdsa-client-key.pem
 create mode 100644 test/recipes/85-test_tlcp_data/ecdsa-root-cert.pem
 create mode 100644 test/recipes/85-test_tlcp_data/ecdsa-server-cert.pem
 create mode 100644 test/recipes/85-test_tlcp_data/ecdsa-server-key.pem
 create mode 100644 test/recipes/85-test_tlcp_data/sm2-client-enc-cert.pem
 create mode 100644 test/recipes/85-test_tlcp_data/sm2-client-enc-key.pem
 create mode 100644 test/recipes/85-test_tlcp_data/sm2-client-sig-cert.pem
 create mode 100644 test/recipes/85-test_tlcp_data/sm2-client-sig-key.pem
 create mode 100644 test/recipes/85-test_tlcp_data/sm2-root-cert.pem
 create mode 100644 test/recipes/85-test_tlcp_data/sm2-server-enc-cert.pem
 create mode 100644 test/recipes/85-test_tlcp_data/sm2-server-enc-key.pem
 create mode 100644 test/recipes/85-test_tlcp_data/sm2-server-sig-cert.pem
 create mode 100644 test/recipes/85-test_tlcp_data/sm2-server-sig-key.pem
 create mode 100644 test/tlcptest.c

diff --git a/Configure b/Configure
index 4236e6c..a41c897 100755
--- a/Configure
+++ b/Configure
@@ -425,6 +425,7 @@ my @disablables = (
     "stdio",
     "tests",
     "threads",
+    "tlcp",
     "tls",
     "ts",
     "ubsan",
@@ -469,6 +470,7 @@ our %disabled = ( # "what"         => "comment"
                   "ssl-trace"           => "default",
                   "ssl3"                => "default",
                   "ssl3-method"         => "default",
+                  "tlcp"                => "default",
                   "ubsan"               => "default",
                   "unit-test"           => "default",
                   "weak-ssl-ciphers"    => "default",
@@ -512,8 +514,9 @@ my @disable_cascades = (
     "apps"              => [ "tests" ],
     "tests"             => [ "external-tests" ],
     "comp"              => [ "zlib" ],
-    "ec"                => [ "tls1_3", "sm2" ],
-    "sm3"               => [ "sm2" ],
+    "ec"                => [ "tls1_3", "sm2", "tlcp" ],
+    "sm3"               => [ "sm2", "tlcp" ],
+    "sm2"               => [ "tlcp" ],
     sub { !$disabled{"unit-test"} } => [ "heartbeats" ],
 
     sub { !$disabled{"msan"} } => [ "asm" ],
diff --git a/apps/s_client.c b/apps/s_client.c
index 121cd14..a41f98a 100644
--- a/apps/s_client.c
+++ b/apps/s_client.c
@@ -578,6 +578,7 @@ typedef enum OPTION_choice {
     OPT_SRPUSER, OPT_SRPPASS, OPT_SRP_STRENGTH, OPT_SRP_LATEUSER,
     OPT_SRP_MOREGROUPS,
 #endif
+    OPT_TLCP, OPT_DCERT, OPT_DKEY, OPT_DPASS,
     OPT_SSL3, OPT_SSL_CONFIG,
     OPT_TLS1_3, OPT_TLS1_2, OPT_TLS1_1, OPT_TLS1, OPT_DTLS, OPT_DTLS1,
     OPT_DTLS1_2, OPT_SCTP, OPT_TIMEOUT, OPT_MTU, OPT_KEYFORM, OPT_PASS,
@@ -738,6 +739,12 @@ const OPTIONS s_client_options[] = {
 #ifndef OPENSSL_NO_TLS1_3
     {"tls1_3", OPT_TLS1_3, '-', "Just use TLSv1.3"},
 #endif
+#ifndef OPENSSL_NO_TCLP
+    {"tlcp", OPT_TLCP, '-', "Just use TLCP"},
+    {"dcert", OPT_DCERT, '<', "Encryption certificate file to use (usually for TLCP)"},
+    {"dkey", OPT_DKEY, '<', "Encryption private key file to use (usually for TLCP)"},
+    {"dpass", OPT_DPASS, 's', "Encryption private key file pass phrase source"},
+#endif
 #ifndef OPENSSL_NO_DTLS
     {"dtls", OPT_DTLS, '-', "Use any version of DTLS"},
     {"timeout", OPT_TIMEOUT, '-',
@@ -836,7 +843,7 @@ static const OPT_PAIR services[] = {
 
 #define IS_PROT_FLAG(o) \
  (o == OPT_SSL3 || o == OPT_TLS1 || o == OPT_TLS1_1 || o == OPT_TLS1_2 \
-  || o == OPT_TLS1_3 || o == OPT_DTLS || o == OPT_DTLS1 || o == OPT_DTLS1_2)
+  || o == OPT_TLS1_3 || o == OPT_DTLS || o == OPT_DTLS1 || o == OPT_DTLS1_2 || o == OPT_TLCP)
 
 /* Free |*dest| and optionally set it to a copy of |source|. */
 static void freeandcopy(char **dest, const char *source)
@@ -982,6 +989,10 @@ int s_client_main(int argc, char **argv)
 #ifndef OPENSSL_NO_SCTP
     int sctp_label_bug = 0;
 #endif
+    char *s_dcert_file = NULL, *s_dkey_file = NULL;
+    char *dpassarg = NULL, *dpass = NULL;
+    X509 *s_dcert = NULL;
+    EVP_PKEY *s_dkey = NULL;
 
     FD_ZERO(&readfds);
     FD_ZERO(&writefds);
@@ -1318,6 +1329,14 @@ int s_client_main(int argc, char **argv)
             socket_type = SOCK_STREAM;
 #ifndef OPENSSL_NO_DTLS
             isdtls = 0;
+#endif
+            break;
+        case OPT_TLCP:
+            min_version = TLCP_VERSION;
+            max_version = TLCP_VERSION;
+            socket_type = SOCK_STREAM;
+#ifndef OPENSSL_NO_DTLS
+            isdtls = 0;
 #endif
             break;
         case OPT_DTLS:
@@ -1381,6 +1400,15 @@ int s_client_main(int argc, char **argv)
         case OPT_KEY:
             key_file = opt_arg();
             break;
+        case OPT_DCERT:
+            s_dcert_file = opt_arg();
+            break;
+        case OPT_DPASS:
+            dpassarg = opt_arg();
+            break;
+        case OPT_DKEY:
+            s_dkey_file = opt_arg();
+            break;
         case OPT_RECONNECT:
             reconnect = 5;
             break;
@@ -1650,7 +1678,7 @@ int s_client_main(int argc, char **argv)
         next_proto.data = NULL;
 #endif
 
-    if (!app_passwd(passarg, NULL, &pass, NULL)) {
+    if (!app_passwd(passarg, dpassarg, &pass, &dpass)) {
         BIO_printf(bio_err, "Error getting password\n");
         goto end;
     }
@@ -1681,6 +1709,26 @@ int s_client_main(int argc, char **argv)
             goto end;
     }
 
+    if (s_dcert_file != NULL) {
+        if (s_dkey_file == NULL)
+            s_dkey_file = s_dcert_file;
+
+        s_dkey = load_key(s_dkey_file, key_format, 0, dpass, e,
+                            "Encrypt certificate private key file");
+        if (s_dkey == NULL) {
+            ERR_print_errors(bio_err);
+            goto end;
+        }
+
+        s_dcert = load_cert(s_dcert_file, key_format,
+                            "Encrypt server certificate file");
+
+        if (s_dcert == NULL) {
+            ERR_print_errors(bio_err);
+            goto end;
+        }
+    }
+
     if (crl_file != NULL) {
         X509_CRL *crl;
         crl = load_crl(crl_file, crl_format);
@@ -1932,6 +1980,11 @@ int s_client_main(int argc, char **argv)
 
     if (!set_cert_key_stuff(ctx, cert, key, chain, build_chain))
         goto end;
+    
+    if (s_dcert != NULL) {
+        if (!set_cert_key_stuff(ctx, s_dcert, s_dkey, chain, build_chain))
+            goto end;
+    }
 
     if (!noservername) {
         tlsextcbp.biodebug = bio_err;
@@ -3146,6 +3199,9 @@ int s_client_main(int argc, char **argv)
     EVP_PKEY_free(key);
     sk_X509_pop_free(chain, X509_free);
     OPENSSL_free(pass);
+    X509_free(s_dcert);
+    EVP_PKEY_free(s_dkey);
+    OPENSSL_free(dpass);
 #ifndef OPENSSL_NO_SRP
     OPENSSL_free(srp_arg.srppassin);
 #endif
diff --git a/crypto/dh/dh_err.c b/crypto/dh/dh_err.c
index 9778138..c7ac6ae 100644
--- a/crypto/dh/dh_err.c
+++ b/crypto/dh/dh_err.c
@@ -1,6 +1,6 @@
 /*
  * Generated by util/mkerr.pl DO NOT EDIT
- * Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 1995-2022 The OpenSSL Project Authors. All Rights Reserved.
  *
  * Licensed under the OpenSSL license (the "License").  You may not use
  * this file except in compliance with the License.  You can obtain a copy
@@ -26,8 +26,8 @@ static const ERR_STRING_DATA DH_str_functs[] = {
     {ERR_PACK(ERR_LIB_DH, DH_F_DH_CMS_SET_SHARED_INFO, 0),
      "dh_cms_set_shared_info"},
     {ERR_PACK(ERR_LIB_DH, DH_F_DH_COMPUTE_KEY, 0), "DH_compute_key"},
-    {ERR_PACK(ERR_LIB_DH, DH_F_DH_GENERATE_KEY, 0), "DH_generate_key"},
-    {ERR_PACK(ERR_LIB_DH, DH_F_DH_GENERATE_PARAMETERS_EX, 0), "DH_generate_parameters_ex"},
+    {ERR_PACK(ERR_LIB_DH, DH_F_DH_GENERATE_PARAMETERS_EX, 0),
+     "DH_generate_parameters_ex"},
     {ERR_PACK(ERR_LIB_DH, DH_F_DH_METH_DUP, 0), "DH_meth_dup"},
     {ERR_PACK(ERR_LIB_DH, DH_F_DH_METH_NEW, 0), "DH_meth_new"},
     {ERR_PACK(ERR_LIB_DH, DH_F_DH_METH_SET1_NAME, 0), "DH_meth_set1_name"},
@@ -78,11 +78,11 @@ static const ERR_STRING_DATA DH_str_reasons[] = {
     {ERR_PACK(ERR_LIB_DH, 0, DH_R_KEY_SIZE_TOO_SMALL), "key size too small"},
     {ERR_PACK(ERR_LIB_DH, 0, DH_R_MISSING_PUBKEY), "missing pubkey"},
     {ERR_PACK(ERR_LIB_DH, 0, DH_R_MODULUS_TOO_LARGE), "modulus too large"},
+    {ERR_PACK(ERR_LIB_DH, 0, DH_R_NON_FIPS_METHOD), "non fips method"},
     {ERR_PACK(ERR_LIB_DH, 0, DH_R_NOT_SUITABLE_GENERATOR),
     "not suitable generator"},
     {ERR_PACK(ERR_LIB_DH, 0, DH_R_NO_PARAMETERS_SET), "no parameters set"},
     {ERR_PACK(ERR_LIB_DH, 0, DH_R_NO_PRIVATE_VALUE), "no private value"},
-    {ERR_PACK(ERR_LIB_DH, 0, DH_R_NON_FIPS_METHOD), "non FIPS method"},
     {ERR_PACK(ERR_LIB_DH, 0, DH_R_PARAMETER_ENCODING_ERROR),
     "parameter encoding error"},
     {ERR_PACK(ERR_LIB_DH, 0, DH_R_PEER_KEY_ERROR), "peer key error"},
diff --git a/crypto/dsa/dsa_err.c b/crypto/dsa/dsa_err.c
index d85d221..26210c5 100644
--- a/crypto/dsa/dsa_err.c
+++ b/crypto/dsa/dsa_err.c
@@ -1,6 +1,6 @@
 /*
  * Generated by util/mkerr.pl DO NOT EDIT
- * Copyright 1995-2019 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 1995-2022 The OpenSSL Project Authors. All Rights Reserved.
  *
  * Licensed under the OpenSSL license (the "License").  You may not use
  * this file except in compliance with the License.  You can obtain a copy
@@ -24,7 +24,8 @@ static const ERR_STRING_DATA DSA_str_functs[] = {
     {ERR_PACK(ERR_LIB_DSA, DSA_F_DSA_DO_SIGN, 0), "DSA_do_sign"},
     {ERR_PACK(ERR_LIB_DSA, DSA_F_DSA_DO_VERIFY, 0), "DSA_do_verify"},
     {ERR_PACK(ERR_LIB_DSA, DSA_F_DSA_GENERATE_KEY, 0), "DSA_generate_key"},
-    {ERR_PACK(ERR_LIB_DSA, DSA_F_DSA_GENERATE_PARAMETERS_EX, 0), "DSA_generate_parameters_ex"},
+    {ERR_PACK(ERR_LIB_DSA, DSA_F_DSA_GENERATE_PARAMETERS_EX, 0),
+     "DSA_generate_parameters_ex"},
     {ERR_PACK(ERR_LIB_DSA, DSA_F_DSA_METH_DUP, 0), "DSA_meth_dup"},
     {ERR_PACK(ERR_LIB_DSA, DSA_F_DSA_METH_NEW, 0), "DSA_meth_new"},
     {ERR_PACK(ERR_LIB_DSA, DSA_F_DSA_METH_SET1_NAME, 0), "DSA_meth_set1_name"},
@@ -60,8 +61,9 @@ static const ERR_STRING_DATA DSA_str_reasons[] = {
     {ERR_PACK(ERR_LIB_DSA, 0, DSA_R_MISSING_PRIVATE_KEY),
     "missing private key"},
     {ERR_PACK(ERR_LIB_DSA, 0, DSA_R_MODULUS_TOO_LARGE), "modulus too large"},
+    {ERR_PACK(ERR_LIB_DSA, 0, DSA_R_NON_FIPS_DSA_METHOD),
+    "non fips dsa method"},
     {ERR_PACK(ERR_LIB_DSA, 0, DSA_R_NO_PARAMETERS_SET), "no parameters set"},
-    {ERR_PACK(ERR_LIB_DSA, 0, DSA_R_NON_FIPS_DSA_METHOD), "non FIPS DSA method"},
     {ERR_PACK(ERR_LIB_DSA, 0, DSA_R_PARAMETER_ENCODING_ERROR),
     "parameter encoding error"},
     {ERR_PACK(ERR_LIB_DSA, 0, DSA_R_Q_NOT_PRIME), "q not prime"},
diff --git a/crypto/err/openssl.txt b/crypto/err/openssl.txt
index b93cace..3ea4c02 100644
--- a/crypto/err/openssl.txt
+++ b/crypto/err/openssl.txt
@@ -1,4 +1,4 @@
-# Copyright 1999-2021 The OpenSSL Project Authors. All Rights Reserved.
+# Copyright 1999-2022 The OpenSSL Project Authors. All Rights Reserved.
 #
 # Licensed under the OpenSSL license (the "License").  You may not use
 # this file except in compliance with the License.  You can obtain a copy
@@ -1102,6 +1102,7 @@ SM2_F_PKEY_SM2_CTRL_STR:110:pkey_sm2_ctrl_str
 SM2_F_PKEY_SM2_DIGEST_CUSTOM:114:pkey_sm2_digest_custom
 SM2_F_PKEY_SM2_INIT:111:pkey_sm2_init
 SM2_F_PKEY_SM2_SIGN:112:pkey_sm2_sign
+SM2_F_SM2_COMPUTE_KEY:116:SM2_compute_key
 SM2_F_SM2_COMPUTE_MSG_HASH:100:sm2_compute_msg_hash
 SM2_F_SM2_COMPUTE_USERID_DIGEST:101:sm2_compute_userid_digest
 SM2_F_SM2_COMPUTE_Z_DIGEST:113:sm2_compute_z_digest
@@ -1184,7 +1185,7 @@ SSL_F_OSSL_STATEM_SERVER_CONSTRUCT_MESSAGE:431:*
 SSL_F_OSSL_STATEM_SERVER_POST_PROCESS_MESSAGE:601:\
 	ossl_statem_server_post_process_message
 SSL_F_OSSL_STATEM_SERVER_POST_WORK:602:ossl_statem_server_post_work
-SSL_F_OSSL_STATEM_SERVER_PRE_WORK:640:
+SSL_F_OSSL_STATEM_SERVER_PRE_WORK:640:ossl_statem_server_pre_work
 SSL_F_OSSL_STATEM_SERVER_PROCESS_MESSAGE:603:ossl_statem_server_process_message
 SSL_F_OSSL_STATEM_SERVER_READ_TRANSITION:418:ossl_statem_server_read_transition
 SSL_F_OSSL_STATEM_SERVER_WRITE_TRANSITION:604:\
@@ -1270,6 +1271,10 @@ SSL_F_SSL_CTX_SET_TLSEXT_MAX_FRAGMENT_LENGTH:551:\
 SSL_F_SSL_CTX_USE_CERTIFICATE:171:SSL_CTX_use_certificate
 SSL_F_SSL_CTX_USE_CERTIFICATE_ASN1:172:SSL_CTX_use_certificate_ASN1
 SSL_F_SSL_CTX_USE_CERTIFICATE_FILE:173:SSL_CTX_use_certificate_file
+SSL_F_SSL_CTX_USE_GM_CERTIFICATE:641:SSL_CTX_use_gm_certificate
+SSL_F_SSL_CTX_USE_GM_CERTIFICATE_ASN1:642:SSL_CTX_use_gm_certificate_ASN1
+SSL_F_SSL_CTX_USE_GM_PRIVATEKEY:643:SSL_CTX_use_gm_PrivateKey
+SSL_F_SSL_CTX_USE_GM_PRIVATEKEY_ASN1:644:SSL_CTX_use_gm_PrivateKey_ASN1
 SSL_F_SSL_CTX_USE_PRIVATEKEY:174:SSL_CTX_use_PrivateKey
 SSL_F_SSL_CTX_USE_PRIVATEKEY_ASN1:175:SSL_CTX_use_PrivateKey_ASN1
 SSL_F_SSL_CTX_USE_PRIVATEKEY_FILE:176:SSL_CTX_use_PrivateKey_file
@@ -1296,7 +1301,9 @@ SSL_F_SSL_GET_SIGN_PKEY:183:*
 SSL_F_SSL_HANDSHAKE_HASH:560:ssl_handshake_hash
 SSL_F_SSL_INIT_WBIO_BUFFER:184:ssl_init_wbio_buffer
 SSL_F_SSL_KEY_UPDATE:515:SSL_key_update
+SSL_F_SSL_LOAD_CERT_FILE:645:ssl_load_cert_file
 SSL_F_SSL_LOAD_CLIENT_CA_FILE:185:SSL_load_client_CA_file
+SSL_F_SSL_LOAD_PKEY_FILE:646:ssl_load_pkey_file
 SSL_F_SSL_LOG_MASTER_SECRET:498:*
 SSL_F_SSL_LOG_RSA_CLIENT_KEY_EXCHANGE:499:ssl_log_rsa_client_key_exchange
 SSL_F_SSL_MODULE_INIT:392:ssl_module_init
@@ -1330,11 +1337,14 @@ SSL_F_SSL_SET_CERT_AND_KEY:621:ssl_set_cert_and_key
 SSL_F_SSL_SET_CIPHER_LIST:271:SSL_set_cipher_list
 SSL_F_SSL_SET_CT_VALIDATION_CALLBACK:399:SSL_set_ct_validation_callback
 SSL_F_SSL_SET_FD:192:SSL_set_fd
+SSL_F_SSL_SET_GM_CERT_AND_KEY:647:ssl_set_gm_cert_and_key
 SSL_F_SSL_SET_PKEY:193:ssl_set_pkey
 SSL_F_SSL_SET_RFD:194:SSL_set_rfd
 SSL_F_SSL_SET_SESSION:195:SSL_set_session
 SSL_F_SSL_SET_SESSION_ID_CONTEXT:218:SSL_set_session_id_context
 SSL_F_SSL_SET_SESSION_TICKET_EXT:294:SSL_set_session_ticket_ext
+SSL_F_SSL_SET_SIGN_ENC_CERT:648:ssl_set_sign_enc_cert
+SSL_F_SSL_SET_SIGN_ENC_PKEY:649:ssl_set_sign_enc_pkey
 SSL_F_SSL_SET_TLSEXT_MAX_FRAGMENT_LENGTH:550:SSL_set_tlsext_max_fragment_length
 SSL_F_SSL_SET_WFD:196:SSL_set_wfd
 SSL_F_SSL_SHUTDOWN:224:SSL_shutdown
@@ -1345,6 +1355,10 @@ SSL_F_SSL_UNDEFINED_VOID_FUNCTION:244:ssl_undefined_void_function
 SSL_F_SSL_USE_CERTIFICATE:198:SSL_use_certificate
 SSL_F_SSL_USE_CERTIFICATE_ASN1:199:SSL_use_certificate_ASN1
 SSL_F_SSL_USE_CERTIFICATE_FILE:200:SSL_use_certificate_file
+SSL_F_SSL_USE_GM_CERTIFICATE:650:SSL_use_gm_certificate
+SSL_F_SSL_USE_GM_CERTIFICATE_ASN1:651:SSL_use_gm_certificate_ASN1
+SSL_F_SSL_USE_GM_PRIVATEKEY:652:SSL_use_gm_PrivateKey
+SSL_F_SSL_USE_GM_PRIVATEKEY_ASN1:653:SSL_use_gm_PrivateKey_ASN1
 SSL_F_SSL_USE_PRIVATEKEY:201:SSL_use_PrivateKey
 SSL_F_SSL_USE_PRIVATEKEY_ASN1:202:SSL_use_PrivateKey_ASN1
 SSL_F_SSL_USE_PRIVATEKEY_FILE:203:SSL_use_PrivateKey_file
@@ -1361,6 +1375,20 @@ SSL_F_SSL_WRITE_EARLY_FINISH:527:*
 SSL_F_SSL_WRITE_EX:433:SSL_write_ex
 SSL_F_SSL_WRITE_INTERNAL:524:ssl_write_internal
 SSL_F_STATE_MACHINE:353:state_machine
+SSL_F_TLCP_CHOOSE_SIGALG:662:tlcp_choose_sigalg
+SSL_F_TLCP_CONSTRUCT_CKE_SM2DHE:663:tlcp_construct_cke_sm2dhe
+SSL_F_TLCP_CONSTRUCT_CKE_SM2ECC:658:tlcp_construct_cke_sm2ecc
+SSL_F_TLCP_CONSTRUCT_CLIENT_KEY_EXCHANGE:654:tlcp_construct_client_key_exchange
+SSL_F_TLCP_CONSTRUCT_SERVER_KEY_EXCHANGE:655:tlcp_construct_server_key_exchange
+SSL_F_TLCP_CONSTRUCT_SKE_SM2DHE:664:tlcp_construct_ske_sm2dhe
+SSL_F_TLCP_CONSTRUCT_SKE_SM2ECC:659:tlcp_construct_ske_sm2ecc
+SSL_F_TLCP_DERIVE:665:tlcp_derive
+SSL_F_TLCP_PROCESS_CKE_SM2DHE:666:tlcp_process_cke_sm2dhe
+SSL_F_TLCP_PROCESS_CKE_SM2ECC:660:tlcp_process_cke_sm2ecc
+SSL_F_TLCP_PROCESS_CLIENT_KEY_EXCHANGE:656:tlcp_process_client_key_exchange
+SSL_F_TLCP_PROCESS_KEY_EXCHANGE:657:tlcp_process_key_exchange
+SSL_F_TLCP_PROCESS_SKE_SM2DHE:667:tlcp_process_ske_sm2dhe
+SSL_F_TLCP_PROCESS_SKE_SM2ECC:661:tlcp_process_ske_sm2ecc
 SSL_F_TLS12_CHECK_PEER_SIGALG:333:tls12_check_peer_sigalg
 SSL_F_TLS12_COPY_SIGALGS:533:tls12_copy_sigalgs
 SSL_F_TLS13_CHANGE_CIPHER_STATE:440:tls13_change_cipher_state
@@ -1769,7 +1797,7 @@ X509_F_X509_STORE_NEW:158:X509_STORE_new
 X509_F_X509_TO_X509_REQ:126:X509_to_X509_REQ
 X509_F_X509_TRUST_ADD:133:X509_TRUST_add
 X509_F_X509_TRUST_SET:141:X509_TRUST_set
-X509_F_X509_VERIFY:161:X509_verify
+X509_F_X509_VERIFY:166:X509_verify
 X509_F_X509_VERIFY_CERT:127:X509_verify_cert
 X509_F_X509_VERIFY_PARAM_NEW:159:X509_VERIFY_PARAM_new
 X509_F_X509_VERIFY_SM2:162:x509_verify_sm2
diff --git a/crypto/evp/evp_err.c b/crypto/evp/evp_err.c
index daf7fdc..e3c9e05 100644
--- a/crypto/evp/evp_err.c
+++ b/crypto/evp/evp_err.c
@@ -1,6 +1,6 @@
 /*
  * Generated by util/mkerr.pl DO NOT EDIT
- * Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 1995-2022 The OpenSSL Project Authors. All Rights Reserved.
  *
  * Licensed under the OpenSSL license (the "License").  You may not use
  * this file except in compliance with the License.  You can obtain a copy
@@ -187,7 +187,7 @@ static const ERR_STRING_DATA EVP_str_reasons[] = {
     "different key types"},
     {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_DIFFERENT_PARAMETERS),
     "different parameters"},
-    {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_DISABLED_FOR_FIPS), "disabled for FIPS"},
+    {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_DISABLED_FOR_FIPS), "disabled for fips"},
     {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_ERROR_LOADING_SECTION),
     "error loading section"},
     {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_ERROR_SETTING_FIPS_MODE),
@@ -279,8 +279,6 @@ static const ERR_STRING_DATA EVP_str_reasons[] = {
     "wrap mode not allowed"},
     {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_WRONG_FINAL_BLOCK_LENGTH),
     "wrong final block length"},
-    {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_XTS_DATA_UNIT_IS_TOO_LARGE),
-    "xts data unit is too large"},
     {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_XTS_DUPLICATED_KEYS),
     "xts duplicated keys"},
     {0, NULL}
diff --git a/crypto/evp/p_lib.c b/crypto/evp/p_lib.c
index 1f36cb2..9e25ae1 100644
--- a/crypto/evp/p_lib.c
+++ b/crypto/evp/p_lib.c
@@ -459,6 +459,24 @@ const unsigned char *EVP_PKEY_get0_siphash(const EVP_PKEY *pkey, size_t *len)
 }
 #endif
 
+# 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_get0_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)
 {
diff --git a/crypto/rsa/rsa_err.c b/crypto/rsa/rsa_err.c
index cf43265..888fd07 100644
--- a/crypto/rsa/rsa_err.c
+++ b/crypto/rsa/rsa_err.c
@@ -1,6 +1,6 @@
 /*
  * Generated by util/mkerr.pl DO NOT EDIT
- * Copyright 1995-2019 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 1995-2022 The OpenSSL Project Authors. All Rights Reserved.
  *
  * Licensed under the OpenSSL license (the "License").  You may not use
  * this file except in compliance with the License.  You can obtain a copy
@@ -34,7 +34,8 @@ static const ERR_STRING_DATA RSA_str_functs[] = {
     {ERR_PACK(ERR_LIB_RSA, RSA_F_RSA_CHECK_KEY_EX, 0), "RSA_check_key_ex"},
     {ERR_PACK(ERR_LIB_RSA, RSA_F_RSA_CMS_DECRYPT, 0), "rsa_cms_decrypt"},
     {ERR_PACK(ERR_LIB_RSA, RSA_F_RSA_CMS_VERIFY, 0), "rsa_cms_verify"},
-    {ERR_PACK(ERR_LIB_RSA, RSA_F_RSA_GENERATE_KEY_EX, 0), "RSA_generate_key_ex"},
+    {ERR_PACK(ERR_LIB_RSA, RSA_F_RSA_GENERATE_KEY_EX, 0),
+     "RSA_generate_key_ex"},
     {ERR_PACK(ERR_LIB_RSA, RSA_F_RSA_GENERATE_MULTI_PRIME_KEY, 0),
      "RSA_generate_multi_prime_key"},
     {ERR_PACK(ERR_LIB_RSA, RSA_F_RSA_ITEM_VERIFY, 0), "rsa_item_verify"},
@@ -93,16 +94,21 @@ static const ERR_STRING_DATA RSA_str_functs[] = {
     {ERR_PACK(ERR_LIB_RSA, RSA_F_RSA_PARAM_DECODE, 0), "rsa_param_decode"},
     {ERR_PACK(ERR_LIB_RSA, RSA_F_RSA_PRINT, 0), "RSA_print"},
     {ERR_PACK(ERR_LIB_RSA, RSA_F_RSA_PRINT_FP, 0), "RSA_print_fp"},
+    {ERR_PACK(ERR_LIB_RSA, RSA_F_RSA_PRIVATE_DECRYPT, 0),
+     "RSA_private_decrypt"},
+    {ERR_PACK(ERR_LIB_RSA, RSA_F_RSA_PRIVATE_ENCRYPT, 0),
+     "RSA_private_encrypt"},
     {ERR_PACK(ERR_LIB_RSA, RSA_F_RSA_PRIV_DECODE, 0), "rsa_priv_decode"},
     {ERR_PACK(ERR_LIB_RSA, RSA_F_RSA_PRIV_ENCODE, 0), "rsa_priv_encode"},
-    {ERR_PACK(ERR_LIB_RSA, RSA_F_RSA_PRIVATE_DECRYPT, 0), "RSA_private_decrypt"},
-    {ERR_PACK(ERR_LIB_RSA, RSA_F_RSA_PRIVATE_ENCRYPT, 0), "RSA_private_encrypt"},
     {ERR_PACK(ERR_LIB_RSA, RSA_F_RSA_PSS_GET_PARAM, 0), "rsa_pss_get_param"},
     {ERR_PACK(ERR_LIB_RSA, RSA_F_RSA_PSS_TO_CTX, 0), "rsa_pss_to_ctx"},
-    {ERR_PACK(ERR_LIB_RSA, RSA_F_RSA_PUB_DECODE, 0), "rsa_pub_decode"},
     {ERR_PACK(ERR_LIB_RSA, RSA_F_RSA_PUBLIC_DECRYPT, 0), "RSA_public_decrypt"},
     {ERR_PACK(ERR_LIB_RSA, RSA_F_RSA_PUBLIC_ENCRYPT, 0), "RSA_public_encrypt"},
+    {ERR_PACK(ERR_LIB_RSA, RSA_F_RSA_PUB_DECODE, 0), "rsa_pub_decode"},
     {ERR_PACK(ERR_LIB_RSA, RSA_F_RSA_SETUP_BLINDING, 0), "RSA_setup_blinding"},
+    {ERR_PACK(ERR_LIB_RSA, RSA_F_RSA_SET_DEFAULT_METHOD, 0),
+     "RSA_set_default_method"},
+    {ERR_PACK(ERR_LIB_RSA, RSA_F_RSA_SET_METHOD, 0), "RSA_set_method"},
     {ERR_PACK(ERR_LIB_RSA, RSA_F_RSA_SIGN, 0), "RSA_sign"},
     {ERR_PACK(ERR_LIB_RSA, RSA_F_RSA_SIGN_ASN1_OCTET_STRING, 0),
      "RSA_sign_ASN1_OCTET_STRING"},
@@ -111,8 +117,6 @@ static const ERR_STRING_DATA RSA_str_functs[] = {
      "RSA_verify_ASN1_OCTET_STRING"},
     {ERR_PACK(ERR_LIB_RSA, RSA_F_RSA_VERIFY_PKCS1_PSS_MGF1, 0),
      "RSA_verify_PKCS1_PSS_mgf1"},
-    {ERR_PACK(ERR_LIB_RSA, RSA_F_RSA_SET_DEFAULT_METHOD, 0), "RSA_set_default_method"},
-    {ERR_PACK(ERR_LIB_RSA, RSA_F_RSA_SET_METHOD, 0), "RSA_set_method"},
     {ERR_PACK(ERR_LIB_RSA, RSA_F_SETUP_TBUF, 0), "setup_tbuf"},
     {0, NULL}
 };
@@ -193,8 +197,9 @@ static const ERR_STRING_DATA RSA_str_reasons[] = {
     {ERR_PACK(ERR_LIB_RSA, 0, RSA_R_MP_EXPONENT_NOT_CONGRUENT_TO_D),
     "mp exponent not congruent to d"},
     {ERR_PACK(ERR_LIB_RSA, 0, RSA_R_MP_R_NOT_PRIME), "mp r not prime"},
+    {ERR_PACK(ERR_LIB_RSA, 0, RSA_R_NON_FIPS_RSA_METHOD),
+    "non fips rsa method"},
     {ERR_PACK(ERR_LIB_RSA, 0, RSA_R_NO_PUBLIC_EXPONENT), "no public exponent"},
-    {ERR_PACK(ERR_LIB_RSA, 0, RSA_R_NON_FIPS_RSA_METHOD), "non FIPS rsa method"},
     {ERR_PACK(ERR_LIB_RSA, 0, RSA_R_NULL_BEFORE_BLOCK_MISSING),
     "null before block missing"},
     {ERR_PACK(ERR_LIB_RSA, 0, RSA_R_N_DOES_NOT_EQUAL_PRODUCT_OF_PRIMES),
@@ -204,7 +209,7 @@ static const ERR_STRING_DATA RSA_str_reasons[] = {
     {ERR_PACK(ERR_LIB_RSA, 0, RSA_R_OAEP_DECODING_ERROR),
     "oaep decoding error"},
     {ERR_PACK(ERR_LIB_RSA, 0, RSA_R_OPERATION_NOT_ALLOWED_IN_FIPS_MODE),
-    "operation not allowed in FIPS mode"},
+    "operation not allowed in fips mode"},
     {ERR_PACK(ERR_LIB_RSA, 0, RSA_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE),
     "operation not supported for this keytype"},
     {ERR_PACK(ERR_LIB_RSA, 0, RSA_R_PADDING_CHECK_FAILED),
diff --git a/crypto/sm2/build.info b/crypto/sm2/build.info
index be76d96..adaf5f3 100644
--- a/crypto/sm2/build.info
+++ b/crypto/sm2/build.info
@@ -1,5 +1,5 @@
 LIBS=../../libcrypto
 SOURCE[../../libcrypto]=\
-        sm2_sign.c sm2_crypt.c sm2_err.c sm2_pmeth.c
+        sm2_sign.c sm2_crypt.c sm2_err.c sm2_pmeth.c sm2_kep.c
 
 
diff --git a/crypto/sm2/sm2_err.c b/crypto/sm2/sm2_err.c
index e5973e9..f5f75cb 100644
--- a/crypto/sm2/sm2_err.c
+++ b/crypto/sm2/sm2_err.c
@@ -1,6 +1,6 @@
 /*
  * Generated by util/mkerr.pl DO NOT EDIT
- * Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 1995-2022 The OpenSSL Project Authors. All Rights Reserved.
  *
  * Licensed under the OpenSSL license (the "License").  You may not use
  * this file except in compliance with the License.  You can obtain a copy
@@ -21,6 +21,7 @@ static const ERR_STRING_DATA SM2_str_functs[] = {
      "pkey_sm2_digest_custom"},
     {ERR_PACK(ERR_LIB_SM2, SM2_F_PKEY_SM2_INIT, 0), "pkey_sm2_init"},
     {ERR_PACK(ERR_LIB_SM2, SM2_F_PKEY_SM2_SIGN, 0), "pkey_sm2_sign"},
+    {ERR_PACK(ERR_LIB_SM2, SM2_F_SM2_COMPUTE_KEY, 0), "SM2_compute_key"},
     {ERR_PACK(ERR_LIB_SM2, SM2_F_SM2_COMPUTE_MSG_HASH, 0),
      "sm2_compute_msg_hash"},
     {ERR_PACK(ERR_LIB_SM2, SM2_F_SM2_COMPUTE_USERID_DIGEST, 0),
@@ -51,6 +52,7 @@ static const ERR_STRING_DATA SM2_str_reasons[] = {
     {ERR_PACK(ERR_LIB_SM2, 0, SM2_R_INVALID_ENCODING), "invalid encoding"},
     {ERR_PACK(ERR_LIB_SM2, 0, SM2_R_INVALID_FIELD), "invalid field"},
     {ERR_PACK(ERR_LIB_SM2, 0, SM2_R_NO_PARAMETERS_SET), "no parameters set"},
+    {ERR_PACK(ERR_LIB_SM2, 0, SM2_R_NO_PRIVATE_VALUE), "no private value"},
     {ERR_PACK(ERR_LIB_SM2, 0, SM2_R_USER_ID_TOO_LARGE), "user id too large"},
     {0, NULL}
 };
diff --git a/crypto/sm2/sm2_kep.c b/crypto/sm2/sm2_kep.c
new file mode 100644
index 0000000..a7bd681
--- /dev/null
+++ b/crypto/sm2/sm2_kep.c
@@ -0,0 +1,254 @@
+/*
+ * Copyright 2019 The BabaSSL Project Authors. All Rights Reserved.
+ */
+
+#include "internal/cryptlib.h"
+#include <openssl/ec.h>
+#include <openssl/evp.h>
+#include <openssl/bn.h>
+#include "crypto/sm2.h"
+#include "crypto/ec.h" /* ecdh_KDF_X9_63() */
+#include "crypto/sm2err.h"
+
+
+#ifndef OPENSSL_NO_SM2
+int SM2_compute_key(void *out, size_t outlen, int server,
+                    const char *peer_uid, int peer_uid_len,
+                    const char *self_uid, int self_uid_len,
+                    const EC_KEY *peer_ecdhe_key, const EC_KEY *self_ecdhe_key,
+                    const EC_KEY *peer_pub_key, const EC_KEY *self_eckey,
+                    const EVP_MD *md)
+{
+    BN_CTX *ctx = NULL;
+    EC_POINT *UorV = NULL;
+    const EC_POINT *Rs, *Rp;
+    BIGNUM *Xs = NULL, *Xp = NULL, *h = NULL, *t = NULL, *two_power_w = NULL, *order = NULL;
+    const BIGNUM *priv_key, *r;
+    const EC_GROUP *group;
+    int w;
+    int ret = -1;
+    size_t buflen, len;
+    unsigned char *buf = NULL;
+    size_t elemet_len, idx;
+
+    if (outlen > INT_MAX) {
+        SM2err(SM2_F_SM2_COMPUTE_KEY, ERR_R_MALLOC_FAILURE);
+        goto err;
+    }
+
+    if (peer_pub_key == NULL || self_eckey == NULL) {
+        SM2err(SM2_F_SM2_COMPUTE_KEY, SM2_R_NO_PRIVATE_VALUE);
+        goto err;
+    }
+
+    priv_key = EC_KEY_get0_private_key(self_eckey);
+    if (priv_key == NULL) {
+        SM2err(SM2_F_SM2_COMPUTE_KEY, SM2_R_NO_PRIVATE_VALUE);
+        goto err;
+    }
+
+    if (peer_ecdhe_key == NULL || self_ecdhe_key == NULL) {
+        SM2err(SM2_F_SM2_COMPUTE_KEY, ERR_R_PASSED_NULL_PARAMETER);
+        goto err;
+    }
+
+    Rs = EC_KEY_get0_public_key(self_ecdhe_key);
+    Rp = EC_KEY_get0_public_key(peer_ecdhe_key);
+    r = EC_KEY_get0_private_key(self_ecdhe_key);
+
+    if (Rs == NULL || Rp == NULL || r == NULL) {
+        SM2err(SM2_F_SM2_COMPUTE_KEY, ERR_R_PASSED_NULL_PARAMETER);
+        goto err;
+    }
+
+    ctx = BN_CTX_new();
+    if (ctx == NULL) {
+        SM2err(SM2_F_SM2_COMPUTE_KEY, ERR_R_MALLOC_FAILURE);
+        goto err;
+    }
+
+    BN_CTX_start(ctx);
+    Xs = BN_CTX_get(ctx);
+    Xp = BN_CTX_get(ctx);
+    h = BN_CTX_get(ctx);
+    t = BN_CTX_get(ctx);
+    two_power_w = BN_CTX_get(ctx);
+    order = BN_CTX_get(ctx);
+
+    if (order == NULL) {
+        SM2err(SM2_F_SM2_COMPUTE_KEY, ERR_R_MALLOC_FAILURE);
+        goto err;
+    }
+
+    group = EC_KEY_get0_group(self_eckey);
+
+    if (!EC_GROUP_get_order(group, order, ctx)
+            || !EC_GROUP_get_cofactor(group, h, ctx)) {
+        SM2err(SM2_F_SM2_COMPUTE_KEY, ERR_R_MALLOC_FAILURE);
+        goto err;
+    }
+
+    w = (BN_num_bits(order) + 1) / 2 - 1;
+    if (!BN_lshift(two_power_w, BN_value_one(), w)) {
+        SM2err(SM2_F_SM2_COMPUTE_KEY, ERR_R_BN_LIB);
+        goto err;
+    }
+
+    /*Third: Caculate -- X =  2 ^ w + (x & (2 ^ w - 1)) = 2 ^ w + (x mod 2 ^ w)*/
+    UorV = EC_POINT_new(group);
+    if (UorV == NULL) {
+        SM2err(SM2_F_SM2_COMPUTE_KEY, ERR_R_MALLOC_FAILURE);
+        goto err;
+    }
+
+    /*Test peer public key On curve*/
+    if (!EC_POINT_is_on_curve(group, Rp, ctx)) {
+        SM2err(SM2_F_SM2_COMPUTE_KEY, ERR_R_EC_LIB);
+        goto err;
+    }
+
+    /*Get x*/
+    if (EC_METHOD_get_field_type(EC_GROUP_method_of(group))
+            == NID_X9_62_prime_field) {
+        if (!EC_POINT_get_affine_coordinates_GFp(group, Rs, Xs, NULL, ctx)) {
+            SM2err(SM2_F_SM2_COMPUTE_KEY, ERR_R_EC_LIB);
+            goto err;
+        }
+
+        if (!EC_POINT_get_affine_coordinates_GFp(group, Rp, Xp, NULL, ctx)) {
+            SM2err(SM2_F_SM2_COMPUTE_KEY, ERR_R_EC_LIB);
+            goto err;
+        }
+    }
+
+    /*x mod 2 ^ w*/
+    /*Caculate Self x*/
+    if (!BN_nnmod(Xs, Xs, two_power_w, ctx)) {
+        SM2err(SM2_F_SM2_COMPUTE_KEY, ERR_R_BN_LIB);
+        goto err;
+    }
+
+    if (!BN_add(Xs, Xs, two_power_w)) {
+        SM2err(SM2_F_SM2_COMPUTE_KEY, ERR_R_BN_LIB);
+        goto err;
+    }
+
+    /*Caculate Peer x*/
+    if (!BN_nnmod(Xp, Xp, two_power_w, ctx)) {
+        SM2err(SM2_F_SM2_COMPUTE_KEY, ERR_R_BN_LIB);
+        goto err;
+    }
+
+    if (!BN_add(Xp, Xp, two_power_w)) {
+        SM2err(SM2_F_SM2_COMPUTE_KEY, ERR_R_BN_LIB);
+        goto err;
+    }
+
+    /*Forth: Caculate t*/
+    if (!BN_mod_mul(t, Xs, r, order, ctx)) {
+        SM2err(SM2_F_SM2_COMPUTE_KEY, ERR_R_BN_LIB);
+        goto err;
+    }
+
+    if (!BN_mod_add(t, t, priv_key, order, ctx)) {
+        SM2err(SM2_F_SM2_COMPUTE_KEY, ERR_R_BN_LIB);
+        goto err;
+    }
+
+    /*Fifth: Caculate V or U*/
+    if (!BN_mul(t, t, h, ctx)) {
+        SM2err(SM2_F_SM2_COMPUTE_KEY, ERR_R_BN_LIB);
+        goto err;
+    }
+
+    /* [x]R */
+    if (!EC_POINT_mul(group, UorV, NULL, Rp, Xp, ctx)) {
+        SM2err(SM2_F_SM2_COMPUTE_KEY, ERR_R_EC_LIB);
+        goto err;
+    }
+
+    /* P + [x]R */
+    if (!EC_POINT_add(group, UorV, UorV,
+                      EC_KEY_get0_public_key(peer_pub_key), ctx)) {
+        SM2err(SM2_F_SM2_COMPUTE_KEY, ERR_R_EC_LIB);
+        goto err;
+    }
+
+    if (!EC_POINT_mul(group, UorV, NULL, UorV, t, ctx)) {
+        SM2err(SM2_F_SM2_COMPUTE_KEY, ERR_R_EC_LIB);
+        goto err;
+    }
+
+    if (EC_POINT_is_at_infinity(group, UorV)) {
+        SM2err(SM2_F_SM2_COMPUTE_KEY, ERR_R_EC_LIB);
+        goto err;
+    }
+
+    /*Sixth: Caculate Key -- Need Xuorv, Yuorv, Zc, Zs, klen*/
+
+    elemet_len = (size_t)((EC_GROUP_get_degree(group) + 7) / 8);
+    buflen = elemet_len * 2 + 32 * 2 + 1;    /*add 1 byte tag*/
+    buf = (unsigned char *)OPENSSL_zalloc(buflen + 10);
+    if (buf == NULL) {
+        SM2err(SM2_F_SM2_COMPUTE_KEY, ERR_R_MALLOC_FAILURE);
+        goto err;
+    }
+
+    /*1 : Get public key for UorV, Notice: the first byte is a tag, not a valid char*/
+    idx = EC_POINT_point2oct(group, UorV, 4, buf, buflen, ctx);
+    if (!idx) {
+        SM2err(SM2_F_SM2_COMPUTE_KEY, ERR_R_EC_LIB);
+        goto err;
+    }
+
+    len = EVP_MD_size(md);
+
+    /* Z_A || Z_B, server is initiator(Z_A), client is responder(Z_B) */
+    if (server) {
+        if (!sm2_compute_z_digest((uint8_t *)(buf + idx), md,
+                                  (const uint8_t *)self_uid,
+                                  self_uid_len, self_eckey)) {
+            SM2err(SM2_F_SM2_COMPUTE_KEY, ERR_R_INTERNAL_ERROR);
+            goto err;
+        }
+
+        idx += len;
+    }
+
+    if (!sm2_compute_z_digest((uint8_t *)(buf + idx), md,
+                              (const uint8_t *)peer_uid, peer_uid_len,
+                              peer_pub_key)) {
+        SM2err(SM2_F_SM2_COMPUTE_KEY, ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+    idx += len;
+
+    if (!server) {
+        if (!sm2_compute_z_digest((uint8_t *)(buf + idx), md,
+                                  (const uint8_t *)self_uid,
+                                  self_uid_len, self_eckey)) {
+            SM2err(SM2_F_SM2_COMPUTE_KEY, ERR_R_INTERNAL_ERROR);
+            goto err;
+        }
+        idx += len;
+    }
+
+    if (!ecdh_KDF_X9_63(out, outlen, (const unsigned char *)(buf + 1), idx - 1,
+                        NULL, 0, md)) {
+        SM2err(SM2_F_SM2_COMPUTE_KEY, ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+
+    ret = outlen;
+
+ err:
+    EC_POINT_free(UorV);
+    OPENSSL_free(buf);
+    if (ctx != NULL)
+        BN_CTX_end(ctx);
+    BN_CTX_free(ctx);
+
+    return ret;
+}
+
+#endif
diff --git a/crypto/sm2/sm2_pmeth.c b/crypto/sm2/sm2_pmeth.c
index 9551d70..1998812 100644
--- a/crypto/sm2/sm2_pmeth.c
+++ b/crypto/sm2/sm2_pmeth.c
@@ -287,6 +287,10 @@ static int pkey_sm2_digest_custom(EVP_PKEY_CTX *ctx, EVP_MD_CTX *mctx)
     const EVP_MD *md = EVP_MD_CTX_md(mctx);
     int mdlen = EVP_MD_size(md);
 
+    if (!smctx->id_set)
+        (void)pkey_sm2_ctrl(ctx, EVP_PKEY_CTRL_SET1_ID, SM2_DEFAULT_USERID_LEN
+            , (void *)SM2_DEFAULT_USERID);
+
     if (!smctx->id_set) {
         /*
          * An ID value must be set. The specifications are not clear whether a
diff --git a/doc/man1/s_client.pod b/doc/man1/s_client.pod
index f1a2c4a..8fa82a1 100644
--- a/doc/man1/s_client.pod
+++ b/doc/man1/s_client.pod
@@ -20,8 +20,10 @@ B<openssl> B<s_client>
 [B<-verify depth>]
 [B<-verify_return_error>]
 [B<-cert filename>]
+[B<-dcert filename>]
 [B<-certform DER|PEM>]
 [B<-key filename>]
+[B<-dkey filename>]
 [B<-keyform DER|PEM>]
 [B<-cert_chain filename>]
 [B<-build_chain>]
@@ -32,6 +34,7 @@ B<openssl> B<s_client>
 [B<-xcertform PEM|DER>]
 [B<-xkeyform PEM|DER>]
 [B<-pass arg>]
+[B<-dpass arg>]
 [B<-CApath directory>]
 [B<-CAfile filename>]
 [B<-chainCApath directory>]
@@ -91,6 +94,7 @@ B<openssl> B<s_client>
 [B<-tls1_1>]
 [B<-tls1_2>]
 [B<-tls1_3>]
+[B<-tlcp>]
 [B<-no_ssl3>]
 [B<-no_tls1>]
 [B<-no_tls1_1>]
@@ -214,6 +218,11 @@ ClientHello message. Cannot be used in conjunction with the B<-servername> or
 The certificate to use, if one is requested by the server. The default is
 not to use a certificate.
 
+=item B<-dcert infile>, B<-dkey infile>, B<-dpass val>
+
+Specify an encryption certificate, private key and passphrase
+respectively, usually for TLCP.
+
 =item B<-certform format>
 
 The certificate format to use: DER or PEM. PEM is the default.
diff --git a/doc/man3/EVP_PKEY_set1_RSA.pod b/doc/man3/EVP_PKEY_set1_RSA.pod
index d571e58..f9ee16d 100644
--- a/doc/man3/EVP_PKEY_set1_RSA.pod
+++ b/doc/man3/EVP_PKEY_set1_RSA.pod
@@ -9,7 +9,7 @@ EVP_PKEY_assign_RSA, EVP_PKEY_assign_DSA, EVP_PKEY_assign_DH,
 EVP_PKEY_assign_EC_KEY, EVP_PKEY_assign_POLY1305, EVP_PKEY_assign_SIPHASH,
 EVP_PKEY_get0_hmac, EVP_PKEY_get0_poly1305, EVP_PKEY_get0_siphash,
 EVP_PKEY_type, EVP_PKEY_id, EVP_PKEY_base_id, EVP_PKEY_set_alias_type,
-EVP_PKEY_set1_engine, EVP_PKEY_get0_engine - EVP_PKEY assignment functions
+EVP_PKEY_is_sm2, EVP_PKEY_set1_engine, EVP_PKEY_get0_engine - EVP_PKEY assignment functions
 
 =head1 SYNOPSIS
 
@@ -45,6 +45,8 @@ EVP_PKEY_set1_engine, EVP_PKEY_get0_engine - EVP_PKEY assignment functions
  int EVP_PKEY_type(int type);
  int EVP_PKEY_set_alias_type(EVP_PKEY *pkey, int type);
 
+ int EVP_PKEY_is_sm2(EVP_PKEY *pkey);
+
  ENGINE *EVP_PKEY_get0_engine(const EVP_PKEY *pkey);
  int EVP_PKEY_set1_engine(EVP_PKEY *pkey, ENGINE *engine);
 
@@ -93,6 +95,9 @@ EVP_PKEY_set_alias_type() allows modifying a EVP_PKEY to use a
 different set of algorithms than the default. This is currently used
 to support SM2 keys, which use an identical encoding to ECDSA.
 
+EVP_PKEY_is_sm2() can be used to determine whether the B<pkey> is
+SM2 curve.
+
 =head1 NOTES
 
 In accordance with the OpenSSL naming convention the key obtained
@@ -134,6 +139,8 @@ EVP_PKEY_set1_engine() returns 1 for success and 0 for failure.
 
 EVP_PKEY_set_alias_type() returns 1 for success and 0 for error.
 
+EVP_PKEY_is_sm2() returns 1 for success and 0 for error.
+
 =head1 EXAMPLES
 
 After loading an ECC key, it is possible to convert it to using SM2
diff --git a/doc/man3/SSL_CTX_new.pod b/doc/man3/SSL_CTX_new.pod
index a6c036c..23f93f6 100644
--- a/doc/man3/SSL_CTX_new.pod
+++ b/doc/man3/SSL_CTX_new.pod
@@ -9,7 +9,8 @@ TLSv1_1_method, TLSv1_1_server_method, TLSv1_1_client_method, TLS_method,
 TLS_server_method, TLS_client_method, SSLv23_method, SSLv23_server_method,
 SSLv23_client_method, DTLS_method, DTLS_server_method, DTLS_client_method,
 DTLSv1_method, DTLSv1_server_method, DTLSv1_client_method,
-DTLSv1_2_method, DTLSv1_2_server_method, DTLSv1_2_client_method
+DTLSv1_2_method, DTLSv1_2_server_method, DTLSv1_2_client_method,
+TLCP_method, TLCP_server_method, TLCP_client_method,
 - create a new SSL_CTX object as framework for TLS/SSL or DTLS enabled
 functions
 
@@ -68,6 +69,12 @@ functions
  const SSL_METHOD *DTLSv1_2_client_method(void);
  #endif
 
+ #ifndef OPENSSL_NO_TLCP
+ const SSL_METHOD *TLCP_method(void);
+ const SSL_METHOD *TLCP_server_method(void);
+ const SSL_METHOD *TLCP_client_method(void);
+ #endif
+
 =head1 DESCRIPTION
 
 SSL_CTX_new() creates a new B<SSL_CTX> object as framework to
@@ -93,6 +100,8 @@ These are the general-purpose I<version-flexible> SSL/TLS methods.
 The actual protocol version used will be negotiated to the highest version
 mutually supported by the client and the server.
 The supported protocols are SSLv3, TLSv1, TLSv1.1, TLSv1.2 and TLSv1.3.
+TLS_method() and TLS_server_method() can aslo support TLCP protocol
+by using TLCP_client_method().
 Applications should use these methods, and avoid the version-specific
 methods described below, which are deprecated.
 
@@ -141,6 +150,12 @@ These methods are deprecated.
 These are the version-specific methods for DTLSv1.
 These methods are deprecated.
 
+=item TLCP_method(), TLCP_server_method(), TLCP_client_method()
+
+These are the GM version-specific methods for TLCP protocol.
+Valid TLCP ciphersuite names are ECDHE-SM4-CBC-SM3 and ECC-SM4-CBC-SM3.
+B<enable-tlcp>(argument to Configure) was required.
+
 =back
 
 SSL_CTX_new() initializes the list of ciphers, the session cache setting, the
@@ -162,7 +177,7 @@ allow newer protocols like TLS 1.0, TLS 1.1, TLS 1.2 or TLS 1.3.
 
 The list of protocols available can also be limited using the
 B<SSL_OP_NO_SSLv3>, B<SSL_OP_NO_TLSv1>, B<SSL_OP_NO_TLSv1_1>,
-B<SSL_OP_NO_TLSv1_3>, B<SSL_OP_NO_TLSv1_2> and B<SSL_OP_NO_TLSv1_3>
+B<SSL_OP_NO_TLSv1_3>, B<SSL_OP_NO_TLSv1_2>, B<SSL_OP_NO_TLSv1_3> and B<SSL_OP_NO_TLCP>
 options of the
 L<SSL_CTX_set_options(3)> or L<SSL_set_options(3)> functions, but this approach
 is not recommended. Clients should avoid creating "holes" in the set of
diff --git a/doc/man3/SSL_CTX_set_options.pod b/doc/man3/SSL_CTX_set_options.pod
index 969e036..304e966 100644
--- a/doc/man3/SSL_CTX_set_options.pod
+++ b/doc/man3/SSL_CTX_set_options.pod
@@ -114,11 +114,11 @@ preferences. When not set, the SSL server will always follow the clients
 preferences. When set, the SSL/TLS server will choose following its
 own preferences.
 
-=item SSL_OP_NO_SSLv3, SSL_OP_NO_TLSv1, SSL_OP_NO_TLSv1_1,
+=item SSL_OP_NO_SSLv3, SSL_OP_NO_TLSv1, SSL_OP_NO_TLSv1_1, SSL_OP_NO_TLCP
 SSL_OP_NO_TLSv1_2, SSL_OP_NO_TLSv1_3, SSL_OP_NO_DTLSv1, SSL_OP_NO_DTLSv1_2
 
 These options turn off the SSLv3, TLSv1, TLSv1.1, TLSv1.2 or TLSv1.3 protocol
-versions with TLS or the DTLSv1, DTLSv1.2 versions with DTLS,
+versions with TLS or the DTLSv1, DTLSv1.2 versions with DTLS, TLCP
 respectively.
 As of OpenSSL 1.1.0, these options are deprecated, use
 L<SSL_CTX_set_min_proto_version(3)> and
diff --git a/doc/man3/SSL_CTX_use_certificate.pod b/doc/man3/SSL_CTX_use_certificate.pod
index b065d8f..7a717e7 100644
--- a/doc/man3/SSL_CTX_use_certificate.pod
+++ b/doc/man3/SSL_CTX_use_certificate.pod
@@ -12,7 +12,12 @@ SSL_CTX_use_RSAPrivateKey_ASN1, SSL_CTX_use_RSAPrivateKey_file,
 SSL_use_PrivateKey_file, SSL_use_PrivateKey_ASN1, SSL_use_PrivateKey,
 SSL_use_RSAPrivateKey, SSL_use_RSAPrivateKey_ASN1,
 SSL_use_RSAPrivateKey_file, SSL_CTX_check_private_key, SSL_check_private_key,
-SSL_CTX_use_cert_and_key, SSL_use_cert_and_key
+SSL_CTX_use_cert_and_key, SSL_use_cert_and_key,
+SSL_CTX_use_gm_certificate, SSL_CTX_use_gm_certificate_ASN1, SSL_CTX_use_gm_certificate_file,
+SSL_use_gm_certificate, SSL_use_gm_certificate_ASN1, SSL_use_gm_certificate_file,
+SSL_CTX_use_gm_PrivateKey, SSL_CTX_use_gm_PrivateKey_ASN1, SSL_CTX_use_gm_PrivateKey_file,
+SSL_use_gm_PrivateKey, SSL_use_gm_PrivateKey_ASN1, SSL_use_gm_PrivateKey_file,
+SSL_CTX_use_gm_cert_and_key, SSL_use_gm_cert_and_key
 - load certificate and key data
 
 =head1 SYNOPSIS
@@ -26,6 +31,13 @@ SSL_CTX_use_cert_and_key, SSL_use_cert_and_key
  int SSL_use_certificate_ASN1(SSL *ssl, unsigned char *d, int len);
  int SSL_use_certificate_file(SSL *ssl, const char *file, int type);
 
+ int SSL_CTX_use_gm_certificate(SSL_CTX *ctx, X509 *x, int usage);
+ int SSL_CTX_use_gm_certificate_ASN1(SSL_CTX *ctx, int len, unsigned char *d, int usage);
+ int SSL_CTX_use_gm_certificate_file(SSL_CTX *ctx, const char *file, int type, int usage);
+ int SSL_use_gm_certificate(SSL *ssl, X509 *x, int usage);
+ int SSL_use_gm_certificate_ASN1(SSL *ssl, unsigned char *d, int len, int usage);
+ int SSL_use_gm_certificate_file(SSL *ssl, const char *file, int type, int usage);
+
  int SSL_CTX_use_certificate_chain_file(SSL_CTX *ctx, const char *file);
  int SSL_use_certificate_chain_file(SSL *ssl, const char *file);
 
@@ -43,12 +55,23 @@ SSL_CTX_use_cert_and_key, SSL_use_cert_and_key
  int SSL_use_RSAPrivateKey_ASN1(SSL *ssl, unsigned char *d, long len);
  int SSL_use_RSAPrivateKey_file(SSL *ssl, const char *file, int type);
 
+ int SSL_CTX_use_gm_PrivateKey(SSL_CTX *ctx, EVP_PKEY *pkey, int usage);
+ int SSL_CTX_use_gm_PrivateKey_ASN1(int pk, SSL_CTX *ctx, unsigned char *d,
+                                 long len, int usage);
+ int SSL_CTX_use_gm_PrivateKey_file(SSL_CTX *ctx, const char *file, int type, int usage);
+ int SSL_use_gm_PrivateKey(SSL *ssl, EVP_PKEY *pkey, int usage);
+ int SSL_use_gm_PrivateKey_ASN1(int pk, SSL *ssl, unsigned char *d, long len, int usage);
+ int SSL_use_gm_PrivateKey_file(SSL *ssl, const char *file, int type, int usage);
+
  int SSL_CTX_check_private_key(const SSL_CTX *ctx);
  int SSL_check_private_key(const SSL *ssl);
 
  int SSL_CTX_use_cert_and_key(SSL_CTX *ctx, X509 *x, EVP_PKEY *pkey, STACK_OF(X509) *chain, int override);
  int SSL_use_cert_and_key(SSL *ssl, X509 *x, EVP_PKEY *pkey, STACK_OF(X509) *chain, int override);
 
+ int SSL_CTX_use_gm_cert_and_key(SSL_CTX *ctx, X509 *x, EVP_PKEY *pkey, STACK_OF(X509) *chain, int override, int usage);
+ int SSL_use_gm_cert_and_key(SSL *ssl, X509 *x, EVP_PKEY *pkey, STACK_OF(X509) *chain, int override, int usage);
+
 =head1 DESCRIPTION
 
 These functions load the certificates and private keys into the SSL_CTX
@@ -81,6 +104,21 @@ SSL_use_certificate_file() loads the certificate from B<file> into B<ssl>.
 See the NOTES section on why SSL_CTX_use_certificate_chain_file()
 should be preferred.
 
+SSL_CTX_use_gm_certificate() loads the certificate B<x> into B<ctx>
+and specify B<usage>. SSL_use_gm_certificate() loads B<x> into B<ssl>
+and specify B<usage>. The B<usage> should be SSL_USAGE_SIG or SSL_USAGE_ENC.
+
+SSL_CTX_use_gm_certificate_ASN1() loads the ASN1 encoded certificate from
+the memory location B<d> (with length B<len>) into B<ctx> and specify B<usage>,
+SSL_use_gm_certificate_ASN1() loads the ASN1 encoded certificate into B<ssl>
+and specify B<usage>.
+
+SSL_CTX_use_gm_certificate_file() loads the first certificate stored in B<file>
+into B<ctx> and specify B<usage>. The formatting B<type> of the certificate must
+be specified from the known types SSL_FILETYPE_PEM, SSL_FILETYPE_ASN1.
+SSL_use_gm_certificate_file() loads the certificate from B<file> into B<ssl>
+and specify B<usage>.
+
 SSL_CTX_use_certificate_chain_file() loads a certificate chain from
 B<file> into B<ctx>. The certificates must be in PEM format and must
 be sorted starting with the subject's certificate (actual client or server
@@ -127,6 +165,22 @@ B<file> to B<ctx>. SSL_use_PrivateKey_file() adds the first private key found
 in B<file> to B<ssl>; SSL_use_RSAPrivateKey_file() adds the first private
 RSA key found to B<ssl>.
 
+SSL_CTX_use_gm_PrivateKey() adds B<pkey> as private key to B<ctx> and
+specify B<usage>. SSL_CTX_use_gm_PrivateKey_ASN1() adds the private key of
+type B<pk> stored at memory location B<d> (length B<len>) to B<ctx> and
+specify B<usage>. SSL_CTX_use_gm_PrivateKey_file() adds the first private
+key found in B<file> to B<ctx>. The formatting B<type> of the private key 
+must be specified from the known types SSL_FILETYPE_PEM, SSL_FILETYPE_ASN1.
+
+SSL_use_PrivateKey() adds B<pkey> as private key to B<ssl> and sprcify B<usage>.
+SSL_use_gm_PrivateKey_ASN1() adds the private key to B<ssl> and sprcify B<usage>.
+SSL_use_gm_PrivateKey_file() adds the first private key found in B<file> to B<ssl>
+and sprcify B<usage>.
+
+SSL_CTX_use_gm_cert_and_key() and SSL_use_gm_cert_and_key() assign the X.509
+certificate B<x>, private key B<key>, and certificate B<chain> onto the
+corresponding B<ssl> or B<ctx> and specify B<usage>.
+
 SSL_CTX_check_private_key() checks the consistency of a private key with
 the corresponding certificate loaded into B<ctx>. If more than one
 key/certificate pair (RSA/DSA) is installed, the last item installed will
diff --git a/doc/man7/ssl.pod b/doc/man7/ssl.pod
index d439860..8d7293a 100644
--- a/doc/man7/ssl.pod
+++ b/doc/man7/ssl.pod
@@ -183,6 +183,18 @@ Constructor for the SSLv3 SSL_METHOD structure for clients.
 
 Constructor for the SSLv3 SSL_METHOD structure for servers.
 
+=item const SSL_METHOD *B<TLCP_method>(void);
+
+Constructor for the TLCP SSL_METHOD structure for clients, servers or both.
+
+=item const SSL_METHOD *B<TLCP_client_method>(void);
+
+Constructor for the TLCP SSL_METHOD structure for clients.
+
+=item const SSL_METHOD *B<TLCP_server_method>(void);
+
+Constructor for the TLCP SSL_METHOD structure for servers.
+
 =back
 
 =head2 Dealing with Ciphers
@@ -393,6 +405,12 @@ Use the file path to locate trusted CA certificates.
 
 =item int B<SSL_CTX_use_RSAPrivateKey_file>(SSL_CTX *ctx, const char *file, int type);
 
+=item int B<SSL_CTX_use_gm_PrivateKey>(SSL_CTX *ctx, EVP_PKEY *pkey, int usage);
+
+=item int B<SSL_CTX_use_gm_PrivateKey_ASN1>(int type, SSL_CTX *ctx, unsigned char *d, long len, int usage);
+
+=item int B<SSL_CTX_use_gm_PrivateKey_file>(SSL_CTX *ctx, const char *file, int type, int usage);
+
 =item int B<SSL_CTX_use_certificate>(SSL_CTX *ctx, X509 *x);
 
 =item int B<SSL_CTX_use_certificate_ASN1>(SSL_CTX *ctx, int len, unsigned char *d);
@@ -401,6 +419,14 @@ Use the file path to locate trusted CA certificates.
 
 =item int B<SSL_CTX_use_cert_and_key>(SSL_CTX *ctx, X509 *x, EVP_PKEY *pkey, STACK_OF(X509) *chain, int override);
 
+=item int B<SSL_CTX_use_gm_certificate>(SSL_CTX *ctx, X509 *x, int usage);
+
+=item int B<SSL_CTX_use_gm_certificate_ASN1>(SSL_CTX *ctx, int len, unsigned char *d, int usage);
+
+=item int B<SSL_CTX_use_gm_certificate_file>(SSL_CTX *ctx, const char *file, int type, int usage);
+
+=item int B<SSL_CTX_use_gm_cert_and_key>(SSL_CTX *ctx, X509 *x, EVP_PKEY *pkey, STACK_OF(X509) *chain, int override, int usage);
+
 =item X509 *B<SSL_CTX_get0_certificate>(const SSL_CTX *ctx);
 
 =item EVP_PKEY *B<SSL_CTX_get0_privatekey>(const SSL_CTX *ctx);
@@ -704,6 +730,12 @@ Returns the current handshake state.
 
 =item int B<SSL_use_RSAPrivateKey_file>(SSL *ssl, const char *file, int type);
 
+=item int B<SSL_use_gm_PrivateKey>(SSL *ssl, EVP_PKEY *pkey, int usage);
+
+=item int B<SSL_use_gm_PrivateKey_ASN1>(int type, SSL *ssl, unsigned char *d, long len, int usage);
+
+=item int B<SSL_use_gm_PrivateKey_file>(SSL *ssl, const char *file, int type, int usage);
+
 =item int B<SSL_use_certificate>(SSL *ssl, X509 *x);
 
 =item int B<SSL_use_certificate_ASN1>(SSL *ssl, int len, unsigned char *d);
@@ -712,6 +744,14 @@ Returns the current handshake state.
 
 =item int B<SSL_use_cert_and_key>(SSL *ssl, X509 *x, EVP_PKEY *pkey, STACK_OF(X509) *chain, int override);
 
+=item int B<SSL_use_gm_certificate>(SSL *ssl, X509 *x, int usage);
+
+=item int B<SSL_use_gm_certificate_ASN1>(SSL *ssl, int len, unsigned char *d, int usage);
+
+=item int B<SSL_use_gm_certificate_file>(SSL *ssl, const char *file, int type, int usage);
+
+=item int B<SSL_use_gm_cert_and_key>(SSL *ssl, X509 *x, EVP_PKEY *pkey, STACK_OF(X509) *chain, int override, int usage);
+
 =item int B<SSL_version>(const SSL *ssl);
 
 =item int B<SSL_want>(const SSL *ssl);
diff --git a/include/crypto/sm2.h b/include/crypto/sm2.h
index a7f5548..720bdd4 100644
--- a/include/crypto/sm2.h
+++ b/include/crypto/sm2.h
@@ -19,6 +19,7 @@
 
 /* The default user id as specified in GM/T 0009-2012 */
 #  define SM2_DEFAULT_USERID "1234567812345678"
+#  define SM2_DEFAULT_USERID_LEN 16
 
 int sm2_compute_z_digest(uint8_t *out,
                          const EVP_MD *digest,
diff --git a/include/crypto/sm2err.h b/include/crypto/sm2err.h
index d1c0ee2..251c4f9 100644
--- a/include/crypto/sm2err.h
+++ b/include/crypto/sm2err.h
@@ -1,6 +1,6 @@
 /*
  * Generated by util/mkerr.pl DO NOT EDIT
- * Copyright 1995-2019 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 1995-2022 The OpenSSL Project Authors. All Rights Reserved.
  *
  * Licensed under the OpenSSL license (the "License").  You may not use
  * this file except in compliance with the License.  You can obtain a copy
@@ -8,12 +8,10 @@
  * https://www.openssl.org/source/license.html
  */
 
-#ifndef OSSL_CRYPTO_SM2ERR_H
-# define OSSL_CRYPTO_SM2ERR_H
+#ifndef HEADER_SM2ERR_H
+# define HEADER_SM2ERR_H
 
-# ifndef HEADER_SYMHACKS_H
-#  include <openssl/symhacks.h>
-# endif
+# include <openssl/symhacks.h>
 
 # include <openssl/opensslconf.h>
 
@@ -33,6 +31,7 @@ int ERR_load_SM2_strings(void);
 #  define SM2_F_PKEY_SM2_DIGEST_CUSTOM                     114
 #  define SM2_F_PKEY_SM2_INIT                              111
 #  define SM2_F_PKEY_SM2_SIGN                              112
+#  define SM2_F_SM2_COMPUTE_KEY                            116
 #  define SM2_F_SM2_COMPUTE_MSG_HASH                       100
 #  define SM2_F_SM2_COMPUTE_USERID_DIGEST                  101
 #  define SM2_F_SM2_COMPUTE_Z_DIGEST                       113
@@ -59,6 +58,7 @@ int ERR_load_SM2_strings(void);
 #  define SM2_R_INVALID_ENCODING                           104
 #  define SM2_R_INVALID_FIELD                              105
 #  define SM2_R_NO_PARAMETERS_SET                          109
+#  define SM2_R_NO_PRIVATE_VALUE                           113
 #  define SM2_R_USER_ID_TOO_LARGE                          106
 
 # endif
diff --git a/include/openssl/dherr.h b/include/openssl/dherr.h
index b2d62eb..e7fdb21 100644
--- a/include/openssl/dherr.h
+++ b/include/openssl/dherr.h
@@ -1,6 +1,6 @@
 /*
  * Generated by util/mkerr.pl DO NOT EDIT
- * Copyright 1995-2019 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 1995-2022 The OpenSSL Project Authors. All Rights Reserved.
  *
  * Licensed under the OpenSSL license (the "License").  You may not use
  * this file except in compliance with the License.  You can obtain a copy
@@ -11,9 +11,7 @@
 #ifndef HEADER_DHERR_H
 # define HEADER_DHERR_H
 
-# ifndef HEADER_SYMHACKS_H
-#  include <openssl/symhacks.h>
-# endif
+# include <openssl/symhacks.h>
 
 # include <openssl/opensslconf.h>
 
@@ -36,9 +34,8 @@ int ERR_load_DH_strings(void);
 #  define DH_F_DH_CMS_DECRYPT                              114
 #  define DH_F_DH_CMS_SET_PEERKEY                          115
 #  define DH_F_DH_CMS_SET_SHARED_INFO                      116
-#  define DH_F_DH_COMPUTE_KEY                              203
-#  define DH_F_DH_GENERATE_KEY                             202
-#  define DH_F_DH_GENERATE_PARAMETERS_EX                   201
+#  define DH_F_DH_COMPUTE_KEY                              126
+#  define DH_F_DH_GENERATE_PARAMETERS_EX                   127
 #  define DH_F_DH_METH_DUP                                 117
 #  define DH_F_DH_METH_NEW                                 118
 #  define DH_F_DH_METH_SET1_NAME                           119
@@ -76,14 +73,14 @@ int ERR_load_DH_strings(void);
 #  define DH_R_INVALID_PARAMETER_NID                       114
 #  define DH_R_INVALID_PUBKEY                              102
 #  define DH_R_KDF_PARAMETER_ERROR                         112
-#  define DH_R_KEY_SIZE_TOO_SMALL                          201
 #  define DH_R_KEYS_NOT_SET                                108
+#  define DH_R_KEY_SIZE_TOO_SMALL                          126
 #  define DH_R_MISSING_PUBKEY                              125
 #  define DH_R_MODULUS_TOO_LARGE                           103
+#  define DH_R_NON_FIPS_METHOD                             127
 #  define DH_R_NOT_SUITABLE_GENERATOR                      120
 #  define DH_R_NO_PARAMETERS_SET                           107
 #  define DH_R_NO_PRIVATE_VALUE                            100
-#  define DH_R_NON_FIPS_METHOD                             202
 #  define DH_R_PARAMETER_ENCODING_ERROR                    105
 #  define DH_R_PEER_KEY_ERROR                              111
 #  define DH_R_SHARED_INFO_ERROR                           113
diff --git a/include/openssl/dsaerr.h b/include/openssl/dsaerr.h
index 19f650a..83f1b68 100644
--- a/include/openssl/dsaerr.h
+++ b/include/openssl/dsaerr.h
@@ -1,6 +1,6 @@
 /*
  * Generated by util/mkerr.pl DO NOT EDIT
- * Copyright 1995-2019 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 1995-2022 The OpenSSL Project Authors. All Rights Reserved.
  *
  * Licensed under the OpenSSL license (the "License").  You may not use
  * this file except in compliance with the License.  You can obtain a copy
@@ -11,9 +11,7 @@
 #ifndef HEADER_DSAERR_H
 # define HEADER_DSAERR_H
 
-# ifndef HEADER_SYMHACKS_H
-#  include <openssl/symhacks.h>
-# endif
+# include <openssl/symhacks.h>
 
 # include <openssl/opensslconf.h>
 
@@ -29,13 +27,13 @@ int ERR_load_DSA_strings(void);
  */
 #  define DSA_F_DSAPARAMS_PRINT                            100
 #  define DSA_F_DSAPARAMS_PRINT_FP                         101
-#  define DSA_F_DSA_BUILTIN_KEYGEN                         202
+#  define DSA_F_DSA_BUILTIN_KEYGEN                         108
 #  define DSA_F_DSA_BUILTIN_PARAMGEN                       125
 #  define DSA_F_DSA_BUILTIN_PARAMGEN2                      126
-#  define DSA_F_DSA_GENERATE_KEY                           201
-#  define DSA_F_DSA_GENERATE_PARAMETERS_EX                 200
 #  define DSA_F_DSA_DO_SIGN                                112
 #  define DSA_F_DSA_DO_VERIFY                              113
+#  define DSA_F_DSA_GENERATE_KEY                           109
+#  define DSA_F_DSA_GENERATE_PARAMETERS_EX                 110
 #  define DSA_F_DSA_METH_DUP                               127
 #  define DSA_F_DSA_METH_NEW                               128
 #  define DSA_F_DSA_METH_SET1_NAME                         129
@@ -63,13 +61,13 @@ int ERR_load_DSA_strings(void);
 #  define DSA_R_DECODE_ERROR                               104
 #  define DSA_R_INVALID_DIGEST_TYPE                        106
 #  define DSA_R_INVALID_PARAMETERS                         112
-#  define DSA_R_KEY_SIZE_INVALID                           201
-#  define DSA_R_KEY_SIZE_TOO_SMALL                         202
+#  define DSA_R_KEY_SIZE_INVALID                           114
+#  define DSA_R_KEY_SIZE_TOO_SMALL                         115
 #  define DSA_R_MISSING_PARAMETERS                         101
 #  define DSA_R_MISSING_PRIVATE_KEY                        111
 #  define DSA_R_MODULUS_TOO_LARGE                          103
+#  define DSA_R_NON_FIPS_DSA_METHOD                        116
 #  define DSA_R_NO_PARAMETERS_SET                          107
-#  define DSA_R_NON_FIPS_DSA_METHOD                        200
 #  define DSA_R_PARAMETER_ENCODING_ERROR                   105
 #  define DSA_R_Q_NOT_PRIME                                113
 #  define DSA_R_SEED_LEN_SMALL                             110
diff --git a/include/openssl/evp.h b/include/openssl/evp.h
index 0f7fbd1..3116c1b 100644
--- a/include/openssl/evp.h
+++ b/include/openssl/evp.h
@@ -1011,6 +1011,10 @@ const unsigned char *EVP_PKEY_get0_poly1305(const EVP_PKEY *pkey, size_t *len);
 const unsigned char *EVP_PKEY_get0_siphash(const EVP_PKEY *pkey, size_t *len);
 # endif
 
+# 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);
diff --git a/include/openssl/evperr.h b/include/openssl/evperr.h
index bfa2e68..da604ca 100644
--- a/include/openssl/evperr.h
+++ b/include/openssl/evperr.h
@@ -1,6 +1,6 @@
 /*
  * Generated by util/mkerr.pl DO NOT EDIT
- * Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 1995-2022 The OpenSSL Project Authors. All Rights Reserved.
  *
  * Licensed under the OpenSSL license (the "License").  You may not use
  * this file except in compliance with the License.  You can obtain a copy
@@ -22,15 +22,15 @@ int ERR_load_EVP_strings(void);
  * EVP function codes.
  */
 # define EVP_F_AESNI_INIT_KEY                             165
-# define EVP_F_AESNI_XTS_INIT_KEY                         233
+# define EVP_F_AESNI_XTS_INIT_KEY                         207
 # define EVP_F_AES_GCM_CTRL                               196
 # define EVP_F_AES_INIT_KEY                               133
 # define EVP_F_AES_OCB_CIPHER                             169
 # define EVP_F_AES_T4_INIT_KEY                            178
-# define EVP_F_AES_T4_XTS_INIT_KEY                        234
+# define EVP_F_AES_T4_XTS_INIT_KEY                        208
 # define EVP_F_AES_WRAP_CIPHER                            170
-# define EVP_F_AES_XTS_CIPHER                             229
-# define EVP_F_AES_XTS_INIT_KEY                           235
+# define EVP_F_AES_XTS_CIPHER                             210
+# define EVP_F_AES_XTS_INIT_KEY                           209
 # define EVP_F_ALG_MODULE_INIT                            177
 # define EVP_F_ARIA_CCM_INIT_KEY                          175
 # define EVP_F_ARIA_GCM_CTRL                              197
@@ -141,9 +141,9 @@ int ERR_load_EVP_strings(void);
 # define EVP_R_CTRL_OPERATION_NOT_IMPLEMENTED             133
 # define EVP_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH          138
 # define EVP_R_DECODE_ERROR                               114
-# define EVP_R_DISABLED_FOR_FIPS                          200
 # define EVP_R_DIFFERENT_KEY_TYPES                        101
 # define EVP_R_DIFFERENT_PARAMETERS                       153
+# define EVP_R_DISABLED_FOR_FIPS                          185
 # define EVP_R_ERROR_LOADING_SECTION                      165
 # define EVP_R_ERROR_SETTING_FIPS_MODE                    166
 # define EVP_R_EXPECTING_AN_HMAC_KEY                      174
@@ -186,7 +186,7 @@ int ERR_load_EVP_strings(void);
 # define EVP_R_PRIVATE_KEY_DECODE_ERROR                   145
 # define EVP_R_PRIVATE_KEY_ENCODE_ERROR                   146
 # define EVP_R_PUBLIC_KEY_NOT_RSA                         106
-# define EVP_R_TOO_LARGE                                  201
+# define EVP_R_TOO_LARGE                                  186
 # define EVP_R_UNKNOWN_CIPHER                             160
 # define EVP_R_UNKNOWN_DIGEST                             161
 # define EVP_R_UNKNOWN_OPTION                             169
@@ -202,7 +202,6 @@ int ERR_load_EVP_strings(void);
 # define EVP_R_UNSUPPORTED_SALT_TYPE                      126
 # define EVP_R_WRAP_MODE_NOT_ALLOWED                      170
 # define EVP_R_WRONG_FINAL_BLOCK_LENGTH                   109
-# define EVP_R_XTS_DATA_UNIT_IS_TOO_LARGE                 191
-# define EVP_R_XTS_DUPLICATED_KEYS                        192
+# define EVP_R_XTS_DUPLICATED_KEYS                        183
 
 #endif
diff --git a/include/openssl/rsaerr.h b/include/openssl/rsaerr.h
index a8bcfdf..6bbd265 100644
--- a/include/openssl/rsaerr.h
+++ b/include/openssl/rsaerr.h
@@ -1,6 +1,6 @@
 /*
  * Generated by util/mkerr.pl DO NOT EDIT
- * Copyright 1995-2019 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 1995-2022 The OpenSSL Project Authors. All Rights Reserved.
  *
  * Licensed under the OpenSSL license (the "License").  You may not use
  * this file except in compliance with the License.  You can obtain a copy
@@ -11,9 +11,7 @@
 #ifndef HEADER_RSAERR_H
 # define HEADER_RSAERR_H
 
-# ifndef HEADER_SYMHACKS_H
-#  include <openssl/symhacks.h>
-# endif
+# include <openssl/symhacks.h>
 
 # ifdef  __cplusplus
 extern "C"
@@ -25,7 +23,7 @@ int ERR_load_RSA_strings(void);
  */
 # define RSA_F_CHECK_PADDING_MD                           140
 # define RSA_F_ENCODE_PKCS1                               146
-# define RSA_F_FIPS_RSA_BUILTIN_KEYGEN                    206
+# define RSA_F_FIPS_RSA_BUILTIN_KEYGEN                    168
 # define RSA_F_INT_RSA_VERIFY                             145
 # define RSA_F_OLD_RSA_PRIV_DECODE                        147
 # define RSA_F_PKEY_PSS_INIT                              165
@@ -40,8 +38,8 @@ int ERR_load_RSA_strings(void);
 # define RSA_F_RSA_CHECK_KEY_EX                           160
 # define RSA_F_RSA_CMS_DECRYPT                            159
 # define RSA_F_RSA_CMS_VERIFY                             158
-# define RSA_F_RSA_GENERATE_KEY_EX                        204
-# define RSA_F_RSA_GENERATE_MULTI_PRIME_KEY               207
+# define RSA_F_RSA_GENERATE_KEY_EX                        169
+# define RSA_F_RSA_GENERATE_MULTI_PRIME_KEY               170
 # define RSA_F_RSA_ITEM_VERIFY                            148
 # define RSA_F_RSA_METH_DUP                               161
 # define RSA_F_RSA_METH_NEW                               162
@@ -77,18 +75,18 @@ int ERR_load_RSA_strings(void);
 # define RSA_F_RSA_PARAM_DECODE                           164
 # define RSA_F_RSA_PRINT                                  115
 # define RSA_F_RSA_PRINT_FP                               116
+# define RSA_F_RSA_PRIVATE_DECRYPT                        171
+# define RSA_F_RSA_PRIVATE_ENCRYPT                        172
 # define RSA_F_RSA_PRIV_DECODE                            150
 # define RSA_F_RSA_PRIV_ENCODE                            138
-# define RSA_F_RSA_PRIVATE_DECRYPT                        200
-# define RSA_F_RSA_PRIVATE_ENCRYPT                        201
 # define RSA_F_RSA_PSS_GET_PARAM                          151
 # define RSA_F_RSA_PSS_TO_CTX                             155
+# define RSA_F_RSA_PUBLIC_DECRYPT                         173
+# define RSA_F_RSA_PUBLIC_ENCRYPT                         174
 # define RSA_F_RSA_PUB_DECODE                             139
-# define RSA_F_RSA_PUBLIC_DECRYPT                         202
-# define RSA_F_RSA_PUBLIC_ENCRYPT                         203
 # define RSA_F_RSA_SETUP_BLINDING                         136
-# define RSA_F_RSA_SET_DEFAULT_METHOD                     205
-# define RSA_F_RSA_SET_METHOD                             204
+# define RSA_F_RSA_SET_DEFAULT_METHOD                     175
+# define RSA_F_RSA_SET_METHOD                             176
 # define RSA_F_RSA_SIGN                                   117
 # define RSA_F_RSA_SIGN_ASN1_OCTET_STRING                 118
 # define RSA_F_RSA_VERIFY                                 119
@@ -139,19 +137,19 @@ int ERR_load_RSA_strings(void);
 # define RSA_R_KEY_PRIME_NUM_INVALID                      165
 # define RSA_R_KEY_SIZE_TOO_SMALL                         120
 # define RSA_R_LAST_OCTET_INVALID                         134
-# define RSA_R_MISSING_PRIVATE_KEY                        179
 # define RSA_R_MGF1_DIGEST_NOT_ALLOWED                    152
+# define RSA_R_MISSING_PRIVATE_KEY                        179
 # define RSA_R_MODULUS_TOO_LARGE                          105
 # define RSA_R_MP_COEFFICIENT_NOT_INVERSE_OF_R            168
 # define RSA_R_MP_EXPONENT_NOT_CONGRUENT_TO_D             169
 # define RSA_R_MP_R_NOT_PRIME                             170
+# define RSA_R_NON_FIPS_RSA_METHOD                        171
 # define RSA_R_NO_PUBLIC_EXPONENT                         140
-# define RSA_R_NON_FIPS_RSA_METHOD                        200
 # define RSA_R_NULL_BEFORE_BLOCK_MISSING                  113
 # define RSA_R_N_DOES_NOT_EQUAL_PRODUCT_OF_PRIMES         172
 # define RSA_R_N_DOES_NOT_EQUAL_P_Q                       127
 # define RSA_R_OAEP_DECODING_ERROR                        121
-# define RSA_R_OPERATION_NOT_ALLOWED_IN_FIPS_MODE         201
+# define RSA_R_OPERATION_NOT_ALLOWED_IN_FIPS_MODE         173
 # define RSA_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE   148
 # define RSA_R_PADDING_CHECK_FAILED                       114
 # define RSA_R_PKCS_DECODING_ERROR                        159
@@ -171,7 +169,7 @@ int ERR_load_RSA_strings(void);
 # define RSA_R_UNSUPPORTED_LABEL_SOURCE                   163
 # define RSA_R_UNSUPPORTED_MASK_ALGORITHM                 153
 # define RSA_R_UNSUPPORTED_MASK_PARAMETER                 154
-# define RSA_R_UNSUPPORTED_PARAMETERS                     202
+# define RSA_R_UNSUPPORTED_PARAMETERS                     174
 # define RSA_R_UNSUPPORTED_SIGNATURE_TYPE                 155
 # define RSA_R_VALUE_MISSING                              147
 # define RSA_R_WRONG_SIGNATURE_LENGTH                     119
diff --git a/include/openssl/sm2.h b/include/openssl/sm2.h
new file mode 100644
index 0000000..505ebfc
--- /dev/null
+++ b/include/openssl/sm2.h
@@ -0,0 +1,20 @@
+#ifndef HEADER_SM2_H
+# define HEADER_SM2_H
+
+#include "ossl_typ.h"
+
+# ifdef  __cplusplus
+extern "C" {
+# endif
+
+int SM2_compute_key(void *out, size_t outlen,
+                    int server, const char *peer_uid, int peer_uid_len,
+                    const char *self_uid, int self_uid_len,
+                    const EC_KEY *peer_ecdhe_key, const EC_KEY *self_ecdhe_key,
+                    const EC_KEY *peer_pub_key, const EC_KEY *self_eckey,
+                    const EVP_MD *md);
+
+# ifdef  __cplusplus
+}
+# endif
+#endif
diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h
index fd0c5a9..a6acbc4 100644
--- a/include/openssl/ssl.h
+++ b/include/openssl/ssl.h
@@ -300,6 +300,11 @@ typedef int (*SSL_verify_cb)(int preverify_ok, X509_STORE_CTX *x509_ctx);
  * Reserved value (until OpenSSL 1.2.0)                  0x00000001U
  * Reserved value (until OpenSSL 1.2.0)                  0x00000002U
  */
+#ifndef OPENSSL_NO_TLCP
+/* Use reserved value for the position of enc cert, default is placed at the end */
+# define SSL_OP_ENCCERT_SECOND_POSITION                  0x00000002U
+#endif
+
 /* Allow initial connection to servers that don't support RI */
 # define SSL_OP_LEGACY_SERVER_CONNECT                    0x00000004U
 
@@ -383,8 +388,15 @@ typedef int (*SSL_verify_cb)(int preverify_ok, X509_STORE_CTX *x509_ctx);
 # define SSL_OP_NO_DTLSv1                                0x04000000U
 # define SSL_OP_NO_DTLSv1_2                              0x08000000U
 
+#ifndef OPENSSL_NO_TLCP
+/* Use reserved value for TCLP(GB/T 38636-2020) */
+# define SSL_OP_NO_TLCP                                  0x00000001U
+# define SSL_OP_NO_SSL_MASK (SSL_OP_NO_TLCP|SSL_OP_NO_SSLv3|\
+        SSL_OP_NO_TLSv1|SSL_OP_NO_TLSv1_1|SSL_OP_NO_TLSv1_2|SSL_OP_NO_TLSv1_3)
+#else
 # define SSL_OP_NO_SSL_MASK (SSL_OP_NO_SSLv3|\
         SSL_OP_NO_TLSv1|SSL_OP_NO_TLSv1_1|SSL_OP_NO_TLSv1_2|SSL_OP_NO_TLSv1_3)
+#endif
 # define SSL_OP_NO_DTLS_MASK (SSL_OP_NO_DTLSv1|SSL_OP_NO_DTLSv1_2)
 
 /* Disallow all renegotiation */
@@ -1041,6 +1053,11 @@ typedef enum {
     TLS_ST_SR_END_OF_EARLY_DATA
 } OSSL_HANDSHAKE_STATE;
 
+#ifndef OPENSSL_NO_TLCP
+# define SSL_USAGE_SIG              0
+# define SSL_USAGE_ENC              1
+#endif
+
 /*
  * Most of the following state values are no longer used and are defined to be
  * the closest equivalent value in the current state machine code. Not all
@@ -1177,6 +1194,19 @@ DECLARE_PEM_rw(SSL_SESSION, SSL_SESSION)
 /* fatal */
 # define SSL_AD_INAPPROPRIATE_FALLBACK   TLS1_AD_INAPPROPRIATE_FALLBACK
 # define SSL_AD_NO_APPLICATION_PROTOCOL  TLS1_AD_NO_APPLICATION_PROTOCOL
+
+/* These alert types are for TLCP */
+# define SSL_AD_UNSUPPORTED_SITE2SITE    TLCP_AD_UNSUPPORTED_SITE2SITE
+/* fatal */
+# define SSL_AD_NO_AREA                  TLCP_AD_NO_AREA
+# define SSL_AD_UNSUPPORTED_AREATYPE     TLCP_AD_UNSUPPORTED_AREATYPE
+# define SSL_AD_BAD_IBCPARAM             TLCP_AD_BAD_IBCPARAM
+/* fatal */
+# define SSL_AD_UNSUPPORTED_IBCPARAM     TLCP_AD_UNSUPPORTED_IBCPARAM
+/* fatal */
+# define SSL_AD_IDENTITY_NEED            TLCP_AD_IDENTITY_NEED
+/* fatal */
+
 # define SSL_ERROR_NONE                  0
 # define SSL_ERROR_SSL                   1
 # define SSL_ERROR_WANT_READ             2
@@ -1560,9 +1590,20 @@ __owur int SSL_use_RSAPrivateKey(SSL *ssl, RSA *rsa);
 __owur int SSL_use_RSAPrivateKey_ASN1(SSL *ssl, const unsigned char *d,
                                       long len);
 # endif
+# ifndef OPENSSL_NO_TLCP
+__owur int SSL_use_gm_PrivateKey(SSL *ssl, EVP_PKEY *pkey, int usage);
+__owur int SSL_use_gm_PrivateKey_ASN1(int pk, SSL *ssl, const unsigned char *d,
+                                   long len, int usage);
+# endif
 __owur int SSL_use_PrivateKey(SSL *ssl, EVP_PKEY *pkey);
 __owur int SSL_use_PrivateKey_ASN1(int pk, SSL *ssl, const unsigned char *d,
                                    long len);
+# ifndef OPENSSL_NO_TLCP
+__owur int SSL_use_gm_certificate(SSL *ssl, X509 *x, int usage);
+__owur int SSL_use_gm_certificate_ASN1(SSL *ssl, const unsigned char *d, int len, int usage);
+__owur int SSL_use_gm_cert_and_key(SSL *ssl, X509 *x509, EVP_PKEY *privatekey,
+                                STACK_OF(X509) *chain, int override, int usage);
+# endif
 __owur int SSL_use_certificate(SSL *ssl, X509 *x);
 __owur int SSL_use_certificate_ASN1(SSL *ssl, const unsigned char *d, int len);
 __owur int SSL_use_cert_and_key(SSL *ssl, X509 *x509, EVP_PKEY *privatekey,
@@ -1585,6 +1626,11 @@ __owur int SSL_CTX_use_serverinfo_file(SSL_CTX *ctx, const char *file);
 __owur int SSL_use_RSAPrivateKey_file(SSL *ssl, const char *file, int type);
 #endif
 
+#ifndef OPENSSL_NO_TLCP
+__owur int SSL_use_gm_PrivateKey_file(SSL *ssl, const char *file, int type, int usage);
+__owur int SSL_use_gm_certificate_file(SSL *ssl, const char *file, int type, int usage);
+#endif
+
 __owur int SSL_use_PrivateKey_file(SSL *ssl, const char *file, int type);
 __owur int SSL_use_certificate_file(SSL *ssl, const char *file, int type);
 
@@ -1592,6 +1638,13 @@ __owur int SSL_use_certificate_file(SSL *ssl, const char *file, int type);
 __owur int SSL_CTX_use_RSAPrivateKey_file(SSL_CTX *ctx, const char *file,
                                           int type);
 #endif
+
+#ifndef OPENSSL_NO_TLCP
+__owur int SSL_CTX_use_gm_PrivateKey_file(SSL_CTX *ctx, const char *file,
+                                       int type, int usage);
+__owur int SSL_CTX_use_gm_certificate_file(SSL_CTX *ctx, const char *file,
+                                        int type, int usage);
+#endif
 __owur int SSL_CTX_use_PrivateKey_file(SSL_CTX *ctx, const char *file,
                                        int type);
 __owur int SSL_CTX_use_certificate_file(SSL_CTX *ctx, const char *file,
@@ -1695,6 +1748,18 @@ __owur int SSL_CTX_use_RSAPrivateKey(SSL_CTX *ctx, RSA *rsa);
 __owur int SSL_CTX_use_RSAPrivateKey_ASN1(SSL_CTX *ctx, const unsigned char *d,
                                           long len);
 # endif
+
+# ifndef OPENSSL_NO_TLCP
+__owur int SSL_CTX_use_gm_PrivateKey(SSL_CTX *ctx, EVP_PKEY *pkey, int usage);
+__owur int SSL_CTX_use_gm_PrivateKey_ASN1(int pk, SSL_CTX *ctx,
+                                       const unsigned char *d, long len, int usage);
+__owur int SSL_CTX_use_gm_certificate(SSL_CTX *ctx, X509 *x, int usage);
+__owur int SSL_CTX_use_gm_certificate_ASN1(SSL_CTX *ctx, int len,
+                                        const unsigned char *d, int usage);
+__owur int SSL_CTX_use_gm_cert_and_key(SSL_CTX *ctx, X509 *x509, EVP_PKEY *privatekey,
+                                    STACK_OF(X509) *chain, int override, int usage);
+# endif
+
 __owur int SSL_CTX_use_PrivateKey(SSL_CTX *ctx, EVP_PKEY *pkey);
 __owur int SSL_CTX_use_PrivateKey_ASN1(int pk, SSL_CTX *ctx,
                                        const unsigned char *d, long len);
@@ -1873,6 +1938,12 @@ __owur const SSL_METHOD *TLS_method(void);
 __owur const SSL_METHOD *TLS_server_method(void);
 __owur const SSL_METHOD *TLS_client_method(void);
 
+#ifndef OPENSSL_NO_TLCP
+__owur const SSL_METHOD *TLCP_method(void);
+__owur const SSL_METHOD *TLCP_server_method(void);
+__owur const SSL_METHOD *TLCP_client_method(void);
+#endif
+
 # ifndef OPENSSL_NO_TLS1_METHOD
 DEPRECATEDIN_1_1_0(__owur const SSL_METHOD *TLSv1_method(void)) /* TLSv1.0 */
 DEPRECATEDIN_1_1_0(__owur const SSL_METHOD *TLSv1_server_method(void))
diff --git a/include/openssl/sslerr.h b/include/openssl/sslerr.h
index 701d61c..aa5f56a 100644
--- a/include/openssl/sslerr.h
+++ b/include/openssl/sslerr.h
@@ -1,6 +1,6 @@
 /*
  * Generated by util/mkerr.pl DO NOT EDIT
- * Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 1995-2022 The OpenSSL Project Authors. All Rights Reserved.
  *
  * Licensed under the OpenSSL license (the "License").  You may not use
  * this file except in compliance with the License.  You can obtain a copy
@@ -11,9 +11,7 @@
 #ifndef HEADER_SSLERR_H
 # define HEADER_SSLERR_H
 
-# ifndef HEADER_SYMHACKS_H
-#  include <openssl/symhacks.h>
-# endif
+# include <openssl/symhacks.h>
 
 # ifdef  __cplusplus
 extern "C"
@@ -171,6 +169,10 @@ int ERR_load_SSL_strings(void);
 # define SSL_F_SSL_CTX_USE_CERTIFICATE                    171
 # define SSL_F_SSL_CTX_USE_CERTIFICATE_ASN1               172
 # define SSL_F_SSL_CTX_USE_CERTIFICATE_FILE               173
+# define SSL_F_SSL_CTX_USE_GM_CERTIFICATE                 641
+# define SSL_F_SSL_CTX_USE_GM_CERTIFICATE_ASN1            642
+# define SSL_F_SSL_CTX_USE_GM_PRIVATEKEY                  643
+# define SSL_F_SSL_CTX_USE_GM_PRIVATEKEY_ASN1             644
 # define SSL_F_SSL_CTX_USE_PRIVATEKEY                     174
 # define SSL_F_SSL_CTX_USE_PRIVATEKEY_ASN1                175
 # define SSL_F_SSL_CTX_USE_PRIVATEKEY_FILE                176
@@ -197,7 +199,9 @@ int ERR_load_SSL_strings(void);
 # define SSL_F_SSL_HANDSHAKE_HASH                         560
 # define SSL_F_SSL_INIT_WBIO_BUFFER                       184
 # define SSL_F_SSL_KEY_UPDATE                             515
+# define SSL_F_SSL_LOAD_CERT_FILE                         645
 # define SSL_F_SSL_LOAD_CLIENT_CA_FILE                    185
+# define SSL_F_SSL_LOAD_PKEY_FILE                         646
 # define SSL_F_SSL_LOG_MASTER_SECRET                      498
 # define SSL_F_SSL_LOG_RSA_CLIENT_KEY_EXCHANGE            499
 # define SSL_F_SSL_MODULE_INIT                            392
@@ -231,11 +235,14 @@ int ERR_load_SSL_strings(void);
 # define SSL_F_SSL_SET_CIPHER_LIST                        271
 # define SSL_F_SSL_SET_CT_VALIDATION_CALLBACK             399
 # define SSL_F_SSL_SET_FD                                 192
+# define SSL_F_SSL_SET_GM_CERT_AND_KEY                    647
 # define SSL_F_SSL_SET_PKEY                               193
 # define SSL_F_SSL_SET_RFD                                194
 # define SSL_F_SSL_SET_SESSION                            195
 # define SSL_F_SSL_SET_SESSION_ID_CONTEXT                 218
 # define SSL_F_SSL_SET_SESSION_TICKET_EXT                 294
+# define SSL_F_SSL_SET_SIGN_ENC_CERT                      648
+# define SSL_F_SSL_SET_SIGN_ENC_PKEY                      649
 # define SSL_F_SSL_SET_TLSEXT_MAX_FRAGMENT_LENGTH         550
 # define SSL_F_SSL_SET_WFD                                196
 # define SSL_F_SSL_SHUTDOWN                               224
@@ -246,6 +253,10 @@ int ERR_load_SSL_strings(void);
 # define SSL_F_SSL_USE_CERTIFICATE                        198
 # define SSL_F_SSL_USE_CERTIFICATE_ASN1                   199
 # define SSL_F_SSL_USE_CERTIFICATE_FILE                   200
+# define SSL_F_SSL_USE_GM_CERTIFICATE                     650
+# define SSL_F_SSL_USE_GM_CERTIFICATE_ASN1                651
+# define SSL_F_SSL_USE_GM_PRIVATEKEY                      652
+# define SSL_F_SSL_USE_GM_PRIVATEKEY_ASN1                 653
 # define SSL_F_SSL_USE_PRIVATEKEY                         201
 # define SSL_F_SSL_USE_PRIVATEKEY_ASN1                    202
 # define SSL_F_SSL_USE_PRIVATEKEY_FILE                    203
@@ -262,6 +273,20 @@ int ERR_load_SSL_strings(void);
 # define SSL_F_SSL_WRITE_EX                               433
 # define SSL_F_SSL_WRITE_INTERNAL                         524
 # define SSL_F_STATE_MACHINE                              353
+# define SSL_F_TLCP_CHOOSE_SIGALG                         662
+# define SSL_F_TLCP_CONSTRUCT_CKE_SM2DHE                  663
+# define SSL_F_TLCP_CONSTRUCT_CKE_SM2ECC                  658
+# define SSL_F_TLCP_CONSTRUCT_CLIENT_KEY_EXCHANGE         654
+# define SSL_F_TLCP_CONSTRUCT_SERVER_KEY_EXCHANGE         655
+# define SSL_F_TLCP_CONSTRUCT_SKE_SM2DHE                  664
+# define SSL_F_TLCP_CONSTRUCT_SKE_SM2ECC                  659
+# define SSL_F_TLCP_DERIVE                                665
+# define SSL_F_TLCP_PROCESS_CKE_SM2DHE                    666
+# define SSL_F_TLCP_PROCESS_CKE_SM2ECC                    660
+# define SSL_F_TLCP_PROCESS_CLIENT_KEY_EXCHANGE           656
+# define SSL_F_TLCP_PROCESS_KEY_EXCHANGE                  657
+# define SSL_F_TLCP_PROCESS_SKE_SM2DHE                    667
+# define SSL_F_TLCP_PROCESS_SKE_SM2ECC                    661
 # define SSL_F_TLS12_CHECK_PEER_SIGALG                    333
 # define SSL_F_TLS12_COPY_SIGALGS                         533
 # define SSL_F_TLS13_CHANGE_CIPHER_STATE                  440
diff --git a/include/openssl/tls1.h b/include/openssl/tls1.h
index 76d9fda..f05382a 100644
--- a/include/openssl/tls1.h
+++ b/include/openssl/tls1.h
@@ -24,6 +24,7 @@ extern "C" {
 #  define OPENSSL_TLS_SECURITY_LEVEL 1
 # endif
 
+# define TLCP_VERSION                    0x0101
 # define TLS1_VERSION                    0x0301
 # define TLS1_1_VERSION                  0x0302
 # define TLS1_2_VERSION                  0x0303
@@ -33,6 +34,9 @@ extern "C" {
 /* Special value for method supporting multiple versions */
 # define TLS_ANY_VERSION                 0x10000
 
+# define TLCP_VERSION_MAJOR              0x01
+# define TLCP_VERSION_MINOR              0x01
+
 # define TLS1_VERSION_MAJOR              0x03
 # define TLS1_VERSION_MINOR              0x01
 
@@ -73,6 +77,14 @@ extern "C" {
 # define TLS1_AD_UNKNOWN_PSK_IDENTITY    115/* fatal */
 # define TLS1_AD_NO_APPLICATION_PROTOCOL 120 /* fatal */
 
+/* TLCP(GB/T 38636-2020) alerts */
+# define TLCP_AD_UNSUPPORTED_SITE2SITE   200 /* fatal */
+# define TLCP_AD_NO_AREA                 201
+# define TLCP_AD_UNSUPPORTED_AREATYPE    202
+# define TLCP_AD_BAD_IBCPARAM            203 /* fatal */
+# define TLCP_AD_UNSUPPORTED_IBCPARAM    204 /* fatal */
+# define TLCP_AD_IDENTITY_NEED           205 /* fatal */
+
 /* ExtensionType values from RFC3546 / RFC4366 / RFC6066 */
 # define TLSEXT_TYPE_server_name                 0
 # define TLSEXT_TYPE_max_fragment_length         1
@@ -641,6 +653,10 @@ __owur int SSL_check_chain(SSL *s, X509 *x, EVP_PKEY *pk, STACK_OF(X509) *chain)
 # define TLS1_CK_RSA_PSK_WITH_ARIA_128_GCM_SHA256         0x0300C06E
 # define TLS1_CK_RSA_PSK_WITH_ARIA_256_GCM_SHA384         0x0300C06F
 
+/* some TLCP ciphersuites from GB/T 38636-2020 */
+# define TLCP_CK_ECDHE_SM2_WITH_SM4_CBC_SM3               0x0300E011
+# define TLCP_CK_ECC_SM2_WITH_SM4_CBC_SM3                 0x0300E013
+
 /* a bundle of RFC standard cipher names, generated from ssl3_ciphers[] */
 # define TLS1_RFC_RSA_WITH_AES_128_SHA                   "TLS_RSA_WITH_AES_128_CBC_SHA"
 # define TLS1_RFC_DHE_DSS_WITH_AES_128_SHA               "TLS_DHE_DSS_WITH_AES_128_CBC_SHA"
@@ -1127,6 +1143,10 @@ __owur int SSL_check_chain(SSL *s, X509 *x, EVP_PKEY *pk, STACK_OF(X509) *chain)
 # define TLS1_TXT_RSA_PSK_WITH_ARIA_128_GCM_SHA256         "RSA-PSK-ARIA128-GCM-SHA256"
 # define TLS1_TXT_RSA_PSK_WITH_ARIA_256_GCM_SHA384         "RSA-PSK-ARIA256-GCM-SHA384"
 
+/* some TLCP ciphersuites from GB/T 38636-2020 */
+# define TLCP_TXT_ECDHE_SM2_WITH_SM4_CBC_SM3               "ECDHE-SM4-CBC-SM3"
+# define TLCP_TXT_ECC_SM2_WITH_SM4_CBC_SM3                 "ECC-SM4-CBC-SM3"
+
 # define TLS_CT_RSA_SIGN                 1
 # define TLS_CT_DSS_SIGN                 2
 # define TLS_CT_RSA_FIXED_DH             3
diff --git a/include/openssl/x509.h b/include/openssl/x509.h
index 42e9eee..f6e82f1 100644
--- a/include/openssl/x509.h
+++ b/include/openssl/x509.h
@@ -55,6 +55,10 @@ extern "C" {
 # define X509v3_KU_ENCIPHER_ONLY         0x0001
 # define X509v3_KU_DECIPHER_ONLY         0x8000
 # define X509v3_KU_UNDEF                 0xffff
+/* For TLCP sm2 certificates */
+# define X509v3_KU_SM2_SIGN (X509v3_KU_DIGITAL_SIGNATURE | X509v3_KU_NON_REPUDIATION)
+# define X509v3_KU_SM2_ENC_ENCIPHERMENT (X509v3_KU_KEY_ENCIPHERMENT | X509v3_KU_DATA_ENCIPHERMENT)
+# define X509v3_KU_SM2_ENC_CIPHER_ONLY (X509v3_KU_ENCIPHER_ONLY | X509v3_KU_DECIPHER_ONLY)
 
 struct X509_algor_st {
     ASN1_OBJECT *algorithm;
diff --git a/include/openssl/x509err.h b/include/openssl/x509err.h
index 0a84ef0..1e51e04 100644
--- a/include/openssl/x509err.h
+++ b/include/openssl/x509err.h
@@ -1,6 +1,6 @@
 /*
  * Generated by util/mkerr.pl DO NOT EDIT
- * Copyright 1995-2020 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 1995-2022 The OpenSSL Project Authors. All Rights Reserved.
  *
  * Licensed under the OpenSSL license (the "License").  You may not use
  * this file except in compliance with the License.  You can obtain a copy
@@ -84,7 +84,7 @@ int ERR_load_X509_strings(void);
 # define X509_F_X509_TO_X509_REQ                          126
 # define X509_F_X509_TRUST_ADD                            133
 # define X509_F_X509_TRUST_SET                            141
-# define X509_F_X509_VERIFY                               161
+# define X509_F_X509_VERIFY                               166
 # define X509_F_X509_VERIFY_CERT                          127
 # define X509_F_X509_VERIFY_PARAM_NEW                     159
 # define X509_F_X509_VERIFY_SM2                           162
diff --git a/ssl/methods.c b/ssl/methods.c
index c5e8898..2a6cd73 100644
--- a/ssl/methods.c
+++ b/ssl/methods.c
@@ -109,6 +109,25 @@ IMPLEMENT_tls_meth_func(TLS1_VERSION, SSL_METHOD_NO_SUITEB, SSL_OP_NO_TLSv1,
 IMPLEMENT_ssl3_meth_func(sslv3_client_method,
                          ssl_undefined_function, ossl_statem_connect)
 #endif
+/*-
+ * TLCP methods
+ */
+#ifndef OPENSSL_NO_TLCP
+IMPLEMENT_tls_meth_func(TLCP_VERSION, 0, SSL_OP_NO_TLCP,
+                        tlcp_method,
+                        ossl_statem_accept,
+                        ossl_statem_connect, TLCP_enc_data)
+
+IMPLEMENT_tls_meth_func(TLCP_VERSION, 0, SSL_OP_NO_TLCP,
+                        tlcp_server_method,
+                        ossl_statem_accept,
+                        ssl_undefined_function, TLCP_enc_data)
+
+IMPLEMENT_tls_meth_func(TLCP_VERSION, 0, SSL_OP_NO_TLCP,
+                        tlcp_client_method,
+                        ssl_undefined_function,
+                        ossl_statem_connect, TLCP_enc_data)
+#endif
 /*-
  * DTLS methods
  */
@@ -207,6 +226,23 @@ const SSL_METHOD *TLSv1_1_client_method(void)
 }
 # endif
 
+# ifndef OPENSSL_NO_TLCP
+const SSL_METHOD *TLCP_method(void)
+{
+    return tlcp_method();
+}
+
+const SSL_METHOD *TLCP_server_method(void)
+{
+    return tlcp_server_method();
+}
+
+const SSL_METHOD *TLCP_client_method(void)
+{
+    return tlcp_client_method();
+}
+# endif
+
 # ifndef OPENSSL_NO_TLS1_METHOD
 const SSL_METHOD *TLSv1_method(void)
 {
diff --git a/ssl/record/ssl3_record.c b/ssl/record/ssl3_record.c
index f158544..af825b1 100644
--- a/ssl/record/ssl3_record.c
+++ b/ssl/record/ssl3_record.c
@@ -309,7 +309,11 @@ int ssl3_get_record(SSL *s)
                     return -1;
                 }
 
+#ifndef OPENSSL_NO_TLCP
+                if ((version >> 8) != SSL3_VERSION_MAJOR && (version != TLCP_VERSION)) {
+#else
                 if ((version >> 8) != SSL3_VERSION_MAJOR) {
+#endif
                     if (RECORD_LAYER_is_first_record(&s->rlayer)) {
                         /* Go back to start of packet, look at the five bytes
                          * that we have. */
diff --git a/ssl/s3_lib.c b/ssl/s3_lib.c
index 918cab0..5ecd953 100644
--- a/ssl/s3_lib.c
+++ b/ssl/s3_lib.c
@@ -15,6 +15,8 @@
 #include "ssl_local.h"
 #include <openssl/md5.h>
 #include <openssl/dh.h>
+#include "include/crypto/sm2.h"
+#include <openssl/sm2.h>
 #include <openssl/rand.h>
 #include "internal/cryptlib.h"
 
@@ -2667,6 +2669,43 @@ static SSL_CIPHER ssl3_ciphers[] = {
      },
 #endif                          /* OPENSSL_NO_GOST */
 
+#ifndef OPENSSL_NO_TLCP
+    {
+     1,
+     TLCP_TXT_ECDHE_SM2_WITH_SM4_CBC_SM3,
+     NULL,
+     TLCP_CK_ECDHE_SM2_WITH_SM4_CBC_SM3,
+     SSL_kSM2DHE,
+     SSL_aSM2,
+     SSL_SM4CBC,
+     SSL_SM3,
+     TLCP_VERSION,
+     TLS1_2_VERSION,
+     0, 0,
+     SSL_HIGH,
+     SSL_HANDSHAKE_MAC_SM3 | TLS1_PRF_SM3,
+     128,
+     128,
+    },
+    {
+     1,
+     TLCP_TXT_ECC_SM2_WITH_SM4_CBC_SM3,
+     NULL,
+     TLCP_CK_ECC_SM2_WITH_SM4_CBC_SM3,
+     SSL_kSM2ECC,
+     SSL_aSM2,
+     SSL_SM4CBC,
+     SSL_SM3,
+     TLCP_VERSION,
+     TLS1_2_VERSION,
+     0, 0,
+     SSL_HIGH,
+     SSL_HANDSHAKE_MAC_SM3 | TLS1_PRF_SM3,
+     128,
+     128,
+    },
+#endif                          /* OPENSSL_NO_TLCP */
+
 #ifndef OPENSSL_NO_IDEA
     {
      1,
@@ -4313,6 +4352,20 @@ const SSL_CIPHER *ssl3_choose_cipher(SSL *s, STACK_OF(SSL_CIPHER) *clnt,
                     ret = tmp;
                 continue;
             }
+#ifndef OPENSSL_NO_TLCP
+            /* Prefer ECC-SM4-CBC-SM3 while enabling TLCP */
+            if (!(s->options & SSL_OP_NO_TLCP)) {
+                const SSL_CIPHER *tmp = sk_SSL_CIPHER_value(allow, ii);
+
+                if (tmp->id == TLCP_CK_ECC_SM2_WITH_SM4_CBC_SM3) {
+                    ret = tmp;
+                    break;
+                }
+                if (ret == NULL)
+                    ret = tmp;
+                continue;
+            }
+#endif
             ret = sk_SSL_CIPHER_value(allow, ii);
             break;
         }
@@ -4856,3 +4909,76 @@ EVP_PKEY *ssl_dh_to_pkey(DH *dh)
     return ret;
 }
 #endif
+
+#ifndef OPENSSL_NO_TLCP
+int tlcp_derive(SSL *s, EVP_PKEY *privkey, EVP_PKEY *pubkey)
+{
+    unsigned char *pms;
+    int pmslen = SSL_MAX_MASTER_KEY_LENGTH;
+    EC_KEY *tmp_peer_pub_key, *tmp_self_priv_key;
+    EC_KEY *self_priv_key, *peer_pub_key;
+    X509 *peer_enc_cert;
+    int ret;
+
+    if ((tmp_self_priv_key = EVP_PKEY_get0_EC_KEY(privkey)) == NULL
+            || (tmp_peer_pub_key = EVP_PKEY_get0_EC_KEY(pubkey)) == NULL) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLCP_DERIVE,
+                 ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    if (s->cert->pkeys[SSL_PKEY_SM2_ENC].privatekey == NULL) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLCP_DERIVE,
+                 ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    if ((self_priv_key = EVP_PKEY_get0_EC_KEY(s->cert->pkeys[SSL_PKEY_SM2_ENC].privatekey)) == NULL) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLCP_DERIVE,
+                 ERR_R_EC_LIB);
+        return 0;
+    }
+
+    peer_enc_cert = ssl_get_sm2_enc_cert(s, s->session->peer_chain);
+    if (peer_enc_cert == NULL) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLCP_DERIVE,
+                 ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    if ((peer_pub_key = EVP_PKEY_get0_EC_KEY(X509_get0_pubkey(peer_enc_cert))) == NULL) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLCP_DERIVE,
+                 ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    pms = OPENSSL_malloc(pmslen);
+    if (pms == NULL) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLCP_DERIVE,
+                 ERR_R_MALLOC_FAILURE);
+        return 0;
+    }
+
+    if (SM2_compute_key(pms, pmslen, s->server, 
+                         SM2_DEFAULT_USERID, SM2_DEFAULT_USERID_LEN, 
+                         SM2_DEFAULT_USERID, SM2_DEFAULT_USERID_LEN, 
+                         tmp_peer_pub_key, tmp_self_priv_key, 
+                         peer_pub_key, self_priv_key,
+                         EVP_sm3()) != pmslen) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLCP_DERIVE,
+                 ERR_R_INTERNAL_ERROR);
+        OPENSSL_free(pms);
+        return 0;
+    }
+
+    if (s->server) {
+        ret = ssl_generate_master_secret(s, pms, (size_t)pmslen, 1);
+    } else {
+        s->s3->tmp.pms = pms;
+        s->s3->tmp.pmslen = pmslen;
+        ret = 1;
+    }
+
+    return ret;
+}
+#endif
diff --git a/ssl/ssl_asn1.c b/ssl/ssl_asn1.c
index 9264364..beb3c3b 100644
--- a/ssl/ssl_asn1.c
+++ b/ssl/ssl_asn1.c
@@ -265,7 +265,8 @@ SSL_SESSION *d2i_SSL_SESSION(SSL_SESSION **a, const unsigned char **pp,
 
     if ((as->ssl_version >> 8) != SSL3_VERSION_MAJOR
         && (as->ssl_version >> 8) != DTLS1_VERSION_MAJOR
-        && as->ssl_version != DTLS1_BAD_VER) {
+        && as->ssl_version != DTLS1_BAD_VER
+        && as->ssl_version != TLCP_VERSION) {
         SSLerr(SSL_F_D2I_SSL_SESSION, SSL_R_UNSUPPORTED_SSL_VERSION);
         goto err;
     }
diff --git a/ssl/ssl_cert.c b/ssl/ssl_cert.c
index e7feda8..73d76a5 100644
--- a/ssl/ssl_cert.c
+++ b/ssl/ssl_cert.c
@@ -937,18 +937,31 @@ static int ssl_security_default_callback(const SSL *s, const SSL_CTX *ctx,
                 return 0;
             /* Level 3: forward secure ciphersuites only */
             if (level >= 3 && c->min_tls != TLS1_3_VERSION &&
+#ifndef OPENSSL_NO_TLCP
+                               !(c->algorithm_mkey & (SSL_kEDH | SSL_kEECDH | SSL_kSM2DHE)))
+#else
                                !(c->algorithm_mkey & (SSL_kEDH | SSL_kEECDH)))
+#endif
                 return 0;
             break;
         }
     case SSL_SECOP_VERSION:
         if (!SSL_IS_DTLS(s)) {
+#ifndef OPENSSL_NO_TLCP
+            /* SSLv3 not allowed at level 2 */
+            if (nid <= SSL3_VERSION && nid != TLCP_VERSION && level >= 2)
+                return 0;
+            /* TLS v1.1 and above only for level 3 */
+            if (nid <= TLS1_VERSION && nid != TLCP_VERSION && level >= 3)
+                return 0;
+#else
             /* SSLv3 not allowed at level 2 */
             if (nid <= SSL3_VERSION && level >= 2)
                 return 0;
             /* TLS v1.1 and above only for level 3 */
             if (nid <= TLS1_VERSION && level >= 3)
                 return 0;
+#endif
             /* TLS v1.2 only for level 4 and above */
             if (nid <= TLS1_1_VERSION && level >= 4)
                 return 0;
@@ -1003,6 +1016,11 @@ const SSL_CERT_LOOKUP *ssl_cert_lookup_by_pkey(const EVP_PKEY *pk, size_t *pidx)
 {
     int nid = EVP_PKEY_id(pk);
     size_t tmpidx;
+#ifndef OPENSSL_NO_TLCP
+    if (EVP_PKEY_is_sm2((EVP_PKEY *)pk)) {
+        nid = NID_sm2;
+    }
+#endif
 
     if (nid == NID_undef)
         return NULL;
diff --git a/ssl/ssl_cert_table.h b/ssl/ssl_cert_table.h
index 0c47241..1e1864f 100644
--- a/ssl/ssl_cert_table.h
+++ b/ssl/ssl_cert_table.h
@@ -19,5 +19,9 @@ static const SSL_CERT_LOOKUP ssl_cert_info [] = {
     {NID_id_GostR3410_2012_256, SSL_aGOST12}, /* SSL_PKEY_GOST12_256 */
     {NID_id_GostR3410_2012_512, SSL_aGOST12}, /* SSL_PKEY_GOST12_512 */
     {EVP_PKEY_ED25519, SSL_aECDSA}, /* SSL_PKEY_ED25519 */
-    {EVP_PKEY_ED448, SSL_aECDSA} /* SSL_PKEY_ED448 */
+    {EVP_PKEY_ED448, SSL_aECDSA}, /* SSL_PKEY_ED448 */
+#ifndef OPENSSL_NO_TLCP
+    {EVP_PKEY_SM2, SSL_aSM2},  /* SSL_PKEY_SM2_SIGN */
+    {EVP_PKEY_SM2, SSL_aSM2}    /* SSL_PKEY_SM2_ENC */
+#endif
 };
diff --git a/ssl/ssl_ciph.c b/ssl/ssl_ciph.c
index b8eba0c..b0d50b5 100644
--- a/ssl/ssl_ciph.c
+++ b/ssl/ssl_ciph.c
@@ -43,7 +43,12 @@
 #define SSL_ENC_CHACHA_IDX      19
 #define SSL_ENC_ARIA128GCM_IDX  20
 #define SSL_ENC_ARIA256GCM_IDX  21
+#ifndef OPENSSL_NO_TLCP
+#define SSL_ENC_SM4CBC_IDX      22
+#define SSL_ENC_NUM_IDX         23
+#else
 #define SSL_ENC_NUM_IDX         22
+#endif
 
 /* NB: make sure indices in these tables match values above */
 
@@ -76,6 +81,9 @@ static const ssl_cipher_table ssl_cipher_table_cipher[SSL_ENC_NUM_IDX] = {
     {SSL_CHACHA20POLY1305, NID_chacha20_poly1305}, /* SSL_ENC_CHACHA_IDX 19 */
     {SSL_ARIA128GCM, NID_aria_128_gcm}, /* SSL_ENC_ARIA128GCM_IDX 20 */
     {SSL_ARIA256GCM, NID_aria_256_gcm}, /* SSL_ENC_ARIA256GCM_IDX 21 */
+#ifndef OPENSSL_NO_TLCP
+    {SSL_SM4CBC, NID_sm4_cbc},          /* SSL_ENC_SM4CBC_IDX 22*/
+#endif
 };
 
 static const EVP_CIPHER *ssl_cipher_methods[SSL_ENC_NUM_IDX];
@@ -110,11 +118,17 @@ static const ssl_cipher_table ssl_cipher_table_mac[SSL_MD_NUM_IDX] = {
     {SSL_GOST12_512, NID_id_GostR3411_2012_512}, /* SSL_MD_GOST12_512_IDX 8 */
     {0, NID_md5_sha1},          /* SSL_MD_MD5_SHA1_IDX 9 */
     {0, NID_sha224},            /* SSL_MD_SHA224_IDX 10 */
-    {0, NID_sha512}             /* SSL_MD_SHA512_IDX 11 */
+    {0, NID_sha512},             /* SSL_MD_SHA512_IDX 11 */
+#ifndef OPENSSL_NO_TLCP
+    {SSL_SM3, NID_sm3}          /* SSL_MD_SM3_IDX 12 */
+#endif
 };
 
 static const EVP_MD *ssl_digest_methods[SSL_MD_NUM_IDX] = {
-    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
+    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+#ifndef OPENSSL_NO_TLCP
+    NULL
+#endif
 };
 
 /* *INDENT-OFF* */
@@ -172,7 +186,10 @@ static int ssl_mac_pkey_id[SSL_MD_NUM_IDX] = {
     /* GOST2012_512 */
     EVP_PKEY_HMAC,
     /* MD5/SHA1, SHA224, SHA512 */
-    NID_undef, NID_undef, NID_undef
+    NID_undef, NID_undef, NID_undef,
+#ifndef OPENSSL_NO_TLCP
+    EVP_PKEY_HMAC
+#endif
 };
 
 static size_t ssl_mac_secret_size[SSL_MD_NUM_IDX];
@@ -1696,6 +1713,14 @@ char *SSL_CIPHER_description(const SSL_CIPHER *cipher, char *buf, int len)
     case SSL_kANY:
         kx = "any";
         break;
+#ifndef OPENSSL_NO_TLCP
+    case SSL_kSM2ECC:
+        kx = "SM2ECC";
+        break;
+    case SSL_kSM2DHE:
+        kx = "SM2DHE";
+        break;
+#endif
     default:
         kx = "unknown";
     }
@@ -1729,6 +1754,11 @@ char *SSL_CIPHER_description(const SSL_CIPHER *cipher, char *buf, int len)
     case SSL_aANY:
         au = "any";
         break;
+#ifndef OPENSSL_NO_TLCP
+    case SSL_aSM2:
+        au = "SM2";
+        break;
+#endif
     default:
         au = "unknown";
         break;
@@ -1799,6 +1829,11 @@ char *SSL_CIPHER_description(const SSL_CIPHER *cipher, char *buf, int len)
     case SSL_CHACHA20POLY1305:
         enc = "CHACHA20/POLY1305(256)";
         break;
+#ifndef OPENSSL_NO_TLCP
+    case SSL_SM4CBC:
+        enc = "SM4CBC";
+        break;
+#endif
     default:
         enc = "unknown";
         break;
@@ -1831,6 +1866,11 @@ char *SSL_CIPHER_description(const SSL_CIPHER *cipher, char *buf, int len)
     case SSL_GOST12_512:
         mac = "GOST2012";
         break;
+#ifndef OPENSSL_NO_TLCP
+    case SSL_SM3:
+        mac = "SM3";
+        break;
+#endif
     default:
         mac = "unknown";
         break;
diff --git a/ssl/ssl_err.c b/ssl/ssl_err.c
index 324f2cc..5a7c42a 100644
--- a/ssl/ssl_err.c
+++ b/ssl/ssl_err.c
@@ -1,6 +1,6 @@
 /*
  * Generated by util/mkerr.pl DO NOT EDIT
- * Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 1995-2022 The OpenSSL Project Authors. All Rights Reserved.
  *
  * Licensed under the OpenSSL license (the "License").  You may not use
  * this file except in compliance with the License.  You can obtain a copy
@@ -113,6 +113,8 @@ static const ERR_STRING_DATA SSL_str_functs[] = {
      "ossl_statem_server_post_process_message"},
     {ERR_PACK(ERR_LIB_SSL, SSL_F_OSSL_STATEM_SERVER_POST_WORK, 0),
      "ossl_statem_server_post_work"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_OSSL_STATEM_SERVER_PRE_WORK, 0),
+     "ossl_statem_server_pre_work"},
     {ERR_PACK(ERR_LIB_SSL, SSL_F_OSSL_STATEM_SERVER_PROCESS_MESSAGE, 0),
      "ossl_statem_server_process_message"},
     {ERR_PACK(ERR_LIB_SSL, SSL_F_OSSL_STATEM_SERVER_READ_TRANSITION, 0),
@@ -244,6 +246,14 @@ static const ERR_STRING_DATA SSL_str_functs[] = {
      "SSL_CTX_use_certificate_ASN1"},
     {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_CTX_USE_CERTIFICATE_FILE, 0),
      "SSL_CTX_use_certificate_file"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_CTX_USE_GM_CERTIFICATE, 0),
+     "SSL_CTX_use_gm_certificate"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_CTX_USE_GM_CERTIFICATE_ASN1, 0),
+     "SSL_CTX_use_gm_certificate_ASN1"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_CTX_USE_GM_PRIVATEKEY, 0),
+     "SSL_CTX_use_gm_PrivateKey"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_CTX_USE_GM_PRIVATEKEY_ASN1, 0),
+     "SSL_CTX_use_gm_PrivateKey_ASN1"},
     {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_CTX_USE_PRIVATEKEY, 0),
      "SSL_CTX_use_PrivateKey"},
     {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_CTX_USE_PRIVATEKEY_ASN1, 0),
@@ -285,8 +295,10 @@ static const ERR_STRING_DATA SSL_str_functs[] = {
     {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_INIT_WBIO_BUFFER, 0),
      "ssl_init_wbio_buffer"},
     {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_KEY_UPDATE, 0), "SSL_key_update"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_LOAD_CERT_FILE, 0), "ssl_load_cert_file"},
     {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_LOAD_CLIENT_CA_FILE, 0),
      "SSL_load_client_CA_file"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_LOAD_PKEY_FILE, 0), "ssl_load_pkey_file"},
     {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_LOG_MASTER_SECRET, 0), ""},
     {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_LOG_RSA_CLIENT_KEY_EXCHANGE, 0),
      "ssl_log_rsa_client_key_exchange"},
@@ -331,6 +343,8 @@ static const ERR_STRING_DATA SSL_str_functs[] = {
     {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_SET_CT_VALIDATION_CALLBACK, 0),
      "SSL_set_ct_validation_callback"},
     {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_SET_FD, 0), "SSL_set_fd"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_SET_GM_CERT_AND_KEY, 0),
+     "ssl_set_gm_cert_and_key"},
     {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_SET_PKEY, 0), "ssl_set_pkey"},
     {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_SET_RFD, 0), "SSL_set_rfd"},
     {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_SET_SESSION, 0), "SSL_set_session"},
@@ -338,6 +352,10 @@ static const ERR_STRING_DATA SSL_str_functs[] = {
      "SSL_set_session_id_context"},
     {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_SET_SESSION_TICKET_EXT, 0),
      "SSL_set_session_ticket_ext"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_SET_SIGN_ENC_CERT, 0),
+     "ssl_set_sign_enc_cert"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_SET_SIGN_ENC_PKEY, 0),
+     "ssl_set_sign_enc_pkey"},
     {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_SET_TLSEXT_MAX_FRAGMENT_LENGTH, 0),
      "SSL_set_tlsext_max_fragment_length"},
     {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_SET_WFD, 0), "SSL_set_wfd"},
@@ -355,6 +373,14 @@ static const ERR_STRING_DATA SSL_str_functs[] = {
      "SSL_use_certificate_ASN1"},
     {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_USE_CERTIFICATE_FILE, 0),
      "SSL_use_certificate_file"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_USE_GM_CERTIFICATE, 0),
+     "SSL_use_gm_certificate"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_USE_GM_CERTIFICATE_ASN1, 0),
+     "SSL_use_gm_certificate_ASN1"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_USE_GM_PRIVATEKEY, 0),
+     "SSL_use_gm_PrivateKey"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_USE_GM_PRIVATEKEY_ASN1, 0),
+     "SSL_use_gm_PrivateKey_ASN1"},
     {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_USE_PRIVATEKEY, 0), "SSL_use_PrivateKey"},
     {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_USE_PRIVATEKEY_ASN1, 0),
      "SSL_use_PrivateKey_ASN1"},
@@ -380,6 +406,32 @@ static const ERR_STRING_DATA SSL_str_functs[] = {
     {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_WRITE_EX, 0), "SSL_write_ex"},
     {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_WRITE_INTERNAL, 0), "ssl_write_internal"},
     {ERR_PACK(ERR_LIB_SSL, SSL_F_STATE_MACHINE, 0), "state_machine"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLCP_CHOOSE_SIGALG, 0), "tlcp_choose_sigalg"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLCP_CONSTRUCT_CKE_SM2DHE, 0),
+     "tlcp_construct_cke_sm2dhe"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLCP_CONSTRUCT_CKE_SM2ECC, 0),
+     "tlcp_construct_cke_sm2ecc"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLCP_CONSTRUCT_CLIENT_KEY_EXCHANGE, 0),
+     "tlcp_construct_client_key_exchange"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLCP_CONSTRUCT_SERVER_KEY_EXCHANGE, 0),
+     "tlcp_construct_server_key_exchange"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLCP_CONSTRUCT_SKE_SM2DHE, 0),
+     "tlcp_construct_ske_sm2dhe"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLCP_CONSTRUCT_SKE_SM2ECC, 0),
+     "tlcp_construct_ske_sm2ecc"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLCP_DERIVE, 0), "tlcp_derive"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLCP_PROCESS_CKE_SM2DHE, 0),
+     "tlcp_process_cke_sm2dhe"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLCP_PROCESS_CKE_SM2ECC, 0),
+     "tlcp_process_cke_sm2ecc"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLCP_PROCESS_CLIENT_KEY_EXCHANGE, 0),
+     "tlcp_process_client_key_exchange"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLCP_PROCESS_KEY_EXCHANGE, 0),
+     "tlcp_process_key_exchange"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLCP_PROCESS_SKE_SM2DHE, 0),
+     "tlcp_process_ske_sm2dhe"},
+    {ERR_PACK(ERR_LIB_SSL, SSL_F_TLCP_PROCESS_SKE_SM2ECC, 0),
+     "tlcp_process_ske_sm2ecc"},
     {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS12_CHECK_PEER_SIGALG, 0),
      "tls12_check_peer_sigalg"},
     {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS12_COPY_SIGALGS, 0), "tls12_copy_sigalgs"},
diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c
index 78c4f99..27e5ed2 100644
--- a/ssl/ssl_lib.c
+++ b/ssl/ssl_lib.c
@@ -560,8 +560,14 @@ static int ssl_check_allowed_versions(int min_version, int max_version)
 #ifdef OPENSSL_NO_TLS1_3
             || (min_version <= TLS1_3_VERSION && TLS1_3_VERSION <= max_version)
 #endif
-            )
+            ) {
+#ifndef OPENSSL_NO_TLCP
+            if (min_version == TLCP_VERSION || max_version == TLCP_VERSION) {
+                return 1;
+            }
+#endif
             return 0;
+        }
     }
     return 1;
 }
@@ -3365,6 +3371,9 @@ void ssl_set_masks(SSL *s)
     unsigned long mask_k, mask_a;
 #ifndef OPENSSL_NO_EC
     int have_ecc_cert, ecdsa_ok;
+#endif
+#ifndef OPENSSL_NO_TLCP
+    int tlcp_sm2_sign, tlcp_sm2_enc;
 #endif
     if (c == NULL)
         return;
@@ -3380,14 +3389,23 @@ void ssl_set_masks(SSL *s)
     dsa_sign = pvalid[SSL_PKEY_DSA_SIGN] & CERT_PKEY_VALID;
 #ifndef OPENSSL_NO_EC
     have_ecc_cert = pvalid[SSL_PKEY_ECC] & CERT_PKEY_VALID;
+#endif
+#ifndef OPENSSL_NO_TLCP
+    tlcp_sm2_sign = ssl_has_cert(s, SSL_PKEY_SM2_SIGN);
+    tlcp_sm2_enc = ssl_has_cert(s, SSL_PKEY_SM2_ENC);
 #endif
     mask_k = 0;
     mask_a = 0;
 
 #ifdef CIPHER_DEBUG
+#ifndef OPENSSL_NO_TLCP
+    fprintf(stderr, "dht=%d re=%d rs=%d ds=%d tss=%d tse=%d\n",
+            dh_tmp, rsa_enc, rsa_sign, dsa_sign, tlcp_sm2_sign, tlcp_sm2_enc);
+#else
     fprintf(stderr, "dht=%d re=%d rs=%d ds=%d\n",
             dh_tmp, rsa_enc, rsa_sign, dsa_sign);
 #endif
+#endif
 
 #ifndef OPENSSL_NO_GOST
     if (ssl_has_cert(s, SSL_PKEY_GOST12_512)) {
@@ -3457,6 +3475,14 @@ void ssl_set_masks(SSL *s)
     mask_k |= SSL_kECDHE;
 #endif
 
+#ifndef OPENSSL_NO_TLCP
+    if (tlcp_sm2_sign)
+        mask_a |= SSL_aSM2;
+
+    if (tlcp_sm2_enc)
+        mask_k |= SSL_kSM2ECC | SSL_kSM2DHE;
+#endif
+
 #ifndef OPENSSL_NO_PSK
     mask_k |= SSL_kPSK;
     mask_a |= SSL_aPSK;
@@ -3786,6 +3812,11 @@ const char *ssl_protocol_to_string(int version)
     case TLS1_VERSION:
         return "TLSv1";
 
+#ifndef OPENSSL_NO_TLCP
+    case TLCP_VERSION:
+        return "TLCP";
+#endif
+
     case SSL3_VERSION:
         return "SSLv3";
 
@@ -5700,3 +5731,51 @@ void SSL_set_allow_early_data_cb(SSL *s,
     s->allow_early_data_cb = cb;
     s->allow_early_data_cb_data = arg;
 }
+
+#ifndef OPENSSL_NO_TLCP
+int ssl_is_sm2_cert(X509 *x)
+{
+    return x && EVP_PKEY_is_sm2(X509_get0_pubkey(x));
+}
+
+int ssl_is_sm2_sign_usage(X509 *x)
+{
+    return x && (X509_get_extension_flags(x) & EXFLAG_KUSAGE) &&
+        (X509_get_key_usage(x) & X509v3_KU_SM2_SIGN);
+}
+
+int ssl_is_sm2_enc_usage(X509 *x)
+{
+    return x && (X509_get_extension_flags(x) & EXFLAG_KUSAGE) &&
+        ((X509_get_key_usage(x) & X509v3_KU_SM2_ENC_ENCIPHERMENT) ||
+         ((X509_get_key_usage(x) & X509v3_KU_SM2_ENC_CIPHER_ONLY) &&
+         (X509_get_key_usage(x) & X509v3_KU_KEY_AGREEMENT))
+        );
+}
+
+X509 *ssl_get_sm2_enc_cert(SSL *s, STACK_OF(X509) *chain)
+{
+    X509 *x;
+    int i;
+
+    for (i = sk_X509_num(chain) - 1; i >= 0 ; --i) {
+        x = sk_X509_value(chain, i);
+        if (ssl_is_sm2_cert(x) && ssl_is_sm2_enc_usage(x)) {
+            return x;
+        }
+    }
+    return NULL;
+}
+
+int ssl_get_sm2_cert_id(X509 *x, size_t *id)
+{
+    if (ssl_is_sm2_sign_usage(x) && !ssl_is_sm2_enc_usage(x)) {
+        *id = SSL_PKEY_SM2_SIGN;
+        return 1;
+    } else if (!ssl_is_sm2_sign_usage(x) && ssl_is_sm2_enc_usage(x)) {
+        *id = SSL_PKEY_SM2_ENC;
+        return 1;
+    }
+    return 0;
+}
+#endif
\ No newline at end of file
diff --git a/ssl/ssl_local.h b/ssl/ssl_local.h
index a33cb9a..8135248 100644
--- a/ssl/ssl_local.h
+++ b/ssl/ssl_local.h
@@ -177,6 +177,13 @@
 # define SSL_kECDHEPSK           0x00000080U
 # define SSL_kDHEPSK             0x00000100U
 
+#ifndef OPENSSL_NO_TLCP
+/* TLCP ECC*/
+# define SSL_kSM2ECC             0x00000800U
+/* TLCP ECDHE */
+# define SSL_kSM2DHE           0x00001000U
+#endif
+
 /* all PSK */
 
 # define SSL_PSK     (SSL_kPSK | SSL_kRSAPSK | SSL_kECDHEPSK | SSL_kDHEPSK)
@@ -203,9 +210,21 @@
 # define SSL_aGOST12             0x00000080U
 /* Any appropriate signature auth (for TLS 1.3 ciphersuites) */
 # define SSL_aANY                0x00000000U
+
+#ifndef OPENSSL_NO_TLCP
+/* SM2 auth */
+# define SSL_aSM2                0x00000100U
+#endif
+
+#ifndef OPENSSL_NO_TLCP
+/* All bits requiring a certificate */
+#define SSL_aCERT \
+    (SSL_aRSA | SSL_aDSS | SSL_aECDSA | SSL_aGOST01 | SSL_aGOST12 | SSL_aSM2)
+#else
 /* All bits requiring a certificate */
 #define SSL_aCERT \
     (SSL_aRSA | SSL_aDSS | SSL_aECDSA | SSL_aGOST01 | SSL_aGOST12)
+#endif
 
 /* Bits for algorithm_enc (symmetric encryption) */
 # define SSL_DES                 0x00000001U
@@ -231,6 +250,10 @@
 # define SSL_ARIA128GCM          0x00100000U
 # define SSL_ARIA256GCM          0x00200000U
 
+#ifndef OPENSSL_NO_TLCP
+# define SSL_SM4CBC              0x00800000U
+#endif
+
 # define SSL_AESGCM              (SSL_AES128GCM | SSL_AES256GCM)
 # define SSL_AESCCM              (SSL_AES128CCM | SSL_AES256CCM | SSL_AES128CCM8 | SSL_AES256CCM8)
 # define SSL_AES                 (SSL_AES128|SSL_AES256|SSL_AESGCM|SSL_AESCCM)
@@ -253,6 +276,10 @@
 # define SSL_GOST89MAC12         0x00000100U
 # define SSL_GOST12_512          0x00000200U
 
+#ifndef OPENSSL_NO_TLCP
+# define SSL_SM3                 0x00000400U
+#endif
+
 /*
  * When adding new digest in the ssl_ciph.c and increment SSL_MD_NUM_IDX make
  * sure to update this constant too
@@ -270,8 +297,12 @@
 # define SSL_MD_MD5_SHA1_IDX 9
 # define SSL_MD_SHA224_IDX 10
 # define SSL_MD_SHA512_IDX 11
+#ifndef OPENSSL_NO_TLCP
+# define SSL_MD_SM3_IDX 12
+# define SSL_MAX_DIGEST 13
+#else
 # define SSL_MAX_DIGEST 12
-
+#endif
 /* Bits for algorithm2 (handshake digests and other extra flags) */
 
 /* Bits 0-7 are handshake MAC */
@@ -283,6 +314,9 @@
 # define SSL_HANDSHAKE_MAC_GOST12_256 SSL_MD_GOST12_256_IDX
 # define SSL_HANDSHAKE_MAC_GOST12_512 SSL_MD_GOST12_512_IDX
 # define SSL_HANDSHAKE_MAC_DEFAULT  SSL_HANDSHAKE_MAC_MD5_SHA1
+#ifndef OPENSSL_NO_TLCP
+# define SSL_HANDSHAKE_MAC_SM3      SSL_MD_SM3_IDX
+#endif
 
 /* Bits 8-15 bits are PRF */
 # define TLS1_PRF_DGST_SHIFT 8
@@ -293,6 +327,9 @@
 # define TLS1_PRF_GOST12_256 (SSL_MD_GOST12_256_IDX << TLS1_PRF_DGST_SHIFT)
 # define TLS1_PRF_GOST12_512 (SSL_MD_GOST12_512_IDX << TLS1_PRF_DGST_SHIFT)
 # define TLS1_PRF            (SSL_MD_MD5_SHA1_IDX << TLS1_PRF_DGST_SHIFT)
+#ifndef OPENSSL_NO_TLCP
+# define TLS1_PRF_SM3        (SSL_MD_SM3_IDX << TLS1_PRF_DGST_SHIFT)
+#endif
 
 /*
  * Stream MAC for GOST ciphersuites from cryptopro draft (currently this also
@@ -318,6 +355,8 @@
 /* Check if an SSL structure is using DTLS */
 # define SSL_IS_DTLS(s)  (s->method->ssl3_enc->enc_flags & SSL_ENC_FLAG_DTLS)
 
+# define SSL_IS_TLCP(s)  (s->version == TLCP_VERSION)
+
 /* Check if we are using TLSv1.3 */
 # define SSL_IS_TLS13(s) (!SSL_IS_DTLS(s) \
                           && (s)->method->version >= TLS1_3_VERSION \
@@ -383,7 +422,13 @@
 # define SSL_PKEY_GOST12_512     6
 # define SSL_PKEY_ED25519        7
 # define SSL_PKEY_ED448          8
+#ifndef OPENSSL_NO_TLCP
+# define SSL_PKEY_SM2_SIGN       9
+# define SSL_PKEY_SM2_ENC        10
+# define SSL_PKEY_NUM            11
+#else
 # define SSL_PKEY_NUM            9
+#endif
 
 /*-
  * SSL_kRSA <- RSA_ENC
@@ -2027,6 +2072,9 @@ typedef enum downgrade_en {
 #define TLSEXT_SIGALG_ecdsa_secp521r1_sha512                    0x0603
 #define TLSEXT_SIGALG_ecdsa_sha224                              0x0303
 #define TLSEXT_SIGALG_ecdsa_sha1                                0x0203
+#ifndef OPENSSL_NO_TLCP
+#define TLSEXT_SIGALG_sm2dsa_sm3                                0x0708
+#endif
 #define TLSEXT_SIGALG_rsa_pss_rsae_sha256                       0x0804
 #define TLSEXT_SIGALG_rsa_pss_rsae_sha384                       0x0805
 #define TLSEXT_SIGALG_rsa_pss_rsae_sha512                       0x0806
@@ -2096,6 +2144,18 @@ __owur const SSL_METHOD *dtls_bad_ver_client_method(void);
 __owur const SSL_METHOD *dtlsv1_2_method(void);
 __owur const SSL_METHOD *dtlsv1_2_server_method(void);
 __owur const SSL_METHOD *dtlsv1_2_client_method(void);
+# ifndef OPENSSL_NO_TLCP
+__owur const SSL_METHOD *tlcp_method(void);
+__owur const SSL_METHOD *tlcp_server_method(void);
+__owur const SSL_METHOD *tlcp_client_method(void);
+
+/* TLCP helper functions */
+__owur int ssl_is_sm2_cert(X509 *x);
+__owur int ssl_is_sm2_sign_usage(X509 *x);
+__owur int ssl_is_sm2_enc_usage(X509 *x);
+__owur X509 *ssl_get_sm2_enc_cert(SSL *s, STACK_OF(X509) *chain);
+__owur int ssl_get_sm2_cert_id(X509 *x, size_t *id);
+# endif
 
 extern const SSL3_ENC_METHOD TLSv1_enc_data;
 extern const SSL3_ENC_METHOD TLSv1_1_enc_data;
@@ -2104,6 +2164,9 @@ extern const SSL3_ENC_METHOD TLSv1_3_enc_data;
 extern const SSL3_ENC_METHOD SSLv3_enc_data;
 extern const SSL3_ENC_METHOD DTLSv1_enc_data;
 extern const SSL3_ENC_METHOD DTLSv1_2_enc_data;
+# ifndef OPENSSL_NO_TLCP
+extern const SSL3_ENC_METHOD TLCP_enc_data;
+# endif
 
 /*
  * Flags for SSL methods
@@ -2331,6 +2394,7 @@ __owur int ssl_generate_master_secret(SSL *s, unsigned char *pms, size_t pmslen,
 __owur EVP_PKEY *ssl_generate_pkey(EVP_PKEY *pm);
 __owur int ssl_derive(SSL *s, EVP_PKEY *privkey, EVP_PKEY *pubkey,
                       int genmaster);
+__owur int tlcp_derive(SSL *s, EVP_PKEY *privkey, EVP_PKEY *pubkey);
 __owur EVP_PKEY *ssl_dh_to_pkey(DH *dh);
 __owur unsigned int ssl_get_max_send_fragment(const SSL *ssl);
 __owur unsigned int ssl_get_split_send_fragment(const SSL *ssl);
@@ -2502,6 +2566,9 @@ __owur int tls13_export_keying_material_early(SSL *s, unsigned char *out,
 __owur int tls1_alert_code(int code);
 __owur int tls13_alert_code(int code);
 __owur int ssl3_alert_code(int code);
+#  ifndef OPENSSL_NO_TLCP
+__owur int tlcp_alert_code(int code);
+#  endif
 
 #  ifndef OPENSSL_NO_EC
 __owur int ssl_check_srvr_ecc_cert_and_alg(X509 *x, SSL *s);
diff --git a/ssl/ssl_rsa.c b/ssl/ssl_rsa.c
index 6457c0c..5a495ec 100644
--- a/ssl/ssl_rsa.c
+++ b/ssl/ssl_rsa.c
@@ -19,6 +19,15 @@
 static int ssl_set_cert(CERT *c, X509 *x509);
 static int ssl_set_pkey(CERT *c, EVP_PKEY *pkey);
 
+#ifndef OPENSSL_NO_TLCP
+#include <openssl/x509v3.h>
+
+static int ssl_set_sign_enc_pkey(CERT *c, EVP_PKEY *pkey, size_t id);
+static int ssl_set_sign_enc_cert(CERT *c, X509 *x, size_t id);
+static int ssl_load_pkey_file(SSL *ssl, SSL_CTX *ctx, const char *file, int type, EVP_PKEY **pkey);
+static int ssl_load_cert_file(SSL *ssl, SSL_CTX *ctx, const char *file, int type, X509 **x);
+#endif
+
 #define  SYNTHV1CONTEXT     (SSL_EXT_TLS1_2_AND_BELOW_ONLY \
                              | SSL_EXT_CLIENT_HELLO \
                              | SSL_EXT_TLS1_2_SERVER_HELLO \
@@ -97,6 +106,99 @@ int SSL_use_certificate_ASN1(SSL *ssl, const unsigned char *d, int len)
     return ret;
 }
 
+#ifndef OPENSSL_NO_TLCP
+static int ssl_load_cert_file(SSL *ssl, SSL_CTX *ctx, const char *file, int type, X509 **x)
+{
+    int j;
+    BIO *in;
+    int ret = 0;
+    *x = NULL;
+
+    in = BIO_new(BIO_s_file());
+    if (in == NULL) {
+        SSLerr(SSL_F_SSL_LOAD_CERT_FILE, ERR_R_BUF_LIB);
+        goto end;
+    }
+
+    if (BIO_read_filename(in, file) <= 0) {
+        SSLerr(SSL_F_SSL_LOAD_CERT_FILE, ERR_R_SYS_LIB);
+        goto end;
+    }
+    if (type == SSL_FILETYPE_ASN1) {
+        j = ERR_R_ASN1_LIB;
+        *x = d2i_X509_bio(in, NULL);
+    } else if (type == SSL_FILETYPE_PEM) {
+        j = ERR_R_PEM_LIB;
+        pem_password_cb *cb = (ssl != NULL) ? ssl->default_passwd_callback : 
+                ctx->default_passwd_callback;
+        void *userdata = (ssl != NULL) ? ssl->default_passwd_callback_userdata :
+                ctx->default_passwd_callback_userdata;
+        *x = PEM_read_bio_X509(in, NULL, cb, userdata);
+    } else {
+        SSLerr(SSL_F_SSL_LOAD_CERT_FILE, SSL_R_BAD_SSL_FILETYPE);
+        goto end;
+    }
+
+    if (*x == NULL) {
+        SSLerr(SSL_F_SSL_LOAD_CERT_FILE, j);
+        goto end;
+    }
+    ret = 1;
+end:
+    BIO_free(in);
+    return ret;
+}
+
+int SSL_use_gm_certificate(SSL *ssl, X509 *x, int usage)
+{
+    int rv;
+    if (x == NULL) {
+        SSLerr(SSL_F_SSL_USE_GM_CERTIFICATE, ERR_R_PASSED_NULL_PARAMETER);
+        return 0;
+    }
+    rv = ssl_security_cert(ssl, NULL, x, 0, 1);
+    if (rv != 1) {
+        SSLerr(SSL_F_SSL_USE_GM_CERTIFICATE, rv);
+        return 0;
+    }
+    if (usage == SSL_USAGE_SIG) {
+        return ssl_set_sign_enc_cert(ssl->cert, x, SSL_PKEY_SM2_SIGN);
+    } else if (usage == SSL_USAGE_ENC) {
+        return ssl_set_sign_enc_cert(ssl->cert, x, SSL_PKEY_SM2_ENC);
+    }
+    SSLerr(SSL_F_SSL_USE_GM_CERTIFICATE, ERR_R_PASSED_INVALID_ARGUMENT);
+    return 0;
+}
+
+int SSL_use_gm_certificate_ASN1(SSL *ssl, const unsigned char *d, int len, int usage)
+{
+    X509 *x;
+    int ret;
+
+    x = d2i_X509(NULL, &d, (long)len);
+    if (x == NULL) {
+        SSLerr(SSL_F_SSL_USE_GM_CERTIFICATE_ASN1, ERR_R_ASN1_LIB);
+        return 0;
+    }
+
+    ret = SSL_use_gm_certificate(ssl, x, usage);
+    X509_free(x);
+    return ret;
+}
+
+int SSL_use_gm_certificate_file(SSL *ssl, const char *file, int type, int usage)
+{
+    int ret;
+    X509 *x = NULL;
+    ret = ssl_load_cert_file(ssl, NULL, file, type, &x);
+    if (ret == 1) {
+        ret = SSL_use_gm_certificate(ssl, x, usage);
+    }
+    X509_free(x);
+    return ret;
+}
+#endif
+
 #ifndef OPENSSL_NO_RSA
 int SSL_use_RSAPrivateKey(SSL *ssl, RSA *rsa)
 {
@@ -162,6 +264,50 @@ static int ssl_set_pkey(CERT *c, EVP_PKEY *pkey)
     return 1;
 }
 
+#ifndef OPENSSL_NO_TLCP
+int ssl_set_sign_enc_pkey(CERT *c, EVP_PKEY *pkey, size_t id)
+{
+    if (id != SSL_PKEY_SM2_SIGN && id != SSL_PKEY_SM2_ENC) {
+        SSLerr(SSL_F_SSL_SET_SIGN_ENC_PKEY, ERR_R_PASSED_INVALID_ARGUMENT);
+        return 0;
+    }
+
+    if (EVP_PKEY_is_sm2(pkey) == 0) {
+        SSLerr(SSL_F_SSL_SET_SIGN_ENC_PKEY, SSL_R_UNKNOWN_PKEY_TYPE);
+        return 0;
+    }
+
+    if (c->pkeys[id].x509 != NULL) {
+        EVP_PKEY *pktmp;
+        pktmp = X509_get0_pubkey(c->pkeys[id].x509);
+        if (pktmp == NULL) {
+            SSLerr(SSL_F_SSL_SET_SIGN_ENC_PKEY, ERR_R_MALLOC_FAILURE);
+            return 0;
+        }
+        /*
+         * The return code from EVP_PKEY_copy_parameters is deliberately
+         * ignored. Some EVP_PKEY types cannot do this.
+         */
+        EVP_PKEY_copy_parameters(pktmp, pkey);
+        ERR_clear_error();
+
+        if (!X509_check_private_key(c->pkeys[id].x509, pkey)) {
+            X509_free(c->pkeys[id].x509);
+            c->pkeys[id].x509 = NULL;
+            return 0;
+        }
+    }
+
+    EVP_PKEY_free(c->pkeys[id].privatekey);
+    EVP_PKEY_up_ref(pkey);
+    c->pkeys[id].privatekey = pkey;
+    if (id != SSL_PKEY_SM2_ENC) {
+        c->key = &(c->pkeys[id]);
+    }
+    return 1;
+}
+#endif
+
 #ifndef OPENSSL_NO_RSA
 int SSL_use_RSAPrivateKey_file(SSL *ssl, const char *file, int type)
 {
@@ -228,6 +374,17 @@ int SSL_use_PrivateKey(SSL *ssl, EVP_PKEY *pkey)
         SSLerr(SSL_F_SSL_USE_PRIVATEKEY, ERR_R_PASSED_NULL_PARAMETER);
         return 0;
     }
+#ifndef OPENSSL_NO_TLCP
+    if (EVP_PKEY_is_sm2(pkey)) {
+        if (X509_check_private_key(ssl->cert->pkeys[SSL_PKEY_SM2_SIGN].x509, pkey)) {
+            return ssl_set_sign_enc_pkey(ssl->cert, pkey, SSL_PKEY_SM2_SIGN);
+        } else if (X509_check_private_key(ssl->cert->pkeys[SSL_PKEY_SM2_ENC].x509, pkey)) {
+            return ssl_set_sign_enc_pkey(ssl->cert, pkey, SSL_PKEY_SM2_ENC);
+        }
+        SSLerr(SSL_F_SSL_USE_PRIVATEKEY, ERR_R_PASSED_INVALID_ARGUMENT);
+        return 0;
+    }
+#endif
     ret = ssl_set_pkey(ssl->cert, pkey);
     return ret;
 }
@@ -289,6 +446,94 @@ int SSL_use_PrivateKey_ASN1(int type, SSL *ssl, const unsigned char *d,
     return ret;
 }
 
+#ifndef OPENSSL_NO_TLCP
+static int ssl_load_pkey_file(SSL *ssl, SSL_CTX *ctx, const char *file, int type, EVP_PKEY **pkey)
+{
+    int j, ret = 0;
+    BIO *in;
+    *pkey = NULL;
+
+    in = BIO_new(BIO_s_file());
+    if (in == NULL) {
+        SSLerr(SSL_F_SSL_LOAD_PKEY_FILE, ERR_R_BUF_LIB);
+        goto end;
+    }
+
+    if (BIO_read_filename(in, file) <= 0) {
+        SSLerr(SSL_F_SSL_LOAD_PKEY_FILE, ERR_R_SYS_LIB);
+        goto end;
+    }
+    if (type == SSL_FILETYPE_PEM) {
+        j = ERR_R_PEM_LIB;
+        pem_password_cb *cb = (ssl != NULL) ? ssl->default_passwd_callback : 
+                ctx->default_passwd_callback;
+        void *userdata = (ssl != NULL) ? ssl->default_passwd_callback_userdata :
+                ctx->default_passwd_callback_userdata;
+        *pkey = PEM_read_bio_PrivateKey(in, NULL, cb, userdata);
+    } else if (type == SSL_FILETYPE_ASN1) {
+        j = ERR_R_ASN1_LIB;
+        *pkey = d2i_PrivateKey_bio(in, NULL);
+    } else {
+        SSLerr(SSL_F_SSL_LOAD_PKEY_FILE, SSL_R_BAD_SSL_FILETYPE);
+        goto end;
+    }
+    if (*pkey == NULL) {
+        SSLerr(SSL_F_SSL_LOAD_PKEY_FILE, j);
+        goto end;
+    }
+    ret = 1;
+end:
+    BIO_free(in);
+    return ret;
+}
+
+int SSL_use_gm_PrivateKey(SSL *ssl, EVP_PKEY *pkey, int usage)
+{
+    if (pkey == NULL) {
+        SSLerr(SSL_F_SSL_USE_GM_PRIVATEKEY, ERR_R_PASSED_NULL_PARAMETER);
+        return 0;
+    }
+    if (usage == SSL_USAGE_SIG) {
+        return ssl_set_sign_enc_pkey(ssl->cert, pkey, SSL_PKEY_SM2_SIGN);
+    } else if (usage == SSL_USAGE_ENC) {
+        return ssl_set_sign_enc_pkey(ssl->cert, pkey, SSL_PKEY_SM2_ENC);
+    }
+    SSLerr(SSL_F_SSL_USE_GM_PRIVATEKEY, ERR_R_PASSED_INVALID_ARGUMENT);
+    return 0;
+}
+
+int SSL_use_gm_PrivateKey_ASN1(int type, SSL *ssl, const unsigned char *d,
+                            long len, int usage)
+{
+    int ret;
+    const unsigned char *p;
+    EVP_PKEY *pkey;
+
+    p = d;
+    if ((pkey = d2i_PrivateKey(type, NULL, &p, (long)len)) == NULL) {
+        SSLerr(SSL_F_SSL_USE_GM_PRIVATEKEY_ASN1, ERR_R_ASN1_LIB);
+        return 0;
+    }
+
+    ret = SSL_use_gm_PrivateKey(ssl, pkey, usage);
+    EVP_PKEY_free(pkey);
+    return ret;
+}
+
+int SSL_use_gm_PrivateKey_file(SSL *ssl, const char *file, int type, int usage)
+{
+    int ret;
+    EVP_PKEY *pkey = NULL;
+
+    ret = ssl_load_pkey_file(ssl, NULL, file, type, &pkey);
+    if (ret == 1) {
+        ret = SSL_use_gm_PrivateKey(ssl, pkey, usage);
+    }
+    EVP_PKEY_free(pkey);
+    return ret;
+}
+#endif
+
 int SSL_CTX_use_certificate(SSL_CTX *ctx, X509 *x)
 {
     int rv;
@@ -319,6 +564,12 @@ static int ssl_set_cert(CERT *c, X509 *x)
         SSLerr(SSL_F_SSL_SET_CERT, SSL_R_UNKNOWN_CERTIFICATE_TYPE);
         return 0;
     }
+#ifndef OPENSSL_NO_TLCP
+    if (i == SSL_PKEY_SM2_SIGN && !ssl_get_sm2_cert_id(x, &i)) {
+        SSLerr(SSL_F_SSL_SET_CERT, SSL_R_UNKNOWN_CERTIFICATE_TYPE);
+        return 0;
+    }
+#endif
 #ifndef OPENSSL_NO_EC
     if (i == SSL_PKEY_ECC && !EC_KEY_can_sign(EVP_PKEY_get0_EC_KEY(pkey))) {
         SSLerr(SSL_F_SSL_SET_CERT, SSL_R_ECC_CERT_NOT_FOR_SIGNING);
@@ -349,7 +600,13 @@ static int ssl_set_cert(CERT *c, X509 *x)
     X509_free(c->pkeys[i].x509);
     X509_up_ref(x);
     c->pkeys[i].x509 = x;
+#ifndef OPENSSL_NO_TLCP
+    if (i != SSL_PKEY_SM2_ENC) {
+        c->key = &(c->pkeys[i]);
+    }
+#else
     c->key = &(c->pkeys[i]);
+#endif
 
     return 1;
 }
@@ -411,6 +668,109 @@ int SSL_CTX_use_certificate_ASN1(SSL_CTX *ctx, int len, const unsigned char *d)
     return ret;
 }
 
+#ifndef OPENSSL_NO_TLCP
+static int ssl_set_sign_enc_cert(CERT *c, X509 *x, size_t id)
+{
+    EVP_PKEY *pkey;
+
+    pkey = X509_get0_pubkey(x);
+    if (pkey == NULL) {
+        SSLerr(SSL_F_SSL_SET_SIGN_ENC_CERT, SSL_R_X509_LIB);
+        return 0;
+    }
+
+    if (ssl_is_sm2_cert(x) == 0 ||
+        (id == SSL_PKEY_SM2_ENC && !ssl_is_sm2_enc_usage(x)) ||
+        (id == SSL_PKEY_SM2_SIGN && !ssl_is_sm2_sign_usage(x))) {
+        SSLerr(SSL_F_SSL_SET_SIGN_ENC_CERT, SSL_R_UNKNOWN_CERTIFICATE_TYPE);
+        return 0;
+    }
+
+    if (id == SSL_PKEY_SM2_SIGN && !EC_KEY_can_sign(EVP_PKEY_get0_EC_KEY(pkey))) {
+        SSLerr(SSL_F_SSL_SET_SIGN_ENC_CERT, SSL_R_ECC_CERT_NOT_FOR_SIGNING);
+        return 0;
+    }
+
+    if (c->pkeys[id].privatekey != NULL) {
+        /*
+         * The return code from EVP_PKEY_copy_parameters is deliberately
+         * ignored. Some EVP_PKEY types cannot do this.
+         */
+        EVP_PKEY_copy_parameters(pkey, c->pkeys[id].privatekey);
+        ERR_clear_error();
+
+        if (!X509_check_private_key(x, c->pkeys[id].privatekey)) {
+            /*
+             * don't fail for a cert/key mismatch, just free current private
+             * key (when switching to a different cert & key, first this
+             * function should be used, then ssl_set_pkey
+             */
+            EVP_PKEY_free(c->pkeys[id].privatekey);
+            c->pkeys[id].privatekey = NULL;
+            /* clear error queue */
+            ERR_clear_error();
+        }
+    }
+
+    X509_free(c->pkeys[id].x509);
+    X509_up_ref(x);
+    c->pkeys[id].x509 = x;
+    if (id != SSL_PKEY_SM2_ENC) {
+        c->key = &(c->pkeys[id]);
+    }
+    return 1;
+}
+
+int SSL_CTX_use_gm_certificate(SSL_CTX *ctx, X509 *x, int usage)
+{
+    int rv;
+    if (x == NULL) {
+        SSLerr(SSL_F_SSL_CTX_USE_GM_CERTIFICATE, ERR_R_PASSED_NULL_PARAMETER);
+        return 0;
+    }
+    rv = ssl_security_cert(NULL, ctx, x, 0, 1);
+    if (rv != 1) {
+        SSLerr(SSL_F_SSL_CTX_USE_GM_CERTIFICATE, rv);
+        return 0;
+    }
+    if (usage == SSL_USAGE_SIG) {
+        return ssl_set_sign_enc_cert(ctx->cert, x, SSL_PKEY_SM2_SIGN);
+    } else if (usage == SSL_USAGE_ENC) {
+        return ssl_set_sign_enc_cert(ctx->cert, x, SSL_PKEY_SM2_ENC);
+    }
+    SSLerr(SSL_F_SSL_CTX_USE_GM_CERTIFICATE, ERR_R_PASSED_INVALID_ARGUMENT);
+    return 0;
+}
+
+int SSL_CTX_use_gm_certificate_file(SSL_CTX *ctx, const char *file, int type, int usage)
+{
+    int ret;
+    X509 *x = NULL;
+    ret = ssl_load_cert_file(NULL, ctx, file, type, &x);
+    if (ret == 1) {
+        ret = SSL_CTX_use_gm_certificate(ctx, x, usage);
+    }
+    X509_free(x);
+    return ret;
+}
+
+int SSL_CTX_use_gm_certificate_ASN1(SSL_CTX *ctx, int len, const unsigned char *d, int usage)
+{
+    X509 *x;
+    int ret;
+
+    x = d2i_X509(NULL, &d, (long)len);
+    if (x == NULL) {
+        SSLerr(SSL_F_SSL_CTX_USE_GM_CERTIFICATE_ASN1, ERR_R_ASN1_LIB);
+        return 0;
+    }
+
+    ret = SSL_CTX_use_gm_certificate(ctx, x, usage);
+    X509_free(x);
+    return ret;
+}
+#endif
+
 #ifndef OPENSSL_NO_RSA
 int SSL_CTX_use_RSAPrivateKey(SSL_CTX *ctx, RSA *rsa)
 {
@@ -502,6 +862,17 @@ int SSL_CTX_use_PrivateKey(SSL_CTX *ctx, EVP_PKEY *pkey)
         SSLerr(SSL_F_SSL_CTX_USE_PRIVATEKEY, ERR_R_PASSED_NULL_PARAMETER);
         return 0;
     }
+#ifndef OPENSSL_NO_TLCP
+    if (EVP_PKEY_is_sm2(pkey)) {
+        if (X509_check_private_key(ctx->cert->pkeys[SSL_PKEY_SM2_SIGN].x509, pkey)) {
+            return ssl_set_sign_enc_pkey(ctx->cert, pkey, SSL_PKEY_SM2_SIGN);
+        } else if (X509_check_private_key(ctx->cert->pkeys[SSL_PKEY_SM2_ENC].x509, pkey)) {
+            return ssl_set_sign_enc_pkey(ctx->cert, pkey, SSL_PKEY_SM2_ENC);
+        }
+        SSLerr(SSL_F_SSL_CTX_USE_PRIVATEKEY, ERR_R_PASSED_INVALID_ARGUMENT);
+        return 0;
+    }
+#endif
     return ssl_set_pkey(ctx->cert, pkey);
 }
 
@@ -562,6 +933,54 @@ int SSL_CTX_use_PrivateKey_ASN1(int type, SSL_CTX *ctx,
     return ret;
 }
 
+#ifndef OPENSSL_NO_TLCP
+int SSL_CTX_use_gm_PrivateKey(SSL_CTX *ctx, EVP_PKEY *pkey, int usage)
+{
+    if (pkey == NULL) {
+        SSLerr(SSL_F_SSL_CTX_USE_GM_PRIVATEKEY, ERR_R_PASSED_NULL_PARAMETER);
+        return 0;
+    }
+    if (usage == SSL_USAGE_SIG) {
+        return ssl_set_sign_enc_pkey(ctx->cert, pkey, SSL_PKEY_SM2_SIGN);
+    } else if (usage == SSL_USAGE_ENC) {
+        return ssl_set_sign_enc_pkey(ctx->cert, pkey, SSL_PKEY_SM2_ENC);
+    }
+    SSLerr(SSL_F_SSL_CTX_USE_GM_PRIVATEKEY, ERR_R_PASSED_INVALID_ARGUMENT);
+    return 0;
+}
+
+int SSL_CTX_use_gm_PrivateKey_file(SSL_CTX *ctx, const char *file, int type, int usage)
+{
+    int ret;
+    EVP_PKEY *pkey = NULL;
+
+    ret = ssl_load_pkey_file(NULL, ctx, file, type, &pkey);
+    if (ret == 1) {
+        ret = SSL_CTX_use_gm_PrivateKey(ctx, pkey, usage);
+    }
+    EVP_PKEY_free(pkey);
+    return ret;
+}
+
+int SSL_CTX_use_gm_PrivateKey_ASN1(int type, SSL_CTX *ctx,
+                                const unsigned char *d, long len, int usage)
+{
+    int ret;
+    const unsigned char *p;
+    EVP_PKEY *pkey;
+
+    p = d;
+    if ((pkey = d2i_PrivateKey(type, NULL, &p, (long)len)) == NULL) {
+        SSLerr(SSL_F_SSL_CTX_USE_GM_PRIVATEKEY_ASN1, ERR_R_ASN1_LIB);
+        return 0;
+    }
+
+    ret = SSL_CTX_use_gm_PrivateKey(ctx, pkey, usage);
+    EVP_PKEY_free(pkey);
+    return ret;
+}
+#endif
+
 /*
  * Read a file that contains our certificate in "PEM" format, possibly
  * followed by a sequence of CA certificates that should be sent to the peer
@@ -1073,6 +1492,12 @@ static int ssl_set_cert_and_key(SSL *ssl, SSL_CTX *ctx, X509 *x509, EVP_PKEY *pr
         SSLerr(SSL_F_SSL_SET_CERT_AND_KEY, SSL_R_UNKNOWN_CERTIFICATE_TYPE);
         goto out;
     }
+#ifndef OPENSSL_NO_TLCP
+    if (i == SSL_PKEY_SM2_SIGN && !ssl_get_sm2_cert_id(x509, &i)) {
+        SSLerr(SSL_F_SSL_SET_CERT_AND_KEY, SSL_R_UNKNOWN_CERTIFICATE_TYPE);
+        return 0;
+    }
+#endif
 
     if (!override && (c->pkeys[i].x509 != NULL
                       || c->pkeys[i].privatekey != NULL
@@ -1101,7 +1526,13 @@ static int ssl_set_cert_and_key(SSL *ssl, SSL_CTX *ctx, X509 *x509, EVP_PKEY *pr
     EVP_PKEY_up_ref(privatekey);
     c->pkeys[i].privatekey = privatekey;
 
+#ifndef OPENSSL_NO_TLCP
+    if (i != SSL_PKEY_SM2_ENC) {
+        c->key = &(c->pkeys[i]);
+    }
+#else
     c->key = &(c->pkeys[i]);
+#endif
 
     ret = 1;
  out:
@@ -1120,3 +1551,113 @@ int SSL_CTX_use_cert_and_key(SSL_CTX *ctx, X509 *x509, EVP_PKEY *privatekey,
 {
     return ssl_set_cert_and_key(NULL, ctx, x509, privatekey, chain, override);
 }
+
+#ifndef OPENSSL_NO_TLCP
+static int ssl_set_gm_cert_and_key(SSL *ssl, SSL_CTX *ctx, X509 *x509, EVP_PKEY *privatekey,
+                                STACK_OF(X509) *chain, int override, int usage)
+{
+    int ret = 0;
+    size_t id;
+    int j;
+    int rv;
+    CERT *c = ssl != NULL ? ssl->cert : ctx->cert;
+    STACK_OF(X509) *dup_chain = NULL;
+    EVP_PKEY *pubkey = NULL;
+
+    /* Do all security checks before anything else */
+    rv = ssl_security_cert(ssl, ctx, x509, 0, 1);
+    if (rv != 1) {
+        SSLerr(SSL_F_SSL_SET_GM_CERT_AND_KEY, rv);
+        goto out;
+    }
+    for (j = 0; j < sk_X509_num(chain); j++) {
+        rv = ssl_security_cert(ssl, ctx, sk_X509_value(chain, j), 0, 0);
+        if (rv != 1) {
+            SSLerr(SSL_F_SSL_SET_GM_CERT_AND_KEY, rv);
+            goto out;
+        }
+    }
+
+    pubkey = X509_get_pubkey(x509); /* bumps reference */
+    if (pubkey == NULL)
+        goto out;
+    if (privatekey == NULL) {
+        privatekey = pubkey;
+    } else {
+        /* For RSA, which has no parameters, missing returns 0 */
+        if (EVP_PKEY_missing_parameters(privatekey)) {
+            if (EVP_PKEY_missing_parameters(pubkey)) {
+                /* nobody has parameters? - error */
+                SSLerr(SSL_F_SSL_SET_GM_CERT_AND_KEY, SSL_R_MISSING_PARAMETERS);
+                goto out;
+            } else {
+                /* copy to privatekey from pubkey */
+                EVP_PKEY_copy_parameters(privatekey, pubkey);
+            }
+        } else if (EVP_PKEY_missing_parameters(pubkey)) {
+            /* copy to pubkey from privatekey */
+            EVP_PKEY_copy_parameters(pubkey, privatekey);
+        } /* else both have parameters */
+
+        /* check that key <-> cert match */
+        if (EVP_PKEY_cmp(pubkey, privatekey) != 1) {
+            SSLerr(SSL_F_SSL_SET_GM_CERT_AND_KEY, SSL_R_PRIVATE_KEY_MISMATCH);
+            goto out;
+        }
+    }
+    if (usage == SSL_USAGE_SIG) {
+        id = SSL_PKEY_SM2_SIGN;
+    } else if (usage == SSL_USAGE_ENC) {
+        id = SSL_PKEY_SM2_ENC;
+    } else {
+        SSLerr(SSL_F_SSL_SET_GM_CERT_AND_KEY, ERR_R_PASSED_INVALID_ARGUMENT);
+        goto out;
+    }
+
+    if (!override && (c->pkeys[id].x509 != NULL
+                      || c->pkeys[id].privatekey != NULL
+                      || c->pkeys[id].chain != NULL)) {
+        /* No override, and something already there */
+        SSLerr(SSL_F_SSL_SET_GM_CERT_AND_KEY, SSL_R_NOT_REPLACING_CERTIFICATE);
+        goto out;
+    }
+
+    if (chain != NULL) {
+        dup_chain = X509_chain_up_ref(chain);
+        if  (dup_chain == NULL) {
+            SSLerr(SSL_F_SSL_SET_GM_CERT_AND_KEY, ERR_R_MALLOC_FAILURE);
+            goto out;
+        }
+    }
+
+    sk_X509_pop_free(c->pkeys[id].chain, X509_free);
+    c->pkeys[id].chain = dup_chain;
+
+    X509_free(c->pkeys[id].x509);
+    X509_up_ref(x509);
+    c->pkeys[id].x509 = x509;
+
+    EVP_PKEY_free(c->pkeys[id].privatekey);
+    EVP_PKEY_up_ref(privatekey);
+    c->pkeys[id].privatekey = privatekey;
+    if (id != SSL_PKEY_SM2_ENC) {
+        c->key = &(c->pkeys[id]);
+    }
+    ret = 1;
+ out:
+    EVP_PKEY_free(pubkey);
+    return ret;
+}
+
+int SSL_use_gm_cert_and_key(SSL *ssl, X509 *x509, EVP_PKEY *privatekey,
+                         STACK_OF(X509) *chain, int override, int usage)
+{
+    return ssl_set_gm_cert_and_key(ssl, NULL, x509, privatekey, chain, override, usage);
+}
+
+int SSL_CTX_use_gm_cert_and_key(SSL_CTX *ctx, X509 *x509, EVP_PKEY *privatekey,
+                             STACK_OF(X509) *chain, int override, int usage)
+{
+    return ssl_set_gm_cert_and_key(NULL, ctx, x509, privatekey, chain, override, usage);
+}
+#endif
\ No newline at end of file
diff --git a/ssl/ssl_sess.c b/ssl/ssl_sess.c
index cda6b7c..fb354e6 100644
--- a/ssl/ssl_sess.c
+++ b/ssl/ssl_sess.c
@@ -283,6 +283,9 @@ int ssl_generate_session_id(SSL *s, SSL_SESSION *ss)
     GEN_SESSION_CB cb = def_generate_session_id;
 
     switch (s->version) {
+#ifndef OPENSSL_NO_TLCP
+    case TLCP_VERSION:
+#endif
     case SSL3_VERSION:
     case TLS1_VERSION:
     case TLS1_1_VERSION:
diff --git a/ssl/ssl_stat.c b/ssl/ssl_stat.c
index ca51c03..1750bdb 100644
--- a/ssl/ssl_stat.c
+++ b/ssl/ssl_stat.c
@@ -312,6 +312,20 @@ const char *SSL_alert_desc_string(int value)
         return "BH";
     case TLS1_AD_UNKNOWN_PSK_IDENTITY:
         return "UP";
+#ifndef OPENSSL_NO_TLCP
+    case TLCP_AD_UNSUPPORTED_SITE2SITE:
+        return "U2";
+    case TLCP_AD_NO_AREA:
+        return "NA";
+    case TLCP_AD_UNSUPPORTED_AREATYPE:
+        return "AT";
+    case TLCP_AD_BAD_IBCPARAM:
+        return "BI";
+    case TLCP_AD_UNSUPPORTED_IBCPARAM:
+        return "UI";
+    case TLCP_AD_IDENTITY_NEED:
+        return "IN";
+#endif
     default:
         return "UK";
     }
@@ -382,6 +396,20 @@ const char *SSL_alert_desc_string_long(int value)
         return "unknown PSK identity";
     case TLS1_AD_NO_APPLICATION_PROTOCOL:
         return "no application protocol";
+#ifndef OPENSSL_NO_TLCP
+    case TLCP_AD_UNSUPPORTED_SITE2SITE:
+        return "unsupported site2site";
+    case TLCP_AD_NO_AREA:
+        return "no area";
+    case TLCP_AD_UNSUPPORTED_AREATYPE:
+        return "unsupported areatype";
+    case TLCP_AD_BAD_IBCPARAM:
+        return "bad ibcparam";
+    case TLCP_AD_UNSUPPORTED_IBCPARAM:
+        return "unsupported ibcparam";
+    case TLCP_AD_IDENTITY_NEED:
+        return "identity need";
+#endif
     default:
         return "unknown";
     }
diff --git a/ssl/statem/extensions.c b/ssl/statem/extensions.c
index 0f39275..a03b6cd 100644
--- a/ssl/statem/extensions.c
+++ b/ssl/statem/extensions.c
@@ -1056,7 +1056,11 @@ static int final_ec_pt_formats(SSL *s, unsigned int context, int sent)
             && s->ext.ecpointformats_len > 0
             && s->ext.peer_ecpointformats != NULL
             && s->ext.peer_ecpointformats_len > 0
-            && ((alg_k & SSL_kECDHE) || (alg_a & SSL_aECDSA))) {
+            && ((alg_k & SSL_kECDHE) || (alg_a & SSL_aECDSA)
+#ifndef OPENSSL_NO_TLCP
+            || (alg_k & SSL_kSM2DHE) || (alg_a & SSL_aSM2)
+#endif
+            )) {
         /* we are using an ECC cipher */
         size_t i;
         unsigned char *list = s->ext.peer_ecpointformats;
diff --git a/ssl/statem/extensions_clnt.c b/ssl/statem/extensions_clnt.c
index 9d38ac2..23ca93e 100644
--- a/ssl/statem/extensions_clnt.c
+++ b/ssl/statem/extensions_clnt.c
@@ -132,6 +132,9 @@ static int use_ecc(SSL *s)
         alg_a = c->algorithm_auth;
         if ((alg_k & (SSL_kECDHE | SSL_kECDHEPSK))
                 || (alg_a & SSL_aECDSA)
+#ifndef OPENSSL_NO_TLCP
+                || (alg_k & SSL_kSM2DHE) || (alg_a & SSL_aSM2)
+#endif
                 || c->min_tls >= TLS1_3_VERSION) {
             ret = 1;
             break;
diff --git a/ssl/statem/extensions_srvr.c b/ssl/statem/extensions_srvr.c
index 04f64f8..7c5e3bf 100644
--- a/ssl/statem/extensions_srvr.c
+++ b/ssl/statem/extensions_srvr.c
@@ -1386,7 +1386,11 @@ EXT_RETURN tls_construct_stoc_ec_pt_formats(SSL *s, WPACKET *pkt,
 {
     unsigned long alg_k = s->s3->tmp.new_cipher->algorithm_mkey;
     unsigned long alg_a = s->s3->tmp.new_cipher->algorithm_auth;
-    int using_ecc = ((alg_k & SSL_kECDHE) || (alg_a & SSL_aECDSA))
+    int using_ecc = ((alg_k & SSL_kECDHE) || (alg_a & SSL_aECDSA)
+#ifndef OPENSSL_NO_TLCP
+                    || (alg_k & SSL_kSM2DHE) || (alg_a & SSL_aSM2)
+#endif
+                    )
                     && (s->ext.peer_ecpointformats != NULL);
     const unsigned char *plist;
     size_t plistlen;
diff --git a/ssl/statem/statem.c b/ssl/statem/statem.c
index 20f5bd5..d1fc2cc 100644
--- a/ssl/statem/statem.c
+++ b/ssl/statem/statem.c
@@ -361,7 +361,11 @@ static int state_machine(SSL *s, int server)
                 goto end;
             }
         } else {
+#ifndef OPENSSL_NO_TLCP
+            if ((s->version >> 8) != SSL3_VERSION_MAJOR && s->version != TLCP_VERSION) {
+#else
             if ((s->version >> 8) != SSL3_VERSION_MAJOR) {
+#endif
                 SSLfatal(s, SSL_AD_NO_ALERT, SSL_F_STATE_MACHINE,
                          ERR_R_INTERNAL_ERROR);
                 goto end;
diff --git a/ssl/statem/statem_clnt.c b/ssl/statem/statem_clnt.c
index d1a3969..052a733 100644
--- a/ssl/statem/statem_clnt.c
+++ b/ssl/statem/statem_clnt.c
@@ -61,6 +61,10 @@ static int key_exchange_expected(SSL *s)
 {
     long alg_k = s->s3->tmp.new_cipher->algorithm_mkey;
 
+#ifndef OPENSSL_NO_TLCP
+    if (SSL_IS_TLCP(s))
+        return 1;
+#endif
     /*
      * Can't skip server key exchange if this is an ephemeral
      * ciphersuite or for SRP
@@ -2252,8 +2256,277 @@ static int tls_process_ske_ecdhe(SSL *s, PACKET *pkt, EVP_PKEY **pkey)
 #endif
 }
 
+#ifndef OPENSSL_NO_TLCP
+static int tlcp_process_ske_sm2ecc(SSL *s, PACKET *pkt)
+{
+    EVP_MD_CTX *md_ctx = NULL;
+    EVP_PKEY_CTX *pctx = NULL;
+    unsigned char *encbuf = NULL;
+    unsigned char *tbs = NULL;
+    
+    PACKET signature;
+    X509 *peer_sign_cert;
+    X509 *peer_enc_cert;
+    EVP_PKEY *peer_sign_pkey;
+    const EVP_MD *md;
+    unsigned char *tmp;
+    int rv, ebuflen, tbslen;
+
+    rv = 0;
+    peer_sign_cert = s->session->peer;
+    peer_enc_cert = ssl_get_sm2_enc_cert(s, s->session->peer_chain);
+    if (peer_sign_cert == NULL || peer_enc_cert == NULL
+        || !ssl_is_sm2_cert(peer_sign_cert)
+        || !ssl_is_sm2_sign_usage(peer_sign_cert)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                 SSL_F_TLCP_PROCESS_SKE_SM2ECC, ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+
+    peer_sign_pkey = X509_get0_pubkey(peer_sign_cert);
+    if (!EVP_PKEY_set_alias_type(peer_sign_pkey, EVP_PKEY_SM2)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLCP_PROCESS_SKE_SM2ECC,
+                    ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+    /* Get the signature algorithm according to the peer sign key */
+    if (SSL_USE_SIGALGS(s)) {
+        unsigned int sigalg;
+
+        if (!PACKET_get_net_2(pkt, &sigalg)) {
+            SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLCP_PROCESS_SKE_SM2ECC,
+                        SSL_R_LENGTH_TOO_SHORT);
+            goto err;
+        }
+        if (tls12_check_peer_sigalg(s, sigalg, peer_sign_pkey) <=0) {
+            /* SSLfatal() already called */
+            goto err;
+        }
+    } else if (!tls1_set_peer_legacy_sigalg(s, peer_sign_pkey)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLCP_PROCESS_SKE_SM2ECC,
+                    ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+    if (!tls1_lookup_md(s->s3->tmp.peer_sigalg, &md)
+        || EVP_PKEY_size(peer_sign_pkey) < 0) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLCP_PROCESS_SKE_SM2ECC,
+                    ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+
+    if (!PACKET_get_length_prefixed_2(pkt, &signature)
+        || PACKET_remaining(pkt) != 0
+        || PACKET_remaining(&signature) > EVP_PKEY_size(peer_sign_pkey)) {
+        SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLCP_PROCESS_SKE_SM2ECC,
+                    SSL_R_LENGTH_MISMATCH);
+        goto err;
+    }
+
+    ebuflen = i2d_X509(peer_enc_cert, NULL);
+    if (ebuflen < 0) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLCP_PROCESS_SKE_SM2ECC,
+                 ERR_R_BUF_LIB);
+        goto err;
+    }
+
+    md_ctx = EVP_MD_CTX_new();
+    encbuf = OPENSSL_malloc(ebuflen + 3);
+    if (md_ctx == NULL || encbuf == NULL) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLCP_PROCESS_SKE_SM2ECC,
+                 ERR_R_MALLOC_FAILURE);
+        goto err;
+    }
+    /* Encode the DER encoding of an X509 structure, reserve 3 bytes for length */
+    tmp = encbuf;
+    l2n3(ebuflen, tmp);
+    ebuflen = i2d_X509(peer_enc_cert, &tmp);
+    if (ebuflen < 0) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLCP_PROCESS_SKE_SM2ECC,
+                 ERR_R_BUF_LIB);
+        goto err;
+    }
+    ebuflen += 3;
+
+    if (EVP_DigestVerifyInit(md_ctx, &pctx, md, NULL, peer_sign_pkey) <= 0) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLCP_PROCESS_SKE_SM2ECC,
+                    ERR_R_EVP_LIB);
+        goto err;
+    }
+
+    tbslen = construct_key_exchange_tbs(s, &tbs, encbuf, ebuflen);
+    if (tbslen == 0) {
+        goto err;
+    }
+
+    rv = EVP_DigestVerify(md_ctx, PACKET_data(&signature),
+                            PACKET_remaining(&signature), tbs, tbslen);
+    if (rv <= 0) {
+        SSLfatal(s, SSL_AD_DECRYPT_ERROR, SSL_F_TLCP_PROCESS_SKE_SM2ECC,
+                    SSL_R_BAD_SIGNATURE);
+    }
+err:
+    OPENSSL_free(encbuf);
+    OPENSSL_free(tbs);
+    EVP_MD_CTX_free(md_ctx);
+    return rv;
+}
+
+static int tlcp_process_ske_sm2dhe(SSL *s, PACKET *pkt)
+{
+    unsigned char *ecparams;
+    int ecparams_len;
+    PACKET pt_encoded;
+    PACKET signature;
+    EVP_PKEY *pkey;
+    EVP_PKEY_CTX *pctx;
+    EVP_PKEY_CTX *verify_ctx;
+    EVP_MD_CTX *md_ctx = NULL;
+    char *id = "1234567812345678";
+    int ret = 0;
+    int max_sig_len;
+
+    if(!PACKET_get_bytes(pkt, (const unsigned char**)&ecparams, 3)
+            || !PACKET_get_length_prefixed_1(pkt, &pt_encoded)
+            || !PACKET_get_length_prefixed_2(pkt, &signature)
+    ) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                 SSL_F_TLCP_PROCESS_SKE_SM2DHE, SSL_R_LENGTH_TOO_SHORT);
+        return 0;
+    }
+
+    if (PACKET_remaining(pkt) != 0) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                 SSL_F_TLCP_PROCESS_SKE_SM2DHE, SSL_R_LENGTH_TOO_LONG);
+        return 0;
+    }
+
+    // generate tmp pkey s->s3->peer_tmp with peer pub key
+    if ((pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL)) == NULL) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                 SSL_F_TLCP_PROCESS_SKE_SM2DHE, ERR_R_MALLOC_FAILURE);
+        return 0;
+    }
+
+    if (EVP_PKEY_paramgen_init(pctx) <= 0 
+            || EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, NID_sm2) <= 0
+            || EVP_PKEY_paramgen(pctx, &s->s3->peer_tmp) <= 0) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                 SSL_F_TLCP_PROCESS_SKE_SM2DHE, ERR_R_EVP_LIB);
+        goto end;
+    }
+
+    if (s->s3->peer_tmp == NULL) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                 SSL_F_TLCP_PROCESS_SKE_SM2DHE, ERR_R_INTERNAL_ERROR);
+        goto end;
+    }
+
+    if (!EVP_PKEY_set1_tls_encodedpoint(s->s3->peer_tmp, 
+            PACKET_data(&pt_encoded), PACKET_remaining(&pt_encoded))) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                 SSL_F_TLCP_PROCESS_SKE_SM2DHE, SSL_R_BAD_ECPOINT);
+        goto end;
+    }
+
+    // verify the msg using peer sign cert's pubkey
+    if ((pkey = X509_get0_pubkey(s->session->peer)) == NULL) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                 SSL_F_TLCP_PROCESS_SKE_SM2DHE, ERR_R_INTERNAL_ERROR);
+        goto end;
+    }
+
+    max_sig_len = EVP_PKEY_size(pkey);
+    if (PACKET_remaining(&signature) > max_sig_len) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                 SSL_F_TLCP_PROCESS_SKE_SM2DHE, SSL_R_LENGTH_TOO_LONG);
+        goto end;
+    }
+
+    if (!EVP_PKEY_set_alias_type(pkey, EVP_PKEY_SM2)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                 SSL_F_TLCP_PROCESS_SKE_SM2DHE, ERR_R_EVP_LIB);
+        goto end;
+    }
+
+    if ((md_ctx = EVP_MD_CTX_new()) == NULL) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                 SSL_F_TLCP_PROCESS_SKE_SM2DHE, ERR_R_MALLOC_FAILURE);
+        goto end;
+    }
+
+    if (EVP_DigestVerifyInit(md_ctx, &verify_ctx, EVP_sm3(), NULL, pkey) <= 0) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                 SSL_F_TLCP_PROCESS_SKE_SM2DHE, ERR_R_EVP_LIB);
+        goto end;
+    }
+
+    if (EVP_PKEY_CTX_set1_id(verify_ctx, id, strlen(id)) <= 0) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                 SSL_F_TLCP_PROCESS_SKE_SM2DHE, ERR_R_EVP_LIB);
+        goto end;
+    }
+
+    ecparams_len = PACKET_data(&pt_encoded) + PACKET_remaining(&pt_encoded) - ecparams;
+    if (EVP_DigestVerifyUpdate(md_ctx, s->s3->client_random, SSL3_RANDOM_SIZE) <= 0
+            || EVP_DigestVerifyUpdate(md_ctx, s->s3->server_random, SSL3_RANDOM_SIZE) <= 0
+            || EVP_DigestVerifyUpdate(md_ctx, ecparams, ecparams_len) <= 0) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                 SSL_F_TLCP_PROCESS_SKE_SM2DHE, ERR_R_EVP_LIB);
+        goto end;
+    }
+
+    if (EVP_DigestVerifyFinal(md_ctx, 
+            PACKET_data(&signature), PACKET_remaining(&signature)) <= 0) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                 SSL_F_TLCP_PROCESS_SKE_SM2DHE, SSL_R_BAD_SIGNATURE);
+        goto end;
+    }
+
+    ret = 1;
+
+end:
+    EVP_PKEY_CTX_free(pctx);
+    EVP_MD_CTX_free(md_ctx);
+
+    return ret;
+}
+
+static MSG_PROCESS_RETURN tlcp_process_key_exchange(SSL *s, PACKET *pkt)
+{
+    unsigned long alg_k;
+
+    alg_k = s->s3->tmp.new_cipher->algorithm_mkey;
+
+    if (alg_k & SSL_kSM2ECC) {
+        if (!tlcp_process_ske_sm2ecc(s, pkt)) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                 SSL_F_TLCP_PROCESS_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
+            goto err;
+        }
+    } else if (alg_k & SSL_kSM2DHE) {
+        if (!tlcp_process_ske_sm2dhe(s, pkt)) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                 SSL_F_TLCP_PROCESS_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
+            goto err;
+        }
+    } else {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                 SSL_F_TLCP_PROCESS_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+
+    return MSG_PROCESS_CONTINUE_READING;
+err:
+    return MSG_PROCESS_ERROR;
+}
+#endif
+
 MSG_PROCESS_RETURN tls_process_key_exchange(SSL *s, PACKET *pkt)
 {
+#ifndef OPENSSL_NO_TLCP
+    if (SSL_IS_TLCP(s))
+        return tlcp_process_key_exchange(s, pkt);
+#endif
     long alg_k;
     EVP_PKEY *pkey = NULL;
     EVP_MD_CTX *md_ctx = NULL;
@@ -3315,8 +3588,169 @@ static int tls_construct_cke_srp(SSL *s, WPACKET *pkt)
 #endif
 }
 
+#ifndef OPENSSL_NO_TLCP
+static int tlcp_construct_cke_sm2ecc(SSL *s, WPACKET *pkt)
+{
+    unsigned char *encdata = NULL;
+    EVP_PKEY_CTX *pctx = NULL;
+    unsigned char *pms = NULL;
+    size_t pmslen = 0;
+
+    X509 *peer_enc_cert;
+    EVP_PKEY *peer_enc_pkey;
+    size_t enclen;
+
+    peer_enc_cert = ssl_get_sm2_enc_cert(s, s->session->peer_chain);
+    peer_enc_pkey = X509_get0_pubkey(peer_enc_cert);
+    if (peer_enc_cert == NULL || peer_enc_pkey == NULL
+        || !EVP_PKEY_set_alias_type(peer_enc_pkey, EVP_PKEY_SM2)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                 SSL_F_TLCP_CONSTRUCT_CKE_SM2ECC, ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+
+    pmslen = SSL_MAX_MASTER_KEY_LENGTH;
+    pms = OPENSSL_malloc(pmslen);
+    if (pms == NULL) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLCP_CONSTRUCT_CKE_SM2ECC,
+                 ERR_R_MALLOC_FAILURE);
+        goto err;
+    }
+
+    pms[0] = s->client_version >> 8;
+    pms[1] = s->client_version & 0xff;
+    if (RAND_bytes(pms + 2, (int)(pmslen - 2)) <= 0) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLCP_CONSTRUCT_CKE_SM2ECC,
+                 ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+
+    if (!WPACKET_start_sub_packet_u16(pkt)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLCP_CONSTRUCT_CKE_SM2ECC,
+                 ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+    /* Encrypt premaster secret { client_version, random[46] }*/
+    pctx = EVP_PKEY_CTX_new(peer_enc_pkey, NULL);
+    if (pctx == NULL || EVP_PKEY_encrypt_init(pctx) <= 0
+        || EVP_PKEY_encrypt(pctx, NULL, &enclen, pms, pmslen) <= 0) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLCP_CONSTRUCT_CKE_SM2ECC,
+                 ERR_R_EVP_LIB);
+        goto err;
+    }
+    if (!WPACKET_reserve_bytes(pkt, enclen, &encdata)
+            || EVP_PKEY_encrypt(pctx, encdata, &enclen, pms, pmslen) <= 0) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLCP_CONSTRUCT_CKE_SM2ECC,
+                 ERR_R_EVP_LIB);
+        goto err;
+    }
+    pkt->written += enclen;
+    pkt->curr += enclen;
+    EVP_PKEY_CTX_free(pctx);
+    pctx = NULL;
+
+    if (!WPACKET_close(pkt)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLCP_CONSTRUCT_CKE_SM2ECC,
+                 ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+
+    s->s3->tmp.pms = pms;
+    s->s3->tmp.pmslen = pmslen;
+
+    return 1;
+err:
+    OPENSSL_clear_free(pms, pmslen);
+    EVP_PKEY_CTX_free(pctx);
+    return 0;
+}
+
+static int tlcp_construct_cke_sm2dhe(SSL *s, WPACKET *pkt)
+{
+    EVP_PKEY *skey, *ckey;
+    unsigned char * pt_encoded = NULL;
+    int pt_encoded_len;
+    int ret = 0;
+
+    if ((skey = s->s3->peer_tmp) == NULL) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                 SSL_F_TLCP_CONSTRUCT_CKE_SM2DHE, ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    if (!WPACKET_put_bytes_u8(pkt, NAMED_CURVE_TYPE)
+            || !WPACKET_put_bytes_u8(pkt, 0)
+            || !WPACKET_put_bytes_u8(pkt, 41)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                 SSL_F_TLCP_CONSTRUCT_CKE_SM2DHE, ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    if ((ckey = ssl_generate_pkey(skey)) == NULL) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                 SSL_F_TLCP_CONSTRUCT_CKE_SM2DHE, ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    if ((pt_encoded_len = EVP_PKEY_get1_tls_encodedpoint(ckey, &pt_encoded)) <= 0) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                 SSL_F_TLCP_CONSTRUCT_CKE_SM2DHE, ERR_R_EC_LIB);
+        goto end;
+    }
+
+    if (!WPACKET_sub_memcpy_u8(pkt, pt_encoded, pt_encoded_len)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                 SSL_F_TLCP_CONSTRUCT_CKE_SM2DHE, ERR_R_INTERNAL_ERROR);
+        goto end;
+    }
+
+    if (!tlcp_derive(s, ckey, skey)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                 SSL_F_TLCP_CONSTRUCT_CKE_SM2DHE, ERR_R_INTERNAL_ERROR);
+        goto end;
+    }
+
+    ret = 1;
+
+end:
+    EVP_PKEY_free(ckey);
+    if (pt_encoded) {
+        OPENSSL_free(pt_encoded);
+    }
+
+    return ret;
+}
+
+static int tlcp_construct_client_key_exchange(SSL *s, WPACKET *pkt)
+{
+    unsigned long alg_k;
+
+    alg_k = s->s3->tmp.new_cipher->algorithm_mkey;
+
+    if (alg_k & SSL_kSM2ECC) {
+        if (!tlcp_construct_cke_sm2ecc(s, pkt))
+            goto err;
+    } else if (alg_k & SSL_kSM2DHE) {
+        if (!tlcp_construct_cke_sm2dhe(s, pkt))
+            goto err;
+    } else {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                 SSL_F_TLCP_CONSTRUCT_CLIENT_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+
+    return 1;
+err:
+    return 0;
+}
+#endif
+
 int tls_construct_client_key_exchange(SSL *s, WPACKET *pkt)
 {
+#ifndef OPENSSL_NO_TLCP
+    if (SSL_IS_TLCP(s))
+        return tlcp_construct_client_key_exchange(s, pkt);
+#endif
     unsigned long alg_k;
 
     alg_k = s->s3->tmp.new_cipher->algorithm_mkey;
diff --git a/ssl/statem/statem_lib.c b/ssl/statem/statem_lib.c
index 695caab..777a474 100644
--- a/ssl/statem/statem_lib.c
+++ b/ssl/statem/statem_lib.c
@@ -227,6 +227,29 @@ static int get_cert_verify_tbs_data(SSL *s, unsigned char *tls13tbs,
     return 1;
 }
 
+#ifndef OPENSSL_NO_TLCP
+static int get_tbs_hash_data(void *hdata, size_t hdatalen, unsigned char *out, size_t *outlen)
+{
+    EVP_MD_CTX *md_ctx;
+    int rv = 0;
+
+    md_ctx = EVP_MD_CTX_new();
+    if (md_ctx == NULL)
+        goto err;
+
+    // TLCP is only used SM3
+    if (!EVP_DigestInit(md_ctx, EVP_sm3())
+            || !EVP_DigestUpdate(md_ctx, (const void *)hdata, hdatalen)
+            || !EVP_DigestFinal(md_ctx, out, (unsigned int *)outlen)) {
+        goto err;
+    }
+    rv = 1;
+err:
+    EVP_MD_CTX_free(md_ctx);
+    return rv;
+}
+#endif
+
 int tls_construct_cert_verify(SSL *s, WPACKET *pkt)
 {
     EVP_PKEY *pkey = NULL;
@@ -238,6 +261,9 @@ int tls_construct_cert_verify(SSL *s, WPACKET *pkt)
     unsigned char *sig = NULL;
     unsigned char tls13tbs[TLS13_TBS_PREAMBLE_SIZE + EVP_MAX_MD_SIZE];
     const SIGALG_LOOKUP *lu = s->s3->tmp.sigalg;
+#ifndef OPENSSL_NO_TLCP
+    unsigned char out[EVP_MAX_MD_SIZE] = {0};
+#endif
 
     if (lu == NULL || s->s3->tmp.cert == NULL) {
         SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CERT_VERIFY,
@@ -251,6 +277,15 @@ int tls_construct_cert_verify(SSL *s, WPACKET *pkt)
                  ERR_R_INTERNAL_ERROR);
         goto err;
     }
+#ifndef OPENSSL_NO_TLCP
+    if (SSL_IS_TLCP(s) && EVP_PKEY_is_sm2(pkey)) {
+        if (!EVP_PKEY_set_alias_type(pkey, EVP_PKEY_SM2)) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CERT_VERIFY,
+                 ERR_R_INTERNAL_ERROR);
+            goto err;
+        }
+    }
+#endif
 
     mctx = EVP_MD_CTX_new();
     if (mctx == NULL) {
@@ -264,7 +299,17 @@ int tls_construct_cert_verify(SSL *s, WPACKET *pkt)
         /* SSLfatal() already called */
         goto err;
     }
-
+#ifndef OPENSSL_NO_TLCP
+    if (SSL_IS_TLCP(s)) {
+        if (!get_tbs_hash_data(hdata, hdatalen, out, &hdatalen)) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CERT_VERIFY,
+                ERR_R_INTERNAL_ERROR);
+            goto err;
+        }
+        /* Use new hash data for sign */
+        hdata = out;
+    }
+#endif
     if (SSL_USE_SIGALGS(s) && !WPACKET_put_bytes_u16(pkt, lu->sigalg)) {
         SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CERT_VERIFY,
                  ERR_R_INTERNAL_ERROR);
@@ -359,6 +404,9 @@ MSG_PROCESS_RETURN tls_process_cert_verify(SSL *s, PACKET *pkt)
     unsigned char tls13tbs[TLS13_TBS_PREAMBLE_SIZE + EVP_MAX_MD_SIZE];
     EVP_MD_CTX *mctx = EVP_MD_CTX_new();
     EVP_PKEY_CTX *pctx = NULL;
+#ifndef OPENSSL_NO_TLCP
+    unsigned char out[EVP_MAX_MD_SIZE] = {0};
+#endif
 
     if (mctx == NULL) {
         SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PROCESS_CERT_VERIFY,
@@ -373,6 +421,15 @@ MSG_PROCESS_RETURN tls_process_cert_verify(SSL *s, PACKET *pkt)
                  ERR_R_INTERNAL_ERROR);
         goto err;
     }
+#ifndef OPENSSL_NO_TLCP
+    if (SSL_IS_TLCP(s) && EVP_PKEY_is_sm2(pkey)) {
+        if (!EVP_PKEY_set_alias_type(pkey, EVP_PKEY_SM2)) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PROCESS_CERT_VERIFY,
+                 ERR_R_INTERNAL_ERROR);
+            goto err;
+        }
+    }
+#endif
 
     if (ssl_cert_lookup_by_pkey(pkey, NULL) == NULL) {
         SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_F_TLS_PROCESS_CERT_VERIFY,
@@ -448,6 +505,17 @@ MSG_PROCESS_RETURN tls_process_cert_verify(SSL *s, PACKET *pkt)
         /* SSLfatal() already called */
         goto err;
     }
+#ifndef OPENSSL_NO_TLCP
+    if (SSL_IS_TLCP(s)) {
+        if (!get_tbs_hash_data(hdata, hdatalen, out, &hdatalen)) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PROCESS_CERT_VERIFY,
+                ERR_R_INTERNAL_ERROR);
+            goto err;
+        }
+        /* Use new hash data for verify */
+        hdata = out;
+    }
+#endif
 
 #ifdef SSL_DEBUG
     fprintf(stderr, "Using client verify alg %s\n",
@@ -907,6 +975,60 @@ static int ssl_add_cert_to_wpacket(SSL *s, WPACKET *pkt, X509 *x, int chain)
     return 1;
 }
 
+#ifndef OPENSSL_NO_TLCP
+static int ssl_add_sm2_cert_for_tlcp(SSL *s, STACK_OF(X509) *chain, WPACKET *pkt, X509 *sign_cert)
+{
+    CERT_PKEY *enc_cpk;
+    X509 *x;
+    int i = 0;
+    int idx = 0;
+    int count;
+    X509 *enc_cert;
+
+    enc_cpk = &s->cert->pkeys[SSL_PKEY_SM2_ENC];
+    // server must have enc cert
+    if (s->server && (enc_cpk == NULL || enc_cpk->x509 == NULL))
+        return 0;
+
+    enc_cert = enc_cpk->x509;
+
+    if (sign_cert != NULL) {
+        if (!ssl_add_cert_to_wpacket(s, pkt, sign_cert, idx++)) {
+            return 0;
+        }
+    } else {
+        if (!ssl_add_cert_to_wpacket(s, pkt, sk_X509_value(chain, i++), idx++)) {
+            return 0;
+        }
+    }
+
+    // enc cert put the second position
+    if (enc_cert != NULL && (s->options & SSL_OP_ENCCERT_SECOND_POSITION)) {
+        if (!ssl_add_cert_to_wpacket(s, pkt, enc_cert, idx++)) {
+            return 0;
+        }
+        enc_cert = NULL;
+    }
+
+    count = sk_X509_num(chain);
+    for (; i < count; i++) {
+        x = sk_X509_value(chain, i);
+        if (!ssl_add_cert_to_wpacket(s, pkt, x, idx++)) {
+            return 0;
+        }
+    }
+
+    // enc cert in the last position
+    if (enc_cert) {
+        if (!ssl_add_cert_to_wpacket(s, pkt, enc_cpk->x509, idx++)) {
+            return 0;
+        }
+    }
+
+    return 1;
+}
+#endif
+
 /* Add certificate chain to provided WPACKET */
 static int ssl_add_cert_chain(SSL *s, WPACKET *pkt, CERT_PKEY *cpk)
 {
@@ -972,6 +1094,14 @@ static int ssl_add_cert_chain(SSL *s, WPACKET *pkt, CERT_PKEY *cpk)
             SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_SSL_ADD_CERT_CHAIN, i);
             return 0;
         }
+#ifndef OPENSSL_NO_TLCP
+        if (SSL_IS_TLCP(s)) {
+            if (!ssl_add_sm2_cert_for_tlcp(s, chain, pkt, NULL)) {
+                X509_STORE_CTX_free(xs_ctx);
+                return 0;
+            }
+        } else {
+#endif
         chain_count = sk_X509_num(chain);
         for (i = 0; i < chain_count; i++) {
             x = sk_X509_value(chain, i);
@@ -982,6 +1112,9 @@ static int ssl_add_cert_chain(SSL *s, WPACKET *pkt, CERT_PKEY *cpk)
                 return 0;
             }
         }
+#ifndef OPENSSL_NO_TLCP
+        }
+#endif
         X509_STORE_CTX_free(xs_ctx);
     } else {
         i = ssl_security_cert_chain(s, extra_certs, x, 0);
@@ -989,6 +1122,11 @@ static int ssl_add_cert_chain(SSL *s, WPACKET *pkt, CERT_PKEY *cpk)
             SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_SSL_ADD_CERT_CHAIN, i);
             return 0;
         }
+#ifndef OPENSSL_NO_TLCP
+        if (SSL_IS_TLCP(s)) {
+            return ssl_add_sm2_cert_for_tlcp(s, extra_certs, pkt, x);
+        } else {
+#endif
         if (!ssl_add_cert_to_wpacket(s, pkt, x, 0)) {
             /* SSLfatal() already called */
             return 0;
@@ -1000,6 +1138,9 @@ static int ssl_add_cert_chain(SSL *s, WPACKET *pkt, CERT_PKEY *cpk)
                 return 0;
             }
         }
+#ifndef OPENSSL_NO_TLCP
+        }
+#endif
     }
     return 1;
 }
@@ -1444,6 +1585,9 @@ static const version_info tls_version_table[] = {
 #else
     {TLS1_VERSION, NULL, NULL},
 #endif
+#ifndef OPENSSL_NO_TLCP
+    {TLCP_VERSION, tlcp_client_method, tlcp_server_method},
+#endif
 #ifndef OPENSSL_NO_SSL3
     {SSL3_VERSION, sslv3_client_method, sslv3_server_method},
 #else
@@ -1596,7 +1740,10 @@ int ssl_version_supported(const SSL *s, int version, const SSL_METHOD **meth)
     }
 
     for (vent = table;
-         vent->version != 0 && version_cmp(s, version, vent->version) <= 0;
+#ifndef OPENSSL_NO_TLCP
+         ((version == SSL3_VERSION) && (vent->version == TLCP_VERSION)) ||
+#endif
+         (vent->version != 0 && version_cmp(s, version, vent->version) <= 0);
          ++vent) {
         if (vent->cmeth != NULL
                 && version_cmp(s, version, vent->version) == 0
@@ -1675,8 +1822,11 @@ int ssl_set_version_bound(int method_version, int version, int *bound)
         *bound = version;
         return 1;
     }
-
+#ifndef OPENSSL_NO_TLCP
+    valid_tls = version >= TLCP_VERSION && version <= TLS_MAX_VERSION;
+#else
     valid_tls = version >= SSL3_VERSION && version <= TLS_MAX_VERSION;
+#endif
     valid_dtls =
         DTLS_VERSION_LE(version, DTLS_MAX_VERSION) &&
         DTLS_VERSION_GE(version, DTLS1_BAD_VER);
@@ -1868,6 +2018,9 @@ int ssl_choose_server_version(SSL *s, CLIENTHELLO_MSG *hello, DOWNGRADE *dgrd)
         const SSL_METHOD *method;
 
         if (vent->smeth == NULL ||
+#ifndef OPENSSL_NO_TLCP
+            ((client_version != TLCP_VERSION) && (vent->version == TLCP_VERSION)) ||
+#endif
             version_cmp(s, client_version, vent->version) < 0)
             continue;
         method = vent->smeth();
@@ -2097,6 +2250,11 @@ int ssl_get_min_max_version(const SSL *s, int *min_version, int *max_version,
          * A table entry with a NULL client method is still a hole in the
          * "version capability" vector.
          */
+#ifndef OPENSSL_NO_TLCP
+        if (vent->version == TLCP_VERSION) {
+            continue;
+        }
+#endif
         if (vent->cmeth == NULL) {
             hole = 1;
             tmp_real_max = 0;
@@ -2120,7 +2278,23 @@ int ssl_get_min_max_version(const SSL *s, int *min_version, int *max_version,
             hole = 0;
         }
     }
-
+#ifndef OPENSSL_NO_TLCP
+    if (version == 0 && s->method->version == TLS_ANY_VERSION) {
+        /* 
+         * enable tlcp condition (when only sslv3 version, dont choose tlcp):
+         * 1. version is TLS_ANY_VERSION, and all tls/ssl protocol disabled
+         * 2. max version > sslv3 or max version == tlcp_version
+         * 3. s->options not set SSL_OP_NO_TLCP
+         */
+        if ((s->max_proto_version > SSL3_VERSION 
+                || s->max_proto_version == TLCP_VERSION
+                || s->max_proto_version == 0)
+                && (s->options & SSL_OP_NO_TLCP) == 0) {
+            *min_version = *max_version = TLCP_VERSION;
+            return 0;
+        }
+    }
+#endif
     *max_version = version;
 
     /* Fail if everything is disabled */
diff --git a/ssl/statem/statem_srvr.c b/ssl/statem/statem_srvr.c
index d701c46..ef13eec 100644
--- a/ssl/statem/statem_srvr.c
+++ b/ssl/statem/statem_srvr.c
@@ -325,6 +325,11 @@ static int send_server_key_exchange(SSL *s)
 {
     unsigned long alg_k = s->s3->tmp.new_cipher->algorithm_mkey;
 
+#ifndef OPENSSL_NO_TLCP
+    /* TLCP: send ServerKeyExchange */
+    if (SSL_IS_TLCP(s))
+        return 1;
+#endif
     /*
      * only send a ServerKeyExchange if DH or fortezza but we have a
      * sign only certificate PSK: may send PSK identity hints For
@@ -2356,7 +2361,17 @@ WORK_STATE tls_post_process_client_hello(SSL *s, WORK_STATE wst)
         }
     }
 #endif
-
+#ifndef OPENSSL_NO_TLCP
+    /*
+     * As described by TLCP, when using ecdhe algorithm, 
+     * client is required to send a certificate, 
+     * so we set VEERFY_PEER mode.
+     */
+    if (s->s3->tmp.new_cipher->algorithm_mkey & SSL_kSM2DHE) {
+        SSL_set_verify(s, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT 
+            | SSL_VERIFY_CLIENT_ONCE, NULL);
+    }
+#endif
     return WORK_FINISHED_STOP;
  err:
     return WORK_ERROR;
@@ -2485,8 +2500,270 @@ int tls_construct_server_done(SSL *s, WPACKET *pkt)
     return 1;
 }
 
+#ifndef OPENSSL_NO_TLCP
+static int tlcp_construct_ske_sm2ecc(SSL *s, WPACKET *pkt)
+{
+    EVP_MD_CTX *md_ctx = NULL;
+    EVP_PKEY_CTX *pctx = NULL;
+    unsigned char *encbuf = NULL;
+    unsigned char *tbs = NULL;
+
+    const SIGALG_LOOKUP *lu;
+    EVP_PKEY *sign_pkey;
+    X509 *enc_cert;
+    const EVP_MD *md;
+    unsigned char *sigbytes1, *sigbytes2, *tmp;
+    size_t siglen, tbslen;
+    int rv, ebuflen;
+
+    rv = 0;
+    lu = s->s3->tmp.sigalg;
+    sign_pkey = s->cert->pkeys[SSL_PKEY_SM2_SIGN].privatekey;
+    enc_cert = s->cert->pkeys[SSL_PKEY_SM2_ENC].x509;
+
+    if (lu == NULL || sign_pkey == NULL || enc_cert == NULL
+        || !tls1_lookup_md(lu, &md)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                     SSL_F_TLCP_CONSTRUCT_SKE_SM2ECC,
+                     ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+
+    if (!EVP_PKEY_is_sm2(sign_pkey) 
+        || !EVP_PKEY_set_alias_type(sign_pkey, EVP_PKEY_SM2)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                     SSL_F_TLCP_CONSTRUCT_SKE_SM2ECC,
+                     ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+
+    /* send signature algorithm */
+    if (SSL_USE_SIGALGS(s) && !WPACKET_put_bytes_u16(pkt, lu->sigalg)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                    SSL_F_TLCP_CONSTRUCT_SKE_SM2ECC,
+                    ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+
+    ebuflen = i2d_X509(enc_cert, NULL);
+    if (ebuflen < 0) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLCP_CONSTRUCT_SKE_SM2ECC,
+                 ERR_R_BUF_LIB);
+        goto err;
+    }
+
+    md_ctx = EVP_MD_CTX_new();
+    encbuf = OPENSSL_malloc(ebuflen + 3);
+    if (md_ctx == NULL || encbuf == NULL) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLCP_CONSTRUCT_SKE_SM2ECC,
+                 ERR_R_MALLOC_FAILURE);
+        goto err;
+    }
+    /* Encode the DER encoding of an X509 structure, reserve 3 bytes for length */
+    tmp = encbuf;
+    l2n3(ebuflen, tmp);
+    ebuflen = i2d_X509(enc_cert, &tmp);
+    if (ebuflen < 0) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLCP_CONSTRUCT_SKE_SM2ECC,
+                 ERR_R_BUF_LIB);
+        goto err;
+    }
+    ebuflen += 3;
+
+    siglen = EVP_PKEY_size(sign_pkey);
+    if (!WPACKET_sub_reserve_bytes_u16(pkt, siglen, &sigbytes1)
+        || EVP_DigestSignInit(md_ctx, &pctx, md, NULL, sign_pkey) <= 0) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                    SSL_F_TLCP_CONSTRUCT_SKE_SM2ECC,
+                    ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+    /* 
+     * As described by TLCP, client_random, server_random and encryption
+     * certificate are signed.
+     */
+    tbslen = construct_key_exchange_tbs(s, &tbs, encbuf, ebuflen);
+    if (tbslen == 0) {
+        goto err;
+    }
+
+    rv = EVP_DigestSign(md_ctx, sigbytes1, &siglen, tbs, tbslen);
+    
+    if (rv <= 0 || !WPACKET_sub_allocate_bytes_u16(pkt, siglen, &sigbytes2)
+        || sigbytes1 != sigbytes2) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                    SSL_F_TLCP_CONSTRUCT_SKE_SM2ECC,
+                    ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+err:
+    OPENSSL_free(encbuf);
+    OPENSSL_free(tbs);
+    EVP_MD_CTX_free(md_ctx);
+    return rv;
+}
+
+static int tlcp_construct_ske_sm2dhe(SSL *s, WPACKET *pkt)
+{
+    EVP_PKEY_CTX *ctx;
+    EVP_PKEY *pkey;
+    EVP_MD_CTX *md_ctx = NULL;
+    unsigned char *pt;
+    int ptLen;
+    char *id = "1234567812345678";
+    unsigned char *ecparam;
+    size_t ecparam_len = 0;
+    int ret = 0;
+    size_t siglen;
+    unsigned char *sig;
+    
+    ecparam = WPACKET_get_curr(pkt);
+
+    // ECParam: NameCurved, curvedtype {NameCurved(3), curveid(41, rfc8898 defined, but this msg is ignored)
+    if (!WPACKET_put_bytes_u8(pkt, NAMED_CURVE_TYPE)
+            || !WPACKET_put_bytes_u8(pkt, 0)
+            || !WPACKET_put_bytes_u8(pkt, 41)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLCP_CONSTRUCT_SKE_SM2DHE,
+                 ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    pkey = s->cert->pkeys[SSL_PKEY_SM2_SIGN].privatekey;
+    if (pkey == NULL) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLCP_CONSTRUCT_SKE_SM2DHE,
+                 ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    if (s->s3->tmp.pkey != NULL) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLCP_CONSTRUCT_SKE_SM2DHE,
+                 ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+    s->s3->tmp.pkey = ssl_generate_pkey_group(s, 41);
+    if (s->s3->tmp.pkey == NULL) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLCP_CONSTRUCT_SKE_SM2DHE,
+                 ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    ptLen = EVP_PKEY_get1_tls_encodedpoint(s->s3->tmp.pkey, &pt);
+    if (ptLen == 0) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLCP_CONSTRUCT_SKE_SM2DHE,
+                 ERR_R_EC_LIB);
+        return 0;
+    }
+
+    if (!WPACKET_sub_memcpy_u8(pkt, pt, ptLen)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLCP_CONSTRUCT_SKE_SM2DHE,
+                 ERR_R_INTERNAL_ERROR);
+        OPENSSL_free(pt);
+        return 0;
+    }
+    OPENSSL_free(pt);
+    ecparam_len = WPACKET_get_curr(pkt) - ecparam;
+
+    if (!EVP_PKEY_is_sm2(pkey) || !EVP_PKEY_set_alias_type(pkey, EVP_PKEY_SM2)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLCP_CONSTRUCT_SKE_SM2DHE,
+                 ERR_R_EC_LIB);
+        goto err;
+    }
+
+    md_ctx = EVP_MD_CTX_new();
+    if (md_ctx == NULL) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLCP_CONSTRUCT_SKE_SM2DHE,
+                 ERR_R_MALLOC_FAILURE);
+        return 0;
+    }
+
+    if (EVP_DigestSignInit(md_ctx, &ctx, EVP_sm3(), NULL, pkey) <= 0) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLCP_CONSTRUCT_SKE_SM2DHE,
+                 ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+
+    if (EVP_PKEY_CTX_set1_id(ctx, id, strlen(id)) <= 0) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLCP_CONSTRUCT_SKE_SM2DHE,
+                 ERR_R_EC_LIB);
+        return 0;
+    }
+
+    if (EVP_DigestSignUpdate(md_ctx, s->s3->client_random, SSL3_RANDOM_SIZE) <= 0 
+        || EVP_DigestSignUpdate(md_ctx, s->s3->server_random, SSL3_RANDOM_SIZE) <= 0
+        || EVP_DigestSignUpdate(md_ctx, ecparam, ecparam_len) <= 0
+    ) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLCP_CONSTRUCT_SKE_SM2DHE,
+                 ERR_R_EVP_LIB);
+        goto err;
+    }
+
+    if ((siglen = EVP_PKEY_size(pkey)) <= 0) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLCP_CONSTRUCT_SKE_SM2DHE,
+                 ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+
+    if (!WPACKET_sub_reserve_bytes_u16(pkt, siglen, &sig)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLCP_CONSTRUCT_SKE_SM2DHE,
+                 ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+
+    if (EVP_DigestSignFinal(md_ctx, sig, &siglen) <= 0) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLCP_CONSTRUCT_SKE_SM2DHE,
+                 SSL_R_SIGNATURE_ALGORITHMS_ERROR);
+        goto err;
+    }
+
+    unsigned char* sig2 = NULL;
+    if (!WPACKET_sub_allocate_bytes_u16(pkt, siglen, &sig2) || sig != sig2) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLCP_CONSTRUCT_SKE_SM2DHE,
+                 ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+
+    ret = 1;
+
+err:
+    EVP_MD_CTX_free(md_ctx);
+    if (!ret && s->s3->tmp.pkey) {
+        EVP_PKEY_free(s->s3->tmp.pkey);
+        s->s3->tmp.pkey = NULL;
+    }
+
+    return ret;
+}
+
+static int tlcp_construct_server_key_exchange(SSL *s, WPACKET *pkt)
+{
+    unsigned long alg_k;
+
+    alg_k = s->s3->tmp.new_cipher->algorithm_mkey;
+
+    if (alg_k & SSL_kSM2ECC) {
+        if (!tlcp_construct_ske_sm2ecc(s, pkt))
+            goto err;
+    } else if (alg_k & SSL_kSM2DHE) {
+        if (!tlcp_construct_ske_sm2dhe(s, pkt))
+            goto err;
+    } else {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                 SSL_F_TLCP_CONSTRUCT_SERVER_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+
+    return 1;
+err:
+    return 0;
+}
+#endif
+
 int tls_construct_server_key_exchange(SSL *s, WPACKET *pkt)
 {
+#ifndef OPENSSL_NO_TLCP
+    if (SSL_IS_TLCP(s))
+        return tlcp_construct_server_key_exchange(s, pkt);
+#endif
 #ifndef OPENSSL_NO_DH
     EVP_PKEY *pkdh = NULL;
 #endif
@@ -3455,8 +3732,174 @@ static int tls_process_cke_gost(SSL *s, PACKET *pkt)
 #endif
 }
 
+#ifndef OPENSSL_NO_TLCP
+static int tlcp_process_cke_sm2ecc(SSL *s, PACKET *pkt)
+{
+    EVP_PKEY_CTX *pctx = NULL;
+    int ret = 0;
+
+    unsigned char premaster_secret[SSL_MAX_MASTER_KEY_LENGTH];
+    EVP_PKEY *enc_prv_pkey;
+    PACKET enc_premaster;
+    size_t decrypt_len;
+
+    enc_prv_pkey = s->cert->pkeys[SSL_PKEY_SM2_ENC].privatekey;
+    if (enc_prv_pkey == NULL || !EVP_PKEY_is_sm2(enc_prv_pkey)
+        || !EVP_PKEY_set_alias_type(enc_prv_pkey, EVP_PKEY_SM2)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLCP_PROCESS_CKE_SM2ECC,
+                 SSL_R_NO_PRIVATE_KEY_ASSIGNED);
+        return 0;
+    }
+
+    if (!PACKET_get_length_prefixed_2(pkt, &enc_premaster)
+        || PACKET_remaining(pkt) != 0) {
+        SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLCP_PROCESS_CKE_SM2ECC,
+                    SSL_R_LENGTH_MISMATCH);
+        return 0;
+    }
+
+    pctx = EVP_PKEY_CTX_new(enc_prv_pkey, NULL);
+    if (pctx == NULL || EVP_PKEY_decrypt_init(pctx) <= 0) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLCP_PROCESS_CKE_SM2ECC,
+                 ERR_R_EVP_LIB);
+        goto err;
+    }
+
+    /* Decrypt premaster secret { client_version, random[46] }*/
+    decrypt_len = sizeof(premaster_secret);
+    if (EVP_PKEY_decrypt(pctx, premaster_secret, &decrypt_len,
+        PACKET_data(&enc_premaster), PACKET_remaining(&enc_premaster)) <= 0) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLCP_PROCESS_CKE_SM2ECC,
+                 ERR_R_EVP_LIB);
+        goto err;
+    }
+    if (decrypt_len != SSL_MAX_MASTER_KEY_LENGTH) {
+        SSLfatal(s, SSL_AD_DECRYPT_ERROR, SSL_F_TLCP_PROCESS_CKE_SM2ECC,
+                    SSL_R_DECRYPTION_FAILED);
+        goto err;
+    }
+
+    /* Check client version */
+    if (constant_time_eq_8(premaster_secret[0], (unsigned)(s->client_version >> 8)) == 0 ||
+        constant_time_eq_8(premaster_secret[1], (unsigned)(s->client_version & 0xff)) == 0) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLCP_PROCESS_CKE_SM2ECC,
+                ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+
+    if (!ssl_generate_master_secret(s, premaster_secret,
+                                    sizeof(premaster_secret), 0)) {
+        /* SSLfatal() already called */
+        goto err;
+    }
+
+    ret = 1;
+ err:
+    OPENSSL_cleanse(premaster_secret, sizeof(premaster_secret));
+    EVP_PKEY_CTX_free(pctx);
+    return ret;
+}
+
+static int tlcp_process_cke_sm2dhe(SSL *s, PACKET *pkt)
+{
+    int ret = 0;
+    const unsigned char *ecparams;
+    PACKET pt_encoded;
+    EVP_PKEY *skey;
+    EVP_PKEY *ckey = NULL;
+
+    if ((skey = s->s3->tmp.pkey) == NULL) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLCP_PROCESS_CKE_SM2DHE,
+                 ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    if (!PACKET_get_bytes(pkt, &ecparams, 3)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLCP_PROCESS_CKE_SM2DHE,
+                 SSL_R_LENGTH_TOO_SHORT);
+        goto end;
+    }
+
+    if (!PACKET_get_length_prefixed_1(pkt, &pt_encoded)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLCP_PROCESS_CKE_SM2DHE,
+                 SSL_R_LENGTH_TOO_SHORT);
+        goto end;
+    }
+
+    if (PACKET_remaining(pkt) != 0) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLCP_PROCESS_CKE_SM2DHE,
+                 SSL_R_LENGTH_TOO_LONG);
+        goto end;
+    }
+
+    if ((ckey = EVP_PKEY_new()) == NULL) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLCP_PROCESS_CKE_SM2DHE,
+                 ERR_R_MALLOC_FAILURE);
+        goto end;
+    }
+
+    if (EVP_PKEY_copy_parameters(ckey, skey) <= 0) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLCP_PROCESS_CKE_SM2DHE,
+                 ERR_R_INTERNAL_ERROR);
+        goto end;
+    }
+
+    if (EVP_PKEY_set1_tls_encodedpoint(ckey, 
+            PACKET_data(&pt_encoded), PACKET_remaining(&pt_encoded)) <= 0) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLCP_PROCESS_CKE_SM2DHE,
+                 ERR_R_EC_LIB);
+        goto end;
+    }
+
+    if (!tlcp_derive(s, skey, ckey)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLCP_PROCESS_CKE_SM2DHE,
+                 ERR_R_INTERNAL_ERROR);
+        goto end;
+    }
+
+    ret = 1;
+
+end:
+    EVP_PKEY_free(ckey);
+    EVP_PKEY_free(skey);
+    s->s3->tmp.pkey = NULL;
+
+    return ret;
+}
+
+static MSG_PROCESS_RETURN tlcp_process_client_key_exchange(SSL *s, PACKET *pkt)
+{
+    unsigned long alg_k;
+
+    alg_k = s->s3->tmp.new_cipher->algorithm_mkey;
+
+    if (alg_k & SSL_kSM2ECC) {
+        if (!tlcp_process_cke_sm2ecc(s, pkt)) {
+            goto err;
+        }
+    } else if (alg_k & SSL_kSM2DHE) {
+        if (!tlcp_process_cke_sm2dhe(s, pkt)) {
+            goto err;
+        }
+    } else {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                 SSL_F_TLCP_PROCESS_CLIENT_KEY_EXCHANGE,
+                 SSL_R_UNKNOWN_CIPHER_TYPE);
+        goto err;
+    }
+
+    return MSG_PROCESS_CONTINUE_PROCESSING;
+err:
+    return MSG_PROCESS_ERROR;
+}
+#endif
+
 MSG_PROCESS_RETURN tls_process_client_key_exchange(SSL *s, PACKET *pkt)
 {
+#ifndef OPENSSL_NO_TLCP
+    if (SSL_IS_TLCP(s))
+        return tlcp_process_client_key_exchange(s, pkt);
+#endif
     unsigned long alg_k;
 
     alg_k = s->s3->tmp.new_cipher->algorithm_mkey;
diff --git a/ssl/t1_enc.c b/ssl/t1_enc.c
index c85c0b0..e86a663 100644
--- a/ssl/t1_enc.c
+++ b/ssl/t1_enc.c
@@ -676,3 +676,87 @@ int tls1_alert_code(int code)
         return -1;
     }
 }
+
+#ifndef OPENSSL_NO_TLCP
+int tlcp_alert_code(int code)
+{
+    switch (code) {
+    case SSL_AD_CLOSE_NOTIFY:
+        return (SSL3_AD_CLOSE_NOTIFY);
+    case SSL_AD_UNEXPECTED_MESSAGE:
+        return (SSL3_AD_UNEXPECTED_MESSAGE);
+    case SSL_AD_BAD_RECORD_MAC:
+        return (SSL3_AD_BAD_RECORD_MAC);
+    case SSL_AD_DECRYPTION_FAILED:
+        return (TLS1_AD_DECRYPTION_FAILED);
+    case SSL_AD_RECORD_OVERFLOW:
+        return (TLS1_AD_RECORD_OVERFLOW);
+    case SSL_AD_DECOMPRESSION_FAILURE:
+        return (SSL3_AD_DECOMPRESSION_FAILURE);
+    case SSL_AD_HANDSHAKE_FAILURE:
+        return (SSL3_AD_HANDSHAKE_FAILURE);
+    case SSL_AD_BAD_CERTIFICATE:
+        return (SSL3_AD_BAD_CERTIFICATE);
+    case SSL_AD_UNSUPPORTED_CERTIFICATE:
+        return (SSL3_AD_UNSUPPORTED_CERTIFICATE);
+    case SSL_AD_CERTIFICATE_REVOKED:
+        return (SSL3_AD_CERTIFICATE_REVOKED);
+    case SSL_AD_CERTIFICATE_EXPIRED:
+        return (SSL3_AD_CERTIFICATE_EXPIRED);
+    case SSL_AD_CERTIFICATE_UNKNOWN:
+        return (SSL3_AD_CERTIFICATE_UNKNOWN);
+    case SSL_AD_ILLEGAL_PARAMETER:
+        return (SSL3_AD_ILLEGAL_PARAMETER);
+    case SSL_AD_UNKNOWN_CA:
+        return (TLS1_AD_UNKNOWN_CA);
+    case SSL_AD_ACCESS_DENIED:
+        return (TLS1_AD_ACCESS_DENIED);
+    case SSL_AD_DECODE_ERROR:
+        return (TLS1_AD_DECODE_ERROR);
+    case SSL_AD_DECRYPT_ERROR:
+        return (TLS1_AD_DECRYPT_ERROR);
+    case SSL_AD_EXPORT_RESTRICTION:
+        return (TLS1_AD_EXPORT_RESTRICTION);
+    case SSL_AD_PROTOCOL_VERSION:
+        return (TLS1_AD_PROTOCOL_VERSION);
+    case SSL_AD_INSUFFICIENT_SECURITY:
+        return (TLS1_AD_INSUFFICIENT_SECURITY);
+    case SSL_AD_INTERNAL_ERROR:
+        return (TLS1_AD_INTERNAL_ERROR);
+    case SSL_AD_USER_CANCELLED:
+        return (TLS1_AD_USER_CANCELLED);
+    case SSL_AD_NO_RENEGOTIATION:
+        return (TLS1_AD_NO_RENEGOTIATION);
+    case SSL_AD_UNSUPPORTED_EXTENSION:
+        return (TLS1_AD_UNSUPPORTED_EXTENSION);
+    case SSL_AD_CERTIFICATE_UNOBTAINABLE:
+        return (TLS1_AD_CERTIFICATE_UNOBTAINABLE);
+    case SSL_AD_UNRECOGNIZED_NAME:
+        return (TLS1_AD_UNRECOGNIZED_NAME);
+    case SSL_AD_BAD_CERTIFICATE_STATUS_RESPONSE:
+        return (TLS1_AD_BAD_CERTIFICATE_STATUS_RESPONSE);
+    case SSL_AD_BAD_CERTIFICATE_HASH_VALUE:
+        return (TLS1_AD_BAD_CERTIFICATE_HASH_VALUE);
+    case SSL_AD_INAPPROPRIATE_FALLBACK:
+        return (TLS1_AD_INAPPROPRIATE_FALLBACK);
+    case SSL_AD_NO_APPLICATION_PROTOCOL:
+        return (TLS1_AD_NO_APPLICATION_PROTOCOL);
+    case SSL_AD_CERTIFICATE_REQUIRED:
+        return (SSL_AD_HANDSHAKE_FAILURE);
+    case SSL_AD_UNSUPPORTED_SITE2SITE:
+        return (TLCP_AD_UNSUPPORTED_SITE2SITE);
+    case SSL_AD_NO_AREA:
+        return (TLCP_AD_NO_AREA);
+    case SSL_AD_UNSUPPORTED_AREATYPE:
+        return (TLCP_AD_UNSUPPORTED_AREATYPE);
+    case SSL_AD_BAD_IBCPARAM:
+        return (TLCP_AD_BAD_IBCPARAM);
+    case SSL_AD_UNSUPPORTED_IBCPARAM:
+        return (TLCP_AD_UNSUPPORTED_IBCPARAM);
+    case SSL_AD_IDENTITY_NEED:
+        return (TLCP_AD_IDENTITY_NEED);
+    default:
+        return (-1);
+    }
+}
+#endif
\ No newline at end of file
diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c
index 841feec..8b4a61b 100644
--- a/ssl/t1_lib.c
+++ b/ssl/t1_lib.c
@@ -93,6 +93,25 @@ SSL3_ENC_METHOD const TLSv1_3_enc_data = {
     ssl3_handshake_write
 };
 
+#ifndef OPENSSL_NO_TLCP
+SSL3_ENC_METHOD const TLCP_enc_data = {
+    tls1_enc,
+    tls1_mac,
+    tls1_setup_key_block,
+    tls1_generate_master_secret,
+    tls1_change_cipher_state,
+    tls1_final_finish_mac,
+    TLS_MD_CLIENT_FINISH_CONST, TLS_MD_CLIENT_FINISH_CONST_SIZE,
+    TLS_MD_SERVER_FINISH_CONST, TLS_MD_SERVER_FINISH_CONST_SIZE,
+    tlcp_alert_code,
+    tls1_export_keying_material,
+    SSL_ENC_FLAG_EXPLICIT_IV,
+    ssl3_set_handshake_header,
+    tls_close_construct_packet,
+    ssl3_handshake_write
+};
+#endif
+
 long tls1_default_timeout(void)
 {
     /*
@@ -169,6 +188,9 @@ static const TLS_GROUP_INFO nid_list[] = {
     {NID_brainpoolP512r1, 256, TLS_CURVE_PRIME}, /* brainpool512r1 (28) */
     {EVP_PKEY_X25519, 128, TLS_CURVE_CUSTOM}, /* X25519 (29) */
     {EVP_PKEY_X448, 224, TLS_CURVE_CUSTOM}, /* X448 (30) */
+#ifndef OPENSSL_NO_TLCP
+    [40] = {EVP_PKEY_SM2, 128, TLS_CURVE_PRIME} /* sm2 (41) */
+#endif
 };
 
 static const unsigned char ecformats_default[] = {
@@ -184,6 +206,9 @@ static const uint16_t eccurves_default[] = {
     30,                      /* X448 (30) */
     25,                      /* secp521r1 (25) */
     24,                      /* secp384r1 (24) */
+#ifndef OPENSSL_NO_TLCP
+    41,                      /* sm2 (41) */
+#endif
 };
 
 static const uint16_t suiteb_curves[] = {
@@ -260,6 +285,12 @@ int tls_curve_allowed(SSL *s, uint16_t curve, int op)
 # endif
     if (FIPS_mode() && !(cinfo->flags & TLS_CURVE_FIPS))
         return 0;
+#ifndef OPENSSL_NO_TLCP
+    // SM2 is only allowed in TLCP
+    if (s->version != TLCP_VERSION && cinfo->nid == NID_sm2) {
+        return 0;
+    }
+#endif
     ctmp[0] = curve >> 8;
     ctmp[1] = curve & 0xff;
     return ssl_security(s, op, cinfo->secbits, cinfo->nid, (void *)ctmp);
@@ -547,6 +578,10 @@ void tls1_get_formatlist(SSL *s, const unsigned char **pformats,
         /* For Suite B we don't support char2 fields */
         if (tls1_suiteb(s))
             *num_formats = sizeof(ecformats_default) - 1;
+#ifndef OPENSSL_NO_TLCP
+        else if (SSL_IS_TLCP(s))    // TLCP version only support uncompressed
+            *num_formats = sizeof(ecformats_default) - 2;
+#endif
         else
             *num_formats = sizeof(ecformats_default);
     }
@@ -639,6 +674,9 @@ static int tls1_check_cert_param(SSL *s, X509 *x, int set_ee_md)
 /* Default sigalg schemes */
 static const uint16_t tls12_sigalgs[] = {
 #ifndef OPENSSL_NO_EC
+#ifndef OPENSSL_NO_TLCP
+    TLSEXT_SIGALG_sm2dsa_sm3,
+#endif
     TLSEXT_SIGALG_ecdsa_secp256r1_sha256,
     TLSEXT_SIGALG_ecdsa_secp384r1_sha384,
     TLSEXT_SIGALG_ecdsa_secp521r1_sha512,
@@ -687,6 +725,11 @@ static const uint16_t suiteb_sigalgs[] = {
 
 static const SIGALG_LOOKUP sigalg_lookup_tbl[] = {
 #ifndef OPENSSL_NO_EC
+#ifndef OPENSSL_NO_TLCP
+    {"sm2dsa_sm3", TLSEXT_SIGALG_sm2dsa_sm3,
+     NID_sm3, SSL_MD_SM3_IDX, EVP_PKEY_SM2, SSL_PKEY_SM2_SIGN,
+     NID_SM2_with_SM3, NID_sm2},
+#endif
     {"ecdsa_secp256r1_sha256", TLSEXT_SIGALG_ecdsa_secp256r1_sha256,
      NID_sha256, SSL_MD_SHA256_IDX, EVP_PKEY_EC, SSL_PKEY_ECC,
      NID_ecdsa_with_SHA256, NID_X9_62_prime256v1},
@@ -796,6 +839,10 @@ static const uint16_t tls_default_sigalg[] = {
     TLSEXT_SIGALG_gostr34102012_512_gostr34112012_512, /* SSL_PKEY_GOST12_512 */
     0, /* SSL_PKEY_ED25519 */
     0, /* SSL_PKEY_ED448 */
+#ifndef OPENSSL_NO_TLCP
+    TLSEXT_SIGALG_sm2dsa_sm3, /* SSL_PKEY_SM2_SIGN */
+    0, /* SSL_PKEY_SM2_ENC */
+#endif
 };
 
 /* Lookup TLS signature algorithm */
@@ -983,7 +1030,7 @@ int tls_check_sigalg_curve(const SSL *s, int curve)
 
         if (lu == NULL)
             continue;
-        if (lu->sig == EVP_PKEY_EC
+        if ((lu->sig == EVP_PKEY_EC || lu->sig == EVP_PKEY_SM2)
                 && lu->curve != NID_undef
                 && curve == lu->curve)
             return 1;
@@ -1055,6 +1102,9 @@ int tls12_check_peer_sigalg(SSL *s, uint16_t sig, EVP_PKEY *pkey)
     if (lu == NULL
         || (SSL_IS_TLS13(s) && (lu->hash == NID_sha1 || lu->hash == NID_sha224))
         || (pkeyid != lu->sig
+#ifndef OPENSSL_NO_TCLP
+        && (lu->sig != EVP_PKEY_SM2)
+#endif
         && (lu->sig != EVP_PKEY_RSA_PSS || pkeyid != EVP_PKEY_RSA))) {
         SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_F_TLS12_CHECK_PEER_SIGALG,
                  SSL_R_WRONG_SIGNATURE_TYPE);
@@ -1199,6 +1249,13 @@ int ssl_set_client_disabled(SSL *s)
         s->s3->tmp.mask_a |= SSL_aSRP;
         s->s3->tmp.mask_k |= SSL_kSRP;
     }
+#endif
+#ifndef OPENSSL_NO_TLCP
+    /* TLCP ciphersuites will be disabled while using other protocols */
+    if (s->version != TLCP_VERSION) {
+        s->s3->tmp.mask_a |= SSL_aSM2;
+        s->s3->tmp.mask_k |= SSL_kSM2ECC | SSL_kSM2DHE;
+    }
 #endif
     return 1;
 }
@@ -1319,7 +1376,11 @@ SSL_TICKET_STATUS tls_get_ticket_from_client(SSL *s, CLIENTHELLO_MSG *hello,
      * (e.g. TLSv1.3) behave as if no ticket present to permit stateful
      * resumption.
      */
+#ifndef OPENSSL_NO_TLCP
+    if ((s->version <= SSL3_VERSION && s->version != TLCP_VERSION) || !tls_use_ticket(s))
+#else
     if (s->version <= SSL3_VERSION || !tls_use_ticket(s))
+#endif
         return SSL_TICKET_NONE;
 
     ticketext = &hello->pre_proc_exts[TLSEXT_IDX_session_ticket];
@@ -1597,6 +1658,13 @@ static int tls12_sigalg_allowed(const SSL *s, int op, const SIGALG_LOOKUP *lu)
     unsigned char sigalgstr[2];
     int secbits;
 
+#ifndef OPENSSL_NO_TLCP
+    // SM2 is only allowed in TLCP
+    if (s->version != TLCP_VERSION && lu != NULL && lu->sig == EVP_PKEY_SM2) {
+        return 0;
+    }
+#endif
+
     /* See if sigalgs is recognised and if hash is enabled */
     if (!tls1_lookup_md(lu, NULL))
         return 0;
@@ -2430,6 +2498,10 @@ void tls1_set_cert_validity(SSL *s)
     tls1_check_chain(s, NULL, NULL, NULL, SSL_PKEY_GOST12_512);
     tls1_check_chain(s, NULL, NULL, NULL, SSL_PKEY_ED25519);
     tls1_check_chain(s, NULL, NULL, NULL, SSL_PKEY_ED448);
+#ifndef OPENSSL_NO_TLCP
+    tls1_check_chain(s, NULL, NULL, NULL, SSL_PKEY_SM2_ENC);
+    tls1_check_chain(s, NULL, NULL, NULL, SSL_PKEY_SM2_SIGN);
+#endif
 }
 
 /* User level utility function to check a chain is suitable */
@@ -2734,6 +2806,55 @@ static const SIGALG_LOOKUP *find_sig_alg(SSL *s, X509 *x, EVP_PKEY *pkey)
     return lu;
 }
 
+#ifndef OPENSSL_NO_TLCP
+int tlcp_choose_sigalg(SSL *s, int fatalerrs)
+{
+    int sig_idx;
+    const SIGALG_LOOKUP *lu = NULL;
+
+    // sever must used sm2dsa cert for signature
+    if (s->server) {
+        s->cert->key = &(s->cert->pkeys[SSL_PKEY_SM2_SIGN]);
+    }
+
+    sig_idx = s->cert->key - s->cert->pkeys;
+
+    // check cert is existed
+    if (!ssl_has_cert(s, sig_idx)) {
+        if (!fatalerrs)
+            return 1;
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLCP_CHOOSE_SIGALG,
+                         ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    // only support sm2dsa cert now
+    switch(sig_idx) {
+        case SSL_PKEY_ECC:
+            if (!EVP_PKEY_is_sm2(s->cert->key->privatekey))
+                break;
+        case SSL_PKEY_SM2_SIGN:
+            lu = tls1_lookup_sigalg(TLSEXT_SIGALG_sm2dsa_sm3);
+            break;
+        default:
+            lu = NULL;
+    }
+
+    if (lu == NULL) {
+        if (!fatalerrs)
+            return 1;
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLCP_CHOOSE_SIGALG,
+                         ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    s->s3->tmp.cert = &s->cert->pkeys[sig_idx];
+    s->cert->key = s->s3->tmp.cert;
+    s->s3->tmp.sigalg = lu;
+    return 1;
+}
+#endif
+
 /*
  * Choose an appropriate signature algorithm based on available certificates
  * Sets chosen certificate and signature algorithm.
@@ -2753,6 +2874,12 @@ int tls_choose_sigalg(SSL *s, int fatalerrs)
     s->s3->tmp.cert = NULL;
     s->s3->tmp.sigalg = NULL;
 
+#ifndef OPENSSL_NO_TLCP
+    if (SSL_IS_TLCP(s)) {
+        return tlcp_choose_sigalg(s, fatalerrs);
+    }
+#endif
+
     if (SSL_IS_TLS13(s)) {
         lu = find_sig_alg(s, NULL, NULL);
         if (lu == NULL) {
@@ -2766,6 +2893,7 @@ int tls_choose_sigalg(SSL *s, int fatalerrs)
         /* If ciphersuite doesn't require a cert nothing to do */
         if (!(s->s3->tmp.new_cipher->algorithm_auth & SSL_aCERT))
             return 1;
+
         if (!s->server && !ssl_has_cert(s, s->cert->key - s->cert->pkeys))
                 return 1;
 
diff --git a/test/build.info b/test/build.info
index 726bd22..db16a1f 100644
--- a/test/build.info
+++ b/test/build.info
@@ -51,7 +51,7 @@ INCLUDE_MAIN___test_libtestutil_OLB = /INCLUDE=MAIN
           recordlentest drbgtest drbg_cavs_test sslbuffertest \
           time_offset_test pemtest ssl_cert_table_internal_test ciphername_test \
           servername_test ocspapitest rsa_mp_test fatalerrtest tls13ccstest \
-          sysdefaulttest errtest ssl_ctx_test gosttest
+          sysdefaulttest errtest ssl_ctx_test gosttest tlcptest
 
   SOURCE[versions]=versions.c
   INCLUDE[versions]=../include
@@ -320,6 +320,10 @@ INCLUDE_MAIN___test_libtestutil_OLB = /INCLUDE=MAIN
   INCLUDE[dtlstest]=../include
   DEPEND[dtlstest]=../libcrypto ../libssl libtestutil.a
 
+  SOURCE[tlcptest]=tlcptest.c ssltestlib.c
+  INCLUDE[tlcptest]=.. ../include
+  DEPEND[tlcptest]=../libcrypto ../libssl libtestutil.a
+
   SOURCE[sslcorrupttest]=sslcorrupttest.c ssltestlib.c
   INCLUDE[sslcorrupttest]=../include
   DEPEND[sslcorrupttest]=../libcrypto ../libssl libtestutil.a
diff --git a/test/ciphername_test.c b/test/ciphername_test.c
index 303e28f..5c9edf4 100644
--- a/test/ciphername_test.c
+++ b/test/ciphername_test.c
@@ -434,6 +434,9 @@ static int test_cipher_name(void)
         if ((id == 0xFF85) || (id == 0xFF87))
             /* skip GOST2012-GOST8912-GOST891 and GOST2012-NULL-GOST12 */
             continue;
+        if ((id == 0xE011) || (id == 0xE013))
+            /* skip ECDHE_SM2_WITH_SM4_CBC_SM3 and ECC_SM2_WITH_SM4_CBC_SM3 */
+            continue;
         p = SSL_CIPHER_standard_name(c);
         q = get_std_name_by_id(id);
         if (!TEST_ptr(p)) {
diff --git a/test/recipes/85-test_tlcp.t b/test/recipes/85-test_tlcp.t
new file mode 100644
index 0000000..eb87123
--- /dev/null
+++ b/test/recipes/85-test_tlcp.t
@@ -0,0 +1,34 @@
+#! /usr/bin/env perl
+# Copyright 2022 Huawei Technologies Co., Ltd. All Rights Reserved.
+#
+# Licensed under the OpenSSL license (the "License").  You may not use
+# this file except in compliance with the License.  You can obtain a copy
+# in the file LICENSE in the source distribution or at
+# https://www.openssl.org/source/license.html
+
+use OpenSSL::Test::Utils;
+use OpenSSL::Test qw/:DEFAULT data_file/;
+
+setup("test_tlcp");
+
+plan skip_all => "TLCP is not supported by this OpenSSL build"
+    if disabled("tlcp");
+
+plan tests => 1;
+
+ok(run(test(["tlcptest",
+            data_file("sm2-root-cert.pem"),             # 0
+            data_file("sm2-server-sig-cert.pem"),       # 1
+            data_file("sm2-server-sig-key.pem"),        # 2
+            data_file("sm2-server-enc-cert.pem"),       # 3
+            data_file("sm2-server-enc-key.pem"),        # 4
+            data_file("sm2-client-sig-cert.pem"),       # 5
+            data_file("sm2-client-sig-key.pem"),        # 6
+            data_file("sm2-client-enc-cert.pem"),       # 7
+            data_file("sm2-client-enc-key.pem"),        # 8
+            data_file("ecdsa-root-cert.pem"),           # 9
+            data_file("ecdsa-server-cert.pem"),         # 10
+            data_file("ecdsa-server-key.pem"),          # 11
+            data_file("ecdsa-client-cert.pem"),         # 12
+            data_file("ecdsa-client-key.pem")           # 13
+            ])));
\ No newline at end of file
diff --git a/test/recipes/85-test_tlcp_data/ecdsa-client-cert.pem b/test/recipes/85-test_tlcp_data/ecdsa-client-cert.pem
new file mode 100644
index 0000000..4f41232
--- /dev/null
+++ b/test/recipes/85-test_tlcp_data/ecdsa-client-cert.pem
@@ -0,0 +1,12 @@
+-----BEGIN CERTIFICATE-----
+MIIB2zCCAYGgAwIBAgIUIxUR+f5s2IPkP5kd86umC0jtOy0wCgYIKoZIzj0EAwIw
+YDELMAkGA1UEBhMCQ04xEjAQBgNVBAgMCUd1YW5nZG9uZzERMA8GA1UECgwIVGVz
+dCBPcmcxEDAOBgNVBAsMB1Rlc3QgT1UxGDAWBgNVBAMMD1Rlc3QgQ0EgKEVDRFNB
+KTAeFw0yMjA1MTkwOTI3MTVaFw0yNjA2MjcwOTI3MTVaMF8xCzAJBgNVBAYTAkNO
+MRIwEAYDVQQIDAlHdWFuZ2RvbmcxETAPBgNVBAoMCFRlc3QgT3JnMRAwDgYDVQQL
+DAdUZXN0IE9VMRcwFQYDVQQDDA5jbGllbnQgKEVDRFNBKTBZMBMGByqGSM49AgEG
+CCqGSM49AwEHA0IABJg2jl8qqQkLHwcqKC+gu8SWpDNHl8x2xSlsNkS8hm2edlsJ
+5QHfMPw7b138CmEE2FEtMqCtpRtsQnb5JRcxfTajGjAYMAkGA1UdEwQCMAAwCwYD
+VR0PBAQDAgbAMAoGCCqGSM49BAMCA0gAMEUCICBPe4rSKQdIWdB3u8EZ9+AR6Slu
+wsqdPm8p2mE409x4AiEAx513RsVDYohfejrvJmEL9ELIHmqTHjX+WjTjfMR/qrY=
+-----END CERTIFICATE-----
diff --git a/test/recipes/85-test_tlcp_data/ecdsa-client-key.pem b/test/recipes/85-test_tlcp_data/ecdsa-client-key.pem
new file mode 100644
index 0000000..8a356ba
--- /dev/null
+++ b/test/recipes/85-test_tlcp_data/ecdsa-client-key.pem
@@ -0,0 +1,5 @@
+-----BEGIN PRIVATE KEY-----
+MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgj/hA8kscmW1VDMMn
+jWDNu/JrGrZ5Xr1kH0Q61zpRhIShRANCAASYNo5fKqkJCx8HKigvoLvElqQzR5fM
+dsUpbDZEvIZtnnZbCeUB3zD8O29d/AphBNhRLTKgraUbbEJ2+SUXMX02
+-----END PRIVATE KEY-----
diff --git a/test/recipes/85-test_tlcp_data/ecdsa-root-cert.pem b/test/recipes/85-test_tlcp_data/ecdsa-root-cert.pem
new file mode 100644
index 0000000..80d8c06
--- /dev/null
+++ b/test/recipes/85-test_tlcp_data/ecdsa-root-cert.pem
@@ -0,0 +1,14 @@
+-----BEGIN CERTIFICATE-----
+MIICHzCCAcWgAwIBAgIUcxkoWsrQfKvdPzNFeZt9sUACCv8wCgYIKoZIzj0EAwIw
+YDELMAkGA1UEBhMCQ04xEjAQBgNVBAgMCUd1YW5nZG9uZzERMA8GA1UECgwIVGVz
+dCBPcmcxEDAOBgNVBAsMB1Rlc3QgT1UxGDAWBgNVBAMMD1Rlc3QgQ0EgKEVDRFNB
+KTAeFw0yMjA1MTkwOTI3MTVaFw0yNjA2MjcwOTI3MTVaMGAxCzAJBgNVBAYTAkNO
+MRIwEAYDVQQIDAlHdWFuZ2RvbmcxETAPBgNVBAoMCFRlc3QgT3JnMRAwDgYDVQQL
+DAdUZXN0IE9VMRgwFgYDVQQDDA9UZXN0IENBIChFQ0RTQSkwWTATBgcqhkjOPQIB
+BggqhkjOPQMBBwNCAAQb8M+p/ywfaaLb6y5jP/6essKMw+HBYIzluA8JpAyuSEag
+hiiIegi/fJA9tONUKGGQrE92gFIjsyrGvwPnYqF1o10wWzAdBgNVHQ4EFgQU+BnE
+9UFgm03egYusuG7wtBeF12kwHwYDVR0jBBgwFoAU+BnE9UFgm03egYusuG7wtBeF
+12kwDAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMCAQYwCgYIKoZIzj0EAwIDSAAwRQIh
+AO3LVs9OBinihB4W22ju3zoqfXTtHGdF0d9nbHbZEYqdAiAum1ZhMbtyWo/3YLDR
+2DqMuw5al5FbOlCIwrMbqcL+qQ==
+-----END CERTIFICATE-----
diff --git a/test/recipes/85-test_tlcp_data/ecdsa-server-cert.pem b/test/recipes/85-test_tlcp_data/ecdsa-server-cert.pem
new file mode 100644
index 0000000..7e0d8d7
--- /dev/null
+++ b/test/recipes/85-test_tlcp_data/ecdsa-server-cert.pem
@@ -0,0 +1,12 @@
+-----BEGIN CERTIFICATE-----
+MIIB2zCCAYGgAwIBAgIUIxUR+f5s2IPkP5kd86umC0jtOywwCgYIKoZIzj0EAwIw
+YDELMAkGA1UEBhMCQ04xEjAQBgNVBAgMCUd1YW5nZG9uZzERMA8GA1UECgwIVGVz
+dCBPcmcxEDAOBgNVBAsMB1Rlc3QgT1UxGDAWBgNVBAMMD1Rlc3QgQ0EgKEVDRFNB
+KTAeFw0yMjA1MTkwOTI3MTVaFw0yNjA2MjcwOTI3MTVaMF8xCzAJBgNVBAYTAkNO
+MRIwEAYDVQQIDAlHdWFuZ2RvbmcxETAPBgNVBAoMCFRlc3QgT3JnMRAwDgYDVQQL
+DAdUZXN0IE9VMRcwFQYDVQQDDA5zZXJ2ZXIgKEVDRFNBKTBZMBMGByqGSM49AgEG
+CCqGSM49AwEHA0IABAAmT2rADtfh1M/AW6n3cgLm2kEq/StWWcFDQ/AmTz54nFMp
+9AHt7xAqnizKl2UcdzUcDbhyBeNwjZ+80Eavvx2jGjAYMAkGA1UdEwQCMAAwCwYD
+VR0PBAQDAgbAMAoGCCqGSM49BAMCA0gAMEUCIQC70m1KUdKAsLI8zq78azjV2r/Z
+Oc6vwXfAqLKgF7EhtQIgYvh0XrMU9ETKKbfHORqJK+BD9DmFnAkxNpc9KVmN/D8=
+-----END CERTIFICATE-----
diff --git a/test/recipes/85-test_tlcp_data/ecdsa-server-key.pem b/test/recipes/85-test_tlcp_data/ecdsa-server-key.pem
new file mode 100644
index 0000000..9d9af8d
--- /dev/null
+++ b/test/recipes/85-test_tlcp_data/ecdsa-server-key.pem
@@ -0,0 +1,5 @@
+-----BEGIN PRIVATE KEY-----
+MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgqMLQcziYtVwg+30u
+MvCIb3bYAfxAazvxQ8I69Jtml9uhRANCAAQAJk9qwA7X4dTPwFup93IC5tpBKv0r
+VlnBQ0PwJk8+eJxTKfQB7e8QKp4sypdlHHc1HA24cgXjcI2fvNBGr78d
+-----END PRIVATE KEY-----
diff --git a/test/recipes/85-test_tlcp_data/sm2-client-enc-cert.pem b/test/recipes/85-test_tlcp_data/sm2-client-enc-cert.pem
new file mode 100644
index 0000000..4a3e3f0
--- /dev/null
+++ b/test/recipes/85-test_tlcp_data/sm2-client-enc-cert.pem
@@ -0,0 +1,12 @@
+-----BEGIN CERTIFICATE-----
+MIIB2DCCAYCgAwIBAgIUMsQnTMiHshN4IOMc/ydgCOWB3WQwCgYIKoEcz1UBg3Uw
+XjELMAkGA1UEBhMCQ04xEjAQBgNVBAgMCUd1YW5nZG9uZzERMA8GA1UECgwIVGVz
+dCBPcmcxEDAOBgNVBAsMB1Rlc3QgT1UxFjAUBgNVBAMMDVRlc3QgQ0EgKFNNMikw
+HhcNMjIwNTE5MDkyNzEwWhcNMjYwNjI3MDkyNzEwWjBgMQswCQYDVQQGEwJDTjES
+MBAGA1UECAwJR3Vhbmdkb25nMREwDwYDVQQKDAhUZXN0IE9yZzEQMA4GA1UECwwH
+VGVzdCBPVTEYMBYGA1UEAwwPY2xpZW50IGVuYyhTTTIpMFkwEwYHKoZIzj0CAQYI
+KoEcz1UBgi0DQgAEsjxuZnSYi2M2iL4vUqHFdegJqxALkFxq+XiA/C8vQSMOCDaz
+8ZH1XrCwU3kMShiQyNM8AkjufKgCOGSB3B58qKMaMBgwCQYDVR0TBAIwADALBgNV
+HQ8EBAMCAzgwCgYIKoEcz1UBg3UDRgAwQwIgcwaVeJ3pa/WUuR28r9+tGRg2EIEO
+IOlzRUlo6mwqcDACHxugAc0CFsB1dUWLOJuwJtpYsEmNpNHwLzxa16cfW3w=
+-----END CERTIFICATE-----
diff --git a/test/recipes/85-test_tlcp_data/sm2-client-enc-key.pem b/test/recipes/85-test_tlcp_data/sm2-client-enc-key.pem
new file mode 100644
index 0000000..7a03991
--- /dev/null
+++ b/test/recipes/85-test_tlcp_data/sm2-client-enc-key.pem
@@ -0,0 +1,5 @@
+-----BEGIN PRIVATE KEY-----
+MIGHAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBG0wawIBAQQg5xwdNhYtjBcZ5YEd
+VNu5609rYpePHUZUlQvlAJIqMB2hRANCAASyPG5mdJiLYzaIvi9SocV16AmrEAuQ
+XGr5eID8Ly9BIw4INrPxkfVesLBTeQxKGJDI0zwCSO58qAI4ZIHcHnyo
+-----END PRIVATE KEY-----
diff --git a/test/recipes/85-test_tlcp_data/sm2-client-sig-cert.pem b/test/recipes/85-test_tlcp_data/sm2-client-sig-cert.pem
new file mode 100644
index 0000000..ce539a6
--- /dev/null
+++ b/test/recipes/85-test_tlcp_data/sm2-client-sig-cert.pem
@@ -0,0 +1,12 @@
+-----BEGIN CERTIFICATE-----
+MIIB3DCCAYKgAwIBAgIUMsQnTMiHshN4IOMc/ydgCOWB3WMwCgYIKoEcz1UBg3Uw
+XjELMAkGA1UEBhMCQ04xEjAQBgNVBAgMCUd1YW5nZG9uZzERMA8GA1UECgwIVGVz
+dCBPcmcxEDAOBgNVBAsMB1Rlc3QgT1UxFjAUBgNVBAMMDVRlc3QgQ0EgKFNNMikw
+HhcNMjIwNTE5MDkyNzEwWhcNMjYwNjI3MDkyNzEwWjBiMQswCQYDVQQGEwJDTjES
+MBAGA1UECAwJR3Vhbmdkb25nMREwDwYDVQQKDAhUZXN0IE9yZzEQMA4GA1UECwwH
+VGVzdCBPVTEaMBgGA1UEAwwRY2xpZW50IHNpZ24gKFNNMikwWTATBgcqhkjOPQIB
+BggqgRzPVQGCLQNCAAQDr0xTp4anFz8UHoMWyAWq/yYpiXdysF1dvciTvgET7CAA
+PydlOnKQw2K1NguwiecT4/XCpZMmbvhthMcCsyywoxowGDAJBgNVHRMEAjAAMAsG
+A1UdDwQEAwIGwDAKBggqgRzPVQGDdQNIADBFAiEA1pxw3tMJ6epz6r/wonHMWBE/
+3MBbRIsOq9xxhOhqhyECIBR0V+O51j3gsuDwSqSU81rYLXPaE0RGuhbdWOHi4bII
+-----END CERTIFICATE-----
diff --git a/test/recipes/85-test_tlcp_data/sm2-client-sig-key.pem b/test/recipes/85-test_tlcp_data/sm2-client-sig-key.pem
new file mode 100644
index 0000000..d2c537d
--- /dev/null
+++ b/test/recipes/85-test_tlcp_data/sm2-client-sig-key.pem
@@ -0,0 +1,5 @@
+-----BEGIN PRIVATE KEY-----
+MIGHAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBG0wawIBAQQg0x2USJzgAonYJeiQ
+VkBw/u6/uo6B9M88YVL3A1OmorKhRANCAAQDr0xTp4anFz8UHoMWyAWq/yYpiXdy
+sF1dvciTvgET7CAAPydlOnKQw2K1NguwiecT4/XCpZMmbvhthMcCsyyw
+-----END PRIVATE KEY-----
diff --git a/test/recipes/85-test_tlcp_data/sm2-root-cert.pem b/test/recipes/85-test_tlcp_data/sm2-root-cert.pem
new file mode 100644
index 0000000..a20df8c
--- /dev/null
+++ b/test/recipes/85-test_tlcp_data/sm2-root-cert.pem
@@ -0,0 +1,14 @@
+-----BEGIN CERTIFICATE-----
+MIICGjCCAcGgAwIBAgIUV3TWPlV09Vqm5/FpSqR7ryeGrfEwCgYIKoEcz1UBg3Uw
+XjELMAkGA1UEBhMCQ04xEjAQBgNVBAgMCUd1YW5nZG9uZzERMA8GA1UECgwIVGVz
+dCBPcmcxEDAOBgNVBAsMB1Rlc3QgT1UxFjAUBgNVBAMMDVRlc3QgQ0EgKFNNMikw
+HhcNMjIwNTE5MDkyNzEwWhcNMjYwNjI3MDkyNzEwWjBeMQswCQYDVQQGEwJDTjES
+MBAGA1UECAwJR3Vhbmdkb25nMREwDwYDVQQKDAhUZXN0IE9yZzEQMA4GA1UECwwH
+VGVzdCBPVTEWMBQGA1UEAwwNVGVzdCBDQSAoU00yKTBZMBMGByqGSM49AgEGCCqB
+HM9VAYItA0IABHsTJfkk1NiaYrPidOIQHCGWBs77fKEhXoG1uONGTfHEDhhhA3EX
+QZBL9cVO//farVmKF9ipYR9GA4pk0wHtGEKjXTBbMB0GA1UdDgQWBBQ9YT+D7/Cv
+3KqG4b9YxuWOSbMRRzAfBgNVHSMEGDAWgBQ9YT+D7/Cv3KqG4b9YxuWOSbMRRzAM
+BgNVHRMEBTADAQH/MAsGA1UdDwQEAwIBBjAKBggqgRzPVQGDdQNHADBEAiAOJ4al
+v3c1AHBohqZQkAAZsY9+LSH/3/e3C4Q4jQsDUQIgUDJFXbXSUrsMoKFmkvHONmz+
+9zGXND9ctJ1Dineo9dI=
+-----END CERTIFICATE-----
diff --git a/test/recipes/85-test_tlcp_data/sm2-server-enc-cert.pem b/test/recipes/85-test_tlcp_data/sm2-server-enc-cert.pem
new file mode 100644
index 0000000..c7a5ef2
--- /dev/null
+++ b/test/recipes/85-test_tlcp_data/sm2-server-enc-cert.pem
@@ -0,0 +1,12 @@
+-----BEGIN CERTIFICATE-----
+MIIB2jCCAYGgAwIBAgIUMsQnTMiHshN4IOMc/ydgCOWB3WIwCgYIKoEcz1UBg3Uw
+XjELMAkGA1UEBhMCQ04xEjAQBgNVBAgMCUd1YW5nZG9uZzERMA8GA1UECgwIVGVz
+dCBPcmcxEDAOBgNVBAsMB1Rlc3QgT1UxFjAUBgNVBAMMDVRlc3QgQ0EgKFNNMikw
+HhcNMjIwNTE5MDkyNzEwWhcNMjYwNjI3MDkyNzEwWjBhMQswCQYDVQQGEwJDTjES
+MBAGA1UECAwJR3Vhbmdkb25nMREwDwYDVQQKDAhUZXN0IE9yZzEQMA4GA1UECwwH
+VGVzdCBPVTEZMBcGA1UEAwwQc2VydmVyIGVuYyAoU00yKTBZMBMGByqGSM49AgEG
+CCqBHM9VAYItA0IABCWsJ/Vs/68DYkqIgoTdE8zoOA86UMHLASZriw+AF0lbmiOD
+dngO7RvDd55OOAmFK6sY7d+vzsIeMNQus4YLkc2jGjAYMAkGA1UdEwQCMAAwCwYD
+VR0PBAQDAgM4MAoGCCqBHM9VAYN1A0cAMEQCICZgP6OiaVyAbYTX5yJpiwusEvDU
+bMB/+hpnNA0ors3zAiB4EkZEBWZkd0su+umAXpO44IYaDvUumPSaGZLBbg7m1w==
+-----END CERTIFICATE-----
diff --git a/test/recipes/85-test_tlcp_data/sm2-server-enc-key.pem b/test/recipes/85-test_tlcp_data/sm2-server-enc-key.pem
new file mode 100644
index 0000000..ae509ec
--- /dev/null
+++ b/test/recipes/85-test_tlcp_data/sm2-server-enc-key.pem
@@ -0,0 +1,5 @@
+-----BEGIN PRIVATE KEY-----
+MIGHAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBG0wawIBAQQgE32DrOaCm3ai/cPZ
+/9nnxJoCH171qVL7ignjIrMBGdGhRANCAAQlrCf1bP+vA2JKiIKE3RPM6DgPOlDB
+ywEma4sPgBdJW5ojg3Z4Du0bw3eeTjgJhSurGO3fr87CHjDULrOGC5HN
+-----END PRIVATE KEY-----
diff --git a/test/recipes/85-test_tlcp_data/sm2-server-sig-cert.pem b/test/recipes/85-test_tlcp_data/sm2-server-sig-cert.pem
new file mode 100644
index 0000000..8238bad
--- /dev/null
+++ b/test/recipes/85-test_tlcp_data/sm2-server-sig-cert.pem
@@ -0,0 +1,12 @@
+-----BEGIN CERTIFICATE-----
+MIIB2zCCAYKgAwIBAgIUMsQnTMiHshN4IOMc/ydgCOWB3WEwCgYIKoEcz1UBg3Uw
+XjELMAkGA1UEBhMCQ04xEjAQBgNVBAgMCUd1YW5nZG9uZzERMA8GA1UECgwIVGVz
+dCBPcmcxEDAOBgNVBAsMB1Rlc3QgT1UxFjAUBgNVBAMMDVRlc3QgQ0EgKFNNMikw
+HhcNMjIwNTE5MDkyNzEwWhcNMjYwNjI3MDkyNzEwWjBiMQswCQYDVQQGEwJDTjES
+MBAGA1UECAwJR3Vhbmdkb25nMREwDwYDVQQKDAhUZXN0IE9yZzEQMA4GA1UECwwH
+VGVzdCBPVTEaMBgGA1UEAwwRc2VydmVyIHNpZ24gKFNNMikwWTATBgcqhkjOPQIB
+BggqgRzPVQGCLQNCAAQgP2f+HnNb6BWCGscITDpf53BwVvpj3gxrlHz05Po3i2IA
+qyL5yL2VE+bqTrxCFpQOHupjW3f5Bkihv7IUW/zMoxowGDAJBgNVHRMEAjAAMAsG
+A1UdDwQEAwIGwDAKBggqgRzPVQGDdQNHADBEAiA63GVhHaDzcVJ9DMLK/53wQZvg
+HR+tj4MCBtb6F9hL9QIgbojf0R49GnO6VYHHUx0fe+4+2DfAcMdVIutOmbpRc60=
+-----END CERTIFICATE-----
diff --git a/test/recipes/85-test_tlcp_data/sm2-server-sig-key.pem b/test/recipes/85-test_tlcp_data/sm2-server-sig-key.pem
new file mode 100644
index 0000000..f7fa712
--- /dev/null
+++ b/test/recipes/85-test_tlcp_data/sm2-server-sig-key.pem
@@ -0,0 +1,5 @@
+-----BEGIN PRIVATE KEY-----
+MIGHAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBG0wawIBAQQgr9nuyaNIE7aSQw/I
+sc7JhizpuCPUNKBF9zZy1on8BHShRANCAAQgP2f+HnNb6BWCGscITDpf53BwVvpj
+3gxrlHz05Po3i2IAqyL5yL2VE+bqTrxCFpQOHupjW3f5Bkihv7IUW/zM
+-----END PRIVATE KEY-----
diff --git a/test/sm2_internal_test.c b/test/sm2_internal_test.c
index 4951cd3..0ab84b2 100644
--- a/test/sm2_internal_test.c
+++ b/test/sm2_internal_test.c
@@ -7,6 +7,7 @@
  * https://www.openssl.org/source/license.html
  */
 
+#include <errno.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -17,6 +18,7 @@
 #include <openssl/crypto.h>
 #include <openssl/err.h>
 #include <openssl/rand.h>
+#include <openssl/sm2.h>
 #include "testutil.h"
 
 #ifndef OPENSSL_NO_SM2
@@ -404,6 +406,114 @@ static int sm2_sig_test(void)
     return testresult;
 }
 
+static EC_KEY* create_EC_key(EC_GROUP *group, const char *prv_hex, const char *x_hex, const char *y_hex)
+{
+    BIGNUM *prv = NULL;
+    BIGNUM *x = NULL;
+    BIGNUM *y = NULL;
+    EC_KEY *key = NULL;
+
+    if (!TEST_true(BN_hex2bn(&prv, prv_hex))
+            || !TEST_true(BN_hex2bn(&x, x_hex))
+            || !TEST_true(BN_hex2bn(&y, y_hex)))
+        goto err;
+    
+    if (!TEST_ptr(key = EC_KEY_new())
+            || !TEST_true(EC_KEY_set_group(key, group))
+            || !TEST_true(EC_KEY_set_private_key(key, prv))
+            || !TEST_true(EC_KEY_set_public_key_affine_coordinates(key, x, y))) {
+        EC_KEY_free(key);
+        key = NULL;
+    }
+        
+err:
+    BN_free(prv);
+    BN_free(x);
+    BN_free(y);
+
+    return key;
+}
+
+static int sm2_key_exchange_test(void)
+{
+    const char *userA = "ALICE123@YAHOO.COM";
+    const char *userB = "BILL456@YAHOO.COM";
+    const char *privA_hex = "6FCBA2EF9AE0AB902BC3BDE3FF915D44BA4CC78F88E2F8E7F8996D3B8CCEEDEE";
+    const char *pubA_x_hex = "3099093BF3C137D8FCBBCDF4A2AE50F3B0F216C3122D79425FE03A45DBFE1655";
+    const char *pubA_y_hex = "3DF79E8DAC1CF0ECBAA2F2B49D51A4B387F2EFAF482339086A27A8E05BAED98B";
+    const char *privB_hex = "5E35D7D3F3C54DBAC72E61819E730B019A84208CA3A35E4C2E353DFCCB2A3B53";
+    const char *pubB_x_hex = "245493D446C38D8CC0F118374690E7DF633A8A4BFB3329B5ECE604B2B4F37F43";
+    const char *pubB_y_hex = "53C0869F4B9E17773DE68FEC45E14904E0DEA45BF6CECF9918C85EA047C60A4C";
+    const char *ra = "83A2C9C8B96E5AF70BD480B472409A9A327257F1EBB73F5B073354B248668563";
+    const char *x1 = "6CB5633816F4DD560B1DEC458310CBCC6856C09505324A6D23150C408F162BF0";
+    const char *y1 = "0D6FCF62F1036C0A1B6DACCF57399223A65F7D7BF2D9637E5BBBEB857961BF1A";
+    const char *rb = "33FE21940342161C55619C4A0C060293D543C80AF19748CE176D83477DE71C80";
+    const char *x2 = "1799B2A2C778295300D9A2325C686129B8F2B5337B3DCF4514E8BBC19D900EE5";
+    const char *y2 = "54C9288C82733EFDF7808AE7F27D0E732F7C73A7D9AC98B7D8740A91D0DB3CF4";
+
+    EC_KEY *keyA = NULL;
+    EC_KEY *keyB = NULL;
+    EC_KEY *keyRa = NULL;
+    EC_KEY *keyRb = NULL;
+
+    unsigned char Ka[16];
+    unsigned char Kb[16];
+    unsigned char K[] = {0x55, 0xB0, 0xAC, 0x62, 0xA6, 0xB9, 0x27, 0xBA, 0x23, 0x70, 0x38, 0x32, 0xC8, 0x53, 0xDE, 0xD4};
+
+    int ret = 0;
+
+    EC_GROUP *test_group =
+        create_EC_group
+        ("8542D69E4C044F18E8B92435BF6FF7DE457283915C45517D722EDB8B08F1DFC3",
+         "787968B4FA32C3FD2417842E73BBFEFF2F3C848B6831D7E0EC65228B3937E498",
+         "63E4C6D3B23B0C849CF84241484BFE48F61D59A5B16BA06E6E12D1DA27C5249A",
+         "421DEBD61B62EAB6746434EBC3CC315E32220B3BADD50BDC4C4E6C147FEDD43D",
+         "0680512BCBB42C07D47349D2153B70C4E5D7FDFCBFA36EA1A85841B9E46E09A2",
+         "8542D69E4C044F18E8B92435BF6FF7DD297720630485628D5AE74EE7C32E79B7",
+         "1");
+
+    if (!TEST_ptr(keyA = create_EC_key(test_group, privA_hex, pubA_x_hex, pubA_y_hex))
+            || !TEST_ptr(keyB = create_EC_key(test_group, privB_hex, pubB_x_hex, pubB_y_hex)))
+        goto done;
+
+    if (!TEST_ptr(keyRa = create_EC_key(test_group, ra, x1, y1))
+            || !TEST_ptr(keyRb = create_EC_key(test_group, rb, x2, y2)))
+        goto done;
+
+    ret = SM2_compute_key(Ka, sizeof(Ka), 1, 
+        userB, strlen(userB), userA, strlen(userA),
+        keyRb, keyRa,
+        keyB, keyA, 
+        EVP_sm3());
+    if (!TEST_int_eq(ret, sizeof(Ka))) {
+        ret = 0;
+        goto done;
+    }
+
+    ret = SM2_compute_key(Kb, sizeof(Kb), 0, 
+        userA, strlen(userA), userB, strlen(userB),
+        keyRa, keyRb,
+        keyA, keyB,
+        EVP_sm3());
+    if (!TEST_int_eq(ret, sizeof(Kb))) {
+        ret = 0;
+        goto done;
+    }
+    
+    if (!TEST_mem_eq(Ka, sizeof(Ka), K, sizeof(K))
+            || !TEST_mem_eq(Kb, sizeof(Kb), K, sizeof(K)))
+        ret = 0;
+
+done:
+    EC_KEY_free(keyA);
+    EC_KEY_free(keyB);
+    EC_KEY_free(keyRa);
+    EC_KEY_free(keyRb);
+    EC_GROUP_free(test_group);
+
+    return ret;
+}
+
 #endif
 
 int setup_tests(void)
@@ -413,6 +523,7 @@ int setup_tests(void)
 #else
     ADD_TEST(sm2_crypt_test);
     ADD_TEST(sm2_sig_test);
+    ADD_TEST(sm2_key_exchange_test);
 #endif
     return 1;
 }
diff --git a/test/tlcptest.c b/test/tlcptest.c
new file mode 100644
index 0000000..7ebf1a2
--- /dev/null
+++ b/test/tlcptest.c
@@ -0,0 +1,746 @@
+/*
+ * Copyright 2022 Huawei Technologies Co., Ltd. All Rights Reserved.
+ *
+ * Licensed under the OpenSSL license (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include <string.h>
+#include <openssl/bio.h>
+#include <openssl/crypto.h>
+#include <openssl/ssl.h>
+#include <openssl/err.h>
+
+#include "internal/nelem.h"
+#include "ssltestlib.h"
+#include "testutil.h"
+
+#ifndef OPENSSL_NO_TLCP
+
+typedef enum {
+    IDX_SM2_ROOT_CERT = 0,
+    IDX_SM2_SERVER_SIG_CERT,
+    IDX_SM2_SERVER_SIG_KEY,
+    IDX_SM2_SERVER_ENC_CERT,
+    IDX_SM2_SERVER_ENC_KEY,
+    IDX_SM2_CLIENT_SIG_CERT,
+    IDX_SM2_CLIENT_SIG_KEY,
+    IDX_SM2_CLIENT_ENC_CERT,
+    IDX_SM2_CLIENT_ENC_KEY,
+    IDX_ECDSA_ROOT_CERT,
+    IDX_ECDSA_SERVER_CERT,
+    IDX_ECDSA_SERVER_KEY,
+    IDX_ECDSA_CLIENT_CERT,
+    IDX_ECDSA_CLIENT_KEY,
+    IDX_MAX
+} TEST_FILES_IDX;
+
+#define OPTION_IS_CA              0x00000001U
+#define OPTION_IS_CERT            0x00000002U
+#define OPTION_IS_KEY             0x00000004U
+#define OPTION_USE_NEWAPI         0x00000008U
+#define OPTION_USE_EXTRA          0x00000010U
+#define OPTION_IS_SIG             0x00000020U
+#define OPTION_IS_ENC             0x00000040U
+
+typedef struct {
+    TEST_FILES_IDX idx;
+    int flag;
+} LOAD_OPTION;
+
+typedef struct {
+    const char *method_name;
+    const char *sid_ctx;
+    int verify_mode;
+    int ssl_options;
+    int set_version;
+    LOAD_OPTION load_options[IDX_MAX];
+} SSL_CTX_OPTION;
+typedef struct {
+    const char *case_name;
+    SSL_CTX_OPTION server;
+    SSL_CTX_OPTION client;
+    const char *ciphersuite;
+    const char *expected_version;
+    const char *expected_cipher;
+    int regenotiate;
+    int reuse_session;
+} TLCP_TEST_CASE;
+
+static const TLCP_TEST_CASE tlcp_test_cases[] = {
+    {   "test_ecc_and_cert_position",
+        {
+            "TLS_server", NULL, SSL_VERIFY_PEER, SSL_OP_ENCCERT_SECOND_POSITION, 0,
+            {
+                {IDX_SM2_ROOT_CERT, OPTION_IS_CA},
+                {IDX_SM2_SERVER_SIG_CERT, OPTION_USE_NEWAPI | OPTION_IS_SIG | OPTION_IS_CERT },
+                {IDX_SM2_SERVER_SIG_KEY, OPTION_USE_NEWAPI | OPTION_IS_SIG | OPTION_IS_KEY },
+                {IDX_SM2_SERVER_ENC_CERT, OPTION_USE_NEWAPI | OPTION_IS_ENC | OPTION_IS_CERT },
+                {IDX_SM2_SERVER_ENC_KEY, OPTION_USE_NEWAPI | OPTION_IS_ENC | OPTION_IS_KEY }
+            }
+        },
+        {
+            "TLCP_client", NULL, SSL_VERIFY_PEER, SSL_OP_ENCCERT_SECOND_POSITION, 0,
+            {
+                {IDX_SM2_ROOT_CERT, OPTION_IS_CA},
+                {IDX_SM2_CLIENT_SIG_CERT, OPTION_USE_NEWAPI | OPTION_IS_SIG | OPTION_IS_CERT },
+                {IDX_SM2_CLIENT_SIG_KEY, OPTION_USE_NEWAPI | OPTION_IS_SIG | OPTION_IS_KEY },
+                {IDX_SM2_CLIENT_ENC_CERT, OPTION_USE_NEWAPI | OPTION_IS_ENC | OPTION_IS_CERT },
+                {IDX_SM2_CLIENT_ENC_KEY, OPTION_USE_NEWAPI | OPTION_IS_ENC | OPTION_IS_KEY }
+            }
+        },
+        "ECC-SM4-CBC-SM3",
+        "TLCP",
+        "ECC-SM4-CBC-SM3",
+        0, 0
+    },
+    {   "test_extra_cert",
+        {
+            "TLS_server", NULL, SSL_VERIFY_NONE, 0, 0,
+            {
+                {IDX_SM2_ROOT_CERT, OPTION_IS_CA | OPTION_USE_EXTRA},
+                {IDX_SM2_SERVER_SIG_CERT, OPTION_USE_NEWAPI | OPTION_IS_SIG | OPTION_IS_CERT },
+                {IDX_SM2_SERVER_SIG_KEY, OPTION_USE_NEWAPI | OPTION_IS_SIG | OPTION_IS_KEY },
+                {IDX_SM2_SERVER_ENC_CERT, OPTION_USE_NEWAPI | OPTION_IS_ENC | OPTION_IS_CERT },
+                {IDX_SM2_SERVER_ENC_KEY, OPTION_USE_NEWAPI | OPTION_IS_ENC | OPTION_IS_KEY }
+            }
+        },
+        {
+            "TLCP_client", NULL, SSL_VERIFY_NONE, 0, 0,
+            {
+                {IDX_SM2_ROOT_CERT, OPTION_IS_CA | OPTION_USE_EXTRA},
+                {IDX_SM2_CLIENT_SIG_CERT, OPTION_USE_NEWAPI | OPTION_IS_SIG | OPTION_IS_CERT },
+                {IDX_SM2_CLIENT_SIG_KEY, OPTION_USE_NEWAPI | OPTION_IS_SIG | OPTION_IS_KEY },
+                {IDX_SM2_CLIENT_ENC_CERT, OPTION_USE_NEWAPI | OPTION_IS_ENC | OPTION_IS_CERT },
+                {IDX_SM2_CLIENT_ENC_KEY, OPTION_USE_NEWAPI | OPTION_IS_ENC | OPTION_IS_KEY }
+            }
+        },
+        "ECC-SM4-CBC-SM3",
+        "TLCP",
+        "ECC-SM4-CBC-SM3",
+        0, 0
+    },
+    {   "test_ssl_op_no",
+        {
+            "TLS_server", NULL, SSL_VERIFY_PEER, SSL_OP_NO_TLSv1_3 | SSL_OP_NO_TLSv1_2 | SSL_OP_NO_TLSv1_1 | SSL_OP_NO_TLSv1 | SSL_OP_NO_SSLv3, 0,
+            {
+                {IDX_SM2_ROOT_CERT, OPTION_IS_CA},
+                {IDX_SM2_SERVER_SIG_CERT, OPTION_USE_NEWAPI | OPTION_IS_SIG | OPTION_IS_CERT },
+                {IDX_SM2_SERVER_SIG_KEY, OPTION_USE_NEWAPI | OPTION_IS_SIG | OPTION_IS_KEY },
+                {IDX_SM2_SERVER_ENC_CERT, OPTION_USE_NEWAPI | OPTION_IS_ENC | OPTION_IS_CERT },
+                {IDX_SM2_SERVER_ENC_KEY, OPTION_USE_NEWAPI | OPTION_IS_ENC | OPTION_IS_KEY }
+            }
+        },
+        {
+            "TLS_client", NULL, SSL_VERIFY_PEER, SSL_OP_NO_TLSv1_3 | SSL_OP_NO_TLSv1_2 | SSL_OP_NO_TLSv1_1 | SSL_OP_NO_TLSv1 | SSL_OP_NO_SSLv3, 0,
+            {
+                {IDX_SM2_ROOT_CERT, OPTION_IS_CA},
+                {IDX_SM2_CLIENT_SIG_CERT, OPTION_USE_NEWAPI | OPTION_IS_SIG | OPTION_IS_CERT },
+                {IDX_SM2_CLIENT_SIG_KEY, OPTION_USE_NEWAPI | OPTION_IS_SIG | OPTION_IS_KEY },
+                {IDX_SM2_CLIENT_ENC_CERT, OPTION_USE_NEWAPI | OPTION_IS_ENC | OPTION_IS_CERT },
+                {IDX_SM2_CLIENT_ENC_KEY, OPTION_USE_NEWAPI | OPTION_IS_ENC | OPTION_IS_KEY }
+            }
+        },
+        "ECC-SM4-CBC-SM3",
+        "TLCP",
+        "ECC-SM4-CBC-SM3",
+        0, 0
+    },
+    {   "test_set_version_bound",
+        {
+            "TLCP_server", NULL, SSL_VERIFY_PEER, 0, TLCP_VERSION,
+            {
+                {IDX_SM2_ROOT_CERT, OPTION_IS_CA},
+                {IDX_SM2_SERVER_SIG_CERT, OPTION_USE_NEWAPI | OPTION_IS_SIG | OPTION_IS_CERT },
+                {IDX_SM2_SERVER_SIG_KEY, OPTION_USE_NEWAPI | OPTION_IS_SIG | OPTION_IS_KEY },
+                {IDX_SM2_SERVER_ENC_CERT, OPTION_USE_NEWAPI | OPTION_IS_ENC | OPTION_IS_CERT },
+                {IDX_SM2_SERVER_ENC_KEY, OPTION_USE_NEWAPI | OPTION_IS_ENC | OPTION_IS_KEY }
+            }
+        },
+        {
+            "TLS_client", NULL, SSL_VERIFY_PEER, 0, TLCP_VERSION,
+            {
+                {IDX_SM2_ROOT_CERT, OPTION_IS_CA},
+                {IDX_SM2_CLIENT_SIG_CERT, OPTION_USE_NEWAPI | OPTION_IS_SIG | OPTION_IS_CERT },
+                {IDX_SM2_CLIENT_SIG_KEY, OPTION_USE_NEWAPI | OPTION_IS_SIG | OPTION_IS_KEY },
+                {IDX_SM2_CLIENT_ENC_CERT, OPTION_USE_NEWAPI | OPTION_IS_ENC | OPTION_IS_CERT },
+                {IDX_SM2_CLIENT_ENC_KEY, OPTION_USE_NEWAPI | OPTION_IS_ENC | OPTION_IS_KEY }
+            }
+        },
+        NULL,
+        "TLCP",
+        "ECC-SM4-CBC-SM3",
+        0, 0
+    },
+    {   "test_use_old_api_and_other_certs",
+        {
+            "TLS_server", NULL, SSL_VERIFY_PEER, 0, 0,
+            {
+                {IDX_SM2_ROOT_CERT, OPTION_IS_CA},
+                {IDX_SM2_SERVER_SIG_CERT, OPTION_IS_SIG | OPTION_IS_CERT },
+                {IDX_SM2_SERVER_SIG_KEY, OPTION_IS_SIG | OPTION_IS_KEY },
+                {IDX_SM2_SERVER_ENC_CERT, OPTION_IS_ENC | OPTION_IS_CERT },
+                {IDX_SM2_SERVER_ENC_KEY, OPTION_IS_ENC | OPTION_IS_KEY },
+                {IDX_ECDSA_ROOT_CERT, OPTION_IS_CA},
+                {IDX_ECDSA_SERVER_CERT, OPTION_IS_CERT},
+                {IDX_ECDSA_SERVER_KEY, OPTION_IS_KEY}
+            }
+        },
+        {
+            "TLCP_client", NULL, SSL_VERIFY_PEER, 0, 0,
+            {
+                {IDX_SM2_ROOT_CERT, OPTION_IS_CA},
+                {IDX_SM2_CLIENT_SIG_CERT, OPTION_IS_SIG | OPTION_IS_CERT },
+                {IDX_SM2_CLIENT_SIG_KEY, OPTION_IS_SIG | OPTION_IS_KEY },
+                {IDX_SM2_CLIENT_ENC_CERT, OPTION_IS_ENC | OPTION_IS_CERT },
+                {IDX_SM2_CLIENT_ENC_KEY, OPTION_IS_ENC | OPTION_IS_KEY },
+                {IDX_ECDSA_ROOT_CERT, OPTION_IS_CA},
+                {IDX_ECDSA_CLIENT_CERT, OPTION_IS_CERT},
+                {IDX_ECDSA_CLIENT_KEY, OPTION_IS_KEY}
+            }
+        },
+        NULL,
+        "TLCP",
+        "ECC-SM4-CBC-SM3",
+        0, 0
+    },
+    {   "test_sm2dhe_and_cert_position",
+        {
+            "TLS_server", NULL, SSL_VERIFY_PEER, SSL_OP_ENCCERT_SECOND_POSITION, 0,
+            {
+                {IDX_SM2_ROOT_CERT, OPTION_IS_CA},
+                {IDX_SM2_SERVER_SIG_CERT, OPTION_USE_NEWAPI | OPTION_IS_SIG | OPTION_IS_CERT },
+                {IDX_SM2_SERVER_SIG_KEY, OPTION_USE_NEWAPI | OPTION_IS_SIG | OPTION_IS_KEY },
+                {IDX_SM2_SERVER_ENC_CERT, OPTION_USE_NEWAPI | OPTION_IS_ENC | OPTION_IS_CERT },
+                {IDX_SM2_SERVER_ENC_KEY, OPTION_USE_NEWAPI | OPTION_IS_ENC | OPTION_IS_KEY }
+            }
+        },
+        {
+            "TLCP_client", NULL, SSL_VERIFY_PEER, SSL_OP_ENCCERT_SECOND_POSITION, 0,
+            {
+                {IDX_SM2_ROOT_CERT, OPTION_IS_CA},
+                {IDX_SM2_CLIENT_SIG_CERT, OPTION_USE_NEWAPI | OPTION_IS_SIG | OPTION_IS_CERT },
+                {IDX_SM2_CLIENT_SIG_KEY, OPTION_USE_NEWAPI | OPTION_IS_SIG | OPTION_IS_KEY },
+                {IDX_SM2_CLIENT_ENC_CERT, OPTION_USE_NEWAPI | OPTION_IS_ENC | OPTION_IS_CERT },
+                {IDX_SM2_CLIENT_ENC_KEY, OPTION_USE_NEWAPI | OPTION_IS_ENC | OPTION_IS_KEY }
+            }
+        },
+        "ECDHE-SM4-CBC-SM3",
+        "TLCP",
+        "ECDHE-SM4-CBC-SM3",
+        0, 0
+    },
+    {   "test_ecc_regenotiate",
+        {
+            "TLS_server", NULL, SSL_VERIFY_PEER, SSL_OP_ENCCERT_SECOND_POSITION, 0,
+            {
+                {IDX_SM2_ROOT_CERT, OPTION_IS_CA},
+                {IDX_SM2_SERVER_SIG_CERT, OPTION_USE_NEWAPI | OPTION_IS_SIG | OPTION_IS_CERT },
+                {IDX_SM2_SERVER_SIG_KEY, OPTION_USE_NEWAPI | OPTION_IS_SIG | OPTION_IS_KEY },
+                {IDX_SM2_SERVER_ENC_CERT, OPTION_USE_NEWAPI | OPTION_IS_ENC | OPTION_IS_CERT },
+                {IDX_SM2_SERVER_ENC_KEY, OPTION_USE_NEWAPI | OPTION_IS_ENC | OPTION_IS_KEY }
+            }
+        },
+        {
+            "TLCP_client", NULL, SSL_VERIFY_PEER, SSL_OP_ENCCERT_SECOND_POSITION, 0,
+            {
+                {IDX_SM2_ROOT_CERT, OPTION_IS_CA},
+                {IDX_SM2_CLIENT_SIG_CERT, OPTION_USE_NEWAPI | OPTION_IS_SIG | OPTION_IS_CERT },
+                {IDX_SM2_CLIENT_SIG_KEY, OPTION_USE_NEWAPI | OPTION_IS_SIG | OPTION_IS_KEY },
+                {IDX_SM2_CLIENT_ENC_CERT, OPTION_USE_NEWAPI | OPTION_IS_ENC | OPTION_IS_CERT },
+                {IDX_SM2_CLIENT_ENC_KEY, OPTION_USE_NEWAPI | OPTION_IS_ENC | OPTION_IS_KEY }
+            }
+        },
+        "ECC-SM4-CBC-SM3",
+        "TLCP",
+        "ECC-SM4-CBC-SM3",
+        1, 0
+    },
+    {   "test_sm2dhe_regenotiate",
+        {
+            "TLS_server", NULL, SSL_VERIFY_PEER, SSL_OP_ENCCERT_SECOND_POSITION, 0,
+            {
+                {IDX_SM2_ROOT_CERT, OPTION_IS_CA},
+                {IDX_SM2_SERVER_SIG_CERT, OPTION_USE_NEWAPI | OPTION_IS_SIG | OPTION_IS_CERT },
+                {IDX_SM2_SERVER_SIG_KEY, OPTION_USE_NEWAPI | OPTION_IS_SIG | OPTION_IS_KEY },
+                {IDX_SM2_SERVER_ENC_CERT, OPTION_USE_NEWAPI | OPTION_IS_ENC | OPTION_IS_CERT },
+                {IDX_SM2_SERVER_ENC_KEY, OPTION_USE_NEWAPI | OPTION_IS_ENC | OPTION_IS_KEY }
+            }
+        },
+        {
+            "TLCP_client", NULL, SSL_VERIFY_PEER, SSL_OP_ENCCERT_SECOND_POSITION, 0,
+            {
+                {IDX_SM2_ROOT_CERT, OPTION_IS_CA},
+                {IDX_SM2_CLIENT_SIG_CERT, OPTION_USE_NEWAPI | OPTION_IS_SIG | OPTION_IS_CERT },
+                {IDX_SM2_CLIENT_SIG_KEY, OPTION_USE_NEWAPI | OPTION_IS_SIG | OPTION_IS_KEY },
+                {IDX_SM2_CLIENT_ENC_CERT, OPTION_USE_NEWAPI | OPTION_IS_ENC | OPTION_IS_CERT },
+                {IDX_SM2_CLIENT_ENC_KEY, OPTION_USE_NEWAPI | OPTION_IS_ENC | OPTION_IS_KEY }
+            }
+        },
+        "ECDHE-SM4-CBC-SM3",
+        "TLCP",
+        "ECDHE-SM4-CBC-SM3",
+        1, 0
+    },
+    {   "test_ecc_reused_sessionid",
+        {
+            "TLS_server", "TEST", SSL_VERIFY_PEER, SSL_OP_NO_TICKET | SSL_OP_ENCCERT_SECOND_POSITION, 0,
+            {
+                {IDX_SM2_ROOT_CERT, OPTION_IS_CA},
+                {IDX_SM2_SERVER_SIG_CERT, OPTION_USE_NEWAPI | OPTION_IS_SIG | OPTION_IS_CERT },
+                {IDX_SM2_SERVER_SIG_KEY, OPTION_USE_NEWAPI | OPTION_IS_SIG | OPTION_IS_KEY },
+                {IDX_SM2_SERVER_ENC_CERT, OPTION_USE_NEWAPI | OPTION_IS_ENC | OPTION_IS_CERT },
+                {IDX_SM2_SERVER_ENC_KEY, OPTION_USE_NEWAPI | OPTION_IS_ENC | OPTION_IS_KEY }
+            }
+        },
+        {
+            "TLCP_client", NULL, SSL_VERIFY_PEER, SSL_OP_NO_TICKET | SSL_OP_ENCCERT_SECOND_POSITION, 0,
+            {
+                {IDX_SM2_ROOT_CERT, OPTION_IS_CA},
+                {IDX_SM2_CLIENT_SIG_CERT, OPTION_USE_NEWAPI | OPTION_IS_SIG | OPTION_IS_CERT },
+                {IDX_SM2_CLIENT_SIG_KEY, OPTION_USE_NEWAPI | OPTION_IS_SIG | OPTION_IS_KEY },
+                {IDX_SM2_CLIENT_ENC_CERT, OPTION_USE_NEWAPI | OPTION_IS_ENC | OPTION_IS_CERT },
+                {IDX_SM2_CLIENT_ENC_KEY, OPTION_USE_NEWAPI | OPTION_IS_ENC | OPTION_IS_KEY }
+            }
+        },
+        "ECC-SM4-CBC-SM3",
+        "TLCP",
+        "ECC-SM4-CBC-SM3",
+        0, 1
+    },
+    {   "test_sm2dhe_reused_sessionid",
+        {
+            "TLS_server", "TEST", SSL_VERIFY_PEER, SSL_OP_NO_TICKET | SSL_OP_ENCCERT_SECOND_POSITION, 0,
+            {
+                {IDX_SM2_ROOT_CERT, OPTION_IS_CA},
+                {IDX_SM2_SERVER_SIG_CERT, OPTION_USE_NEWAPI | OPTION_IS_SIG | OPTION_IS_CERT },
+                {IDX_SM2_SERVER_SIG_KEY, OPTION_USE_NEWAPI | OPTION_IS_SIG | OPTION_IS_KEY },
+                {IDX_SM2_SERVER_ENC_CERT, OPTION_USE_NEWAPI | OPTION_IS_ENC | OPTION_IS_CERT },
+                {IDX_SM2_SERVER_ENC_KEY, OPTION_USE_NEWAPI | OPTION_IS_ENC | OPTION_IS_KEY }
+            }
+        },
+        {
+            "TLCP_client", NULL, SSL_VERIFY_PEER, SSL_OP_NO_TICKET | SSL_OP_ENCCERT_SECOND_POSITION, 0,
+            {
+                {IDX_SM2_ROOT_CERT, OPTION_IS_CA},
+                {IDX_SM2_CLIENT_SIG_CERT, OPTION_USE_NEWAPI | OPTION_IS_SIG | OPTION_IS_CERT },
+                {IDX_SM2_CLIENT_SIG_KEY, OPTION_USE_NEWAPI | OPTION_IS_SIG | OPTION_IS_KEY },
+                {IDX_SM2_CLIENT_ENC_CERT, OPTION_USE_NEWAPI | OPTION_IS_ENC | OPTION_IS_CERT },
+                {IDX_SM2_CLIENT_ENC_KEY, OPTION_USE_NEWAPI | OPTION_IS_ENC | OPTION_IS_KEY }
+            }
+        },
+        "ECDHE-SM4-CBC-SM3",
+        "TLCP",
+        "ECDHE-SM4-CBC-SM3",
+        0, 1
+    },
+    {   "test_ecc_reused_ticket",
+        {
+            "TLS_server", NULL, SSL_VERIFY_NONE, SSL_OP_ENCCERT_SECOND_POSITION, 0,
+            {
+                {IDX_SM2_ROOT_CERT, OPTION_IS_CA},
+                {IDX_SM2_SERVER_SIG_CERT, OPTION_USE_NEWAPI | OPTION_IS_SIG | OPTION_IS_CERT },
+                {IDX_SM2_SERVER_SIG_KEY, OPTION_USE_NEWAPI | OPTION_IS_SIG | OPTION_IS_KEY },
+                {IDX_SM2_SERVER_ENC_CERT, OPTION_USE_NEWAPI | OPTION_IS_ENC | OPTION_IS_CERT },
+                {IDX_SM2_SERVER_ENC_KEY, OPTION_USE_NEWAPI | OPTION_IS_ENC | OPTION_IS_KEY }
+            }
+        },
+        {
+            "TLCP_client", NULL, SSL_VERIFY_NONE, SSL_OP_ENCCERT_SECOND_POSITION, 0,
+            {
+                {IDX_SM2_ROOT_CERT, OPTION_IS_CA},
+                {IDX_SM2_CLIENT_SIG_CERT, OPTION_USE_NEWAPI | OPTION_IS_SIG | OPTION_IS_CERT },
+                {IDX_SM2_CLIENT_SIG_KEY, OPTION_USE_NEWAPI | OPTION_IS_SIG | OPTION_IS_KEY },
+                {IDX_SM2_CLIENT_ENC_CERT, OPTION_USE_NEWAPI | OPTION_IS_ENC | OPTION_IS_CERT },
+                {IDX_SM2_CLIENT_ENC_KEY, OPTION_USE_NEWAPI | OPTION_IS_ENC | OPTION_IS_KEY }
+            }
+        },
+        "ECC-SM4-CBC-SM3",
+        "TLCP",
+        "ECC-SM4-CBC-SM3",
+        0, 1
+    },
+    {   "test_sm2dhe_reused_ticket",
+        {
+            "TLS_server", NULL, SSL_VERIFY_NONE, SSL_OP_ENCCERT_SECOND_POSITION, 0,
+            {
+                {IDX_SM2_ROOT_CERT, OPTION_IS_CA},
+                {IDX_SM2_SERVER_SIG_CERT, OPTION_USE_NEWAPI | OPTION_IS_SIG | OPTION_IS_CERT },
+                {IDX_SM2_SERVER_SIG_KEY, OPTION_USE_NEWAPI | OPTION_IS_SIG | OPTION_IS_KEY },
+                {IDX_SM2_SERVER_ENC_CERT, OPTION_USE_NEWAPI | OPTION_IS_ENC | OPTION_IS_CERT },
+                {IDX_SM2_SERVER_ENC_KEY, OPTION_USE_NEWAPI | OPTION_IS_ENC | OPTION_IS_KEY }
+            }
+        },
+        {
+            "TLCP_client", NULL, SSL_VERIFY_NONE, SSL_OP_ENCCERT_SECOND_POSITION, 0,
+            {
+                {IDX_SM2_ROOT_CERT, OPTION_IS_CA},
+                {IDX_SM2_CLIENT_SIG_CERT, OPTION_USE_NEWAPI | OPTION_IS_SIG | OPTION_IS_CERT },
+                {IDX_SM2_CLIENT_SIG_KEY, OPTION_USE_NEWAPI | OPTION_IS_SIG | OPTION_IS_KEY },
+                {IDX_SM2_CLIENT_ENC_CERT, OPTION_USE_NEWAPI | OPTION_IS_ENC | OPTION_IS_CERT },
+                {IDX_SM2_CLIENT_ENC_KEY, OPTION_USE_NEWAPI | OPTION_IS_ENC | OPTION_IS_KEY }
+            }
+        },
+        "ECDHE-SM4-CBC-SM3",
+        "TLCP",
+        "ECDHE-SM4-CBC-SM3",
+        0, 1
+    },
+};
+
+static const char *test_files[IDX_MAX];
+
+static X509 *PEM_file_to_X509(const char *file)
+{
+    BIO *in;
+    X509 *x = NULL;
+
+    in = BIO_new(BIO_s_file());
+    if (in == NULL || BIO_read_filename(in, file) <= 0)
+        goto err;
+
+    x = PEM_read_bio_X509(in, NULL, NULL, NULL);
+err:
+    BIO_free(in);
+    return x;
+}
+
+static EVP_PKEY *PEM_file_to_PrivateKey(const char *file)
+{
+    BIO *in;
+    EVP_PKEY *pkey = NULL;
+
+    in = BIO_new(BIO_s_file());
+    if (in == NULL || BIO_read_filename(in, file) <= 0)
+        goto err;
+
+    pkey = PEM_read_bio_PrivateKey(in, NULL, NULL, NULL);
+err:
+    BIO_free(in);
+    return pkey;
+}
+
+static int use_extra_cert_file(SSL_CTX *ctx, const char *file)
+{
+    X509 *x;
+
+    x = PEM_file_to_X509(file);
+
+    if (x == NULL)
+        return 0;
+
+    if (!SSL_CTX_add_extra_chain_cert(ctx, x)) {
+        X509_free(x);
+        return 0;
+    }
+    return 1;
+}
+
+static int load_test_file_by_option(SSL_CTX *ctx, LOAD_OPTION opt)
+{
+    int usage = -1;
+    if (opt.idx >= IDX_MAX)
+        return 0;
+
+    if (opt.flag & OPTION_IS_CA) {
+        return (opt.flag & OPTION_USE_EXTRA) 
+                    ? use_extra_cert_file(ctx, test_files[opt.idx])
+                    : SSL_CTX_load_verify_locations(ctx, test_files[opt.idx], NULL);
+    }
+
+    if (opt.flag & OPTION_IS_SIG) {
+        usage = SSL_USAGE_SIG;
+    } else if (opt.flag & OPTION_IS_ENC) {
+        usage = SSL_USAGE_ENC;
+    }
+
+    if (opt.flag & OPTION_IS_CERT) {
+        return (opt.flag & OPTION_USE_NEWAPI) 
+                    ? SSL_CTX_use_gm_certificate_file(ctx, test_files[opt.idx], SSL_FILETYPE_PEM, usage)
+                    : SSL_CTX_use_certificate_file(ctx, test_files[opt.idx], SSL_FILETYPE_PEM);
+    } else if (opt.flag & OPTION_IS_KEY){
+        return (opt.flag & OPTION_USE_NEWAPI) 
+                    ? SSL_CTX_use_gm_PrivateKey_file(ctx, test_files[opt.idx], SSL_FILETYPE_PEM, usage)
+                    : SSL_CTX_use_PrivateKey_file(ctx, test_files[opt.idx], SSL_FILETYPE_PEM);
+    }
+    return 1;
+}
+
+static int load_test_files(SSL_CTX *ctx, LOAD_OPTION *opt, size_t optlen)
+{
+    int i;
+    for (i = 0; i < optlen; ++i) {
+        if (!load_test_file_by_option(ctx, opt[i])) {
+            return 0;
+        }
+    }
+    return 1;
+}
+
+static SSL_CTX *SSL_CTX_create_by_option(const SSL_CTX_OPTION *opt)
+{
+    SSL_CTX *ctx = NULL;
+    if (opt == NULL)
+        return NULL;
+
+    if (strcmp(opt->method_name, "TLS_server") == 0) {
+        ctx = SSL_CTX_new(TLS_server_method());
+    } else if (strcmp(opt->method_name, "TLS_client") == 0) {
+        ctx = SSL_CTX_new(TLS_client_method());
+    } else if (strcmp(opt->method_name, "TLCP_server") == 0) {
+        ctx = SSL_CTX_new(TLCP_server_method());
+    } else if (strcmp(opt->method_name, "TLCP_client") == 0) {
+        ctx = SSL_CTX_new(TLCP_client_method());
+    }
+    if (ctx == NULL)
+        return NULL;
+
+    SSL_CTX_set_verify(ctx, opt->verify_mode, NULL);
+    SSL_CTX_set_options(ctx, opt->ssl_options);
+    SSL_CTX_set_min_proto_version(ctx, opt->set_version);
+    SSL_CTX_set_max_proto_version(ctx, opt->set_version);
+
+    if (opt->sid_ctx
+            && SSL_CTX_set_session_id_context(ctx, (unsigned char*)opt->sid_ctx, strlen(opt->sid_ctx)) != 1) {
+        SSL_CTX_free(ctx);
+        return NULL;
+    }
+
+    if (!load_test_files(ctx, (LOAD_OPTION *)opt->load_options, OSSL_NELEM(opt->load_options))) {
+        SSL_CTX_free(ctx);
+        return NULL;
+    }
+    return ctx;
+}
+
+static int test_tlcp_regenotiate(SSL *server_ssl, SSL *client_ssl)
+{
+    SSL_SESSION *sess_pre;
+    SSL_SESSION *sess_post;
+
+    if (!TEST_ptr(sess_pre = SSL_get0_session(server_ssl)))
+        return 0;
+
+    if (!TEST_int_eq(SSL_renegotiate(client_ssl), 1)
+            || !TEST_int_eq(SSL_renegotiate_pending(client_ssl), 1))
+        return 0;
+
+    for (int i = 0; i < 3; i++) {
+        unsigned char buf;
+        size_t readbytes;
+        int ret = SSL_read_ex(client_ssl, &buf, sizeof(buf), &readbytes);
+        if ((ret > 0 && !TEST_ulong_eq(readbytes, 0))
+                || (ret <= 0 && !TEST_int_eq(SSL_get_error(client_ssl, 0), SSL_ERROR_WANT_READ))) {
+            return 0;
+        }
+
+        ret = SSL_read_ex(server_ssl, &buf, sizeof(buf), &readbytes);
+        if ((ret > 0 && !TEST_ulong_eq(readbytes, 0))
+                || (ret <= 0 && SSL_get_error(server_ssl, 0) != SSL_ERROR_WANT_READ)) {
+            if (!strcmp("ECDHE-SM4-CBC-SM3", SSL_CIPHER_get_name(SSL_get_current_cipher(client_ssl))))
+                return 1;
+            return 0;
+        }
+    }
+
+    if (!TEST_false(SSL_renegotiate_pending(client_ssl))
+            || !TEST_int_eq(SSL_session_reused(client_ssl), 0)
+            || !TEST_int_eq(SSL_session_reused(server_ssl), 0)
+            || !TEST_ptr(sess_post = SSL_get0_session(server_ssl))
+            || !TEST_ptr_ne(sess_pre, sess_post))
+        return 0;
+
+    return 1;
+}
+
+static int test_tlcp_reuse_session(SSL **p_server_ssl, SSL **p_client_ssl)
+{
+    int ret = 0;
+    SSL *server_ssl = *p_server_ssl;
+    SSL *client_ssl = *p_client_ssl;
+    SSL_CTX *server_ctx;
+    SSL_CTX *client_ctx;
+    SSL_SESSION *sess_pre;
+    SSL_SESSION *sess_post;
+    SSL_SESSION *sess;
+    const unsigned char *sess_pre_id;
+    unsigned int sess_pre_id_len;
+    const unsigned char *sess_post_id;
+    unsigned int sess_post_id_len;
+    const char *ciph_name = SSL_CIPHER_get_name(SSL_get_current_cipher(client_ssl));
+
+    if (!TEST_ptr(server_ctx = SSL_get_SSL_CTX(server_ssl))
+            || !TEST_ptr(client_ctx = SSL_get_SSL_CTX(client_ssl)))
+        return 0;
+
+    if (!TEST_ptr(sess_pre = SSL_get0_session(server_ssl)))
+        return 0;
+    
+    if (!TEST_ptr(sess = SSL_get1_session(client_ssl)))
+        return 0;
+
+    shutdown_ssl_connection(server_ssl, client_ssl);
+    *p_server_ssl = NULL;
+    *p_client_ssl = NULL;
+    
+    if (!TEST_int_eq(create_ssl_objects(server_ctx, client_ctx, p_server_ssl, p_client_ssl, NULL, NULL), 1))
+        goto out;
+
+    server_ssl = *p_server_ssl;
+    client_ssl = *p_client_ssl;
+
+    if (!TEST_int_eq(SSL_set_session(client_ssl, sess), 1))
+        goto out;
+
+    if (!TEST_int_eq(create_ssl_connection(server_ssl, client_ssl, SSL_ERROR_NONE), 1))
+        goto out;
+
+    if (!TEST_int_eq(SSL_session_reused(client_ssl), 1)
+            || !TEST_int_eq(SSL_session_reused(server_ssl), 1))
+        goto out;
+
+    if (!TEST_ptr(sess_post = SSL_get0_session(server_ssl))
+            || !TEST_str_eq(ciph_name, SSL_CIPHER_get_name(SSL_get_current_cipher(client_ssl))))
+        goto out;
+    
+    if ((SSL_get_options(client_ssl) & SSL_OP_NO_TICKET) && (SSL_get_options(server_ssl) & SSL_OP_NO_TICKET)
+            && !TEST_ptr_eq(sess_pre, sess_post))
+        goto out;
+
+    sess_post_id = SSL_SESSION_get_id(sess_post, &sess_post_id_len);
+    sess_pre_id = SSL_SESSION_get_id(sess, &sess_pre_id_len);
+
+    if (!TEST_mem_eq(sess_pre_id, sess_pre_id_len, sess_post_id, sess_post_id_len))
+        goto out;
+
+    ret = 1;
+
+out:
+    SSL_SESSION_free(sess);
+
+    return ret;
+}
+
+static int test_tlcp_ciphersuites(int idx)
+{
+    int result = 0;
+    SSL_CTX *server_ctx = NULL;
+    SSL_CTX *client_ctx = NULL;
+    SSL *server_ssl = NULL;
+    SSL *client_ssl = NULL;
+    const TLCP_TEST_CASE *case_ptr;
+
+    case_ptr = &tlcp_test_cases[idx];
+    if (!TEST_ptr(server_ctx = SSL_CTX_create_by_option(&case_ptr->server))
+            || !TEST_ptr(client_ctx = SSL_CTX_create_by_option(&case_ptr->client)))
+        goto err;
+
+    if (case_ptr->ciphersuite != NULL &&
+            !TEST_int_eq(SSL_CTX_set_cipher_list(client_ctx, case_ptr->ciphersuite), 1))
+        goto err;
+
+    if (!TEST_int_eq(create_ssl_objects(server_ctx, client_ctx
+            , &server_ssl, &client_ssl, NULL, NULL), 1))
+        goto err;
+
+    if (!TEST_int_eq(create_ssl_connection(server_ssl, client_ssl, SSL_ERROR_NONE), 1))
+        goto err;
+
+    if (case_ptr->expected_version != NULL &&
+            !TEST_str_eq(SSL_get_version(client_ssl), case_ptr->expected_version))
+        goto err;
+
+    if (case_ptr->expected_cipher &&
+            !TEST_str_eq(SSL_get_cipher(client_ssl), case_ptr->expected_cipher))
+        goto err;
+
+    if (case_ptr->regenotiate
+            && !TEST_int_eq(test_tlcp_regenotiate(server_ssl, client_ssl), 1))
+        goto err;
+
+    if (case_ptr->reuse_session
+            && !TEST_int_eq(test_tlcp_reuse_session(&server_ssl, &client_ssl), 1))
+        goto err;
+
+    result = 1;
+err:
+    if (server_ssl != NULL)
+        SSL_shutdown(server_ssl);
+    if (client_ssl != NULL)
+        SSL_shutdown(client_ssl);
+    SSL_free(server_ssl);
+    SSL_free(client_ssl);
+    SSL_CTX_free(server_ctx);
+    SSL_CTX_free(client_ctx);
+    return result;
+}
+
+static int test_use_certs_and_keys(void)
+{
+    SSL_CTX *ctx = NULL;
+    SSL *ssl = NULL;
+    X509 *x = NULL;
+    EVP_PKEY *pkey = NULL;
+    int result = 0;
+
+    ctx = SSL_CTX_new(TLCP_method());
+    if (ctx == NULL)
+        goto err;
+    
+    ssl = SSL_new(ctx);
+    if (ssl == NULL)
+        goto err;
+
+    if (!TEST_int_ne(SSL_use_gm_certificate_file(ssl, test_files[IDX_ECDSA_SERVER_CERT], 
+            SSL_FILETYPE_PEM, SSL_USAGE_SIG), 1)
+        || !TEST_int_ne(SSL_use_gm_PrivateKey_file(ssl, test_files[IDX_ECDSA_CLIENT_KEY], 
+            SSL_FILETYPE_PEM, SSL_USAGE_SIG), 1)) {
+        goto err;
+    }
+
+    if (!TEST_int_eq(SSL_use_certificate_file(ssl, test_files[IDX_SM2_SERVER_SIG_CERT], 
+            SSL_FILETYPE_PEM), 1)
+        || !TEST_int_eq(SSL_use_gm_PrivateKey_file(ssl, test_files[IDX_SM2_SERVER_SIG_KEY], 
+            SSL_FILETYPE_PEM, SSL_USAGE_SIG), 1)
+        || !TEST_int_eq(SSL_use_gm_certificate_file(ssl, test_files[IDX_SM2_SERVER_ENC_CERT], 
+            SSL_FILETYPE_PEM, SSL_USAGE_ENC), 1)
+        || !TEST_int_eq(SSL_use_PrivateKey_file(ssl, test_files[IDX_SM2_SERVER_ENC_KEY], 
+            SSL_FILETYPE_PEM), 1)){
+        goto err;
+    }
+
+    if (!TEST_ptr(x = PEM_file_to_X509(test_files[IDX_SM2_CLIENT_SIG_CERT]))
+        || !TEST_ptr(pkey = PEM_file_to_PrivateKey(test_files[IDX_SM2_CLIENT_SIG_KEY]))
+        || !TEST_int_eq(SSL_use_gm_cert_and_key(ssl, x, pkey, NULL, 1, SSL_USAGE_SIG), 1)) {
+        goto err;
+    }
+    result = 1;
+err:
+    X509_free(x);
+
+    EVP_PKEY_free(pkey);
+    SSL_free(ssl);
+    SSL_CTX_free(ctx);
+    return result;
+}
+
+#endif
+
+int setup_tests(void)
+{
+#ifndef OPENSSL_NO_TLCP
+    int argc;
+
+    for (argc = 0; argc < IDX_MAX; ++argc) {
+        if (!TEST_ptr(test_files[argc] = test_get_argument(argc))) {
+            return 0;
+        }
+    }
+
+    ADD_ALL_TESTS(test_tlcp_ciphersuites, OSSL_NELEM(tlcp_test_cases));
+    ADD_TEST(test_use_certs_and_keys);
+#endif 
+    return 1;
+}
diff --git a/util/libcrypto.num b/util/libcrypto.num
index 81a6388..95bccf9 100644
--- a/util/libcrypto.num
+++ b/util/libcrypto.num
@@ -4630,3 +4630,5 @@ X509_set0_sm2_id                        6383	1_1_1m	EXIST::FUNCTION:SM2
 X509_get0_sm2_id                        6384	1_1_1m	EXIST::FUNCTION:SM2
 X509_REQ_get0_sm2_id                    6385	1_1_1m	EXIST::FUNCTION:SM2
 X509_REQ_set0_sm2_id                    6386	1_1_1m	EXIST::FUNCTION:SM2
+EVP_PKEY_is_sm2                         6387	1_1_1m	EXIST::FUNCTION:SM2
+SM2_compute_key                         6388	1_1_1m	EXIST::FUNCTION:
diff --git a/util/libssl.num b/util/libssl.num
index 297522c..f120bed 100644
--- a/util/libssl.num
+++ b/util/libssl.num
@@ -498,3 +498,20 @@ SSL_CTX_get_recv_max_early_data         498	1_1_1	EXIST::FUNCTION:
 SSL_CTX_set_recv_max_early_data         499	1_1_1	EXIST::FUNCTION:
 SSL_CTX_set_post_handshake_auth         500	1_1_1	EXIST::FUNCTION:
 SSL_get_signature_type_nid              501	1_1_1a	EXIST::FUNCTION:
+SSL_use_gm_PrivateKey                   502	1_1_1m	EXIST::FUNCTION:TLCP
+SSL_CTX_use_gm_certificate_file         503	1_1_1m	EXIST::FUNCTION:TLCP
+SSL_CTX_use_gm_certificate              504	1_1_1m	EXIST::FUNCTION:TLCP
+SSL_use_gm_certificate_file             505	1_1_1m	EXIST::FUNCTION:TLCP
+SSL_CTX_use_gm_certificate_ASN1         506	1_1_1m	EXIST::FUNCTION:TLCP
+SSL_use_gm_PrivateKey_file              507	1_1_1m	EXIST::FUNCTION:TLCP
+TLCP_method                             508	1_1_1m	EXIST::FUNCTION:TLCP
+SSL_CTX_use_gm_PrivateKey_file          509	1_1_1m	EXIST::FUNCTION:TLCP
+SSL_use_gm_PrivateKey_ASN1              510	1_1_1m	EXIST::FUNCTION:TLCP
+TLCP_client_method                      511	1_1_1m	EXIST::FUNCTION:TLCP
+SSL_CTX_use_gm_cert_and_key             512	1_1_1m	EXIST::FUNCTION:TLCP
+SSL_CTX_use_gm_PrivateKey               513	1_1_1m	EXIST::FUNCTION:TLCP
+TLCP_server_method                      514	1_1_1m	EXIST::FUNCTION:TLCP
+SSL_use_gm_cert_and_key                 515	1_1_1m	EXIST::FUNCTION:TLCP
+SSL_use_gm_certificate                  516	1_1_1m	EXIST::FUNCTION:TLCP
+SSL_use_gm_certificate_ASN1             517	1_1_1m	EXIST::FUNCTION:TLCP
+SSL_CTX_use_gm_PrivateKey_ASN1          518	1_1_1m	EXIST::FUNCTION:TLCP
-- 
2.20.1 (Apple Git-117)

