Просмотр исходного кода

change: 调整gmssl库的实现,不依赖mbedtls

当前sm加密最佳性能, 调整为-O3编译
1. air101/air103, 耗时300ms
2. air105,耗时180ms
7. ec618,耗时780ms
Wendal Chen 2 лет назад
Родитель
Сommit
736080a89e
100 измененных файлов с 20219 добавлено и 2741 удалено
  1. 176 0
      components/gmssl/LICENSE
  2. 103 91
      components/gmssl/bind/luat_lib_gmssl.c
  3. 111 0
      components/gmssl/include/gmssl/aead.h
  4. 90 0
      components/gmssl/include/gmssl/aes.h
  5. 22 0
      components/gmssl/include/gmssl/api.h
  6. 301 0
      components/gmssl/include/gmssl/asn1.h
  7. 72 0
      components/gmssl/include/gmssl/base64.h
  8. 74 0
      components/gmssl/include/gmssl/block_cipher.h
  9. 57 0
      components/gmssl/include/gmssl/chacha20.h
  10. 552 0
      components/gmssl/include/gmssl/cms.h
  11. 58 0
      components/gmssl/include/gmssl/des.h
  12. 87 0
      components/gmssl/include/gmssl/digest.h
  13. 54 0
      components/gmssl/include/gmssl/dylib.h
  14. 64 0
      components/gmssl/include/gmssl/ec.h
  15. 78 0
      components/gmssl/include/gmssl/endian.h
  16. 71 0
      components/gmssl/include/gmssl/error.h
  17. 29 0
      components/gmssl/include/gmssl/file.h
  18. 73 0
      components/gmssl/include/gmssl/gcm.h
  19. 53 0
      components/gmssl/include/gmssl/gf128.h
  20. 79 0
      components/gmssl/include/gmssl/hash_drbg.h
  21. 32 0
      components/gmssl/include/gmssl/hex.h
  22. 45 0
      components/gmssl/include/gmssl/hkdf.h
  23. 47 0
      components/gmssl/include/gmssl/hmac.h
  24. 29 0
      components/gmssl/include/gmssl/http.h
  25. 48 0
      components/gmssl/include/gmssl/md5.h
  26. 27 0
      components/gmssl/include/gmssl/mem.h
  27. 215 0
      components/gmssl/include/gmssl/oid.h
  28. 54 0
      components/gmssl/include/gmssl/pbkdf2.h
  29. 33 0
      components/gmssl/include/gmssl/pem.h
  30. 169 0
      components/gmssl/include/gmssl/pkcs8.h
  31. 35 0
      components/gmssl/include/gmssl/rand.h
  32. 40 0
      components/gmssl/include/gmssl/rc4.h
  33. 30 0
      components/gmssl/include/gmssl/rdrand.h
  34. 56 0
      components/gmssl/include/gmssl/rsa.h
  35. 69 0
      components/gmssl/include/gmssl/sdf.h
  36. 45 0
      components/gmssl/include/gmssl/sha1.h
  37. 102 0
      components/gmssl/include/gmssl/sha2.h
  38. 92 0
      components/gmssl/include/gmssl/sha3.h
  39. 116 0
      components/gmssl/include/gmssl/skf.h
  40. 382 0
      components/gmssl/include/gmssl/sm2.h
  41. 49 0
      components/gmssl/include/gmssl/sm2_blind.h
  42. 40 0
      components/gmssl/include/gmssl/sm2_commit.h
  43. 67 0
      components/gmssl/include/gmssl/sm2_elgamal.h
  44. 45 0
      components/gmssl/include/gmssl/sm2_key_share.h
  45. 31 0
      components/gmssl/include/gmssl/sm2_recover.h
  46. 63 0
      components/gmssl/include/gmssl/sm2_ring.h
  47. 89 0
      components/gmssl/include/gmssl/sm3.h
  48. 42 0
      components/gmssl/include/gmssl/sm3_rng.h
  49. 33 0
      components/gmssl/include/gmssl/sm3_x8_avx2.h
  50. 131 0
      components/gmssl/include/gmssl/sm4.h
  51. 35 0
      components/gmssl/include/gmssl/sm4_cbc_mac.h
  52. 55 0
      components/gmssl/include/gmssl/sm4_cl.h
  53. 43 0
      components/gmssl/include/gmssl/sm4_rng.h
  54. 561 0
      components/gmssl/include/gmssl/sm9.h
  55. 73 0
      components/gmssl/include/gmssl/socket.h
  56. 875 0
      components/gmssl/include/gmssl/tls.h
  57. 37 0
      components/gmssl/include/gmssl/version.h
  58. 16 0
      components/gmssl/include/gmssl/x509.h
  59. 68 0
      components/gmssl/include/gmssl/x509_alg.h
  60. 390 0
      components/gmssl/include/gmssl/x509_cer.h
  61. 309 0
      components/gmssl/include/gmssl/x509_crl.h
  62. 641 0
      components/gmssl/include/gmssl/x509_ext.h
  63. 81 0
      components/gmssl/include/gmssl/x509_req.h
  64. 147 0
      components/gmssl/include/gmssl/zuc.h
  65. 0 6
      components/gmssl/include/internal/ayconfig.h
  66. 0 123
      components/gmssl/include/internal/ssl_random.h
  67. 0 12
      components/gmssl/include/modes_lcl.h
  68. 0 430
      components/gmssl/include/openssl/modes.h
  69. 0 376
      components/gmssl/include/sm2/sm2.h
  70. 0 115
      components/gmssl/include/sm3/sm3.h
  71. 0 379
      components/gmssl/include/sm4/sm4.h
  72. 534 0
      components/gmssl/src/aead.c
  73. 1937 0
      components/gmssl/src/asn1.c
  74. 82 0
      components/gmssl/src/block_cipher.c
  75. 85 0
      components/gmssl/src/chacha20.c
  76. 2480 0
      components/gmssl/src/cms.c
  77. 504 0
      components/gmssl/src/digest.c
  78. 140 0
      components/gmssl/src/ec.c
  79. 206 0
      components/gmssl/src/gcm.c
  80. 177 0
      components/gmssl/src/gf128.c
  81. 299 0
      components/gmssl/src/hash_drbg.c
  82. 219 0
      components/gmssl/src/hex.c
  83. 205 0
      components/gmssl/src/hkdf.c
  84. 129 0
      components/gmssl/src/hmac.c
  85. 181 0
      components/gmssl/src/md5.c
  86. 0 154
      components/gmssl/src/modes/cbc128.c
  87. 188 0
      components/gmssl/src/pbkdf2.c
  88. 122 0
      components/gmssl/src/pem.c
  89. 454 0
      components/gmssl/src/pkcs8.c
  90. 23 0
      components/gmssl/src/rand.c
  91. 372 0
      components/gmssl/src/sgd.h
  92. 0 1055
      components/gmssl/src/sm2/sm2.c
  93. 1351 0
      components/gmssl/src/sm2_alg.c
  94. 174 0
      components/gmssl/src/sm2_blind.c
  95. 172 0
      components/gmssl/src/sm2_commit.c
  96. 412 0
      components/gmssl/src/sm2_elgamal.c
  97. 691 0
      components/gmssl/src/sm2_key.c
  98. 215 0
      components/gmssl/src/sm2_key_share.c
  99. 938 0
      components/gmssl/src/sm2_lib.c
  100. 138 0
      components/gmssl/src/sm2_recover.c

+ 176 - 0
components/gmssl/LICENSE

@@ -0,0 +1,176 @@
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS

+ 103 - 91
components/gmssl/src/luat_lib_gmssl.c → components/gmssl/bind/luat_lib_gmssl.c

@@ -2,7 +2,7 @@
 /*
 @module  gmssl
 @summary 国密算法
-@version 1.0
+@version 1.1
 @date    2023.03.02
 @author  chenxudong1208
 @demo gmssl
@@ -13,11 +13,10 @@
 #include "luat_str.h"
 #include <time.h>
 #include "luat_zbuff.h"
-#include "sm2.h"
-#include "sm3.h"
-#include "sm4.h"
-
-#include "luat_crypto.h"
+#include "gmssl/sm2.h"
+#include "gmssl/sm3.h"
+#include "gmssl/sm4.h"
+// #include "mbedtls/hmac_drbg.h"
 
 #define LUAT_LOG_TAG "sm"
 #include "luat_log.h"
@@ -26,11 +25,7 @@
 #define SM2_STR_LEN 300
 #define HEX_CODE 16
 
-static int myrand(void *ctx, unsigned char *msg, size_t size)
-{
-    luat_crypto_trng(msg, size);
-	return 0;
-}
+extern void luat_str_fromhex(char* str, size_t len, char* buff);
 
 static void DeletePaddingBuf(luaL_Buffer *B, uint8_t *pPadding, size_t nBufLen, uint8_t *pBuf, uint8_t pPaddLen)
 {
@@ -82,7 +77,7 @@ sm2算法加密
 @api sm.sm2encrypt(pkx,pky,data)
 @string 公钥x,必选
 @string 公钥y,必选
-@string 待计算的数据,必选
+@string 待计算的数据,必选,最长255字节
 @return string 加密后的字符串, 原样输出,未经HEX转换
 @usage
 local originStr = "encryption standard"
@@ -101,8 +96,8 @@ static int l_sm2_encrypt(lua_State *L)
     size_t pBufLen = 0;
     uint8_t *pkx = lua_tolstring(L, 1,&pkxLen);
     uint8_t *pky = lua_tolstring(L, 2,&pkyLen);
-    uint8_t *rand = lua_tolstring(L, 3,&randLen);
-    uint8_t *pBuf = lua_tolstring(L, 4,&pBufLen);
+    uint8_t *pBuf = lua_tolstring(L, 3,&pBufLen);
+    int ret = 0;
 
     //检查参数合法性
     if((pkxLen!=64))
@@ -113,27 +108,26 @@ static int l_sm2_encrypt(lua_State *L)
     {
         return luaL_error(L, "invalid pky password length=%d", pkyLen);
     }
-    
-    // TODO 改为luaBuffer
-    unsigned char *out = calloc(SM2_STR_LEN, sizeof(unsigned char));
-    int ret = 0;
-    size_t olen = 0;
-    sm2_context sm2;
-	sm2_init(&sm2);
-
-    //set key
-	sm2_read_string_public(&sm2, pkx, pky);
+    if (pBufLen > SM2_MAX_PLAINTEXT_SIZE) {
+        LLOGD("data too large max %d but %d", SM2_MAX_PLAINTEXT_SIZE, pBufLen);
+        return 0;
+    }
 
-    ret = sm2_do_encrypt(&sm2, (const unsigned char *)pBuf, pBufLen, out, SM2_STR_LEN, &olen,
-							 myrand, rand);
+    SM2_KEY sm2 = {0};
+    const SM2_POINT point;
+    char x[32];
+    char y[32];
+    luat_str_fromhex(pkx, 64, point.x);
+    luat_str_fromhex(pky, 64, point.y);
+    ret = sm2_key_set_public_key(&sm2.public_key, &point);
+    LLOGD("sm2_key_set_public_key %d", ret);
 
-    luaL_Buffer b;
-    luaL_buffinit( L, &b );                         
-    luaL_addlstring(&b, out, olen);
-    luaL_pushresult( &b );
+    unsigned char out[SM2_MAX_CIPHERTEXT_SIZE] = {0};
+    size_t olen = 0;
 
-    sm2_free(&sm2);
-    free(out);
+    ret = sm2_encrypt(&sm2, (const unsigned char *)pBuf, pBufLen, out, &olen);
+    LLOGD("sm2_encrypt ret %d", ret);
+    lua_pushlstring(L, out, olen);
     return 1;
 }
 
@@ -159,6 +153,7 @@ static int l_sm2_decrypt(lua_State *L)
     size_t pBufLen = 0;
     uint8_t *private = lua_tolstring(L, 1,&privateLen);
     uint8_t *pBuf = lua_tolstring(L, 2,&pBufLen);
+    int ret = 0;
 
     //检查参数合法性
     if((privateLen!=64))
@@ -166,64 +161,69 @@ static int l_sm2_decrypt(lua_State *L)
         return luaL_error(L, "invalid private password length=%d", privateLen);
     }
     
-    unsigned char *out = calloc(SM2_STR_LEN, sizeof(unsigned char));
-    int ret = 0;
+    SM2_KEY sm2 = {0};
+    char out[512] = {0};
     size_t olen = 0;
-    sm2_context sm2;
-	sm2_init(&sm2);
+    luat_str_fromhex(private, 64, sm2.private_key);
 
-    //set key
-    sm2_read_string_private(&sm2, private);
+    ret = sm2_decrypt(&sm2, pBuf, pBufLen, out, &olen);
+    LLOGD("sm2_decrypt ret %d", ret);
+    lua_pushlstring(L, out, olen);
+    return 1;
+}
 
-    ret = sm2_do_decrypt(&sm2, pBuf, pBufLen, out, SM2_STR_LEN, &olen);
 
-    luaL_Buffer b;
-    luaL_buffinit( L, &b );                         
-    luaL_addlstring(&b, out, olen);
-    luaL_pushresult( &b );
+/*
+sm3算法,算HASH值
+@api sm.sm3(data)
+@string 待计算的数据,必选
+@return string 对应的hash值
+@usage
+local encodeStr = gmssl.sm3("lqlq666lqlq946")
+log.info("testsm.sm3update",string.toHex(encodeStr))
+*/
+static int l_sm3_update(lua_State *L)
+{
+    size_t inputLen = 0;
+    uint8_t dgst[SM3_DIGEST_LENGTH];
+    const char *inputData = lua_tolstring(L,1,&inputLen);
+    sm3_digest(inputData, inputLen, dgst);
 
-    sm2_free(&sm2);
-    free(out);
+    lua_pushlstring(L, dgst, SM3_DIGEST_LENGTH);   
     return 1;
 }
 
+
 /*
-流式sm3算法加密
-@api sm.sm3update(data)
+sm3算法,算HASH值,但带HMAC
+@api sm.sm3hmac(data, key)
 @string 待计算的数据,必选
+@string 密钥
 @return string 对应的hash值
 @usage
-local encodeStr = gmssl.sm3update("lqlq666lqlq946")
+local encodeStr = gmssl.sm3hmac("lqlq666lqlq946", "123")
 log.info("testsm.sm3update",string.toHex(encodeStr))
 */
-static int l_sm3_update(lua_State *L)
+static int l_sm3hmac_update(lua_State *L)
 {
-    sm3_context ctx;
-    size_t inputLen;
-    uint8_t out[SM3_DIGEST_LENGTH];
-	uint32_t i = 0;
-    luaL_Buffer b;
-    luaL_buffinit(L, &b);  
-
-    const char *inputData = lua_tolstring(L,1,&inputLen);
-    sm3_init(&ctx);
-    sm3_starts(&ctx);
-    sm3_update(&ctx,(unsigned char *)inputData, inputLen);
-    memset(out, 0, SM3_DIGEST_LENGTH);   
-    sm3_finish(&ctx, out);
-    sm3_free(&ctx);
-
-    luaL_addlstring(&b, out, SM3_DIGEST_LENGTH);
-    luaL_pushresult(&b);
-    
+    size_t inputLen = 0;
+    size_t keyLen = 0;
+    uint8_t dgst[SM3_DIGEST_LENGTH];
+    const char *inputData = lua_tolstring(L, 1, &inputLen);
+    const char *keyData = lua_tolstring(L, 2, &keyLen);
+    sm3_hmac(keyData, keyLen, inputData, inputLen, dgst);
+
+    lua_pushlstring(L, dgst, SM3_DIGEST_LENGTH);   
     return 1;
 }
 
+#if 1
+
 /*
 SM4加密算法
 @api gmssl.sm4encrypt(mode,padding,originStr,password)
-@number  加密模式   
-@number  填充方式 
+@string  加密模式, CBC或ECB   
+@string  填充方式, NONE/ZERO/PKCS5/PKCS7
 @string  加密的字符串
 @string  密钥
 @return string 加密后的数据
@@ -264,11 +264,11 @@ static int l_sm4_encrypt(lua_State *L)
     //检查参数合法性
     if((nPswdLen!=16))
     {
-        return luaL_error(L, "invalid password length=%d, only support AES128,AES192,AES256", nPswdLen);
+        return luaL_error(L, "invalid password length=%d, only support 128bit Password", nPswdLen);
     }
     if((strcmp(pMode, "ECB")!=0) && (strcmp(pMode, "CBC")!=0))
     {
-        return luaL_error(L, "invalid mode=%s, only support ECB,CBC,CTR", pMode);
+        return luaL_error(L, "invalid mode=%s, only support ECB,CBC", pMode);
     }
     if((strcmp(pPadding, "NONE")!=0) && (strcmp(pPadding, "PKCS5")!=0) && (strcmp(pPadding, "PKCS7")!=0) && (strcmp(pPadding, "ZERO")!=0))
     {
@@ -276,7 +276,7 @@ static int l_sm4_encrypt(lua_State *L)
     }
     if(((strcmp(pMode, "CBC")==0)) && (nIVLen!=16))
     {
-        return luaL_error(L, "invalid iv length=%d, only support 16", nIVLen);
+        return luaL_error(L, "invalid iv length=%d, only support 128bit IV", nIVLen);
     }
 
     //构造填充数据
@@ -342,16 +342,21 @@ static int l_sm4_encrypt(lua_State *L)
             //开始分组加密,每16字节一组
             while(nRmnLen>0)
             {
-                sm4_ecb_encrypt(pInBuf+nBufLen-nRmnLen,pInBuf+nBufLen-nRmnLen,&sm4_key,1);	
-                luaL_addlstring(&b, pInBuf+nBufLen-nRmnLen, SM4_BLOCK_LEN);
+                // sm4_ecb_encrypt(pInBuf+nBufLen-nRmnLen,pInBuf+nBufLen-nRmnLen,&sm4_key,1);
+                char out[SM4_BLOCK_LEN];
+                sm4_encrypt(&sm4_key,pBuf+nBufLen-nRmnLen, out);
+                luaL_addlstring(&b, out, SM4_BLOCK_LEN);
                 nRmnLen -= SM4_BLOCK_LEN;
             }
         }
         else if((strcmp(pMode, "CBC") == 0))
         {
             //待加密数据一次性传入
-            sm4_cbc_encrypt(pInBuf,pInBuf,nBufLen,&sm4_key,pIV,1);
-            luaL_addlstring(&b, pInBuf, nBufLen);
+            // sm4_cbc_encrypt(pInBuf,pInBuf,nBufLen,&sm4_key,pIV,1);
+            char *out = luat_heap_malloc(nBufLen);
+            sm4_cbc_encrypt(&sm4_key, pIV, pInBuf, nBufLen / SM4_BLOCK_LEN, out);
+            luaL_addlstring(&b, out, nBufLen);
+            luat_heap_free(out);
         }
 
         if(pInBuf != NULL)
@@ -369,8 +374,8 @@ static int l_sm4_encrypt(lua_State *L)
 /*
 SM4解密算法
 @api gmssl.sm4decrypt(mode,padding,encodeStr,password)
-@number  加密模式   
-@number  填充方式 
+@string  加密模式, CBC或ECB   
+@string  填充方式, NONE/ZERO/PKCS5/PKCS7
 @string  已加密的字符串
 @string  密钥
 @return string 解密的字符串
@@ -388,9 +393,12 @@ static int l_sm4_decrypt(lua_State *L)
     uint8_t *pPassword = lua_tolstring(L, 4, &nPswdLen);
     size_t nIVLen = 0;
     uint8_t *pIV =  lua_tolstring(L, 5, &nIVLen);
+    char out[SM4_BLOCK_LEN];
 
     //检查参数合法性
-    if((strcmp(pMode, "CBC")==0) || (strcmp(pMode, "ECB")==0)){
+    int isCBC = strcmp(pMode, "CBC") == 0;
+    int isECB = strcmp(pMode, "ECB") == 0;
+    if(isCBC || isECB){
 	    if((nBufLen % 16) != 0){
 			return luaL_error(L, "invalid BufLen length=%d, BufLen must be Integer multiples of 16", nBufLen);
 		}
@@ -399,7 +407,7 @@ static int l_sm4_decrypt(lua_State *L)
     {
         return luaL_error(L, "invalid password length=%d, only support AES128,AES192,AES256", nPswdLen);
     }
-    if((strcmp(pMode, "ECB")!=0) && (strcmp(pMode, "CBC")!=0))
+    if(!isCBC && !isECB)
     {
         return luaL_error(L, "invalid mode=%s, only support ECB,CBC,CTR", pMode);
     }
@@ -407,7 +415,7 @@ static int l_sm4_decrypt(lua_State *L)
     {
         return luaL_error(L, "invalid padding=%s, only support NONE,PKCS5,PKCS7,ZERO", pPadding);
     }
-    if(((strcmp(pMode, "CBC")==0)) && (nIVLen!=16)) 
+    if(isCBC && (nIVLen!=16)) 
     {
         return luaL_error(L, "invalid iv length=%d, only support 16", nIVLen);
     }    
@@ -416,7 +424,6 @@ static int l_sm4_decrypt(lua_State *L)
     {       
         luaL_Buffer b;
         uint32_t nRmnLen;
-        memset(b.initb,0,LUAL_BUFFERSIZE);
         luaL_buffinit( L, &b );
 
         nRmnLen = nBufLen;
@@ -424,29 +431,32 @@ static int l_sm4_decrypt(lua_State *L)
         memset(&sm4_key,0,sizeof(SM4_KEY));
         sm4_set_decrypt_key(&sm4_key,pPassword);
 
-        if(strcmp(pMode, "ECB") == 0)
+        if(isECB == 0)
         {
             //开始分组解密,每16字节一组
             while(nRmnLen>0)
             {
-                sm4_ecb_encrypt(pBuf+nBufLen-nRmnLen,pBuf+nBufLen-nRmnLen,&sm4_key,0);
+                sm4_decrypt(&sm4_key,pBuf+nBufLen-nRmnLen, out);
                 //删除填充数据
                 if(nRmnLen==SM4_BLOCK_LEN)
                 {
-                    DeletePaddingBuf(&b, pPadding, SM4_BLOCK_LEN, pBuf+nBufLen-nRmnLen, SM4_BLOCK_LEN);
+                    DeletePaddingBuf(&b, pPadding, SM4_BLOCK_LEN, out, SM4_BLOCK_LEN);
                 }
                 else
                 {
-                    luaL_addlstring(&b, pBuf+nBufLen-nRmnLen, SM4_BLOCK_LEN);
+                    luaL_addlstring(&b, out, SM4_BLOCK_LEN);
                 }
                 nRmnLen -= SM4_BLOCK_LEN;
             }
         }
-        else if((strcmp(pMode, "CBC") == 0))
+        else if (isCBC)
         {
             //待解密数据一次性传入
-            sm4_cbc_encrypt(pBuf,pBuf,nBufLen,&sm4_key,pIV,0);
-            DeletePaddingBuf(&b, pPadding, nBufLen, pBuf, SM4_BLOCK_LEN);
+            char *out = luat_heap_malloc(nBufLen);
+            // sm4_cbc_encrypt(pBuf,pBuf,nBufLen,&sm4_key,pIV,0);
+            sm4_cbc_decrypt(&sm4_key, pIV, pBuf, nBufLen/SM4_BLOCK_LEN, out);
+            DeletePaddingBuf(&b, pPadding, nBufLen, out, SM4_BLOCK_LEN);
+            luat_heap_free(out);
         }
 		
         luaL_pushresult( &b );
@@ -454,14 +464,16 @@ static int l_sm4_decrypt(lua_State *L)
     }    
 }
 
+#endif
+
 #include "rotable2.h"
 static const rotable_Reg_t reg_gmssl[] =
 {
-#if defined(ECP_DP_SM2_256V1_ENABLED) && defined(MBEDTLS_ECP_C)
     { "sm2encrypt",      ROREG_FUNC(l_sm2_encrypt)},
     { "sm2decrypt",      ROREG_FUNC(l_sm2_decrypt)},
-#endif
     { "sm3update",       ROREG_FUNC(l_sm3_update)},
+    { "sm3",             ROREG_FUNC(l_sm3_update)},
+    { "sm3hmac",         ROREG_FUNC(l_sm3hmac_update)},
     { "sm4encrypt",      ROREG_FUNC(l_sm4_encrypt)},
     { "sm4decrypt",      ROREG_FUNC(l_sm4_decrypt)},
 

+ 111 - 0
components/gmssl/include/gmssl/aead.h

@@ -0,0 +1,111 @@
+/*
+ *  Copyright 2014-2023 The GmSSL Project. All Rights Reserved.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the License); you may
+ *  not use this file except in compliance with the License.
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ */
+
+#ifndef GMSSL_AEAD_H
+#define GMSSL_AEAD_H
+
+#include <string.h>
+#include <stdint.h>
+#include <gmssl/sm3.h>
+#include <gmssl/sm4.h>
+#include <gmssl/gcm.h>
+#include <gmssl/api.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+typedef struct {
+	SM4_CBC_CTX enc_ctx;
+	SM3_HMAC_CTX mac_ctx;
+	uint8_t mac[SM3_HMAC_SIZE];
+	size_t maclen;
+} SM4_CBC_SM3_HMAC_CTX;
+
+#define SM4_CBC_SM3_HMAC_KEY_SIZE 48
+#define SM4_CBC_SM3_HMAC_IV_SIZE  16
+
+_gmssl_export int sm4_cbc_sm3_hmac_encrypt_init(SM4_CBC_SM3_HMAC_CTX *ctx,
+	const uint8_t *key, size_t keylen, const uint8_t *iv, size_t ivlen,
+	const uint8_t *aad, size_t aadlen);
+_gmssl_export int sm4_cbc_sm3_hmac_encrypt_update(SM4_CBC_SM3_HMAC_CTX *ctx,
+	const uint8_t *in, size_t inlen, uint8_t *out, size_t *outlen);
+_gmssl_export int sm4_cbc_sm3_hmac_encrypt_finish(SM4_CBC_SM3_HMAC_CTX *ctx,
+	uint8_t *out, size_t *outlen);
+_gmssl_export int sm4_cbc_sm3_hmac_decrypt_init(SM4_CBC_SM3_HMAC_CTX *ctx,
+	const uint8_t *key, size_t keylen, const uint8_t *iv, size_t ivlen,
+	const uint8_t *aad, size_t aadlen);
+_gmssl_export int sm4_cbc_sm3_hmac_decrypt_update(SM4_CBC_SM3_HMAC_CTX *ctx,
+	const uint8_t *in, size_t inlen, uint8_t *out, size_t *outlen);
+_gmssl_export int sm4_cbc_sm3_hmac_decrypt_finish(SM4_CBC_SM3_HMAC_CTX *ctx,
+	uint8_t *out, size_t *outlen);
+
+
+typedef struct {
+	SM4_CTR_CTX enc_ctx;
+	SM3_HMAC_CTX mac_ctx;
+	uint8_t mac[SM3_HMAC_SIZE];
+	size_t maclen;
+} SM4_CTR_SM3_HMAC_CTX;
+
+#define SM4_CTR_SM3_HMAC_KEY_SIZE 48
+#define SM4_CTR_SM3_HMAC_IV_SIZE  16
+
+_gmssl_export int sm4_ctr_sm3_hmac_encrypt_init(SM4_CTR_SM3_HMAC_CTX *ctx,
+	const uint8_t *key, size_t keylen, const uint8_t *iv, size_t ivlen,
+	const uint8_t *aad, size_t aadlen);
+_gmssl_export int sm4_ctr_sm3_hmac_encrypt_update(SM4_CTR_SM3_HMAC_CTX *ctx,
+	const uint8_t *in, size_t inlen, uint8_t *out, size_t *outlen);
+_gmssl_export int sm4_ctr_sm3_hmac_encrypt_finish(SM4_CTR_SM3_HMAC_CTX *ctx,
+	uint8_t *out, size_t *outlen);
+_gmssl_export int sm4_ctr_sm3_hmac_decrypt_init(SM4_CTR_SM3_HMAC_CTX *ctx,
+	const uint8_t *key, size_t keylen, const uint8_t *iv, size_t ivlen,
+	const uint8_t *aad, size_t aadlen);
+_gmssl_export int sm4_ctr_sm3_hmac_decrypt_update(SM4_CTR_SM3_HMAC_CTX *ctx,
+	const uint8_t *in, size_t inlen, uint8_t *out, size_t *outlen);
+_gmssl_export int sm4_ctr_sm3_hmac_decrypt_finish(SM4_CTR_SM3_HMAC_CTX *ctx,
+	uint8_t *out, size_t *outlen);
+
+
+typedef struct {
+	SM4_CTR_CTX enc_ctx;
+	GHASH_CTX mac_ctx;
+	uint8_t Y[16]; // E(K, Y_0)
+	size_t taglen;
+	uint8_t mac[16];
+	size_t maclen;
+} SM4_GCM_CTX;
+
+#define SM4_GCM_KEY_SIZE 16
+#define SM4_GCM_MIN_IV_SIZE 1
+#define SM4_GCM_DEFAULT_IV_SIZE 12
+#define SM4_GCM_MAX_IV_SIZE 64
+#define SM4_GCM_DEFAULT_TAG_SIZE 16
+
+_gmssl_export int sm4_gcm_encrypt_init(SM4_GCM_CTX *ctx,
+	const uint8_t *key, size_t keylen, const uint8_t *iv, size_t ivlen,
+	const uint8_t *aad, size_t aadlen, size_t taglen);
+_gmssl_export int sm4_gcm_encrypt_update(SM4_GCM_CTX *ctx,
+	const uint8_t *in, size_t inlen, uint8_t *out, size_t *outlen);
+_gmssl_export int sm4_gcm_encrypt_finish(SM4_GCM_CTX *ctx,
+	uint8_t *out, size_t *outlen);
+_gmssl_export int sm4_gcm_decrypt_init(SM4_GCM_CTX *ctx,
+	const uint8_t *key, size_t keylen, const uint8_t *iv, size_t ivlen,
+	const uint8_t *aad, size_t aadlen, size_t taglen);
+_gmssl_export int sm4_gcm_decrypt_update(SM4_GCM_CTX *ctx,
+	const uint8_t *in, size_t inlen, uint8_t *out, size_t *outlen);
+_gmssl_export int sm4_gcm_decrypt_finish(SM4_GCM_CTX *ctx,
+	uint8_t *out, size_t *outlen);
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif

+ 90 - 0
components/gmssl/include/gmssl/aes.h

@@ -0,0 +1,90 @@
+/*
+ *  Copyright 2014-2022 The GmSSL Project. All Rights Reserved.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the License); you may
+ *  not use this file except in compliance with the License.
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ */
+
+
+
+#ifndef GMSSL_AES_H
+#define GMSSL_AES_H
+
+#include <stdint.h>
+#include <stdlib.h>
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+
+#define AES128_KEY_BITS		128
+#define AES192_KEY_BITS		192
+#define AES256_KEY_BITS		256
+
+#define AES128_KEY_SIZE		(AES128_KEY_BITS/8)
+#define AES192_KEY_SIZE		(AES192_KEY_BITS/8)
+#define AES256_KEY_SIZE		(AES256_KEY_BITS/8)
+
+#define AES_BLOCK_SIZE		16
+
+#define AES128_ROUNDS		10
+#define AES192_ROUNDS		12
+#define AES256_ROUNDS		14
+#define AES_MAX_ROUNDS		AES256_ROUNDS
+
+
+typedef struct {
+	uint32_t rk[4 * (AES_MAX_ROUNDS + 1)];
+	size_t rounds;
+} AES_KEY;
+
+int aes_set_encrypt_key(AES_KEY *key, const uint8_t *raw_key, size_t raw_key_len);
+int aes_set_decrypt_key(AES_KEY *key, const uint8_t *raw_key, size_t raw_key_len);
+void aes_encrypt(const AES_KEY *key, const uint8_t in[AES_BLOCK_SIZE], uint8_t out[AES_BLOCK_SIZE]);
+void aes_decrypt(const AES_KEY *key, const uint8_t in[AES_BLOCK_SIZE], uint8_t out[AES_BLOCK_SIZE]);
+
+
+void aes_cbc_encrypt(const AES_KEY *key, const uint8_t iv[AES_BLOCK_SIZE],
+	const uint8_t *in, size_t nblocks, uint8_t *out);
+void aes_cbc_decrypt(const AES_KEY *key, const uint8_t iv[AES_BLOCK_SIZE],
+	const uint8_t *in, size_t nblocks, uint8_t *out);
+int aes_cbc_padding_encrypt(const AES_KEY *key, const uint8_t iv[AES_BLOCK_SIZE],
+	const uint8_t *in, size_t inlen,
+	uint8_t *out, size_t *outlen);
+int aes_cbc_padding_decrypt(const AES_KEY *key, const uint8_t iv[AES_BLOCK_SIZE],
+	const uint8_t *in, size_t inlen,
+	uint8_t *out, size_t *outlen);
+
+void aes_ctr_encrypt(const AES_KEY *key, uint8_t ctr[AES_BLOCK_SIZE],
+	const uint8_t *in, size_t inlen, uint8_t *out);
+#define aes_ctr_decrypt(key,ctr,in,inlen,out) aes_ctr_encrypt(key,ctr,in,inlen,out)
+
+
+#define AES_GCM_IV_MIN_SIZE		1
+#define AES_GCM_IV_MAX_SIZE		((uint64_t)(1 << (64-3)))
+#define AES_GCM_IV_DEFAULT_BITS		96
+#define AES_GCM_IV_DEFAULT_SIZE		12
+
+#define AES_GCM_MIN_AAD_SIZE		0
+#define AES_GCM_MAX_AAD_SIZE		((uint64_t)(1 << (64-3)))
+
+#define AES_GCM_MIN_PLAINTEXT_SIZE	0
+#define AES_GCM_MAX_PLAINTEXT_SIZE	((((uint64_t)1 << 39) - 256) >> 3)
+
+#define AES_GCM_MAX_TAG_SIZE		16
+
+int aes_gcm_encrypt(const AES_KEY *key, const uint8_t *iv, size_t ivlen,
+	const uint8_t *aad, size_t aadlen, const uint8_t *in, size_t inlen,
+	uint8_t *out, size_t taglen, uint8_t *tag);
+int aes_gcm_decrypt(const AES_KEY *key, const uint8_t *iv, size_t ivlen,
+	const uint8_t *aad, size_t aadlen, const uint8_t *in, size_t inlen,
+	const uint8_t *tag, size_t taglen, uint8_t *out);
+
+
+#ifdef  __cplusplus
+}
+#endif
+#endif

+ 22 - 0
components/gmssl/include/gmssl/api.h

@@ -0,0 +1,22 @@
+/*
+ *  Copyright 2014-2023 The GmSSL Project. All Rights Reserved.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the License); you may
+ *  not use this file except in compliance with the License.
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ */
+
+#ifndef GMSSL_API_H
+#define GMSSL_API_H
+
+
+#ifdef WIN32
+#define _gmssl_export  __declspec(dllexport)
+#else
+// use -fvisibility=hidden to change the "default" behavior
+#define _gmssl_export  __attribute__((visibility("default")))
+#endif
+
+
+#endif

+ 301 - 0
components/gmssl/include/gmssl/asn1.h

@@ -0,0 +1,301 @@
+/*
+ *  Copyright 2014-2023 The GmSSL Project. All Rights Reserved.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the License); you may
+ *  not use this file except in compliance with the License.
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ */
+
+
+
+#ifndef GMSSL_ASN1_H
+#define GMSSL_ASN1_H
+
+#include <time.h>
+#include <stdlib.h>
+#include <stdint.h>
+
+#if __cplusplus
+extern "C" {
+#endif
+
+
+
+#define ASN1_TAG_UNIVERSAL		0x00
+#define ASN1_TAG_APPLICATION		0x40
+#define ASN1_TAG_CONTENT_SPECIFIC	0x80
+#define ASN1_TAG_PRIVATE		0xC0
+#define ASN1_TAG_PRIMITIVE		0x00
+#define ASN1_TAG_CONSTRUCTED		0x20
+
+#define ASN1_TAG_IMPLICIT(index)	(ASN1_TAG_CONTENT_SPECIFIC|(index))
+#define ASN1_TAG_EXPLICIT(index)	ASN1_TAG_IMPLICIT(ASN1_TAG_CONSTRUCTED|(index))
+
+
+#define ASN1_FMT_FULL	0x01
+
+
+enum ASN1_TAG {
+	ASN1_TAG_BOOLEAN		= 1,
+	ASN1_TAG_INTEGER		= 2,
+	ASN1_TAG_BIT_STRING		= 3,
+	ASN1_TAG_OCTET_STRING		= 4,
+	ASN1_TAG_NULL			= 5,
+	ASN1_TAG_OBJECT_IDENTIFIER	= 6,
+	ASN1_TAG_ObjectDescriptor	= 7,
+	ASN1_TAG_EXTERNAL		= 8,
+	ASN1_TAG_REAL			= 9,
+	ASN1_TAG_ENUMERATED		= 10, // 0x0A
+	ASN1_TAG_EMBEDDED		= 11, // 0x0B
+	ASN1_TAG_UTF8String		= 12, // 0x0C
+	ASN1_TAG_RELATIVE_OID		= 13, // 0x0D
+	ASN1_TAG_NumericString		= 18, // 0x12
+	ASN1_TAG_PrintableString	= 19, // 0x13, printable subset of ascii
+	ASN1_TAG_TeletexString		= 20, // 0x14, T61String
+	ASN1_TAG_VideotexString		= 21, // 0x15
+	ASN1_TAG_IA5String		= 22, // 0x16, 7-bit ascii
+	ASN1_TAG_UTCTime		= 23, // 0x17
+	ASN1_TAG_GeneralizedTime	= 24, // 0x18
+	ASN1_TAG_GraphicString		= 25, // 0x19
+	ASN1_TAG_VisibleString		= 26, // 0x20
+	ASN1_TAG_GeneralString		= 27, // 0x21
+	ASN1_TAG_UniversalString	= 28, // 0x22
+	ASN1_TAG_CHARACTER_STRING	= 29, // 0x23
+	ASN1_TAG_BMPString		= 30, // 0x24, 2-byte unicode with zeros
+	ASN1_TAG_SEQUENCE		= 0x30,
+	ASN1_TAG_SET			= 0x31,
+	ASN1_TAG_EXPLICIT		= 0xa0,
+};
+
+
+const char *asn1_tag_name(int tag);
+int asn1_tag_is_cstring(int tag);
+int asn1_tag_to_der(int tag, uint8_t **out, size_t *outlen);
+int asn1_tag_from_der(int *tag, const uint8_t **in, size_t *inlen);
+int asn1_tag_from_der_readonly(int *tag, const uint8_t **in, size_t *inlen); // read the next tag without changing *in,*inlen
+int asn1_length_to_der(size_t dlen, uint8_t **out, size_t *outlen);
+int asn1_length_from_der(size_t *dlen, const uint8_t **in, size_t *inlen);
+int asn1_length_is_zero(size_t len);
+int asn1_length_le(size_t len1, size_t len2); // less than
+int asn1_data_to_der(const uint8_t *d, size_t dlen, uint8_t **out, size_t *outlen);
+int asn1_data_from_der(const uint8_t **d, size_t dlen, const uint8_t **in, size_t *inlen);
+
+int asn1_type_to_der(int tag, const uint8_t *d, size_t dlen, uint8_t **out, size_t *outlen);
+int asn1_type_from_der(int tag, const uint8_t **d, size_t *dlen, const uint8_t **in, size_t *inlen);
+int asn1_nonempty_type_to_der(int tag, const uint8_t *d, size_t dlen, uint8_t **out, size_t *outlen);
+int asn1_nonempty_type_from_der(int tag, const uint8_t **d, size_t *dlen, const uint8_t **in, size_t *inlen);
+int asn1_any_type_from_der(int *tag, const uint8_t **d, size_t *dlen, const uint8_t **in, size_t *inlen);
+int asn1_any_to_der(const uint8_t *a, size_t alen, uint8_t **out, size_t *outlen); // 调用方应保证a,alen为TLV
+int asn1_any_from_der(const uint8_t **a, size_t *alen, const uint8_t **in, size_t *inlen); // 该函数会检查输入是否为TLV
+
+#define ASN1_TRUE 0xff
+#define ASN1_FALSE 0x00
+
+const char *asn1_boolean_name(int val);
+int asn1_boolean_from_name(int *val, const char *name);
+int asn1_boolean_to_der_ex(int tag, int val, uint8_t **out, size_t *outlen);
+int asn1_boolean_from_der_ex(int tag, int *val, const uint8_t **in, size_t *inlen);
+#define asn1_boolean_to_der(val,out,outlen) asn1_boolean_to_der_ex(ASN1_TAG_BOOLEAN,val,out,outlen)
+#define asn1_boolean_from_der(val,in,inlen) asn1_boolean_from_der_ex(ASN1_TAG_BOOLEAN,val,in,inlen)
+#define asn1_implicit_boolean_to_der(i,val,out,outlen) asn1_boolean_to_der_ex(ASN1_TAG_IMPLICIT(i),val,out,outlen)
+#define asn1_implicit_boolean_from_der(i,val,in,inlen) asn1_boolean_from_der_ex(ASN1_TAG_IMPLICIT(i),val,in,inlen)
+
+// asn1_integer_ 不支持负数编解码
+int asn1_integer_to_der_ex(int tag, const uint8_t *d, size_t dlen, uint8_t **out, size_t *outlen);
+int asn1_integer_from_der_ex(int tag, const uint8_t **d, size_t *dlen, const uint8_t **in, size_t *inlen);
+#define asn1_integer_to_der(d,dlen,out,outlen) asn1_integer_to_der_ex(ASN1_TAG_INTEGER,d,dlen,out,outlen)
+#define asn1_integer_from_der(d,dlen,in,inlen) asn1_integer_from_der_ex(ASN1_TAG_INTEGER,d,dlen,in,inlen)
+#define asn1_implicit_integer_to_der(i,d,dlen,out,outlen) asn1_integer_to_der_ex(ASN1_TAG_IMPLICIT(i),d,dlen,out,outlen)
+#define asn1_implicit_integer_from_der(i,d,dlen,in,inlen) asn1_integer_from_der_ex(ASN1_TAG_IMPLICIT(i),d,dlen,in,inlen)
+
+// asn1_int_ 只支持小的无符号整数的编解码,不支持负数
+int asn1_int_to_der_ex(int tag, int val, uint8_t **out, size_t *outlen); // 当 val == -1 时,不输出,返回 0
+int asn1_int_from_der_ex(int tag, int *val, const uint8_t **in, size_t *inlen); // 不支持负数,返回0时 *val 设置为 -1
+#define asn1_int_to_der(val,out,outlen) asn1_int_to_der_ex(ASN1_TAG_INTEGER,val,out,outlen)
+#define asn1_int_from_der(val,in,inlen) asn1_int_from_der_ex(ASN1_TAG_INTEGER,val,in,inlen)
+#define asn1_implicit_int_to_der(i,val,out,outlen) asn1_int_to_der_ex(ASN1_TAG_IMPLICIT(i),val,out,outlen)
+#define asn1_implicit_int_from_der(i,val,in,inlen) asn1_int_from_der_ex(ASN1_TAG_IMPLICIT(i),val,in,inlen)
+
+// 比特长度不必须为8的整数倍
+int asn1_bit_string_to_der_ex(int tag, const uint8_t *d, size_t nbits, uint8_t **out, size_t *outlen);
+int asn1_bit_string_from_der_ex(int tag, const uint8_t **d, size_t *nbits, const uint8_t **in, size_t *inlen);
+#define asn1_bit_string_to_der(d,nbits,out,outlen) asn1_bit_string_to_der_ex(ASN1_TAG_BIT_STRING,d,nbits,out,outlen)
+#define asn1_bit_string_from_der(d,nbits,in,inlen) asn1_bit_string_from_der_ex(ASN1_TAG_BIT_STRING,d,nbits,in,inlen)
+#define asn1_implicit_bit_string_to_der(i,d,nbits,out,outlen) asn1_bit_string_to_der_ex(ASN1_TAG_IMPLICIT(i),d,nbits,out,outlen)
+#define asn1_implicit_bit_string_from_der(i,d,nbits,in,inlen) asn1_bit_string_from_der_ex(ASN1_TAG_IMPLICIT(i),d,nbits,in,inlen)
+
+// 比特长度必须为8的整数倍,因此使用字节长度
+int asn1_bit_octets_to_der_ex(int tag, const uint8_t *d, size_t dlen, uint8_t **out, size_t *outlen);
+int asn1_bit_octets_from_der_ex(int tag, const uint8_t **d, size_t *dlen, const uint8_t **in, size_t *inlen);
+#define asn1_bit_octets_to_der(d,dlen,out,outlen) asn1_bit_octets_to_der_ex(ASN1_TAG_BIT_STRING,d,dlen,out,outlen)
+#define asn1_bit_octets_from_der(d,dlen,in,inlen) asn1_bit_octets_from_der_ex(ASN1_TAG_BIT_STRING,d,dlen,in,inlen)
+#define asn1_implicit_bit_octets_to_der(i,d,dlen,out,outlen) asn1_bit_octets_to_der_ex(ASN1_TAG_IMPLICIT(i),d,dlen,out,outlen)
+#define asn1_implicit_bit_octets_from_der(i,d,dlen,in,inlen) asn1_bit_octets_from_der_ex(ASN1_TAG_IMPLICIT(i),d,dlen,in,inlen)
+
+// bits == -1 不编码,只支持较少的比特数量
+int asn1_bits_to_der_ex(int tag, int bits, uint8_t **out, size_t *outlen);
+int asn1_bits_from_der_ex(int tag, int *bits, const uint8_t **in, size_t *inlen);
+#define asn1_bits_to_der(bits,out,outlen) asn1_bits_to_der_ex(ASN1_TAG_BIT_STRING,bits,out,outlen)
+#define asn1_bits_from_der(bits,in,inlen) asn1_bits_from_der_ex(ASN1_TAG_BIT_STRING,bits,in,inlen)
+#define asn1_implicit_bits_to_der(i,bits,out,outlen) asn1_bits_to_der_ex(ASN1_TAG_IMPLICIT(i),bits,out,outlen)
+#define asn1_implicit_bits_from_der(i,bits,in,inlen) asn1_bits_from_der_ex(ASN1_TAG_IMPLICIT(i),bits,in,inlen)
+// names[i]对应第i个比特
+int asn1_bits_print(FILE *fp, int fmt, int ind, const char *label, const char **names, size_t names_cnt, int bits);
+
+#define asn1_octet_string_to_der_ex(tag,d,dlen,out,outlen) asn1_type_to_der(tag,d,dlen,out,outlen)
+#define asn1_octet_string_from_der_ex(tag,d,dlen,in,inlen) asn1_type_from_der(tag,d,dlen,in,inlen)
+#define asn1_octet_string_to_der(d,dlen,out,outlen) asn1_type_to_der(ASN1_TAG_OCTET_STRING,d,dlen,out,outlen)
+#define asn1_octet_string_from_der(d,dlen,in,inlen) asn1_type_from_der(ASN1_TAG_OCTET_STRING,d,dlen,in,inlen)
+#define asn1_implicit_octet_string_to_der(i,d,dlen,out,outlen) asn1_type_to_der(ASN1_TAG_IMPLICIT(i),d,dlen,out,outlen)
+#define asn1_implicit_octet_string_from_der(i,d,dlen,in,inlen) asn1_type_from_der(ASN1_TAG_IMPLICIT(i),d,dlen,in,inlen)
+
+const char *asn1_null_name(void);
+int asn1_null_to_der(uint8_t **out, size_t *outlen);
+int asn1_null_from_der(const uint8_t **in, size_t *inlen);
+
+#define ASN1_OID_MIN_NODES 2
+#define ASN1_OID_MAX_NODES 32
+#define ASN1_OID_MIN_OCTETS 1
+#define ASN1_OID_MAX_OCTETS (1 + (ASN1_OID_MAX_NODES - 2) * 5)
+int asn1_object_identifier_to_octets(const uint32_t *nodes, size_t nodes_cnt, uint8_t *out, size_t *outlen);
+int asn1_object_identifier_from_octets(uint32_t *nodes, size_t *nodes_cnt, const uint8_t *in, size_t inlen);
+
+int asn1_object_identifier_to_der_ex(int tag, const uint32_t *nodes, size_t nodes_cnt, uint8_t **out, size_t *outlen);
+int asn1_object_identifier_from_der_ex(int tag, uint32_t *nodes, size_t *nodes_cnt, const uint8_t **in, size_t *inlen);
+#define asn1_object_identifier_to_der(nodes,nodes_cnt,out,outlen) asn1_object_identifier_to_der_ex(ASN1_TAG_OBJECT_IDENTIFIER,nodes,nodes_cnt,out,outlen)
+#define asn1_object_identifier_from_der(nodes,nodes_cnt,in,inlen) asn1_object_identifier_from_der_ex(ASN1_TAG_OBJECT_IDENTIFIER,nodes,nodes_cnt,in,inlen)
+#define asn1_implicit_object_identifier_to_der(i,nodes,nodes_cnt,out,outlen) asn1_object_identifier_to_der_ex(ASN1_TAG_IMPLICIT(i),nodes,nodes_cnt,out,outlen)
+#define asn1_implicit_object_identifier_from_der(i,nodes,nodes_cnt,in,inlen) asn1_object_identifier_from_der_ex(ASN1_TAG_IMPLICIT(i),nodes,nodes_cnt,in,inlen)
+int asn1_object_identifier_equ(const uint32_t *a, size_t a_cnt, const uint32_t *b, size_t b_cnt);
+int asn1_object_identifier_print(FILE *fp, int fmt, int ind, const char *label, const char *name,
+	const uint32_t *nodes, size_t nodes_cnt);
+
+typedef struct {
+	int oid;
+	char *name;
+	uint32_t *nodes;
+	size_t nodes_cnt;
+	int flags;
+	char *description;
+} ASN1_OID_INFO;
+
+const ASN1_OID_INFO *asn1_oid_info_from_name(const ASN1_OID_INFO *infos, size_t count, const char *name);
+const ASN1_OID_INFO *asn1_oid_info_from_oid(const ASN1_OID_INFO *infos, size_t count, int oid);
+// 如果一个正确解析的OID并不在infos列表中,那么仍然返回1,但是调用方必须检查返回的info是否为空
+int asn1_oid_info_from_der_ex(const ASN1_OID_INFO **info, uint32_t *nodes, size_t *nodes_cnt,
+	const ASN1_OID_INFO *infos, size_t count, const uint8_t **in, size_t *inlen);
+int asn1_oid_info_from_der(const ASN1_OID_INFO **info,
+	const ASN1_OID_INFO *infos, size_t count, const uint8_t **in, size_t *inlen);
+
+#define asn1_enumerated_to_der_ex(tag,val,out,outlen) asn1_int_to_der_ex(tag,val,out,outlen)
+#define asn1_enumerated_from_der_ex(tag,val,in,inlen) asn1_int_from_der_ex(tag,val,in,inlen)
+#define asn1_enumerated_to_der(val,out,outlen) asn1_int_to_der_ex(ASN1_TAG_ENUMERATED,val,out,outlen)
+#define asn1_enumerated_from_der(val,in,inlen) asn1_int_from_der_ex(ASN1_TAG_ENUMERATED,val,in,inlen)
+#define asn1_implicit_enumerated_to_der(i,val,out,outlen) asn1_int_to_der_ex(ASN1_TAG_IMPLICIT(i),val,out,outlen)
+#define asn1_implicit_enumerated_from_der(i,val,in,inlen) asn1_int_from_der_ex(ASN1_TAG_IMPLICIT(i),val,in,inlen)
+
+int asn1_string_is_utf8_string(const char *d, size_t dlen);
+int asn1_utf8_string_to_der_ex(int tag, const char *d, size_t dlen, uint8_t **out, size_t *outlen);
+int asn1_utf8_string_from_der_ex(int tag, const char **d, size_t *dlen, const uint8_t **in, size_t *inlen);
+#define asn1_utf8_string_to_der(d,dlen,out,outlen) asn1_utf8_string_to_der_ex(ASN1_TAG_UTF8String,d,dlen,out,outlen)
+#define asn1_utf8_string_from_der(d,dlen,in,inlen) asn1_utf8_string_from_der_ex(ASN1_TAG_UTF8String,d,dlen,in,inlen)
+#define asn1_implicit_utf8_string_to_der(i,d,dlen,out,outlen) asn1_utf8_string_to_der_ex(ASN1_TAG_IMPLICIT(i),d,dlen,out,outlen)
+#define asn1_implicit_utf8_string_from_der(i,d,dlen,in,inlen) asn1_utf8_string_from_der_ex(ASN1_TAG_IMPLICIT(i),d,dlen,in,inlen)
+
+int asn1_string_is_printable_string(const char *d, size_t dlen);
+int asn1_printable_string_case_ignore_match(const char *a, size_t alen, const char *b, size_t blen);
+int asn1_printable_string_to_der_ex(int tag, const char *d, size_t dlen, uint8_t **out, size_t *outlen);
+int asn1_printable_string_from_der_ex(int tag, const char **d, size_t *dlen, const uint8_t **in, size_t *inlen);
+#define asn1_printable_string_to_der(d,dlen,out,outlen)	asn1_printable_string_to_der_ex(ASN1_TAG_PrintableString,d,dlen,out,outlen)
+#define asn1_printable_string_from_der(d,dlen,in,inlen)	asn1_printable_string_from_der_ex(ASN1_TAG_PrintableString,d,dlen,in,inlen)
+#define asn1_implicit_printable_string_to_der(i,d,dlen,out,outlen) asn1_printable_string_to_der_ex(ASN1_TAG_IMPLICIT(i),d,dlen,out,outlen)
+#define asn1_implicit_printable_string_from_der(i,d,dlen,in,inlen) asn1_printable_string_from_der_ex(ASN1_TAG_IMPLICIT(i),d,dlen,in,inlen)
+
+int asn1_string_is_ia5_string(const char *d, size_t dlen);
+int asn1_ia5_string_to_der_ex(int tag, const char *d, size_t dlen, uint8_t **out, size_t *outlen);
+int asn1_ia5_string_from_der_ex(int tag, const char **d, size_t *dlen, const uint8_t **in, size_t *inlen);
+#define asn1_ia5_string_to_der(d,dlen,out,outlen) asn1_ia5_string_to_der_ex(ASN1_TAG_IA5String,d,dlen,out,outlen)
+#define asn1_ia5_string_from_der(d,dlen,in,inlen) asn1_ia5_string_from_der_ex(ASN1_TAG_IA5String,d,dlen,in,inlen)
+#define asn1_implicit_ia5_string_to_der(i,d,dlen,out,outlen) asn1_ia5_string_to_der_ex(ASN1_TAG_IMPLICIT(i),d,dlen,out,outlen)
+#define asn1_implicit_ia5_string_from_der(i,d,dlen,in,inlen) asn1_ia5_string_from_der_ex(ASN1_TAG_IMPLICIT(i),d,dlen,in,inlen)
+
+int asn1_string_print(FILE *fp, int fmt, int ind, const char *label, int tag, const uint8_t *d, size_t dlen);
+
+#define ASN1_UTC_TIME_STRLEN		(sizeof("YYMMDDHHMMSSZ")-1)
+#define ASN1_GENERALIZED_TIME_STRLEN	(sizeof("YYYYMMDDHHMMSSZ")-1)
+#define ASN1_GENERALIZED_TIME_MAX_SIZE	(2 + ASN1_GENERALIZED_TIME_STRLEN)
+
+int asn1_time_to_str(int utc_time, time_t timestamp, char *str);
+int asn1_time_from_str(int utc_time, time_t *timestamp, const char *str);
+
+int asn1_utc_time_to_der_ex(int tag, time_t tv, uint8_t **out, size_t *outlen);
+int asn1_utc_time_from_der_ex(int tag, time_t *tv, const uint8_t **in, size_t *inlen);
+#define asn1_utc_time_to_der(tv,out,outlen) asn1_utc_time_to_der_ex(ASN1_TAG_UTCTime,tv,out,outlen)
+#define asn1_utc_time_from_der(tv,in,inlen) asn1_utc_time_from_der_ex(ASN1_TAG_UTCTime,tv,in,inlen)
+#define asn1_implicit_utc_time_to_der(i,tv,out,outlen) asn1_utc_time_to_der_ex(ASN1_TAG_IMPLICIT(i),tv,out,outlen)
+#define asn1_implicit_utc_time_from_der(i,tv,in,inlen) asn1_utc_time_from_der_ex(ASN1_TAG_IMPLICIT(i),tv,in,inlen)
+
+int asn1_generalized_time_to_der_ex(int tag, time_t tv, uint8_t **out, size_t *outlen);
+int asn1_generalized_time_from_der_ex(int tag, time_t *tv, const uint8_t **in, size_t *inlen);
+#define asn1_generalized_time_to_der(tv,out,outlen) asn1_generalized_time_to_der_ex(ASN1_TAG_GeneralizedTime,tv,out,outlen)
+#define asn1_generalized_time_from_der(tv,in,inlen) asn1_generalized_time_from_der_ex(ASN1_TAG_GeneralizedTime,tv,in,inlen)
+#define asn1_implicit_generalized_time_to_der(i,tv,out,outlen) asn1_generalized_time_to_der_ex(ASN1_TAG_IMPLICIT(i),tv,out,outlen)
+#define asn1_implicit_generalized_time_from_der(i,tv,in,inlen) asn1_generalized_time_from_der_ex(ASN1_TAG_IMPLICIT(i),tv,in,inlen)
+
+// BasicConstraints might be an empty sequence in entity certificates
+#define asn1_sequence_to_der(d,dlen,out,outlen) asn1_type_to_der(ASN1_TAG_SEQUENCE,d,dlen,out,outlen)
+#define asn1_sequence_from_der(d,dlen,in,inlen) asn1_type_from_der(ASN1_TAG_SEQUENCE,d,dlen,in,inlen)
+#define asn1_implicit_sequence_to_der(i,d,dlen,out,outlen) asn1_nonempty_type_to_der(ASN1_TAG_EXPLICIT(i),d,dlen,out,outlen)
+#define asn1_implicit_sequence_from_der(i,d,dlen,in,inlen) asn1_nonempty_type_from_der(ASN1_TAG_EXPLICIT(i),d,dlen,in,inlen)
+
+#define asn1_sequence_of_to_der(d,dlen,out,outlen) asn1_nonempty_type_to_der(ASN1_TAG_SEQUENCE,d,dlen,out,outlen)
+#define asn1_sequence_of_from_der(d,dlen,in,inlen) asn1_nonempty_type_from_der(ASN1_TAG_SEQUENCE,d,dlen,in,inlen)
+int asn1_sequence_of_int_to_der(const int *nums, size_t nums_cnt, uint8_t **out, size_t *outlen);
+int asn1_sequence_of_int_from_der(int *nums, size_t *nums_cnt, size_t max_nums, const uint8_t **in, size_t *inlen);
+int asn1_sequence_of_int_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen);
+
+#define asn1_set_to_der(d,dlen,out,outlen) asn1_nonempty_type_to_der(ASN1_TAG_SET,d,dlen,out,outlen)
+#define asn1_set_from_der(d,dlen,in,inlen) asn1_nonempty_type_from_der(ASN1_TAG_SET,d,dlen,in,inlen)
+#define asn1_implicit_set_to_der(i,d,dlen,out,outlen) asn1_type_to_der(ASN1_TAG_EXPLICIT(i),d,dlen,out,outlen)
+#define asn1_implicit_set_from_der(i,d,dlen,in,inlen) asn1_type_from_der(ASN1_TAG_EXPLICIT(i),d,dlen,in,inlen)
+
+#define asn1_set_of_to_der(d,dlen,out,outlen) asn1_nonempty_type_to_der(ASN1_TAG_SET,d,dlen,out,outlen)
+#define asn1_set_of_from_der(d,dlen,in,inlen) asn1_nonempty_type_from_der(ASN1_TAG_SET,d,dlen,in,inlen)
+
+#define asn1_implicit_to_der(i,d,dlen,out,outlen) asn1_type_to_der(ASN1_TAG_IMPLICIT(i),d,dlen,out,outlen)
+#define asn1_implicit_from_der(i,d,dlen,in,inlen) asn1_type_from_der(ASN1_TAG_IMPLICIT(i),d,dlen,in,inlen)
+
+int asn1_header_to_der(int tag, size_t dlen, uint8_t **out, size_t *outlen);
+#define asn1_implicit_header_to_der(i,dlen,out,outlen) asn1_header_to_der(ASN1_TAG_EXPLICIT(i),dlen,out,outlen)
+
+#define asn1_octet_string_header_to_der(dlen,out,outlen) asn1_header_to_der(ASN1_TAG_OCTET_STRING,dlen,out,outlen)
+
+#define asn1_sequence_header_to_der_ex(tag,dlen,out,outlen) asn1_header_to_der(tag,dlen,out,outlen)
+#define asn1_sequence_header_to_der(dlen,out,outlen) asn1_header_to_der(ASN1_TAG_SEQUENCE,dlen,out,outlen)
+#define asn1_implicit_sequence_header_to_der(i,dlen,out,outlen) asn1_header_to_der(ASN1_TAG_EXPLICIT(i),dlen,out,outlen)
+
+#define asn1_set_header_to_der(dlen,out,outlen) asn1_header_to_der(ASN1_TAG_SET,dlen,out,outlen)
+#define asn1_implicit_set_header_to_der(i,dlen,out,outlen) asn1_header_to_der(ASN1_TAG_EXPLICIT(i),dlen,out,outlen)
+
+#define asn1_explicit_header_to_der(i,dlen,out,outlen) asn1_header_to_der(ASN1_TAG_EXPLICIT(i),dlen,out,outlen)
+
+#define asn1_explicit_to_der(i,d,dlen,out,outlen) asn1_nonempty_type_to_der(ASN1_TAG_EXPLICIT(i),d,dlen,out,outlen)
+#define asn1_explicit_from_der(i,d,dlen,in,inlen) asn1_nonempty_type_from_der(ASN1_TAG_EXPLICIT(i),d,dlen,in,inlen)
+
+// d,dlen 是 SEQUENCE OF, SET OF 中的值
+int asn1_types_get_count(const uint8_t *d, size_t dlen, int tag, size_t *cnt);
+int asn1_types_get_item_by_index(const uint8_t *d, size_t dlen, int tag,
+	int index, const uint8_t **item_d, size_t *item_dlen);
+
+
+
+
+
+int asn1_check(int expr);
+
+
+#if __cplusplus
+}
+#endif
+#endif

+ 72 - 0
components/gmssl/include/gmssl/base64.h

@@ -0,0 +1,72 @@
+/*
+ *  Copyright 2014-2022 The GmSSL Project. All Rights Reserved.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the License); you may
+ *  not use this file except in compliance with the License.
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ */
+
+
+
+#ifndef GMSSL_BASE64_H
+#define GMSSL_BASE64_H
+
+#include <stdint.h>
+#include <stdlib.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+BASE64 Public API
+
+	BASE64_CTX
+	base64_encode_init
+	base64_encode_update
+	base64_encode_finish
+	base64_decode_init
+	base64_decode_update
+	base64_decode_finish
+
+*/
+
+
+typedef struct {
+    /* number saved in a partial encode/decode */
+    int num;
+    /*
+     * The length is either the output line length (in input bytes) or the
+     * shortest input line length that is ok.  Once decoding begins, the
+     * length is adjusted up each time a longer line is decoded
+     */
+    int length;
+    /* data to encode */
+    unsigned char enc_data[80];
+    /* number read on current line */
+    int line_num;
+    int expect_nl;
+} BASE64_CTX;
+
+# define BASE64_ENCODE_LENGTH(l)    (((l+2)/3*4)+(l/48+1)*2+80)
+# define BASE64_DECODE_LENGTH(l)    ((l+3)/4*3+80)
+
+
+void base64_encode_init(BASE64_CTX *ctx);
+int  base64_encode_update(BASE64_CTX *ctx, const uint8_t *in, int inlen, uint8_t *out, int *outlen);
+void base64_encode_finish(BASE64_CTX *ctx, uint8_t *out, int *outlen);
+
+void base64_decode_init(BASE64_CTX *ctx);
+int  base64_decode_update(BASE64_CTX *ctx, const uint8_t *in, int inlen, uint8_t *out, int *outlen);
+int  base64_decode_finish(BASE64_CTX *ctx, uint8_t *out, int *outlen);
+
+
+int base64_encode_block(unsigned char *t, const unsigned char *f, int dlen);
+int base64_decode_block(unsigned char *t, const unsigned char *f, int n);
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif

+ 74 - 0
components/gmssl/include/gmssl/block_cipher.h

@@ -0,0 +1,74 @@
+/*
+ *  Copyright 2014-2022 The GmSSL Project. All Rights Reserved.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the License); you may
+ *  not use this file except in compliance with the License.
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ */
+
+
+
+
+#ifndef GMSSL_BLOCK_CIPHER_H
+#define GMSSL_BLOCK_CIPHER_H
+
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <gmssl/aes.h>
+#include <gmssl/sm4.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#define BLOCK_CIPHER_BLOCK_SIZE		16
+#define BLOCK_CIPHER_MIN_KEY_SIZE	16
+#define BLOCK_CIPHER_MAX_KEY_SIZE	32
+
+
+typedef struct BLOCK_CIPHER BLOCK_CIPHER;
+typedef struct BLOCK_CIPHER_KEY BLOCK_CIPHER_KEY;
+
+struct BLOCK_CIPHER_KEY {
+	union {
+		SM4_KEY sm4_key;
+		AES_KEY aes_key;
+	} u;
+	const BLOCK_CIPHER *cipher;
+};
+
+typedef void (*block_cipher_set_encrypt_key_func)(BLOCK_CIPHER_KEY *key, const uint8_t *raw_key);
+typedef void (*block_cipher_set_decrypt_key_func)(BLOCK_CIPHER_KEY *key, const uint8_t *raw_key);
+typedef void (*block_cipher_encrypt_func)(const BLOCK_CIPHER_KEY *key, const uint8_t *in, uint8_t *out);
+typedef void (*block_cipher_decrypt_func)(const BLOCK_CIPHER_KEY *key, const uint8_t *in, uint8_t *out);
+
+struct BLOCK_CIPHER {
+	int oid;
+	size_t key_size;
+	size_t block_size;
+	block_cipher_set_encrypt_key_func set_encrypt_key;
+	block_cipher_set_decrypt_key_func set_decrypt_key;
+	block_cipher_encrypt_func encrypt;
+	block_cipher_decrypt_func decrypt;
+};
+
+const BLOCK_CIPHER *BLOCK_CIPHER_sm4(void);
+const BLOCK_CIPHER *BLOCK_CIPHER_aes128(void);
+
+const BLOCK_CIPHER *block_cipher_from_name(const char *name);
+const char *block_cipher_name(const BLOCK_CIPHER *cipher);
+int block_cipher_set_encrypt_key(BLOCK_CIPHER_KEY *key, const BLOCK_CIPHER *cipher, const uint8_t *raw_key);
+int block_cipher_set_decrypt_key(BLOCK_CIPHER_KEY *key, const BLOCK_CIPHER *cipher, const uint8_t *raw_key);
+int block_cipher_encrypt(const BLOCK_CIPHER_KEY *key, const uint8_t *in, uint8_t *out);
+int block_cipher_decrypt(const BLOCK_CIPHER_KEY *key, const uint8_t *in, uint8_t *out);
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif

+ 57 - 0
components/gmssl/include/gmssl/chacha20.h

@@ -0,0 +1,57 @@
+/*
+ *  Copyright 2014-2022 The GmSSL Project. All Rights Reserved.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the License); you may
+ *  not use this file except in compliance with the License.
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ */
+
+
+/* RFC 8439 "ChaCha20 and Poly1305 for IETF Protocols" */
+
+#ifndef GMSSL_CHACHA20_H
+#define GMSSL_CHACHA20_H
+
+#define CHACHA20_IS_BIG_ENDIAN	0
+
+#include <stdint.h>
+#include <stdlib.h>
+
+#include <string.h>
+
+#define CHACHA20_KEY_BITS	256
+#define CHACHA20_NONCE_BITS	96
+#define CHACHA20_COUNTER_BITS	32
+
+#define CHACHA20_KEY_SIZE	(CHACHA20_KEY_BITS/8)
+#define CHACHA20_NONCE_SIZE	(CHACHA20_NONCE_BITS/8)
+#define CHACHA20_COUNTER_SIZE	(CHACHA20_COUNTER_BITS/8)
+
+#define CHACHA20_KEY_WORDS	(CHACHA20_KEY_SIZE/sizeof(uint32_t))
+#define CHACHA20_NONCE_WORDS	(CHACHA20_NONCE_SIZE/sizeof(uint32_t))
+#define CHACHA20_COUNTER_WORDS	(CHACHA20_COUNTER_SIZE/sizeof(uint32_t))
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+typedef struct {
+	uint32_t d[16];
+} CHACHA20_STATE;
+
+
+void chacha20_init(CHACHA20_STATE *state,
+	const uint8_t key[CHACHA20_KEY_SIZE],
+	const uint8_t nonce[CHACHA20_NONCE_SIZE], uint32_t counter);
+
+void chacha20_generate_keystream(CHACHA20_STATE *state,
+	size_t counts, uint8_t *out);
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif

+ 552 - 0
components/gmssl/include/gmssl/cms.h

@@ -0,0 +1,552 @@
+/*
+ *  Copyright 2014-2022 The GmSSL Project. All Rights Reserved.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the License); you may
+ *  not use this file except in compliance with the License.
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ */
+
+
+/*
+References:
+  1. GM/T 0010-2012 SM2 Cryptography Message Syntax Specification
+  2. RFC 2315 PKCS #7 Cryptographic Message Syntax Version 1.5
+  3. RFC 5652 Cryptographic Message Syntax (CMS)
+*/
+
+#ifndef GMSSL_CMS_H
+#define GMSSL_CMS_H
+
+
+#include <string.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <gmssl/x509.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+enum {
+	CMS_version_v1 = 1,
+};
+
+
+/*
+ContentType:
+	OID_cms_data
+	OID_cms_signed_data
+	OID_cms_enveloped_data
+	OID_cms_signed_and_enveloped_data
+	OID_cms_encrypted_data
+	OID_cms_key_agreement_info
+*/
+const char *cms_content_type_name(int oid);
+int cms_content_type_from_name(const char *name);
+int cms_content_type_to_der(int oid, uint8_t **out, size_t *outlen);
+int cms_content_type_from_der(int *oid, const uint8_t **in, size_t *inlen);
+
+/*
+ContentInfo ::= SEQUENCE {
+	contentType	OBJECT IDENTIFIER,
+	content		[0] EXPLICIT ANY OPTIONAL }
+*/
+int cms_content_info_header_to_der(
+	int content_type, size_t content_len,
+	uint8_t **out, size_t *outlen);
+int cms_content_info_to_der(
+	int content_type,
+	const uint8_t *content, size_t content_len,
+	uint8_t **out, size_t *outlen);
+int cms_content_info_from_der(
+	int *content_type,
+	const uint8_t **content, size_t *content_len, // 这里获得的是完整的TLV
+	const uint8_t **in, size_t *inlen);
+int cms_content_info_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen);
+
+/*
+Data ::= OCTET STRING
+*/
+#define cms_data_to_der(d,dlen,out,outlen) asn1_octet_string_to_der(d,dlen,out,outlen)
+#define cms_data_from_der(d,dlen,in,inlen) asn1_octet_string_from_der(d,dlen,in,inlen)
+#define cms_data_print(fp,fmt,ind,label,d,dlen) format_bytes(fp,fmt,ind,label,d,dlen)
+
+/*
+EncryptedContentInfo ::= SEQUENCE {
+	contentType			OBJECT IDENTIFIER,
+	contentEncryptionAlgorithm	AlgorithmIdentifier,
+	encryptedContent		[0] IMPLICIT OCTET STRING OPTIONAL,
+	sharedInfo1			[1] IMPLICIT OCTET STRING OPTIONAL,
+	sharedInfo2			[2] IMPLICIT OCTET STRING OPTIONAL }
+*/
+int cms_enced_content_info_to_der(
+	int content_type,
+	int enc_algor, const uint8_t *enc_iv, size_t enc_iv_len,
+	const uint8_t *enced_content, size_t enced_content_len,
+	const uint8_t *shared_info1, size_t shared_info1_len,
+	const uint8_t *shared_info2, size_t shared_info2_len,
+	uint8_t **out, size_t *outlen);
+int cms_enced_content_info_from_der(
+	int *content_type,
+	int *enc_algor, const uint8_t **enc_iv, size_t *enc_iv_len,
+	const uint8_t **enced_content, size_t *enced_content_len,
+	const uint8_t **shared_info1, size_t *shared_info1_len,
+	const uint8_t **shared_info2, size_t *shared_info2_len,
+	const uint8_t **in, size_t *inlen);
+int cms_enced_content_info_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen);
+
+int cms_enced_content_info_encrypt_to_der(
+	int enc_algor,
+	const uint8_t *key, size_t keylen,
+	const uint8_t *iv, size_t ivlen,
+	int content_type, const uint8_t *content, size_t content_len,
+	const uint8_t *shared_info1, size_t shared_info1_len,
+	const uint8_t *shared_info2, size_t shared_info2_len,
+	uint8_t **out, size_t *outlen);
+int cms_enced_content_info_decrypt_from_der(
+	int *enc_algor,
+	const uint8_t *key, size_t keylen,
+	int *content_type, uint8_t *content, size_t *content_len,
+	const uint8_t **shared_info1, size_t *shared_info1_len,
+	const uint8_t **shared_info2, size_t *shared_info2_len,
+	const uint8_t **in, size_t *inlen);
+
+/*
+EncryptedData ::= SEQUENCE {
+	version			INTEGER (1),
+	encryptedContentInfo	EncryptedContentInfo }
+*/
+int cms_encrypted_data_to_der(
+	int version,
+	int content_type,
+	int enc_algor, const uint8_t *iv, size_t ivlen,
+	const uint8_t *enced_content, size_t enced_content_len,
+	const uint8_t *shared_info1, size_t shared_info1_len,
+	const uint8_t *shared_info2, size_t shared_info2_len,
+	uint8_t **out, size_t *outlen);
+int cms_encrypted_data_from_der(
+	int *version,
+	int *content_type,
+	int *enc_algor, const uint8_t **iv, size_t *ivlen,
+	const uint8_t **enced_content, size_t *enced_content_len,
+	const uint8_t **shared_info1, size_t *shared_info1_len,
+	const uint8_t **shared_info2, size_t *shared_info2_len,
+	const uint8_t **in, size_t *inlen);
+int cms_encrypted_data_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen);
+
+int cms_encrypted_data_encrypt_to_der(
+	int enc_algor,
+	const uint8_t *key, size_t keylen,
+	const uint8_t *iv, size_t ivlen,
+	int content_type, const uint8_t *content, size_t content_len,
+	const uint8_t *shared_info1, size_t shared_info1_len,
+	const uint8_t *shared_info2, size_t shared_info2_len,
+	uint8_t **out, size_t *outlen);
+int cms_encrypted_data_decrypt_from_der(
+	int *enc_algor,
+	const uint8_t *key, size_t keylen,
+	int *content_type, uint8_t *content, size_t *content_len,
+	const uint8_t **shared_info1, size_t *shared_info1_len,
+	const uint8_t **shared_info2, size_t *shared_info2_len,
+	const uint8_t **in, size_t *inlen);
+
+/*
+IssuerAndSerialNumber ::= SEQUENCE {
+	isser		Name,
+	serialNumber	INTEGER }
+*/
+int cms_issuer_and_serial_number_to_der(
+	const uint8_t *issuer, size_t issuer_len,
+	const uint8_t *serial_number, size_t serial_number_len,
+	uint8_t **out, size_t *outlen);
+int cms_issuer_and_serial_number_from_der(
+	const uint8_t **issuer, size_t *issuer_len,
+	const uint8_t **serial_number, size_t *serial_number_len,
+	const uint8_t **in, size_t *inlen);
+int cms_issuer_and_serial_number_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen);
+
+/*
+SignerInfo ::= SEQUENCE {
+	version				INTEGER (1),
+	issuerAndSerialNumber		IssuerAndSerialNumber,
+	digestAlgorithm			AlgorithmIdentifier,
+	authenticatedAttributes		[0] IMPLICIT SET OF Attribute OPTINOAL,
+	digestEncryptionAlgorithm	AlgorithmIdentifier,
+	encryptedDigest			OCTET STRING,
+	unauthenticatedAttributes       [1] IMPLICIT SET OF Attribute OPTINOAL, }
+*/
+int cms_signer_info_to_der(
+	int version,
+	const uint8_t *issuer, size_t issuer_len,
+	const uint8_t *serial_number, size_t serial_number_len,
+	int digest_algor,
+	const uint8_t *authed_attrs, size_t authed_attrs_len,
+	int signature_algor,
+	const uint8_t *enced_digest, size_t enced_digest_len,
+	const uint8_t *unauthed_attrs, size_t unauthed_attrs_len,
+	uint8_t **out, size_t *outlen);
+int cms_signer_info_from_der(
+	int *version,
+	const uint8_t **issuer, size_t *issuer_len,
+	const uint8_t **serial_number, size_t *serial_number_len,
+	int *digest_algor,
+	const uint8_t **authed_attrs, size_t *authed_attrs_len,
+	int *signature_algor,
+	const uint8_t **enced_digest, size_t *enced_digest_len,
+	const uint8_t **unauthed_attrs, size_t *unauthed_attrs_len,
+	const uint8_t **in, size_t *inlen);
+int cms_signer_info_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen);
+
+int cms_signer_info_sign_to_der(
+	const SM3_CTX *sm3_ctx, const SM2_KEY *sm2_key,
+	const uint8_t *issuer, size_t issuer_len,
+	const uint8_t *serial_number, size_t serial_number_len,
+	const uint8_t *authed_attrs, size_t authed_attrs_len,
+	const uint8_t *unauthed_attrs, size_t unauthed_attrs_len,
+	uint8_t **out, size_t *outlen);
+int cms_signer_info_verify_from_der(
+	const SM3_CTX *sm3_ctx, const uint8_t *certs, size_t certslen,
+	const uint8_t **cert, size_t *certlen,
+	const uint8_t **issuer, size_t *issuer_len,
+	const uint8_t **serial, size_t *serial_len,
+	const uint8_t **authed_attrs, size_t *authed_attrs_len,
+	const uint8_t **unauthed_attrs, size_t *unauthed_attrs_len,
+	const uint8_t **in, size_t *inlen);
+/*
+SignerInfos ::= SET OF SignerInfo;
+*/
+int cms_signer_infos_add_signer_info(
+	uint8_t *d, size_t *dlen, size_t maxlen,
+	const SM3_CTX *sm3_ctx, const SM2_KEY *sign_key,
+	const uint8_t *issuer, size_t issuer_len,
+	const uint8_t *serial_number, size_t serial_number_len,
+	const uint8_t *authed_attrs, size_t authed_attrs_len,
+	const uint8_t *unauthed_attrs, size_t unauthed_attrs_len);
+#define cms_signer_infos_to_der(d,dlen,out,outlen) asn1_set_to_der(d,dlen,out,outlen)
+#define cms_signer_infos_from_der(d,dlen,in,inlen) asn1_set_from_der(d,dlen,in,inlen)
+int cms_signer_infos_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen);
+
+int cms_digest_algors_to_der(const int *digest_algors, size_t digest_algors_cnt, uint8_t **out, size_t *outlen);
+int cms_digest_algors_from_der(int *digest_algors, size_t *digest_algors_cnt, size_t max_digest_algors,
+	const uint8_t **in, size_t *inlen);
+int cms_digest_algors_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen);
+
+/*
+SignedData ::= SEQUENCE {
+	version			INTEGER (1),
+	digestAlgorithms	SET OF AlgorithmIdentifier,
+	contentInfo		ContentInfo,
+	certificates		[0] IMPLICIT SET OF Certificate OPTIONAL,
+	crls			[1] IMPLICIT SET OF CertificateRevocationList OPTIONAL,
+	signerInfos		SET OF SignerInfo }
+*/
+int cms_signed_data_to_der(
+	int version,
+	const int *digest_algors, size_t digest_algors_cnt,
+	const int content_type, const uint8_t *content, const size_t content_len,
+	const uint8_t *certs, size_t certs_len,
+	const uint8_t *crls, const size_t crls_len,
+	const uint8_t *signer_infos, size_t signer_infos_len,
+	uint8_t **out, size_t *outlen);
+int cms_signed_data_from_der(
+	int *version,
+	int *digest_algors, size_t *digest_algors_cnt, size_t max_digest_algors,
+	int *content_type, const uint8_t **content, size_t *content_len,
+	const uint8_t **certs, size_t *certs_len,
+	const uint8_t **crls, size_t *crls_len,
+	const uint8_t **signer_infos, size_t *signer_infos_len,
+	const uint8_t **in, size_t *inlen);
+int cms_signed_data_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen);
+
+
+typedef struct {
+	uint8_t *certs;
+	size_t certs_len;
+	SM2_KEY *sign_key;
+} CMS_CERTS_AND_KEY;
+
+int cms_signed_data_sign_to_der(
+	const CMS_CERTS_AND_KEY *signers, size_t signers_cnt,
+	int content_type, const uint8_t *data, size_t datalen, // 当OID_cms_data时为raw data
+	const uint8_t *crls, size_t crls_len, // 可以为空
+	uint8_t **out, size_t *outlen);
+int cms_signed_data_verify_from_der(
+	const uint8_t *extra_certs, size_t extra_certs_len,
+	const uint8_t *extra_crls, size_t extra_crls_len,
+	int *content_type, const uint8_t **content, size_t *content_len, // 是否应该返回raw data呢?			
+	const uint8_t **certs, size_t *certs_len,
+	const uint8_t **crls, size_t *crls_len,
+	const uint8_t **signer_infos, size_t *signer_infos_len,
+	const uint8_t **in, size_t *inlen);
+
+
+/*
+RecipientInfo ::= SEQUENCE {
+	version				INTEGER (1),
+	issuerAndSerialNumber		IssuerAndSerialNumber,
+	keyEncryptionAlgorithm		AlgorithmIdentifier,
+	encryptedKey			OCTET STRING -- DER-encoding of SM2Cipher
+}
+由于encryptedKey的类型为SM2Cipher, 而SM2Cipher中有2个INTEGER,因此长度是不固定的。
+因此不能预先确定输出长度
+*/
+int cms_recipient_info_to_der(
+	int version,
+	const uint8_t *issuer, size_t issuer_len,
+	const uint8_t *serial_number, size_t serial_number_len,
+	int public_key_enc_algor,
+	const uint8_t *enced_key, size_t enced_key_len,
+	uint8_t **out, size_t *outlen);
+int cms_recipient_info_from_der(
+	int *version,
+	const uint8_t **issuer, size_t *issuer_len,
+	const uint8_t **serial_number, size_t *serial_number_len,
+	int *pke_algor, const uint8_t **params, size_t *params_len,// SM2加密只使用SM3,没有默认参数,但是ECIES可能有
+	const uint8_t **enced_key, size_t *enced_key_len,
+	const uint8_t **in, size_t *inlen);
+int cms_recipient_info_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen);
+
+
+int cms_recipient_info_encrypt_to_der(
+	const SM2_KEY *public_key,
+	const uint8_t *issuer, size_t issuer_len,
+	const uint8_t *serial, size_t serial_len,
+	const uint8_t *in, size_t inlen,
+	uint8_t **out, size_t *outlen);
+int cms_recipient_info_decrypt_from_der(
+	const SM2_KEY *sm2_key,
+	const uint8_t *rcpt_issuer, size_t rcpt_issuer_len,
+	const uint8_t *rcpt_serial, size_t rcpt_serial_len,
+	uint8_t *out, size_t *outlen, size_t maxlen,
+	const uint8_t **in, size_t *inlen);
+
+int cms_recipient_infos_add_recipient_info(
+	uint8_t *d, size_t *dlen, size_t maxlen,
+	const SM2_KEY *public_key,
+	const uint8_t *issuer, size_t issuer_len,
+	const uint8_t *serial, size_t serial_len,
+	const uint8_t *in, size_t inlen);
+#define cms_recipient_infos_to_der(d,dlen,out,outlen) asn1_set_to_der(d,dlen,out,outlen)
+#define cms_recipient_infos_from_der(d,dlen,in,inlen) asn1_set_from_der(d,dlen,in,inlen)
+int cms_recipient_infos_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen);
+
+/*
+EnvelopedData ::= SEQUENCE {
+	version			Version,
+	recipientInfos		SET OF RecipientInfo,
+	encryptedContentInfo	EncryptedContentInfo }
+*/
+int cms_enveloped_data_to_der(
+	int version,
+	const uint8_t *rcpt_infos, size_t rcpt_infos_len,
+	int content_type,
+	int enc_algor, const uint8_t *enc_iv, size_t enc_iv_len,
+	const uint8_t *enced_content, size_t enced_content_len,
+	const uint8_t *shared_info1, size_t shared_info1_len,
+	const uint8_t *shared_info2, size_t shared_info2_len,
+	uint8_t **out, size_t *outlen);
+int cms_enveloped_data_from_der(
+	int *version,
+	const uint8_t **rcpt_infos, size_t *rcpt_infos_len,
+	const uint8_t **enced_content_info, size_t *enced_content_info_len,
+	const uint8_t **in, size_t *inlen);
+int cms_enveloped_data_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen);
+
+int cms_enveloped_data_encrypt_to_der(
+	const uint8_t *rcpt_certs, size_t rcpt_certs_len,
+	int enc_algor, const uint8_t *key, size_t keylen, const uint8_t *iv, size_t ivlen,
+	int content_type, const uint8_t *content, size_t content_len,
+	const uint8_t *shared_info1, size_t shared_info1_len,
+	const uint8_t *shared_info2, size_t shared_info2_len,
+	uint8_t **out, size_t *outlen);
+int cms_enveloped_data_decrypt_from_der(
+	const SM2_KEY *sm2_key,
+	const uint8_t *issuer, size_t issuer_len,
+	const uint8_t *serial_number, size_t serial_number_len,
+	int *content_type, uint8_t *content, size_t *content_len,
+	const uint8_t **rcpt_infos, size_t *rcpt_infos_len,
+	const uint8_t **shared_info1, size_t *shared_info1_len,
+	const uint8_t **shared_info2, size_t *shared_info2_len,
+	const uint8_t **in, size_t *inlen);
+
+/*
+SignedAndEnvelopedData ::= SEQUENCE {
+	version			INTEGER (1),
+	recipientInfos		SET OF RecipientInfo,
+	digestAlgorithms	SET OF AlgorithmIdentifier,
+	encryptedContentInfo	EncryptedContentInfo,
+	certificates		[0] IMPLICIT SET OF Certificate OPTIONAL,
+	crls			[1] IMPLICIT SET OF CertificateRevocationList OPTIONAL,
+	signerInfos		SET OF SignerInfo }
+*/
+int cms_signed_and_enveloped_data_to_der(
+	int version,
+	const uint8_t *rcpt_infos, size_t rcpt_infos_len,
+	const int *digest_algors, size_t digest_algors_cnt,
+	int content_type,
+	int enc_algor, const uint8_t *iv, size_t ivlen,
+	const uint8_t *enced_content, size_t enced_content_len,
+	const uint8_t *shared_info1, size_t shared_info1_len,
+	const uint8_t *shared_info2, size_t shared_info2_len,
+	const uint8_t *certs, size_t certs_len,
+	const uint8_t *crls, size_t crls_len,
+	const uint8_t *signer_infos, size_t signer_infos_len,
+	uint8_t **out, size_t *outlen);
+int cms_signed_and_enveloped_data_from_der(
+	int *version,
+	const uint8_t **rcpt_infos, size_t *rcpt_infos_len,
+	int *digest_algors, size_t *digest_algors_cnt, size_t max_digest_algors,
+	const uint8_t **enced_content_info, size_t *enced_content_info_len,
+	const uint8_t **certs, size_t *certs_len,
+	const uint8_t **crls, size_t *crls_len,
+	const uint8_t **signer_infos, size_t *signer_infos_len,
+	const uint8_t **in, size_t *inlen);
+int cms_signed_and_enveloped_data_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen);
+
+int cms_signed_and_enveloped_data_encipher_to_der(
+	const CMS_CERTS_AND_KEY *signers, size_t signers_cnt,
+	const uint8_t *rcpt_certs, size_t rcpt_certs_len,
+	int enc_algor, const uint8_t *key, size_t keylen, const uint8_t *iv, size_t ivlen,
+	int content_type, const uint8_t *content, size_t content_len,
+	const uint8_t *signers_crls, size_t signers_crls_len,
+	const uint8_t *shared_info1, size_t shared_info1_len,
+	const uint8_t *shared_info2, size_t shared_info2_len,
+	uint8_t **out, size_t *outlen);
+int cms_signed_and_enveloped_data_decipher_from_der(
+	const SM2_KEY *rcpt_key,
+	const uint8_t *rcpt_issuer, size_t rcpt_issuer_len,
+	const uint8_t *rcpt_serial, size_t rcpt_serial_len,
+	int *content_type, uint8_t *content, size_t *content_len,
+	const uint8_t **prcpt_infos, size_t *prcpt_infos_len,
+	const uint8_t **shared_info1, size_t *shared_info1_len,
+	const uint8_t **shared_info2, size_t *shared_info2_len,
+	const uint8_t **certs, size_t *certs_len,
+	const uint8_t **crls, size_t *crls_len,
+	const uint8_t **psigner_infos, size_t *psigner_infos_len,
+	const uint8_t *extra_certs, size_t extra_certs_len,
+	const uint8_t *extra_crls, size_t extra_crls_len,
+	const uint8_t **in, size_t *inlen);
+
+/*
+KeyAgreementInfo ::= SEQUENCE {
+	version			INTEGER (1),
+	tempPublicKeyR		SM2PublicKey,
+	userCertificate		Certificate,
+	userID			OCTET STRING }
+*/
+int cms_key_agreement_info_to_der(
+	int version,
+	const SM2_KEY *temp_public_key_r,
+	const uint8_t *user_cert, size_t user_cert_len,
+	const uint8_t *user_id, size_t user_id_len,
+	uint8_t **out, size_t *outlen);
+int cms_key_agreement_info_from_der(
+	int *version,
+	SM2_KEY *temp_public_key_r,
+	const uint8_t **user_cert, size_t *user_cert_len,
+	const uint8_t **user_id, size_t *user_id_len,
+	const uint8_t **in, size_t *inlen);
+int cms_key_agreement_info_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen);
+
+
+
+// 下面是公开API
+// 公开API的设计考虑:
+// 1. 不需要调用其他函数
+// 2. 在逻辑上容易理解
+// 3. 将cms,cmslen看做对象
+
+
+// 生成ContentInfo, type == data
+int cms_set_data(uint8_t *cms, size_t *cmslen,
+	const uint8_t *d, size_t dlen);
+
+int cms_encrypt(
+	uint8_t *cms, size_t *cmslen, // 输出的ContentInfo (type encryptedData)
+	int enc_algor, const uint8_t *key, size_t keylen, const uint8_t *iv, size_t ivlen, // 对称加密算法、密钥和IV
+	int content_type, const uint8_t *content, size_t content_len, // 待加密的输入数据
+	const uint8_t *shared_info1, size_t shared_info1_len, // 附加信息
+	const uint8_t *shared_info2, size_t shared_info2_len);
+
+int cms_decrypt(
+	const uint8_t *cms, size_t cmslen, // 输入的ContentInfo (type encryptedData)
+	int *enc_algor, const uint8_t *key, size_t keylen, // 解密密钥(我们不知道解密算法)
+	int *content_type, uint8_t *content, size_t *content_len, // 输出的解密数据类型及数据
+	const uint8_t **shared_info1, size_t *shared_info1_len, // 附加信息
+	const uint8_t **shared_info2, size_t *shared_info2_len);
+
+int cms_sign(
+	uint8_t *cms, size_t *cms_len,
+	const CMS_CERTS_AND_KEY *signers, size_t signers_cnt, // 签名者的签名私钥和证书
+	int content_type, const uint8_t *content, size_t content_len, // 待签名的输入数据
+	const uint8_t *crls, size_t crls_len);
+
+int cms_verify(
+	const uint8_t *cms, size_t cms_len,
+	const uint8_t *extra_certs, size_t extra_certs_len,
+	const uint8_t *extra_crls, size_t extra_crls_len,
+	int *content_type, const uint8_t **content, size_t *content_len,
+	const uint8_t **certs, size_t *certs_len,
+	const uint8_t **crls, size_t *crls_len,
+	const uint8_t **signer_infos, size_t *signer_infos_len);
+
+int cms_envelop(
+	uint8_t *cms, size_t *cms_len,
+	const uint8_t *rcpt_certs, size_t rcpt_certs_len, // 接收方证书,注意这个参数的类型可以容纳多个证书,但是只有在一个接受者时对调用方最方便
+	int enc_algor, const uint8_t *key, size_t keylen, const uint8_t *iv, size_t ivlen, // 对称加密算法及参数
+	int content_type, const uint8_t *content, size_t content_len, // 待加密的输入数据
+	const uint8_t *shared_info1, size_t shared_info1_len, // 附加输入信息
+	const uint8_t *shared_info2, size_t shared_info2_len);
+
+int cms_deenvelop(
+	const uint8_t *cms, size_t cms_len,
+	const SM2_KEY *rcpt_key, const uint8_t *rcpt_cert, size_t rcpt_cert_len, // 接收方的解密私钥和对应的证书,注意只需要一个解密方
+	int *content_type, uint8_t *content, size_t *content_len,
+	const uint8_t **rcpt_infos, size_t *rcpt_infos_len, // 解析得到,用于显示
+	const uint8_t **shared_info1, size_t *shared_info1_len,
+	const uint8_t **shared_info2, size_t *shared_info2_len);
+
+int cms_sign_and_envelop(
+	uint8_t *cms, size_t *cms_len,
+	const CMS_CERTS_AND_KEY *signers, size_t signers_cnt,
+	const uint8_t *rcpt_certs, size_t rcpt_certs_len,
+	int enc_algor, const uint8_t *key, size_t keylen, const uint8_t *iv, size_t ivlen,
+	int content_type, const uint8_t *content, size_t content_len,
+	const uint8_t *signers_crls, size_t signers_crls_len,
+	const uint8_t *shared_info1, size_t shared_info1_len,
+	const uint8_t *shared_info2, size_t shared_info2_len);
+
+int cms_deenvelop_and_verify(
+	const uint8_t *cms, size_t cms_len,
+	const SM2_KEY *rcpt_key, const uint8_t *rcpt_cert, size_t rcpt_cert_len,
+	const uint8_t *extra_signer_certs, size_t extra_signer_certs_len,
+	const uint8_t *extra_signer_crls, size_t extra_signer_crls_len,
+	int *content_type, uint8_t *content, size_t *content_len,
+	const uint8_t **rcpt_infos, size_t *rcpt_infos_len,
+	const uint8_t **signer_infos, size_t *signer_infos_len,
+	const uint8_t **signer_certs, size_t *signer_certs_len,
+	const uint8_t **signer_crls, size_t *signer_crls_len,
+	const uint8_t **shared_info1, size_t *shared_info1_len,
+	const uint8_t **shared_info2, size_t *shared_info2_len);
+
+// 生成ContentInfo, type == keyAgreementInfo
+int cms_set_key_agreement_info(
+	uint8_t *cms, size_t *cms_len,
+	const SM2_KEY *temp_public_key_r,
+	const uint8_t *user_cert, size_t user_cert_len,
+	const uint8_t *user_id, size_t user_id_len);
+
+#define PEM_CMS "CMS"
+int cms_to_pem(const uint8_t *cms, size_t cms_len, FILE *fp);
+int cms_from_pem(uint8_t *cms, size_t *cms_len, size_t maxlen, FILE *fp);
+
+
+int cms_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *a, size_t alen);
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif

+ 58 - 0
components/gmssl/include/gmssl/des.h

@@ -0,0 +1,58 @@
+/*
+ *  Copyright 2014-2022 The GmSSL Project. All Rights Reserved.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the License); you may
+ *  not use this file except in compliance with the License.
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ */
+
+
+/* FIPS PUB 46-3 "Data Encryption Standard (DES)" */
+
+#ifndef GMSSL_DES_H
+#define GMSSL_DES_H
+
+
+#include <stdint.h>
+#include <stdlib.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#define DES_KEY_BITS	56
+#define DES_BLOCK_BITS	64
+#define DES_KEY_SIZE	((DES_KEY_BITS)/7)
+#define DES_BLOCK_SIZE	(DES_BLOCK_BITS/8)
+
+#define DES_RK_BITS	48
+#define DES_RK_SIZE	(DES_RK_BITS/8)
+#define DES_ROUNDS	16
+
+#define DES_EDE_KEY_SIZE	(DES_KEY_SIZE * 3)
+
+typedef struct {
+	uint64_t rk[DES_ROUNDS];
+} DES_KEY;
+
+void des_set_encrypt_key(DES_KEY *key, const uint8_t raw_key[DES_KEY_SIZE]);
+void des_set_decrypt_key(DES_KEY *key, const uint8_t raw_key[DES_KEY_SIZE]);
+void des_encrypt(DES_KEY *key, const uint8_t in[DES_BLOCK_SIZE], uint8_t out[DES_BLOCK_SIZE]);
+
+
+typedef struct {
+	DES_KEY K[3];
+} DES_EDE_KEY;
+
+void des_ede_set_encrypt_key(DES_EDE_KEY *key, const uint8_t raw_key[DES_EDE_KEY_SIZE]);
+void des_ede_set_decrypt_key(DES_EDE_KEY *key, const uint8_t raw_key[DES_EDE_KEY_SIZE]);
+void des_ede_encrypt(DES_EDE_KEY *key, const uint8_t in[DES_BLOCK_SIZE], uint8_t out[DES_BLOCK_SIZE]);
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif

+ 87 - 0
components/gmssl/include/gmssl/digest.h

@@ -0,0 +1,87 @@
+/*
+ *  Copyright 2014-2022 The GmSSL Project. All Rights Reserved.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the License); you may
+ *  not use this file except in compliance with the License.
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ */
+
+
+
+#ifndef GMSSL_DIGEST_H
+#define GMSSL_DIGEST_H
+
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <gmssl/sm3.h>
+#ifdef ENABLE_BROKEN_CRYPTO
+#include <gmssl/md5.h>
+#include <gmssl/sha1.h>
+#endif
+#include <gmssl/sha2.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+typedef struct DIGEST DIGEST;
+typedef struct DIGEST_CTX DIGEST_CTX;
+
+
+#define DIGEST_MAX_SIZE		64
+#define DIGEST_MAX_BLOCK_SIZE (1024/8)
+
+
+struct DIGEST_CTX {
+	union {
+		SM3_CTX sm3_ctx;
+#ifdef ENABLE_BROKEN_CRYPTO
+		MD5_CTX md5_ctx;
+		SHA1_CTX sha1_ctx;
+#endif
+		SHA224_CTX sha224_ctx;
+		SHA256_CTX sha256_ctx;
+		SHA384_CTX sha384_ctx;
+		SHA512_CTX sha512_ctx;
+	} u;
+	const DIGEST *digest;
+};
+
+struct DIGEST {
+	int oid;
+	size_t digest_size;
+	size_t block_size;
+	size_t ctx_size;
+	int (*init)(DIGEST_CTX *ctx);
+	int (*update)(DIGEST_CTX *ctx, const uint8_t *data, size_t datalen);
+	int (*finish)(DIGEST_CTX *ctx, uint8_t *dgst);
+};
+
+const DIGEST *DIGEST_sm3(void);
+#ifdef ENABLE_BROKEN_CRYPTO
+const DIGEST *DIGEST_md5(void);
+const DIGEST *DIGEST_sha1(void);
+#endif
+const DIGEST *DIGEST_sha224(void);
+const DIGEST *DIGEST_sha256(void);
+const DIGEST *DIGEST_sha384(void);
+const DIGEST *DIGEST_sha512(void);
+const DIGEST *DIGEST_sha512_224(void);
+const DIGEST *DIGEST_sha512_256(void);
+
+const DIGEST *digest_from_name(const char *name);
+const char *digest_name(const DIGEST *digest);
+int digest_init(DIGEST_CTX *ctx, const DIGEST *algor);
+int digest_update(DIGEST_CTX *ctx, const uint8_t *data, size_t datalen);
+int digest_finish(DIGEST_CTX *ctx, uint8_t *dgst, size_t *dgstlen);
+int digest(const DIGEST *digest, const uint8_t *data, size_t datalen, uint8_t *dgst, size_t *dgstlen);
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif

+ 54 - 0
components/gmssl/include/gmssl/dylib.h

@@ -0,0 +1,54 @@
+/*
+ *  Copyright 2014-2022 The GmSSL Project. All Rights Reserved.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the License); you may
+ *  not use this file except in compliance with the License.
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ */
+
+
+#ifndef GMSSL_DYLIB_H
+#define GMSSL_DYLIB_H
+
+#include <string.h>
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#ifdef WIN32
+
+#include <windows.h>
+
+typedef HMODULE dylib_handle_t;
+
+#define dylib_load_library(so_path)	LoadLibraryA(so_path)
+#define dylib_get_function(handle,name)	GetProcAddress(handle,name)
+#define dylib_close_library(handle)
+#define dylib_error_str()		""
+
+
+#else
+
+#include <dlfcn.h>
+
+typedef void *dylib_handle_t;
+
+#define dylib_load_library(so_path)	dlopen(so_path,RTLD_LAZY)
+#define dylib_get_function(handle,name)	dlsym(handle,name)
+#define dylib_close_library(handle)	dlclose(handle)
+#define dylib_error_str()		dlerror()
+
+
+#endif
+
+
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif

+ 64 - 0
components/gmssl/include/gmssl/ec.h

@@ -0,0 +1,64 @@
+/*
+ *  Copyright 2014-2022 The GmSSL Project. All Rights Reserved.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the License); you may
+ *  not use this file except in compliance with the License.
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ */
+
+
+#ifndef GMSSL_EC_H
+#define GMSSL_EC_H
+
+
+#include <time.h>
+#include <string.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <gmssl/sm2.h>
+#include <gmssl/oid.h>
+#include <gmssl/asn1.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+NamedCurve:
+	OID_sm2
+	OID_prime192v1
+	OID_prime256v1
+	OID_secp256k1
+	OID_secp384r1
+	OID_secp521r1
+*/
+const char *ec_named_curve_name(int curve);
+int ec_named_curve_from_name(const char *name);
+int ec_named_curve_to_der(int curve, uint8_t **out, size_t *outlen);
+int ec_named_curve_from_der(int *curve, const uint8_t **in, size_t *inlen);
+
+/*
+ECPoint ::= OCTET STRING -- uncompressed point
+*/
+int ec_point_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen);
+
+/*
+ECPrivateKey ::= SEQUENCE {
+	version		INTEGER,	-- value MUST be (1)
+	privateKey	OCTET STRING,	-- big endian encoding of integer
+	parameters	[0] EXPLICIT OBJECT IDENTIFIER OPTIONAL, -- namedCurve
+	publicKey	[1] EXPLICIT BIT STRING OPTIONAL -- ECPoint
+}
+*/
+
+enum {
+	EC_private_key_version = 1,
+};
+
+int ec_private_key_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen);
+
+#ifdef __cplusplus
+}
+#endif
+#endif

+ 78 - 0
components/gmssl/include/gmssl/endian.h

@@ -0,0 +1,78 @@
+/*
+ *  Copyright 2014-2022 The GmSSL Project. All Rights Reserved.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the License); you may
+ *  not use this file except in compliance with the License.
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ */
+
+
+#ifndef GMSSL_ENDIAN_H
+#define GMSSL_ENDIAN_H
+
+
+/* Big Endian R/W */
+
+#define GETU16(p) \
+	((uint16_t)(p)[0] <<  8 | \
+	 (uint16_t)(p)[1])
+
+#define GETU32(p) \
+	((uint32_t)(p)[0] << 24 | \
+	 (uint32_t)(p)[1] << 16 | \
+	 (uint32_t)(p)[2] <<  8 | \
+	 (uint32_t)(p)[3])
+
+#define GETU64(p) \
+	((uint64_t)(p)[0] << 56 | \
+	 (uint64_t)(p)[1] << 48 | \
+	 (uint64_t)(p)[2] << 40 | \
+	 (uint64_t)(p)[3] << 32 | \
+	 (uint64_t)(p)[4] << 24 | \
+	 (uint64_t)(p)[5] << 16 | \
+	 (uint64_t)(p)[6] <<  8 | \
+	 (uint64_t)(p)[7])
+
+
+// 注意:PUTU32(buf, val++) 会出错!
+#define PUTU16(p,V) \
+	((p)[0] = (uint8_t)((V) >> 8), \
+	 (p)[1] = (uint8_t)(V))
+
+#define PUTU32(p,V) \
+	((p)[0] = (uint8_t)((V) >> 24), \
+	 (p)[1] = (uint8_t)((V) >> 16), \
+	 (p)[2] = (uint8_t)((V) >>  8), \
+	 (p)[3] = (uint8_t)(V))
+
+#define PUTU64(p,V) \
+	((p)[0] = (uint8_t)((V) >> 56), \
+	 (p)[1] = (uint8_t)((V) >> 48), \
+	 (p)[2] = (uint8_t)((V) >> 40), \
+	 (p)[3] = (uint8_t)((V) >> 32), \
+	 (p)[4] = (uint8_t)((V) >> 24), \
+	 (p)[5] = (uint8_t)((V) >> 16), \
+	 (p)[6] = (uint8_t)((V) >>  8), \
+	 (p)[7] = (uint8_t)(V))
+
+/* Little Endian R/W */
+
+#define GETU16_LE(p)	(*(const uint16_t *)(p))
+#define GETU32_LE(p)	(*(const uint32_t *)(p))
+#define GETU64_LE(p)	(*(const uint64_t *)(p))
+
+#define PUTU16_LE(p,V)	*(uint16_t *)(p) = (V)
+#define PUTU32_LE(p,V)	*(uint32_t *)(p) = (V)
+#define PUTU64_LE(p,V)	*(uint64_t *)(p) = (V)
+
+/* Rotate */
+
+#define ROL32(a,n)     (((a)<<(n))|(((a)&0xffffffff)>>(32-(n))))
+#define ROL64(a,n)	(((a)<<(n))|((a)>>(64-(n))))
+
+#define ROR32(a,n)	ROL32((a),32-(n))
+#define ROR64(a,n)	ROL64(a,64-n)
+
+
+#endif

+ 71 - 0
components/gmssl/include/gmssl/error.h

@@ -0,0 +1,71 @@
+/*
+ *  Copyright 2014-2022 The GmSSL Project. All Rights Reserved.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the License); you may
+ *  not use this file except in compliance with the License.
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ */
+
+
+
+#ifndef GMSSL_ERROR_H
+#define GMSSL_ERROR_H
+
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <stdint.h>
+
+#include "luat_base.h"
+#define LUAT_LOG_TAG "gmssl"
+#include "luat_log.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#define GMSSL_FMT_BIN	1
+#define GMSSL_FMT_HEX	2
+#define GMSSL_FMT_DER	4
+#define GMSSL_FMT_PEM	8
+
+
+
+#define DEBUG 1
+
+#define warning_print() \
+	do { if (DEBUG) LLOGW("%s:%d:%s():\n",__FILE__, __LINE__, __func__); } while (0)
+
+#define error_print() \
+	do { if (DEBUG) LLOGE("%s:%d:%s():\n",__FILE__, __LINE__, __func__); } while (0)
+
+#define error_print_msg(fmt, ...) \
+	do { if (DEBUG) LLOGE("%s:%d:%s(): " fmt, __FILE__, __LINE__, __func__, __VA_ARGS__); } while (0)
+
+#define error_puts(str) \
+            do { if (DEBUG) LLOGE("%s: %d: %s: %s", __FILE__, __LINE__, __func__, str); } while (0)
+
+
+void print_der(const uint8_t *in, size_t inlen);
+void print_bytes(const uint8_t *in, size_t inlen);
+void print_nodes(const uint32_t *in, size_t inlen);
+
+#define FMT_CARRAY 0x80
+
+
+int format_print(FILE *fp, int format, int indent, const char *str, ...);
+int format_bytes(FILE *fp, int format, int indent, const char *str, const uint8_t *data, size_t datalen);
+int format_string(FILE *fp, int format, int indent, const char *str, const uint8_t *data, size_t datalen);
+
+
+
+//int tls_trace(int format, int indent, const char *str, ...);
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif

+ 29 - 0
components/gmssl/include/gmssl/file.h

@@ -0,0 +1,29 @@
+/*
+ *  Copyright 2014-2023 The GmSSL Project. All Rights Reserved.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the License); you may
+ *  not use this file except in compliance with the License.
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ */
+
+#ifndef GMSSL_FILE_H
+#define GMSSL_FILE_H
+
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+int file_size(FILE *fp, size_t *size);
+int file_read_all(const char *file, uint8_t **out, size_t *outlen);
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif

+ 73 - 0
components/gmssl/include/gmssl/gcm.h

@@ -0,0 +1,73 @@
+/*
+ *  Copyright 2014-2022 The GmSSL Project. All Rights Reserved.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the License); you may
+ *  not use this file except in compliance with the License.
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ */
+
+
+#ifndef GMSSL_GCM_H
+#define GMSSL_GCM_H
+
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <gmssl/gf128.h>
+#include <gmssl/block_cipher.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define GCM_IV_MIN_SIZE		1
+#define GCM_IV_MAX_SIZE		((uint64_t)(1 << (64-3)))
+#define GCM_IV_DEFAULT_BITS	96
+#define GCM_IV_DEFAULT_SIZE	12
+
+#define GCM_MIN_AAD_SIZE	0
+#define GCM_MAX_AAD_SIZE	((uint64_t)(1 << (64-3)))
+
+#define GCM_MIN_PLAINTEXT_SIZE	0
+#define GCM_MAX_PLAINTEXT_SIZE	((((uint64_t)1 << 39) - 256) >> 3)
+
+
+#define GHASH_SIZE		(16)
+
+
+#define GCM_IS_LITTLE_ENDIAN 1
+
+
+void ghash(const uint8_t h[16], const uint8_t *aad, size_t aadlen,
+	const uint8_t *c, size_t clen, uint8_t out[16]);
+
+typedef struct {
+	gf128_t H;
+	gf128_t X;
+	size_t aadlen;
+	size_t clen;
+	uint8_t block[16];
+	size_t num;
+} GHASH_CTX;
+
+void ghash_init(GHASH_CTX *ctx, const uint8_t h[16], const uint8_t *aad, size_t aadlen);
+void ghash_update(GHASH_CTX *ctx, const uint8_t *c, size_t clen);
+void ghash_finish(GHASH_CTX *ctx, uint8_t out[16]);
+
+
+int gcm_encrypt(const BLOCK_CIPHER_KEY *key, const uint8_t *iv, size_t ivlen,
+	const uint8_t *aad, size_t aadlen, const uint8_t *in, size_t inlen,
+	uint8_t *out, size_t taglen, uint8_t *tag);
+
+int gcm_decrypt(const BLOCK_CIPHER_KEY *key, const uint8_t *iv, size_t ivlen,
+	const uint8_t *aad, size_t aadlen, const uint8_t *in, size_t inlen,
+	const uint8_t *tag, size_t taglen, uint8_t *out);
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif

+ 53 - 0
components/gmssl/include/gmssl/gf128.h

@@ -0,0 +1,53 @@
+/*
+ *  Copyright 2014-2022 The GmSSL Project. All Rights Reserved.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the License); you may
+ *  not use this file except in compliance with the License.
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ */
+
+
+/* GF(2^128) defined by f(x) = x^128 + x^7 + x^2 + x + 1
+ * A + B mod f(x) = a xor b
+ * A * 2 mod f(x)
+ */
+
+#ifndef GMSSL_GF128_H
+#define GMSSL_GF128_H
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+//typedef unsigned __int128 gf128_t;
+
+typedef struct {
+	uint64_t hi;
+	uint64_t lo;
+} gf128_t;
+
+
+// Note: send by value is comptabile with uint128_t and sse2
+gf128_t gf128_from_hex(const char *s);
+int gf128_equ_hex(gf128_t a, const char *s);
+gf128_t gf128_zero(void);
+gf128_t gf128_add(gf128_t a, gf128_t b);
+gf128_t gf128_mul(gf128_t a, gf128_t b);
+gf128_t gf128_mul2(gf128_t a);
+gf128_t gf128_from_bytes(const uint8_t p[16]);
+void gf128_to_bytes(gf128_t a, uint8_t p[16]);
+int gf128_print(FILE *fp, int fmt ,int ind, const char *label, gf128_t a);
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif

+ 79 - 0
components/gmssl/include/gmssl/hash_drbg.h

@@ -0,0 +1,79 @@
+/*
+ *  Copyright 2014-2022 The GmSSL Project. All Rights Reserved.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the License); you may
+ *  not use this file except in compliance with the License.
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ */
+
+
+/* NIST SP800-90A Rev.1 "Recommendation for Random Number Generation
+ * Using Deterministic Random Bit Generators", 10.1.1 Hash_DRBG */
+
+#ifndef GMSSL_HASH_DRBG_H
+#define GMSSL_HASH_DRBG_H
+
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <gmssl/digest.h>
+
+
+/* seedlen for hash_drgb, table 2 of nist sp 800-90a rev.1 */
+#define HASH_DRBG_SM3_SEED_BITS		440 /* 55 bytes */
+#define HASH_DRBG_SHA1_SEED_BITS	440
+#define HASH_DRBG_SHA224_SEED_BITS	440
+#define HASH_DRBG_SHA512_224_SEED_BITS	440
+#define HASH_DRBG_SHA256_SEED_BITS	440
+#define HASH_DRBG_SHA512_256_SEED_BITS	440
+#define HASH_DRBG_SHA384_SEED_BITS	888 /* 110 bytes */
+#define HASH_DRBG_SHA512_SEED_BITS	888
+#define HASH_DRBG_MAX_SEED_BITS		888
+
+#define HASH_DRBG_SM3_SEED_SIZE		(HASH_DRBG_SM3_SEED_BITS/8)
+#define HASH_DRBG_SHA1_SEED_SIZE	(HASH_DRBG_SHA1_SEED_BITS/8)
+#define HASH_DRBG_SHA224_SEED_SIZE	(HASH_DRBG_SHA224_SEED_BITS/8)
+#define HASH_DRBG_SHA512_224_SEED_SIZE	(HASH_DRBG_SHA512_224_SEED_BITS/8)
+#define HASH_DRBG_SHA256_SEED_SIZE	(HASH_DRBG_SHA256_SEED_BITS/8)
+#define HASH_DRBG_SHA512_256_SEED_SIZE	(HASH_DRBG_SHA512_256_SEED_BITS/8)
+#define HASH_DRBG_SHA384_SEED_SIZE	(HASH_DRBG_SHA384_SEED_BITS/8)
+#define HASH_DRBG_SHA512_SEED_SIZE	(HASH_DRBG_SHA512_SEED_BITS/8)
+#define HASH_DRBG_MAX_SEED_SIZE		(HASH_DRBG_MAX_SEED_BITS/8)
+
+#define HASH_DRBG_RESEED_INTERVAL	((uint64_t)1 << 48)
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+typedef struct {
+	const DIGEST *digest;
+	uint8_t V[HASH_DRBG_MAX_SEED_SIZE];
+	uint8_t C[HASH_DRBG_MAX_SEED_SIZE];
+	size_t seedlen;
+	uint64_t reseed_counter;
+} HASH_DRBG;
+
+
+int hash_drbg_init(HASH_DRBG *drbg,
+	const DIGEST *digest,
+	const uint8_t *entropy, size_t entropy_len,
+	const uint8_t *nonce, size_t nonce_len,
+	const uint8_t *personalstr, size_t personalstr_len);
+
+int hash_drbg_reseed(HASH_DRBG *drbg,
+	const uint8_t *entropy, size_t entropy_len,
+	const uint8_t *additional, size_t additional_len);
+
+int hash_drbg_generate(HASH_DRBG *drbg,
+	const uint8_t *additional, size_t additional_len,
+	size_t outlen, uint8_t *out);
+
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif

+ 32 - 0
components/gmssl/include/gmssl/hex.h

@@ -0,0 +1,32 @@
+/*
+ *  Copyright 2014-2022 The GmSSL Project. All Rights Reserved.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the License); you may
+ *  not use this file except in compliance with the License.
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ */
+
+
+
+#ifndef GMSSL_HEX_H
+#define GMSSL_HEX_H
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int hex_to_bytes(const char *in, size_t inlen, uint8_t *out, size_t *outlen);
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif

+ 45 - 0
components/gmssl/include/gmssl/hkdf.h

@@ -0,0 +1,45 @@
+/*
+ *  Copyright 2014-2022 The GmSSL Project. All Rights Reserved.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the License); you may
+ *  not use this file except in compliance with the License.
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ */
+
+// RFC 5869
+
+#ifndef GMSSL_HKDF_H
+#define GMSSL_HKDF_H
+
+#include <string.h>
+#include <gmssl/digest.h>
+#include <gmssl/hmac.h>
+
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+
+int hkdf_extract(const DIGEST *digest, const uint8_t *salt, size_t saltlen,
+	const uint8_t *ikm, size_t ikmlen,
+	uint8_t *prk, size_t *prklen);
+
+int hkdf_expand(const DIGEST *digest, const uint8_t *prk, size_t prklen,
+	const uint8_t *opt_info, size_t opt_infolen,
+	size_t L, uint8_t *okm);
+
+int sm3_hkdf_extract(const uint8_t *salt, size_t saltlen,
+	const uint8_t *ikm, size_t ikmlen,
+	uint8_t *prk, size_t *prklen);
+
+int sm3_hkdf_expand(const uint8_t *prk, size_t prklen,
+	const uint8_t *opt_info, size_t opt_infolen,
+	size_t L, uint8_t *okm);
+
+
+#ifdef  __cplusplus
+}
+#endif
+#endif

+ 47 - 0
components/gmssl/include/gmssl/hmac.h

@@ -0,0 +1,47 @@
+/*
+ *  Copyright 2014-2022 The GmSSL Project. All Rights Reserved.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the License); you may
+ *  not use this file except in compliance with the License.
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ */
+
+
+#ifndef GMSSL_HMAC_H
+#define GMSSL_HMAC_H
+
+#include <string.h>
+#include <gmssl/digest.h>
+
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+#define HMAC_MAX_SIZE	(DIGEST_MAX_SIZE)
+
+
+typedef struct hmac_ctx_st {
+	const DIGEST *digest;
+	DIGEST_CTX digest_ctx;
+	DIGEST_CTX i_ctx;
+	DIGEST_CTX o_ctx;
+} HMAC_CTX;
+
+
+size_t hmac_size(const HMAC_CTX *ctx);
+
+int hmac_init(HMAC_CTX *ctx, const DIGEST *digest, const uint8_t *key, size_t keylen);
+int hmac_update(HMAC_CTX *ctx, const uint8_t *data, size_t datalen);
+int hmac_finish(HMAC_CTX *ctx, uint8_t *mac, size_t *maclen);
+
+int hmac(const DIGEST *md, const uint8_t *key, size_t keylen,
+	const uint8_t *data, size_t dlen,
+	uint8_t *mac, size_t *maclen);
+
+
+#ifdef  __cplusplus
+}
+#endif
+#endif

+ 29 - 0
components/gmssl/include/gmssl/http.h

@@ -0,0 +1,29 @@
+/*
+ *  Copyright 2014-2023 The GmSSL Project. All Rights Reserved.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the License); you may
+ *  not use this file except in compliance with the License.
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ */
+
+
+#ifndef GMSSL_HTTP_H
+#define GMSSL_HTTP_H
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+int http_parse_uri(const char *uri, char host[128], int *port, char path[256]);
+int http_parse_response(char *buf, size_t buflen, uint8_t **content, size_t *contentlen, size_t *left);
+int http_get(const char *uri, uint8_t *buf, size_t *contentlen, size_t buflen);
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif

+ 48 - 0
components/gmssl/include/gmssl/md5.h

@@ -0,0 +1,48 @@
+/*
+ *  Copyright 2014-2022 The GmSSL Project. All Rights Reserved.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the License); you may
+ *  not use this file except in compliance with the License.
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ */
+
+
+
+#ifndef GMSSL_MD5_H
+#define GMSSL_MD5_H
+
+
+#include <string.h>
+#include <stdint.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#define MD5_IS_BIG_ENDIAN	0
+
+#define MD5_DIGEST_SIZE		16
+#define MD5_BLOCK_SIZE		64
+#define MD5_STATE_WORDS		(MD5_BLOCK_SIZE/sizeof(uint32_t))
+
+typedef struct {
+	uint32_t state[MD5_STATE_WORDS];
+	uint64_t nblocks;
+	uint8_t block[MD5_BLOCK_SIZE];
+	size_t num;
+} MD5_CTX;
+
+
+void md5_init(MD5_CTX *ctx);
+void md5_update(MD5_CTX *ctx, const uint8_t *data, size_t datalen);
+void md5_finish(MD5_CTX *ctx, uint8_t dgst[MD5_DIGEST_SIZE]);
+void md5_digest(const uint8_t *data, size_t datalen, uint8_t dgst[MD5_DIGEST_SIZE]);
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif

+ 27 - 0
components/gmssl/include/gmssl/mem.h

@@ -0,0 +1,27 @@
+/*
+ *  Copyright 2014-2022 The GmSSL Project. All Rights Reserved.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the License); you may
+ *  not use this file except in compliance with the License.
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ */
+
+
+#ifndef GMSSL_MEM_H
+#define GMSSL_MEM_H
+
+#include <stdint.h>
+#include <stddef.h> // where size_t from
+
+
+void memxor(void *r, const void *a, size_t len);
+void gmssl_memxor(void *r, const void *a, const void *b, size_t len);
+
+int gmssl_secure_memcmp(const volatile void * volatile in_a, const volatile void * volatile in_b, size_t len);
+void gmssl_secure_clear(void *ptr, size_t len);
+
+int mem_is_zero(const uint8_t *buf, size_t len); // FIXME: uint8_t * to void *
+
+#endif
+

+ 215 - 0
components/gmssl/include/gmssl/oid.h

@@ -0,0 +1,215 @@
+/*
+ *  Copyright 2014-2023 The GmSSL Project. All Rights Reserved.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the License); you may
+ *  not use this file except in compliance with the License.
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ */
+
+
+
+#ifndef GMSSL_OID_H
+#define GMSSL_OID_H
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+enum {
+	OID_undef = 0,
+
+	// ShangMi schemes in GM/T 0006-2012
+	OID_sm1,
+	OID_ssf33,
+	OID_sm4,
+	OID_zuc,
+	OID_sm2,
+	OID_sm2sign,
+	OID_sm2keyagreement,
+	OID_sm2encrypt,
+	OID_sm9,
+	OID_sm9sign,
+	OID_sm9keyagreement,
+	OID_sm9encrypt,
+	OID_sm3,
+	OID_sm3_keyless,
+	OID_hmac_sm3,
+	OID_sm2sign_with_sm3,
+	OID_rsasign_with_sm3,
+	OID_ec_public_key, // X9.62 ecPublicKey
+	OID_prime192v1,
+	OID_prime256v1,
+	OID_secp256k1,
+	OID_secp192k1,
+	OID_secp224k1,
+	OID_secp224r1,
+	OID_secp384r1,
+	OID_secp521r1,
+
+	OID_at_name,
+	OID_at_surname,
+	OID_at_given_name,
+	OID_at_initials,
+	OID_at_generation_qualifier,
+	OID_at_common_name,
+	OID_at_locality_name,
+	OID_at_state_or_province_name,
+	OID_at_organization_name,
+	OID_at_organizational_unit_name,
+	OID_at_title,
+	OID_at_dn_qualifier,
+	OID_at_country_name,
+	OID_at_serial_number,
+	OID_at_pseudonym,
+	OID_domain_component,
+	OID_email_address,
+
+	// Cert Extensions
+	OID_ce_authority_key_identifier,
+	OID_ce_subject_key_identifier,
+	OID_ce_key_usage,
+	OID_ce_certificate_policies,
+	OID_ce_policy_mappings,
+	OID_ce_subject_alt_name,
+	OID_ce_issuer_alt_name,
+	OID_ce_subject_directory_attributes,
+	OID_ce_basic_constraints,
+	OID_ce_name_constraints,
+	OID_ce_policy_constraints,
+	OID_ce_ext_key_usage,
+	OID_ce_crl_distribution_points,
+	OID_ce_inhibit_any_policy,
+	OID_ce_freshest_crl,
+	OID_netscape_cert_type,
+	OID_netscape_cert_comment,
+	OID_ct_precertificate_scts,
+
+	OID_ad_ca_issuers,
+	OID_ad_ocsp,
+
+	// CRL Extensions
+	//OID_ce_authority_key_identifier,
+	//OID_ce_issuer_alt_name,
+	OID_ce_crl_number,
+	OID_ce_delta_crl_indicator,
+	OID_ce_issuing_distribution_point,
+	//OID_ce_freshest_crl,
+	OID_pe_authority_info_access,
+
+	// CRL Entry Extensions
+	OID_ce_crl_reasons,
+	OID_ce_invalidity_date,
+	OID_ce_certificate_issuer,
+
+	// X.509 KeyPropuseID
+	OID_any_extended_key_usage,
+	OID_kp_server_auth,
+	OID_kp_client_auth,
+	OID_kp_code_signing,
+	OID_kp_email_protection,
+	OID_kp_time_stamping,
+	OID_kp_ocsp_signing,
+
+	OID_qt_cps,
+	OID_qt_unotice,
+
+	OID_md5,
+	OID_sha1,
+	OID_sha224,
+	OID_sha256,
+	OID_sha384,
+	OID_sha512,
+	OID_sha512_224,
+	OID_sha512_256,
+
+
+	OID_hmac_sha1,
+	OID_hmac_sha224,
+	OID_hmac_sha256,
+	OID_hmac_sha384,
+	OID_hmac_sha512,
+	OID_hmac_sha512_224,
+	OID_hmac_sha512_256,
+
+	OID_pbkdf2, // {pkcs-5 12}
+	OID_pbes2,  // {pkcs-5 13}
+
+
+
+	OID_sm4_ecb, // 1 2 156 10197 1 104 1
+	OID_sm4_cbc, // 1 2 156 10197 1 104 2
+
+	OID_aes,
+	OID_aes128_cbc,
+	OID_aes192_cbc,
+	OID_aes256_cbc,
+
+	OID_aes128, // 没有OID
+
+	OID_ecdsa_with_sha1,
+	OID_ecdsa_with_sha224,
+	OID_ecdsa_with_sha256,
+	OID_ecdsa_with_sha384,
+	OID_ecdsa_with_sha512,
+
+	OID_rsasign_with_md5,
+	OID_rsasign_with_sha1,
+	OID_rsasign_with_sha224,
+	OID_rsasign_with_sha256,
+	OID_rsasign_with_sha384,
+	OID_rsasign_with_sha512,
+
+	OID_rsa_encryption,
+	OID_rsaes_oaep,
+
+	OID_any_policy,
+
+	OID_cms_data,
+	OID_cms_signed_data,
+	OID_cms_enveloped_data,
+	OID_cms_signed_and_enveloped_data,
+	OID_cms_encrypted_data,
+	OID_cms_key_agreement_info,
+};
+
+// {iso(1) org(3) dod(6) internet(1) security(5) mechanisms(5) pkix(7)}
+#define oid_pkix	1,3,6,1,5,5,7
+
+#define oid_pe		oid_pkix,1
+#define oid_qt		oid_pkix,2
+#define oid_kp		oid_pkix,3
+#define oid_ad		oid_pkix,48
+
+// {iso(1) member-body(2) us(840) rsadsi(113549)}
+#define oid_rsadsi	1,2,840,113549
+#define oid_pkcs	oid_rsadsi,1
+#define oid_pkcs5	oid_pkcs,5
+
+// {iso(1) member-body(2) us(840) ansi-x962(10045)}
+#define oid_x9_62	1,2,840,10045
+
+
+
+#define oid_at	2,5,4
+#define oid_ce	2,5,29
+
+
+#define oid_sm		1,2,156,10197
+#define oid_sm_algors	oid_sm,1
+#define oid_sm2_cms	oid_sm,6,1,4,2
+
+
+
+
+
+#define oid_cnt(nodes)	(sizeof(nodes)/sizeof((nodes)[0]))
+
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif

+ 54 - 0
components/gmssl/include/gmssl/pbkdf2.h

@@ -0,0 +1,54 @@
+/*
+ *  Copyright 2014-2022 The GmSSL Project. All Rights Reserved.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the License); you may
+ *  not use this file except in compliance with the License.
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ */
+
+
+#ifndef GMSSL_PBKDF2_H
+#define GMSSL_PBKDF2_H
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <limits.h>
+#include <gmssl/hmac.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+PBKDF2 Public API
+
+	PBKDF2_MIN_ITER
+	PBKDF2_DEFAULT_SALT_SIZE
+	PBKDF2_MAX_SALT_SIZE
+
+	pbkdf2_hmac_sm3_genkey
+*/
+
+
+#define PBKDF2_MIN_ITER			10000
+#define PBKDF2_MAX_ITER			(INT_MAX)
+#define PBKDF2_MAX_SALT_SIZE		64
+#define PBKDF2_DEFAULT_SALT_SIZE	8
+
+
+int pbkdf2_genkey(const DIGEST *digest,
+	const char *pass, size_t passlen, const uint8_t *salt, size_t saltlen, size_t iter,
+	size_t outlen, uint8_t *out);
+
+int pbkdf2_hmac_sm3_genkey(
+	const char *pass, size_t passlen, const uint8_t *salt, size_t saltlen, size_t iter,
+	size_t outlen, uint8_t *out);
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif

+ 33 - 0
components/gmssl/include/gmssl/pem.h

@@ -0,0 +1,33 @@
+/*
+ *  Copyright 2014-2022 The GmSSL Project. All Rights Reserved.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the License); you may
+ *  not use this file except in compliance with the License.
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ */
+
+
+#ifndef GMSSL_PEM_H
+#define GMSSL_PEM_H
+
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <gmssl/base64.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+int pem_read(FILE *fp, const char *name, uint8_t *out, size_t *outlen, size_t maxlen);
+int pem_write(FILE *fp, const char *name, const uint8_t *in, size_t inlen);
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif

+ 169 - 0
components/gmssl/include/gmssl/pkcs8.h

@@ -0,0 +1,169 @@
+/*
+ *  Copyright 2014-2022 The GmSSL Project. All Rights Reserved.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the License); you may
+ *  not use this file except in compliance with the License.
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ */
+
+// RFC 5208: PKCS #8: Private-Key Information Syntax Specification version 1.2
+
+
+#ifndef GMSSL_PKCS8_H
+#define GMSSL_PKCS8_H
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <gmssl/sm2.h>
+#include <gmssl/pem.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/*
+id-PBKDF2 OBJECT IDENTIFIER ::= {pkcs-5 12}
+
+PBKDF2-params ::= SEQUENCE {
+	salt CHOICE {
+		specified	OCTET STRING,
+		otherSource	AlgorithmIdentifier {{PBKDF2-SaltSources}}
+	},
+	iterationCount		INTEGER (1..MAX),
+	keyLength		INTEGER (1..MAX) OPTIONAL, -- 这个参数可以由函数指定
+	prf			AlgorithmIdentifier {{PBKDF2-PRFs}} DEFAULT algid-hmacWithSHA1
+}
+
+prf must be OID_hmac_sm3
+cipher must be OID_sm4_cbc
+*/
+int pbkdf2_params_to_der(const uint8_t *salt, size_t saltlen, int iter, int keylen, int prf,
+	uint8_t **out, size_t *outlen);
+int pbkdf2_params_from_der(const uint8_t **salt, size_t *saltlen, int *iter, int *keylen, int *prf,
+	const uint8_t **in, size_t *inlen);
+int pbkdf2_params_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen);
+
+int pbkdf2_algor_to_der(
+	const uint8_t *salt, size_t saltlen,
+	int iter,
+	int keylen,
+	int prf,
+	uint8_t **out, size_t *outlen);
+int pbkdf2_algor_from_der(
+	const uint8_t **salt, size_t *saltlen,
+	int *iter,
+	int *keylen,
+	int *prf,
+	const uint8_t **in, size_t *inlen);
+int pbkdf2_algor_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen);
+
+
+/*
+id-PBES2 OBJECT IDENTIFIER ::= {pkcs-5 13}
+
+PBES2-params ::= SEQUENCE {
+	keyDerivationFunc	AlgorithmIdentifier {{PBES2-KDFs}}, -- id-PBKDF2
+	encryptionScheme	AlgorithmIdentifier {{PBES2-Encs}}}
+
+PBES2-Encs:
+	AES-CBC-Pad [RFC2898]
+	RC5-CBC-Pad
+	DES-CBC-Pad		legacy
+	DES-EDE3-CBC-Pad	legacy
+	RC2-CBC-Pad		legacy
+*/
+
+int pbes2_enc_algor_to_der(
+	int cipher,
+	const uint8_t *iv, size_t ivlen,
+	uint8_t **out, size_t *outlen);
+int pbes2_enc_algor_from_der(
+	int *cipher,
+	const uint8_t **iv, size_t *ivlen,
+	const uint8_t **in, size_t *inlen);
+int pbes2_enc_algor_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen);
+
+
+int pbes2_params_to_der(
+	const uint8_t *salt, size_t saltlen,
+	int iter,
+	int keylen,
+	int prf,
+	int cipher,
+	const uint8_t *iv, size_t ivlen,
+	uint8_t **out, size_t *outlen);
+int pbes2_params_from_der(
+	const uint8_t **salt, size_t *saltlen,
+	int *iter,
+	int *keylen,
+	int *prf,
+	int *cipher,
+	const uint8_t **iv, size_t *ivlen,
+	const uint8_t **in, size_t *inlen);
+int pbes2_params_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen);
+
+
+int pbes2_algor_to_der(
+	const uint8_t *salt, size_t saltlen,
+	int iter,
+	int keylen,
+	int prf,
+	int cipher,
+	const uint8_t *iv, size_t ivlen,
+	uint8_t **out, size_t *outlen);
+int pbes2_algor_from_der(
+	const uint8_t **salt, size_t *saltlen,
+	int *iter,
+	int *keylen,
+	int *prf,
+	int *cipher,
+	const uint8_t **iv, size_t *ivlen,
+	const uint8_t **in, size_t *inlen);
+int pbes2_algor_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen);
+
+/*
+from [RFC 5208]
+
+EncryptedPrivateKeyInfo ::= SEQUENCE {
+	encryptionAlgorithm	EncryptionAlgorithmIdentifier,
+	encryptedData		OCTET STRING }
+
+encryptionAlgorithm:
+	id-PBES2
+
+PrivateKeyInfo ::= SEQUENCE {
+	version			INTEGER { v1(0) },
+	privateKeyAlgorithm	AlgorithmIdentifier,
+	privateKey		OCTET STRING,
+	attributes		[0] Attributes OPTIONAL }
+*/
+
+int pkcs8_enced_private_key_info_to_der(
+	const uint8_t *salt, size_t saltlen,
+	int iter,
+	int keylen,
+	int prf,
+	int cipher,
+	const uint8_t *iv, size_t ivlen,
+	const uint8_t *enced, size_t encedlen,
+	uint8_t **out, size_t *outlen);
+int pkcs8_enced_private_key_info_from_der(
+	const uint8_t **salt, size_t *saltlen,
+	int *iter,
+	int *keylen,
+	int *prf,
+	int *cipher,
+	const uint8_t **iv, size_t *ivlen,
+	const uint8_t **enced, size_t *encedlen,
+	const uint8_t **in, size_t *inlen);
+int pkcs8_enced_private_key_info_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen);
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif

+ 35 - 0
components/gmssl/include/gmssl/rand.h

@@ -0,0 +1,35 @@
+/*
+ *  Copyright 2014-2022 The GmSSL Project. All Rights Reserved.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the License); you may
+ *  not use this file except in compliance with the License.
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ */
+
+
+#ifndef GMSSL_RAND_H
+#define GMSSL_RAND_H
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <gmssl/api.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+Rand Public API
+
+	rand_bytes
+
+*/
+
+_gmssl_export int rand_bytes(uint8_t *buf, size_t buflen);
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif

+ 40 - 0
components/gmssl/include/gmssl/rc4.h

@@ -0,0 +1,40 @@
+/*
+ *  Copyright 2014-2022 The GmSSL Project. All Rights Reserved.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the License); you may
+ *  not use this file except in compliance with the License.
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ */
+
+
+
+#ifndef GMSSL_RC4_H
+#define GMSSL_RC4_H
+
+
+#include <string.h>
+#include <stdint.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#define RC4_MIN_KEY_BITS	40
+#define RC4_STATE_NUM_WORDS	256
+
+
+typedef struct {
+	uint8_t d[RC4_STATE_NUM_WORDS];
+} RC4_STATE;
+
+void rc4_init(RC4_STATE *state, const uint8_t *key, size_t keylen);
+void rc4_generate_keystream(RC4_STATE *state, size_t outlen, uint8_t *out);
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif

+ 30 - 0
components/gmssl/include/gmssl/rdrand.h

@@ -0,0 +1,30 @@
+/*
+ *  Copyright 2014-2022 The GmSSL Project. All Rights Reserved.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the License); you may
+ *  not use this file except in compliance with the License.
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ */
+
+
+#ifndef GMSSL_RDRAND_H
+#define GMSSL_RDRAND_H
+
+#include <stdint.h>
+#include <stdlib.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+int rdrand_bytes(uint8_t *buf, size_t buflen);
+int rdseed_bytes(uint8_t *buf, size_t buflen);
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif

+ 56 - 0
components/gmssl/include/gmssl/rsa.h

@@ -0,0 +1,56 @@
+/*
+ *  Copyright 2014-2022 The GmSSL Project. All Rights Reserved.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the License); you may
+ *  not use this file except in compliance with the License.
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ */
+
+
+
+#ifndef GMSSL_RSA_H
+#define GMSSL_RSA_H
+
+
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/*
+RSAPublicKey ::= SEQUENCE {
+	modulus			INTEGER,  -- n
+	publicExponent		INTEGER   -- e
+}
+
+RSAPrivateKey ::= SEQUENCE {
+	version			INTEGER, -- 0
+	modulus			INTEGER, -- n
+	publicExponent		INTEGER, -- e
+	privateExponent		INTEGER, -- d
+	prime1			INTEGER, -- p
+	prime2			INTEGER, -- q
+	exponent1		INTEGER, -- d mod (p-1)
+	exponent2		INTEGER, -- d mod (q-1)
+	coefficient		INTEGER  -- q^-1 mod p
+}
+*/
+
+
+int rsa_public_key_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen);
+
+
+
+
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif

+ 69 - 0
components/gmssl/include/gmssl/sdf.h

@@ -0,0 +1,69 @@
+/*
+ *  Copyright 2014-2022 The GmSSL Project. All Rights Reserved.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the License); you may
+ *  not use this file except in compliance with the License.
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ */
+
+
+#ifndef GMSSL_SDF_H
+#define GMSSL_SDF_H
+
+#include <string.h>
+#include <stdint.h>
+#include <gmssl/sm2.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+SDF Public API
+
+	sdf_load_library
+	sdf_unload_library
+
+	SDF_DEVICE
+	sdf_open_device
+	sdf_close_device
+	sdf_print_device_info
+	sdf_rand_bytes
+	sdf_load_sign_key
+
+	SDF_KEY
+	sdf_sign
+	sdf_release_key
+*/
+
+typedef struct {
+	void *handle;
+	char issuer[41];
+	char name[17];
+	char serial[17];
+} SDF_DEVICE;
+
+typedef struct {
+	SM2_KEY public_key;
+	void *session;
+	int index;
+} SDF_KEY;
+
+
+int sdf_load_library(const char *so_path, const char *vendor);
+int sdf_open_device(SDF_DEVICE *dev);
+int sdf_print_device_info(FILE *fp, int fmt, int ind, const char *lable, SDF_DEVICE *dev);
+int sdf_rand_bytes(SDF_DEVICE *dev, uint8_t *buf, size_t len);
+int sdf_load_sign_key(SDF_DEVICE *dev, SDF_KEY *key, int index, const char *pass);
+int sdf_sign(SDF_KEY *key, const uint8_t dgst[32], uint8_t *sig, size_t *siglen);
+int sdf_release_key(SDF_KEY *key);
+int sdf_close_device(SDF_DEVICE *dev);
+void sdf_unload_library(void);
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif

+ 45 - 0
components/gmssl/include/gmssl/sha1.h

@@ -0,0 +1,45 @@
+/*
+ *  Copyright 2014-2022 The GmSSL Project. All Rights Reserved.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the License); you may
+ *  not use this file except in compliance with the License.
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ */
+
+
+#ifndef GMSSL_SHA1_H
+#define GMSSL_SHA1_H
+
+#include <string.h>
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#define SHA1_IS_BIG_ENDIAN	1
+
+#define SHA1_DIGEST_SIZE	20
+#define SHA1_BLOCK_SIZE		64
+#define SHA1_STATE_WORDS	(SHA1_DIGEST_SIZE/sizeof(uint32_t))
+
+
+typedef struct {
+	uint32_t state[SHA1_STATE_WORDS];
+	uint64_t nblocks;
+	uint8_t block[SHA1_BLOCK_SIZE];
+	size_t num;
+} SHA1_CTX;
+
+void sha1_init(SHA1_CTX *ctx);
+void sha1_update(SHA1_CTX *ctx, const uint8_t *data, size_t datalen);
+void sha1_finish(SHA1_CTX *ctx, uint8_t dgst[SHA1_DIGEST_SIZE]);
+void sha1_digest(const uint8_t *data, size_t datalen, uint8_t dgst[SHA1_DIGEST_SIZE]);
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif

+ 102 - 0
components/gmssl/include/gmssl/sha2.h

@@ -0,0 +1,102 @@
+/*
+ *  Copyright 2014-2022 The GmSSL Project. All Rights Reserved.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the License); you may
+ *  not use this file except in compliance with the License.
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ */
+
+
+
+#ifndef GMSSL_SHA2_H
+#define GMSSL_SHA2_H
+
+#include <string.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#define SHA2_IS_BIG_ENDIAN	1
+
+
+#define SHA224_DIGEST_SIZE	28
+#define SHA224_BLOCK_SIZE	64
+#define SHA224_STATE_WORDS	8
+
+typedef struct {
+	uint32_t state[SHA224_STATE_WORDS];
+	uint64_t nblocks;
+	uint8_t block[SHA224_BLOCK_SIZE];
+	size_t num;
+} SHA224_CTX;
+
+void sha224_init(SHA224_CTX *ctx);
+void sha224_update(SHA224_CTX *ctx, const uint8_t* data, size_t datalen);
+void sha224_finish(SHA224_CTX *ctx, uint8_t dgst[SHA224_DIGEST_SIZE]);
+void sha224_digest(const uint8_t *data, size_t datalen,
+	uint8_t dgst[SHA224_DIGEST_SIZE]);
+
+
+#define SHA256_DIGEST_SIZE	32
+#define SHA256_BLOCK_SIZE	64
+#define SHA256_STATE_WORDS	8
+
+typedef struct {
+	uint32_t state[SHA256_STATE_WORDS];
+	uint64_t nblocks;
+	uint8_t block[SHA256_BLOCK_SIZE];
+	size_t num;
+} SHA256_CTX;
+
+void sha256_init(SHA256_CTX *ctx);
+void sha256_update(SHA256_CTX *ctx, const uint8_t* data, size_t datalen);
+void sha256_finish(SHA256_CTX *ctx, uint8_t dgst[SHA256_DIGEST_SIZE]);
+void sha256_digest(const uint8_t *data, size_t datalen,
+	uint8_t dgst[SHA256_DIGEST_SIZE]);
+
+
+#define SHA384_DIGEST_SIZE	48
+#define SHA384_BLOCK_SIZE	128
+#define SHA384_STATE_WORDS	8
+
+typedef struct {
+	uint64_t state[SHA384_STATE_WORDS];
+	uint64_t nblocks;
+	uint8_t block[SHA384_BLOCK_SIZE];
+	size_t num;
+} SHA384_CTX;
+
+void sha384_init(SHA384_CTX *ctx);
+void sha384_update(SHA384_CTX *ctx, const uint8_t* data, size_t datalen);
+void sha384_finish(SHA384_CTX *ctx, uint8_t dgst[SHA384_DIGEST_SIZE]);
+void sha384_digest(const uint8_t *data, size_t datalen,
+	uint8_t dgst[SHA384_DIGEST_SIZE]);
+
+
+#define SHA512_DIGEST_SIZE	64
+#define SHA512_BLOCK_SIZE	128
+#define SHA512_STATE_WORDS	8
+
+typedef struct {
+	uint64_t state[SHA512_STATE_WORDS];
+	uint64_t nblocks;
+	uint8_t block[SHA512_BLOCK_SIZE];
+	size_t num;
+} SHA512_CTX;
+
+void sha512_init(SHA512_CTX *ctx);
+void sha512_update(SHA512_CTX *ctx, const uint8_t* data, size_t datalen);
+void sha512_finish(SHA512_CTX *ctx, uint8_t dgst[SHA512_DIGEST_SIZE]);
+void sha512_digest(const uint8_t *data, size_t datalen,
+	uint8_t dgst[SHA512_DIGEST_SIZE]);
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif

+ 92 - 0
components/gmssl/include/gmssl/sha3.h

@@ -0,0 +1,92 @@
+/*
+ *  Copyright 2014-2022 The GmSSL Project. All Rights Reserved.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the License); you may
+ *  not use this file except in compliance with the License.
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ */
+
+
+
+#ifndef GMSSL_SHA3_H
+#define GMSSL_SHA3_H
+
+
+#include <string.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#define SHA3_KECCAK_P_SIZE (1600/8)
+
+#define SHA3_224_DIGEST_SIZE (224/8)
+#define SHA3_256_DIGEST_SIZE (256/8)
+#define SHA3_384_DIGEST_SIZE (384/8)
+#define SHA3_512_DIGEST_SIZE (512/8)
+
+#define SHA3_224_CAPACITY (SHA3_224_DIGEST_SIZE * 2)
+#define SHA3_256_CAPACITY (SHA3_256_DIGEST_SIZE * 2)
+#define SHA3_384_CAPACITY (SHA3_384_DIGEST_SIZE * 2)
+#define SHA3_512_CAPACITY (SHA3_512_DIGEST_SIZE * 2)
+
+#define SHA3_224_BLOCK_SIZE (SHA3_KECCAK_P_SIZE - SHA3_224_CAPACITY) // 144
+#define SHA3_256_BLOCK_SIZE (SHA3_KECCAK_P_SIZE - SHA3_224_CAPACITY) // 136
+#define SHA3_384_BLOCK_SIZE (SHA3_KECCAK_P_SIZE - SHA3_224_CAPACITY) // 104
+#define SHA3_512_BLOCK_SIZE (SHA3_KECCAK_P_SIZE - SHA3_224_CAPACITY) // 72
+
+
+typedef struct {
+	uint64_t A[5][5];
+	uint8_t buf[SHA3_224_BLOCK_SIZE];
+	int num;
+} SHA3_224_CTX;
+
+void sha3_224_init(SHA3_224_CTX *ctx);
+void sha3_224_update(SHA3_224_CTX *ctx, const uint8_t *data, size_t datalen);
+void sha3_224_finish(SHA3_224_CTX *ctx, uint8_t dgst[SHA3_224_DIGEST_SIZE]);
+
+typedef struct {
+	uint64_t A[5][5];
+	uint8_t buf[SHA3_256_BLOCK_SIZE];
+	int num;
+} SHA3_256_CTX;
+
+void sha3_256_init(SHA3_256_CTX *ctx);
+void sha3_256_update(SHA3_256_CTX *ctx, const uint8_t *data, size_t datalen);
+void sha3_256_finish(SHA3_256_CTX *ctx, uint8_t dgst[SHA3_256_DIGEST_SIZE]);
+
+typedef struct {
+	uint64_t A[5][5];
+	uint8_t buf[SHA3_384_BLOCK_SIZE];
+	int num;
+} SHA3_384_CTX;
+
+void sha3_384_init(SHA3_384_CTX *ctx);
+void sha3_384_update(SHA3_384_CTX *ctx, const uint8_t *data, size_t datalen);
+void sha3_384_finish(SHA3_384_CTX *ctx, uint8_t dgst[SHA3_384_DIGEST_SIZE]);
+
+typedef struct {
+	uint64_t A[5][5];
+	uint8_t buf[SHA3_512_BLOCK_SIZE];
+	int num;
+} SHA3_512_CTX;
+
+void sha3_512_init(SHA3_512_CTX *ctx);
+void sha3_512_update(SHA3_512_CTX *ctx, const uint8_t *data, size_t datalen);
+void sha3_512_finish(SHA3_512_CTX *ctx, uint8_t dgst[SHA3_512_DIGEST_SIZE]);
+
+void sha3_shake128(const uint8_t *in, size_t *inlen, size_t outlen, uint8_t *out);
+void sha3_shake256(const uint8_t *in, size_t *inlen, size_t outlen, uint8_t *out);
+void sha3_keccak_p(uint8_t state[SHA3_KECCAK_P_SIZE]);
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif

+ 116 - 0
components/gmssl/include/gmssl/skf.h

@@ -0,0 +1,116 @@
+/*
+ *  Copyright 2014-2022 The GmSSL Project. All Rights Reserved.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the License); you may
+ *  not use this file except in compliance with the License.
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ */
+
+
+#ifndef GMSSL_SKF_H
+#define GMSSL_SKF_H
+
+
+#include <string.h>
+#include <stdint.h>
+#include <gmssl/sm2.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/*
+SKF Public API
+
+	skf_load_library
+	skf_unload_library
+	skf_list_devices
+	skf_print_device_info
+
+	SKF_DEVICE
+	skf_open_device
+	skf_close_deivce
+	skf_set_label
+	skf_change_authkey
+	skf_list_apps
+	skf_create_app
+	skf_delete_app
+	skf_change_app_admin_pin
+	skf_change_app_user_pin
+	skf_unblock_user_pin
+	skf_list_objects
+	skf_import_object
+	skf_export_object
+	skf_delete_object
+	skf_list_containers
+	skf_create_container
+	skf_delete_container
+	skf_import_sign_cert
+	skf_export_sign_cert
+	skf_rand_bytes
+	skf_load_sign_key
+
+	SKF_KEY
+	skf_sign
+	skf_release_key
+*/
+
+typedef struct {
+	void *handle;
+	char manufacturer[65];
+	char issuer[65];
+	char label[33];
+	char serial[33];
+	uint8_t hardware_version[2];
+	uint8_t firmware_version[2];
+} SKF_DEVICE;
+
+typedef struct {
+	SM2_KEY public_key;
+	void *app_handle;
+	char app_name[65];
+	void *container_handle;
+	char container_name[65];
+} SKF_KEY;
+
+int skf_load_library(const char *so_path, const char *vendor);
+void skf_unload_library(void);
+
+int skf_list_devices(FILE *fp, int fmt, int ind, const char *label);
+int skf_print_device_info(FILE *fp, int fmt, int ind, const char *devname);
+int skf_open_device(SKF_DEVICE *dev, const char *devname, const uint8_t authkey[16]);
+int skf_set_label(SKF_DEVICE *dev, const char *label);
+int skf_change_authkey(SKF_DEVICE *dev, const uint8_t authkey[16]);
+int skf_close_device(SKF_DEVICE *dev);
+
+int skf_list_apps(SKF_DEVICE *dev, int fmt, int ind, const char *label, FILE *fp);
+int skf_create_app(SKF_DEVICE *dev, const char *appname, const char *admin_pin, const char *user_pin);
+int skf_delete_app(SKF_DEVICE *dev, const char *appname);
+int skf_change_app_admin_pin(SKF_DEVICE *dev, const char *appname, const char *oid_pin, const char *new_pin);
+int skf_change_app_user_pin(SKF_DEVICE *dev, const char *appname, const char *oid_pin, const char *new_pin);
+int skf_unblock_user_pin(SKF_DEVICE *dev, const char *appname, const char *admin_pin, const char *new_user_pin);
+
+int skf_list_objects(FILE *fp, int fmt, int ind, const char *label, SKF_DEVICE *dev, const char *appname, const char *pin);
+int skf_import_object(SKF_DEVICE *dev, const char *appname, const char *pin, const char *objname, const uint8_t *data, size_t datalen);
+int skf_export_object(SKF_DEVICE *dev, const char *appname, const char *pin, const char *objname, uint8_t *out, size_t *outlen);
+int skf_delete_object(SKF_DEVICE *dev, const char *appname, const char *pin, const char *objname);
+
+int skf_list_containers(FILE *fp, int fmt, int ind, const char *label, SKF_DEVICE *dev, const char *appname, const char *pin);
+int skf_create_container(SKF_DEVICE *dev, const char *appname, const char *pin, const char *container_name);
+int skf_delete_container(SKF_DEVICE *dev, const char *appname, const char *pin, const char *container_name);
+int skf_import_sign_cert(SKF_DEVICE *dev, const char *appname, const char *pin, const char *container_name, const uint8_t *cert, size_t certlen);
+int skf_export_sign_cert(SKF_DEVICE *dev, const char *appname, const char *pin, const char *container_name, uint8_t *cert, size_t *certlen);
+
+int skf_rand_bytes(SKF_DEVICE *dev, uint8_t *buf, size_t len);
+int skf_load_sign_key(SKF_DEVICE *dev, const char *appname, const char *pin, const char *container_name, SKF_KEY *key);
+int skf_sign(SKF_KEY *key, const uint8_t dgst[32], uint8_t *sig, size_t *siglen);
+int skf_release_key(SKF_KEY *key);
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif

+ 382 - 0
components/gmssl/include/gmssl/sm2.h

@@ -0,0 +1,382 @@
+/*
+ *  Copyright 2014-2023 The GmSSL Project. All Rights Reserved.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the License); you may
+ *  not use this file except in compliance with the License.
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ */
+
+
+
+#ifndef GMSSL_SM2_H
+#define GMSSL_SM2_H
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <gmssl/sm3.h>
+#include <gmssl/api.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/*
+SM2 Public API
+
+	SM2_DEFAULT_ID
+	SM2_MAX_ID_LENGTH
+	SM2_MAX_SIGNATURE_SIZE
+	SM2_MAX_PLAINTEXT_SIZE
+	SM2_MAX_CIPHERTEXT_SIZE
+
+	SM2_KEY
+	sm2_key_generate
+	sm2_private_key_info_encrypt_to_der
+	sm2_private_key_info_decrypt_from_der
+	sm2_private_key_info_encrypt_to_pem
+	sm2_private_key_info_decrypt_from_pem
+	sm2_public_key_info_to_der
+	sm2_public_key_info_from_der
+	sm2_public_key_info_to_pem
+	sm2_public_key_info_from_pem
+
+	sm2_sign
+	sm2_verify
+	sm2_encrypt
+	sm2_decrypt
+	sm2_ecdh
+
+	SM2_SIGN_CTX
+	sm2_sign_init
+	sm2_sign_update
+	sm2_sign_finish
+	sm2_verify_init
+	sm2_verify_update
+	sm2_verify_finish
+*/
+
+typedef uint64_t SM2_BN[8];
+
+int sm2_bn_is_zero(const SM2_BN a);
+int sm2_bn_is_one(const SM2_BN a);
+int sm2_bn_is_odd(const SM2_BN a);
+int sm2_bn_cmp(const SM2_BN a, const SM2_BN b);
+int sm2_bn_from_hex(SM2_BN r, const char hex[64]);
+int sm2_bn_from_asn1_integer(SM2_BN r, const uint8_t *d, size_t dlen);
+int sm2_bn_equ_hex(const SM2_BN a, const char *hex);
+int sm2_bn_print(FILE *fp, int fmt, int ind, const char *label, const SM2_BN a);
+int sm2_bn_rshift(SM2_BN ret, const SM2_BN a, unsigned int nbits);
+
+void sm2_bn_to_bytes(const SM2_BN a, uint8_t out[32]);
+void sm2_bn_from_bytes(SM2_BN r, const uint8_t in[32]);
+void sm2_bn_to_hex(const SM2_BN a, char hex[64]);
+void sm2_bn_to_bits(const SM2_BN a, char bits[256]);
+void sm2_bn_set_word(SM2_BN r, uint32_t a);
+void sm2_bn_add(SM2_BN r, const SM2_BN a, const SM2_BN b);
+void sm2_bn_sub(SM2_BN ret, const SM2_BN a, const SM2_BN b);
+int  sm2_bn_rand_range(SM2_BN r, const SM2_BN range);
+
+#define sm2_bn_init(r) memset((r),0,sizeof(SM2_BN))
+#define sm2_bn_set_zero(r) memset((r),0,sizeof(SM2_BN))
+#define sm2_bn_set_one(r) sm2_bn_set_word((r),1)
+#define sm2_bn_copy(r,a) memcpy((r),(a),sizeof(SM2_BN))
+#define sm2_bn_clean(r) memset((r),0,sizeof(SM2_BN))
+
+
+// GF(p)
+typedef SM2_BN SM2_Fp;
+
+void sm2_fp_add(SM2_Fp r, const SM2_Fp a, const SM2_Fp b);
+void sm2_fp_sub(SM2_Fp r, const SM2_Fp a, const SM2_Fp b);
+void sm2_fp_mul(SM2_Fp r, const SM2_Fp a, const SM2_Fp b);
+void sm2_fp_exp(SM2_Fp r, const SM2_Fp a, const SM2_Fp e);
+void sm2_fp_dbl(SM2_Fp r, const SM2_Fp a);
+void sm2_fp_tri(SM2_Fp r, const SM2_Fp a);
+void sm2_fp_div2(SM2_Fp r, const SM2_Fp a);
+void sm2_fp_neg(SM2_Fp r, const SM2_Fp a);
+void sm2_fp_sqr(SM2_Fp r, const SM2_Fp a);
+void sm2_fp_inv(SM2_Fp r, const SM2_Fp a);
+int  sm2_fp_rand(SM2_Fp r);
+
+int sm2_fp_sqrt(SM2_Fp r, const SM2_Fp a);
+
+#define sm2_fp_init(r)		sm2_bn_init(r)
+#define sm2_fp_set_zero(r)	sm2_bn_set_zero(r)
+#define sm2_fp_set_one(r)	sm2_bn_set_one(r)
+#define sm2_fp_copy(r,a)	sm2_bn_copy(r,a)
+#define sm2_fp_clean(r)		sm2_bn_clean(r)
+
+// GF(n)
+typedef SM2_BN SM2_Fn;
+
+void sm2_fn_add(SM2_Fn r, const SM2_Fn a, const SM2_Fn b);
+void sm2_fn_sub(SM2_Fn r, const SM2_Fn a, const SM2_Fn b);
+void sm2_fn_mul(SM2_Fn r, const SM2_Fn a, const SM2_Fn b);
+void sm2_fn_mul_word(SM2_Fn r, const SM2_Fn a, uint32_t b);
+void sm2_fn_exp(SM2_Fn r, const SM2_Fn a, const SM2_Fn e);
+void sm2_fn_neg(SM2_Fn r, const SM2_Fn a);
+void sm2_fn_sqr(SM2_Fn r, const SM2_Fn a);
+void sm2_fn_inv(SM2_Fn r, const SM2_Fn a);
+int  sm2_fn_rand(SM2_Fn r);
+
+#define sm2_fn_init(r)		sm2_bn_init(r)
+#define sm2_fn_set_zero(r)	sm2_bn_set_zero(r)
+#define sm2_fn_set_one(r)	sm2_bn_set_one(r)
+#define sm2_fn_copy(r,a)	sm2_bn_copy(r,a)
+#define sm2_fn_clean(r)		sm2_bn_clean(r)
+
+
+typedef struct {
+	SM2_BN X;
+	SM2_BN Y;
+	SM2_BN Z;
+} SM2_JACOBIAN_POINT;
+
+void sm2_jacobian_point_init(SM2_JACOBIAN_POINT *R);
+void sm2_jacobian_point_set_xy(SM2_JACOBIAN_POINT *R, const SM2_BN x, const SM2_BN y);
+void sm2_jacobian_point_get_xy(const SM2_JACOBIAN_POINT *P, SM2_BN x, SM2_BN y);
+void sm2_jacobian_point_neg(SM2_JACOBIAN_POINT *R, const SM2_JACOBIAN_POINT *P);
+void sm2_jacobian_point_dbl(SM2_JACOBIAN_POINT *R, const SM2_JACOBIAN_POINT *P);
+void sm2_jacobian_point_add(SM2_JACOBIAN_POINT *R, const SM2_JACOBIAN_POINT *P, const SM2_JACOBIAN_POINT *Q);
+void sm2_jacobian_point_sub(SM2_JACOBIAN_POINT *R, const SM2_JACOBIAN_POINT *P, const SM2_JACOBIAN_POINT *Q);
+void sm2_jacobian_point_mul(SM2_JACOBIAN_POINT *R, const SM2_BN k, const SM2_JACOBIAN_POINT *P);
+void sm2_jacobian_point_to_bytes(const SM2_JACOBIAN_POINT *P, uint8_t out[64]);
+void sm2_jacobian_point_from_bytes(SM2_JACOBIAN_POINT *P, const uint8_t in[64]);
+void sm2_jacobian_point_mul_generator(SM2_JACOBIAN_POINT *R, const SM2_BN k);
+void sm2_jacobian_point_mul_sum(SM2_JACOBIAN_POINT *R, const SM2_BN t, const SM2_JACOBIAN_POINT *P, const SM2_BN s);
+void sm2_jacobian_point_from_hex(SM2_JACOBIAN_POINT *P, const char hex[64 * 2]); // for testing only
+
+int sm2_jacobian_point_is_at_infinity(const SM2_JACOBIAN_POINT *P);
+int sm2_jacobian_point_is_on_curve(const SM2_JACOBIAN_POINT *P);
+int sm2_jacobian_point_equ_hex(const SM2_JACOBIAN_POINT *P, const char hex[128]); // for testing only
+int sm2_jacobian_point_print(FILE *fp, int fmt, int ind, const char *label, const SM2_JACOBIAN_POINT *P);
+
+#define sm2_jacobian_point_set_infinity(R) sm2_jacobian_point_init(R)
+#define sm2_jacobian_point_copy(R, P) memcpy((R), (P), sizeof(SM2_JACOBIAN_POINT))
+
+typedef uint8_t sm2_bn_t[32];
+
+typedef struct {
+	uint8_t x[32];
+	uint8_t y[32];
+} SM2_POINT;
+
+#define sm2_point_init(P) memset((P),0,sizeof(SM2_POINT))
+#define sm2_point_set_infinity(P) sm2_point_init(P)
+int sm2_point_from_octets(SM2_POINT *P, const uint8_t *in, size_t inlen);
+void sm2_point_to_compressed_octets(const SM2_POINT *P, uint8_t out[33]);
+void sm2_point_to_uncompressed_octets(const SM2_POINT *P, uint8_t out[65]);
+
+int sm2_point_from_x(SM2_POINT *P, const uint8_t x[32], int y);
+int sm2_point_from_xy(SM2_POINT *P, const uint8_t x[32], const uint8_t y[32]);
+int sm2_point_is_on_curve(const SM2_POINT *P);
+int sm2_point_is_at_infinity(const SM2_POINT *P);
+int sm2_point_add(SM2_POINT *R, const SM2_POINT *P, const SM2_POINT *Q);
+int sm2_point_sub(SM2_POINT *R, const SM2_POINT *P, const SM2_POINT *Q);
+int sm2_point_neg(SM2_POINT *R, const SM2_POINT *P);
+int sm2_point_dbl(SM2_POINT *R, const SM2_POINT *P);
+int sm2_point_mul(SM2_POINT *R, const uint8_t k[32], const SM2_POINT *P);
+int sm2_point_mul_generator(SM2_POINT *R, const uint8_t k[32]);
+int sm2_point_mul_sum(SM2_POINT *R, const uint8_t k[32], const SM2_POINT *P, const uint8_t s[32]); // R = k * P + s * G
+
+/*
+RFC 5480 Elliptic Curve Cryptography Subject Public Key Information
+ECPoint ::= OCTET STRING
+*/
+#define SM2_POINT_MAX_SIZE (2 + 65)
+int sm2_point_to_der(const SM2_POINT *P, uint8_t **out, size_t *outlen);
+int sm2_point_from_der(SM2_POINT *P, const uint8_t **in, size_t *inlen);
+int sm2_point_print(FILE *fp, int fmt, int ind, const char *label, const SM2_POINT *P);
+int sm2_point_from_hash(SM2_POINT *R, const uint8_t *data, size_t datalen);
+
+
+typedef struct {
+	SM2_POINT public_key;
+	uint8_t private_key[32];
+} SM2_KEY;
+
+
+_gmssl_export int sm2_key_generate(SM2_KEY *key);
+int sm2_key_set_private_key(SM2_KEY *key, const uint8_t private_key[32]); // key->public_key will be replaced
+int sm2_key_set_public_key(SM2_KEY *key, const SM2_POINT *public_key); // key->private_key will be cleared // FIXME: support octets as input?
+int sm2_key_print(FILE *fp, int fmt, int ind, const char *label, const SM2_KEY *key);
+
+int sm2_public_key_equ(const SM2_KEY *sm2_key, const SM2_KEY *pub_key);
+//int sm2_public_key_copy(SM2_KEY *sm2_key, const SM2_KEY *pub_key); // do we need this?
+int sm2_public_key_digest(const SM2_KEY *key, uint8_t dgst[32]);
+int sm2_public_key_print(FILE *fp, int fmt, int ind, const char *label, const SM2_KEY *pub_key);
+
+/*
+from RFC 5915
+
+ECPrivateKey ::= SEQUENCE {
+	version		INTEGER,	-- value MUST be (1)
+	privateKey	OCTET STRING,	-- big endian encoding of integer 这里不是以INTEGER编码的,因此长度固定
+	parameters	[0] EXPLICIT ECParameters OPTIONAL,
+					-- ONLY namedCurve OID is permitted, by RFC 5480
+					-- MUST always include this field, by RFC 5915
+	publicKey	[1] EXPLICIT BIT STRING OPTIONAL -- compressed_point
+					-- SHOULD always include this field, by RFC 5915 }
+
+ECParameters ::= CHOICE { namedCurve OBJECT IDENTIFIER }
+*/
+#define SM2_PRIVATE_KEY_DEFAULT_SIZE 120 // generated
+#define SM2_PRIVATE_KEY_BUF_SIZE 512 // MUST >= SM2_PRIVATE_KEY_DEFAULT_SIZE
+
+int sm2_private_key_to_der(const SM2_KEY *key, uint8_t **out, size_t *outlen);
+int sm2_private_key_from_der(SM2_KEY *key, const uint8_t **in, size_t *inlen);
+int sm2_private_key_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen);
+int sm2_private_key_to_pem(const SM2_KEY *key, FILE *fp);
+int sm2_private_key_from_pem(SM2_KEY *key, FILE *fp);
+
+/*
+AlgorithmIdentifier ::= {
+	algorithm	OBJECT IDENTIFIER { id-ecPublicKey },
+	parameters	OBJECT IDENTIFIER { id-sm2 } }
+*/
+int sm2_public_key_algor_to_der(uint8_t **out, size_t *outlen);
+int sm2_public_key_algor_from_der(const uint8_t **in, size_t *inlen);
+
+/*
+SubjectPublicKeyInfo from RFC 5280
+
+SubjectPublicKeyInfo  ::=  SEQUENCE  {
+	algorithm            AlgorithmIdentifier,
+	subjectPublicKey     BIT STRING  -- uncompressed octets of ECPoint }
+*/
+_gmssl_export int sm2_public_key_info_to_der(const SM2_KEY *a, uint8_t **out, size_t *outlen);
+_gmssl_export int sm2_public_key_info_from_der(SM2_KEY *a, const uint8_t **in, size_t *inlen);
+_gmssl_export int sm2_public_key_info_to_pem(const SM2_KEY *a, FILE *fp);
+_gmssl_export int sm2_public_key_info_from_pem(SM2_KEY *a, FILE *fp);
+
+/*
+PKCS #8 PrivateKeyInfo from RFC 5208
+
+PrivateKeyInfo ::= SEQUENCE {
+	version			Version { v1(0) },
+	privateKeyAlgorithm	AlgorithmIdentifier,
+	privateKey		OCTET STRING, -- DER-encoding of ECPrivateKey
+	attributes		[0] IMPLICIT SET OF Attribute OPTIONAL }
+*/
+enum {
+	PKCS8_private_key_info_version = 0,
+};
+
+
+int sm2_private_key_info_to_der(const SM2_KEY *key, uint8_t **out, size_t *outlen);
+int sm2_private_key_info_from_der(SM2_KEY *key, const uint8_t **attrs, size_t *attrslen, const uint8_t **in, size_t *inlen);
+int sm2_private_key_info_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen);
+int sm2_private_key_info_to_pem(const SM2_KEY *key, FILE *fp);
+// FIXME: #define default buffer size for sm2_private_key_info_from_pem
+int sm2_private_key_info_from_pem(SM2_KEY *key, FILE *fp);
+
+/*
+EncryptedPrivateKeyInfo ::= SEQUENCE {
+	encryptionAlgorithm	EncryptionAlgorithmIdentifier, -- id-PBES2
+	encryptedData		OCTET STRING }
+*/
+_gmssl_export int sm2_private_key_info_encrypt_to_der(const SM2_KEY *key,
+	const char *pass, uint8_t **out, size_t *outlen);
+_gmssl_export int sm2_private_key_info_decrypt_from_der(SM2_KEY *key, const uint8_t **attrs, size_t *attrs_len,
+	const char *pass, const uint8_t **in, size_t *inlen);
+_gmssl_export int sm2_private_key_info_encrypt_to_pem(const SM2_KEY *key, const char *pass, FILE *fp);
+// FIXME: #define default buffer size
+_gmssl_export int sm2_private_key_info_decrypt_from_pem(SM2_KEY *key, const char *pass, FILE *fp);
+
+
+typedef struct {
+	uint8_t r[32];
+	uint8_t s[32];
+} SM2_SIGNATURE;
+
+int sm2_do_sign(const SM2_KEY *key, const uint8_t dgst[32], SM2_SIGNATURE *sig);
+int sm2_do_sign_fast(const SM2_Fn d, const uint8_t dgst[32], SM2_SIGNATURE *sig);
+int sm2_do_verify(const SM2_KEY *key, const uint8_t dgst[32], const SM2_SIGNATURE *sig);
+
+
+#define SM2_MIN_SIGNATURE_SIZE 8
+#define SM2_MAX_SIGNATURE_SIZE 72
+int sm2_signature_to_der(const SM2_SIGNATURE *sig, uint8_t **out, size_t *outlen);
+int sm2_signature_from_der(SM2_SIGNATURE *sig, const uint8_t **in, size_t *inlen);
+int sm2_signature_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *sig, size_t siglen);
+_gmssl_export int sm2_sign(const SM2_KEY *key, const uint8_t dgst[32], uint8_t *sig, size_t *siglen);
+_gmssl_export int sm2_verify(const SM2_KEY *key, const uint8_t dgst[32], const uint8_t *sig, size_t siglen);
+
+enum {
+	SM2_signature_compact_size = 70,
+	SM2_signature_typical_size = 71,
+	SM2_signature_max_size = 72,
+};
+int sm2_sign_fixlen(const SM2_KEY *key, const uint8_t dgst[32], size_t siglen, uint8_t *sig);
+
+#define SM2_DEFAULT_ID		"1234567812345678"
+#define SM2_DEFAULT_ID_LENGTH	(sizeof(SM2_DEFAULT_ID) - 1)  // LENGTH for string and SIZE for bytes
+#define SM2_DEFAULT_ID_BITS	(SM2_DEFAULT_ID_LENGTH * 8)
+#define SM2_MAX_ID_BITS		65535
+#define SM2_MAX_ID_LENGTH	(SM2_MAX_ID_BITS/8)
+
+int sm2_compute_z(uint8_t z[32], const SM2_POINT *pub, const char *id, size_t idlen);
+
+
+typedef struct {
+	SM3_CTX sm3_ctx;
+	SM2_KEY key;
+} SM2_SIGN_CTX;
+
+_gmssl_export int sm2_sign_init(SM2_SIGN_CTX *ctx, const SM2_KEY *key, const char *id, size_t idlen);
+_gmssl_export int sm2_sign_update(SM2_SIGN_CTX *ctx, const uint8_t *data, size_t datalen);
+_gmssl_export int sm2_sign_finish(SM2_SIGN_CTX *ctx, uint8_t *sig, size_t *siglen);
+int sm2_sign_finish_fixlen(SM2_SIGN_CTX *ctx, size_t siglen, uint8_t *sig);
+
+_gmssl_export int sm2_verify_init(SM2_SIGN_CTX *ctx, const SM2_KEY *key, const char *id, size_t idlen);
+_gmssl_export int sm2_verify_update(SM2_SIGN_CTX *ctx, const uint8_t *data, size_t datalen);
+_gmssl_export int sm2_verify_finish(SM2_SIGN_CTX *ctx, const uint8_t *sig, size_t siglen);
+
+/*
+SM2Cipher ::= SEQUENCE {
+	XCoordinate	INTEGER,
+	YCoordinate	INTEGER,
+	HASH		OCTET STRING SIZE(32),
+	CipherText	OCTET STRING }
+*/
+#define SM2_MIN_PLAINTEXT_SIZE	1 // re-compute SM2_MIN_CIPHERTEXT_SIZE when modify
+#define SM2_MAX_PLAINTEXT_SIZE	255 // re-compute SM2_MAX_CIPHERTEXT_SIZE when modify
+
+typedef struct {
+	SM2_POINT point;
+	uint8_t hash[32];
+	uint8_t ciphertext_size;
+	uint8_t ciphertext[SM2_MAX_PLAINTEXT_SIZE];
+} SM2_CIPHERTEXT;
+
+int sm2_do_encrypt(const SM2_KEY *key, const uint8_t *in, size_t inlen, SM2_CIPHERTEXT *out);
+int sm2_do_decrypt(const SM2_KEY *key, const SM2_CIPHERTEXT *in, uint8_t *out, size_t *outlen);
+
+#define SM2_MIN_CIPHERTEXT_SIZE	 45 // depends on SM2_MIN_PLAINTEXT_SIZE
+#define SM2_MAX_CIPHERTEXT_SIZE	366 // depends on SM2_MAX_PLAINTEXT_SIZE
+int sm2_ciphertext_to_der(const SM2_CIPHERTEXT *c, uint8_t **out, size_t *outlen);
+int sm2_ciphertext_from_der(SM2_CIPHERTEXT *c, const uint8_t **in, size_t *inlen);
+int sm2_ciphertext_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *a, size_t alen);
+_gmssl_export int sm2_encrypt(const SM2_KEY *key, const uint8_t *in, size_t inlen, uint8_t *out, size_t *outlen);
+_gmssl_export int sm2_decrypt(const SM2_KEY *key, const uint8_t *in, size_t inlen, uint8_t *out, size_t *outlen);
+
+enum {
+	SM2_ciphertext_compact_point_size = 68,
+	SM2_ciphertext_typical_point_size = 69,
+	SM2_ciphertext_max_point_size = 70,
+};
+int sm2_do_encrypt_fixlen(const SM2_KEY *key, const uint8_t *in, size_t inlen, int point_size, SM2_CIPHERTEXT *out);
+int sm2_encrypt_fixlen(const SM2_KEY *key, const uint8_t *in, size_t inlen, int point_size, uint8_t *out, size_t *outlen);
+
+
+int sm2_do_ecdh(const SM2_KEY *key, const SM2_POINT *peer_public, SM2_POINT *out);
+_gmssl_export int sm2_ecdh(const SM2_KEY *key, const uint8_t *peer_public, size_t peer_public_len, SM2_POINT *out);
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif

+ 49 - 0
components/gmssl/include/gmssl/sm2_blind.h

@@ -0,0 +1,49 @@
+/*
+ *  Copyright 2014-2022 The GmSSL Project. All Rights Reserved.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the License); you may
+ *  not use this file except in compliance with the License.
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ */
+#ifndef GMSSL_SM2_BLIND_H
+#define GMSSL_SM2_BLIND_H
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <gmssl/sm2.h>
+#include <gmssl/mem.h>
+#include <gmssl/asn1.h>
+#include <gmssl/error.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+typedef struct {
+	SM3_CTX sm3_ctx;
+	SM2_KEY public_key;
+	uint8_t blind_factor_a[32];
+	uint8_t blind_factor_b[32];
+	uint8_t sig_r[32];
+} SM2_BLIND_SIGN_CTX;
+
+
+#define SM2_BLIND_SIGN_MAX_COMMITLEN	65
+
+int sm2_blind_sign_commit(SM2_Fn k, uint8_t *commit, size_t *commitlen);
+int sm2_blind_sign_init(SM2_BLIND_SIGN_CTX *ctx, const SM2_KEY *public_key, const char *id, size_t idlen);
+int sm2_blind_sign_update(SM2_BLIND_SIGN_CTX *ctx, const uint8_t *data, size_t datalen);
+int sm2_blind_sign_finish(SM2_BLIND_SIGN_CTX *ctx, const uint8_t *commit, size_t commitlen, uint8_t blinded_sig_r[32]);
+int sm2_blind_sign(const SM2_KEY *key, const SM2_Fn k, const uint8_t blinded_sig_r[32], uint8_t blinded_sig_s[32]);
+int sm2_blind_sign_unblind(SM2_BLIND_SIGN_CTX *ctx, const uint8_t blinded_sig_s[32], uint8_t *sig, size_t *siglen);
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif

+ 40 - 0
components/gmssl/include/gmssl/sm2_commit.h

@@ -0,0 +1,40 @@
+/*
+ *  Copyright 2014-2022 The GmSSL Project. All Rights Reserved.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the License); you may
+ *  not use this file except in compliance with the License.
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ */
+#ifndef GMSSL_SM2_COMMIT_H
+#define GMSSL_SM2_COMMIT_H
+
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <stdint.h>
+#include <gmssl/sm2.h>
+#include <gmssl/sm3.h>
+#include <gmssl/mem.h>
+#include <gmssl/asn1.h>
+#include <gmssl/rand.h>
+#include <gmssl/error.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+int sm2_commit_generate(const uint8_t x[32], uint8_t r[32], uint8_t commit[65], size_t *commitlen);
+int sm2_commit_open(const uint8_t x[32], const uint8_t r[32], const uint8_t *commit, size_t commitlen);
+int sm2_commit_vector_generate(const sm2_bn_t *x, size_t count, uint8_t r[32], uint8_t commit[65], size_t *commitlen);
+int sm2_commit_vector_open(const sm2_bn_t *x, size_t count, const uint8_t r[32], const uint8_t *commit, size_t commitlen);
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif

+ 67 - 0
components/gmssl/include/gmssl/sm2_elgamal.h

@@ -0,0 +1,67 @@
+/*
+ *  Copyright 2014-2022 The GmSSL Project. All Rights Reserved.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the License); you may
+ *  not use this file except in compliance with the License.
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ */
+
+#ifndef GMSSL_SM2_ELGAMAL_H
+#define GMSSL_SM2_ELGAMAL_H
+
+
+#include <string.h>
+#include <stdint.h>
+#include <gmssl/sm2.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#define SM2_PRE_COMPUTE_MAX_OFFSETS	6
+
+typedef struct {
+	uint16_t offset[SM2_PRE_COMPUTE_MAX_OFFSETS];
+	uint8_t offset_count;
+	uint8_t x_coordinate[32];
+} SM2_PRE_COMPUTE;
+
+int sm2_elgamal_decrypt_pre_compute(SM2_PRE_COMPUTE table[1<<16]);
+int sm2_elgamal_solve_ecdlp(const SM2_PRE_COMPUTE table[1<<16], const SM2_POINT *point, uint32_t *private);
+
+
+typedef struct {
+	SM2_POINT C1;
+	SM2_POINT C2;
+} SM2_ELGAMAL_CIPHERTEXT;
+
+int sm2_elgamal_do_encrypt(const SM2_KEY *pub_key, uint32_t in, SM2_ELGAMAL_CIPHERTEXT *out);
+int sm2_elgamal_do_decrypt(const SM2_KEY *key, const SM2_ELGAMAL_CIPHERTEXT *in, uint32_t *out);
+
+int sm2_elgamal_ciphertext_add(SM2_ELGAMAL_CIPHERTEXT *r,
+	const SM2_ELGAMAL_CIPHERTEXT *a,
+	const SM2_ELGAMAL_CIPHERTEXT *b,
+	const SM2_KEY *pub_key);
+int sm2_elgamal_cipehrtext_sub(SM2_ELGAMAL_CIPHERTEXT *r,
+	const SM2_ELGAMAL_CIPHERTEXT *a, const SM2_ELGAMAL_CIPHERTEXT *b,
+	const SM2_KEY *pub_key);
+int sm2_elgamal_cipehrtext_neg(SM2_ELGAMAL_CIPHERTEXT *r,
+	const SM2_ELGAMAL_CIPHERTEXT *a, const SM2_KEY *pub_key);
+int sm2_elgamal_ciphertext_scalar_mul(SM2_ELGAMAL_CIPHERTEXT *R,
+	const uint8_t scalar[32], const SM2_ELGAMAL_CIPHERTEXT *A,
+	const SM2_KEY *pub_key);
+
+int sm2_elgamal_ciphertext_to_der(const SM2_ELGAMAL_CIPHERTEXT *c, uint8_t **out, size_t *outlen);
+int sm2_elgamal_ciphertext_from_der(SM2_ELGAMAL_CIPHERTEXT *c, const uint8_t **in, size_t *inlen);
+
+int sm2_elgamal_encrypt(const SM2_KEY *pub_key, uint32_t in, uint8_t *out, size_t *outlen);
+int sm2_elgamal_decrypt(SM2_KEY *key, const uint8_t *in, size_t inlen, uint32_t *out);
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif

+ 45 - 0
components/gmssl/include/gmssl/sm2_key_share.h

@@ -0,0 +1,45 @@
+/*
+ *  Copyright 2014-2022 The GmSSL Project. All Rights Reserved.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the License); you may
+ *  not use this file except in compliance with the License.
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ */
+
+// SM2 Key Shamir Secret Sharing
+
+
+#ifndef GMSSL_SM2_KEY_SHARE_H
+#define GMSSL_SM2_KEY_SHARE_H
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <gmssl/sm2.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#define SM2_KEY_MAX_SHARES 12 // 12! = 479001600 < 2^31 = 2147483648
+
+
+typedef struct {
+	SM2_KEY key;
+	size_t index;
+	size_t total_cnt;
+} SM2_KEY_SHARE;
+
+int sm2_key_split(const SM2_KEY *key, size_t recover_cnt, size_t total_cnt, SM2_KEY_SHARE *shares);
+int sm2_key_recover(SM2_KEY *key, const SM2_KEY_SHARE *shares, size_t shares_cnt);
+int sm2_key_share_encrypt_to_file(const SM2_KEY_SHARE *share, const char *pass, const char *path_prefix);
+int sm2_key_share_decrypt_from_file(SM2_KEY_SHARE *share, const char *pass, const char *file);
+int sm2_key_share_print(FILE *fp, int fmt, int ind, const char *label, const SM2_KEY_SHARE *share);
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif

+ 31 - 0
components/gmssl/include/gmssl/sm2_recover.h

@@ -0,0 +1,31 @@
+/*
+ *  Copyright 2014-2022 The GmSSL Project. All Rights Reserved.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the License); you may
+ *  not use this file except in compliance with the License.
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ */
+
+
+
+#ifndef GMSSL_SM2_RECOVER_H
+#define GMSSL_SM2_RECOVER_H
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <gmssl/sm3.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int sm2_signature_to_public_key_points(const SM2_SIGNATURE *sig, const uint8_t dgst[32],
+	SM2_POINT points[4], size_t *points_cnt);
+int sm2_signature_conjugate(const SM2_SIGNATURE *sig, SM2_SIGNATURE *new_sig);
+
+#ifdef __cplusplus
+}
+#endif
+#endif

+ 63 - 0
components/gmssl/include/gmssl/sm2_ring.h

@@ -0,0 +1,63 @@
+/*
+ *  Copyright 2014-2022 The GmSSL Project. All Rights Reserved.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the License); you may
+ *  not use this file except in compliance with the License.
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ */
+
+
+
+#ifndef GMSSL_SM2_RING_H
+#define GMSSL_SM2_RING_H
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <gmssl/sm2.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+typedef uint8_t sm2_bn_t[32];
+
+int sm2_ring_do_sign(const SM2_KEY *sign_key, const SM2_POINT *public_keys, size_t public_keys_cnt,
+	const uint8_t dgst[32], uint8_t r[32], sm2_bn_t *s);
+int sm2_ring_do_verify(const SM2_POINT *public_keys, size_t public_keys_cnt,
+	const uint8_t dgst[32], const uint8_t r[32], const sm2_bn_t *s);
+int sm2_ring_signature_to_der(const sm2_bn_t r, const sm2_bn_t *s, size_t s_cnt, uint8_t **out, size_t *outlen);
+int sm2_ring_signature_from_der(sm2_bn_t r, sm2_bn_t *s, size_t *s_cnt, const uint8_t **in, size_t *inlen);
+int sm2_ring_sign(const SM2_KEY *sign_key, const SM2_POINT *public_keys, size_t public_keys_cnt,
+	const uint8_t dgst[32], uint8_t *sig, size_t *siglen);
+int sm2_ring_verify(const SM2_POINT *public_keys, size_t public_keys_cnt,
+	const uint8_t dgst[32], const uint8_t *sig, size_t siglen);
+
+
+#define SM2_RING_SIGN_MAX_SIGNERS  32
+typedef struct {
+	int state;
+	SM3_CTX sm3_ctx;
+	SM2_KEY sign_key;
+	SM2_POINT public_keys[SM2_RING_SIGN_MAX_SIGNERS];
+	size_t public_keys_count;
+	char *id;
+	size_t idlen;
+} SM2_RING_SIGN_CTX;
+
+int sm2_ring_sign_init(SM2_RING_SIGN_CTX *ctx, const SM2_KEY *sign_key, const char *id, size_t idlen);
+int sm2_ring_sign_add_signer(SM2_RING_SIGN_CTX *ctx, const SM2_KEY *public_key);
+int sm2_ring_sign_update(SM2_RING_SIGN_CTX *ctx, const uint8_t *data, size_t datalen);
+int sm2_ring_sign_finish(SM2_RING_SIGN_CTX *ctx, uint8_t *sig, size_t *siglen);
+int sm2_ring_verify_init(SM2_RING_SIGN_CTX *ctx, const char *id, size_t idlen);
+int sm2_ring_verify_add_signer(SM2_RING_SIGN_CTX *ctx, const SM2_KEY *public_key);
+int sm2_ring_verify_update(SM2_RING_SIGN_CTX *ctx, const uint8_t *data, size_t datalen);
+int sm2_ring_verify_finish(SM2_RING_SIGN_CTX *ctx, uint8_t *sig, size_t siglen);
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif

+ 89 - 0
components/gmssl/include/gmssl/sm3.h

@@ -0,0 +1,89 @@
+/*
+ *  Copyright 2014-2022 The GmSSL Project. All Rights Reserved.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the License); you may
+ *  not use this file except in compliance with the License.
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ */
+
+
+#ifndef GMSSL_SM3_H
+#define GMSSL_SM3_H
+
+#include <string.h>
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+SM3 Public API
+
+	SM3_DIGEST_SIZE
+	SM3_HMAC_SIZE
+
+	SM3_CTX
+	sm3_init
+	sm3_update
+	sm3_finish
+
+	SM3_HMAC_CTX
+	sm3_hmac_init
+	sm3_hmac_update
+	sm3_hmac_finish
+
+	sm3_digest
+	sm3_hmac
+*/
+
+#define SM3_IS_BIG_ENDIAN	1
+
+#define SM3_DIGEST_SIZE		32
+#define SM3_BLOCK_SIZE		64
+#define SM3_STATE_WORDS		8
+#define SM3_HMAC_SIZE		(SM3_DIGEST_SIZE)
+
+
+typedef struct {
+	uint32_t digest[SM3_STATE_WORDS];
+	uint64_t nblocks;
+	uint8_t block[SM3_BLOCK_SIZE];
+	size_t num;
+} SM3_CTX;
+
+void sm3_init(SM3_CTX *ctx);
+void sm3_update(SM3_CTX *ctx, const uint8_t *data, size_t datalen);
+void sm3_finish(SM3_CTX *ctx, uint8_t dgst[SM3_DIGEST_SIZE]);
+void sm3_digest(const uint8_t *data, size_t datalen, uint8_t dgst[SM3_DIGEST_SIZE]);
+
+void sm3_compress_blocks(uint32_t digest[8], const uint8_t *data, size_t blocks);
+
+typedef struct {
+	SM3_CTX sm3_ctx;
+	unsigned char key[SM3_BLOCK_SIZE];
+} SM3_HMAC_CTX;
+
+void sm3_hmac_init(SM3_HMAC_CTX *ctx, const uint8_t *key, size_t keylen);
+void sm3_hmac_update(SM3_HMAC_CTX *ctx, const uint8_t *data, size_t datalen);
+void sm3_hmac_finish(SM3_HMAC_CTX *ctx, uint8_t mac[SM3_HMAC_SIZE]);
+void sm3_hmac(const uint8_t *key, size_t keylen,
+	const uint8_t *data, size_t datalen,
+	uint8_t mac[SM3_HMAC_SIZE]);
+
+
+typedef struct {
+	SM3_CTX sm3_ctx;
+	size_t outlen;
+} SM3_KDF_CTX;
+
+void sm3_kdf_init(SM3_KDF_CTX *ctx, size_t outlen);
+void sm3_kdf_update(SM3_KDF_CTX *ctx, const uint8_t *data, size_t datalen);
+void sm3_kdf_finish(SM3_KDF_CTX *ctx, uint8_t *out);
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif

+ 42 - 0
components/gmssl/include/gmssl/sm3_rng.h

@@ -0,0 +1,42 @@
+/*
+ *  Copyright 2014-2022 The GmSSL Project. All Rights Reserved.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the License); you may
+ *  not use this file except in compliance with the License.
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ */
+
+#ifndef GMSSL_SM3_RNG_H
+#define GMSSL_SM3_RNG_H
+
+#include <time.h>
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#define SM3_RNG_MAX_RESEED_COUNTER (1<<20)
+#define SM3_RNG_MAX_RESEED_SECONDS 600
+
+
+typedef struct {
+	uint8_t V[55];
+	uint8_t C[55];
+	uint32_t reseed_counter;
+	time_t last_reseed_time;
+} SM3_RNG;
+
+int sm3_rng_init(SM3_RNG *rng, const uint8_t *nonce, size_t nonce_len,
+	const uint8_t *label, size_t label_len);
+int sm3_rng_reseed(SM3_RNG *rng, const uint8_t *addin, size_t addin_len);
+int sm3_rng_generate(SM3_RNG *rng, const uint8_t *addin, size_t addin_len,
+	uint8_t *out, size_t outlen);
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif

+ 33 - 0
components/gmssl/include/gmssl/sm3_x8_avx2.h

@@ -0,0 +1,33 @@
+/*
+ *  Copyright 2014-2022 The GmSSL Project. All Rights Reserved.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the License); you may
+ *  not use this file except in compliance with the License.
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ */
+
+#ifndef GMSSL_SM3_X8_AVX2_H
+#define GMSSL_SM3_X8_AVX2_H
+
+#include <stdint.h>
+#include <immintrin.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+typedef struct {
+	__m256i digest[8];
+} SM3_X8_CTX;
+
+void sm3_x8_init(SM3_X8_CTX *ctx);
+void sm3_x8_compress_blocks(__m256i digest[8], const uint8_t *data, size_t datalen);
+void sm3_x8_digest(const uint8_t *data, size_t datalen, uint8_t dgst[8][32]);
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif

+ 131 - 0
components/gmssl/include/gmssl/sm4.h

@@ -0,0 +1,131 @@
+/*
+ *  Copyright 2014-2022 The GmSSL Project. All Rights Reserved.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the License); you may
+ *  not use this file except in compliance with the License.
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ */
+
+
+#ifndef GMSSL_SM4_H
+#define GMSSL_SM4_H
+
+#include <stdint.h>
+#include <string.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/*
+SM4 Public API
+
+	SM4_KEY_SIZE
+	SM4_BLOCK_SIZE
+
+	SM4_CBC_CTX
+	sm4_cbc_encrypt_init
+	sm4_cbc_encrypt_update
+	sm4_cbc_encrypt_finish
+	sm4_cbc_decrypt_init
+	sm4_cbc_decrypt_update
+	sm4_cbc_decrypt_finish
+
+	SM4_CTR_CTX
+	sm4_ctr_encrypt_init
+	sm4_ctr_encrypt_update
+	sm4_ctr_encrypt_finish
+	sm4_ctr_decrypt_init
+	sm4_ctr_decrypt_update
+	sm4_ctr_decrypt_finish
+*/
+
+#define SM4_KEY_SIZE		(16)
+#define SM4_BLOCK_SIZE		(16)
+#define SM4_NUM_ROUNDS		(32)
+
+
+typedef struct {
+	uint32_t rk[SM4_NUM_ROUNDS];
+} SM4_KEY;
+
+void sm4_set_encrypt_key(SM4_KEY *key, const uint8_t raw_key[SM4_KEY_SIZE]);
+void sm4_set_decrypt_key(SM4_KEY *key, const uint8_t raw_key[SM4_KEY_SIZE]);
+void sm4_encrypt(const SM4_KEY *key, const uint8_t in[SM4_BLOCK_SIZE], uint8_t out[SM4_BLOCK_SIZE]);
+#define sm4_decrypt(key,in,out) sm4_encrypt(key,in,out)
+
+
+void sm4_cbc_encrypt(const SM4_KEY *key, const uint8_t iv[SM4_BLOCK_SIZE],
+	const uint8_t *in, size_t nblocks, uint8_t *out);
+void sm4_cbc_decrypt(const SM4_KEY *key, const uint8_t iv[SM4_BLOCK_SIZE],
+	const uint8_t *in, size_t nblocks, uint8_t *out);
+int sm4_cbc_padding_encrypt(const SM4_KEY *key, const uint8_t iv[SM4_BLOCK_SIZE],
+	const uint8_t *in, size_t inlen, uint8_t *out, size_t *outlen);
+int sm4_cbc_padding_decrypt(const SM4_KEY *key, const uint8_t iv[SM4_BLOCK_SIZE],
+	const uint8_t *in, size_t inlen, uint8_t *out, size_t *outlen);
+
+
+void sm4_ctr_encrypt(const SM4_KEY *key, uint8_t ctr[SM4_BLOCK_SIZE],
+	const uint8_t *in, size_t inlen, uint8_t *out);
+#define sm4_ctr_decrypt(key,ctr,in,inlen,out) sm4_ctr_encrypt(key,ctr,in,inlen,out)
+
+
+#define SM4_GCM_IV_MIN_SIZE		1
+#define SM4_GCM_IV_MAX_SIZE		((uint64_t)(1 << (64-3)))
+#define SM4_GCM_IV_DEFAULT_BITS		96
+#define SM4_GCM_IV_DEFAULT_SIZE		12
+
+#define SM4_GCM_MIN_AAD_SIZE		0
+#define SM4_GCM_MAX_AAD_SIZE		((uint64_t)(1 << (64-3)))
+
+#define SM4_GCM_MIN_PLAINTEXT_SIZE	0
+#define SM4_GCM_MAX_PLAINTEXT_SIZE	((((uint64_t)1 << 39) - 256) >> 3)
+
+#define SM4_GCM_MAX_TAG_SIZE		16
+
+int sm4_gcm_encrypt(const SM4_KEY *key, const uint8_t *iv, size_t ivlen,
+	const uint8_t *aad, size_t aadlen, const uint8_t *in, size_t inlen,
+	uint8_t *out, size_t taglen, uint8_t *tag);
+int sm4_gcm_decrypt(const SM4_KEY *key, const uint8_t *iv, size_t ivlen,
+	const uint8_t *aad, size_t aadlen, const uint8_t *in, size_t inlen,
+	const uint8_t *tag, size_t taglen, uint8_t *out);
+
+
+typedef struct {
+	SM4_KEY sm4_key;
+	uint8_t iv[SM4_BLOCK_SIZE];
+	uint8_t block[SM4_BLOCK_SIZE];
+	size_t block_nbytes;
+} SM4_CBC_CTX;
+
+int sm4_cbc_encrypt_init(SM4_CBC_CTX *ctx, const uint8_t key[SM4_KEY_SIZE], const uint8_t iv[SM4_BLOCK_SIZE]);
+int sm4_cbc_encrypt_update(SM4_CBC_CTX *ctx, const uint8_t *in, size_t inlen, uint8_t *out, size_t *outlen);
+int sm4_cbc_encrypt_finish(SM4_CBC_CTX *ctx, uint8_t *out, size_t *outlen);
+
+int sm4_cbc_decrypt_init(SM4_CBC_CTX *ctx, const uint8_t key[SM4_KEY_SIZE], const uint8_t iv[SM4_BLOCK_SIZE]);
+int sm4_cbc_decrypt_update(SM4_CBC_CTX *ctx, const uint8_t *in, size_t inlen, uint8_t *out, size_t *outlen);
+int sm4_cbc_decrypt_finish(SM4_CBC_CTX *ctx, uint8_t *out, size_t *outlen);
+
+
+typedef struct {
+	SM4_KEY sm4_key;
+	uint8_t ctr[SM4_BLOCK_SIZE];
+	uint8_t block[SM4_BLOCK_SIZE];
+	size_t block_nbytes;
+} SM4_CTR_CTX;
+
+int sm4_ctr_encrypt_init(SM4_CTR_CTX *ctx, const uint8_t key[SM4_KEY_SIZE], const uint8_t ctr[SM4_BLOCK_SIZE]);
+int sm4_ctr_encrypt_update(SM4_CTR_CTX *ctx, const uint8_t *in, size_t inlen, uint8_t *out, size_t *outlen);
+int sm4_ctr_encrypt_finish(SM4_CTR_CTX *ctx, uint8_t *out, size_t *outlen);
+
+#define sm4_ctr_decrypt_init(ctx,key,ctr) sm4_ctr_encrypt_init(ctx,key,ctr)
+#define sm4_ctr_decrypt_update(ctx,in,inlen,out,outlen) sm4_ctr_encrypt_update(ctx,in,inlen,out,outlen)
+#define sm4_ctr_decrypt_finish(ctx,out,outlen) sm4_ctr_encrypt_finish(ctx,out,outlen)
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif

+ 35 - 0
components/gmssl/include/gmssl/sm4_cbc_mac.h

@@ -0,0 +1,35 @@
+/*
+ *  Copyright 2014-2022 The GmSSL Project. All Rights Reserved.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the License); you may
+ *  not use this file except in compliance with the License.
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ */
+
+#ifndef GMSSL_SM4_CBC_MAC_H
+#define GMSSL_SM4_CBC_MAC_H
+
+#include <stdint.h>
+#include <gmssl/sm4.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+typedef struct {
+	SM4_KEY key;
+	uint8_t iv[16];
+	size_t ivlen;
+} SM4_CBC_MAC_CTX;
+
+void sm4_cbc_mac_init(SM4_CBC_MAC_CTX *ctx, const uint8_t key[16]);
+void sm4_cbc_mac_update(SM4_CBC_MAC_CTX *ctx, const uint8_t *data, size_t datalen);
+void sm4_cbc_mac_finish(SM4_CBC_MAC_CTX *ctx, uint8_t mac[16]);
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif

+ 55 - 0
components/gmssl/include/gmssl/sm4_cl.h

@@ -0,0 +1,55 @@
+/*
+ *  Copyright 2014-2022 The GmSSL Project. All Rights Reserved.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the License); you may
+ *  not use this file except in compliance with the License.
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ */
+
+#ifndef GMSSL_SM4_CL_H
+#define GMSSL_SM4_CL_H
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <gmssl/sm4.h>
+
+
+#ifdef APPLE
+#include <OpenCL/OpenCL.h>
+#else
+#include <CL/cl.h>
+#endif
+
+
+typedef struct {
+	uint32_t rk[32];
+	cl_context context;
+	cl_command_queue queue;
+	cl_program program;
+	cl_kernel kernel;
+	cl_mem mem_rk;
+	cl_mem mem_io;
+	size_t workgroup_size;
+} SM4_CL_CTX;
+
+
+int sm4_cl_set_encrypt_key(SM4_CL_CTX *ctx, const uint8_t key[16]);
+int sm4_cl_set_decrypt_key(SM4_CL_CTX *ctx, const uint8_t key[16]);
+int sm4_cl_encrypt(SM4_CL_CTX *ctx, const uint8_t *in, size_t nblocks, uint8_t *out);
+void sm4_cl_cleanup(SM4_CL_CTX *ctx);
+
+int test_sm4_cl_encrypt(void);
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif

+ 43 - 0
components/gmssl/include/gmssl/sm4_rng.h

@@ -0,0 +1,43 @@
+/*
+ *  Copyright 2014-2022 The GmSSL Project. All Rights Reserved.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the License); you may
+ *  not use this file except in compliance with the License.
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ */
+
+#ifndef GMSSL_SM4_RNG_H
+#define GMSSL_SM4_RNG_H
+
+#include <time.h>
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#define SM4_RNG_MAX_RESEED_COUNTER (1<<20)
+#define SM4_RNG_MAX_RESEED_SECONDS 600
+
+typedef struct {
+	uint8_t V[16];
+	uint8_t K[16];
+	uint32_t reseed_counter;
+	time_t last_reseed_time;
+} SM4_RNG;
+
+
+int sm4_rng_init(SM4_RNG *rng, const uint8_t *nonce, size_t nonce_len,
+	const uint8_t *label, size_t label_len);
+int sm4_rng_update(SM4_RNG *rng, const uint8_t seed[32]);
+int sm4_rng_reseed(SM4_RNG *rng, const uint8_t *addin, size_t addin_len);
+int sm4_rng_generate(SM4_RNG *rng, const uint8_t *addin, size_t addin_len,
+	uint8_t *out, size_t outlen);
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif

+ 561 - 0
components/gmssl/include/gmssl/sm9.h

@@ -0,0 +1,561 @@
+/*
+ *  Copyright 2014-2022 The GmSSL Project. All Rights Reserved.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the License); you may
+ *  not use this file except in compliance with the License.
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ */
+
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <gmssl/sm3.h>
+#include <gmssl/sm2.h>
+
+
+#ifndef GMSSL_SM9_H
+#define GMSSL_SM9_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+SM9 Public API
+
+	SM9_SIGNATURE_SIZE
+	SM9_MAX_PLAINTEXT_SIZE
+	SM9_MAX_CIPHERTEXT_SIZE
+
+	SM9_SIGN_MASTER_KEY
+	sm9_sign_master_key_generate
+	sm9_sign_master_key_extract_key
+	sm9_sign_master_key_info_encrypt_to_der
+	sm9_sign_master_key_info_decrypt_from_der
+	sm9_sign_master_key_info_encrypt_to_pem
+	sm9_sign_master_key_info_decrypt_from_pem
+	sm9_sign_master_public_key_to_der
+	sm9_sign_master_public_key_from_der
+	sm9_sign_master_public_key_to_pem
+	sm9_sign_master_public_key_from_pem
+
+	SM9_SIGN_KEY
+	sm9_sign_key_info_encrypt_to_der
+	sm9_sign_key_info_decrypt_from_der
+	sm9_sign_key_info_encrypt_to_pem
+	sm9_sign_key_info_decrypt_from_pem
+
+	SM9_SIGN_CTX
+	sm9_sign_init
+	sm9_sign_update
+	sm9_sign_finish
+	sm9_verify_init
+	sm9_verify_update
+	sm9_verify_finish
+
+	SM9_ENC_MASTER_KEY
+	sm9_enc_master_key_generate
+	sm9_enc_master_key_extract_key
+	sm9_enc_master_key_info_encrypt_to_der
+	sm9_enc_master_key_info_decrypt_from_der
+	sm9_enc_master_key_info_encrypt_to_pem
+	sm9_enc_master_key_info_decrypt_from_pem
+	sm9_enc_master_public_key_to_der
+	sm9_enc_master_public_key_from_der
+	sm9_enc_master_public_key_to_pem
+	sm9_enc_master_public_key_from_pem
+
+	SM9_ENC_KEY
+	sm9_enc_key_info_encrypt_to_der
+	sm9_enc_key_info_decrypt_from_der
+	sm9_enc_key_info_encrypt_to_pem
+	sm9_enc_key_info_decrypt_from_pem
+
+	sm9_encrypt
+	sm9_decrypt
+*/
+
+#define SM9_HEX_SEP '\n'
+
+typedef uint64_t sm9_bn_t[8];
+
+#define sm9_bn_init(r)		sm9_bn_set_zero(r)
+#define sm9_bn_clean(r)		sm9_bn_set_zero(r)
+
+void sm9_bn_set_zero(sm9_bn_t r);
+void sm9_bn_set_one(sm9_bn_t r);
+int  sm9_bn_is_zero(const sm9_bn_t a);
+int  sm9_bn_is_one(const sm9_bn_t a);
+void sm9_bn_set_word(sm9_bn_t r, uint32_t a);
+void sm9_bn_copy(sm9_bn_t r, const sm9_bn_t a);
+int  sm9_bn_rand_range(sm9_bn_t r, const sm9_bn_t range);
+int  sm9_bn_equ(const sm9_bn_t a, const sm9_bn_t b);
+int  sm9_bn_cmp(const sm9_bn_t a, const sm9_bn_t b);
+void sm9_bn_add(sm9_bn_t r, const sm9_bn_t a, const sm9_bn_t b);
+void sm9_bn_sub(sm9_bn_t ret, const sm9_bn_t a, const sm9_bn_t b);
+void sm9_bn_to_bits(const sm9_bn_t a, char bits[256]);
+void sm9_bn_to_bytes(const sm9_bn_t a, uint8_t out[32]);
+void sm9_bn_from_bytes(sm9_bn_t r, const uint8_t in[32]);
+void sm9_bn_to_hex(const sm9_bn_t a, char hex[64]);
+int  sm9_bn_from_hex(sm9_bn_t r, const char hex[64]);
+int  sm9_bn_print(FILE *fp, int fmt, int ind, const char *label, const sm9_bn_t a);
+void sm9_print_bn(const char *prefix, const sm9_bn_t a); // 标准打印格式
+
+
+typedef sm9_bn_t sm9_fp_t;
+
+#define sm9_fp_init(r)		sm9_fp_set_zero(r)
+#define sm9_fp_clean(f)		sm9_fp_set_zero(r)
+#define sm9_fp_set_zero(r)	sm9_bn_set_zero(r)
+#define sm9_fp_set_one(r)	sm9_bn_set_one(r)
+#define sm9_fp_copy(r,a)	sm9_bn_copy((r),(a))
+#define sm9_fp_rand(r)		sm9_bn_rand_range((r), SM9_P)
+#define sm9_fp_is_zero(a)	sm9_bn_is_zero(a)
+#define sm9_fp_is_one(a)	sm9_bn_is_one(a)
+#define sm9_fp_equ(a,b)		sm9_bn_equ((a),(b))
+#define sm9_fp_to_bytes(a,buf)	sm9_bn_to_bytes((a),(buf))
+#define sm9_fp_to_hex(a,s)	sm9_bn_to_hex((a),(s))
+#define sm9_fp_print(fp,fmt,ind,label,a) sm9_bn_print(fp,fmt,ind,label,a)
+
+void sm9_fp_add(sm9_fp_t r, const sm9_fp_t a, const sm9_fp_t b);
+void sm9_fp_sub(sm9_fp_t r, const sm9_fp_t a, const sm9_fp_t b);
+void sm9_fp_dbl(sm9_fp_t r, const sm9_fp_t a);
+void sm9_fp_tri(sm9_fp_t r, const sm9_fp_t a);
+void sm9_fp_neg(sm9_fp_t r, const sm9_fp_t a);
+void sm9_fp_mul(sm9_fp_t r, const sm9_fp_t a, const sm9_fp_t b);
+void sm9_fp_sqr(sm9_fp_t r, const sm9_fp_t a);
+void sm9_fp_pow(sm9_fp_t r, const sm9_fp_t a, const sm9_bn_t e);
+void sm9_fp_inv(sm9_fp_t r, const sm9_fp_t a);
+void sm9_fp_div2(sm9_fp_t r, const sm9_fp_t a);
+int sm9_fp_from_bytes(sm9_fp_t r, const uint8_t buf[32]);
+int sm9_fp_from_hex(sm9_fp_t r, const char hex[64]);
+
+
+typedef sm9_bn_t sm9_fn_t;
+
+#define sm9_fn_init(r)		sm9_fn_set_zero(r)
+#define sm9_fn_clean(f)		sm9_fn_set_zero(r)
+#define sm9_fn_set_zero(r)	sm9_bn_set_zero(r)
+#define sm9_fn_set_one(r)	sm9_bn_set_one(r)
+#define sm9_fn_copy(r,a)	sm9_bn_copy((r),(a))
+#define sm9_fn_rand(r)		sm9_bn_rand_range((r), SM9_N)
+#define sm9_fn_is_zero(a)	sm9_bn_is_zero(a)
+#define sm9_fn_is_one(a)	sm9_bn_is_one(a)
+#define sm9_fn_equ(a,b)		sm9_bn_equ((a),(b))
+#define sm9_fn_to_bytes(a,out)	sm9_bn_to_bytes((a),(out))
+#define sm9_fn_to_hex(a,s)	sm9_bn_to_hex((a),(s))
+#define sm9_fn_print(fp,fmt,ind,label,a) sm9_bn_print(fp,fmt,ind,label,a)
+
+void sm9_fn_add(sm9_fn_t r, const sm9_fn_t a, const sm9_fn_t b);
+void sm9_fn_sub(sm9_fn_t r, const sm9_fn_t a, const sm9_fn_t b);
+void sm9_fn_mul(sm9_fn_t r, const sm9_fn_t a, const sm9_fn_t b);
+void sm9_fn_pow(sm9_fn_t r, const sm9_fn_t a, const sm9_bn_t e);
+void sm9_fn_inv(sm9_fn_t r, const sm9_fn_t a);
+void sm9_fn_from_hash(sm9_fn_t h, const uint8_t Ha[40]);
+int  sm9_fn_from_bytes(sm9_fn_t a, const uint8_t in[32]);
+int  sm9_fn_from_hex(sm9_fn_t r, const char hex[64]);
+
+
+typedef uint64_t sm9_barrett_bn_t[9];
+
+int  sm9_barrett_bn_cmp(const sm9_barrett_bn_t a, const sm9_barrett_bn_t b);
+void sm9_barrett_bn_add(sm9_barrett_bn_t r, const sm9_barrett_bn_t a, const sm9_barrett_bn_t b);
+void sm9_barrett_bn_sub(sm9_barrett_bn_t ret, const sm9_barrett_bn_t a, const sm9_barrett_bn_t b);
+
+
+typedef sm9_fp_t sm9_fp2_t[2];
+extern const sm9_fp2_t SM9_FP2_ZERO;
+extern const sm9_fp2_t SM9_FP2_ONE;
+extern const sm9_fp2_t SM9_FP2_U;
+
+#define sm9_fp2_init(a)		sm9_fp2_set_zero(a)
+#define sm9_fp2_clean(a)	sm9_fp2_set_zero(a)
+#define sm9_fp2_set_zero(a)	sm9_fp2_copy((a), SM9_FP2_ZERO)
+#define sm9_fp2_set_one(a)	sm9_fp2_copy((a), SM9_FP2_ONE)
+#define sm9_fp2_set_u(a)	sm9_fp2_copy((a), SM9_FP2_U)
+#define sm9_fp2_is_zero(a)	sm9_fp2_equ((a), SM9_FP2_ZERO)
+#define sm9_fp2_is_one(a)	sm9_fp2_equ((a), SM9_FP2_ONE)
+
+void sm9_fp2_set_fp(sm9_fp2_t r, const sm9_fp_t a);
+void sm9_fp2_set(sm9_fp2_t r, const sm9_fp_t a0, const sm9_fp_t a1);
+void sm9_fp2_copy(sm9_fp2_t r, const sm9_fp2_t a);
+int  sm9_fp2_rand(sm9_fp2_t r);
+int  sm9_fp2_equ(const sm9_fp2_t a, const sm9_fp2_t b);
+void sm9_fp2_add(sm9_fp2_t r, const sm9_fp2_t a, const sm9_fp2_t b);
+void sm9_fp2_dbl(sm9_fp2_t r, const sm9_fp2_t a);
+void sm9_fp2_tri(sm9_fp2_t r, const sm9_fp2_t a);
+void sm9_fp2_sub(sm9_fp2_t r, const sm9_fp2_t a, const sm9_fp2_t b);
+void sm9_fp2_neg(sm9_fp2_t r, const sm9_fp2_t a);
+void sm9_fp2_mul(sm9_fp2_t r, const sm9_fp2_t a, const sm9_fp2_t b);
+void sm9_fp2_mul_u(sm9_fp2_t r, const sm9_fp2_t a, const sm9_fp2_t b);
+void sm9_fp2_mul_fp(sm9_fp2_t r, const sm9_fp2_t a, const sm9_fp_t k);
+void sm9_fp2_sqr(sm9_fp2_t r, const sm9_fp2_t a);
+void sm9_fp2_sqr_u(sm9_fp2_t r, const sm9_fp2_t a);
+void sm9_fp2_inv(sm9_fp2_t r, const sm9_fp2_t a);
+void sm9_fp2_div(sm9_fp2_t r, const sm9_fp2_t a, const sm9_fp2_t b);
+void sm9_fp2_div2(sm9_fp2_t r, const sm9_fp2_t a);
+void sm9_fp2_to_hex(const sm9_fp2_t a, char hex[129]);
+int  sm9_fp2_from_hex(sm9_fp2_t r, const char hex[129]);
+int  sm9_fp2_print(FILE *fp, int fmt, int ind, const char *label, const sm9_fp2_t a);
+
+
+typedef sm9_fp2_t sm9_fp4_t[2];
+extern const sm9_fp4_t SM9_FP4_ZERO;
+extern const sm9_fp4_t SM9_FP4_ONE;
+extern const sm9_fp4_t SM9_FP4_U;
+extern const sm9_fp4_t SM9_FP4_V;
+
+#define sm9_fp4_init(a)		sm9_fp4_set_zero(a)
+#define sm9_fp4_clean(a)	sm9_fp4_set_zero(a)
+#define sm9_fp4_set_zero(a)	sm9_fp4_copy((a), SM9_FP4_ZERO)
+#define sm9_fp4_set_one(a)	sm9_fp4_copy((a), SM9_FP4_ONE)
+#define sm9_fp4_is_zero(a)	sm9_fp4_equ((a), SM9_FP4_ZERO)
+#define sm9_fp4_is_one(a)	sm9_fp4_equ((a), SM9_FP4_ONE)
+
+void sm9_fp4_set_u(sm9_fp4_t r);
+void sm9_fp4_set_v(sm9_fp4_t r);
+void sm9_fp4_set_fp(sm9_fp4_t r, const sm9_fp_t a);
+void sm9_fp4_set_fp2(sm9_fp4_t r, const sm9_fp2_t a);
+void sm9_fp4_set(sm9_fp4_t r, const sm9_fp2_t a0, const sm9_fp2_t a1);
+void sm9_fp4_copy(sm9_fp4_t r, const sm9_fp4_t a);
+int  sm9_fp4_rand(sm9_fp4_t r);
+int  sm9_fp4_equ(const sm9_fp4_t a, const sm9_fp4_t b);
+void sm9_fp4_add(sm9_fp4_t r, const sm9_fp4_t a, const sm9_fp4_t b);
+void sm9_fp4_dbl(sm9_fp4_t r, const sm9_fp4_t a);
+void sm9_fp4_sub(sm9_fp4_t r, const sm9_fp4_t a, const sm9_fp4_t b);
+void sm9_fp4_neg(sm9_fp4_t r, const sm9_fp4_t a);
+void sm9_fp4_mul(sm9_fp4_t r, const sm9_fp4_t a, const sm9_fp4_t b);
+void sm9_fp4_mul_fp(sm9_fp4_t r, const sm9_fp4_t a, const sm9_fp_t k);
+void sm9_fp4_mul_fp2(sm9_fp4_t r, const sm9_fp4_t a, const sm9_fp2_t b0);
+void sm9_fp4_mul_v(sm9_fp4_t r, const sm9_fp4_t a, const sm9_fp4_t b);
+void sm9_fp4_sqr(sm9_fp4_t r, const sm9_fp4_t a);
+void sm9_fp4_sqr_v(sm9_fp4_t r, const sm9_fp4_t a);
+void sm9_fp4_inv(sm9_fp4_t r, const sm9_fp4_t a);
+void sm9_fp4_to_bytes(const sm9_fp4_t a, uint8_t buf[128]);
+int  sm9_fp4_from_bytes(sm9_fp4_t r, const uint8_t buf[128]);
+void sm9_fp4_to_hex(const sm9_fp4_t a, char hex[259]);
+int  sm9_fp4_from_hex(sm9_fp4_t r, const char hex[259]);
+
+
+typedef sm9_fp4_t sm9_fp12_t[3];
+
+#define sm9_fp12_init(r)	sm9_fp12_set_zero(a)
+#define sm9_fp12_clean(r)	sm9_fp12_set_zero(a)
+
+void sm9_fp12_set_zero(sm9_fp12_t r);
+void sm9_fp12_set_one(sm9_fp12_t r);
+void sm9_fp12_set_u(sm9_fp12_t r);
+void sm9_fp12_set_v(sm9_fp12_t r);
+void sm9_fp12_set_w(sm9_fp12_t r);
+void sm9_fp12_set_w_sqr(sm9_fp12_t r);
+void sm9_fp12_set_fp(sm9_fp12_t r, const sm9_fp_t a);
+void sm9_fp12_set_fp2(sm9_fp12_t r, const sm9_fp2_t a);
+void sm9_fp12_set_fp4(sm9_fp12_t r, const sm9_fp4_t a);
+void sm9_fp12_set(sm9_fp12_t r, const sm9_fp4_t a0, const sm9_fp4_t a1, const sm9_fp4_t a2);
+void sm9_fp12_copy(sm9_fp12_t r, const sm9_fp12_t a);
+int  sm9_fp12_rand(sm9_fp12_t r);
+int  sm9_fp12_is_one(const sm9_fp12_t a);
+int  sm9_fp12_is_zero(const sm9_fp12_t a);
+int  sm9_fp12_equ(const sm9_fp12_t a, const sm9_fp12_t b);
+void sm9_fp12_add(sm9_fp12_t r, const sm9_fp12_t a, const sm9_fp12_t b);
+void sm9_fp12_dbl(sm9_fp12_t r, const sm9_fp12_t a);
+void sm9_fp12_tri(sm9_fp12_t r, const sm9_fp12_t a);
+void sm9_fp12_sub(sm9_fp12_t r, const sm9_fp12_t a, const sm9_fp12_t b);
+void sm9_fp12_neg(sm9_fp12_t r, const sm9_fp12_t a);
+void sm9_fp12_mul(sm9_fp12_t r, const sm9_fp12_t a, const sm9_fp12_t b);
+void sm9_fp12_sqr(sm9_fp12_t r, const sm9_fp12_t a);
+void sm9_fp12_inv(sm9_fp12_t r, const sm9_fp12_t a);
+void sm9_fp12_pow(sm9_fp12_t r, const sm9_fp12_t a, const sm9_bn_t k);
+void sm9_fp12_to_bytes(const sm9_fp12_t a, uint8_t buf[32 * 12]);
+int  sm9_fp12_from_bytes(sm9_fp12_t r, const uint8_t in[32 * 12]);
+void sm9_fp12_to_hex(const sm9_fp12_t a, char hex[65 * 12]);
+int  sm9_fp12_from_hex(sm9_fp12_t r, const char hex[65 * 12]); // 这个明显是不对的
+void sm9_fp12_print(const char *prefix, const sm9_fp12_t a);
+
+
+void sm9_fp2_conjugate(sm9_fp2_t r, const sm9_fp2_t a);
+void sm9_fp2_frobenius(sm9_fp2_t r, const sm9_fp2_t a);
+void sm9_fp4_frobenius(sm9_fp4_t r, const sm9_fp4_t a);
+void sm9_fp4_conjugate(sm9_fp4_t r, const sm9_fp4_t a);
+void sm9_fp4_frobenius2(sm9_fp4_t r, const sm9_fp4_t a);
+void sm9_fp4_frobenius3(sm9_fp4_t r, const sm9_fp4_t a);
+void sm9_fp12_frobenius(sm9_fp12_t r, const sm9_fp12_t x);
+void sm9_fp12_frobenius2(sm9_fp12_t r, const sm9_fp12_t x);
+void sm9_fp12_frobenius3(sm9_fp12_t r, const sm9_fp12_t x);
+void sm9_fp12_frobenius6(sm9_fp12_t r, const sm9_fp12_t x);
+
+
+typedef struct {
+	sm9_fp_t X;
+	sm9_fp_t Y;
+	sm9_fp_t Z;
+} SM9_POINT;
+
+#define sm9_point_init(R)	sm9_point_set_infinity(R)
+#define sm9_point_clean(R)	sm9_point_set_infinity(R)
+
+void sm9_point_set_infinity(SM9_POINT *R);
+void sm9_point_copy(SM9_POINT *R, const SM9_POINT *P);
+void sm9_point_get_xy(const SM9_POINT *P, sm9_fp_t x, sm9_fp_t y);
+int  sm9_point_is_at_infinity(const SM9_POINT *P);
+int  sm9_point_equ(const SM9_POINT *P, const SM9_POINT *Q);
+int  sm9_point_is_on_curve(const SM9_POINT *P);
+void sm9_point_dbl(SM9_POINT *R, const SM9_POINT *P);
+void sm9_point_add(SM9_POINT *R, const SM9_POINT *P, const SM9_POINT *Q);
+void sm9_point_neg(SM9_POINT *R, const SM9_POINT *P);
+void sm9_point_sub(SM9_POINT *R, const SM9_POINT *P, const SM9_POINT *Q);
+void sm9_point_mul(SM9_POINT *R, const sm9_bn_t k, const SM9_POINT *P);
+void sm9_point_mul_generator(SM9_POINT *R, const sm9_bn_t k);
+void sm9_point_from_hex(SM9_POINT *R, const char hex[65 * 2]);		
+int sm9_point_to_uncompressed_octets(const SM9_POINT *P, uint8_t octets[65]);
+int sm9_point_from_uncompressed_octets(SM9_POINT *P, const uint8_t octets[65]);
+int sm9_point_print(FILE *fp, int fmt, int ind, const char *label, const SM9_POINT *P);
+
+
+typedef struct {
+	sm9_fp2_t X;
+	sm9_fp2_t Y;
+	sm9_fp2_t Z;
+} SM9_TWIST_POINT;
+
+#define sm9_twist_point_copy(R, P)	memcpy((R), (P), sizeof(SM9_TWIST_POINT))
+
+int sm9_twist_point_to_uncompressed_octets(const SM9_TWIST_POINT *P, uint8_t octets[129]);
+int sm9_twist_point_from_uncompressed_octets(SM9_TWIST_POINT *P, const uint8_t octets[129]);
+
+
+void sm9_twist_point_from_hex(SM9_TWIST_POINT *R, const char hex[65 * 4]);
+int  sm9_twist_point_is_at_infinity(const SM9_TWIST_POINT *P);
+void sm9_twist_point_set_infinity(SM9_TWIST_POINT *R);
+void sm9_twist_point_get_xy(const SM9_TWIST_POINT *P, sm9_fp2_t x, sm9_fp2_t y);
+
+int  sm9_twist_point_equ(const SM9_TWIST_POINT *P, const SM9_TWIST_POINT *Q);
+int  sm9_twist_point_is_on_curve(const SM9_TWIST_POINT *P);
+void sm9_twist_point_neg(SM9_TWIST_POINT *R, const SM9_TWIST_POINT *P);
+void sm9_twist_point_dbl(SM9_TWIST_POINT *R, const SM9_TWIST_POINT *P);
+void sm9_twist_point_add(SM9_TWIST_POINT *R, const SM9_TWIST_POINT *P, const SM9_TWIST_POINT *Q);
+void sm9_twist_point_sub(SM9_TWIST_POINT *R, const SM9_TWIST_POINT *P, const SM9_TWIST_POINT *Q);
+void sm9_twist_point_add_full(SM9_TWIST_POINT *R, const SM9_TWIST_POINT *P, const SM9_TWIST_POINT *Q);
+void sm9_twist_point_mul(SM9_TWIST_POINT *R, const sm9_bn_t k, const SM9_TWIST_POINT *P);
+void sm9_twist_point_mul_generator(SM9_TWIST_POINT *R, const sm9_bn_t k);
+int sm9_twist_point_print(FILE *fp, int fmt, int ind, const char *label, const SM9_TWIST_POINT *P);
+
+
+
+void sm9_eval_g_tangent(sm9_fp12_t num, sm9_fp12_t den, const SM9_TWIST_POINT *P, const SM9_POINT *Q);
+void sm9_eval_g_line(sm9_fp12_t num, sm9_fp12_t den, const SM9_TWIST_POINT *T, const SM9_TWIST_POINT *P, const SM9_POINT *Q);
+void sm9_twist_point_pi1(SM9_TWIST_POINT *R, const SM9_TWIST_POINT *P);
+void sm9_twist_point_pi2(SM9_TWIST_POINT *R, const SM9_TWIST_POINT *P);
+void sm9_twist_point_neg_pi2(SM9_TWIST_POINT *R, const SM9_TWIST_POINT *P);
+void sm9_final_exponent_hard_part(sm9_fp12_t r, const sm9_fp12_t f);
+void sm9_final_exponent(sm9_fp12_t r, const sm9_fp12_t f);
+void sm9_pairing(sm9_fp12_t r, const SM9_TWIST_POINT *Q, const SM9_POINT *P);
+
+
+/* private key extract algorithms */
+#define SM9_HID_SIGN		0x01
+#define SM9_HID_EXCH		0x02
+#define SM9_HID_ENC		0x03
+
+#define SM9_HASH1_PREFIX	0x01
+#define SM9_HASH2_PREFIX	0x02
+
+int sm9_hash1(sm9_bn_t h1, const char *id, size_t idlen, uint8_t hid);
+
+
+const char *sm9_oid_name(int oid);
+int sm9_oid_from_name(const char *name);
+int sm9_oid_to_der(int oid, uint8_t **out, size_t *outlen);
+int sm9_oid_from_der(int *oid, const uint8_t **in, size_t *inlen);
+int sm9_algor_to_der(int alg, int params, uint8_t **out, size_t *outlen);
+int sm9_algor_from_der(int *alg, int *params, const uint8_t **in, size_t *inlen);
+
+
+#define PEM_SM9_SIGN_MASTER_KEY		"ENCRYPTED SM9 SIGN MASTER KEY"
+#define PEM_SM9_SIGN_MASTER_PUBLIC_KEY	"SM9 SIGN MASTER PUBLIC KEY"
+#define PEM_SM9_SIGN_PRIVATE_KEY	"ENCRYPTED SM9 SIGN PRIVATE KEY"
+#define PEM_SM9_ENC_MASTER_KEY		"ENCRYPTED SM9 ENC MASTER KEY"
+#define PEM_SM9_ENC_MASTER_PUBLIC_KEY	"SM9 ENC MASTER PUBLIC KEY"
+#define PEM_SM9_ENC_PRIVATE_KEY		"ENCRYPTED SM9 ENC PRIVATE KEY"
+
+
+#define SM9_MAX_ID_SIZE		(SM2_MAX_ID_SIZE)
+
+/*
+SM9SignMasterKey ::= SEQUENCE {
+	ks	INTEGER,
+	Ppubs	BIT STRING -- uncompressed octets of twisted point }
+
+SM9SignMasterPublicKey ::= SEQUENCE {
+	Ppubs   BIT STRING -- uncompressed octets of twisted point }
+
+SM9SignPrivateKey ::= SEQUENCE {
+	ds	BIT STRING, -- uncompressed octets of ECPoint
+	Ppubs	BIT STRING -- uncompressed octets of twisted point }
+*/
+typedef struct {
+	SM9_TWIST_POINT Ppubs; // Ppubs = ks * P2
+	sm9_fn_t ks;
+} SM9_SIGN_MASTER_KEY;
+
+typedef struct {
+	SM9_TWIST_POINT Ppubs;
+	SM9_POINT ds;
+} SM9_SIGN_KEY;
+
+int sm9_sign_master_key_generate(SM9_SIGN_MASTER_KEY *master);
+int sm9_sign_master_key_extract_key(SM9_SIGN_MASTER_KEY *master, const char *id, size_t idlen, SM9_SIGN_KEY *key);
+
+// algorthm,parameters = sm9,sm9sign
+#define SM9_SIGN_MASTER_KEY_MAX_SIZE 171
+int sm9_sign_master_key_to_der(const SM9_SIGN_MASTER_KEY *msk, uint8_t **out, size_t *outlen);
+int sm9_sign_master_key_from_der(SM9_SIGN_MASTER_KEY *msk, const uint8_t **in, size_t *inlen);
+int sm9_sign_master_key_info_encrypt_to_der(const SM9_SIGN_MASTER_KEY *msk, const char *pass, uint8_t **out, size_t *outlen);
+int sm9_sign_master_key_info_decrypt_from_der(SM9_SIGN_MASTER_KEY *msk, const char *pass, const uint8_t **in, size_t *inlen);
+int sm9_sign_master_key_info_encrypt_to_pem(const SM9_SIGN_MASTER_KEY *msk, const char *pass, FILE *fp);
+int sm9_sign_master_key_info_decrypt_from_pem(SM9_SIGN_MASTER_KEY *msk, const char *pass, FILE *fp);
+int sm9_sign_master_key_print(FILE *fp, int fmt, int ind, const char *label, const SM9_SIGN_MASTER_KEY *msk);
+
+#define SM9_SIGN_MASTER_PUBLIC_KEY_SIZE 136
+int sm9_sign_master_public_key_to_der(const SM9_SIGN_MASTER_KEY *mpk, uint8_t **out, size_t *outlen);
+int sm9_sign_master_public_key_from_der(SM9_SIGN_MASTER_KEY *mpk, const uint8_t **in, size_t *inlen);
+int sm9_sign_master_public_key_to_pem(const SM9_SIGN_MASTER_KEY *mpk, FILE *fp);
+int sm9_sign_master_public_key_from_pem(SM9_SIGN_MASTER_KEY *mpk, FILE *fp);
+int sm9_sign_master_public_key_print(FILE *fp, int fmt, int ind, const char *label, const SM9_SIGN_MASTER_KEY *mpk);
+
+// algorithm,parameters = sm9sign,<null>
+#define SM9_SIGN_KEY_SIZE 204
+int sm9_sign_key_to_der(const SM9_SIGN_KEY *key, uint8_t **out, size_t *outlen);
+int sm9_sign_key_from_der(SM9_SIGN_KEY *key, const uint8_t **in, size_t *inlen);
+int sm9_sign_key_info_encrypt_to_der(const SM9_SIGN_KEY *key, const char *pass, uint8_t **out, size_t *outlen);
+int sm9_sign_key_info_decrypt_from_der(SM9_SIGN_KEY *key, const char *pass, const uint8_t **in, size_t *inlen);
+int sm9_sign_key_info_encrypt_to_pem(const SM9_SIGN_KEY *key, const char *pass, FILE *fp);
+int sm9_sign_key_info_decrypt_from_pem(SM9_SIGN_KEY *key, const char *pass, FILE *fp);
+int sm9_sign_key_print(FILE *fp, int fmt, int ind, const char *label, const SM9_SIGN_KEY *key);
+
+/*
+from GM/T 0080-2020 SM9 Cryptographic Alagorithm Application Specification
+SM9Signature ::= SEQUENCE {
+	h	OCTET STRING,
+	S	BIT STRING -- uncompressed octets of ECPoint }
+*/
+typedef struct {
+	sm9_fn_t h;
+	SM9_POINT S;
+} SM9_SIGNATURE;
+
+int sm9_do_sign(const SM9_SIGN_KEY *key, const SM3_CTX *sm3_ctx, SM9_SIGNATURE *sig);
+int sm9_do_verify(const SM9_SIGN_MASTER_KEY *mpk, const char *id, size_t idlen, const SM3_CTX *sm3_ctx, const SM9_SIGNATURE *sig);
+
+#define SM9_SIGNATURE_SIZE 104
+int sm9_signature_to_der(const SM9_SIGNATURE *sig, uint8_t **out, size_t *outlen);
+int sm9_signature_from_der(SM9_SIGNATURE *sig, const uint8_t **in, size_t *inlen);
+int sm9_signature_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *sig, size_t siglen);
+
+typedef struct {
+	SM3_CTX sm3_ctx;
+} SM9_SIGN_CTX;
+
+int sm9_sign_init(SM9_SIGN_CTX *ctx);
+int sm9_sign_update(SM9_SIGN_CTX *ctx, const uint8_t *data, size_t datalen);
+int sm9_sign_finish(SM9_SIGN_CTX *ctx, const SM9_SIGN_KEY *key, uint8_t *sig, size_t *siglen);
+int sm9_verify_init(SM9_SIGN_CTX *ctx);
+int sm9_verify_update(SM9_SIGN_CTX *ctx, const uint8_t *data, size_t datalen);
+int sm9_verify_finish(SM9_SIGN_CTX *ctx, const uint8_t *sig, size_t siglen,
+	const SM9_SIGN_MASTER_KEY *mpk, const char *id, size_t idlen);
+
+
+/*
+SM9EncMasterKey ::= SEQUENCE {
+	de	INTEGER,
+	Ppube	BIT STRING -- uncompressed octets of ECPoint }
+
+SM9EncMasterPublicKey ::= SEQUENCE {
+	Ppube	BIT STRING -- uncompressed octets of ECPoint }
+
+SM9EncPrivateKey ::= SEQUENCE {
+	de	BIT STRING, -- uncompressed octets of twisted point
+	Ppube	BIT STRING -- uncompressed octets of ECPoint }
+*/
+
+typedef struct {
+	SM9_POINT Ppube; // Ppube = ke * P1
+	sm9_fn_t ke;
+} SM9_ENC_MASTER_KEY;
+
+typedef struct {
+	SM9_POINT Ppube;
+	SM9_TWIST_POINT de;
+} SM9_ENC_KEY;
+
+int sm9_enc_master_key_generate(SM9_ENC_MASTER_KEY *master);
+int sm9_enc_master_key_extract_key(SM9_ENC_MASTER_KEY *master, const char *id, size_t idlen, SM9_ENC_KEY *key);
+
+// algorithm,parameters = sm9,sm9encrypt
+#define SM9_ENC_MASTER_KEY_MAX_SIZE 105
+int sm9_enc_master_key_to_der(const SM9_ENC_MASTER_KEY *msk, uint8_t **out, size_t *outlen);
+int sm9_enc_master_key_from_der(SM9_ENC_MASTER_KEY *msk, const uint8_t **in, size_t *inlen);
+int sm9_enc_master_key_info_encrypt_to_der(const SM9_ENC_MASTER_KEY *msk, const char *pass, uint8_t **out, size_t *outlen);
+int sm9_enc_master_key_info_decrypt_from_der(SM9_ENC_MASTER_KEY *msk, const char *pass, const uint8_t **in, size_t *inlen);
+int sm9_enc_master_key_info_encrypt_to_pem(const SM9_ENC_MASTER_KEY *msk, const char *pass, FILE *fp);
+int sm9_enc_master_key_info_decrypt_from_pem(SM9_ENC_MASTER_KEY *msk, const char *pass, FILE *fp);
+int sm9_enc_master_key_print(FILE *fp, int fmt, int ind, const char *label, const SM9_ENC_MASTER_KEY *msk);
+
+#define SM9_ENC_MASTER_PUBLIC_KEY_SIZE 70
+int sm9_enc_master_public_key_to_der(const SM9_ENC_MASTER_KEY *mpk, uint8_t **out, size_t *outlen);
+int sm9_enc_master_public_key_from_der(SM9_ENC_MASTER_KEY *mpk, const uint8_t **in, size_t *inlen);
+int sm9_enc_master_public_key_to_pem(const SM9_ENC_MASTER_KEY *mpk, FILE *fp);
+int sm9_enc_master_public_key_from_pem(SM9_ENC_MASTER_KEY *mpk, FILE *fp);
+int sm9_enc_master_public_key_print(FILE *fp, int fmt, int ind, const char *label, const SM9_ENC_MASTER_KEY *mpk);
+
+// algorithm,parameters = sm9encrypt,<null>
+#define SM9_ENC_KEY_SIZE 204
+int sm9_enc_key_to_der(const SM9_ENC_KEY *key, uint8_t **out, size_t *outlen);
+int sm9_enc_key_from_der(SM9_ENC_KEY *key, const uint8_t **in, size_t *inlen);
+int sm9_enc_key_info_encrypt_to_der(const SM9_ENC_KEY *key, const char *pass, uint8_t **out, size_t *outlen);
+int sm9_enc_key_info_decrypt_from_der(SM9_ENC_KEY *key, const char *pass, const uint8_t **in, size_t *inlen);
+int sm9_enc_key_info_encrypt_to_pem(const SM9_ENC_KEY *key, const char *pass, FILE *fp);
+int sm9_enc_key_info_decrypt_from_pem(SM9_ENC_KEY *key, const char *pass, FILE *fp);
+int sm9_enc_key_print(FILE *fp, int fmt, int ind, const char *label, const SM9_ENC_KEY *key);
+
+#define SM9_MAX_PRIVATE_KEY_SIZE (SM9_SIGN_KEY_SIZE) // MAX(SIGN_MASTER_KEY, SIGN_KEY, ENC_MASTER_KEY, ENC_KEY)
+#define SM9_MAX_PRIVATE_KEY_INFO_SIZE 512
+#define SM9_MAX_ENCED_PRIVATE_KEY_INFO_SIZE 1024
+
+/*
+from GM/T 0080-2020 SM9 Cryptographic Alagorithm Application Specification
+SM9Cipher ::= SEQUENCE {
+	EnType		INTEGER, -- 0 for XOR
+	C1		BIT STRING, -- uncompressed octets of ECPoint
+	C3		OCTET STRING, -- 32 bytes HMAC-SM3 tag
+	CipherText	OCTET STRING }
+*/
+
+int sm9_kem_encrypt(const SM9_ENC_MASTER_KEY *mpk, const char *id, size_t idlen, size_t klen, uint8_t *kbuf, SM9_POINT *C);
+int sm9_kem_decrypt(const SM9_ENC_KEY *key, const char *id, size_t idlen, const SM9_POINT *C, size_t klen, uint8_t *kbuf);
+int sm9_do_encrypt(const SM9_ENC_MASTER_KEY *mpk, const char *id, size_t idlen,
+	const uint8_t *in, size_t inlen, SM9_POINT *C1, uint8_t *c2, uint8_t c3[SM3_HMAC_SIZE]);
+int sm9_do_decrypt(const SM9_ENC_KEY *key, const char *id, size_t idlen,
+	const SM9_POINT *C1, const uint8_t *c2, size_t c2len, const uint8_t c3[SM3_HMAC_SIZE], uint8_t *out);
+
+#define SM9_MAX_PLAINTEXT_SIZE 255
+#define SM9_MAX_CIPHERTEXT_SIZE 367 // calculated in test_sm9_ciphertext()
+int sm9_ciphertext_to_der(const SM9_POINT *C1, const uint8_t *c2, size_t c2len,
+	const uint8_t c3[SM3_HMAC_SIZE], uint8_t **out, size_t *outlen);
+int sm9_ciphertext_from_der(SM9_POINT *C1, const uint8_t **c2, size_t *c2len,
+	const uint8_t **c3, const uint8_t **in, size_t *inlen);
+int sm9_ciphertext_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *a, size_t alen);
+int sm9_encrypt(const SM9_ENC_MASTER_KEY *mpk, const char *id, size_t idlen,
+	const uint8_t *in, size_t inlen, uint8_t *out, size_t *outlen);
+int sm9_decrypt(const SM9_ENC_KEY *key, const char *id, size_t idlen,
+	const uint8_t *in, size_t inlen, uint8_t *out, size_t *outlen);
+
+
+
+#ifdef  __cplusplus
+}
+#endif
+#endif

+ 73 - 0
components/gmssl/include/gmssl/socket.h

@@ -0,0 +1,73 @@
+/*
+ *  Copyright 2014-2022 The GmSSL Project. All Rights Reserved.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the License); you may
+ *  not use this file except in compliance with the License.
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ */
+
+
+#ifndef GMSSL_SOCKET_H
+#define GMSSL_SOCKET_H
+
+#include <string.h>
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+
+#ifdef WIN32
+#pragma comment (lib, "Ws2_32.lib")
+#pragma comment (lib, "Mswsock.lib")
+#pragma comment (lib, "AdvApi32.lib")
+
+#include <winsock2.h>
+
+typedef SOCKET tls_socket_t;
+typedef int tls_ret_t;
+typedef int tls_socklen_t;
+
+
+#define tls_socket_send(sock,buf,len,flags)	send(sock,buf,(int)(len),flags)
+#define tls_socket_recv(sock,buf,len,flags)	recv(sock,buf,(int)(len),flags)
+#define tls_socket_close(sock)			closesocket(sock)
+
+
+#else
+
+#include <fcntl.h>
+#include <netdb.h>
+#include <arpa/inet.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <unistd.h>
+
+typedef int tls_socket_t;
+typedef ssize_t tls_ret_t;
+typedef socklen_t tls_socklen_t;
+
+
+#define tls_socket_send(sock,buf,len,flags)	send(sock,buf,len,flags)
+#define tls_socket_recv(sock,buf,len,flags)	recv(sock,buf,len,flags)
+#define tls_socket_close(sock)			close(sock)
+
+#endif
+
+int tls_socket_lib_init(void);
+int tls_socket_lib_cleanup(void);
+int tls_socket_create(tls_socket_t *sock, int af, int type, int protocl);
+int tls_socket_connect(tls_socket_t sock, const struct sockaddr_in *addr);
+int tls_socket_bind(tls_socket_t sock, const struct sockaddr_in *addr);
+int tls_socket_listen(tls_socket_t sock, int backlog);
+int tls_socket_accept(tls_socket_t sock, struct sockaddr_in *addr, tls_socket_t *conn_sock);
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif

+ 875 - 0
components/gmssl/include/gmssl/tls.h

@@ -0,0 +1,875 @@
+/*
+ *  Copyright 2014-2022 The GmSSL Project. All Rights Reserved.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the License); you may
+ *  not use this file except in compliance with the License.
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ */
+
+
+
+#ifndef GMSSL_TLS_H
+#define GMSSL_TLS_H
+
+
+#include <stdint.h>
+#include <gmssl/sm2.h>
+#include <gmssl/sm3.h>
+#include <gmssl/sm4.h>
+#include <gmssl/digest.h>
+#include <gmssl/block_cipher.h>
+#include <gmssl/socket.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/*
+TLS Public API
+
+	TLS_PROTOCOL
+	TLS_protocol_tlcp
+	TLS_protocol_tls12
+	TLS_protocol_tls13
+
+	TLS_CIPHER_SUITE
+	TLS_cipher_ecc_sm4_cbc_sm3
+	TLS_cipher_ecc_sm4_gcm_sm3
+	TLS_cipher_ecdhe_sm4_cbc_sm3
+	TLS_cipher_ecdhe_sm4_gcm_sm3
+	TLS_cipher_sm4_gcm_sm3
+
+	TLS_CTX
+	tls_ctx_init
+	tls_ctx_set_cipher_suites
+	tls_ctx_set_ca_certificates
+	tls_ctx_set_certificate_and_key
+	tls_ctx_set_tlcp_server_certificate_and_keys
+	tls_ctx_cleanup
+
+	TLS_CONNECT
+	tls_init
+	tls_set_socket
+	tls_do_handshake
+	tls_send
+	tls_recv
+	tls_shutdown
+	tls_cleanup
+*/
+
+typedef uint32_t uint24_t;
+
+#define tls_uint8_size()	1
+#define tls_uint16_size()	2
+#define tls_uint24_size()	3
+
+void tls_uint8_to_bytes(uint8_t a, uint8_t **out, size_t *outlen);
+void tls_uint16_to_bytes(uint16_t a, uint8_t **out, size_t *outlen);
+void tls_uint24_to_bytes(uint24_t a, uint8_t **out, size_t *outlen);
+void tls_uint32_to_bytes(uint32_t a, uint8_t **out, size_t *outlen);
+void tls_array_to_bytes(const uint8_t *data, size_t len, uint8_t **out, size_t *outlen);
+void tls_uint8array_to_bytes(const uint8_t *data, size_t datalen, uint8_t **out, size_t *outlen);
+void tls_uint16array_to_bytes(const uint8_t *data, size_t datalen, uint8_t **out, size_t *outlen);
+void tls_uint24array_to_bytes(const uint8_t *data, size_t datalen, uint8_t **out, size_t *outlen);
+int tls_uint8_from_bytes(uint8_t *a, const uint8_t **in, size_t *inlen);
+int tls_uint16_from_bytes(uint16_t *a, const uint8_t **in, size_t *inlen);
+int tls_uint24_from_bytes(uint24_t *a, const uint8_t **in, size_t *inlen);
+int tls_uint32_from_bytes(uint32_t *a, const uint8_t **in, size_t *inlen);
+int tls_array_from_bytes(const uint8_t **data, size_t datalen, const uint8_t **in, size_t *inlen);
+int tls_uint8array_from_bytes(const uint8_t **data, size_t *datalen, const uint8_t **in, size_t *inlen);
+int tls_uint16array_from_bytes(const uint8_t **data, size_t *datalen, const uint8_t **in, size_t *inlen);
+int tls_uint24array_from_bytes(const uint8_t **data, size_t *datalen, const uint8_t **in, size_t *inlen);
+int tls_length_is_zero(size_t len);
+
+
+typedef enum {
+	TLS_protocol_tlcp			= 0x0101,
+	TLS_protocol_ssl2			= 0x0200,
+	TLS_protocol_ssl3			= 0x0300,
+	TLS_protocol_tls1			= 0x0301,
+	TLS_protocol_tls11			= 0x0302,
+	TLS_protocol_tls12			= 0x0303,
+	TLS_protocol_tls13			= 0x0304,
+	TLS_protocol_dtls1			= 0xfeff, // {254, 255}
+	TLS_protocol_dtls12			= 0xfefd, // {254, 253}
+} TLS_PROTOCOL;
+
+const char *tls_protocol_name(int proto);
+
+
+typedef enum {
+	TLS_cipher_null_with_null_null		= 0x0000,
+
+	// TLS 1.3, RFC 8998
+	TLS_cipher_sm4_gcm_sm3			= 0x00c6,
+	TLS_cipher_sm4_ccm_sm3			= 0x00c7,
+
+	// TLCP, GB/T 38636-2020, GM/T 0024-2012
+	TLS_cipher_ecdhe_sm4_cbc_sm3		= 0xe011, // 可以让TLSv1.2使用这个
+	TLS_cipher_ecdhe_sm4_gcm_sm3		= 0xe051,
+	TLS_cipher_ecc_sm4_cbc_sm3		= 0xe013,
+	TLS_cipher_ecc_sm4_gcm_sm3		= 0xe053,
+	TLS_cipher_ibsdh_sm4_cbc_sm3		= 0xe015,
+	TLS_cipher_ibsdh_sm4_gcm_sm3		= 0xe055,
+	TLS_cipher_ibc_sm4_cbc_sm3		= 0xe017,
+	TLS_cipher_ibc_sm4_gcm_sm3		= 0xe057,
+	TLS_cipher_rsa_sm4_cbc_sm3		= 0xe019,
+	TLS_cipher_rsa_sm4_gcm_sm3		= 0xe059,
+	TLS_cipher_rsa_sm4_cbc_sha256		= 0xe01c,
+	TLS_cipher_rsa_sm4_gcm_sha256		= 0xe05a,
+
+	// TLS 1.3 RFC 8446
+	TLS_cipher_aes_128_gcm_sha256		= 0x1301, // Mandatory-to-implement
+	TLS_cipher_aes_256_gcm_sha384		= 0x1302, // SHOULD implement
+	TLS_cipher_chacha20_poly1305_sha256	= 0x1303, // SHOULD implement
+	TLS_cipher_aes_128_ccm_sha256		= 0x1304,
+	TLS_cipher_aes_128_ccm_8_sha256		= 0x1305,
+
+	TLS_cipher_empty_renegotiation_info_scsv = 0x00ff,
+} TLS_CIPHER_SUITE;
+
+const char *tls_cipher_suite_name(int cipher);
+int tls_cipher_suites_select(const uint8_t *client_ciphers, size_t client_ciphers_len,
+	const int *server_ciphers, size_t server_ciphers_cnt, int *selected_cipher);
+int tls_cipher_suite_in_list(int cipher, const int *list, size_t list_count);
+
+
+typedef enum {
+	TLS_compression_null	= 0,
+	TLS_compression_default	= 1,
+} TLS_COMPRESSION_METHOD;
+
+const char *tls_compression_method_name(int meth);
+
+
+typedef enum {
+	TLS_record_invalid			= 0,  // TLS 1.3
+	TLS_record_change_cipher_spec		= 20, // 0x14
+	TLS_record_alert			= 21, // 0x15
+	TLS_record_handshake			= 22, // 0x16
+	TLS_record_application_data		= 23, // 0x17
+	TLS_record_heartbeat			= 24, // 0x18
+	TLS_record_tls12_cid			= 25, // 0x19
+} TLS_RECORD_TYPE;
+
+const char *tls_record_type_name(int type);
+
+
+typedef enum  {
+	TLS_handshake_hello_request		= 0,
+	TLS_handshake_client_hello		= 1,
+	TLS_handshake_server_hello		= 2,
+	TLS_handshake_hello_verify_request	= 3,
+	TLS_handshake_new_session_ticket	= 4,
+	TLS_handshake_end_of_early_data		= 5,
+	TLS_handshake_hello_retry_request	= 6,
+	TLS_handshake_encrypted_extensions	= 8,
+	TLS_handshake_certificate		= 11,
+	TLS_handshake_server_key_exchange	= 12,
+	TLS_handshake_certificate_request	= 13,
+	TLS_handshake_server_hello_done		= 14,
+	TLS_handshake_certificate_verify	= 15,
+	TLS_handshake_client_key_exchange	= 16,
+	TLS_handshake_finished			= 20,
+	TLS_handshake_certificate_url		= 21,
+	TLS_handshake_certificate_status	= 22,
+	TLS_handshake_supplemental_data		= 23,
+	TLS_handshake_key_update		= 24,
+	TLS_handshake_compressed_certificate	= 25,
+	TLS_handshake_ekt_key			= 26,
+	TLS_handshake_message_hash		= 254,
+} TLS_HANDSHAKE_TYPE;
+
+const char *tls_handshake_type_name(int type);
+
+
+typedef enum {
+	TLS_cert_type_rsa_sign			= 1,
+	TLS_cert_type_dss_sign			= 2,
+	TLS_cert_type_rsa_fixed_dh		= 3,
+	TLS_cert_type_dss_fixed_dh		= 4,
+	TLS_cert_type_rsa_ephemeral_dh_RESERVED = 5,
+	TLS_cert_type_dss_ephemeral_dh_RESERVED = 6,
+	TLS_cert_type_fortezza_dms_RESERVED	= 20,
+	TLS_cert_type_ecdsa_sign		= 64, // also for sm2
+	TLS_cert_type_rsa_fixed_ecdh		= 65,
+	TLS_cert_type_ecdsa_fixed_ecdh		= 66,
+	TLS_cert_type_gost_sign256		= 67,
+	TLS_cert_type_gost_sign512		= 68,
+	TLS_cert_type_ibc_params		= 80,
+} TLS_CERTIFICATE_TYPE;
+
+const char *tls_cert_type_name(int type);
+int tls_cert_type_from_oid(int oid);
+
+typedef enum {
+	TLS_extension_server_name		= 0,
+	TLS_extension_max_fragment_length	= 1,
+	TLS_extension_client_certificate_url	= 2,
+	TLS_extension_trusted_ca_keys		= 3,
+	TLS_extension_truncated_hmac		= 4,
+	TLS_extension_status_request		= 5,
+	TLS_extension_user_mapping		= 6,
+	TLS_extension_client_authz		= 7,
+	TLS_extension_server_authz		= 8,
+	TLS_extension_cert_type			= 9,
+	TLS_extension_supported_groups		= 10,
+	TLS_extension_ec_point_formats		= 11,
+	TLS_extension_srp			= 12,
+	TLS_extension_signature_algorithms	= 13,
+	TLS_extension_use_srtp			= 14,
+	TLS_extension_heartbeat			= 15,
+	TLS_extension_application_layer_protocol_negotiation= 16,
+	TLS_extension_status_request_v2		= 17,
+	TLS_extension_signed_certificate_timestamp = 18,
+	TLS_extension_client_certificate_type	= 19,
+	TLS_extension_server_certificate_type	= 20,
+	TLS_extension_padding			= 21,
+	TLS_extension_encrypt_then_mac		= 22,
+	TLS_extension_extended_master_secret	= 23,
+	TLS_extension_token_binding		= 24,
+	TLS_extension_cached_info		= 25,
+	TLS_extension_tls_lts			= 26,
+	TLS_extension_compress_certificate	= 27,
+	TLS_extension_record_size_limit		= 28,
+	TLS_extension_pwd_protect		= 29,
+	TLS_extension_pwd_clear			= 30,
+	TLS_extension_password_salt		= 31,
+	TLS_extension_ticket_pinning		= 32,
+	TLS_extension_tls_cert_with_extern_psk	= 33,
+	TLS_extension_delegated_credentials	= 34,
+	TLS_extension_session_ticket		= 35,
+	TLS_extension_TLMSP			= 36,
+	TLS_extension_TLMSP_proxying		= 37,
+	TLS_extension_TLMSP_delegate		= 38,
+	TLS_extension_supported_ekt_ciphers	= 39,
+	TLS_extension_pre_shared_key		= 41,
+	TLS_extension_early_data		= 42,
+	TLS_extension_supported_versions	= 43,
+	TLS_extension_cookie			= 44,
+	TLS_extension_psk_key_exchange_modes	= 46,
+	TLS_extension_certificate_authorities	= 47,
+	TLS_extension_oid_filters		= 48,
+	TLS_extension_post_handshake_auth	= 49,
+	TLS_extension_signature_algorithms_cert	= 50,
+	TLS_extension_key_share			= 51,
+	TLS_extension_transparency_info		= 52,
+	TLS_extension_connection_id		= 53,
+	TLS_extension_external_id_hash		= 55,
+	TLS_extension_external_session_id	= 56,
+	TLS_extension_quic_transport_parameters	= 57,
+	TLS_extension_ticket_request		= 58,
+	TLS_extension_renegotiation_info	= 65281,
+} TLS_EXTENSION_TYPE;
+
+const char *tls_extension_name(int ext);
+
+
+typedef enum {
+	TLS_point_uncompressed			= 0,
+	TLS_point_ansix962_compressed_prime	= 1,
+	TLS_point_ansix962_compressed_char2	= 2,
+} TLS_EC_POINT_FORMAT;
+
+const char *tls_ec_point_format_name(int format);
+
+
+typedef enum {
+	TLS_curve_type_explicit_prime		= 1,
+	TLS_curve_type_explicit_char2		= 2,
+	TLS_curve_type_named_curve		= 3,
+} TLS_CURVE_TYPE;
+
+const char *tls_curve_type_name(int type);
+
+
+// 与其支持v2,还不如直接修改v2,让v2和v3兼容
+
+typedef enum {
+	TLS_curve_secp256k1			= 22,
+	TLS_curve_secp256r1			= 23,
+	TLS_curve_secp384r1			= 24,
+	TLS_curve_secp521r1			= 25,
+	TLS_curve_brainpoolp256r1		= 26,
+	TLS_curve_brainpoolp384r1		= 27,
+	TLS_curve_brainpoolp512r1		= 28,
+	TLS_curve_x25519			= 29,
+	TLS_curve_x448				= 30,
+	TLS_curve_brainpoolp256r1tls13		= 31,
+	TLS_curve_brainpoolp384r1tls13		= 32,
+	TLS_curve_brainpoolp512r1tls13		= 33,
+	TLS_curve_sm2p256v1			= 41, // GmSSLv2: 30
+} TLS_NAMED_CURVE;
+
+const char *tls_named_curve_name(int curve);
+
+
+typedef enum {
+	TLS_sig_rsa_pkcs1_sha1			= 0x0201,
+	TLS_sig_ecdsa_sha1			= 0x0203,
+	TLS_sig_rsa_pkcs1_sha256		= 0x0401,
+	TLS_sig_ecdsa_secp256r1_sha256		= 0x0403,
+	TLS_sig_rsa_pkcs1_sha256_legacy		= 0x0420,
+	TLS_sig_rsa_pkcs1_sha384		= 0x0501,
+	TLS_sig_ecdsa_secp384r1_sha384		= 0x0503,
+	TLS_sig_rsa_pkcs1_sha384_legacy		= 0x0520,
+	TLS_sig_rsa_pkcs1_sha512		= 0x0601,
+	TLS_sig_ecdsa_secp521r1_sha512		= 0x0603,
+	TLS_sig_rsa_pkcs1_sha512_legacy		= 0x0620,
+	TLS_sig_sm2sig_sm3			= 0x0708, // GmSSLv2: 0x0707
+	TLS_sig_rsa_pss_rsae_sha256		= 0x0804,
+	TLS_sig_rsa_pss_rsae_sha384		= 0x0805,
+	TLS_sig_rsa_pss_rsae_sha512		= 0x0806,
+	TLS_sig_ed25519				= 0x0807,
+	TLS_sig_ed448				= 0x0808,
+	TLS_sig_rsa_pss_pss_sha256		= 0x0809,
+	TLS_sig_rsa_pss_pss_sha384		= 0x080A,
+	TLS_sig_rsa_pss_pss_sha512		= 0x080B,
+	TLS_sig_ecdsa_brainpoolP256r1tls13_sha256 = 0x081A,
+	TLS_sig_ecdsa_brainpoolP384r1tls13_sha384 = 0x081B,
+	TLS_sig_ecdsa_brainpoolP512r1tls13_sha512 = 0x081C,
+} TLS_SIGNATURE_SCHEME;
+
+const char *tls_signature_scheme_name(int scheme);
+
+
+typedef enum {
+	TLS_change_cipher_spec = 1,
+} TLS_CHANGE_CIPHER_SPEC_TYPE;
+
+
+typedef enum {
+	TLS_alert_level_warning = 1,
+	TLS_alert_level_fatal = 2,
+} TLS_ALERT_LEVEL;
+
+const char *tls_alert_level_name(int level);
+
+
+typedef enum {
+	TLS_alert_close_notify			= 0,
+	TLS_alert_unexpected_message		= 10,
+	TLS_alert_bad_record_mac		= 20,
+	TLS_alert_decryption_failed		= 21,
+	TLS_alert_record_overflow		= 22,
+	TLS_alert_decompression_failure		= 30,
+	TLS_alert_handshake_failure		= 40,
+	TLS_alert_no_certificate		= 41,
+	TLS_alert_bad_certificate		= 42,
+	TLS_alert_unsupported_certificate	= 43,
+	TLS_alert_certificate_revoked		= 44,
+	TLS_alert_certificate_expired		= 45,
+	TLS_alert_certificate_unknown		= 46,
+	TLS_alert_illegal_parameter		= 47,
+	TLS_alert_unknown_ca			= 48,
+	TLS_alert_access_denied			= 49,
+	TLS_alert_decode_error			= 50,
+	TLS_alert_decrypt_error			= 51,
+	TLS_alert_export_restriction		= 60,
+	TLS_alert_protocol_version		= 70,
+	TLS_alert_insufficient_security		= 71,
+	TLS_alert_internal_error		= 80,
+	TLS_alert_user_canceled			= 90,
+	TLS_alert_no_renegotiation		= 100,
+	TLS_alert_unsupported_extension		= 110,
+	TLS_alert_unsupported_site2site		= 200,
+	TLS_alert_no_area			= 201,
+	TLS_alert_unsupported_areatype		= 202,
+	TLS_alert_bad_ibcparam			= 203,
+	TLS_alert_unsupported_ibcparam		= 204,
+	TLS_alert_identity_need			= 205,
+} TLS_ALERT_DESCRIPTION;
+
+const char *tls_alert_description_text(int description);
+
+
+int tls_prf(const uint8_t *secret, size_t secretlen, const char *label,
+	const uint8_t *seed, size_t seedlen,
+	const uint8_t *more, size_t morelen,
+	size_t outlen, uint8_t *out);
+int tls13_hkdf_extract(const DIGEST *digest, const uint8_t salt[32], const uint8_t in[32], uint8_t out[32]);
+int tls13_hkdf_expand_label(const DIGEST *digest, const uint8_t secret[32],
+	const char *label, const uint8_t *context, size_t context_len,
+	size_t outlen, uint8_t *out);
+int tls13_derive_secret(const uint8_t secret[32], const char *label, const DIGEST_CTX *dgst_ctx, uint8_t out[32]);
+
+int tls_cbc_encrypt(const SM3_HMAC_CTX *hmac_ctx, const SM4_KEY *enc_key,
+	const uint8_t seq_num[8], const uint8_t header[5],
+	const uint8_t *in, size_t inlen, uint8_t *out, size_t *outlen);
+int tls_cbc_decrypt(const SM3_HMAC_CTX *hmac_ctx, const SM4_KEY *dec_key,
+	const uint8_t seq_num[8], const uint8_t header[5],
+	const uint8_t *in, size_t inlen, uint8_t *out, size_t *outlen);
+int tls_record_encrypt(const SM3_HMAC_CTX *hmac_ctx, const SM4_KEY *cbc_key,
+	const uint8_t seq_num[8], const uint8_t *in, size_t inlen,
+	uint8_t *out, size_t *outlen);
+int tls_record_decrypt(const SM3_HMAC_CTX *hmac_ctx, const SM4_KEY *cbc_key,
+	const uint8_t seq_num[8], const uint8_t *in, size_t inlen,
+	uint8_t *out, size_t *outlen);
+
+int tls_seq_num_incr(uint8_t seq_num[8]);
+int tls_random_generate(uint8_t random[32]);
+int tls_random_print(FILE *fp, const uint8_t random[32], int format, int indent);
+int tls_pre_master_secret_generate(uint8_t pre_master_secret[48], int protocol);
+int tls_pre_master_secret_print(FILE *fp, const uint8_t pre_master_secret[48], int format, int indent);
+
+int tls_secrets_print(FILE *fp,
+	const uint8_t *pre_master_secret, size_t pre_master_secret_len,
+	const uint8_t client_random[32], const uint8_t server_random[32],
+	const uint8_t master_secret[48],
+	const uint8_t *key_block, size_t key_block_len,
+	int format, int indent);
+
+
+typedef struct {
+	uint8_t type;
+	uint8_t protocol[2];
+	uint8_t data_length[2];
+} TLS_RECORD_HEADER;
+
+#define TLS_RECORD_HEADER_SIZE		(1 + tls_uint16_size() + tls_uint16_size())		// 5
+#define TLS_MAX_PLAINTEXT_SIZE		(1 << 14)						// 16384
+#define TLS_MAX_COMPRESSED_SIZE		((1 << 14) + 1024)					// 17408
+#define TLS_MAX_CIPHERTEXT_SIZE		((1 << 14) + 2048)					// 18432
+#define TLS_MAX_RECORD_SIZE		(TLS_RECORD_HEADER_SIZE + TLS_MAX_CIPHERTEXT_SIZE)	// 18437
+
+#define tls_record_type(record)		((record)[0])
+#define tls_record_header(record)	((record)+0)
+#define tls_record_protocol(record)	(((uint16_t)((record)[1]) << 8) | (record)[2])
+#define tls_record_data(record)		((record)+TLS_RECORD_HEADER_SIZE)
+#define tls_record_data_length(record)	(((uint16_t)((record)[3]) << 8) | (record)[4])
+#define tls_record_length(record)	(TLS_RECORD_HEADER_SIZE + tls_record_data_length(record))
+
+int tls_record_set_type(uint8_t *record, int type);
+int tls_record_set_protocol(uint8_t *record, int protocol);
+int tls_record_set_data_length(uint8_t *record, size_t length);
+int tls_record_set_data(uint8_t *record, const uint8_t *data, size_t datalen);
+
+// 握手消息ServerKeyExchange, ClientKeyExchange的解析依赖当前密码套件
+#define tls_format_set_cipher_suite(fmt,cipher)	do {(fmt)|=((cipher)<<8);} while (0)
+int tls_record_print(FILE *fp, const uint8_t *record,  size_t recordlen, int format, int indent);
+int tlcp_record_print(FILE *fp, const uint8_t *record,  size_t recordlen, int format, int indent);
+
+int tls_record_send(const uint8_t *record, size_t recordlen, tls_socket_t sock);
+int tls_record_recv(uint8_t *record, size_t *recordlen, tls_socket_t sock);
+int tls12_record_recv(uint8_t *record, size_t *recordlen, tls_socket_t sock);
+
+
+// Handshake
+typedef struct {
+	uint8_t type;
+	uint8_t length[3];
+} TLS_HANDSHAKE_HEADER;
+
+#define TLS_HANDSHAKE_HEADER_SIZE	4
+#define TLS_MAX_HANDSHAKE_DATA_SIZE 	(TLS_MAX_PLAINTEXT_SIZE - TLS_HANDSHAKE_HEADER_SIZE)
+
+#define tls_handshake_data(p)		((p) + TLS_HANDSHAKE_HEADER_SIZE)
+//#define tls_handshake_data_length(p)
+
+
+int tls_record_set_handshake(uint8_t *record, size_t *recordlen,
+	int type, const uint8_t *data, size_t datalen);
+int tls_record_get_handshake(const uint8_t *record,
+	int *type, const uint8_t **data, size_t *datalen);
+int tls_handshake_print(FILE *fp, const uint8_t *handshake, size_t handshakelen, int format, int indent);
+
+// HelloRequest
+int tls_hello_request_print(FILE *fp, const uint8_t *data, size_t datalen, int format, int indent);
+
+// ClientHello, ServerHello
+#define TLS_MIN_SESSION_ID_SIZE		0
+#define TLS_MAX_SESSION_ID_SIZE		32
+
+int tls_record_set_handshake_client_hello(uint8_t *record, size_t *recordlen,
+	int client_protocol, const uint8_t random[32],
+	const uint8_t *session_id, size_t session_id_len,
+	const int *cipher_suites, size_t cipher_suites_count,
+	const uint8_t *exts, size_t exts_len);
+int tls_record_get_handshake_client_hello(const uint8_t *record,
+	int *client_protocol, const uint8_t **random,
+	const uint8_t **session_id, size_t *session_id_len,
+	const uint8_t **cipher_suites, size_t *cipher_suites_len,
+	const uint8_t **exts, size_t *exts_len);
+int tls_client_hello_print(FILE *fp, const uint8_t *data, size_t datalen, int format, int indent);
+
+int tls_record_set_handshake_server_hello(uint8_t *record, size_t *recordlen,
+	int server_protocol, const uint8_t random[32],
+	const uint8_t *session_id, size_t session_id_len,
+	int cipher_suite, const uint8_t *exts, size_t exts_len);
+int tls_record_get_handshake_server_hello(const uint8_t *record,
+	int *protocol, const uint8_t **random, const uint8_t **session_id, size_t *session_id_len,
+	int *cipher_suite, const uint8_t **exts, size_t *exts_len);
+int tls_server_hello_print(FILE *fp, const uint8_t *server_hello, size_t len, int format, int indent);
+
+// Extensions
+int tls_ec_point_formats_ext_to_bytes(const int *formats, size_t formats_cnt,
+	uint8_t **out, size_t *outlen);
+int tls_process_client_ec_point_formats(const uint8_t *ext_data, size_t ext_datalen,
+	uint8_t **out, size_t *outlen);
+int tls_process_server_ec_point_formats(const uint8_t *ext_data, size_t ext_datalen);
+
+int tls_supported_groups_ext_to_bytes(const int *groups, size_t groups_cnt,
+	uint8_t **out, size_t *outlen);
+int tls_process_client_supported_groups(const uint8_t *ext_data, size_t ext_datalen,
+	uint8_t **out, size_t *outlen);
+int tls_process_server_supported_groups(const uint8_t *ext_data, size_t ext_datalen);
+
+int tls_signature_algorithms_ext_to_bytes_ex(int ext_type, const int *algs, size_t algs_cnt,
+	uint8_t **out, size_t *outlen);
+int tls_signature_algorithms_ext_to_bytes(const int *algs, size_t algs_cnt,
+	uint8_t **out, size_t *outlen);
+int tls13_signature_algorithms_cert_ext_to_bytes(const int *algs, size_t algs_cnt,
+	uint8_t **out, size_t *outlen);
+int tls_process_client_signature_algorithms(const uint8_t *ext_data, size_t ext_datalen,
+	uint8_t **out, size_t *outlen);
+int tls_process_server_signature_algors(const uint8_t *ext_data, size_t ext_datalen);
+
+int tls13_supported_versions_ext_to_bytes(int handshake_type, const int *protos, size_t protos_cnt,
+	uint8_t **out, size_t *outlen);
+int tls13_process_client_supported_versions(const uint8_t *ext_data, size_t ext_datalen,
+	uint8_t **out, size_t *outlen);
+
+int tls13_process_server_supported_versions(const uint8_t *ext_data, size_t ext_datalen);
+
+int tls13_key_share_entry_to_bytes(const SM2_POINT *point, uint8_t **out, size_t *outlen);
+int tls13_client_key_share_ext_to_bytes(const SM2_POINT *point, uint8_t **out, size_t *outlen);
+int tls13_server_key_share_ext_to_bytes(const SM2_POINT *point, uint8_t **out, size_t *outlen);
+int tls13_process_client_key_share(const uint8_t *ext_data, size_t ext_datalen,
+	const SM2_KEY *server_ecdhe_key, SM2_POINT *client_ecdhe_public,
+	uint8_t **out, size_t *outlen);
+int tls13_process_server_key_share(const uint8_t *ext_data, size_t ext_datalen, SM2_POINT *point);
+
+
+int tls13_certificate_authorities_ext_to_bytes(const uint8_t *ca_names, size_t ca_names_len,
+	uint8_t **out, size_t *outlen);
+
+int tls_ext_from_bytes(int *type, const uint8_t **data, size_t *datalen, const uint8_t **in, size_t *inlen);
+int tls_process_client_exts(const uint8_t *exts, size_t extslen, uint8_t *out, size_t *outlen, size_t maxlen);
+int tls_process_server_exts(const uint8_t *exts, size_t extslen,
+	int *ec_point_format, int *supported_group, int *signature_algor);
+
+
+// Certificate
+int tls_record_set_handshake_certificate(uint8_t *record, size_t *recordlen,
+	const uint8_t *certs, size_t certslen);
+// 这个函数比较特殊,是直接解析了证书链,而不是返回指针
+// 应该提供一个独立的解析函数来解析TLS的证书链
+int tls_record_get_handshake_certificate(const uint8_t *record, uint8_t *certs, size_t *certslen);
+
+// ServerKeyExchange
+int tls_server_key_exchange_print(FILE *fp, const uint8_t *ske, size_t skelen, int format, int indent);
+
+#define TLS_MAX_SIGNATURE_SIZE	SM2_MAX_SIGNATURE_SIZE
+int tls_sign_server_ecdh_params(const SM2_KEY *server_sign_key,
+	const uint8_t client_random[32], const uint8_t server_random[32],
+	int curve, const SM2_POINT *point, uint8_t *sig, size_t *siglen);
+int tls_verify_server_ecdh_params(const SM2_KEY *server_sign_key,
+	const uint8_t client_random[32], const uint8_t server_random[32],
+	int curve, const SM2_POINT *point, const uint8_t *sig, size_t siglen);
+int tls_record_set_handshake_server_key_exchange_ecdhe(uint8_t *record, size_t *recordlen,
+	int curve, const SM2_POINT *point, const uint8_t *sig, size_t siglen);
+int tls_record_get_handshake_server_key_exchange_ecdhe(const uint8_t *record,
+	int *curve, SM2_POINT *point, const uint8_t **sig, size_t *siglen);
+int tls_server_key_exchange_ecdhe_print(FILE *fp, const uint8_t *data, size_t datalen,
+	int format, int indent);
+
+int tlcp_record_set_handshake_server_key_exchange_pke(uint8_t *record, size_t *recordlen,
+	const uint8_t *sig, size_t siglen);
+int tlcp_record_get_handshake_server_key_exchange_pke(const uint8_t *record,
+	const uint8_t **sig, size_t *siglen);
+int tlcp_server_key_exchange_pke_print(FILE *fp, const uint8_t *sig, size_t siglen, int format, int indent);
+
+
+
+// CertificateRequest
+#define TLS_MAX_CERTIFICATE_TYPES	256
+#define TLS_MAX_CA_NAMES_SIZE		(TLS_MAX_HANDSHAKE_DATA_SIZE - tls_uint8_size() - tls_uint16_size())
+
+int tls_authorities_from_certs(uint8_t *ca_names, size_t *ca_names_len, size_t maxlen, const uint8_t *certs, size_t certslen);
+int tls_authorities_issued_certificate(const uint8_t *ca_names, size_t ca_namelen, const uint8_t *certs, size_t certslen);
+int tls_cert_types_accepted(const uint8_t *types, size_t types_len, const uint8_t *client_certs, size_t client_certs_len);
+
+int tls_record_set_handshake_certificate_request(uint8_t *record, size_t *recordlen,
+	const uint8_t *cert_types, size_t cert_types_len,
+	const uint8_t *ca_names, size_t ca_names_len);
+int tls_record_get_handshake_certificate_request(const uint8_t *record,
+	const uint8_t **cert_types, size_t *cert_types_len,
+	const uint8_t **ca_names, size_t *ca_names_len);
+int tls_certificate_request_print(FILE *fp, const uint8_t *data, size_t datalen, int format, int indent);
+
+
+// ServerHelloDone
+int tls_record_set_handshake_server_hello_done(uint8_t *record, size_t *recordlen);
+int tls_record_get_handshake_server_hello_done(const uint8_t *record);
+int tls_server_hello_done_print(FILE *fp, const uint8_t *data, size_t datalen, int format, int indent);
+
+// ClientKeyExchange
+int tls_record_set_handshake_client_key_exchange_pke(uint8_t *record, size_t *recordlen,
+	const uint8_t *enced_pms, size_t enced_pms_len);
+int tls_record_get_handshake_client_key_exchange_pke(const uint8_t *record,
+	const uint8_t **enced_pms, size_t *enced_pms_len);
+int tls_client_key_exchange_pke_print(FILE *fp, const uint8_t *cke, size_t ckelen, int format, int indent);
+int tls_client_key_exchange_print(FILE *fp, const uint8_t *cke, size_t ckelen, int format, int indent);
+
+int tls_record_set_handshake_client_key_exchange_ecdhe(uint8_t *record, size_t *recordlen,
+	const SM2_POINT *point); // 这里不应该支持SM2_POINT类型						
+int tls_record_get_handshake_client_key_exchange_ecdhe(const uint8_t *record, SM2_POINT *point);			
+int tls_client_key_exchange_ecdhe_print(FILE *fp, const uint8_t *data, size_t datalen,
+	int format, int indent);
+
+// CertificateVerify
+int tls_record_set_handshake_certificate_verify(uint8_t *record, size_t *recordlen,
+	const uint8_t *sig, size_t siglen);
+int tls_record_get_handshake_certificate_verify(const uint8_t *record,
+	const uint8_t **sig, size_t *siglen);
+int tls_certificate_verify_print(FILE *fp, const uint8_t *p, size_t len, int format, int indent);
+
+typedef enum {
+	TLS_client_verify_client_hello		= 0,
+	TLS_client_verify_server_hello		= 1,
+	TLS_client_verify_server_certificate	= 2,
+	TLS_client_verify_server_key_exchange	= 3,
+	TLS_client_verify_cert_request		= 4,
+	TLS_client_verify_server_hello_done	= 5,
+	TLS_client_verify_client_certificate	= 6,
+	TLS_client_verify_client_key_exchange	= 7,
+} TLS_CLIENT_VERIFY_INDEX;
+
+typedef struct {
+	TLS_CLIENT_VERIFY_INDEX index;
+	uint8_t *handshake[8]; // Record data only, no record header
+	size_t handshake_len[8];
+} TLS_CLIENT_VERIFY_CTX;
+
+int tls_client_verify_init(TLS_CLIENT_VERIFY_CTX *ctx);
+int tls_client_verify_update(TLS_CLIENT_VERIFY_CTX *ctx, const uint8_t *handshake, size_t handshake_len);
+int tls_client_verify_finish(TLS_CLIENT_VERIFY_CTX *ctx, const uint8_t *sig, size_t siglen, const SM2_KEY *public_key);
+void tls_client_verify_cleanup(TLS_CLIENT_VERIFY_CTX *ctx);
+
+// Finished
+// FIXME: 支持TLS 1.3 提供MIN, MAX或TLS12, TLS13, TLCP...
+#define TLS_VERIFY_DATA_SIZE 12 // TLS 1.3或者其他版本支持更长的verify_data
+#define TLS_FINISHED_RECORD_SIZE	(TLS_RECORD_HEADER_SIZE + TLS_HANDSHAKE_HEADER_SIZE + TLS_VERIFY_DATA_SIZE) // 21
+#define TLS_MAX_PADDING_SIZE		(1 + 255)
+#define TLS_MAC_SIZE			SM3_HMAC_SIZE
+#define TLS_FINISHED_RECORD_BUF_SIZE	(TLS_FINISHED_RECORD_SIZE + TLS_MAC_SIZE + TLS_MAX_PADDING_SIZE) // 309
+
+
+int tls_record_set_handshake_finished(uint8_t *record, size_t *recordlen,
+	const uint8_t *verify_data, size_t verify_data_len);
+int tls_record_get_handshake_finished(const uint8_t *record,
+	const uint8_t **verify_data, size_t *verify_data_len);
+int tls_finished_print(FILE *fp, const uint8_t *a, size_t len, int format, int indent);
+
+
+// Alert
+typedef struct {
+	uint8_t level;
+	uint8_t description;
+} TLS_ALERT;
+
+#define TLS_ALERT_RECORD_SIZE (TLS_RECORD_HEADER_SIZE + 2)
+
+int tls_record_set_alert(uint8_t *record, size_t *recordlen, int alert_level, int alert_description);
+int tls_record_get_alert(const uint8_t *record, int *alert_level, int *alert_description);
+int tls_alert_print(FILE *fp, const uint8_t *data, size_t datalen, int format, int indent);
+
+
+// ChangeCipherSpec
+typedef struct {
+	uint8_t type;
+} TLS_CHANGE_CIPHER_SPEC;
+
+const char *tls_change_cipher_spec_text(int change_cipher_spec);
+int tls_change_cipher_spec_print(FILE *fp, const uint8_t *data, size_t datalen, int format, int indent);
+int tls_record_set_change_cipher_spec(uint8_t *record, size_t *recordlen);
+int tls_record_get_change_cipher_spec(const uint8_t *record);
+
+// ApplicationData
+int tls_record_set_application_data(uint8_t *record, size_t *recordlen,
+	const uint8_t *data, size_t datalen);
+int tls_record_get_application_data(uint8_t *record,
+	const uint8_t **data, size_t *datalen);
+int tls_application_data_print(FILE *fp, const uint8_t *data, size_t datalen, int format, int indent);
+
+
+
+enum {
+	TLS_server_mode = 0,
+	TLS_client_mode = 1,
+};
+
+#define TLS_MAX_CIPHER_SUITES_COUNT	64
+
+typedef struct {
+	int protocol;
+	int is_client;
+	int cipher_suites[TLS_MAX_CIPHER_SUITES_COUNT];
+	size_t cipher_suites_cnt;
+	uint8_t *cacerts;
+	size_t cacertslen;
+	uint8_t *certs;
+	size_t certslen;
+	SM2_KEY signkey;
+	SM2_KEY kenckey;
+	int verify_depth;
+} TLS_CTX;
+
+int tls_ctx_init(TLS_CTX *ctx, int protocol, int is_client);
+int tls_ctx_set_cipher_suites(TLS_CTX *ctx, const int *cipher_suites, size_t cipher_suites_cnt);
+int tls_ctx_set_ca_certificates(TLS_CTX *ctx, const char *cacertsfile, int depth);
+int tls_ctx_set_certificate_and_key(TLS_CTX *ctx, const char *chainfile,
+	const char *keyfile, const char *keypass);
+int tls_ctx_set_tlcp_server_certificate_and_keys(TLS_CTX *ctx, const char *chainfile,
+	const char *signkeyfile, const char *signkeypass,
+	const char *kenckeyfile, const char *kenckeypass);
+void tls_ctx_cleanup(TLS_CTX *ctx);
+
+
+
+#define TLS_MAX_CERTIFICATES_SIZE	2048
+#define TLS_DEFAULT_VERIFY_DEPTH	4
+#define TLS_MAX_VERIFY_DEPTH		5
+
+
+typedef struct {
+	int protocol;
+	int is_client;
+	int cipher_suites[TLS_MAX_CIPHER_SUITES_COUNT];
+	size_t cipher_suites_cnt;
+	tls_socket_t sock;
+
+	uint8_t enced_record[TLS_MAX_RECORD_SIZE];
+	size_t enced_record_len;
+
+
+	uint8_t record[TLS_MAX_RECORD_SIZE];
+
+	// 其实这个就不太对了,还是应该有一个完整的密文记录
+	uint8_t databuf[TLS_MAX_PLAINTEXT_SIZE];
+	uint8_t *data;
+	size_t datalen;
+
+	int cipher_suite;
+	uint8_t session_id[32];
+	size_t session_id_len;
+	uint8_t server_certs[TLS_MAX_CERTIFICATES_SIZE]; // 动态的可能会好一点
+	size_t server_certs_len;
+	uint8_t client_certs[TLS_MAX_CERTIFICATES_SIZE];
+	size_t client_certs_len;
+	uint8_t ca_certs[2048];
+	size_t ca_certs_len;
+
+	SM2_KEY sign_key;
+	SM2_KEY kenc_key;
+
+	int verify_result;
+
+	uint8_t master_secret[48];
+	uint8_t key_block[96];
+
+	SM3_HMAC_CTX client_write_mac_ctx;
+	SM3_HMAC_CTX server_write_mac_ctx;
+	SM4_KEY client_write_enc_key;
+	SM4_KEY server_write_enc_key;
+	uint8_t client_seq_num[8];
+	uint8_t server_seq_num[8];
+
+	uint8_t client_write_iv[12]; // tls13
+	uint8_t server_write_iv[12]; // tls13
+	BLOCK_CIPHER_KEY client_write_key;
+	BLOCK_CIPHER_KEY server_write_key;
+
+} TLS_CONNECT;
+
+
+#define TLS_MAX_EXTENSIONS_SIZE 512 // 这个应该再考虑一下数值,是否可以用其他的缓冲区装载?
+
+
+int tls_init(TLS_CONNECT *conn, const TLS_CTX *ctx);
+int tls_set_socket(TLS_CONNECT *conn, tls_socket_t sock);
+int tls_do_handshake(TLS_CONNECT *conn);
+int tls_send(TLS_CONNECT *conn, const uint8_t *in, size_t inlen, size_t *sentlen);
+int tls_recv(TLS_CONNECT *conn, uint8_t *out, size_t outlen, size_t *recvlen);
+int tls_shutdown(TLS_CONNECT *conn);
+void tls_cleanup(TLS_CONNECT *conn);
+
+int tlcp_do_connect(TLS_CONNECT *conn);
+int tlcp_do_accept(TLS_CONNECT *conn);
+int tls12_do_connect(TLS_CONNECT *conn);
+int tls12_do_accept(TLS_CONNECT *conn);
+
+
+#define TLS13_SM2_ID		"TLSv1.3+GM+Cipher+Suite"
+#define TLS13_SM2_ID_LENGTH	(sizeof(TLS13_SM2_ID)-1)
+
+int tls13_do_connect(TLS_CONNECT *conn);
+int tls13_do_accept(TLS_CONNECT *conn);
+
+int tls_send_alert(TLS_CONNECT *conn, int alert);
+int tls_send_warning(TLS_CONNECT *conn, int alert);
+
+int tls13_send(TLS_CONNECT *conn, const uint8_t *data, size_t datalen, size_t *sentlen);
+int tls13_recv(TLS_CONNECT *conn, uint8_t *out, size_t outlen, size_t *recvlen);
+
+
+int tls13_connect(TLS_CONNECT *conn, const char *hostname, int port, FILE *server_cacerts_fp,
+	FILE *client_certs_fp, const SM2_KEY *client_sign_key);
+int tls13_accept(TLS_CONNECT *conn, int port,
+	FILE *server_certs_fp, const SM2_KEY *server_sign_key,
+	FILE *client_cacerts_fp);
+
+
+int tls13_supported_versions_ext_print(FILE *fp, int fmt, int ind, int handshake_type, const uint8_t *data, size_t datalen);
+int tls13_key_share_ext_print(FILE *fp, int fmt, int ind, int handshake_type, const uint8_t *data, size_t datalen);
+
+
+int tls_process_client_hello_exts(const uint8_t *exts, size_t extslen, uint8_t *out, size_t *outlen, size_t maxlen);
+int tls_process_server_hello_exts(const uint8_t *exts, size_t extslen,
+	int *ec_point_format, int *supported_group, int *signature_algor);
+
+
+int tls13_encrypted_extensions_print(FILE *fp, int fmt, int ind, const uint8_t *data, size_t datalen);
+
+int tls13_extension_print(FILE *fp, int fmt, int ind,
+	int handshake_type, int ext_type, const uint8_t *ext_data, size_t ext_datalen);
+int tls13_extensions_print(FILE *fp, int fmt, int ind,
+	int handshake_type, const uint8_t *exts, size_t extslen);
+
+int tls13_certificate_print(FILE *fp, int fmt, int ind, const uint8_t *cert, size_t certlen);
+int tls13_certificate_request_print(FILE *fp, int fmt, int ind, const uint8_t *cert, size_t certlen);
+int tls13_certificate_verify_print(FILE *fp, int fmt, int ind, const uint8_t *d, size_t dlen);
+int tls13_record_print(FILE *fp, int format, int indent, const uint8_t *record, size_t recordlen);
+
+
+int tls13_gcm_encrypt(const BLOCK_CIPHER_KEY *key, const uint8_t iv[12],
+	const uint8_t seq_num[8], int record_type,
+	const uint8_t *in, size_t inlen, size_t padding_len, // TLSInnerPlaintext.content
+	uint8_t *out, size_t *outlen); // TLSCiphertext.encrypted_record
+int tls13_gcm_decrypt(const BLOCK_CIPHER_KEY *key, const uint8_t iv[12],
+	const uint8_t seq_num[8], const uint8_t *in, size_t inlen,
+	int *record_type, uint8_t *out, size_t *outlen);
+
+
+#ifdef TLS_DEBUG
+#	define tls_trace(s) fprintf(stderr,(s))
+#	define tls_record_trace(fp,rec,reclen,fmt,ind)  tls_record_print(fp,rec,reclen,fmt,ind)
+#	define tlcp_record_trace(fp,rec,reclen,fmt,ind)  tlcp_record_print(fp,rec,reclen,fmt,ind)
+#	define tls12_record_trace(fp,rec,reclen,fmt,ind)  tls12_record_print(fp,rec,reclen,fmt,ind)
+#	define tls13_record_trace(fp,rec,reclen,fmt,ind)  tls13_record_print(fp,fmt,ind,rec,reclen)
+#else
+#	define tls_trace(s)
+#	define tls_record_trace(fp,rec,reclen,fmt,ind)
+#	define tlcp_record_trace(fp,rec,reclen,fmt,ind)
+#	define tls12_record_trace(fp,rec,reclen,fmt,ind)
+#	define tls13_record_trace(fp,rec,reclen,fmt,ind)
+#endif
+
+
+#ifdef  __cplusplus
+}
+#endif
+#endif

+ 37 - 0
components/gmssl/include/gmssl/version.h

@@ -0,0 +1,37 @@
+/*
+ *  Copyright 2014-2023 The GmSSL Project. All Rights Reserved.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the License); you may
+ *  not use this file except in compliance with the License.
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ */
+
+
+
+#ifndef GMSSL_VERSION_H
+#define GMSSL_VERSION_H
+
+#include <gmssl/api.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+Version Public API
+
+	gmssl_version_num
+	gmssl_version_str
+*/
+
+#define GMSSL_VERSION_NUM	30100
+#define GMSSL_VERSION_STR	"GmSSL 3.1.0"
+
+_gmssl_export int gmssl_version_num(void);
+_gmssl_export const char *gmssl_version_str(void);
+
+#ifdef __cplusplus
+}
+#endif
+#endif

+ 16 - 0
components/gmssl/include/gmssl/x509.h

@@ -0,0 +1,16 @@
+/*
+ *  Copyright 2014-2023 The GmSSL Project. All Rights Reserved.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the License); you may
+ *  not use this file except in compliance with the License.
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ */
+
+
+#ifndef GMSSL_X509_H
+#define GMSSL_X509_H
+
+#include <gmssl/x509_cer.h>
+
+#endif

+ 68 - 0
components/gmssl/include/gmssl/x509_alg.h

@@ -0,0 +1,68 @@
+/*
+ *  Copyright 2014-2022 The GmSSL Project. All Rights Reserved.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the License); you may
+ *  not use this file except in compliance with the License.
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ */
+
+
+#ifndef GMSSL_X509_ALG_H
+#define GMSSL_X509_ALG_H
+
+
+#include <time.h>
+#include <string.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <gmssl/sm2.h>
+#include <gmssl/oid.h>
+#include <gmssl/asn1.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+AlgorithmIdentifier ::= SEQUENCE {
+	algorithm	OBJECT IDENTIFIER,
+	parameters	ANY }
+*/
+
+const char *x509_digest_algor_name(int oid);
+int x509_digest_algor_from_name(const char *name);
+int x509_digest_algor_from_der(int *oid, const uint8_t **in, size_t *inlen);
+int x509_digest_algor_to_der(int oid, uint8_t **out, size_t *outlen);
+int x509_digest_algor_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen);
+
+const char *x509_encryption_algor_name(int oid);
+int x509_encryption_algor_from_name(const char *name);
+int x509_encryption_algor_from_der(int *oid, const uint8_t **iv, size_t *ivlen, const uint8_t **in, size_t *inlen);
+int x509_encryption_algor_to_der(int oid, const uint8_t *iv, size_t ivlen, uint8_t **out, size_t *outlen);
+int x509_encryption_algor_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen);
+
+const char *x509_signature_algor_name(int oid);
+int x509_signature_algor_from_name(const char *name);
+int x509_signature_algor_from_der(int *oid, const uint8_t **in, size_t *inlen);
+int x509_signature_algor_to_der(int oid, uint8_t **out, size_t *outlen);
+int x509_signature_algor_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen);
+
+const char *x509_public_key_encryption_algor_name(int oid);
+int x509_public_key_encryption_algor_from_name(const char *name);
+int x509_public_key_encryption_algor_from_der(int *oid, const uint8_t **params, size_t *params_len, const uint8_t **in, size_t *inlen);
+int x509_public_key_encryption_algor_to_der(int oid, uint8_t **out, size_t *outlen);
+int x509_public_key_encryption_algor_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen);
+
+const char *x509_public_key_algor_name(int oid);
+int x509_public_key_algor_from_name(const char *name);
+int x509_public_key_algor_to_der(int oid, int curve, uint8_t **out, size_t *outlen);
+int x509_public_key_algor_from_der(int *oid, int *curve_or_null, const uint8_t **in, size_t *inlen);
+int x509_public_key_algor_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen);
+
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif

+ 390 - 0
components/gmssl/include/gmssl/x509_cer.h

@@ -0,0 +1,390 @@
+/*
+ *  Copyright 2014-2023 The GmSSL Project. All Rights Reserved.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the License); you may
+ *  not use this file except in compliance with the License.
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ */
+
+
+#ifndef GMSSL_X509_CER_H
+#define GMSSL_X509_CER_H
+
+
+#include <time.h>
+#include <string.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <gmssl/sm2.h>
+#include <gmssl/oid.h>
+#include <gmssl/asn1.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+enum X509_Version {
+	X509_version_v1 = 0,
+	X509_version_v2 = 1,
+	X509_version_v3 = 2,
+};
+
+const char *x509_version_name(int version);
+int x509_explicit_version_to_der(int index, int version, uint8_t **out, size_t *outlen);
+int x509_explicit_version_from_der(int index, int *version, const uint8_t **in, size_t *inlen);
+
+/*
+Time ::= CHOICE {
+	utcTime		UTCTime,
+	generalTime	GeneralizedTime }
+*/
+#define X509_MAX_UTC_TIME            2524607999 // "20491231235959Z"
+#define X509_MAX_GENERALIZED_TIME  253402300799 // "99991231235959Z"
+int x509_time_to_der(time_t a, uint8_t **out, size_t *outlen);
+int x509_time_from_der(time_t *a, const uint8_t **in, size_t *inlen);
+
+/*
+Validity ::= SEQUENCE {
+	notBefore	Time,
+	notAfter	Time }
+*/
+#define X509_VALIDITY_MIN_DAYS 1
+#define X509_VALIDITY_MAX_DAYS 3653
+#define X509_VALIDITY_MAX_SECONDS (X509_VALIDITY_MAX_DAYS * 86400)
+int x509_validity_add_days(time_t *not_after, time_t not_before, int days);
+int x509_validity_to_der(time_t not_before, time_t not_after, uint8_t **out, size_t *outlen);
+int x509_validity_from_der(time_t *not_before, time_t *not_after, const uint8_t **in, size_t *inlen);
+int x509_validity_check(time_t not_before, time_t not_after, time_t now, int max_secs);
+int x509_validity_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen);
+
+/*
+DirectoryString or DirectoryName
+
+DirectoryName ::= CHOICE {
+	teletexString		TeletexString	(SIZE (1..MAX)),
+	printableString		PrintableString	(SIZE (1..MAX)),
+	universalString		UniversalString	(SIZE (1..MAX)),
+	utf8String		UTF8String	(SIZE (1..MAX)),
+	bmpString		BMPString	(SIZE (1..MAX)),
+}
+*/
+int x509_directory_name_check(int tag, const uint8_t *d, size_t dlen);
+int x509_directory_name_check_ex(int tag, const uint8_t *d, size_t dlen, size_t minlen, size_t maxlen);
+int x509_directory_name_to_der(int tag, const uint8_t *d, size_t dlen, uint8_t **out, size_t *outlen);
+int x509_directory_name_from_der(int *tag, const uint8_t **d, size_t *dlen, const uint8_t **in, size_t *inlen);
+int x509_explicit_directory_name_to_der(int index, int tag, const uint8_t *d, size_t dlen, uint8_t **out, size_t *outlen);
+int x509_explicit_directory_name_from_der(int index, int *tag, const uint8_t **d, size_t *dlen, const uint8_t **in, size_t *inlen);
+int x509_directory_name_print(FILE *fp, int fmt, int ind, const char *label, int tag, const uint8_t *d, size_t dlen);
+
+/*
+AttributeTypeAndValue ::= SEQUENCE {
+	type OBJECT IDENTIFIER,
+	value ANY -- DEFINED BY AttributeType }
+
+id-at
+	OID_at_name			name			DirectoryName		1..ub-name
+	OID_at_surname			surname			DirectoryName		1..ub-name
+	OID_at_given_name		givenName		DirectoryName		1..ub-name
+	OID_at_initials			initials		DirectoryName		1..ub-name
+	OID_at_generation_qualifier	generationQualifier	DirectoryName		1..ub-name
+	OID_at_common_name		commonName		DirectoryName		1..ub-common-name
+	OID_at_locality_name		localityName		DirectoryName		1..ub-locality-name
+	OID_at_state_or_province_name	stateOrProvinceName	DirectoryName		1..ub-state-name
+	OID_at_organization_name	organizationName	DirectoryName		1..ub-organization-name
+	OID_at_organizational_unit_name	organizationalUnitName	DirectoryName		1..ub-organizational-unit-name
+	OID_at_title			title			DirectoryName		1..ub-title
+	OID_at_dn_qualifier		dnQualifier		PrintableString		N/A
+	OID_at_country_name		countryName		PrintableString		2..2
+	OID_at_serial_number		serialNumber		PrintableString		1..ub-serial-number
+	OID_at_pseudonym		pseudonym		DirectoryName		1..ub-pseudonym
+	OID_domain_component		domainComponent		IA5String		N/A
+*/
+const char *x509_name_type_name(int oid);
+int x509_name_type_from_name(const char *name);
+int x509_name_type_from_der(int *oid, const uint8_t **in, size_t *inlen);
+int x509_name_type_to_der(int oid, uint8_t **out, size_t *outlen);
+
+#define X509_ub_name 32768
+#define X509_ub_common_name 64
+#define X509_ub_locality_name 128
+#define X509_ub_state_name 128
+#define X509_ub_organization_name 64
+#define X509_ub_organizational_unit_name 64
+#define X509_ub_title 64
+#define X509_ub_serial_number 64
+#define X509_ub_pseudonym 128
+
+int x509_attr_type_and_value_check(int oid, int tag, const uint8_t *val, size_t vlen);
+int x509_attr_type_and_value_to_der(int oid, int tag, const uint8_t *val, size_t vlen, uint8_t **out, size_t *outlen);
+int x509_attr_type_and_value_from_der(int *oid, int *tag, const uint8_t **val, size_t *vlen, const uint8_t **in, size_t *inlen);
+int x509_attr_type_and_value_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen);
+
+/*
+RelativeDistinguishedName ::= SET SIZE (1..MAX) OF AttributeTypeAndValue
+*/
+int x509_rdn_to_der(int oid, int tag, const uint8_t *val, size_t vlen, const uint8_t *more, size_t mlen, uint8_t **out, size_t *outlen);
+int x509_rdn_from_der(int *oid, int *tag, const uint8_t **val, size_t *vlen, const uint8_t **more, size_t *mlen, const uint8_t **in, size_t *inlen);
+int x509_rdn_check(const uint8_t *d, size_t dlen);
+int x509_rdn_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen);
+
+/*
+Name ::= SEQUENCE OF RelativeDistinguishedName
+*/
+int x509_name_add_rdn(uint8_t *d, size_t *dlen, size_t maxlen, int oid, int tag, const uint8_t *val, size_t vlen, const uint8_t *more, size_t mlen);
+int x509_name_add_country_name(uint8_t *d, size_t *dlen, size_t maxlen, const char val[2] ); // val: PrintableString SIZE(2)
+int x509_name_add_state_or_province_name(uint8_t *d, size_t *dlen, size_t maxlen, int tag, const uint8_t *val, size_t vlen);
+int x509_name_add_locality_name(uint8_t *d, size_t *dlen, size_t maxlen, int tag, const uint8_t *val, size_t vlen);
+int x509_name_add_organization_name(uint8_t *d, size_t *dlen, size_t maxlen, int tag, const uint8_t *val, size_t vlen);
+int x509_name_add_organizational_unit_name(uint8_t *d, size_t *dlen, size_t maxlen, int tag, const uint8_t *val, size_t vlen);
+int x509_name_add_common_name(uint8_t *d, size_t *dlen, size_t maxlen, int tag, const uint8_t *val, size_t vlen);
+int x509_name_add_domain_component(uint8_t *d, size_t *dlen, size_t maxlen, const char *val, size_t vlen); // val: IA5String
+
+int x509_name_set(uint8_t *d, size_t *dlen, size_t maxlen,
+	const char country[2], const char *state, const char *locality,
+	const char *org, const char *org_unit, const char *common_name);
+
+#define x509_name_to_der(d,dlen,out,outlen) asn1_sequence_to_der(d,dlen,out,outlen)
+#define x509_name_from_der(d,dlen,in,inlen) asn1_sequence_from_der(d,dlen,in,inlen)
+int x509_name_check(const uint8_t *d, size_t dlen);
+int x509_name_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen);
+int x509_name_get_value_by_type(const uint8_t *d, size_t dlen, int oid, int *tag, const uint8_t **val, size_t *vlen);
+int x509_name_get_common_name(const uint8_t *d, size_t dlen, int *tag, const uint8_t **val, size_t *vlen);
+int x509_name_equ(const uint8_t *a, size_t alen, const uint8_t *b, size_t blen);
+
+int x509_names_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen);
+
+/*
+SubjectPublicKeyInfo  ::=  SEQUENCE  {
+	algorithm            AlgorithmIdentifier,
+	subjectPublicKey     BIT STRING  }
+
+algorithm.algorithm = OID_ec_public_key;
+algorithm.parameters = OID_sm2;
+subjectPublicKey = ECPoint
+*/
+#define x509_public_key_info_to_der(key,out,outlen) sm2_public_key_info_to_der(key,out,outlen)
+#define x509_public_key_info_from_der(key,in,inlen) sm2_public_key_info_from_der(key,in,inlen)
+int x509_public_key_info_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen);
+
+/*
+Extension  ::=  SEQUENCE  {
+	extnID OBJECT IDENTIFIER,
+	critical BOOLEAN DEFAULT FALSE,
+	extnValue OCTET STRING -- contains the DER encoding of an ASN.1 value
+
+id-ce:
+	OID_ce_authority_key_identifier
+	OID_ce_subject_key_identifier
+	OID_ce_key_usage
+	OID_ce_certificate_policies
+	OID_ce_policy_mappings
+	OID_ce_subject_alt_name
+	OID_ce_issuer_alt_name
+	OID_ce_subject_directory_attributes
+	OID_ce_basic_constraints
+	OID_ce_name_constraints
+	OID_ce_policy_constraints
+	OID_ce_ext_key_usage
+	OID_ce_crl_distribution_points
+	OID_ce_inhibit_any_policy
+	OID_ce_freshest_crl
+	OID_netscape_cert_comment
+*/
+const char *x509_ext_id_name(int oid);
+int x509_ext_id_from_name(const char *name);
+int x509_ext_id_from_der(int *oid, uint32_t *nodes, size_t *nodes_count, const uint8_t **in, size_t *inlen);
+int x509_ext_id_to_der(int oid, uint8_t **out, size_t *outlen);
+
+int x509_ext_to_der(int oid, int critical, const uint8_t *val, size_t vlen, uint8_t **out, size_t *outlen);
+int x509_ext_from_der(int *oid, uint32_t *nodes, size_t *nodes_cnt, int *critical, const uint8_t **val, size_t *vlen, const uint8_t **in, size_t *inlen);
+int x509_ext_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen);
+
+/*
+[3] EXPLICIT SEQUENCE OF Extension
+ */
+int x509_explicit_exts_to_der(int index, const uint8_t *d, size_t dlen, uint8_t **out, size_t *outlen);
+int x509_explicit_exts_from_der(int index, const uint8_t **d, size_t *dlen, const uint8_t **in, size_t *inlen);
+#define x509_exts_to_der(d,dlen,out,outlen) x509_explicit_exts_to_der(3,d,dlen,out,outlen)
+#define x509_exts_from_der(d,dlen,in,inlen) x509_explicit_exts_from_der(3,d,dlen,in,inlen)
+
+int x509_exts_get_ext_by_oid(const uint8_t *d, size_t dlen, int oid,
+	int *critical, const uint8_t **val, size_t *vlen);
+int x509_exts_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen);
+
+/*
+TBSCertificate ::= SEQUENCE {
+	version			[0] EXPLICIT INTEGER DEFAULT v1,
+	serialNumber		INTEGER,
+	siganture		AlgorithmIdentifier,
+	issuer			Name,
+	validity		Validity,
+	subject			Name,
+	subjectPulbicKeyInfo	SubjectPublicKeyInfo,
+	issuerUniqueID		[1] IMPLICIT BIT STRING OPTIONAL, -- If present, must be v2,v3
+	subjectUniqueID		[2] IMPLICIT BIT STRING OPTIONAL, -- If present, must be v2,v3
+	extensions		[3] EXPLICIT Extensions OPTIONAL  -- If present, must be v3 }
+*/
+#define X509_SERIAL_NUMBER_MIN_LEN	1
+#define X509_SERIAL_NUMBER_MAX_LEN	20
+#define X509_UNIQUE_ID_MIN_LEN 		32
+#define X509_UNIQUE_ID_MAX_LEN 		32
+
+int x509_tbs_cert_to_der(
+	int version,
+	const uint8_t *serial, size_t serial_len,
+	int signature_algor,
+	const uint8_t *issuer, size_t issuer_len,
+	time_t not_before, time_t not_after,
+	const uint8_t *subject, size_t subject_len,
+	const SM2_KEY *subject_public_key,
+	const uint8_t *issuer_unique_id, size_t issuer_unique_id_len,
+	const uint8_t *subject_unique_id, size_t subject_unique_id_len,
+	const uint8_t *exts, size_t exts_len,
+	uint8_t **out, size_t *outlen);
+int x509_tbs_cert_from_der(
+	int *version,
+	const uint8_t **serial, size_t *serial_len,
+	int *signature_algor,
+	const uint8_t **issuer, size_t *issuer_len,
+	time_t *not_before, time_t *not_after,
+	const uint8_t **subject, size_t *subject_len,
+	SM2_KEY *subject_public_key,
+	const uint8_t **issuer_unique_id, size_t *issuer_unique_id_len,
+	const uint8_t **subject_unique_id, size_t *subject_unique_id_len,
+	const uint8_t **exts, size_t *exts_len,
+	const uint8_t **in, size_t *inlen);
+int x509_tbs_cert_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen);
+
+/*
+Certificate  ::=  SEQUENCE  {
+	tbsCertificate       TBSCertificate,
+	signatureAlgorithm   AlgorithmIdentifier,
+	signatureValue       BIT STRING }
+*/
+int x509_certificate_to_der(
+	const uint8_t *tbs, size_t tbslen,
+	int signature_algor,
+	const uint8_t *sig, size_t siglen,
+	uint8_t **out, size_t *outlen);
+int x509_certificate_from_der(
+	const uint8_t **tbs, size_t *tbslen,
+	int *signature_algor,
+	const uint8_t **sig, size_t *siglen,
+	const uint8_t **in, size_t *inlen);
+
+int x509_signed_from_der(
+	const uint8_t **tbs, size_t *tbslen,
+	int *signature_algor,
+	const uint8_t **sig, size_t *siglen,
+	const uint8_t **in, size_t *inlen);
+int x509_signed_verify(const uint8_t *a, size_t alen, const SM2_KEY *pub_key,
+	const char *signer_id, size_t signer_id_len);
+int x509_signed_verify_by_ca_cert(const uint8_t *a, size_t alen, const uint8_t *cacert, size_t cacertlen,
+	const char *signer_id, size_t signer_id_len);
+
+// x509_cert functions
+int x509_cert_sign_to_der(
+	int version,
+	const uint8_t *serial, size_t serial_len,
+	int signature_algor,
+	const uint8_t *issuer, size_t issuer_len,
+	time_t not_before, time_t not_after,
+	const uint8_t *subject, size_t subject_len,
+	const SM2_KEY *subject_public_key,
+	const uint8_t *issuer_unique_id, size_t issuer_unique_id_len,
+	const uint8_t *subject_unique_id, size_t subject_unique_id_len,
+	const uint8_t *exts, size_t exts_len,
+	const SM2_KEY *sign_key, const char *signer_id, size_t signer_id_len,
+	uint8_t **out, size_t *outlen);
+
+int x509_cert_to_der(const uint8_t *a, size_t alen, uint8_t **out, size_t *outlen);
+int x509_cert_from_der(const uint8_t **a, size_t *alen, const uint8_t **in, size_t *inlen);
+int x509_cert_to_pem(const uint8_t *a, size_t alen, FILE *fp);
+int x509_cert_from_pem(uint8_t *a, size_t *alen, size_t maxlen, FILE *fp);
+int x509_cert_from_pem_by_subject(uint8_t *a, size_t *alen, size_t maxlen, const uint8_t *name, size_t namelen, FILE *fp);
+int x509_cert_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *a, size_t alen);
+
+int x509_cert_verify_by_ca_cert(const uint8_t *a, size_t alen, const uint8_t *cacert, size_t cacertlen,
+	const char *signer_id, size_t signer_id_len);
+
+int x509_cert_get_details(const uint8_t *a, size_t alen,
+	int *version,
+	const uint8_t **serial_number, size_t *serial_number_len,
+	int *inner_signature_algor,
+	const uint8_t **issuer, size_t *issuer_len,
+	time_t *not_before, time_t *not_after,
+	const uint8_t **subject, size_t *subject_len,
+	SM2_KEY *subject_public_key,
+	const uint8_t **issuer_unique_id, size_t *issuer_unique_id_len,
+	const uint8_t **subject_unique_id, size_t *subject_unique_id_len,
+	const uint8_t **extensions, size_t *extensions_len,
+	int *signature_algor,
+	const uint8_t **signature, size_t *signature_len);
+
+
+typedef enum {
+	X509_cert_server_auth,
+	X509_cert_client_auth,
+	X509_cert_server_key_encipher,
+	X509_cert_client_key_encipher,
+	X509_cert_ca,
+	X509_cert_root_ca,
+	X509_cert_crl_sign,
+} X509_CERT_TYPE;
+
+int x509_cert_check(const uint8_t *cert, size_t certlen, int cert_type, int *path_len_constraint);
+
+/*
+IssuerAndSerialNumber ::= SEQUENCE {
+	isser		Name,
+	serialNumber	INTEGER }
+*/
+int x509_cert_get_issuer_and_serial_number(const uint8_t *a, size_t alen,
+	const uint8_t **issuer, size_t *issuer_len,
+	const uint8_t **serial_number, size_t *serial_number_len);
+int x509_cert_get_issuer(const uint8_t *a, size_t alen, const uint8_t **name, size_t *namelen);
+int x509_cert_get_subject(const uint8_t *a, size_t alen, const uint8_t **subj, size_t *subj_len);
+int x509_cert_get_subject_public_key(const uint8_t *a, size_t alen, SM2_KEY *public_key);
+int x509_cert_get_exts(const uint8_t *a, size_t alen, const uint8_t **d, size_t *dlen);
+
+int x509_certs_to_pem(const uint8_t *d, size_t dlen, FILE *fp);
+int x509_certs_from_pem(uint8_t *d, size_t *dlen, size_t maxlen, FILE *fp);
+int x509_certs_get_count(const uint8_t *d, size_t dlen, size_t *cnt);
+int x509_certs_get_cert_by_index(const uint8_t *d, size_t dlen, int index, const uint8_t **cert, size_t *certlen);
+int x509_certs_get_cert_by_subject(const uint8_t *d, size_t dlen, const uint8_t *subject, size_t subject_len, const uint8_t **cert, size_t *certlen);
+int x509_certs_get_last(const uint8_t *d, size_t dlen, const uint8_t **cert, size_t *certlen);
+
+int x509_certs_get_cert_by_subject_and_key_identifier(const uint8_t *d, size_t dlen,
+	const uint8_t *subject, size_t subject_len,
+	const uint8_t *key_id, size_t key_id_len,
+	const uint8_t **cert, size_t *certlen);
+int x509_certs_get_cert_by_issuer_and_serial_number(
+	const uint8_t *certs, size_t certs_len,
+	const uint8_t *issuer, size_t issuer_len,
+	const uint8_t *serial, size_t serial_len,
+	const uint8_t **cert, size_t *cert_len);
+
+typedef enum {
+	X509_cert_chain_server,
+	X509_cert_chain_client,
+} X509_CERT_CHAIN_TYPE;
+
+#define X509_MAX_VERIFY_DEPTH	6
+int x509_certs_verify(const uint8_t *certs, size_t certslen, int certs_type,
+	const uint8_t *rootcerts, size_t rootcertslen, int depth, int *verify_result);
+int x509_certs_verify_tlcp(const uint8_t *certs, size_t certslen, int certs_type,
+	const uint8_t *rootcerts, size_t rootcertslen, int depth, int *verify_result);
+int x509_certs_get_subjects(const uint8_t *certs, size_t certslen, uint8_t *names, size_t *nameslen);
+int x509_certs_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen);
+
+
+int x509_cert_new_from_file(uint8_t **out, size_t *outlen, const char *file);
+int x509_certs_new_from_file(uint8_t **out, size_t *outlen, const char *file);
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif

+ 309 - 0
components/gmssl/include/gmssl/x509_crl.h

@@ -0,0 +1,309 @@
+/*
+ *  Copyright 2014-2023 The GmSSL Project. All Rights Reserved.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the License); you may
+ *  not use this file except in compliance with the License.
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ */
+
+
+
+#ifndef GMSSL_X509_CRL_H
+#define GMSSL_X509_CRL_H
+
+
+#include <time.h>
+#include <stdint.h>
+#include <gmssl/sm2.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/*
+CRLReason ::= ENUMERATED
+*/
+typedef enum {
+	X509_cr_unspecified = 0,
+	X509_cr_key_compromise = 1,
+	X509_cr_ca_compromise = 2 ,
+	X509_cr_affiliation_changed = 3,
+	X509_cr_superseded = 4,
+	X509_cr_cessation_of_operation = 5,
+	X509_cr_certificate_hold = 6,
+	X509_cr_not_assigned = 7,
+	X509_cr_remove_from_crl = 8,
+	X509_cr_privilege_withdrawn = 9,
+	X509_cr_aa_compromise = 10,
+} X509_CRL_REASON;
+
+const char *x509_crl_reason_name(int reason);
+int x509_crl_reason_from_name(int *reason, const char *name);
+int x509_crl_reason_to_der(int reason, uint8_t **out, size_t *outlen);
+int x509_crl_reason_from_der(int *reason, const uint8_t **in, size_t *inlen);
+int x509_implicit_crl_reason_from_der(int index, int *reason, const uint8_t **in, size_t *inlen);
+
+/*
+CRL Entry Extensions:
+	OID_ce_crl_reasons		ENUMERATED		non-critical
+	OID_ce_invalidity_date		GeneralizedTime		non-critical
+	OID_ce_certificate_issuer	GeneralNames		MUST critical
+*/
+const char *x509_crl_entry_ext_id_name(int oid);
+int x509_crl_entry_ext_id_from_name(const char *name);
+int x509_crl_entry_ext_id_to_der(int oid, uint8_t **out, size_t *outlen);
+int x509_crl_entry_ext_id_from_der(int *oid, const uint8_t **in, size_t *inlen);
+
+int x509_crl_entry_ext_to_der(int oid, int critical, const uint8_t *val, size_t vlen, uint8_t **out, size_t *outlen);
+int x509_crl_entry_ext_from_der(int *oid, int *critical, const uint8_t **val, size_t *vlen, const uint8_t **in, size_t *inlen);
+int x509_crl_entry_ext_critical_check(int oid, int critical);
+int x509_crl_entry_ext_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen);
+
+int x509_crl_reason_ext_to_der(int critical, int reason, uint8_t **out, size_t *outlen);
+int x509_invalidity_date_ext_to_der(int critical, time_t date, uint8_t **out, size_t *outlen);
+int x509_cert_issuer_ext_to_der(int critical, const uint8_t *d, size_t dlen, uint8_t **out, size_t *outlen);
+int x509_crl_entry_ext_from_der_ex(int *oid, int *critical,
+	int *reason, time_t *invalid_date, const uint8_t **cert_issuer, size_t *cert_issuer_len,
+	const uint8_t **in, size_t *inlen);
+
+int x509_crl_entry_exts_to_der(
+	int reason, time_t invalid_date, const uint8_t *cert_issuer, size_t cert_issuer_len,
+	uint8_t **out, size_t *outlen);
+int x509_crl_entry_exts_from_der(
+	int *reason, time_t *invalid_date, const uint8_t **cert_issuer, size_t *cert_issuer_len,
+	const uint8_t **in, size_t *inlen);
+int x509_crl_entry_exts_get(const uint8_t *d, size_t dlen,
+	int *reason, time_t *invalid_date, const uint8_t **cert_issuer, size_t *cert_issuer_len);
+int x509_crl_entry_exts_check(const uint8_t *d, size_t dlen);
+int x509_crl_entry_exts_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen);
+
+/*
+RevokedCertificate ::= SEQUENCE {
+	userCertificate		CertificateSerialNumber,
+	revocationDate		Time,
+	crlEntryExtensions	Extensions OPTIONAL }
+*/
+int x509_revoked_cert_to_der(
+	const uint8_t *serial, size_t serial_len, time_t revoke_date,
+	const uint8_t *crl_entry_exts, size_t crl_entry_exts_len,
+	uint8_t **out, size_t *outlen);
+int x509_revoked_cert_from_der(
+	const uint8_t **serial, size_t *serial_len, time_t *revoke_date,
+	const uint8_t **crl_entry_exts, size_t *crl_entry_exts_len,
+	const uint8_t **in, size_t *inlen);
+int x509_revoked_cert_to_der_ex(
+	const uint8_t *serial, size_t serial_len, time_t revoke_date,
+	int reason, time_t invalid_date, const uint8_t *cert_issuer, size_t cert_issuer_len,
+	uint8_t **out, size_t *outlen);
+int x509_revoked_cert_from_der_ex(
+	const uint8_t **serial, size_t *serial_len, time_t *revoke_date,
+	int *reason, time_t *invalid_date, const uint8_t **cert_issuer, size_t *cert_issuer_len,
+	const uint8_t **in, size_t *inlen);
+int x509_revoked_cert_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen);
+
+int x509_cert_revoke_to_der(const uint8_t *cert, size_t certlen,
+	time_t revoke_date, int reason, time_t invalid_date, const uint8_t *cert_issuer, size_t cert_issuer_len,
+	uint8_t **out, size_t *outlen);
+
+/*
+RevokedCertificates ::= SEQUENCE OF RevokedCertificate
+*/
+int x509_revoked_certs_find_revoked_cert_by_serial_number(const uint8_t *d, size_t dlen,
+	const uint8_t *serial, size_t serial_len, time_t *revoke_date,
+	const uint8_t **crl_entry_exts, size_t *crl_entry_exts_len);
+int x509_revoked_certs_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen);
+
+/*
+CRL Extensions:
+	OID_ce_authority_key_identifier		AuthorityKeyIdentifier		critical or non-critical
+	OID_ce_issuer_alt_name			GeneralNames			SHOULD non-critical
+	OID_ce_crl_number			INTEGER				MUST non-critical
+	OID_ce_delta_crl_indicator		INTEGER				MUST critical
+	OID_ce_issuing_distribution_point	IssuingDistributionPoint	critical
+	OID_ce_freshest_crl			CRLDistributionPoints		MUST non-critical
+	OID_pe_authority_info_access		AccessDescriptions		MUST non-critical
+*/
+const char *x509_crl_ext_id_name(int oid);
+int x509_crl_ext_id_from_name(const char *name);
+int x509_crl_ext_id_to_der(int oid, uint8_t **out, size_t *outlen);
+int x509_crl_ext_id_from_der(int *oid, const uint8_t **in, size_t *inlen);
+int x509_crl_ext_id_from_der_ex(int *oid, uint32_t *nodes, size_t *nodes_cnt, const uint8_t **in, size_t *inlen);
+
+/*
+IssuingDistributionPoint ::= SEQUENCE {
+	distributionPoint		[0] EXPLICIT DistributionPointName OPTIONAL,
+	onlyContainsUserCerts		[1] IMPLICIT BOOLEAN DEFAULT FALSE,
+	onlyContainsCACerts		[2] IMPLICIT BOOLEAN DEFAULT FALSE,
+	onlySomeReasons			[3] IMPLICIT ReasonFlags OPTIONAL,
+	indirectCRL			[4] IMPLICIT BOOLEAN DEFAULT FALSE,
+	onlyContainsAttributeCerts	[5] IMPLICIT BOOLEAN DEFAULT FALSE }
+*/
+int x509_issuing_distribution_point_to_der(
+	const char *dist_point_uri, size_t dist_point_uri_len,
+	int only_contains_user_certs,
+	int only_contains_ca_certs,
+	int only_some_reasons,
+	int indirect_crl,
+	int only_contains_attr_certs,
+	uint8_t **out, size_t *outlen);
+int x509_issuing_distribution_point_from_der(
+	int *dist_point_choice, const uint8_t **dist_point, size_t *dist_point_len,
+	int *only_contains_user_certs,
+	int *only_contains_ca_certs,
+	int *only_some_reasons,
+	int *indirect_crl,
+	int *only_contains_attr_certs,
+	const uint8_t **in, size_t *inlen);
+int x509_issuing_distribution_point_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen);
+
+int x509_crl_ext_to_der(int oid, int critical, const uint8_t *val, size_t vlen, uint8_t **out, size_t *outlen);
+int x509_crl_ext_from_der_ex(int *oid, uint32_t *nodes, size_t *nodes_cnt,
+	int *critical, const uint8_t **val, size_t *vlen,
+	const uint8_t **in, size_t *inlen);
+int x509_crl_ext_critical_check(int oid, int critical);
+int x509_crl_ext_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen);
+
+
+int x509_crl_exts_add_authority_key_identifier(
+	uint8_t *exts, size_t *extslen, size_t maxlen,
+	int critical,
+	const uint8_t *keyid, size_t keyid_len,
+	const uint8_t *issuer, size_t issuer_len,
+	const uint8_t *serial, size_t serial_len);
+int x509_crl_exts_add_default_authority_key_identifier(uint8_t *exts, size_t *extslen, size_t maxlen,
+	const SM2_KEY *public_key);
+int x509_crl_exts_add_issuer_alt_name(
+	uint8_t *exts, size_t *extslen, size_t maxlen,
+	int critical,
+	const uint8_t *d, size_t dlen);
+int x509_crl_exts_add_crl_number_ex(
+ 	uint8_t *exts, size_t *extslen, size_t maxlen,
+	int oid, int critical, int num);
+int x509_crl_exts_add_crl_number(
+	uint8_t *exts, size_t *extslen, size_t maxlen,
+	int critical,
+	int num);
+int x509_crl_exts_add_delta_crl_indicator(
+	uint8_t *exts, size_t *extslen, size_t maxlen,
+	int critical,
+	int num);
+int x509_crl_exts_add_issuing_distribution_point(
+	uint8_t *exts, size_t *extslen, size_t maxlen,
+	int critical,
+	const char *dist_point_uri, size_t dist_point_uri_len,
+	int only_contains_user_certs,
+	int only_contains_ca_certs,
+	int only_some_reasons,
+	int indirect_crl,
+	int only_contains_attr_certs);
+int x509_crl_exts_add_freshest_crl(
+	uint8_t *exts, size_t *extslen, size_t maxlen, int critical,
+	const char *http_uri, size_t http_urilen,
+	const char *ldap_uri, size_t ldap_urilen);
+int x509_crl_exts_add_authority_info_acess(
+	uint8_t *exts, size_t *extslen, size_t maxlen, int critical,
+	const char *ca_issuers_uri, size_t ca_issuers_urilen,
+	const char *ocsp_uri, size_t ocsp_urilen);
+
+#define x509_crl_exts_to_der(d,dlen,out,outlen) x509_explicit_exts_to_der(0,d,dlen,out,outlen)
+#define x509_crl_exts_from_der(d,dlen,in,inlen) x509_explicit_exts_from_der(0,d,dlen,in,inlen)
+int x509_crl_exts_check(const uint8_t *d, size_t dlen);
+int x509_crl_exts_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen);
+
+/*
+TBSCertList ::= SEQUENCE {
+	version			INTEGER OPTIONAL, -- if present, MUST be v2
+	signature		AlgorithmIdentifier,
+	issuer			Name,
+	thisUpdate		Time,
+	nextUpdate		Time OPTIONAL,
+	revokedCertificates	RevokedCertificates OPTIONAL,
+	crlExtensions		[0] EXPLICIT Extensions OPTIONAL, -- if present, MUST be v2 }
+*/
+int x509_tbs_crl_to_der(
+	int version,
+	int signature_algor,
+	const uint8_t *issuer, size_t issuer_len,
+	time_t this_update,
+	time_t next_update,
+	const uint8_t *revoked_certs, size_t revoked_certs_len,
+	const uint8_t *exts, size_t exts_len,
+	uint8_t **out, size_t *outlen);
+int x509_tbs_crl_from_der(
+	int *version,
+	int *signature_algor,
+	const uint8_t **issuer, size_t *issuer_len,
+	time_t *this_update,
+	time_t *next_update,
+	const uint8_t **revoked_certs, size_t *revoked_certs_len,
+	const uint8_t **exts, size_t *exts_len,
+	const uint8_t **in, size_t *inlen);
+int x509_tbs_crl_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen);
+
+/*
+CertificateList ::= SEQUENCE {
+	tbsCertList		TBSCertList,
+	signatureAlgorithm	AlgorithmIdentifier,
+	signatureValue		BIT STRING }
+*/
+int x509_crl_to_der(const uint8_t *a, size_t alen, uint8_t **out, size_t *outlen);
+int x509_crl_from_der(const uint8_t **a, size_t *alen, const uint8_t **in, size_t *inlen);
+int x509_crl_to_pem(const uint8_t *a, size_t alen, FILE *fp);
+int x509_crl_from_pem(uint8_t *a, size_t *alen, size_t maxlen, FILE *fp);
+int x509_crl_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *a, size_t alen);
+
+
+int x509_crl_sign_to_der(
+	int version, int sig_alg,
+	const uint8_t *issuer, size_t issuer_len,
+	time_t this_update, time_t next_update,
+	const uint8_t *revoked_certs, size_t revoked_certs_len,
+	const uint8_t *crl_exts, size_t crl_exts_len,
+	const SM2_KEY *sign_key, const char *signer_id, size_t signer_id_len,
+	uint8_t **out, size_t *outlen);
+int x509_crl_from_der_ex(
+	int *version,
+	int *inner_sig_alg,
+	const uint8_t **issuer, size_t *issuer_len,
+	time_t *this_update, time_t *next_update,
+	const uint8_t **revoked_certs, size_t *revoked_certs_len,
+	const uint8_t **exts, size_t *exts_len,
+	int *sig_alg, const uint8_t **sig, size_t *siglen,
+	const uint8_t **in, size_t *inlen);
+int x509_crl_check(const uint8_t *a, size_t alen, time_t now);
+int x509_crl_verify(const uint8_t *a, size_t alen,
+	const SM2_KEY *sign_pub_key, const char *signer_id, size_t signer_id_len);
+int x509_crl_verify_by_ca_cert(const uint8_t *a, size_t alen, const uint8_t *cacert, size_t cacertlen,
+	const char *signer_id, size_t signer_id_len);
+int x509_crl_get_details(const uint8_t *crl, size_t crl_len,
+	int *version,
+	int *inner_sig_alg,
+	const uint8_t **issuer, size_t *issuer_len,
+	time_t *this_update,
+	time_t *next_update,
+	const uint8_t **revoked_certs, size_t *revoked_certs_len,
+	const uint8_t **exts, size_t *exts_len,
+	int *signature_algor,
+	const uint8_t **sig, size_t *siglen);
+int x509_crl_get_issuer(const uint8_t *crl, size_t crl_len,
+	const uint8_t **issuer, size_t *issuer_len);
+int x509_crl_get_revoked_certs(const uint8_t *a, size_t alen, const uint8_t **d, size_t *dlen);
+int x509_crl_find_revoked_cert_by_serial_number(const uint8_t *a, size_t alen,
+	const uint8_t *serial, size_t serial_len, time_t *revoke_date,
+	const uint8_t **entry_exts, size_t *entry_exts_len);
+
+int x509_crls_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen);
+
+int x509_crl_new_from_uri(uint8_t **crl, size_t *crl_len, const char *uri, size_t urilen);
+int x509_crl_new_from_cert(uint8_t **crl, size_t *crl_len, const uint8_t *cert, size_t certlen);
+int x509_cert_check_crl(const uint8_t *cert, size_t certlen, const uint8_t *cacert, size_t cacertlen,
+	const char *ca_signer_id, size_t ca_signer_id_len);
+
+
+#ifdef  __cplusplus
+}
+#endif
+#endif

+ 641 - 0
components/gmssl/include/gmssl/x509_ext.h

@@ -0,0 +1,641 @@
+/*
+ *  Copyright 2014-2023 The GmSSL Project. All Rights Reserved.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the License); you may
+ *  not use this file except in compliance with the License.
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ */
+
+
+#ifndef GMSSL_X509_EXT_H
+#define GMSSL_X509_EXT_H
+
+
+#include <time.h>
+#include <string.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <gmssl/sm2.h>
+#include <gmssl/oid.h>
+#include <gmssl/asn1.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+enum {
+	X509_non_critical = 0,
+	X509_critical = 1,
+};
+
+/*
+Extensions:
+
+	1.  AuthorityKeyIdentifier	SEQUENCE			AuthorityKeyIdentifier		MUST non-critical
+	2.  SubjectKeyIdentifier	OCTET STRING							MUST non-critical
+	3.  KeyUsage			BIT STRING							SHOULD critical
+	4.  CertificatePolicies		SEQUENCE OF SEQUENCE		CertificatePolicies
+	5.  PolicyMappings		SEQUENCE OF SEQUENCE		PolicyMappings			SHOULD critical
+	6.  SubjectAltName		SEQUENCE OF SEQUENCE		GeneralNames			SHOULD non-critical
+	7.  IssuerAltName		SEQUENCE OF SEQUENCE		GeneralNames			SHOULD non-critical
+	8.  SubjectDirectoryAttributes	SEQUENCE OF SEQUENCE		Attributes			MUST non-critical
+	9.  BasicConstraints		SEQUENCE			BasicConstraints		CA: MUST critical, End-entity: MAY critical or non-critical
+	10. NameConstraints		SEQUENCE			NameConstraints
+	11. PolicyConstraints		SEQUENCE			PolicyConstraints		MUST critical
+	12. ExtKeyUsageSyntax		SEQUENCE OF OBJECT IDENTIFIER					MAY critical or non-critical
+	13. CRLDistributionPoints	SEQUENCE OF SEQUENCE		DistributionPoints
+	14. InhibitAnyPolicy		INTEGER								MUST critical
+	15. FreshestCRL			SEQUENCE OF SEQUENCE		DistributionPoints		MUST non-critical
+*/
+
+int x509_exts_add_authority_key_identifier(uint8_t *exts, size_t *extslen, size_t maxlen, int critical,
+	const uint8_t *keyid, size_t keyid_len,
+	const uint8_t *issuer, size_t issuer_len,
+	const uint8_t *serial, size_t serial_len);
+int x509_exts_add_default_authority_key_identifier(uint8_t *exts, size_t *extslen, size_t maxlen,
+	const SM2_KEY *public_key);
+int x509_exts_add_subject_key_identifier(uint8_t *exts, size_t *extslen, size_t maxlen, int critical, const uint8_t *d, size_t dlen);
+int x509_exts_add_subject_key_identifier_ex(uint8_t *exts, size_t *extslen, size_t maxlen, int critical, const SM2_KEY *subject_key);
+int x509_exts_add_key_usage(uint8_t *exts, size_t *extslen, size_t maxlen, int critical, int bits);
+int x509_exts_add_certificate_policies(uint8_t *exts, size_t *extslen, size_t maxlen, int critical, const uint8_t *d, size_t dlen);
+int x509_exts_add_policy_mappings(uint8_t *exts, size_t *extslen, size_t maxlen, int critical, const uint8_t *d, size_t dlen);
+int x509_exts_add_subject_alt_name(uint8_t *exts, size_t *extslen, size_t maxlen, int critical, const uint8_t *d, size_t dlen);
+int x509_exts_add_issuer_alt_name(uint8_t *exts, size_t *extslen, size_t maxlen, int critical, const uint8_t *d, size_t dlen);
+int x509_exts_add_subject_directory_attributes(uint8_t *exts, size_t *extslen, size_t maxlen, int critical, const uint8_t *d, size_t dlen);
+int x509_exts_add_name_constraints(uint8_t *exts, size_t *extslen, size_t maxlen, int critical,
+	const uint8_t *permitted_subtrees, size_t permitted_subtrees_len,
+	const uint8_t *excluded_subtrees, size_t excluded_subtrees_len);
+int x509_exts_add_policy_constraints(uint8_t *exts, size_t *extslen, size_t maxlen, int critical,
+	int require_explicit_policy, int inhibit_policy_mapping);
+int x509_exts_add_basic_constraints(uint8_t *exts, size_t *extslen, size_t maxlen, int critical, int ca, int path_len_constraint);
+int x509_exts_add_ext_key_usage(uint8_t *exts, size_t *extslen, size_t maxlen, int critical, const int *key_purposes, size_t key_purposes_cnt);
+int x509_exts_add_crl_distribution_points_ex(uint8_t *exts, size_t *extslen, size_t maxlen, int critical, int oid,
+	const char *http_uri, size_t http_urilen, const char *ldap_uri, size_t ldap_urilen);
+int x509_exts_add_crl_distribution_points(uint8_t *exts, size_t *extslen, size_t maxlen, int critical,
+	const char *http_uri, size_t http_urilen, const char *ldap_uri, size_t ldap_urilen);
+int x509_exts_add_inhibit_any_policy(uint8_t *exts, size_t *extslen, size_t maxlen, int critical, int skip_certs);
+int x509_exts_add_freshest_crl(uint8_t *exts, size_t *extslen, size_t maxlen, int critical, const uint8_t *d, size_t dlen);
+int x509_exts_add_authority_info_access(uint8_t *exts, size_t *extslen, size_t maxlen, int critical,
+	const char *ca_issuers_uri, size_t ca_issuers_urilen, // ca_issuers_uri is the URI (http://examaple.com/subCA.crt) of DER-encoded CA cert
+	const char *ocsp_uri, size_t ocsp_urilen);
+
+int x509_exts_add_sequence(uint8_t *exts, size_t *extslen, size_t maxlen,
+	int oid, int critical, const uint8_t *d, size_t dlen);
+
+/*
+OtherName ::= SEQUENCE {
+	type-id		OBJECT IDENTIFIER, -- known oid from x509_rdn_oid such as OID_at_common_name, or oid nodes
+	value		[0] EXPLICIT ANY DEFINED BY type-id }
+*/
+int x509_other_name_to_der(
+	const uint32_t *nodes, size_t nodes_count,
+	const uint8_t *value, size_t value_len,
+	uint8_t **out, size_t *outlen);
+int x509_other_name_from_der(
+	uint32_t *nodes, size_t *nodes_count,
+	const uint8_t **value, size_t *valuelen,
+	const uint8_t **in, size_t *inlen);
+int x509_other_name_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen);
+
+/*
+EDIPartyName ::= SEQUENCE {
+	nameAssigner	[0] EXPLICIT DirectoryString OPTIONAL,
+	partyName	[1] EXPLICIT DirectoryString }
+*/
+int x509_edi_party_name_to_der(
+	int assigner_tag, const uint8_t *assigner, size_t assigner_len,
+	int party_name_tag, const uint8_t *party_name, size_t party_name_len,
+	uint8_t **out, size_t *outlen);
+int x509_edi_party_name_from_der(
+	int *assigner_tag, const uint8_t **assigner, size_t *assigner_len,
+	int *party_name_tag, const uint8_t **party_name, size_t *party_name_len,
+	const uint8_t **in, size_t *inlen);
+int x509_edi_party_name_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen);
+
+/*
+GeneralName ::= CHOICE {
+	otherName			[0] IMPLICIT OtherName,	-- Only in GeneralName
+	rfc822Name			[1] IMPLICIT IA5String,
+	dNSName				[2] IMPLICIT IA5String,
+	x400Address			[3] IMPLICIT ORAddress,
+	directoryName			[4] IMPLICIT Name,	-- SEQENCE OF
+	ediPartyName			[5] IMPLICIT EDIPartyName, -- Only in GeneralName
+	uniformResourceIdentifier	[6] IMPLICIT IA5String,
+	iPAddress			[7] IMPLICIT OCTET STRING, -- 4 bytes or string?
+	registeredID			[8] IMPLICIT OBJECT IDENTIFIER }
+*/
+typedef enum {
+	X509_gn_other_name = 0,
+	X509_gn_rfc822_name = 1,
+	X509_gn_dns_name = 2,
+	X509_gn_x400_address = 3,
+	X509_gn_directory_name = 4,
+	X509_gn_edi_party_name = 5,
+	X509_gn_uniform_resource_identifier = 6,
+	X509_gn_ip_address = 7,
+	X509_gn_registered_id = 8,
+} X509_GENERAL_NAME_CHOICE;
+
+int x509_general_name_to_der(int choice, const uint8_t *d, size_t dlen, uint8_t **out, size_t *outlen);
+int x509_general_name_from_der(int *choice, const uint8_t **d, size_t *dlen, const uint8_t **in, size_t *inlen);
+int x509_general_name_print(FILE *fp, int fmt, int ind, const char *label, int choice, const uint8_t *d, size_t dlen);
+
+/*
+GeneralNames ::= SEQUENCE OF GeneralName
+*/
+#define x509_general_names_to_der(d,dlen,out,outlen) asn1_sequence_to_der(d,dlen,out,outlen)
+#define x509_general_names_from_der(d,dlen,in,inlen) asn1_sequence_from_der(d,dlen,in,inlen)
+int x509_general_names_add_general_name(uint8_t *gns, size_t *gnslen, size_t maxlen,
+	int choice, const uint8_t *d, size_t dlen);
+int x509_general_names_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen);
+
+int x509_general_names_add_other_name(uint8_t *gns, size_t *gnslen, size_t maxlen,
+	const uint32_t *nodes, size_t nodes_count,
+	const uint8_t *value, size_t value_len);
+#define x509_general_names_add_rfc822_name(a,alen,maxlen,s) x509_general_names_add_general_name(a,alen,maxlen,X509_gn_rfc822_name,(uint8_t*)s,strlen(s))
+#define x509_general_names_add_dns_name(a,alen,maxlen,s) x509_general_names_add_general_name(a,alen,maxlen,X509_gn_dns_name,(uint8_t*)s,strlen(s))
+#define x509_general_names_add_x400_address(a,alen,maxlen,d,dlen) x509_general_names_add_general_name(a,alen,maxlen,X509_gn_x400_address,d,dlen)
+#define x509_general_names_add_directory_name(a,alen,maxlen,d,dlen) x509_general_names_add_general_name(a,alen,maxlen,X509_gn_directory_name,d,dlen)
+int x509_general_names_add_edi_party_name(uint8_t *gns, size_t *gnslen, size_t maxlen,
+	int assigner_tag, const uint8_t *assigner, size_t assigner_len,
+	int party_name_tag, const uint8_t *party_name, size_t party_name_len);
+#define x509_general_names_add_uniform_resource_identifier(a,alen,maxlen,s) x509_general_names_add_general_name(a,alen,maxlen,X509_gn_uniform_resource_identifier,(uint8_t*)s,strlen(s))
+#define x509_general_names_add_ip_address(a,alen,maxlen,s) x509_general_names_add_general_name(a,alen,maxlen,X509_gn_ip_address,(uint8_t*)s,strlen(s))
+int x509_general_names_add_registered_id(uint8_t *gns, size_t *gnslen, size_t maxlen,
+	const uint32_t *nodes, size_t nodes_cnt);
+
+int x509_uri_as_general_names_to_der_ex(int tag, const char *uri, size_t urilen, uint8_t **out, size_t *outlen);
+#define x509_uri_as_general_names_to_der(uri,urilen,out,outlen) x509_uri_as_general_names_to_der_ex(ASN1_TAG_SEQUENCE,uri,urilen,out,outlen)
+
+/*
+AuthorityKeyIdentifier ::= SEQUENCE {
+	keyIdentifier			[0] IMPLICIT OCTET STRING OPTIONAL,
+	authorityCertIssuer		[1] IMPLICIT GeneralNames OPTIONAL,
+	authorityCertSerialNumber	[2] IMPLICIT INTEGER OPTIONAL }
+*/
+int x509_authority_key_identifier_to_der(
+	const uint8_t *keyid, size_t keyid_len,
+	const uint8_t *issuer, size_t issuer_len,
+	const uint8_t *serial, size_t serial_len,
+	uint8_t **out, size_t *outlen);
+int x509_authority_key_identifier_from_der(
+	const uint8_t **keyid, size_t *keyid_len,
+	const uint8_t **issuer, size_t *issuer_len,
+	const uint8_t **serial, size_t *serial_len,
+	const uint8_t **in, size_t *inlen);
+int x509_authority_key_identifier_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen);
+
+/*
+SubjectKeyIdentifier ::= OCTET STRING
+*/
+#define X509_SUBJECT_KEY_IDENTIFIER_MIN_LEN 16
+#define X509_SUBJECT_KEY_IDENTIFIER_MAX_LEN 64
+
+/*
+KeyUsage ::= BIT STRING {
+	digitalSignature	(0),
+	nonRepudiation		(1), -- recent renamed contentCommitment
+	keyEncipherment		(2),
+	dataEncipherment	(3),
+	keyAgreement		(4),
+	keyCertSign		(5),
+	cRLSign			(6),
+	encipherOnly		(7),
+	decipherOnly		(8) }
+*/
+#define X509_KU_DIGITAL_SIGNATURE	(1 << 0)
+#define X509_KU_NON_REPUDIATION		(1 << 1)
+#define X509_KU_KEY_ENCIPHERMENT	(1 << 2)
+#define X509_KU_DATA_ENCIPHERMENT	(1 << 3)
+#define X509_KU_KEY_AGREEMENT		(1 << 4)
+#define X509_KU_KEY_CERT_SIGN		(1 << 5)
+#define X509_KU_CRL_SIGN		(1 << 6)
+#define X509_KU_ENCIPHER_ONLY		(1 << 7)
+#define X509_KU_DECIPHER_ONLY		(1 << 8)
+
+const char *x509_key_usage_name(int flag);
+int x509_key_usage_from_name(int *flag, const char *name);
+#define x509_key_usage_to_der(bits,out,outlen) asn1_bits_to_der(bits,out,outlen)
+#define x509_key_usage_from_der(bits,in,inlen) asn1_bits_from_der(bits,in,inlen)
+int x509_key_usage_check(int bits, int cert_type);
+int x509_key_usage_print(FILE *fp, int fmt, int ind, const char *label, int bits);
+
+/*
+DisplayText ::= CHOICE {
+	ia5String		IA5String	(SIZE (1..200)),
+	visibleString		VisibleString	(SIZE (1..200)),
+	bmpString		BMPString	(SIZE (1..200)),
+	utf8String		UTF8String	(SIZE (1..200))
+}
+*/
+#define X509_DISPLAY_TEXT_MIN_LEN 1
+#define X509_DISPLAY_TEXT_MAX_LEN 200
+
+int x509_display_text_check(int tag, const uint8_t *d, size_t dlen);
+int x509_display_text_to_der(int tag, const uint8_t *d, size_t dlen, uint8_t **out, size_t *outlen);
+int x509_display_text_from_der(int *tag, const uint8_t **d, size_t *dlen, const uint8_t **in, size_t *inlen);
+int x509_display_text_print(FILE *fp, int fmt, int ind, const char *label, int tag, const uint8_t *d, size_t dlen);
+
+/*
+NoticeReference ::= SEQUENCE {
+	organization	DisplayText,
+	noticeNumbers	SEQUENCE OF INTEGER }
+
+UserNotice ::= SEQUENCE {
+        noticeRef	NoticeReference OPTIONAL,
+        explicitText	DisplayText OPTIONAL }
+*/
+#define X509_MAX_NOTICE_NUMBERS	32
+
+int x509_notice_reference_to_der(
+	int org_tag, const uint8_t *org, size_t org_len,
+	const int *notice_numbers, size_t notice_numbers_cnt,
+	uint8_t **out, size_t *outlen);
+int x509_notice_reference_from_der(
+	int *org_tag, const uint8_t **org, size_t *org_len,
+	int *notice_numbers, size_t *notice_numbers_cnt, size_t max_notice_numbers,
+	const uint8_t **in, size_t *inlen);
+int x509_notice_reference_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen);
+
+int x509_user_notice_to_der(
+	int notice_ref_org_tag, const uint8_t *notice_ref_org, size_t notice_ref_org_len,
+	const int *notice_ref_notice_numbers, size_t notice_ref_notice_numbers_cnt,
+	int explicit_text_tag, const uint8_t *explicit_text, size_t explicit_text_len,
+	uint8_t **out, size_t *outlen);
+int x509_user_notice_from_der(
+	int *notice_ref_org_tag, const uint8_t **notice_ref_org, size_t *notice_ref_org_len,
+	int *notice_ref_notice_numbers, size_t *notice_ref_notice_numbers_cnt, size_t max_notice_ref_notice_numbers,
+	int *explicit_text_tag, const uint8_t **explicit_text, size_t *explicit_text_len,
+	const uint8_t **in, size_t *inlen);
+int x509_user_notice_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen);
+
+/*
+PolicyQualifierInfo ::= SEQUENCE {
+        policyQualifierId  PolicyQualifierId,
+        qualifier          ANY DEFINED BY policyQualifierId }
+
+id-qt
+	OID_qt_cps
+	OID_qt_unotice
+
+	switch(policyQualifierId)
+	case id-qt-cps		: qualifier ::= IA5String
+	case id-qt-unotice	: qualifier ::= UserNotice
+*/
+const char *x509_qualifier_id_name(int oid);
+int x509_qualifier_id_from_name(const char *name);
+int x509_qualifier_id_from_der(int *oid, const uint8_t **in, size_t *inlen);
+int x509_qualifier_id_to_der(int oid, uint8_t **out, size_t *outlen);
+
+int x509_policy_qualifier_info_to_der(
+	int oid,
+	const uint8_t *qualifier, size_t qualifier_len,
+	uint8_t **out, size_t *outlen);
+int x509_policy_qualifier_info_from_der(
+	int *oid,
+	const uint8_t **qualifier, size_t *qualifier_len,
+	const uint8_t **in, size_t *inlen);
+int x509_policy_qualifier_info_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen);
+
+#define x509_policy_qualifier_infos_to_der(d,dlen,out,outlen) asn1_sequence_to_der(d,dlen,out,outlen)
+#define x509_policy_qualifier_infos_from_der(d,dlen,in,ineln) asn1_sequence_from_der(d,dlen,in,inlen)
+int x509_policy_qualifier_infos_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen);
+
+/*
+PolicyInformation ::= SEQUENCE {
+        policyIdentifier   CertPolicyId,
+        policyQualifiers   SEQUENCE SIZE (1..MAX) OF PolicyQualifierInfo OPTIONAL }
+
+CertPolicyId ::= OBJECT IDENTIFIER -- undefined
+
+	OID_any_policy
+*/
+char *x509_cert_policy_id_name(int oid);
+int x509_cert_policy_id_from_name(const char *name);
+int x509_cert_policy_id_from_der(int *oid, uint32_t *nodes, size_t *nodes_cnt, const uint8_t **in, size_t *inlen);
+int x509_cert_policy_id_to_der(int oid, const uint32_t *nodes, size_t nodes_cnt, uint8_t **out, size_t *outlen);
+
+int x509_policy_information_to_der(
+	int policy_oid, const uint32_t *policy_nodes, size_t policy_nodes_cnt,
+	const uint8_t *qualifiers, size_t qualifiers_len,
+	uint8_t **out, size_t *outlen);
+int x509_policy_information_from_der(
+	int *policy_oid, uint32_t *policy_nodes, size_t *policy_nodes_cnt,
+	const uint8_t **qualifiers, size_t *qualifiers_len,
+	const uint8_t **in, size_t *inlen);
+int x509_policy_information_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen);
+
+/*
+CertificatePolicies ::= SEQUENCE SIZE (1..MAX) OF PolicyInformation
+*/
+int x509_certificate_policies_add_policy_information(uint8_t *d, size_t *dlen, size_t maxlen,
+	int policy_oid, const uint32_t *policy_nodes, size_t policy_nodes_cnt,
+	const uint8_t *qualifiers, size_t qualifiers_len);
+int x509_certificate_policies_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen);
+#define x509_certificate_policies_to_der(d,dlen,out,outlen) asn1_sequence_to_der(d,dlen,out,outlen)
+#define x509_certificate_policies_from_der(d,dlen,in,inlen) asn1_sequence_from_der(d,dlen,in,inlen)
+
+/*
+PolicyMapping ::= SEQUENCE {
+	issuerDomainPolicy	CertPolicyId, -- id-anyPolicy or other undefined
+	subjectDomainPolicy	CertPolicyId }
+*/
+int x509_policy_mapping_to_der(
+	int issuer_policy_oid, const uint32_t *issuer_policy_nodes, size_t issuer_policy_nodes_cnt,
+	int subject_policy_oid, const uint32_t *subject_policy_nodes, size_t subject_policy_nodes_cnt,
+	uint8_t **out, size_t *outlen);
+int x509_policy_mapping_from_der(
+	int *issuer_policy_oid, uint32_t *issuer_policy_nodes, size_t *issuer_policy_nodes_cnt,
+	int *subject_policy_oid, uint32_t *subject_policy_nodes, size_t *subject_policy_nodes_cnt,
+	const uint8_t **in, size_t *inlen);
+int x509_policy_mapping_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen);
+
+/*
+PolicyMappings ::= SEQUENCE OF PolicyMapping
+*/
+int x509_policy_mappings_add_policy_mapping(uint8_t *d, size_t *dlen, size_t maxlen,
+	int issuer_policy_oid, const uint32_t *issuer_policy_nodes, size_t issuer_policy_nodes_cnt,
+	int subject_policy_oid, const uint32_t *subject_policy_nodes, size_t subject_policy_nodes_cnt);
+int x509_policy_mappings_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen);
+#define x509_policy_mappings_to_der(d,dlen,out,outlen) asn1_sequence_to_der(d,dlen,out,outlen)
+#define x509_policy_mappings_from_der(d,dlen,in,inlen) asn1_sequence_from_der(d,dlen,in,inlen)
+
+/*
+SubjectAltName ::= GeneralNames
+*/
+#define x509_subject_alt_name_print(fp,fmt,ind,label,d,dlen) x509_general_names_print(fp,fmt,ind,label,d,dlen)
+
+/*
+IssuerAltName ::= GeneralNames
+*/
+#define x509_issuer_alt_name_print(fp,fmt,ind,label,d,dlen) x509_general_names_print(fp,fmt,ind,label,d,dlen)
+
+/*
+SubjectDirectoryAttributes ::= SEQUENCE OF Attribute
+
+Attribute ::= SEQUENCE {
+	type		OBJECT IDENTIFIER,
+	values		SET OF ANY }
+*/
+int x509_attribute_to_der(
+	const uint32_t *nodes, size_t nodes_cnt,
+	const uint8_t *values, size_t values_len,
+	uint8_t **out, size_t *outlen);
+int x509_attribute_from_der(
+	int *oid, uint32_t *nodes, size_t *nodes_cnt,
+	const uint8_t **values, size_t *values_len,
+	const uint8_t **in, size_t *inlen);
+int x509_attribute_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen);
+
+int x509_attributes_add_attribute(uint8_t *d, size_t *dlen, size_t maxlen,
+	const uint32_t *nodes, size_t nodes_cnt,
+	const uint8_t *values, size_t values_len);
+int x509_attributes_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen);
+#define x509_attributes_to_der(d,dlen,out,outlen) asn1_sequence_to_der(d,dlen,out,outlen)
+#define x509_attributes_from_der(d,dlen,in,inlen) asn1_sequence_from_der(d,dlen,in,inlen)
+
+/*
+BasicConstraints ::= SEQUENCE {
+	cA			BOOLEAN DEFAULT FALSE,
+	pathLenConstraint	INTEGER (0..MAX) OPTIONAL }
+*/
+#define X509_MAX_PATH_LEN_CONSTRAINT 6
+int x509_basic_constraints_to_der(int ca, int path_len_cons, uint8_t **out, size_t *outlen);
+int x509_basic_constraints_from_der(int *ca, int *path_len_cons, const uint8_t **in, size_t *inlen);
+int x509_basic_constraints_check(int ca, int path_len_cons, int cert_type);
+int x509_basic_constraints_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen);
+
+/*
+GeneralSubtree ::= SEQUENCE {
+	base		GeneralName,
+	minimum		[0] IMPLICIT BaseDistance DEFAULT 0,
+	maximum		[1] IMPLICIT BaseDistance OPTIONAL }
+
+BaseDistance ::= INTEGER (0..MAX)
+*/
+int x509_general_subtree_to_der(
+	int base_choice, const uint8_t *base, size_t base_len,
+	int minimum, int maximum,
+	uint8_t **out, size_t *outlen);
+int x509_general_subtree_from_der(
+	int *base_choice, const uint8_t **base, size_t *base_len,
+	int *minimum, int *maximum,
+	const uint8_t **in, size_t *inlen);
+int x509_general_subtree_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen);
+
+/*
+GeneralSubtrees ::= SEQUENCE SIZE (1..MAX) OF GeneralSubtree
+*/
+int x509_general_subtrees_add_general_subtree(uint8_t *d, size_t *dlen, size_t maxlen,
+	int base_choice, const uint8_t *base, size_t base_len,
+	int minimum, int maximum);
+int x509_general_subtrees_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen);
+#define x509_general_subtrees_to_der(d,dlen,out,outlen) asn1_sequence_to_der(d,dlen,out,outlen)
+#define x509_general_subtrees_from_der(d,dlen,in,inlen) asn1_sequence_from_der(d,dlen,in,inlen)
+
+/*
+NameConstraints ::= SEQUENCE {
+	permittedSubtrees	[0] GeneralSubtrees OPTIONAL,
+	excludedSubtrees	[1] GeneralSubtrees OPTIONAL }
+*/
+int x509_name_constraints_to_der(
+	const uint8_t *permitted_subtrees, size_t permitted_subtrees_len,
+	const uint8_t *excluded_subtrees, size_t excluded_subtrees_len,
+	uint8_t **out, size_t *outlen);
+int x509_name_constraints_from_der(
+	const uint8_t **permitted_subtrees, size_t *permitted_subtrees_len,
+	const uint8_t **excluded_subtrees, size_t *excluded_subtrees_len,
+	const uint8_t **in, size_t *inlen);
+int x509_name_constraints_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen);
+
+/*
+PolicyConstraints ::= SEQUENCE {
+	requireExplicitPolicy	[0] IMPLICIT SkipCerts OPTIONAL,
+	inhibitPolicyMapping	[1] IMPLICIT SkipCerts OPTIONAL
+}
+
+SkipCerts ::= INTEGER (0..MAX)
+*/
+int x509_policy_constraints_to_der(int require_explicit_policy, int inhibit_policy_mapping, uint8_t **out, size_t *outlen);
+int x509_policy_constraints_from_der(int *require_explicit_policy, int *inhibit_policy_mapping, const uint8_t **in, size_t *inlen);
+int x509_policy_constraints_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen);
+
+/*
+ExtKeyUsageSyntax ::= SEQUENCE SIZE (1..MAX) OF KeyPurposeId
+
+KeyPurposeId:
+	OID_any_extended_key_usage
+  id-kp
+	OID_kp_server_auth
+	OID_kp_client_auth
+	OID_kp_code_signing
+	OID_kp_email_protection
+	OID_kp_time_stamping
+	OID_kp_ocsp_signing
+*/
+#define X509_MAX_KEY_PURPOSES	7
+const char *x509_key_purpose_name(int oid);
+const char *x509_key_purpose_text(int oid);
+int x509_key_purpose_from_name(const char *name);
+int x509_key_purpose_from_der(int *oid, const uint8_t **in, size_t *inlen);
+int x509_key_purpose_to_der(int oid, uint8_t **out, size_t *outlen);
+
+int x509_ext_key_usage_to_der(const int *oids, size_t oids_cnt, uint8_t **out, size_t *outlen);
+int x509_ext_key_usage_from_der(int *oids, size_t *oids_cnt, size_t max_cnt, const uint8_t **in, size_t *inlen);
+int x509_ext_key_usage_check(const int *oids, size_t oids_cnt, int cert_type);
+int x509_ext_key_usage_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen);
+
+/*
+ReasonFlags ::= BIT STRING {
+	unused			(0),
+	keyCompromise		(1),
+	cACompromise		(2),
+	affiliationChanged	(3),
+	superseded		(4),
+	cessationOfOperation	(5),
+	certificateHold		(6),
+	privilegeWithdrawn	(7),
+	aACompromise		(8) }
+*/
+#define X509_RF_UNUSED			(1 << 0)
+#define X509_RF_KEY_COMPROMISE		(1 << 1)
+#define X509_RF_CA_COMPROMISE		(1 << 2)
+#define X509_RF_AFFILIATION_CHANGED	(1 << 3)
+#define X509_RF_SUPERSEDED		(1 << 4)
+#define X509_RF_CESSATION_OF_OPERATION	(1 << 5)
+#define X509_RF_CERTIFICATE_HOLD	(1 << 6)
+#define X509_RF_PRIVILEGE_WITHDRAWN	(1 << 7)
+#define X509_RF_AA_COMPROMISE		(1 << 8)
+
+const char *x509_revoke_reason_flag_name(int flag);
+int x509_revoke_reason_flag_from_name(int *flag, const char *name);
+#define x509_revoke_reason_flags_to_der(bits,out,outlen) asn1_bits_to_der(bits,out,outlen)
+#define x509_revoke_reason_flags_from_der(bits,in,inlen) asn1_bits_from_der(bits,in,inlen)
+int x509_revoke_reason_flags_print(FILE *fp, int fmt, int ind, const char *label, int bits);
+
+/*
+DistributionPointName ::= CHOICE {
+	fullName		[0] IMPLICIT GeneralNames, -- SEQUENCE OF
+	nameRelativeToCRLIssuer	[1] IMPLICIT RelativeDistinguishedName } -- SET OF
+*/
+enum {
+	X509_full_name = 0,
+	X509_name_relative_to_crl_issuer = 1,
+};
+
+int x509_uri_as_distribution_point_name_to_der(const char *uri, size_t urilen, uint8_t **out, size_t *outlen);
+int x509_distribution_point_name_from_der(int *choice, const uint8_t **d, size_t *dlen, const uint8_t **in, size_t *inlen);
+int x509_uri_as_distribution_point_name_from_der(const char **uri, size_t *urilen, const uint8_t **in, size_t *inlen);
+int x509_distribution_point_name_print(FILE *fp, int fmt, int ind, const char *label,const uint8_t *a, size_t alen);
+
+int x509_uri_as_explicit_distribution_point_name_to_der(int index, const char *uri, size_t urilen, uint8_t **out, size_t *outlen);
+int x509_uri_as_explicit_distribution_point_name_from_der(int index, const char **uri, size_t *urilen, const uint8_t **in, size_t *inlen);
+
+/*
+DistributionPoint ::= SEQUENCE {
+	distributionPoint	[0] EXPLICIT DistributionPointName OPTIONAL,
+	reasons			[1] IMPLICIT ReasonFlags OPTIONAL,
+	cRLIssuer		[2] IMPLICIT GeneralNames OPTIONAL }
+*/
+int x509_uri_as_distribution_point_to_der(const char *uri, size_t urilen,
+	int reasons, const uint8_t *crl_issuer, size_t crl_issuer_len,
+	uint8_t **out, size_t *outlen);
+int x509_uri_as_distribution_point_from_der(const char **uri, size_t *urilen,
+	int *reasons, const uint8_t **crl_issuer, size_t *crl_issuer_len,
+	const uint8_t **in, size_t *inlen);
+int x509_distribution_point_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen);
+
+/*
+DistributionPoints ::= SEQUENCE OF DistributionPoint
+*/
+int x509_uri_as_distribution_points_to_der(const char *uri, size_t urilen,
+	int reasons, const uint8_t *crl_issuer, size_t crl_issuer_len,
+	uint8_t **out, size_t *outlen);
+int x509_uri_as_distribution_points_from_der(const char **uri, size_t *urilen,
+	int *reasons, const uint8_t **crl_issuer, size_t *crl_issuer_len,
+	const uint8_t **in, size_t *inlen);
+int x509_distribution_points_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen);
+
+
+/*
+CRLDistributionPoints ::= SEQUENCE SIZE (1..MAX) OF DistributionPoint
+*/
+#define x509_crl_distribution_points_to_der(d,dlen,out,outlen) x509_distribution_points_to_der(d,dlen,out,outlen)
+#define x509_crl_distribution_points_from_der(d,dlen,in,inlen) x509_distribution_points_from_der(d,dlen,in,inlen)
+#define x509_crl_distribution_points_print(fp,fmt,ind,label,d,dlen) x509_distribution_points_print(fp,fmt,ind,label,d,dlen)
+
+
+/*
+InhibitAnyPolicy ::= SkipCerts
+SkipCerts ::= INTEGER (0..MAX)
+*/
+#define x509_inhibit_any_policy_to_der(val,out,outlen) asn1_int_to_der(val,out,outlen)
+#define x509_inhibit_any_policy_from_der(val,in,inlen) asn1_int_from_der(val,in,inlen)
+
+/*
+FreshestCRL ::= CRLDistributionPoints
+ */
+#define x509_freshest_crl_to_der(d,dlen,out,outlen) x509_crl_distribution_points_to_der(d,dlen,out,outlen)
+#define x509_freshest_crl_from_der(d,dlen,in,inlen) x509_crl_distribution_points_from_der(d,dlen,in,inlen)
+#define x509_freshest_crl_print(fp,fmt,ind,label,d,dlen) x509_crl_distribution_points_print(fp,fmt,ind,label,d,dlen)
+
+/*
+Netscape-Defined Certificate Extensions
+https://docs.oracle.com/cd/E19957-01/816-5533-10/ext.htm#1023061
+
+NetscapeCertType ::= BIT STRING
+
+	bit 0: SSL Client certificate
+	bit 1: SSL Server certificate
+	bit 2: S/MIME certificate
+	bit 3: Object-signing certificate
+	bit 4: Reserved for future use
+	bit 5: SSL CA certificate
+	bit 6: S/MIME CA certificate
+	bit 7: Object-signing CA certificate
+
+NetscapeCertComment ::= IA5String
+*/
+int x509_netscape_cert_type_print(FILE *fp, int fmt, int ind, const char *label, int bits);
+
+int x509_exts_check(const uint8_t *exts, size_t extslen, int cert_type,
+	int *path_len_constraints);
+
+/*
+AuthorityInfoAccessSyntax ::= SEQUENCE OF AccessDescription
+
+AccessDescription ::= SEQUENCE {
+	accessMethod	OBJECT IDENTIFIER,
+	accessLocation	GeneralName }
+
+accessMethods:
+	OID_ad_ca_issuers
+	OID_ad_ocsp
+*/
+const char *x509_access_method_name(int oid);
+int x509_access_method_from_name(const char *name);
+int x509_access_method_to_der(int oid, uint8_t **out, size_t *outlen);
+int x509_access_method_from_der(int *oid, const uint8_t **in, size_t *inlen);
+
+int x509_access_description_to_der(int oid, const char *uri, size_t urilen, uint8_t **out, size_t *outlen);
+int x509_access_description_from_der(int *oid, const char **uri, size_t *urilen, const uint8_t **in, size_t *inlen);
+int x509_access_description_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen);
+
+int x509_authority_info_access_to_der(
+	const char *ca_issuers_uri, size_t ca_issuers_urilen,
+	const char *ocsp_uri, size_t ocsp_urilen,
+	uint8_t **out, size_t *outlen);
+int x509_authority_info_access_from_der(
+	const char **ca_issuers_uri, size_t *ca_issuers_urilen,
+	const char **ocsp_uri, size_t *ocsp_urilen,
+	const uint8_t **in, size_t *inlen);
+int x509_authority_info_access_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen);
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+

+ 81 - 0
components/gmssl/include/gmssl/x509_req.h

@@ -0,0 +1,81 @@
+/*
+ *  Copyright 2014-2022 The GmSSL Project. All Rights Reserved.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the License); you may
+ *  not use this file except in compliance with the License.
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ */
+
+
+#ifndef GMSSL_X509_REQ_H
+#define GMSSL_X509_REQ_H
+
+
+#include <time.h>
+#include <string.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <gmssl/sm2.h>
+#include <gmssl/oid.h>
+#include <gmssl/asn1.h>
+#include <gmssl/x509.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+from RFC 2986
+
+CertificationRequestInfo ::= SEQUENCE {
+	version                   INTEGER { v1(0) },
+	subject                   Name,
+	subjectPKInfo             SubjectPublicKeyInfo,
+	attributes                [0] IMPLICIT SET OF Attribute }
+*/
+int x509_request_info_to_der(int version, const uint8_t *subject, size_t subject_len,
+	const SM2_KEY *subject_public_key, const uint8_t *attrs, size_t attrs_len,
+	uint8_t **out, size_t *outlen);
+int x509_request_info_from_der(int *version, const uint8_t **subject, size_t *subject_len,
+	SM2_KEY *subject_public_key, const uint8_t **attrs, size_t *attrs_len,
+	const uint8_t **in, size_t *inlen);
+int x509_request_info_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen);
+
+/*
+CertificationRequest ::= SEQUENCE {
+	certificationRequestInfo  CertificationRequestInfo,
+	signatureAlgorithm        AlgorithmIdentifier,
+	signature                 BIT STRING }
+*/
+int x509_req_sign_to_der(
+	int version,
+	const uint8_t *subject, size_t subject_len,
+	const SM2_KEY *subject_public_key,
+	const uint8_t *attrs, size_t attrs_len,
+	int signature_algor,
+	const SM2_KEY *sign_key, const char *signer_id, size_t signer_id_len,
+	uint8_t **out, size_t *outlen);
+int x509_req_verify(const uint8_t *req, size_t reqlen,
+	const char *signer_id, size_t signer_id_len);
+int x509_req_get_details(const uint8_t *req, size_t reqlen,
+	int *verison,
+	const uint8_t **subject, size_t *subject_len,
+	SM2_KEY *subject_public_key,
+	const uint8_t **attributes, size_t *attributes_len,
+	int *signature_algor,
+	const uint8_t **signature, size_t *signature_len);
+int x509_req_to_der(const uint8_t *a, size_t alen, uint8_t **out, size_t *outlen);
+int x509_req_from_der(const uint8_t **a, size_t *alen, const uint8_t **in, size_t *inlen);
+int x509_req_to_pem(const uint8_t *req, size_t reqlen, FILE *fp);
+int x509_req_from_pem(uint8_t *req, size_t *reqlen, size_t maxlen, FILE *fp);
+int x509_req_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *req, size_t reqlen);
+
+int x509_req_new_from_pem(uint8_t **req, size_t *reqlen, FILE *fp);
+int x509_req_new_from_file(uint8_t **req, size_t *reqlen, const char *file);
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif

+ 147 - 0
components/gmssl/include/gmssl/zuc.h

@@ -0,0 +1,147 @@
+/*
+ *  Copyright 2014-2022 The GmSSL Project. All Rights Reserved.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the License); you may
+ *  not use this file except in compliance with the License.
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ */
+
+
+#ifndef GMSSL_ZUC_H
+#define GMSSL_ZUC_H
+
+
+#include <stdlib.h>
+#include <stdint.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/*
+ZUC Public API
+
+	ZUC_KEY_SIZE
+	ZUC_IV_SIZE
+	ZUC_MAC_SIZE
+
+	ZUC_CTX
+	zuc_encrypt_init
+	zuc_encrypt_update
+	zuc_encrypt_finish
+	zuc_decrypt_init
+	zuc_decrypt_update
+	zuc_decrypt_finish
+
+	ZUC_MAC_CTX
+	zuc_mac_init
+	zuc_mac_update
+	zuc_mac_finish
+
+	zuc_eea_encrypt
+	zuc_eia_generate_mac
+*/
+
+
+# define ZUC_KEY_SIZE	16
+# define ZUC_IV_SIZE	16
+# define ZUC_MAC_SIZE	4
+
+typedef uint32_t ZUC_BIT;
+typedef uint32_t ZUC_UINT5;
+typedef uint8_t  ZUC_UINT6;
+typedef uint32_t ZUC_UINT15;
+typedef uint32_t ZUC_UINT31;
+typedef uint32_t ZUC_UINT32;
+
+typedef struct {
+	ZUC_UINT31 LFSR[16];
+	ZUC_UINT32 R1;
+	ZUC_UINT32 R2;
+} ZUC_STATE;
+
+void zuc_init(ZUC_STATE *state, const uint8_t key[ZUC_KEY_SIZE], const uint8_t iv[ZUC_IV_SIZE]);
+void zuc_generate_keystream(ZUC_STATE *state, size_t nwords, ZUC_UINT32 *words);
+ZUC_UINT32 zuc_generate_keyword(ZUC_STATE *state);
+void zuc_encrypt(ZUC_STATE *state, const uint8_t *in, size_t inlen, uint8_t *out);
+
+typedef struct ZUC_MAC_CTX_st {
+	ZUC_UINT31 LFSR[16];
+	ZUC_UINT32 R1;
+	ZUC_UINT32 R2;
+	ZUC_UINT32 T;
+	ZUC_UINT32 K0;
+	uint8_t buf[4];
+	size_t buflen;
+} ZUC_MAC_CTX;
+
+void zuc_mac_init(ZUC_MAC_CTX *ctx, const uint8_t key[ZUC_KEY_SIZE], const uint8_t iv[ZUC_IV_SIZE]);
+void zuc_mac_update(ZUC_MAC_CTX *ctx, const uint8_t *data, size_t len);
+void zuc_mac_finish(ZUC_MAC_CTX *ctx, const uint8_t *data, size_t nbits, uint8_t mac[ZUC_MAC_SIZE]);
+
+#define ZUC_EEA_ENCRYPT_NWORDS(nbits) ((nbits + 31)/32)
+#define ZUC_EEA_ENCRYPT_NBYTES(nbits) (ZUC_EEA_ENCRYPT_NWORDS(nbits)*4)
+void zuc_eea_encrypt(const ZUC_UINT32 *in, ZUC_UINT32 *out, size_t nbits,
+	const uint8_t key[ZUC_KEY_SIZE], ZUC_UINT32 count, ZUC_UINT5 bearer,
+	ZUC_BIT direction);
+ZUC_UINT32 zuc_eia_generate_mac(const ZUC_UINT32 *data, size_t nbits,
+	const uint8_t key[ZUC_KEY_SIZE], ZUC_UINT32 count, ZUC_UINT5 bearer,
+	ZUC_BIT direction);
+
+
+# define ZUC256_KEY_SIZE	32
+# define ZUC256_IV_SIZE		23
+# define ZUC256_MAC32_SIZE	4
+# define ZUC256_MAC64_SIZE	8
+# define ZUC256_MAC128_SIZE	16
+# define ZUC256_MIN_MAC_SIZE	ZUC256_MAC32_SIZE
+# define ZUC256_MAX_MAC_SIZE	ZUC256_MAC128_SIZE
+
+typedef ZUC_STATE ZUC256_STATE;
+
+void zuc256_init(ZUC256_STATE *state, const uint8_t key[ZUC256_KEY_SIZE], const uint8_t iv[ZUC256_IV_SIZE]);
+#define zuc256_generate_keystream(state,nwords,words) zuc_generate_keystream(state,nwords,words)
+#define zuc256_generate_keyword(state) zuc_generate_keyword(state)
+
+
+typedef struct ZUC256_MAC_CTX_st {
+	ZUC_UINT31 LFSR[16];
+	ZUC_UINT32 R1;
+	ZUC_UINT32 R2;
+	ZUC_UINT32 T[4];
+	ZUC_UINT32 K0[4];
+	uint8_t buf[4];
+	size_t buflen;
+	int macbits;
+} ZUC256_MAC_CTX;
+
+void zuc256_mac_init(ZUC256_MAC_CTX *ctx, const uint8_t key[ZUC256_KEY_SIZE],
+	const uint8_t iv[ZUC256_IV_SIZE], int macbits);
+void zuc256_mac_update(ZUC256_MAC_CTX *ctx, const uint8_t *data, size_t len);
+void zuc256_mac_finish(ZUC256_MAC_CTX *ctx, const uint8_t *data, size_t nbits, uint8_t mac[ZUC_MAC_SIZE]);
+
+
+// Public API
+
+typedef struct {
+	ZUC_STATE zuc_state;
+	uint8_t block[4];
+	size_t block_nbytes;
+} ZUC_CTX;
+
+int zuc_encrypt_init(ZUC_CTX *ctx, const uint8_t key[ZUC_KEY_SIZE], const uint8_t iv[ZUC_IV_SIZE]);
+int zuc_encrypt_update(ZUC_CTX *ctx, const uint8_t *in, size_t inlen, uint8_t *out, size_t *outlen);
+int zuc_encrypt_finish(ZUC_CTX *ctx, uint8_t *out, size_t *outlen);
+
+#define zuc_decrypt_init(ctx,key,iv) zuc_encrypt_init(ctx,key,iv)
+#define zuc_decrypt_update(ctx,in,inlen,out,outlen) zuc_encrypt_update(ctx,in,inlen,out,outlen)
+#define zuc_decrypt_finish(ctx,out,outlen) zuc_encrypt_finish(ctx,out,outlen)
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif

+ 0 - 6
components/gmssl/include/internal/ayconfig.h

@@ -1,6 +0,0 @@
-#ifndef AYCONFIG_H
-#define AYCONFIG_H
-
-#define OPENSSL_NO_OCB
-
-#endif //AYCONFIG_H

+ 0 - 123
components/gmssl/include/internal/ssl_random.h

@@ -1,123 +0,0 @@
-#ifndef HEADER_SSL_RANDOM_H
-#define HEADER_SSL_RANDOM_H
-
-/*
-Random Module
-
-Sample:
-ssl_random_context ctx;
-ssl_random_init(&ctx);
-ssl_random_seed(&ctx, NULL, 0);
-// ctx->drbg_ctx CAN BE USED TO hmac_drbg
-ssl_random_rand_int_array(&ctx, arr, 30);
-ssl_random_free(&ctx);
-
-*/
-
-#ifdef _WIN32
-#define _CRT_RAND_S
-#endif
-#include <stdlib.h>
-
-#include <time.h>
-#include <string.h>
-#include <openssl/modes.h>
-#include <mbedtls/md.h>
-#include <mbedtls/hmac_drbg.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#ifdef ANDROID_VER
-#include <sys/system_properties.h>
-#include <android/sensor.h>
-#include <android/looper.h>
-#endif
-
-// Control HMAC-DRBG Hash Algorithm
-// Attention! Use #define to set it
-#ifndef RANDOM_HASH_ALGORITHM
-#define RANDOM_HASH_ALGORITHM MD_SM3
-#endif
-
-// SET ANDROID SENSOR
-// NOTE: https://developer.android.com/ndk/reference/group/sensor
-//#define ENABLE_SEED_ANDROID_SENSOR
-#define SEED_DEFAULT_SENSOR ASENSOR_TYPE_MAGNETIC_FIELD
-
-// SET iOS SENSOR
-// TODO: some bugs need be fixed (Issue #4)
-#define ENABLE_SEED_IOS_SENSOR
-
-// For Android test
-//#define _DEBUG_
-
-// static unsigned int SSLRandomContextCount = 0;
-
-// HMAC-DRBG Random Class
-typedef struct {
-    short isInitial;
-    short isSeeded;
-
-    unsigned char hashLen;
-    unsigned char *hash;
-
-    const mbedtls_md_info_t *md_info;     /*!<  Hash Type Info    */
-    mbedtls_md_context_t *md_ctx;         /*!<  MD Context        */
-    mbedtls_hmac_drbg_context *drbg_ctx;  /*!<  HMAC DRBG Context */
-} ssl_random_context;
-
-// Init Random Context
-int ssl_random_init(ssl_random_context *ctx);
-
-// Set or reset a seed
-int ssl_random_seed(void* rand_ctx, unsigned char *seed_buf, size_t buf_size);
-int ssl_random_seed_with_option(void *rand_ctx, unsigned char *seed_buf, size_t buf_size, int options);
-
-// Rand a list of Number
-int ssl_random_rand(void *rand_ctx, unsigned char *output, size_t size);
-
-// Rand a list of int32
-int ssl_random_rand_int_array(ssl_random_context *ctx, int *output, int count);
-
-// Rand a list of Uint32
-int ssl_random_rand_uint_array(ssl_random_context *ctx, unsigned int *output, int count);
-
-// Release random context
-void ssl_random_free(ssl_random_context *ctx);
-
-// Shuffle unsigned char array
-int ssl_random_shuffle_u8(u8 *list, int len);
-
-// Rand a list of int32 (if ctx==NULL, then init a global ctx)
-int ssl_random_list(ssl_random_context* ctx, int *list, int len);
-
-// ERROR define
-#define SSL_RANDOM_ERROR_HASH_ALGO_NOT_FOUND -0xF101
-#define SSL_RANDOM_ERROR_NOT_INITIAL -0xF102
-#define SSL_RANDOM_ERROR_NOT_SEEDED -0xF103
-#define SSL_RANDOM_ERROR_OUT_SIZE_TO_LARGE -0xF104
-#define SSL_RANDOM_ERROR_INVLIAD_SIZE -0xF105
-
-// OPTION define
-#define SSL_RANDOM_DISABLE_TIME 0x1
-#define SSL_RANDOM_DISABLE_URANDOM 0x2
-#define SSL_RANDOM_DISABLE_CPU_CYCLE 0x4
-#define SSL_RANDOM_DISABLE_RAND_S 0x8
-#define SSL_RANDOM_DISABLE_ANDROID_INFO 0x10
-#define SSL_RANDOM_DISABLE_ANDROID_SENSOR 0x20
-
-// OTHER define
-#define SSL_RANDOM_MAX_BYTES_COUNT 1024
-#define SSL_RANDOM_MAX_INT_COUNT (1024/4)
-
-// ------ UTIL ------
-
-
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif

+ 0 - 12
components/gmssl/include/modes_lcl.h

@@ -1,12 +0,0 @@
-/*
- * Copyright 2010-2016 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
- * in the file LICENSE in the source distribution or at
- * https://www.openssl.org/source/license.html
- */
-
-#include <internal/ayconfig.h>
-
-#include <openssl/modes.h>

+ 0 - 430
components/gmssl/include/openssl/modes.h

@@ -1,430 +0,0 @@
-/*
- * Copyright 2008-2016 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
- * in the file LICENSE in the source distribution or at
- * https://www.openssl.org/source/license.html
- */
-
-#ifndef HEADER_MODE_H
-#define HEADER_MODE_H
-
-#include <internal/ayconfig.h>
-#include <stddef.h>
-#include <string.h>
-#include <stdlib.h>
-#include <stdio.h>
-
-#ifdef  __cplusplus
-extern "C" {
-#endif
-typedef void (*block128_f) (const unsigned char in[16],
-                            unsigned char out[16], const void *key);
-
-typedef void (*cbc128_f) (const unsigned char *in, unsigned char *out,
-                          size_t len, const void *key,
-                          unsigned char ivec[16], int enc);
-
-typedef void (*ctr128_f) (const unsigned char *in, unsigned char *out,
-                          size_t blocks, const void *key,
-                          const unsigned char ivec[16]);
-
-typedef void (*ccm128_f) (const unsigned char *in, unsigned char *out,
-                          size_t blocks, const void *key,
-                          const unsigned char ivec[16],
-                          unsigned char cmac[16]);
-
-void ctr128_inc(unsigned char *counter);
-void ctr128_dec(unsigned char *ctr_buf);
-void ctr128_init(unsigned char nonce[4], unsigned char iv[8], unsigned char ctr_buf[16]);
-
-
-void CRYPTO_cbc128_encrypt(const unsigned char *in, unsigned char *out,
-                           size_t len, const void *key,
-                           unsigned char ivec[16], block128_f block);
-void CRYPTO_cbc128_decrypt(const unsigned char *in, unsigned char *out,
-                           size_t len, const void *key,
-                           unsigned char ivec[16], block128_f block);
-
-void CRYPTO_ctr128_encrypt(const unsigned char *in, unsigned char *out,
-                           size_t len, const void *key,
-                           unsigned char ivec[16],
-                           unsigned char ecount_buf[16], unsigned int *num,
-                           block128_f block);
-
-void CRYPTO_ctr128_encrypt_ctr32(const unsigned char *in, unsigned char *out,
-                                 size_t len, const void *key,
-                                 unsigned char ivec[16],
-                                 unsigned char ecount_buf[16],
-                                 unsigned int *num, ctr128_f ctr);
-
-void CRYPTO_ofb128_encrypt(const unsigned char *in, unsigned char *out,
-                           size_t len, const void *key,
-                           unsigned char ivec[16], int *num,
-                           block128_f block);
-
-void CRYPTO_cfb128_encrypt(const unsigned char *in, unsigned char *out,
-                           size_t len, const void *key,
-                           unsigned char ivec[16], int *num,
-                           int enc, block128_f block);
-void CRYPTO_cfb128_8_encrypt(const unsigned char *in, unsigned char *out,
-                             size_t length, const void *key,
-                             unsigned char ivec[16], int *num,
-                             int enc, block128_f block);
-void CRYPTO_cfb128_1_encrypt(const unsigned char *in, unsigned char *out,
-                             size_t bits, const void *key,
-                             unsigned char ivec[16], int *num,
-                             int enc, block128_f block);
-
-size_t CRYPTO_cts128_encrypt_block(const unsigned char *in,
-                                   unsigned char *out, size_t len,
-                                   const void *key, unsigned char ivec[16],
-                                   block128_f block);
-size_t CRYPTO_cts128_encrypt(const unsigned char *in, unsigned char *out,
-                             size_t len, const void *key,
-                             unsigned char ivec[16], cbc128_f cbc);
-size_t CRYPTO_cts128_decrypt_block(const unsigned char *in,
-                                   unsigned char *out, size_t len,
-                                   const void *key, unsigned char ivec[16],
-                                   block128_f block);
-size_t CRYPTO_cts128_decrypt(const unsigned char *in, unsigned char *out,
-                             size_t len, const void *key,
-                             unsigned char ivec[16], cbc128_f cbc);
-
-size_t CRYPTO_nistcts128_encrypt_block(const unsigned char *in,
-                                       unsigned char *out, size_t len,
-                                       const void *key,
-                                       unsigned char ivec[16],
-                                       block128_f block);
-size_t CRYPTO_nistcts128_encrypt(const unsigned char *in, unsigned char *out,
-                                 size_t len, const void *key,
-                                 unsigned char ivec[16], cbc128_f cbc);
-size_t CRYPTO_nistcts128_decrypt_block(const unsigned char *in,
-                                       unsigned char *out, size_t len,
-                                       const void *key,
-                                       unsigned char ivec[16],
-                                       block128_f block);
-size_t CRYPTO_nistcts128_decrypt(const unsigned char *in, unsigned char *out,
-                                 size_t len, const void *key,
-                                 unsigned char ivec[16], cbc128_f cbc);
-
-typedef struct gcm128_context GCM128_CONTEXT;
-
-GCM128_CONTEXT *CRYPTO_gcm128_new(void *key, block128_f block);
-void CRYPTO_gcm128_init(GCM128_CONTEXT *ctx, void *key, block128_f block);
-void CRYPTO_gcm128_setiv(GCM128_CONTEXT *ctx, const unsigned char *iv,
-                         size_t len);
-int CRYPTO_gcm128_aad(GCM128_CONTEXT *ctx, const unsigned char *aad,
-                      size_t len);
-int CRYPTO_gcm128_encrypt(GCM128_CONTEXT *ctx,
-                          const unsigned char *in, unsigned char *out,
-                          size_t len);
-int CRYPTO_gcm128_decrypt(GCM128_CONTEXT *ctx,
-                          const unsigned char *in, unsigned char *out,
-                          size_t len);
-int CRYPTO_gcm128_encrypt_ctr32(GCM128_CONTEXT *ctx,
-                                const unsigned char *in, unsigned char *out,
-                                size_t len, ctr128_f stream);
-int CRYPTO_gcm128_decrypt_ctr32(GCM128_CONTEXT *ctx,
-                                const unsigned char *in, unsigned char *out,
-                                size_t len, ctr128_f stream);
-int CRYPTO_gcm128_finish(GCM128_CONTEXT *ctx, const unsigned char *tag,
-                         size_t len);
-void CRYPTO_gcm128_tag(GCM128_CONTEXT *ctx, unsigned char *tag, size_t len);
-void CRYPTO_gcm128_release(GCM128_CONTEXT *ctx);
-
-/*
-*  Created on: 2017.10.18
-*      Author: lzj
-*
-*  encrypted file format:
-*
-*  MAGIC_TAG  : AYCF-SM4-GCM
-*  VERSION	  : 1
-*  TAG		    : cipher tag
-*  SIZE	      : plaintext size
-*  CONTENT	  : cipher text
-*
-*	how to use?  see the test function under below .check out!
-*/
-#define GCM_FILE_MAGIC_TAG "AYCF-SM4-GCM"
-#define GCM_FILE_MAGIC_TAG_LEN 12
-#define GCM_FILE_VERSION 1
-#define GCM_FILE_TAG_LEN 16
-#define GCM_FILE_MAX_BLOCK_LEN 128
-
-typedef struct {
-		GCM128_CONTEXT *gcm;
-		unsigned char tag[GCM_FILE_TAG_LEN];
-} gcmf_context;
-
-int gcmf_init(gcmf_context *ctx, void * key, block128_f block);
-int gcmf_free(gcmf_context *ctx);
-int gcmf_set_iv(gcmf_context *ctx, const unsigned char * iv, size_t len);
-int gcmf_encrypt_file(gcmf_context * ctx, char *infpath, char *outfpath);
-int gcmf_decrypt_file(gcmf_context * ctx, char *infpath, char *outfpath);
-
-typedef struct ccm128_context CCM128_CONTEXT;
-
-void CRYPTO_ccm128_init(CCM128_CONTEXT *ctx,
-                        unsigned int M, unsigned int L, void *key,
-                        block128_f block);
-int CRYPTO_ccm128_setiv(CCM128_CONTEXT *ctx, const unsigned char *nonce,
-                        size_t nlen, size_t mlen);
-void CRYPTO_ccm128_aad(CCM128_CONTEXT *ctx, const unsigned char *aad,
-                       size_t alen);
-int CRYPTO_ccm128_encrypt(CCM128_CONTEXT *ctx, const unsigned char *inp,
-                          unsigned char *out, size_t len);
-int CRYPTO_ccm128_decrypt(CCM128_CONTEXT *ctx, const unsigned char *inp,
-                          unsigned char *out, size_t len);
-int CRYPTO_ccm128_encrypt_ccm64(CCM128_CONTEXT *ctx, const unsigned char *inp,
-                                unsigned char *out, size_t len,
-                                ccm128_f stream);
-int CRYPTO_ccm128_decrypt_ccm64(CCM128_CONTEXT *ctx, const unsigned char *inp,
-                                unsigned char *out, size_t len,
-                                ccm128_f stream);
-size_t CRYPTO_ccm128_tag(CCM128_CONTEXT *ctx, unsigned char *tag, size_t len);
-
-typedef struct xts128_context XTS128_CONTEXT;
-
-int CRYPTO_xts128_encrypt(const XTS128_CONTEXT *ctx,
-                          const unsigned char iv[16],
-                          const unsigned char *inp, unsigned char *out,
-                          size_t len, int enc);
-
-size_t CRYPTO_128_wrap(void *key, const unsigned char *iv,
-                       unsigned char *out,
-                       const unsigned char *in, size_t inlen,
-                       block128_f block);
-
-size_t CRYPTO_128_unwrap(void *key, const unsigned char *iv,
-                         unsigned char *out,
-                         const unsigned char *in, size_t inlen,
-                         block128_f block);
-size_t CRYPTO_128_wrap_pad(void *key, const unsigned char *icv,
-                           unsigned char *out, const unsigned char *in,
-                           size_t inlen, block128_f block);
-size_t CRYPTO_128_unwrap_pad(void *key, const unsigned char *icv,
-                             unsigned char *out, const unsigned char *in,
-                             size_t inlen, block128_f block);
-
-#ifndef OPENSSL_NO_OCB
-typedef struct ocb128_context OCB128_CONTEXT;
-
-typedef void (*ocb128_f) (const unsigned char *in, unsigned char *out,
-                          size_t blocks, const void *key,
-                          size_t start_block_num,
-                          unsigned char offset_i[16],
-                          const unsigned char L_[][16],
-                          unsigned char checksum[16]);
-
-OCB128_CONTEXT *CRYPTO_ocb128_new(void *keyenc, void *keydec,
-                                  block128_f encrypt, block128_f decrypt,
-                                  ocb128_f stream);
-int CRYPTO_ocb128_init(OCB128_CONTEXT *ctx, void *keyenc, void *keydec,
-                       block128_f encrypt, block128_f decrypt,
-                       ocb128_f stream);
-int CRYPTO_ocb128_copy_ctx(OCB128_CONTEXT *dest, OCB128_CONTEXT *src,
-                           void *keyenc, void *keydec);
-int CRYPTO_ocb128_setiv(OCB128_CONTEXT *ctx, const unsigned char *iv,
-                        size_t len, size_t taglen);
-int CRYPTO_ocb128_aad(OCB128_CONTEXT *ctx, const unsigned char *aad,
-                      size_t len);
-int CRYPTO_ocb128_encrypt(OCB128_CONTEXT *ctx, const unsigned char *in,
-                          unsigned char *out, size_t len);
-int CRYPTO_ocb128_decrypt(OCB128_CONTEXT *ctx, const unsigned char *in,
-                          unsigned char *out, size_t len);
-int CRYPTO_ocb128_finish(OCB128_CONTEXT *ctx, const unsigned char *tag,
-                         size_t len);
-int CRYPTO_ocb128_tag(OCB128_CONTEXT *ctx, unsigned char *tag, size_t len);
-void CRYPTO_ocb128_cleanup(OCB128_CONTEXT *ctx);
-#endif                          /* OPENSSL_NO_OCB */
-
-#ifdef  __cplusplus
-}
-#endif
-
-
-#ifndef AISINOSSL_MODES_LCL
-#define AISINOSSL_MODES_LCL
-
-#if (defined(_WIN32) || defined(_WIN64)) && !defined(__MINGW32__)
-typedef __int64 i64;
-typedef unsigned __int64 u64;
-# define U64(C) C##UI64
-#elif defined(__arch64__)
-typedef long i64;
-typedef unsigned long u64;
-# define U64(C) C##UL
-#else
-typedef long long i64;
-typedef unsigned long long u64;
-# define U64(C) C##ULL
-#endif
-
-typedef unsigned int u32;
-typedef unsigned char u8;
-
-#define STRICT_ALIGNMENT 1
-#ifndef PEDANTIC
-# if defined(__i386)    || defined(__i386__)    || \
-     defined(__x86_64)  || defined(__x86_64__)  || \
-     defined(_M_IX86)   || defined(_M_AMD64)    || defined(_M_X64) || \
-     defined(__aarch64__)                       || \
-     defined(__s390__)  || defined(__s390x__)
-#  undef STRICT_ALIGNMENT
-# endif
-#endif
-
-#if !defined(PEDANTIC) && !defined(OPENSSL_NO_ASM) && !defined(OPENSSL_NO_INLINE_ASM)
-# if defined(__GNUC__) && __GNUC__>=2
-#  if defined(__x86_64) || defined(__x86_64__)
-#   define BSWAP8(x) ({ u64 ret_=(x);                   \
-                        __asm__ ("bswapq %0  "              \
-                        : "+r"(ret_));   ret_;          })
-#   define BSWAP4(x) ({ u32 ret_=(x);                   \
-                        __asm__ ("bswapl %0 "               \
-                        : "+r"(ret_));   ret_;          })
-#  elif (defined(__i386) || defined(__i386__)) && !defined(I386_ONLY)
-#   define BSWAP8(x) ({ u32 lo_=(u64)(x)>>32,hi_=(x);   \
-                        asm ("bswapl %0; bswapl %1"     \
-                        : "+r"(hi_),"+r"(lo_));         \
-                        (u64)hi_<<32|lo_;               })
-#   define BSWAP4(x) ({ u32 ret_=(x);                   \
-                        asm ("bswapl %0"                \
-                        : "+r"(ret_));   ret_;          })
-#  elif defined(__aarch64__)
-#   define BSWAP8(x) ({ u64 ret_;                       \
-                        asm ("rev %0,%1"                \
-                        : "=r"(ret_) : "r"(x)); ret_;   })
-#   define BSWAP4(x) ({ u32 ret_;                       \
-                        asm ("rev %w0,%w1"              \
-                        : "=r"(ret_) : "r"(x)); ret_;   })
-#  elif (defined(__arm__) || defined(__arm)) && !defined(STRICT_ALIGNMENT)
-#   define BSWAP8(x) ({ u32 lo_=(u64)(x)>>32,hi_=(x);   \
-                        asm ("rev %0,%0; rev %1,%1"     \
-                        : "+r"(hi_),"+r"(lo_));         \
-                        (u64)hi_<<32|lo_;               })
-#   define BSWAP4(x) ({ u32 ret_;                       \
-                        asm ("rev %0,%1"                \
-                        : "=r"(ret_) : "r"((u32)(x)));  \
-                        ret_;                           })
-#  endif
-# elif defined(_MSC_VER)
-#  if _MSC_VER>=1300
-#   pragma intrinsic(_byteswap_uint64,_byteswap_ulong)
-#   define BSWAP8(x)    _byteswap_uint64((u64)(x))
-#   define BSWAP4(x)    _byteswap_ulong((u32)(x))
-#  elif defined(_M_IX86)
-__inline u32 _bswap4(u32 val)
-{
-	_asm mov eax, val _asm bswap eax
-}
-#   define BSWAP4(x)    _bswap4(x)
-#  endif
-# endif
-#endif
-#if defined(BSWAP4) && !defined(STRICT_ALIGNMENT)
-# define GETU32(p)       BSWAP4(*(const u32 *)(p))
-# define PUTU32(p,v)     *(u32 *)(p) = BSWAP4(v)
-#else
-# define GETU32(p)       ((u32)(p)[0]<<24|(u32)(p)[1]<<16|(u32)(p)[2]<<8|(u32)(p)[3])
-# define PUTU32(p,v)     ((p)[0]=(u8)((v)>>24),(p)[1]=(u8)((v)>>16),(p)[2]=(u8)((v)>>8),(p)[3]=(u8)(v))
-#endif
-/*- GCM definitions */ typedef struct {
-	u64 hi, lo;
-} u128;
-
-#ifdef  TABLE_BITS
-# undef  TABLE_BITS
-#endif
-/*
-* Even though permitted values for TABLE_BITS are 8, 4 and 1, it should
-* never be set to 8 [or 1]. For further information see gcm128.c.
-*/
-#define TABLE_BITS 4
-
-struct gcm128_context {
-	/* Following 6 names follow names in GCM specification */
-	union {
-		u64 u[2];
-		u32 d[4];
-		u8 c[16];
-		size_t t[16 / sizeof(size_t)];
-	} Yi, EKi, EK0, len, Xi, H;
-	/*
-	* Relative position of Xi, H and pre-computed Htable is used in some
-	* assembler modules, i.e. don't change the order!
-	*/
-#if TABLE_BITS==8
-	u128 Htable[256];
-#else
-	u128 Htable[16];
-	void(*gmult) (u64 Xi[2], const u128 Htable[16]);
-	void(*ghash) (u64 Xi[2], const u128 Htable[16], const u8 *inp,
-		size_t len);
-#endif
-	unsigned int mres, ares;
-	block128_f block;
-	void *key;
-};
-
-struct xts128_context {
-	void *key1, *key2;
-	block128_f block1, block2;
-};
-
-struct ccm128_context {
-	union {
-		u64 u[2];
-		u8 c[16];
-	} nonce, cmac;
-	u64 blocks;
-	block128_f block;
-	void *key;
-};
-
-#ifndef OPENSSL_NO_OCB
-
-typedef union {
-	u64 a[2];
-	unsigned char c[16];
-} OCB_BLOCK;
-# define ocb_block16_xor(in1,in2,out) \
-    ( (out)->a[0]=(in1)->a[0]^(in2)->a[0], \
-      (out)->a[1]=(in1)->a[1]^(in2)->a[1] )
-# if STRICT_ALIGNMENT
-#  define ocb_block16_xor_misaligned(in1,in2,out) \
-    ocb_block_xor((in1)->c,(in2)->c,16,(out)->c)
-# else
-#  define ocb_block16_xor_misaligned ocb_block16_xor
-# endif
-
-struct ocb128_context {
-	/* Need both encrypt and decrypt key schedules for decryption */
-	block128_f encrypt;
-	block128_f decrypt;
-	void *keyenc;
-	void *keydec;
-	ocb128_f stream;    /* direction dependent */
-						/* Key dependent variables. Can be reused if key remains the same */
-	size_t l_index;
-	size_t max_l_index;
-	OCB_BLOCK l_star;
-	OCB_BLOCK l_dollar;
-	OCB_BLOCK *l;
-	/* Must be reset for each session */
-	u64 blocks_hashed;
-	u64 blocks_processed;
-	OCB_BLOCK tag;
-	OCB_BLOCK offset_aad;
-	OCB_BLOCK sum;
-	OCB_BLOCK offset;
-	OCB_BLOCK checksum;
-};
-#endif                          /* OPENSSL_NO_OCB */
-
-#endif /* AISINOSSL_MODES_LCL */
-
-#endif

+ 0 - 376
components/gmssl/include/sm2/sm2.h

@@ -1,376 +0,0 @@
-//
-// Created by  lzj on 2017/8/15.
-//
-
-#ifndef LIBCRYPTO_SM2_H
-#define LIBCRYPTO_SM2_H
-
-#include <internal/ssl_random.h>
-#include <mbedtls/ecp.h>
-#include <stddef.h>
-
-
-/*
- * sm2 Error codes
- */
-#define MBEDTLS_ERR_SM2_BAD_INPUT_DATA                    -0x7080  /**< Bad input parameters to function. */
-#define MBEDTLS_ERR_SM2_KEY_GEN_FAILED                    -0x7180  /**< Something failed during generation of a key. */
-#define MBEDTLS_ERR_SM2_KEY_CHECK_FAILED                  -0x7200  /**< Key failed to pass the library's validity check. */
-#define MBEDTLS_ERR_SM2_PUBLIC_FAILED                     -0x7280  /**< The public key operation failed. */
-#define MBEDTLS_ERR_SM2_PRIVATE_FAILED                    -0x7300  /**< The private key operation failed. */
-#define MBEDTLS_ERR_SM2_VERIFY_FAILED                     -0x7380  /**< The standard verification failed. */
-#define MBEDTLS_ERR_SM2_OUTPUT_TOO_LARGE                  -0x7400  /**< The output buffer for decryption is not large enough. */
-#define MBEDTLS_ERR_SM2_RNG_FAILED                        -0x7480  /**< The random generator failed to generate non-zeros. */
-#define MBEDTLS_ERR_SM2_ALLOC_FAILED                      -0x7500  /**< Failed to allocate memory. */
-
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/**
- *
- */
-typedef int (*get_rand_from_range)(mbedtls_mpi *k, mbedtls_mpi *range);
-
-/**
- * \brief           sm2 context structure
- */
-typedef struct {
-    mbedtls_ecp_group grp;      /*!<  elliptic curve used  group                 */
-    mbedtls_mpi d;              /*!<   secret value (private key)                */
-    mbedtls_ecp_point Pb;        /*!<   public value (public key)                 */
-} sm2_context;
-
-
-/**
- * \brief           Initialize context set default group
- *
- * \param ctx       Context to initialize
- *
- * \return          0 if successful,
- *                  MBEDTLS_ERR_MPI_XXX if initialization failed
- *                  MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE for unkownn groups
- */
-int sm2_init(sm2_context *ctx);
-
-/**
- * \brief           Free context
- *
- * \param ctx       Context to free
- */
-void sm2_free(sm2_context *ctx);
-
-/**
- * \brief           set private key by hex buf
- *
- * \param ctx       m2 context
- *
- * \param buf       private key hex buf
- *
- * \return          0 if successful,
- *                  or a MBEDTLS_ERR_MPI_XXX error code.
- */
-int sm2_read_string_private(sm2_context *ctx, const char *buf);
-
-/**
- * \brief           set public key by hex buf of point
- *
- * \param ctx       m2 context
- *
- * \param x         point x hex buf
- *
- * \param y         point y hex buf
- *
- * \return          0 if successful,
- *                  or a MBEDTLS_ERR_MPI_XXX error code.
- */
-int sm2_read_string_public(sm2_context *ctx, const char *x, const char *y);
-
-/**
- * \brief           Generate a  keypair.
- *                  Raw function that only does the core computation.
- *
- * \param ctx       sm2 context (no-null)
- *
- * \param f_rng     RNG function  (generate the private key suggest the sm3 drbg)
- *
- * \param p_rng     RNG parameter
- *
- * \return          0 if successful,
- *                  or a MBEDTLS_ERR_ECP_XXX or MBEDTLS_MPI_XXX error code
- */
-int sm2_gen_keypair(sm2_context *ctx, int (*f_rng)(void *, unsigned char *, size_t),
-                    void *p_rng);
-
-/**
- *
- * \brief           set sm2 group by hex string param
- *
- * \param ctx       sm2 context
- *
- * \param p         p hex string buffer 64 word
- *
- * \param a         a hex string buffer 64 word
- *
- * \param b         b hex string buffer 64 word
- *
- * \param gx        gx hex string buffer 64 word
- *
- * \param gy        gy hex string buffer 64 word
- *
- * \param n         n hex string buffer 64 word
- *
- * \return          0 if successful, or a MBEDTLS_ERR_MPI_XXX error code
- */
-int sm2_read_group_string(sm2_context *ctx, const char *p, const char *a, const char *b,
-                          const char *gx, const char *gy, const char *n);
-
-/**
- * \brief           Check that an mbedtls_mpi is a valid private key for this curve
- *
- * \param ctx       sm2 context
- *
- * \return          0 if point is a valid private key,
- *                  MBEDTLS_ERR_ECP_INVALID_KEY otherwise.
- */
-int sm2_check_private(sm2_context *ctx);
-
-
-/**
- * \brief           Check that an mbedtls_mpi_point is a valid public key for this curve
- *
- * \param ctx       sm2 context
- *
- * \return          0 if point is a valid private key,
- *                  MBEDTLS_ERR_ECP_INVALID_KEY otherwise.
- */
-int sm2_check_public(sm2_context *ctx);
-
-/**
- * \brief           generate the message H(m`), with sm3;
- *                  m` = Z || M
- *
- * \param ctx       sm2 context
- *
- * \param id        user id string
- *
- * \param idlen     id string length
- *
- * \param message   need digest message string
- *
- * \param msglen    message length
- *
- * \param out       result
- *
- * \return          0 if successful,otherwise
- *                  MBEDTLS_ERR_SM2_ALLOC_FAILED,MBEDTLS_ERR_MPI_ALLOC_FAILED
- *
- */
-int sm2_z_generate(sm2_context *ctx, const char *id, size_t idlen, const char *message,
-                   size_t msglen, unsigned char *out);
-
-/**
- * \brief           sm2 encrypt
- *
- * \param ctx       sm2 context
- *
- * \param buffer    bytes need to encrypt
- *
- * \param plen      string length
- *
- * \param out       cipher text in byte array (not hex string)
- *
- * \param max_out_len   out max length ,
- *                  if the len smaller than olen the encrypt option will failed
- *
- * \param olen      the cipher length
- *
- * \param f_rng     RNG function
- * \param p_rng     RNG parameter
- *
- * \return          0 if successful
- *                  otherwise MBEDTLS_ERR_SM2_OUTPUT_TOO_LARGE,
- *                  MBEDTLS_ERR_SM2_BAD_INPUT_DATA,MBEDTLS_ERR_SM2_ALLOC_FAILED
- *                  ,MBEDTLS_ERR_ECP_XXX or MBEDTLS_ERR_MPI_XXX
- */
-int sm2_do_encrypt(sm2_context *ctx, const unsigned char *buffer, size_t plen,
-                   unsigned char *out, size_t max_out_len, size_t *olen,
-                   int (*f_rng)(void *, unsigned char *, size_t), void *p_rng);
-
-/**
- * \brief           sm2 decrypt
- *
- * \param ctx       sm2 context
- *
- * \param cipher    cipher text need to decrypt ;
- *                  onte: the cipher are byte array ,them are not string
- *                  if you input the string ,should transform the string to byte
- *                  such as "120DEDF" is hex string, should make it to byte using the function you did
- *                  hexString2byte.
- *
- * \param clen      the cipher byte length
- *
- * \param out       the message in byte (not hex string)
- *
- * \param max_out_len out max length ,
- *                  if the len smaller than olen the decrypt option will failed
- *
- * \param olen      the out byte length
- *
- * \return          0 if successful
- *                  otherwise MBEDTLS_ERR_SM2_OUTPUT_TOO_LARGE,
- *                  MBEDTLS_ERR_SM2_BAD_INPUT_DATA,MBEDTLS_ERR_SM2_ALLOC_FAILED
- *                  ,MBEDTLS_ERR_ECP_XXX or MBEDTLS_ERR_MPI_XXX
- */
-int sm2_do_decrypt(sm2_context *ctx, const unsigned char *cipher, size_t clen,
-                   unsigned char *out, size_t max_out_len, size_t *olen);
-
-
-/**
- * \brief           sm2 sign byte (e)
- *
- * \param ctx       sm2 context
- *
- * \param dgst      the e in byte  (e = H(m))
- *
- * \param dgstlen   e length ,commonly is 32, that meaning 256 bits
- *
- * \param out       the (r,s) byte array ,which format is r||s. 64 word
- *
- * \param max_out_len out max length ,
- *                  if the len smaller than olen the sign option will failed
- *
- * \param olen      the out byte array length commonly is 64 word
- *
- * \param f_rng     RNG function
- * \param p_rng     RNG parameter
- *
- * \return          0 if successful
- *                  otherwise MBEDTLS_ERR_SM2_OUTPUT_TOO_LARGE,
- *                  MBEDTLS_ERR_SM2_BAD_INPUT_DATA,MBEDTLS_ERR_SM2_ALLOC_FAILED
- *                  ,MBEDTLS_ERR_ECP_XXX or MBEDTLS_ERR_MPI_XXX
- */
-int sm2_do_sign(sm2_context *ctx, const unsigned char *dgst, size_t dgstlen,
-                unsigned char *out, size_t max_out_len, size_t *olen,
-                int (*f_rng)(void *, unsigned char *, size_t), void *p_rng);
-
-/**
- * \brief           sm2 sign
- *
- * \param ctx       sm2 context
- *
- * \param id        user id such as user mail string
- *
- * \param idlen     id string length
- *
- * \param message   need sign message string
- *
- * \param msglen    message length
- *
- * \param out       the (r,s) byte array ,which format is r||s. 64 word
- *
- * \param max_out_len out max length ,
- *                  if the len smaller than olen the sign option will failed
- *
- * \param olen      the out byte array length commonly is 64 word
- *
- * \param f_rng     RNG function
- * \param p_rng     RNG parameter
- *
- * \return          0 if successful
- *                  otherwise MBEDTLS_ERR_SM2_OUTPUT_TOO_LARGE,
- *                  MBEDTLS_ERR_SM2_BAD_INPUT_DATA,MBEDTLS_ERR_SM2_ALLOC_FAILED
- *                  ,MBEDTLS_ERR_ECP_XXX or MBEDTLS_ERR_MPI_XXX
- */
-int sm2_do_id_sign(sm2_context *ctx, const char *id, size_t idlen, const char *message,
-                   size_t msglen, unsigned char *out, size_t max_out_len, size_t *olen,
-                   int (*f_rng)(void *, unsigned char *, size_t), void *p_rng);
-
-/**
- *
- * \brief           sm2 sign verify byte (e)
- *
- * \param ctx       sm2 context
- *
- * \param message   the e in byte  (e = H(m))
- *
- * \param msglen    e length ,commonly is 32 that meaning 256 bite
- *
- * \param dgst      need to verify byte array (not hex string)
- *                  onte: the buff are byte array ,them are not string
- *                  if you input the string ,should transform the string to byte
- *                  such as "120DEDF" is hex string, should make it to byte using the function you did
- *                  hexString2byte.
- *
- * \param dgstlen   dgst byte array length
- *
- * \return          0 if successful
- *                  otherwise MBEDTLS_ERR_SM2_OUTPUT_TOO_LARGE,
- *                  MBEDTLS_ERR_SM2_BAD_INPUT_DATA,MBEDTLS_ERR_SM2_ALLOC_FAILED
- *                  ,MBEDTLS_ERR_ECP_XXX or MBEDTLS_ERR_MPI_XXX
- */
-int sm2_do_verify(sm2_context *ctx, const unsigned char *message, size_t msglen,
-                  const unsigned char *dgst, size_t dgstlen);
-
-/**
- *
- * \brief           sm2 sign verify
- *
- * \param ctx       sm2 context
- *
- * \param id        user id such as user mail string
- *
- * \param idlen     id string length
- *
- * \param message   received message string
- *
- * \param msglen    messgae string length
- *
- * \param dgst      need to verify byte array (not hex string)
- *                  onte: the buff are byte array ,them are not string
- *                  if you input the string ,should transform the string to byte
- *                  such as "120DEDF" is hex string, should make it to byte using the function you did
- *                  hexString2byte.
- *
- * \param dgstlen   dgst byte array length
- *
- * \return          0 if successful
- *                  otherwise MBEDTLS_ERR_SM2_OUTPUT_TOO_LARGE,
- *                  MBEDTLS_ERR_SM2_BAD_INPUT_DATA,MBEDTLS_ERR_SM2_ALLOC_FAILED
- *                  ,MBEDTLS_ERR_ECP_XXX or MBEDTLS_ERR_MPI_XXX
- */
-
-int sm2_do_id_verify(sm2_context *ctx, const char *id, size_t idlen, const char *message,
-                     size_t msglen, const unsigned char *dgst, size_t dgstlen);
-
-/**
- * \brief           sm2 context copy
- *
- * \param dst       dst sm2 context
- *
- * \param src       const src sm2 context
- *
- * \return         0 if successful
- *                  otherwise MBEDTLS_ERR_SM2_OUTPUT_TOO_LARGE,
- *                  MBEDTLS_ERR_SM2_BAD_INPUT_DATA,MBEDTLS_ERR_SM2_ALLOC_FAILED
- *                  ,MBEDTLS_ERR_ECP_XXX or MBEDTLS_ERR_MPI_XXX
- */
-int sm2_copy(sm2_context *dst, const sm2_context *src);
-
-/**
- * \brief           sm2 test
- *
- * \param verbose   0 is nothing ;
- *                  1 is test encrypt and decrypt;
- *                  2 is test sign and verify
- *
- * @return          0 if successful
- */
-int mbedtls_sm2_self_test(int verbose);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif //LIBCRYPTO_SM2_H

+ 0 - 115
components/gmssl/include/sm3/sm3.h

@@ -1,115 +0,0 @@
-/**
- *
- *
- * \file        sm3.h
- *
- * \brief       this file is header file for sm3(chinese business Digital Digest).
- *              and  compatible md framework.
- *
- * \anchor      lzj
- *
- * \date        2017/8/14
- *
- *
- */
-
-
-#ifndef LIBCRYPTO_SM3_H
-#define LIBCRYPTO_SM3_H
-
-
-
-#include <stddef.h>
-#include <stdint.h>
-
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/**
- * \brief          SM3 context structure
- */
-typedef struct {
-    uint32_t total[2];          /*!< number of bytes processed  */
-    uint32_t state[8];          /*!< intermediate digest state  */
-    unsigned char buffer[64];   /*!< data block being processed */
-} sm3_context;
-
-
-/**
- * \brief          Initialize SM3 context
- *
- * \param ctx      SM3 context to be initialized
- */
-void sm3_init(sm3_context *ctx);
-
-/**
- * \brief          Clear SM3 context
- *
- * \param ctx      SM3 context to be cleared
- */
-void sm3_free(sm3_context *ctx);
-
-/**
- * \brief          Clone (the state of) a SM3 context
- *
- * \param dst      The destination context
- * \param src      The context to be cloned
- */
-void sm3_clone(sm3_context *dst, const sm3_context *src);
-
-
-/**
- * \brief          SM3 context setup
- *
- * \param ctx      context to be initialized
- */
-void sm3_starts( sm3_context *ctx );
-
-
-/**
- * \brief          SM3 process buffer
- *
- * \param ctx      SM3 context
- * \param input    buffer holding the  data
- * \param ilen     length of the input data
- */
-void sm3_update(sm3_context *ctx, const unsigned char *input,
-                size_t ilen);
-
-/**
- * \brief          SM3 final digest
- *
- * \param ctx      SM3 context
- * \param output   SM3 checksum result
- */
-void sm3_finish(sm3_context *ctx, unsigned char output[32]);
-
-/* Internal use */
-void sm3_process(sm3_context *ctx, const unsigned char block[64]);
-
-/**
- * \brief          Output = SM3( input buffer )
- *
- * \param input    buffer holding the  data
- * \param ilen     length of the input data
- * \param output   SM3 checksum result
- */
-void sm3(const unsigned char *input, size_t ilen,
-         unsigned char output[32]);
-
-/**
- * \brief          Checkup routine
- *
- * \return         0 if successful, or 1 if the test failed
- */
-int sm3_self_test(int verbose);
-
-
-#ifdef __cplusplus
-}
-#endif
-
-
-#endif //LIBCRYPTO_SM3_H

+ 0 - 379
components/gmssl/include/sm4/sm4.h

@@ -1,379 +0,0 @@
-/* ====================================================================
- * Copyright (c) 2014 - 2017 The GmSSL Project.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the
- *    distribution.
- *
- * 3. All advertising materials mentioning features or use of this
- *    software must display the following acknowledgment:
- *    "This product includes software developed by the GmSSL Project.
- *    (http://gmssl.org/)"
- *
- * 4. The name "GmSSL Project" must not be used to endorse or promote
- *    products derived from this software without prior written
- *    permission. For written permission, please contact
- *    guanzhi1980@gmail.com.
- *
- * 5. Products derived from this software may not be called "GmSSL"
- *    nor may "GmSSL" appear in their names without prior written
- *    permission of the GmSSL Project.
- *
- * 6. Redistributions of any form whatsoever must retain the following
- *    acknowledgment:
- *    "This product includes software developed by the GmSSL Project
- *    (http://gmssl.org/)"
- *
- * THIS SOFTWARE IS PROVIDED BY THE GmSSL PROJECT ``AS IS'' AND ANY
- * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE GmSSL PROJECT OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
- * OF THE POSSIBILITY OF SUCH DAMAGE.
- * ====================================================================
- */
-
-#ifndef HEADER_SM4_H
-#define HEADER_SM4_H
-
-// #include <openssl/opensslconf.h>
-#ifndef NO_GMSSL
-
-# define SM4_ENCRYPT     1
-# define SM4_DECRYPT     0
-
-#define SM4_KEY_LENGTH		16
-#define SM4_BLOCK_SIZE		16
-#define SM4_IV_LENGTH		(SM4_BLOCK_SIZE)
-#define SM4_NUM_ROUNDS		32
-
-#include <sys/types.h>
-#include <stdint.h>
-#include <string.h>
-#include <openssl/modes.h>
-#include "stdlib.h"
-#include "stdio.h"
-
-//#define SIMPLE_EXTERNAL_ENCODINGS
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef struct sm4_key_t {
-	uint32_t rk[SM4_NUM_ROUNDS];
-#ifdef SIMPLE_EXTERNAL_ENCODINGS
-    uint8_t G[SM4_NUM_ROUNDS+1][256];
-    uint8_t F[SM4_NUM_ROUNDS+1][256];
-#endif //SIMPLE_EXTERNAL_ENCODINGS
-} sm4_key_t;
-
-typedef struct sm4_key_t SM4_KEY;
-
-/**
- sm4_set_encrypt_key
-
- @param key SM4_KEY
- @param user_key key
- */
-void sm4_set_encrypt_key(sm4_key_t *key, const unsigned char *user_key);
-
-/**
- sm4_set_decrypt_key
-
- @param key SM4_KEY
- @param user_key key
- */
-void sm4_set_decrypt_key(sm4_key_t *key, const unsigned char *user_key);
-
-/**
- sm4_encrypt
-
- @param in in
- @param out out
- @param key SM4_KEY
- */
-void sm4_encrypt(const unsigned char *in, unsigned char *out, const sm4_key_t *key);
-#define sm4_decrypt(in,out,key)  sm4_encrypt(in,out,key)
-
-/**
- sm4_encrypt_init
-
- @param key SM4_KEY
- */
-void sm4_encrypt_init(sm4_key_t *key);
-void sm4_encrypt_8blocks(const unsigned char *in, unsigned char *out, const sm4_key_t *key);
-void sm4_encrypt_16blocks(const unsigned char *in, unsigned char *out, const sm4_key_t *key);
-
-/**
- sm4_ecb_encrypt
-
- @param in in
- @param out out
- @param key key
- @param enc 1 to SM4_ENCRYPT, 0 to SM4_DECRYPT
- */
-void sm4_ecb_encrypt(const unsigned char *in, unsigned char *out,
-	const sm4_key_t *key, int enc);
-
-/**
- sm4_cbc_encrypt
-
- @param in in
- @param out out
- @param len byte size of in
- @param key key
- @param iv iv
- @param enc 1 to SM4_ENCRYPT, 0 to SM4_DECRYPT
- */
-void sm4_cbc_encrypt(const unsigned char *in, unsigned char *out,
-	size_t len, const sm4_key_t *key, unsigned char *iv, int enc);
-void sm4_cfb128_encrypt(const unsigned char *in, unsigned char *out,
-	size_t len, const sm4_key_t *key, unsigned char *iv, int *num, int enc);
-void sm4_ofb128_encrypt(const unsigned char *in, unsigned char *out,
-	size_t len, const sm4_key_t *key, unsigned char *iv, int *num);
-/**
- sm4_ctr128_encrypt
- The input encrypted as though 128bit counter mode is being used.  The
- extra state information to record how much of the 128bit block we have
- used is contained in *num, and the encrypted counter is kept in
- ecount_buf.  Both *num and ecount_buf must be initialised with zeros
- before the first call to sm4_ctr128_encrypt(). This algorithm assumes
- that the counter is in the x lower bits of the IV (ivec), and that the
- application has full control over overflow and the rest of the IV.  This
- implementation takes NO responsibility for checking that the counter
- doesn't overflow into the rest of the IV when incremented.
-
- @param in in
- @param out out
- @param len byte size of in
- @param key key
- @param iv iv
- @param ecount_buf extra state, must be initialised with zeros before the first call
- @param num extra state, must be initialised with zeros before the first call
- */
-void sm4_ctr128_encrypt(const unsigned char *in, unsigned char *out,
-	size_t len, const sm4_key_t *key, unsigned char *iv,
-	unsigned char ecount_buf[SM4_BLOCK_SIZE], unsigned int *num);
-
-/**
- sm4_wrap_key
-
- @param key key
- @param iv iv
- @param out out
- @param in in
- @param inlen byte size of in
- @return 1 to successful, otherwise fault
- */
-int sm4_wrap_key(sm4_key_t *key, const unsigned char *iv,
-	unsigned char *out, const unsigned char *in, unsigned int inlen);
-/**
- sm4_unwrap_key
-
- @param key key
- @param iv iv
- @param out out
- @param in in
- @param inlen byte size of in
- @return 1 to successful, otherwise fault
- */
-int sm4_unwrap_key(sm4_key_t *key, const unsigned char *iv,
-	unsigned char *out, const unsigned char *in, unsigned int inlen);
-
-typedef GCM128_CONTEXT SM4_GCM128_CONTEXT;
-
-/**
- sm4_gcm128_init
-
- @param ctx SM4_GCM128_CONTEXT
- @param key SM4_KEY
- */
-void sm4_gcm128_init(SM4_GCM128_CONTEXT *ctx, SM4_KEY *key);
-
-/**
- sm4_gcm128_setiv
-
- @param ctx SM4_GCM128_CONTEXT
- @param ivec iv
- @param len byte size of iv
- */
-void sm4_gcm128_setiv(SM4_GCM128_CONTEXT *ctx, const unsigned char *ivec,
-                      size_t len);
-
-/**
- addition message of gcm
-
- @param ctx SM4_GCM128_CONTEXT
- @param aad addition message
- @param len byte size of aad
- @return 1 to successful, otherwises fault
- */
-int sm4_gcm128_aad(SM4_GCM128_CONTEXT *ctx, const unsigned char *aad,
-                    size_t len);
-
-/**
- sm4_gcm128_encrypt
-
- @param in in
- @param out out
- @param length byte size of in
- @param ctx SM4_GCM128_CONTEXT
- @param enc 1 to SM4_ENCRYPT, 0 to SM4_DECRYPT
- @return 1 to successful, otherwises fault
- */
-int sm4_gcm128_encrypt(const unsigned char *in, unsigned char *out,
-                        size_t length, SM4_GCM128_CONTEXT *ctx, const int enc);
-
-/**
- get tag of sm4_gcm128
-
- @param ctx SM4_GCM128_CONTEXT
- @param tag memory for storage tag
- @param len byte size of tag
- */
-void sm4_gcm128_tag(SM4_GCM128_CONTEXT *ctx, unsigned char *tag,
-                    size_t len);
-
-/**
- sm4_gcm128_finish
-
- @param ctx SM4_GCM128_CONTEXT
- @param tag memory for storage tag
- @param len byte size of tag
- @return 1 to successful, otherwises fault
- */
-int sm4_gcm128_finish(SM4_GCM128_CONTEXT *ctx, const unsigned char *tag,
-                      size_t len);
-
-/**
- release SM4_GCM128_CONTEXT
-
- @param ctx SM4_GCM128_CONTEXT
- */
-void sm4_gcm128_release(SM4_GCM128_CONTEXT *ctx);
-
-/*
-void sm4_avx2_encrypt_init(sm4_key_t *key);
-void sm4_avx2_encrypt_8blocks(const unsigned char *in, unsigned char *out, const sm4_key_t *key);
-void sm4_avx2_encrypt_16blocks(const unsigned char *in, unsigned char *out, const sm4_key_t *key);
-
-void sm4_knc_encrypt_init(sm4_key_t *key);
-void sm4_knc_encrypt_8blocks(const unsigned char *in, unsigned char *out, const sm4_key_t *key);
-void sm4_knc_encrypt_16blocks(const unsigned char *in, unsigned char *out, const sm4_key_t *key);
-
-#define SM4_EDE_KEY_LENGTH	32
-
-typedef struct {
-	sm4_key_t k1;
-	sm4_key_t k2;
-} sm4_ede_key_t;
-
-void sm4_ede_set_encrypt_key(sm4_ede_key_t *key, const unsigned char *user_key);
-void sm4_ede_set_decrypt_key(sm4_ede_key_t *key, const unsigned char *user_key);
-void sm4_ede_encrypt(sm4_ede_key_t *key, const unsigned char *in, unsigned char *out);
-void sm4_ede_encrypt_8blocks(sm4_ede_key_t *key, const unsigned char *in, unsigned char *out);
-void sm4_ede_encrypt_16blocks(sm4_ede_key_t *key, const unsigned char *in, unsigned char *out);
-void sm4_ede_decrypt(sm4_ede_key_t *key, const unsigned char *in, unsigned char *out);
-void sm4_ede_decrypt_8blocks(sm4_ede_key_t *key, const unsigned char *in, unsigned char *out);
-void sm4_ede_decrypt_16blocks(sm4_ede_key_t *key, const unsigned char *in, unsigned char *out);
-*/
-
-/**
- * sm4 gcm file context
- */
-typedef gcmf_context sm4_gcmf_context;
-
-/**
- * init the sm4 gcm file context
- *
- * @param  ctx [in]		gcm file context
- *
- * @param  sm4_key [in]		sm4 key
- *
- * @return     [flag]		if successful o,otherwise failed
- */
-int sm4_gcmf_init(sm4_gcmf_context *ctx, const SM4_KEY *sm4_key);
-
-/**
- * gcm file context free
- *
- * @param  ctx [in]		gcm file context
- *
- * @return     [flag]		if successful o,otherwise failed
- */
-int sm4_gcmf_free(sm4_gcmf_context *ctx);
-
-/**
- * set sm4 iv param
- *
- * @param  ctx [in]		gcm file context
- *
- * @param  iv  [iv]		iv array
- *
- * @param  len [in]		iv array length
- *
- * @return     [flag]		if successful o,otherwise failed
- */
-int sm4_gcmf_set_iv(sm4_gcmf_context *ctx, const unsigned char * iv, size_t len);
-
-
-/**
- * encrypte file
- *
- * @param  ctx      [in]		gcm file context
- *
- * @param  infpath  [in]		plaintext file input path
- *
- * @param  outfpath [in]		cipher file output path
- *
- * @return          [fage]		if successful o,otherwise failed
- */
-int sm4_gcmf_encrypt_file(sm4_gcmf_context * ctx, char *infpath, char *outfpath);
-
-
-/**
- * decrypt file
- *
- * @param  ctx      [in]		gcm file context
- *
- * @param  infpath  [in]		cipher file input path
- *
- * @param  outfpath [in]		plaintext file output path
- *
- * @return          [flag]		if successful o,otherwise failed
- */
-int sm4_gcmf_decrypt_file(sm4_gcmf_context * ctx, char *infpath, char *outfpath);
-
-//same as fucntion rfc3686_init
-//4Bytes nounce + 8bytes iv + 4bytes counter
-void sm4_ctr128_ctr_init(unsigned char nonce[4], unsigned char iv[8], unsigned char ctr_buf[16]);
-
-///* increment counter (128-bit int) by 1 */
-void sm4_ctr128_ctr_inc(unsigned char *counter);
-
-/* decrement counter (128-bit int) by 1 */
-void sm4_ctr128_ctr_dec(unsigned char *counter);
-
-void sm4_ctr128_subctr(unsigned char *counter, const unsigned char *in, unsigned char *out,
-                        size_t length, const SM4_KEY *key);
-
-#ifdef __cplusplus
-}
-#endif
-#endif
-#endif

+ 534 - 0
components/gmssl/src/aead.c

@@ -0,0 +1,534 @@
+/*
+ *  Copyright 2014-2023 The GmSSL Project. All Rights Reserved.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the License); you may
+ *  not use this file except in compliance with the License.
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ */
+
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <gmssl/sm4.h>
+#include <gmssl/mem.h>
+#include <gmssl/aead.h>
+#include <gmssl/error.h>
+
+
+int sm4_cbc_sm3_hmac_encrypt_init(SM4_CBC_SM3_HMAC_CTX *ctx,
+	const uint8_t *key, size_t keylen, const uint8_t *iv, size_t ivlen,
+	const uint8_t *aad, size_t aadlen)
+{
+	if (!ctx || !key || !iv || (!aad && aadlen)) {
+		error_print();
+		return -1;
+	}
+	if (keylen != 48 || ivlen != 16) {
+		error_print();
+		return -1;
+	}
+	memset(ctx, 0, sizeof(*ctx));
+	if (sm4_cbc_encrypt_init(&ctx->enc_ctx, key, iv) != 1) {
+		error_print();
+		return -1;
+	}
+	sm3_hmac_init(&ctx->mac_ctx, key + SM4_KEY_SIZE, SM3_HMAC_SIZE);
+	if (aad && aadlen) {
+		sm3_hmac_update(&ctx->mac_ctx, aad, aadlen);
+	}
+	return 1;
+}
+
+int sm4_cbc_sm3_hmac_encrypt_update(SM4_CBC_SM3_HMAC_CTX *ctx, const uint8_t *in, size_t inlen, uint8_t *out, size_t *outlen)
+{
+	if (!ctx || !in || !out || !outlen) {
+		error_print();
+		return -1;
+	}
+	if (sm4_cbc_encrypt_update(&ctx->enc_ctx, in, inlen, out, outlen) != 1) {
+		error_print();
+		return -1;
+	}
+	sm3_hmac_update(&ctx->mac_ctx, out, *outlen);
+	return 1;
+}
+
+int sm4_cbc_sm3_hmac_encrypt_finish(SM4_CBC_SM3_HMAC_CTX *ctx, uint8_t *out, size_t *outlen)
+{
+	if (!ctx || !out || !outlen) {
+		error_print();
+		return -1;
+	}
+	if (sm4_cbc_encrypt_finish(&ctx->enc_ctx, out, outlen) != 1) {
+		error_print();
+		return -1;
+	}
+	sm3_hmac_update(&ctx->mac_ctx, out, *outlen);
+	sm3_hmac_finish(&ctx->mac_ctx, out + *outlen);
+	*outlen += SM3_HMAC_SIZE;
+	return 1;
+}
+
+int sm4_cbc_sm3_hmac_decrypt_init(SM4_CBC_SM3_HMAC_CTX *ctx,
+	const uint8_t *key, size_t keylen, const uint8_t *iv, size_t ivlen,
+	const uint8_t *aad, size_t aadlen)
+{
+	if (!ctx || !key || !iv || (!aad && aadlen)) {
+		error_print();
+		return -1;
+	}
+	if (keylen != 48 || ivlen != 16) {
+		error_print();
+		return -1;
+	}
+	memset(ctx, 0, sizeof(*ctx));
+	if (sm4_cbc_decrypt_init(&ctx->enc_ctx, key, iv) != 1) {
+		error_print();
+		return -1;
+	}
+	sm3_hmac_init(&ctx->mac_ctx, key + SM4_KEY_SIZE, SM3_HMAC_SIZE);
+	if (aad && aadlen) {
+		sm3_hmac_update(&ctx->mac_ctx, aad, aadlen);
+	}
+	return 1;
+}
+
+int sm4_cbc_sm3_hmac_decrypt_update(SM4_CBC_SM3_HMAC_CTX *ctx, const uint8_t *in, size_t inlen, uint8_t *out, size_t *outlen)
+{
+	size_t len;
+
+	if (!ctx || !in || !out || !outlen) {
+		error_print();
+		return -1;
+	}
+	if (ctx->maclen > SM3_HMAC_SIZE) {
+		error_print();
+		return -1;
+	}
+
+	if (ctx->maclen < SM3_HMAC_SIZE) {
+		len = SM3_HMAC_SIZE - ctx->maclen;
+		if (inlen <= len) {
+			memcpy(ctx->mac + ctx->maclen, in, inlen);
+			ctx->maclen += inlen;
+			return 1;
+		} else {
+			memcpy(ctx->mac + ctx->maclen, in, len);
+			ctx->maclen += len;
+			in += len;
+			inlen -= len;
+		}
+	}
+
+	if (inlen <= SM3_HMAC_SIZE) {
+		uint8_t tmp[32];
+		sm3_hmac_update(&ctx->mac_ctx, ctx->mac, inlen);
+		if (sm4_cbc_decrypt_update(&ctx->enc_ctx, ctx->mac, inlen, out, outlen) != 1) {
+			error_print();
+			return -1;
+		}
+		len = SM3_HMAC_SIZE - inlen;
+		memcpy(tmp, ctx->mac + inlen, len);
+		memcpy(tmp + len, in, inlen);
+		memcpy(ctx->mac, tmp, 32);
+	} else {
+		sm3_hmac_update(&ctx->mac_ctx, ctx->mac, SM3_HMAC_SIZE);
+		if (sm4_cbc_decrypt_update(&ctx->enc_ctx, ctx->mac, SM3_HMAC_SIZE, out, outlen) != 1) {
+			error_print();
+			return -1;
+		}
+		out += *outlen;
+
+		inlen -= SM3_HMAC_SIZE;
+		sm3_hmac_update(&ctx->mac_ctx, in, inlen);
+		if (sm4_cbc_decrypt_update(&ctx->enc_ctx, in, inlen, out, &len) != 1) {
+			error_print();
+			return -1;
+		}
+		*outlen += len;
+		memcpy(ctx->mac, in + inlen, SM3_HMAC_SIZE);
+	}
+	return 1;
+}
+
+int sm4_cbc_sm3_hmac_decrypt_finish(SM4_CBC_SM3_HMAC_CTX *ctx, uint8_t *out, size_t *outlen)
+{
+	uint8_t mac[SM3_HMAC_SIZE];
+
+	if (!ctx || !out || !outlen) {
+		error_print();
+		return -1;
+	}
+	if (ctx->maclen != SM3_HMAC_SIZE) {
+		error_print();
+		return -1;
+	}
+	sm3_hmac_finish(&ctx->mac_ctx, mac);
+	if (sm4_cbc_decrypt_finish(&ctx->enc_ctx, out, outlen) != 1) {
+		error_print();
+		return -1;
+	}
+	if (memcmp(mac, ctx->mac, SM3_HMAC_SIZE) != 0) {
+		error_print();
+		return -1;
+	}
+	memset(ctx->mac, 0, SM3_HMAC_SIZE);
+	ctx->maclen = 0;
+	return 1;
+}
+
+int sm4_ctr_sm3_hmac_encrypt_init(SM4_CTR_SM3_HMAC_CTX *ctx,
+	const uint8_t *key, size_t keylen, const uint8_t *iv, size_t ivlen,
+	const uint8_t *aad, size_t aadlen)
+{
+	if (!ctx || !key || !iv || (!aad && aadlen)) {
+		error_print();
+		return -1;
+	}
+	if (keylen != 48 || ivlen != 16) {
+		error_print();
+		return -1;
+	}
+	memset(ctx, 0, sizeof(*ctx));
+	if (sm4_ctr_encrypt_init(&ctx->enc_ctx, key, iv) != 1) {
+		error_print();
+		return -1;
+	}
+	sm3_hmac_init(&ctx->mac_ctx, key + SM4_KEY_SIZE, SM3_HMAC_SIZE);
+	if (aad && aadlen) {
+		sm3_hmac_update(&ctx->mac_ctx, aad, aadlen);
+	}
+	return 1;
+}
+
+int sm4_ctr_sm3_hmac_encrypt_update(SM4_CTR_SM3_HMAC_CTX *ctx, const uint8_t *in, size_t inlen, uint8_t *out, size_t *outlen)
+{
+	if (!ctx || !in || !out || !outlen) {
+		error_print();
+		return -1;
+	}
+	if (sm4_ctr_encrypt_update(&ctx->enc_ctx, in, inlen, out, outlen) != 1) {
+		error_print();
+		return -1;
+	}
+	sm3_hmac_update(&ctx->mac_ctx, out, *outlen);
+	return 1;
+}
+
+int sm4_ctr_sm3_hmac_encrypt_finish(SM4_CTR_SM3_HMAC_CTX *ctx, uint8_t *out, size_t *outlen)
+{
+	if (!ctx || !out  || !outlen) {
+		error_print();
+		return -1;
+	}
+	if (sm4_ctr_encrypt_finish(&ctx->enc_ctx, out, outlen) != 1) {
+		error_print();
+		return -1;
+	}
+	sm3_hmac_update(&ctx->mac_ctx, out, *outlen);
+	sm3_hmac_finish(&ctx->mac_ctx, out + *outlen);
+	*outlen += SM3_HMAC_SIZE;
+	return 1;
+}
+
+int sm4_ctr_sm3_hmac_decrypt_init(SM4_CTR_SM3_HMAC_CTX *ctx,
+	const uint8_t *key, size_t keylen, const uint8_t *iv, size_t ivlen,
+	const uint8_t *aad, size_t aadlen)
+{
+	if (!ctx || !key || !iv || (!aad && aadlen)) {
+		error_print();
+		return -1;
+	}
+	if (keylen != 48 || ivlen != 16) {
+		error_print();
+		return -1;
+	}
+	memset(ctx, 0, sizeof(*ctx));
+	if (sm4_ctr_decrypt_init(&ctx->enc_ctx, key, iv) != 1) {
+		error_print();
+		return -1;
+	}
+	sm3_hmac_init(&ctx->mac_ctx, key + SM4_KEY_SIZE, SM3_HMAC_SIZE);
+	if (aad && aadlen) {
+		sm3_hmac_update(&ctx->mac_ctx, aad, aadlen);
+	}
+	return 1;
+}
+
+int sm4_ctr_sm3_hmac_decrypt_update(SM4_CTR_SM3_HMAC_CTX *ctx, const uint8_t *in, size_t inlen, uint8_t *out, size_t *outlen)
+{
+	size_t len;
+
+	if (!ctx || !in || !out || !outlen) {
+		error_print();
+		return -1;
+	}
+	if (ctx->maclen > SM3_HMAC_SIZE) {
+		error_print();
+		return -1;
+	}
+
+	if (ctx->maclen < SM3_HMAC_SIZE) {
+		len = SM3_HMAC_SIZE - ctx->maclen;
+		if (inlen <= len) {
+			memcpy(ctx->mac + ctx->maclen, in, inlen);
+			ctx->maclen += inlen;
+			return 1;
+		} else {
+			memcpy(ctx->mac + ctx->maclen, in, len);
+			ctx->maclen += len;
+			in += len;
+			inlen -= len;
+		}
+	}
+
+	if (inlen <= SM3_HMAC_SIZE) {
+		uint8_t tmp[32];
+		sm3_hmac_update(&ctx->mac_ctx, ctx->mac, inlen);
+		if (sm4_ctr_decrypt_update(&ctx->enc_ctx, ctx->mac, inlen, out, outlen) != 1) {
+			error_print();
+			return -1;
+		}
+		len = SM3_HMAC_SIZE - inlen;
+		memcpy(tmp, ctx->mac + inlen, len);
+		memcpy(tmp + len, in, inlen);
+		memcpy(ctx->mac, tmp, 32);
+	} else {
+		sm3_hmac_update(&ctx->mac_ctx, ctx->mac, SM3_HMAC_SIZE);
+		if (sm4_ctr_decrypt_update(&ctx->enc_ctx, ctx->mac, SM3_HMAC_SIZE, out, outlen) != 1) {
+			error_print();
+			return -1;
+		}
+		out += *outlen;
+
+		inlen -= SM3_HMAC_SIZE;
+		sm3_hmac_update(&ctx->mac_ctx, in, inlen);
+		if (sm4_ctr_decrypt_update(&ctx->enc_ctx, in, inlen, out, &len) != 1) {
+			error_print();
+			return -1;
+		}
+		*outlen += len;
+		memcpy(ctx->mac, in + inlen, SM3_HMAC_SIZE);
+	}
+	return 1;
+}
+
+int sm4_ctr_sm3_hmac_decrypt_finish(SM4_CTR_SM3_HMAC_CTX *ctx, uint8_t *out, size_t *outlen)
+{
+	uint8_t mac[SM3_HMAC_SIZE];
+
+	if (!ctx || !out || !outlen) {
+		error_print();
+		return -1;
+	}
+	if (ctx->maclen != SM3_HMAC_SIZE) {
+		error_print();
+		return -1;
+	}
+	sm3_hmac_finish(&ctx->mac_ctx, mac);
+	if (sm4_ctr_decrypt_finish(&ctx->enc_ctx, out, outlen) != 1) {
+		error_print();
+		return -1;
+	}
+	if (memcmp(mac, ctx->mac, SM3_HMAC_SIZE) != 0) {
+		error_print();
+		return -1;
+	}
+	memset(ctx->mac, 0, SM3_HMAC_SIZE);
+	ctx->maclen = 0;
+	return 1;
+}
+
+static void ctr_incr(uint8_t a[16])
+{
+	int i;
+	for (i = 15; i >= 0; i--) {
+		a[i]++;
+		if (a[i]) break;
+	}
+}
+
+int sm4_gcm_encrypt_init(SM4_GCM_CTX *ctx,
+	const uint8_t *key, size_t keylen, const uint8_t *iv, size_t ivlen,
+	const uint8_t *aad, size_t aadlen, size_t taglen)
+{
+	uint8_t H[16] = {0};
+	uint8_t Y[16];
+
+	if (!ctx || !key || !iv || (!aad && aadlen)) {
+		error_print();
+		return -1;
+	}
+	if (keylen != 16) {
+		error_print();
+		return -1;
+	}
+	if (ivlen < SM4_GCM_MIN_IV_SIZE || ivlen > SM4_GCM_MAX_IV_SIZE) {
+		error_print();
+		return -1;
+	}
+	if (taglen < 8 || taglen > 16) {
+		error_print();
+		return -1;
+	}
+
+	memset(ctx, 0, sizeof(*ctx));
+	ctx->taglen = taglen;
+
+	if (sm4_ctr_encrypt_init(&ctx->enc_ctx, key, H) != 1) {
+		error_print();
+		return -1;
+	}
+
+	sm4_encrypt(&ctx->enc_ctx.sm4_key, H, H);
+
+	ghash_init(&ctx->mac_ctx, H, aad, aadlen);
+
+	if (ivlen == 12) {
+		memcpy(Y, iv, 12);
+		Y[12] = Y[13] = Y[14] = 0;
+		Y[15] = 1;
+	} else {
+		ghash(H, NULL, 0, iv, ivlen, Y);
+	}
+
+	sm4_encrypt(&ctx->enc_ctx.sm4_key, Y, ctx->Y);
+
+	ctr_incr(Y);
+	memcpy(ctx->enc_ctx.ctr, Y, 16);
+
+	gmssl_secure_clear(H, sizeof(H));
+	gmssl_secure_clear(Y, sizeof(Y));
+	return 1;
+}
+
+int sm4_gcm_encrypt_update(SM4_GCM_CTX *ctx, const uint8_t *in, size_t inlen, uint8_t *out, size_t *outlen)
+{
+	if (!ctx || !in || !out || !outlen) {
+		error_print();
+		return -1;
+	}
+	if (sm4_ctr_encrypt_update(&ctx->enc_ctx, in, inlen, out, outlen) != 1) {
+		error_print();
+		return -1;
+	}
+	ghash_update(&ctx->mac_ctx, out, *outlen);
+	return 1;
+}
+
+int sm4_gcm_encrypt_finish(SM4_GCM_CTX *ctx, uint8_t *out, size_t *outlen)
+{
+	uint8_t mac[16];
+
+	if (!ctx || !out || !outlen) {
+		error_print();
+		return -1;
+	}
+	if (sm4_ctr_encrypt_finish(&ctx->enc_ctx, out, outlen) != 1) {
+		error_print();
+		return -1;
+	}
+	ghash_update(&ctx->mac_ctx, out, *outlen);
+	ghash_finish(&ctx->mac_ctx, mac);
+
+	gmssl_memxor(mac, mac, ctx->Y, ctx->taglen);
+	memcpy(out + *outlen, mac, ctx->taglen);
+	*outlen += ctx->taglen;
+
+	return 1;
+}
+
+int sm4_gcm_decrypt_init(SM4_GCM_CTX *ctx,
+	const uint8_t *key, size_t keylen, const uint8_t *iv, size_t ivlen,
+	const uint8_t *aad, size_t aadlen, size_t taglen)
+{
+	return sm4_gcm_encrypt_init(ctx, key, keylen, iv, ivlen, aad, aadlen, taglen);
+}
+
+int sm4_gcm_decrypt_update(SM4_GCM_CTX *ctx, const uint8_t *in, size_t inlen, uint8_t *out, size_t *outlen)
+{
+	size_t len;
+
+	if (!ctx || !in || !out || !outlen) {
+		error_print();
+		return -1;
+	}
+	if (ctx->maclen > ctx->taglen) {
+		error_print();
+		return -1;
+	}
+
+	if (ctx->maclen < ctx->taglen) {
+		len = ctx->taglen - ctx->maclen;
+		if (inlen <= len) {
+			memcpy(ctx->mac + ctx->maclen, in, inlen);
+			ctx->maclen += inlen;
+			return 1;
+		} else {
+			memcpy(ctx->mac + ctx->maclen, in, len);
+			ctx->maclen += len;
+			in += len;
+			inlen -= len;
+		}
+	}
+
+	if (inlen <= ctx->taglen) {
+		uint8_t tmp[32];
+		ghash_update(&ctx->mac_ctx, ctx->mac, inlen);
+		if (sm4_ctr_decrypt_update(&ctx->enc_ctx, ctx->mac, inlen, out, outlen) != 1) {
+			error_print();
+			return -1;
+		}
+		len = ctx->taglen - inlen;
+		memcpy(tmp, ctx->mac + inlen, len);
+		memcpy(tmp + len, in, inlen);
+		memcpy(ctx->mac, tmp, 32);
+	} else {
+		ghash_update(&ctx->mac_ctx, ctx->mac, ctx->taglen);
+		if (sm4_ctr_decrypt_update(&ctx->enc_ctx, ctx->mac, ctx->taglen, out, outlen) != 1) {
+			error_print();
+			return -1;
+		}
+		out += *outlen;
+
+		inlen -= ctx->taglen;
+		ghash_update(&ctx->mac_ctx, in, inlen);
+		if (sm4_ctr_decrypt_update(&ctx->enc_ctx, in, inlen, out, &len) != 1) {
+			error_print();
+			return -1;
+		}
+		*outlen += len;
+		memcpy(ctx->mac, in + inlen, GHASH_SIZE);
+	}
+	return 1;
+}
+
+int sm4_gcm_decrypt_finish(SM4_GCM_CTX *ctx, uint8_t *out, size_t *outlen)
+{
+	uint8_t mac[GHASH_SIZE];
+
+	if (!ctx || !out || !outlen) {
+		error_print();
+		return -1;
+	}
+	if (ctx->maclen != ctx->taglen) {
+		error_print();
+		return -1;
+	}
+	ghash_finish(&ctx->mac_ctx, mac);
+	if (sm4_ctr_decrypt_finish(&ctx->enc_ctx, out, outlen) != 1) {
+		error_print();
+		return -1;
+	}
+
+	gmssl_memxor(mac, mac, ctx->Y, ctx->taglen);
+	if (memcmp(mac, ctx->mac, ctx->taglen) != 0) {
+		error_print();
+		return -1;
+	}
+	memset(ctx->mac, 0, GHASH_SIZE);
+	ctx->maclen = 0;
+	return 1;
+}

+ 1937 - 0
components/gmssl/src/asn1.c

@@ -0,0 +1,1937 @@
+/*
+ *  Copyright 2014-2023 The GmSSL Project. All Rights Reserved.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the License); you may
+ *  not use this file except in compliance with the License.
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ */
+
+
+// https://www.obj-sys.com/asn1tutorial/node128.html
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <limits.h>
+#include <time.h>
+#include <ctype.h>
+#include <gmssl/oid.h>
+#include <gmssl/asn1.h>
+#include <gmssl/error.h>
+#include <gmssl/endian.h>
+
+
+static const char *asn1_tag_index[] = {
+	"[0]",  "[1]",  "[2]",  "[3]",  "[4]",  "[5]",  "[6]",  "[7]",  "[8]",  "[9]",
+	"[10]", "[11]", "[12]", "[13]", "[14]", "[15]", "[16]", "[17]", "[18]", "[19]",
+	"[20]", "[21]", "[22]", "[23]", "[24]", "[25]", "[26]", "[27]", "[28]", "[29]",
+	"[30]", "[31]",
+};
+
+const char *asn1_tag_name(int tag)
+{
+	if (tag < 0 || tag > 0xff) {
+		error_print();
+		return NULL;
+	}
+
+	switch (tag & 0xc0) {
+	case ASN1_TAG_CONTENT_SPECIFIC: return asn1_tag_index[tag & 0xe0];
+	case ASN1_TAG_APPLICATION: return "Application";
+	case ASN1_TAG_PRIVATE: return "Private";
+	}
+
+	switch (tag) {
+	case ASN1_TAG_BOOLEAN: return "BOOLEAN";
+	case ASN1_TAG_INTEGER: return "INTEGER";
+	case ASN1_TAG_BIT_STRING: return "BIT STRING";
+	case ASN1_TAG_OCTET_STRING: return "OCTET STRING";
+	case ASN1_TAG_NULL: return "NULL";
+	case ASN1_TAG_OBJECT_IDENTIFIER: return "OBJECT IDENTIFIER";
+	case ASN1_TAG_ObjectDescriptor: return "ObjectDescriptor";
+	case ASN1_TAG_EXTERNAL: return "EXTERNAL";
+	case ASN1_TAG_REAL: return "REAL";
+	case ASN1_TAG_ENUMERATED: return "ENUMERATED";
+	case ASN1_TAG_EMBEDDED: return "EMBEDDED";
+	case ASN1_TAG_UTF8String: return "UTF8String";
+	case ASN1_TAG_RELATIVE_OID: return "RELATIVE_OID";
+	case ASN1_TAG_NumericString: return "NumericString";
+	case ASN1_TAG_PrintableString: return "PrintableString";
+	case ASN1_TAG_TeletexString: return "TeletexString";
+	case ASN1_TAG_VideotexString: return "VideotexString";
+	case ASN1_TAG_IA5String: return "IA5String";
+	case ASN1_TAG_UTCTime: return "UTCTime";
+	case ASN1_TAG_GeneralizedTime: return "GeneralizedTime";
+	case ASN1_TAG_GraphicString: return "GraphicString";
+	case ASN1_TAG_VisibleString: return "VisibleString";
+	case ASN1_TAG_GeneralString: return "GeneralString";
+	case ASN1_TAG_UniversalString: return "UniversalString";
+	case ASN1_TAG_CHARACTER_STRING: return "CHARACTER STRING";
+	case ASN1_TAG_BMPString: return "BMPString";
+	case ASN1_TAG_SEQUENCE: return "SEQUENCE";
+	case ASN1_TAG_SET: return "SET";
+	case ASN1_TAG_EXPLICIT: return "EXPLICIT";
+	}
+
+	error_print();
+	return NULL;
+}
+
+// not in-use
+int asn1_tag_is_cstring(int tag)
+{
+	switch (tag) {
+	case ASN1_TAG_UTF8String:
+	case ASN1_TAG_NumericString:
+	case ASN1_TAG_PrintableString:
+	case ASN1_TAG_TeletexString:
+	case ASN1_TAG_IA5String:
+	case ASN1_TAG_GeneralString:
+		return 1;
+	}
+	return 0;
+}
+
+// not in-use
+int asn1_tag_to_der(int tag, uint8_t **out, size_t *outlen)
+{
+	if (!outlen) {
+		error_print();
+		return -1;
+	}
+	if (out && *out) {
+		*(*out)++ = (uint8_t)tag;
+	}
+	(*outlen)++;
+	return 1;
+}
+
+// not in-use
+int asn1_tag_from_der(int *tag, const uint8_t **in, size_t *inlen)
+{
+	if (!tag || !in || !(*in) || !inlen) {
+		error_print();
+		return -1;
+	}
+	if (*inlen == 0) {
+		return 0;
+	}
+	*tag = *(*in)++;
+	(*inlen)--;
+	return 1;
+}
+
+int asn1_tag_from_der_readonly(int *tag, const uint8_t **in, size_t *inlen)
+{
+	if (!tag || !in || !(*in) || !inlen) {
+		error_print();
+		return -1;
+	}
+	if (*inlen == 0) {
+		return 0;
+	}
+	*tag = **in;
+	return 1;
+}
+
+int asn1_length_to_der(size_t len, uint8_t **out, size_t *outlen)
+{
+	if (len > INT_MAX) {
+		error_print();
+		return -1;
+	}
+	if (!outlen) {
+		error_print();
+		return -1;
+	}
+
+	if (len < 128) {
+		if (out && *out) {
+			*(*out)++ = (uint8_t)len;
+		}
+		(*outlen)++;
+
+	} else {
+		uint8_t buf[4];
+		int nbytes;
+
+		if (len < 256) nbytes = 1;
+		else if (len < 65536) nbytes = 2;
+		else if (len < (1 << 24)) nbytes = 3;
+		else nbytes = 4;
+		PUTU32(buf, (uint32_t)len);
+
+		if (out && *out) {
+			*(*out)++ = 0x80 + nbytes;
+			memcpy(*out, buf + 4 - nbytes, nbytes);
+			(*out) += nbytes;
+		}
+		(*outlen) += 1 + nbytes;
+	}
+	return 1;
+}
+
+int asn1_length_from_der(size_t *len, const uint8_t **in, size_t *inlen)
+{
+	if (!len || !in || !(*in) || !inlen) {
+		error_print();
+		return -1;
+	}
+
+	if (*inlen == 0) {
+		error_print();
+		return -1;
+	}
+
+	if (**in < 128) {
+		*len = *(*in)++;
+		(*inlen)--;
+
+	} else {
+		uint8_t buf[4] = {0};
+		int nbytes  = *(*in)++ & 0x7f;
+		(*inlen)--;
+
+		if (nbytes < 1 || nbytes > 4) {
+			error_print();
+			return -1;
+		}
+		if (*inlen < nbytes) {
+			error_print();
+			return -1;
+		}
+
+		memcpy(buf + 4 - nbytes, *in, nbytes);
+		*len = (size_t)GETU32(buf);
+		*in += nbytes;
+		*inlen -= nbytes;
+	}
+
+	// check if the left input is enough for reading (d,dlen)
+	if (*inlen < *len) {
+		error_print();
+		return -2; // 特殊错误值用于 test_asn1_length() 的测试 // TODO: 修改 asn1test.c 的测试向量
+	}
+	return 1;
+}
+
+// asn1_data_to_der do not check the validity of data
+int asn1_data_to_der(const uint8_t *data, size_t datalen, uint8_t **out, size_t *outlen)
+{
+	if (!outlen) {
+		error_print();
+		return -1;
+	}
+	if (datalen == 0) {
+		return 0;
+	}
+	if (out && *out) {
+		if (!data) {
+			error_print();
+			return -1;
+		}
+		memcpy(*out, data, datalen);
+		*out += datalen;
+	}
+	*outlen += datalen;
+	return 1;
+}
+
+// not in-use
+int asn1_data_from_der(const uint8_t **data, size_t datalen, const uint8_t **in, size_t *inlen)
+{
+	if (!data || !datalen || !in || !(*in) || !inlen) {
+		error_print();
+		return -1;
+	}
+	if (*inlen < datalen) {
+		error_print();
+		return -1;
+	}
+	*data = *in;
+	*in += datalen;
+	*inlen -= datalen;
+	return 1;
+}
+
+int asn1_header_to_der(int tag, size_t dlen, uint8_t **out, size_t *outlen)
+{
+	if (!outlen) {
+		error_print();
+		return -1;
+	}
+
+	if (out && *out) {
+		*(*out)++ = (uint8_t)tag;
+	}
+	(*outlen)++;
+
+	(void)asn1_length_to_der(dlen, out, outlen);
+	return 1;
+}
+
+int asn1_type_to_der(int tag, const uint8_t *d, size_t dlen, uint8_t **out, size_t *outlen)
+{
+	if (!outlen) {
+		error_print();
+		return -1;
+	}
+
+	if (!d) {
+		if (dlen) {
+			error_print();
+			return -1;
+		}
+		return 0;
+	}
+
+	// tag
+	if (out && *out) {
+		*(*out)++ = (uint8_t)tag;
+	}
+	(*outlen)++;
+
+	// length
+	(void)asn1_length_to_der(dlen, out, outlen);
+
+	// data
+	if (out && *out) {
+		memcpy(*out, d, dlen);
+		*out += dlen;
+	}
+	*outlen += dlen;
+
+	return 1;
+}
+
+int asn1_type_from_der(int tag, const uint8_t **d, size_t *dlen, const uint8_t **in, size_t *inlen)
+{
+	if (!d || !dlen || !in || !(*in) || !inlen) {
+		error_print();
+		return -1;
+	}
+
+	// tag
+	if (*inlen == 0 || **in != tag) {
+		*d = NULL;
+		*dlen = 0;
+		return 0;
+	}
+	(*in)++;
+	(*inlen)--;
+
+	// length
+	if (asn1_length_from_der(dlen, in, inlen) != 1) {
+		error_print();
+		return -1;
+	}
+
+	// data
+	*d = *in;
+	*in += *dlen;
+	*inlen -= *dlen;
+	return 1;
+}
+
+int asn1_nonempty_type_to_der(int tag, const uint8_t *d, size_t dlen, uint8_t **out, size_t *outlen)
+{
+	int ret;
+
+	if (d && dlen == 0) {
+		error_print();
+		return -1;
+	}
+	if ((ret = asn1_type_to_der(tag, d, dlen, out, outlen)) != 1) {
+		if (ret) error_print();
+		return ret;
+	}
+	return 1;
+}
+
+int asn1_nonempty_type_from_der(int tag, const uint8_t **d, size_t *dlen, const uint8_t **in, size_t *inlen)
+{
+	int ret;
+
+	if ((ret = asn1_type_from_der(tag, d, dlen, in, inlen)) != 1) {
+		if (ret) error_print();
+		return ret;
+	}
+	if (*dlen == 0) {
+		error_print();
+		return -1;
+	}
+	return 1;
+}
+
+int asn1_any_type_from_der(int *tag, const uint8_t **d, size_t *dlen, const uint8_t **in, size_t *inlen)
+{
+	if (!tag || !d || !dlen || !in || !(*in) || !inlen) {
+		error_print();
+		return -1;
+	}
+
+	if (*inlen == 0) {
+		*tag = - 1;
+		*d = NULL;
+		*dlen = 0;
+		return 0;
+	}
+
+	*tag = *(*in)++;
+	(*inlen)--;
+
+	if (asn1_length_from_der(dlen, in, inlen) != 1) {
+		error_print();
+		return -1;
+	}
+
+	*d = *in;
+	*in += *dlen;
+	*inlen -= *dlen;
+	return 1;
+}
+
+// we need to check this is an asn.1 type
+int asn1_any_to_der(const uint8_t *a, size_t alen, uint8_t **out, size_t *outlen)
+{
+	if (!outlen) {
+		error_print();
+		return -1;
+	}
+
+	if (!a) {
+		if (a) {
+			error_print();
+			return -1;
+		}
+		return 0;
+	}
+
+	if (out && *out) {
+		memcpy(*out, a, alen);
+		*out += alen;
+	}
+	*outlen += alen;
+
+	return 1;
+}
+
+int asn1_any_from_der(const uint8_t **a, size_t *alen, const uint8_t **in, size_t *inlen)
+{
+	int ret;
+	int tag;
+	const uint8_t *d;
+	size_t dlen;
+
+	if (!a || !alen || !in || !(*in) || !inlen) {
+		error_print();
+		return -1;
+	}
+	*a = *in;
+	*alen = *inlen;
+
+	if ((ret = asn1_any_type_from_der(&tag, &d, &dlen, in, inlen)) != 1) {
+		if (ret) error_print();
+		return ret;
+	}
+	*alen -= *inlen;
+
+	return 1;
+}
+
+const char *asn1_boolean_name(int val)
+{
+	switch (val) {
+	case 1: return "true";
+	case 0: return "false";
+	}
+	return NULL;
+}
+
+int asn1_boolean_from_name(int *val, const char *name)
+{
+	if (strcmp(name, "true") == 0) {
+		*val = 1;
+		return 1;
+	} else if (strcmp(name, "false") == 0) {
+		*val = 0;
+		return 1;
+	}
+	*val = -1;
+	return -1;
+}
+
+int asn1_boolean_to_der_ex(int tag, int val, uint8_t **out, size_t *outlen)
+{
+	if (!outlen) {
+		error_print();
+		return -1;
+	}
+
+	if (val < 0) {
+		return 0;
+	}
+
+	if (out && *out) {
+		*(*out)++ = tag;
+		*(*out)++ = 0x01;
+		*(*out)++ = val ? 0xff : 0x00;
+	}
+	(*outlen) += 3;
+	return 1;
+}
+
+int asn1_boolean_from_der_ex(int tag, int *val, const uint8_t **in, size_t *inlen)
+{
+	if (!val || !in || !(*in) || !inlen) {
+		error_print();
+		return -1;
+	}
+	if (*inlen == 0 || (*in)[0] != tag) {
+		*val = -1;
+		return 0;
+	}
+
+	if (*inlen < 3) {
+		error_print();
+		return -1;
+	}
+	if ((*in)[1] != 0x01) {
+		error_print();
+		return -1;
+	}
+
+	if ((*in)[2] != ASN1_TRUE && (*in)[2] != ASN1_FALSE) {
+		error_print();
+		return -1;
+	}
+	*val = ((*in)[2] == ASN1_TRUE) ? 1 : 0;
+	*in += 3;
+	*inlen -= 3;
+	return 1;
+}
+
+int asn1_integer_to_der_ex(int tag, const uint8_t *a, size_t alen, uint8_t **out, size_t *outlen)
+{
+	if (!outlen) {
+		error_print();
+		return -1;
+	}
+
+	if (!a) {
+		return 0;
+	}
+	if (alen <= 0 || alen > INT_MAX) {
+		error_print();
+		return -1;
+	}
+
+	if (out && *out)
+		*(*out)++ = tag;
+	(*outlen)++;
+
+	while (*a == 0 && alen > 1) {
+		a++;
+		alen--;
+	}
+
+	if (a[0] & 0x80) {
+		asn1_length_to_der(alen + 1, out, outlen);
+		if (out && *out) {
+			*(*out)++ = 0x00;
+			memcpy(*out, a, alen);
+			(*out) += alen;
+		}
+		(*outlen) += 1 + alen;
+	} else {
+		asn1_length_to_der(alen, out ,outlen);
+		if (out && *out) {
+			memcpy(*out, a, alen);
+			(*out) += alen;
+		}
+		(*outlen) += alen;
+	}
+
+	return 1;
+}
+
+int asn1_integer_from_der_ex(int tag, const uint8_t **a, size_t *alen, const uint8_t **in, size_t *inlen)
+{
+	size_t len;
+
+	if (!a || !alen || !in || !(*in) || !inlen) {
+		error_print();
+		return -1;
+	}
+
+	// tag
+	if (*inlen == 0 || **in != tag) {
+		*a = NULL;
+		*alen = 0;
+		return 0;
+	}
+	(*in)++;
+	(*inlen)--;
+
+	// length (not zero)
+	if (asn1_length_from_der(&len, in, inlen) != 1) {
+		error_print();
+		return -1;
+	}
+	if (len == 0) {
+		error_print();
+		return -1;
+	}
+
+	// check if ASN1_INTEGER is negative
+	if (**in & 0x80) {
+		error_print();
+		return -1;
+	}
+
+	// remove leading zero
+	if (**in == 0 && len > 1) {
+		(*in)++;
+		(*inlen)--;
+		len--;
+
+		// the following bit should be one
+		if (((**in) & 0x80) == 0) {
+			error_print();
+			return -1;
+		}
+	}
+
+	// no leading zeros
+	if (**in == 0 && len > 1) {
+		error_print();
+		return -1;
+	}
+
+	// return integer bytes
+	*a = *in;
+	*alen = len;
+	*in += len;
+	*inlen -= len;
+
+	return 1;
+}
+
+int asn1_int_to_der_ex(int tag, int a, uint8_t **out, size_t *outlen)
+{
+	uint8_t buf[4] = {0};
+	size_t len = 0;
+
+	if (a == -1) {
+		return 0;
+	}
+
+	while (a > 0) {
+		buf[3 - len] = a & 0xff;
+		a >>= 8;
+		len++;
+	}
+	if (!len) {
+		len = 1;
+	}
+
+	if (asn1_integer_to_der_ex(tag, buf + 4 - len, len, out, outlen) != 1) {
+		error_print();
+		return -1;
+	}
+	return 1;
+}
+
+int asn1_int_from_der_ex(int tag, int *a, const uint8_t **in, size_t *inlen)
+{
+	int ret;
+	const uint8_t *p;
+	size_t len;
+	size_t i;
+
+	if (!a || !in || !(*in) || !inlen) {
+		error_print();
+		return -1;
+	}
+
+	if ((ret = asn1_integer_from_der_ex(tag, &p, &len, in, inlen)) != 1) {
+		if (ret < 0) error_print();
+		else *a = -1;
+		return ret;
+	}
+	if (len > sizeof(*a)) {
+		error_print();
+		return -1;
+	}
+
+	*a = 0;
+	for (i = 0; i < len; i++) {
+		*a = ((*a) << 8) | p[i];
+	}
+	if (*a < 0) {
+		error_print();
+		return -1;
+	}
+	return 1;
+}
+
+int asn1_bit_string_to_der_ex(int tag, const uint8_t *bits, size_t nbits, uint8_t **out, size_t *outlen)
+{
+	size_t nbytes = (nbits + 7) / 8;
+	size_t unused_nbits = nbytes * 8 - nbits;
+
+	if (!outlen) {
+		error_print();
+		return -1;
+	}
+
+	if (!bits) {
+		if (nbits) {
+			error_print();
+			return -1;
+		}
+		return 0;
+	}
+
+	// tag
+	if (out && *out) {
+		*(*out)++ = tag;
+	}
+	(*outlen)++;
+
+	// length
+	(void)asn1_length_to_der(nbytes + 1, out, outlen);
+
+	// unused num of bits
+	if (out && *out) {
+		*(*out)++ = (uint8_t)unused_nbits;
+	}
+	(*outlen)++;
+
+	// bits
+	if (out && *out) {
+		memcpy(*out, bits, nbytes);
+		*out += nbytes;
+	}
+	*outlen += nbytes;
+
+	return 1;
+}
+
+int asn1_bit_string_from_der_ex(int tag, const uint8_t **bits, size_t *nbits, const uint8_t **in, size_t *inlen)
+{
+	size_t len;
+	int unused_bits;
+
+	if (!bits || !nbits || !in || !(*in) || !inlen) {
+		error_print();
+		return -1;
+	}
+
+	// tag
+	if (*inlen == 0 || **in != tag) {
+		*bits = NULL;
+		*nbits = 0;
+		return 0;
+	}
+	(*in)++;
+	(*inlen)--;
+
+	// length (min == 2)
+	if (asn1_length_from_der(&len, in, inlen) != 1) {
+		error_print();
+		return -1;
+	}
+	if (len < 2) {
+		error_print();
+		return -1;
+	}
+
+	// unused_bits counter
+	unused_bits = **in;
+	if (unused_bits > 7) {
+		error_print();
+		return -1;
+	}
+	(*in)++;
+	(*inlen)--;
+	len--;
+
+	// return bits
+	*bits = *in;
+	*nbits = (len << 3) - unused_bits;
+	*in += len;
+	*inlen -= len;
+
+	return 1;
+}
+
+int asn1_bit_octets_to_der_ex(int tag, const uint8_t *octs, size_t nocts, uint8_t **out, size_t *outlen)
+{
+	int ret;
+	if ((ret = asn1_bit_string_to_der_ex(tag, octs, nocts << 3, out, outlen)) != 1) {
+		if (ret) error_print();
+		return ret;
+	}
+	return 1;
+}
+
+int asn1_bit_octets_from_der_ex(int tag, const uint8_t **octs, size_t *nocts, const uint8_t **in, size_t *inlen)
+{
+	int ret;
+	const uint8_t *bits;
+	size_t nbits;
+
+	if (!octs || !nocts) {
+		error_print();
+		return -1;
+	}
+
+	if ((ret = asn1_bit_string_from_der_ex(tag, &bits, &nbits, in, inlen)) != 1) {
+		if (ret < 0) error_print();
+		else {
+			*octs = NULL;
+			*nocts = 0;
+		}
+		return ret;
+	}
+
+	if (nbits % 8) {
+		error_print();
+		return -1;
+	}
+	*octs = bits;
+	*nocts = nbits >> 3;
+	return 1;
+}
+
+int asn1_bits_to_der_ex(int tag, int bits, uint8_t **out, size_t *outlen)
+{
+	size_t nbits = 0;
+	uint8_t mask = 0x80;
+	uint8_t buf[4] = {0};
+	int i = 0;
+
+	if (bits < 0) {
+		return 0;
+	}
+	while (bits > 0) {
+		if (bits & 1)
+			buf[i] |= mask;
+		mask >>= 1;
+		bits >>= 1;
+		nbits++;
+		if (nbits % 8 == 0) {
+			i++;
+			mask = 0x80;
+		}
+	}
+	if (!nbits) {
+		nbits = 1;
+	}
+
+	if (asn1_bit_string_to_der_ex(tag, buf, nbits, out, outlen) != 1) {
+		error_print();
+		return -1;
+	}
+	return 1;
+}
+
+int asn1_bits_from_der_ex(int tag, int *bits, const uint8_t **in, size_t *inlen)
+{
+	int ret;
+	const uint8_t *p;
+	uint8_t c;
+	size_t nbits;
+	size_t i;
+
+	if (!bits) {
+		error_print();
+		return -1;
+	}
+
+	if ((ret = asn1_bit_string_from_der_ex(tag, &p, &nbits, in, inlen)) != 1) {
+		if (ret < 0) error_print();
+		else *bits = -1;
+		return ret;
+	}
+
+	if (nbits > 31) {
+		error_print();
+		return -1;
+	}
+
+	*bits = 0;
+	for (i = 0; i < nbits; i++) {
+		if (i % 8 == 0) {
+			c = *p++;
+		}
+		*bits |= ((c & 0x80) >> 7) << i;
+		c <<= 1;
+	}
+	return 1;
+}
+
+int asn1_bits_print(FILE *fp, int fmt, int ind, const char *label, const char **names, size_t names_cnt, int bits)
+{
+	size_t i;
+	format_print(fp, fmt, ind, "%s: ", label);
+
+	for (i = 0; i < names_cnt; i++) {
+		if (bits & 0x01)
+			fprintf(fp, "%s%s", names[i], bits >> 1 ? "," : "");
+		bits >>= 1;
+	}
+	fprintf(fp, "\n");
+	if (bits) {
+		error_print();
+		return -1;
+	}
+	return 1;
+}
+
+const char *asn1_null_name(void)
+{
+	return "null";
+}
+
+int asn1_null_to_der(uint8_t **out, size_t *outlen)
+{
+	if (!outlen) {
+		error_print();
+		return -1;
+	}
+	if (out && *out) {
+		*(*out)++ = ASN1_TAG_NULL;
+		*(*out)++ = 0x00;
+	}
+	*outlen += 2;
+	return 1;
+}
+
+int asn1_null_from_der(const uint8_t **in, size_t *inlen)
+{
+	if (!in || !(*in) || !inlen) {
+		error_print();
+		return -1;
+	}
+
+	// tag
+	if (*inlen == 0 || **in != ASN1_TAG_NULL) {
+		return 0;
+	}
+	(*in)++;
+	(*inlen)--;
+
+	// value
+	if (*inlen < 1) {
+		error_print();
+		return -1;
+	}
+	if (**in != 0x00) {
+		error_print();
+		return -1;
+	}
+	(*in)++;
+	(*inlen)--;
+	return 1;
+}
+
+static void asn1_oid_node_to_base128(uint32_t a, uint8_t **out, size_t *outlen)
+{
+	uint8_t buf[5];
+	int n = 0;
+
+	buf[n++] = a & 0x7f;
+	a >>= 7;
+
+	while (a) {
+		buf[n++] = 0x80 | (a & 0x7f);
+		a >>= 7;
+	}
+
+	while (n--) {
+		if (out && *out) {
+			*(*out)++ = buf[n];
+		}
+		(*outlen)++;
+	}
+}
+
+static int asn1_oid_node_from_base128(uint32_t *a, const uint8_t **in, size_t *inlen)
+{
+	uint8_t buf[5];
+	int n = 0;
+	int i;
+
+	for (;;) {
+		if ((*inlen)-- < 1 || n >= 5) {
+			error_print();
+			return -1;
+		}
+		buf[n] = *(*in)++;
+		if ((buf[n++] & 0x80) == 0) {
+			break;
+		}
+	}
+
+	// 32 - 7*4 = 4, so the first byte should be like 1000bbbb
+	if (n == 5 && (buf[0] & 0x70)) {
+		error_print();
+		return -1;
+	}
+
+	*a = 0;
+	for (i = 0; i < n; i++) {
+		*a = ((*a) << 7) | (buf[i] & 0x7f);
+	}
+
+	return 1;
+}
+
+int asn1_object_identifier_to_octets(const uint32_t *nodes, size_t nodes_cnt, uint8_t *out, size_t *outlen)
+{
+	if (!nodes || !outlen) {
+		error_print();
+		return -1;
+	}
+	if (nodes_cnt < ASN1_OID_MIN_NODES || nodes_cnt > ASN1_OID_MAX_NODES) {
+		error_print();
+		return -1;
+	}
+	if (out) {
+		*out++ = (uint8_t)(nodes[0] * 40 + nodes[1]);
+	}
+	(*outlen) = 1;
+	nodes += 2;
+	nodes_cnt -= 2;
+
+	while (nodes_cnt--) {
+		asn1_oid_node_to_base128(*nodes++, &out, outlen);
+	}
+	return 1;
+}
+
+int asn1_object_identifier_from_octets(uint32_t *nodes, size_t *nodes_cnt, const uint8_t *in, size_t inlen)
+{
+	if (!nodes_cnt || !in || !inlen) {
+		error_print();
+		return -1;
+	}
+
+	if (nodes) {
+		*nodes++ = (*in) / 40;
+		*nodes++ = (*in) % 40;
+	}
+	in++;
+	inlen--;
+	*nodes_cnt = 2;
+
+	while (inlen) {
+		uint32_t val;
+		if (*nodes_cnt > ASN1_OID_MAX_NODES) {
+			error_print();
+			return -1;
+		}
+		if (asn1_oid_node_from_base128(&val, &in, &inlen) < 0) {
+			error_print();
+			return -1;
+		}
+		if (nodes) {
+			*nodes++ = val;
+		}
+		(*nodes_cnt)++;
+	}
+
+	return 1;
+}
+
+int asn1_object_identifier_to_der_ex(int tag, const uint32_t *nodes, size_t nodes_cnt, uint8_t **out, size_t *outlen)
+{
+	uint8_t octets[ASN1_OID_MAX_OCTETS];
+	size_t octetslen = 0;
+
+	if (!outlen) {
+		error_print();
+		return -1;
+	}
+	if (!nodes) {
+		if (nodes_cnt) {
+			error_print();
+			return -1;
+		}
+		return 0;
+	}
+
+	if (asn1_object_identifier_to_octets(nodes, nodes_cnt, octets, &octetslen) != 1) {
+		error_print();
+		return -1;
+	}
+
+	if (out && *out) {
+		*(*out)++ = tag;
+	}
+	(*outlen)++;
+
+	(void)asn1_length_to_der(octetslen, out, outlen);
+
+	if (out && *out) {
+		memcpy(*out, octets, octetslen);
+		*out += octetslen;
+	}
+	*outlen += octetslen;
+	return 1;
+}
+
+int asn1_object_identifier_from_der_ex(int tag, uint32_t *nodes, size_t *nodes_cnt,
+	const uint8_t **in, size_t *inlen)
+{
+	size_t len;
+
+	// unlike _from_octets(), _from_der() require output buffer
+	if (!nodes || !nodes_cnt || !in || !(*in) || !inlen) {
+		error_print();
+		return -1;
+	}
+
+	// tag
+	if (*inlen == 0 || **in != tag) {
+		*nodes_cnt = 0;
+		return 0;
+	}
+	(*in)++;
+	(*inlen)--;
+
+	// length (not zero)
+	if (asn1_length_from_der(&len, in, inlen) != 1) {
+		error_print();
+		return -1;
+	}
+	if (len < ASN1_OID_MIN_OCTETS) {
+		error_print();
+		return -1;
+	}
+
+	// parse OID
+	if (asn1_object_identifier_from_octets(nodes, nodes_cnt, *in, len) != 1) {
+		error_print();
+		return -1;
+	}
+	*in += len;
+	*inlen -= len;
+
+	return 1;
+}
+
+int asn1_object_identifier_equ(const uint32_t *a, size_t a_cnt, const uint32_t *b, size_t b_cnt)
+{
+	if (!a || a_cnt < ASN1_OID_MIN_NODES || a_cnt > ASN1_OID_MAX_NODES
+		|| !b || b_cnt < ASN1_OID_MIN_NODES || b_cnt > ASN1_OID_MAX_NODES) {
+		error_print();
+		return 0; // _equ() should return 1 or 0
+	}
+	if (a_cnt != b_cnt || memcmp(a, b, b_cnt * sizeof(uint32_t))) {
+		return 0;
+	}
+	return 1;
+}
+
+int asn1_object_identifier_print(FILE *fp, int format, int indent, const char *label, const char *name,
+	const uint32_t *nodes, size_t nodes_cnt)
+{
+	size_t i;
+	format_print(fp, format, indent, "%s: %s", label, name ? name : "(unknown)");
+	if (nodes) {
+		fprintf(fp, " (");
+		for (i = 0; i < nodes_cnt - 1; i++) {
+			fprintf(fp, "%d.", (int)nodes[i]);
+		}
+		fprintf(fp, "%d)", nodes[i]);
+	}
+	fprintf(fp, "\n");
+	return 1;
+}
+
+const ASN1_OID_INFO *asn1_oid_info_from_name(const ASN1_OID_INFO *infos, size_t infos_cnt, const char *name)
+{
+	size_t i;
+
+	if (!infos || !infos_cnt || !name) {
+		error_print();
+		return NULL;
+	}
+	for (i = 0; i < infos_cnt; i++) {
+		if (strcmp(infos[i].name, name) == 0) {
+			return &infos[i];
+		}
+	}
+	return NULL;
+}
+
+const ASN1_OID_INFO *asn1_oid_info_from_oid(const ASN1_OID_INFO *infos, size_t infos_cnt, int oid)
+{
+	size_t i;
+
+	if (!infos || !infos_cnt || oid < 0) {
+		error_print();
+		return NULL;
+	}
+	for (i = 0; i < infos_cnt; i++) {
+		if (infos[i].oid == oid) {
+			return &infos[i];
+		}
+	}
+	return NULL;
+}
+
+int asn1_oid_info_from_der_ex(const ASN1_OID_INFO **info, uint32_t *nodes, size_t *nodes_cnt,
+	const ASN1_OID_INFO *infos, size_t infos_cnt, const uint8_t **in, size_t *inlen)
+{
+	int ret;
+	size_t i;
+
+	if (!info) {
+		error_print();
+		return -1;
+	}
+	if ((ret = asn1_object_identifier_from_der(nodes, nodes_cnt, in, inlen)) != 1) {
+		if (ret < 0) error_print();
+		else *info = NULL;
+		return ret;
+	}
+
+	for (i = 0; i < infos_cnt; i++) {
+		if (*nodes_cnt == infos[i].nodes_cnt
+			&& memcmp(nodes, infos[i].nodes, (*nodes_cnt) * sizeof(int)) == 0) {
+			*info = &infos[i];
+			return 1;
+		}
+	}
+
+	// OID with correct encoding but in the (infos, infos_cnt) list
+	*info = NULL;
+	return 1;
+}
+
+int asn1_oid_info_from_der(const ASN1_OID_INFO **info, const ASN1_OID_INFO *infos, size_t count, const uint8_t **in, size_t *inlen)
+{
+	int ret;
+	uint32_t nodes[ASN1_OID_MAX_NODES];
+	size_t nodes_cnt;
+
+	if ((ret = asn1_oid_info_from_der_ex(info, nodes, &nodes_cnt, infos, count, in, inlen)) != 1) {
+		if (ret < 0) error_print();
+		return ret;
+	}
+	if (*info == NULL) {
+		asn1_object_identifier_print(stderr, 0, 0, "Unknown OID", NULL, nodes, nodes_cnt);
+		error_print();
+		return -1;
+	}
+	return 1;
+}
+
+/*
+utf-8 character encoding
+ 	1-byte: 0xxxxxxx
+	2-byte: 110xxxxx 10xxxxxx
+	3-byte: 1110xxxx 10xxxxxx 10xxxxxx
+	4-byte: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
+*/
+static int asn1_utf8char_from_bytes(uint32_t *c, const uint8_t **pin, size_t *pinlen)
+{
+	uint32_t utf8char;
+	const uint8_t *in = *pin;
+	size_t inlen = *pinlen;
+	uint32_t utf8char_len, i;
+
+	if (!inlen) {
+		return 0;
+	}
+
+	if ((in[0] & 0x80) == 0x00) {
+		utf8char_len = 1;
+	} else if ((in[0] & 0xe0) == 0xc0) {
+		utf8char_len = 2;
+	} else if ((in[0] & 0xf0) == 0xe0) {
+		utf8char_len = 3;
+	} else if ((in[0] & 0xf8) == 0xf0) {
+		utf8char_len = 4;
+	} else {
+		//error_print(); // disable error_print for _is_ compare
+		return -1;
+	}
+
+	if (inlen < utf8char_len) {
+		//error_print(); // disable error_print for _is_ compare
+		return -1;
+	}
+
+	utf8char = in[0];
+	for (i = 1; i < utf8char_len; i++) {
+		if ((in[i] & 0x60) != 0x80) {
+			//error_print(); // disable error_print for _is_ compare
+			return -1;
+		}
+		utf8char = (utf8char << 8) | in[i];
+	}
+
+	*c = utf8char;
+	(*pin) += utf8char_len;
+	(*pinlen) -= utf8char_len;
+	return 1;
+}
+
+
+int asn1_string_is_utf8_string(const char *a, size_t alen)
+{
+	uint32_t utf8char;
+
+	if (!a || !alen) {
+		return 0;
+	}
+	while (alen) {
+		if (asn1_utf8char_from_bytes(&utf8char, (const uint8_t **)&a, &alen) != 1) {
+			return 0;
+		}
+	}
+	return 1;
+}
+
+int asn1_utf8_string_to_der_ex(int tag, const char *d, size_t dlen, uint8_t **out, size_t *outlen)
+{
+	int ret;
+	if (asn1_string_is_utf8_string(d, dlen) != 1) {
+		error_print();
+		return -1;
+	}
+	if ((ret = asn1_type_to_der(tag, (const uint8_t *)d, dlen, out, outlen)) != 1) {
+		if (ret) error_print();
+		return ret;
+	}
+	return 1;
+}
+
+int asn1_utf8_string_from_der_ex(int tag, const char **a, size_t *alen, const uint8_t **in, size_t *inlen)
+{
+	int ret;
+	if ((ret = asn1_type_from_der(tag, (const uint8_t **)a, alen, in, inlen)) != 1) {
+		if (ret < 0) error_print();
+		return ret;
+	}
+	if (*a == NULL || *alen == 0) {
+		error_print();
+		return -1;
+	}
+	if (asn1_string_is_utf8_string(*a, *alen) != 1) {
+		error_print();
+		return -1;
+	}
+	return 1;
+}
+
+static int asn1_char_is_printable(int a)
+{
+	if (('0' <= a && a <= '9')
+		|| ('a' <= a && a <= 'z')
+		|| ('A' <= a && a <= 'Z')) {
+		return 1;
+	}
+
+	switch (a) {
+	case ' ': case '\'': case '(': case ')':
+	case '+': case ',': case '-': case '.':
+	case '/': case ':': case '=': case '?':
+		return 1;
+	}
+	return 0;
+}
+
+int asn1_string_is_printable_string(const char *a, size_t alen)
+{
+	size_t i;
+	for (i = 0; i < alen; i++) {
+		if (asn1_char_is_printable(a[i]) != 1) {
+			return 0;
+		}
+	}
+	return 1;
+}
+
+int asn1_printable_string_case_ignore_match(const char *a, size_t alen,
+	const char *b, size_t blen)
+{
+	// remove leading and suffix space chars
+	while (alen && *a == ' ') {
+		a++;
+		alen--;
+	}
+	while (alen && a[alen - 1] == ' ') {
+		alen--;
+	}
+
+	// remove leading and suffix space chars
+	while (blen && *b == ' ') {
+		b++;
+		blen--;
+	}
+	while (blen && b[blen - 1] == ' ') {
+		blen--;
+	}
+
+	if (alen != blen) {
+		return 0;
+	}
+	// case insensitive compare
+	while (alen--) {
+		if (toupper(*a) != toupper(*b)) {
+			return 0;
+		}
+	}
+	return 1;
+}
+
+int asn1_printable_string_to_der_ex(int tag, const char *d, size_t dlen, uint8_t **out, size_t *outlen)
+{
+	int ret;
+	if (asn1_string_is_printable_string(d, dlen) != 1) {
+		error_print();
+		return -1;
+	}
+	if ((ret = asn1_type_to_der(tag, (const uint8_t *)d, dlen, out, outlen)) != 1) {
+		if (ret) error_print();
+		return ret;
+	}
+	return 1;
+}
+
+int asn1_printable_string_from_der_ex(int tag, const char **a, size_t *alen, const uint8_t **in, size_t *inlen)
+{
+	int ret;
+
+	if ((ret = asn1_type_from_der(tag, (const uint8_t **)a, alen, in, inlen)) != 1) {
+		if (ret < 0) error_print();
+		return ret;
+	}
+	if (*a == NULL || *alen == 0) {
+		error_print();
+		return -1;
+	}
+	if (asn1_string_is_printable_string(*a, *alen) != 1) {
+		error_print();
+		return -1;
+	}
+	return 1;
+}
+
+int asn1_string_is_ia5_string(const char *a, size_t alen)
+{
+	size_t i;
+	for (i = 0; i < alen; i++) {
+		if (!isascii(a[i])) {
+			return 0;
+		}
+	}
+	return 1;
+}
+
+int asn1_ia5_string_to_der_ex(int tag, const char *d, size_t dlen, uint8_t **out, size_t *outlen)
+{
+	int ret;
+	if (asn1_string_is_ia5_string(d, dlen) != 1) {
+		error_print();
+		return -1;
+	}
+	if ((ret = asn1_type_to_der(tag, (const uint8_t *)d, dlen, out, outlen)) != 1) {
+		if (ret) error_print();
+		return ret;
+	}
+	return 1;
+}
+
+int asn1_ia5_string_from_der_ex(int tag, const char **a, size_t *alen, const uint8_t **in, size_t *inlen)
+{
+	int ret;
+
+	if ((ret = asn1_type_from_der(tag, (const uint8_t **)a, alen, in, inlen)) != 1) {
+		if (ret < 0) error_print();
+		return ret;
+	}
+	if (*a == NULL || *alen == 0) {
+		error_print();
+		return -1;
+	}
+	if (asn1_string_is_ia5_string(*a, *alen) != 1) {
+		error_print();
+		return -1;
+	}
+	return 1;
+}
+
+int asn1_string_print(FILE *fp, int fmt, int ind, const char *label, int tag, const uint8_t *d, size_t dlen)
+{
+	format_print(fp, fmt, ind, "%s: ", label);
+	while (dlen--) {
+		fprintf(fp, "%c", *d++);
+	}
+	fprintf(fp, "\n");
+	return 1;
+}
+
+static int is_leap_year(int year) {
+	return ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)) ? 1 : 0;
+}
+
+#define val(c)	((c)-'0')
+
+int asn1_time_from_str(int utc_time, time_t *timestamp, const char *str)
+{
+	int time_str_len[2] = { 15, 13 };
+	int days_per_year[2] = { 365, 366 };
+	int days_per_month[] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };
+	int year, month, day, hour, minute, second;
+	const char *p = str;
+	int i;
+
+	utc_time &= 1;
+	for (i = 0; i < time_str_len[utc_time] - 1; i++) {
+		if (!('0' <= str[i] && str[i] <= '9')) {
+			error_print();
+			return -1;
+		}
+	}
+	if (str[i] != 'Z') {
+		error_print();
+		return -1;
+	}
+
+	if (utc_time) {
+		year = val(p[0]) * 10 + val(p[1]);
+		if (year <= 50) {
+			year += 2000;
+		} else {
+			year += 1900;
+		}
+		p += 2;
+	} else {
+		year = val(p[0]) * 1000 + val(str[1]) * 100 + val(str[2]) * 10 + val(str[3]);
+		p += 4;
+	}
+	if (is_leap_year(year)) {
+		days_per_month[2] = 29;
+	}
+	month	= val(p[0]) * 10 + val(p[1]); p += 2;
+	day	= val(p[0]) * 10 + val(p[1]); p += 2;
+	hour	= val(p[0]) * 10 + val(p[1]); p += 2;
+	minute	= val(p[0]) * 10 + val(p[1]); p += 2;
+	second	= val(p[0]) * 10 + val(p[1]); p += 2;
+
+	if (year < 1970
+		|| month < 1 || month > 12
+		|| day < 1 || day > days_per_month[month]
+		|| hour < 0 || hour > 23
+		|| minute < 0 || minute > 59
+		|| second < 0 || second > 59) {
+		error_print();
+		return -1;
+	}
+
+	day--;
+
+	while (year-- > 1970) {
+		day += days_per_year[is_leap_year(year)];
+	}
+	while (month-- > 1) {
+		day += days_per_month[month];
+	}
+	*timestamp = (time_t)day * 86400 + hour * 3600 + minute * 60 + second;
+
+	return 1;
+}
+
+int asn1_time_to_str(int utc_time, time_t timestamp, char *str)
+{
+	int days_per_month[] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };
+	int days_per_year[2] = { 365, 366 };
+	int max_year[2] = { 9999, 2050 };
+	int year, month, second, hour, minute;
+	time_t day;
+	char *p = str;
+
+	utc_time &= 1;
+	day = timestamp / 86400;
+	second = timestamp % 86400;
+
+	// In UTCTime, year in [1951, 2050], YY <= 50, year = 20YY; YY > 50, year = 19YY
+	// For Validity, year SHOULD <= 2049 (NOT 2050)
+	for (year = 1970; year <= max_year[utc_time]; year++) {
+		if (day < days_per_year[is_leap_year(year)]) {
+			break;
+		}
+		day -= days_per_year[is_leap_year(year)];
+	}
+	if (year > max_year[utc_time]) {
+		error_print();
+		return -1;
+	}
+
+	day++;
+
+	if (is_leap_year(year)) {
+		days_per_month[2] = 29;
+	}
+	for (month = 1; month <= 12; month++) {
+		if (day <= days_per_month[month]) {
+			break;
+		}
+		day -= days_per_month[month];
+	}
+
+	hour = second / 3600;
+	second %= 3600;
+	minute = second / 60;
+	second %= 60;
+
+	if (utc_time) {
+		memset(p, '0', 12);
+	} else {
+		memset(p, '0', 14);
+		p[0] += (year / 100) / 10;
+		p[1] += (year / 100) % 10;
+		p += 2;
+	}
+
+	year %= 100;
+	p[0] += year / 10;
+	p[1] += year % 10;
+	p[2] += month / 10;
+	p[3] += month % 10;
+	p[4] += (int)day / 10;
+	p[5] += day % 10;
+	p[6] += hour / 10;
+	p[7] += hour % 10;
+	p[8] += minute / 10;
+	p[9] += minute % 10;
+	p[10] += second / 10;
+	p[11] += second % 10;
+	p[12] = 'Z';
+
+	return 1;
+}
+
+int asn1_utc_time_to_der_ex(int tag, time_t a, uint8_t **out, size_t *outlen)
+{
+	char buf[ASN1_UTC_TIME_STRLEN + 1] = {0};
+	int utc_time = 1;
+
+	if (!outlen) {
+		error_print();
+		return -1;
+	}
+	if (a == -1) {
+		return 0;
+	}
+
+	if (asn1_time_to_str(utc_time, a, buf) != 1) {
+		error_print();
+		return -1;
+	}
+
+	if (out && *out) {
+		*(*out)++ = tag;
+	}
+	(*outlen)++;
+	asn1_length_to_der(ASN1_UTC_TIME_STRLEN, out, outlen);
+	if (out && *out) {
+		memcpy(*out, buf, ASN1_UTC_TIME_STRLEN);
+		(*out) += ASN1_UTC_TIME_STRLEN;
+	}
+	*outlen += ASN1_UTC_TIME_STRLEN;
+
+	return 1;
+}
+
+int asn1_utc_time_from_der_ex(int tag, time_t *t, const uint8_t **in, size_t *inlen)
+{
+	size_t len;
+
+	if (!t || !in || !(*in) || !inlen) {
+		error_print();
+		return -1;
+	}
+
+	// tag
+	if (*inlen == 0 || **in != tag) {
+		*t = -1;
+		return 0;
+	}
+	(*in)++;
+	(*inlen)--;
+
+	// length
+	if (asn1_length_from_der(&len, in, inlen) != 1) {
+		error_print();
+		return -1;
+	}
+
+	if (len == sizeof("YYMMDDHHMMSSZ")-1) {
+		char buf[sizeof("YYMMDDHHMMSSZ")-1];
+		memcpy(buf, *in, len);
+		if (asn1_time_from_str(1, t, buf) != 1) {
+			error_print();
+			return -1;
+		}
+	} else if (len == sizeof("YYMMDDHHMMSS+HHMM")-1) {
+		char buf[sizeof("YYMMDDHHMMSS+HHMM")-1];
+		memcpy(buf, *in, len);
+		// this format is not supported yet
+		error_print();
+		return -1;
+	} else {
+		error_print();
+		return -1;
+	}
+
+	*in += len;
+	*inlen -= len;
+	return 1;
+}
+
+int asn1_generalized_time_to_der_ex(int tag, time_t a, uint8_t **out, size_t *outlen)
+{
+	char buf[ASN1_GENERALIZED_TIME_STRLEN + 1] = {0};
+	int utc_time = 0;
+
+	if (!outlen) {
+		error_print();
+		return -1;
+	}
+	if (a == -1) {
+		return 0;
+	}
+
+	if (asn1_time_to_str(utc_time, a, buf) != 1) {
+		error_print();
+		return -1;
+	}
+
+	if (out && *out)
+		*(*out)++ = tag;
+	(*outlen)++;
+	asn1_length_to_der(ASN1_GENERALIZED_TIME_STRLEN, out, outlen);
+	if (out && *out) {
+		memcpy(*out, buf, ASN1_GENERALIZED_TIME_STRLEN);
+		(*out) += ASN1_GENERALIZED_TIME_STRLEN;
+	}
+	*outlen += ASN1_GENERALIZED_TIME_STRLEN;
+
+	return 1;
+}
+
+int asn1_generalized_time_from_der_ex(int tag, time_t *t, const uint8_t **in, size_t *inlen)
+{
+	size_t len;
+
+	if (!t || !in || !(*in) || !inlen) {
+		error_print();
+		return -1;
+	}
+
+	// tag
+	if (*inlen == 0 || **in != tag) {
+		*t = -1;
+		return 0;
+	}
+	(*in)++;
+	(*inlen)--;
+
+	// length
+	if (asn1_length_from_der(&len, in, inlen) != 1) {
+		error_print();
+		return -1;
+	}
+
+	if (len == sizeof("YYYYMMDDHHMMSSZ")-1) {
+		char buf[sizeof("YYYYMMDDHHMMSSZ")-1];
+		memcpy(buf, *in, len);
+		if (asn1_time_from_str(0, t, buf) != 1) {
+			error_print();
+			return -1;
+		}
+	} else if (len == sizeof("YYYYMMDDHHMMSS+HHMM")-1) {
+		char buf[sizeof("YYYYMMDDHHMMSS+HHMM")-1];
+		memcpy(buf, *in, len);
+		error_print();
+		return -1;
+	} else {
+		error_print();
+		return -1;
+	}
+
+	*in += len;
+	*inlen -= len;
+	return 1;
+}
+
+int asn1_sequence_of_int_to_der(const int *nums, size_t nums_cnt, uint8_t **out, size_t *outlen)
+{
+	size_t len = 0;
+	size_t i;
+
+	if (!nums || !nums_cnt || !outlen) {
+		error_print();
+		return -1;
+	}
+
+	for (i = 0; i < nums_cnt; i++) {
+		if (asn1_int_to_der(nums[i], NULL, &len) != 1) {
+			error_print();
+			return -1;
+		}
+	}
+	if (asn1_sequence_header_to_der(len, out, outlen) != 1) {
+		error_print();
+		return -1;
+	}
+	for (i = 0; i < nums_cnt; i++) {
+		if (asn1_int_to_der(nums[i], out, outlen) != 1) {
+			error_print();
+			return -1;
+		}
+	}
+	return 1;
+}
+
+int asn1_sequence_of_int_from_der(int *nums, size_t *nums_cnt, size_t max_nums, const uint8_t **in, size_t *inlen)
+{
+	int ret;
+	const uint8_t *d;
+	size_t dlen;
+
+	if (!nums || !nums_cnt || !max_nums) {
+		error_print();
+		return -1;
+	}
+
+	*nums_cnt = 0;
+	if ((ret = asn1_sequence_from_der(&d, &dlen, in, inlen)) != 1) {
+		if (ret < 0) error_print();
+		return ret;
+	}
+	while (dlen) {
+		int num;
+		if (*nums_cnt > max_nums) {
+			error_print();
+			return -1;
+		}
+		if (asn1_int_from_der(&num, &d, &dlen) != 1) {
+			error_print();
+			return -1;
+		}
+		*nums++ = num;
+		(*nums_cnt)++;
+	}
+	return 1;
+}
+
+int asn1_sequence_of_int_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen)
+{
+	int val;
+	format_print(fp, fmt, ind, "%s: ", label);
+	while (dlen) {
+		if (asn1_int_from_der(&val, &d, &dlen) != 1) {
+			error_print();
+			return -1;
+		}
+		fprintf(fp, "%d%s", val, dlen ? "," : "");
+	}
+	fprintf(fp, "\n");
+	return 1;
+}
+
+int asn1_types_get_count(const uint8_t *d, size_t dlen, int tag, size_t *cnt)
+{
+	int item_tag;
+	const uint8_t *item_d;
+	size_t item_dlen;
+
+	if (!d || !cnt) {
+		error_print();
+		return -1;
+	}
+	*cnt = 0;
+	while (dlen) {
+		if (asn1_any_type_from_der(&item_tag, &item_d, &item_dlen, &d, &dlen) != 1) {
+			error_print();
+			return -1;
+		}
+		if (item_tag != tag) {
+			error_print();
+			return -1;
+		}
+		(*cnt)++;
+	}
+	return 1;
+}
+
+int asn1_types_get_item_by_index(const uint8_t *d, size_t dlen, int tag,
+	int index, const uint8_t **item_d, size_t *item_dlen)
+{
+	int a_tag;
+	const uint8_t *a_d;
+	size_t a_dlen;
+	int i = 0;
+
+	if (!d || !item_d || !item_dlen) {
+		error_print();
+		return -1;
+	}
+
+	while (dlen) {
+		if (asn1_any_type_from_der(&a_tag, &a_d, &a_dlen, &d, &dlen) != 1) {
+			error_print();
+			return -1;
+		}
+		if (a_tag != tag) {
+			error_print();
+			return -1;
+		}
+		if (i++ == index) {
+			*item_d = d;
+			*item_dlen = dlen;
+			return 1; // do not check the following
+		}
+	}
+
+	error_print();
+	return -1;
+}
+
+int asn1_check(int expr)
+{
+	if (expr)
+		return 1;
+	error_print();
+	return -1;
+}
+
+int asn1_length_is_zero(size_t len)
+{
+	if (len) {
+		error_print();
+		return -1;
+	}
+	return 1;
+}
+
+int asn1_length_le(size_t len1, size_t len2)
+{
+	if (len1 > len2) {
+		error_print();
+		// format_print(stderr, 0, 0, "%s: %zu <= %zu failed\n", __FUNCTION__, len1, len2);
+		return -1;
+	}
+	return 1;
+}

+ 82 - 0
components/gmssl/src/block_cipher.c

@@ -0,0 +1,82 @@
+/*
+ *  Copyright 2014-2022 The GmSSL Project. All Rights Reserved.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the License); you may
+ *  not use this file except in compliance with the License.
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ */
+
+
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <gmssl/oid.h>
+#include <gmssl/block_cipher.h>
+#include <gmssl/endian.h>
+
+
+int block_cipher_set_encrypt_key(BLOCK_CIPHER_KEY *key, const BLOCK_CIPHER *cipher, const uint8_t *raw_key)
+{
+	memset(key, 0, sizeof(BLOCK_CIPHER_KEY));
+	cipher->set_encrypt_key(key, raw_key);
+	key->cipher = cipher;
+	return 1;
+}
+
+int block_cipher_set_decrypt_key(BLOCK_CIPHER_KEY *key, const BLOCK_CIPHER *cipher, const uint8_t *raw_key)
+{
+	memset(key, 0, sizeof(BLOCK_CIPHER_KEY));
+	cipher->set_decrypt_key(key, raw_key);
+	key->cipher = cipher;
+	return 1;
+}
+
+int block_cipher_encrypt(const BLOCK_CIPHER_KEY *key, const uint8_t *in, uint8_t *out)
+{
+	key->cipher->encrypt(key, in, out);
+	return 1;
+}
+
+int block_cipher_decrypt(const BLOCK_CIPHER_KEY *key, const uint8_t *in, uint8_t *out)
+{
+	key->cipher->decrypt(key, in, out);
+	return 1;
+}
+
+static const BLOCK_CIPHER sm4_block_cipher_object = {
+	OID_sm4,
+	SM4_KEY_SIZE,
+	SM4_BLOCK_SIZE,
+	(block_cipher_set_encrypt_key_func)sm4_set_encrypt_key,
+	(block_cipher_set_decrypt_key_func)sm4_set_decrypt_key,
+	(block_cipher_encrypt_func)sm4_encrypt,
+	(block_cipher_decrypt_func)sm4_encrypt,
+};
+
+const BLOCK_CIPHER *BLOCK_CIPHER_sm4(void) {
+	return &sm4_block_cipher_object;
+}
+
+static int aes128_set_encrypt_key(AES_KEY *aes_key, const uint8_t key[16]) {
+	return aes_set_encrypt_key(aes_key, key, 16);
+}
+
+static int aes128_set_decrypt_key(AES_KEY *aes_key, const uint8_t key[16]) {
+	return aes_set_decrypt_key(aes_key, key, 16);
+}
+
+static const BLOCK_CIPHER aes128_block_cipher_object = {
+	OID_aes128,
+	AES128_KEY_SIZE,
+	AES_BLOCK_SIZE,
+	(block_cipher_set_encrypt_key_func)aes128_set_encrypt_key,
+	(block_cipher_set_decrypt_key_func)aes128_set_decrypt_key,
+	(block_cipher_encrypt_func)aes_encrypt,
+	(block_cipher_decrypt_func)aes_encrypt,
+};
+
+const BLOCK_CIPHER *BLOCK_CIPHER_aes128(void) {
+	return &aes128_block_cipher_object;
+}

+ 85 - 0
components/gmssl/src/chacha20.c

@@ -0,0 +1,85 @@
+/*
+ *  Copyright 2014-2022 The GmSSL Project. All Rights Reserved.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the License); you may
+ *  not use this file except in compliance with the License.
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ */
+
+
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <gmssl/chacha20.h>
+#include <gmssl/endian.h>
+
+
+void chacha20_init(CHACHA20_STATE *state,
+	const uint8_t key[CHACHA20_KEY_SIZE],
+	const uint8_t nonce[CHACHA20_NONCE_SIZE],
+	uint32_t counter)
+{
+	state->d[ 0] = 0x61707865;
+	state->d[ 1] = 0x3320646e;
+	state->d[ 2] = 0x79622d32;
+	state->d[ 3] = 0x6b206574;
+	state->d[ 4] = GETU32_LE(key     );
+	state->d[ 5] = GETU32_LE(key +  4);
+	state->d[ 6] = GETU32_LE(key +  8);
+	state->d[ 7] = GETU32_LE(key + 12);
+	state->d[ 8] = GETU32_LE(key + 16);
+	state->d[ 9] = GETU32_LE(key + 20);
+	state->d[10] = GETU32_LE(key + 24);
+	state->d[11] = GETU32_LE(key + 28);
+	state->d[12] = counter;
+	state->d[13] = GETU32_LE(nonce);
+	state->d[14] = GETU32_LE(nonce + 4);
+	state->d[15] = GETU32_LE(nonce + 8);
+}
+
+/* quarter round */
+#define QR(A, B, C, D) \
+	A += B; D ^= A; D = ROL32(D, 16); \
+	C += D; B ^= C; B = ROL32(B, 12); \
+	A += B; D ^= A; D = ROL32(D,  8); \
+	C += D; B ^= C; B = ROL32(B,  7)
+
+/* double round on state 4x4 matrix:
+ * four column rounds and and four diagonal rounds
+ *
+ *   0   1   2   3
+ *   4   5   6   7
+ *   8   9  10  11
+ *  12  13  14  15
+ *
+ */
+#define DR(S) \
+	QR(S[0], S[4], S[ 8], S[12]);  \
+	QR(S[1], S[5], S[ 9], S[13]);  \
+	QR(S[2], S[6], S[10], S[14]);  \
+	QR(S[3], S[7], S[11], S[15]);  \
+	QR(S[0], S[5], S[10], S[15]);  \
+	QR(S[1], S[6], S[11], S[12]);  \
+	QR(S[2], S[7], S[ 8], S[13]);  \
+	QR(S[3], S[4], S[ 9], S[14])
+
+void chacha20_generate_keystream(CHACHA20_STATE *state, size_t counts, uint8_t *out)
+{
+	uint32_t working_state[16];
+	int i;
+
+	while (counts-- > 0) {
+		memcpy(working_state, state->d, sizeof(working_state));
+		for (i = 0; i < 10; i++) {
+			DR(working_state);
+		}
+		for (i = 0; i < 16; i++) {
+			working_state[i] += state->d[i];
+			PUTU32_LE(out, working_state[i]);
+			out += sizeof(uint32_t);
+		}
+		state->d[12]++;
+	}
+}

+ 2480 - 0
components/gmssl/src/cms.c

@@ -0,0 +1,2480 @@
+/*
+ *  Copyright 2014-2022 The GmSSL Project. All Rights Reserved.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the License); you may
+ *  not use this file except in compliance with the License.
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ */
+
+
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <gmssl/asn1.h>
+#include <gmssl/aes.h>
+#include <gmssl/sm4.h>
+#include <gmssl/sm3.h>
+#include <gmssl/sm2.h>
+#include <gmssl/digest.h>
+#include <gmssl/error.h>
+#include <gmssl/x509.h>
+#include <gmssl/x509_alg.h>
+#include <gmssl/x509_ext.h>
+#include <gmssl/x509_crl.h>
+#include <gmssl/rand.h>
+#include <gmssl/pem.h>
+#include <gmssl/cms.h>
+
+
+
+static uint32_t oid_cms_data[] = { oid_sm2_cms,1 };
+static uint32_t oid_cms_signed_data[] = { oid_sm2_cms,2 };
+static uint32_t oid_cms_enveloped_data[] = { oid_sm2_cms,3 };
+static uint32_t oid_cms_signed_and_enveloped_data[] = { oid_sm2_cms,4 };
+static uint32_t oid_cms_encrypted_data[] = { oid_sm2_cms,5 };
+static uint32_t oid_cms_key_agreement_info[] = { oid_sm2_cms,6 };
+#define OID_CMS_CONUNT (sizeof(oid_cms_data)/sizeof(int))
+
+static const ASN1_OID_INFO cms_content_types[] = {
+	{ OID_cms_data, "data", oid_cms_data, OID_CMS_CONUNT },
+	{ OID_cms_signed_data, "signedData", oid_cms_signed_data, OID_CMS_CONUNT },
+	{ OID_cms_enveloped_data, "envelopedData", oid_cms_enveloped_data, OID_CMS_CONUNT },
+	{ OID_cms_signed_and_enveloped_data, "signedAndEnvelopedData", oid_cms_signed_and_enveloped_data, OID_CMS_CONUNT },
+	{ OID_cms_encrypted_data, "encryptedData", oid_cms_encrypted_data, OID_CMS_CONUNT },
+	{ OID_cms_key_agreement_info, "keyAgreementInfo", oid_cms_key_agreement_info, OID_CMS_CONUNT }
+};
+
+static const size_t cms_content_types_count =
+	sizeof(cms_content_types)/sizeof(cms_content_types[0]);
+
+const char *cms_content_type_name(int oid)
+{
+	const ASN1_OID_INFO *info;
+	if (!(info = asn1_oid_info_from_oid(cms_content_types, cms_content_types_count, oid))) {
+		error_print();
+		return NULL;
+	}
+	return info->name;
+}
+
+int cms_content_type_from_name(const char *name)
+{
+	const ASN1_OID_INFO *info;
+	if (!(info = asn1_oid_info_from_name(cms_content_types, cms_content_types_count, name))) {
+		error_print();
+		return OID_undef;
+	}
+	return info->oid;
+}
+
+int cms_content_type_to_der(int oid, uint8_t **out, size_t *outlen)
+{
+	const ASN1_OID_INFO *info;
+
+	if (oid == -1) {
+		return 0;
+	}
+	if (!(info = asn1_oid_info_from_oid(cms_content_types, cms_content_types_count, oid))) {
+		error_print();
+		return -1;
+	}
+	if (asn1_object_identifier_to_der(info->nodes, info->nodes_cnt, out, outlen) != 1) {
+		error_print();
+		return -1;
+	}
+	return 1;
+}
+
+int cms_content_type_from_der(int *oid, const uint8_t **in, size_t *inlen)
+{
+	int ret;
+	const ASN1_OID_INFO *info;
+
+	if ((ret = asn1_oid_info_from_der(&info, cms_content_types, cms_content_types_count, in, inlen)) != 1) {
+		if (ret < 0) error_print();
+		else *oid = -1;
+		return ret;
+	}
+	*oid = info->oid;
+	return 1;
+}
+
+/*
+static int cms_content_info_data_header_to_der(size_t dlen, uint8_t **out, size_t *outlen)
+{
+	uint8_t d[1];
+	size_t len = 0;
+	size_t content_len = 0;
+	if (asn1_octet_string_to_der(p, dlen, NULL, &content_len) != 1
+		|| cms_content_type_to_der(OID_cms_data, out, outlen) != 1
+		|| asn1_explicit_header_to_der(0, content_len, out, outlen) < 0
+		|| asn1_octet_string_to_der(dlen, out, outlen) < 0) {
+		error_print();
+		return -1;
+	}
+	return 1;
+}
+*/
+
+int cms_content_info_header_to_der(int content_type, size_t content_len, uint8_t **out, size_t *outlen)
+{
+	size_t len = content_len; // 注意:由于header_to_der没有输出数据,因此需要加上数据的长度,header length 才是正确的值
+	/*
+	if (content_type == OID_cms_data) {
+		return cms_content_info_data_header_to_der(content_len, out, outlen);
+	}
+	*/
+
+	if (cms_content_type_to_der(content_type, NULL, &len) != 1
+		|| asn1_explicit_header_to_der(0, content_len, NULL, &len) < 0
+		|| asn1_sequence_header_to_der(len, out, outlen) != 1
+		|| cms_content_type_to_der(content_type, out, outlen) != 1
+		|| asn1_explicit_header_to_der(0, content_len, out, outlen) < 0) {
+		error_print();
+		return -1;
+	}
+	return 1;
+}
+
+static int cms_content_info_data_to_der(const uint8_t *d, size_t dlen, uint8_t **out, size_t *outlen)
+{
+	size_t len = 0;
+	size_t content_len = 0;
+	if (asn1_octet_string_to_der(d, dlen, NULL, &content_len) != 1
+		|| cms_content_type_to_der(OID_cms_data, NULL, &len) != 1
+		|| asn1_explicit_to_der(0, d, content_len, NULL, &len) != 1
+		|| asn1_sequence_header_to_der(len, out, outlen) != 1
+		|| cms_content_type_to_der(OID_cms_data, out, outlen) != 1
+		|| asn1_explicit_header_to_der(0, content_len, out, outlen) != 1
+		|| asn1_octet_string_to_der(d, dlen, out, outlen) != 1) {
+		error_print();
+		return -1;
+	}
+	return 1;
+}
+
+int cms_content_info_to_der(
+	int content_type, const uint8_t *content, size_t content_len,
+	uint8_t **out, size_t *outlen)
+{
+	size_t len = 0;
+	if (content_type == OID_cms_data) {
+		return cms_content_info_data_to_der(content, content_len, out, outlen);
+	}
+	if (cms_content_type_to_der(content_type, NULL, &len) != 1
+		|| asn1_explicit_to_der(0, content, content_len, NULL, &len) < 0
+		|| asn1_sequence_header_to_der(len, out, outlen) != 1
+		|| cms_content_type_to_der(content_type, out, outlen) != 1
+		|| asn1_explicit_to_der(0, content, content_len, out, outlen) < 0) {
+		error_print();
+		return -1;
+	}
+	return 1;
+}
+
+int cms_content_info_from_der(
+	int *content_type,
+	const uint8_t **content, size_t *content_len,
+	const uint8_t **in, size_t *inlen)
+{
+	int ret;
+	const uint8_t *d;
+	size_t dlen;
+
+	if ((ret = asn1_sequence_from_der(&d, &dlen, in, inlen)) != 1) {
+		if (ret < 0) error_print();
+		return ret;
+	}
+	if (cms_content_type_from_der(content_type, &d, &dlen) != 1
+		|| asn1_explicit_from_der(0, content, content_len, &d, &dlen) < 0
+		|| asn1_length_is_zero(dlen) != 1) {
+		error_print();
+		return -1;
+	}
+	return 1;
+}
+
+int cms_content_info_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen)
+{
+	int ret;
+	int content_type;
+	const uint8_t *content;
+	size_t content_len;
+	const uint8_t *p;
+	size_t len;
+
+	format_print(fp, fmt, ind, "%s\n", label);
+	ind += 4;
+
+	if (cms_content_type_from_der(&content_type, &d, &dlen) != 1) goto err;
+	format_print(fp, fmt, ind, "contentType: %s\n", cms_content_type_name(content_type));
+
+	/*
+		if (content_type == OID_cms_data) {
+			if (asn1_octet_string_from_der(&p, &len, &content, &content_len) != 1) goto err;
+		} else {
+			if (asn1_sequence_from_der(&p, &len, &content, &content_len) != 1) goto err;
+		}
+	*/
+
+	//format_bytes(stderr, 0, 0, "content", d, dlen);
+
+	if ((ret = asn1_explicit_from_der(0, &content, &content_len, &d, &dlen)) < 0) { error_print(); goto err; }
+	if (ret == 0) { error_print(); goto err; }
+
+	if (content_type == OID_cms_data) {
+		if (asn1_octet_string_from_der(&p, &len, &content, &content_len) != 1
+			|| asn1_length_is_zero(content_len) != 1) {
+			error_print();
+			return -1;
+		}
+		format_bytes(fp, fmt, ind, "content", p, len);
+		return 1;
+	}
+
+
+	if (asn1_sequence_from_der(&p, &len, &content, &content_len) != 1) { error_print(); goto err; }
+
+	switch (content_type) {
+	//case OID_cms_data: format_bytes(fp, fmt, ind, "content", p, len); break;
+	case OID_cms_signed_data: cms_signed_data_print(fp, fmt, ind, "content", p, len); break;
+	case OID_cms_enveloped_data: cms_enveloped_data_print(fp, fmt, ind, "content", p, len); break;
+	case OID_cms_signed_and_enveloped_data: cms_signed_and_enveloped_data_print(fp, fmt, ind, "content", p, len); break;
+	case OID_cms_encrypted_data: cms_encrypted_data_print(fp, fmt, ind, "content", p, len); break;
+	case OID_cms_key_agreement_info: cms_key_agreement_info_print(fp, fmt, ind, "content", p, len); break;
+	}
+	if (asn1_length_is_zero(content_len) != 1) goto err;
+
+
+	if (asn1_length_is_zero(dlen) != 1) goto err;
+	return 1;
+err:
+	error_print();
+	return -1;
+}
+
+int cms_enced_content_info_to_der(
+	int content_type,
+	int enc_algor, const uint8_t *enc_iv, size_t enc_iv_len,
+	const uint8_t *enced_content, size_t enced_content_len,
+	const uint8_t *shared_info1, size_t shared_info1_len,
+	const uint8_t *shared_info2, size_t shared_info2_len,
+	uint8_t **out, size_t *outlen)
+{
+	size_t len = 0;
+	if (cms_content_type_to_der(content_type, NULL, &len) != 1
+		|| x509_encryption_algor_to_der(enc_algor, enc_iv, enc_iv_len, NULL, &len) != 1
+		|| asn1_implicit_octet_string_to_der(0, enced_content, enced_content_len, NULL, &len) < 0
+		|| asn1_implicit_octet_string_to_der(1, shared_info1, shared_info1_len, NULL, &len) < 0
+		|| asn1_implicit_octet_string_to_der(2, shared_info2, shared_info2_len, NULL, &len) < 0
+		|| asn1_sequence_header_to_der(len, out, outlen) != 1
+		|| cms_content_type_to_der(content_type, out, outlen) != 1
+		|| x509_encryption_algor_to_der(enc_algor, enc_iv, enc_iv_len, out, outlen) != 1
+		|| asn1_implicit_octet_string_to_der(0, enced_content, enced_content_len, out, outlen) < 0
+		|| asn1_implicit_octet_string_to_der(1, shared_info1, shared_info1_len, out, outlen) < 0
+		|| asn1_implicit_octet_string_to_der(2, shared_info2, shared_info2_len, out, outlen) < 0) {
+		error_print();
+		return -1;
+	}
+	return 1;
+}
+
+int cms_enced_content_info_from_der(
+	int *content_type,
+	int *enc_algor, const uint8_t **enc_iv, size_t *enc_iv_len,
+	const uint8_t **enced_content, size_t *enced_content_len,
+	const uint8_t **shared_info1, size_t *shared_info1_len,
+	const uint8_t **shared_info2, size_t *shared_info2_len,
+	const uint8_t **in, size_t *inlen)
+{
+	int ret;
+	const uint8_t *d;
+	size_t dlen;
+
+	if ((ret = asn1_sequence_from_der(&d, &dlen, in, inlen)) != 1) {
+		if (ret < 0) error_print();
+		return ret;
+	}
+	if (cms_content_type_from_der(content_type, &d, &dlen) != 1
+		|| x509_encryption_algor_from_der(enc_algor, enc_iv, enc_iv_len, &d, &dlen) != 1
+		|| asn1_implicit_octet_string_from_der(0, enced_content, enced_content_len, &d, &dlen) < 0
+		|| asn1_implicit_octet_string_from_der(1, shared_info1, shared_info1_len, &d, &dlen) < 0
+		|| asn1_implicit_octet_string_from_der(2, shared_info2, shared_info2_len, &d, &dlen) < 0
+		|| asn1_length_is_zero(dlen) != 1) {
+		error_print();
+		return -1;
+	}
+	return 1;
+}
+
+int cms_enced_content_info_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen)
+{
+	int ret, val;
+	const uint8_t *p;
+	size_t len;
+
+	format_print(fp, fmt, ind, "%s\n", label);
+	ind += 4;
+
+	if (cms_content_type_from_der(&val, &d, &dlen) != 1) goto err;
+	format_print(fp, fmt, ind, "contentType: %s\n", cms_content_type_name(val));
+	if (asn1_sequence_from_der(&p, &len, &d, &dlen) != 1) goto err;
+	x509_encryption_algor_print(fp, fmt, ind, "contentEncryptionAlgorithm", p, len);
+	if ((ret = asn1_implicit_octet_string_from_der(0, &p, &len, &d, &dlen)) < 0) goto err;
+	if (ret) format_bytes(fp, fmt, ind, "encryptedContent", p, len);
+	if ((ret = asn1_implicit_octet_string_from_der(1, &p, &len, &d, &dlen)) < 0) goto err;
+	if (ret) format_bytes(fp, fmt, ind, "sharedInfo1", p, len);
+	if ((ret = asn1_implicit_octet_string_from_der(2, &p, &len, &d, &dlen)) < 0) goto err;
+	if (ret) format_bytes(fp, fmt, ind, "sharedInfo2", p, len);
+	if (asn1_length_is_zero(dlen) != 1) goto err;
+	return 1;
+err:
+	error_print();
+	return -1;
+}
+
+int cms_enced_content_info_encrypt_to_der(
+	int enc_algor, const uint8_t *key, size_t keylen, const uint8_t *iv, size_t ivlen,
+	int content_type, const uint8_t *content, size_t content_len,
+	const uint8_t *shared_info1, size_t shared_info1_len,
+	const uint8_t *shared_info2, size_t shared_info2_len,
+	uint8_t **out, size_t *outlen)
+{
+	int ret;
+	SM4_KEY sm4_key;
+	uint8_t* enced_content = NULL;							
+	size_t enced_content_len = 100; // FIXME: why 100?					
+
+	if (!(enced_content = malloc(32 + content_len))) {
+		error_print();
+		return -1;
+	}
+
+
+
+	if (enc_algor != OID_sm4_cbc || keylen != 16 || ivlen != 16) {
+		error_print();
+		return -1;
+	}
+
+	sm4_set_encrypt_key(&sm4_key, key);
+	if (sm4_cbc_padding_encrypt(&sm4_key, iv, content, content_len,
+		enced_content, &enced_content_len) != 1) {
+		memset(&sm4_key, 0, sizeof(SM4_KEY));
+		error_print();
+		return -1;
+	}
+	memset(&sm4_key, 0, sizeof(SM4_KEY));
+
+	if ((ret = cms_enced_content_info_to_der(content_type,
+		enc_algor, iv, ivlen, enced_content, enced_content_len,
+		shared_info1, shared_info1_len,
+		shared_info2, shared_info2_len,
+		out, outlen)) != 1) {
+		if (ret < 0) error_print();
+		return ret;
+	}
+	return 1;
+}
+
+// 这个函数显然是有问题的,调用方根本不知道应该准备多大的buffer			
+// 应该为content_len 输出给一个maxlen 的最大buffer值				
+int cms_enced_content_info_decrypt_from_der(
+	int *enc_algor, const uint8_t *key, size_t keylen,
+	int *content_type, uint8_t *content, size_t *content_len,
+	const uint8_t **shared_info1, size_t *shared_info1_len,// 支持可选null输出	
+	const uint8_t **shared_info2, size_t *shared_info2_len,// 支持可选null输出	
+	const uint8_t **in, size_t *inlen)
+{
+	SM4_KEY sm4_key;
+	const uint8_t *iv;
+	size_t ivlen;
+	const uint8_t *enced_content;
+	size_t enced_content_len;
+
+	if (cms_enced_content_info_from_der(content_type,
+			enc_algor, &iv, &ivlen, &enced_content, &enced_content_len,
+			shared_info1, shared_info1_len,
+			shared_info2, shared_info2_len,
+			in, inlen) != 1
+		|| asn1_check(*enc_algor == OID_sm4_cbc) != 1
+		|| asn1_check(ivlen == SM4_BLOCK_SIZE) != 1
+		|| asn1_check(keylen == SM4_KEY_SIZE) != 1) {
+		error_print();
+		return -1;
+	}
+
+	sm4_set_decrypt_key(&sm4_key, key);
+	if (sm4_cbc_padding_decrypt(&sm4_key, iv, enced_content, enced_content_len,
+		content, content_len) != 1) {
+		memset(&sm4_key, 0, sizeof(SM4_KEY));
+		return -1;
+	}
+	memset(&sm4_key, 0, sizeof(SM4_KEY));
+
+	return 1;
+}
+
+int cms_encrypted_data_to_der(
+	int version,
+	int content_type,
+	int enc_algor, const uint8_t *iv, size_t ivlen,
+	const uint8_t *enced_content, size_t enced_content_len,
+	const uint8_t *shared_info1, size_t shared_info1_len,
+	const uint8_t *shared_info2, size_t shared_info2_len,
+	uint8_t **out, size_t *outlen)
+{
+	size_t len = 0;
+	if (version != 1) {
+		error_print();
+		return -1;
+	}
+	if (asn1_int_to_der(version, NULL, &len) != 1
+		|| cms_enced_content_info_to_der(
+			content_type,
+			enc_algor, iv, ivlen,
+			enced_content, enced_content_len,
+			shared_info1, shared_info1_len,
+			shared_info2, shared_info2_len,
+			NULL, &len) != 1
+		|| asn1_sequence_header_to_der(len, out, outlen) != 1
+		|| asn1_int_to_der(version, out, outlen) != 1
+		|| cms_enced_content_info_to_der(
+			content_type,
+			enc_algor, iv, ivlen,
+			enced_content, enced_content_len,
+			shared_info1, shared_info1_len,
+			shared_info2, shared_info2_len,
+			NULL, &len) != 1) {
+		error_print();
+		return -1;
+	}
+	return 1;
+}
+
+int cms_encrypted_data_from_der(
+	int *version,
+	int *content_type,
+	int *enc_algor, const uint8_t **iv, size_t *ivlen,
+	const uint8_t **enced_content, size_t *enced_content_len,
+	const uint8_t **shared_info1, size_t *shared_info1_len,
+	const uint8_t **shared_info2, size_t *shared_info2_len,
+	const uint8_t **in, size_t *inlen)
+{
+	int ret;
+	const uint8_t *d;
+	size_t dlen;
+
+	if ((ret = asn1_sequence_from_der(&d, &dlen, in, inlen)) != 1) {
+		if (ret < 0) error_print();
+		return ret;
+	}
+	if (asn1_int_from_der(version, &d, &dlen) != 1
+		|| cms_enced_content_info_from_der(
+			content_type,
+			enc_algor, iv, ivlen,
+			enced_content, enced_content_len,
+			shared_info1, shared_info1_len,
+			shared_info2, shared_info2_len,
+			&d, &dlen) != 1
+		|| asn1_length_is_zero(dlen) != 1) {
+		error_print();
+		return -1;
+	}
+	if (*version != 1) {
+		error_print();
+		return -1;
+	}
+	return 1;
+}
+
+int cms_encrypted_data_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen)
+{
+	int val;
+	const uint8_t *p;
+	size_t len;
+
+	format_print(fp, fmt, ind, "%s\n", label);
+	ind += 4;
+
+	if (asn1_int_from_der(&val, &d, &dlen) != 1) goto err;
+	format_print(fp, fmt, ind, "version: %d\n", val);
+	if (asn1_sequence_from_der(&p, &len, &d, &dlen) != 1) goto err;
+	cms_enced_content_info_print(fp, fmt, ind, "encryptedContentInfo", p, len);
+	if (asn1_length_is_zero(dlen) != 1) goto err;
+	return 1;
+err:
+	error_print();
+	return -1;
+}
+
+int cms_encrypted_data_encrypt_to_der(
+	int enc_algor, const uint8_t *key, size_t keylen, const uint8_t *iv, size_t ivlen,
+	int content_type, const uint8_t *content, size_t content_len,
+	const uint8_t *shared_info1, size_t shared_info1_len,
+	const uint8_t *shared_info2, size_t shared_info2_len,
+	uint8_t **out, size_t *outlen)
+{
+	size_t len = 0;
+	if (asn1_int_to_der(CMS_version_v1, NULL, &len) != 1
+		|| cms_enced_content_info_encrypt_to_der(
+			enc_algor, key, keylen, iv, ivlen,
+			content_type, content, content_len,
+			shared_info1, shared_info1_len,
+			shared_info2, shared_info2_len,
+			NULL, &len) != 1
+		|| asn1_sequence_header_to_der(len, out, outlen) != 1
+		|| asn1_int_to_der(CMS_version_v1, out, outlen) != 1
+		|| cms_enced_content_info_encrypt_to_der(
+			enc_algor, key, keylen, iv, ivlen,
+			content_type, content, content_len,
+			shared_info1, shared_info1_len,
+			shared_info2, shared_info2_len,
+			out, outlen) != 1) {
+		error_print();
+		return -1;
+	}
+	return 1;
+}
+
+int cms_encrypted_data_decrypt_from_der(
+	int *enc_algor, const uint8_t *key, size_t keylen,
+	int *content_type, uint8_t *content, size_t *content_len,
+	const uint8_t **shared_info1, size_t *shared_info1_len,
+	const uint8_t **shared_info2, size_t *shared_info2_len,
+	const uint8_t **in, size_t *inlen)
+{
+	int ret, version;
+	const uint8_t *d;
+	size_t dlen;
+
+	if ((ret = asn1_sequence_from_der(&d, &dlen, in, inlen)) != 1) {
+		if (ret < 0) error_print();
+		return ret;
+	}
+	if (asn1_int_from_der(&version, &d, &dlen) != 1
+		|| asn1_check(version == CMS_version_v1) != 1
+		|| cms_enced_content_info_decrypt_from_der(
+			enc_algor, key, keylen,
+			content_type, content, content_len,
+			shared_info1, shared_info1_len,
+			shared_info2, shared_info2_len,
+			&d, &dlen) != 1
+		|| asn1_length_is_zero(dlen) != 1) {
+		error_print();
+		return -1;
+	}
+	return 1;
+}
+
+int cms_issuer_and_serial_number_to_der(
+	const uint8_t *issuer, size_t issuer_len,
+	const uint8_t *serial_number, size_t serial_number_len,
+	uint8_t **out, size_t *outlen)
+{
+	size_t len = 0;
+	if (asn1_sequence_to_der(issuer, issuer_len, NULL, &len) != 1
+		|| asn1_integer_to_der(serial_number, serial_number_len, NULL, &len) != 1
+		|| asn1_sequence_header_to_der(len, out, outlen) != 1
+		|| asn1_sequence_to_der(issuer, issuer_len, out, outlen) != 1
+		|| asn1_integer_to_der(serial_number, serial_number_len, out, outlen) != 1) {
+		error_print();
+		return -1;
+	}
+	return 1;
+}
+
+int cms_issuer_and_serial_number_from_der(
+	const uint8_t **issuer, size_t *issuer_len,
+	const uint8_t **serial_number, size_t *serial_number_len,
+	const uint8_t **in, size_t *inlen)
+{
+	int ret;
+	const uint8_t *d;
+	size_t dlen;
+
+	if ((ret = asn1_sequence_from_der(&d, &dlen, in, inlen)) != 1) {
+		if (ret < 0) error_print();
+		return ret;
+	}
+	if (asn1_sequence_from_der(issuer, issuer_len, &d, &dlen) != 1
+		|| asn1_integer_from_der(serial_number, serial_number_len, &d, &dlen) != 1
+		|| asn1_length_is_zero(dlen) != 1) {
+		error_print();
+		return -1;
+	}
+	return 1;
+}
+
+int cms_issuer_and_serial_number_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen)
+{
+	const uint8_t *p;
+	size_t len;
+
+	format_print(fp, fmt, ind, "%s\n", label);
+	ind += 4;
+
+	if (asn1_sequence_from_der(&p, &len, &d, &dlen) != 1) goto err;
+	x509_name_print(fp, fmt, ind, "issuer", p, len);
+	if (asn1_integer_from_der(&p, &len, &d, &dlen) != 1) goto err;
+	format_bytes(fp, fmt, ind, "serialNumber", p, len);
+	if (asn1_length_is_zero(dlen) != 1) goto err;
+	return 1;
+err:
+	error_print();
+	return -1;
+}
+
+int cms_signer_info_to_der(
+	int version,
+	const uint8_t *issuer, size_t issuer_len,
+	const uint8_t *serial_number, size_t serial_number_len,
+	int digest_algor,
+	const uint8_t *authed_attrs, size_t authed_attrs_len,
+	int signature_algor,
+	const uint8_t *enced_digest, size_t enced_digest_len,
+	const uint8_t *unauthed_attrs, size_t unauthed_attrs_len,
+	uint8_t **out, size_t *outlen)
+{
+	size_t len = 0;
+	if (version != 1) {
+		error_print();
+		return -1;
+	}
+
+	if (asn1_int_to_der(version, NULL, &len) != 1
+		|| cms_issuer_and_serial_number_to_der(
+			issuer, issuer_len,
+			serial_number, serial_number_len, NULL, &len) != 1
+		|| x509_digest_algor_to_der(digest_algor, NULL, &len) != 1
+		|| asn1_implicit_set_to_der(0, authed_attrs, authed_attrs_len, NULL, &len) < 0
+		|| x509_signature_algor_to_der(signature_algor, NULL, &len) != 1
+		|| asn1_octet_string_to_der(enced_digest, enced_digest_len, NULL, &len) != 1
+		|| asn1_implicit_set_to_der(1, unauthed_attrs, unauthed_attrs_len, NULL, &len) < 0
+		|| asn1_sequence_header_to_der(len, out, outlen) != 1
+		|| asn1_int_to_der(version, out, outlen) != 1
+		|| cms_issuer_and_serial_number_to_der(
+			issuer, issuer_len,
+			serial_number, serial_number_len, out, outlen) != 1
+		|| x509_digest_algor_to_der(digest_algor, out, outlen) != 1
+		|| asn1_implicit_set_to_der(0, authed_attrs, authed_attrs_len, out, outlen) < 0
+		|| x509_signature_algor_to_der(signature_algor, out, outlen) != 1
+		|| asn1_octet_string_to_der(enced_digest, enced_digest_len, out, outlen) != 1
+		|| asn1_implicit_set_to_der(1, unauthed_attrs, unauthed_attrs_len, out, outlen) < 0) {
+		error_print();
+		return -1;
+	}
+	return 1;
+}
+
+int cms_signer_info_from_der(
+	int *version,
+	const uint8_t **issuer, size_t *issuer_len,
+	const uint8_t **serial_number, size_t *serial_number_len,
+	int *digest_algor,
+	const uint8_t **authed_attrs, size_t *authed_attrs_len,
+	int *signature_algor,
+	const uint8_t **enced_digest, size_t *enced_digest_len,
+	const uint8_t **unauthed_attrs, size_t *unauthed_attrs_len,
+	const uint8_t **in, size_t *inlen)
+{
+	int ret;
+	const uint8_t *d;
+	size_t dlen;
+
+	if ((ret = asn1_sequence_from_der(&d, &dlen, in, inlen)) != 1) {
+		if (ret < 0) error_print();
+		return ret;
+	}
+	if (asn1_int_from_der(version, &d, &dlen) != 1
+		|| cms_issuer_and_serial_number_from_der(issuer, issuer_len,
+			serial_number, serial_number_len, &d, &dlen) != 1
+		|| x509_digest_algor_from_der(digest_algor, &d, &dlen) != 1
+		|| asn1_implicit_set_from_der(0, authed_attrs, authed_attrs_len, &d, &dlen) < 0
+		|| x509_signature_algor_from_der(signature_algor, &d, &dlen) != 1
+		|| asn1_octet_string_from_der(enced_digest, enced_digest_len, &d, &dlen) != 1
+		|| asn1_implicit_set_from_der(1, unauthed_attrs, unauthed_attrs_len, &d, &dlen) < 0
+		|| asn1_length_is_zero(dlen) != 1) {
+		error_print();
+		return -1;
+	}
+	return 1;
+}
+
+int cms_signer_info_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen)
+{
+	int ret, val;
+	const uint8_t *p;
+	size_t len;
+
+	format_print(fp, fmt, ind, "%s\n", label);
+	ind += 4;
+
+	if (asn1_int_from_der(&val, &d, &dlen) != 1) goto err;
+	format_print(fp, fmt, ind, "version: %d\n", val);
+	if (asn1_sequence_from_der(&p, &len, &d, &dlen) != 1) goto err;
+	cms_issuer_and_serial_number_print(fp, fmt, ind, "issuerAndSerialNumber", p, len);
+	if (x509_digest_algor_from_der(&val, &d, &dlen) != 1) goto err;
+	format_print(fp, fmt, ind, "digestAlgorithm: %s\n", x509_digest_algor_name(val));
+	if ((ret = asn1_implicit_set_from_der(0, &p, &len, &d, &dlen)) < 0) goto err;
+	if (ret) x509_attributes_print(fp, fmt, ind, "authenticatedAttributes", p, len);
+	if (asn1_sequence_from_der(&p, &len, &d, &dlen) != 1) goto err;
+	x509_signature_algor_print(fp, fmt, ind, "digestEncryptionAlgorithm", p, len);
+	if (asn1_octet_string_from_der(&p, &len, &d, &dlen) != 1) goto err;
+	format_bytes(fp, fmt, ind, "encryptedDigest", p, len);
+	if ((ret = asn1_implicit_set_from_der(1, &p, &len, &d, &dlen)) < 0) goto err;
+	if (ret) x509_attributes_print(fp, fmt, ind, "unauthenticatedAttributes", p, len);
+	if (asn1_length_is_zero(dlen) != 1) goto err;
+	return 1;
+err:
+	error_print();
+	return -1;
+}
+
+int cms_signer_info_sign_to_der(
+	const SM3_CTX *sm3_ctx, const SM2_KEY *sign_key,
+	const uint8_t *issuer, size_t issuer_len,
+	const uint8_t *serial_number, size_t serial_number_len,
+	const uint8_t *authed_attrs, size_t authed_attrs_len,
+	const uint8_t *unauthed_attrs, size_t unauthed_attrs_len,
+	uint8_t **out, size_t *outlen)
+{
+	SM3_CTX ctx = *sm3_ctx;
+	int fixed_outlen = 1;
+	uint8_t dgst[SM3_DIGEST_SIZE];
+	uint8_t sig[SM2_MAX_SIGNATURE_SIZE];
+	size_t siglen = SM2_signature_typical_size;
+
+	sm3_update(&ctx, authed_attrs, authed_attrs_len);
+	sm3_finish(&ctx, dgst);
+
+	if (sm2_sign_fixlen(sign_key, dgst, siglen, sig) != 1) {
+		error_print();
+		return -1;
+	}
+	if (cms_signer_info_to_der(CMS_version_v1,
+		issuer, issuer_len, serial_number, serial_number_len,
+		OID_sm3, authed_attrs, authed_attrs_len,
+		OID_sm2sign_with_sm3, sig, siglen,
+		unauthed_attrs, unauthed_attrs_len, out, outlen) != 1) {
+		error_print();
+		return -1;
+	}
+	return 1;
+}
+
+int cms_signer_info_verify_from_der(
+	const SM3_CTX *ctx, const uint8_t *certs, size_t certslen,
+	const uint8_t **cert, size_t *certlen,
+	const uint8_t **issuer, size_t *issuer_len,
+	const uint8_t **serial, size_t *serial_len,
+	const uint8_t **authed_attrs, size_t *authed_attrs_len,
+	const uint8_t **unauthed_attrs, size_t *unauthed_attrs_len,
+	const uint8_t **in, size_t *inlen)
+{
+	int version;
+	int digest_algor;
+	int signature_algor;
+	const uint8_t *sig;
+	size_t siglen;
+	SM2_KEY public_key;
+	SM3_CTX sm3_ctx = *ctx;
+	uint8_t dgst[32];
+
+	if (cms_signer_info_from_der(&version,
+			issuer, issuer_len,
+			serial, serial_len,
+			&digest_algor, authed_attrs, authed_attrs_len,
+			&signature_algor, &sig, &siglen,
+			unauthed_attrs, unauthed_attrs_len,
+			in, inlen) != 1
+		|| asn1_check(version == CMS_version_v1) != 1
+		|| asn1_check(digest_algor == OID_sm3) != 1
+		|| asn1_check(signature_algor == OID_sm2sign_with_sm3) != 1) {
+		error_print();
+		return -1;
+	}
+	if (x509_certs_get_cert_by_issuer_and_serial_number(certs, certslen,
+			*issuer, *issuer_len, *serial, *serial_len, cert, certlen) != 1
+		|| x509_cert_get_subject_public_key(*cert, *certlen, &public_key) != 1) {
+		error_print();
+		return -1;
+	}
+
+	sm3_update(&sm3_ctx, *authed_attrs, *authed_attrs_len);
+	sm3_finish(&sm3_ctx, dgst);
+
+	if (sm2_verify(&public_key, dgst, sig, siglen) != 1) {
+		error_print();
+		return -1;
+	}
+	return 1;
+}
+
+int cms_signer_infos_add_signer_info(
+	uint8_t *d, size_t *dlen, size_t maxlen,
+	const SM3_CTX *sm3_ctx, const SM2_KEY *sign_key,
+	const uint8_t *issuer, size_t issuer_len,
+	const uint8_t *serial_number, size_t serial_number_len,
+	const uint8_t *authed_attrs, size_t authed_attrs_len,
+	const uint8_t *unauthed_attrs, size_t unauthed_attrs_len)
+{
+	size_t len = *dlen;
+	d += *dlen;
+	if (cms_signer_info_sign_to_der(sm3_ctx, sign_key,
+			issuer, issuer_len, serial_number, serial_number_len,
+			authed_attrs, authed_attrs_len,
+			unauthed_attrs, unauthed_attrs_len,
+			NULL, &len) != 1
+		|| asn1_length_le(len, maxlen) != 1
+		|| cms_signer_info_sign_to_der(sm3_ctx, sign_key,
+			issuer, issuer_len, serial_number, serial_number_len,
+			authed_attrs, authed_attrs_len,
+			unauthed_attrs, unauthed_attrs_len,
+			&d, dlen) != 1) {
+		error_print();
+		return -1;
+	}
+	return 1;
+}
+
+int cms_signer_infos_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen)
+{
+	const uint8_t *p;
+	size_t len;
+
+	format_print(fp, fmt, ind, "%s\n", label);
+	ind += 4;
+
+	while (dlen) {
+		if (asn1_sequence_from_der(&p, &len, &d, &dlen) != 1) {
+			error_print();
+			return -1;
+		}
+		cms_signer_info_print(fp, fmt, ind, "SignerInfo", p, len);
+	}
+	return 1;
+}
+
+int cms_digest_algors_to_der(const int *digest_algors, size_t digest_algors_cnt,
+	uint8_t **out, size_t *outlen)
+{
+	size_t len = 0, i;
+	for (i = 0; i < digest_algors_cnt; i++) {
+		if (x509_digest_algor_to_der(digest_algors[i], NULL, &len) != 1) {
+			error_print();
+			return -1;
+		}
+	}
+	if (asn1_set_header_to_der(len, out, outlen) != 1) {
+		error_print();
+		return -1;
+	}
+	for (i = 0; i < digest_algors_cnt; i++) {
+		if (x509_digest_algor_to_der(digest_algors[i], out, outlen) != 1) {
+			error_print();
+			return -1;
+		}
+	}
+	return 1;
+}
+
+int cms_digest_algors_from_der(int *digest_algors, size_t *digest_algors_cnt, size_t max_digest_algors,
+	const uint8_t **in, size_t *inlen)
+{
+	int ret;
+	const uint8_t *d;
+	size_t dlen;
+
+	if ((ret = asn1_set_from_der(&d, &dlen, in, inlen)) != 1) {
+		if (ret < 0) error_print();
+		return ret;
+	}
+
+	*digest_algors_cnt = 0;
+	while (dlen) {
+		if (*digest_algors_cnt > max_digest_algors) {
+			error_print();
+			return -1;
+		}
+		if (x509_digest_algor_from_der(digest_algors, &d, &dlen) != 1) {
+			error_print();
+			return -1;
+		}
+		digest_algors++;
+		(*digest_algors_cnt)++;
+	}
+	return 1;
+}
+
+int cms_digest_algors_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen)
+{
+	int oid;
+
+	format_print(fp, fmt, ind, "%s\n", label);
+	ind += 4;
+
+	while (dlen) {
+		if (x509_digest_algor_from_der(&oid, &d, &dlen) != 1) {
+			error_print();
+			return -1;
+		}
+		format_print(fp, fmt, ind, "%s\n", x509_digest_algor_name(oid));
+	}
+	return 1;
+}
+
+int cms_signed_data_to_der(
+	int version,
+	const int *digest_algors, size_t digest_algors_cnt,
+	const int content_type, const uint8_t *content, const size_t content_len,
+	const uint8_t *certs, size_t certs_len,
+	const uint8_t *crls, const size_t crls_len,
+	const uint8_t *signer_infos, size_t signer_infos_len,
+	uint8_t **out, size_t *outlen)
+{
+	size_t len = 0;
+	if (asn1_int_to_der(version, NULL, &len) != 1
+		|| cms_digest_algors_to_der(digest_algors, digest_algors_cnt, NULL, &len) != 1
+		|| cms_content_info_to_der(content_type, content, content_len, NULL, &len) != 1
+		|| asn1_implicit_set_to_der(0, certs, certs_len, NULL, &len) < 0
+		|| asn1_implicit_set_to_der(1, crls, crls_len, NULL, &len) < 0
+		|| cms_signer_infos_to_der(signer_infos, signer_infos_len, NULL, &len) != 1
+		|| asn1_sequence_header_to_der(len, out, outlen) != 1
+		|| asn1_int_to_der(version, out, outlen) != 1
+		|| cms_digest_algors_to_der(digest_algors, digest_algors_cnt, out, outlen) != 1
+		|| cms_content_info_to_der(content_type, content, content_len, out, outlen) != 1
+		|| asn1_implicit_set_to_der(0, certs, certs_len, out, outlen) < 0
+		|| asn1_implicit_set_to_der(1, crls, crls_len, out, outlen) < 0
+		|| cms_signer_infos_to_der(signer_infos, signer_infos_len, out, outlen) != 1) {
+		error_print();
+		return -1;
+	}
+	return 1;
+}
+
+int cms_signed_data_from_der(
+	int *version,
+	int *digest_algors, size_t *digest_algors_cnt, size_t max_digest_algors,
+	int *content_type, const uint8_t **content, size_t *content_len,
+	const uint8_t **certs, size_t *certs_len,
+	const uint8_t **crls, size_t *crls_len,
+	const uint8_t **signer_infos, size_t *signer_infos_len,
+	const uint8_t **in, size_t *inlen)
+{
+	int ret;
+	const uint8_t *d;
+	size_t dlen;
+
+	if ((ret = asn1_sequence_from_der(&d, &dlen, in, inlen)) != 1) {
+		if (ret < 0) error_print();
+		return ret;
+	}
+	if (asn1_int_from_der(version, &d, &dlen) != 1
+		|| cms_digest_algors_from_der(digest_algors, digest_algors_cnt, max_digest_algors, &d, &dlen) != 1
+		|| cms_content_info_from_der(content_type, content, content_len, &d, &dlen) != 1
+		|| asn1_implicit_set_from_der(0, certs, certs_len, &d, &dlen) < 0
+		|| asn1_implicit_set_from_der(1, crls, crls_len, &d, &dlen) < 0
+		|| asn1_set_from_der(signer_infos, signer_infos_len, &d, &dlen) != 1
+		|| asn1_length_is_zero(dlen) != 1) {
+		error_print();
+		return -1;
+	}
+	if (*version != CMS_version_v1) {
+		error_print();
+		return -1;
+	}
+	return 1;
+}
+
+int cms_signed_data_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen)
+{
+	int ret, val;
+	const uint8_t *p;
+	size_t len;
+
+	format_print(fp, fmt, ind, "%s\n", label);
+	ind += 4;
+
+	if (asn1_int_from_der(&val, &d, &dlen) != 1) goto err;
+	format_print(fp, fmt, ind, "version: %d\n", val);
+	if (asn1_set_from_der(&p, &len, &d, &dlen) != 1) goto err;
+	cms_digest_algors_print(fp, fmt, ind, "digestAlgorithms", p, len);
+	if (asn1_sequence_from_der(&p, &len, &d, &dlen) != 1) goto err;
+	cms_content_info_print(fp, fmt, ind, "contentInfo", p, len);
+	if ((ret = asn1_implicit_set_from_der(0, &p, &len, &d, &dlen)) < 0) goto err;
+	if (ret) x509_certs_print(fp, fmt, ind, "certificates", p, len);
+	if ((ret = asn1_implicit_set_from_der(1, &p, &len, &d, &dlen)) < 0) goto err;
+	if (asn1_set_from_der(&p, &len, &d, &dlen) != 1) goto err;
+	cms_signer_infos_print(fp, fmt, ind, "signerInfos", p, len);
+	if (asn1_length_is_zero(dlen) != 1) goto err;
+	return 1;
+err:
+	error_print();
+	return -1;
+}
+
+static int cms_implicit_signers_certs_to_der(int index,
+	const CMS_CERTS_AND_KEY *signers, size_t signers_cnt,
+	uint8_t **out, size_t *outlen)
+{
+	size_t i;
+	size_t len = 0;
+	for (i = 0; i < signers_cnt; i++) {
+		if (asn1_data_to_der(signers[i].certs, signers[i].certs_len, NULL, &len) != 1) {
+			error_print();
+			return -1;
+		}
+	}
+	if (asn1_implicit_header_to_der(index, len, out, outlen) != 1) {
+		error_print();
+		return -1;
+	}
+	for (i = 0; i < signers_cnt; i++) {
+		if (asn1_data_to_der(signers[i].certs, signers[i].certs_len, out, outlen) != 1) {
+			error_print();
+			return -1;
+		}
+	}
+	return 1;
+}
+
+int cms_signed_data_sign_to_der(
+	const CMS_CERTS_AND_KEY *signers, size_t signers_cnt,
+	int content_type, const uint8_t *data, size_t datalen,
+	const uint8_t *crls, size_t crls_len,
+	uint8_t **out, size_t *outlen)
+{
+	int digest_algors[] = { OID_sm3 };
+	size_t digest_algors_cnt = sizeof(digest_algors)/sizeof(int);
+	uint8_t content_header[256];
+	size_t content_header_len;
+	size_t certs_len = 0;
+	uint8_t signer_infos[512];
+	size_t signer_infos_len = 0;
+	SM3_CTX sm3_ctx;
+	const uint8_t *issuer;
+	size_t issuer_len;
+	const uint8_t *serial;
+	size_t serial_len;
+	uint8_t *p;
+	size_t len = 0;
+	size_t i;
+
+
+	// 当content_type == OID_cms_data 时,data是raw data,被封装为OCTET STRING编码输出
+	// 而content_type为其他类型时,data均为TLV的DER数据
+	// 在to_der/from_der 中已经处理,但是计算哈希值时也需要做处理
+	p = content_header;
+	content_header_len = 0;
+	if (content_type == OID_cms_data) {
+		size_t content_len = 0;
+		if (asn1_octet_string_to_der(data, datalen, NULL, &content_len) != 1
+			|| cms_content_info_header_to_der(content_type, content_len, &p, &content_header_len) != 1
+			|| asn1_octet_string_header_to_der(datalen, &p, &content_header_len) != 1) {
+			error_print();
+			return -1;
+		}
+	} else {
+		if (cms_content_info_header_to_der(content_type, datalen, &p, &content_header_len) != 1) {
+			error_print();
+			return -1;
+		}
+	}
+
+	sm3_init(&sm3_ctx);
+	sm3_update(&sm3_ctx, content_header, content_header_len);
+	sm3_update(&sm3_ctx, data, datalen);
+
+	for (i = 0; i < signers_cnt; i++) {
+		if (x509_cert_get_issuer_and_serial_number(
+				signers[i].certs, signers[i].certs_len,
+				&issuer, &issuer_len, &serial, &serial_len) != 1
+			|| cms_signer_infos_add_signer_info(
+				signer_infos, &signer_infos_len, sizeof(signer_infos),
+				&sm3_ctx, signers->sign_key,
+				issuer, issuer_len, serial, serial_len,
+				NULL, 0, NULL, 0) != 1) {
+			error_print();
+			return -1;
+		}
+	}
+
+	if (asn1_int_to_der(CMS_version_v1, NULL, &len) != 1
+		|| cms_digest_algors_to_der(digest_algors, digest_algors_cnt, NULL, &len) != 1
+		|| cms_content_info_to_der(content_type, data, datalen, NULL, &len) != 1
+		|| cms_implicit_signers_certs_to_der(0, signers, signers_cnt, NULL, &len) < 0
+		|| asn1_implicit_set_to_der(1, crls, crls_len, NULL, &len) < 0
+		|| asn1_set_to_der(signer_infos, signer_infos_len, NULL, &len) != 1
+		|| asn1_sequence_header_to_der(len, out, outlen) != 1
+		|| asn1_int_to_der(CMS_version_v1, out, outlen) != 1
+		|| cms_digest_algors_to_der(digest_algors, digest_algors_cnt, out, outlen) != 1
+		|| cms_content_info_to_der(content_type, data, datalen, out, outlen) != 1
+		|| cms_implicit_signers_certs_to_der(0, signers, signers_cnt, out, outlen) < 0
+		|| asn1_implicit_set_to_der(1, crls, crls_len, out, outlen) < 0
+		|| asn1_set_to_der(signer_infos, signer_infos_len, out, outlen) != 1) {
+		error_print();
+		return -1;
+	}
+	return 1;
+}
+
+int cms_signed_data_verify_from_der(
+	const uint8_t *extra_certs, size_t extra_certs_len,
+	const uint8_t *extra_crls, size_t extra_crls_len,
+	int *content_type, const uint8_t **content, size_t *content_len,
+	const uint8_t **certs, size_t *certs_len,
+	const uint8_t **crls, size_t *crls_len,
+	const uint8_t **psigner_infos, size_t *psigner_infos_len,
+	const uint8_t **in, size_t *inlen)
+{
+	int version;
+	int digest_algors[4];
+	size_t digest_algors_cnt;
+	SM3_CTX sm3_ctx;
+	uint8_t content_info_header[128];
+	size_t content_info_header_len;
+	uint8_t *p = content_info_header;
+	const uint8_t *signer_infos;
+	size_t signer_infos_len;
+
+	if (cms_signed_data_from_der(
+			&version,
+			digest_algors, &digest_algors_cnt, sizeof(digest_algors)/sizeof(int),
+			content_type, content, content_len,
+			certs, certs_len,
+			crls, crls_len,
+			&signer_infos, &signer_infos_len,
+			in, inlen) != 1
+		|| asn1_check(version == CMS_version_v1) != 1
+		|| asn1_check(digest_algors[0] == OID_sm3) != 1
+		|| asn1_check(digest_algors_cnt == 1) != 1) {
+		error_print();
+		return -1;
+	}
+	*psigner_infos = signer_infos;
+	*psigner_infos_len = signer_infos_len;
+
+	content_info_header_len = 0;
+	if (cms_content_info_header_to_der(*content_type, *content_len,
+		&p, &content_info_header_len) != 1) {
+		error_print();
+		return -1;
+	}
+	sm3_init(&sm3_ctx);
+
+	sm3_update(&sm3_ctx, content_info_header, content_info_header_len);
+	sm3_update(&sm3_ctx, *content, *content_len);
+
+	while (signer_infos_len) {
+		const uint8_t *cert;
+		size_t certlen;
+		const uint8_t *issuer;
+		size_t issuer_len;
+		const uint8_t *serial;
+		size_t serial_len;
+		const uint8_t *authed_attrs;
+		size_t authed_attrs_len;
+		const uint8_t *unauthed_attrs;
+		size_t unauthed_attrs_len;
+
+		if (cms_signer_info_verify_from_der(
+			&sm3_ctx, *certs, *certs_len,
+			&cert, &certlen,
+			&issuer, &issuer_len,
+			&serial, &serial_len,
+			&authed_attrs, &authed_attrs_len,
+			&unauthed_attrs, &unauthed_attrs_len,
+			&signer_infos, &signer_infos_len) != 1) {
+
+			error_print();
+			return -1;
+		}
+	}
+	return 1;
+}
+
+int cms_recipient_info_to_der(
+	int version,
+	const uint8_t *issuer, size_t issuer_len,
+	const uint8_t *serial_number, size_t serial_number_len,
+	int public_key_enc_algor,
+	const uint8_t *enced_key, size_t enced_key_len,
+	uint8_t **out, size_t *outlen)
+{
+	size_t len = 0;
+	if (version != 1) {
+		error_print();
+		return -1;
+	}
+	if (asn1_int_to_der(version, NULL, &len) != 1
+		|| cms_issuer_and_serial_number_to_der(issuer, issuer_len,
+			serial_number, serial_number_len, NULL, &len) != 1
+		|| x509_public_key_encryption_algor_to_der(public_key_enc_algor, NULL, &len) != 1
+		|| asn1_octet_string_to_der(enced_key, enced_key_len, NULL, &len) != 1
+		|| asn1_sequence_header_to_der(len, out, outlen) != 1
+		|| asn1_int_to_der(version, out, outlen) != 1
+		|| cms_issuer_and_serial_number_to_der(issuer, issuer_len,
+			serial_number, serial_number_len, out, outlen) != 1
+		|| x509_public_key_encryption_algor_to_der(public_key_enc_algor, out, outlen) != 1
+		|| asn1_octet_string_to_der(enced_key, enced_key_len, out, outlen) != 1) {
+		error_print();
+		return -1;
+	}
+	return 1;
+}
+
+int cms_recipient_info_from_der(
+	int *version,
+	const uint8_t **issuer, size_t *issuer_len,
+	const uint8_t **serial_number, size_t *serial_number_len,
+	int *pke_algor, const uint8_t **params, size_t *params_len,// SM2加密只使用SM3,没有默认参数,但是ECIES可能有
+	const uint8_t **enced_key, size_t *enced_key_len,
+	const uint8_t **in, size_t *inlen)
+{
+	int ret;
+	const uint8_t *d;
+	size_t dlen;
+
+	if ((ret = asn1_sequence_from_der(&d, &dlen, in, inlen)) != 1) {
+		if (ret < 0) error_print();
+		return ret;
+	}
+	if (asn1_int_from_der(version, &d, &dlen) != 1
+		|| cms_issuer_and_serial_number_from_der(issuer, issuer_len,
+			serial_number, serial_number_len, &d, &dlen) != 1
+		|| x509_public_key_encryption_algor_from_der(pke_algor, params, params_len, &d, &dlen) != 1
+		|| asn1_octet_string_from_der(enced_key, enced_key_len, &d, &dlen) != 1
+	//	|| asn1_length_is_zero(dlen) != 1				
+		) {
+		error_print();
+		return -1;
+	}
+	if (*version != 1) {
+		error_print();
+		return -1;
+	}
+	if (*pke_algor != OID_sm2encrypt) {
+		error_print();
+		return -1;
+	}
+	if (*params || *params_len) {
+		error_print();
+		return -1;
+	}
+	return 1;
+}
+
+int cms_recipient_info_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen)
+{
+	int val;
+	const uint8_t *p;
+	size_t len;
+
+	format_print(fp, fmt, ind, "%s\n", label);
+	ind += 4;
+
+	if (asn1_int_from_der(&val, &d, &dlen) != 1) goto err;
+	format_print(fp, fmt, ind, "version: %d\n", val);
+	if (asn1_sequence_from_der(&p, &len, &d, &dlen) != 1) goto err;
+	cms_issuer_and_serial_number_print(fp, fmt, ind, "issuerAndSerialNumber", p, len);
+	if (asn1_sequence_from_der(&p, &len, &d, &dlen) != 1) goto err;
+	x509_public_key_encryption_algor_print(fp, fmt, ind, "keyEncryptionAlgorithm", p, len);
+	if (asn1_octet_string_from_der(&p, &len, &d, &dlen) != 1) goto err;
+	format_bytes(fp, fmt, ind, "encryptedKey", p, len);
+	if (asn1_length_is_zero(dlen) != 1) goto err;
+	return 1;
+err:
+	error_print();
+	return -1;
+}
+
+int cms_recipient_info_encrypt_to_der(
+	const SM2_KEY *public_key,
+	const uint8_t *issuer, size_t issuer_len,
+	const uint8_t *serial_number, size_t serial_number_len,
+	const uint8_t *in, size_t inlen,
+	uint8_t **out, size_t *outlen)
+{
+	int pke_algor = OID_sm2encrypt;
+	uint8_t enced_key[SM2_MAX_CIPHERTEXT_SIZE];
+	size_t enced_key_len;
+	int fixed_outlen = 1;
+
+	if (pke_algor != OID_sm2encrypt) {
+		error_print();
+		return -1;
+	}
+
+	if (sm2_encrypt_fixlen(public_key, in, inlen, SM2_ciphertext_typical_point_size,
+		enced_key, &enced_key_len) != 1) {
+		error_print();
+		return -1;
+	}
+	if (cms_recipient_info_to_der(CMS_version_v1,
+		issuer, issuer_len, serial_number, serial_number_len,
+		pke_algor, enced_key, enced_key_len,
+		out, outlen) != 1) {
+		error_print();
+		return -1;
+	}
+	return 1;
+}
+
+int cms_recipient_info_decrypt_from_der(
+	const SM2_KEY *sm2_key,
+	const uint8_t *rcpt_issuer, size_t rcpt_issuer_len,
+	const uint8_t *rcpt_serial, size_t rcpt_serial_len,
+	uint8_t *out, size_t *outlen, size_t maxlen,
+	const uint8_t **in, size_t *inlen)
+{
+	int version;
+	int pke_algor;
+	const uint8_t *params;
+	size_t params_len;
+	const uint8_t *enced_key;
+	size_t enced_key_len;
+	const uint8_t *issuer;
+	size_t issuer_len;
+	const uint8_t *serial;
+	size_t serial_len;
+	uint8_t outbuf[SM2_MAX_PLAINTEXT_SIZE];
+
+	if (cms_recipient_info_from_der(&version,
+		&issuer, &issuer_len, &serial, &serial_len,
+		&pke_algor, &params, &params_len,
+		&enced_key, &enced_key_len,
+		in, inlen) != 1) {
+		error_print();
+		return -1;
+	}
+	if (issuer_len != rcpt_issuer_len
+		|| memcmp(issuer, rcpt_issuer, rcpt_issuer_len) != 0
+		|| serial_len != rcpt_serial_len
+		|| memcmp(serial, rcpt_serial, serial_len) != 0) {
+		error_print();
+		return 0;
+	}
+	if (pke_algor != OID_sm2encrypt || params || params_len) {
+		error_print();
+		return -1;
+	}
+	if (sm2_decrypt(sm2_key, enced_key, enced_key_len, outbuf, outlen) != 1) {
+		error_print();
+		return -1;
+	}
+	if (maxlen < *outlen) {
+		error_print();
+		return -1;
+	}
+	memcpy(out, outbuf, *outlen);
+	return 1;
+}
+
+int cms_recipient_infos_add_recipient_info(
+	uint8_t *d, size_t *dlen, size_t maxlen,
+	const SM2_KEY *public_key,
+	const uint8_t *issuer, size_t issuer_len,
+	const uint8_t *serial, size_t serial_len,
+	const uint8_t *in, size_t inlen)
+{
+	size_t len = *dlen;
+	d += *dlen;
+
+	if (cms_recipient_info_encrypt_to_der(
+			public_key,
+			issuer, issuer_len,
+			serial, serial_len,
+			in, inlen,
+			NULL, &len) != 1
+		|| asn1_length_le(len, maxlen) != 1
+		|| cms_recipient_info_encrypt_to_der(
+			public_key,
+			issuer, issuer_len,
+			serial, serial_len,
+			in, inlen,
+			&d, dlen) != 1) {
+		error_print();
+		return -1;
+	}
+	return 1;
+}
+
+int cms_recipient_infos_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen)
+{
+	const uint8_t *p;
+	size_t len;
+
+	format_print(fp, fmt, ind, "%s\n", label);
+	ind += 4;
+
+	while (dlen) {
+		if (asn1_sequence_from_der(&p, &len, &d, &dlen) != 1) {
+			error_print();
+			return -1;
+		}
+		cms_recipient_info_print(fp, fmt, ind, "RecipientInfo", p, len);
+	}
+	return 1;
+}
+
+int cms_enveloped_data_to_der(
+	int version,
+	const uint8_t *rcpt_infos, size_t rcpt_infos_len,
+	int content_type,
+	int enc_algor, const uint8_t *iv, size_t ivlen,
+	const uint8_t *enced_content, size_t enced_content_len,
+	const uint8_t *shared_info1, size_t shared_info1_len,
+	const uint8_t *shared_info2, size_t shared_info2_len,
+	uint8_t **out, size_t *outlen)
+{
+	size_t len = 0;
+	if (asn1_int_to_der(version, NULL, &len) != 1
+		|| asn1_set_to_der(rcpt_infos, rcpt_infos_len, NULL, &len) != 1
+		|| cms_enced_content_info_to_der(content_type,
+			enc_algor, iv, ivlen,
+			enced_content, enced_content_len,
+			shared_info1, shared_info1_len,
+			shared_info2, shared_info2_len,
+			NULL, &len) != 1
+		|| asn1_sequence_header_to_der(len, out, outlen) != 1
+		|| asn1_int_to_der(version, out, outlen) != 1
+		|| asn1_set_to_der(rcpt_infos, rcpt_infos_len, out, outlen) != 1
+		|| cms_enced_content_info_to_der(content_type,
+			enc_algor, iv, ivlen,
+			enced_content, enced_content_len,
+			shared_info1, shared_info1_len,
+			shared_info2, shared_info2_len,
+			out, outlen) != 1) {
+		error_print();
+		return -1;
+	}
+	return 1;
+}
+
+int cms_enveloped_data_from_der(
+	int *version,
+	const uint8_t **rcpt_infos, size_t *rcpt_infos_len,
+	const uint8_t **enced_content_info, size_t *enced_content_info_len,
+	const uint8_t **in, size_t *inlen)
+{
+	int ret;
+	const uint8_t *d;
+	size_t dlen;
+
+	if ((ret = asn1_sequence_from_der(&d, &dlen, in, inlen)) != 1) {
+		if (ret < 0) error_print();
+		return ret;
+	}
+	if (asn1_int_from_der(version, &d, &dlen) != 1
+		|| asn1_set_from_der(rcpt_infos, rcpt_infos_len, &d, &dlen) != 1
+		|| asn1_any_from_der(enced_content_info, enced_content_info_len, &d, &dlen) != 1
+		|| asn1_length_is_zero(dlen) != 1) {
+		error_print();
+		return -1;
+	}
+	return 1;
+}
+
+int cms_enveloped_data_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen)
+{
+	int val;
+	const uint8_t *p;
+	size_t len;
+
+	format_print(fp, fmt, ind, "%s\n", label);
+	ind += 4;
+
+	if (asn1_int_from_der(&val, &d, &dlen) != 1) goto err;
+	format_print(fp, fmt, ind, "version: %d\n", val);
+	if (asn1_set_from_der(&p, &len, &d, &dlen) != 1) goto err;
+	cms_recipient_infos_print(fp, fmt, ind, "recipientInfos", p, len);
+	if (asn1_sequence_from_der(&p, &len, &d, &dlen) != 1) goto err;
+	cms_enced_content_info_print(fp, fmt, ind, "encryptedContentInfo", p, len);
+	if (asn1_length_is_zero(dlen) != 1) goto err;
+	return 1;
+err:
+	error_print();
+	return -1;
+}
+
+int cms_enveloped_data_encrypt_to_der(
+	const uint8_t *rcpt_certs, size_t rcpt_certs_len,
+	int enc_algor, const uint8_t *key, size_t keylen, const uint8_t *iv, size_t ivlen,
+	int content_type, const uint8_t *content, size_t content_len,
+	const uint8_t *shared_info1, size_t shared_info1_len,
+	const uint8_t *shared_info2, size_t shared_info2_len,
+	uint8_t **out, size_t *outlen)
+{
+	uint8_t rcpt_infos[1024]; // 到底需要多大?				
+	size_t rcpt_infos_len = 0;
+	uint8_t *p = rcpt_infos;
+	size_t len = 0;
+
+	while (rcpt_certs_len) {
+		const uint8_t *cert;
+		size_t certlen;
+		SM2_KEY public_key;
+		const uint8_t *issuer;
+		size_t issuer_len;
+		const uint8_t *serial;
+		size_t serial_len;
+
+		if (asn1_any_from_der(&cert, &certlen, &rcpt_certs, &rcpt_certs_len) != 1
+			|| x509_cert_get_issuer_and_serial_number(cert, certlen,
+				&issuer, &issuer_len, &serial, &serial_len) != 1
+			|| x509_cert_get_subject_public_key(cert, certlen, &public_key) != 1) {
+			error_print();
+			return -1;
+		}
+		if (cms_recipient_info_encrypt_to_der(&public_key,
+				issuer, issuer_len, serial, serial_len,
+				key, keylen, NULL, &len) != 1
+			|| asn1_length_le(len, sizeof(rcpt_infos)) != 1
+			|| cms_recipient_info_encrypt_to_der(&public_key,
+				issuer, issuer_len, serial, serial_len,
+				key, keylen, &p, &rcpt_infos_len) != 1) {
+			error_print();
+			return -1;
+		}
+	}
+	len = 0;
+	if (asn1_int_to_der(CMS_version_v1, NULL, &len) != 1
+		|| asn1_set_to_der(rcpt_infos, rcpt_infos_len, NULL, &len) != 1
+		|| cms_enced_content_info_encrypt_to_der(
+			enc_algor, key, keylen, iv, ivlen,
+			content_type, content, content_len,
+			shared_info1, shared_info1_len,
+			shared_info2, shared_info2_len,
+			NULL, &len) != 1
+		|| asn1_sequence_header_to_der(len, out, outlen) != 1
+		|| asn1_int_to_der(CMS_version_v1, out, outlen) != 1
+		|| asn1_set_to_der(rcpt_infos, rcpt_infos_len, out, outlen) != 1
+		|| cms_enced_content_info_encrypt_to_der(
+			enc_algor, key, keylen, iv, ivlen,
+			content_type, content, content_len,
+			shared_info1, shared_info1_len,
+			shared_info2, shared_info2_len,
+			out, outlen) != 1) {
+		error_print();
+		return -1;
+	}
+	return 1;
+}
+
+int cms_enveloped_data_decrypt_from_der(
+	const SM2_KEY *sm2_key,
+	const uint8_t *issuer, size_t issuer_len,
+	const uint8_t *serial, size_t serial_len,
+	int *content_type, uint8_t *content, size_t *content_len,
+	const uint8_t **recipient_infos, size_t *recipient_infos_len,
+	const uint8_t **shared_info1, size_t *shared_info1_len,
+	const uint8_t **shared_info2, size_t *shared_info2_len,
+	const uint8_t **in, size_t *inlen)
+{
+	int ret = 0;
+	int version;
+	const uint8_t *rcpt_infos;
+	size_t rcpt_infos_len;
+	const uint8_t *enced_content_info;
+	size_t enced_content_info_len;
+	int enc_algor;
+	uint8_t key[32];
+	size_t keylen;
+
+	if (cms_enveloped_data_from_der(
+			&version, &rcpt_infos, &rcpt_infos_len,
+			&enced_content_info, &enced_content_info_len,
+			in, inlen) != 1
+		|| asn1_check(version == CMS_version_v1) != 1) {
+		return -1;
+	}
+	*recipient_infos = rcpt_infos;
+	*recipient_infos_len = rcpt_infos_len;
+
+	while (rcpt_infos_len) {
+		if ((ret = cms_recipient_info_decrypt_from_der(
+			sm2_key,
+			issuer, issuer_len,
+			serial, serial_len,
+			key, &keylen, sizeof(key),
+			&rcpt_infos, &rcpt_infos_len)) < 0) {
+			error_print();
+			return -1;
+		} else if (ret) {
+			break;
+		}
+	}
+	if (!ret) {
+		error_print();
+		return -1;
+	}
+
+	if (cms_enced_content_info_decrypt_from_der(
+		&enc_algor, key, keylen,
+		content_type, content, content_len,
+		shared_info1, shared_info1_len,
+		shared_info2, shared_info2_len,
+		&enced_content_info, &enced_content_info_len) != 1) {
+		error_print();
+		return -1;
+	}
+	return 1;
+}
+
+int cms_signed_and_enveloped_data_to_der(
+	int version,
+	const uint8_t *rcpt_infos, size_t rcpt_infos_len,
+	const int *digest_algors, size_t digest_algors_cnt,
+	int content_type,
+	int enc_algor, const uint8_t *iv, size_t ivlen,
+	const uint8_t *enced_content, size_t enced_content_len,
+	const uint8_t *shared_info1, size_t shared_info1_len,
+	const uint8_t *shared_info2, size_t shared_info2_len,
+	const uint8_t *certs, size_t certs_len,
+	const uint8_t *crls, size_t crls_len,
+	const uint8_t *signer_infos, size_t signer_infos_len,
+	uint8_t **out, size_t *outlen)
+{
+	size_t len = 0;
+	if (asn1_int_to_der(version, NULL, &len) != 1
+		|| asn1_set_to_der(rcpt_infos, rcpt_infos_len, NULL, &len) != 1
+		|| cms_digest_algors_to_der(digest_algors, digest_algors_cnt, NULL, &len) != 1
+		|| cms_enced_content_info_to_der(content_type,
+			enc_algor, iv, ivlen,
+			enced_content, enced_content_len,
+			shared_info1, shared_info1_len,
+			shared_info2, shared_info2_len,
+			NULL, &len) != 1
+		|| asn1_implicit_set_to_der(0, certs, certs_len, NULL, &len) < 0
+		|| asn1_implicit_set_to_der(1, crls, crls_len, NULL, &len) < 0
+		|| asn1_set_to_der(signer_infos, signer_infos_len, NULL, &len) != 1
+		|| asn1_sequence_header_to_der(len, out, outlen) != 1
+		|| asn1_int_to_der(version, out, outlen) != 1
+		|| asn1_set_to_der(rcpt_infos, rcpt_infos_len, out, outlen) != 1
+		|| cms_digest_algors_to_der(digest_algors, digest_algors_cnt, out, outlen) != 1
+		|| cms_enced_content_info_to_der(content_type,
+			enc_algor, iv, ivlen,
+			enced_content, enced_content_len,
+			shared_info1, shared_info1_len,
+			shared_info2, shared_info2_len,
+			out, outlen) != 1
+		|| asn1_implicit_set_to_der(0, certs, certs_len, out, outlen) < 0
+		|| asn1_implicit_set_to_der(1, crls, crls_len, out, outlen) < 0
+		|| asn1_set_to_der(signer_infos, signer_infos_len, out, outlen) != 1) {
+		error_print();
+		return -1;
+	}
+	return 1;
+}
+
+int cms_signed_and_enveloped_data_from_der(
+	int *version,
+	const uint8_t **rcpt_infos, size_t *rcpt_infos_len,
+	int *digest_algors, size_t *digest_algors_cnt, size_t max_digest_algors,
+	const uint8_t **enced_content_info, size_t *enced_content_info_len,
+	const uint8_t **certs, size_t *certs_len,
+	const uint8_t **crls, size_t *crls_len,
+	const uint8_t **signer_infos, size_t *signer_infos_len,
+	const uint8_t **in, size_t *inlen)
+{
+	int ret;
+	const uint8_t *d;
+	size_t dlen;
+
+	if ((ret = asn1_sequence_from_der(&d, &dlen, in, inlen)) != 1) {
+		if (ret < 0) error_print();
+		return ret;
+	}
+	if (asn1_int_from_der(version, &d, &dlen) != 1
+		|| asn1_set_from_der(rcpt_infos, rcpt_infos_len, &d, &dlen) != 1
+		|| cms_digest_algors_from_der(digest_algors, digest_algors_cnt, max_digest_algors, &d, &dlen) != 1
+		|| asn1_any_from_der(enced_content_info, enced_content_info_len, &d, &dlen) != 1
+		|| asn1_implicit_set_from_der(0, certs, certs_len, &d, &dlen) < 0
+		|| asn1_implicit_set_from_der(1, crls, crls_len, &d, &dlen) < 0
+		|| asn1_set_from_der(signer_infos, signer_infos_len, &d, &dlen) != 1
+		|| asn1_length_is_zero(dlen) != 1) {
+		error_print();
+		return -1;
+	}
+	return 1;
+}
+
+int cms_signed_and_enveloped_data_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen)
+{
+	int ret, val;
+	const uint8_t *p;
+	size_t len;
+
+	format_print(fp, fmt, ind, "%s\n", label);
+	ind += 4;
+
+	if (asn1_int_from_der(&val, &d, &dlen) != 1) goto err;
+	format_print(fp, fmt, ind, "version: %d\n", val);
+	if (asn1_set_from_der(&p, &len, &d, &dlen) != 1) goto err;
+	cms_recipient_infos_print(fp, fmt, ind, "recipientInfos", p, len);
+	if (asn1_set_from_der(&p, &len, &d, &dlen) != 1) goto err;
+	cms_digest_algors_print(fp, fmt, ind, "digestAlgorithms", p, len);
+	if (asn1_sequence_from_der(&p, &len, &d, &dlen) != 1) goto err;
+	cms_enced_content_info_print(fp, fmt, ind, "encryptedContentInfo", p, len);
+	if ((ret = asn1_implicit_set_from_der(0, &p, &len, &d, &dlen)) < 0) goto err;
+	if (ret) x509_certs_print(fp, fmt, ind, "certificates", p, len);
+	if ((ret = asn1_implicit_set_from_der(1, &p, &len, &d, &dlen)) < 0) goto err;
+	if (ret) x509_crls_print(fp, fmt, ind, "crls", p, len);
+	if (asn1_set_from_der(&p, &len, &d, &dlen) != 1) goto err;
+	cms_signer_infos_print(fp, fmt, ind, "signerInfos", p, len);
+	if (asn1_length_is_zero(dlen) != 1) goto err;
+	return 1;
+err:
+	error_print();
+	return -1;
+}
+
+int cms_signed_and_enveloped_data_encipher_to_der(
+	const CMS_CERTS_AND_KEY *signers, size_t signers_cnt,
+	const uint8_t *rcpt_certs, size_t rcpt_certs_len,
+	int enc_algor, const uint8_t *key, size_t keylen, const uint8_t *iv, size_t ivlen,
+	int content_type, const uint8_t *content, size_t content_len,
+	const uint8_t *signers_crls, size_t signers_crls_len,
+	const uint8_t *shared_info1, size_t shared_info1_len,
+	const uint8_t *shared_info2, size_t shared_info2_len,
+	uint8_t **out, size_t *outlen)
+{
+	uint8_t rcpt_infos[512];
+	size_t rcpt_infos_len = 0;
+	int digest_algors[] = { OID_sm3 };
+	size_t digest_algors_cnt = sizeof(digest_algors)/sizeof(int);
+	uint8_t content_info_header[256];
+	size_t content_info_header_len = 0;
+	uint8_t signer_infos[512];
+	size_t signer_infos_len = 0;
+	SM3_CTX sm3_ctx;
+	const uint8_t *issuer;
+	const uint8_t *serial;
+	size_t issuer_len;
+	size_t serial_len;
+	uint8_t *p;
+	size_t len = 0;
+	size_t i;
+
+	p = rcpt_infos;
+	while (rcpt_certs_len) {
+		const uint8_t *cert;
+		size_t certlen;
+		SM2_KEY public_key;
+
+		if (asn1_any_from_der(&cert, &certlen, &rcpt_certs, &rcpt_certs_len) != 1
+			|| x509_cert_get_issuer_and_serial_number(cert, certlen,
+				&issuer, &issuer_len, &serial, &serial_len) != 1
+			|| x509_cert_get_subject_public_key(cert, certlen, &public_key) != 1
+			|| cms_recipient_info_encrypt_to_der(&public_key,
+				issuer, issuer_len, serial, serial_len,
+				key, keylen, NULL, &len) != 1
+			|| asn1_length_le(len, sizeof(rcpt_infos)) != 1
+			|| cms_recipient_info_encrypt_to_der(&public_key,
+				issuer, issuer_len, serial, serial_len,
+				key, keylen, &p, &rcpt_infos_len) != 1) {
+			error_print();
+			return -1;
+		}
+	}
+
+	p = content_info_header;
+	if (cms_content_info_header_to_der(content_type, content_len,
+		&p, &content_info_header_len) != 1) {
+		error_print();
+		return -1;
+	}
+	sm3_init(&sm3_ctx);
+	sm3_update(&sm3_ctx, content_info_header, content_info_header_len);
+	sm3_update(&sm3_ctx, content, content_len);
+
+	for (i = 0; i < signers_cnt; i++) {
+		if (x509_cert_get_issuer_and_serial_number(
+				signers[i].certs, signers[i].certs_len,
+				&issuer, &issuer_len, &serial, &serial_len) != 1
+			|| cms_signer_infos_add_signer_info(
+				signer_infos, &signer_infos_len, sizeof(signer_infos),
+				&sm3_ctx, signers->sign_key,
+				issuer, issuer_len, serial, serial_len,
+				NULL, 0, NULL, 0) != 1) {
+			error_print();
+			return -1;
+		}
+	}
+
+	len = 0;
+	if (asn1_int_to_der(CMS_version_v1, NULL, &len) != 1
+		|| asn1_set_to_der(rcpt_infos, rcpt_infos_len, NULL, &len) != 1
+		|| cms_digest_algors_to_der(digest_algors, digest_algors_cnt, NULL, &len) != 1
+		|| cms_enced_content_info_encrypt_to_der(
+			enc_algor, key, keylen, iv, ivlen,
+			content_type, content, content_len,
+			shared_info1, shared_info1_len,
+			shared_info2, shared_info2_len,
+			NULL, &len) != 1
+		|| cms_implicit_signers_certs_to_der(0, signers, signers_cnt, NULL, &len) != 1
+		|| asn1_implicit_set_to_der(1, signers_crls, signers_crls_len, NULL, &len) < 0
+		|| asn1_set_to_der(signer_infos, signer_infos_len, NULL, &len) != 1
+		|| asn1_sequence_header_to_der(len, out, outlen) != 1
+		|| asn1_int_to_der(CMS_version_v1, out, outlen) != 1
+		|| asn1_set_to_der(rcpt_infos, rcpt_infos_len, out, outlen) != 1
+		|| cms_digest_algors_to_der(digest_algors, digest_algors_cnt, out, outlen) != 1
+		|| cms_enced_content_info_encrypt_to_der(
+			enc_algor, key, keylen, iv, ivlen,
+			content_type, content, content_len,
+			shared_info1, shared_info1_len,
+			shared_info2, shared_info2_len,
+			out, outlen) != 1
+		|| cms_implicit_signers_certs_to_der(0, signers, signers_cnt, out, outlen) != 1
+		|| asn1_implicit_set_to_der(1, signers_crls, signers_crls_len, out, outlen) != 1
+		|| asn1_set_to_der(signer_infos, signer_infos_len, out, outlen) != 1) {
+		error_print();
+		return -1;
+	}
+	return 1;
+}
+
+int cms_signed_and_enveloped_data_decipher_from_der(
+	const SM2_KEY *rcpt_key,
+	const uint8_t *rcpt_issuer, size_t rcpt_issuer_len,
+	const uint8_t *rcpt_serial, size_t rcpt_serial_len,
+	int *content_type, uint8_t *content, size_t *content_len,
+	const uint8_t **prcpt_infos, size_t *prcpt_infos_len,
+	const uint8_t **shared_info1, size_t *shared_info1_len,
+	const uint8_t **shared_info2, size_t *shared_info2_len,
+	const uint8_t **certs, size_t *certs_len,
+	const uint8_t **crls, size_t *crls_len,
+	const uint8_t **psigner_infos, size_t *psigner_infos_len,
+	const uint8_t *extra_certs, size_t extra_certs_len,
+	const uint8_t *extra_crls, size_t extra_crls_len,
+	const uint8_t **in, size_t *inlen)
+{
+	int ret;
+	int version;
+	const uint8_t *rcpt_infos;
+	size_t rcpt_infos_len;
+	int digest_algors[4];
+	size_t digest_algors_cnt;
+	const uint8_t *enced_content_info;
+	size_t enced_content_info_len;
+	const uint8_t *signer_infos;
+	size_t signer_infos_len;
+	int enc_algor;
+	uint8_t key[32];
+	size_t keylen;
+	SM3_CTX sm3_ctx;
+	uint8_t content_info_header[128];
+	size_t content_info_header_len = 0;
+	uint8_t *p = content_info_header;
+
+	if (cms_signed_and_enveloped_data_from_der(
+			&version,
+			&rcpt_infos, &rcpt_infos_len,
+			digest_algors, &digest_algors_cnt, sizeof(digest_algors)/sizeof(int),
+			&enced_content_info, &enced_content_info_len,
+			certs, certs_len,
+			crls, crls_len,
+			&signer_infos, &signer_infos_len,
+			in, inlen) != 1
+		|| asn1_check(version == CMS_version_v1) != 1
+		|| asn1_check(digest_algors[0] == OID_sm3) != 1) {
+		error_print();
+		return -1;
+	}
+	*prcpt_infos = rcpt_infos;
+	*prcpt_infos_len = rcpt_infos_len;
+	*psigner_infos = signer_infos;
+	*psigner_infos_len = signer_infos_len;
+
+	while (rcpt_infos_len) {
+		if ((ret = cms_recipient_info_decrypt_from_der(
+			rcpt_key,
+			rcpt_issuer, rcpt_issuer_len,
+			rcpt_serial, rcpt_serial_len,
+			key, &keylen, sizeof(key),
+			&rcpt_infos, &rcpt_infos_len)) < 0) {
+			error_print();
+			return -1;
+		} else if (ret) {
+			break;
+		}
+	}
+	if (!ret) {
+		error_print();
+		return -1;
+	}
+
+	if (cms_enced_content_info_decrypt_from_der(
+		&enc_algor, key, keylen,
+		content_type, content, content_len,
+		shared_info1, shared_info1_len,
+		shared_info2, shared_info2_len,
+		&enced_content_info, &enced_content_info_len) != 1) {
+		error_print();
+		return -1;
+	}
+
+	if (cms_content_info_header_to_der(*content_type, *content_len,
+		&p, &content_info_header_len) != 1) {
+		error_print();
+		return -1;
+	}
+	sm3_init(&sm3_ctx);
+	sm3_update(&sm3_ctx, content_info_header, content_info_header_len);
+	sm3_update(&sm3_ctx, content, *content_len);
+
+	while (signer_infos_len) {
+		const uint8_t *cert;
+		size_t certlen;
+		const uint8_t *issuer;
+		size_t issuer_len;
+		const uint8_t *serial;
+		size_t serial_len;
+		const uint8_t *authed_attrs;
+		size_t authed_attrs_len;
+		const uint8_t *unauthed_attrs;
+		size_t unauthed_attrs_len;
+
+		if (cms_signer_info_verify_from_der(
+			&sm3_ctx, *certs, *certs_len,
+			&cert, &certlen,
+			&issuer, &issuer_len,
+			&serial, &serial_len,
+			&authed_attrs, &authed_attrs_len,
+			&unauthed_attrs, &unauthed_attrs_len,
+			&signer_infos, &signer_infos_len) != 1) {
+			error_print();
+			return -1;
+		}
+	}
+
+	return 1;
+}
+
+int cms_key_agreement_info_to_der(
+	int version,
+	const SM2_KEY *temp_public_key_r,
+	const uint8_t *user_cert, size_t user_cert_len,
+	const uint8_t *user_id, size_t user_id_len,
+	uint8_t **out, size_t *outlen)
+{
+	size_t len = 0;
+	if (asn1_int_to_der(version, NULL, &len) != 1
+		|| sm2_public_key_info_to_der(temp_public_key_r, NULL, &len) != 1
+		|| x509_cert_to_der(user_cert, user_cert_len, NULL, &len) != 1
+		|| asn1_octet_string_to_der(user_id, user_id_len, NULL, &len) != 1
+		|| asn1_sequence_header_to_der(len, out, outlen) != 1
+		|| asn1_int_to_der(version, out, outlen) != 1
+		|| sm2_public_key_info_to_der(temp_public_key_r, out, outlen) != 1
+		|| x509_cert_to_der(user_cert, user_cert_len, out, outlen) != 1
+		|| asn1_octet_string_to_der(user_id, user_id_len, out, outlen) != 1) {
+		error_print();
+		return -1;
+	}
+	return 1;
+}
+
+int cms_key_agreement_info_from_der(
+	int *version,
+	SM2_KEY *temp_public_key_r,
+	const uint8_t **user_cert, size_t *user_cert_len,
+	const uint8_t **user_id, size_t *user_id_len,
+	const uint8_t **in, size_t *inlen)
+{
+	int ret;
+	const uint8_t *d;
+	size_t dlen;
+
+	if ((ret = asn1_sequence_from_der(&d, &dlen, in, inlen)) != 1) {
+		if (ret < 0) error_print();
+		return ret;
+	}
+	if (asn1_int_from_der(version, &d, &dlen) != 1
+		|| sm2_public_key_info_from_der(temp_public_key_r, &d, &dlen) != 1
+		|| x509_cert_from_der(user_cert, user_cert_len, &d, &dlen) != 1
+		|| asn1_octet_string_from_der(user_id, user_id_len, &d, &dlen) != 1
+		|| asn1_length_is_zero(dlen) != 1) {
+		error_print();
+		return -1;
+	}
+	return 1;
+}
+
+int cms_key_agreement_info_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen)
+{
+	int val;
+	SM2_KEY pub_key;
+	const uint8_t *p;
+	size_t len;
+
+	format_print(fp, fmt, ind, "%s\n", label);
+	ind += 4;
+
+	if (asn1_int_from_der(&val, &d, &dlen) != 1) goto err;
+	format_print(fp, fmt, ind, "version: %d\n", val);
+	if (sm2_public_key_info_from_der(&pub_key, &d, &dlen) != 1) goto err;
+	sm2_public_key_print(fp, fmt, ind, "tempPublicKeyR", &pub_key);
+	if (x509_cert_from_der(&p, &len, &d, &dlen) != 1) goto err;
+	x509_cert_print(fp, fmt, ind, "certificate", p, len);
+	if (asn1_octet_string_from_der(&p, &len, &d, &dlen) != 1) goto err;
+	format_string(fp, fmt, ind, "userID", p, len);
+	if (asn1_length_is_zero(dlen) != 1) goto err;
+	return 1;
+err:
+	error_print();
+	return -1;
+}
+
+int cms_set_data(uint8_t *cms, size_t *cmslen, const uint8_t *d, size_t dlen)
+{
+	int oid = OID_cms_data;
+	size_t len = 0;
+
+	if (asn1_octet_string_to_der(d, dlen, NULL, &len) < 0) {
+		error_print();
+		return -1;
+	}
+	*cmslen = 0;
+	if (!cms) {
+		uint8_t data[1];
+		if (cms_content_info_to_der(oid, data, len, NULL, cmslen) != 1) {
+			error_print();
+			return -1;
+		}
+		return 1;
+	}
+	if (cms_content_info_header_to_der(oid, len, &cms, cmslen) != 1
+		|| asn1_octet_string_to_der(d, dlen, &cms, cmslen) < 0) {
+		error_print();
+		return -1;
+	}
+	return 1;
+}
+
+int cms_encrypt(uint8_t *cms, size_t *cmslen,
+	int enc_algor, const uint8_t *key, size_t keylen, const uint8_t *iv, size_t ivlen,
+	int content_type, const uint8_t *content, size_t content_len,
+	const uint8_t *shared_info1, size_t shared_info1_len,
+	const uint8_t *shared_info2, size_t shared_info2_len)
+{
+	int oid = OID_cms_encrypted_data;
+	size_t len = 0;
+
+	if (cms_encrypted_data_encrypt_to_der(
+		enc_algor, key, keylen, iv, ivlen,
+		content_type, content, content_len,
+		shared_info1, shared_info1_len,
+		shared_info2, shared_info2_len,
+		NULL, &len) != 1) {
+		error_print();
+		return -1;
+	}
+	*cmslen = 0;
+	if (!cms) {
+		uint8_t data[1];
+		if (cms_content_info_to_der(oid, data, len, NULL, cmslen) != 1) {
+			error_print();
+			return -1;
+		}
+		return 1;
+	}
+	if (cms_content_info_header_to_der(oid, len, &cms, cmslen) != 1
+		|| cms_encrypted_data_encrypt_to_der(
+			enc_algor, key, keylen, iv, ivlen,
+			content_type, content, content_len,
+			shared_info1, shared_info1_len,
+			shared_info2, shared_info2_len,
+			&cms, cmslen) != 1) {
+		error_print();
+		return -1;
+	}
+	return 1;
+}
+
+int cms_decrypt(const uint8_t *cms, size_t cmslen,
+	int *enc_algor, const uint8_t *key, size_t keylen,
+	int *content_type, uint8_t *content, size_t *content_len,
+	const uint8_t **shared_info1, size_t *shared_info1_len,
+	const uint8_t **shared_info2, size_t *shared_info2_len)
+{
+	int cms_type;
+	const uint8_t *cms_content;
+	size_t cms_content_len;
+
+	if (cms_content_info_from_der(&cms_type, &cms_content, &cms_content_len, &cms, &cmslen) != 1
+		|| asn1_check(cms_type == OID_cms_encrypted_data) != 1
+		|| asn1_check(cms_content && cms_content_len) != 1
+		|| asn1_length_is_zero(cmslen) != 1) {
+		error_print();
+		return -1;
+	}
+	if (cms_encrypted_data_decrypt_from_der(
+			enc_algor, key, keylen,
+			content_type, content, content_len,
+			shared_info1, shared_info1_len,
+			shared_info2, shared_info2_len,
+			&cms_content, &cms_content_len) != 1
+		|| asn1_length_is_zero(cms_content_len) != 1) {
+		error_print();
+		return -1;
+	}
+	return 1;
+}
+
+int cms_sign(uint8_t *cms, size_t *cmslen,
+	const CMS_CERTS_AND_KEY *signers, size_t signers_cnt,
+	int content_type, const uint8_t *content, size_t content_len,
+	const uint8_t *crls, size_t crls_len)
+{
+	int oid = OID_cms_signed_data;
+	size_t len = 0;
+
+	if (cms_signed_data_sign_to_der(
+		signers, signers_cnt,
+		content_type, content, content_len,
+		crls, crls_len,
+		NULL, &len) != 1) {
+		error_print();
+		return -1;
+	}
+	*cmslen = 0;
+	if (!cms) {
+		uint8_t data[1];
+		if (cms_content_info_to_der(oid, data, len, NULL, cmslen) != 1) {
+			error_print();
+			return -1;
+		}
+		return 1;
+	}
+	if (cms_content_info_header_to_der(oid, len, &cms, cmslen) != 1
+		|| cms_signed_data_sign_to_der(
+			signers, signers_cnt,
+			content_type, content, content_len,
+			crls, crls_len,
+			&cms, cmslen) != 1) {
+		error_print();
+		return -1;
+	}
+	return 1;
+}
+
+int cms_verify(const uint8_t *cms, size_t cmslen,
+	const uint8_t *extra_certs, size_t extra_certs_len,
+	const uint8_t *extra_crls, size_t extra_crls_len,
+	int *content_type, const uint8_t **content, size_t *content_len,
+	const uint8_t **certs, size_t *certs_len,
+	const uint8_t **crls, size_t *crls_len,
+	const uint8_t **signer_infos, size_t *signer_infos_len)
+{
+	int cms_type;
+	const uint8_t *cms_content;
+	size_t cms_content_len;
+
+	if (cms_content_info_from_der(&cms_type, &cms_content, &cms_content_len, &cms, &cmslen) != 1
+		|| asn1_length_is_zero(cmslen) != 1) {
+		error_print();
+		return -1;
+	}
+	if (cms_type != OID_cms_signed_data) {
+		error_print();
+		return -1;
+	}
+	if (cms_content_len <= 0) {
+		error_print();
+		return -1;
+	}
+
+	if (cms_signed_data_verify_from_der(
+			extra_certs, extra_certs_len,
+			extra_crls, extra_crls_len,
+			content_type, content, content_len,
+			certs, certs_len,
+			crls, crls_len,
+			signer_infos, signer_infos_len,
+			&cms_content, &cms_content_len) != 1
+		|| asn1_length_is_zero(cms_content_len) != 1) {
+		error_print();
+		return -1;
+	}
+	return 1;
+}
+
+int cms_envelop(
+	uint8_t *cms, size_t *cmslen,
+	const uint8_t *rcpt_certs, size_t rcpt_certs_len,
+	int enc_algor, const uint8_t *key, size_t keylen, const uint8_t *iv, size_t ivlen,
+	int content_type, const uint8_t *content, size_t content_len,
+	const uint8_t *shared_info1, size_t shared_info1_len,
+	const uint8_t *shared_info2, size_t shared_info2_len)
+{
+	int oid = OID_cms_enveloped_data;
+	size_t len = 0;
+
+	if (cms_enveloped_data_encrypt_to_der(
+		rcpt_certs, rcpt_certs_len,
+		enc_algor, key, keylen, iv, ivlen,
+		content_type, content, content_len,
+		shared_info1, shared_info1_len,
+		shared_info2, shared_info2_len,
+		NULL, &len) != 1) {
+		error_print();
+		return -1;
+	}
+	*cmslen = 0;
+	if (!cms) {
+		uint8_t data[1];
+		if (cms_content_info_to_der(oid, data, len, NULL, cmslen) != 1) {
+			error_print();
+			return -1;
+		}
+		return 1;
+	}
+	if (cms_content_info_header_to_der(oid, len, &cms, cmslen) != 1
+		|| cms_enveloped_data_encrypt_to_der(
+			rcpt_certs, rcpt_certs_len,
+			enc_algor, key, keylen, iv, ivlen,
+			content_type, content, content_len,
+			shared_info1, shared_info1_len,
+			shared_info2, shared_info2_len,
+			&cms, cmslen) != 1) {
+		error_print();
+		return -1;
+	}
+	return 1;
+}
+
+int cms_deenvelop(const uint8_t *cms, size_t cmslen,
+	const SM2_KEY *rcpt_key, const uint8_t *rcpt_cert, size_t rcpt_cert_len,
+	int *content_type, uint8_t *content, size_t *content_len,
+	const uint8_t **rcpt_infos, size_t *rcpt_infos_len,
+	const uint8_t **shared_info1, size_t *shared_info1_len,
+	const uint8_t **shared_info2, size_t *shared_info2_len)
+{
+	int cms_type;
+	const uint8_t *cms_content;
+	size_t cms_content_len;
+	const uint8_t *issuer;
+	size_t issuer_len;
+	const uint8_t *serial;
+	size_t serial_len;
+	SM2_KEY public_key;
+
+	if (cms_content_info_from_der(&cms_type, &cms_content, &cms_content_len, &cms, &cmslen) != 1
+		|| asn1_check(cms_type == OID_cms_enveloped_data) != 1
+		|| asn1_check(cms_content && cms_content_len) != 1
+		|| asn1_length_is_zero(cmslen) != 1) {
+		error_print();
+		return -1;
+	}
+
+	if (x509_cert_get_issuer_and_serial_number(rcpt_cert, rcpt_cert_len,
+			&issuer, &issuer_len, &serial, &serial_len) != 1
+		|| x509_cert_get_subject_public_key(rcpt_cert, rcpt_cert_len,
+			&public_key) != 1) {
+		error_print();
+		return -1;
+	}
+	if (memcmp(&public_key, rcpt_key, sizeof(SM2_POINT)) != 0) {
+		error_print();
+		return -1;
+	}
+
+	if (cms_enveloped_data_decrypt_from_der(
+			rcpt_key, issuer, issuer_len, serial, serial_len,
+			content_type, content, content_len,
+			rcpt_infos, rcpt_infos_len,
+			shared_info1, shared_info1_len,
+			shared_info2, shared_info2_len,
+			&cms_content, &cms_content_len) != 1
+		|| asn1_length_is_zero(cms_content_len) != 1) {
+		error_print();
+		return -1;
+	}
+	return 1;
+}
+
+int cms_sign_and_envelop(uint8_t *cms, size_t *cmslen,
+	const CMS_CERTS_AND_KEY *signers, size_t signers_cnt,
+	const uint8_t *rcpt_certs, size_t rcpt_certs_len,
+	int enc_algor, const uint8_t *key, size_t keylen, const uint8_t *iv, size_t ivlen,
+	int content_type, const uint8_t *content, size_t content_len,
+	const uint8_t *crls, size_t crls_len,
+	const uint8_t *shared_info1, size_t shared_info1_len,
+	const uint8_t *shared_info2, size_t shared_info2_len)
+{
+	int oid = OID_cms_signed_and_enveloped_data;
+	size_t len = 0;
+
+	if (cms_signed_and_enveloped_data_encipher_to_der(
+		signers, signers_cnt,
+		rcpt_certs, rcpt_certs_len,
+		enc_algor, key, keylen, iv, ivlen,
+		content_type, content, content_len,
+		crls, crls_len,
+		shared_info1, shared_info1_len,
+		shared_info2, shared_info2_len,
+		NULL, &len) != 1) {
+		error_print();
+		return -1;
+	}
+	*cmslen = 0;
+	if (!cms) {
+		uint8_t data[1];
+		if (cms_content_info_to_der(oid, data, len, NULL, cmslen) != 1) {
+			error_print();
+			return -1;
+		}
+		return 1;
+	}
+	if (cms_content_info_header_to_der(oid, len, &cms, cmslen) != 1
+		|| cms_signed_and_enveloped_data_encipher_to_der(
+			signers, signers_cnt,
+			rcpt_certs, rcpt_certs_len,
+			enc_algor, key, keylen, iv, ivlen,
+			content_type, content, content_len,
+			crls, crls_len,
+			shared_info1, shared_info1_len,
+			shared_info2, shared_info2_len,
+			&cms, cmslen) != 1) {
+		error_print();
+		return -1;
+	}
+	return 1;
+}
+
+int cms_deenvelop_and_verify(const uint8_t *cms, size_t cmslen,
+	const SM2_KEY *rcpt_key, const uint8_t *rcpt_cert, size_t rcpt_cert_len,
+	const uint8_t *extra_certs, size_t extra_certs_len,
+	const uint8_t *extra_crls, size_t extra_crls_len,
+	int *content_type, uint8_t *content, size_t *content_len,
+	const uint8_t **rcpt_infos, size_t *rcpt_infos_len,
+	const uint8_t **signer_infos, size_t *signer_infos_len,
+	const uint8_t **certs, size_t *certs_len,
+	const uint8_t **crls, size_t *crls_len,
+	const uint8_t **shared_info1, size_t *shared_info1_len,
+	const uint8_t **shared_info2, size_t *shared_info2_len)
+{
+	const uint8_t *rcpt_issuer;
+	size_t rcpt_issuer_len;
+	const uint8_t *rcpt_serial;
+	size_t rcpt_serial_len;
+	SM2_KEY public_key;
+	int cms_type;
+	const uint8_t *cms_content;
+	size_t cms_content_len;
+
+	if (cms_content_info_from_der(&cms_type, &cms_content, &cms_content_len, &cms, &cmslen) != 1
+		|| asn1_check(cms_type == OID_cms_signed_and_enveloped_data) != 1
+		|| asn1_check(cms_content && cms_content_len) != 1
+		|| asn1_length_is_zero(cmslen) != 1) {
+		error_print();
+		return -1;
+	}
+
+	if (x509_cert_get_issuer_and_serial_number(rcpt_cert, rcpt_cert_len,
+			&rcpt_issuer, &rcpt_issuer_len,
+			&rcpt_serial, &rcpt_serial_len) != 1
+		|| x509_cert_get_subject_public_key(rcpt_cert, rcpt_cert_len,
+			&public_key) != 1) {
+		error_print();
+		return -1;
+	}
+	if (memcmp(&public_key, rcpt_key, sizeof(SM2_POINT)) != 0) {
+		error_print();
+		return -1;
+	}
+
+	if (cms_signed_and_enveloped_data_decipher_from_der(
+			rcpt_key,
+			rcpt_issuer, rcpt_issuer_len,
+			rcpt_serial, rcpt_serial_len,
+			content_type, content, content_len,
+			rcpt_infos, rcpt_infos_len,
+			shared_info1, shared_info1_len,
+			shared_info2, shared_info2_len,
+			certs, certs_len,
+			crls, crls_len,
+			signer_infos, signer_infos_len,
+			extra_certs, extra_certs_len,
+			extra_crls, extra_crls_len,
+			&cms_content, &cms_content_len) != 1
+		|| asn1_length_is_zero(cms_content_len) != 1) {
+		error_print();
+		return -1;
+	}
+	return 1;
+}
+
+int cms_set_key_agreement_info(
+	uint8_t *cms, size_t *cmslen,
+	const SM2_KEY *temp_public_key_r,
+	const uint8_t *user_cert, size_t user_cert_len,
+	const uint8_t *user_id, size_t user_id_len)
+{
+	int oid = OID_cms_key_agreement_info;
+	size_t len = 0;
+
+	if (cms_key_agreement_info_to_der(CMS_version_v1, temp_public_key_r,
+		user_cert, user_cert_len, user_id, user_id_len, NULL, &len) != 1) {
+		error_print();
+		return -1;
+	}
+	*cmslen = 0;
+	if (!cms) {
+		uint8_t data[1];
+		if (cms_content_info_to_der(oid, data, len, NULL, cmslen) != 1) {
+			error_print();
+			return -1;
+		}
+		return 1;
+	}
+	if (cms_content_info_header_to_der(oid, len, &cms, cmslen) != 1
+		|| cms_key_agreement_info_to_der(CMS_version_v1, temp_public_key_r,
+			user_cert, user_cert_len, user_id, user_id_len, &cms, cmslen) != 1) {
+		error_print();
+		return -1;
+	}
+	return 1;
+}
+
+int cms_to_pem(const uint8_t *cms, size_t cms_len, FILE *fp)
+{
+	if (pem_write(fp, PEM_CMS, cms, cms_len) != 1) {
+		error_print();
+		return -1;
+	}
+	return 1;
+}
+
+int cms_from_pem(uint8_t *cms, size_t *cms_len, size_t maxlen, FILE *fp)
+{
+	int ret;
+	if ((ret = pem_read(fp, PEM_CMS, cms, cms_len, maxlen)) != 1) {
+		if (ret < 0) error_print();
+		return ret;
+	}
+
+	return 1;
+}
+
+int cms_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *a, size_t alen)
+{
+	const uint8_t *d;
+	size_t dlen;
+
+
+	if (asn1_sequence_from_der(&d, &dlen, &a, &alen) != 1) goto err;
+
+
+	cms_content_info_print(fp, fmt, ind, label, d, dlen);
+	//if (asn1_length_is_zero(alen) != 1) goto err;			
+	return 1;
+err:
+	error_print();
+	return -1;
+}
+
+

+ 504 - 0
components/gmssl/src/digest.c

@@ -0,0 +1,504 @@
+/*
+ *  Copyright 2014-2022 The GmSSL Project. All Rights Reserved.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the License); you may
+ *  not use this file except in compliance with the License.
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ */
+
+
+
+#include <stdio.h>
+#include <gmssl/sm3.h>
+#include <gmssl/oid.h>
+#include <gmssl/digest.h>
+#include <gmssl/error.h>
+
+
+typedef struct {
+	int oid;
+	char *short_name;
+	char *display_name;
+} DIGEST_TABLE;
+
+DIGEST_TABLE digest_table[] = {
+	{ OID_sm3, "sm3", "SM3" },
+#ifdef ENABLE_BROKEN_CRYPTO
+	{ OID_md5, "md5", "MD5" },
+	{ OID_sha1, "sha1", "SHA-1" },
+#endif
+	{ OID_sha224, "sha224", "SHA-224" },
+	{ OID_sha256, "sha256", "SHA-256" },
+	{ OID_sha384, "sha384", "SHA-384" },
+	{ OID_sha512, "sha512", "SHA-512" },
+};
+
+const char *digest_name(const DIGEST *digest)
+{
+	int i;
+	for (i = 0; i < sizeof(digest_table)/sizeof(digest_table[0]); i++) {
+		if (digest->oid == digest_table[i].oid) {
+			return digest_table[i].short_name;
+		}
+	}
+	return NULL;
+}
+
+int digest_init(DIGEST_CTX *ctx, const DIGEST *algor)
+{
+	memset(ctx, 0, sizeof(DIGEST_CTX));
+	if (algor == NULL) {
+		error_print();
+		return -1;
+	}
+	ctx->digest = algor;
+	ctx->digest->init(ctx);
+	return 1;
+}
+
+int digest_update(DIGEST_CTX *ctx, const uint8_t *data, size_t datalen)
+{
+	if (data == NULL || datalen == 0) {
+		return 0;
+	}
+	ctx->digest->update(ctx, data, datalen);
+	return 1;
+}
+
+int digest_finish(DIGEST_CTX *ctx, uint8_t *dgst, size_t *dgstlen)
+{
+	if (dgst == NULL || dgstlen == NULL) {
+		error_print();
+		return -1;
+	}
+	ctx->digest->finish(ctx, dgst);
+	*dgstlen = ctx->digest->digest_size;
+	return 1;
+}
+
+int digest(const DIGEST *digest, const uint8_t *data, size_t datalen,
+	uint8_t *dgst, size_t *dgstlen)
+{
+	DIGEST_CTX ctx;
+	if (digest_init(&ctx, digest) != 1
+		|| digest_update(&ctx, data, datalen) < 0
+		|| digest_finish(&ctx, dgst, dgstlen) != 1) {
+		error_print();
+		return -1;
+	}
+	memset(&ctx, 0, sizeof(DIGEST_CTX));
+	return 1;
+}
+
+const DIGEST *digest_from_name(const char *name)
+{
+	if (!strcmp(name, "sm3") || !strcmp(name, "SM3")) {
+		return DIGEST_sm3();
+#ifdef ENABLE_BROKEN_CRYPTO
+	} else if (!strcmp(name, "md5") || !strcmp(name, "MD5")) {
+		return DIGEST_md5();
+	} else if (!strcmp(name, "sha1") || !strcmp(name, "SHA1")) {
+		return DIGEST_sha1();
+#endif
+	} else if (!strcmp(name, "sha224") || !strcmp(name, "SHA224")) {
+		return DIGEST_sha224();
+	} else if (!strcmp(name, "sha256") || !strcmp(name, "SHA256")) {
+		return DIGEST_sha256();
+	} else if (!strcmp(name, "sha384") || !strcmp(name, "SHA384")) {
+		return DIGEST_sha384();
+	} else if (!strcmp(name, "sha512") || !strcmp(name, "SHA512")) {
+		return DIGEST_sha512();
+	} else if (!strcmp(name, "sha512-224") || !strcmp(name, "SHA512-224")) {
+		return DIGEST_sha512_224();
+	} else if (!strcmp(name, "sha512-256") || !strcmp(name, "SHA512-256")) {
+		return DIGEST_sha512_256();
+	}
+	return NULL;
+}
+
+static int sm3_digest_init(DIGEST_CTX *ctx)
+{
+	if (!ctx) {
+		error_print();
+		return -1;
+	}
+	sm3_init(&ctx->u.sm3_ctx);
+	return 1;
+}
+
+static int sm3_digest_update(DIGEST_CTX *ctx, const uint8_t *in, size_t inlen)
+{
+	if (!ctx || (!in && inlen != 0)) {
+		error_print();
+		return -1;
+	}
+	sm3_update(&ctx->u.sm3_ctx, in, inlen);
+	return 1;
+}
+
+static int sm3_digest_finish(DIGEST_CTX *ctx, uint8_t *dgst)
+{
+	if (!ctx || !dgst) {
+		error_print();
+		return -1;
+	}
+	sm3_finish(&ctx->u.sm3_ctx, dgst);
+	return 1;
+}
+
+static const DIGEST sm3_digest_object = {
+	OID_sm3,
+	SM3_DIGEST_SIZE,
+	SM3_BLOCK_SIZE,
+	sizeof(SM3_CTX),
+	sm3_digest_init,
+	sm3_digest_update,
+	sm3_digest_finish,
+};
+
+const DIGEST *DIGEST_sm3(void)
+{
+        return &sm3_digest_object;
+}
+
+#ifdef ENABLE_BROKEN_CRYPTO
+
+#include <gmssl/md5.h>
+
+static int md5_digest_init(DIGEST_CTX *ctx)
+{
+	if (!ctx) {
+		error_print();
+		return -1;
+	}
+	md5_init(&ctx->u.md5_ctx);
+	return 1;
+}
+
+static int md5_digest_update(DIGEST_CTX *ctx, const uint8_t *in, size_t inlen)
+{
+	if (!ctx || (!in && inlen != 0)) {
+		error_print();
+		return -1;
+	}
+	md5_update(&ctx->u.md5_ctx, in, inlen);
+	return 1;
+}
+
+static int md5_digest_finish(DIGEST_CTX *ctx, uint8_t *dgst)
+{
+	if (!ctx || !dgst) {
+		error_print();
+		return -1;
+	}
+	md5_finish(&ctx->u.md5_ctx, dgst);
+	return 1;
+}
+
+static const DIGEST md5_digest_object = {
+	OID_md5,
+	MD5_DIGEST_SIZE,
+	MD5_BLOCK_SIZE,
+	sizeof(MD5_CTX),
+	md5_digest_init,
+	md5_digest_update,
+	md5_digest_finish,
+};
+
+const DIGEST *DIGEST_md5(void)
+{
+        return &md5_digest_object;
+}
+
+
+#include <gmssl/sha1.h>
+
+static int sha1_digest_init(DIGEST_CTX *ctx)
+{
+	if (!ctx) {
+		error_print();
+		return -1;
+	}
+	sha1_init(&ctx->u.sha1_ctx);
+	return 1;
+}
+
+static int sha1_digest_update(DIGEST_CTX *ctx, const uint8_t *in, size_t inlen)
+{
+	if (!ctx || (!in && inlen != 0)) {
+		error_print();
+		return -1;
+	}
+	sha1_update(&ctx->u.sha1_ctx, in, inlen);
+	return 1;
+}
+
+static int sha1_digest_finish(DIGEST_CTX *ctx, uint8_t *dgst)
+{
+	if (!ctx || !dgst) {
+		error_print();
+		return -1;
+	}
+	sha1_finish(&ctx->u.sha1_ctx, dgst);
+	return 1;
+}
+
+static const DIGEST sha1_digest_object = {
+	OID_sha1,
+	SHA1_DIGEST_SIZE,
+	SHA1_BLOCK_SIZE,
+	sizeof(SHA1_CTX),
+	sha1_digest_init,
+	sha1_digest_update,
+	sha1_digest_finish,
+};
+
+const DIGEST *DIGEST_sha1(void)
+{
+        return &sha1_digest_object;
+}
+#endif
+
+#include <gmssl/sha2.h>
+
+static int sha224_digest_init(DIGEST_CTX *ctx)
+{
+	if (!ctx) {
+		error_print();
+		return -1;
+	}
+	sha224_init(&ctx->u.sha224_ctx);
+	return 1;
+}
+
+static int sha224_digest_update(DIGEST_CTX *ctx, const uint8_t *in, size_t inlen)
+{
+	if (!ctx || (!in && inlen != 0)) {
+		error_print();
+		return -1;
+	}
+	sha224_update(&ctx->u.sha224_ctx, in, inlen);
+	return 1;
+}
+
+static int sha224_digest_finish(DIGEST_CTX *ctx, uint8_t *dgst)
+{
+	if (!ctx || !dgst) {
+		error_print();
+		return -1;
+	}
+	sha224_finish(&ctx->u.sha224_ctx, dgst);
+	return 1;
+}
+
+static const DIGEST sha224_digest_object = {
+	OID_sha224,
+	SHA224_DIGEST_SIZE,
+	SHA224_BLOCK_SIZE,
+	sizeof(SHA224_CTX),
+	sha224_digest_init,
+	sha224_digest_update,
+	sha224_digest_finish,
+};
+
+const DIGEST *DIGEST_sha224(void)
+{
+        return &sha224_digest_object;
+}
+
+static int sha256_digest_init(DIGEST_CTX *ctx)
+{
+	if (!ctx) {
+		error_print();
+		return -1;
+	}
+	sha256_init(&ctx->u.sha256_ctx);
+	return 1;
+}
+
+static int sha256_digest_update(DIGEST_CTX *ctx, const uint8_t *in, size_t inlen)
+{
+	if (!ctx || (!in && inlen != 0)) {
+		error_print();
+		return -1;
+	}
+	sha256_update(&ctx->u.sha256_ctx, in, inlen);
+	return 1;
+}
+
+static int sha256_digest_finish(DIGEST_CTX *ctx, uint8_t *dgst)
+{
+	if (!ctx || !dgst) {
+		error_print();
+		return -1;
+	}
+	sha256_finish(&ctx->u.sha256_ctx, dgst);
+	return 1;
+}
+
+static const DIGEST sha256_digest_object = {
+	OID_sha256,
+	SHA256_DIGEST_SIZE,
+	SHA256_BLOCK_SIZE,
+	sizeof(SHA256_CTX),
+	sha256_digest_init,
+	sha256_digest_update,
+	sha256_digest_finish,
+};
+
+const DIGEST *DIGEST_sha256(void)
+{
+        return &sha256_digest_object;
+}
+
+
+static int sha384_digest_init(DIGEST_CTX *ctx)
+{
+	if (!ctx) {
+		error_print();
+		return -1;
+	}
+	sha384_init(&ctx->u.sha384_ctx);
+	return 1;
+}
+
+static int sha384_digest_update(DIGEST_CTX *ctx, const uint8_t *in, size_t inlen)
+{
+	if (!ctx || (!in && inlen != 0)) {
+		error_print();
+		return -1;
+	}
+	sha384_update(&ctx->u.sha384_ctx, in, inlen);
+	return 1;
+}
+
+static int sha384_digest_finish(DIGEST_CTX *ctx, uint8_t *dgst)
+{
+	if (!ctx || !dgst) {
+		error_print();
+		return -1;
+	}
+	sha384_finish(&ctx->u.sha384_ctx, dgst);
+	return 1;
+}
+
+static const DIGEST sha384_digest_object = {
+	OID_sha384,
+	SHA384_DIGEST_SIZE,
+	SHA384_BLOCK_SIZE,
+	sizeof(SHA384_CTX),
+	sha384_digest_init,
+	sha384_digest_update,
+	sha384_digest_finish,
+};
+
+const DIGEST *DIGEST_sha384(void)
+{
+        return &sha384_digest_object;
+}
+
+
+static int sha512_digest_init(DIGEST_CTX *ctx)
+{
+	if (!ctx) {
+		error_print();
+		return -1;
+	}
+	sha512_init(&ctx->u.sha512_ctx);
+	return 1;
+}
+
+static int sha512_digest_update(DIGEST_CTX *ctx, const uint8_t *in, size_t inlen)
+{
+	if (!ctx || (!in && inlen != 0)) {
+		error_print();
+		return -1;
+	}
+	sha512_update(&ctx->u.sha512_ctx, in, inlen);
+	return 1;
+}
+
+static int sha512_digest_finish(DIGEST_CTX *ctx, uint8_t *dgst)
+{
+	if (!ctx || !dgst) {
+		error_print();
+		return -1;
+	}
+	sha512_finish(&ctx->u.sha512_ctx, dgst);
+	return 1;
+}
+
+static const DIGEST sha512_digest_object = {
+	OID_sha512,
+	SHA512_DIGEST_SIZE,
+	SHA512_BLOCK_SIZE,
+	sizeof(SHA512_CTX),
+	sha512_digest_init,
+	sha512_digest_update,
+	sha512_digest_finish,
+};
+
+const DIGEST *DIGEST_sha512(void)
+{
+        return &sha512_digest_object;
+}
+
+
+static int sha512_224_digest_finish(DIGEST_CTX *ctx, uint8_t *dgst)
+{
+	uint8_t buf[SHA512_DIGEST_SIZE];
+	if (!ctx || !dgst) {
+		error_print();
+		return -1;
+	}
+	sha512_finish(&ctx->u.sha512_ctx, buf);
+	memcpy(dgst, buf, SHA224_DIGEST_SIZE);
+	memset(buf, 0, sizeof(buf));
+	return 1;
+}
+
+static const DIGEST sha512_224_digest_object = {
+	OID_sha512_224,
+	SHA224_DIGEST_SIZE,
+	SHA512_BLOCK_SIZE,
+	sizeof(SHA512_CTX),
+	sha512_digest_init,
+	sha512_digest_update,
+	sha512_224_digest_finish,
+};
+
+const DIGEST *DIGEST_sha512_224(void)
+{
+        return &sha512_224_digest_object;
+}
+
+
+static int sha512_256_digest_finish(DIGEST_CTX *ctx, uint8_t *dgst)
+{
+	uint8_t buf[SHA512_DIGEST_SIZE];
+	if (!ctx || !dgst) {
+		error_print();
+		return -1;
+	}
+	sha512_finish(&ctx->u.sha512_ctx, buf);
+	memcpy(dgst, buf, SHA256_DIGEST_SIZE);
+	memset(buf, 0, sizeof(buf));
+	return 1;
+}
+
+
+static const DIGEST sha512_256_digest_object = {
+	OID_sha512_256,
+	SHA256_DIGEST_SIZE,
+	SHA512_BLOCK_SIZE,
+	sizeof(SHA512_CTX),
+	sha512_digest_init,
+	sha512_digest_update,
+	sha512_256_digest_finish,
+};
+
+const DIGEST *DIGEST_sha512_256(void)
+{
+        return &sha512_256_digest_object;
+}

+ 140 - 0
components/gmssl/src/ec.c

@@ -0,0 +1,140 @@
+/*
+ *  Copyright 2014-2022 The GmSSL Project. All Rights Reserved.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the License); you may
+ *  not use this file except in compliance with the License.
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ */
+
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <gmssl/ec.h>
+#include <gmssl/error.h>
+
+
+#define oid_sm_scheme 1,2,156,10197,1
+static uint32_t oid_sm2[] = { oid_sm_scheme,301 };
+
+#define oid_x9_62_curves oid_x9_62,3
+#define oid_x9_62_prime_curves oid_x9_62_curves,1
+static uint32_t oid_prime192v1[] = { oid_x9_62_prime_curves,1 };
+static uint32_t oid_prime256v1[] = { oid_x9_62_prime_curves,7 }; // NIST P-256
+
+#define oid_secg_curve 1,3,132,0
+static uint32_t oid_secp256k1[] = { oid_secg_curve,10 };
+static uint32_t oid_secp384r1[] = { oid_secg_curve,34 }; // NIST P-384
+static uint32_t oid_secp521r1[] = { oid_secg_curve,35 }; // NIST P-521
+
+
+static const ASN1_OID_INFO ec_named_curves[] = {
+	{ OID_sm2, "sm2p256v1", oid_sm2, sizeof(oid_sm2)/sizeof(int), 0, "SM2" },
+	{ OID_prime192v1, "prime192v1", oid_prime192v1, sizeof(oid_prime192v1)/sizeof(int), 0, },
+	{ OID_prime256v1, "prime256v1", oid_prime256v1, sizeof(oid_prime256v1)/sizeof(int), 0, "NIST P-256" },
+	{ OID_secp256k1, "secp256k1", oid_secp256k1, sizeof(oid_secp256k1)/sizeof(int) },
+	{ OID_secp384r1, "secp384r1", oid_secp384r1, sizeof(oid_secp384r1)/sizeof(int), 0, "NIST P-384" },
+	{ OID_secp521r1, "secp521r1", oid_secp521r1, sizeof(oid_secp521r1)/sizeof(int), 0, "NIST P-521" }
+};
+
+static const int ec_named_curves_count =
+	sizeof(ec_named_curves)/sizeof(ec_named_curves[0]);
+
+const char *ec_named_curve_name(int oid)
+{
+	const ASN1_OID_INFO *info;
+	if (!(info = asn1_oid_info_from_oid(ec_named_curves, ec_named_curves_count, oid))) {
+		error_print();
+		return NULL;
+	}
+	return info->name;
+}
+
+int ec_named_curve_from_name(const char *name)
+{
+	const ASN1_OID_INFO *info;
+	if (!(info = asn1_oid_info_from_name(ec_named_curves, ec_named_curves_count, name))) {
+		error_print();
+		return OID_undef;
+	}
+	return info->oid;
+}
+
+int ec_named_curve_to_der(int oid, uint8_t **out, size_t *outlen)
+{
+	const ASN1_OID_INFO *info;
+	if (!(info = asn1_oid_info_from_oid(ec_named_curves, ec_named_curves_count, oid))) {
+		error_print();
+		return -1;
+	}
+	if (asn1_object_identifier_to_der(info->nodes, info->nodes_cnt, out, outlen) != 1) {
+		error_print();
+		return -1;
+	}
+	return 1;
+}
+
+int ec_named_curve_from_der(int *oid, const uint8_t **in, size_t *inlen)
+{
+	int ret;
+	const ASN1_OID_INFO *info;
+	if ((ret = asn1_oid_info_from_der(&info, ec_named_curves, ec_named_curves_count, in, inlen)) != 1) {
+		if (ret < 0) error_print();
+		else *oid = -1;
+		return ret;
+	}
+	*oid = info->oid;
+	return 1;
+}
+
+int ec_point_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen)
+{
+	const uint8_t *p;
+	size_t len;
+
+	if (asn1_octet_string_from_der(&p, &len, &d, &dlen) != 1) goto err;
+	format_bytes(fp, fmt, ind, label, p, len);
+	if (asn1_length_is_zero(dlen) != 1) goto err;
+	return 1;
+err:
+	error_print();
+	return -1;
+}
+
+int ec_private_key_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen)
+{
+	int ret;
+	const uint8_t *a;
+	size_t alen;
+	const uint8_t *p;
+	size_t len;
+	int val;
+
+	format_print(fp, fmt, ind, "%s\n", label);
+	ind += 4;
+
+	if (asn1_int_from_der(&val, &d, &dlen) != 1) goto err;
+	format_print(fp, fmt, ind, "version: %d\n", val);
+	if (asn1_octet_string_from_der(&p, &len, &d, &dlen) != 1) goto err;
+	format_bytes(fp, fmt, ind, "privateKey", p, len);
+	if ((ret = asn1_explicit_from_der(0, &a, &alen, &d, &dlen)) < 0) goto err;
+	else if (ret) {
+		if (ec_named_curve_from_der(&val, &a, &alen) != 1) goto err;
+		format_print(fp, fmt, ind, "parameters: %s\n", ec_named_curve_name(val));
+		if (asn1_length_is_zero(alen) != 1) goto err;
+	}
+	format_print(fp, fmt, ind, "publicKey\n");
+	ind += 4;
+	if ((ret = asn1_explicit_from_der(1, &a, &alen, &d, &dlen)) < 0) goto err;
+	else if (ret) {
+		if (asn1_bit_octets_from_der(&p, &len, &a, &alen) != 1) goto err;
+		format_bytes(fp, fmt, ind, "ECPoint", p, len);
+		if (asn1_length_is_zero(alen) != 1) goto err;
+	}
+	if (asn1_length_is_zero(dlen) != 1) goto err;
+	return 1;
+err:
+	error_print();
+	return -1;
+}

+ 206 - 0
components/gmssl/src/gcm.c

@@ -0,0 +1,206 @@
+/*
+ *  Copyright 2014-2022 The GmSSL Project. All Rights Reserved.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the License); you may
+ *  not use this file except in compliance with the License.
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ */
+
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <gmssl/mem.h>
+#include <gmssl/gf128.h>
+#include <gmssl/gcm.h>
+#include <gmssl/oid.h>
+#include <gmssl/error.h>
+#include <gmssl/aes.h>
+#include <gmssl/endian.h>
+
+
+/*
+ * GHASH(H, A, C) = X_{m + n + 1}
+ *   A additional authenticated data, A = A_1, ..., A_{m-1}, A_{m^*}, nbits(A_{m^*}) = v
+ *   C ciphertext, C = C_1, ..., C_{n-1}, C_{n^*}, nbits(C_{n^*}) = u
+ *   H = E_K(0^128)
+ *
+ * X_i = 0                                         for i = 0
+ *     = (X_{i-1}   xor  A_i                ) * H  for i = 1, ..., m-1
+ *     = (X_{m-1}   xor (A_m^* || 0^{128-v})) * H  for i = m
+ *     = (X_{i-1}   xor  C_i                ) * H  for i = m+1, ..., m + n − 1
+ *     = (X_{m+n-1} xor (C_m^* || 0^{128-u})) * H  for i = m + n
+ *     = (X_{m+n}   xor (nbits(A)||nbits(C))) * H  for i = m + n + 1
+ */
+void ghash(const uint8_t h[16], const uint8_t *aad, size_t aadlen, const uint8_t *c, size_t clen, uint8_t out[16])
+{
+	gf128_t H = gf128_from_bytes(h);
+	gf128_t X = gf128_zero();
+	gf128_t L;
+
+	PUTU64(out, (uint64_t)aadlen << 3);
+	PUTU64(out + 8, (uint64_t)clen << 3);
+	L = gf128_from_bytes(out);
+
+	while (aadlen) {
+		gf128_t A;
+		if (aadlen >= 16) {
+			A = gf128_from_bytes(aad);
+			aad += 16;
+			aadlen -= 16;
+		} else {
+			memset(out, 0, 16);
+			memcpy(out, aad, aadlen);
+			A = gf128_from_bytes(out);
+			aadlen = 0;
+		}
+		X = gf128_add(X, A);
+		X = gf128_mul(X, H);
+	}
+
+	while (clen) {
+		gf128_t C;
+		if (clen >= 16) {
+			C = gf128_from_bytes(c);
+			c += 16;
+			clen -= 16;
+		} else {
+			memset(out, 0, 16);
+			memcpy(out, c, clen);
+			C = gf128_from_bytes(out);
+			clen = 0;
+		}
+		X = gf128_add(X, C);
+		X = gf128_mul(X, H);
+	}
+
+	X = gf128_add(X, L);
+	H = gf128_mul(X, H);
+	gf128_to_bytes(H, out);
+}
+
+
+void ghash_init(GHASH_CTX *ctx, const uint8_t h[16], const uint8_t *aad, size_t aadlen)
+{
+	gf128_t A;
+
+	memset(ctx, 0, sizeof(*ctx));
+	ctx->H = gf128_from_bytes(h);
+	ctx->X = gf128_zero();
+	ctx->aadlen = aadlen;
+	ctx->clen = 0;
+
+	while (aadlen) {
+		if (aadlen >= 16) {
+			A = gf128_from_bytes(aad);
+			aad += 16;
+			aadlen -= 16;
+		} else {
+			memset(ctx->block, 0, 16);
+			memcpy(ctx->block, aad, aadlen);
+			A = gf128_from_bytes(ctx->block);
+			aadlen = 0;
+		}
+		ctx->X = gf128_add(ctx->X, A);
+		ctx->X = gf128_mul(ctx->X, ctx->H);
+	}
+}
+
+void ghash_update(GHASH_CTX *ctx, const uint8_t *c, size_t clen)
+{
+	gf128_t C;
+
+	assert(ctx->num < 16);
+
+	ctx->clen += clen;
+
+	if (ctx->num) {
+		size_t left = 16 - ctx->num;
+		if (clen < left) {
+			memcpy(ctx->block + ctx->num, c, clen);
+			ctx->num += clen;
+			return;
+		} else {
+			memcpy(ctx->block + ctx->num, c, left);
+			C = gf128_from_bytes(ctx->block);
+			ctx->X = gf128_add(ctx->X, C);
+			ctx->X = gf128_mul(ctx->X, ctx->H);
+			c += left;
+			clen -= left;
+		}
+	}
+
+	while (clen >= 16) {
+		C = gf128_from_bytes(c);
+		ctx->X = gf128_add(ctx->X, C);
+		ctx->X = gf128_mul(ctx->X, ctx->H);
+		c += 16;
+		clen -= 16;
+	}
+
+	ctx->num = clen;
+	if (clen) {
+		memcpy(ctx->block, c, clen);
+	}
+}
+
+void ghash_finish(GHASH_CTX *ctx, uint8_t out[16])
+{
+	gf128_t C;
+	gf128_t L;
+
+	if (ctx->num) {
+		memset(ctx->block + ctx->num, 0, 16 - ctx->num);
+		C = gf128_from_bytes(ctx->block);
+		ctx->X = gf128_add(ctx->X, C);
+		ctx->X = gf128_mul(ctx->X, ctx->H);
+	}
+
+	PUTU64(ctx->block, (uint64_t)ctx->aadlen << 3);
+	PUTU64(ctx->block + 8, (uint64_t)ctx->clen << 3);
+	L = gf128_from_bytes(ctx->block);
+
+	ctx->X = gf128_add(ctx->X, L);
+	ctx->H = gf128_mul(ctx->X, ctx->H);
+	gf128_to_bytes(ctx->H, out);
+
+	gmssl_secure_clear(ctx, sizeof(*ctx));
+}
+
+int gcm_encrypt(const BLOCK_CIPHER_KEY *key, const uint8_t *iv, size_t ivlen,
+	const uint8_t *aad, size_t aadlen, const uint8_t *in, size_t inlen,
+	uint8_t *out, size_t taglen, uint8_t *tag)
+{
+	if (key->cipher == BLOCK_CIPHER_sm4()) {
+		if (sm4_gcm_encrypt(&(key->u.sm4_key), iv, ivlen, aad, aadlen,  in, inlen, out, taglen, tag) != 1) {
+			error_print();
+			return -1;
+		}
+	} else if (key->cipher == BLOCK_CIPHER_aes128()) {
+		if (aes_gcm_encrypt(&(key->u.aes_key), iv, ivlen, aad, aadlen,  in, inlen, out, taglen, tag) != 1) {
+			error_print();
+			return -1;
+		}
+	}
+	return 1;
+}
+
+int gcm_decrypt(const BLOCK_CIPHER_KEY *key, const uint8_t *iv, size_t ivlen,
+	const uint8_t *aad, size_t aadlen, const uint8_t *in, size_t inlen,
+	const uint8_t *tag, size_t taglen, uint8_t *out)
+{
+	if (key->cipher == BLOCK_CIPHER_sm4()) {
+		if (sm4_gcm_decrypt(&(key->u.sm4_key), iv, ivlen, aad, aadlen,  in, inlen, tag, taglen, out) != 1) {
+			error_print();
+			return -1;
+		}
+	} else if (key->cipher == BLOCK_CIPHER_aes128()) {
+		if (aes_gcm_decrypt(&(key->u.aes_key), iv, ivlen, aad, aadlen,  in, inlen, tag, taglen, out) != 1) {
+			error_print();
+			return -1;
+		}
+	}
+	return 1;
+}

+ 177 - 0
components/gmssl/src/gf128.c

@@ -0,0 +1,177 @@
+/*
+ *  Copyright 2014-2022 The GmSSL Project. All Rights Reserved.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the License); you may
+ *  not use this file except in compliance with the License.
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ */
+
+
+/* GF(2^128) defined by f(x) = x^128 + x^7 + x^2 + x + 1
+ * A + B mod f(x) = a xor b
+ * A * 2 mod f(x)
+ */
+
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <gmssl/hex.h>
+#include <gmssl/gf128.h>
+#include <gmssl/endian.h>
+#include <gmssl/error.h>
+
+
+gf128_t gf128_zero(void)
+{
+	uint8_t zero[16] = {0};
+	return gf128_from_bytes(zero);
+}
+
+gf128_t gf128_from_hex(const char *s)
+{
+	uint8_t bin[16];
+	size_t len;
+	hex_to_bytes(s, strlen(s), bin, &len);
+	return gf128_from_bytes(bin);
+}
+
+int gf128_equ_hex(gf128_t a, const char *s)
+{
+	uint8_t bin1[16];
+	uint8_t bin2[16];
+	size_t len;
+	hex_to_bytes(s, strlen(s), bin1, &len);
+	gf128_to_bytes(a, bin2);
+	return memcmp(bin1, bin2, sizeof(bin1)) == 0;
+}
+
+void gf128_print_bits(gf128_t a)
+{
+	int i;
+	for (i = 0; i < 64; i++) {
+		printf("%d", (int)(a.hi % 2));
+		a.hi >>= 1;
+	}
+	for (i = 0; i < 64; i++) {
+		printf("%d", (int)(a.lo % 2));
+		a.lo >>= 1;
+	}
+	printf("\n");
+}
+
+int gf128_print(FILE *fp, int fmt, int ind, const char *label, gf128_t a)
+{
+	uint8_t be[16];
+	int i;
+
+	printf("%s: ", label);
+	gf128_to_bytes(a, be);
+	for (i = 0; i < 16; i++) {
+		printf("%02x", be[i]);
+	}
+	printf("\n");
+	return 1;
+}
+
+static uint64_t reverse_bits(uint64_t a)
+{
+	uint64_t r = 0;
+	int i;
+
+	for (i = 0; i < 63; i++) {
+		r |= a & 1;
+		r <<= 1;
+		a >>= 1;
+	}
+	r |= a & 1;
+	return r;
+}
+
+gf128_t gf128_from_bytes(const uint8_t p[16])
+{
+	gf128_t r;
+
+	r.lo = GETU64(p);
+	r.hi = GETU64(p + 8);
+
+	r.lo = reverse_bits(r.lo);
+	r.hi = reverse_bits(r.hi);
+	return r;
+}
+
+void gf128_to_bytes(gf128_t a, uint8_t p[16])
+{
+	a.lo = reverse_bits(a.lo);
+	a.hi = reverse_bits(a.hi);
+	PUTU64(p, a.lo);
+	PUTU64(p + 8, a.hi);
+}
+
+gf128_t gf128_add(gf128_t a, gf128_t b)
+{
+	gf128_t r;
+	r.hi = a.hi ^ b.hi;
+	r.lo = a.lo ^ b.lo;
+	return r;
+}
+
+gf128_t gf128_mul(gf128_t a, gf128_t b)
+{
+	gf128_t r = {0, 0};
+	uint64_t mask = (uint64_t)1 << 63;
+	int i;
+
+	for (i = 0; i < 64; i++) {
+		if (r.hi & mask) {
+			r.hi = r.hi << 1 | r.lo >> 63;
+			r.lo = (r.lo << 1);
+			r.lo ^= 0x87;
+		} else {
+			r.hi = r.hi << 1 | r.lo >> 63;
+			r.lo = r.lo << 1;
+		}
+
+		if (b.hi & mask) {
+			r.hi ^= a.hi;
+			r.lo ^= a.lo;
+		}
+
+		b.hi <<= 1;
+	}
+	for (i = 0; i < 64; i++) {
+		if (r.hi & mask) {
+			r.hi = r.hi << 1 | r.lo >> 63;
+			r.lo = (r.lo << 1) ^ 0x87;
+		} else {
+			r.hi = r.hi << 1 | r.lo >> 63;
+			r.lo = r.lo << 1;
+		}
+
+		if (b.lo & mask) {
+			r.hi ^= a.hi;
+			r.lo ^= a.lo;
+		}
+
+		b.lo <<= 1;
+	}
+
+	return r;
+}
+
+gf128_t gf128_mul2(gf128_t a)
+{
+	gf128_t r;
+
+	if (a.hi & ((uint64_t)1 << 63)) {
+		r.hi = a.hi << 1 | a.lo >> 63;
+		r.lo = a.lo << 1;
+		r.lo ^= 0x87;
+	} else {
+		r.hi = a.hi << 1 | a.lo >> 63;
+		r.lo = a.lo << 1;
+	}
+
+	return r;
+}

+ 299 - 0
components/gmssl/src/hash_drbg.c

@@ -0,0 +1,299 @@
+/*
+ *  Copyright 2014-2022 The GmSSL Project. All Rights Reserved.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the License); you may
+ *  not use this file except in compliance with the License.
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ */
+
+
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <gmssl/hash_drbg.h>
+#include <gmssl/error.h>
+#include <gmssl/endian.h>
+
+
+static int hash_df(const DIGEST *digest, const uint8_t *in, size_t inlen,
+	size_t outlen, uint8_t *out)
+{
+	int ret = 0;
+	DIGEST_CTX ctx;
+	uint8_t counter;
+	uint8_t outbits[4];
+	unsigned char dgst[64];
+	size_t len;
+
+	counter = 0x01;
+	PUTU32(outbits, (uint32_t)outlen << 3);
+
+	while (outlen > 0) {
+		if (digest_init(&ctx, digest) != 1
+			|| digest_update(&ctx, &counter, sizeof(counter)) != 1
+			|| digest_update(&ctx, outbits, sizeof(outbits)) != 1
+			|| digest_update(&ctx, in, inlen) != 1
+			|| digest_finish(&ctx, dgst, &len) != 1) {
+			goto end;
+		}
+
+		if (outlen < len) {
+			len = outlen;
+		}
+		memcpy(out, dgst, len);
+		out += len;
+		outlen -= len;
+
+		counter++;
+	}
+
+	ret = 1;
+end:
+	memset(&ctx, 0, sizeof(ctx));
+	memset(dgst, 0, sizeof(dgst));
+	return ret;
+}
+
+int hash_drbg_init(HASH_DRBG *drbg, const DIGEST *digest,
+	const uint8_t *entropy, size_t entropy_len,
+	const uint8_t *nonce, size_t nonce_len,
+	const uint8_t *personalstr, size_t personalstr_len)
+{
+	int ret = 0;
+	unsigned char *seed_material = NULL;
+	size_t seed_material_len;
+	uint8_t buf[1 + HASH_DRBG_MAX_SEED_SIZE];
+	uint8_t *p;
+
+	memset(drbg, 0, sizeof(HASH_DRBG));
+
+	/* set digest */
+	drbg->digest = digest;
+
+	/* set seedlen */
+	if (digest->digest_size <= 32) {
+		drbg->seedlen = HASH_DRBG_SM3_SEED_SIZE;
+	} else {
+		drbg->seedlen = HASH_DRBG_SHA512_SEED_SIZE;
+	}
+
+	/* seed_material = entropy_input || nonce || personalization_string */
+	seed_material_len = entropy_len + nonce_len + personalstr_len;
+	if (!(seed_material = malloc(seed_material_len))) {
+		return 0;
+	}
+	p = seed_material;
+	memcpy(p, entropy, entropy_len);
+	p += entropy_len;
+	memcpy(p, nonce, nonce_len);
+	p += nonce_len;
+	memcpy(p, personalstr, personalstr_len);
+
+	/* V = Hash_df (seed_material, seedlen) */
+	if (!hash_df(drbg->digest, seed_material, seed_material_len, drbg->seedlen,
+		drbg->V)) {
+		goto end;
+	}
+
+	/* C = Hash_df ((0x00 || V), seedlen) */
+	buf[0] = 0x00;
+	memcpy(buf + 1, drbg->V, drbg->seedlen);
+	if (!hash_df(drbg->digest, buf, 1 + drbg->seedlen, drbg->seedlen,
+		drbg->C)) {
+		goto end;
+	}
+
+	/* reseed_counter = 1 */
+	drbg->reseed_counter = 1;
+
+	ret = 1;
+end:
+	if (seed_material) {
+		memset(seed_material, 0, seed_material_len);
+		free(seed_material);
+	}
+	memset(buf, 0, sizeof(buf));
+	return ret;
+}
+
+int hash_drbg_reseed(HASH_DRBG *drbg,
+	const uint8_t *entropy, size_t entropy_len,
+	const uint8_t *additional, size_t additional_len)
+{
+	int ret = 0;
+	uint8_t *seed_material = NULL;
+	size_t seed_material_len;
+	uint8_t *p;
+	uint8_t buf[1 + HASH_DRBG_MAX_SEED_SIZE];
+
+	/* seed_material = 0x01 || V || entropy_input || additional_input */
+	seed_material_len = 1 + drbg->seedlen + entropy_len + additional_len;
+	if (!(seed_material = malloc(seed_material_len))) {
+		return 0;
+	}
+	seed_material[0] = 0x01;
+	p = seed_material + 1;
+	memcpy(p, drbg->V, drbg->seedlen);
+	p += drbg->seedlen;
+	memcpy(p, entropy, entropy_len);
+	p += entropy_len;
+	memcpy(p, additional, additional_len);
+
+	/* V = Hash_df(seed_material, seedlen) */
+	if (!hash_df(drbg->digest, seed_material, seed_material_len, drbg->seedlen,
+		drbg->V)) {
+		goto end;
+	}
+
+	/* C = Hash_df((0x00 || V), seedlen) */
+	buf[0] = 0x00;
+	memcpy(buf + 1, drbg->V, drbg->seedlen);
+	if (!hash_df(drbg->digest, buf, 1 + drbg->seedlen, drbg->seedlen,
+		drbg->C)) {
+		goto end;
+	}
+
+	/* reseed_counter = 1 */
+	drbg->reseed_counter = 1;
+
+	ret = 1;
+end:
+	if (seed_material) {
+		memset(seed_material, 0, seed_material_len);
+		free(seed_material);
+	}
+	memset(buf, 0, sizeof(buf));
+	return ret;
+}
+
+/* seedlen is always >= dgstlen
+ *      R0 ...  Ru-v .. .. ..   Ru-1
+ *    +          A0    A1 A2 .. Av-1
+ */
+static void drbg_add(uint8_t *R, const uint8_t *A, size_t seedlen)
+{
+	int temp = 0;
+	while (seedlen--) {
+		temp += R[seedlen] + A[seedlen];
+		R[seedlen] = temp & 0xff;
+		temp >>= 8;
+	}
+}
+
+static void drbg_add1(uint8_t *R, size_t seedlen)
+{
+	int temp = 1;
+	while (seedlen--) {
+		temp += R[seedlen];
+		R[seedlen] = temp & 0xff;
+		temp >>= 8;
+	}
+}
+
+static int drbg_hashgen(HASH_DRBG *drbg, size_t outlen, uint8_t *out)
+{
+	int ret = 0;
+	DIGEST_CTX ctx;
+	uint8_t data[HASH_DRBG_MAX_SEED_SIZE];
+	uint8_t dgst[DIGEST_MAX_SIZE];
+	size_t len;
+
+	/* data = V */
+	memcpy(data, drbg->V, drbg->seedlen);
+
+	while (outlen > 0) {
+
+		/* output Hash(data) */
+		if (digest_init(&ctx, drbg->digest) != 1
+			|| digest_update(&ctx, data, drbg->seedlen) != 1
+			|| digest_finish(&ctx, dgst, &len) != 1) {
+			goto end;
+		}
+
+		if (outlen < len) {
+			len = outlen;
+		}
+		memcpy(out, dgst, len);
+		out += len;
+		outlen -= len;
+
+		/* data = (data + 1) mod 2^seedlen */
+		drbg_add1(data, drbg->seedlen);
+	}
+
+	ret = 1;
+end:
+	memset(&ctx, 0, sizeof(ctx));
+	memset(data, 0, sizeof(data));
+	return ret;
+}
+
+int hash_drbg_generate(HASH_DRBG *drbg,
+	const uint8_t *additional, size_t additional_len,
+	size_t outlen, uint8_t *out)
+{
+	int ret = 0;
+	DIGEST_CTX ctx;
+	uint8_t prefix;
+	uint8_t T[HASH_DRBG_MAX_SEED_SIZE];
+	uint8_t dgst[DIGEST_MAX_SIZE];
+	size_t dgstlen;
+
+	// FIXME: check outlen max value
+
+	if (drbg->reseed_counter > HASH_DRBG_RESEED_INTERVAL) {
+		return 0;
+	}
+
+	if (additional) {
+		/* w = Hash (0x02 || V || additional_input) */
+		prefix = 0x02;
+		if (digest_init(&ctx, drbg->digest) != 1
+			|| digest_update(&ctx, &prefix, 1) != 1
+			|| digest_update(&ctx, drbg->V, drbg->seedlen) != 1
+			|| digest_update(&ctx, additional, additional_len) != 1
+			|| digest_finish(&ctx, dgst, &dgstlen) != 1) {
+			goto end;
+		}
+
+		/* V = (V + w) mod 2^seedlen */
+		memset(T, 0, drbg->seedlen - dgstlen);
+		memcpy(T + drbg->seedlen - dgstlen, dgst, dgstlen);
+		drbg_add(drbg->V, T, drbg->seedlen);
+	}
+
+	/* (returned_bits) = Hashgen (requested_number_of_bits, V). */
+	drbg_hashgen(drbg, outlen, out);
+
+	/* H = Hash (0x03 || V). */
+	prefix = 0x03;
+	if (digest_init(&ctx, drbg->digest) != 1
+		|| digest_update(&ctx, &prefix, 1) != 1
+		|| digest_update(&ctx, drbg->V, drbg->seedlen) != 1
+		|| digest_finish(&ctx, dgst, &dgstlen) != 1) {
+		goto end;
+	}
+
+	/* V = (V + H + C + reseed_counter) mod 2^seedlen */
+	memset(T, 0, drbg->seedlen - dgstlen);
+	memcpy(T + drbg->seedlen - dgstlen, dgst, dgstlen);
+	drbg_add(drbg->V, T, drbg->seedlen);
+
+	drbg_add(drbg->V, drbg->C, drbg->seedlen);
+
+	memset(T, 0, drbg->seedlen - sizeof(uint64_t));
+	PUTU64(T + drbg->seedlen - sizeof(uint64_t), drbg->reseed_counter);
+	drbg_add(drbg->V, T, drbg->seedlen);
+
+	/* reseed_counter = reseed_counter + 1 */
+	drbg->reseed_counter++;
+
+	ret = 1;
+end:
+	memset(&ctx, 0, sizeof(ctx));
+	memset(T, 0, sizeof(T));
+	memset(dgst, 0, sizeof(dgst));
+	return ret;
+}

+ 219 - 0
components/gmssl/src/hex.c

@@ -0,0 +1,219 @@
+/*
+ *  Copyright 2014-2022 The GmSSL Project. All Rights Reserved.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the License); you may
+ *  not use this file except in compliance with the License.
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ */
+
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <gmssl/error.h>
+
+int OPENSSL_hexchar2int(unsigned char c)
+{
+    switch (c) {
+    case '0':
+        return 0;
+    case '1':
+        return 1;
+    case '2':
+        return 2;
+    case '3':
+        return 3;
+    case '4':
+          return 4;
+    case '5':
+          return 5;
+    case '6':
+          return 6;
+    case '7':
+          return 7;
+    case '8':
+          return 8;
+    case '9':
+          return 9;
+    case 'a':
+    case 'A':
+          return 0x0A;
+    case 'b': case 'B':
+          return 0x0B;
+    case 'c': case 'C':
+          return 0x0C;
+    case 'd': case 'D':
+          return 0x0D;
+    case 'e': case 'E':
+          return 0x0E;
+    case 'f': case 'F':
+          return 0x0F;
+    }
+    return -1;
+}
+
+unsigned char *OPENSSL_hexstr2buf(const char *str, size_t *len)
+{
+    unsigned char *hexbuf, *q;
+    unsigned char ch, cl;
+    int chi, cli;
+    const unsigned char *p;
+    size_t s;
+
+    s = strlen(str);
+    if ((hexbuf = malloc(s >> 1)) == NULL) {
+        return NULL;
+    }
+    for (p = (const unsigned char *)str, q = hexbuf; *p; ) {
+        ch = *p++;
+        if (ch == ':')
+            continue;
+        cl = *p++;
+        if (!cl) {
+            //CRYPTOerr(CRYPTO_F_OPENSSL_HEXSTR2BUF, CRYPTO_R_ODD_NUMBER_OF_DIGITS);
+            free(hexbuf);
+            return NULL;
+        }
+        cli = OPENSSL_hexchar2int(cl);
+        chi = OPENSSL_hexchar2int(ch);
+        if (cli < 0 || chi < 0) {
+            free(hexbuf);
+            //CRYPTOerr(CRYPTO_F_OPENSSL_HEXSTR2BUF, CRYPTO_R_ILLEGAL_HEX_DIGIT);
+            return NULL;
+        }
+        *q++ = (unsigned char)((chi << 4) | cli);
+    }
+
+    if (len)
+        *len = q - hexbuf;
+    return hexbuf;
+}
+
+
+static int hexchar2int(char c)
+{
+	if      ('0' <= c && c <= '9') return c - '0';
+	else if ('a' <= c && c <= 'f') return c - 'a' + 10;
+	else if ('A' <= c && c <= 'F') return c - 'A' + 10;
+	else return -1;
+}
+
+int hex2bin(const char *in, size_t inlen, uint8_t *out)
+{
+	int c;
+	if (inlen % 2) {
+		error_print_msg("hex %s len = %zu\n", in, inlen);
+		return -1;
+	}
+
+	while (inlen) {
+		if ((c = hexchar2int(*in++)) < 0) {
+			error_print_msg("%d", 5);
+			return -1;
+		}
+		*out = (uint8_t)c << 4;
+		if ((c = hexchar2int(*in++)) < 0) {
+			error_print();
+			return -1;
+		}
+		*out |= (uint8_t)c;
+		inlen -= 2;
+		out++;
+	}
+	return 1;
+}
+
+int hex_to_bytes(const char *in, size_t inlen, uint8_t *out, size_t *outlen)
+{
+	*outlen = inlen/2;
+	return hex2bin(in, inlen, out);
+}
+
+
+void memxor(void *r, const void *a, size_t len)
+{
+	uint8_t *pr = r;
+	const uint8_t *pa = a;
+	size_t i;
+	for (i = 0; i < len; i++) {
+		pr[i] ^= pa[i];
+	}
+
+}
+
+
+void gmssl_memxor(void *r, const void *a, const void *b, size_t len)
+{
+	uint8_t *pr = r;
+	const uint8_t *pa = a;
+	const uint8_t *pb = b;
+	size_t i;
+	for (i = 0; i < len; i++) {
+		pr[i] = pa[i] ^ pb[i];
+	}
+}
+
+
+// Note: comments and code from OpenSSL crypto/cryptlib.c:CRYPTO_memcmp()
+/* volatile unsigned char* pointers are there because
+ * 1. Accessing a variable declared volatile via a pointer
+ *    that lacks a volatile qualifier causes undefined behavior.
+ * 2. When the variable itself is not volatile the compiler is
+ *    not required to keep all those reads and can convert
+ *    this into canonical memcmp() which doesn't read the whole block.
+ * Pointers to volatile resolve the first problem fully. The second
+ * problem cannot be resolved in any Standard-compliant way but this
+ * works the problem around. Compilers typically react to
+ * pointers to volatile by preserving the reads and writes through them.
+ * The latter is not required by the Standard if the memory pointed to
+ * is not volatile.
+ * Pointers themselves are volatile in the function signature to work
+ * around a subtle bug in gcc 4.6+ which causes writes through
+ * pointers to volatile to not be emitted in some rare,
+ * never needed in real life, pieces of code.
+ */
+int gmssl_secure_memcmp(const volatile void * volatile in_a, const volatile void * volatile in_b, size_t len)
+{
+	size_t i;
+	const volatile unsigned char *a = in_a;
+	const volatile unsigned char *b = in_b;
+	unsigned char x = 0;
+
+	for (i = 0; i < len; i++) {
+		x |= a[i] ^ b[i];
+	}
+
+	return x;
+}
+
+/*
+ * Pointer to memset is volatile so that compiler must de-reference
+ * the pointer and can't assume that it points to any function in
+ * particular (such as memset, which it then might further "optimize")
+ */
+typedef void *(*memset_t)(void *, int, size_t);
+
+static volatile memset_t memset_func = memset;
+
+void gmssl_secure_clear(void *ptr, size_t len)
+{
+	memset_func(ptr, 0, len);
+}
+
+int mem_is_zero(const uint8_t *buf, size_t len)
+{
+	int ret = 1;
+	size_t i;
+	for (i = 0; i < len; i++) {
+		if (buf[i]) ret = 0;
+	}
+	return ret;
+}
+
+
+
+
+

+ 205 - 0
components/gmssl/src/hkdf.c

@@ -0,0 +1,205 @@
+/*
+ *  Copyright 2014-2022 The GmSSL Project. All Rights Reserved.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the License); you may
+ *  not use this file except in compliance with the License.
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ */
+
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <gmssl/sm3.h>
+#include <gmssl/hmac.h>
+#include <gmssl/error.h>
+
+/*
+
+HKDF-Extract(salt, IKM) -> PRK
+
+	salt optional, len(salt) == hash_len is recommended
+	IKM input key material
+	PRK output pseudorandom key, len(PRK) = hashLen
+
+	PRK = HMAC_hash(salt, IKM)
+	salt as key?
+
+
+HKDF-Expand(PRK, info, L) -> OKM
+	info optional
+	L output length, L <= 255 * hashLen
+	OKM output key
+
+
+	N = (L + hashLen - 1)//hashLen
+	T = T(1) || T(2) || ... | T(N)
+	OKM = T[0..L-1]
+
+	T(0) = empty string (len = 0)
+	T(1) = HMAC_hash(PRK, T(0) | info | 0x01)
+	T(2) = HMAC_hash(PRK, T(1) | info | 0x02)
+	T(3) = HMAC_hash(PRK, T(2) | info | 0x03)
+	...
+
+
+*/
+
+int hkdf_extract(const DIGEST *digest, const uint8_t *salt, size_t saltlen,
+	const uint8_t *ikm, size_t ikmlen,
+	uint8_t *prk, size_t *prklen)
+{
+	HMAC_CTX hmac_ctx;
+
+	if (!salt || saltlen == 0) {
+		uint8_t zeros[DIGEST_MAX_SIZE] = {0};
+		if (hmac_init(&hmac_ctx, digest, zeros, digest->digest_size) != 1) {
+			error_print();
+			return -1;
+		}
+	} else {
+		if (hmac_init(&hmac_ctx, digest, salt, saltlen) != 1) {
+			error_print();
+			return -1;
+		}
+	}
+
+	if (hmac_update(&hmac_ctx, ikm, ikmlen) != 1
+		|| hmac_finish(&hmac_ctx, prk, prklen) != 1) {
+		error_print();
+		return -1;
+	}
+	return 1;
+}
+
+int hkdf_expand(const DIGEST *digest, const uint8_t *prk, size_t prklen,
+	const uint8_t *opt_info, size_t opt_infolen,
+	size_t L, uint8_t *okm)
+{
+	HMAC_CTX hmac_ctx;
+	uint8_t T[HMAC_MAX_SIZE];
+	uint8_t counter = 0x01;
+	size_t len;
+
+	if (L > 0) {
+		if (hmac_init(&hmac_ctx, digest, prk, prklen) != 1
+			|| hmac_update(&hmac_ctx, opt_info, opt_infolen) < 0
+			|| hmac_update(&hmac_ctx, &counter, 1) != 1
+			|| hmac_finish(&hmac_ctx, T, &len) != 1) {
+			error_print();
+			return -1;
+		}
+		counter++;
+		if (len > L) {
+			len = L;
+		}
+		memcpy(okm, T, len);
+		okm += len;
+		L -= len;
+	}
+	while (L > 0) {
+		if (counter == 0) {
+			error_print();
+			return -1;
+		}
+		if (hmac_init(&hmac_ctx, digest, prk, prklen) != 1
+			|| hmac_update(&hmac_ctx, T, len) != 1
+			|| hmac_update(&hmac_ctx, opt_info, opt_infolen) < 0
+			|| hmac_update(&hmac_ctx, &counter, 1) != 1
+			|| hmac_finish(&hmac_ctx, T, &len) != 1) {
+			error_print();
+			return -1;
+		}
+		counter++;
+		if (len > L) {
+			len = L;
+		}
+		memcpy(okm, T, len);
+		okm += len;
+		L -= len;
+	}
+	return 1;
+}
+
+/*
+int sm3_hkdf_extract(const uint8_t *salt, size_t saltlen,
+	const uint8_t *ikm, size_t ikmlen,
+	uint8_t *prk, size_t *prklen)
+{
+	SM3_HMAC_CTX hmac_ctx;
+
+	if (!salt || saltlen == 0) {
+		uint8_t zeros[SM3_HMAC_SIZE] = {0};
+		if (sm3_hmac_init(&hmac_ctx, zeros, SM3_HMAC_SIZE) != 1) {
+			error_print();
+			return -1;
+		}
+	} else {
+		if (sm3_hmac_init(&hmac_ctx, salt, saltlen) != 1) {
+			error_print();
+			return -1;
+		}
+	}
+
+	if (sm3_hmac_update(&hmac_ctx, ikm, ikmlen) != 1
+		|| sm3_hmac_finish(&hmac_ctx, prk) != 1) {
+		error_print();
+		return -1;
+	}
+	*prklen = SM3_HMAC_SIZE;
+	return 1;
+}
+
+int sm3_hkdf_expand(const uint8_t *prk, size_t prklen,
+	const uint8_t *opt_info, size_t opt_infolen,
+	size_t L, uint8_t *okm)
+{
+	SM3_HMAC_CTX hmac_ctx;
+	uint8_t T[SM3_HMAC_SIZE];
+	uint8_t counter = 0x01;
+	size_t len;
+
+	if (L > 0) {
+		if (sm3_hmac_init(&hmac_ctx, prk, prklen) != 1
+			|| sm3_hmac_update(&hmac_ctx, opt_info, opt_infolen) < 0
+			|| sm3_hmac_update(&hmac_ctx, &counter, 1) != 1
+			|| sm3_hmac_finish(&hmac_ctx, T) != 1) {
+			error_print();
+			return -1;
+		}
+		counter++;
+		len = SM3_HMAC_SIZE;
+		if (len > L) {
+			len = L;
+		}
+		memcpy(okm, T, len);
+		okm += len;
+		L -= len;
+	}
+	while (L > 0) {
+		if (counter == 0) {
+			error_print();
+			return -1;
+		}
+		if (sm3_hmac_init(&hmac_ctx, digest, prk, prklen) != 1
+			|| sm3_hmac_update(&hmac_ctx, T, len) != 1
+			|| sm3_hmac_update(&hmac_ctx, opt_info, opt_infolen) < 0
+			|| sm3_hmac_update(&hmac_ctx, &counter, 1) != 1
+			|| sm3_hmac_finish(&hmac_ctx, T) != 1) {
+			error_print();
+			return -1;
+		}
+		counter++;
+		len = SM3_HMAC_SIZE;
+		if (len > L) {
+			len = L;
+		}
+		memcpy(okm, T, len);
+		okm += len;
+		L -= len;
+	}
+	return 1;
+}
+*/

+ 129 - 0
components/gmssl/src/hmac.c

@@ -0,0 +1,129 @@
+/*
+ *  Copyright 2014-2022 The GmSSL Project. All Rights Reserved.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the License); you may
+ *  not use this file except in compliance with the License.
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ */
+
+
+#include <string.h>
+#include <gmssl/hmac.h>
+#include <gmssl/error.h>
+
+
+#define IPAD	0x36
+#define OPAD	0x5C
+
+
+int hmac_init(HMAC_CTX *ctx, const DIGEST *digest, const uint8_t *key, size_t keylen)
+{
+	uint8_t i_key[DIGEST_MAX_BLOCK_SIZE] = {0};
+	uint8_t o_key[DIGEST_MAX_BLOCK_SIZE] = {0};
+	size_t blocksize;
+	int i;
+
+	if (!ctx || !digest || !key || !keylen) {
+		error_print();
+		return -1;
+	}
+
+	ctx->digest = digest;
+
+	blocksize = digest->block_size;
+	if (keylen <= blocksize) {
+		memcpy(i_key, key, keylen);
+		memcpy(o_key, key, keylen);
+	} else {
+		digest_init(&ctx->digest_ctx, digest);
+		digest_update(&ctx->digest_ctx, key, keylen);
+		digest_finish(&ctx->digest_ctx, i_key, &keylen);
+		memcpy(o_key, i_key, keylen);
+	}
+	for (i = 0; i < blocksize; i++) {
+		i_key[i] ^= IPAD;
+		o_key[i] ^= OPAD;
+	}
+
+	digest_init(&ctx->i_ctx, digest);
+	digest_update(&ctx->i_ctx, i_key, blocksize);
+	digest_init(&ctx->o_ctx, digest);
+	digest_update(&ctx->o_ctx, o_key, blocksize);
+	memcpy(&ctx->digest_ctx, &ctx->i_ctx, sizeof(DIGEST_CTX));
+
+	memset(i_key, 0, sizeof(i_key));
+	memset(o_key, 0, sizeof(o_key));
+	return 1;
+}
+
+int hmac_update(HMAC_CTX *ctx, const uint8_t *data, size_t datalen)
+{
+	if (ctx == NULL) {
+		error_print();
+		return -1;
+	}
+	if (data == NULL || datalen == 0) {
+		return 0;
+	}
+	if (digest_update(&ctx->digest_ctx, data, datalen) != 1) {
+		error_print();
+		return -1;
+	}
+	return 1;
+}
+
+int hmac_finish(HMAC_CTX *ctx, uint8_t *mac, size_t *maclen)
+{
+	if (ctx == NULL || maclen == NULL) {
+		error_print();
+		return -1;
+	}
+	if (digest_finish(&ctx->digest_ctx, mac, maclen) != 1) {
+		error_print();
+		return -1;
+	}
+	memcpy(&ctx->digest_ctx, &ctx->o_ctx, sizeof(DIGEST_CTX));
+	if (digest_update(&ctx->digest_ctx, mac, *maclen) != 1
+		|| digest_finish(&ctx->digest_ctx, mac, maclen) != 1) {
+		error_print();
+		return -1;
+	}
+	return 1;
+}
+
+int hmac_finish_and_verify(HMAC_CTX *ctx, const uint8_t *mac, size_t maclen)
+{
+	uint8_t hmac[64];
+	size_t hmaclen;
+
+	if (hmac_finish(ctx, hmac, &hmaclen) != 1) {
+		error_print();
+		return -1;
+	}
+	if (maclen != hmaclen
+		|| memcmp(hmac, mac, maclen) != 0) {
+		error_print();
+		return -1;
+	}
+	return 1;
+}
+
+int hmac(const DIGEST *digest, const uint8_t *key, size_t keylen,
+	const uint8_t *data, size_t datalen,
+	uint8_t *mac, size_t *maclen)
+{
+	int ret = 0;
+	HMAC_CTX ctx;
+
+	if (hmac_init(&ctx, digest, key, keylen) != 1
+		|| hmac_update(&ctx, data, datalen) != 1
+		|| hmac_finish(&ctx, mac, maclen) != 1) {
+		goto end;
+	}
+	ret = 1;
+
+end:
+	memset(&ctx, 0, sizeof(ctx));
+	return ret;
+}

+ 181 - 0
components/gmssl/src/md5.c

@@ -0,0 +1,181 @@
+/*
+ *  Copyright 2014-2022 The GmSSL Project. All Rights Reserved.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the License); you may
+ *  not use this file except in compliance with the License.
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ */
+
+
+
+#include <string.h>
+#include <gmssl/md5.h>
+#include <gmssl/endian.h>
+
+
+#define F(B, C, D)	(((B) & (C)) | ((~(B)) & (D)))
+#define G(B, C, D)	(((B) & (D)) | ((C) & (~(D))))
+#define H(B, C, D)	((B) ^ (C) ^ (D))
+#define I(B, C, D)	((C) ^ ((B) | (~(D))))
+
+static const uint32_t K[] = {
+	0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee,
+	0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
+	0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,
+	0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821,
+	0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa,
+	0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
+	0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed,
+	0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a,
+	0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c,
+	0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
+	0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05,
+	0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
+	0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039,
+	0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
+	0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,
+	0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391,
+};
+
+static const int S[] = {
+	7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22,
+	5,  9, 14, 20, 5,  9, 14, 20, 5,  9, 14, 20, 5,  9, 14, 20,
+	4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23,
+	6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21,
+};
+
+static void md5_compress_blocks(uint32_t state[4],
+	const unsigned char *data, size_t blocks)
+{
+	uint32_t A;
+	uint32_t B;
+	uint32_t C;
+	uint32_t D;
+	uint32_t T;
+	uint32_t W[16];
+	int g, i;
+
+	while (blocks--) {
+
+		A = state[0];
+		B = state[1];
+		C = state[2];
+		D = state[3];
+
+		for (i = 0; i < 16; i++) {
+			W[i] = GETU32_LE(data);
+			data += sizeof(uint32_t);
+		}
+
+		for (i = 0; i < 16; i++) {
+			T = ROL32(A + F(B, C, D) + W[i] + K[i], S[i]) + B;
+			A = D;
+			D = C;
+			C = B;
+			B = T;
+		}
+		for (; i < 32; i++) {
+			g = (5 * i + 1) % 16;
+			T = ROL32(A + G(B, C, D) + W[g] + K[i], S[i]) + B;
+			A = D;
+			D = C;
+			C = B;
+			B = T;
+		}
+		for (; i < 48; i++) {
+			g = (3 * i + 5) % 16;
+			T = ROL32(A + H(B, C, D) + W[g] + K[i], S[i]) + B;
+			A = D;
+			D = C;
+			C = B;
+			B = T;
+		}
+		for (; i < 64; i++) {
+			g = (7 * i) % 16;
+			T = ROL32(A + I(B, C, D) + W[g] + K[i], S[i]) + B;
+			A = D;
+			D = C;
+			C = B;
+			B = T;
+		}
+
+		state[0] += A;
+		state[1] += B;
+		state[2] += C;
+		state[3] += D;
+	}
+}
+
+void md5_init(MD5_CTX *ctx)
+{
+	memset(ctx, 0, sizeof(*ctx));
+	ctx->state[0] = 0x67452301;
+	ctx->state[1] = 0xefcdab89;
+	ctx->state[2] = 0x98badcfe;
+	ctx->state[3] = 0x10325476;
+}
+
+void md5_update(MD5_CTX *ctx, const unsigned char *data, size_t datalen)
+{
+	size_t blocks;
+
+	ctx->num &= 0x3f;
+	if (ctx->num) {
+		size_t left = MD5_BLOCK_SIZE - ctx->num;
+		if (datalen < left) {
+			memcpy(ctx->block + ctx->num, data, datalen);
+			ctx->num += datalen;
+			return;
+		} else {
+			memcpy(ctx->block + ctx->num, data, left);
+			md5_compress_blocks(ctx->state, ctx->block, 1);
+			ctx->nblocks++;
+			data += left;
+			datalen -= left;
+		}
+	}
+
+	blocks = datalen / MD5_BLOCK_SIZE;
+	md5_compress_blocks(ctx->state, data, blocks);
+	ctx->nblocks += blocks;
+	data += MD5_BLOCK_SIZE * blocks;
+	datalen -= MD5_BLOCK_SIZE * blocks;
+
+	ctx->num = datalen;
+	if (datalen) {
+		memcpy(ctx->block, data, datalen);
+	}
+}
+
+void md5_finish(MD5_CTX *ctx, unsigned char *dgst)
+{
+	int i;
+
+	ctx->num &= 0x3f;
+	ctx->block[ctx->num] = 0x80;
+
+	if (ctx->num <= MD5_BLOCK_SIZE - 9) {
+		memset(ctx->block + ctx->num + 1, 0, MD5_BLOCK_SIZE - ctx->num - 9);
+	} else {
+		memset(ctx->block + ctx->num + 1, 0, MD5_BLOCK_SIZE - ctx->num - 1);
+		md5_compress_blocks(ctx->state, ctx->block, 1);
+		memset(ctx->block, 0, MD5_BLOCK_SIZE - 8);
+	}
+	PUTU64_LE(ctx->block + 56, (ctx->nblocks << 9) + (ctx->num << 3));
+	md5_compress_blocks(ctx->state, ctx->block, 1);
+	for (i = 0; i < 4; i++) {
+		PUTU32_LE(dgst, ctx->state[i]);
+		dgst += sizeof(uint32_t);
+	}
+	memset(ctx, 0, sizeof(*ctx));
+}
+
+void md5_digest(const unsigned char *data, size_t datalen,
+	unsigned char dgst[MD5_DIGEST_SIZE])
+{
+	MD5_CTX ctx;
+	md5_init(&ctx);
+	md5_update(&ctx, data, datalen);
+	md5_finish(&ctx, dgst);
+}

+ 0 - 154
components/gmssl/src/modes/cbc128.c

@@ -1,154 +0,0 @@
-/*
- * Copyright 2008-2016 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
- * in the file LICENSE in the source distribution or at
- * https://www.openssl.org/source/license.html
- */
-
-#include "modes_lcl.h"
-#include <string.h>
-
-#if !defined(STRICT_ALIGNMENT) && !defined(PEDANTIC)
-# define STRICT_ALIGNMENT 0
-#endif
-
-void CRYPTO_cbc128_encrypt(const unsigned char *in, unsigned char *out,
-                           size_t len, const void *key,
-                           unsigned char ivec[16], block128_f block)
-{
-    size_t n;
-    const unsigned char *iv = ivec;
-
-#if !defined(OPENSSL_SMALL_FOOTPRINT)
-    if (STRICT_ALIGNMENT &&
-        ((size_t)in | (size_t)out | (size_t)ivec) % sizeof(size_t) != 0) {
-        while (len >= 16) {
-            for (n = 0; n < 16; ++n)
-                out[n] = in[n] ^ iv[n];
-            (*block) (out, out, key);
-            iv = out;
-            len -= 16;
-            in += 16;
-            out += 16;
-        }
-    } else {
-        while (len >= 16) {
-            for (n = 0; n < 16; n += sizeof(size_t))
-                *(size_t *)(out + n) =
-                    *(size_t *)(in + n) ^ *(size_t *)(iv + n);
-            (*block) (out, out, key);
-            iv = out;
-            len -= 16;
-            in += 16;
-            out += 16;
-        }
-    }
-#endif
-    while (len) {
-        for (n = 0; n < 16 && n < len; ++n)
-            out[n] = in[n] ^ iv[n];
-        for (; n < 16; ++n)
-            out[n] = iv[n];
-        (*block) (out, out, key);
-        iv = out;
-        if (len <= 16)
-            break;
-        len -= 16;
-        in += 16;
-        out += 16;
-    }
-    memcpy(ivec, iv, 16);
-}
-
-void CRYPTO_cbc128_decrypt(const unsigned char *in, unsigned char *out,
-                           size_t len, const void *key,
-                           unsigned char ivec[16], block128_f block)
-{
-    size_t n;
-    union {
-        size_t t[16 / sizeof(size_t)];
-        unsigned char c[16];
-    } tmp;
-
-#if !defined(OPENSSL_SMALL_FOOTPRINT)
-    if (in != out) {
-        const unsigned char *iv = ivec;
-
-        if (STRICT_ALIGNMENT &&
-            ((size_t)in | (size_t)out | (size_t)ivec) % sizeof(size_t) != 0) {
-            while (len >= 16) {
-                (*block) (in, out, key);
-                for (n = 0; n < 16; ++n)
-                    out[n] ^= iv[n];
-                iv = in;
-                len -= 16;
-                in += 16;
-                out += 16;
-            }
-        } else if (16 % sizeof(size_t) == 0) { /* always true */
-            while (len >= 16) {
-                size_t *out_t = (size_t *)out, *iv_t = (size_t *)iv;
-
-                (*block) (in, out, key);
-                for (n = 0; n < 16 / sizeof(size_t); n++)
-                    out_t[n] ^= iv_t[n];
-                iv = in;
-                len -= 16;
-                in += 16;
-                out += 16;
-            }
-        }
-        memcpy(ivec, iv, 16);
-    } else {
-        if (STRICT_ALIGNMENT &&
-            ((size_t)in | (size_t)out | (size_t)ivec) % sizeof(size_t) != 0) {
-            unsigned char c;
-            while (len >= 16) {
-                (*block) (in, tmp.c, key);
-                for (n = 0; n < 16; ++n) {
-                    c = in[n];
-                    out[n] = tmp.c[n] ^ ivec[n];
-                    ivec[n] = c;
-                }
-                len -= 16;
-                in += 16;
-                out += 16;
-            }
-        } else if (16 % sizeof(size_t) == 0) { /* always true */
-            while (len >= 16) {
-                size_t c, *out_t = (size_t *)out, *ivec_t = (size_t *)ivec;
-                const size_t *in_t = (const size_t *)in;
-
-                (*block) (in, tmp.c, key);
-                for (n = 0; n < 16 / sizeof(size_t); n++) {
-                    c = in_t[n];
-                    out_t[n] = tmp.t[n] ^ ivec_t[n];
-                    ivec_t[n] = c;
-                }
-                len -= 16;
-                in += 16;
-                out += 16;
-            }
-        }
-    }
-#endif
-    while (len) {
-        unsigned char c;
-        (*block) (in, tmp.c, key);
-        for (n = 0; n < 16 && n < len; ++n) {
-            c = in[n];
-            out[n] = tmp.c[n] ^ ivec[n];
-            ivec[n] = c;
-        }
-        if (len <= 16) {
-            for (; n < 16; ++n)
-                ivec[n] = in[n];
-            break;
-        }
-        len -= 16;
-        in += 16;
-        out += 16;
-    }
-}

+ 188 - 0
components/gmssl/src/pbkdf2.c

@@ -0,0 +1,188 @@
+/*
+ *  Copyright 2014-2022 The GmSSL Project. All Rights Reserved.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the License); you may
+ *  not use this file except in compliance with the License.
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ */
+
+
+
+/*
+   PBKDF2 (P, S, c, dkLen)
+
+   Options:        PRF        underlying pseudorandom function (hLen
+                              denotes the length in octets of the
+                              pseudorandom function output)
+
+   Input:          P          password, an octet string
+                   S          salt, an octet string
+                   c          iteration count, a positive integer
+                   dkLen      intended length in octets of the derived
+                              key, a positive integer, at most
+                              (2^32 - 1) * hLen
+
+   Output:         DK         derived key, a dkLen-octet string
+
+   Steps:
+
+      1. If dkLen > (2^32 - 1) * hLen, output "derived key too long" and
+         stop.
+
+      2. Let l be the number of hLen-octet blocks in the derived key,
+         rounding up, and let r be the number of octets in the last
+         block:
+
+                   l = CEIL (dkLen / hLen) ,
+                   r = dkLen - (l - 1) * hLen .
+
+         Here, CEIL (x) is the "ceiling" function, i.e. the smallest
+         integer greater than, or equal to, x.
+
+      3. For each block of the derived key apply the function F defined
+         below to the password P, the salt S, the iteration count c, and
+         the block index to compute the block:
+
+                   T_1 = F (P, S, c, 1) ,
+                   T_2 = F (P, S, c, 2) ,
+                   ...
+                   T_l = F (P, S, c, l) ,
+
+         where the function F is defined as the exclusive-or sum of the
+         first c iterates of the underlying pseudorandom function PRF
+         applied to the password P and the concatenation of the salt S
+         and the block index i:
+
+                   F (P, S, c, i) = U_1 \xor U_2 \xor ... \xor U_c
+
+         where
+
+                   U_1 = PRF (P, S || INT (i)) ,
+                   U_2 = PRF (P, U_1) ,
+                   ...
+                   U_c = PRF (P, U_{c-1}) .
+
+         Here, INT (i) is a four-octet encoding of the integer i, most
+         significant octet first.
+
+      4. Concatenate the blocks and extract the first dkLen octets to
+         produce a derived key DK:
+
+                   DK = T_1 || T_2 ||  ...  || T_l<0..r-1>
+
+      5. Output the derived key DK.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <gmssl/asn1.h>
+#include <gmssl/hmac.h>
+#include <gmssl/digest.h>
+#include <gmssl/error.h>
+#include <gmssl/oid.h>
+#include <gmssl/endian.h>
+#include <gmssl/mem.h>
+
+int pbkdf2_genkey(const DIGEST *digest,
+	const char *pass, size_t passlen,
+	const uint8_t *salt, size_t saltlen, size_t count,
+	size_t outlen, uint8_t *out)
+{
+	HMAC_CTX ctx;
+	HMAC_CTX ctx_tmpl;
+	uint32_t iter = 1;
+	uint8_t iter_be[4];
+	uint8_t tmp_block[64];
+	uint8_t key_block[64];
+	size_t len;
+
+	hmac_init(&ctx_tmpl, digest, (uint8_t *)pass, passlen);
+
+	while (outlen > 0) {
+		size_t i;
+
+		PUTU32(iter_be, iter);
+		iter++;
+
+		ctx = ctx_tmpl;
+		hmac_update(&ctx, salt, saltlen);
+		hmac_update(&ctx, iter_be, sizeof(iter_be));
+		hmac_finish(&ctx, tmp_block, &len);
+		memcpy(key_block, tmp_block, len);
+
+		for (i = 1; i < count; i++) {
+			ctx = ctx_tmpl;
+			hmac_update(&ctx, tmp_block, len);
+			hmac_finish(&ctx, tmp_block, &len);
+			memxor(key_block, tmp_block, len);
+		}
+
+		if (outlen < len) {
+			memcpy(out, key_block, outlen);
+			out += outlen;
+			outlen = 0;
+		} else {
+			memcpy(out, key_block, len);
+			out += len;
+			outlen -= len;
+		}
+	}
+
+	memset(&ctx, 0, sizeof(ctx));
+	memset(key_block, 0, sizeof(key_block));
+	memset(tmp_block, 0, sizeof(key_block));
+	return 1;
+}
+
+int pbkdf2_hmac_sm3_genkey(
+	const char *pass, size_t passlen,
+	const uint8_t *salt, size_t saltlen, size_t count,
+	size_t outlen, uint8_t *out)
+{
+	SM3_HMAC_CTX ctx;
+	SM3_HMAC_CTX ctx_tmpl;
+	uint32_t iter = 1;
+	uint8_t iter_be[4];
+	uint8_t tmp_block[SM3_DIGEST_SIZE];
+	uint8_t key_block[SM3_DIGEST_SIZE];
+	// TODO: a bug in 3.0.0 is fixied. How to update release version 3.0.0 ? A test is also required!
+
+	sm3_hmac_init(&ctx_tmpl, (uint8_t *)pass, passlen);
+
+	while (outlen > 0) {
+		size_t i;
+
+		PUTU32(iter_be, iter);
+		iter++;
+
+		ctx = ctx_tmpl;
+		sm3_hmac_update(&ctx, salt, saltlen);
+		sm3_hmac_update(&ctx, iter_be, sizeof(iter_be));
+		sm3_hmac_finish(&ctx, tmp_block);
+		memcpy(key_block, tmp_block, SM3_DIGEST_SIZE);
+
+		for (i = 1; i < count; i++) {
+			ctx = ctx_tmpl;
+			sm3_hmac_update(&ctx, tmp_block, SM3_DIGEST_SIZE);
+			sm3_hmac_finish(&ctx, tmp_block);
+			memxor(key_block, tmp_block, SM3_DIGEST_SIZE);
+		}
+
+		if (outlen < SM3_DIGEST_SIZE) {
+			memcpy(out, key_block, outlen);
+			out += outlen;
+			outlen = 0;
+		} else {
+			memcpy(out, key_block, SM3_DIGEST_SIZE);
+			out += SM3_DIGEST_SIZE;
+			outlen -= SM3_DIGEST_SIZE;
+		}
+	}
+
+	memset(&ctx, 0, sizeof(ctx));
+	memset(key_block, 0, sizeof(key_block));
+	memset(tmp_block, 0, sizeof(key_block));
+	return 1;
+}

+ 122 - 0
components/gmssl/src/pem.c

@@ -0,0 +1,122 @@
+/*
+ *  Copyright 2014-2022 The GmSSL Project. All Rights Reserved.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the License); you may
+ *  not use this file except in compliance with the License.
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ */
+
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <gmssl/pem.h>
+#include <gmssl/error.h>
+
+
+static int remove_newline(char *line)
+{
+	size_t len;
+	len = strlen(line);
+
+	if (len >= 2) {
+		if (line[len - 2] == '\r' && line[len - 1] == '\n') {
+			line[len - 2] = line[len - 1] = 0;
+			return 1;
+		}
+	}
+	if (len) {
+		if (line[len - 1] == '\n') {
+			line[len - 1] = 0;
+			return 1;
+		}
+	}
+	return 0; // No newline found, might not be an error
+}
+
+int pem_write(FILE *fp, const char *name, const uint8_t *data, size_t datalen)
+{
+	BASE64_CTX ctx;
+	uint8_t* b64 = NULL;
+	int len;
+
+	if (!datalen) {
+		error_print();
+		return -1;
+	}
+
+	// FIXME: use a fixed-size buffer
+	if (!(b64 = malloc(datalen * 2))) {
+		error_print();
+		return -1;
+	}
+
+	base64_encode_init(&ctx);
+	base64_encode_update(&ctx, data, (int)datalen, b64, &len);
+	base64_encode_finish(&ctx, b64 + len, &len);
+
+	fprintf(fp, "-----BEGIN %s-----\n", name);
+	fprintf(fp, "%s", (char *)b64);
+	fprintf(fp, "-----END %s-----\n", name);
+
+	free(b64);
+	return 1;
+}
+
+int pem_read(FILE *fp, const char *name, uint8_t *data, size_t *datalen, size_t maxlen)
+{
+	char line[80];
+	char begin_line[80];
+	char end_line[80];
+	int len;
+	BASE64_CTX ctx;
+
+	snprintf(begin_line, sizeof(begin_line), "-----BEGIN %s-----", name);
+	snprintf(end_line, sizeof(end_line), "-----END %s-----", name);
+
+	if (feof(fp)) {
+		return 0;
+	}
+
+	if (!fgets(line, sizeof(line), fp)) {
+		if (feof(fp))
+			return 0;
+		else {
+			error_print();
+			return -1;
+		}
+	}
+	remove_newline(line);
+
+	if (strcmp(line, begin_line) != 0) {
+		fprintf(stderr, "%s %d: %s\n", __FILE__, __LINE__, line);
+		fprintf(stderr, "%s %d: %s\n", __FILE__, __LINE__, begin_line);
+		error_print();
+		return -1;
+	}
+
+	*datalen = 0;
+
+	base64_decode_init(&ctx);
+
+	for (;;) {
+		if (!fgets(line, sizeof(line), fp)) {
+			error_print();
+			return -1;
+		}
+		remove_newline(line);
+
+		if (strcmp(line, end_line) == 0) {
+			break;
+		}
+
+		base64_decode_update(&ctx, (uint8_t *)line, (int)strlen(line), data, &len);
+		data += len;
+		*datalen += len;
+	}
+
+	base64_decode_finish(&ctx, data, &len);
+	*datalen += len;
+	return 1;
+}

+ 454 - 0
components/gmssl/src/pkcs8.c

@@ -0,0 +1,454 @@
+/*
+ *  Copyright 2014-2022 The GmSSL Project. All Rights Reserved.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the License); you may
+ *  not use this file except in compliance with the License.
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ */
+
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <gmssl/sm2.h>
+#include <gmssl/pem.h>
+#include <gmssl/oid.h>
+#include <gmssl/asn1.h>
+#include <gmssl/error.h>
+#include <gmssl/pbkdf2.h>
+#include <gmssl/digest.h>
+#include <gmssl/sm4.h>
+#include <gmssl/rand.h>
+#include <gmssl/x509_alg.h>
+
+
+static const uint32_t oid_hmac_sm3[] = { oid_sm_algors,401,2 };
+static const size_t oid_hmac_sm3_cnt = sizeof(oid_hmac_sm3)/sizeof(oid_hmac_sm3[0]);
+
+char *pbkdf2_prf_name(int oid)
+{
+	switch (oid) {
+	case OID_hmac_sm3: return "hmac-sm3";
+	}
+	return NULL;
+}
+
+int pbkdf2_prf_from_name(const char *name)
+{
+	if (strcmp(name, "hmac-sm3") == 0) {
+		return OID_hmac_sm3;
+	}
+	return 0;
+}
+
+int pbkdf2_prf_to_der(int oid, uint8_t **out, size_t *outlen)
+{
+	size_t len = 0;
+	if (oid == -1)
+		return 0;
+
+	if (oid != OID_hmac_sm3) {
+		error_print();
+		return -1;
+	}
+	if (asn1_object_identifier_to_der(oid_hmac_sm3, oid_hmac_sm3_cnt, NULL, &len) != 1
+		|| asn1_sequence_header_to_der(len, out, outlen) != 1
+		|| asn1_object_identifier_to_der(oid_hmac_sm3, oid_hmac_sm3_cnt, out, outlen) != 1) {
+		error_print();
+		return -1;
+	}
+	return 1;
+}
+
+int pbkdf2_prf_from_der(int *oid, const uint8_t **in, size_t *inlen)
+{
+	int ret;
+	const uint8_t *d;
+	size_t dlen;
+	uint32_t nodes[32];
+	size_t nodes_cnt;
+
+	if ((ret = asn1_sequence_from_der(&d, &dlen, in, inlen)) != 1) {
+		if (ret < 0) error_print();
+		else *oid = -1;
+		return ret;
+	}
+	if (asn1_object_identifier_from_der(nodes, &nodes_cnt, &d, &dlen) != 1
+		|| asn1_object_identifier_equ(nodes, nodes_cnt, oid_hmac_sm3, oid_hmac_sm3_cnt) != 1
+		|| asn1_length_is_zero(dlen) != 1) {
+		error_print();
+		return -1;
+	}
+	*oid = OID_hmac_sm3;
+	return 1;
+}
+
+int pbkdf2_params_to_der(
+	const uint8_t *salt, size_t saltlen,
+	int iter,
+	int keylen,
+	int prf,
+	uint8_t **out, size_t *outlen)
+{
+	size_t len = 0;
+	if (asn1_octet_string_to_der(salt, saltlen, NULL, &len) != 1
+		|| asn1_int_to_der(iter, NULL, &len) != 1
+		|| asn1_int_to_der(keylen, NULL, &len) < 0
+		|| pbkdf2_prf_to_der(prf, NULL, &len) < 0
+		|| asn1_sequence_header_to_der(len, out, outlen) != 1
+		|| asn1_octet_string_to_der(salt, saltlen, out, outlen) != 1
+		|| asn1_int_to_der(iter, out, outlen) != 1
+		|| asn1_int_to_der(keylen, out, outlen) < 0
+		|| pbkdf2_prf_to_der(prf, out, outlen) < 0) {
+		error_print();
+		return -1;
+	}
+	return 1;
+}
+
+int pbkdf2_params_from_der(
+	const uint8_t **salt, size_t *saltlen,
+	int *iter,
+	int *keylen,
+	int *prf,
+	const uint8_t **in, size_t *inlen)
+{
+	int ret;
+	const uint8_t *d;
+	size_t dlen;
+
+	if ((ret = asn1_sequence_from_der(&d, &dlen, in, inlen)) != 1) {
+		if (ret < 0) error_print();
+		return ret;
+	}
+	if (asn1_octet_string_from_der(salt, saltlen, &d, &dlen) != 1
+		|| asn1_int_from_der(iter, &d, &dlen) != 1
+		|| asn1_int_from_der(keylen, &d, &dlen) < 0
+		|| pbkdf2_prf_from_der(prf, &d, &dlen) < 0
+		|| asn1_check(*saltlen > 0) != 1
+		|| asn1_check(*iter > 0) != 1
+		|| asn1_length_is_zero(dlen) != 1) {
+		error_print();
+		return -1;
+	}
+	return 1;
+}
+
+int pbkdf2_params_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen)
+{
+	int ret;
+	const uint8_t *p;
+	size_t len;
+	int val;
+
+	format_print(fp, fmt, ind, "%s\n", label);
+	ind += 4;
+
+	if (asn1_octet_string_from_der(&p, &len, &d, &dlen) != 1) goto err;
+	format_bytes(fp, fmt, ind, "salt", p, len);
+	if (asn1_int_from_der(&val, &d, &dlen) != 1) goto err;
+	format_print(fp, fmt, ind, "iterationCount: %d\n", val);
+	if ((ret = asn1_int_from_der(&val, &d, &dlen)) < 0) goto err;
+	if (ret) format_print(fp, fmt, ind, "keyLength: %d\n", val);
+	if ((ret = pbkdf2_prf_from_der(&val, &d, &dlen)) < 0) goto err;
+	if (ret) format_print(fp, fmt, ind, "prf: %s\n", pbkdf2_prf_name(val));
+	if (asn1_length_is_zero(dlen) != 1) goto err;
+	return 1;
+err:
+	error_print();
+	return -1;
+}
+
+static const uint32_t oid_pbkdf2[] = { oid_pkcs5,12 };
+static const size_t oid_pbkdf2_cnt = sizeof(oid_pbkdf2)/sizeof(oid_pbkdf2[0]);
+
+int pbkdf2_algor_to_der(
+	const uint8_t *salt, size_t saltlen,
+	int iter,
+	int keylen,
+	int prf,
+	uint8_t **out, size_t *outlen)
+{
+	size_t len = 0;
+	if (asn1_object_identifier_to_der(oid_pbkdf2, oid_pbkdf2_cnt, NULL, &len) != 1
+		|| pbkdf2_params_to_der(salt, saltlen, iter, keylen, prf, NULL, &len) != 1
+		|| asn1_sequence_header_to_der(len, out, outlen) != 1
+		|| asn1_object_identifier_to_der(oid_pbkdf2, oid_pbkdf2_cnt, out, outlen) != 1
+		|| pbkdf2_params_to_der(salt, saltlen, iter, keylen, prf, out, outlen) != 1) {
+		error_print();
+		return -1;
+	}
+	return 1;
+}
+
+int pbkdf2_algor_from_der(
+	const uint8_t **salt, size_t *saltlen,
+	int *iter,
+	int *keylen,
+	int *prf,
+	const uint8_t **in, size_t *inlen)
+{
+	int ret;
+	const uint8_t *d;
+	size_t dlen;
+	uint32_t nodes[32];
+	size_t nodes_cnt;
+
+	if ((ret = asn1_sequence_from_der(&d, &dlen, in, inlen)) != 1) {
+		if (ret < 0) error_print();
+		return ret;
+	}
+	if (asn1_object_identifier_from_der(nodes, &nodes_cnt, &d, &dlen) != 1
+		|| asn1_object_identifier_equ(nodes, nodes_cnt, oid_pbkdf2, oid_pbkdf2_cnt) != 1
+		|| pbkdf2_params_from_der(salt, saltlen, iter, keylen, prf, &d, &dlen) != 1
+		|| asn1_length_is_zero(dlen) != 1) {
+		error_print();
+		return -1;
+	}
+	return 1;
+}
+
+int pbkdf2_algor_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen)
+{
+	uint32_t nodes[32];
+	size_t nodes_cnt;
+	const uint8_t *p;
+	size_t len;
+
+	format_print(fp, fmt, ind, "%s\n", label);
+	ind += 4;
+
+	if (asn1_object_identifier_from_der(nodes, &nodes_cnt, &d, &dlen) != 1
+		|| asn1_object_identifier_equ(nodes, nodes_cnt, oid_pbkdf2, oid_pbkdf2_cnt) != 1) {
+		error_print();
+		return -1;
+	}
+	format_print(fp, fmt, ind, "algorithm: %s\n", "pbkdf2");
+	if (asn1_sequence_from_der(&p, &len, &d, &dlen) != 1) goto err;
+	pbkdf2_params_print(fp, fmt, ind, "parameters", p, len);
+	if (asn1_length_is_zero(dlen) != 1) goto err;
+	return 1;
+err:
+	error_print();
+	return -1;
+}
+
+int pbes2_enc_algor_to_der(int oid, const uint8_t *iv, size_t ivlen, uint8_t **out, size_t *outlen)
+{
+	if (oid != OID_sm4_cbc) {
+		error_print();
+		return -1;
+	}
+	if (x509_encryption_algor_to_der(oid, iv, ivlen, out, outlen) != 1) {
+		error_print();
+		return -1;
+	}
+	return 1;
+}
+
+int pbes2_enc_algor_from_der(int *oid, const uint8_t **iv, size_t *ivlen, const uint8_t **in, size_t *inlen)
+{
+	int ret;
+	if ((ret = x509_encryption_algor_from_der(oid, iv, ivlen, in, inlen)) != 1) {
+		if (ret < 0) error_print();
+		return ret;
+	}
+	if (*oid != OID_sm4_cbc) {
+		error_print();
+		return -1;
+	}
+	return 1;
+}
+
+int pbes2_enc_algor_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen)
+{
+	return x509_encryption_algor_print(fp, fmt, ind, label, d, dlen);
+}
+
+int pbes2_params_to_der(
+	const uint8_t *salt, size_t saltlen, int iter, int keylen, int prf,
+	int cipher, const uint8_t *iv, size_t ivlen,
+	uint8_t **out, size_t *outlen)
+{
+	size_t len = 0;
+	if (pbkdf2_algor_to_der(salt, saltlen, iter, keylen, prf, NULL, &len) != 1
+		|| pbes2_enc_algor_to_der(cipher, iv, ivlen, NULL, &len) != 1
+		|| asn1_sequence_header_to_der(len, out, outlen) != 1
+		|| pbkdf2_algor_to_der(salt, saltlen, iter, keylen, prf, out, outlen) != 1
+		|| pbes2_enc_algor_to_der(cipher, iv, ivlen, out, outlen) != 1) {
+		error_print();
+		return -1;
+	}
+	return 1;
+}
+
+int pbes2_params_from_der(
+	const uint8_t **salt, size_t *saltlen, int *iter, int *keylen, int *prf,
+	int *cipher, const uint8_t **iv, size_t *ivlen,
+	const uint8_t **in, size_t *inlen)
+{
+	int ret;
+	const uint8_t *d;
+	size_t dlen;
+
+	if ((ret = asn1_sequence_from_der(&d, &dlen, in, inlen)) != 1) {
+		if (ret < 0) error_print();
+		return ret;
+	}
+	if (pbkdf2_algor_from_der(salt, saltlen, iter, keylen, prf, &d, &dlen) != 1
+		|| pbes2_enc_algor_from_der(cipher, iv, ivlen, &d, &dlen) != 1
+		|| asn1_length_is_zero(dlen) != 1) {
+		error_print();
+		return -1;
+	}
+	return 1;
+}
+
+int pbes2_params_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen)
+{
+	const uint8_t *p;
+	size_t len;
+
+	format_print(fp, fmt, ind, "%s\n", label);
+	ind += 4;
+
+	if (asn1_sequence_from_der(&p, &len, &d, &dlen) != 1) goto err;
+	pbkdf2_algor_print(fp, fmt, ind, "keyDerivationFunc", p, len);
+	if (asn1_sequence_from_der(&p, &len, &d, &dlen) != 1) goto err;
+	pbes2_enc_algor_print(fp, fmt, ind, "encryptionScheme", p, len);
+	if (asn1_length_is_zero(dlen) != 1) goto err;
+	return 1;
+err:
+	error_print();
+	return -1;
+}
+
+
+static const uint32_t oid_pbes2[] = { oid_pkcs5,13 };
+static const size_t oid_pbes2_cnt = sizeof(oid_pbes2)/sizeof(oid_pbes2[0]);
+
+int pbes2_algor_to_der(
+	const uint8_t *salt, size_t saltlen, int iter, int keylen, int prf,
+	int cipher, const uint8_t *iv, size_t ivlen,
+	uint8_t **out, size_t *outlen)
+{
+	size_t len = 0;
+	if (asn1_object_identifier_to_der(oid_pbes2, oid_pbes2_cnt, NULL, &len) != 1
+		|| pbes2_params_to_der(salt, saltlen, iter, keylen, prf, cipher, iv, ivlen, NULL, &len) != 1
+		|| asn1_sequence_header_to_der(len, out, outlen) != 1
+		|| asn1_object_identifier_to_der(oid_pbes2, oid_pbes2_cnt, out, outlen) != 1
+		|| pbes2_params_to_der(salt, saltlen, iter, keylen, prf, cipher, iv, ivlen, out, outlen) != 1) {
+		error_print();
+		return -1;
+	}
+	return 1;
+}
+
+int pbes2_algor_from_der(
+	const uint8_t **salt, size_t *saltlen, int *iter, int *keylen, int *prf,
+	int *cipher, const uint8_t **iv, size_t *ivlen,
+	const uint8_t **in, size_t *inlen)
+{
+	int ret;
+	const uint8_t *d;
+	size_t dlen;
+	uint32_t nodes[32];
+	size_t nodes_cnt;
+
+	if ((ret = asn1_sequence_from_der(&d, &dlen, in, inlen)) != 1) {
+		if (ret < 0) error_print();
+		return ret;
+	}
+	if (asn1_object_identifier_from_der(nodes, &nodes_cnt, &d, &dlen) != 1
+		|| asn1_object_identifier_equ(nodes, nodes_cnt, oid_pbes2, oid_pbes2_cnt) != 1
+		|| pbes2_params_from_der(salt, saltlen, iter, keylen, prf, cipher, iv, ivlen, &d, &dlen) != 1
+		|| asn1_length_is_zero(dlen) != 1) {
+		error_print();
+		return -1;
+	}
+	return 1;
+}
+
+int pbes2_algor_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen)
+{
+	uint32_t nodes[32];
+	size_t nodes_cnt;
+	const uint8_t *p;
+	size_t len;
+
+	format_print(fp, fmt, ind, "%s\n", label);
+	ind += 4;
+
+	if (asn1_object_identifier_from_der(nodes, &nodes_cnt, &d, &dlen) != 1
+		|| asn1_object_identifier_equ(nodes, nodes_cnt, oid_pbes2, oid_pbes2_cnt) != 1)
+		goto err;
+	format_print(fp, fmt, ind, "algorithm: %s\n", "pbes2");
+	if (asn1_sequence_from_der(&p, &len, &d, &dlen) != 1) goto err;
+	pbes2_params_print(fp, fmt, ind, "parameters", p, len);
+	if (asn1_length_is_zero(dlen) != 1) goto err;
+	return 1;
+err:
+	error_print();
+	return -1;
+}
+
+int pkcs8_enced_private_key_info_to_der(
+	const uint8_t *salt, size_t saltlen, int iter, int keylen, int prf,
+	int cipher, const uint8_t *iv, size_t ivlen,
+	const uint8_t *enced, size_t encedlen,
+	uint8_t **out, size_t *outlen)
+{
+	size_t len = 0;
+	if (pbes2_algor_to_der(salt, saltlen, iter, keylen, prf, cipher, iv, ivlen, NULL, &len) != 1
+		|| asn1_octet_string_to_der(enced, encedlen, NULL, &len) != 1
+		|| asn1_sequence_header_to_der(len, out, outlen) != 1
+		|| pbes2_algor_to_der(salt, saltlen, iter, keylen, prf, cipher, iv, ivlen, out, outlen) != 1
+		|| asn1_octet_string_to_der(enced, encedlen, out, outlen) != 1) {
+		error_print();
+		return -1;
+	}
+	return 1;
+}
+
+int pkcs8_enced_private_key_info_from_der(
+	const uint8_t **salt, size_t *saltlen, int *iter, int *keylen, int *prf,
+	int *cipher, const uint8_t **iv, size_t *ivlen,
+	const uint8_t **enced, size_t *encedlen,
+	const uint8_t **in, size_t *inlen)
+{
+	int ret;
+	const uint8_t *d;
+	size_t dlen;
+
+	if ((ret = asn1_sequence_from_der(&d, &dlen, in, inlen)) != 1) {
+		if (ret < 0) error_print();
+		return ret;
+	}
+	if (pbes2_algor_from_der(salt, saltlen, iter, keylen, prf, cipher, iv, ivlen, &d, &dlen) != 1
+		|| asn1_octet_string_from_der(enced, encedlen, &d, &dlen) != 1
+		|| asn1_length_is_zero(dlen) != 1) {
+		error_print();
+		return -1;
+	}
+	return 1;
+}
+
+int pkcs8_enced_private_key_info_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen)
+{
+	const uint8_t *p;
+	size_t len;
+
+	format_print(fp, fmt, ind, "%s\n", label);
+	ind += 4;
+
+	if (asn1_sequence_from_der(&p, &len, &d, &dlen) != 1) goto err;
+	pbes2_algor_print(fp, fmt, ind, "encryptionAlgorithm", p, len);
+	if (asn1_octet_string_from_der(&p, &len, &d, &dlen) != 1) goto err;
+	format_bytes(fp, fmt, ind, "encryptedData", p, len);
+	if (asn1_length_is_zero(dlen) != 1) goto err;
+	return 1;
+err:
+	error_print();
+	return -1;
+}

+ 23 - 0
components/gmssl/src/rand.c

@@ -0,0 +1,23 @@
+/*
+ *  Copyright 2014-2022 The GmSSL Project. All Rights Reserved.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the License); you may
+ *  not use this file except in compliance with the License.
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ */
+
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <gmssl/rand.h>
+#include <gmssl/error.h>
+
+extern int luat_crypto_trng(char* buff, size_t len);
+
+int rand_bytes(uint8_t *buf, size_t len)
+{
+	luat_crypto_trng(buf, len);
+	return 1;
+}

+ 372 - 0
components/gmssl/src/sgd.h

@@ -0,0 +1,372 @@
+/*
+ *  Copyright 2014-2022 The GmSSL Project. All Rights Reserved.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the License); you may
+ *  not use this file except in compliance with the License.
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ */
+
+/*
+ * this header file is based on the standard GM/T 0006-2012
+ * Cryptographic Application Identifier Criterion Specification
+ */
+
+#ifndef SDFUTIL_SGD_H
+#define SDFUTIL_SGD_H
+
+
+#include <stdint.h>
+
+
+/* block cipher modes */
+#define SGD_ECB			0x01
+#define SGD_CBC			0x02
+#define SGD_CFB			0x04
+#define SGD_OFB			0x08
+#define SGD_MAC			0x10
+
+/* stream cipher modes */
+#define SGD_EEA3		0x01
+#define SGD_EIA3		0x02
+
+/* ciphers */
+#define SGD_SM1			0x00000100
+#define SGD_SSF33		0x00000200
+#define SGD_SM4			0x00000400
+#define SGD_ZUC			0x00000800
+
+/* ciphers with modes */
+#define SGD_SM1_ECB		(SGD_SM1|SGD_ECB)
+#define SGD_SM1_CBC		(SGD_SM1|SGD_CBC)
+#define SGD_SM1_CFB		(SGD_SM1|SGD_CFB)
+#define SGD_SM1_OFB		(SGD_SM1|SGD_OFB)
+#define SGD_SM1_MAC		(SGD_SM1|SGD_MAC)
+#define SGD_SSF33_ECB		(SGD_SSF33|SGD_ECB)
+#define SGD_SSF33_CBC		(SGD_SSF33|SGD_CBC)
+#define SGD_SSF33_CFB		(SGD_SSF33|SGD_CFB)
+#define SGD_SSF33_OFB		(SGD_SSF33|SGD_OFB)
+#define SGD_SSF33_MAC		(SGD_SSF33|SGD_MAC)
+#define SGD_SM4_ECB		(SGD_SM4|SGD_ECB)
+#define SGD_SM4_CBC		(SGD_SM4|SGD_CBC)
+#define SGD_SM4_CFB		(SGD_SM4|SGD_CFB)
+#define SGD_SM4_OFB		(SGD_SM4|SGD_OFB)
+#define SGD_SM4_MAC		(SGD_SM4|SGD_MAC)
+#define SGD_ZUC_EEA3		(SGD_ZUC|SGD_EEA3)
+#define SGD_ZUC_EIA3		(SGD_ZUC|SGD_EIA3)
+
+/* public key usage */
+#define SGD_PK_SIGN		0x0100 // FIXME: correct?        
+#define SGD_PK_DH		0x0200 // FIXME: correct?        
+#define SGD_PK_ENC		0x0400 // FIXME: correct?        
+
+/* public key types */
+#define SGD_RSA			0x00010000
+#define SGD_RSA_SIGN		(SGD_RSA|SGD_PK_SIGN) // FIXME: correct?	
+#define SGD_RSA_ENC		(SGD_RSA|SGD_PK_ENC) // FIXME: correct?		
+#define SGD_SM2			0x00020100
+#define SGD_SM2_1		0x00020200
+#define SGD_SM2_2		0x00020400
+#define SGD_SM2_3		0x00020800
+
+/* hash */
+#define SGD_SM3			0x00000001
+#define SGD_SHA1		0x00000002
+#define SGD_SHA256		0x00000004
+#define SGD_HASH_FROM		0x00000008
+#define SGD_HASH_TO		0x000000FF
+
+/* signatue schemes */
+#define SGD_SM3_RSA		(SGD_SM3|SGD_RSA)
+#define SGD_SHA1_RSA		(SGD_SHA1|SGD_RSA)
+#define SGD_SHA256_RSA		(SGD_SHA256|SGD_RSA)
+#define SGD_SM3_SM2		(SGD_SM3|SGD_SM2)
+#define SGD_SIG_FROM		0x00040000
+#define SGD_SIG_TO		0x800000FF
+
+/* data types */
+typedef char			SGD_CHAR;
+typedef char			SGD_INT8;
+typedef int16_t			SGD_INT16;
+typedef int32_t			SGD_INT32;
+typedef int64_t			SGD_INT64;
+typedef unsigned char		SGD_UCHAR;
+typedef uint8_t			SGD_UINT8;
+typedef uint16_t		SGD_UINT16;
+typedef uint32_t		SGD_UINT32;
+typedef uint64_t		SGD_UINT64;
+typedef uint32_t		SGD_RV;
+typedef void *			SGD_OBJ;
+typedef int32_t			SGD_BOOL;
+
+#define SGD_TRUE		0x00000001
+#define SGD_FALSE		0x00000000
+
+#define SGD_KEY_INDEX		0x00000101
+#define SGD_SECRET_KEY		0x00000102
+#define SGD_PUBLIC_KEY_SIGN	0x00000103
+#define SGD_PUBLIC_KEY_ENCRYPT	0x00000104
+#define SGD_PRIVATE_KEY_SIGN	0x00000105
+#define SGD_PRIVATE_KEY_ENCRYPT	0x00000106
+#define SGD_KEY_COMPONENT	0x00000107
+#define SGD_PASSWORD		0x00000108
+#define SGD_PUBLIC_KEY_CERT	0x00000109
+#define SGD_ATTRIBUTE_CERT	0x1000010A
+#define SGD_SIGNATURE_DATA	0x10000111
+#define SGD_ENVELOPE_DATA	0x10000112
+#define SGD_RANDOM_DATA		0x10000113
+#define SGD_PLAIN_DATA		0x10000114
+#define SGD_CIPHER_DATA		0x10000115
+#define SGD_DIGEST_DATA		0x10000116
+#define SGD_USER_DATA		0x10000117
+
+/* certificate */
+#define SGD_CERT_VERSION			0x00000001
+#define SGD_CERT_SERIAL				0x00000002
+#define SGD_CERT_ISSUER				0x00000005
+#define SGD_CERT_VALID_TIME			0x00000006
+#define SGD_CERT_SUBJECT			0x00000007
+#define SGD_CERT_DER_PUBLIC_KEY			0x00000008
+#define SGD_CERT_DER_EXTENSIONS			0x00000009
+#define SGD_EXT_AUTHORITYKEYIDENTIFIER_INFO	0x00000011
+#define SGD_EXT_SUBJECTKEYIDENTIFIER_INFO	0x00000012
+#define SGD_EXT_KEYUSAGE_INFO			0x00000013
+#define SGD_EXT_PRIVATEKEYUSAGEPERIOD_INFO	0x00000014
+#define SGD_EXT_CERTIFICATEPOLICIES_INFO	0x00000015
+#define SGD_EXT_POLICYMAPPINGS_INFO		0x00000016
+#define SGD_EXT_BASICCONSTRAINTS_INFO		0x00000017
+#define SGD_EXT_POLICYCONSTRAINTS_INFO		0x00000018
+#define SGD_EXT_EXTKEYUSAGE_INFO		0x00000019
+#define SGD_EXT_CRLDISTRIBUTIONPOINTS_INFO	0x0000001A
+#define SGD_EXT_NETSCAPE_CERT_TYPE_INFO		0x0000001B
+#define SGD_EXT_SELFDEFINED_EXTENSION_INFO	0x0000001C
+#define SGD_CERT_ISSUER_CN			0x00000021
+#define SGD_CERT_ISSUER_O			0x00000022
+#define SGD_CERT_ISSUER_OU			0x00000023
+#define SGD_CERT_SUBJECT_CN			0x00000031
+#define SGD_CERT_SUBJECT_O			0x00000032
+#define SGD_CERT_SUBJECT_OU			0x00000033
+#define SGD_CERT_SUBJECT_EMAIL			0x00000034
+#define SGD_CERT_NOTBEFORE_TIME			0x00000035
+#define SGD_CERT_NOTAFTER_TIME			0x00000036
+
+/* timestamp info */
+#define SGD_TIME_OF_STAMP		0x00000201
+#define SGD_CN_OF_TSSIGNER		0x00000202 /* Common Name of TS Signer */
+#define SGD_ORININAL_DATA		0x00000203
+#define SGD_CERT_OF_TSSSERVER		0x00000204
+#define SGD_GERTCHAIN_OF_TSSERVER	0x00000205
+#define SGD_SOURCE_OF_TIME		0x00000206
+#define SGD_TIME_PRECISION		0x00000207
+#define SGD_RESPONSE_TYPE		0x00000208
+#define SGD_SUBJECT_COUNTRY_OF_TSSIGNER	0x00000209
+#define SGD_SUBJECT_ORGNIZATION_OF_TSSIGNER 0x0000020A
+#define SGD_SUJECT_CITY_OF_TSSIGNER	0x0000020B
+#define SGD_SUBJECT_EMAIL_OF_TSSIGNER	0x0000020C
+
+/* single sign-on */
+#define SGD_SP_ID			0x00000001
+#define SGD_SP_USER_ID			0x00000002
+#define SGD_IDP_ID			0x00000003
+#define SGD_IDP_USER_ID			0x00000004
+
+/* data encoding */
+#define SGD_ENCODING_RAW		0x00000000
+#define SGD_ENCODING_DER		0x01000000
+#define SGD_ENCODING_BASE64		0x02000000
+#define SGD_ENCODING_PEM		0x03000000
+#define SGD_ENCODING_TXT		0x04000000
+
+/* APIs */
+#define SGD_PROTOCOL_CSP		1 /* Microsoft CryptoAPI */
+#define SGD_PROTOCOL_PKCS11		2 /* PKCS#11 */
+#define SGD_PROTOCOL_SDS		3 /* SDF API */
+#define SGD_PROTOCOL_UKEY		4 /* SKF API */
+#define SGD_PROTOCOL_CNG		5 /* Microsoft CryptoAPI Next Gen */
+#define SGD_PROTOCOL_GCS		6 /* */
+
+/* certificate validation */
+#define SGD_CRL_VERIFY			1
+#define SGD_OCSP_VEIFY			2
+
+/* role */
+#define SGD_ROLE_SUPER_MANAGER		0x00000001
+#define SGD_ROLE_MANAGER		0x00000002
+#define SGD_ROLE_AUDIT_MANAGER		0x00000003
+#define SGD_ROLE_AUDITOR		0x00000004
+#define SGD_ROLE_OPERATOR		0x00000005
+#define SGD_ROLE_USER			0x00000006
+
+/* user operations */
+#define SGD_OPERATION_SIGNIN		0x00000001
+#define SGD_OPERATION_SIGNOUT		0x00000002
+#define SGD_OPERATION_CREATE		0x00000003
+#define SGD_OPERATION_DELETE		0x00000004
+#define SGD_OPERATION_MODIFY		0x00000005
+#define SGD_OPERATION_CHG_PWD		0x00000006
+#define SGD_OPERATION_AUTHORIZATION	0x00000007
+
+/* user operation results */
+#define SGD_OPERATION_SUCCESS		0x00000000
+
+/* key types */
+#define SGD_MAIN_KEY			0x00000101
+#define SGD_DEVICE_KEYS			0x00000102
+#define SGD_USER_KEYS			0x00000103
+#define SGD_KEY				0x00000104
+#define SGD_SESSION_KEY			0x00000105
+#define SGD_PRIKEY_PASSWD		0x00000106
+#define SGD_COMPARTITION_KEY		0x00000107
+
+/* key operations */
+#define SGD_KEY_GENERATION		0x00000101
+#define SGD_KEY_DISPENSE		0x00000102
+#define SGD_KEY_IMPORT			0x00000103
+#define SGD_KEY_EXPORT			0x00000104
+#define SGD_KEY_DIVISION		0x00000105
+#define SGD_KEY_COMPOSE			0x00000106
+#define SGD_KEY_RENEWAL			0x00000107
+#define SGD_KEY_BACKUP			0x00000108
+#define SGD_KEY_RESTORE			0x00000109
+#define SGD_KEY_DESTORY			0x0000010A
+
+/* system operations */
+#define SGD_SYSTEM_INIT			0x00000201
+#define SGD_SYSTEM_START		0x00000202
+#define SGD_SYSTEM_SHUT			0x00000203
+#define SGD_SYSTEM_RESTART		0x00000204
+#define SGD_SYSTEM_QUERY		0x00000205
+#define SGD_SYSTEM_BACKUP		0x00000206
+#define SGD_SYSTEM_RESTORE		0x00000207
+
+/* device info */
+#define SGD_DEVICE_SORT			0x00000201
+#define SGD_DEVICE_TYPE			0x00000202
+#define SGD_DEVICE_NAME			0x00000203
+#define SGD_DEVICE_MANUFACTURER		0x00000204
+#define SGD_DEVICE_HARDWARE_VERSION	0x00000205
+#define SGD_DEVICE_SOFTWARE_VERSION	0x00000206
+#define SGD_DEVICE_STANDARD_VERSION	0x00000207
+#define SGD_DEVICE_SERIAL_NUMBER	0x00000208
+#define SGD_DEVICE_SUPPORT_SYMM_ALG	0x00000209
+#define SGD_DEVICE_SUPPORT_PKEY_ALG	0x0000020A
+#define SGD_DEVICE_SUPPORT_HASH_ALG	0x0000020B
+#define SGD_DEVICE_SUPPORT_STORAGE_SPACE 0x0000020C
+#define SGD_DEVICE_SUPPORT_FREE_SPACE	0x0000020D
+#define SGD_DEVICE_RUNTIME		0x0000020E
+#define SGD_DEVICE_USED_TIMES		0x0000020F
+#define SGD_DEVICE_LOCATION		0x00000210
+#define SGD_DEVICE_DESCRIPTION		0x00000211
+#define SGD_DEVICE_MANAGER_INFO		0x00000212
+#define SGD_DEVICE_MAX_DATA_SIZE	0x00000213
+
+/* device types */
+#define SGD_DEVICE_SORT_SJ		0x02000000 /* Server */
+#define SGD_DEVICE_SORT_SK		0x03000000 /* PCI-E Card */
+#define SGD_DEVICE_SORT_SM		0x04000000 /* USB-Key and SmartCard */
+
+/* device functionality */
+#define SGD_DEVICE_SORT_FE		0x00000100 /* encryption */
+#define SGD_DEVICE_SORT_FA		0x00000200 /* authentication */
+#define SGD_DEVICE_SORT_FM		0x00000300 /* key management */
+
+/* device status */
+#define SGD_STATUS_INIT			0x00000201
+#define SGD_STATUS_READY		0x00000202
+#define SGD_STATUS_EXCEPTION		0x00000203
+
+#ifdef WIN32
+#include <windows.h>
+#else
+typedef signed char		INT8;
+typedef signed short		INT16;
+typedef signed int		INT32;
+typedef unsigned char		UINT8;
+typedef unsigned short		UINT16;
+typedef unsigned int		UINT32;
+typedef long			BOOL;
+typedef UINT8			BYTE;
+typedef UINT8			CHAR;
+typedef INT16			SHORT;
+typedef UINT16			USHORT;
+# ifndef SGD_NATIVE_LONG
+typedef INT32			LONG;
+typedef UINT32			ULONG;
+# else
+typedef long			LONG;
+typedef unsigned long		ULONG;
+# endif
+typedef UINT32			UINT;
+typedef UINT16			WORD;
+typedef UINT32			DWORD;
+typedef UINT32			FLAGS;
+typedef CHAR *			LPSTR;
+typedef void *			HANDLE;
+#endif
+
+
+typedef HANDLE DEVHANDLE;
+typedef HANDLE HAPPLICATION;
+typedef HANDLE HSESSION;
+typedef HANDLE HCONTAINER;
+
+#ifndef FALSE
+#define FALSE			0x00000000
+#endif
+
+#ifndef TRUE
+#define TRUE			0x00000001
+#endif
+
+#ifdef WIN32
+#define DEVAPI __stdcall
+#else
+#define DEVAPI
+#endif
+
+#ifndef ADMIN_TYPE
+#define ADMIN_TYPE			0
+#endif
+
+#ifndef USER_TYPE
+#define USER_TYPE			1
+#endif
+
+#define MAX_RSA_MODULUS_LEN		256
+#define MAX_RSA_EXPONENT_LEN		4
+#define ECC_MAX_XCOORDINATE_BITS_LEN	512
+#define ECC_MAX_YCOORDINATE_BITS_LEN	512
+#define ECC_MAX_MODULUS_BITS_LEN	512
+
+#define MAX_IV_LEN			32
+
+#define MAX_FILE_NAME_SIZE		32
+#define MAX_FILE_CONTAINER_NAME_SIZE	64
+
+#define SECURE_NEVER_ACCOUNT		0x00000000
+#define SECURE_ADM_ACCOUNT		0x00000001
+#define SECURE_USER_ACCOUNT		0x00000010
+#define SECURE_ANYONE_ACCOUNT		0x000000FF
+
+
+/* SDF */
+
+#define RSAref_MAX_BITS			2048
+#define RSAref_MAX_LEN			((RSAref_MAX_BITS + 7) / 8)
+#define RSAref_MAX_PBITS		((RSAref_MAX_BITS + 1) / 2)
+#define RSAref_MAX_PLEN			((RSAref_MAX_PBITS + 7)/ 8)
+
+#ifdef SGD_MAX_ECC_BITS_256
+#define ECCref_MAX_BITS			256
+#else
+#define ECCref_MAX_BITS			512
+#endif
+#define ECCref_MAX_LEN			((ECCref_MAX_BITS+7) / 8)
+
+
+/* SAF */
+#define SGD_MAX_COUNT		64
+#define SGD_MAX_NAME_SIZE	256
+
+
+#endif

+ 0 - 1055
components/gmssl/src/sm2/sm2.c

@@ -1,1055 +0,0 @@
-//
-// Created by  lzj on 2017/8/15.
-//
-
-#include <sm2/sm2.h>
-#include <mbedtls/hmac_drbg.h>
-#include <mbedtls/ecp.h>
-#include <sm3/sm3.h>
-#include <mbedtls/bignum.h>
-
-#include <string.h>
-#include <time.h>
-#include <stdint.h>
-
-#define HEX_CODE 16
-#define SM3_LEN 32
-
-#if defined(MBEDTLS_PLATFORM_C)
-#include <mbedtls/platform.h>
-#else
-#include <stdlib.h>
-#define mbedtls_calloc calloc
-#define mbedtls_free free
-#endif
-
-#if defined(MBEDTLS_SELF_TEST)
-
-#ifdef ANDROID_LOG
-
-#include <android/log.h>
-#include <string.h>
-#include <malloc.h>
-#include <stdlib.h>
-#include <time.h>
-
-#define mbedtls_printf(...) __android_log_print(ANDROID_LOG_DEBUG, "SECURITY_LIBRARY", __VA_ARGS__)
-
-#else
-#define mbedtls_printf printf
-#endif // android log
-
-#endif // test end
-
-/**
- * init context and
- * set default group
- * @param ctx
- */
-int sm2_init(sm2_context *ctx)
-{
-#ifdef ECP_DP_SM2_256V1_ENABLED
-	memset(ctx, 0, sizeof(sm2_context));
-	mbedtls_ecp_point_init(&ctx->Pb);
-	mbedtls_mpi_init(&ctx->d);
-	return mbedtls_ecp_group_load(&(ctx->grp), ECP_DP_SM2_256V1);
-#else
-	return -1;
-#endif
-}
-
-/**
- *  free  context
- * @param ctx
- */
-void sm2_free(sm2_context *ctx)
-{
-	if (ctx == NULL)
-	{
-		return;
-	}
-
-	mbedtls_ecp_group_free(&ctx->grp);
-	mbedtls_ecp_point_free(&ctx->Pb);
-	mbedtls_mpi_free(&ctx->d);
-}
-
-/**
- * set private key by hex buf
- * @param ctx
- * @param buf
- * @return
- */
-int sm2_read_string_private(sm2_context *ctx, const char *buf)
-{
-	return mbedtls_mpi_read_string(&(ctx->d), HEX_CODE, buf);
-}
-
-/**
- *   set public key
- * @param ctx
- * @param x
- * @param y
- * @return
- */
-int sm2_read_string_public(sm2_context *ctx, const char *x, const char *y)
-{
-	return mbedtls_ecp_point_read_string(&(ctx->Pb), HEX_CODE, x, y);
-}
-
-/**
- *   generate key
- * @param ctx
- * @param f_rng
- * @param p_rng
- * @return
- */
-int sm2_gen_keypair(sm2_context *ctx,
-					int (*f_rng)(void *, unsigned char *, size_t), void *p_rng)
-{
-	return mbedtls_ecp_gen_keypair(&(ctx->grp), &(ctx->d), &(ctx->Pb), f_rng,
-								   p_rng);
-}
-
-/**
- *  check private key int the group
- * @param ctx
- * @return
- */
-int sm2_check_private(sm2_context *ctx)
-{
-	return mbedtls_ecp_check_privkey(&(ctx->grp), &(ctx->d));
-}
-
-/**
- * check public key int group
- * @param ctx
- * @return
- */
-int sm2_check_public(sm2_context *ctx)
-{
-	return mbedtls_ecp_check_pubkey(&(ctx->grp), &(ctx->Pb));
-}
-
-/**
- *set sm2 group by hex string param
- */
-int sm2_read_group_string(sm2_context *ctx, const char *p, const char *a,
-						  const char *b, const char *gx, const char *gy, const char *n)
-{
-	int ret;
-	static mbedtls_mpi_uint one[] = {1};
-	mbedtls_ecp_group_free(&ctx->grp);
-	MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&(ctx->grp.P), HEX_CODE, p));
-	MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&(ctx->grp.A), HEX_CODE, a));
-	MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&(ctx->grp.B), HEX_CODE, b));
-	MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&(ctx->grp.G.X), HEX_CODE, gx));
-	MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&(ctx->grp.G.Y), HEX_CODE, gy));
-	MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&(ctx->grp.N), HEX_CODE, n));
-
-	ctx->grp.G.Z.s = 1;
-	ctx->grp.G.Z.n = 1;
-	ctx->grp.G.Z.p = one;
-	ctx->grp.pbits = mbedtls_mpi_bitlen(&(ctx->grp.P));
-	ctx->grp.nbits = mbedtls_mpi_bitlen(&(ctx->grp.N));
-	ctx->grp.h = 1;
-cleanup:
-	return ret;
-}
-
-/**
- *  sm2 contest copy
- */
-int sm2_copy(sm2_context *dst, const sm2_context *src)
-{
-
-	int ret;
-	MBEDTLS_MPI_CHK(mbedtls_ecp_group_copy(&dst->grp, &src->grp));
-	MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&dst->d, &src->d));
-	MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&dst->Pb.X, &src->Pb.X));
-	MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&dst->Pb.Y, &src->Pb.Y));
-	MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&dst->Pb.Z, &src->Pb.Z));
-cleanup:
-
-	return (ret);
-}
-
-#define int_to_byte_4(b, i, u)      \
-	b[i] = (unsigned char)(u >> 8); \
-	b[i + 1] = (unsigned char)(u)
-
-#define int_to_byte_8(b, i, u)           \
-	b[i] = (unsigned char)(u >> 24);     \
-	b[i + 1] = (unsigned char)(u >> 16); \
-	b[i + 2] = (unsigned char)(u >> 8);  \
-	b[i + 3] = (unsigned char)(u)
-
-static int kdf(unsigned char *out, const unsigned char *buf, size_t buf_len,
-			   size_t klen)
-{
-	const int CT_LEN = sizeof(size_t);
-	const size_t counts = klen / SM3_LEN;
-	const size_t mod = klen % SM3_LEN;
-
-	size_t tmp_len = buf_len + CT_LEN;
-	size_t ct;
-	//buf len  + ct len ()
-	unsigned char *buf_z_ct = mbedtls_calloc(tmp_len, sizeof(unsigned char));
-	unsigned char *temp_out = mbedtls_calloc(SM3_LEN, sizeof(unsigned char));
-
-	if (buf_z_ct == NULL || temp_out == NULL)
-	{
-		return MBEDTLS_ERR_SM2_ALLOC_FAILED;
-	}
-	for (ct = 1; ct <= counts + 1; ct++)
-	{
-		memset(buf_z_ct, 0, tmp_len);
-		memcpy(buf_z_ct, buf, buf_len);
-		int_to_byte_8(buf_z_ct, buf_len, ct);
-		if (ct <= counts)
-		{
-			sm3(buf_z_ct, tmp_len, out + (ct - 1) * SM3_LEN);
-		}
-		else
-		{
-			memset(temp_out, 0, SM3_LEN);
-			sm3(buf_z_ct, tmp_len, temp_out);
-			memcpy(out + (ct - 1) * SM3_LEN, temp_out, mod);
-		}
-	}
-	mbedtls_free(buf_z_ct);
-	mbedtls_free(temp_out);
-	return 0;
-}
-
-/*byte =  x2 || y2*/
-static int x_y2byte(mbedtls_mpi *x, mbedtls_mpi *y, mbedtls_ecp_group *group,
-					unsigned char *byte, size_t *blen)
-{
-	int ret;
-	size_t tmp_len;
-	/*byte =  x2 || y2*/
-	memset(byte, 0, *blen);
-	tmp_len = mbedtls_mpi_size(&group->P);
-	// temp += x2
-	MBEDTLS_MPI_CHK(mbedtls_mpi_write_binary(x, byte, tmp_len));
-	// temp += y2
-	MBEDTLS_MPI_CHK(mbedtls_mpi_write_binary(y, byte + tmp_len, tmp_len));
-
-cleanup:
-	*blen = tmp_len * 2;
-
-	return (ret);
-}
-
-/*byte =  x2 || y2*/
-static int point2byte(mbedtls_ecp_point *point, mbedtls_ecp_group *group,
-					  unsigned char *byte, size_t *blen)
-{
-	return x_y2byte(&point->X, &point->Y, group, byte, blen);
-}
-
-/*byte = x2 || m || y2*/
-static int byte_cat(mbedtls_ecp_point *point, const unsigned char *m,
-					size_t mlen, mbedtls_ecp_group *group, unsigned char *byte,
-					size_t *blen)
-{
-	int ret;
-	size_t p_len;
-	/*byte = x2 || m || y2*/
-	memset(byte, 0, *blen);
-	p_len = mbedtls_mpi_size(&(group->P));
-	// byte += x2
-	MBEDTLS_MPI_CHK(mbedtls_mpi_write_binary(&point->X, byte, p_len));
-	//byte += m
-	memcpy(byte + p_len, m, mlen);
-	// byte += y2
-	MBEDTLS_MPI_CHK(
-		mbedtls_mpi_write_binary(&point->Y, byte + p_len + mlen, p_len));
-
-cleanup:
-	*blen = p_len * 2 + mlen;
-
-	return (ret);
-}
-
-/**
- * sm2 encrypt
- *
- */
-int sm2_do_encrypt(sm2_context *ctx, const unsigned char *buffer,
-				   size_t plen, unsigned char *out, size_t max_out_len, size_t *olen,
-				   int (*f_rng)(void *, unsigned char *, size_t), void *p_rng)
-{
-	int ret;
-	size_t max_len, c1_len, c2_len, c3_len, temp_len;
-	unsigned char *c1_buf, *c2_buf, *c3_buf, *temp;
-	int i;
-	mbedtls_mpi k;
-	mbedtls_ecp_point KG;
-	mbedtls_ecp_point KPb;
-
-	if (ctx == NULL || buffer == NULL)
-	{
-		return MBEDTLS_ERR_SM2_BAD_INPUT_DATA;
-	}
-
-	max_len = plen + 64 * 2 + 1;
-
-	c1_len = 100;
-	c1_buf = mbedtls_calloc(c1_len, sizeof(unsigned char));
-
-	c2_len = plen + 1;
-	c2_buf = mbedtls_calloc(c2_len, sizeof(unsigned char));
-
-	c3_len = SM3_LEN;
-	c3_buf = mbedtls_calloc(c3_len, sizeof(unsigned char));
-
-	temp_len = max_len;
-	temp = mbedtls_calloc(temp_len, sizeof(unsigned char));
-
-	if (c1_buf == NULL || c2_buf == NULL || c3_buf == NULL || temp == NULL)
-	{
-		return MBEDTLS_ERR_MPI_ALLOC_FAILED;
-	}
-
-	mbedtls_mpi_init(&k);
-	mbedtls_ecp_point_init(&KG);
-	mbedtls_ecp_point_init(&KPb);
-
-	do
-	{
-		size_t n_size, tmp_len;
-		int iter;
-		/* generate rand k  from range n */
-		/* rand k in [1, n-1] */
-		n_size = (ctx->grp.nbits + 7) / 8;
-		MBEDTLS_MPI_CHK(mbedtls_mpi_fill_random(&k, n_size, f_rng, p_rng));
-		MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&k, &k, &ctx->grp.N));
-		// MBEDTLS_MPI_CHK(rand(&k, &(ctx->grp.N)));
-
-		/* compute ephem_point [k]G = (x1, y1)   to KG */
-		MBEDTLS_MPI_CHK(
-			mbedtls_ecp_mul(&(ctx->grp), &KG, &k, &(ctx->grp.G), NULL, NULL));
-		tmp_len = 0;
-		memset(c1_buf, 0, c1_len);
-		MBEDTLS_MPI_CHK(
-			mbedtls_ecp_point_write_binary(&(ctx->grp), &KG, MBEDTLS_ECP_PF_UNCOMPRESSED, &tmp_len, c1_buf, c1_len));
-		c1_len = tmp_len;
-		tmp_len = 0;
-
-		/* compute [k]PukeyB = [k](XB,YB) = (x2,y2)*/
-		MBEDTLS_MPI_CHK(
-			mbedtls_ecp_mul(&(ctx->grp), &KPb, &k, &(ctx->Pb), NULL, NULL));
-
-		/*temp =  x2 || y2*/
-		MBEDTLS_MPI_CHK(point2byte(&KPb, &(ctx->grp), temp, &temp_len));
-
-		/* compute t = KDF(x2 || y2, klen) */
-		MBEDTLS_MPI_CHK(kdf(c2_buf, temp, temp_len, plen));
-		temp_len = max_len;
-
-		// check :if(t == 0) -> return to 1st step
-
-		for (iter = 0; iter < (int)plen; iter++)
-		{
-			if (c2_buf[iter] != 0)
-				break;
-		}
-		if ((int)plen != iter)
-			break;
-
-	} while (1);
-
-	/* cipher_text = t xor M */
-
-	for (i = 0; i < (int)plen; i++)
-	{
-		c2_buf[i] ^= buffer[i];
-	}
-	c2_len = plen;
-
-	/*compute C3 = HASH(x2|| M || y2)*/
-	/*temp buf = x2 || m || y2*/
-	MBEDTLS_MPI_CHK(byte_cat(&KPb, buffer, plen, &(ctx->grp), temp, &temp_len));
-
-	//sm3 temp
-	sm3(temp, temp_len, c3_buf);
-
-	if (max_out_len < c1_len + c2_len + c3_len || NULL == out)
-	{
-		ret = MBEDTLS_ERR_SM2_OUTPUT_TOO_LARGE;
-		goto cleanup;
-	}
-
-	memset(out, 0, max_out_len);
-	memcpy(out, c1_buf, c1_len);
-	memcpy(out + c1_len, c2_buf, c2_len);
-	memcpy(out + c1_len + c2_len, c3_buf, c3_len);
-
-cleanup:
-	*olen = c1_len + c2_len + c3_len;
-
-	mbedtls_mpi_free(&k);
-	mbedtls_ecp_point_free(&KG);
-	mbedtls_ecp_point_free(&KPb);
-	mbedtls_free(temp);
-	mbedtls_free(c1_buf);
-	mbedtls_free(c2_buf);
-	mbedtls_free(c3_buf);
-
-	return (ret);
-}
-
-/**
- * sm2 decrypt
- *
- */
-int sm2_do_decrypt(sm2_context *ctx, const unsigned char *cipher, size_t clen,
-				   unsigned char *out, size_t max_out_len, size_t *olen)
-{
-	int ret;
-	size_t i;
-	size_t temp_len, c1_len, c3_len, c2_len;
-	unsigned char *temp, *c1_buf, *c3_buf, *c2_buf;
-	mbedtls_ecp_point P_1;
-	mbedtls_ecp_point P_2;
-
-	//presume the input data : [C1(65 Byte)][C2(unknown length)][C3(32 Byte)]
-	if (NULL == cipher || 98 > clen)
-	{
-		return -MBEDTLS_ERR_SM2_BAD_INPUT_DATA;
-	}
-
-	temp_len = clen;
-	temp = mbedtls_calloc(temp_len, sizeof(unsigned char));
-	c1_len = 65;
-	c1_buf = mbedtls_calloc(c1_len, sizeof(unsigned char));
-	c3_len = SM3_LEN;
-	c3_buf = mbedtls_calloc(c3_len, sizeof(unsigned char));
-	c2_len = clen - c1_len - c3_len;
-	c2_buf = mbedtls_calloc(c2_len, sizeof(unsigned char));
-
-	if (temp == NULL || c1_buf == NULL || c3_buf == NULL || c2_buf == NULL)
-	{
-		return MBEDTLS_ERR_SM2_ALLOC_FAILED;
-	}
-
-	mbedtls_ecp_point_init(&P_2);
-	mbedtls_ecp_point_init(&P_1);
-
-	memcpy(c1_buf, cipher, c1_len);
-
-	/*get c1 point x1,y1  to P_1*/
-	MBEDTLS_MPI_CHK(
-		mbedtls_ecp_point_read_binary(&(ctx->grp), &P_1, c1_buf, c1_len));
-
-	/* check c1 */
-	MBEDTLS_MPI_CHK(mbedtls_ecp_check_pubkey(&(ctx->grp), &P_1));
-
-	/* P_2 = dA*C1 = (x2,y2) */
-	MBEDTLS_MPI_CHK(
-		mbedtls_ecp_mul(&(ctx->grp), &P_2, &(ctx->d), &P_1, NULL, NULL));
-
-	/* t= KDF(x2||y2, klen)*/
-	/*temp =  x2 || y2 */
-	MBEDTLS_MPI_CHK(point2byte(&P_2, &(ctx->grp), temp, &temp_len));
-
-	/* compute t = KDF(x2 || y2, klen) */
-	MBEDTLS_MPI_CHK(kdf(c2_buf, temp, temp_len, c2_len));
-
-	/*check  t !=0;*/
-
-	for (i = 0; i < c2_len; i++)
-	{
-		if (c2_buf[i] != 0)
-			break;
-	}
-	if (c2_len == i)
-	{
-		ret = MBEDTLS_ERR_SM2_BAD_INPUT_DATA;
-		goto cleanup;
-	}
-
-	/* m` = t xor c2 */
-	for (i = 0; i < c2_len; i++)
-	{
-		c2_buf[i] ^= cipher[c1_len + i];
-	}
-
-	/*compute u = HASH(x2|| M` || y2)*/
-	/*temp buf = x2 || m` || y2*/
-	MBEDTLS_MPI_CHK(
-		byte_cat(&P_2, c2_buf, c2_len, &(ctx->grp), temp, &temp_len));
-
-	sm3(temp, temp_len, c3_buf);
-
-	for (i = 0; i < c3_len; i++)
-	{
-		if (c3_buf[i] != (cipher + c1_len + c2_len)[i])
-		{
-			ret = MBEDTLS_ERR_SM2_PRIVATE_FAILED;
-			goto cleanup;
-		}
-	}
-
-	if (max_out_len < c2_len || NULL == out)
-	{
-		ret = MBEDTLS_ERR_SM2_OUTPUT_TOO_LARGE;
-		goto cleanup;
-	}
-
-	memset(out, 0, max_out_len);
-	memcpy(out, c2_buf, c2_len);
-
-cleanup:
-	*olen = c2_len;
-
-	mbedtls_ecp_point_free(&P_1);
-	mbedtls_ecp_point_free(&P_2);
-	mbedtls_free(c1_buf);
-	mbedtls_free(c2_buf);
-	mbedtls_free(c3_buf);
-
-	return (ret);
-}
-
-/**
- *
- * sm2 sign byte e
- */
-int sm2_do_sign(sm2_context *ctx, const unsigned char *dgst, size_t dgstlen,
-				unsigned char *out, size_t max_out_len, size_t *olen,
-				int (*f_rng)(void *, unsigned char *, size_t), void *p_rng)
-{
-	int ret;
-	mbedtls_mpi e;
-	mbedtls_mpi k;
-	mbedtls_mpi r;
-	mbedtls_mpi s;
-	mbedtls_mpi tmp;
-	mbedtls_mpi tmp_2;
-
-	mbedtls_ecp_point KG;
-
-	mbedtls_mpi_init(&e);
-	mbedtls_mpi_init(&k);
-	mbedtls_mpi_init(&r);
-	mbedtls_mpi_init(&s);
-	mbedtls_mpi_init(&tmp);
-	mbedtls_mpi_init(&tmp_2);
-
-	mbedtls_ecp_point_init(&KG);
-
-	/* convert dgst to e  : e = h(m)  */
-	MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(&e, dgst, dgstlen));
-
-	do
-	{
-		/* generate rand k  from range n*/
-		size_t n_size = (ctx->grp.nbits + 7) / 8;
-		MBEDTLS_MPI_CHK(mbedtls_mpi_fill_random(&k, n_size, f_rng, p_rng));
-		MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&k, &k, &ctx->grp.N));
-
-		/*KG = [K]G = (x1,y1)*/
-		MBEDTLS_MPI_CHK(
-			mbedtls_ecp_mul(&(ctx->grp), &KG, &k, &(ctx->grp.G), NULL, NULL));
-
-		/*r = (e + x1) mod n*/
-		/* tmp = e + x1 */
-		MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(&tmp, &e, &KG.X));
-		MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&r, &tmp, &(ctx->grp.N)));
-
-		/* r !=0 and r + k != n*/
-		if (mbedtls_mpi_cmp_int(&r, 0) == 0)
-		{
-			continue;
-		}
-		else
-		{
-			mbedtls_mpi_free(&tmp);
-			MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(&tmp, &r, &k));
-			if (mbedtls_mpi_cmp_mpi(&tmp, &(ctx->grp.N)) == 0)
-			{
-				continue;
-			}
-		}
-
-		/* s = ((1 + d)^-1 * (k - rd)) mod n
-		 * s = (((1 + d)^-1 mod n) *  ((k - rd) mod n) ) mod n
-		 */
-
-		/*((1 + d)^-1 mod n)*/
-		mbedtls_mpi_free(&tmp);
-		MBEDTLS_MPI_CHK(mbedtls_mpi_add_int(&tmp, &ctx->d, 1));
-		MBEDTLS_MPI_CHK(mbedtls_mpi_inv_mod(&s, &tmp, &(ctx->grp.N)));
-
-		/* ((k - rd) mod n) */
-		/* tmp = rd */
-		mbedtls_mpi_init(&tmp);
-		MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(&tmp, &r, (&ctx->d)));
-		/* tmp_2 = k - rd */
-		MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&tmp_2, &k, &tmp));
-		/* tmp_2 mod n*/
-		mbedtls_mpi_free(&tmp);
-		MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&tmp, &tmp_2, &(ctx->grp.N)));
-
-		/* tmp_2 = ((1 + d)^-1 mod n) *  ((k - rd) mod n) */
-		mbedtls_mpi_free(&tmp_2);
-		MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(&tmp_2, &s, &tmp));
-		/* s = tmp_2 mod n*/
-		mbedtls_mpi_free(&s);
-		MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&s, &tmp_2, &(ctx->grp.N)));
-
-		if (mbedtls_mpi_cmp_int(&s, 0) == 0)
-		{
-			continue;
-		}
-		else
-		{
-			break;
-		}
-
-	} while (1);
-
-	if (max_out_len < SM3_LEN * 2)
-	{
-		ret = MBEDTLS_ERR_SM2_OUTPUT_TOO_LARGE;
-		goto cleanup;
-	}
-	*olen = max_out_len;
-	MBEDTLS_MPI_CHK(x_y2byte(&r, &s, &(ctx->grp), out, olen));
-
-cleanup:
-	mbedtls_mpi_free(&e);
-	mbedtls_mpi_free(&k);
-	mbedtls_mpi_free(&r);
-	mbedtls_mpi_free(&s);
-	mbedtls_mpi_free(&tmp);
-	mbedtls_mpi_free(&tmp_2);
-	mbedtls_ecp_point_free(&KG);
-	return (ret);
-}
-
-/**
- * sm2 sign verify byte e
- *
- */
-int sm2_do_verify(sm2_context *ctx, const unsigned char *message, size_t msglen,
-				  const unsigned char *dgst, size_t dgstlen)
-{
-	int ret;
-	mbedtls_mpi r;
-	mbedtls_mpi s;
-	mbedtls_mpi t;
-	mbedtls_mpi tmp;
-
-	mbedtls_ecp_point pointG;
-	if (dgstlen < SM3_LEN * 2)
-	{
-		return MBEDTLS_ERR_SM2_BAD_INPUT_DATA;
-	}
-
-	mbedtls_mpi_init(&r);
-	mbedtls_mpi_init(&s);
-	mbedtls_mpi_init(&t);
-	mbedtls_mpi_init(&tmp);
-
-	mbedtls_ecp_point_init(&pointG);
-
-	/*init r and s from byte*/
-	mbedtls_mpi_read_binary(&r, dgst, SM3_LEN);
-	mbedtls_mpi_read_binary(&s, dgst + SM3_LEN, SM3_LEN);
-
-	/* check r, s in [1, n-1]*/
-	if (mbedtls_mpi_cmp_int(&r, 1) == -1 || mbedtls_mpi_cmp_int(&s, 1) == -1 || mbedtls_mpi_cmp_mpi(&r, &(ctx->grp.N)) == 1 || mbedtls_mpi_cmp_mpi(&s, &(ctx->grp.N)) == 1)
-	{
-		ret = MBEDTLS_ERR_SM2_BAD_INPUT_DATA;
-		goto cleanup;
-	}
-
-	/*  t = (r + s) mod n  */
-	/* tmp = r + s*/
-	MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(&tmp, &r, &s));
-	MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&t, &tmp, &(ctx->grp.N)));
-
-	/* check t  != 0 */
-	if (mbedtls_mpi_cmp_int(&t, 0) == 0)
-	{
-		ret = MBEDTLS_ERR_SM2_BAD_INPUT_DATA;
-		goto cleanup;
-	}
-
-	/* compute pointG= (x, y) = sG + tP, P is pub_key */
-	MBEDTLS_MPI_CHK(
-		mbedtls_ecp_muladd(&(ctx->grp), &pointG, &s, &(ctx->grp.G), &t,
-						   &(ctx->Pb)));
-
-	/* tmp <- R = (e + x1) mod n  ;x1 in pointG */
-	/* t <- e */
-	mbedtls_mpi_free(&t);
-	MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(&t, message, msglen));
-	/* s <- e + x1 */
-	mbedtls_mpi_free(&s);
-	MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(&s, &t, &(pointG.X)));
-	/*tmp <- R = s mod n*/
-	mbedtls_mpi_free(&tmp);
-	MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&tmp, &s, &(ctx->grp.N)));
-
-	/*tmp (R) = r ?*/
-	if (mbedtls_mpi_cmp_mpi(&tmp, &r) != 0)
-	{
-		ret = MBEDTLS_ERR_SM2_VERIFY_FAILED;
-	}
-
-cleanup:
-
-	mbedtls_mpi_free(&r);
-	mbedtls_mpi_free(&s);
-	mbedtls_mpi_free(&t);
-	mbedtls_mpi_free(&tmp);
-
-	mbedtls_ecp_point_free(&pointG);
-	return (ret);
-}
-
-/**
- *  generate the e   e = H(m)
- */
-int sm2_z_generate(sm2_context *ctx, const char *id, size_t idlen,
-				   const char *message, size_t msglen, unsigned char *out)
-{
-
-	int ret;
-	size_t hasg_len = SM3_LEN + msglen;
-	unsigned char *hash = mbedtls_calloc(hasg_len, sizeof(unsigned char));
-
-	size_t len_idlen = 2;
-	size_t p_len = mbedtls_mpi_size(&(ctx->grp.P));
-	size_t z_len = len_idlen + idlen + p_len * 6;
-	unsigned char *z_buf = mbedtls_calloc(z_len, sizeof(unsigned char));
-
-	if (hash == NULL || z_buf == NULL)
-	{
-		return MBEDTLS_ERR_SM2_ALLOC_FAILED;
-	}
-
-	/* z += ENTLa */
-	int_to_byte_4(z_buf, 0, idlen * 8);
-	/* z += id*/
-	memcpy(z_buf + len_idlen, id, idlen);
-	/* z += a*/
-	MBEDTLS_MPI_CHK(
-		mbedtls_mpi_write_binary(&(ctx->grp.A), z_buf + len_idlen + idlen,
-								 p_len));
-	/* z += b*/
-	MBEDTLS_MPI_CHK(
-		mbedtls_mpi_write_binary(&(ctx->grp.B),
-								 z_buf + len_idlen + idlen + p_len, p_len));
-	/* z += gx*/
-	MBEDTLS_MPI_CHK(
-		mbedtls_mpi_write_binary(&(ctx->grp.G.X),
-								 z_buf + len_idlen + idlen + p_len * 2, p_len));
-	/* z +=gy*/
-	MBEDTLS_MPI_CHK(
-		mbedtls_mpi_write_binary(&(ctx->grp.G.Y),
-								 z_buf + len_idlen + idlen + p_len * 3, p_len));
-	/* z += pk.x*/
-	MBEDTLS_MPI_CHK(
-		mbedtls_mpi_write_binary(&(ctx->Pb.X),
-								 z_buf + len_idlen + idlen + p_len * 4, p_len));
-	/* z += pk.y*/
-	MBEDTLS_MPI_CHK(
-		mbedtls_mpi_write_binary(&(ctx->Pb.Y),
-								 z_buf + len_idlen + idlen + p_len * 5, p_len));
-	/*sm3 z*/
-	sm3(z_buf, z_len, hash);
-
-	memcpy(hash + SM3_LEN, message, msglen);
-
-	/*h(m)*/
-	sm3(hash, hasg_len, out);
-
-cleanup:
-	mbedtls_free(hash);
-	mbedtls_free(z_buf);
-
-	return (ret);
-}
-
-/**
- *  sm2 sign
- */
-int sm2_do_id_sign(sm2_context *ctx, const char *id, size_t idlen,
-				   const char *message, size_t msglen, unsigned char *out,
-				   size_t max_out_len, size_t *olen, int (*f_rng)(void *, unsigned char *, size_t), void *p_rng)
-{
-
-	int ret;
-	unsigned char *hash = mbedtls_calloc(SM3_LEN, sizeof(unsigned char));
-	if (hash == NULL)
-	{
-		return MBEDTLS_ERR_SM2_ALLOC_FAILED;
-	}
-	MBEDTLS_MPI_CHK(sm2_z_generate(ctx, id, idlen, message, msglen, hash));
-	MBEDTLS_MPI_CHK(
-		sm2_do_sign(ctx, hash, SM3_LEN, out, max_out_len, olen, f_rng, p_rng));
-
-cleanup:
-	mbedtls_free(hash);
-	return (ret);
-}
-
-/**
- *   sm2 sign verify
- */
-int sm2_do_id_verify(sm2_context *ctx, const char *id, size_t idlen,
-					 const char *message, size_t msglen, const unsigned char *dgst,
-					 size_t dgstlen)
-{
-	int ret;
-	unsigned char *hash = mbedtls_calloc(SM3_LEN, sizeof(unsigned char));
-	if (hash == NULL)
-	{
-		return MBEDTLS_ERR_SM2_ALLOC_FAILED;
-	}
-	MBEDTLS_MPI_CHK(sm2_z_generate(ctx, id, idlen, message, msglen, hash));
-	MBEDTLS_MPI_CHK(sm2_do_verify(ctx, hash, SM3_LEN, dgst, dgstlen));
-
-cleanup:
-	mbedtls_free(hash);
-	return (ret);
-}
-
-/**
- * test
- */
-
-#if defined(MBEDTLS_SM2_SELF_TEST)
-
-#define STR_LEN 300
-#define PARAM_LEN 64
-
-#define PP "8542D69E4C044F18E8B92435BF6FF7DE457283915C45517D722EDB8B08F1DFC3"
-#define PA "787968B4FA32C3FD2417842E73BBFEFF2F3C848B6831D7E0EC65228B3937E498"
-#define PB "63E4C6D3B23B0C849CF84241484BFE48F61D59A5B16BA06E6E12D1DA27C5249A"
-#define PGX "421DEBD61B62EAB6746434EBC3CC315E32220B3BADD50BDC4C4E6C147FEDD43D"
-#define PGY "0680512BCBB42C07D47349D2153B70C4E5D7FDFCBFA36EA1A85841B9E46E09A2"
-#define PN "8542D69E4C044F18E8B92435BF6FF7DD297720630485628D5AE74EE7C32E79B7"
-
-static int myrand(void *ctx, unsigned char *msg, size_t size)
-{
-	mbedtls_mpi k;
-	mbedtls_mpi_init(&k);
-	mbedtls_mpi_read_string(&k, HEX_CODE,
-							"4C62EEFD6ECFC2B95B92FD6C3D9575148AFA17425546D49018E5388D49DD7B4F");
-	mbedtls_mpi_write_binary(&k, msg, size);
-	mbedtls_mpi_free(&k);
-	return 0;
-}
-
-static int signrand(void *ctx, unsigned char *msg, size_t size)
-{
-	mbedtls_mpi k;
-	if (ctx != NULL)
-	{
-		mbedtls_mpi_init(&k);
-		mbedtls_mpi_read_string(&k, HEX_CODE,
-								"6CB28D99385C175C94F94E934817663FC176D925DD72B727260DBAAE1FB2F96F");
-		mbedtls_mpi_write_binary(&k, msg, size);
-		mbedtls_mpi_free(&k);
-	}
-
-	return 0;
-}
-
-const char d1[] =
-	"1649AB77A00637BD5E2EFE283FBF353534AA7F7CB89463F208DDBC2920BB0DA0";
-const char d2[] =
-	"128B2FA8BD433C6C068C8D803DFF79792A519A55171B1B650C23661D15897263";
-
-const char pk1x[] =
-	"435B39CCA8F3B508C1488AFC67BE491A0F7BA07E581A0E4849A5CF70628A7E0A";
-const char pk1y[] =
-	"75DDBA78F15FEECB4C7895E2C1CDF5FE01DEBB2CDBADF45399CCF77BBA076A42";
-const char pk2x[] =
-	"0AE4C7798AA0F119471BEE11825BE46202BB79E2A5844495E97C04FF4DF2548A";
-const char pk2y[] =
-	"7C0240F88F1CD4E16352A73C17B7F16F07353E53A176D684A9FE0C6BB798E857";
-
-int mbedtls_sm2_self_test(int verbose)
-{
-
-	unsigned char *out = mbedtls_calloc(STR_LEN, sizeof(unsigned char));
-	unsigned char *out2 = mbedtls_calloc(STR_LEN, sizeof(unsigned char));
-
-	int ret = 0;
-	size_t olen = 0, olen2 = 0;
-	sm2_context sm2;
-	sm2_init(&sm2);
-
-	/**
-	 *   not advice to set the group
-	 *   but in here we just to test ,so set the test group param.
-	 *   commonly we do not set the group;
-	 *   because use the default group
-	 *   \see sm2_init(sm2_context * context)
-	 */
-	ret = sm2_read_group_string(&sm2, PP, PA, PB, PGX, PGY, PN);
-	if (ret != 0)
-	{
-		if (verbose > 0)
-		{
-			mbedtls_printf("sm2 init group failed:");
-		}
-		goto cleanup;
-	}
-
-	/**
-	 *  encrypt and decrypt
-	 */
-	if (verbose == 1)
-	{
-		const char *str = "encryption standard";
-		mbedtls_printf("sm2 encrypt start:");
-
-		//set key
-		sm2_read_string_private(&sm2, d1);
-		sm2_read_string_public(&sm2, pk1x, pk1y);
-
-		/**
-		 * here use the test rand k so use myrand
-		 */
-		ret = sm2_do_encrypt(&sm2, (const unsigned char *)str, strlen(str), out, STR_LEN, &olen,
-							 myrand, NULL);
-
-		if (ret == 0)
-		{
-			mbedtls_printf("sm2 encrypt passed.");
-		}
-		else
-		{
-			mbedtls_printf("sm2 encrypt failed.");
-			goto cleanup;
-		}
-
-		mbedtls_printf("sm2 decrypt start:");
-
-		ret = sm2_do_decrypt(&sm2, out, olen, out2, STR_LEN, &olen2);
-
-		if (ret == 0 && strcmp(str, (const char *)out2) == 0)
-		{
-
-			mbedtls_printf("sm2 decrypt passed.");
-		}
-		else
-		{
-
-			mbedtls_printf("sm2 decrypt failed.");
-			goto cleanup;
-		}
-	}
-	else if (verbose == 2)
-	{
-		//sign or verify
-		const char *str = "message digest";
-		const char *id = "ALICE123@YAHOO.COM";
-
-		mbedtls_printf("sm2 sign start:");
-		//set key
-		sm2_read_string_private(&sm2, d2);
-		sm2_read_string_public(&sm2, pk2x, pk2y);
-
-		/**
-		 * here use the test rand k so use signrand
-		 */
-		ret = sm2_do_id_sign(&sm2, id, strlen(id), str, strlen(str), out,
-							 STR_LEN, &olen, signrand, NULL);
-
-		if (ret == 0)
-		{
-			mbedtls_printf("sm2 sign passed.");
-		}
-		else
-		{
-			mbedtls_printf("sm2 sign failed.");
-			goto cleanup;
-		}
-
-		mbedtls_printf("sm2 sign verify start:");
-
-		ret = sm2_do_id_verify(&sm2, id, strlen(id), str, strlen(str), out,
-							   olen);
-		if (ret == 0)
-		{
-			mbedtls_printf("sm2 verify passed.");
-		}
-		else
-		{
-			mbedtls_printf("sm2 verify failed.");
-			goto cleanup;
-		}
-	}
-	else if (verbose == 3)
-	{
-
-		//        other test
-		mbedtls_printf("sm2  key generate start:\n");
-
-		sm2_free(&sm2);
-		sm2_init(&sm2);
-
-		// generate key test
-		ssl_random_context random_ctx;
-
-		ssl_random_init(&random_ctx);
-		ssl_random_seed(&random_ctx, NULL, 0);
-		ret = sm2_gen_keypair(&sm2, ssl_random_rand, &random_ctx);
-		ssl_random_free(&random_ctx);
-
-		if (ret == 0 && mbedtls_mpi_size(&sm2.d) > 0)
-		{
-			mbedtls_printf("sm2 key generate passed.\n");
-			memset(out, 0, STR_LEN);
-			mbedtls_mpi_write_binary(&sm2.d, out, 32);
-
-			mbedtls_printf("private key is : \n");
-			int i = 0;
-			for (i = 0; i < 32; i++)
-				mbedtls_printf("%02x", out[i]);
-			mbedtls_printf("\n");
-
-			mbedtls_printf("public key is \n");
-
-			memset(out, 0, STR_LEN);
-			mbedtls_mpi_write_binary(&sm2.Pb.X, out, 32);
-			for (i = 0; i < 32; i++)
-				mbedtls_printf("%02x", out[i]);
-			mbedtls_printf("\n");
-			memset(out, 0, STR_LEN);
-			mbedtls_mpi_write_binary(&sm2.Pb.Y, out, 32);
-			for (i = 0; i < 32; i++)
-				mbedtls_printf("%02x", out[i]);
-			mbedtls_printf("\n");
-			memset(out, 0, STR_LEN);
-			mbedtls_mpi_write_binary(&sm2.Pb.Z, out, 32);
-			for (i = 0; i < 32; i++)
-				mbedtls_printf("%02x", out[i]);
-			mbedtls_printf("\n");
-		}
-		else
-		{
-			mbedtls_printf("sm2 generate failed. %d", ret);
-			goto cleanup;
-		}
-	}
-
-cleanup:
-	sm2_free(&sm2);
-	mbedtls_free(out);
-	mbedtls_free(out2);
-
-	return ret;
-}
-
-#endif // test

+ 1351 - 0
components/gmssl/src/sm2_alg.c

@@ -0,0 +1,1351 @@
+/*
+ *  Copyright 2014-2022 The GmSSL Project. All Rights Reserved.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the License); you may
+ *  not use this file except in compliance with the License.
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ */
+
+
+
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <gmssl/sm2.h>
+#include <gmssl/mem.h>
+#include <gmssl/asn1.h>
+#include <gmssl/rand.h>
+#include <gmssl/error.h>
+#include <gmssl/endian.h>
+
+
+#define sm2_print_bn(label,a) sm2_bn_print(stderr,0,0,label,a) // 这个不应该放在这里,应该放在测试文件中
+
+
+
+const SM2_BN SM2_P = {
+	0xffffffff, 0xffffffff, 0x00000000, 0xffffffff,
+	0xffffffff, 0xffffffff, 0xffffffff, 0xfffffffe,
+};
+
+const SM2_BN SM2_B = {
+	0x4d940e93, 0xddbcbd41, 0x15ab8f92, 0xf39789f5,
+	0xcf6509a7, 0x4d5a9e4b, 0x9d9f5e34, 0x28e9fa9e,
+};
+
+const SM2_JACOBIAN_POINT _SM2_G = {
+	{
+	0x334c74c7, 0x715a4589, 0xf2660be1, 0x8fe30bbf,
+	0x6a39c994, 0x5f990446, 0x1f198119, 0x32c4ae2c,
+	},
+	{
+	0x2139f0a0, 0x02df32e5, 0xc62a4740, 0xd0a9877c,
+	0x6b692153, 0x59bdcee3, 0xf4f6779c, 0xbc3736a2,
+	},
+	{
+	1, 0, 0, 0, 0, 0, 0, 0,
+	},
+};
+const SM2_JACOBIAN_POINT *SM2_G = &_SM2_G;
+
+const SM2_BN SM2_N = {
+	0x39d54123, 0x53bbf409, 0x21c6052b, 0x7203df6b,
+	0xffffffff, 0xffffffff, 0xffffffff, 0xfffffffe,
+};
+
+// u = (p - 1)/4, u + 1 = (p + 1)/4
+const SM2_BN SM2_U_PLUS_ONE = {
+	0x00000000, 0x40000000, 0xc0000000, 0xffffffff,
+	0xffffffff, 0xffffffff, 0xbfffffff, 0x3fffffff,
+};
+
+const SM2_BN SM2_ONE = {1,0,0,0,0,0,0,0};
+const SM2_BN SM2_TWO = {2,0,0,0,0,0,0,0};
+const SM2_BN SM2_THREE = {3,0,0,0,0,0,0,0};
+
+
+
+int sm2_bn_check(const SM2_BN a)
+{
+	int err = 0;
+	int i;
+	for (i = 0; i < 8; i++) {
+		if (a[i] > 0xffffffff) {
+			fprintf(stderr, "%s %d: error\n", __FILE__, __LINE__);
+			err++;
+		}
+	}
+	if (err)
+		return -1;
+	else	return 1;
+}
+
+int sm2_bn_is_zero(const SM2_BN a)
+{
+	int i;
+	for (i = 0; i < 8; i++) {
+		if (a[i] != 0)
+			return 0;
+	}
+	return 1;
+}
+
+int sm2_bn_is_one(const SM2_BN a)
+{
+	int i;
+	if (a[0] != 1)
+		return 0;
+	for (i = 1; i < 8; i++) {
+		if (a[i] != 0)
+			return 0;
+	}
+	return 1;
+}
+
+void sm2_bn_to_bytes(const SM2_BN a, uint8_t out[32])
+{
+	int i;
+	uint8_t *p = out;
+
+	/*
+	fprintf(stderr, "sm2_bn_to_bytes:\n");
+	for (i = 0; i < 8; i++) {
+		fprintf(stderr, "%016lx ", a[i]);
+	}
+	fprintf(stderr, "\n");
+	*/
+
+	for (i = 7; i >= 0; i--) {
+		uint32_t ai = (uint32_t)a[i];
+		PUTU32(out, ai);
+		out += sizeof(uint32_t);
+	}
+
+	/*
+	for (i = 0; i < 32; i++) {
+		fprintf(stderr, "%02X ", p[i]);
+	}
+	*/
+
+}
+
+void sm2_bn_from_bytes(SM2_BN r, const uint8_t in[32])
+{
+	int i;
+	for (i = 7; i >= 0; i--) {
+		r[i] = GETU32(in);
+		in += sizeof(uint32_t);
+	}
+}
+
+static int hexchar2int(char c)
+{
+	if      ('0' <= c && c <= '9') return c - '0';
+	else if ('a' <= c && c <= 'f') return c - 'a' + 10;
+	else if ('A' <= c && c <= 'F') return c - 'A' + 10;
+	else return -1;
+}
+
+static int hex2bin(const char *in, size_t inlen, uint8_t *out)
+{
+	int c;
+	if (inlen % 2)
+		return -1;
+
+	while (inlen) {
+		if ((c = hexchar2int(*in++)) < 0)
+			return -1;
+		*out = (uint8_t)c << 4;
+		if ((c = hexchar2int(*in++)) < 0)
+			return -1;
+		*out |= (uint8_t)c;
+		inlen -= 2;
+		out++;
+	}
+	return 1;
+}
+
+// void sm2_bn_to_hex(const SM2_BN a, char hex[64])
+// {
+// 	int i;
+// 	for (i = 7; i >= 0; i--) {
+// 		int len;
+// 		len = sprintf(hex, "%08x", (uint32_t)a[i]);
+// 		assert(len == 8);
+// 		hex += 8;
+// 	}
+// }
+
+int sm2_bn_from_hex(SM2_BN r, const char hex[64])
+{
+	uint8_t buf[32];
+	if (hex2bin(hex, 64, buf) < 0)
+		return -1;
+	sm2_bn_from_bytes(r, buf);
+	return 1;
+}
+
+int sm2_bn_from_asn1_integer(SM2_BN r, const uint8_t *d, size_t dlen)
+{
+	uint8_t buf[32] = {0};
+	if (!d || dlen == 0) {
+		error_print();
+		return -1;
+	}
+	if (dlen > sizeof(buf)) {
+		error_print();
+		return -1;
+	}
+	memcpy(buf + sizeof(buf) - dlen, d, dlen);
+	sm2_bn_from_bytes(r, buf);
+	return 1;
+}
+#if 0
+int sm2_bn_print(FILE *fp, int fmt, int ind, const char *label, const SM2_BN a)
+{
+	int ret = 0, i;
+	format_print(fp, fmt, ind, "%s: ", label);
+
+	for (i = 7; i >= 0; i--) {
+		if (a[i] >= ((uint64_t)1 << 32)) {
+			printf("bn_print check failed\n");
+		}
+		ret += fprintf(fp, "%08x", (uint32_t)a[i]);
+	}
+	ret += fprintf(fp, "\n");
+	return ret;
+}
+#endif
+void sm2_bn_to_bits(const SM2_BN a, char bits[256])
+{
+	int i, j;
+	uint64_t w;
+	for (i = 7; i >= 0; i--) {
+		w = a[i];
+		for (j = 0; j < 32; j++) {
+			*bits++ = (w & 0x80000000) ? '1' : '0';
+			w <<= 1;
+		}
+	}
+}
+
+int sm2_bn_cmp(const SM2_BN a, const SM2_BN b)
+{
+	int i;
+	for (i = 7; i >= 0; i--) {
+		if (a[i] > b[i])
+			return 1;
+		if (a[i] < b[i])
+			return -1;
+	}
+	return 0;
+}
+#if 0
+int sm2_bn_equ_hex(const SM2_BN a, const char *hex)
+{
+	char buf[65] = {0};
+	char *p = buf;
+	int i;
+
+	for (i = 7; i >= 0; i--) {
+		sprintf(p, "%08x", (uint32_t)a[i]);
+		p += 8;
+	}
+	return (strcmp(buf, hex) == 0);
+}
+#endif
+int sm2_bn_is_odd(const SM2_BN a)
+{
+	return a[0] & 0x01;
+}
+
+void sm2_bn_set_word(SM2_BN r, uint32_t a)
+{
+	int i;
+	r[0] = a;
+	for (i = 1; i < 8; i++) {
+		r[i] = 0;
+	}
+}
+
+int sm2_bn_rshift(SM2_BN ret, const SM2_BN a, unsigned int nbits)
+{
+	SM2_BN r;
+	int i;
+
+	if (nbits > 31) {
+		error_print();
+		return -1;
+	}
+	if (nbits == 0) {
+		sm2_bn_copy(ret, a);
+	}
+
+	for (i = 0; i < 7; i++) {
+		r[i] = a[i] >> nbits;
+		r[i] |= (a[i+1] << (32 - nbits)) & 0xffffffff;
+	}
+	r[i] = a[i] >> nbits;
+	sm2_bn_copy(ret, r);
+	return 1;
+}
+
+void sm2_bn_add(SM2_BN r, const SM2_BN a, const SM2_BN b)
+{
+	int i;
+	r[0] = a[0] + b[0];
+
+	for (i = 1; i < 8; i++) {
+		r[i] = a[i] + b[i] + (r[i-1] >> 32);
+	}
+	for (i = 0; i < 7; i++) {
+		r[i] &= 0xffffffff;
+	}
+}
+
+void sm2_bn_sub(SM2_BN ret, const SM2_BN a, const SM2_BN b)
+{
+	int i;
+	SM2_BN r;
+	r[0] = ((uint64_t)1 << 32) + a[0] - b[0];
+	for (i = 1; i < 7; i++) {
+		r[i] = 0xffffffff + a[i] - b[i] + (r[i - 1] >> 32);
+		r[i - 1] &= 0xffffffff;
+	}
+	r[i] = a[i] - b[i] + (r[i - 1] >> 32) - 1;
+	r[i - 1] &= 0xffffffff;
+	sm2_bn_copy(ret, r);
+}
+
+int sm2_bn_rand_range(SM2_BN r, const SM2_BN range)
+{
+	uint8_t buf[32];
+	do {
+		if (rand_bytes(buf, sizeof(buf)) != 1) {
+			error_print();
+			return -1;
+		}
+		sm2_bn_from_bytes(r, buf);
+	} while (sm2_bn_cmp(r, range) >= 0);
+	return 1;
+}
+
+int sm2_fp_rand(SM2_Fp r)
+{
+	if (sm2_bn_rand_range(r, SM2_P) != 1) {
+		error_print();
+		return -1;
+	}
+	return 1;
+}
+
+void sm2_fp_add(SM2_Fp r, const SM2_Fp a, const SM2_Fp b)
+{
+	sm2_bn_add(r, a, b);
+	if (sm2_bn_cmp(r, SM2_P) >= 0) {
+		sm2_bn_sub(r, r, SM2_P);
+	}
+}
+
+void sm2_fp_sub(SM2_Fp r, const SM2_Fp a, const SM2_Fp b)
+{
+	if (sm2_bn_cmp(a, b) >= 0) {
+		sm2_bn_sub(r, a, b);
+	} else {
+		SM2_BN t;
+		sm2_bn_sub(t, SM2_P, b);
+		sm2_bn_add(r, t, a);
+	}
+}
+
+void sm2_fp_dbl(SM2_Fp r, const SM2_Fp a)
+{
+	sm2_fp_add(r, a, a);
+}
+
+void sm2_fp_tri(SM2_Fp r, const SM2_Fp a)
+{
+	SM2_BN t;
+	sm2_fp_dbl(t, a);
+	sm2_fp_add(r, t, a);
+}
+
+void sm2_fp_div2(SM2_Fp r, const SM2_Fp a)
+{
+	int i;
+	sm2_bn_copy(r, a);
+	if (r[0] & 0x01) {
+		sm2_bn_add(r, r, SM2_P);
+	}
+	for (i = 0; i < 7; i++) {
+		r[i] = (r[i] >> 1) | ((r[i + 1] & 0x01) << 31);
+	}
+	r[i] >>= 1;
+}
+
+void sm2_fp_neg(SM2_Fp r, const SM2_Fp a)
+{
+	if (sm2_bn_is_zero(a)) {
+		sm2_bn_copy(r, a);
+	} else {
+		sm2_bn_sub(r, SM2_P, a);
+	}
+}
+
+void sm2_fp_mul(SM2_Fp r, const SM2_Fp a, const SM2_Fp b)
+{
+	int i, j;
+	uint64_t s[16] = {0};
+	SM2_BN d = {0};
+	uint64_t u;
+
+	// s = a * b
+	for (i = 0; i < 8; i++) {
+		u = 0;
+		for (j = 0; j < 8; j++) {
+			u = s[i + j] + a[i] * b[j] + u;
+			s[i + j] = u & 0xffffffff;
+			u >>= 32;
+		}
+		s[i + 8] = u;
+	}
+
+	r[0] = s[0] + s[ 8] + s[ 9] + s[10] + s[11] + s[12] + ((s[13] + s[14] + s[15]) << 1);
+	r[1] = s[1] + s[ 9] + s[10] + s[11] + s[12] + s[13] + ((s[14] + s[15]) << 1);
+	r[2] = s[2];
+	r[3] = s[3] + s[ 8] + s[11] + s[12] + s[14] + s[15] + (s[13] << 1);
+	r[4] = s[4] + s[ 9] + s[12] + s[13] + s[15] + (s[14] << 1);
+	r[5] = s[5] + s[10] + s[13] + s[14] + (s[15] << 1);
+	r[6] = s[6] + s[11] + s[14] + s[15];
+	r[7] = s[7] + s[ 8] + s[ 9] + s[10] + s[11] + s[15] + ((s[12] + s[13] + s[14] + s[15]) << 1);
+
+	for (i = 1; i < 8; i++) {
+		r[i] += r[i - 1] >> 32;
+		r[i - 1] &= 0xffffffff;
+	}
+
+	d[2] = s[8] + s[9] + s[13] + s[14];
+	d[3] = d[2] >> 32;
+	d[2] &= 0xffffffff;
+	sm2_bn_sub(r, r, d);
+
+	// max times ?
+	while (sm2_bn_cmp(r, SM2_P) >= 0) {
+		sm2_bn_sub(r, r, SM2_P);
+	}
+}
+
+void sm2_fp_sqr(SM2_Fp r, const SM2_Fp a)
+{
+	sm2_fp_mul(r, a, a);
+}
+
+void sm2_fp_exp(SM2_Fp r, const SM2_Fp a, const SM2_Fp e)
+{
+	SM2_BN t;
+	uint32_t w;
+	int i, j;
+
+	sm2_bn_set_one(t);
+	for (i = 7; i >= 0; i--) {
+		w = (uint32_t)e[i];
+		for (j = 0; j < 32; j++) {
+			sm2_fp_sqr(t, t);
+			if (w & 0x80000000)
+				sm2_fp_mul(t, t, a);
+			w <<= 1;
+		}
+	}
+
+	sm2_bn_copy(r, t);
+}
+
+void sm2_fp_inv(SM2_Fp r, const SM2_Fp a)
+{
+	SM2_BN a1;
+	SM2_BN a2;
+	SM2_BN a3;
+	SM2_BN a4;
+	SM2_BN a5;
+	int i;
+
+	sm2_fp_sqr(a1, a);
+	sm2_fp_mul(a2, a1, a);
+	sm2_fp_sqr(a3, a2);
+	sm2_fp_sqr(a3, a3);
+	sm2_fp_mul(a3, a3, a2);
+	sm2_fp_sqr(a4, a3);
+	sm2_fp_sqr(a4, a4);
+	sm2_fp_sqr(a4, a4);
+	sm2_fp_sqr(a4, a4);
+	sm2_fp_mul(a4, a4, a3);
+	sm2_fp_sqr(a5, a4);
+	for (i = 1; i < 8; i++)
+		sm2_fp_sqr(a5, a5);
+	sm2_fp_mul(a5, a5, a4);
+	for (i = 0; i < 8; i++)
+		sm2_fp_sqr(a5, a5);
+	sm2_fp_mul(a5, a5, a4);
+	for (i = 0; i < 4; i++)
+		sm2_fp_sqr(a5, a5);
+	sm2_fp_mul(a5, a5, a3);
+	sm2_fp_sqr(a5, a5);
+	sm2_fp_sqr(a5, a5);
+	sm2_fp_mul(a5, a5, a2);
+	sm2_fp_sqr(a5, a5);
+	sm2_fp_mul(a5, a5, a);
+	sm2_fp_sqr(a4, a5);
+	sm2_fp_mul(a3, a4, a1);
+	sm2_fp_sqr(a5, a4);
+	for (i = 1; i< 31; i++)
+		sm2_fp_sqr(a5, a5);
+	sm2_fp_mul(a4, a5, a4);
+	sm2_fp_sqr(a4, a4);
+	sm2_fp_mul(a4, a4, a);
+	sm2_fp_mul(a3, a4, a2);
+	for (i = 0; i < 33; i++)
+		sm2_fp_sqr(a5, a5);
+	sm2_fp_mul(a2, a5, a3);
+	sm2_fp_mul(a3, a2, a3);
+	for (i = 0; i < 32; i++)
+		sm2_fp_sqr(a5, a5);
+	sm2_fp_mul(a2, a5, a3);
+	sm2_fp_mul(a3, a2, a3);
+	sm2_fp_mul(a4, a2, a4);
+	for (i = 0; i < 32; i++)
+		sm2_fp_sqr(a5, a5);
+	sm2_fp_mul(a2, a5, a3);
+	sm2_fp_mul(a3, a2, a3);
+	sm2_fp_mul(a4, a2, a4);
+	for (i = 0; i < 32; i++)
+		sm2_fp_sqr(a5, a5);
+	sm2_fp_mul(a2, a5, a3);
+	sm2_fp_mul(a3, a2, a3);
+	sm2_fp_mul(a4, a2, a4);
+	for (i = 0; i < 32; i++)
+		sm2_fp_sqr(a5, a5);
+	sm2_fp_mul(a2, a5, a3);
+	sm2_fp_mul(a3, a2, a3);
+	sm2_fp_mul(a4, a2, a4);
+	for (i = 0; i < 32; i++)
+		sm2_fp_sqr(a5, a5);
+	sm2_fp_mul(r, a4, a5);
+
+	sm2_bn_clean(a1);
+	sm2_bn_clean(a2);
+	sm2_bn_clean(a3);
+	sm2_bn_clean(a4);
+	sm2_bn_clean(a5);
+}
+
+int sm2_fp_sqrt(SM2_Fp r, const SM2_Fp a)
+{
+	SM2_BN u;
+	SM2_BN y; // temp result, prevent call sm2_fp_sqrt(a, a)
+
+	// r = a^((p + 1)/4) when p = 3 (mod 4)
+	sm2_bn_add(u, SM2_P, SM2_ONE);
+	sm2_bn_rshift(u, u, 2);
+	sm2_fp_exp(y, a, u);
+
+	// check r^2 == a
+	sm2_fp_sqr(u, y);
+	if (sm2_bn_cmp(u, a) != 0) {
+		error_print();
+		return -1;
+	}
+
+	sm2_bn_copy(r, y);
+	return 1;
+}
+
+void sm2_fn_add(SM2_Fn r, const SM2_Fn a, const SM2_Fn b)
+{
+	sm2_bn_add(r, a, b);
+	if (sm2_bn_cmp(r, SM2_N) >= 0) {
+		sm2_bn_sub(r, r, SM2_N);
+	}
+}
+
+void sm2_fn_sub(SM2_Fn r, const SM2_Fn a, const SM2_Fn b)
+{
+	if (sm2_bn_cmp(a, b) >= 0) {
+		sm2_bn_sub(r, a, b);
+	} else {
+		SM2_BN t;
+		sm2_bn_add(t, a, SM2_N);
+		sm2_bn_sub(r, t, b);
+	}
+}
+
+void sm2_fn_neg(SM2_Fn r, const SM2_Fn a)
+{
+	if (sm2_bn_is_zero(a)) {
+		sm2_bn_copy(r, a);
+	} else {
+		sm2_bn_sub(r, SM2_N, a);
+	}
+}
+
+/* bn288 only used in barrett reduction */
+static int sm2_bn288_cmp(const uint64_t a[9], const uint64_t b[9])
+{
+	int i;
+	for (i = 8; i >= 0; i--) {
+		if (a[i] > b[i])
+			return 1;
+		if (a[i] < b[i])
+			return -1;
+	}
+	return 0;
+}
+
+static void sm2_bn288_add(uint64_t r[9], const uint64_t a[9], const uint64_t b[9])
+{
+	int i;
+	r[0] = a[0] + b[0];
+	for (i = 1; i < 9; i++) {
+		r[i] = a[i] + b[i] + (r[i-1] >> 32);
+	}
+	for (i = 0; i < 8; i++) {
+		r[i] &= 0xffffffff;
+	}
+}
+
+static void sm2_bn288_sub(uint64_t ret[9], const uint64_t a[9], const uint64_t b[9])
+{
+	int i;
+	uint64_t r[9];
+
+	r[0] = ((uint64_t)1 << 32) + a[0] - b[0];
+	for (i = 1; i < 8; i++) {
+		r[i] = 0xffffffff + a[i] - b[i] + (r[i - 1] >> 32);
+		r[i - 1] &= 0xffffffff;
+	}
+	r[i] = a[i] - b[i] + (r[i - 1] >> 32) - 1;
+	r[i - 1] &= 0xffffffff;
+
+	for (i = 0; i < 9; i++) {
+		ret[i] = r[i];
+	}
+}
+
+void sm2_fn_mul(SM2_BN ret, const SM2_BN a, const SM2_BN b)
+{
+	SM2_BN r;
+	static const uint64_t mu[9] = {
+		0xf15149a0, 0x12ac6361, 0xfa323c01, 0x8dfc2096, 1, 1, 1, 1, 1,
+	};
+
+	uint64_t s[18];
+	uint64_t zh[9];
+	uint64_t zl[9];
+	uint64_t q[9];
+	uint64_t w;
+	int i, j;
+
+	/* z = a * b */
+	for (i = 0; i < 8; i++) {
+		s[i] = 0;
+	}
+	for (i = 0; i < 8; i++) {
+		w = 0;
+		for (j = 0; j < 8; j++) {
+			w += s[i + j] + a[i] * b[j];
+			s[i + j] = w & 0xffffffff;
+			w >>= 32;
+		}
+		s[i + 8] = w;
+	}
+
+	/* zl = z mod (2^32)^9 = z[0..8]
+	 * zh = z // (2^32)^7 = z[7..15] */
+	for (i = 0; i < 9; i++) {
+		zl[i] = s[i];
+		zh[i] = s[7 + i];
+	}
+	//printf("zl = "); for (i = 8; i >= 0; i--) printf("%08x", (uint32_t)zl[i]); printf("\n");
+	//printf("zh = "); for (i = 8; i >= 0; i--) printf("%08x", (uint32_t)zh[i]); printf("\n");
+
+	/* q = zh * mu // (2^32)^9 */
+	for (i = 0; i < 9; i++) {
+		s[i] = 0;
+	}
+	for (i = 0; i < 9; i++) {
+		w = 0;
+		for (j = 0; j < 9; j++) {
+			w += s[i + j] + zh[i] * mu[j];
+			s[i + j] = w & 0xffffffff;
+			w >>= 32;
+		}
+		s[i + 9] = w;
+	}
+	for (i = 0; i < 8; i++) {
+		q[i] = s[9 + i];
+	}
+	//printf("q  = "); for (i = 7; i >= 0; i--) printf("%08x", (uint32_t)q[i]); printf("\n");
+
+	/* q = q * n mod (2^32)^9 */
+	for (i = 0; i < 17; i++) {
+		s[i] = 0;
+	}
+	for (i = 0; i < 8; i++) {
+		w = 0;
+		for (j = 0; j < 8; j++) {
+			w += s[i + j] + q[i] * SM2_N[j];
+			s[i + j] = w & 0xffffffff;
+			w >>= 32;
+		}
+		s[i + 8] = w;
+	}
+	for (i = 0; i < 9; i++) {
+		q[i] = s[i];
+	}
+	//printf("qn = "); for (i = 8; i >= 0; i--) printf("%08x ", (uint32_t)q[i]); printf("\n");
+
+	/* r = zl - q (mod (2^32)^9) */
+
+	if (sm2_bn288_cmp(zl, q)) {
+		sm2_bn288_sub(zl, zl, q);
+	} else {
+		uint64_t c[9] = {0,0,0,0,0,0,0,0,0x100000000};
+		sm2_bn288_sub(q, c, q);
+		sm2_bn288_add(zl, q, zl);
+	}
+	//printf("zl  = "); for (i = 8; i >= 0; i--) printf("%08x ", (uint32_t)zl[i]); printf("\n");
+	for (i = 0; i < 8; i++) {
+		r[i] = zl[i];
+	}
+	r[7] += zl[8] << 32;
+
+	/* while r >= p do: r = r - n */
+	while (sm2_bn_cmp(r, SM2_N) >= 0) {
+		sm2_bn_sub(r, r, SM2_N);
+		//printf("r-n = "); for (i = 7; i >= 0; i--) printf("%16llx ", r[i]); printf("\n");
+	}
+	sm2_bn_copy(ret, r);
+}
+
+void sm2_fn_mul_word(SM2_Fn r, const SM2_Fn a, uint32_t b)
+{
+	SM2_Fn t;
+	sm2_bn_set_word(t, b);
+	sm2_fn_mul(r, a, t);
+}
+
+void sm2_fn_sqr(SM2_BN r, const SM2_BN a)
+{
+	sm2_fn_mul(r, a, a);
+}
+
+void sm2_fn_exp(SM2_BN r, const SM2_BN a, const SM2_BN e)
+{
+	SM2_BN t;
+	uint32_t w;
+	int i, j;
+
+	sm2_bn_set_one(t);
+	for (i = 7; i >= 0; i--) {
+		w = (uint32_t)e[i];
+		for (j = 0; j < 32; j++) {
+			sm2_fn_sqr(t, t);
+			if (w & 0x80000000) {
+				sm2_fn_mul(t, t, a);
+			}
+			w <<= 1;
+		}
+	}
+	sm2_bn_copy(r, t);
+}
+
+void sm2_fn_inv(SM2_BN r, const SM2_BN a)
+{
+	SM2_BN e;
+	sm2_bn_sub(e, SM2_N, SM2_TWO);
+	sm2_fn_exp(r, a, e);
+}
+
+int sm2_fn_rand(SM2_BN r)
+{
+	if (sm2_bn_rand_range(r, SM2_N) != 1) {
+		error_print();
+		return -1;
+	}
+	return 1;
+}
+
+
+
+void sm2_jacobian_point_init(SM2_JACOBIAN_POINT *R)
+{
+	memset(R, 0, sizeof(SM2_JACOBIAN_POINT));
+	R->X[0] = 1;
+	R->Y[0] = 1;
+}
+
+int sm2_jacobian_point_is_at_infinity(const SM2_JACOBIAN_POINT *P)
+{
+	return sm2_bn_is_zero(P->Z);
+}
+
+void sm2_jacobian_point_set_xy(SM2_JACOBIAN_POINT *R, const SM2_BN x, const SM2_BN y)
+{
+	sm2_bn_copy(R->X, x);
+	sm2_bn_copy(R->Y, y);
+	sm2_bn_set_one(R->Z);
+}
+
+void sm2_jacobian_point_get_xy(const SM2_JACOBIAN_POINT *P, SM2_BN x, SM2_BN y)
+{
+	if (sm2_bn_is_one(P->Z)) {
+		sm2_bn_copy(x, P->X);
+		if (y) {
+			sm2_bn_copy(y, P->Y);
+		}
+	} else {
+		SM2_BN z_inv;
+		sm2_fp_inv(z_inv, P->Z);
+		if (y) {
+			sm2_fp_mul(y, P->Y, z_inv);
+		}
+		sm2_fp_sqr(z_inv, z_inv);
+		sm2_fp_mul(x, P->X, z_inv);
+		if (y) {
+			sm2_fp_mul(y, y, z_inv);
+		}
+	}
+}
+
+int sm2_jacobian_pointpoint_print(FILE *fp, int fmt, int ind, const char *label, const SM2_JACOBIAN_POINT *P)
+{
+	int len = 0;
+	SM2_BN x;
+	SM2_BN y;
+
+	format_print(fp, fmt, ind, "%s\n", label);
+	ind += 4;
+
+	sm2_jacobian_point_get_xy(P, x, y);
+
+	sm2_bn_print(fp, fmt, ind, "x", x);
+	sm2_bn_print(fp, fmt, ind, "y", y);
+
+	return 1;
+}
+
+int sm2_jacobian_point_is_on_curve(const SM2_JACOBIAN_POINT *P)
+{
+	SM2_BN t0;
+	SM2_BN t1;
+	SM2_BN t2;
+
+	if (sm2_bn_is_one(P->Z)) {
+		sm2_fp_sqr(t0, P->Y);
+		sm2_fp_add(t0, t0, P->X);
+		sm2_fp_add(t0, t0, P->X);
+		sm2_fp_add(t0, t0, P->X);
+		sm2_fp_sqr(t1, P->X);
+		sm2_fp_mul(t1, t1, P->X);
+		sm2_fp_add(t1, t1, SM2_B);
+	} else {
+		sm2_fp_sqr(t0, P->Y);
+		sm2_fp_sqr(t1, P->Z);
+		sm2_fp_sqr(t2, t1);
+		sm2_fp_mul(t1, t1, t2);
+		sm2_fp_mul(t1, t1, SM2_B);
+		sm2_fp_mul(t2, t2, P->X);
+		sm2_fp_add(t0, t0, t2);
+		sm2_fp_add(t0, t0, t2);
+		sm2_fp_add(t0, t0, t2);
+		sm2_fp_sqr(t2, P->X);
+		sm2_fp_mul(t2, t2, P->X);
+		sm2_fp_add(t1, t1, t2);
+	}
+
+	if (sm2_bn_cmp(t0, t1) != 0) {
+		error_print();
+		return -1;
+	}
+	return 1;
+}
+
+void sm2_jacobian_point_neg(SM2_JACOBIAN_POINT *R, const SM2_JACOBIAN_POINT *P)
+{
+	sm2_bn_copy(R->X, P->X);
+	sm2_fp_neg(R->Y, P->Y);
+	sm2_bn_copy(R->Z, P->Z);
+}
+
+void sm2_jacobian_point_dbl(SM2_JACOBIAN_POINT *R, const SM2_JACOBIAN_POINT *P)
+{
+	const uint64_t *X1 = P->X;
+	const uint64_t *Y1 = P->Y;
+	const uint64_t *Z1 = P->Z;
+	SM2_BN T1;
+	SM2_BN T2;
+	SM2_BN T3;
+	SM2_BN X3;
+	SM2_BN Y3;
+	SM2_BN Z3;
+				//printf("X1 = "); print_bn(X1);
+				//printf("Y1 = "); print_bn(Y1);
+				//printf("Z1 = "); print_bn(Z1);
+
+	if (sm2_jacobian_point_is_at_infinity(P)) {
+		sm2_jacobian_point_copy(R, P);
+		return;
+	}
+
+	sm2_fp_sqr(T1, Z1);		//printf("T1 = Z1^2    = "); print_bn(T1);
+	sm2_fp_sub(T2, X1, T1);	//printf("T2 = X1 - T1 = "); print_bn(T2);
+	sm2_fp_add(T1, X1, T1);	//printf("T1 = X1 + T1 = "); print_bn(T1);
+	sm2_fp_mul(T2, T2, T1);	//printf("T2 = T2 * T1 = "); print_bn(T2);
+	sm2_fp_tri(T2, T2);		//printf("T2 =  3 * T2 = "); print_bn(T2);
+	sm2_fp_dbl(Y3, Y1);		//printf("Y3 =  2 * Y1 = "); print_bn(Y3);
+	sm2_fp_mul(Z3, Y3, Z1);	//printf("Z3 = Y3 * Z1 = "); print_bn(Z3);
+	sm2_fp_sqr(Y3, Y3);		//printf("Y3 = Y3^2    = "); print_bn(Y3);
+	sm2_fp_mul(T3, Y3, X1);	//printf("T3 = Y3 * X1 = "); print_bn(T3);
+	sm2_fp_sqr(Y3, Y3);		//printf("Y3 = Y3^2    = "); print_bn(Y3);
+	sm2_fp_div2(Y3, Y3);	//printf("Y3 = Y3/2    = "); print_bn(Y3);
+	sm2_fp_sqr(X3, T2);		//printf("X3 = T2^2    = "); print_bn(X3);
+	sm2_fp_dbl(T1, T3);		//printf("T1 =  2 * T1 = "); print_bn(T1);
+	sm2_fp_sub(X3, X3, T1);	//printf("X3 = X3 - T1 = "); print_bn(X3);
+	sm2_fp_sub(T1, T3, X3);	//printf("T1 = T3 - X3 = "); print_bn(T1);
+	sm2_fp_mul(T1, T1, T2);	//printf("T1 = T1 * T2 = "); print_bn(T1);
+	sm2_fp_sub(Y3, T1, Y3);	//printf("Y3 = T1 - Y3 = "); print_bn(Y3);
+
+	sm2_bn_copy(R->X, X3);
+	sm2_bn_copy(R->Y, Y3);
+	sm2_bn_copy(R->Z, Z3);
+
+				//printf("X3 = "); print_bn(R->X);
+				//printf("Y3 = "); print_bn(R->Y);
+				//printf("Z3 = "); print_bn(R->Z);
+
+}
+
+void sm2_jacobian_point_add(SM2_JACOBIAN_POINT *R, const SM2_JACOBIAN_POINT *P, const SM2_JACOBIAN_POINT *Q)
+{
+	const uint64_t *X1 = P->X;
+	const uint64_t *Y1 = P->Y;
+	const uint64_t *Z1 = P->Z;
+	const uint64_t *x2 = Q->X;
+	const uint64_t *y2 = Q->Y;
+	SM2_BN T1;
+	SM2_BN T2;
+	SM2_BN T3;
+	SM2_BN T4;
+	SM2_BN X3;
+	SM2_BN Y3;
+	SM2_BN Z3;
+
+	if (sm2_jacobian_point_is_at_infinity(Q)) {
+		sm2_jacobian_point_copy(R, P);
+		return;
+	}
+
+	if (sm2_jacobian_point_is_at_infinity(P)) {
+		sm2_jacobian_point_copy(R, Q);
+		return;
+	}
+
+	assert(sm2_bn_is_one(Q->Z));
+
+	sm2_fp_sqr(T1, Z1);
+	sm2_fp_mul(T2, T1, Z1);
+	sm2_fp_mul(T1, T1, x2);
+	sm2_fp_mul(T2, T2, y2);
+	sm2_fp_sub(T1, T1, X1);
+	sm2_fp_sub(T2, T2, Y1);
+	if (sm2_bn_is_zero(T1)) {
+		if (sm2_bn_is_zero(T2)) {
+			SM2_JACOBIAN_POINT _Q, *Q = &_Q;
+			sm2_jacobian_point_set_xy(Q, x2, y2);
+
+			sm2_jacobian_point_dbl(R, Q);
+			return;
+		} else {
+			sm2_jacobian_point_set_infinity(R);
+			return;
+		}
+	}
+	sm2_fp_mul(Z3, Z1, T1);
+	sm2_fp_sqr(T3, T1);
+	sm2_fp_mul(T4, T3, T1);
+	sm2_fp_mul(T3, T3, X1);
+	sm2_fp_dbl(T1, T3);
+	sm2_fp_sqr(X3, T2);
+	sm2_fp_sub(X3, X3, T1);
+	sm2_fp_sub(X3, X3, T4);
+	sm2_fp_sub(T3, T3, X3);
+	sm2_fp_mul(T3, T3, T2);
+	sm2_fp_mul(T4, T4, Y1);
+	sm2_fp_sub(Y3, T3, T4);
+
+	sm2_bn_copy(R->X, X3);
+	sm2_bn_copy(R->Y, Y3);
+	sm2_bn_copy(R->Z, Z3);
+}
+
+void sm2_jacobian_point_sub(SM2_JACOBIAN_POINT *R, const SM2_JACOBIAN_POINT *P, const SM2_JACOBIAN_POINT *Q)
+{
+	SM2_JACOBIAN_POINT _T, *T = &_T;
+	sm2_jacobian_point_neg(T, Q);
+	sm2_jacobian_point_add(R, P, T);
+}
+
+void sm2_jacobian_point_mul(SM2_JACOBIAN_POINT *R, const SM2_BN k, const SM2_JACOBIAN_POINT *P)
+{
+	char bits[257] = {0};
+	SM2_JACOBIAN_POINT _Q, *Q = &_Q;
+	SM2_JACOBIAN_POINT _T, *T = &_T;
+	int i;
+
+	// FIXME: point_add need affine, so we can not use point_add
+	if (!sm2_bn_is_one(P->Z)) {
+		SM2_BN x;
+		SM2_BN y;
+		sm2_jacobian_point_get_xy(P, x, y);
+		sm2_jacobian_point_set_xy(T, x, y);
+		P = T;
+	}
+
+	sm2_jacobian_point_set_infinity(Q);
+	sm2_bn_to_bits(k, bits);
+	for (i = 0; i < 256; i++) {
+		sm2_jacobian_point_dbl(Q, Q);
+		if (bits[i] == '1') {
+			sm2_jacobian_point_add(Q, Q, P);
+		}
+	}
+	sm2_jacobian_point_copy(R, Q);
+}
+
+void sm2_jacobian_point_to_bytes(const SM2_JACOBIAN_POINT *P, uint8_t out[64])
+{
+	SM2_BN x;
+	SM2_BN y;
+	sm2_jacobian_point_get_xy(P, x, y);
+	sm2_bn_to_bytes(x, out);
+	sm2_bn_to_bytes(y, out + 32);
+}
+
+void sm2_jacobian_point_from_bytes(SM2_JACOBIAN_POINT *P, const uint8_t in[64])
+{
+	sm2_bn_from_bytes(P->X, in);
+	sm2_bn_from_bytes(P->Y, in + 32);
+	sm2_bn_set_word(P->Z, 1);
+	/* should we check if sm2_jacobian_point_is_on_curve */
+}
+
+void sm2_jacobian_point_mul_generator(SM2_JACOBIAN_POINT *R, const SM2_BN k)
+{
+	sm2_jacobian_point_mul(R, k, SM2_G);
+}
+
+/* R = t * P + s * G */
+void sm2_jacobian_point_mul_sum(SM2_JACOBIAN_POINT *R, const SM2_BN t, const SM2_JACOBIAN_POINT *P, const SM2_BN s)
+{
+	SM2_JACOBIAN_POINT _sG, *sG = &_sG;
+	SM2_BN x;
+	SM2_BN y;
+
+	/* T = s * G */
+	sm2_jacobian_point_mul_generator(sG, s);
+
+	// R = t * P
+	sm2_jacobian_point_mul(R, t, P);
+	sm2_jacobian_point_get_xy(R, x, y);
+	sm2_jacobian_point_set_xy(R, x, y);
+
+	// R = R + T
+	sm2_jacobian_point_add(R, sG, R);
+}
+
+void sm2_jacobian_point_from_hex(SM2_JACOBIAN_POINT *P, const char hex[64 * 2])
+{
+	sm2_bn_from_hex(P->X, hex);
+	sm2_bn_from_hex(P->Y, hex + 64);
+	sm2_bn_set_one(P->Z);
+}
+
+int sm2_jacobian_point_equ_hex(const SM2_JACOBIAN_POINT *P, const char hex[128])
+{
+	SM2_BN x;
+	SM2_BN y;
+	SM2_JACOBIAN_POINT _T, *T = &_T;
+
+	sm2_jacobian_point_get_xy(P, x, y);
+	sm2_jacobian_point_from_hex(T, hex);
+
+	return (sm2_bn_cmp(x, T->X) == 0) && (sm2_bn_cmp(y, T->Y) == 0);
+}
+
+int sm2_point_is_on_curve(const SM2_POINT *P)
+{
+	SM2_JACOBIAN_POINT T;
+	sm2_jacobian_point_from_bytes(&T, (const uint8_t *)P);
+	return sm2_jacobian_point_is_on_curve(&T);
+}
+
+int sm2_point_is_at_infinity(const SM2_POINT *P)
+{
+	return mem_is_zero((uint8_t *)P, sizeof(SM2_POINT));
+}
+
+int sm2_point_from_x(SM2_POINT *P, const uint8_t x[32], int y)
+{
+	SM2_BN _x, _y, _g, _z;
+	sm2_bn_from_bytes(_x, x);
+
+	// g = x^3 - 3x + b = (x^2 - 3)*x + b
+	sm2_fp_sqr(_g, _x);
+	sm2_fp_sub(_g, _g, SM2_THREE);
+	sm2_fp_mul(_g, _g, _x);
+	sm2_fp_add(_g, _g, SM2_B);
+
+	// y = g^(u + 1) mod p, u = (p - 3)/4
+	sm2_fp_exp(_y, _g, SM2_U_PLUS_ONE);
+
+	// z = y^2 mod p
+	sm2_fp_sqr(_z, _y);
+	if (sm2_bn_cmp(_z, _g)) {
+		error_print();
+		return -1;
+	}
+
+	if ((y == 0x02 && sm2_bn_is_odd(_y)) || ((y == 0x03) && !sm2_bn_is_odd(_y))) {
+		sm2_fp_neg(_y, _y);
+	}
+
+	sm2_bn_to_bytes(_x, P->x);
+	sm2_bn_to_bytes(_y, P->y);
+
+	sm2_bn_clean(_x);
+	sm2_bn_clean(_y);
+	sm2_bn_clean(_g);
+	sm2_bn_clean(_z);
+
+	if (!sm2_point_is_on_curve(P)) {
+		error_print();
+		return -1;
+	}
+	return 1;
+}
+
+int sm2_point_from_xy(SM2_POINT *P, const uint8_t x[32], const uint8_t y[32])
+{
+	memcpy(P->x, x, 32);
+	memcpy(P->y, y, 32);
+	return sm2_point_is_on_curve(P);
+}
+
+int sm2_point_add(SM2_POINT *R, const SM2_POINT *P, const SM2_POINT *Q)
+{
+	SM2_JACOBIAN_POINT P_;
+	SM2_JACOBIAN_POINT Q_;
+
+	sm2_jacobian_point_from_bytes(&P_, (uint8_t *)P);
+	sm2_jacobian_point_from_bytes(&Q_, (uint8_t *)Q);
+	sm2_jacobian_point_add(&P_, &P_, &Q_);
+	sm2_jacobian_point_to_bytes(&P_, (uint8_t *)R);
+
+	return 1;
+}
+
+int sm2_point_sub(SM2_POINT *R, const SM2_POINT *P, const SM2_POINT *Q)
+{
+	SM2_JACOBIAN_POINT P_;
+	SM2_JACOBIAN_POINT Q_;
+
+	sm2_jacobian_point_from_bytes(&P_, (uint8_t *)P);
+	sm2_jacobian_point_from_bytes(&Q_, (uint8_t *)Q);
+	sm2_jacobian_point_sub(&P_, &P_, &Q_);
+	sm2_jacobian_point_to_bytes(&P_, (uint8_t *)R);
+
+	return 1;
+}
+
+int sm2_point_neg(SM2_POINT *R, const SM2_POINT *P)
+{
+	SM2_JACOBIAN_POINT P_;
+
+	sm2_jacobian_point_from_bytes(&P_, (uint8_t *)P);
+	sm2_jacobian_point_neg(&P_, &P_);
+	sm2_jacobian_point_to_bytes(&P_, (uint8_t *)R);
+
+	return 1;
+}
+
+int sm2_point_dbl(SM2_POINT *R, const SM2_POINT *P)
+{
+	SM2_JACOBIAN_POINT P_;
+
+	sm2_jacobian_point_from_bytes(&P_, (uint8_t *)P);
+	sm2_jacobian_point_dbl(&P_, &P_);
+	sm2_jacobian_point_to_bytes(&P_, (uint8_t *)R);
+
+	return 1;
+}
+
+int sm2_point_mul(SM2_POINT *R, const uint8_t k[32], const SM2_POINT *P)
+{
+	SM2_BN _k;
+	SM2_JACOBIAN_POINT _P;
+
+	sm2_bn_from_bytes(_k, k);
+	sm2_jacobian_point_from_bytes(&_P, (uint8_t *)P);
+	sm2_jacobian_point_mul(&_P, _k, &_P);
+	sm2_jacobian_point_to_bytes(&_P, (uint8_t *)R);
+
+	sm2_bn_clean(_k);
+	return 1;
+}
+
+int sm2_point_mul_generator(SM2_POINT *R, const uint8_t k[32])
+{
+	SM2_BN _k;
+	SM2_JACOBIAN_POINT _R;
+
+	sm2_bn_from_bytes(_k, k);
+	sm2_jacobian_point_mul_generator(&_R, _k);
+	sm2_jacobian_point_to_bytes(&_R, (uint8_t *)R);
+
+	sm2_bn_clean(_k);
+	return 1;
+}
+
+int sm2_point_mul_sum(SM2_POINT *R, const uint8_t k[32], const SM2_POINT *P, const uint8_t s[32])
+{
+	SM2_BN _k;
+	SM2_JACOBIAN_POINT _P;
+	SM2_BN _s;
+
+	sm2_bn_from_bytes(_k, k);
+	sm2_jacobian_point_from_bytes(&_P, (uint8_t *)P);
+	sm2_bn_from_bytes(_s, s);
+	sm2_jacobian_point_mul_sum(&_P, _k, &_P, _s);
+	sm2_jacobian_point_to_bytes(&_P, (uint8_t *)R);
+
+	sm2_bn_clean(_k);
+	sm2_bn_clean(_s);
+	return 1;
+}
+
+int sm2_point_print(FILE *fp, int fmt, int ind, const char *label, const SM2_POINT *P)
+{
+	format_print(fp, fmt, ind, "%s\n", label);
+	ind += 4;
+	format_bytes(fp, fmt, ind, "x", P->x, 32);
+	format_bytes(fp, fmt, ind, "y", P->y, 32);
+	return 1;
+}
+
+void sm2_point_to_compressed_octets(const SM2_POINT *P, uint8_t out[33])
+{
+	*out++ = (P->y[31] & 0x01) ? 0x03 : 0x02;
+	memcpy(out, P->x, 32);
+}
+
+void sm2_point_to_uncompressed_octets(const SM2_POINT *P, uint8_t out[65])
+{
+	*out++ = 0x04;
+	memcpy(out, P, 64);
+}
+
+int sm2_point_from_octets(SM2_POINT *P, const uint8_t *in, size_t inlen)
+{
+	if ((*in == 0x02 || *in == 0x03) && inlen == 33) {
+		if (sm2_point_from_x(P, in + 1, *in) != 1) {
+			error_print();
+			return -1;
+		}
+	} else if (*in == 0x04 && inlen == 65) {
+		if (sm2_point_from_xy(P, in + 1, in + 33) != 1) {
+			error_print();
+			return -1;
+		}
+	} else {
+		error_print();
+		return -1;
+	}
+	return 1;
+}
+
+int sm2_point_to_der(const SM2_POINT *P, uint8_t **out, size_t *outlen)
+{
+	uint8_t octets[65];
+	if (!P) {
+		return 0;
+	}
+	sm2_point_to_uncompressed_octets(P, octets);
+	if (asn1_octet_string_to_der(octets, sizeof(octets), out, outlen) != 1) {
+		error_print();
+		return -1;
+	}
+	return 1;
+}
+
+int sm2_point_from_der(SM2_POINT *P, const uint8_t **in, size_t *inlen)
+{
+	int ret;
+	const uint8_t *d;
+	size_t dlen;
+
+	if ((ret = asn1_octet_string_from_der(&d, &dlen, in, inlen)) != 1) {
+		if (ret < 0) error_print();
+		return ret;
+	}
+	if (dlen != 65) {
+		error_print();
+		return -1;
+	}
+	if (sm2_point_from_octets(P, d, dlen) != 1) {
+		error_print();
+		return -1;
+	}
+	return 1;
+}
+
+int sm2_point_from_hash(SM2_POINT *R, const uint8_t *data, size_t datalen)
+{
+	SM2_BN u;
+	SM2_Fp x;
+	SM2_Fp y;
+	SM2_Fp s;
+	SM2_Fp s_;
+	uint8_t dgst[32];
+
+	// u = (p + 1)/4
+	sm2_bn_add(u, SM2_P, SM2_ONE);
+	sm2_bn_rshift(u, u, 2);
+
+	do {
+		sm3_digest(data, datalen, dgst);
+
+		sm2_bn_from_bytes(x, dgst);
+		if (sm2_bn_cmp(x, SM2_P) >= 0) {
+			sm2_bn_sub(x, x, SM2_P);
+		}
+
+		// s = y^2 = x^3 + a*x + b
+		sm2_fp_sqr(s, x);
+		sm2_fp_sub(s, s, SM2_THREE);
+		sm2_fp_mul(s, s, x);
+		sm2_fp_add(s, s, SM2_B);
+
+		// y = s^((p+1)/4) = (sqrt(s) (mod p))
+		sm2_fp_exp(y, s, u);
+		sm2_fp_sqr(s_, y);
+
+		data = dgst;
+		datalen = sizeof(dgst);
+
+	} while (sm2_bn_cmp(s, s_) != 0);
+
+	sm2_bn_to_bytes(x, R->x);
+	sm2_bn_to_bytes(y, R->y);
+	return 1;
+}
+

+ 174 - 0
components/gmssl/src/sm2_blind.c

@@ -0,0 +1,174 @@
+/*
+ *  Copyright 2014-2022 The GmSSL Project. All Rights Reserved.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the License); you may
+ *  not use this file except in compliance with the License.
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <gmssl/sm2.h>
+#include <gmssl/mem.h>
+#include <gmssl/asn1.h>
+#include <gmssl/error.h>
+#include <gmssl/sm2_blind.h>
+
+
+extern SM2_BN SM2_N;
+extern SM2_BN SM2_ONE;
+
+int sm2_blind_sign_commit(SM2_Fn k, uint8_t *commit, size_t *commitlen)
+{
+	SM2_POINT K;
+	uint8_t k_bytes[32];
+
+	sm2_fn_rand(k); // FIXME: check return
+	sm2_bn_to_bytes(k, k_bytes);
+
+	// commitment = k * G
+	sm2_point_mul_generator(&K, k_bytes);
+	sm2_point_to_compressed_octets(&K, commit);
+	*commitlen = 33;
+	gmssl_secure_clear(k_bytes, sizeof(k_bytes));
+
+	return 1;
+}
+
+int sm2_blind_sign_init(SM2_BLIND_SIGN_CTX *ctx, const SM2_KEY *public_key, const char *id, size_t idlen)
+{
+	ctx->public_key = *public_key;
+	sm3_init(&ctx->sm3_ctx);
+	if (id) {
+		uint8_t z[SM3_DIGEST_SIZE];
+		if (idlen <= 0 || idlen > SM2_MAX_ID_LENGTH) {
+			error_print();
+			return -1;
+		}
+		sm2_compute_z(z, &public_key->public_key, id, idlen);
+		sm3_update(&ctx->sm3_ctx, z, sizeof(z));
+	}
+	return 1;
+}
+
+int sm2_blind_sign_update(SM2_BLIND_SIGN_CTX *ctx, const uint8_t *data, size_t datalen)
+{
+	if (!ctx) {
+		error_print();
+		return -1;
+	}
+	if (data && datalen > 0) {
+		sm3_update(&ctx->sm3_ctx, data, datalen);
+	}
+	return 1;
+}
+
+int sm2_blind_sign_finish(SM2_BLIND_SIGN_CTX *ctx,
+	const uint8_t *commit, size_t commitlen,
+	uint8_t blinded_sig_r[32])
+{
+	int ret = -1;
+	SM2_Fn a;
+	SM2_Fn b;
+	SM2_POINT K;
+	SM2_Fn e;
+	SM2_Fn r;
+	uint8_t dgst[32];
+
+	sm3_finish(&ctx->sm3_ctx, dgst);
+	sm2_bn_from_bytes(e, dgst);
+	if (sm2_bn_cmp(e, SM2_N) >= 0) {
+		sm2_bn_sub(e, e, SM2_N);
+	}
+
+	//FIXME: return value of sm2_fn_rand()
+	sm2_fn_rand(a);
+	sm2_bn_to_bytes(a, ctx->blind_factor_a);
+	sm2_fn_rand(b);
+	sm2_bn_to_bytes(b, ctx->blind_factor_b);
+
+	if (sm2_point_from_octets(&K, commit, commitlen) != 1) {
+		error_print();
+		goto end;
+	}
+	// K'(x1, y1) = a * K + b * G
+	if (sm2_point_mul_sum(&K, ctx->blind_factor_a, &K, ctx->blind_factor_b) != 1) {
+		error_print();
+		goto end;
+	}
+	sm2_bn_from_bytes(r, K.x);
+	if (sm2_bn_cmp(r, SM2_N) >= 0) {
+		sm2_bn_sub(r, r, SM2_N);
+	}
+
+	// r = x1 + e (mod n)
+	sm2_fn_add(r, r, e);
+	sm2_bn_to_bytes(r, ctx->sig_r);
+
+	// r' = a^-1 * (r + b)
+	sm2_fn_add(r, r, b);
+	sm2_fn_inv(a, a);
+	sm2_fn_mul(r, r, a);
+
+	sm2_bn_to_bytes(r, blinded_sig_r);
+	ret = 1;
+
+end:
+	gmssl_secure_clear(a, sizeof(a));
+	gmssl_secure_clear(b, sizeof(b));
+	return ret;
+}
+
+int sm2_blind_sign(const SM2_KEY *key, const SM2_Fn k, const uint8_t blinded_r[32], uint8_t blinded_s[32])
+{
+	SM2_Fn x;
+	SM2_Fn r;
+	SM2_Fn s;
+
+	sm2_bn_from_bytes(x, key->private_key);
+	sm2_bn_from_bytes(r, blinded_r);
+
+	// s = (1 + x)^-1 * (k - r * x) (mod n)
+	sm2_fn_mul(r, r, x);
+	sm2_fn_sub(s, k, r);
+	sm2_fn_add(x, x, SM2_ONE);
+	sm2_fn_inv(x, x);
+	sm2_fn_mul(s, s, x);
+	sm2_bn_to_bytes(s, blinded_s);
+
+	gmssl_secure_clear(x, sizeof(x));
+	gmssl_secure_clear(r, sizeof(r));
+	gmssl_secure_clear(s, sizeof(s));
+	return 1;
+}
+
+int sm2_blind_sign_unblind(SM2_BLIND_SIGN_CTX *ctx, const uint8_t blinded_sig_s[32], uint8_t *sig, size_t *siglen)
+{
+	SM2_Fn a;
+	SM2_Fn b;
+	SM2_Fn s;
+	SM2_SIGNATURE signature;
+
+	sm2_bn_from_bytes(a, ctx->blind_factor_a);
+	sm2_bn_from_bytes(b, ctx->blind_factor_b);
+	sm2_bn_from_bytes(s, blinded_sig_s);
+
+	// s = a * s' + b
+	sm2_fn_mul(s, s, a);
+	sm2_fn_add(s, s, b);
+
+	memcpy(signature.r, ctx->sig_r, 32);
+	sm2_bn_to_bytes(s, signature.s);
+
+
+	*siglen = 0;
+	sm2_signature_to_der(&signature, &sig, siglen);
+
+	gmssl_secure_clear(a, sizeof(a));
+	gmssl_secure_clear(b, sizeof(b));
+	gmssl_secure_clear(ctx, sizeof(*ctx));
+	return 1;
+}

+ 172 - 0
components/gmssl/src/sm2_commit.c

@@ -0,0 +1,172 @@
+/*
+ *  Copyright 2014-2022 The GmSSL Project. All Rights Reserved.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the License); you may
+ *  not use this file except in compliance with the License.
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <stdint.h>
+#include <gmssl/sm2.h>
+#include <gmssl/sm3.h>
+#include <gmssl/mem.h>
+#include <gmssl/asn1.h>
+#include <gmssl/rand.h>
+#include <gmssl/error.h>
+#include <gmssl/sm2_commit.h>
+
+
+#define SM2_COMMIT_SEED "GmSSL SM2 Pederson Commitment Generator H"
+
+
+// C = rG + xH
+int sm2_commit_generate(const uint8_t x[32], uint8_t r[32], uint8_t commit[65], size_t *commitlen)
+{
+	SM2_POINT H;
+	SM2_POINT C;
+	SM2_BN r_;
+
+	if (sm2_point_from_hash(&H, (uint8_t *)SM2_COMMIT_SEED, sizeof(SM2_COMMIT_SEED)-1) != 1) {
+		error_print();
+		return -1;
+	}
+
+	do {
+		sm2_fn_rand(r_);
+	} while (sm2_bn_is_zero(r_));
+
+	sm2_bn_to_bytes(r_, r);
+	gmssl_secure_clear(r_, sizeof(r_));
+
+	// C = xH + rG
+	sm2_point_mul_sum(&C, x, &H, r);
+
+	sm2_point_to_compressed_octets(&C, commit);
+	*commitlen = 33;
+	return 1;
+}
+
+int sm2_commit_open(const uint8_t x[32], const uint8_t r[32], const uint8_t *commit, size_t commitlen)
+{
+	SM2_POINT H;
+	SM2_POINT C;
+	SM2_POINT C_;
+
+	if (sm2_point_from_octets(&C, commit, commitlen) != 1) {
+		error_print();
+		return -1;
+	}
+
+	if (sm2_point_from_hash(&H, (uint8_t *)SM2_COMMIT_SEED, sizeof(SM2_COMMIT_SEED)-1) != 1) {
+		error_print();
+		return -1;
+	}
+
+	// C' = xH + rG
+	if (sm2_point_mul_sum(&C_, x, &H, r) != 1) {
+		error_print();
+		return -1;
+	}
+
+	if (memcmp(&C, &C_, sizeof(SM2_POINT)) != 0) {
+		error_print();
+		return 0;
+	}
+	return 1;
+}
+
+// C = r*G + x1*H1 + x2*H2 + ...
+int sm2_commit_vector_generate(const sm2_bn_t *x, size_t count, uint8_t r[32], uint8_t commit[65], size_t *commitlen)
+{
+	SM2_POINT H;
+	SM2_POINT C;
+	SM2_Fn r_;
+	size_t i;
+
+	if (count < 1) {
+		error_print();
+		return -1;
+	}
+
+	if (sm2_point_from_hash(&H, (uint8_t *)SM2_COMMIT_SEED, sizeof(SM2_COMMIT_SEED)-1) != 1) {
+		error_print();
+		return -1;
+	}
+
+	do {
+		sm2_fn_rand(r_);
+	} while (sm2_bn_is_zero(r_));
+
+	sm2_bn_to_bytes(r_, r);
+	gmssl_secure_clear(r_, sizeof(r_));
+
+	if (sm2_point_mul_sum(&C, x[0], &H, r) != 1) {
+		error_print();
+		return -1;
+	}
+
+	for (i = 1; i < count; i++) {
+		SM2_POINT xH;
+
+		if (sm2_point_from_hash(&H, (uint8_t *)&H, sizeof(H)) != 1
+			|| sm2_point_mul(&xH, x[i], &H) != 1
+			|| sm2_point_add(&C, &C, &xH) != 1) {
+			error_print();
+			return -1;
+		}
+	}
+
+	sm2_point_to_compressed_octets(&C, commit);
+	*commitlen = 33;
+	return 1;
+}
+
+int sm2_commit_vector_open(const sm2_bn_t *x, size_t count, const uint8_t r[32], const uint8_t *commit, size_t commitlen)
+{
+	SM2_POINT H;
+	SM2_POINT C;
+	SM2_POINT C_;
+	size_t i;
+
+	if (count < 1) {
+		error_print();
+		return -1;
+	}
+
+	if (sm2_point_from_octets(&C, commit, commitlen) != 1) {
+		error_print();
+		return -1;
+	}
+
+	if (sm2_point_from_hash(&H, (uint8_t *)SM2_COMMIT_SEED, sizeof(SM2_COMMIT_SEED)-1) != 1) {
+		error_print();
+		return -1;
+	}
+
+	if (sm2_point_mul_sum(&C_, x[0], &H, r) != 1) {
+		error_print();
+		return -1;
+	}
+
+	for (i = 1; i< count; i++) {
+		SM2_POINT xH;
+
+		if (sm2_point_from_hash(&H, (uint8_t *)&H, sizeof(H)) != 1
+			|| sm2_point_mul(&xH, x[i], &H) != 1
+			|| sm2_point_add(&C_, &C_, &xH) != 1) {
+			error_print();
+			return -1;
+		}
+	}
+
+	if (memcmp(&C, &C_, sizeof(SM2_POINT)) != 0) {
+		error_print();
+		return -1;
+	}
+	return 1;
+}

+ 412 - 0
components/gmssl/src/sm2_elgamal.c

@@ -0,0 +1,412 @@
+/*
+ *  Copyright 2014-2022 The GmSSL Project. All Rights Reserved.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the License); you may
+ *  not use this file except in compliance with the License.
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <stdint.h>
+#include <assert.h>
+#include <gmssl/mem.h>
+#include <gmssl/sm2_elgamal.h>
+#include <gmssl/asn1.h>
+#include <gmssl/error.h>
+
+
+extern const SM2_JACOBIAN_POINT *SM2_G;
+
+
+
+// generate baby-step table
+int sm2_elgamal_decrypt_pre_compute(SM2_PRE_COMPUTE table[1<<16])
+{
+	SM2_JACOBIAN_POINT P;
+	SM2_BN x;
+	uint32_t i, j;
+
+	memset(table, 0, sizeof(SM2_PRE_COMPUTE) * (1<<16));
+
+	sm2_jacobian_point_set_infinity(&P);
+	for (i = 0; i < (1<<16); i++) {
+		sm2_jacobian_point_add(&P, &P, SM2_G);
+		sm2_jacobian_point_get_xy(&P, x, NULL);
+		sm2_bn_to_bytes(x, table[i].x_coordinate);
+
+		j = ((uint16_t)table[i].x_coordinate[30] << 8) | table[i].x_coordinate[31];
+		assert(table[j].offset_count <= SM2_PRE_COMPUTE_MAX_OFFSETS);
+
+		table[j].offset[ table[j].offset_count ] = (uint16_t)i;
+		(table[j].offset_count)++;
+	}
+	return 1;
+}
+
+static int sm2_pre_compute_get_offset(const SM2_PRE_COMPUTE table[1<<16], const uint8_t x[32], uint16_t *offset)
+{
+	uint32_t i = ((uint16_t)x[30] << 8) | x[31];
+	uint16_t j;
+	uint8_t w;
+
+	for (w = 0; w < table[i].offset_count; w++) {
+		j = table[i].offset[w];
+		if (memcmp(x, table[j].x_coordinate, 32) == 0) {
+			*offset = j;
+			return 1;
+		}
+	}
+	return 0;
+}
+
+// run gaint-step
+int sm2_elgamal_solve_ecdlp(const SM2_PRE_COMPUTE table[1<<16], const SM2_POINT *point, uint32_t *private)
+{
+	int ret = 0;
+	SM2_JACOBIAN_POINT P;
+	SM2_JACOBIAN_POINT Q;
+	SM2_BN k;
+	SM2_BN x;
+	uint8_t x_bytes[32];
+	uint8_t Q_bytes[64];
+	uint32_t i;
+	uint16_t j;
+
+	sm2_jacobian_point_from_bytes(&P, (uint8_t *)point);
+
+	// Q = -[2^16]G
+	sm2_bn_set_word(k, 65536);
+	sm2_jacobian_point_mul_generator(&Q, k);
+	sm2_jacobian_point_neg(&Q, &Q);
+
+	// Q to Affine
+	sm2_jacobian_point_to_bytes(&Q, Q_bytes);
+	sm2_jacobian_point_from_bytes(&Q, Q_bytes);
+
+	for (i = 0; i < (1<<16); i++) {
+		// P - i*(kG) == O ==> d = i*k
+		if (sm2_jacobian_point_is_at_infinity(&P)) {
+			*private = (i << 16);
+			ret = 1;
+			goto ok;
+		}
+
+		sm2_jacobian_point_get_xy(&P, x, NULL);
+		sm2_bn_to_bytes(x, x_bytes);
+		if (sm2_pre_compute_get_offset(table, x_bytes, &j) == 1) {
+			// P - i*(kG) == j*G ==> d = j + i*k
+			*private = (i<<16) + j + 1; // table[0] is 1*G, so j + 1
+			ret = 1;
+			goto ok;
+		}
+		sm2_jacobian_point_add(&P, &P, &Q);
+	}
+	printf("gaint steps failed\n");
+
+ok:
+	i = j = 0;
+	gmssl_secure_clear(x, sizeof(x));
+	return ret;
+}
+
+int sm2_elgamal_do_encrypt(const SM2_KEY *pub_key, uint32_t in, SM2_ELGAMAL_CIPHERTEXT *out)
+{
+	int ret = -1;
+	SM2_Fn k;
+	SM2_Fn m;
+	uint8_t k_bytes[32];
+	uint8_t m_bytes[32];
+
+	if (!pub_key || !out) {
+		error_print();
+		return -1;
+	}
+
+	do {
+		if (sm2_fn_rand(k) != 1) {
+			error_print();
+			return -1;
+		}
+	} while (sm2_bn_is_zero(k));
+	sm2_bn_to_bytes(k, k_bytes);
+
+	// C1 = k * G
+	if (sm2_point_mul_generator(&out->C1, k_bytes) != 1) {
+		error_print();
+		goto end;
+	}
+
+	// C2 = k * P + m * G
+	sm2_bn_set_word(m, in);
+	sm2_bn_to_bytes(m, m_bytes);
+	if (sm2_point_mul_sum(&out->C2, k_bytes, &pub_key->public_key, m_bytes) != 1) {
+		error_print();
+		goto end;
+	}
+	ret = 1;
+
+end:
+	gmssl_secure_clear(k, sizeof(k));
+	gmssl_secure_clear(m, sizeof(m));
+	gmssl_secure_clear(k_bytes, sizeof(k_bytes));
+	gmssl_secure_clear(m_bytes, sizeof(m_bytes));
+	return ret;
+}
+
+// M = m*G = -x*C1 + C2
+int sm2_elgamal_do_decrypt(const SM2_KEY *key, const SM2_ELGAMAL_CIPHERTEXT *in, uint32_t *out)
+{
+	static SM2_PRE_COMPUTE *table = NULL;
+	SM2_POINT M;
+
+	if (!key || !in || !out) {
+		error_print();
+		return -1;
+	}
+
+	sm2_point_mul(&M, key->private_key, &in->C1);
+	sm2_point_sub(&M, &in->C2, &M);
+
+	if (!table) {
+		if (!(table = malloc(sizeof(SM2_PRE_COMPUTE) * (1<<16)))) {
+			error_print();
+			return -1;
+		}
+		sm2_elgamal_decrypt_pre_compute(table);
+	}
+
+	if (sm2_elgamal_solve_ecdlp(table, &M, out) != 1) {
+		error_print();
+		return -1;
+	}
+	return 1;
+}
+
+// (A1, A2) = (k1*G, m1*G + k1*P)
+// (B1, B2) = (k2*G, m2*G + k2*P)
+// (R1, R2) = (A1 + B1 + k*G, A2 + B2 + k*P)
+int sm2_elgamal_ciphertext_add(SM2_ELGAMAL_CIPHERTEXT *r,
+	const SM2_ELGAMAL_CIPHERTEXT *a,
+	const SM2_ELGAMAL_CIPHERTEXT *b,
+	const SM2_KEY *pub_key)
+{
+	SM2_Fn k;
+	uint8_t k_bytes[32];
+	SM2_POINT R;
+
+	if (!r || !a || !b || !pub_key) {
+		error_print();
+		return -1;
+	}
+
+	do {
+		if (sm2_fn_rand(k) != 1) {
+			error_print();
+			return -1;
+		}
+	} while (sm2_bn_is_zero(k));
+	sm2_bn_to_bytes(k, k_bytes);
+
+	// R1 = A1 + B1 + k*G
+	sm2_point_add(&r->C1, &a->C1, &b->C1);
+	sm2_point_mul_generator(&R, k_bytes);
+	sm2_point_add(&r->C1, &r->C1, &R);
+
+	// R2 = A2 + B2 + k*P
+	sm2_point_add(&r->C2, &a->C2, &b->C2);
+	sm2_point_mul(&R, k_bytes, &pub_key->public_key);
+	sm2_point_add(&r->C2, &r->C2, &R);
+
+	gmssl_secure_clear(k, sizeof(k));
+	gmssl_secure_clear(k_bytes, sizeof(k_bytes));
+	return 1;
+}
+
+int sm2_elgamal_cipehrtext_sub(SM2_ELGAMAL_CIPHERTEXT *r,
+	const SM2_ELGAMAL_CIPHERTEXT *a, const SM2_ELGAMAL_CIPHERTEXT *b,
+	const SM2_KEY *pub_key)
+{
+	SM2_Fn k;
+	uint8_t k_bytes[32];
+	SM2_POINT R;
+
+	if (!r || !a || !b || !pub_key) {
+		error_print();
+		return -1;
+	}
+
+	do {
+		if (sm2_fn_rand(k) != 1) {
+			error_print();
+			return -1;
+		}
+	} while (sm2_bn_is_zero(k));
+	sm2_bn_to_bytes(k, k_bytes);
+
+	// R1 = A1 - B1 + k*G
+	sm2_point_sub(&r->C1, &a->C1, &b->C1);
+	sm2_point_mul_generator(&R, k_bytes);
+	sm2_point_add(&r->C1, &a->C1, &R);
+
+	// R2 = A2 - B2 + k*P
+	sm2_point_sub(&r->C2, &a->C2, &b->C2);
+	sm2_point_mul(&R, k_bytes, &pub_key->public_key);
+	sm2_point_add(&r->C2, &r->C2, &R);
+
+	gmssl_secure_clear(k, sizeof(k));
+	gmssl_secure_clear(k_bytes, sizeof(k_bytes));
+	return 1;
+}
+
+int sm2_elgamal_cipehrtext_neg(SM2_ELGAMAL_CIPHERTEXT *r,
+	const SM2_ELGAMAL_CIPHERTEXT *a, const SM2_KEY *pub_key)
+{
+	SM2_Fn k;
+	uint8_t k_bytes[32];
+	SM2_POINT R;
+
+	if (!r || !a || !pub_key) {
+		error_print();
+		return -1;
+	}
+
+	do {
+		if (sm2_fn_rand(k) != 1) {
+			error_print();
+			return -1;
+		}
+	} while (sm2_bn_is_zero(k));
+	sm2_bn_to_bytes(k, k_bytes);
+
+	// R1 = -A1 + k*G = -r*G + k*G
+	sm2_point_mul_generator(&R, k_bytes);
+	sm2_point_sub(&r->C1, &R, &a->C1);
+
+	// R2 = -A2 + k*P = -m*G -r*P + k*P
+	sm2_point_mul(&R, k_bytes, &pub_key->public_key);
+	sm2_point_sub(&r->C2, &R, &a->C2);
+
+	gmssl_secure_clear(k, sizeof(k));
+	gmssl_secure_clear(k_bytes, sizeof(k_bytes));
+	return 1;
+}
+
+// s * (C1, C2) := (s*C1 + r*G, s*C2 + r*P)
+int sm2_elgamal_ciphertext_scalar_mul(SM2_ELGAMAL_CIPHERTEXT *R,
+	const uint8_t scalar[32], const SM2_ELGAMAL_CIPHERTEXT *A,
+	const SM2_KEY *pub_key)
+{
+	SM2_Fn k;
+	uint8_t k_bytes[32];
+	SM2_POINT kP;
+
+	if (!R || !scalar || !A || !pub_key) {
+		error_print();
+		return -1;
+	}
+
+	do {
+		if (sm2_fn_rand(k) != 1) {
+			error_print();
+			return -1;
+		}
+	} while (sm2_bn_is_zero(k));
+	sm2_bn_to_bytes(k, k_bytes);
+
+	// R1 = s*C1 + k*G
+	sm2_point_mul_sum(&R->C1, scalar, &A->C1, k_bytes);
+
+	// R2 = s*C2 + r*P
+	sm2_point_mul(&kP, k_bytes, &pub_key->public_key);
+	sm2_point_mul(&R->C2, scalar, &A->C2);
+	sm2_point_add(&R->C2, &R->C2, &kP);
+
+	gmssl_secure_clear(k, sizeof(k));
+	gmssl_secure_clear(k_bytes, sizeof(k_bytes));
+	return 1;
+}
+
+int sm2_elgamal_ciphertext_to_der(const SM2_ELGAMAL_CIPHERTEXT *c, uint8_t **out, size_t *outlen)
+{
+	uint8_t c1[65];
+	uint8_t c2[65];
+	size_t len;
+
+	sm2_point_to_uncompressed_octets(&c->C1, c1);
+	sm2_point_to_uncompressed_octets(&c->C2, c2);
+
+	if (asn1_octet_string_to_der(c1, sizeof(c1), NULL, &len) != 1
+		|| asn1_octet_string_to_der(c2, sizeof(c2), NULL, &len) != 1
+		|| asn1_sequence_header_to_der(len, out, outlen) != 1
+		|| asn1_octet_string_to_der(c1, sizeof(c1), out, outlen) != 1
+		|| asn1_octet_string_to_der(c2, sizeof(c2), out, outlen) != 1) {
+		error_print();
+		return -1;
+	}
+
+	return 1;
+}
+
+int sm2_elgamal_ciphertext_from_der(SM2_ELGAMAL_CIPHERTEXT *c, const uint8_t **in, size_t *inlen)
+{
+	int ret;
+	const uint8_t *d;
+	size_t dlen;
+	const uint8_t *c1;
+	size_t c1len;
+	const uint8_t *c2;
+	size_t c2len;
+
+	if ((ret = asn1_sequence_from_der(&d, &dlen, in, inlen)) != 1) {
+		error_print();
+		return -1;
+	}
+	if (asn1_octet_string_from_der(&c1, &c1len, &d, &dlen) != 1
+		|| asn1_octet_string_from_der(&c2, &c2len, &d, &dlen) != 1
+		|| asn1_length_is_zero(dlen) != 1) {
+		error_print();
+		return -1;
+	}
+	if (sm2_point_from_octets(&c->C1, c1, c1len) != 1
+		|| sm2_point_from_octets(&c->C2, c2, c2len) != 1) {
+		error_print();
+		return -1;
+	}
+	return 1;
+}
+
+int sm2_elgamal_encrypt(const SM2_KEY *pub_key, uint32_t in, uint8_t *out, size_t *outlen)
+{
+	SM2_ELGAMAL_CIPHERTEXT C;
+
+	if (sm2_elgamal_do_encrypt(pub_key, in, &C) != 1) {
+		error_print();
+		return -1;
+	}
+	*outlen = 0;
+	if (sm2_elgamal_ciphertext_to_der(&C, &out, outlen) != 1) {
+		error_print();
+		return -1;
+	}
+	return 1;
+}
+
+int sm2_elgamal_decrypt(SM2_KEY *key, const uint8_t *in, size_t inlen, uint32_t *out)
+{
+	SM2_ELGAMAL_CIPHERTEXT C;
+
+	if (sm2_elgamal_ciphertext_from_der(&C, &in, &inlen) != 1
+		|| asn1_length_is_zero(inlen) != 1) {
+		error_print();
+		return -1;
+	}
+	if (sm2_elgamal_do_decrypt(key, &C, out) != 1) {
+		error_print();
+		return -1;
+	}
+	return 1;
+}

+ 691 - 0
components/gmssl/src/sm2_key.c

@@ -0,0 +1,691 @@
+/*
+ *  Copyright 2014-2022 The GmSSL Project. All Rights Reserved.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the License); you may
+ *  not use this file except in compliance with the License.
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ */
+
+
+#include <string.h>
+#include <gmssl/sm2.h>
+#include <gmssl/oid.h>
+#include <gmssl/asn1.h>
+#include <gmssl/pem.h>
+#include <gmssl/sm4.h>
+#include <gmssl/rand.h>
+#include <gmssl/pbkdf2.h>
+#include <gmssl/pkcs8.h>
+#include <gmssl/error.h>
+#include <gmssl/ec.h>
+#include <gmssl/mem.h>
+#include <gmssl/x509_alg.h>
+
+
+extern const SM2_BN SM2_N;
+
+
+int sm2_key_generate(SM2_KEY *key)
+{
+	SM2_BN x;
+	SM2_BN y;
+	SM2_JACOBIAN_POINT _P, *P = &_P;
+
+	if (!key) {
+		error_print();
+		return -1;
+	}
+	memset(key, 0, sizeof(SM2_KEY));
+
+	do {
+		if (sm2_bn_rand_range(x, SM2_N) != 1) {
+			error_print();
+			return -1;
+		}
+	} while (sm2_bn_is_zero(x));
+	sm2_bn_to_bytes(x, key->private_key);
+
+	sm2_jacobian_point_mul_generator(P, x);
+	sm2_jacobian_point_get_xy(P, x, y);
+	sm2_bn_to_bytes(x, key->public_key.x);
+	sm2_bn_to_bytes(y, key->public_key.y);
+
+	return 1;
+}
+
+int sm2_key_set_private_key(SM2_KEY *key, const uint8_t private_key[32])
+{
+	SM2_BN bn;
+
+	sm2_bn_from_bytes(bn, private_key);
+
+	if (sm2_bn_is_zero(bn)
+		|| sm2_bn_cmp(bn, SM2_N) >= 0) {
+		gmssl_secure_clear(bn, sizeof(bn));
+		error_print();
+		return -1;
+	}
+
+	memcpy(&key->private_key, private_key, 32);
+
+	if (sm2_point_mul_generator(&key->public_key, private_key) != 1) {
+		gmssl_secure_clear(bn, sizeof(bn));
+		gmssl_secure_clear(key, sizeof(SM2_KEY));
+		error_print();
+		return -1;
+	}
+
+	gmssl_secure_clear(bn, sizeof(bn));
+	return 1;
+}
+
+int sm2_key_set_public_key(SM2_KEY *key, const SM2_POINT *public_key)
+{
+	if (!key || !public_key) {
+		error_print();
+		return -1;
+	}
+	if (!sm2_point_is_on_curve(public_key)) {
+		error_print();
+		return -1;
+	}
+	gmssl_secure_clear(key, sizeof(SM2_KEY));
+	key->public_key = *public_key;
+	return 1;
+}
+
+int sm2_key_print(FILE *fp, int fmt, int ind, const char *label, const SM2_KEY *key)
+{
+	format_print(fp, fmt, ind, "%s\n", label);
+	ind += 4;
+	sm2_public_key_print(fp, fmt, ind, "publicKey", key);
+	format_bytes(fp, fmt, ind, "privateKey", key->private_key, 32);
+	return 1;
+}
+
+int sm2_public_key_to_der(const SM2_KEY *key, uint8_t **out, size_t *outlen)
+{
+	uint8_t buf[65];
+	size_t len = 0;
+
+	if (!key) {
+		return 0;
+	}
+	sm2_point_to_uncompressed_octets(&key->public_key, buf);
+	if (asn1_bit_octets_to_der(buf, sizeof(buf), out, outlen) != 1) {
+		error_print();
+		return -1;
+	}
+	return 1;
+}
+
+int sm2_public_key_from_der(SM2_KEY *key, const uint8_t **in, size_t *inlen)
+{
+	int ret;
+	const uint8_t *d;
+	size_t dlen;
+	SM2_POINT P;
+
+	if ((ret = asn1_bit_octets_from_der(&d, &dlen, in, inlen)) != 1) {
+		if (ret < 0) error_print();
+		return ret;
+	}
+	if (dlen != 65) {
+		error_print();
+		return -1;
+	}
+	if (sm2_point_from_octets(&P, d, dlen) != 1
+		|| sm2_key_set_public_key(key, &P) != 1) {
+		error_print();
+		return -1;
+	}
+	return 1;
+}
+
+int sm2_public_key_print(FILE *fp, int fmt, int ind, const char *label, const SM2_KEY *pub_key)
+{
+	return sm2_point_print(fp, fmt, ind, label, &pub_key->public_key);
+}
+
+int sm2_public_key_algor_to_der(uint8_t **out, size_t *outlen)
+{
+	if (x509_public_key_algor_to_der(OID_ec_public_key, OID_sm2, out, outlen) != 1) {
+		error_print();
+		return -1;
+	}
+	return 1;
+}
+
+int sm2_public_key_algor_from_der(const uint8_t **in, size_t *inlen)
+{
+	int ret;
+	int oid;
+	int curve;
+
+	if ((ret = x509_public_key_algor_from_der(&oid, &curve, in, inlen)) != 1) {
+		if (ret < 0) error_print();
+		return ret;
+	}
+	if (oid != OID_ec_public_key) {
+		error_print();
+		return -1;
+	}
+	if (curve != OID_sm2) {
+		error_print();
+		return -1;
+	}
+	return 1;
+}
+
+#define SM2_PRIVATE_KEY_DER_SIZE 121
+int sm2_private_key_to_der(const SM2_KEY *key, uint8_t **out, size_t *outlen)
+{
+	size_t len = 0;
+	uint8_t params[64];
+	uint8_t pubkey[128];
+	uint8_t *params_ptr = params;
+	uint8_t *pubkey_ptr = pubkey;
+	size_t params_len = 0;
+	size_t pubkey_len = 0;
+
+	if (!key) {
+		error_print();
+		return -1;
+	}
+	if (ec_named_curve_to_der(OID_sm2, &params_ptr, &params_len) != 1
+		|| sm2_public_key_to_der(key, &pubkey_ptr, &pubkey_len) != 1) {
+		error_print();
+		return -1;
+	}
+	if (asn1_int_to_der(EC_private_key_version, NULL, &len) != 1
+		|| asn1_octet_string_to_der(key->private_key, 32, NULL, &len) != 1
+		|| asn1_explicit_to_der(0, params, params_len, NULL, &len) != 1
+		|| asn1_explicit_to_der(1, pubkey, pubkey_len, NULL, &len) != 1
+		|| asn1_sequence_header_to_der(len, out, outlen) != 1
+		|| asn1_int_to_der(EC_private_key_version, out, outlen) != 1
+		|| asn1_octet_string_to_der(key->private_key, 32, out, outlen) != 1
+		|| asn1_explicit_to_der(0, params, params_len, out, outlen) != 1
+		|| asn1_explicit_to_der(1, pubkey, pubkey_len, out, outlen) != 1) {
+		error_print();
+		return -1;
+	}
+	return 1;
+}
+
+int sm2_private_key_from_der(SM2_KEY *key, const uint8_t **in, size_t *inlen)
+{
+	int ret;
+	const uint8_t *d;
+	size_t dlen;
+	int ver;
+	const uint8_t *prikey;
+	const uint8_t *params;
+	const uint8_t *pubkey;
+	size_t prikey_len, params_len, pubkey_len;
+
+	if ((ret = asn1_sequence_from_der(&d, &dlen, in, inlen)) != 1) {
+		if (ret < 0) error_print();
+		return ret;
+	}
+	if (asn1_int_from_der(&ver, &d, &dlen) != 1
+		|| asn1_octet_string_from_der(&prikey, &prikey_len, &d, &dlen) != 1
+		|| asn1_explicit_from_der(0, &params, &params_len, &d, &dlen) != 1
+		|| asn1_explicit_from_der(1, &pubkey, &pubkey_len, &d, &dlen) != 1
+		|| asn1_check(ver == EC_private_key_version) != 1
+		|| asn1_length_is_zero(dlen) != 1) {
+		error_print();
+		return -1;
+	}
+	if (params) {
+		int curve;
+		if (ec_named_curve_from_der(&curve, &params, &params_len) != 1
+			|| asn1_check(curve == OID_sm2) != 1
+			|| asn1_length_is_zero(params_len) != 1) {
+			error_print();
+			return -1;
+		}
+	}
+	if (asn1_check(prikey_len == 32) != 1
+		|| sm2_key_set_private_key(key, prikey) != 1) {
+		error_print();
+		return -1;
+	}
+
+	// check if the public key is correct
+	if (pubkey) {
+		SM2_KEY tmp_key;
+		if (sm2_public_key_from_der(&tmp_key, &pubkey, &pubkey_len) != 1
+			|| asn1_length_is_zero(pubkey_len) != 1) {
+			error_print();
+			return -1;
+		}
+		if (sm2_public_key_equ(key, &tmp_key) != 1) {
+			error_print();
+			return -1;
+		}
+	}
+	return 1;
+}
+
+int sm2_private_key_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen)
+{
+	return ec_private_key_print(fp, fmt, ind, label, d, dlen);
+}
+
+#define SM2_PRIVATE_KEY_INFO_DER_SIZE 150
+
+int sm2_private_key_info_to_der(const SM2_KEY *sm2_key, uint8_t **out, size_t *outlen)
+{
+	size_t len = 0;
+	uint8_t prikey[SM2_PRIVATE_KEY_DER_SIZE];
+	uint8_t *p = prikey;
+	size_t prikey_len = 0;
+
+	if (sm2_private_key_to_der(sm2_key, &p, &prikey_len) != 1) {
+		error_print();
+		return -1;
+	}
+	if (asn1_int_to_der(PKCS8_private_key_info_version, NULL, &len) != 1
+		|| sm2_public_key_algor_to_der(NULL, &len) != 1
+		|| asn1_octet_string_to_der(prikey, prikey_len, NULL, &len) != 1
+		|| asn1_sequence_header_to_der(len, out, outlen) != 1
+		|| asn1_int_to_der(PKCS8_private_key_info_version, out, outlen) != 1
+		|| sm2_public_key_algor_to_der(out, outlen) != 1
+		|| asn1_octet_string_to_der(prikey, prikey_len, out, outlen) != 1) {
+		memset(prikey, 0, sizeof(prikey));
+		error_print();
+		return -1;
+	}
+	memset(prikey, 0, sizeof(prikey));
+	return 1;
+}
+
+int sm2_private_key_info_from_der(SM2_KEY *sm2_key, const uint8_t **attrs, size_t *attrslen,
+	const uint8_t **in, size_t *inlen)
+{
+	int ret;
+	const uint8_t *d;
+	size_t dlen;
+	int version;
+	const uint8_t *prikey;
+	size_t prikey_len;
+
+	if ((ret = asn1_sequence_from_der(&d, &dlen, in, inlen)) != 1) {
+		if (ret < 0) error_print();
+		return ret;
+	}
+	if (asn1_int_from_der(&version, &d, &dlen) != 1
+		|| sm2_public_key_algor_from_der(&d, &dlen) != 1
+		|| asn1_octet_string_from_der(&prikey, &prikey_len, &d, &dlen) != 1
+		|| asn1_implicit_set_from_der(0, attrs, attrslen, &d, &dlen) < 0
+		|| asn1_length_is_zero(dlen) != 1) {
+		error_print();
+		return -1;
+	}
+	if (asn1_check(version == PKCS8_private_key_info_version) != 1
+		|| sm2_private_key_from_der(sm2_key, &prikey, &prikey_len) != 1
+		|| asn1_length_is_zero(prikey_len) != 1) {
+		error_print();
+		return -1;
+	}
+	return 1;
+}
+
+int sm2_private_key_info_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen)
+{
+	int ret;
+	const uint8_t *p;
+	size_t len;
+	int val;
+	const uint8_t *prikey;
+	size_t prikey_len;
+
+	format_print(fp, fmt, ind, "%s\n", label);
+	ind += 4;
+
+	if (asn1_int_from_der(&val, &d, &dlen) != 1) goto err;
+	format_print(fp, fmt, ind, "version: %d\n", val);
+	if (asn1_sequence_from_der(&p, &len, &d, &dlen) != 1) goto err;
+	x509_public_key_algor_print(fp, fmt, ind, "privateKeyAlgorithm", p, len);
+	if (asn1_octet_string_from_der(&p, &len, &d, &dlen) != 1) goto err;
+	if (asn1_sequence_from_der(&prikey, &prikey_len, &p, &len) != 1) goto err;
+	ec_private_key_print(fp, fmt, ind + 4, "privateKey", prikey, prikey_len);
+	if (asn1_length_is_zero(len) != 1) goto err;
+	if ((ret = asn1_implicit_set_from_der(0, &p, &len, &d, &dlen)) < 0) goto err;
+	else if (ret) format_bytes(fp, fmt, ind, "attributes", p, len);
+	if (asn1_length_is_zero(dlen) != 1) goto err;
+	return 1;
+err:
+	error_print();
+	return -1;
+}
+
+#ifdef SM2_PRIVATE_KEY_EXPORT
+int sm2_private_key_info_to_pem(const SM2_KEY *key, FILE *fp)
+{
+	int ret = -1;
+	uint8_t buf[SM2_PRIVATE_KEY_INFO_DER_SIZE];
+	uint8_t *p = buf;
+	size_t len = 0;
+
+	if (!key || !fp) {
+		error_print();
+		return -1;
+	}
+	if (sm2_private_key_info_to_der(key, &p, &len) != 1) {
+		error_print();
+		goto end;
+	}
+	if (len != sizeof(buf)) {
+		error_print();
+		goto end;
+	}
+	if (pem_write(fp, "PRIVATE KEY", buf, len) != 1) {
+		error_print();
+		goto end;
+	}
+	ret = 1;
+end:
+	gmssl_secure_clear(buf, sizeof(buf));
+	return ret;
+}
+
+int sm2_private_key_info_from_pem(SM2_KEY *sm2_key, FILE *fp)
+{
+	uint8_t buf[512];
+	const uint8_t *cp = buf;
+	size_t len;
+	const uint8_t *attrs;
+	size_t attrs_len;
+
+	if (pem_read(fp, "PRIVATE KEY", buf, &len, sizeof(buf)) != 1
+		|| sm2_private_key_info_from_der(sm2_key, &attrs, &attrs_len, &cp, &len) != 1
+		|| asn1_length_is_zero(len) != 1) {
+		error_print();
+		return -1;
+	}
+	if (attrs_len) {
+		error_print();
+	}
+	return 1;
+}
+#endif
+
+int sm2_public_key_info_to_der(const SM2_KEY *pub_key, uint8_t **out, size_t *outlen)
+{
+	size_t len = 0;
+	if (sm2_public_key_algor_to_der(NULL, &len) != 1
+		|| sm2_public_key_to_der(pub_key, NULL, &len) != 1
+		|| asn1_sequence_header_to_der(len, out, outlen) != 1
+		|| sm2_public_key_algor_to_der(out, outlen) != 1
+		|| sm2_public_key_to_der(pub_key, out, outlen) != 1) {
+		error_print();
+		return -1;
+	}
+	return 1;
+}
+
+int sm2_public_key_info_from_der(SM2_KEY *pub_key, const uint8_t **in, size_t *inlen)
+{
+	int ret;
+	const uint8_t *d;
+	size_t dlen;
+
+	if ((ret = asn1_sequence_from_der(&d, &dlen, in, inlen)) != 1) {
+		if (ret < 0) error_print();
+		return ret;
+	}
+	if (sm2_public_key_algor_from_der(&d, &dlen) != 1
+		|| sm2_public_key_from_der(pub_key, &d, &dlen) != 1
+		|| asn1_length_is_zero(dlen) != 1) {
+		error_print();
+		return -1;
+	}
+	return 1;
+}
+
+#ifdef SM2_PRIVATE_KEY_EXPORT
+
+// FIXME: side-channel of Base64
+int sm2_private_key_to_pem(const SM2_KEY *a, FILE *fp)
+{
+	uint8_t buf[512];
+	uint8_t *p = buf;
+	size_t len = 0;
+
+	if (sm2_private_key_to_der(a, &p, &len) != 1) {
+		error_print();
+		return -1;
+	}
+	if (pem_write(fp, "EC PRIVATE KEY", buf, len) <= 0) {
+		error_print();
+		return -1;
+	}
+	return 1;
+}
+
+int sm2_private_key_from_pem(SM2_KEY *a, FILE *fp)
+{
+	uint8_t buf[512];
+	const uint8_t *cp = buf;
+	size_t len;
+
+	if (pem_read(fp, "EC PRIVATE KEY", buf, &len, sizeof(buf)) != 1) {
+		error_print();
+		return -1;
+	}
+	if (sm2_private_key_from_der(a, &cp, &len) != 1
+		|| len > 0) {
+		error_print();
+		return -1;
+	}
+	return 1;
+}
+#endif
+
+int sm2_public_key_info_to_pem(const SM2_KEY *a, FILE *fp)
+{
+	uint8_t buf[512];
+	uint8_t *p = buf;
+	size_t len = 0;
+
+	if (sm2_public_key_info_to_der(a, &p, &len) != 1) {
+		error_print();
+		return -1;
+	}
+	if (pem_write(fp, "PUBLIC KEY", buf, len) <= 0) {
+		error_print();
+		return -1;
+	}
+	return 1;
+}
+
+int sm2_public_key_info_from_pem(SM2_KEY *a, FILE *fp)
+{
+	uint8_t buf[512];
+	const uint8_t *cp = buf;
+	size_t len;
+
+	if (pem_read(fp, "PUBLIC KEY", buf, &len, sizeof(buf)) != 1) {
+		error_print();
+		return -1;
+	}
+	if (sm2_public_key_info_from_der(a, &cp, &len) != 1
+		|| asn1_length_is_zero(len) != 1) {
+		error_print();
+		return -1;
+	}
+	return 1;
+}
+
+int sm2_public_key_equ(const SM2_KEY *sm2_key, const SM2_KEY *pub_key)
+{
+	if (memcmp(sm2_key, pub_key, sizeof(SM2_POINT)) == 0) {
+		return 1;
+	}
+	return 0;
+}
+
+int sm2_public_key_copy(SM2_KEY *sm2_key, const SM2_KEY *pub_key)
+{
+	return sm2_key_set_public_key(sm2_key, &pub_key->public_key);
+}
+
+int sm2_public_key_digest(const SM2_KEY *sm2_key, uint8_t dgst[32])
+{
+	uint8_t bits[65];
+	sm2_point_to_uncompressed_octets(&sm2_key->public_key, bits);
+	sm3_digest(bits, sizeof(bits), dgst);
+	return 1;
+}
+
+int sm2_private_key_info_encrypt_to_der(const SM2_KEY *sm2_key, const char *pass,
+	uint8_t **out, size_t *outlen)
+{
+	int ret = -1;
+	uint8_t pkey_info[SM2_PRIVATE_KEY_INFO_DER_SIZE];
+	uint8_t *p = pkey_info;
+	size_t pkey_info_len = 0;
+	uint8_t salt[16];
+	int iter = 65536;
+	uint8_t iv[16];
+	uint8_t key[16];
+	SM4_KEY sm4_key;
+	uint8_t enced_pkey_info[sizeof(pkey_info) + 32];
+	size_t enced_pkey_info_len;
+
+	if (!sm2_key || !pass || !outlen) {
+		error_print();
+		return -1;
+	}
+	if (sm2_private_key_info_to_der(sm2_key, &p, &pkey_info_len) != 1
+		|| rand_bytes(salt, sizeof(salt)) != 1
+		|| rand_bytes(iv, sizeof(iv)) != 1
+		|| pbkdf2_genkey(DIGEST_sm3(), pass, strlen(pass),
+			salt, sizeof(salt), iter, sizeof(key), key) != 1) {
+		error_print();
+		goto end;
+	}
+	/*
+	if (pkey_info_len != sizeof(pkey_info)) {
+		error_print();
+		goto end;
+	}
+	*/
+	sm4_set_encrypt_key(&sm4_key, key);
+	if (sm4_cbc_padding_encrypt(
+			&sm4_key, iv, pkey_info, pkey_info_len,
+			enced_pkey_info, &enced_pkey_info_len) != 1
+		|| pkcs8_enced_private_key_info_to_der(
+			salt, sizeof(salt), iter, sizeof(key), OID_hmac_sm3,
+			OID_sm4_cbc, iv, sizeof(iv),
+			enced_pkey_info, enced_pkey_info_len, out, outlen) != 1) {
+		error_print();
+		goto end;
+	}
+
+	ret = 1;
+end:
+	gmssl_secure_clear(pkey_info, sizeof(pkey_info));
+	gmssl_secure_clear(key, sizeof(key));
+	gmssl_secure_clear(&sm4_key, sizeof(sm4_key));
+	return ret;
+}
+
+int sm2_private_key_info_decrypt_from_der(SM2_KEY *sm2,
+	const uint8_t **attrs, size_t *attrs_len,
+	const char *pass, const uint8_t **in, size_t *inlen)
+{
+	int ret = -1;
+	const uint8_t *salt;
+	size_t saltlen;
+	int iter;
+	int keylen;
+	int prf;
+	int cipher;
+	const uint8_t *iv;
+	size_t ivlen;
+	uint8_t key[16];
+	SM4_KEY sm4_key;
+	const uint8_t *enced_pkey_info;
+	size_t enced_pkey_info_len;
+	uint8_t pkey_info[256];
+	const uint8_t *cp = pkey_info;
+	size_t pkey_info_len;
+
+	if (!sm2 || !attrs || !attrs_len || !pass || !in || !(*in) || !inlen) {
+		error_print();
+		return -1;
+	}
+	if (pkcs8_enced_private_key_info_from_der(&salt, &saltlen, &iter, &keylen, &prf,
+		&cipher, &iv, &ivlen, &enced_pkey_info, &enced_pkey_info_len, in, inlen) != 1
+		|| asn1_check(keylen == -1 || keylen == 16) != 1
+		|| asn1_check(prf == - 1 || prf == OID_hmac_sm3) != 1
+		|| asn1_check(cipher == OID_sm4_cbc) != 1
+		|| asn1_check(ivlen == 16) != 1
+		|| asn1_length_le(enced_pkey_info_len, sizeof(pkey_info)) != 1) {
+		error_print();
+		return -1;
+	}
+	if (pbkdf2_genkey(DIGEST_sm3(), pass, strlen(pass), salt, saltlen, iter, sizeof(key), key) != 1) {
+		error_print();
+		goto end;
+	}
+	sm4_set_decrypt_key(&sm4_key, key);
+	if (sm4_cbc_padding_decrypt(&sm4_key, iv, enced_pkey_info, enced_pkey_info_len,
+			pkey_info, &pkey_info_len) != 1
+		|| sm2_private_key_info_from_der(sm2, attrs, attrs_len, &cp, &pkey_info_len) != 1
+		|| asn1_length_is_zero(pkey_info_len) != 1) {
+		error_print();
+		goto end;
+	}
+	ret = 1;
+end:
+	gmssl_secure_clear(&sm4_key, sizeof(sm4_key));
+	gmssl_secure_clear(key, sizeof(key));
+	gmssl_secure_clear(pkey_info, sizeof(pkey_info));
+	return ret;
+}
+
+int sm2_private_key_info_encrypt_to_pem(const SM2_KEY *sm2_key, const char *pass, FILE *fp)
+{
+	uint8_t buf[1024];
+	uint8_t *p = buf;
+	size_t len = 0;
+
+	if (!fp) {
+		error_print();
+		return -1;
+	}
+	if (sm2_private_key_info_encrypt_to_der(sm2_key, pass, &p, &len) != 1) {
+		error_print();
+		return -1;
+	}
+	if (pem_write(fp, "ENCRYPTED PRIVATE KEY", buf, len) != 1) {
+		error_print();
+		return -1;
+	}
+	return 1;
+}
+
+int sm2_private_key_info_decrypt_from_pem(SM2_KEY *key, const char *pass, FILE *fp)
+{
+	uint8_t buf[512];
+	const uint8_t *cp = buf;
+	size_t len;
+	const uint8_t *attrs;
+	size_t attrs_len;
+
+	if (!key || !pass || !fp) {
+		error_print();
+		return -1;
+	}
+	if (pem_read(fp, "ENCRYPTED PRIVATE KEY", buf, &len, sizeof(buf)) != 1
+		|| sm2_private_key_info_decrypt_from_der(key, &attrs, &attrs_len, pass, &cp, &len) != 1
+		|| asn1_length_is_zero(len) != 1) {
+		error_print();
+		return -1;
+	}
+	return 1;
+}

+ 215 - 0
components/gmssl/src/sm2_key_share.c

@@ -0,0 +1,215 @@
+/*
+ *  Copyright 2014-2022 The GmSSL Project. All Rights Reserved.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the License); you may
+ *  not use this file except in compliance with the License.
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <gmssl/sm2_key_share.h>
+#include <gmssl/mem.h>
+#include <gmssl/error.h>
+
+extern SM2_BN SM2_N;
+
+int sm2_key_share_print(FILE *fp, int fmt, int ind, const char *label, const SM2_KEY_SHARE *share)
+{
+	format_print(fp, fmt, ind, "%s\n", label);
+	ind += 4;
+	format_print(fp, fmt, ind, "%zu/%zu\n", share->index, share->total_cnt);
+	format_print(fp, fmt, ind, "key", &share->key);
+	return 1;
+}
+
+
+// y = f(x)
+static void eval_univariate_poly(SM2_Fn y, const SM2_Fn *coeffs, size_t coeffs_cnt, uint32_t x)
+{
+	sm2_bn_set_zero(y);
+	while (coeffs_cnt--) {
+		sm2_fn_mul_word(y, y, x);
+		sm2_fn_add(y, y, coeffs[coeffs_cnt]);
+	}
+}
+
+int sm2_key_split(const SM2_KEY *key, size_t recover_cnt, size_t total_cnt, SM2_KEY_SHARE *shares)
+{
+	SM2_Fn coeffs[SM2_KEY_MAX_SHARES];
+	SM2_Fn y;
+	uint8_t y_bytes[32];
+	size_t i;
+
+	if (!key || !shares) {
+		error_print();
+		return -1;
+	}
+	if (!total_cnt || total_cnt > SM2_KEY_MAX_SHARES) {
+		error_print();
+		return -1;
+	}
+	if (!recover_cnt || recover_cnt > total_cnt) {
+		error_print();
+		return -1;
+	}
+	// try to access mem
+	memset(shares, 0, sizeof(SM2_KEY_SHARE) * total_cnt);
+
+	for (i = 1; i < recover_cnt; i++) {
+		if (sm2_fn_rand(coeffs[i]) != 1) {
+			error_print();
+			return -1;
+		}
+	}
+	sm2_bn_from_bytes(coeffs[0], key->private_key);
+
+	for (i = 0; i < total_cnt; i++) {
+		uint32_t x = (uint32_t)(i + 1);
+		eval_univariate_poly(y, coeffs, recover_cnt, x);
+		sm2_bn_to_bytes(y, y_bytes);
+		sm2_key_set_private_key(&(shares[i].key), y_bytes);
+		shares[i].index = i;
+		shares[i].total_cnt = total_cnt;
+	}
+
+	gmssl_secure_clear(coeffs, sizeof(coeffs));
+	gmssl_secure_clear(y, sizeof(y));
+	gmssl_secure_clear(y_bytes, sizeof(y_bytes));
+	return 1;
+}
+
+int sm2_key_recover(SM2_KEY *key, const SM2_KEY_SHARE *shares, size_t shares_cnt)
+{
+	SM2_Fn s;
+	uint8_t s_bytes[32];
+	int x_i;
+	SM2_Fn y_i;
+	size_t i, j, k, n;
+
+	if (!shares || !shares_cnt || !key) {
+		error_print();
+		return -1;
+	}
+
+	k = shares_cnt;
+	n = shares[0].total_cnt;
+
+	if (n > SM2_KEY_MAX_SHARES) {
+		error_print();
+		return -1;
+	}
+	for (i = 0; i < k; i++) {
+		if (shares[i].total_cnt != n
+			|| shares[i].index >= n) {
+			error_print();
+			return -1;
+		}
+	}
+
+	sm2_bn_set_zero(s);
+
+	for (i = 0; i < k; i++) {
+		// delta_i
+		SM2_Fn d;
+		int num = 1;
+		int den = 1;
+		int sign = 1;
+
+		x_i = (int)(shares[i].index + 1);
+
+		for (j = 0; j < k; j++) {
+			if (i != j) {
+				int x_j = (int)(shares[j].index + 1);
+				num *= -x_j;
+				den *= x_i - x_j;
+			}
+		}
+		if (num < 0) {
+			num = -num;
+			sign = -sign;
+		}
+		if (den < 0) {
+			den = -den;
+			sign = -sign;
+		}
+
+		// delta_i = Fn( num / den )
+		sm2_bn_set_word(d, den);
+		sm2_fn_inv(d, d);
+		sm2_fn_mul_word(d, d, num);
+		if (sign < 0) {
+			sm2_fn_neg(d, d);
+		}
+
+		// s += delta_i * y_i
+		sm2_bn_from_bytes(y_i, shares[i].key.private_key);
+		if (sm2_bn_cmp(y_i, SM2_N) >= 0) {
+			gmssl_secure_clear(y_i, sizeof(y_i));
+			gmssl_secure_clear(s, sizeof(s));
+			error_print();
+			return -1;
+		}
+		sm2_fn_mul(y_i, y_i, d);
+		sm2_fn_add(s, s, y_i);
+	}
+
+	sm2_bn_to_bytes(s, s_bytes);
+	sm2_key_set_private_key(key, s_bytes);
+
+	gmssl_secure_clear(y_i, sizeof(y_i));
+	gmssl_secure_clear(s, sizeof(s));
+	gmssl_secure_clear(s_bytes, sizeof(s_bytes));
+	return 1;
+}
+
+int sm2_key_share_encrypt_to_file(const SM2_KEY_SHARE *share, const char *pass, const char *path_prefix)
+{
+	int ret;
+	char *path = NULL;
+	FILE *fp = NULL;
+	int len;
+
+	if (!share || !pass || !path_prefix) {
+		error_print();
+		return -1;
+	}
+	if (!share->total_cnt || share->total_cnt > 12 || share->index >= share->total_cnt) {
+		sm2_key_share_print(stderr, 0, 0, "share", share);
+		error_print();
+		return -1;
+	}
+	if ((len = snprintf(NULL, 0, "%s-%zu-of-%zu.pem", path_prefix, share->index + 1, share->total_cnt)) <= 0) {
+		error_print();
+		return -1;
+	}
+	if (!(path = malloc(len + 1))) {
+		error_print();
+		return -1;
+	}
+	snprintf(path, len+1, "%s-%zu-of-%zu.pem", path_prefix, share->index + 1, share->total_cnt);
+
+
+	if (!(fp = fopen(path, "wb"))) {
+		error_print();
+		goto end;
+	}
+	if (sm2_private_key_info_encrypt_to_pem(&share->key, pass, fp) != 1) {
+		error_print();
+		goto end;
+	}
+	ret = 1;
+end:
+	if (path) free(path);
+	if (fp) fclose(fp);
+	return ret;
+}
+
+int sm2_key_share_decrypt_from_file(SM2_KEY_SHARE *share, const char *pass, const char *file)
+{
+	error_print();
+	return -1;
+}

+ 938 - 0
components/gmssl/src/sm2_lib.c

@@ -0,0 +1,938 @@
+/*
+ *  Copyright 2014-2023 The GmSSL Project. All Rights Reserved.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the License); you may
+ *  not use this file except in compliance with the License.
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ */
+
+
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <gmssl/mem.h>
+#include <gmssl/sm2.h>
+#include <gmssl/sm3.h>
+#include <gmssl/asn1.h>
+#include <gmssl/error.h>
+#include <gmssl/endian.h>
+
+
+extern const SM2_BN SM2_N;
+extern const SM2_BN SM2_ONE;
+
+int sm2_do_sign(const SM2_KEY *key, const uint8_t dgst[32], SM2_SIGNATURE *sig)
+{
+	SM2_JACOBIAN_POINT _P, *P = &_P;
+	SM2_BN d;
+	SM2_BN d_inv;
+	SM2_BN e;
+	SM2_BN k;
+	SM2_BN x;
+	SM2_BN t;
+	SM2_BN r;
+	SM2_BN s;
+
+	//fprintf(stderr, "sm2_do_sign\n");
+	sm2_bn_from_bytes(d, key->private_key);
+
+	// compute (d + 1)^-1 (mod n)
+	sm2_fn_add(d_inv, d, SM2_ONE);	//sm2_bn_print(stderr, 0, 4, "(1+d)", d_inv);
+	if (sm2_bn_is_zero(d_inv)) {
+		error_print();
+		return -1;
+	}
+	sm2_fn_inv(d_inv, d_inv);	//sm2_bn_print(stderr, 0, 4, "(1+d)^-1", d_inv);
+
+	// e = H(M)
+	sm2_bn_from_bytes(e, dgst);	//sm2_bn_print(stderr, 0, 4, "e", e);
+
+retry:
+	// rand k in [1, n - 1]
+	do {
+		if (sm2_fn_rand(k) != 1) {
+			error_print();
+			return -1;
+		}
+	} while (sm2_bn_is_zero(k));	//sm2_bn_print(stderr, 0, 4, "k", k);
+
+	// (x, y) = kG
+	sm2_jacobian_point_mul_generator(P, k);
+	sm2_jacobian_point_get_xy(P, x, NULL);
+					//sm2_bn_print(stderr, 0, 4, "x", x);
+
+	// r = e + x (mod n)
+	if (sm2_bn_cmp(e, SM2_N) >= 0) {
+		sm2_bn_sub(e, e, SM2_N);
+	}
+	if (sm2_bn_cmp(x, SM2_N) >= 0) {
+		sm2_bn_sub(x, x, SM2_N);
+	}
+	sm2_fn_add(r, e, x);		//sm2_bn_print(stderr, 0, 4, "r = e + x (mod n)", r);
+
+	// if r == 0 or r + k == n re-generate k
+	sm2_bn_add(t, r, k);
+	if (sm2_bn_is_zero(r) || sm2_bn_cmp(t, SM2_N) == 0) {
+					//sm2_bn_print(stderr, 0, 4, "r + k", t);
+		goto retry;
+	}
+
+	// s = ((1 + d)^-1 * (k - r * d)) mod n
+	sm2_fn_mul(t, r, d);		//sm2_bn_print(stderr, 0, 4, "r*d", t);
+	sm2_fn_sub(k, k, t);		//sm2_bn_print(stderr, 0, 4, "k-r*d", k);
+	sm2_fn_mul(s, d_inv, k);	//sm2_bn_print(stderr, 0, 4, "s = ((1 + d)^-1 * (k - r * d)) mod n", s);
+
+	// check s != 0
+	if (sm2_bn_is_zero(s)) {
+		goto retry;
+	}
+
+	sm2_bn_to_bytes(r, sig->r);	//sm2_bn_print_bn(stderr, 0, 4, "r", r);
+	sm2_bn_to_bytes(s, sig->s);	//sm2_bn_print_bn(stderr, 0, 4, "s", s);
+
+	gmssl_secure_clear(d, sizeof(d));
+	gmssl_secure_clear(d_inv, sizeof(d_inv ));
+	gmssl_secure_clear(k, sizeof(k));
+	gmssl_secure_clear(t, sizeof(t));
+	return 1;
+}
+
+int sm2_do_verify(const SM2_KEY *key, const uint8_t dgst[32], const SM2_SIGNATURE *sig)
+{
+	SM2_JACOBIAN_POINT _P, *P = &_P;
+	SM2_JACOBIAN_POINT _R, *R = &_R;
+	SM2_BN r;
+	SM2_BN s;
+	SM2_BN e;
+	SM2_BN x;
+	SM2_BN t;
+
+	// parse public key
+	sm2_jacobian_point_from_bytes(P, (const uint8_t *)&key->public_key);
+					//sm2_jacobian_point_print(stderr, 0, 4, "P", P);
+
+	// parse signature values
+	sm2_bn_from_bytes(r, sig->r);	//sm2_bn_print(stderr, 0, 4, "r", r);
+	sm2_bn_from_bytes(s, sig->s);	//sm2_bn_print(stderr, 0, 4, "s", s);
+
+	// check r, s in [1, n-1]
+	if (sm2_bn_is_zero(r) == 1
+		|| sm2_bn_cmp(r, SM2_N) >= 0
+		|| sm2_bn_is_zero(s) == 1
+		|| sm2_bn_cmp(s, SM2_N) >= 0) {
+		error_print();
+		return -1;
+	}
+
+	// e = H(M)
+	sm2_bn_from_bytes(e, dgst);	//sm2_bn_print(stderr, 0, 4, "e = H(M)", e);
+
+	// t = r + s (mod n), check t != 0
+	sm2_fn_add(t, r, s);		//sm2_bn_print(stderr, 0, 4, "t = r + s (mod n)", t);
+	if (sm2_bn_is_zero(t)) {
+		error_print();
+		return -1;
+	}
+
+	// Q = s * G + t * P
+	sm2_jacobian_point_mul_sum(R, t, P, s);
+	sm2_jacobian_point_get_xy(R, x, NULL);
+					//sm2_bn_print(stderr, 0, 4, "x", x);
+
+	// r' = e + x (mod n)
+	if (sm2_bn_cmp(e, SM2_N) >= 0) {
+		sm2_bn_sub(e, e, SM2_N);
+	}
+	if (sm2_bn_cmp(x, SM2_N) >= 0) {
+		sm2_bn_sub(x, x, SM2_N);
+	}
+	sm2_fn_add(e, e, x);		//sm2_bn_print(stderr, 0, 4, "e + x (mod n)", e);
+
+	// check if r == r'
+	if (sm2_bn_cmp(e, r) != 0) {
+		error_print();
+		return -1;
+	}
+	return 1;
+}
+
+int sm2_signature_to_der(const SM2_SIGNATURE *sig, uint8_t **out, size_t *outlen)
+{
+	size_t len = 0;
+	if (!sig) {
+		return 0;
+	}
+	if (asn1_integer_to_der(sig->r, 32, NULL, &len) != 1
+		|| asn1_integer_to_der(sig->s, 32, NULL, &len) != 1
+		|| asn1_sequence_header_to_der(len, out, outlen) != 1
+		|| asn1_integer_to_der(sig->r, 32, out, outlen) != 1
+		|| asn1_integer_to_der(sig->s, 32, out, outlen) != 1) {
+		error_print();
+		return -1;
+	}
+	return 1;
+}
+
+int sm2_signature_from_der(SM2_SIGNATURE *sig, const uint8_t **in, size_t *inlen)
+{
+	int ret;
+	const uint8_t *d;
+	size_t dlen;
+	const uint8_t *r;
+	size_t rlen;
+	const uint8_t *s;
+	size_t slen;
+
+	if ((ret = asn1_sequence_from_der(&d, &dlen, in, inlen)) != 1) {
+		if (ret < 0) error_print();
+		return ret;
+	}
+	if (asn1_integer_from_der(&r, &rlen, &d, &dlen) != 1
+		|| asn1_integer_from_der(&s, &slen, &d, &dlen) != 1
+		|| asn1_length_le(rlen, 32) != 1
+		|| asn1_length_le(slen, 32) != 1
+		|| asn1_length_is_zero(dlen) != 1) {
+		error_print();
+		return -1;
+	}
+	memset(sig, 0, sizeof(*sig));
+	memcpy(sig->r + 32 - rlen, r, rlen);
+	memcpy(sig->s + 32 - slen, s, slen);
+	return 1;
+}
+
+int sm2_signature_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *a, size_t alen)
+{
+	SM2_SIGNATURE sig;
+	format_print(fp, fmt, ind, "%s\n", label);
+	ind += 4;
+	if (sm2_signature_from_der(&sig, &a, &alen) != 1
+		|| asn1_length_is_zero(alen) != 1) {
+		error_print();
+		return -1;
+	}
+	format_bytes(fp, fmt, ind, "r", sig.r, 32);
+	format_bytes(fp, fmt, ind, "s", sig.s, 32);
+	return 1;
+}
+
+int sm2_sign(const SM2_KEY *key, const uint8_t dgst[32], uint8_t *sigbuf, size_t *siglen)
+{
+	SM2_SIGNATURE sig;
+
+	if (!key || !dgst || !sigbuf || !siglen) {
+		error_print();
+		return -1;
+	}
+
+	if (sm2_do_sign(key, dgst, &sig) != 1) {
+		error_print();
+		return -1;
+	}
+
+	*siglen = 0;
+	if (sm2_signature_to_der(&sig, &sigbuf, siglen) != 1) {
+		error_print();
+		return -1;
+	}
+	return 1;
+}
+
+int sm2_sign_fixlen(const SM2_KEY *key, const uint8_t dgst[32], size_t siglen, uint8_t *sig)
+{
+	unsigned int trys = 200; // 200 trys is engouh
+	uint8_t buf[SM2_MAX_SIGNATURE_SIZE];
+	size_t len;
+
+	switch (siglen) {
+	case SM2_signature_compact_size:
+	case SM2_signature_typical_size:
+	case SM2_signature_max_size:
+		break;
+	default:
+		error_print();
+		return -1;
+	}
+
+	while (trys--) {
+		if (sm2_sign(key, dgst, buf, &len) != 1) {
+			error_print();
+			return -1;
+		}
+		if (len == siglen) {
+			memcpy(sig, buf, len);
+			return 1;
+		}
+	}
+
+	// might caused by bad randomness
+	error_print();
+	return -1;
+}
+
+int sm2_verify(const SM2_KEY *key, const uint8_t dgst[32], const uint8_t *sigbuf, size_t siglen)
+{
+	SM2_SIGNATURE sig;
+
+	if (!key || !dgst || !sigbuf || !siglen) {
+		error_print();
+		return -1;
+	}
+
+	if (sm2_signature_from_der(&sig, &sigbuf, &siglen) != 1
+		|| asn1_length_is_zero(siglen) != 1) {
+		error_print();
+		return -1;
+	}
+	if (sm2_do_verify(key, dgst, &sig) != 1) {
+		error_print();
+		return -1;
+	}
+	return 1;
+}
+
+int sm2_compute_z(uint8_t z[32], const SM2_POINT *pub, const char *id, size_t idlen)
+{
+	SM3_CTX ctx;
+	uint8_t zin[18 + 32 * 6] = {
+		0x00, 0x80,
+		0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,
+		0xFF,0xFF,0xFF,0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+		0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFC,
+		0x28,0xE9,0xFA,0x9E,0x9D,0x9F,0x5E,0x34,0x4D,0x5A,0x9E,0x4B,0xCF,0x65,0x09,0xA7,
+		0xF3,0x97,0x89,0xF5,0x15,0xAB,0x8F,0x92,0xDD,0xBC,0xBD,0x41,0x4D,0x94,0x0E,0x93,
+       		0x32,0xC4,0xAE,0x2C,0x1F,0x19,0x81,0x19,0x5F,0x99,0x04,0x46,0x6A,0x39,0xC9,0x94,
+		0x8F,0xE3,0x0B,0xBF,0xF2,0x66,0x0B,0xE1,0x71,0x5A,0x45,0x89,0x33,0x4C,0x74,0xC7,
+		0xBC,0x37,0x36,0xA2,0xF4,0xF6,0x77,0x9C,0x59,0xBD,0xCE,0xE3,0x6B,0x69,0x21,0x53,
+		0xD0,0xA9,0x87,0x7C,0xC6,0x2A,0x47,0x40,0x02,0xDF,0x32,0xE5,0x21,0x39,0xF0,0xA0,
+	};
+
+	if (!z || !pub || !id) {
+		error_print();
+		return -1;
+	}
+
+	memcpy(&zin[18 + 32 * 4], pub->x, 32);
+	memcpy(&zin[18 + 32 * 5], pub->y, 32);
+
+	sm3_init(&ctx);
+	if (strcmp(id, SM2_DEFAULT_ID) == 0) {
+		sm3_update(&ctx, zin, sizeof(zin));
+	} else {
+		uint8_t idbits[2];
+		idbits[0] = (uint8_t)(idlen >> 5);
+		idbits[1] = (uint8_t)(idlen << 3);
+		sm3_update(&ctx, idbits, 2);
+		sm3_update(&ctx, (uint8_t *)id, idlen);
+		sm3_update(&ctx, zin + 18, 32 * 6);
+	}
+	sm3_finish(&ctx, z);
+	return 1;
+}
+
+int sm2_sign_init(SM2_SIGN_CTX *ctx, const SM2_KEY *key, const char *id, size_t idlen)
+{
+	if (!ctx || !key) {
+		error_print();
+		return -1;
+	}
+	ctx->key = *key;
+	sm3_init(&ctx->sm3_ctx);
+
+	if (id) {
+		uint8_t z[SM3_DIGEST_SIZE];
+		if (idlen <= 0 || idlen > SM2_MAX_ID_LENGTH) {
+			error_print();
+			return -1;
+		}
+		sm2_compute_z(z, &key->public_key, id, idlen);
+		sm3_update(&ctx->sm3_ctx, z, sizeof(z));
+	}
+	return 1;
+}
+
+int sm2_sign_update(SM2_SIGN_CTX *ctx, const uint8_t *data, size_t datalen)
+{
+	if (!ctx) {
+		error_print();
+		return -1;
+	}
+	if (data && datalen > 0) {
+		sm3_update(&ctx->sm3_ctx, data, datalen);
+	}
+	return 1;
+}
+
+int sm2_sign_finish(SM2_SIGN_CTX *ctx, uint8_t *sig, size_t *siglen)
+{
+	uint8_t dgst[SM3_DIGEST_SIZE];
+
+	if (!ctx || !sig || !siglen) {
+		error_print();
+		return -1;
+	}
+	sm3_finish(&ctx->sm3_ctx, dgst);
+	if (sm2_sign(&ctx->key, dgst, sig, siglen) != 1) {
+		error_print();
+		return -1;
+	}
+	return 1;
+}
+
+int sm2_sign_finish_fixlen(SM2_SIGN_CTX *ctx, size_t siglen, uint8_t *sig)
+{
+	uint8_t dgst[SM3_DIGEST_SIZE];
+
+	if (!ctx || !sig || !siglen) {
+		error_print();
+		return -1;
+	}
+	sm3_finish(&ctx->sm3_ctx, dgst);
+	if (sm2_sign_fixlen(&ctx->key, dgst, siglen, sig) != 1) {
+		error_print();
+		return -1;
+	}
+	return 1;
+}
+
+int sm2_verify_init(SM2_SIGN_CTX *ctx, const SM2_KEY *key, const char *id, size_t idlen)
+{
+	if (!ctx || !key) {
+		error_print();
+		return -1;
+	}
+	memset(ctx, 0, sizeof(*ctx));
+	ctx->key.public_key = key->public_key;
+	sm3_init(&ctx->sm3_ctx);
+
+	if (id) {
+		uint8_t z[SM3_DIGEST_SIZE];
+		if (idlen <= 0 || idlen > SM2_MAX_ID_LENGTH) {
+			error_print();
+			return -1;
+		}
+		sm2_compute_z(z, &key->public_key, id, idlen);
+		sm3_update(&ctx->sm3_ctx, z, sizeof(z));
+	}
+	return 1;
+}
+
+int sm2_verify_update(SM2_SIGN_CTX *ctx, const uint8_t *data, size_t datalen)
+{
+	if (!ctx) {
+		error_print();
+		return -1;
+	}
+	if (data && datalen > 0) {
+		sm3_update(&ctx->sm3_ctx, data, datalen);
+	}
+	return 1;
+}
+
+int sm2_verify_finish(SM2_SIGN_CTX *ctx, const uint8_t *sig, size_t siglen)
+{
+	uint8_t dgst[SM3_DIGEST_SIZE];
+
+	if (!ctx || !sig) {
+		error_print();
+		return -1;
+	}
+	sm3_finish(&ctx->sm3_ctx, dgst);
+	if (sm2_verify(&ctx->key, dgst, sig, siglen) != 1) {
+		error_print();
+		return -1;
+	}
+	return 1;
+}
+
+int sm2_kdf(const uint8_t *in, size_t inlen, size_t outlen, uint8_t *out)
+{
+	SM3_CTX ctx;
+	uint8_t counter_be[4];
+	uint8_t dgst[SM3_DIGEST_SIZE];
+	uint32_t counter = 1;
+	size_t len;
+
+	while (outlen) {
+		PUTU32(counter_be, counter);
+		counter++;
+
+		sm3_init(&ctx);
+		sm3_update(&ctx, in, inlen);
+		sm3_update(&ctx, counter_be, sizeof(counter_be));
+		sm3_finish(&ctx, dgst);
+
+		len = outlen < SM3_DIGEST_SIZE ? outlen : SM3_DIGEST_SIZE;
+		memcpy(out, dgst, len);
+		out += len;
+		outlen -= len;
+	}
+
+	memset(&ctx, 0, sizeof(SM3_CTX));
+	memset(dgst, 0, sizeof(dgst));
+	return 1;
+}
+
+static int all_zero(const uint8_t *buf, size_t len)
+{
+	size_t i;
+	for (i = 0; i < len; i++) {
+		if (buf[i]) {
+			return 0;
+		}
+	}
+	return 1;
+}
+
+int sm2_do_encrypt(const SM2_KEY *key, const uint8_t *in, size_t inlen, SM2_CIPHERTEXT *out)
+{
+	SM2_BN k;
+	SM2_JACOBIAN_POINT _P, *P = &_P;
+	SM2_JACOBIAN_POINT _C1, *C1 = &_C1;
+	SM2_JACOBIAN_POINT _kP, *kP = &_kP;
+	uint8_t x2y2[64];
+	SM3_CTX sm3_ctx;
+
+	if (!(SM2_MIN_PLAINTEXT_SIZE <= inlen && inlen <= SM2_MAX_PLAINTEXT_SIZE)) {
+		error_print();
+		return -1;
+	}
+
+	sm2_jacobian_point_from_bytes(P, (uint8_t *)&key->public_key);
+
+	// S = h * P, check S != O
+	// for sm2 curve, h == 1 and S == P
+	// SM2_POINT can not present point at infinity, do do nothing here
+
+retry:
+	// rand k in [1, n - 1]
+	do {
+		if (sm2_fn_rand(k) != 1) {
+			error_print();
+			return -1;
+		}
+	} while (sm2_bn_is_zero(k));	//sm2_bn_print(stderr, 0, 4, "k", k);
+
+	// output C1 = k * G = (x1, y1)
+	sm2_jacobian_point_mul_generator(C1, k);
+	sm2_jacobian_point_to_bytes(C1, (uint8_t *)&out->point);
+
+	// k * P = (x2, y2)
+	sm2_jacobian_point_mul(kP, k, P);
+	sm2_jacobian_point_to_bytes(kP, x2y2);
+
+	// t = KDF(x2 || y2, inlen)
+	sm2_kdf(x2y2, 64, inlen, out->ciphertext);
+
+	// if t is all zero, retry
+	if (all_zero(out->ciphertext, inlen)) {
+		goto retry;
+	}
+
+	// output C2 = M xor t
+	gmssl_memxor(out->ciphertext, out->ciphertext, in, inlen);
+	out->ciphertext_size = (uint32_t)inlen;
+
+	// output C3 = Hash(x2 || m || y2)
+	sm3_init(&sm3_ctx);
+	sm3_update(&sm3_ctx, x2y2, 32);
+	sm3_update(&sm3_ctx, in, inlen);
+	sm3_update(&sm3_ctx, x2y2 + 32, 32);
+	sm3_finish(&sm3_ctx, out->hash);
+
+	gmssl_secure_clear(k, sizeof(k));
+	gmssl_secure_clear(kP, sizeof(SM2_JACOBIAN_POINT));
+	gmssl_secure_clear(x2y2, sizeof(x2y2));
+	return 1;
+}
+
+int sm2_do_encrypt_fixlen(const SM2_KEY *key, const uint8_t *in, size_t inlen, int point_size, SM2_CIPHERTEXT *out)
+{
+	unsigned int trys = 200;
+	SM2_BN k;
+	SM2_JACOBIAN_POINT _P, *P = &_P;
+	SM2_JACOBIAN_POINT _C1, *C1 = &_C1;
+	SM2_JACOBIAN_POINT _kP, *kP = &_kP;
+	uint8_t x2y2[64];
+	SM3_CTX sm3_ctx;
+
+	if (!(SM2_MIN_PLAINTEXT_SIZE <= inlen && inlen <= SM2_MAX_PLAINTEXT_SIZE)) {
+		error_print();
+		return -1;
+	}
+
+	switch (point_size) {
+	case SM2_ciphertext_compact_point_size:
+	case SM2_ciphertext_typical_point_size:
+	case SM2_ciphertext_max_point_size:
+		break;
+	default:
+		error_print();
+		return -1;
+	}
+
+	sm2_jacobian_point_from_bytes(P, (uint8_t *)&key->public_key);
+
+	// S = h * P, check S != O
+	// for sm2 curve, h == 1 and S == P
+	// SM2_POINT can not present point at infinity, do do nothing here
+
+retry:
+	// rand k in [1, n - 1]
+	do {
+		if (sm2_fn_rand(k) != 1) {
+			error_print();
+			return -1;
+		}
+	} while (sm2_bn_is_zero(k));	//sm2_bn_print(stderr, 0, 4, "k", k);
+
+	// output C1 = k * G = (x1, y1)
+	sm2_jacobian_point_mul_generator(C1, k);
+	sm2_jacobian_point_to_bytes(C1, (uint8_t *)&out->point);
+
+	// check fixlen
+	if (trys) {
+		size_t len = 0;
+		asn1_integer_to_der(out->point.x, 32, NULL, &len);
+		asn1_integer_to_der(out->point.y, 32, NULL, &len);
+		if (len != point_size) {
+			trys--;
+			goto retry;
+		}
+	} else {
+		gmssl_secure_clear(k, sizeof(k));
+		error_print();
+		return -1;
+	}
+
+	// k * P = (x2, y2)
+	sm2_jacobian_point_mul(kP, k, P);
+	sm2_jacobian_point_to_bytes(kP, x2y2);
+
+	// t = KDF(x2 || y2, inlen)
+	sm2_kdf(x2y2, 64, inlen, out->ciphertext);
+
+	// if t is all zero, retry
+	if (all_zero(out->ciphertext, inlen)) {
+		goto retry;
+	}
+
+	// output C2 = M xor t
+	gmssl_memxor(out->ciphertext, out->ciphertext, in, inlen);
+	out->ciphertext_size = (uint32_t)inlen;
+
+	// output C3 = Hash(x2 || m || y2)
+	sm3_init(&sm3_ctx);
+	sm3_update(&sm3_ctx, x2y2, 32);
+	sm3_update(&sm3_ctx, in, inlen);
+	sm3_update(&sm3_ctx, x2y2 + 32, 32);
+	sm3_finish(&sm3_ctx, out->hash);
+
+	gmssl_secure_clear(k, sizeof(k));
+	gmssl_secure_clear(kP, sizeof(SM2_JACOBIAN_POINT));
+	gmssl_secure_clear(x2y2, sizeof(x2y2));
+	return 1;
+}
+
+int sm2_do_decrypt(const SM2_KEY *key, const SM2_CIPHERTEXT *in, uint8_t *out, size_t *outlen)
+{
+	int ret = -1;
+	SM2_BN d;
+	SM2_JACOBIAN_POINT _C1, *C1 = &_C1;
+	uint8_t x2y2[64];
+	SM3_CTX sm3_ctx;
+	uint8_t hash[32];
+
+	// check C1 is on sm2 curve
+	sm2_jacobian_point_from_bytes(C1, (uint8_t *)&in->point);
+	if (!sm2_jacobian_point_is_on_curve(C1)) {
+		error_print();
+		return -1;
+	}
+
+	// check if S = h * C1 is point at infinity
+	// this will not happen, as SM2_POINT can not present point at infinity
+
+	// d * C1 = (x2, y2)
+	sm2_bn_from_bytes(d, key->private_key);
+	sm2_jacobian_point_mul(C1, d, C1);
+
+	// t = KDF(x2 || y2, klen) and check t is not all zeros
+	sm2_jacobian_point_to_bytes(C1, x2y2);
+	sm2_kdf(x2y2, 64, in->ciphertext_size, out);
+	if (all_zero(out, in->ciphertext_size)) {
+		error_print();
+		goto end;
+	}
+
+	// M = C2 xor t
+	gmssl_memxor(out, out, in->ciphertext, in->ciphertext_size);
+	*outlen = in->ciphertext_size;
+
+	// u = Hash(x2 || M || y2)
+	sm3_init(&sm3_ctx);
+	sm3_update(&sm3_ctx, x2y2, 32);
+	sm3_update(&sm3_ctx, out, in->ciphertext_size);
+	sm3_update(&sm3_ctx, x2y2 + 32, 32);
+	sm3_finish(&sm3_ctx, hash);
+
+	// check if u == C3
+	if (memcmp(in->hash, hash, sizeof(hash)) != 0) {
+		error_print();
+		goto end;
+	}
+	ret = 1;
+
+end:
+	gmssl_secure_clear(d, sizeof(d));
+	gmssl_secure_clear(C1, sizeof(SM2_JACOBIAN_POINT));
+	gmssl_secure_clear(x2y2, sizeof(x2y2));
+	return ret;
+}
+
+int sm2_ciphertext_to_der(const SM2_CIPHERTEXT *C, uint8_t **out, size_t *outlen)
+{
+	size_t len = 0;
+	if (!C) {
+		return 0;
+	}
+	if (asn1_integer_to_der(C->point.x, 32, NULL, &len) != 1
+		|| asn1_integer_to_der(C->point.y, 32, NULL, &len) != 1
+		|| asn1_octet_string_to_der(C->hash, 32, NULL, &len) != 1
+		|| asn1_octet_string_to_der(C->ciphertext, C->ciphertext_size, NULL, &len) != 1
+		|| asn1_sequence_header_to_der(len, out, outlen) != 1
+		|| asn1_integer_to_der(C->point.x, 32, out, outlen) != 1
+		|| asn1_integer_to_der(C->point.y, 32, out, outlen) != 1
+		|| asn1_octet_string_to_der(C->hash, 32, out, outlen) != 1
+		|| asn1_octet_string_to_der(C->ciphertext, C->ciphertext_size, out, outlen) != 1) {
+		error_print();
+		return -1;
+	}
+	return 1;
+}
+
+int sm2_ciphertext_from_der(SM2_CIPHERTEXT *C, const uint8_t **in, size_t *inlen)
+{
+	int ret;
+	const uint8_t *d;
+	size_t dlen;
+	const uint8_t *x;
+	const uint8_t *y;
+	const uint8_t *hash;
+	const uint8_t *c;
+	size_t xlen, ylen, hashlen, clen;
+
+	if ((ret = asn1_sequence_from_der(&d, &dlen, in, inlen)) != 1) {
+		if (ret < 0) error_print();
+		return ret;
+	}
+	if (asn1_integer_from_der(&x, &xlen, &d, &dlen) != 1
+		|| asn1_length_le(xlen, 32) != 1) {
+		error_print();
+		return -1;
+	}
+	if (asn1_integer_from_der(&y, &ylen, &d, &dlen) != 1
+		|| asn1_length_le(ylen, 32) != 1) {
+		error_print();
+		return -1;
+	}
+	if (asn1_octet_string_from_der(&hash, &hashlen, &d, &dlen) != 1
+		|| asn1_check(hashlen == 32) != 1) {
+		error_print();
+		return -1;
+	}
+	if (asn1_octet_string_from_der(&c, &clen, &d, &dlen) != 1
+	//	|| asn1_length_is_zero(clen) == 1
+		|| asn1_length_le(clen, SM2_MAX_PLAINTEXT_SIZE) != 1) {
+		error_print();
+		return -1;
+	}
+	if (asn1_length_is_zero(dlen) != 1) {
+		error_print();
+		return -1;
+	}
+	memset(C, 0, sizeof(SM2_CIPHERTEXT));
+	memcpy(C->point.x + 32 - xlen, x, xlen);
+	memcpy(C->point.y + 32 - ylen, y, ylen);
+	if (sm2_point_is_on_curve(&C->point) != 1) {
+		error_print();
+		return -1;
+	}
+	memcpy(C->hash, hash, hashlen);
+	memcpy(C->ciphertext, c, clen);
+	C->ciphertext_size = (uint8_t)clen;
+	return 1;
+}
+
+int sm2_ciphertext_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *a, size_t alen)
+{
+	uint8_t buf[512] = {0};
+	SM2_CIPHERTEXT *c = (SM2_CIPHERTEXT *)buf;
+
+	if (sm2_ciphertext_from_der(c, &a, &alen) != 1
+		|| asn1_length_is_zero(alen) != 1) {
+		error_print();
+		return -1;
+	}
+	format_print(fp, fmt, ind, "%s\n", label);
+	ind += 4;
+	format_bytes(fp, fmt, ind, "XCoordinate", c->point.x, 32);
+	format_bytes(fp, fmt, ind, "YCoordinate", c->point.y, 32);
+	format_bytes(fp, fmt, ind, "HASH", c->hash, 32);
+	format_bytes(fp, fmt, ind, "CipherText", c->ciphertext, c->ciphertext_size);
+	return 1;
+}
+
+int sm2_encrypt(const SM2_KEY *key, const uint8_t *in, size_t inlen, uint8_t *out, size_t *outlen)
+{
+	SM2_CIPHERTEXT C;
+
+	if (!key || !in || !out || !outlen) {
+		error_print();
+		return -1;
+	}
+	if (!inlen) {
+		error_print();
+		return -1;
+	}
+
+	if (sm2_do_encrypt(key, in, inlen, &C) != 1) {
+		error_print();
+		return -1;
+	}
+	*outlen = 0;
+	if (sm2_ciphertext_to_der(&C, &out, outlen) != 1) {
+		error_print();
+		return -1;
+	}
+	return 1;
+}
+
+int sm2_encrypt_fixlen(const SM2_KEY *key, const uint8_t *in, size_t inlen, int point_size, uint8_t *out, size_t *outlen)
+{
+	SM2_CIPHERTEXT C;
+
+	if (!key || !in || !out || !outlen) {
+		error_print();
+		return -1;
+	}
+	if (!inlen) {
+		error_print();
+		return -1;
+	}
+
+	if (sm2_do_encrypt_fixlen(key, in, inlen, point_size, &C) != 1) {
+		error_print();
+		return -1;
+	}
+	*outlen = 0;
+	if (sm2_ciphertext_to_der(&C, &out, outlen) != 1) {
+		error_print();
+		return -1;
+	}
+	return 1;
+}
+
+int sm2_decrypt(const SM2_KEY *key, const uint8_t *in, size_t inlen, uint8_t *out, size_t *outlen)
+{
+	SM2_CIPHERTEXT C;
+
+	if (!key || !in || !out || !outlen) {
+		error_print();
+		return -1;
+	}
+	if (sm2_ciphertext_from_der(&C, &in, &inlen) != 1
+		|| asn1_length_is_zero(inlen) != 1) {
+		error_print();
+		return -1;
+	}
+	if (sm2_do_decrypt(key, &C, out, outlen) != 1) {
+		error_print();
+		return -1;
+	}
+	return 1;
+}
+
+int sm2_do_ecdh(const SM2_KEY *key, const SM2_POINT *peer_public, SM2_POINT *out)
+{
+	/*
+	if (sm2_point_is_on_curve(peer_public) != 1) {
+		error_print();
+		return -1;
+	}
+	*/
+	if (sm2_point_mul(out, key->private_key, peer_public) != 1) {
+		error_print();
+		return -1;
+	}
+	return 1;
+}
+
+int sm2_ecdh(const SM2_KEY *key, const uint8_t *peer_public, size_t peer_public_len, SM2_POINT *out)
+{
+	SM2_POINT point;
+
+	if (!key || !peer_public || !peer_public_len || !out) {
+		error_print();
+		return -1;
+	}
+	if (sm2_point_from_octets(&point, peer_public, peer_public_len) != 1) {
+		error_print();
+		return -1;
+	}
+	if (sm2_do_ecdh(key, &point, out) != 1) {
+		error_print();
+		return -1;
+	}
+	return 1;
+}
+
+
+// (x1, y1) = k * G
+// r = e + x1
+// s = (k - r * d)/(1 + d) = (k +r - r * d - r)/(1 + d) = (k + r - r(1 +d))/(1 + d) = (k + r)/(1 + d) - r
+//	= -r + (k + r)*(1 + d)^-1
+//	= -r + (k + r) * d'
+
+int sm2_do_sign_fast(const SM2_Fn d, const uint8_t dgst[32], SM2_SIGNATURE *sig)
+{
+	SM2_JACOBIAN_POINT R;
+	SM2_BN e;
+	SM2_BN k;
+	SM2_BN x1;
+	SM2_BN r;
+	SM2_BN s;
+
+	// e = H(M)
+	sm2_bn_from_bytes(e, dgst);
+	if (sm2_bn_cmp(e, SM2_N) >= 0) {
+		sm2_bn_sub(e, e, SM2_N);
+	}
+
+	// rand k in [1, n - 1]
+	do {
+		if (sm2_fn_rand(k) != 1) {
+			error_print();
+			return -1;
+		}
+	} while (sm2_bn_is_zero(k));
+
+	// (x1, y1) = kG
+	sm2_jacobian_point_mul_generator(&R, k);
+	sm2_jacobian_point_get_xy(&R, x1, NULL);
+
+	// r = e + x1 (mod n)
+	sm2_fn_add(r, e, x1);
+
+	// s = (k + r) * d' - r
+	sm2_bn_add(s, k, r);
+	sm2_fn_mul(s, s, d);
+	sm2_fn_sub(s, s, r);
+
+	sm2_bn_to_bytes(r, sig->r);
+	sm2_bn_to_bytes(s, sig->s);
+	return 1;
+}
+

+ 138 - 0
components/gmssl/src/sm2_recover.c

@@ -0,0 +1,138 @@
+/*
+ *  Copyright 2014-2022 The GmSSL Project. All Rights Reserved.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the License); you may
+ *  not use this file except in compliance with the License.
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <gmssl/sm2.h>
+#include <gmssl/error.h>
+
+
+extern SM2_BN SM2_P;
+extern SM2_BN SM2_B;
+extern SM2_BN SM2_N;
+extern SM2_BN SM2_THREE;
+
+// r = H(Z||M) + x1 (mod n)
+// x1 = r - H(Z||M) (mod n) or (r - H(Z||M) (mod n)) + n
+// y1 = sqrt(x1^3 + a*x1 + b)
+// R = (x1, y1) or (x1, -y1)
+// P = (r + s)^-1 * R - (r + s)^-1 * s * G
+int sm2_signature_to_public_key_points(const SM2_SIGNATURE *sig, const uint8_t dgst[32],
+	SM2_POINT points[4], size_t *points_cnt)
+{
+	SM2_BN SM2_P_SUB_N;
+	SM2_JACOBIAN_POINT P;
+	SM2_JACOBIAN_POINT R;
+
+	SM2_Fp r;
+	SM2_Fp s;
+	SM2_Fp e;
+	SM2_Fn u;
+	SM2_Fn v;
+	SM2_Fp x1;
+	SM2_Fp y1;
+
+	// FIXME: check r, s
+	sm2_bn_from_bytes(r, sig->r);
+	sm2_bn_from_bytes(s, sig->s);
+
+	// u = (r + s)^-1, v = -(r + s)^-1 * s
+	sm2_fn_add(u, r, s);
+	sm2_fn_inv(u, u);
+	sm2_fn_mul(v, u, s);
+	sm2_fn_neg(v, v);
+
+	// e = H(Z||M) (mod n)
+	sm2_bn_from_bytes(e, dgst);
+	if (sm2_bn_cmp(e, SM2_N) >= 0) {
+		sm2_bn_sub(e, e, SM2_N);
+	}
+
+	// x1 = r - e (mod n)
+	sm2_fn_sub(x1, r, e);
+
+	// y1 = sqrt(x1^3 + a*x + b) = sqrt((x1^2 + a)*x1 + b)
+	sm2_fp_sqr(y1, x1);
+	sm2_fp_sub(y1, y1, SM2_THREE);
+	sm2_fp_mul(y1, y1, x1);
+	sm2_fp_add(y1, y1, SM2_B);
+
+	if (sm2_fp_sqrt(y1, y1) != 1) {
+		error_print();
+		return -1;
+	}
+	sm2_jacobian_point_set_xy(&R, x1, y1);
+
+	// P = u * R + v * G
+	sm2_jacobian_point_mul_sum(&P, u, &R, v);
+	sm2_jacobian_point_to_bytes(&P, (uint8_t *)&points[0]);
+
+	// P' = u * (-R) + v * G
+	sm2_jacobian_point_neg(&R, &R);
+	sm2_jacobian_point_mul_sum(&P, u, &R, v);
+	sm2_jacobian_point_to_bytes(&P, (uint8_t *)&points[1]);
+	*points_cnt = 2;
+
+	// if x1 in [n, p-1], x1 (mod n) in [0, p-n-1]
+	// ==> if x1 (mod n) in [0, p-n-1], x1 == (x1 (mod n) + n) (mod p)
+	sm2_bn_sub(SM2_P_SUB_N, SM2_P, SM2_N);
+
+	if (sm2_bn_cmp(x1, SM2_P_SUB_N) < 0) {
+
+		// x1' = x1 (mod n) + n
+		sm2_bn_add(x1, x1, SM2_N);
+
+		// y1' = sqrt(x1'^3 + a*x' + b)
+		sm2_fp_sqr(y1, x1);
+		sm2_fp_sub(y1, y1, SM2_THREE);
+		sm2_fp_mul(y1, y1, x1);
+		sm2_fp_add(y1, y1, SM2_B);
+		if (sm2_fp_sqrt(y1, y1) != 1) {
+			error_print();
+			return -1;
+		}
+		sm2_jacobian_point_set_xy(&R, x1, y1);
+
+		// P = u * R + v * G
+		sm2_jacobian_point_mul_sum(&P, u, &R, v);
+		sm2_jacobian_point_to_bytes(&P, (uint8_t *)&points[2]);
+		// P' = u * (-R) + v * G
+		sm2_jacobian_point_neg(&R, &R);
+		sm2_jacobian_point_mul_sum(&P, u, &R, v);
+		sm2_jacobian_point_to_bytes(&P, (uint8_t *)&points[3]);
+		*points_cnt = 4;
+	}
+
+	return 1;
+}
+
+// verify the xR of R = s * G + (s + r) * P
+// so (-r, -s) is also a valid SM2 signature
+int sm2_signature_conjugate(const SM2_SIGNATURE *sig, SM2_SIGNATURE *new_sig)
+{
+	SM2_Fn r;
+	SM2_Fn s;
+
+	// FIXME: check r,s
+	sm2_bn_from_bytes(r, sig->r);
+	sm2_bn_from_bytes(s, sig->s);
+	sm2_fn_neg(r, r);
+	sm2_fn_neg(s, s);
+	sm2_bn_to_bytes(r, new_sig->r);
+	sm2_bn_to_bytes(s, new_sig->s);
+
+	return 1;
+}
+
+// TODO: Add API to support sig,siglen
+
+
+

Некоторые файлы не были показаны из-за большого количества измененных файлов