diff --git a/.gitignore b/.gitignore index 24705f3..462387f 100644 --- a/.gitignore +++ b/.gitignore @@ -219,3 +219,5 @@ include/openssl/srp.h /rust /python /build +.idea +cmake-build-* \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 2ebed37..4080187 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,155 +14,158 @@ option(NO_SHA1 "Option For Not Compile RC4" OFF) option(NO_SHA2 "Option For Not Compile RC4" OFF) if (NO_RC4) -add_definitions(-DNO_RC4) -endif() + add_definitions(-DNO_RC4) +endif () if (NO_MD5) -add_definitions(-DNO_MD5) -endif() + add_definitions(-DNO_MD5) +endif () if (NO_AES) -add_definitions(-DNO_AES) -endif() + add_definitions(-DNO_AES) +endif () if (NO_DES) -add_definitions(-DNO_DES) -endif() + add_definitions(-DNO_DES) +endif () if (NO_CHACHA20) -add_definitions(-DNO_CHACHA20) -endif() + add_definitions(-DNO_CHACHA20) +endif () if (NO_SHA1) -add_definitions(-DNO_SHA1) -endif() + add_definitions(-DNO_SHA1) +endif () if (NO_SHA2) -add_definitions(-DNO_SHA2) -endif() + add_definitions(-DNO_SHA2) +endif () include_directories(include) add_library( - gmssl - - SHARED - - src/hex.c - src/debug.c - src/rand.c - - # default sm algors - src/sm2_algo.c - src/sm2_lib.c - src/sm2_asn1.c - src/sm2_prn.c - src/sm3.c - src/sm3_hmac.c - src/sm4_common.c - src/sm4_setkey.c - src/sm4_enc.c - src/sm4_modes.c - - # optional sm algors - src/sm9_math.c - src/zuc_core.c - src/zuc_eea.c - src/zuc_eia.c - - # optional nist algors - src/aes.c - src/aes_modes.c - src/chacha20.c - src/sha256.c - src/sha512.c - - # legacy algors - src/rc4.c - src/des.c - src/md5.c - src/sha1.c - - # schemes - src/hash_drbg.c - src/hmac.c - - # abstract - src/digest.c - src/block_cipher.c - - # pkix - src/oid.c - src/asn1.c - src/base64.c - src/pem.c - src/pbkdf2.c - src/pkcs8.c - src/x509_lib.c - src/x509_asn1.c - src/x509_ext.c - src/x509_algor.c - src/cms.c - - # for tls 1.3 - src/hkdf.c - src/gf128.c - src/gcm.c - - # ssl/tls/tlcp - src/tls.c - src/tls_trace.c - src/tls12.c - src/tlcp.c - src/tls13.c - + gmssl + + SHARED + + src/hex.c + src/debug.c + src/rand.c + + # default sm algors + src/sm2_algo.c + src/sm2_lib.c + src/sm2_asn1.c + src/sm2_prn.c + src/sm3.c + src/sm3_hmac.c + src/sm4_common.c + src/sm4_setkey.c + src/sm4_enc.c + src/sm4_modes.c + + # optional sm algors + src/sm9_math.c + src/zuc_core.c + src/zuc_eea.c + src/zuc_eia.c + + # optional nist algors + src/aes.c + src/aes_modes.c + src/chacha20.c + src/sha256.c + src/sha512.c + + # legacy algors + src/rc4.c + src/des.c + src/md5.c + src/sha1.c + + # schemes + src/hash_drbg.c + src/hmac.c + + # abstract + src/digest.c + src/block_cipher.c + + # pkix + src/oid.c + src/asn1.c + src/base64.c + src/pem.c + src/pbkdf2.c + src/pkcs8.c + src/x509_lib.c + src/x509_asn1.c + src/x509_ext.c + src/x509_algor.c + src/cms.c + + # for tls 1.3 + src/hkdf.c + src/gf128.c + src/gcm.c + + # ssl/tls/tlcp + src/tls.c + src/tls_trace.c + src/tls12.c + src/tlcp.c + src/tls13.c + + # tlcp socket + src/tlcp_socket.c + src/tlcp_socket_msg.c + src/tlcp_socket_key.c ) + SET_TARGET_PROPERTIES(gmssl PROPERTIES VERSION 3.0 SOVERSION 3) # tools -add_executable (sm2keygen tools/sm2keygen.c) -target_link_libraries (sm2keygen LINK_PUBLIC gmssl) -add_executable (sm2sign tools/sm2sign.c) -target_link_libraries (sm2sign LINK_PUBLIC gmssl) -add_executable (sm2verify tools/sm2verify.c) -target_link_libraries (sm2verify LINK_PUBLIC gmssl) -add_executable (sm2encrypt tools/sm2encrypt.c) -target_link_libraries (sm2encrypt LINK_PUBLIC gmssl) -add_executable (sm2decrypt tools/sm2decrypt.c) -target_link_libraries (sm2decrypt LINK_PUBLIC gmssl) - -add_executable (sm3 tools/sm3.c) -target_link_libraries (sm3 LINK_PUBLIC gmssl) -add_executable (sm3hmac tools/sm3hmac.c) -target_link_libraries (sm3hmac LINK_PUBLIC gmssl) - -add_executable (reqgen tools/reqgen.c) -target_link_libraries (reqgen LINK_PUBLIC gmssl) -add_executable (reqparse tools/reqparse.c) -target_link_libraries (reqparse LINK_PUBLIC gmssl) - -add_executable (certgen tools/certgen.c) -target_link_libraries (certgen LINK_PUBLIC gmssl) -add_executable (certparse tools/certparse.c) -target_link_libraries (certparse LINK_PUBLIC gmssl) -add_executable (certverify tools/certverify.c) -target_link_libraries (certverify LINK_PUBLIC gmssl) - -add_executable (tlcp_client tools/tlcp_client.c) +add_executable(sm2keygen tools/sm2keygen.c) +target_link_libraries(sm2keygen LINK_PUBLIC gmssl) +add_executable(sm2sign tools/sm2sign.c) +target_link_libraries(sm2sign LINK_PUBLIC gmssl) +add_executable(sm2verify tools/sm2verify.c) +target_link_libraries(sm2verify LINK_PUBLIC gmssl) +add_executable(sm2encrypt tools/sm2encrypt.c) +target_link_libraries(sm2encrypt LINK_PUBLIC gmssl) +add_executable(sm2decrypt tools/sm2decrypt.c) +target_link_libraries(sm2decrypt LINK_PUBLIC gmssl) + +add_executable(sm3 tools/sm3.c) +target_link_libraries(sm3 LINK_PUBLIC gmssl) +add_executable(sm3hmac tools/sm3hmac.c) +target_link_libraries(sm3hmac LINK_PUBLIC gmssl) + +add_executable(reqgen tools/reqgen.c) +target_link_libraries(reqgen LINK_PUBLIC gmssl) +add_executable(reqparse tools/reqparse.c) +target_link_libraries(reqparse LINK_PUBLIC gmssl) + +add_executable(certgen tools/certgen.c) +target_link_libraries(certgen LINK_PUBLIC gmssl) +add_executable(certparse tools/certparse.c) +target_link_libraries(certparse LINK_PUBLIC gmssl) +add_executable(certverify tools/certverify.c) +target_link_libraries(certverify LINK_PUBLIC gmssl) +add_executable(tlcp_client tools/tlcp_client.c) target_link_libraries (tlcp_client LINK_PUBLIC gmssl) -add_executable (tlcp_server tools/tlcp_server.c) +add_executable(tlcp_server tools/tlcp_server.c) target_link_libraries (tlcp_server LINK_PUBLIC gmssl) -add_executable (tls12_client tools/tls12_client.c) -target_link_libraries (tls12_client LINK_PUBLIC gmssl) -add_executable (tls12_server tools/tls12_server.c) -target_link_libraries (tls12_server LINK_PUBLIC gmssl) -add_executable (tls13_client tools/tls13_client.c) -target_link_libraries (tls13_client LINK_PUBLIC gmssl) -add_executable (tls13_server tools/tls13_server.c) -target_link_libraries (tls13_server LINK_PUBLIC gmssl) - +add_executable(tls12_client tools/tls12_client.c) +target_link_libraries(tls12_client LINK_PUBLIC gmssl) +add_executable(tls12_server tools/tls12_server.c) +target_link_libraries(tls12_server LINK_PUBLIC gmssl) +add_executable(tls13_client tools/tls13_client.c) +target_link_libraries(tls13_client LINK_PUBLIC gmssl) +add_executable(tls13_server tools/tls13_server.c) +target_link_libraries(tls13_server LINK_PUBLIC gmssl) # tests @@ -176,129 +179,137 @@ add_executable(sm2asn1test tests/sm2asn1test.c) target_link_libraries (sm2asn1test LINK_PUBLIC gmssl) add_executable(sm3test tests/sm3test.c) -target_link_libraries (sm3test LINK_PUBLIC gmssl) +target_link_libraries(sm3test LINK_PUBLIC gmssl) if (!NO_MD5) -add_executable(md5test tests/md5test.c) -target_link_libraries (md5test LINK_PUBLIC gmssl) -endif() + add_executable(md5test tests/md5test.c) + target_link_libraries(md5test LINK_PUBLIC gmssl) +endif () if (!NO_SHA1) -add_executable(sha1test tests/sha1test.c) -target_link_libraries (sha1test LINK_PUBLIC gmssl) -endif() + add_executable(sha1test tests/sha1test.c) + target_link_libraries(sha1test LINK_PUBLIC gmssl) +endif () if (!NO_SHA2) -add_executable(sha224test tests/sha224test.c) -target_link_libraries (sha224test LINK_PUBLIC gmssl) + add_executable(sha224test tests/sha224test.c) + target_link_libraries(sha224test LINK_PUBLIC gmssl) -add_executable(sha256test tests/sha256test.c) -target_link_libraries (sha256test LINK_PUBLIC gmssl) + add_executable(sha256test tests/sha256test.c) + target_link_libraries(sha256test LINK_PUBLIC gmssl) -add_executable(sha384test tests/sha384test.c) -target_link_libraries (sha384test LINK_PUBLIC gmssl) + add_executable(sha384test tests/sha384test.c) + target_link_libraries(sha384test LINK_PUBLIC gmssl) -add_executable(sha512test tests/sha512test.c) -target_link_libraries (sha512test LINK_PUBLIC gmssl) -endif() + add_executable(sha512test tests/sha512test.c) + target_link_libraries(sha512test LINK_PUBLIC gmssl) +endif () add_executable(hmactest tests/hmactest.c) -target_link_libraries (hmactest LINK_PUBLIC gmssl) +target_link_libraries(hmactest LINK_PUBLIC gmssl) add_executable(hkdftest tests/hkdftest.c) -target_link_libraries (hkdftest LINK_PUBLIC gmssl) +target_link_libraries(hkdftest LINK_PUBLIC gmssl) add_executable(digesttest tests/digesttest.c) -target_link_libraries (digesttest LINK_PUBLIC gmssl) +target_link_libraries(digesttest LINK_PUBLIC gmssl) add_executable(sm4test tests/sm4test.c) -target_link_libraries (sm4test LINK_PUBLIC gmssl) +target_link_libraries(sm4test LINK_PUBLIC gmssl) add_executable(sm4cbctest tests/sm4cbctest.c) -target_link_libraries (sm4cbctest LINK_PUBLIC gmssl) +target_link_libraries(sm4cbctest LINK_PUBLIC gmssl) add_executable(zuctest tests/zuctest.c) -target_link_libraries (zuctest LINK_PUBLIC gmssl) +target_link_libraries(zuctest LINK_PUBLIC gmssl) if (!NO_AES) -add_executable(aestest tests/aestest.c) -target_link_libraries (aestest LINK_PUBLIC gmssl) -endif() + add_executable(aestest tests/aestest.c) + target_link_libraries(aestest LINK_PUBLIC gmssl) +endif () if (!NO_RC4) -add_executable(rc4test tests/rc4test.c) -target_link_libraries (rc4test LINK_PUBLIC gmssl) -endif() + add_executable(rc4test tests/rc4test.c) + target_link_libraries(rc4test LINK_PUBLIC gmssl) +endif () if (!NO_CHACHA20) -add_executable(chacha20test tests/chacha20test.c) -target_link_libraries (chacha20test LINK_PUBLIC gmssl) -endif() + add_executable(chacha20test tests/chacha20test.c) + target_link_libraries(chacha20test LINK_PUBLIC gmssl) +endif () add_executable(hash_drbgtest tests/hash_drbgtest.c) -target_link_libraries (hash_drbgtest LINK_PUBLIC gmssl) +target_link_libraries(hash_drbgtest LINK_PUBLIC gmssl) if (!NO_SHA1) -add_executable(pbkdf2test tests/pbkdf2test.c) -target_link_libraries (pbkdf2test LINK_PUBLIC gmssl) + add_executable(pbkdf2test tests/pbkdf2test.c) + target_link_libraries(pbkdf2test LINK_PUBLIC gmssl) -add_executable(pkcs8test tests/pkcs8test.c) -target_link_libraries (pkcs8test LINK_PUBLIC gmssl) -endif() + add_executable(pkcs8test tests/pkcs8test.c) + target_link_libraries(pkcs8test LINK_PUBLIC gmssl) +endif () add_executable(oidtest tests/oidtest.c) -target_link_libraries (oidtest LINK_PUBLIC gmssl) +target_link_libraries(oidtest LINK_PUBLIC gmssl) add_executable(asn1test tests/asn1test.c) -target_link_libraries (asn1test LINK_PUBLIC gmssl) +target_link_libraries(asn1test LINK_PUBLIC gmssl) add_executable(base64test tests/base64test.c) -target_link_libraries (base64test LINK_PUBLIC gmssl) +target_link_libraries(base64test LINK_PUBLIC gmssl) add_executable(x509test tests/x509test.c) -target_link_libraries (x509test LINK_PUBLIC gmssl) +target_link_libraries(x509test LINK_PUBLIC gmssl) add_executable(cmstest tests/cmstest.c) -target_link_libraries (cmstest LINK_PUBLIC gmssl) +target_link_libraries(cmstest LINK_PUBLIC gmssl) +add_executable(pemtest tests/pemtest.c) +target_link_libraries(pemtest LINK_PUBLIC gmssl) -enable_testing() -add_test(NAME aes COMMAND aestest) -add_test(NAME asn1 COMMAND asn1test) -add_test(NAME base64 COMMAND base64test) -add_test(NAME block_cipher COMMAND block_ciphertext) -add_test(NAME chacha20 COMMAND chacha20test) -add_test(NAME cms COMMAND cmstest) -add_test(NAME ctr COMMAND ctrtest) -add_test(NAME des COMMAND destest) -add_test(NAME digest COMMAND digesttest) -add_test(NAME gcm COMMAND gcmtest) -add_test(NAME gf128 COMMAND gf128test) -add_test(NAME hash_drbg COMMAND hash_drbgtest) -add_test(NAME hkdf COMMAND hkdftest) -add_test(NAME hmac COMMAND hmactest) -add_test(NAME md5 COMMAND md5test) -add_test(NAME oid COMMAND oidtest) -add_test(NAME pbkdf2 COMMAND pbkdf2test) -add_test(NAME pkcs8 COMMAND pkcs8test) -add_test(NAME rc4 COMMAND rc4test) -add_test(NAME sha1 COMMAND sha1test) -add_test(NAME sha224 COMMAND sha224test) -add_test(NAME sha256 COMMAND sha256test) -add_test(NAME sha384 COMMAND sha384test) -add_test(NAME sha512 COMMAND sha512test) -add_test(NAME sm2asn1 COMMAND sm2asn1test) -add_test(NAME sm2 COMMAND sm2test) -add_test(NAME sm3 COMMAND sm3test) -add_test(NAME sm4cbc COMMAND sm4cbctest) -add_test(NAME sm4 COMMAND sm4test) -add_test(NAME tls COMMAND tlstest) -add_test(NAME u128 COMMAND u128test) -add_test(NAME x509 COMMAND x509test) -add_test(NAME zuc COMMAND zuctest) +add_executable(x509_verify tests/x509_verify.c) +target_link_libraries(x509_verify LINK_PUBLIC gmssl) + +add_executable(tlcp_socket_test tests/tlcpsockettest.c) +target_link_libraries(tlcp_socket_test LINK_PUBLIC gmssl) +enable_testing() +add_test(NAME aes COMMAND aestest) +add_test(NAME asn1 COMMAND asn1test) +add_test(NAME base64 COMMAND base64test) +add_test(NAME block_cipher COMMAND block_ciphertext) +add_test(NAME chacha20 COMMAND chacha20test) +add_test(NAME cms COMMAND cmstest) +add_test(NAME ctr COMMAND ctrtest) +add_test(NAME des COMMAND destest) +add_test(NAME digest COMMAND digesttest) +add_test(NAME gcm COMMAND gcmtest) +add_test(NAME gf128 COMMAND gf128test) +add_test(NAME hash_drbg COMMAND hash_drbgtest) +add_test(NAME hkdf COMMAND hkdftest) +add_test(NAME hmac COMMAND hmactest) +add_test(NAME md5 COMMAND md5test) +add_test(NAME oid COMMAND oidtest) +add_test(NAME pbkdf2 COMMAND pbkdf2test) +add_test(NAME pkcs8 COMMAND pkcs8test) +add_test(NAME rc4 COMMAND rc4test) +add_test(NAME sha1 COMMAND sha1test) +add_test(NAME sha224 COMMAND sha224test) +add_test(NAME sha256 COMMAND sha256test) +add_test(NAME sha384 COMMAND sha384test) +add_test(NAME sha512 COMMAND sha512test) +add_test(NAME sm2asn1 COMMAND sm2asn1test) +add_test(NAME sm2 COMMAND sm2test) +add_test(NAME sm3 COMMAND sm3test) +add_test(NAME sm4cbc COMMAND sm4cbctest) +add_test(NAME sm4 COMMAND sm4test) +add_test(NAME tls COMMAND tlstest) +add_test(NAME u128 COMMAND u128test) +add_test(NAME x509 COMMAND x509test) +add_test(NAME zuc COMMAND zuctest) +add_test(NAME tlcp_socket COMMAND tlcp_socket_test) INSTALL(TARGETS certparse certgen certverify reqgen sm3 sm2keygen sm2sign sm2verify sm2encrypt sm2decrypt tlcp_client tlcp_server tls12_client tls12_server tls13_client tls13_server RUNTIME DESTINATION bin) diff --git a/README.md b/README.md index b92c42b..37fbeee 100644 --- a/README.md +++ b/README.md @@ -31,6 +31,7 @@ GmSSL的2.x版本的开发始于2016年,目前主分支在功能上实现了 ### SSL协议 * TLCP 1.1,支持密码套件:`ECDHE_SM4_CBC_SM3 {0xE0,0x11}` (GB/T 38636-2020、GM/T 0024-2014) + * [TLCP SOCKET 使用说明](./doc/TLCP_SOCKET_README.md) * TLS 1.2,支持密码套件:`ECDHE_SM4_CBC_SM3 {0xE0,0x11}` (GB/T 38636-2020、GM/T 0024-2014、RFC 5246) * TLS 1.3,支持密码套件:`TLS_SM4_GCM_SM3 {0x00,0xC6}` +ECDHE/SM2 (RFC 8998), `TLS_AES_128_GCM_SHA256` + ECDHE/ECDSA/NIST-P256 diff --git a/doc/TLCP_SOCKET_README.md b/doc/TLCP_SOCKET_README.md new file mode 100644 index 0000000..2df2842 --- /dev/null +++ b/doc/TLCP_SOCKET_README.md @@ -0,0 +1,268 @@ +# TLCP SOCKET使用说明 + +支持密码套件: + +- `ECDHE_SM4_CBC_SM3 {0xE0,0x11}` (GB/T 38636-2020、GM/T 0024-2014) + +测试用例: + +- [tlcpsockettest](../tests/tlcpsockettest.c) + - TLCP服务端测试:`server_test()` + - TLCP客户端 单向身份认证测试:`client_conn_test()` + - TLCP客户端 双向身份认证测试:`client_auth_test()` + +## TLCP SOCKET API + +### 创建TLCP监听器 + +原型: + +```c +int TLCP_SOCKET_Listen(TLCP_SOCKET_CONFIG *config, + TLCP_SOCKET_Listener *ln, int port); +``` + +描述: 创建 TLCP listener接收TLCP连接 + +参数: + +- `config` [in,out] 配置信息 +- `ln` [out] 连接监听器 +- `port` [in] 服务监听端口 + +返回值: + +- `1` 成功 +- `-1` 失败 + +### 创建TLCP监听器(文件描述符) + +原型: + +```c +int TLCP_SOCKET_Listen_raw(TLCP_SOCKET_CONFIG *config, + TLCP_SOCKET_Listener *ln, int fd); +``` + +描述: 通过文件描述符创建 TLCP listener接收TLCP连接 + +参数: + +- `config` [in,out] 配置信息 +- `ln` [out] 连接监听器 +- `fd` [in] 文件描述符,如socket fd + +返回值: + +- `1` 成功 +- `-1` 失败 + +### 关闭TLCP服务端监听 + +原型: + +```c +void TLCP_SOCKET_Close(TLCP_SOCKET_Listener *ln); +``` + +描述: 关闭TLCP服务端监听 + +参数: + +- `ln` [in] 监听器 + +返回值:无 + +### 接收TLCP连接 + +原型: + +```c +int TLCP_SOCKET_Accept(TLCP_SOCKET_Listener *ln, TLCP_SOCKET_CONNECT *conn); +``` + +描述: 服务端接受TLCP连接 并进行握手 + +参数: + +- `ln` [in] 监听器 +- `conn` [out] 连接对象 + +返回值: + +- `1` 成功 +- `-1` 失败 + +### 读取数据 + +原型: + +```c +ssize_t TLCP_SOCKET_Read(TLCP_SOCKET_CONNECT *conn, + void *buf, size_t count); +``` + +描述:从TLCP连接中解密校验读取数据,设计参考: `unistd.h write()` + +参数: + +- `conn` [in] TCLP连接 +- `buf` [out] 读取数据缓冲区 +- `count` [in] 缓冲区长度 + +返回值: + +- 成功时返回读取字节数; +- 失败时返回`-1`,并存储错误代码errno + +### 写入数据 + +原型: + +```c +ssize_t TLCP_SOCKET_Write(TLCP_SOCKET_CONNECT *conn, void *buf, size_t count); +``` + +描述: 向TLCP连接中加密验证写入数据,设计参考: `unistd.h read` + +参数: + +- `conn` [in] TCLP连接 +- `buf` [in] 待写入数据 +- `count` [in] 待写入数据数量(字节) + +返回值: + +- 成功时返回写入字节数 +- 失败时返回`-1`,并存储错误代码errno + +### TLCP拨号 + +原型: + +```c +int TLCP_SOCKET_Dial(TLCP_SOCKET_CONFIG *config, TLCP_SOCKET_CONNECT *config, + const char *hostname, int port); +``` + +描述:连接TLCP服务端,并进行TLCP握手 + +参数: + +- `config` [in] 配置信息 +- `conn` [out] TLCP连接 +- `hostname` [in] 主机地址(IP) +- `port` [in] 主机端口 + +返回值: + +- `1` 成功 +- `-1` 失败 + +### 关闭TLCP连接 + +原型: + +```c +void TLCP_SOCKET_Connect_Close(TLCP_SOCKET_CONNECT *conn); +``` + +描述: 断开TLCP连接 + +参数: + +- `conn` [in] 连接 + +返回值: 无 + +### 创建SOCKET密钥对 + +原型: + +```c +int TLCP_SOCKET_GMSSL_Key(TLCP_SOCKET_KEY *socket_key, X509_CERTIFICATE *cert, SM2_KEY *sm2_key); +``` + +描述:创建GMSSL类型的 SOCKET密钥对,包含SM2密钥对和关键证书。 + +参数: + +- `socket_key` [in,out] 密钥对指针 +- `cert` [in] 证书指针 +- `sm2_key` [in] SM2私钥 + +返回值: + +- `1` 成功 +- `-1` 失败 + +## 接口 + +在TLCP通信过程最主要的是要确保签名和解密的密钥的安全性。 + +通信过程中的HMAC、对称加解密。 +可以委托GMSSL软件实现,因此抽象 与密钥计算相关的计算部分为接口,用于适配不同密码介质需要。 +在密码领域中随机数的质量决定了安全性,因此将随机发生器进行抽象封装成接口,由外部提供随机源。 + +### 密钥对抽象 + +```c +typedef struct TLCP_SOCKET_KEY_st { + void *ctx; // 上下文,可以是一个设备句柄或会话指针用于函数调用。 + X509_CERTIFICATE *cert; // 证书(公钥) + TLCP_SOCKET_Signer_FuncPtr signer; // 密钥对的签名实现 + TLCP_SOCKET_Decrypter_FuncPtr decrypter; // 密钥对的解密实现 + +} TLCP_SOCKET_KEY; +``` + +- `ctx` 密钥上下文,可以是一个句柄用于在运算是访问。 +- `cert` 密钥关联的证书。 +- `signer` 签名接口 +- `decrypter` 加密接口 + + + +**签名接口原型** + +```c +int TLCP_SOCKET_Signer_FuncPtr(void *ctx, + uint8_t *msg, size_t msglen, + uint8_t *sig, size_t *siglen); +``` + +参数: + +- `ctx` [in] TLCP_SOCKET_KEY.ctx,该参数在每次调用该方法时传入,请根据情况在函数内部强制类型转换使用。 +- `msg` [in] 待签名原文 +- `msglen` [in] 待签名原文长度 +- `sig` [out] 签名值 +- `siglen` [out] 签名值长度 + +返回值: + +- `1` 成功 +- `-1` 失败 + + + +**解密接口原型** + +```c +int TLCP_SOCKET_Decrypter_FuncPtr(void *ctx, + uint8_t *ciphertext, size_t ciphertext_len, + uint8_t *plaintext, size_t *plaintext_len); +``` + +参数: + +- `ctx` [in] TLCP_SOCKET_KEY.ctx,该参数在每次调用该方法时传入,请根据情况在函数内部强制类型转换使用。 +- `ciphertext` [in] 密文 +- `ciphertext_len` [in] 密文长度 +- `plaintext` [out] 明文 +- `plaintext_len` [out] 明文长度 + +返回值: + +- `1` 成功 +- `-1` 失败 diff --git a/include/gmssl/base64.h b/include/gmssl/base64.h index ec45d08..de1e551 100644 --- a/include/gmssl/base64.h +++ b/include/gmssl/base64.h @@ -89,6 +89,15 @@ 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); +/** + * Base64字符串解码 + * @param in Base64字符串 + * @param inlen 字符串长度 + * @param out 解码存储位置 + * @param outlen 解码后字节长度 + * @return 0 解码成功;-1 解码异常 + */ +int base64_str_decode(const uint8_t *in, int inlen, uint8_t *out, int *outlen); #ifdef __cplusplus } diff --git a/include/gmssl/error.h b/include/gmssl/error.h index c4ec5f0..ce85067 100644 --- a/include/gmssl/error.h +++ b/include/gmssl/error.h @@ -75,7 +75,7 @@ extern "C" { 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); - +void print_hex_str(const uint8_t *data, size_t datalen); 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); diff --git a/include/gmssl/pem.h b/include/gmssl/pem.h index 940f0f3..4967830 100644 --- a/include/gmssl/pem.h +++ b/include/gmssl/pem.h @@ -64,7 +64,16 @@ extern "C" { int pem_read(FILE *fp, const char *name, uint8_t *data, size_t *datalen); int pem_write(FILE *fp, const char *name, const uint8_t *data, size_t datalen); - +/** + * 从字符串中读取PEM格式 + * @param in 字符串 + * @param str_len 字符串长度 + * @param name PEM头名称 + * @param data 解码输出位置 + * @param datalen 解码后长度 + * @return 1 - OK;-1 error + */ +int pem_read_str(uint8_t *in, size_t str_len, const char *name, uint8_t *data, size_t *datalen); #ifdef __cplusplus } diff --git a/include/gmssl/rand.h b/include/gmssl/rand.h index 8a27f3d..cceaaf5 100644 --- a/include/gmssl/rand.h +++ b/include/gmssl/rand.h @@ -56,6 +56,14 @@ int rand_bytes(uint8_t *buf, size_t len); +/** + * 随机源函数指针接口 + * + * @param buf [in] 缓冲区 + * @param len [in] 待读取随机数长度 + * @return 1 - 成功;-1 - 失败 + */ +typedef int (*rand_src)(uint8_t *buf, size_t len); #ifdef __cplusplus } diff --git a/include/gmssl/sm2.h b/include/gmssl/sm2.h index 8d6bf1f..f675097 100644 --- a/include/gmssl/sm2.h +++ b/include/gmssl/sm2.h @@ -54,135 +54,257 @@ #include #include #include +#include #ifdef __cplusplus extern "C" { #endif - typedef struct { - uint8_t x[32]; - uint8_t y[32]; + uint8_t x[32]; + uint8_t y[32]; } SM2_POINT; 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_octets(SM2_POINT *P, const uint8_t *in, size_t inlen); + int sm2_point_to_der(const SM2_POINT *a, uint8_t **out, size_t *outlen); + int sm2_point_from_der(SM2_POINT *a, const uint8_t **in, size_t *inlen); + 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_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]); + int sm2_point_print(FILE *fp, const SM2_POINT *P, int format, int indent); int sm2_compute_z(uint8_t z[32], const SM2_POINT *pub, const char *id); typedef struct { - SM2_POINT public_key; - uint8_t private_key[32]; - uint8_t key_usage[4]; + SM2_POINT public_key; + uint8_t private_key[32]; + uint8_t key_usage[4]; } SM2_KEY; int sm2_keygen(SM2_KEY *key); + int sm2_set_private_key(SM2_KEY *key, const uint8_t private_key[32]); + int sm2_set_public_key(SM2_KEY *key, const uint8_t public_key[64]); // FIXME: 这里是否应该用octets呢?这算是椭圆曲线点的一个公开格式了 int sm2_key_print(FILE *fp, const SM2_KEY *key, int format, int indent); + int sm2_public_key_digest(const SM2_KEY *key, uint8_t dgst[32]); // ECPrivateKey int sm2_private_key_to_der(const SM2_KEY *key, uint8_t **out, size_t *outlen); + int sm2_private_key_to_pem(const SM2_KEY *key, FILE *fp); + int sm2_private_key_from_der(SM2_KEY *key, const uint8_t **in, size_t *inlen); + +/** + * 从PEM文件中读取密钥,支持pkcs8、X962(RFC 5915)格式 + * @param key 密钥 + * @param fp 文件 + * @return 1 成功;-1 失败 + */ int sm2_private_key_from_pem(SM2_KEY *key, FILE *fp); +/** + * 解析PKCS8格式SM2私钥 + * @param key SM2私钥 + * @param in 字节串 + * @param inlen 输出长度 + * @return 1 成功;-1 解析失败 + */ +int sm2_private_key_from_pkcs8_der(SM2_KEY *key, const uint8_t **in, size_t *inlen); + +/** + * 从PEM字符串中读取密钥,支持pkcs8、X962(RFC 5915)格式 + * @param a 密钥 + * @param in 字符串 + * @param inlen 字符串长度 + * @return 1 解析成功;-1解析失败 + */ +int sm2_private_key_from_str_pem(SM2_KEY *key, uint8_t *in, size_t inlen); // AlgorithmIdentifier 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); // X.509 SubjectPublicKeyInfo int sm2_public_key_info_to_der(const SM2_KEY *a, uint8_t **out, size_t *outlen); + int sm2_public_key_info_to_pem(const SM2_KEY *a, FILE *fp); + int sm2_public_key_info_from_der(SM2_KEY *a, const uint8_t **in, size_t *inlen); + int sm2_public_key_info_from_pem(SM2_KEY *a, FILE *fp); // PKCS #8 PrivateKeyInfo 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_from_der(SM2_KEY *key, const uint8_t **attrs, size_t *attrslen, const uint8_t **in, size_t *inlen); + int sm2_private_key_info_to_pem(const SM2_KEY *key, FILE *fp); + int sm2_private_key_info_from_pem(SM2_KEY *key, const uint8_t **attrs, size_t *attrslen, FILE *fp); typedef struct { - uint8_t r[32]; - uint8_t s[32]; + uint8_t r[32]; + uint8_t s[32]; } SM2_SIGNATURE; 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_do_sign(const SM2_KEY *key, const uint8_t dgst[32], SM2_SIGNATURE *sig); + +/** + * SM2签名 随机数由外部随机源提供 + * @param rd [in] 随机源 + * @param key [in] sm2密钥 + * @param dgst [in] 预处理值 + * @param sig [out] 签名值对象 + * @return 1 - 成功;-1 - 失败 + */ +int sm2_do_sign_ext(rand_src rd, const SM2_KEY *key, 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); + int sm2_print_signature(FILE *fp, const uint8_t *sig, size_t siglen, int format, int indent); #define SM2_MAX_SIGNATURE_SIZE 72 int sm2_sign(const SM2_KEY *key, const uint8_t dgst[32], uint8_t *sig, size_t *siglen); + +/** + * SM2签名并序列化签名值为DER 随机数由外部随机源提供 + * @param rd [in] 随机源 + * @param key [in] sm2密钥 + * @param dgst [in] 预处理值 + * @param der [out] 签名值DER + * @param derlen [out] 签名值DER长度 + * @return 1 - 成功;-1 - 失败 + */ +int sm2_sign_ext(rand_src rd, const SM2_KEY *key, const uint8_t dgst[32], uint8_t *der, size_t *derlen); + int sm2_verify(const SM2_KEY *key, const uint8_t dgst[32], const uint8_t *sig, size_t siglen); -#define SM2_MAX_ID_BITS 65535 -#define SM2_MAX_ID_LENGTH (SM2_MAX_ID_BITS/8) -#define SM2_MAX_ID_SIZE (SM2_MAX_ID_BITS/8) -#define SM2_DEFAULT_ID_GMT09 "1234567812345678" -#define SM2_DEFAULT_ID_GMSSL "anonym@gmssl.org" -#define SM2_DEFAULT_ID SM2_DEFAULT_ID_GMT09 -#define SM2_DEFAULT_ID_LENGTH (sizeof(SM2_DEFAULT_ID) - 1) -#define SM2_DEFAULT_ID_BITS (SM2_DEFAULT_ID_LENGTH * 8) -#define SM2_DEFAULT_ID_DIGEST_LENGTH SM3_DIGEST_LENGTH +#define SM2_MAX_ID_BITS 65535 +#define SM2_MAX_ID_LENGTH (SM2_MAX_ID_BITS/8) +#define SM2_MAX_ID_SIZE (SM2_MAX_ID_BITS/8) +#define SM2_DEFAULT_ID_GMT09 "1234567812345678" +#define SM2_DEFAULT_ID_GMSSL "anonym@gmssl.org" +#define SM2_DEFAULT_ID SM2_DEFAULT_ID_GMT09 +#define SM2_DEFAULT_ID_LENGTH (sizeof(SM2_DEFAULT_ID) - 1) +#define SM2_DEFAULT_ID_BITS (SM2_DEFAULT_ID_LENGTH * 8) +#define SM2_DEFAULT_ID_DIGEST_LENGTH SM3_DIGEST_LENGTH typedef struct { - SM2_KEY key; - SM3_CTX sm3_ctx; - int flags; + SM2_KEY key; + SM3_CTX sm3_ctx; + int flags; } SM2_SIGN_CTX; int sm2_sign_init(SM2_SIGN_CTX *ctx, const SM2_KEY *key, const char *id); + int sm2_sign_update(SM2_SIGN_CTX *ctx, const uint8_t *data, size_t datalen); + int sm2_sign_finish(SM2_SIGN_CTX *ctx, uint8_t *sig, size_t *siglen); + +/** + * SM2结束签名 + * + * k值由外部随机源产生 + * + * @param rd [in] 随机源 + * @param ctx [in] 签名上下文 + * @param sig [out] 签名值 + * @param siglen [out] 签名值长度 + * @return 1 - 成功;-1 - 失败 + */ +int sm2_sign_finish_ext(rand_src rd,SM2_SIGN_CTX *ctx, uint8_t *sig, size_t *siglen); + int sm2_verify_init(SM2_SIGN_CTX *ctx, const SM2_KEY *key, const char *id); + int sm2_verify_update(SM2_SIGN_CTX *ctx, const uint8_t *data, size_t datalen); + int sm2_verify_finish(SM2_SIGN_CTX *ctx, const uint8_t *sig, size_t siglen); typedef struct { - SM2_POINT point; - uint8_t hash[32]; - uint32_t ciphertext_size; - uint8_t ciphertext[1]; + SM2_POINT point; + uint8_t hash[32]; + uint32_t ciphertext_size; + uint8_t ciphertext[1]; } SM2_CIPHERTEXT; -#define SM2_MAX_PLAINTEXT 256 -#define SM2_MAX_PLAINTEXT_SIZE 256 +#define SM2_MAX_PLAINTEXT 256 +#define SM2_MAX_PLAINTEXT_SIZE 256 #define SM2_CIPHERTEXT_SIZE(inlen) (sizeof(SM2_CIPHERTEXT)-1+inlen) -#define SM2_MAX_CIPHERTEXT_SIZE 512 - +#define SM2_MAX_CIPHERTEXT_SIZE 512 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, const SM2_CIPHERTEXT *c, int format, int indent); + int sm2_do_encrypt(const SM2_KEY *key, const uint8_t *in, size_t inlen, SM2_CIPHERTEXT *out); + +/** + * SM2加密 随机数由外部随机源产生 + * + * @param rd [in] 随机源 + * @param key [in] sm2密钥 + * @param in [in] 明文 + * @param inlen [in] 明文长度 + * @param out [out] 密文对象 + * @return 1 - 成功;-1 - 失败 + */ +int sm2_do_encrypt_ext(rand_src rd, 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); int sm2_encrypt(const SM2_KEY *key, const uint8_t *in, size_t inlen, uint8_t *out, size_t *outlen); + +/** + * SM2加密并编码密文DER 随机数由外部随机源产生 + * + * @param rd [in] 随机源 + * @param key [in] sm2密钥 + * @param in [in] 明文 + * @param inlen [in] 明文长度 + * @param out [out] 密文 + * @param outlen [out] 密文长度 + * @return 1 - 成功;-1 - 失败 + */ +int sm2_encrypt_ext(rand_src rd, const SM2_KEY *key, const uint8_t *in, size_t inlen, uint8_t *out, size_t *outlen); + int sm2_decrypt(const SM2_KEY *key, const uint8_t *in, size_t inlen, uint8_t *out, size_t *outlen); + int sm2_print_ciphertext(FILE *fp, const uint8_t *c, size_t clen, int format, int indent); int sm2_ecdh(const SM2_KEY *key, const SM2_POINT *peer_public, SM2_POINT *out); @@ -192,6 +314,6 @@ int sm2_algo_selftest(void); #ifdef __cplusplus -extern "C" { +} #endif #endif diff --git a/include/gmssl/tlcp_socket.h b/include/gmssl/tlcp_socket.h new file mode 100644 index 0000000..8083701 --- /dev/null +++ b/include/gmssl/tlcp_socket.h @@ -0,0 +1,307 @@ +/* + * Copyright (c) 2021 - 2021 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 GMSSL_TLCP_SOCKET_H +#define GMSSL_TLCP_SOCKET_H +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include +#include + +/** + * 在TLCP通信过程最主要的是要确保签名和解密的密钥的安全性 + * 通信过程中的HMAC、对称加解密,可以委托GMSSL软件实现 + * 因此抽象 与密钥计算相关的计算部分为接口,用于适配不同密码介质需要。 + * + * 在密码领域中随机数的质量决定了安全性,因此将随机发生器进行抽象封装成接口 + * 由外部提供随机源。 + * + * 接口定义,小写字母开头函数表示内部使用,大写字母开头表示对外暴露,私有接口使用static修饰 + * 如:tlcp_* 表示内部使用 + * 如:TLCP_SOCKET_* 表示对外暴露接口 + */ + + +/** + * 获取随机字节(随机源) + * + * 注:随机数一般来说不需要上下文 + * + * @param buf [out] 缓冲区 + * @param len [in] 缓冲区长度 + * @return 1 - 读取成功;-1 - 读取失败 + */ +typedef rand_src TLCP_SOCKET_RandBytes_FuncPtr; + +/** + * TLCP签名接口,用于实现签名 + * + * @param ctx [in] TLCP_SOCKET_KEY.ctx,该参数在每次调用该方法时传入,请根据情况在函数内部强制类型转换使用。 + * @param msg [in] 待签名原文 + * @param msglen [in] 待签名原文长度 + * @param sig [out] 签名值 + * @param siglen [out] 签名值长度 + * @return 1 - 成功;-1 - 失败 + */ +typedef int (*TLCP_SOCKET_Signer_FuncPtr)(void *ctx, uint8_t *msg, size_t msglen, uint8_t *sig, size_t *siglen); + +/** + * TLCP解密接口,用于数据解密 + * + * @param ctx [in] TLCP_SOCKET_KEY.ctx,该参数在每次调用该方法时传入,请根据情况在函数内部强制类型转换使用。 + * @param ciphertext [in] 密文 + * @param ciphertext_len [in] 密文长度 + * @param plaintext [out] 明文 + * @param plaintext_len [out] 明文长度 + * @return 1 - 成功;-1 - 失败 + */ +typedef int (*TLCP_SOCKET_Decrypter_FuncPtr)(void *ctx, uint8_t *ciphertext, size_t ciphertext_len, + uint8_t *plaintext, size_t *plaintext_len); + +/** + * TLCP Socket 密钥对接口 + * + * 公钥、证书、签名、解密 + */ +typedef struct TLCP_SOCKET_KEY_st { + void *ctx; // 上下文,可以是一个设备句柄或会话指针用于函数调用。 + X509_CERTIFICATE *cert; // 证书(公钥) + TLCP_SOCKET_Signer_FuncPtr signer; // 密钥对的签名实现 + TLCP_SOCKET_Decrypter_FuncPtr decrypter; // 密钥对的解密实现 + +} TLCP_SOCKET_KEY; + + +struct TLCP_SOCKET_CONNECT_st; +typedef struct TLCP_SOCKET_CONNECT_st TLCP_SOCKET_CONNECT; + +/** + * 报警协议处理器 + * + * 每当连接收到或发送报警协议时将触发该函数 + * @param conn [in] 连接上下文 + * @param alert_description [in] 报警描述信息 + */ +typedef void (*TLCP_SOCKET_Alert_Handler_FuncPtr)(TLCP_SOCKET_CONNECT *conn, uint8_t alert_description); + +/** + * SOCKET配置上下文 + */ +typedef struct TLCP_SOCKET_CONFIG_st { + TLCP_SOCKET_RandBytes_FuncPtr rand; // 随机源 + X509_CERTIFICATE *root_certs; // 根证书列表,客户端用于验证服务端证书,服务端用于验证客户端证书,如果为空表示不验证。 + int root_cert_len; // 根证书数量 + TLCP_SOCKET_KEY *server_sig_key; // 服务器签名密钥对 + TLCP_SOCKET_KEY *server_enc_key; // 服务器加密密钥对 + TLCP_SOCKET_KEY *client_sig_key; // 客户端认证密钥对 + TLCP_SOCKET_Alert_Handler_FuncPtr alert_handler; // 报警消息处理器 + +} TLCP_SOCKET_CONFIG; + +#define TLCP_SOCKET_SERVER_END 0 +#define TLCP_SOCKET_CLIENT_END 1 +#define TLCP_SOCKET_DEFAULT_FRAME_SIZE 4096 + +#define TLCP_SOCKET_CONNECTED 0 // 成功建立TLCP Socket连接 +#define TLCP_SOCKET_UNCONNECTED 1 // 未建立TLCP Socket连接 + +/** + * TLCP SOCKET连接 + * + * 用于维护在连接过程中需要上下文数据 + * + * 注:握手阶段数据由Accept内部维护,握手结束后初始化完成连接参数。 + * 其中以"_"开头的参数表示私有参数,不应该在外部访问。 + */ +struct TLCP_SOCKET_CONNECT_st { + TLCP_SOCKET_CONFIG *config; // 连接配置上下文 + int sock; // Socket FD + int version; // 协议版本 + int cipher_suite; // 密码套件 + size_t session_id_len; // 会话ID长度 + uint8_t session_id[32]; // 会话ID + + uint8_t entity; // 0 - server, 1 - client + uint8_t connected; // 0 - 未连接; 1 - 已经建立连接 + uint8_t hash_size; // HASH分组长度 + uint8_t key_material_length; // 对称密钥长度 + uint8_t fixed_iv_length; // IV长度 + + uint8_t _client_random[32]; // 客户端随机数 + uint8_t _server_random[32]; // 服务端随机数 + + uint8_t _client_seq_num[8]; // 客户端消息序列号 + uint8_t _server_seq_num[8]; // 服务端消息序列号 + + // 密钥 + uint8_t _master_secret[48]; // 主密钥 + uint8_t _key_block[96]; // 工作密钥,下面是各密钥的指针 + SM3_HMAC_CTX _client_write_mac_ctx; // 客户端写MAC密钥 + SM3_HMAC_CTX _server_write_mac_ctx; // 服务端写MAC密钥 + SM4_KEY _client_write_enc_key; // 客户端写加密密钥 + SM4_KEY _server_write_enc_key; // 服务端写加密密钥 + uint8_t *_client_write_IV; // 客户端写IV + uint8_t *_server_write_IV; // 服务端写IV + + // 连接上下文参数 + uint8_t record[TLS_RECORD_MAX_PLAINDATA_SIZE]; // 解密后记录层消息 + uint8_t _raw_input[TLS_MAX_RECORD_SIZE]; // 未解密原始数据 + uint8_t *_p; // 记录层中数据游标指针,随着读取逐渐向后移动 + size_t _buf_remain; // 记录层中数据剩余长度 + + SM3_CTX *_sm3_ctx; // 用于握手阶段的校验码计算,握手结束后置为NULL +}; + +/** + * 连接监听器,负责接收和建立连接 + */ +typedef struct { + TLCP_SOCKET_CONFIG *config; // 配置上下文 + int _sock; // Server SocketFD +} TLCP_SOCKET_Listener; + +/** + * 创建 TLCP listener接收TLCP连接 + * + * @param config [in,out] 配置信息 + * @param ln [out] 连接监听器 + * @param port [in] 服务监听端口 + * @return 1 - 读取成功;-1 - 读取失败 + */ +int TLCP_SOCKET_Listen(TLCP_SOCKET_CONFIG *config, TLCP_SOCKET_Listener *ln, int port); + +/** + * 通过文件描述符创建 TLCP listener接收TLCP连接 + * + * @param config [in,out] 配置信息 + * @param ln [out] 连接监听器 + * @param fd [in] 文件描述符,如socket fd + * @return 1 - 读取成功;-1 - 读取失败 + */ +int TLCP_SOCKET_Listen_raw(TLCP_SOCKET_CONFIG *config, TLCP_SOCKET_Listener *ln, int fd); + +/** + * 关闭TLCP服务端监听 + * + * @param ln [in] 监听器 + */ +void TLCP_SOCKET_Close(TLCP_SOCKET_Listener *ln); + +/** + * 服务端接受TLCP连接 并进行握手 + * + * 该方法将会发生阻塞,直到发现连接或服务关闭 + * + * @param ln [in] 监听器 + * @param conn [out] 连接对象 + * @return 1 - 连接成功; -1 - 连接失败 + */ +int TLCP_SOCKET_Accept(TLCP_SOCKET_Listener *ln, TLCP_SOCKET_CONNECT *conn); + +/** + * 从TLCP连接中解密校验读取数据 + * + * 设计参考: unistd.h write() + * + * @param conn [in] TCLP连接 + * @param buf [out] 读取数据缓冲区 + * @param count [in] 缓冲区长度 + * @return 成功时返回读取字节数;失败时返回-1,并存储错误代码errno + */ +ssize_t TLCP_SOCKET_Read(TLCP_SOCKET_CONNECT *conn, void *buf, size_t count); + +/** + * 向TLCP连接中加密验证写入数据 + * + * 设计参考: unistd.h read + * + * @param conn [in] TCLP连接 + * @param buf [in] 待写入数据 + * @param count [in] 待写入数据数量(字节) + * @return 成功时返回写入字节数;失败时返回-1,并存储错误代码errno + */ +ssize_t TLCP_SOCKET_Write(TLCP_SOCKET_CONNECT *conn, void *buf, size_t count); + +/** + * 连接TLCP服务端,并进行TLCP握手 + * + * @param config [in] 配置信息 + * @param conn [out] TLCP连接 + * @param hostname [in] 主机地址(IP) + * @param port [in] 主机端口 + * @return 1 - 连接成功;-1 - 连接失败 + */ +int TLCP_SOCKET_Dial(TLCP_SOCKET_CONFIG *config, TLCP_SOCKET_CONNECT *conn, const char *hostname, int port); + +/** + * 断开TLCP连接 + * + * @param conn [in] 连接 + */ +void TLCP_SOCKET_Connect_Close(TLCP_SOCKET_CONNECT *conn); + +/** + * 创建国密SSL类型的 SOCKET密钥对 + * + * @param socket_key [in,out] 密钥对指针 + * @param cert [in] 证书指针 + * @param sm2_key [in] SM2私钥 + * @return 1 - 成功;-1 - 失败 + */ +int TLCP_SOCKET_GMSSL_Key(TLCP_SOCKET_KEY *socket_key, X509_CERTIFICATE *cert, SM2_KEY *sm2_key); + +#ifdef __cplusplus +} +#endif +#endif //GMSSL_TLCP_SOCKET_H diff --git a/include/gmssl/tlcp_socket_msg.h b/include/gmssl/tlcp_socket_msg.h new file mode 100644 index 0000000..7635088 --- /dev/null +++ b/include/gmssl/tlcp_socket_msg.h @@ -0,0 +1,365 @@ +/* + * Copyright (c) 2021 - 2021 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 GMSSL_TLCP_SOCKET_MSG_H +#define GMSSL_TLCP_SOCKET_MSG_H +#ifdef __cplusplus +extern "C" { +#endif + +#include + + +/** + * 读取并处理客户端Hello消息 + * + * @param conn [in,out]连接对象 + * @param record [in] 收到的记录层数据 + * @param recordlen [in] 记录层数据 + * @return 1 - 成功;-1 - 失败 + */ +int tlcp_socket_read_client_hello(TLCP_SOCKET_CONNECT *conn, uint8_t *record, size_t *recordlen); + +/** + * 写入服务端Hello消息 + * + * @param conn [in,out] 连接对象 + * @param out [in,out] 缓冲区,写入后会产生偏移。 + * @param outlen [in,out] 缓冲区长度,写入后增加写入长度。 + * @return 1 - 成功;-1 - 失败 + */ +int tlcp_socket_write_server_hello(TLCP_SOCKET_CONNECT *conn,uint8_t **out, size_t *outlen); + +/** + * 写入服务端证书消息 + * + * @param conn [in,out] 连接对象 + * @param out [in,out] 缓冲区,写入后会产生偏移。 + * @param outlen [in,out] 缓冲区长度,写入后增加写入长度。 + * @param server_enc_cert [out] 加密证书DER + * @param server_enc_certlen [out] 加密证书DER长度 + * @return 1 - 成功;-1 - 失败 + */ +int tlcp_socket_write_server_certificate(TLCP_SOCKET_CONNECT *conn, + uint8_t **out, size_t *outlen, + uint8_t *server_enc_cert, size_t *server_enc_certlen); + +/** + * 生成TLCP随机数(含有UNIX时间戳) + * + * @param randFnc [in] 随机源 + * @param random [out] 随机数 + * @return 1 - 成功;-1 - 失败 + */ +int tlcp_socket_random_generate(TLCP_SOCKET_RandBytes_FuncPtr randFnc, uint8_t random[32]); + + +/** + * 写入服务端密钥交换消息 + * @param conn [in] 连接上下文 + * @param sig_key [in] 签名密钥对 + * @param out [in,out] 缓冲区,写入后会产生偏移。 + * @param outlen [in,out] 缓冲区长度,写入后增加写入长度。 + * @param server_enc_cert [in] 加密证书DER + * @param server_enc_certlen [in] 加密证书DER长度 + * @return 1 - 成功;-1 - 失败 + */ +int tlcp_socket_write_server_key_exchange(TLCP_SOCKET_CONNECT *conn, TLCP_SOCKET_KEY *sig_key, + uint8_t **out, size_t *outlen, + uint8_t *server_enc_cert, size_t server_enc_certlen); + +/** + * 写入服务端DONE消息 + * + * @param conn [in] 连接上下文 + * @param out [in,out] 缓冲区,写入后会产生偏移。 + * @param outlen [in,out] 缓冲区长度,写入后增加写入长度。 + * @return 1 - 成功;-1 - 失败 + */ +int tlcp_socket_write_server_hello_done(TLCP_SOCKET_CONNECT *conn, uint8_t **out, size_t *outlen); + +/** + * 读取客户端密钥交换消息 + * + * 解密预主密钥,生成主密钥,派生工作密钥 + * + * @param conn [in] 连接上下文 + * @param enc_key [in] 加密密钥对 + * @param record [in] 收到的记录层数据 + * @param recordlen [in] 记录层数据 + * @return 1 - 成功;-1 - 失败 + */ +int tlcp_socket_read_client_key_exchange(TLCP_SOCKET_CONNECT *conn, TLCP_SOCKET_KEY *enc_key, + uint8_t *record, size_t *recordlen); + +/** + * 读取客户端密钥变更消息和解密验证Finished消息 + * + * @param conn [in] 连接上下文 + * @param record [in] 收到的记录层数据 + * @param recordlen [in] 记录层数据 + * @return 1 - 成功;-1 - 失败 + */ +int tlcp_socket_read_client_spec_finished(TLCP_SOCKET_CONNECT *conn, uint8_t *record, size_t *recordlen); + +/** + * 写入服务端密钥变更消息和Finished消息 + * + * @param conn [in] 连接上下文 + * @param out [in,out] 缓冲区,写入后会产生偏移。 + * @param outlen [in,out] 缓冲区长度,写入后增加写入长度。 + * @return 1 - 成功;-1 - 失败 + */ +int tlcp_socket_write_server_spec_finished(TLCP_SOCKET_CONNECT *conn, uint8_t **out, size_t *outlen); + + +/** + * 接收并解密记录层消息,数据将会被解密读取到缓冲区 + * + * @param conn [in] 连接对象 + * @param data [in,out] 解密消息缓冲区 + * @param datalen [in,out] 解密数据长度 + * @return 1 - 成功;-1 - 失败 + */ +int tlcp_socket_read_app_data(TLCP_SOCKET_CONNECT *conn); + +/** + * 写入并加密记录层消息 + * + * @param conn [in] 连接对象 + * @param data [in] 待写入数据 + * @param datalen [in] 数据长度,长度应小于 TLCP_SOCKET_DEFAULT_FRAME_SIZE + * @return 1 - 成功;-1 - 失败 + */ +int tlcp_socket_write_app_data(TLCP_SOCKET_CONNECT *conn, const uint8_t *data, size_t datalen); + + +/** + * 发送TLCP alert消息 + * + * 如果消息为错误消息,那么将会关闭连接 + * + * @param conn [in] 连接上下文 + * @param alert_description [in] 错误报警描述 + */ +void tlcp_socket_alert(TLCP_SOCKET_CONNECT *conn, int alert_description); + +/** + * 生成并写入客户端Hello消息 + * + * @param conn [in] socket连接 + * @param record [in,out] 收到的记录层数据 + * @param recordlen [in,out] 记录层数据 + * @return 1 - 成功;-1 - 失败 + */ +int tlcp_socket_write_client_hello(TLCP_SOCKET_CONNECT *conn, uint8_t *record, size_t *recordlen); + +/** + * 读取并处理服务端Hello消息 + * + * @param conn [in] socket连接 + * @param record [in,out] 收到的记录层数据 + * @param recordlen [in,out] 记录层数据 + * @return 1 - 成功;-1 - 失败 + */ +int tlcp_socket_read_server_hello(TLCP_SOCKET_CONNECT *conn, uint8_t *record, size_t *recordlen); + + +/** + * 读取并解析服务端证书 + * + * @param conn [in] socket连接 + * @param record [in,out] 收到的记录层数据 + * @param recordlen [in,out] 记录层数据 + * @param server_certs [in,out] 服务端证书(按顺序签名证书、加密证书) + * @param enc_cert_vector [out] 加密证书DER编码向量 + * @param enc_cert_vector_len [out] 加密证书DER编码向量长度 + * @return 1 - 成功;-1 - 失败 + */ +int tlcp_socket_read_server_certs(TLCP_SOCKET_CONNECT *conn, + uint8_t *record, size_t *recordlen, + X509_CERTIFICATE server_certs[2], + uint8_t *enc_cert_vector, size_t *enc_cert_der_len); + +/** + * 读取并处理服务端密钥交换 + * + * 验证签名值 + * + * @param conn [in] socket连接 + * @param record [in,out] 收到的记录层数据 + * @param recordlen [in,out] 记录层数据 + * @param server_sig_cert [in] 服务端签名证书 + * @param enc_cert_vector [in] 服务端加密证书向量 + * @param enc_cert_vector_len [in] 服务端加密证书向量长度 + * @return 1 - 成功;-1 - 失败 + */ +int tlcp_socket_read_server_key_exchange(TLCP_SOCKET_CONNECT *conn, + uint8_t *record, size_t *recordlen, + X509_CERTIFICATE *server_sig_cert, + uint8_t *enc_cert_vector, size_t enc_cert_vector_len); + +/** + * 读取并处理证书请求(如果存在)和服务端Done消息 + * + * @param conn [in] socket连接 + * @param record [in,out] 记录层数据 + * @param recordlen [in,out] 记录层数据长度 + * @param need_auth [out] 是否需要客户端认证 + * @return 1 - 成功;-1 - 失败 + */ +int tlcp_socket_read_cert_req_server_done(TLCP_SOCKET_CONNECT *conn, uint8_t *record, + size_t *recordlen, uint8_t *need_auth); + +/** + * 生成预主密钥工作密钥,并写入客户端密钥交换消息 + * + * @param conn [in] socket连接 + * @param out [in,out] 缓冲区,写入后会产生偏移。 + * @param outlen [in,out] 缓冲区长度,写入后增加写入长度。 + * @param server_enc_cert [in] 加密证书 + * @return 1 - 成功;-1 - 失败 + */ +int tlcp_socket_write_client_key_exchange(TLCP_SOCKET_CONNECT *conn, + uint8_t **out, size_t *outlen, + X509_CERTIFICATE *server_enc_cert); + +/** + * 写入密钥变更消息并生成finished消息 + * + * @param conn [in] socket连接 + * @param out [in,out] 缓冲区,写入后会产生偏移。 + * @param outlen [in,out] 缓冲区长度,写入后增加写入长度。 + * @return 1 - 成功;-1 - 失败 + */ +int tlcp_socket_write_client_spec_finished(TLCP_SOCKET_CONNECT *conn, uint8_t **out, size_t *outlen); + +/** + * 读取服务端密钥变更消息,并验证服务端finished消息 + * + * @param conn [in] socket连接 + * @param record [in,out] 记录层数据 + * @param recordlen [in,out] 记录层数据长度 + * @return 1 - 成功;-1 - 失败 + */ +int tlcp_socket_read_server_spec_finished(TLCP_SOCKET_CONNECT *conn, uint8_t *record, size_t *recordlen); + +/** + * 写入客户端认证证书 + * + * @param conn [in] socket连接 + * @param out [in,out] 缓冲区,写入后会产生偏移。 + * @param outlen [in,out] 缓冲区长度,写入后增加写入长度。 + * @return 1 - 成功;-1 - 失败 + */ +int tlcp_socket_write_client_certificate(TLCP_SOCKET_CONNECT *conn, uint8_t **out, size_t *outlen); + +/** + * 生成客户端证书验证消息并发送 + * + * @param conn [in] socket连接 + * @param out [in,out] 缓冲区,写入后会产生偏移。 + * @param outlen [in,out] 缓冲区长度,写入后增加写入长度。 + * @return 1 - 成功;-1 - 失败 + */ +int tlcp_socket_write_client_cert_verify(TLCP_SOCKET_CONNECT *conn, + uint8_t **out, size_t *outlen); + +/** + * 生成并写入证书请求消息 + * + * @param conn [in] socket连接 + * @param out [in,out] 缓冲区,写入后会产生偏移。 + * @param outlen [in,out] 缓冲区长度,写入后增加写入长度。 + * @return 1 - 成功;-1 - 失败 + */ +int tlcp_socket_write_cert_req(TLCP_SOCKET_CONNECT *conn, + uint8_t **out, size_t *outlen); + +/** + * 读取客户端证书消息 + * + * @param conn [in] socket连接 + * @param record [in,out] 记录层数据 + * @param recordlen [in,out] 记录层数据长度 + * @param client_cert [out] 客户端证书 + * @return 1 - 成功;-1 - 失败 + */ +int tlcp_socket_read_client_cert(TLCP_SOCKET_CONNECT *conn, + uint8_t *record, size_t *recordlen, + X509_CERTIFICATE *client_cert); + +/** + * 读取并验证客户端验证消息 + * + * @param conn [in] socket连接 + * @param record [in,out] 记录层数据 + * @param recordlen [in,out] 记录层数据长度 + * @param client_cert [in] 客户端证书 + * @return 1 - 成功;-1 - 失败 + */ +int tlcp_socket_read_client_cert_verify(TLCP_SOCKET_CONNECT *conn, + uint8_t *record, size_t *recordlen, + X509_CERTIFICATE *client_cert); + +/** + * 发送粘黏在一起的记录层数据 + * + * @param conn [in] 连接对象 + * @param buff [in] 缓冲区 + * @param records_len [in] 多个记录层数据包的总长度 + * @return 1 - 成功;-1 - 失败 + */ +int tlcp_socket_send_records(TLCP_SOCKET_CONNECT *conn, const uint8_t *buff, size_t records_len); + +#ifdef __cplusplus +} +#endif +#endif //GMSSL_TLCP_SOCKET_MSG_H diff --git a/include/gmssl/tls.h b/include/gmssl/tls.h index 5e63bf4..d5d1e67 100644 --- a/include/gmssl/tls.h +++ b/include/gmssl/tls.h @@ -121,10 +121,10 @@ typedef enum { TLCP_cipher_rsa_sm4_gcm_sm3 = 0xe059, TLCP_cipher_rsa_sm4_cbc_sha256 = 0xe01c, TLCP_cipher_rsa_sm4_gcm_sha256 = 0xe05a, - GMSSL_cipher_ecdhe_sm2_with_sm4_sm3 = 0xe102, + GMSSL_cipher_ecdhe_sm2_with_sm4_sm3 = 0xe102, GMSSL_cipher_ecdhe_sm2_with_sm4_gcm_sm3 = 0xe107, GMSSL_cipher_ecdhe_sm2_with_sm4_ccm_sm3 = 0xe108, - GMSSL_cipher_ecdhe_sm2_with_zuc_sm3 = 0xe10d, + GMSSL_cipher_ecdhe_sm2_with_zuc_sm3 = 0xe10d, TLS_cipher_empty_renegotiation_info_scsv = 0x00ff, // TLS 1.3 ciphers (rfc 8446 p.133) @@ -137,38 +137,38 @@ typedef enum { } TLS_CIPHER_SUITE; typedef enum { - TLS_record_invalid = 0, // TLS 1.3 + TLS_record_invalid = 0, // TLS 1.3 TLS_record_change_cipher_spec = 20, - TLS_record_alert = 21, - TLS_record_handshake = 22, - TLS_record_application_data = 23, - TLS_record_heartbeat = 24, - TLS_record_tls12_cid = 25, + TLS_record_alert = 21, + TLS_record_handshake = 22, + TLS_record_application_data = 23, + TLS_record_heartbeat = 24, + TLS_record_tls12_cid = 25, } TLS_RECORD_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_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_ekt_key = 26, + TLS_handshake_message_hash = 254, } TLS_HANDSHAKE_TYPE; typedef enum { @@ -316,36 +316,36 @@ typedef enum { } TLS_ALERT_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_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_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_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; @@ -446,6 +446,18 @@ typedef struct { int tlcp_connect(TLS_CONNECT *conn, const char *hostname, int port, FILE *ca_certs_fp, FILE *client_certs_fp, const SM2_KEY *client_sign_key); +/** + * 服务端接受一个TLCP连接 + * @param conn TLCP连接上下文 + * @param port 端口 + * @param server_certs_fp 服务端签名证书和加密证书PEM文件 + * @param server_sign_key 服务端签名密钥对 + * @param server_enc_key 服务端加密密钥对 + * @param client_cacerts_fp 客户端根证书PEM文件,用于验证客户端证书,仅在需要双向身份认证时使用。 + * @param client_cert_verify_buf 客户端证书校验消息缓冲区,仅在需要双向身份认证时使用。 + * @param client_cert_verify_buflen 缓冲区长度 + * @return 1 - 连接成功;-1 - 连接失败 + */ int tlcp_accept(TLS_CONNECT *conn, int port, FILE *server_certs_fp, const SM2_KEY *server_sign_key, const SM2_KEY *server_enc_key, FILE *client_cacerts_fp, uint8_t *client_cert_verify_buf, size_t client_cert_verify_buflen); diff --git a/include/gmssl/x509.h b/include/gmssl/x509.h index ebabe18..ec678ed 100644 --- a/include/gmssl/x509.h +++ b/include/gmssl/x509.h @@ -135,7 +135,7 @@ typedef struct { int oids[8]; int tags[8]; - char country[3]; // printableString + char country[65]; // printableString char state_or_province[129]; char locality[129]; char org[65]; @@ -169,6 +169,13 @@ AlgorithmIdentifier ::= SEQUENCE { 当 algorithm 为 RSA 时,parameters 为 ASN1_NULL 对象 */ +typedef struct { + int algorithm; + int has_null_obj; // 部分SM2非规范可能含有NULL +} X509_ALGORITHMIDENTIFIER; + + + const char *x509_digest_algor_name(int algor); int x509_digest_algor_from_name(const char *name); int x509_digest_algor_to_der(int algor, uint8_t **out, size_t *outlen); @@ -188,6 +195,9 @@ int x509_signature_algor_from_name(const char *name); int x509_signature_algor_to_der(int algor, uint8_t **out, size_t *outlen); int x509_signature_algor_from_der(int *algor, uint32_t *nodes, size_t *nodes_count, const uint8_t **in, size_t *inlen); +int x509_signature_algor_null_to_der(int algor, int has_null_obj, uint8_t **out, size_t *outlen); +int x509_signature_algor_null_from_der(int *algor, int *has_null_obj, uint32_t *nodes, size_t *nodes_count, + const uint8_t **in, size_t *inlen); const char *x509_public_key_encryption_algor_name(int algor); int x509_public_key_encryption_algor_from_name(const char *name); @@ -252,24 +262,20 @@ int x509_extensions_get_next_item(const X509_EXTENSIONS *a, const uint8_t **next int x509_extensions_print(FILE *fp, const X509_EXTENSIONS *a, int format, int indent); - - - - typedef struct { - int version; // [0] EXPLICIT INTEGER DEFAULT v1 - uint8_t serial_number[20]; // INTEGER + int version; // [0] EXPLICIT INTEGER DEFAULT v1 + uint8_t serial_number[20]; // INTEGER size_t serial_number_len; - int signature_algor; // AlgorithmIdentifier + X509_ALGORITHMIDENTIFIER signature_algor; // AlgorithmIdentifier X509_NAME issuer; X509_VALIDITY validity; X509_NAME subject; X509_PUBLIC_KEY_INFO subject_public_key_info; - uint8_t issuer_unique_id[64]; // [1] IMPLICIT BIT STRING OPTIONAL + uint8_t issuer_unique_id[64]; // [1] IMPLICIT BIT STRING OPTIONAL size_t issuer_unique_id_len; - uint8_t subject_unique_id[64]; // [2] IMPLICIT BIT STRING OPTIONAL + uint8_t subject_unique_id[64]; // [2] IMPLICIT BIT STRING OPTIONAL size_t subject_unique_id_len; - X509_EXTENSIONS extensions; // [3] EXPLICIT, If present, version MUST be v3 + X509_EXTENSIONS extensions; // [3] EXPLICIT, If present, version MUST be v3 } X509_TBS_CERTIFICATE; int x509_tbs_certificate_to_der(const X509_TBS_CERTIFICATE *a, uint8_t **out, size_t *outlen); @@ -329,7 +335,14 @@ int x509_certificate_from_pem_by_name(X509_CERTIFICATE *cert, FILE *certs_fp, co int x509_certificate_verify_by_certificate(const X509_CERTIFICATE *cert, const X509_CERTIFICATE *cacert); - +/** + * 从字节串中解析X509数字证书,支持Base64、Hex、PEM、DER + * @param a 证书指针 + * @param in 待解析字符串、或DER字节串 + * @param inlen 输入数据长度 + * @return -1 解析失败;1解析成功 + */ +int x509_certificate_from_bytes(X509_CERTIFICATE *a,const uint8_t *in, size_t inlen); diff --git a/src/base64.c b/src/base64.c index c7ed60c..9288962 100644 --- a/src/base64.c +++ b/src/base64.c @@ -375,3 +375,23 @@ int base64_decode_finish(BASE64_CTX *ctx, uint8_t *out, int *outl) } else return (1); } + + +int base64_str_decode(const uint8_t *in, int inlen, uint8_t *out, int *outlen) { + BASE64_CTX ctx; + int ret = 0; + int len = 0; + base64_decode_init(&ctx); + ret = base64_decode_update(&ctx, in, inlen, out, &len); + if (ret != 0) { + return -1; + } + *outlen = len; + out += len; + ret = base64_decode_finish(&ctx, out, &len); + if (ret != 1) { + return -1; + } + *outlen += len; + return 0; +} \ No newline at end of file diff --git a/src/debug.c b/src/debug.c index 609dca2..5e78ba6 100644 --- a/src/debug.c +++ b/src/debug.c @@ -71,6 +71,16 @@ void print_bytes(const uint8_t *data, size_t datalen) printf("\n"); } +void print_hex_str(const uint8_t *data, size_t datalen) +{ + size_t i; + for (i = 0; i < datalen; i++) { + printf("%02X", data[i]); + } + printf("\n"); +} + + void print_nodes(const uint32_t *in, size_t inlen) { size_t i; diff --git a/src/pem.c b/src/pem.c index 233dba7..fa44a46 100644 --- a/src/pem.c +++ b/src/pem.c @@ -53,64 +53,120 @@ #include -int pem_write(FILE *fp, const char *name, const uint8_t *data, size_t datalen) -{ - int ret = 0; - BASE64_CTX ctx; - uint8_t b64[datalen * 2]; - int len; - - base64_encode_init(&ctx); - base64_encode_update(&ctx, data, (int)datalen, b64, &len); - base64_encode_finish(&ctx, b64 + len, &len); - - ret += fprintf(fp, "-----BEGIN %s-----\n", name); - ret += fprintf(fp, "%s", (char *)b64); - ret += fprintf(fp, "-----END %s-----\n", name); - return ret; +int pem_write(FILE *fp, const char *name, const uint8_t *data, size_t datalen) { + int ret = 0; + BASE64_CTX ctx; + uint8_t b64[datalen * 2]; + int len; + + base64_encode_init(&ctx); + base64_encode_update(&ctx, data, (int) datalen, b64, &len); + base64_encode_finish(&ctx, b64 + len, &len); + + ret += fprintf(fp, "-----BEGIN %s-----\n", name); + ret += fprintf(fp, "%s", (char *) b64); + ret += fprintf(fp, "-----END %s-----\n", name); + return ret; } -int pem_read(FILE *fp, const char *name, uint8_t *data, size_t *datalen) -{ - char line[80]; - char begin_line[80]; - char end_line[80]; - int len; - BASE64_CTX ctx; - - snprintf(begin_line, sizeof(begin_line), "-----BEGIN %s-----\n", name); - snprintf(end_line, sizeof(end_line), "-----END %s-----\n", name); - - if (!fgets(line, sizeof(line), fp)) { - //FIXME: feof 判断是不是文件结束了呢 - return 0; - } - - if (strcmp(line, begin_line) != 0) { - // FIXME: 这里是不是应该容忍一些错误呢? - error_print(); - return -1; - } - - *datalen = 0; - - base64_decode_init(&ctx); - - for (;;) { - if (!fgets(line, sizeof(line), fp)) { - error_print(); - return -1; - } - if (strcmp(line, end_line) == 0) { - break; - } - - base64_decode_update(&ctx, (uint8_t *)line, strlen(line), data, &len); - data += len; - *datalen += len; - } - - base64_decode_finish(&ctx, data, &len); - *datalen += len; - return 1; +int pem_read(FILE *fp, const char *name, uint8_t *data, size_t *datalen) { + char line[80]; + char begin_line[80]; + char end_line[80]; + int len; + BASE64_CTX ctx; + + snprintf(begin_line, sizeof(begin_line), "-----BEGIN %s-----\n", name); + snprintf(end_line, sizeof(end_line), "-----END %s-----", name); + + if (!fgets(line, sizeof(line), fp)) { + //FIXME: feof 判断是不是文件结束了呢 + return 0; + } + + if (strcmp(line, begin_line) != 0) { + // FIXME: 这里是不是应该容忍一些错误呢? + error_print(); + return -1; + } + + *datalen = 0; + + base64_decode_init(&ctx); + + for (;;) { + if (!fgets(line, sizeof(line), fp)) { + error_print(); + return -1; + } + if (strncmp(line, end_line, strlen(end_line)) == 0) { + break; + } + + base64_decode_update(&ctx, (uint8_t *) line, strlen(line), data, &len); + data += len; + *datalen += len; + } + + base64_decode_finish(&ctx, data, &len); + *datalen += len; + return 1; } + +/** + * 从字符串中读取PEM格式 + * @param in 字符串 + * @param str_len 字符串长度 + * @param name PEM头名称 + * @param data 解码输出位置 + * @param datalen 解码后长度 + * @return 1 - OK,-1 error + */ +int pem_read_str(uint8_t *in, size_t str_len, const char *name, uint8_t *data, size_t *datalen) { + BASE64_CTX ctx; + char begin_line[80]; + char end_line[80]; + + uint8_t *line = NULL; + int line_len = 0; + + int len = 0; + int i = 0; + + snprintf(begin_line, sizeof(begin_line), "-----BEGIN %s-----\n", name); + snprintf(end_line, sizeof(end_line), "-----END %s-----", name); + base64_decode_init(&ctx); + + for (i = 0; i < str_len; ++i) { + if (in[i] != '\n') { + line_len++; + continue; + } + // 读取出一行 + if (line == NULL) { + line = in; + } else { + line = &in[i] - line_len; + } + + // 第一行 + if (strncmp((const char *) line, begin_line, strlen(begin_line)) == 0) { + line_len = 0; + continue; + } + // 最后一行 + if (strncmp((const char *) line, end_line, strlen(end_line)) == 0) { + break; + } + if (base64_decode_update(&ctx, line, line_len, data, &len) == -1) { + // 非BASE64错误 + return -1; + } + *datalen += len; + data += len; + line_len = 0; + } + base64_decode_finish(&ctx, data, &len); + *datalen += len; + return 1; +} \ No newline at end of file diff --git a/src/rand.c b/src/rand.c index ec07306..4959c20 100644 --- a/src/rand.c +++ b/src/rand.c @@ -61,5 +61,7 @@ int rand_bytes(uint8_t *buf, size_t len) return -1; } fread(buf, 1, len, fp); + // 由于随机源也是文件,所以需要关闭,否则会造成 too many file open + fclose(fp); return 1; } diff --git a/src/sm2_algo.c b/src/sm2_algo.c index 5165309..1056bd0 100644 --- a/src/sm2_algo.c +++ b/src/sm2_algo.c @@ -337,6 +337,22 @@ static void bn_rand_range(bignum_t r, const bignum_t range) fclose(fp); } +/** + * 从外部随机源中读取 范围内的大整数 + * + * @param rd [in] 随机源 + * @param r [in] 大整数 + * @param range [in] 取值范围 + */ +static void bn_rand_src_range(rand_src rd, bignum_t r, const bignum_t range) +{ + uint8_t buf[256]; + do { + rd(buf, 256); + bn_from_bytes(r, buf); + } while (bn_cmp(r, range) >= 0); +} + static void fp_add(bignum_t r, const bignum_t a, const bignum_t b) { bn_add(r, a, b); @@ -1446,6 +1462,66 @@ int sm2_do_sign(const SM2_KEY *key, const uint8_t dgst[32], SM2_SIGNATURE *sig) return 1; } + +int sm2_do_sign_ext(rand_src rd, const SM2_KEY *key, const uint8_t dgst[32], SM2_SIGNATURE *sig) +{ + point_t _P, *P = &_P; + bignum_t d; + bignum_t e; + bignum_t k; + bignum_t x; + bignum_t r; + bignum_t s; + + if (!key || !dgst || !sig) { + return -1; + } + + bn_from_bytes(d, key->private_key); + + // e = H(M) + bn_from_bytes(e, dgst); //print_bn("e", e); + +retry: + + // rand k in [1, n - 1] + do { + bn_rand_src_range(rd, k, SM2_N); + } while (bn_is_zero(k)); + //print_bn("k", k); + + // (x, y) = kG + point_mul_generator(P, k); + point_get_xy(P, x, NULL); //print_bn("x", x); + + + // r = e + x (mod n) + fn_add(r, e, x); //print_bn("r = e + x (mod n)", r); + + /* if r == 0 or r + k == n re-generate k */ + if (bn_is_zero(r)) { + goto retry; + } + bn_add(x, r, k); + if (bn_cmp(x, SM2_N) == 0) { + goto retry; + } + + /* s = ((1 + d)^-1 * (k - r * d)) mod n */ + + fn_mul(e, r, d); //print_bn("r*d", e); + fn_sub(k, k, e); //print_bn("k-r*d", k); + fn_add(e, ONE, d); //print_bn("1 +d", e); + fn_inv(e, e); //printf("(1+d)^-1", e); + fn_mul(s, e, k); //print_bn("s = ((1 + d)^-1 * (k - r * d)) mod n", s); + + bn_clean(d); + bn_clean(k); + bn_to_bytes(r, sig->r); //print_bn("r", r); + bn_to_bytes(s, sig->s); //print_bn("s", s); + return 1; +} + int sm2_do_verify(const SM2_KEY *key, const uint8_t dgst[32], const SM2_SIGNATURE *sig) { point_t _P, *P = &_P; @@ -1497,7 +1573,7 @@ int sm2_do_verify(const SM2_KEY *key, const uint8_t dgst[32], const SM2_SIGNATUR if (bn_cmp(e, r) == 0) { return 1; } else { - error_print(); // 此处不应该打印错误,因为验证失败是预期的返回结果之一 + // error_print(); // 此处不应该打印错误,因为验证失败是预期的返回结果之一 return 0; } } @@ -1591,6 +1667,56 @@ int sm2_do_encrypt(const SM2_KEY *key, const uint8_t *in, size_t inlen, SM2_CIPH return 1; } +int sm2_do_encrypt_ext(rand_src rd, const SM2_KEY *key, const uint8_t *in, size_t inlen, SM2_CIPHERTEXT *out) +{ + bignum_t k; + point_t _P, *P = &_P; + SM3_CTX sm3_ctx; + uint8_t buf[64]; + int i; + + if (!key || !in || !inlen || !out) { + return -1; + } + + // rand k in [1, n - 1] + do { + bn_rand_src_range(rd, k, SM2_N); + } while (bn_is_zero(k)); + + // C1 = k * G = (x1, y1) + point_mul_generator(P, k); + point_to_bytes(P, (uint8_t *)&out->point); + + + // Q = k * P = (x2, y2) + point_from_bytes(P, (uint8_t *)&key->public_key); + + point_mul(P, k, P); + + point_to_bytes(P, buf); + + + // t = KDF(x2 || y2, klen) + sm2_kdf(buf, sizeof(buf), inlen, out->ciphertext); + + + // C2 = M xor t + for (i = 0; i < inlen; i++) { + out->ciphertext[i] ^= in[i]; + } + out->ciphertext_size = (uint32_t)inlen; + + // C3 = Hash(x2 || m || y2) + sm3_init(&sm3_ctx); + sm3_update(&sm3_ctx, buf, 32); + sm3_update(&sm3_ctx, in, inlen); + sm3_update(&sm3_ctx, buf + 32, 32); + sm3_finish(&sm3_ctx, out->hash); + + return 1; +} + int sm2_do_decrypt(const SM2_KEY *key, const SM2_CIPHERTEXT *in, uint8_t *out, size_t *outlen) { uint32_t inlen; diff --git a/src/sm2_asn1.c b/src/sm2_asn1.c index 0aea2ad..98b4548 100644 --- a/src/sm2_asn1.c +++ b/src/sm2_asn1.c @@ -107,33 +107,53 @@ int sm2_point_from_der(SM2_POINT *a, const uint8_t **in, size_t *inlen) int sm2_signature_to_der(const SM2_SIGNATURE *sig, uint8_t **out, size_t *outlen) { - size_t len = 0; - asn1_integer_to_der(sig->r, 32, NULL, &len); - asn1_integer_to_der(sig->s, 32, NULL, &len); - asn1_sequence_header_to_der(len, out, outlen); - asn1_integer_to_der(sig->r, 32, out, outlen); - asn1_integer_to_der(sig->s, 32, out, outlen); - return 1; + size_t len = 0; + uint8_t off_r = 0, off_s = 0; + uint8_t i = 0; + for (i = 0; i < 32; i++) { + if (sig->r[i] == 0) { + off_r++; + } else { + break; + } + } + for (i = 0; i < 32; i++) { + if (sig->s[i] == 0) { + off_s++; + } else { + break; + } + } + asn1_integer_to_der(sig->r + off_r, 32 - off_r, NULL, &len); + asn1_integer_to_der(sig->s + off_s, 32 - off_s, NULL, &len); + asn1_sequence_header_to_der(len, out, outlen); + asn1_integer_to_der(sig->r + off_r, 32 - off_r, out, outlen); + asn1_integer_to_der(sig->s + off_s, 32 - off_s, out, outlen); + return 1; } int sm2_signature_from_der(SM2_SIGNATURE *sig, const uint8_t **in, size_t *inlen) { - const uint8_t *data, *r, *s; - size_t datalen, rlen, slen; - - if (asn1_sequence_from_der(&data, &datalen, in, inlen) < 0 - || asn1_integer_from_der(&r, &rlen, &data, &datalen) < 0 - || asn1_integer_from_der(&s, &slen, &data, &datalen) < 0 - || datalen > 0) { - return -1; - } - if (rlen != 32 || slen != 32) { - return -2; - } - - memcpy(sig->r, r, 32); - memcpy(sig->s, s, 32); - return 1; + const uint8_t *data, *r, *s; + size_t datalen, rlen, slen; + uint8_t offset = 0; + + if (asn1_sequence_from_der(&data, &datalen, in, inlen) < 0 + || asn1_integer_from_der(&r, &rlen, &data, &datalen) < 0 + || asn1_integer_from_der(&s, &slen, &data, &datalen) < 0 + || datalen > 0) { + return -1; + } + if (rlen > 32 || slen > 32) { + return -2; + } + // DER格式不含前置0,对于长度不足32时需要补足前缀0 + memset(sig, 0, sizeof(SM2_SIGNATURE)); + offset = 32 - rlen; + memcpy(sig->r + offset, r, rlen); + offset = 32 - slen; + memcpy(sig->s + offset, s, slen); + return 1; } /* @@ -146,49 +166,71 @@ SM2Cipher ::= SEQUENCE { */ int sm2_ciphertext_to_der(const SM2_CIPHERTEXT *c, uint8_t **out, size_t *outlen) { - size_t len = 0; - asn1_integer_to_der(c->point.x, 32, NULL, &len); - asn1_integer_to_der(c->point.y, 32, NULL, &len); - asn1_octet_string_to_der(c->hash, 32, NULL, &len); - asn1_octet_string_to_der(c->ciphertext, c->ciphertext_size, NULL, &len); - asn1_sequence_header_to_der(len, out, outlen); - asn1_integer_to_der(c->point.x, 32, out, outlen); - asn1_integer_to_der(c->point.y, 32, out, outlen); - asn1_octet_string_to_der(c->hash, 32, out, outlen); - asn1_octet_string_to_der(c->ciphertext, c->ciphertext_size, out, outlen); - return 1; + size_t len = 0; + // 整数长度不足32字节的情况含有前置0需要计算偏移量去除 + uint8_t off_x = 0, off_y = 0; + uint8_t i = 0; + for (i = 0; i < 32; i++) { + if (c->point.x[i] == 0) { + off_x++; + } else { + break; + } + } + for (i = 0; i < 32; i++) { + if (c->point.y[i] == 0) { + off_y++; + } else { + break; + } + } + + asn1_integer_to_der(c->point.x + off_x, 32 - off_x, NULL, &len); + asn1_integer_to_der(c->point.y + off_y, 32 - off_y, NULL, &len); + asn1_octet_string_to_der(c->hash, 32, NULL, &len); + asn1_octet_string_to_der(c->ciphertext, c->ciphertext_size, NULL, &len); + + asn1_sequence_header_to_der(len, out, outlen); + asn1_integer_to_der(c->point.x + off_x, 32 - off_x, out, outlen); + asn1_integer_to_der(c->point.y + off_y, 32 - off_y, out, outlen); + asn1_octet_string_to_der(c->hash, 32, out, outlen); + asn1_octet_string_to_der(c->ciphertext, c->ciphertext_size, out, outlen); + return 1; } int sm2_ciphertext_from_der(SM2_CIPHERTEXT *a, const uint8_t **in, size_t *inlen) { - const uint8_t *data, *x, *y, *hash, *c; - size_t datalen, xlen, ylen, hashlen, clen; - - if (asn1_sequence_from_der(&data, &datalen, in, inlen) < 0 - || asn1_integer_from_der(&x, &xlen, &data, &datalen) < 0 - || asn1_integer_from_der(&y, &ylen, &data, &datalen) < 0 - || asn1_octet_string_from_der(&hash, &hashlen, &data, &datalen) < 0 - || asn1_octet_string_from_der(&c, &clen, &data, &datalen) < 0 - || datalen > 0) { - return -1; - } - if (xlen != 32 - || ylen != 32 - || hashlen != 32 - || clen < 1) { - return -1; - } - - memcpy(a->point.x, x, 32); - memcpy(a->point.y, y, 32); - memcpy(a->hash, hash, 32); - memcpy(a->ciphertext, c, clen); - a->ciphertext_size = (uint32_t)clen; + const uint8_t *data, *x, *y, *hash, *c; + size_t datalen, xlen, ylen, hashlen, clen; + uint8_t offset = 0; + + if (asn1_sequence_from_der(&data, &datalen, in, inlen) < 0 + || asn1_integer_from_der(&x, &xlen, &data, &datalen) < 0 + || asn1_integer_from_der(&y, &ylen, &data, &datalen) < 0 + || asn1_octet_string_from_der(&hash, &hashlen, &data, &datalen) < 0 + || asn1_octet_string_from_der(&c, &clen, &data, &datalen) < 0 + || datalen > 0) { + return -1; + } + if (xlen > 32 + || ylen > 32 + || hashlen != 32 + || clen < 1) { + return -1; + } + memset(&a->point, 0, sizeof(SM2_POINT)); + offset = 32 - xlen; + memcpy(a->point.x + offset, x, xlen); + offset = 32 - ylen; + memcpy(a->point.y + offset, y, ylen); + memcpy(a->hash, hash, 32); + memcpy(a->ciphertext, c, clen); + a->ciphertext_size = (uint32_t) clen; return 1; } /* -from RFC 5915 +from RFC 5915 见《GM/T0010-2012》 附录A.3 ECPrivateKey ::= SEQUENCE { version INTEGER, -- value MUST be ecPrivkeyVer1(1) @@ -306,6 +348,46 @@ int sm2_private_key_from_der(SM2_KEY *key, const uint8_t **in, size_t *inlen) return 1; } +/* +from RFC 5208 Cap.5 + +PrivateKeyInfo ::= SEQUENCE { + version Version, + privateKeyAlgorithm PrivateKeyAlgorithmIdentifier, + privateKey PrivateKey, + attributes [0] IMPLICIT Attributes OPTIONAL +} + +Version ::= INTEGER +PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier +PrivateKey ::= OCTET STRING +Attributes ::= SET OF Attribute +*/ +int sm2_private_key_from_pkcs8_der(SM2_KEY *key, const uint8_t **in, size_t *inlen) +{ + int ret; + const uint8_t *data; + size_t datalen; + int version; + const uint8_t *prikey; + const uint8_t *attributes; + size_t prikey_len; + size_t attributes_len; + + if ((ret = asn1_sequence_from_der(&data, &datalen, in, inlen)) != 1) { + if (ret < 0) error_print(); + return ret; + } + if (asn1_int_from_der(&version, &data, &datalen) != 1 + || sm2_public_key_algor_from_der(&data, &datalen) != 1 + || asn1_octet_string_from_der(&prikey, &prikey_len, &data, &datalen) < 0 + || asn1_explicit_from_der(0, &attributes, &attributes_len, &data, &datalen) < 0 + || datalen > 0) { + return -1; + } + // 暂时忽略对 AlgorithmIdentifier 判断,直接解析ECPrivateKey结构 + return sm2_private_key_from_der(key,&prikey ,&prikey_len); +} /* AlgorithmIdentifier ::= { @@ -529,21 +611,57 @@ int sm2_private_key_to_pem(const SM2_KEY *a, FILE *fp) int sm2_private_key_from_pem(SM2_KEY *a, FILE *fp) { uint8_t buf[512]; - const uint8_t *cp = buf; + const uint8_t *cp = buf; + const uint8_t *cp2 = buf; size_t len; + size_t src_len; if (pem_read(fp, "EC PRIVATE KEY", buf, &len) != 1) { error_print(); return -1; } - if (sm2_private_key_from_der(a, &cp, &len) != 1 - || len > 0) { - error_print(); - return -1; + src_len = len; + // 尝试解析X962 RFC 5915格式 + if (sm2_private_key_from_der(a, &cp, &len) == 1) { + return 1; } + // 尝试解析PKCS8格式 + len = src_len; + if (sm2_private_key_from_pkcs8_der(a, &cp2, &len) != 1){ + error_print(); + return -1; + } + return 1; } +int sm2_private_key_from_str_pem(SM2_KEY *key, uint8_t *in, size_t inlen){ + uint8_t buf[512]; + const uint8_t *cp = buf; + const uint8_t *cp2 = buf; + size_t len; + size_t src_len; + + if (pem_read_str(in, inlen, "EC PRIVATE KEY", buf, &len) != 1) { + if (pem_read_str(in, inlen, "SM2 PRIVATE KEY", buf, &len) != 1) { + error_print(); + return -1; + } + } + src_len = len; + // 尝试解析X962 RFC 5915格式 + if (sm2_private_key_from_der(key, &cp, &len) == 1) { + return 1; + } + // 尝试解析PKCS8格式 + len = src_len; + if (sm2_private_key_from_pkcs8_der(key, &cp2, &len) != 1){ + error_print(); + return -1; + } + return 1; +} + int sm2_public_key_info_to_pem(const SM2_KEY *a, FILE *fp) { uint8_t buf[512]; diff --git a/src/sm2_lib.c b/src/sm2_lib.c index 10852c1..226882b 100644 --- a/src/sm2_lib.c +++ b/src/sm2_lib.c @@ -58,6 +58,27 @@ #define SM2_SIGNATURE_MAX_DER_SIZE 77 +int sm2_sign_ext(rand_src rd, const SM2_KEY *key, const uint8_t dgst[32], uint8_t *der, size_t *derlen) +{ + SM2_SIGNATURE sig; + uint8_t *p = der; + size_t len = 0; + + if (!der && derlen) { + *derlen = SM2_SIGNATURE_MAX_DER_SIZE; + return 1; + } + if (!key || !der || !derlen) { + return -1; + } + + sm2_do_sign_ext(rd, key, dgst, &sig); + sm2_signature_to_der(&sig, &p, &len); + *derlen = len; + + return 1; +} + int sm2_sign(const SM2_KEY *key, const uint8_t dgst[32], uint8_t *der, size_t *derlen) { SM2_SIGNATURE sig; @@ -115,6 +136,19 @@ int sm2_encrypt(const SM2_KEY *key, const uint8_t *in, size_t inlen, uint8_t *ou return 1; } +int sm2_encrypt_ext(rand_src rd, const SM2_KEY *key, const uint8_t *in, size_t inlen, uint8_t *out, size_t *outlen) +{ + size_t clen = SM2_CIPHERTEXT_SIZE(inlen); + size_t cbuf[clen]; + SM2_CIPHERTEXT *c = (SM2_CIPHERTEXT *)cbuf; + + sm2_do_encrypt_ext(rd, key, in, inlen, c); + + *outlen = 0; + sm2_ciphertext_to_der(c, &out, outlen); + return 1; +} + int sm2_decrypt(const SM2_KEY *key, const uint8_t *in, size_t inlen, uint8_t *out, size_t *outlen) { size_t cbuf[inlen]; @@ -170,24 +204,25 @@ int sm2_compute_z(uint8_t z[32], const SM2_POINT *pub, const char *id) return -1; } - if (strcmp(id, "1234567812345678") == 0) { - uint32_t digest[8] = { - 0xadadedb5U, 0x0446043fU, 0x08a87aceU, 0xe86d2243U, - 0x8e232383U, 0xbfc81fe2U, 0xcf9117c8U, 0x4707011dU, - }; - memcpy(&zin[128], pub->x, 32); - memcpy(&zin[160], pub->y, 32); - sm3_compress_blocks(digest, zin, 2); - PUTU32(z , digest[0]); - PUTU32(z + 4, digest[1]); - PUTU32(z + 8, digest[2]); - PUTU32(z + 12, digest[3]); - PUTU32(z + 16, digest[4]); - PUTU32(z + 20, digest[5]); - PUTU32(z + 24, digest[6]); - PUTU32(z + 28, digest[7]); - - } else { +// if (strcmp(id, "1234567812345678") == 0) { +// uint32_t digest[8] = { +// 0xadadedb5U, 0x0446043fU, 0x08a87aceU, 0xe86d2243U, +// 0x8e232383U, 0xbfc81fe2U, 0xcf9117c8U, 0x4707011dU, +// }; +// memcpy(&zin[128], pub->x, 32); +// memcpy(&zin[160], pub->y, 32); +// sm3_compress_blocks(digest, zin, 2); +// PUTU32(z , digest[0]); +// PUTU32(z + 4, digest[1]); +// PUTU32(z + 8, digest[2]); +// PUTU32(z + 12, digest[3]); +// PUTU32(z + 16, digest[4]); +// PUTU32(z + 20, digest[5]); +// PUTU32(z + 24, digest[6]); +// PUTU32(z + 28, digest[7]); +// +// } else { + SM3_CTX ctx; uint8_t idbits[2]; size_t len; @@ -203,7 +238,7 @@ int sm2_compute_z(uint8_t z[32], const SM2_POINT *pub, const char *id) sm3_update(&ctx, pub->x, 32); sm3_update(&ctx, pub->y, 32); sm3_finish(&ctx, z); - } +// } return 1; } @@ -236,6 +271,14 @@ int sm2_sign_finish(SM2_SIGN_CTX *ctx, uint8_t *sig, size_t *siglen) return 1; } +int sm2_sign_finish_ext(rand_src rd,SM2_SIGN_CTX *ctx, uint8_t *sig, size_t *siglen) +{ + uint8_t dgst[32]; + sm3_finish(&ctx->sm3_ctx, dgst); + sm2_sign_ext(rd, &ctx->key, dgst, sig, siglen); + return 1; +} + int sm2_sign_resume(SM2_SIGN_CTX *ctx) { return 0; diff --git a/src/tlcp.c b/src/tlcp.c index 960d88f..979b3cd 100644 --- a/src/tlcp.c +++ b/src/tlcp.c @@ -86,7 +86,8 @@ int tlcp_record_set_handshake_server_key_exchange_pke(uint8_t *record, size_t *r error_print(); return -1; } - tls_array_to_bytes(sig, siglen, &p, &hslen); + // signed_param 为一个向量 16bit的向量 + tls_uint16array_to_bytes(sig, siglen, &p, &hslen); tls_record_set_handshake(record, recordlen, type, NULL, hslen); return 1; } @@ -115,16 +116,11 @@ int tlcp_record_get_handshake_server_key_exchange_pke(const uint8_t *record, error_print(); return -1; } - /* - if (tls_uint16array_copy_from_bytes(sig, siglen, *siglen, &p, &len) != 1 + if (tls_uint16array_copy_from_bytes(sig, siglen, len-2, &p, &len) != 1 || len > 0) { error_print(); return -1; } - */ - // FIXME: check *siglen >= len - memcpy(sig, p, len); - *siglen = len; return 1; } @@ -180,13 +176,15 @@ int tlcp_certificate_chain_verify(const uint8_t *data, size_t datalen, FILE *ca_ return -1; } } else { - if (x509_certificate_from_pem_by_name(&ca_cert, ca_certs_fp, &sign_cert.tbs_certificate.issuer) != 1 - || x509_certificate_verify_by_certificate(&sign_cert, &ca_cert) != 1) { + if (x509_certificate_from_pem_by_name(&ca_cert, ca_certs_fp, &sign_cert.tbs_certificate.issuer) != 1){ + error_print(); + return -1; + } + if (x509_certificate_verify_by_certificate(&sign_cert, &ca_cert) != 1) { error_print(); return -1; } - if (x509_certificate_from_pem_by_name(&ca_cert, ca_certs_fp, &enc_cert.tbs_certificate.issuer) != 1 - || x509_certificate_verify_by_certificate(&enc_cert, &ca_cert) != 1) { + if (x509_certificate_verify_by_certificate(&enc_cert, &ca_cert) != 1) { error_print(); return -1; } @@ -595,7 +593,7 @@ int tlcp_accept(TLS_CONNECT *conn, int port, return -1; } - error_puts("start listen ..."); + error_print_msg("start listen port %d...", port); listen(sock, 5); memset(conn, 0, sizeof(*conn)); diff --git a/src/tlcp_socket.c b/src/tlcp_socket.c new file mode 100644 index 0000000..da8e5e3 --- /dev/null +++ b/src/tlcp_socket.c @@ -0,0 +1,511 @@ +/* + * Copyright (c) 2021 - 2021 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +int TLCP_SOCKET_Listen(TLCP_SOCKET_CONFIG *ctx, TLCP_SOCKET_Listener *ln, int port) { + struct sockaddr_in server_addr; + int sock; + if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + error_print(); + return -1; + } + server_addr.sin_family = AF_INET; + server_addr.sin_addr.s_addr = INADDR_ANY; + server_addr.sin_port = htons(port); + // 绑定端口,任意来源。 + if (bind(sock, (struct sockaddr *) &server_addr, sizeof(server_addr)) < 0) { + error_print(); + return -1; + } + // printf("TLCP Socket listen in port %d\n", port); + return TLCP_SOCKET_Listen_raw(ctx, ln, sock); +} + +int TLCP_SOCKET_Listen_raw(TLCP_SOCKET_CONFIG *ctx, TLCP_SOCKET_Listener *ln, int fd) { + if (ctx == NULL) { + error_print(); + return -1; + } + if (ctx->rand == NULL) { + // 如果没有提供随机源,那么使用GMSSL默认随机源 + ctx->rand = rand_bytes; + } + if (ctx->server_sig_key == NULL || ctx->server_enc_key == NULL) { + error_print(); + return -1; + } + ln->_sock = fd; + ln->config = ctx; + + // 启动监听 + if (listen(ln->_sock, 16) != 0) { + error_print(); + return -1; + } + return 1; +} + +void TLCP_SOCKET_Close(TLCP_SOCKET_Listener *ln) { + if (ln != NULL && ln->_sock != 0) { + close(ln->_sock); + } +} + +int TLCP_SOCKET_Accept(TLCP_SOCKET_Listener *ln, TLCP_SOCKET_CONNECT *conn) { + SM3_CTX sm3_ctx = {0}; // 握手消息Hash + X509_CERTIFICATE client_cert = {0}; + struct sockaddr_in client_addr = {0}; + socklen_t client_addrlen = sizeof(client_addr); + + uint8_t buf[TLS_MAX_RECORD_SIZE] = {0}; + uint8_t server_enc_cert[TLS_MAX_CERTIFICATES_SIZE] = {0}; + uint8_t need_client_auth = 0; + size_t server_enc_certlen = 0; + size_t buf_len = 0; + uint8_t *p = buf; + + + + if (ln == NULL || conn == NULL) { + error_puts("illegal parameter"); + return -1; + } + need_client_auth = ln->config->root_cert_len > 0 && ln->config->root_certs != NULL; + memset(conn, 0, sizeof(*conn)); + + if (ln->config->rand == NULL) { + // 使用系统默认随机源 + ln->config->rand = rand_bytes; + } + conn->config = ln->config; + + // 阻塞接收连接 + if ((conn->sock = accept(ln->_sock, (struct sockaddr *) &client_addr, &client_addrlen)) < 0) { + error_print(); + return -1; + } + + // 开始握手协议 + sm3_init(&sm3_ctx); + conn->_sm3_ctx = &sm3_ctx; + conn->entity = TLCP_SOCKET_SERVER_END; + conn->connected = TLCP_SOCKET_UNCONNECTED; + + // tls_trace("<<<< ClientHello\n"); + if (tlcp_socket_read_client_hello(conn, buf, &buf_len) != 1) { + close(conn->sock); + return -1; + } + + buf_len = 0; + // tls_trace(">>>> ServerHello\n"); + if (tlcp_socket_write_server_hello(conn, &p, &buf_len) != 1) { + close(conn->sock); + return -1; + } + + // tls_trace(">>>> ServerCertificate\n"); + if (tlcp_socket_write_server_certificate(conn, &p, &buf_len, + server_enc_cert, &server_enc_certlen) != 1) { + close(conn->sock); + return -1; + } + + // tls_trace(">>>> ServerKeyExchange\n"); + if (tlcp_socket_write_server_key_exchange(conn, ln->config->server_sig_key, + &p, &buf_len, + server_enc_cert, server_enc_certlen) != 1) { + close(conn->sock); + return -1; + } + + if (need_client_auth) { + // tls_trace(">>>> CertificateRequest\n"); + // Certificate Request消息 + if (tlcp_socket_write_cert_req(conn, &p, &buf_len) != 1) { + close(conn->sock); + return -1; + } + } + + // tls_trace(">>>> ServerHelloDone\n"); + if (tlcp_socket_write_server_hello_done(conn, &p, &buf_len) != 1) { + close(conn->sock); + return -1; + } + + if (tlcp_socket_send_records(conn, buf, buf_len) != 1) { + error_print(); + return -1; + } + + if (need_client_auth) { + // Client Certificate消息 + // tls_trace("<<<< ClientCertificate\n"); + if (tlcp_socket_read_client_cert(conn, buf, &buf_len, &client_cert) != 1) { + close(conn->sock); + return -1; + } + } + // tls_trace("<<<< ClientKeyExchange\n"); + if (tlcp_socket_read_client_key_exchange(conn, ln->config->server_enc_key, buf, &buf_len) != 1) { + close(conn->sock); + return -1; + } + + if (need_client_auth) { + // tls_trace("<<<< CertificateVerify\n"); + // 验证 Certificate Verify消息 + if (tlcp_socket_read_client_cert_verify(conn, buf, &buf_len, &client_cert) != 1) { + close(conn->sock); + return -1; + } + } + + // 读取并处理密钥变更消息和客户端finished消息 + if (tlcp_socket_read_client_spec_finished(conn, buf, &buf_len) != 1) { + close(conn->sock); + return -1; + } + + p = buf; + buf_len = 0; + // 服务端变更密码协议,发送finished消息 + if (tlcp_socket_write_server_spec_finished(conn, &p, &buf_len) != 1) { + close(conn->sock); + return -1; + } + + if (tlcp_socket_send_records(conn, buf, buf_len) != 1) { + error_print(); + return -1; + } + + conn->connected = TLCP_SOCKET_CONNECTED; + conn->_sm3_ctx = NULL; + return 1; +} + +ssize_t TLCP_SOCKET_Read(TLCP_SOCKET_CONNECT *conn, void *buf, size_t count) { + size_t n = 0; + if (conn == NULL || conn->sock <= 0) { + error_puts("illegal parameter conn"); + return -1; + } + + if (buf == NULL || count <= 0) { + error_puts("illegal parameter buf"); + return -1; + } + + if (conn->_buf_remain == 0) { + if (tlcp_socket_read_app_data(conn) != 1) { + return -1; + } + // 对读取的消息进行错误处理 + if (conn->record[0] == TLS_record_alert) { + switch (conn->record[0]) { + case TLS_alert_level_warning: // 也当做fatal处理 + case TLS_alert_level_fatal: + if (conn->record[1] == TLS_alert_close_notify) { + return EOF; + } else { + error_print_msg("remote error alert description %d", conn->record[2]); + return -1; + } + default: + error_puts("unknown alert message type"); + return -1; + } + } + } + // 从读入的缓冲区中获取需要复制的数据数量 + if (count > conn->_buf_remain) { + n = conn->_buf_remain; + } else { + n = count; + } + // 从缓冲区中复制数据 + memcpy(buf, conn->_p, n); + // 缓冲区 偏移指针 和 剩余数据数量 + conn->_p += n; + conn->_buf_remain -= n; + return (ssize_t) n; +} + +ssize_t TLCP_SOCKET_Write(TLCP_SOCKET_CONNECT *conn, void *buf, size_t count) { + uint8_t *p = buf; + size_t offset = 0; + + if (conn == NULL || buf == NULL || count == 0) { + error_puts("illegal parameter"); + return -1; + } + // 分段发送 + for (;;) { + if (offset + TLCP_SOCKET_DEFAULT_FRAME_SIZE < count) { + if (tlcp_socket_write_app_data(conn, p, TLCP_SOCKET_DEFAULT_FRAME_SIZE) != 1) { + return -1; + } + offset += TLCP_SOCKET_DEFAULT_FRAME_SIZE; + p = buf + offset; + } else { + if (tlcp_socket_write_app_data(conn, p, count - offset) != 1) { + return -1; + } + break; + } + } + return (ssize_t) count; +} + + +int TLCP_SOCKET_Dial(TLCP_SOCKET_CONFIG *ctx, TLCP_SOCKET_CONNECT *conn, const char *hostname, int port) { + SM3_CTX sm3_ctx = {0}; // 握手消息Hash + X509_CERTIFICATE server_certs[2] = {0}; // 服务端证书:签名证书[0]、加密证书[1] + uint8_t buf[TLS_MAX_RECORD_SIZE] = {0}; + uint8_t enc_cert_vector[TLS_MAX_CERT_SIZE] = {0}; // 加密证书DER向量 + size_t enc_cert_vector_len = 0; // 加密证书DER向量长度 + struct sockaddr_in server_addr = {0}; + uint8_t need_auth = 0; // 是否需要客户端身份认证 0 - 不需要; 1 - 需要 + size_t buf_len = 0; + uint8_t *p = buf; + + if (conn == NULL || ctx == NULL || hostname == NULL || port <= 0) { + error_puts("illegal parameter"); + return -1; + } + + server_addr.sin_addr.s_addr = inet_addr(hostname); + server_addr.sin_family = AF_INET; + server_addr.sin_port = htons(port); + memset(conn, 0, sizeof(*conn)); + if (ctx->rand == NULL) { + // 使用系统默认随机源 + ctx->rand = rand_bytes; + } + conn->config = ctx; + + if ((conn->sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + error_print(); + return -1; + } + if (connect(conn->sock, (struct sockaddr *) &server_addr, sizeof(server_addr)) < 0) { + error_print(); + return -1; + } + + sm3_init(&sm3_ctx); + conn->_sm3_ctx = &sm3_ctx; + conn->entity = TLCP_SOCKET_CLIENT_END; + conn->connected = TLCP_SOCKET_UNCONNECTED; + tls_record_set_version(buf, TLS_version_tlcp); + + // 开始握手 + // tls_trace(">>>> ClientHello\n"); + if (tlcp_socket_write_client_hello(conn, buf, &buf_len) != 1) { + close(conn->sock); + return -1; + } + + + // tls_trace("<<<< ServerHello\n"); + if (tlcp_socket_read_server_hello(conn, buf, &buf_len) != 1) { + close(conn->sock); + return -1; + } + // tls_trace("<<<< ServerCertificate\n"); + if (tlcp_socket_read_server_certs(conn, + buf, &buf_len, + server_certs, + enc_cert_vector, &enc_cert_vector_len) != 1) { + close(conn->sock); + return -1; + } + // tls_trace("<<<< ServerKeyExchange\n"); + if (tlcp_socket_read_server_key_exchange(conn, + buf, &buf_len, + &server_certs[0], + enc_cert_vector, enc_cert_vector_len) != 1) { + close(conn->sock); + return -1; + } + // tls_trace("<<<< ServerHelloDone\n"); + // 解析并处理证书请求(如果存在)和服务端Done + if (tlcp_socket_read_cert_req_server_done(conn, buf, &buf_len, &need_auth) != 1) { + close(conn->sock); + return -1; + } + + p = buf; + buf_len = 0; + if (need_auth == 1) { + // tls_trace(">>>> Certificate\n"); + // 客户端身份认证,发送客户端认证证书 + if (tlcp_socket_write_client_certificate(conn, &p, &buf_len) != 1) { + close(conn->sock); + return -1; + } + } + // tls_trace(">>>> ClientKeyExchange\n"); + if (tlcp_socket_write_client_key_exchange(conn, &p, &buf_len, &server_certs[1]) != 1) { + close(conn->sock); + return -1; + } + if (need_auth == 1) { + // tls_trace(">>>> CertificateVerify\n"); + // 生成并发送证书验证消息 + if (tlcp_socket_write_client_cert_verify(conn, &p, &buf_len) != 1) { + close(conn->sock); + return -1; + } + } + // tls_trace(">>>> [ChangeCipherSpec]\n"); + // tls_trace(">>>> Finished\n"); + // 发送客户端 密钥变更和 生成finished + if (tlcp_socket_write_client_spec_finished(conn, &p, &buf_len) != 1) { + close(conn->sock); + return -1; + } + // 发送系列记录层消息 + if (tlcp_socket_send_records(conn, buf, buf_len) != 1) { + close(conn->sock); + return -1; + } + buf_len = 0; + + // tls_trace("<<<< [ChangeCipherSpec]\n"); + // tls_trace("<<<< Finished\n"); + // 接收服务端 密钥变更 和 验证finished + if (tlcp_socket_read_server_spec_finished(conn, buf, &buf_len) != 1) { + close(conn->sock); + return -1; + } + conn->connected = TLCP_SOCKET_CONNECTED; + conn->_sm3_ctx = NULL; + return 1; +} + +/** + * 发送关闭消息 + * + * 根据握手状态,决定是否加密消息 + * + * socket连接应该由调用负责关闭 + * + * @param conn [in] 连接状态 + */ +static void tlcp_socket_send_close_alert(TLCP_SOCKET_CONNECT *conn) { + const SM3_HMAC_CTX *hmac_ctx; + const SM4_KEY *enc_key; + uint8_t *seq_num; + uint8_t mrec[8 + 8]; // 记录层明文 (头6B) + uint8_t crec[8 + 128]; // 记录层密码文 (头+加密填充和IV+MAC) + size_t mlen = sizeof(mrec); + size_t clen = sizeof(crec); + + // 设置消息 + if (tls_record_set_version(mrec, conn->version) != 1 + || tls_record_set_alert(mrec, &mlen, TLS_alert_level_warning, TLS_alert_close_notify) != 1) { + return; + } + if (conn->connected == TLCP_SOCKET_CONNECTED) { + // 已经握手成功的情况,close消息需要被加密 + if (conn->entity == TLCP_SOCKET_CLIENT_END) { + hmac_ctx = &conn->_client_write_mac_ctx; + enc_key = &conn->_client_write_enc_key; + seq_num = conn->_client_seq_num; + } else { + hmac_ctx = &conn->_server_write_mac_ctx; + enc_key = &conn->_server_write_enc_key; + seq_num = conn->_server_seq_num; + } + if (tls_record_encrypt(hmac_ctx, enc_key, seq_num, mrec, mlen, crec, &clen) != 1 + || tls_seq_num_incr(seq_num) != 1 + || tls_record_send(crec, clen, conn->sock) != 1) { + error_print(); + return; + } + } else { + // 没有握手的情况直接明文发送 + tls_record_send(mrec, mlen, conn->sock); + } +} + + +/** + * 断开TLCP连接 + * + * 关闭连接将会销毁连接过程中所有信息,包括密钥信息。 + * + * @param conn [in,out] 连接 + */ +void TLCP_SOCKET_Connect_Close(TLCP_SOCKET_CONNECT *conn) { + if (conn == NULL || conn->sock == 0) { + return; + } + // 发送关闭消息 + tlcp_socket_send_close_alert(conn); + // 关闭 TCP socket + close(conn->sock); + // 将连接上下文中的工作密钥销毁 + memset(conn, 0, sizeof(*conn)); +} + + + diff --git a/src/tlcp_socket_key.c b/src/tlcp_socket_key.c new file mode 100644 index 0000000..3a65ddb --- /dev/null +++ b/src/tlcp_socket_key.c @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2021 - 2021 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. + */ + +#include +#include +#include +#include + + +/** + * 【私有】 基于国密SSL SM2私钥的签名接口实现 + * @param ctx [in] SM2_KEY指针 + * @param msg [in] 待签名消息 + * @param msglen [in]消息长度 + * @param sig [out] 签名值 + * @param siglen [out] 签名值长度 + * @return 1 - 连接成功;-1 - 连接失败 + */ +static int gmssl_sm2_signer(void *ctx, uint8_t *msg, size_t msglen, uint8_t *sig, size_t *siglen) { + SM2_SIGN_CTX sign_ctx; + if (sm2_sign_init(&sign_ctx, (SM2_KEY *) ctx, SM2_DEFAULT_ID) != 1) { + error_print(); + return -1; + } + if (sm2_sign_update(&sign_ctx, msg, msglen) != 1) { + error_print(); + return -1; + } + if (sm2_sign_finish(&sign_ctx, sig, siglen) != 1) { + error_print(); + return -1; + } + return 1; +} + + +/** + * 【私有】 基于国密SSL SM2私钥的解密接口实现 + * + * @param ctx [in] SM2_KEY指针 + * @param ciphertext [in] 密文 + * @param ciphertext_len [in] 密文长度 + * @param plaintext [out] 明文 + * @param plaintext_len [out] 明文长度 + * @return 1 - 成功;-1 - 失败 + */ +static int gmssl_sm2_decrypter(void *ctx, uint8_t *ciphertext, size_t ciphertext_len, + uint8_t *plaintext, size_t *plaintext_len) { + return sm2_decrypt((SM2_KEY *) ctx, ciphertext, ciphertext_len, + plaintext, plaintext_len); +} + +int TLCP_SOCKET_GMSSL_Key(TLCP_SOCKET_KEY *socket_key, X509_CERTIFICATE *cert, SM2_KEY *sm2_key) { + if (sm2_key == NULL || cert == NULL || socket_key == NULL) { + error_print(); + return -1; + } + + socket_key->ctx = sm2_key; + socket_key->cert = cert; + socket_key->signer = gmssl_sm2_signer; + socket_key->decrypter = gmssl_sm2_decrypter; + return 1; +} diff --git a/src/tlcp_socket_msg.c b/src/tlcp_socket_msg.c new file mode 100644 index 0000000..df65681 --- /dev/null +++ b/src/tlcp_socket_msg.c @@ -0,0 +1,1504 @@ +/* + * Copyright (c) 2021 - 2021 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. + */ + +#include +#include +#include +#include +#include +#include + + +static const int tlcp_ciphers[] = {TLCP_cipher_ecc_sm4_cbc_sm3}; +static const size_t tlcp_ciphers_count = sizeof(tlcp_ciphers) / sizeof(tlcp_ciphers[0]); + + +/** + * 产生预主密钥 + * + * @param ctx [in] 上下文 + * @param pre_master_secret [out] 预主密钥 + * @param version [in] 协议版本号 + * @return 1 - 成功;-1 - 失败 + */ +static int tlcp_socket_pre_master_secret_generate(rand_src rad, uint8_t pre_master_secret[48], int version) { + if (!tls_version_text(version)) { + error_print(); + return -1; + } + pre_master_secret[0] = version >> 8; + pre_master_secret[1] = version; + if (rad(pre_master_secret + 2, 46) != 1) { + error_print(); + return -1; + } + return 1; +} + + +static int tlcp_socket_record_recv(TLCP_SOCKET_CONNECT *conn, uint8_t *record, size_t *recordlen) { + ssize_t r; + size_t len; + + if ((r = recv(conn->sock, record, 5, 0)) < 0) { + error_print(); + return -1; + } else if (r != 5) { + // 如果对方已经中断连接,那么认为是EOF不做处理,错误原因通过error.h接口获取 + // error_print(); + // perror(""); // 否则打印ioctl错误 + return -1; + } + + if (!tls_record_type_name(record[0])) { + error_print_msg("invalid record type: %d\n", record[0]); + return -1; + } + if (!tls_version_text(tls_record_version(record))) { + error_print_msg("invalid record version: %d.%d\n", record[1], record[2]); + return -1; + } + len = (size_t) record[3] << 8 | record[4]; + *recordlen = 5 + len; + if (len) { + if ((r = recv(conn->sock, record + 5, len, 0)) < 0) { + error_print(); + return -1; + } else if (r != len) { + error_print(); + return -1; + } + } + return 1; +} + +/** + * 加密生成 GenericBlockCipher + * + * @param rd [in] 随机源 + * @param inited_hmac_ctx [in] hmac上下文 + * @param enc_key [in] 加密密钥 + * @param seq_num [in] 消息序列号 + * @param header [in] 记录层头部 + * @param in [in] 明文 + * @param inlen [in] 明文长度 + * @param out [out] 密文 + * @param outlen [out] 密文长度 + * @return 1 - 成功;-1 - 失败 + */ +static int tlcp_socket_cbc_encrypt( + rand_src rd, + const SM3_HMAC_CTX *inited_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) { + SM3_HMAC_CTX hmac_ctx; + uint8_t last_blocks[32 + 16] = {0}; + uint8_t *mac, *padding, *iv; + int rem, padding_len; + int i; + + if (!inited_hmac_ctx || !enc_key || !seq_num || !header || (!in && inlen) || !out || !outlen) { + error_print(); + return -1; + } + if (inlen > (1 << 14)) { + error_print_msg("invalid tls record data length %zu\n", inlen); + return -1; + } + + rem = (inlen + 32) % 16; + memcpy(last_blocks, in + inlen - rem, rem); + mac = last_blocks + rem; + + memcpy(&hmac_ctx, inited_hmac_ctx, sizeof(SM3_HMAC_CTX)); + sm3_hmac_update(&hmac_ctx, seq_num, 8); + sm3_hmac_update(&hmac_ctx, header, 5); + sm3_hmac_update(&hmac_ctx, in, inlen); + sm3_hmac_finish(&hmac_ctx, mac); + + padding = mac + 32; + padding_len = 16 - rem - 1; + for (i = 0; i <= padding_len; i++) { + padding[i] = padding_len; + } + + iv = out; + if (rd(iv, 16) != 1) { + error_print(); + return -1; + } + out += 16; + + if (inlen >= 16) { + sm4_cbc_encrypt(enc_key, iv, in, inlen / 16, out); + out += inlen - rem; + iv = out - 16; + } + sm4_cbc_encrypt(enc_key, iv, last_blocks, sizeof(last_blocks) / 16, out); + *outlen = 16 + inlen - rem + sizeof(last_blocks); + return 1; +} + +/** + * 加密记录层数据 + * + * @param rd [in] 随机源 + * @param hmac_ctx [in] hmac上下文 + * @param cbc_key [in] 加密密钥 + * @param seq_num [in] 消息序列号 + * @param in [in] 明文 + * @param inlen [in] 明文长度 + * @param out [out] 密文 + * @param outlen [out] 密文长度 + * @return 1 - 成功;-1 - 失败 + */ +static int tlcp_socket_record_encrypt( + rand_src rd, + 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) { + if (tlcp_socket_cbc_encrypt(rd, hmac_ctx, cbc_key, seq_num, in, + in + 5, inlen - 5, + out + 5, outlen) != 1) { + error_print(); + return -1; + } + + out[0] = in[0]; + out[1] = in[1]; + out[2] = in[2]; + out[3] = (*outlen) >> 8; + out[4] = (*outlen); + (*outlen) += 5; + return 1; +} + +/** + * 读取握手消息 + * + * 读取失败或非握手消息时返回-1 + * + * @param conn [in] TLCP连接对象 + * @param record [out] 记录层数据 + * @param recordlen [out] 数据长度 + * @return 1 - 成功;-1 - 失败 + */ +static int tlcp_socket_read_handshake(TLCP_SOCKET_CONNECT *conn, uint8_t *record, size_t *recordlen) { + if (tlcp_socket_record_recv(conn, record, recordlen) != 1) { + return -1; + } + // 报警协议部署于握手协议消息 + if (record[0] != TLS_record_handshake) { + return -1; + } + return 1; +} + +int tlcp_socket_read_client_hello(TLCP_SOCKET_CONNECT *conn, + uint8_t *record, size_t *recordlen) { + size_t i = 0; + int client_ciphers[12] = {0}; + size_t client_ciphers_count = sizeof(client_ciphers) / sizeof(client_ciphers[0]); + + // 读取消息 + if (tlcp_socket_read_handshake(conn, record, recordlen) != 1 + || tls_record_version(record) != TLS_version_tlcp) { + error_print(); + return -1; + } + sm3_update(conn->_sm3_ctx, record + 5, *recordlen - 5); + if (tls_record_get_handshake_client_hello(record, &conn->version, conn->_client_random, + conn->session_id, &conn->session_id_len, + client_ciphers, &client_ciphers_count, + NULL, 0) != 1) { + tlcp_socket_alert(conn, TLS_alert_internal_error); + error_print(); + return -1; + } + if (conn->version != TLS_version_tlcp) { + tlcp_socket_alert(conn, TLS_alert_protocol_version); + error_print(); + return -1; + } + // 取出兼容的密码套件 + for (i = 0; i < tlcp_ciphers_count; i++) { + if (tls_cipher_suite_in_list(tlcp_ciphers[i], client_ciphers, client_ciphers_count) == 1) { + conn->cipher_suite = tlcp_ciphers[i]; + break; + } + } + if (conn->cipher_suite == 0) { + tlcp_socket_alert(conn, TLS_alert_handshake_failure); + error_puts("no common cipher_suite"); + return -1; + } + + conn->entity = TLCP_SOCKET_SERVER_END; + // 根据算法套件设置密钥长度 + switch (conn->cipher_suite) { + case TLCP_cipher_ecc_sm4_cbc_sm3: + default: + conn->hash_size = SM3_DIGEST_SIZE; + conn->key_material_length = SM4_BLOCK_SIZE; + conn->fixed_iv_length = SM3_HMAC_SIZE; + break; + } + return 1; +} + +int tlcp_socket_write_server_hello(TLCP_SOCKET_CONNECT *conn, + uint8_t **out, size_t *outlen) { + uint8_t *record = *out; + size_t recordlen = 0; + + tls_record_set_version(record, conn->version); + // 生成客户端随机数 + tlcp_socket_random_generate(conn->config->rand, conn->_server_random); + // 随机产生一个会话ID + tlcp_socket_random_generate(conn->config->rand, conn->session_id); + conn->session_id_len = 32; + if (tls_record_set_handshake_server_hello(record, &recordlen, + TLS_version_tlcp, conn->_server_random, + conn->session_id, conn->session_id_len, + conn->cipher_suite, NULL, 0) != 1) { + tlcp_socket_alert(conn, TLS_alert_internal_error); + error_print(); + return -1; + } +// if (tls_record_send(record, recordlen, conn->sock) != 1) { +// error_print(); +// return -1; +// } + sm3_update(conn->_sm3_ctx, record + 5, recordlen - 5); + + *out += recordlen; + *outlen += recordlen; + return 1; +} + +int tlcp_socket_write_server_certificate(TLCP_SOCKET_CONNECT *conn, + uint8_t **out, size_t *outlen, + uint8_t *server_enc_cert, size_t *server_enc_certlen) { + uint8_t *record = *out; + size_t recordlen = 0; + + uint8_t der[1024] = {0}; + uint8_t *cp = der; + uint8_t *data = record + 5 + 4; + uint8_t *certs = data + 3; + size_t datalen = 0; + size_t certslen = 0; + size_t derlen = 0; + + + tls_record_set_version(record, conn->version); + // 序列化签名证书DER + if (x509_certificate_to_der(conn->config->server_sig_key->cert, &cp, &derlen) != 1) { + tlcp_socket_alert(conn, TLS_alert_internal_error); + error_print(); + return -1; + } + tls_uint24array_to_bytes(der, derlen, &certs, &certslen); + + // 序列化加密证书DER + cp = der; + derlen = 0; + if (x509_certificate_to_der(conn->config->server_enc_key->cert, &cp, &derlen) != 1) { + tlcp_socket_alert(conn, TLS_alert_internal_error); + error_print(); + return -1; + } + memcpy(server_enc_cert, der, derlen); + *server_enc_certlen = derlen; + tls_uint24array_to_bytes(der, derlen, &certs, &certslen); + + datalen = certslen; + tls_uint24_to_bytes((uint24_t) certslen, &data, &datalen); + tls_record_set_handshake(record, &recordlen, TLS_handshake_certificate, NULL, datalen); +// if (tls_record_send(record, recordlen, conn->sock) != 1) { +// error_print(); +// return -1; +// } + sm3_update(conn->_sm3_ctx, record + 5, recordlen - 5); + *out += recordlen; + *outlen += recordlen; + return 1; +} + +int tlcp_socket_random_generate(TLCP_SOCKET_RandBytes_FuncPtr randFnc, uint8_t random[32]) { + uint32_t gmt_unix_time = (uint32_t) time(NULL); + uint8_t *p = random; + size_t len = 0; + tls_uint32_to_bytes(gmt_unix_time, &p, &len); + if (randFnc != NULL) { + return randFnc(random + 4, 28); + } else { + return rand_bytes(random + 4, 28); + } +} + + +int tlcp_socket_write_server_key_exchange(TLCP_SOCKET_CONNECT *conn, TLCP_SOCKET_KEY *sig_key, + uint8_t **out, size_t *outlen, + uint8_t *server_enc_cert, size_t server_enc_certlen) { + uint8_t *record = *out; + size_t recordlen = 0; + + uint8_t sig[TLS_MAX_SIGNATURE_SIZE]; + size_t siglen = sizeof(sig); + uint8_t tbs[TLS_MAX_CERTIFICATES_SIZE + 68]; + size_t len = 0; + uint8_t *p = tbs; + + tls_record_set_version(record, conn->version); + /* + * 当密钥交换方式为ECC时,signed_params是服务端对双方随机数和服务端证书的签名 + * + * digitally-signed struct{ + * opaque _client_random[32]; + * opaque _server_random[32]; + * opaque ASN1.1Cert<1..2^24-1>; + * }signed_params; + */ + tls_array_to_bytes(conn->_client_random, 32, &p, &len); + tls_array_to_bytes(conn->_server_random, 32, &p, &len); + tls_uint24array_to_bytes(server_enc_cert, server_enc_certlen, &p, &len); + + if (sig_key->signer(sig_key->ctx, tbs, len, sig, &siglen) != 1) { + error_print(); + return -1; + } + if (tlcp_record_set_handshake_server_key_exchange_pke(record, &recordlen, sig, siglen) != 1) { + tlcp_socket_alert(conn, TLS_alert_internal_error); + error_print(); + return -1; + } +// if (tls_record_send(record, *recordlen, conn->sock) != 1) { +// error_print(); +// return -1; +// } + sm3_update(conn->_sm3_ctx, record + 5, recordlen - 5); + *out += recordlen; + *outlen += recordlen; + return 1; +} + +int tlcp_socket_write_server_hello_done(TLCP_SOCKET_CONNECT *conn, uint8_t **out, size_t *outlen) { + uint8_t *record = *out; + size_t recordlen = 0; + + tls_record_set_version(record, conn->version); + if (tls_record_set_handshake_server_hello_done(record, &recordlen) != 1) { + tlcp_socket_alert(conn, TLS_alert_internal_error); + error_print(); + return -1; + } +// if (tls_record_send(record, recordlen, conn->sock) != 1) { +// error_print(); +// return -1; +// } + sm3_update(conn->_sm3_ctx, record + 5, recordlen - 5); + *out += recordlen; + *outlen += recordlen; + return 1; +} + +int tlcp_socket_read_client_key_exchange(TLCP_SOCKET_CONNECT *conn, TLCP_SOCKET_KEY *enc_key, + uint8_t *record, size_t *recordlen) { + + uint8_t enced_pms[256]; + uint8_t pre_master_secret[48]; + size_t enced_pms_len = sizeof(enced_pms); + size_t pre_master_secret_len = 48; + uint8_t *p = NULL; + + + if (tlcp_socket_read_handshake(conn, record, recordlen) != 1 + || tls_record_version(record) != TLS_version_tlcp) { + error_print(); + return -1; + } + sm3_update(conn->_sm3_ctx, record + 5, *recordlen - 5); + if (tls_record_get_handshake_client_key_exchange_pke(record, enced_pms, &enced_pms_len) != 1) { + error_print(); + return -1; + } + + // 解密密钥对 + if (enc_key->decrypter(enc_key->ctx, + enced_pms, enced_pms_len, + pre_master_secret, &pre_master_secret_len) != 1) { + tlcp_socket_alert(conn, TLS_alert_decrypt_error); + return -1; + } + // 生成预主密钥 + // tls_trace("++++ generate secrets\n"); + if (tls_prf(pre_master_secret, pre_master_secret_len, "master secret", + conn->_client_random, 32, conn->_server_random, 32, + 48, conn->_master_secret) != 1) { + tlcp_socket_alert(conn, TLS_alert_internal_error); + error_print(); + return -1; + } + // 生成工作密钥 + if (tls_prf(conn->_master_secret, 48, "key expansion", + conn->_server_random, 32, conn->_client_random, 32, + 96, conn->_key_block) != 1) { + tlcp_socket_alert(conn, TLS_alert_internal_error); + error_print(); + return -1; + } + // 切分各个密钥 + p = conn->_key_block; + // conn->client_write_MAC_secret = _p; + sm3_hmac_init(&conn->_client_write_mac_ctx, p, conn->hash_size); + p += conn->hash_size; + // conn->server_write_MAC_secret = _p; + sm3_hmac_init(&conn->_server_write_mac_ctx, p, conn->hash_size); + p += conn->hash_size; + // conn->client_write_key = _p; + sm4_set_decrypt_key(&conn->_client_write_enc_key, p); + p += conn->key_material_length; + // conn->server_write_key = _p; + sm4_set_encrypt_key(&conn->_server_write_enc_key, p); + + p += conn->key_material_length; + conn->_client_write_IV = p; + p += conn->fixed_iv_length; + conn->_server_write_IV = p; + + return 1; +} + +int tlcp_socket_read_client_spec_finished(TLCP_SOCKET_CONNECT *conn, uint8_t *record, size_t *recordlen) { + + SM3_CTX tmp_sm3_ctx; + uint8_t sm3_hash[32] = {0}; + uint8_t finished[256] = {0}; + uint8_t verify_data[12] = {0}; + uint8_t local_verify_data[12] = {0}; + size_t finishedlen = sizeof(finished); + + // tls_trace("<<<< Client CipherSpec\n"); + if (tlcp_socket_record_recv(conn, record, recordlen) != 1 + || tls_record_version(record) != TLS_version_tlcp) { + error_print(); + return -1; + } + if (tls_record_get_change_cipher_spec(record) != 1) { + error_print(); + return -1; + } + + // tls_trace("<<<< ClientFinished\n"); + if (tlcp_socket_read_handshake(conn, record, recordlen) != 1 + || tls_record_version(record) != TLS_version_tlcp) { + error_print(); + return -1; + } + // 解密客户端Finished消息 + if (tls_record_decrypt(&conn->_client_write_mac_ctx, &conn->_client_write_enc_key, + conn->_client_seq_num, record, *recordlen, finished, &finishedlen) != 1) { + error_print(); + return -1; + } + tls_seq_num_incr(conn->_client_seq_num); + if (tls_record_get_handshake_finished(finished, verify_data) != 1) { + tlcp_socket_alert(conn, TLS_alert_illegal_parameter); + return -1; + } + + memcpy(&tmp_sm3_ctx, conn->_sm3_ctx, sizeof(SM3_CTX)); + sm3_finish(&tmp_sm3_ctx, sm3_hash); + + // 计算校验数据 PRF(_master_secret, finished_label, SM3(handshake_messages))[0..11] + if (tls_prf(conn->_master_secret, 48, "client finished", sm3_hash, 32, NULL, 0, + 12, local_verify_data) != 1) { + tlcp_socket_alert(conn, TLS_alert_internal_error); + error_print(); + return -1; + } + sm3_update(conn->_sm3_ctx, finished + 5, finishedlen - 5); + + // 比较数据校验码是否一致 + if (memcmp(local_verify_data, verify_data, 12) != 0) { + tlcp_socket_alert(conn, TLS_alert_handshake_failure); + error_puts("client_finished.verify_data verification failure"); + return -1; + } + + return 1; +} + +int tlcp_socket_write_server_spec_finished(TLCP_SOCKET_CONNECT *conn, uint8_t **out, size_t *outlen) { + uint8_t *record = *out; + size_t recordlen = 0; + + uint8_t sm3_hash[32]; + uint8_t verify_data[12]; + uint8_t finished[256]; + size_t finishedlen = sizeof(finished); + + // tls_trace(">>>> [ChangeCipherSpec]\n"); + tls_record_set_version(record, TLS_version_tlcp); + if (tls_record_set_change_cipher_spec(record, &recordlen) != 1) { + error_print(); + return -1; + } + +// if (tls_record_send(record, recordlen, conn->sock) != 1) { +// error_print(); +// return -1; +// } + *out += recordlen; + *outlen += recordlen; + record = *out; + recordlen = 0; + + // tls_trace(">>>> ServerFinished\n"); + sm3_finish(conn->_sm3_ctx, sm3_hash); + if (tls_prf(conn->_master_secret, 48, "server finished", sm3_hash, 32, NULL, 0, + 12, verify_data) != 1) { + tlcp_socket_alert(conn, TLS_alert_internal_error); + error_print(); + return -1; + } + // 创建的缓冲区,需要手动设置协议版本号。 + tls_record_set_version(finished, TLS_version_tlcp); + if (tls_record_set_handshake_finished(finished, &finishedlen, verify_data) != 1) { + tlcp_socket_alert(conn, TLS_alert_internal_error); + error_print(); + return -1; + } + // tls_record_print(stderr, finished, finishedlen, 0, 0); + if (tlcp_socket_record_encrypt(conn->config->rand, + &conn->_server_write_mac_ctx, &conn->_server_write_enc_key, + conn->_server_seq_num, finished, finishedlen, record, &recordlen) != 1) { + error_print(); + return -1; + } + tls_seq_num_incr(conn->_server_seq_num); +// if (tls_record_send(record, *recordlen, conn->sock) != 1) { +// error_print(); +// return -1; +// } + *out += recordlen; + *outlen += recordlen; + return 1; +} + +int tlcp_socket_read_app_data(TLCP_SOCKET_CONNECT *conn) { + const SM3_HMAC_CTX *hmac_ctx; + const SM4_KEY *dec_key; + uint8_t *seq_num; + uint8_t *crec = conn->_raw_input; // 密文 + uint8_t *mrec = conn->record; // 原文 + size_t mlen = sizeof(conn->_raw_input); + size_t clen = sizeof(conn->record); + int vers = 0; + + if (conn->entity == TLCP_SOCKET_CLIENT_END) { + hmac_ctx = &conn->_server_write_mac_ctx; + dec_key = &conn->_server_write_enc_key; + seq_num = conn->_server_seq_num; + } else { + hmac_ctx = &conn->_client_write_mac_ctx; + dec_key = &conn->_client_write_enc_key; + seq_num = conn->_client_seq_num; + } + // tls_trace("<<<< ApplicationData\n"); + if (tlcp_socket_record_recv(conn, crec, &clen) != 1) { + error_print(); + return -1; + } + + // 解密消息。 + vers = crec[1] << 8 | crec[2]; + if (conn->version != vers + || tls_record_decrypt(hmac_ctx, dec_key, seq_num, crec, clen, mrec, &mlen) != 1 + || tls_seq_num_incr(seq_num) != 1) { + error_print(); + return -1; + } + // 读写过程中出现报警消息,返回错误 + if (crec[0] == TLS_record_alert) { + // Record header {0...4} Alert {level: 5,description: 6} + if (mrec[6] != TLS_alert_close_notify) { + if (conn->config->alert_handler != NULL) { + conn->config->alert_handler(conn, conn->record[2]); + } + error_print_msg("remote error code: %d", mrec[6]); + } + return -1; + } + // 向后偏移头部,得到数据部分 + conn->_p = mrec + 5; + // 设置剩余长度为除头部分外长度 + conn->_buf_remain = mlen - 5; + // memcpy(data, mrec + 5, mlen - 5); + // *datalen = mlen - 5; + return 1; +} + +int tlcp_socket_write_app_data(TLCP_SOCKET_CONNECT *conn, const uint8_t *data, size_t datalen) { + const SM3_HMAC_CTX *hmac_ctx; + const SM4_KEY *enc_key; + uint8_t *seq_num; + uint8_t mrec[TLCP_SOCKET_DEFAULT_FRAME_SIZE + 8]; // 记录层明文 (头6B) + uint8_t crec[TLCP_SOCKET_DEFAULT_FRAME_SIZE + 128]; // 记录层密码文 (头+加密填充和IV+MAC) + size_t mlen = sizeof(mrec); + size_t clen = sizeof(crec); + // header 5B; iv 16B; mac 16B; padding 16B + if (datalen > TLCP_SOCKET_DEFAULT_FRAME_SIZE) { + error_puts("datalen overflow"); + return -1; + } + + if (conn->entity == TLCP_SOCKET_CLIENT_END) { + hmac_ctx = &conn->_client_write_mac_ctx; + enc_key = &conn->_client_write_enc_key; + seq_num = conn->_client_seq_num; + } else { + hmac_ctx = &conn->_server_write_mac_ctx; + enc_key = &conn->_server_write_enc_key; + seq_num = conn->_server_seq_num; + } + + // tls_trace(">>>> ApplicationData\n"); + if (tls_record_set_version(mrec, conn->version) != 1 + || tls_record_set_application_data(mrec, &mlen, data, datalen) != 1 + || tlcp_socket_record_encrypt(conn->config->rand, hmac_ctx, enc_key, seq_num, mrec, mlen, crec, &clen) != 1 + || tls_seq_num_incr(seq_num) != 1 + || tls_record_send(crec, clen, conn->sock) != 1) { + error_print(); + return -1; + } + // (void) tls_record_print(stderr, crec, clen, 0, 0); + return 1; +} + +void tlcp_socket_alert(TLCP_SOCKET_CONNECT *conn, int alert_description) { + uint8_t record[8]; + size_t len; + int alert_level; + switch (alert_description) { + case TLS_alert_close_notify: + case TLS_alert_user_canceled: + case TLS_alert_no_renegotiation: + alert_level = TLS_alert_level_warning; + break; + case TLS_alert_unexpected_message: + case TLS_alert_bad_record_mac: + case TLS_alert_decryption_failed: + case TLS_alert_record_overflow: + case TLS_alert_decompression_failure: + case TLS_alert_handshake_failure: + case TLS_alert_no_certificate: + case TLS_alert_bad_certificate: + case TLS_alert_unsupported_certificate: + case TLS_alert_certificate_revoked: + case TLS_alert_certificate_expired: + case TLS_alert_certificate_unknown: + case TLS_alert_illegal_parameter: + case TLS_alert_unknown_ca: + case TLS_alert_access_denied: + case TLS_alert_decode_error: + case TLS_alert_decrypt_error: + case TLS_alert_export_restriction: + case TLS_alert_protocol_version: + case TLS_alert_insufficient_security: + case TLS_alert_internal_error: + case TLS_alert_unsupported_site2site: + case TLS_alert_no_area: + case TLS_alert_unsupported_areatype: + case TLS_alert_bad_ibcparam: + case TLS_alert_unsupported_ibcparam: + case TLS_alert_identity_need: + default: + alert_level = TLS_alert_level_fatal; + break; + } + record[1] = TLCP_VERSION_MAJOR; + record[2] = TLCP_VERSION_MINOR; + // 设置消息 + tls_record_set_alert(record, &len, alert_level, alert_description); + tls_record_send(record, len, conn->sock); + // 致命类型的消息关闭连接 + if (alert_level == TLS_alert_level_fatal) { + //关闭连接 + close(conn->sock); + } + // 如果存在错误处理器,那么进入错误处理流程 + if (conn->config->alert_handler != NULL) { + conn->config->alert_handler(conn, alert_description); + } +} + +int tlcp_socket_write_client_hello(TLCP_SOCKET_CONNECT *conn, + uint8_t *record, size_t *recordlen) { + tlcp_socket_random_generate(conn->config->rand, conn->_client_random); + if (tls_record_set_handshake_client_hello(record, recordlen, + TLS_version_tlcp, conn->_client_random, NULL, 0, + tlcp_ciphers, tlcp_ciphers_count, NULL, 0) != 1) { + error_print(); + return -1; + } + if (tls_record_send(record, *recordlen, conn->sock) != 1) { + error_print(); + return -1; + } + sm3_update(conn->_sm3_ctx, record + 5, *recordlen - 5); + + return 1; +} + +int tlcp_socket_read_server_hello(TLCP_SOCKET_CONNECT *conn, uint8_t *record, size_t *recordlen) { + if (tlcp_socket_read_handshake(conn, record, recordlen) != 1) { + error_print(); + return -1; + } + sm3_update(conn->_sm3_ctx, record + 5, *recordlen - 5); + // 检查协议版本 + if (tls_record_version(record) != TLS_version_tlcp) { + tlcp_socket_alert(conn, TLS_alert_protocol_version); + return -1; + } + if (tls_record_get_handshake_server_hello(record, + &conn->version, conn->_server_random, conn->session_id, + &conn->session_id_len, + &conn->cipher_suite, NULL, 0) != 1) { + error_print(); + tlcp_socket_alert(conn, TLS_alert_internal_error); + return -1; + } + // 检查协议版本 + if (conn->version != TLS_version_tlcp) { + tlcp_socket_alert(conn, TLS_alert_protocol_version); + return -1; + } + // 选择密码套件 + if (tls_cipher_suite_in_list(conn->cipher_suite, tlcp_ciphers, tlcp_ciphers_count) != 1) { + error_print(); + return -1; + } + return 1; +} + +int tlcp_socket_read_server_certs(TLCP_SOCKET_CONNECT *conn, + uint8_t *record, size_t *recordlen, + X509_CERTIFICATE server_certs[2], + uint8_t *enc_cert_vector, size_t *enc_cert_vector_len) { + uint8_t certs_vector[TLS_MAX_CERTIFICATES_SIZE] = {0}; + size_t certs_vector_len = 0; + const uint8_t *p = certs_vector; + const uint8_t *certs = NULL; + const uint8_t *der = NULL; + size_t certslen = 0; + size_t derlen = 0; + size_t i = 0; + X509_CERTIFICATE *sign_cert = &server_certs[0]; + X509_CERTIFICATE *enc_cert = &server_certs[1]; + X509_CERTIFICATE *ca_cert = NULL; + TLCP_SOCKET_CONFIG *ctx = conn->config; + + if (tlcp_socket_read_handshake(conn, record, recordlen) != 1 + || tls_record_version(record) != TLS_version_tlcp) { + error_print(); + return -1; + } + sm3_update(conn->_sm3_ctx, record + 5, *recordlen - 5); + + if (tls_record_get_handshake_certificate(record, certs_vector, &certs_vector_len) != 1) { + error_print(); + return -1; + } + + if (tls_uint24array_from_bytes(&certs, &certslen, &p, &certs_vector_len) != 1 + || certs_vector_len > 0) { + error_print(); + return -1; + } + // 解析签名证书 + if (tls_uint24array_from_bytes(&der, &derlen, &certs, &certslen) != 1 + || x509_certificate_from_der(sign_cert, &der, &derlen) != 1 + || derlen > 0) { + tlcp_socket_alert(conn, TLS_alert_bad_certificate); + error_print(); + return -1; + } + + if (tls_uint24array_from_bytes(&der, &derlen, &certs, &certslen) != 1) { + tlcp_socket_alert(conn, TLS_alert_bad_certificate); + error_print(); + return -1; + } + // 复制加密证书向量,用于验证服务端密钥交换消息 + tls_uint24array_to_bytes(der, derlen, &enc_cert_vector, enc_cert_vector_len); + // 解析加密证书 + if (x509_certificate_from_der(enc_cert, &der, &derlen) != 1 || derlen > 0) { + error_print(); + tlcp_socket_alert(conn, TLS_alert_bad_certificate); + return -1; + } + if (x509_name_equ(&sign_cert->tbs_certificate.issuer, + &enc_cert->tbs_certificate.issuer) != 1) { + tlcp_socket_alert(conn, TLS_alert_bad_certificate); + return -1; + } + + if (certslen) { + // 如果还有证书,那么忽略后续的证书 + } + + if (ctx->root_certs == NULL || ctx->root_cert_len == 0) { + // 没有根证书,那么忽略证书的验证 + return 1; + } + + for (i = 0; i < ctx->root_cert_len; i++) { + if (x509_name_equ(&ctx->root_certs[i].tbs_certificate.subject, &sign_cert->tbs_certificate.issuer) == 1) { + ca_cert = &ctx->root_certs[i]; + break; + } + } + // 没有找到匹配的根证书,那么报警 + if (ca_cert == NULL) { + tlcp_socket_alert(conn, TLS_alert_bad_certificate); + return -1; + } + // 验证签名证书 + if (x509_certificate_verify_by_certificate(sign_cert, ca_cert) != 1) { + error_print(); + tlcp_socket_alert(conn, TLS_alert_bad_certificate); + return -1; + } + + // 验证加密证书 + if (x509_certificate_verify_by_certificate(enc_cert, ca_cert) != 1) { + error_print(); + tlcp_socket_alert(conn, TLS_alert_bad_certificate); + return -1; + } + return 1; +} + + +int tlcp_socket_read_server_key_exchange(TLCP_SOCKET_CONNECT *conn, + uint8_t *record, size_t *recordlen, + X509_CERTIFICATE *server_sig_cert, + uint8_t *enc_cert_vector, size_t enc_cert_vector_len) { + uint8_t sig[TLS_MAX_SIGNATURE_SIZE] = {0}; + size_t sig_len = sizeof(sig); + SM2_KEY server_sign_key = {0}; + SM2_SIGN_CTX verify_ctx = {0}; + + + if (tlcp_socket_read_handshake(conn, record, recordlen) != 1 + || tls_record_version(record) != TLS_version_tlcp) { + tlcp_socket_alert(conn, TLS_alert_handshake_failure); + error_print(); + return -1; + } + sm3_update(conn->_sm3_ctx, record + 5, *recordlen - 5); + // 解析出签名值 + if (tlcp_record_get_handshake_server_key_exchange_pke(record, sig, &sig_len) != 1) { + tlcp_socket_alert(conn, TLS_alert_internal_error); + error_print(); + return -1; + } + // 解析签名证书中的公钥 + if (x509_certificate_get_public_key(server_sig_cert, &server_sign_key) != 1) { + error_print(); + tlcp_socket_alert(conn, TLS_alert_bad_certificate); + return -1; + } + + // tls_trace("++++ process ServerKeyExchange\n"); + if (sm2_verify_init(&verify_ctx, &server_sign_key, SM2_DEFAULT_ID) != 1 + || sm2_verify_update(&verify_ctx, conn->_client_random, 32) != 1 + || sm2_verify_update(&verify_ctx, conn->_server_random, 32) != 1 + || sm2_verify_update(&verify_ctx, enc_cert_vector, enc_cert_vector_len) != 1) { + tlcp_socket_alert(conn, TLS_alert_internal_error); + error_print(); + return -1; + } + + if (sm2_verify_finish(&verify_ctx, sig, sig_len) != 1) { + error_puts("ServerKeyExchange signature verification failure"); + tlcp_socket_alert(conn, TLS_alert_handshake_failure); + return -1; + } + return 1; +} + +/** + * 处理证书请求消息,并验证本地证书是否匹配 + * + * 若本地证书不匹配,那么发出 TLS_alert_no_certificate 错误并关闭连接 + * + * @param ctx [in] 上下文 + * @param conn [in] 连接上下文 + * @param record [in] 证书请求记录层消息 + * @param recordlen [in] 消息长度 + * @return 1 - 成功;-1 - 失败 + */ +static int tlcp_socket_process_cert_req(TLCP_SOCKET_CONNECT *conn, + uint8_t *record, size_t *recordlen) { + + int cert_types[TLS_MAX_CERTIFICATE_TYPES]; + size_t cert_types_count; + + uint8_t ca_names[TLS_MAX_CA_NAMES_SIZE]; + size_t ca_names_len = 0; + const uint8_t *cap = ca_names; + const uint8_t *dn = ca_names; + size_t dn_len = 0; + + uint8_t local_dn[256] = {0}; + size_t local_dn_len = 0; + uint8_t *lp = local_dn; + TLCP_SOCKET_CONFIG *ctx = conn->config; + + + // tls_trace("<<<< CertificateRequest\n"); + if (tls_record_get_handshake_certificate_request(record, + cert_types, &cert_types_count, + ca_names, &ca_names_len) != 1) { + tlcp_socket_alert(conn, TLS_alert_internal_error); + error_print(); + return -1; + } + // read ServerHelloDone + if (tlcp_socket_read_handshake(conn, record, recordlen) != 1 + || tls_record_version(record) != TLS_version_tlcp) { + error_print(); + return -1; + } + sm3_update(conn->_sm3_ctx, record + 5, *recordlen - 5); + + // 检查证书、密钥是否存在 + if (ctx->client_sig_key == NULL || ctx->client_sig_key->cert == NULL) { + error_print(); + tlcp_socket_alert(conn, TLS_alert_no_certificate); + return -1; + } + // 解析当前签名证书信息 + if (x509_name_to_der(&ctx->client_sig_key->cert->tbs_certificate.issuer, &lp, &local_dn_len) != 1) { + error_print(); + tlcp_socket_alert(conn, TLS_alert_internal_error); + return -1; + } + // 查找与本地证书匹配的 服务器证书 + do { + if (tls_uint16array_from_bytes(&dn, &dn_len, &cap, &ca_names_len) != 1) { + // 无法解析 DN + return -1; + } + if (local_dn_len != dn_len) { + return -1; + } + if (memcmp(dn, local_dn, dn_len) == 0) { + return 1; + } + } while (ca_names_len > 0); + + return -1; +} + +int tlcp_socket_read_cert_req_server_done(TLCP_SOCKET_CONNECT *conn, + uint8_t *record, size_t *recordlen, + uint8_t *need_auth) { + + int type; + const uint8_t *data; + size_t data_len; + + + if (tlcp_socket_read_handshake(conn, record, recordlen) != 1 + || tls_record_version(record) != TLS_version_tlcp + || tls_record_get_handshake(record, &type, &data, &data_len) != 1) { + tlcp_socket_alert(conn, TLS_alert_internal_error); + error_print(); + return -1; + } + sm3_update(conn->_sm3_ctx, record + 5, *recordlen - 5); + // 判断消息是否为证书请求 + if (type == TLS_handshake_certificate_request) { + // 处理证书请求消息,并验证本地证书是否匹配 + if (tlcp_socket_process_cert_req(conn, record, recordlen) != 1) { + return -1; + } + // 需要客户端认证 + *need_auth = 1; + } + if (tls_record_get_handshake_server_hello_done(record) != 1) { + error_print(); + return -1; + } + + return 1; +} + +int tlcp_socket_write_client_key_exchange(TLCP_SOCKET_CONNECT *conn, + uint8_t **out, size_t *outlen, + X509_CERTIFICATE *server_enc_cert) { + uint8_t *record = *out; + size_t recordlen = 0; + + SM2_KEY server_enc_key = {0}; + uint8_t pre_master_secret[48] = {0}; + uint8_t enced_pre_master_secret[256] = {0}; + size_t enced_pre_master_secret_len = {0}; + + tls_record_set_version(record, conn->version); + if (tlcp_socket_pre_master_secret_generate(conn->config->rand, pre_master_secret, conn->version) != 1) { + error_print(); + tlcp_socket_alert(conn, TLS_alert_internal_error); + return -1; + } + // 解析加密证书中的公钥 + if (x509_certificate_get_public_key(server_enc_cert, &server_enc_key) != 1) { + error_print(); + tlcp_socket_alert(conn, TLS_alert_bad_certificate); + return -1; + } + // 使用加密证书中的公钥加密预主密钥,使用外部随机源。 + if (sm2_encrypt_ext(conn->config->rand, &server_enc_key, pre_master_secret, 48, + enced_pre_master_secret, &enced_pre_master_secret_len) != 1) { + error_print(); + tlcp_socket_alert(conn, TLS_alert_internal_error); + return -1; + } + if (tls_record_set_handshake_client_key_exchange_pke(record, &recordlen, + enced_pre_master_secret, enced_pre_master_secret_len) != 1) { + error_print(); + tlcp_socket_alert(conn, TLS_alert_internal_error); + return -1; + } + sm3_update(conn->_sm3_ctx, record + 5, recordlen - 5); + *out += recordlen; + *outlen += recordlen; + + // tls_trace("++++ generate secrets\n"); + if (tls_prf(pre_master_secret, 48, "master secret", + conn->_client_random, 32, conn->_server_random, 32, + 48, conn->_master_secret) != 1 + || tls_prf(conn->_master_secret, 48, "key expansion", + conn->_server_random, 32, conn->_client_random, 32, + 96, conn->_key_block) != 1) { + error_print(); + tlcp_socket_alert(conn, TLS_alert_internal_error); + return -1; + } + sm3_hmac_init(&conn->_client_write_mac_ctx, conn->_key_block, 32); + sm3_hmac_init(&conn->_server_write_mac_ctx, conn->_key_block + 32, 32); + sm4_set_encrypt_key(&conn->_client_write_enc_key, conn->_key_block + 64); + sm4_set_decrypt_key(&conn->_server_write_enc_key, conn->_key_block + 80); + conn->_client_write_IV = conn->_key_block + 96; + conn->_server_write_IV = conn->_key_block + 112; + + return 1; +} + + +int tlcp_socket_write_client_spec_finished(TLCP_SOCKET_CONNECT *conn, uint8_t **out, size_t *outlen) { + uint8_t *record = *out; + size_t recordlen = 0; + + SM3_CTX tmp_sm3_ctx; + uint8_t sm3_hash[32]; + uint8_t verify_data[12]; + uint8_t finished[256]; + size_t finishedlen; + + tls_record_set_version(record, conn->version); + // tls_trace(">>>> [ChangeCipherSpec]\n"); + if (tls_record_set_change_cipher_spec(record, &recordlen) != 1) { + tlcp_socket_alert(conn, TLS_alert_internal_error); + return -1; + } + *out += recordlen; + *outlen += recordlen; + record = *out; + recordlen = 0; + + // tls_trace(">>>> Finished\n"); + memcpy(&tmp_sm3_ctx, conn->_sm3_ctx, sizeof(SM3_CTX)); + sm3_finish(&tmp_sm3_ctx, sm3_hash); + + if (tls_prf(conn->_master_secret, 48, "client finished", + sm3_hash, 32, NULL, 0, + sizeof(verify_data), verify_data) != 1) { + tlcp_socket_alert(conn, TLS_alert_internal_error); + return -1; + } + // 设置缓冲区消息的协议版本号 + tls_record_set_version(finished, TLS_version_tlcp); + if (tls_record_set_handshake_finished(finished, &finishedlen, verify_data) != 1) { + error_print(); + return -1; + } + // tls_record_print(stderr, finished, finishedlen, 0, 0); + sm3_update(conn->_sm3_ctx, finished + 5, finishedlen - 5); + + if (tlcp_socket_record_encrypt(conn->config->rand, + &conn->_client_write_mac_ctx, &conn->_client_write_enc_key, + conn->_client_seq_num, finished, finishedlen, record, &recordlen) != 1) { + error_print(); + tlcp_socket_alert(conn, TLS_alert_decode_error); + return -1; + } + tls_seq_num_incr(conn->_client_seq_num); + + *out += recordlen; + *outlen += recordlen; + return 1; +} + +int tlcp_socket_read_server_spec_finished(TLCP_SOCKET_CONNECT *conn, uint8_t *record, size_t *recordlen) { + uint8_t verify_data[12] = {0}; + uint8_t local_verify_data[12] = {0}; + uint8_t sm3_hash[32] = {0}; + uint8_t finished[256] = {0}; + size_t finishedlen; + // 设置缓冲区消息的协议版本号 + tls_record_set_version(finished, TLS_version_tlcp); + + // tls_trace("<<<< [ChangeCipherSpec]\n"); + if (tlcp_socket_record_recv(conn, record, recordlen) != 1 + || tls_record_version(record) != TLS_version_tlcp) { + error_print(); + tlcp_socket_alert(conn, TLS_alert_handshake_failure); + return -1; + } + if (tls_record_get_change_cipher_spec(record) != 1) { + error_print(); + return -1; + } + + // tls_trace("<<<< Finished\n"); + if (tlcp_socket_read_handshake(conn, record, recordlen) != 1 + || tls_record_version(record) != TLS_version_tlcp) { + error_print(); + tlcp_socket_alert(conn, TLS_alert_handshake_failure); + return -1; + } + // 解密finished消息 + if (tls_record_decrypt(&conn->_server_write_mac_ctx, &conn->_server_write_enc_key, + conn->_server_seq_num, record, *recordlen, finished, &finishedlen) != 1) { + error_print(); + tlcp_socket_alert(conn, TLS_alert_internal_error); + return -1; + } + tls_seq_num_incr(conn->_server_seq_num); + // 获取finished消息中的 验证数据 verify_data + if (tls_record_get_handshake_finished(finished, verify_data) != 1) { + error_print(); + tlcp_socket_alert(conn, TLS_alert_handshake_failure); + return -1; + } + // 通过计算之前的消息,生成本地的验证数据 + sm3_finish(conn->_sm3_ctx, sm3_hash); + if (tls_prf(conn->_master_secret, 48, "server finished", + sm3_hash, 32, NULL, 0, + sizeof(local_verify_data), local_verify_data) != 1) { + error_print(); + tlcp_socket_alert(conn, TLS_alert_internal_error); + return -1; + } + if (memcmp(local_verify_data, verify_data, 12) != 0) { + error_puts("server_finished.verify_data verification failure"); + tlcp_socket_alert(conn, TLS_alert_handshake_failure); + return -1; + } + + // tls_trace("++++ Connection established\n"); + return 1; +} + + +int tlcp_socket_write_client_certificate(TLCP_SOCKET_CONNECT *conn, uint8_t **out, size_t *outlen) { + uint8_t *record = *out; + size_t recordlen = 0; + + int type = TLS_handshake_certificate; + uint8_t *data = record + 5 + 4; + uint8_t *certs = data + 3; + size_t datalen = 0; + size_t certslen = 0; + uint8_t der[1024]; + uint8_t *cp = der; + size_t derlen = 0; + X509_CERTIFICATE *client_cert = conn->config->client_sig_key->cert; + + tls_record_set_version(record, conn->version); + // 序列化签名证书DER + if (x509_certificate_to_der(client_cert, &cp, &derlen) != 1) { + tlcp_socket_alert(conn, TLS_alert_internal_error); + error_print(); + return -1; + } + tls_uint24array_to_bytes(der, derlen, &certs, &certslen); + + datalen = certslen; + tls_uint24_to_bytes((uint24_t) certslen, &data, &datalen); + tls_record_set_handshake(record, &recordlen, type, NULL, datalen); + sm3_update(conn->_sm3_ctx, record + 5, recordlen - 5); + + *out += recordlen; + *outlen += recordlen; + return 1; +} + +int tlcp_socket_write_client_cert_verify(TLCP_SOCKET_CONNECT *conn, + uint8_t **out, size_t *outlen) { + uint8_t *record = *out; + size_t recordlen = 0; + + SM3_CTX tmp_sm3_ctx; + TLCP_SOCKET_KEY *sig_key = conn->config->client_sig_key; + uint8_t sig[TLS_MAX_SIGNATURE_SIZE] = {0}; + size_t siglen = sizeof(sig); + uint8_t msg[SM3_DIGEST_SIZE] = {0}; + uint8_t sig_vector[TLS_MAX_SIGNATURE_SIZE + 2] = {0}; // 签名向量 + uint8_t *p = sig_vector; // 向量指针 + size_t sig_vector_len = 0; + + tls_record_set_version(record, conn->version); + memcpy(&tmp_sm3_ctx, conn->_sm3_ctx, sizeof(SM3_CTX)); + sm3_finish(&tmp_sm3_ctx, msg); + /* + * from GBT38636 6.4.5.6 + * + * case ecc_sm3: // 当ECC为SM2算法时,用这个套件 + * digitally-signed struct{ + * opaque sm3_hash[32]; + * } + * sm3_hash 是指hash运行的结果,运算的内容时客户端hello消息开始 + * 直到本消息(不包括本消息)的所有与握手有关的消息,包括握手消息 + * 的类型和长度域。 + */ + if (sig_key->signer(sig_key->ctx, msg, SM3_DIGEST_SIZE, sig, &siglen) != 1) { + error_puts("client signature fail"); + tlcp_socket_alert(conn, TLS_alert_internal_error); + return -1; + } + // 签名值是一个向量 + tls_uint16array_to_bytes(sig, siglen, &p, &sig_vector_len); + if (tls_record_set_handshake_certificate_verify(record, &recordlen, sig_vector, sig_vector_len) != 1) { + error_print(); + tlcp_socket_alert(conn, TLS_alert_internal_error); + return -1; + } + + sm3_update(conn->_sm3_ctx, record + 5, recordlen - 5); + *out += recordlen; + *outlen += recordlen; + return 1; +} + +int tlcp_socket_write_cert_req(TLCP_SOCKET_CONNECT *conn, uint8_t **out, size_t *outlen) { + uint8_t *record = *out; + size_t recordlen = 0; + + const int cert_types[] = {TLS_cert_type_ecdsa_sign,}; + uint8_t ca_names[TLS_MAX_CA_NAMES_SIZE] = {0}; + size_t cert_types_count = sizeof(cert_types) / sizeof(cert_types[0]); + size_t ca_names_len = 0; + + uint8_t *p = ca_names; + size_t i = 0; + uint8_t dn_item[256] = {0}; + size_t dn_item_len = 0; + uint8_t *p_dn = dn_item; + TLCP_SOCKET_CONFIG *ctx = conn->config; + + tls_record_set_version(record, conn->version); + // 构造服务端信任的CA证书DN列表,也就是根证书Subject列表 + for (i = 0; i < ctx->root_cert_len; i++) { + p_dn = dn_item; + dn_item_len = 0; + // 解析根证数中的subject DN为DER格式 + if (x509_name_to_der(&ctx->root_certs[i].tbs_certificate.subject, &p_dn, &dn_item_len) != 1) { + // 忽略证书无法解析的情况 + continue; + } + if (ca_names_len + (2 + dn_item_len) > TLS_MAX_CA_NAMES_SIZE) { + // 超过最大能容纳数量,忽略后续的证书 + break; + } + tls_uint16array_to_bytes(dn_item, dn_item_len, &p, &ca_names_len); + } + + if (tls_record_set_handshake_certificate_request(record, &recordlen, + cert_types, cert_types_count, + ca_names, ca_names_len) != 1) { + error_print(); + tlcp_socket_alert(conn, TLS_alert_internal_error); + return -1; + } +// if (tls_record_send(record, recordlen, conn->sock) != 1) { +// error_print(); +// return -1; +// } + sm3_update(conn->_sm3_ctx, record + 5, recordlen - 5); + *out += recordlen; + *outlen += recordlen; + return 1; +} + + +int tlcp_socket_read_client_cert(TLCP_SOCKET_CONNECT *conn, + uint8_t *record, size_t *recordlen, + X509_CERTIFICATE *client_cert) { + uint8_t certs_vector[TLS_MAX_CERTIFICATES_SIZE] = {0}; + size_t certs_vector_len = 0; + const uint8_t *p = certs_vector; + const uint8_t *certs = NULL; + const uint8_t *der = NULL; + size_t certslen = 0; + size_t derlen = 0; + + if (tlcp_socket_record_recv(conn, record, recordlen) != 1 + || tls_record_version(record) != TLS_version_tlcp) { + error_print(); + return -1; + } + sm3_update(conn->_sm3_ctx, record + 5, *recordlen - 5); + + if (tls_record_get_handshake_certificate(record, certs_vector, &certs_vector_len) != 1) { + error_print(); + return -1; + } + + if (tls_uint24array_from_bytes(&certs, &certslen, &p, &certs_vector_len) != 1) { + error_print(); + tlcp_socket_alert(conn, TLS_alert_internal_error); + return -1; + } + + // 解析客户端证书 + if (tls_uint24array_from_bytes(&der, &derlen, &certs, &certslen) != 1 + || x509_certificate_from_der(client_cert, &der, &derlen) != 1) { + error_print(); + tlcp_socket_alert(conn, TLS_alert_bad_certificate); + return -1; + } + + return 1; +} + + +int tlcp_socket_read_client_cert_verify(TLCP_SOCKET_CONNECT *conn, + uint8_t *record, size_t *recordlen, + X509_CERTIFICATE *client_cert) { + + SM3_CTX tmp_sm3_ctx; + SM2_SIGN_CTX sign_ctx = {0}; + SM2_KEY *pub_key = &sign_ctx.key; + + uint8_t dgst[SM3_DIGEST_SIZE] = {0}; + uint8_t sig_vector[TLS_MAX_SIGNATURE_SIZE + 2] = {0}; // 签名向量 + const uint8_t *p = sig_vector; // 向量指针 + const uint8_t *sig = NULL; + size_t siglen = 0; + size_t sig_vector_len = 0; + + memcpy(&tmp_sm3_ctx, conn->_sm3_ctx, sizeof(SM3_CTX)); + sm3_finish(&tmp_sm3_ctx, dgst); + + if (tlcp_socket_record_recv(conn, record, recordlen) != 1 + || tls_record_version(record) != TLS_version_tlcp) { + error_print(); + return -1; + } + sm3_update(conn->_sm3_ctx, record + 5, *recordlen - 5); + + if (tls_record_get_handshake_certificate_verify(record, sig_vector, &sig_vector_len) != 1) { + error_print(); + return -1; + } + // 签名值是一个向量 + tls_uint16array_from_bytes(&sig, &siglen, &p, &sig_vector_len); + if (x509_certificate_get_public_key_sm2(client_cert, pub_key) != 1) { + error_print(); + tlcp_socket_alert(conn, TLS_alert_bad_certificate); + return -1; + } + /* + * from GBT38636 6.4.5.6 + * + * case ecc_sm3: // 当ECC为SM2算法时,用这个套件 + * digitally-signed struct{ + * opaque sm3_hash[32]; + * } + * sm3_hash 是指hash运行的结果,运算的内容时客户端hello消息开始 + * 直到本消息(不包括本消息)的所有与握手有关的消息,包括握手消息 + * 的类型和长度域。 + */ + sm2_verify_init(&sign_ctx, pub_key, SM2_DEFAULT_ID); + sm2_verify_update(&sign_ctx, dgst, SM3_DIGEST_SIZE); + if (sm2_verify_finish(&sign_ctx, sig, siglen) != 1) { + error_print(); + tlcp_socket_alert(conn, TLS_alert_handshake_failure); + return -1; + } + return 1; +} + +int tlcp_socket_send_records(TLCP_SOCKET_CONNECT *conn, const uint8_t *buff, size_t records_len) { + ssize_t r; + if ((r = send(conn->sock, buff, records_len, 0)) < 0) { + error_print(); + return -1; + } else if (r != records_len) { + error_print(); + return -1; + } + return 1; +} \ No newline at end of file diff --git a/src/tls.c b/src/tls.c index 94235c6..c7951f6 100644 --- a/src/tls.c +++ b/src/tls.c @@ -776,13 +776,14 @@ int tls_record_get_handshake_client_hello(const uint8_t *record, uint16_t cipher_suite; tls_uint16_from_bytes(&cipher_suite, &ciphers, &ciphers_len); if (!tls_cipher_suite_name(cipher_suite)) { - error_print(); - return -1; + // error_print(); + // return -1; + continue; } *cipher_suites++ = cipher_suite; (*cipher_suites_count)++; } - if (len > 0) { + if (len > 0 && exts != NULL) { if (*version < TLS_version_tls12) { error_print(); return -1; @@ -1465,9 +1466,9 @@ int tls_record_recv(uint8_t *record, size_t *recordlen, int sock) error_print(); return -1; } else if (r != 5) { - // FIXME: 如果对方已经中断连接,那么我们要判断这个错误吗? - error_print(); - perror(""); // 否则打印ioctl错误 + // 如果对方已经中断连接,那么认为是EOF不做处理,错误原因通过error.h接口获取 + // error_print(); + // perror(""); // 否则打印ioctl错误 return -1; } diff --git a/src/x509_algor.c b/src/x509_algor.c index 7dd41c5..b8c1a72 100644 --- a/src/x509_algor.c +++ b/src/x509_algor.c @@ -361,7 +361,6 @@ int x509_signature_algor_from_der(int *algor, uint32_t *nodes, size_t *nodes_cou int ret; const uint8_t *data; size_t datalen; - int has_null_obj; int i; if ((ret = asn1_sequence_from_der(&data, &datalen, in, inlen)) != 1) { @@ -377,7 +376,6 @@ int x509_signature_algor_from_der(int *algor, uint32_t *nodes, size_t *nodes_cou if (*nodes_count == x509_sign_algors[i].nodes_count && memcmp(nodes, x509_sign_algors[i].nodes, (*nodes_count) * sizeof(int)) == 0) { *algor = x509_sign_algors[i].algor; - has_null_obj = x509_sign_algors[i].has_params; break; } } @@ -386,10 +384,11 @@ int x509_signature_algor_from_der(int *algor, uint32_t *nodes, size_t *nodes_cou return -1; } - if (has_null_obj && asn1_null_from_der(&data, &datalen) != 1) { - error_print(); - return -1; - } + // 如果 在读取了algorithm 后还有剩余,那么尝试读取NULL,解决可选参数 parameters 为NULL的情况 + if (datalen > 0 && asn1_null_from_der(&data, &datalen) != 1) { + error_print(); + return -1; + } if (datalen) { error_print(); return -1; @@ -397,6 +396,79 @@ int x509_signature_algor_from_der(int *algor, uint32_t *nodes, size_t *nodes_cou return 1; } +int x509_signature_algor_null_to_der(int algor, int has_null_obj, uint8_t **out, size_t *outlen){ + size_t len = 0; + const uint32_t *nodes; + size_t nodes_count; + int i; + + for (i = 0; i < x509_sign_algors_count; i++) { + if (algor == x509_sign_algors[i].algor) { + nodes = x509_sign_algors[i].nodes; + nodes_count = x509_sign_algors[i].nodes_count; + break; + } + } + if (i >= x509_sign_algors_count) { + error_print(); + return -1; + } + + if (asn1_object_identifier_to_der(OID_undef, nodes, nodes_count, NULL, &len) != 1 + || (has_null_obj && asn1_null_to_der(NULL, &len) != 1) + || asn1_sequence_header_to_der(len, out, outlen) != 1 + || asn1_object_identifier_to_der(OID_undef, nodes, nodes_count, out, outlen) != 1 + || (has_null_obj && asn1_null_to_der(out, outlen) != 1)) { + error_print(); + return -1; + } + return 1; +} +int x509_signature_algor_null_from_der(int *algor, int *has_null_obj, uint32_t *nodes, size_t *nodes_count, + const uint8_t **in, size_t *inlen){ + int ret; + const uint8_t *data; + size_t datalen; + int i; + + if ((ret = asn1_sequence_from_der(&data, &datalen, in, inlen)) != 1) { + if (ret < 0) error_print(); + if (ret == 0) error_print(); + return ret; + } + if (asn1_object_identifier_from_der(algor, nodes, nodes_count, &data, &datalen) != 1) { + error_print(); + return -1; + } + for (i = 0; i < x509_sign_algors_count; i++) { + if (*nodes_count == x509_sign_algors[i].nodes_count + && memcmp(nodes, x509_sign_algors[i].nodes, (*nodes_count) * sizeof(int)) == 0) { + *algor = x509_sign_algors[i].algor; + break; + } + } + if (i >= x509_sign_algors_count) { + error_print(); + return -1; + } + + // 如果 在读取了algorithm 后还有剩余,那么尝试读取NULL,解决可选参数 parameters 为NULL的情况 + if (datalen > 0) { + if (asn1_null_from_der(&data, &datalen) == 1){ + *has_null_obj = 1; + }else{ + error_print(); + return -1; + } + } + + if (datalen) { + error_print(); + return -1; + } + return 1; +} + /* from rfc 3560: RSAES-OAEP-params ::= SEQUENCE { diff --git a/src/x509_asn1.c b/src/x509_asn1.c index 75624f8..062a342 100644 --- a/src/x509_asn1.c +++ b/src/x509_asn1.c @@ -338,14 +338,14 @@ static int x509_rdn_check(int oid, int tag, const char *str, int len) error_print(); return -1; } - if (x509_rdns[i].is_printable_string_only && tag != ASN1_TAG_PrintableString) { - error_print(); - return -1; - } - if (len < x509_rdns[i].minlen || len > x509_rdns[i].maxlen) { - error_print(); - return -1; - } +// if (x509_rdns[i].is_printable_string_only && tag != ASN1_TAG_PrintableString) { +// error_print(); +// return -1; +// } +// if (len < x509_rdns[i].minlen || len > x509_rdns[i].maxlen) { +// error_print(); +// return -1; +// } } } return 1; @@ -959,13 +959,13 @@ int x509_tbs_certificate_to_der(const X509_TBS_CERTIFICATE *a, uint8_t **out, si if (x509_version_to_der(a->version, NULL, &len) != 1 || asn1_integer_to_der(a->serial_number, a->serial_number_len, NULL, &len) != 1 - || x509_signature_algor_to_der(a->signature_algor, NULL, &len) != 1 + || x509_signature_algor_null_to_der(a->signature_algor.algorithm,a->signature_algor.has_null_obj, NULL, &len) != 1 || x509_name_to_der(&a->issuer, NULL, &len) != 1 || x509_validity_to_der(&a->validity, NULL, &len) != 1 || x509_name_to_der(&a->subject, NULL, &len) != 1 || x509_public_key_info_to_der(&a->subject_public_key_info, NULL, &len) != 1 - || asn1_implicit_bit_string_to_der(1, a->issuer_unique_id, a->issuer_unique_id_len * 8, NULL, &len) < 0 - || asn1_implicit_bit_string_to_der(2, a->subject_unique_id, a->subject_unique_id_len * 8, NULL, &len) <0 + || (a->issuer_unique_id_len && asn1_implicit_bit_string_to_der(1, a->issuer_unique_id, a->issuer_unique_id_len * 8, NULL, &len) < 0) + || (a->subject_unique_id_len && asn1_implicit_bit_string_to_der(2, a->subject_unique_id, a->subject_unique_id_len * 8, NULL, &len) <0) || x509_extensions_to_der(&a->extensions, NULL, &len) < 0) { error_print(); return -1; @@ -973,13 +973,13 @@ int x509_tbs_certificate_to_der(const X509_TBS_CERTIFICATE *a, uint8_t **out, si if (asn1_sequence_header_to_der(len, out, outlen) != 1 || x509_version_to_der(a->version, out, outlen) != 1 || asn1_integer_to_der(a->serial_number, a->serial_number_len, out, outlen) != 1 - || x509_signature_algor_to_der(a->signature_algor, out, outlen) != 1 + || x509_signature_algor_null_to_der(a->signature_algor.algorithm,a->signature_algor.has_null_obj, out, outlen) != 1 || x509_name_to_der(&a->issuer, out, outlen) != 1 || x509_validity_to_der(&a->validity, out, outlen) != 1 || x509_name_to_der(&a->subject, out, outlen) != 1 || x509_public_key_info_to_der(&a->subject_public_key_info, out, outlen) != 1 - || asn1_implicit_bit_string_to_der(1, a->issuer_unique_id, a->issuer_unique_id_len * 8, out, outlen) < 0 - || asn1_implicit_bit_string_to_der(2, a->subject_unique_id, a->subject_unique_id_len * 8, out, outlen) < 0 + || (a->issuer_unique_id_len && asn1_implicit_bit_string_to_der(1, a->issuer_unique_id, a->issuer_unique_id_len * 8, out, outlen) < 0) + || (a->subject_unique_id_len && asn1_implicit_bit_string_to_der(2, a->subject_unique_id, a->subject_unique_id_len * 8, out, outlen) < 0) || x509_extensions_to_der(&a->extensions, out, outlen) < 0) { error_print(); return -1; @@ -1015,7 +1015,7 @@ int x509_tbs_certificate_from_der(X509_TBS_CERTIFICATE *a, const uint8_t **in, s if (x509_version_from_der(&a->version, &data, &datalen) != 1 || asn1_integer_from_der(&serial_number, &a->serial_number_len, &data, &datalen) != 1 - || x509_signature_algor_from_der(&a->signature_algor, nodes, &nodes_count, &data, &datalen) != 1 + || x509_signature_algor_null_from_der(&(a->signature_algor.algorithm), &(a->signature_algor.has_null_obj), nodes, &nodes_count, &data, &datalen) != 1 || x509_name_from_der(&a->issuer, &data, &datalen) != 1 || x509_validity_from_der(&a->validity, &data, &datalen) != 1 || x509_name_from_der(&a->subject, &data, &datalen) != 1 @@ -1027,33 +1027,20 @@ int x509_tbs_certificate_from_der(X509_TBS_CERTIFICATE *a, const uint8_t **in, s error_print(); return -1; } - - // FIXME: 应该提供了检查函数,可以返回错误行数 - if (a->serial_number_len > 20 - || issuer_unique_id_nbits != 32 * 8 - || subject_unique_id_nbits != 32 * 8) { - - error_print(); - return -1; - } - - a->issuer_unique_id_len = issuer_unique_id_nbits/8; - a->subject_unique_id_len = subject_unique_id_nbits/8; - - - // asn1_implicit_bit_string_from_der 返回的是比特长度! - // 应该改变 issue - - - // FIXME: 这几个都应该用copy的方式 - memcpy(a->serial_number, serial_number, a->serial_number_len); - if (issuer_unique_id) { - memcpy(a->issuer_unique_id, issuer_unique_id, a->issuer_unique_id_len); - } - if (subject_unique_id) { - memcpy(a->subject_unique_id, subject_unique_id, a->subject_unique_id_len); - } - + // asn1_implicit_bit_string_from_der 返回的是比特长度! + memcpy(a->serial_number, serial_number, a->serial_number_len); + if (issuer_unique_id_nbits > 0){ + a->issuer_unique_id_len = issuer_unique_id_nbits/8; + if (issuer_unique_id) { + memcpy(a->issuer_unique_id, issuer_unique_id, a->issuer_unique_id_len); + } + } + if (subject_unique_id_nbits > 0){ + a->subject_unique_id_len = subject_unique_id_nbits/8; + if (subject_unique_id) { + memcpy(a->subject_unique_id, subject_unique_id, a->subject_unique_id_len); + } + } return 1; } @@ -1159,7 +1146,7 @@ int x509_certificate_print(FILE *fp, const X509_CERTIFICATE *a, int format, int indent += 4; format_print(fp, format, indent, "Version : %s (%d)\n", x509_version_name(tbs->version), tbs->version); format_bytes(fp, format, indent, "SerialNumber : ", tbs->serial_number, tbs->serial_number_len); - format_print(fp, format, indent, "SigantureAlgorithm : %s\n", asn1_object_identifier_name(tbs->signature_algor)); + format_print(fp, format, indent, "SigantureAlgorithm : %s\n", asn1_object_identifier_name(tbs->signature_algor.algorithm)); format_print(fp, format, indent, "Issuer\n"); x509_name_print(fp, &tbs->issuer, format, indent + 4); format_print(fp, format, indent, "Validity\n"); diff --git a/src/x509_lib.c b/src/x509_lib.c index c4f3188..9dd7bec 100644 --- a/src/x509_lib.c +++ b/src/x509_lib.c @@ -61,6 +61,8 @@ #include #include #include +#include +#include #include @@ -88,7 +90,7 @@ int x509_certificate_set_serial_number(X509_CERTIFICATE *cert, const uint8_t *sn int x509_certificate_set_signature_algor_sm2(X509_CERTIFICATE *cert) { - cert->tbs_certificate.signature_algor = OID_sm2sign_with_sm3; + cert->tbs_certificate.signature_algor.algorithm = OID_sm2sign_with_sm3; cert->signature_algor = OID_sm2sign_with_sm3; return 1; } @@ -116,7 +118,7 @@ int x509_certificate_set_validity(X509_CERTIFICATE *cert, time_t not_before, int int x509_certificate_set_signature_algor(X509_CERTIFICATE *cert, int oid) { - cert->tbs_certificate.signature_algor = oid; + cert->tbs_certificate.signature_algor.algorithm = oid; return 1; } @@ -238,3 +240,42 @@ int x509_certificate_from_pem_by_name(X509_CERTIFICATE *cert, FILE *fp, const X5 } return 0; } + +// 从字节串中解析X509数字证书,支持Base64、Hex、PEM、DER +int x509_certificate_from_bytes(X509_CERTIFICATE *a, const uint8_t *in, size_t inlen) { + uint8_t der[1024]; + const uint8_t *cp = der; + + size_t der_len = 0; + int len = 0; + + const char start_line[] = "-----BEGIN CERTIFICATE-----"; + + if (in == NULL || inlen == 0) { + return -1; + } + // 尝试1 DER ASN1 Sequence 格式 + // Class: 0, P/C=C(1) tag: 0x10 => 30 (SEQUENCE) + if ((in[0] & 0xFF) == 0x30) { + return x509_certificate_from_der(a, &in, &inlen); + } + + // 尝试2 PEM格式 + if (strncmp((const char *) in, start_line, strlen(start_line)) == 0) { + if (pem_read_str((uint8_t *) in, inlen, "CERTIFICATE", der, &der_len) == 1) { + return x509_certificate_from_der(a, &cp, &der_len); + } + } + // 尝试3 Base64格式 + len = (int)der_len; + if (base64_str_decode(in, (int)inlen, der, &len) == 0) { + der_len = len; + return x509_certificate_from_der(a, &cp, &der_len); + } + // 尝试4 Hex格式 + if (hex_to_bytes((const char *) in, inlen, der, &der_len) != -1 ){ + return x509_certificate_from_der(a, &cp, &der_len); + } + // 上述手段都无法解码 + return -1; +} \ No newline at end of file diff --git a/tests/base64test.c b/tests/base64test.c index 97b0c69..4e4735b 100644 --- a/tests/base64test.c +++ b/tests/base64test.c @@ -94,9 +94,25 @@ int test_base64(void) return err; } +int test_base64_str_decode(void){ + const uint8_t str[] = "MIIBszCCAVegAwIBAgIIaeL+wBcKxnswDAYIKoEcz1UBg3UFADAuMQswCQYDVQQGEwJDTjEOMAwGA1UECgwFTlJDQUMxDzANBgNVBAMMBlJPT1RDQTAeFw0xMjA3MTQwMzExNTlaFw00MjA3MDcwMzExNTlaMC4xCzAJBgNVBAYTAkNOMQ4wDAYDVQQKDAVOUkNBQzEPMA0GA1UEAwwGUk9PVENBMFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAEMPCca6pmgcchsTf2UnBeL9rtp4nw+itk1Kzrmbnqo05lUwkwlWK+4OIrtFdAqnRTV7Q9v1htkv42TsIutzd126NdMFswHwYDVR0jBBgwFoAUTDKxl9kzG8SmBcHG5YtiW/CXdlgwDAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMCAQYwHQYDVR0OBBYEFEwysZfZMxvEpgXBxuWLYlvwl3ZYMAwGCCqBHM9VAYN1BQADSAAwRQIgG1bSLeOXp3oB8H7b53W+CKOPl2PknmWEq/lMhtn25HkCIQDaHDgWxWFtnCrBjH16/W3Ezn7/U/Vjo5xIpDoiVhsLwg=="; + uint8_t buf[1024]; + int len; + int ret = 0; + + ret = base64_str_decode(str, strlen(str), buf,&len); + if (ret != 0){ + error_puts("无法解析BASE64字符串"); + return -1; + } + printf("expect len = 439, actual len = %d\n", len); + print_bytes(buf, len); + return 0; +} int main(void) { test_base64(); + test_base64_str_decode(); return 0; } diff --git a/tests/pemtest.c b/tests/pemtest.c index e69de29..92931c6 100644 --- a/tests/pemtest.c +++ b/tests/pemtest.c @@ -0,0 +1,41 @@ +#include +#include +#include +#include +#include + +static uint8_t str[] = "-----BEGIN CERTIFICATE-----\n\ +MIIBszCCAVegAwIBAgIIaeL+wBcKxnswDAYIKoEcz1UBg3UFADAuMQswCQYDVQQG\n\ +EwJDTjEOMAwGA1UECgwFTlJDQUMxDzANBgNVBAMMBlJPT1RDQTAeFw0xMjA3MTQw\n\ +MzExNTlaFw00MjA3MDcwMzExNTlaMC4xCzAJBgNVBAYTAkNOMQ4wDAYDVQQKDAVO\n\ +UkNBQzEPMA0GA1UEAwwGUk9PVENBMFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAE\n\ +MPCca6pmgcchsTf2UnBeL9rtp4nw+itk1Kzrmbnqo05lUwkwlWK+4OIrtFdAqnRT\n\ +V7Q9v1htkv42TsIutzd126NdMFswHwYDVR0jBBgwFoAUTDKxl9kzG8SmBcHG5Yti\n\ +W/CXdlgwDAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMCAQYwHQYDVR0OBBYEFEwysZfZ\n\ +MxvEpgXBxuWLYlvwl3ZYMAwGCCqBHM9VAYN1BQADSAAwRQIgG1bSLeOXp3oB8H7b\n\ +53W+CKOPl2PknmWEq/lMhtn25HkCIQDaHDgWxWFtnCrBjH16/W3Ezn7/U/Vjo5xI\n\ +pDoiVhsLwg==\n\ +-----END CERTIFICATE-----"; + + +int main(int argc, char **argv) { + int ret = 0; + uint8_t buf[1024]; + const uint8_t *cp = buf; + size_t len = 0; + + X509_CERTIFICATE a; + memset(buf,0, 1024); + ret = pem_read_str(str, strlen(str), "CERTIFICATE", buf, &len); + if (ret != 1){ + error_print(); + return -1; + } +// print_der(buf, len); + ret = x509_certificate_from_der(&a, &cp, &len); + if (ret != 1){ + error_print(); + return -1; + } + x509_certificate_print(stderr, &a, 0, 0); +} \ No newline at end of file diff --git a/tests/sm2asn1test.c b/tests/sm2asn1test.c index c041940..f4eb998 100644 --- a/tests/sm2asn1test.c +++ b/tests/sm2asn1test.c @@ -51,130 +51,198 @@ #include #include #include +#include #include +#include + + +static int test_sm2_point_octets(void) { + int err = 0; + SM2_KEY sm2_key; + SM2_POINT point; + uint8_t buf[65]; + int i; + + // compress + for (i = 0; i < 8; i++) { + uint8_t buf[33]; + sm2_keygen(&sm2_key); + sm2_point_to_compressed_octets(&sm2_key.public_key, buf); + if (sm2_point_from_octets(&point, buf, sizeof(buf)) != 1) { + error_print(); + err++; + break; + } + if (memcmp(&sm2_key.public_key, &point, sizeof(SM2_POINT)) != 0) { + error_print(); + err++; + break; + } + } + + // uncompress + for (i = 0; i < 8; i++) { + uint8_t buf[65]; + sm2_keygen(&sm2_key); + sm2_point_to_uncompressed_octets(&sm2_key.public_key, buf); + if (sm2_point_from_octets(&point, buf, sizeof(buf)) != 1) { + error_print(); + err++; + break; + } + if (memcmp(&sm2_key.public_key, &point, sizeof(SM2_POINT)) != 0) { + error_print(); + err++; + break; + } + } + + printf("%s : %s\n", __func__, err ? "failed" : "ok"); + return err; +} - -static int test_sm2_point_octets(void) -{ - int err = 0; - SM2_KEY sm2_key; - SM2_POINT point; - uint8_t buf[65]; - int i; - - // compress - for (i = 0; i < 8; i++) { - uint8_t buf[33]; - sm2_keygen(&sm2_key); - sm2_point_to_compressed_octets(&sm2_key.public_key, buf); - if (sm2_point_from_octets(&point, buf, sizeof(buf)) != 1) { - error_print(); - err++; - break; - } - if (memcmp(&sm2_key.public_key, &point, sizeof(SM2_POINT)) != 0) { - error_print(); - err++; - break; - } - } - - // uncompress - for (i = 0; i < 8; i++) { - uint8_t buf[65]; - sm2_keygen(&sm2_key); - sm2_point_to_uncompressed_octets(&sm2_key.public_key, buf); - if (sm2_point_from_octets(&point, buf, sizeof(buf)) != 1) { - error_print(); - err++; - break; - } - if (memcmp(&sm2_key.public_key, &point, sizeof(SM2_POINT)) != 0) { - error_print(); - err++; - break; - } - } - - printf("%s : %s\n", __func__, err ? "failed" : "ok"); - return err; +static int test_sm2_private_key(void) { + int err = 0; + SM2_KEY sm2_key; + SM2_KEY sm2_tmp; + uint8_t buf[256]; + uint8_t *p = buf; + const uint8_t *cp = buf; + size_t len = 0; + + + sm2_keygen(&sm2_key); + + if (sm2_private_key_to_der(&sm2_key, &p, &len) != 1) { + error_print(); + err++; + goto end; + } + if (sm2_private_key_from_der(&sm2_tmp, &cp, &len) != 1 + || len > 0) { + error_print(); + err++; + goto end; + } + // 比较密钥字段移除密钥用法部分 + if (memcmp(&sm2_tmp, &sm2_key, sizeof(SM2_KEY)-4) != 0) { + error_print(); + err++; + goto end; + } + + printf("%s : ok\n", __func__); + end: + return err; } -static int test_sm2_private_key(void) -{ - int err = 0; - SM2_KEY sm2_key; - SM2_KEY sm2_tmp; - uint8_t buf[256]; - uint8_t *p = buf; - const uint8_t *cp = buf; - size_t len = 0; - - - sm2_keygen(&sm2_key); - - if (sm2_private_key_to_der(&sm2_key, &p, &len) != 1) { - error_print(); - err++; - goto end; - } - if (sm2_private_key_from_der(&sm2_tmp, &cp, &len) != 1 - || len > 0) { - error_print(); - err++; - goto end; - } - if (memcmp(&sm2_tmp, &sm2_key, sizeof(SM2_KEY)) != 0) { - error_print(); - err++; - goto end; - } - - printf("%s : ok\n", __func__); -end: - return err; +static int test_sm2_public_key_info(void) { + int err = 0; + SM2_KEY sm2_key; + SM2_KEY sm2_tmp; + uint8_t buf[256]; + uint8_t *p = buf; + const uint8_t *cp = buf; + size_t len = 0; + + sm2_keygen(&sm2_key); + + if (sm2_public_key_info_to_der(&sm2_key, &p, &len) != 1) { + error_print(); + err++; + goto end; + } + if (sm2_public_key_info_from_der(&sm2_tmp, &cp, &len) != 1 + || len > 0) { + error_print(); + err++; + goto end; + } + if (memcmp(&sm2_key.public_key, &sm2_tmp.public_key, sizeof(SM2_POINT)) != 0) { + error_print(); + err++; + goto end; + } + printf("%s : ok\n", __func__); + end: + return err; } -static int test_sm2_public_key_info(void) -{ - int err = 0; - SM2_KEY sm2_key; - SM2_KEY sm2_tmp; - uint8_t buf[256]; - uint8_t *p = buf; - const uint8_t *cp = buf; - size_t len = 0; - - sm2_keygen(&sm2_key); - - if (sm2_public_key_info_to_der(&sm2_key, &p, &len) != 1) { - error_print(); - err++; - goto end; - } - if (sm2_public_key_info_from_der(&sm2_tmp, &cp, &len) != 1 - || len > 0) { - error_print(); - err++; - goto end; - } - if (memcmp(&sm2_key.public_key, &sm2_tmp.public_key, sizeof(SM2_POINT)) != 0) { - error_print(); - err++; - goto end; - } - printf("%s : ok\n", __func__); -end: - return err; +static void test_sm2_parse_pkcs8__private_key(void) { + uint8_t str[] = "-----BEGIN EC PRIVATE KEY-----\n\ +MIGTAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBHkwdwIBAQQgmfgsjOI+jhOcwu7f\n\ +Cy6PYSYBmjAzTijLaJicJorUEsmgCgYIKoEcz1UBgi2hRANCAAQJTFguoSNb/TEX\n\ +XwY1w3Xw+79W3YFg3JWQlJVx2FZmzWuT8x6aIeiciv0wuwuaYfocUC3OHwkRKqhf\n\ +CkPArdH2\n\ +-----END EC PRIVATE KEY-----"; + uint8_t buf[1024]; + const uint8_t *cp = buf; + size_t len = 0; + SM2_KEY key; + + if (pem_read_str(str, strlen(str), "EC PRIVATE KEY", buf, &len) != 1) { + error_puts("无法解析PEM"); + goto end; + } + + if (sm2_private_key_from_pkcs8_der(&key, &cp, &len) != 1) { + error_puts("PKCS8解码失败"); + goto end; + } + printf("%s : ok\n", __func__); + end: + return; } +static void test_sm2_ciphertext_to_der() { + // X 长度不足32字节,含有前置一个字节的00 + uint8_t x_str[] = "00ABD5FD079006A141C605B44455027B311B453E3A24FEDD16B5446C83567B99"; + // Y 32字节元素 + uint8_t y_str[] = "B8ACFE0E01D5E8B1513F32E29F6A6B0CEA967CC6ED3860EE4A5A4785EBC32D47"; + uint8_t expect_str[] = "\ +3069022000ABD5FD079006A141C605B44455027B311B453E3A24FEDD16B5446C\ +83567B99022100B8ACFE0E01D5E8B1513F32E29F6A6B0CEA967CC6ED3860EE4A\ +5A4785EBC32D4704200000000000000000000000000000000000000000000000\ +0000000000000000000400"; + + int i = 0; + size_t clen = SM2_CIPHERTEXT_SIZE(32); + size_t cbuf[clen]; + SM2_CIPHERTEXT *c = (SM2_CIPHERTEXT *) cbuf; + + + memset(cbuf, 0, clen); + + uint8_t expect[128] = {0}; + uint8_t out[256] = {0}; + size_t outlen = 0; + uint8_t *p = out; + + hex2bin(x_str, strlen(x_str), c->point.x); + hex2bin(y_str, strlen(y_str), c->point.y); + hex2bin(expect_str, strlen(expect_str), expect); + + sm2_ciphertext_to_der(c, &p, &outlen); + + if (memcmp(out, expect, outlen) != 0) { + printf("Expect:\n"); + print_bytes(expect, outlen); + printf("Actual:\n"); + print_bytes(out, outlen); + } else { + printf("%s : ok\n", __func__); + } +} -int main(void) -{ - test_sm2_point_octets(); - test_sm2_private_key(); - test_sm2_public_key_info(); - return 0; +int main(void) { + test_sm2_point_octets(); + test_sm2_private_key(); + test_sm2_public_key_info(); + test_sm2_parse_pkcs8__private_key(); + test_sm2_ciphertext_to_der(); + return 0; } + + diff --git a/tests/tlcpsockettest.c b/tests/tlcpsockettest.c new file mode 100644 index 0000000..16a1b32 --- /dev/null +++ b/tests/tlcpsockettest.c @@ -0,0 +1,378 @@ +#include +#include +#include +#include +#include +#include + + +static const uint8_t rootca_str[] = "-----BEGIN CERTIFICATE-----\n\ +MIIBszCCAVegAwIBAgIIaeL+wBcKxnswDAYIKoEcz1UBg3UFADAuMQswCQYDVQQG\n\ +EwJDTjEOMAwGA1UECgwFTlJDQUMxDzANBgNVBAMMBlJPT1RDQTAeFw0xMjA3MTQw\n\ +MzExNTlaFw00MjA3MDcwMzExNTlaMC4xCzAJBgNVBAYTAkNOMQ4wDAYDVQQKDAVO\n\ +UkNBQzEPMA0GA1UEAwwGUk9PVENBMFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAE\n\ +MPCca6pmgcchsTf2UnBeL9rtp4nw+itk1Kzrmbnqo05lUwkwlWK+4OIrtFdAqnRT\n\ +V7Q9v1htkv42TsIutzd126NdMFswHwYDVR0jBBgwFoAUTDKxl9kzG8SmBcHG5Yti\n\ +W/CXdlgwDAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMCAQYwHQYDVR0OBBYEFEwysZfZ\n\ +MxvEpgXBxuWLYlvwl3ZYMAwGCCqBHM9VAYN1BQADSAAwRQIgG1bSLeOXp3oB8H7b\n\ +53W+CKOPl2PknmWEq/lMhtn25HkCIQDaHDgWxWFtnCrBjH16/W3Ezn7/U/Vjo5xI\n\ +pDoiVhsLwg==\n\ +-----END CERTIFICATE-----"; + +static uint8_t cacert_str[] = "-----BEGIN CERTIFICATE-----\n\ +MIIB3jCCAYOgAwIBAgIIAs4MAPwpIBcwCgYIKoEcz1UBg3UwQjELMAkGA1UEBhMC\n\ +Q04xDzANBgNVBAgMBua1meaxnzEPMA0GA1UEBwwG5p2t5beeMREwDwYDVQQKDAjm\n\ +tYvor5VDQTAeFw0yMTEyMjMwODQ4MzNaFw0zMTEyMjMwODQ4MzNaMEIxCzAJBgNV\n\ +BAYTAkNOMQ8wDQYDVQQIDAbmtZnmsZ8xDzANBgNVBAcMBuadreW3njERMA8GA1UE\n\ +CgwI5rWL6K+VQ0EwWTATBgcqhkjOPQIBBggqgRzPVQGCLQNCAARKs6B5ZBy753Os\n\ +ZSeIfv8zScbiiXkLjB+Plw+YWvoesRkqYGe/Mqjr8rrmThq6iEWubYK6ZiQQV54k\n\ +Klcva3Hto2MwYTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV\n\ +HQ4EFgQUNpPjFOdFCfrV7+ovEi3ToZY8wqQwHwYDVR0jBBgwFoAUNpPjFOdFCfrV\n\ +7+ovEi3ToZY8wqQwCgYIKoEcz1UBg3UDSQAwRgIhALDhtLKVziUhXbTedDovRANS\n\ +Cdu6CJ0MAw7Wbl3vAWGOAiEAzCXLcF32DM5Aze9MqpUfQfYPaRTLYkNwSXlw/LUY\n\ +E6E=\n\ +-----END CERTIFICATE-----"; + +static uint8_t sigcert_str[] = "-----BEGIN CERTIFICATE-----\n\ +MIICHTCCAcSgAwIBAgIIAs4MDJsDUfcwCgYIKoEcz1UBg3UwQjELMAkGA1UEBhMC\n\ +Q04xDzANBgNVBAgMBua1meaxnzEPMA0GA1UEBwwG5p2t5beeMREwDwYDVQQKDAjm\n\ +tYvor5VDQTAeFw0yMTEyMjgwNzU4MDdaFw0yMjEyMjgwNzU4MDdaMHExCzAJBgNV\n\ +BAYTAkNOMQ8wDQYDVQQIDAbmtZnmsZ8xDzANBgNVBAcMBuadreW3njEPMA0GA1UE\n\ +CgwG5rWL6K+VMRUwEwYDVQQLDAzmtYvor5Xpg6jpl6gxGDAWBgNVBAMMD+a1i+iv\n\ +leacjeWKoeWZqDBZMBMGByqGSM49AgEGCCqBHM9VAYItA0IABAlMWC6hI1v9MRdf\n\ +BjXDdfD7v1bdgWDclZCUlXHYVmbNa5PzHpoh6JyK/TC7C5ph+hxQLc4fCREqqF8K\n\ +Q8Ct0fajdTBzMA4GA1UdDwEB/wQEAwIGwDATBgNVHSUEDDAKBggrBgEFBQcDATAM\n\ +BgNVHRMBAf8EAjAAMB0GA1UdDgQWBBRVnXu8fDpWLji6+B4agt+UjtenVTAfBgNV\n\ +HSMEGDAWgBQ2k+MU50UJ+tXv6i8SLdOhljzCpDAKBggqgRzPVQGDdQNHADBEAiAC\n\ +cFef0JAGpBPlrUZLf56fLEGQx5ifSqBZJ9qTANAAfwIgM/nrEqeO7Scjzn9dFFRk\n\ +Yf4zl0ev+DBFoMBySPj4SIk=\n\ +-----END CERTIFICATE-----"; + +static uint8_t enccert_str[] = "-----BEGIN CERTIFICATE-----\n\ +MIICHTCCAcSgAwIBAgIIAs4MDJsDWYcwCgYIKoEcz1UBg3UwQjELMAkGA1UEBhMC\n\ +Q04xDzANBgNVBAgMBua1meaxnzEPMA0GA1UEBwwG5p2t5beeMREwDwYDVQQKDAjm\n\ +tYvor5VDQTAeFw0yMTEyMjgwNzU4MDdaFw0yMjEyMjgwNzU4MDdaMHExCzAJBgNV\n\ +BAYTAkNOMQ8wDQYDVQQIDAbmtZnmsZ8xDzANBgNVBAcMBuadreW3njEPMA0GA1UE\n\ +CgwG5rWL6K+VMRUwEwYDVQQLDAzmtYvor5Xpg6jpl6gxGDAWBgNVBAMMD+a1i+iv\n\ +leacjeWKoeWZqDBZMBMGByqGSM49AgEGCCqBHM9VAYItA0IABAjaZJ4zeudYfvQ+\n\ +d5PscKx116VQBzLtYzFcQKPeI8DXis2rDdT7BrGa8ixdF1iatD+TyT5kmMz4Jf1G\n\ +6QNNYeKjdTBzMA4GA1UdDwEB/wQEAwIDODATBgNVHSUEDDAKBggrBgEFBQcDATAM\n\ +BgNVHRMBAf8EAjAAMB0GA1UdDgQWBBQChe9/DMXc8kGC84j8FW4Nkb41uTAfBgNV\n\ +HSMEGDAWgBQ2k+MU50UJ+tXv6i8SLdOhljzCpDAKBggqgRzPVQGDdQNHADBEAiAh\n\ +MIuWxdAQ71kwT95+0fvm9VuuCOpusHgbDWJanyZBnAIgTIXAkehTXPLYXjYJ/uVE\n\ +4DdAQJFVrWNugK3eiDgECMc=\n\ +-----END CERTIFICATE-----"; + +static uint8_t client_cert_str[] = "-----BEGIN CERTIFICATE-----\n\ +MIICADCCAaWgAwIBAgIIAs5czZZPpv4wCgYIKoEcz1UBg3UwQjELMAkGA1UEBhMC\n\ +Q04xDzANBgNVBAgMBua1meaxnzEPMA0GA1UEBwwG5p2t5beeMREwDwYDVQQKDAjm\n\ +tYvor5VDQTAeFw0yMjAxMDcwNTM4MTBaFw0yMzAxMDcwNTM4MTBaMGcxCzAJBgNV\n\ +BAYTAkNOMQ8wDQYDVQQIDAbmtZnmsZ8xDzANBgNVBAcMBuadreW3njEPMA0GA1UE\n\ +CgwG5rWL6K+VMQ8wDQYDVQQLDAbmtYvor5UxFDASBgNVBAMMC+WuouaIt+errzAx\n\ +MFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAEfjd+8UWsZh/mOtbOV7vtCwJCqSda\n\ +abwljsV6mZH7Ugbp7Zx3nTRGE0L2WXGQaOe/78Ph2kErp/WGrJUNRVUbwaNgMF4w\n\ +DgYDVR0PAQH/BAQDAgbAMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFBiDmyfgvxB7\n\ +TeH0OZez3Cod88iaMB8GA1UdIwQYMBaAFDaT4xTnRQn61e/qLxIt06GWPMKkMAoG\n\ +CCqBHM9VAYN1A0kAMEYCIQDxELAl+/+puw6/qp9D8ZzwtqXw9W3YKOGS1zRVzJJF\n\ +VQIhAOMUyOxCdqvM0xwh9QyfPunnzOzKa4HP3RrFDxDqXYC/\n\ +-----END CERTIFICATE-----"; + +static uint8_t sigkey_str[] = "-----BEGIN EC PRIVATE KEY-----\n\ +MIGTAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBHkwdwIBAQQgmfgsjOI+jhOcwu7f\n\ +Cy6PYSYBmjAzTijLaJicJorUEsmgCgYIKoEcz1UBgi2hRANCAAQJTFguoSNb/TEX\n\ +XwY1w3Xw+79W3YFg3JWQlJVx2FZmzWuT8x6aIeiciv0wuwuaYfocUC3OHwkRKqhf\n\ +CkPArdH2\n\ +-----END EC PRIVATE KEY-----"; + +static uint8_t enckey_str[] = "-----BEGIN EC PRIVATE KEY-----\n\ +MIGTAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBHkwdwIBAQQgBdQfH874+gihD5WM\n\ +q2UGdLWzXoVEANZ+nShGd7aW8OegCgYIKoEcz1UBgi2hRANCAAQI2mSeM3rnWH70\n\ +PneT7HCsddelUAcy7WMxXECj3iPA14rNqw3U+waxmvIsXRdYmrQ/k8k+ZJjM+CX9\n\ +RukDTWHi\n\ +-----END EC PRIVATE KEY-----"; + +static uint8_t client_key_str[] = "-----BEGIN PRIVATE KEY-----\n\ +MIGTAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBHkwdwIBAQQgcuCN3FyCvaM+XZ9L\n\ +xBdBYxtPPBT6Zcb22c5Ho5EiD9agCgYIKoEcz1UBgi2hRANCAAR+N37xRaxmH+Y6\n\ +1s5Xu+0LAkKpJ1ppvCWOxXqZkftSBuntnHedNEYTQvZZcZBo57/vw+HaQSun9Yas\n\ +lQ1FVRvB\n\ +-----END PRIVATE KEY-----"; + + +static X509_CERTIFICATE cacert; +static X509_CERTIFICATE rootcert; +static X509_CERTIFICATE sigcert; +static X509_CERTIFICATE enccert; +static X509_CERTIFICATE client_cert; +static SM2_KEY sigkey; +static SM2_KEY enckey; +static SM2_KEY client_key; + +/** + * 加载测试用使用的证书和密钥对 + */ +static int load_cert_keys(); + +/** + * TLCP服务器 HTTP测试 + */ +static void handle_http(TLCP_SOCKET_CONNECT *conn); + +/** + * TLCP服务器 回音测试 + */ +static void handle_echo(TLCP_SOCKET_CONNECT *conn); + +/** + * TLCP客户端 连接读写回音测试 + */ +static void client_conn_test(); + +/** + * TLCP客户端 双向身份认证测试 + */ +static void client_auth_test(); + +/** + * 运行TLCP服务端 + */ +static void server_test(); + +int main(void) { + // 加载证书和相关密钥 + if (load_cert_keys() != 1) { + error_puts("cert and key load fail."); + return 1; + } + server_test(); +// client_conn_test(); +// client_auth_test(); + + return 1; +} + +static void server_test() { + TLCP_SOCKET_CONFIG config = {0}; + TLCP_SOCKET_Listener ln = {0}; + TLCP_SOCKET_KEY socket_sigkey = {0}; + TLCP_SOCKET_KEY socket_enckey = {0}; + TLCP_SOCKET_CONNECT conn = {0}; + + // 创建SOCKET使用的密钥对 + if (TLCP_SOCKET_GMSSL_Key(&socket_sigkey, &sigcert, &sigkey) != 1) { + error_puts("sig key create fail."); + return; + } + if (TLCP_SOCKET_GMSSL_Key(&socket_enckey, &enccert, &enckey) != 1) { + error_puts("enc key create fail."); + return; + } + // 初始化上下文 + config.rand = rand_bytes; + config.server_sig_key = &socket_sigkey; + config.server_enc_key = &socket_enckey; + + /* 配置根证书表示需要对客户端进行身份认证 */ + /* 多个根证书 */ + X509_CERTIFICATE roots[] = {cacert, rootcert}; + config.root_certs = roots; + config.root_cert_len = 2; + + // 打开端口监听TLCP连接 + if (TLCP_SOCKET_Listen(&config, &ln, 30443) != 1) { + perror("TLCP server listen fail"); + return; + } + for (;;) { + if (TLCP_SOCKET_Accept(&ln, &conn) != 1) { + perror("TLCP server Accept fail"); + return; + } +// handle_http(&conn); + handle_echo(&conn); + TLCP_SOCKET_Connect_Close(&conn); + } + // 关闭连接 + TLCP_SOCKET_Close(&ln); +} + + +static void handle_echo(TLCP_SOCKET_CONNECT *conn) { + ssize_t n = 0; + uint8_t buf[TLS_MAX_RECORD_SIZE] = {0}; + + n = sizeof(buf); + for (;;) { + if ((n = TLCP_SOCKET_Read(conn, buf, n)) < 0) { + // error_print(); + break; + } + if ((n = TLCP_SOCKET_Write(conn, buf, n)) < 0) { + // error_print(); + break; + } + } +} + +static void handle_http(TLCP_SOCKET_CONNECT *conn) { + size_t n = 0; + uint8_t buf[TLS_MAX_RECORD_SIZE] = {0}; + uint8_t resp[] = "HTTP/1.1 200 OK\r\n\ +Content-Length: 6\r\n\ +Content-Type: text/plain; charset=utf-8\r\n\ +\r\n\ +Hello!"; + + n = sizeof(buf); + if ((n = TLCP_SOCKET_Read(conn, buf, n)) < 0) { + error_print(); + return; + } + printf("%s\n", buf); + if ((n = TLCP_SOCKET_Write(conn, resp, sizeof(resp))) < 0) { + error_print(); + return; + } +} + +static int load_cert_keys() { + if (x509_certificate_from_bytes(&rootcert, rootca_str, strlen(rootca_str)) != 1) { + error_print(); + return -1; + } + if (x509_certificate_from_bytes(&cacert, cacert_str, strlen(cacert_str)) != 1) { + error_print(); + return -1; + } + if (x509_certificate_from_bytes(&sigcert, sigcert_str, strlen(sigcert_str)) != 1) { + error_print(); + return -1; + } + if (x509_certificate_from_bytes(&enccert, enccert_str, strlen(enccert_str)) != 1) { + error_print(); + return -1; + } + if (x509_certificate_from_bytes(&client_cert, client_cert_str, strlen(client_cert_str)) != 1) { + error_print(); + return -1; + } + if (sm2_private_key_from_str_pem(&sigkey, sigkey_str, strlen(sigkey_str)) != 1) { + error_print(); + return -1; + } + if (sm2_private_key_from_str_pem(&enckey, enckey_str, strlen(enckey_str)) != 1) { + error_print(); + return -1; + } + if (sm2_private_key_from_str_pem(&client_key, client_key_str, strlen(client_key_str)) != 1) { + error_print(); + return -1; + } + return 1; +} + +#define BUFFER_SIZE 4096 + + +static void client_conn_test() { + TLCP_SOCKET_CONFIG config = {0}; + TLCP_SOCKET_CONNECT conn = {0}; + int ret = 1; + uint8_t send[BUFFER_SIZE] = {0}; + uint8_t recv[BUFFER_SIZE] = {0}; + size_t n = BUFFER_SIZE; + size_t rd = 0; + uint8_t *p = 0; + + config.root_certs = &cacert; + config.root_cert_len = 1; + errno = 0; + + // 拨号连接服务端 + ret = TLCP_SOCKET_Dial(&config, &conn, "127.0.0.1", 30443); + if (ret != 1) { + error_print(); + return; + } + for (;;) { + n = BUFFER_SIZE; + if (rand_bytes(send, n) != 1) { + perror("rand_bytes() ERROR"); + break; + } + + if ((n = TLCP_SOCKET_Write(&conn, send, n)) < 0) { + perror("TLCP_SOCKET_Write() ERROR"); + break; + } + // print_bytes(send, n); + + // 不断读取数据直到满足长度 + rd = 0; + p = recv; + do { + if ((n = TLCP_SOCKET_Read(&conn, p, BUFFER_SIZE - rd)) < 0) { + perror("TLCP_SOCKET_Read() ERROR"); + break; + } + rd += n; + p = recv + rd; + } while (rd < BUFFER_SIZE); + + // print_bytes(recv, n); + // 比较数据读写数据是否一致 + if (memcmp(send, recv, BUFFER_SIZE) != 0) { + perror("Write Read Different!"); + break; + } + break; + } + TLCP_SOCKET_Connect_Close(&conn); + +} + +static void client_auth_test() { + TLCP_SOCKET_CONFIG config = {0}; + TLCP_SOCKET_CONNECT conn = {0}; + TLCP_SOCKET_KEY key = {0}; + int ret = 1; + uint8_t buff[16] = {0}; + ssize_t n = 16; + size_t i = 0; + errno = 0; + clock_t start, end; + + if (TLCP_SOCKET_GMSSL_Key(&key, &client_cert, &client_key) == -1) { + perror("TLCP_SOCKET_GMSSL_Key() ERROR"); + return; + } + config.root_certs = &cacert; + config.root_cert_len = 1; + config.client_sig_key = &key; + + for (i = 0; i < n; ++i) { + buff[i] = i; + } + start = clock(); + for (i = 0; i < 1000; i++) { + // 拨号连接服务端 + ret = TLCP_SOCKET_Dial(&config, &conn, "127.0.0.1", 30443); + if (ret != 1) { + error_print(); + return; + } + + if ((n = TLCP_SOCKET_Write(&conn, buff, n)) < 0) { + perror("TLCP_SOCKET_Write() ERROR"); + return; + } + if ((n = TLCP_SOCKET_Read(&conn, buff, n)) < 0) { + perror("TLCP_SOCKET_Read() ERROR"); + return; + } + // print_bytes(buff, n); + TLCP_SOCKET_Connect_Close(&conn); + } + end = clock(); + printf(">> Cost: %.2f s\n", (double) (end - start) / CLOCKS_PER_SEC); +} \ No newline at end of file diff --git a/tests/x509_verify.c b/tests/x509_verify.c new file mode 100644 index 0000000..24704a9 --- /dev/null +++ b/tests/x509_verify.c @@ -0,0 +1,57 @@ +#include +#include +#include +#include + +static const uint8_t rootca[] = "-----BEGIN CERTIFICATE-----\n\ +MIIBszCCAVegAwIBAgIIaeL+wBcKxnswDAYIKoEcz1UBg3UFADAuMQswCQYDVQQG\n\ +EwJDTjEOMAwGA1UECgwFTlJDQUMxDzANBgNVBAMMBlJPT1RDQTAeFw0xMjA3MTQw\n\ +MzExNTlaFw00MjA3MDcwMzExNTlaMC4xCzAJBgNVBAYTAkNOMQ4wDAYDVQQKDAVO\n\ +UkNBQzEPMA0GA1UEAwwGUk9PVENBMFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAE\n\ +MPCca6pmgcchsTf2UnBeL9rtp4nw+itk1Kzrmbnqo05lUwkwlWK+4OIrtFdAqnRT\n\ +V7Q9v1htkv42TsIutzd126NdMFswHwYDVR0jBBgwFoAUTDKxl9kzG8SmBcHG5Yti\n\ +W/CXdlgwDAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMCAQYwHQYDVR0OBBYEFEwysZfZ\n\ +MxvEpgXBxuWLYlvwl3ZYMAwGCCqBHM9VAYN1BQADSAAwRQIgG1bSLeOXp3oB8H7b\n\ +53W+CKOPl2PknmWEq/lMhtn25HkCIQDaHDgWxWFtnCrBjH16/W3Ezn7/U/Vjo5xI\n\ +pDoiVhsLwg==\n\ +-----END CERTIFICATE-----"; + +static const uint8_t subca[]= "-----BEGIN CERTIFICATE-----\n\ +MIICpjCCAkqgAwIBAgIQHzXZGQVs5o0CLlHzinoINzAMBggqgRzPVQGDdQUAMC4x\n\ +CzAJBgNVBAYTAkNOMQ4wDAYDVQQKDAVOUkNBQzEPMA0GA1UEAwwGUk9PVENBMB4X\n\ +DTEzMTIyMTAyNDY0MVoXDTMzMTIxNjAyNDY0MVowUjELMAkGA1UEBhMCQ04xLzAt\n\ +BgNVBAoMJlpoZWppYW5nIERpZ2l0YWwgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MRIw\n\ +EAYDVQQDDAlaSkNBIE9DQTEwWTATBgcqhkjOPQIBBggqgRzPVQGCLQNCAATp48tm\n\ +okIXIRCe6x9O5iaVViNlv1Yjwt1YbF9DpX63uSuuq2BioZhy+SWwNdXIYroR4zAV\n\ +DQoPMSzrFJ1SmEyfo4IBIjCCAR4wHwYDVR0jBBgwFoAUTDKxl9kzG8SmBcHG5Yti\n\ +W/CXdlgwDwYDVR0TAQH/BAUwAwEB/zCBugYDVR0fBIGyMIGvMEGgP6A9pDswOTEL\n\ +MAkGA1UEBhMCQ04xDjAMBgNVBAoMBU5SQ0FDMQwwCgYDVQQLDANBUkwxDDAKBgNV\n\ +BAMMA2FybDAqoCigJoYkaHR0cDovL3d3dy5yb290Y2EuZ292LmNuL2FybC9hcmwu\n\ +Y3JsMD6gPKA6hjhsZGFwOi8vbGRhcC5yb290Y2EuZ292LmNuOjM4OS9DTj1hcmws\n\ +T1U9QVJMLE89TlJDQUMsQz1DTjAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFKfT\n\ +sSSQIB09tFTuSzcoUpGuLGoiMAwGCCqBHM9VAYN1BQADSAAwRQIhAJLutfL7dLEb\n\ +M7EP0QCwN5g0WMLBI/MG5He9N6oREaYZAiAbWypQB34bhGNSqUQs+RQIYpct4yN5\n\ +UIufisb9BHWQIQ==\n\ +-----END CERTIFICATE-----"; + + +int main() { + X509_CERTIFICATE ca; + X509_CERTIFICATE ss; + + + if (x509_certificate_from_bytes(&ca, rootca, strlen(rootca)) != 1) { + error_print(); + return -1; + } + if (x509_certificate_from_bytes(&ss, subca, strlen(subca)) != 1) { + error_print(); + return -1; + } + + if ((x509_certificate_verify_by_certificate(&ss,&ca)) != 1){ + error_print(); + return -1; + } + +} \ No newline at end of file diff --git a/tests/x509test.c b/tests/x509test.c index 6b30968..93d6c83 100644 --- a/tests/x509test.c +++ b/tests/x509test.c @@ -53,6 +53,8 @@ #include #include #include +#include + static int test_x509_validity(void) @@ -314,17 +316,86 @@ static int test_x509_cert_request(void) return err; } +int test_x509_cert_parse() { + uint8_t pem_str[] = "-----BEGIN CERTIFICATE-----\n\ +MIIBszCCAVegAwIBAgIIaeL+wBcKxnswDAYIKoEcz1UBg3UFADAuMQswCQYDVQQG\n\ +EwJDTjEOMAwGA1UECgwFTlJDQUMxDzANBgNVBAMMBlJPT1RDQTAeFw0xMjA3MTQw\n\ +MzExNTlaFw00MjA3MDcwMzExNTlaMC4xCzAJBgNVBAYTAkNOMQ4wDAYDVQQKDAVO\n\ +UkNBQzEPMA0GA1UEAwwGUk9PVENBMFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAE\n\ +MPCca6pmgcchsTf2UnBeL9rtp4nw+itk1Kzrmbnqo05lUwkwlWK+4OIrtFdAqnRT\n\ +V7Q9v1htkv42TsIutzd126NdMFswHwYDVR0jBBgwFoAUTDKxl9kzG8SmBcHG5Yti\n\ +W/CXdlgwDAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMCAQYwHQYDVR0OBBYEFEwysZfZ\n\ +MxvEpgXBxuWLYlvwl3ZYMAwGCCqBHM9VAYN1BQADSAAwRQIgG1bSLeOXp3oB8H7b\n\ +53W+CKOPl2PknmWEq/lMhtn25HkCIQDaHDgWxWFtnCrBjH16/W3Ezn7/U/Vjo5xI\n\ +pDoiVhsLwg==\n\ +-----END CERTIFICATE-----"; + uint8_t base64_str[] = "MIIBszCCAVegAwIBAgIIaeL+wBcKxnswDAYIKoEcz1UBg3UFADAuMQswCQYDVQQGEwJDTjEOMAwGA1UECgwFTlJDQUMxDzANBgNVBAMMBlJPT1RDQTAeFw0xMjA3MTQwMzExNTlaFw00MjA3MDcwMzExNTlaMC4xCzAJBgNVBAYTAkNOMQ4wDAYDVQQKDAVOUkNBQzEPMA0GA1UEAwwGUk9PVENBMFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAEMPCca6pmgcchsTf2UnBeL9rtp4nw+itk1Kzrmbnqo05lUwkwlWK+4OIrtFdAqnRTV7Q9v1htkv42TsIutzd126NdMFswHwYDVR0jBBgwFoAUTDKxl9kzG8SmBcHG5YtiW/CXdlgwDAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMCAQYwHQYDVR0OBBYEFEwysZfZMxvEpgXBxuWLYlvwl3ZYMAwGCCqBHM9VAYN1BQADSAAwRQIgG1bSLeOXp3oB8H7b53W+CKOPl2PknmWEq/lMhtn25HkCIQDaHDgWxWFtnCrBjH16/W3Ezn7/U/Vjo5xIpDoiVhsLwg=="; + uint8_t hex_str[] = "308202A63082024AA00302010202101F35D919056CE68D022E51F38A7A0837300C06082A811CCF550183750500302E310B300906035504061302434E310E300C060355040A0C054E52434143310F300D06035504030C06524F4F544341301E170D3133313232313032343634315A170D3333313231363032343634315A3052310B300906035504061302434E312F302D060355040A0C265A68656A69616E67204469676974616C20436572746966696361746520417574686F726974793112301006035504030C095A4A4341204F4341313059301306072A8648CE3D020106082A811CCF5501822D03420004E9E3CB66A2421721109EEB1F4EE62695562365BF5623C2DD586C5F43A57EB7B92BAEAB6062A19872F925B035D5C862BA11E330150D0A0F312CEB149D52984C9FA38201223082011E301F0603551D230418301680144C32B197D9331BC4A605C1C6E58B625BF0977658300F0603551D130101FF040530030101FF3081BA0603551D1F0481B23081AF3041A03FA03DA43B3039310B300906035504061302434E310E300C060355040A0C054E52434143310C300A060355040B0C0341524C310C300A06035504030C0361726C302AA028A0268624687474703A2F2F7777772E726F6F7463612E676F762E636E2F61726C2F61726C2E63726C303EA03CA03A86386C6461703A2F2F6C6461702E726F6F7463612E676F762E636E3A3338392F434E3D61726C2C4F553D41524C2C4F3D4E524341432C433D434E300E0603551D0F0101FF040403020106301D0603551D0E04160414A7D3B12490201D3DB454EE4B37285291AE2C6A22300C06082A811CCF550183750500034800304502210092EEB5F2FB74B11B33B10FD100B037983458C2C123F306E477BD37AA1111A61902201B5B2A50077E1B846352A9442CF9140862972DE32379508B9F8AC6FD04759021"; + uint8_t der[1024]; + const uint8_t *cp = der; + size_t der_len = 0; + int len; + X509_CERTIFICATE a; + + if (base64_str_decode(base64_str, strlen(base64_str), der, &len) == -1){ + error_puts("无法解码BASE64"); + return -1; + } + der_len = len; + + printf("Base64 解码成功, DER len = %d\n", len); + // CASE 1 测试DER编码 + if (x509_certificate_from_bytes(&a, der, der_len) == -1){ + error_puts("CASE1 DER解析失败"); + return -1; + } + printf("CASE1 DER解析成功\n"); + memset(der, 0, 1024); + memset(&a,0,sizeof(a)); + + // CASE 2 测试PEM解码 + if (x509_certificate_from_bytes(&a, pem_str, strlen(pem_str)) == -1){ + error_puts("CASE2 PEM解析失败"); + return -1; + } + printf("CASE2 PEM解析成功\n"); + memset(der, 0, 1024); + memset(&a,0,sizeof(a)); + + // CASE 3 BASE64解码 + if (x509_certificate_from_bytes(&a, base64_str, strlen(base64_str)) == -1){ + error_puts("CASE3 BASE64解析失败"); + return -1; + } + printf("CASE3 BASE64解析成功\n"); + memset(der, 0, 1024); + memset(&a,0,sizeof(a)); + + // CASE 4 HEX解码 + if (x509_certificate_from_bytes(&a, hex_str, strlen(hex_str)) == -1){ + error_puts("CASE4 HEX解析失败"); + return -1; + } + printf("CASE4 HEX解析成功\n"); + memset(der, 0, 1024); + memset(&a,0,sizeof(a)); + + return 0; +} + int main(void) { int err = 0; - //err += test_x509_validity(); - err += test_x509_signature_algor(OID_sm2sign_with_sm3); - err += test_x509_signature_algor(OID_rsasign_with_sm3); - err += test_x509_name(); - err += test_x509_public_key_info(); - err += test_x509_certificate(); - err += test_x509_cert_request(); - //test_x509_extensions(); + // err += test_x509_validity(); + err += test_x509_signature_algor(OID_sm2sign_with_sm3); + err += test_x509_signature_algor(OID_rsasign_with_sm3); + err += test_x509_name(); + err += test_x509_public_key_info(); + err += test_x509_certificate(); + // err += test_x509_cert_request(); + err += test_x509_cert_parse(); + // test_x509_extensions(); + return 1; }