国密gmtls协议-双证书体系的服务端和客户端通信代码

内容介绍

  • 国密的双证书体系,将证书按照使用目的的不同划分为加密证书和签名证书两种,也就是两对公私钥,二者本质一致,均为SM2密钥对,区别仅体现在用法
  • 国密CA体系中,加密密钥对由CA产生,签名密钥对由用户自己产生,那么加密密钥涉及到的 私钥是如何通过安全的方式由CA传递到用户侧呢?使用数字信封的机理
  • 从道理上来说两个密钥具有不同的属性,逻辑上应该分开处理。其实最主要的原因是国家要保证必要的时候有能力对某些通讯进行监控,如果采用单证书,除了自己谁也无法解密(理论上如此),不利于国家安全。因此某些国家法律规定使用双证书。如果拥有加密证书的私钥,可以进行实时监控。使用过wireshark抓HTTPS包的朋友应该知道,如果配置了RSA密钥,可以解密出HTTPS通信中的加密信息。

加密证书和私钥的生成过程

  • 用户产生签名密钥对,生成签名证书的请求,发送签名证书给CA
  • CA验证用户的签名密钥对,产生加密证书
  • CA生成对称密钥,使用用户的签名公钥加密对称密钥,生成对称秘钥的密文
  • CA使用对称密钥对称加密 加密证书所对应的私钥,输出加密私钥的密文
  • CA将加密证书、对称密钥密文和加密私钥的密文 返还给 用户
  • 用户使用签名私钥解密对称密钥的密文得到对称密钥
  • 用户使用对称密钥解密加密私钥,得到加密私钥的明文

国标文档

注意事项

  • 双证书与标准TLS报文格式一样,但至少要包含两个证书,签名证书在前,加密证书在后。如果牵扯到证书链,问题就复杂了,而且协议这里也没有规定清楚。是签名证书 + 证书链 + 加密证书,还是签名证书 + 加密证书 + 证书链?在实现中发现TASSL采用的是前者,而沃通测试网站采用后者。在编码时请注意,最好是两者都兼容。

参考链接

最关键的参考链接

命令行 模式

-dcert filename-dkey keyname

specify an additional certificate and private key, these behave in the same manner as the -cert and -key options except there is no default if they are not specified (no additional certificate and key is used). As noted above some cipher suites require a certificate containing a key of a certain type. Some cipher suites need a certificate carrying an RSA key and some a DSS (DSA) key. By using RSA and DSS certificates and keys a server can support clients which only support RSA or DSS cipher suites by using an appropriate certificate.

-dcert文件名,-dkey密钥名
指定一个额外的证书和私钥,它们的行为方式与-cert和-key选项相同,除非没有指定它们,否则没有默认值(不使用额外的证书和密钥)。如上所述,一些密码套件需要包含特定类型密钥的证书。一些密码套件需要携带RSA密钥和一些DSS (DSA)密钥的证书。通过使用RSA和DSS证书和密钥,服务器可以通过使用适当的证书来支持仅支持RSA或DSS密码套件的客户端。

双证书双向认证 

服务端

  • 在设置双证书时,需要先设置签名证书,然后再设置加密证书,具体可参考源码。
  • 服务端执行命令 需要在指定的文件下执行
  • 必须要有 verify,verify是开启gmtls双向证书认证的关键,也就是对等证书验证,客户端也会验证服务端的证书
  • gmssl s_server -gmtls -accept 44330 -key SS.key.pem -cert SS.cert.pem -dkey SE.key.pem -dcert SE.cert.pem -CAfile CA.cert.pem -state -verify 1
chy-cpabe@ubuntu:~/GMSSL_certificate/sm2Certs$ gmssl s_server -gmtls -accept 44330 -key SS.key.pem -cert SS.cert.pem -dkey SE.key.pem -dcert SE.cert.pem -CAfile CA.cert.pem -state -verify 1
verify depth is 1
Using default temp DH parameters
[GMTLS_DEBUG] set sm2 signing certificate
[GMTLS_DEBUG] set sm2 signing private key
[GMTLS_DEBUG] set sm2 encryption certificate
[GMTLS_DEBUG] set sm2 decryption private key
ACCEPT
SSL_accept:before SSL initialization
SSL_accept:before SSL initialization
SSL_accept:SSLv3/TLS read client hello
SSL_accept:SSLv3/TLS write server hello
SSL_accept:SSLv3/TLS write certificate
SSL_accept:SSLv3/TLS write key exchange
SSL_accept:SSLv3/TLS write certificate request
SSL_accept:SSLv3/TLS write server done
SSL_accept:SSLv3/TLS write server done
depth=1 C = CN, ST = BJ, L = HaiDian, O = Beijing JNTA Technology LTD., OU = SORB of TASS, CN = Test CA (SM2)
verify return:1
depth=0 C = CN, ST = BJ, L = HaiDian, O = Beijing JNTA Technology LTD., OU = BSRC of TASS, CN = client sign (SM2)
verify return:1
SSL_accept:SSLv3/TLS read client certificate
ssl_get_algorithm2=f227000008x
SSL_accept:SSLv3/TLS read client key exchange
SSL_accept:SSLv3/TLS read certificate verify
SSL_accept:SSLv3/TLS read change cipher spec
SSL_accept:SSLv3/TLS read finished
SSL_accept:SSLv3/TLS write change cipher spec
SSL_accept:SSLv3/TLS write finished
-----BEGIN SSL SESSION PARAMETERS-----
MIICmAIBAQICAQEEAuATBCAWcAdtfPyMiEJmINUd/e/AmYdNqNTalV1AAbACRSQE
CgQwtuURXPYQpQ7gQIZ3fWRd9QpsP0Zi57oDT1D/X1xVBL3wy9yrr/BOpRw2afsu
4DH3oQYCBGMw/gSiBAICHCCjggIfMIICGzCCAcGgAwIBAgIJAIVjx+dwZIdmMAoG
CCqBHM9VAYN1MIGCMQswCQYDVQQGEwJDTjELMAkGA1UECAwCQkoxEDAOBgNVBAcM
B0hhaURpYW4xJTAjBgNVBAoMHEJlaWppbmcgSk5UQSBUZWNobm9sb2d5IExURC4x
FTATBgNVBAsMDFNPUkIgb2YgVEFTUzEWMBQGA1UEAwwNVGVzdCBDQSAoU00yKTAe
Fw0yMDA2MjAxMDE4MjZaFw0yNDA3MjkxMDE4MjZaMIGGMQswCQYDVQQGEwJDTjEL
MAkGA1UECAwCQkoxEDAOBgNVBAcMB0hhaURpYW4xJTAjBgNVBAoMHEJlaWppbmcg
Sk5UQSBUZWNobm9sb2d5IExURC4xFTATBgNVBAsMDEJTUkMgb2YgVEFTUzEaMBgG
A1UEAwwRY2xpZW50IHNpZ24gKFNNMikwWTATBgcqhkjOPQIBBggqgRzPVQGCLQNC
AARV/eII1n2NVqYjwt9r9A5Eh6Z0iG+WUpsw4sGxhfKL0vr0OKcur6DZqjqLDSCr
ZEhU6yuntNtaW+pexPblqXAroxowGDAJBgNVHRMEAjAAMAsGA1UdDwQEAwIGwDAK
BggqgRzPVQGDdQNIADBFAiEAiX+PoCNW/n9SDbv6/o+NyCCV/7kBgunc7w5b7xGm
4RICIBMDlLjPZE2ACYhu1Wjqph23PfMPMgae4+Gtd7wzFz2UpAYEBAEAAAA=
-----END SSL SESSION PARAMETERS-----
Client certificate
-----BEGIN CERTIFICATE-----
MIICGzCCAcGgAwIBAgIJAIVjx+dwZIdmMAoGCCqBHM9VAYN1MIGCMQswCQYDVQQG
EwJDTjELMAkGA1UECAwCQkoxEDAOBgNVBAcMB0hhaURpYW4xJTAjBgNVBAoMHEJl
aWppbmcgSk5UQSBUZWNobm9sb2d5IExURC4xFTATBgNVBAsMDFNPUkIgb2YgVEFT
UzEWMBQGA1UEAwwNVGVzdCBDQSAoU00yKTAeFw0yMDA2MjAxMDE4MjZaFw0yNDA3
MjkxMDE4MjZaMIGGMQswCQYDVQQGEwJDTjELMAkGA1UECAwCQkoxEDAOBgNVBAcM
B0hhaURpYW4xJTAjBgNVBAoMHEJlaWppbmcgSk5UQSBUZWNobm9sb2d5IExURC4x
FTATBgNVBAsMDEJTUkMgb2YgVEFTUzEaMBgGA1UEAwwRY2xpZW50IHNpZ24gKFNN
MikwWTATBgcqhkjOPQIBBggqgRzPVQGCLQNCAARV/eII1n2NVqYjwt9r9A5Eh6Z0
iG+WUpsw4sGxhfKL0vr0OKcur6DZqjqLDSCrZEhU6yuntNtaW+pexPblqXAroxow
GDAJBgNVHRMEAjAAMAsGA1UdDwQEAwIGwDAKBggqgRzPVQGDdQNIADBFAiEAiX+P
oCNW/n9SDbv6/o+NyCCV/7kBgunc7w5b7xGm4RICIBMDlLjPZE2ACYhu1Wjqph23
PfMPMgae4+Gtd7wzFz2U
-----END CERTIFICATE-----
subject=/C=CN/ST=BJ/L=HaiDian/O=Beijing JNTA Technology LTD./OU=BSRC of TASS/CN=client sign (SM2)
issuer=/C=CN/ST=BJ/L=HaiDian/O=Beijing JNTA Technology LTD./OU=SORB of TASS/CN=Test CA (SM2)
Shared ciphers:SM9-WITH-SMS4-SM3:SM9DHE-WITH-SMS4-SM3:SM2-WITH-SMS4-SM3:SM2DHE-WITH-SMS4-SM3:RSA-WITH-SMS4-SHA1:RSA-WITH-SMS4-SM3
CIPHER is SM2-WITH-SMS4-SM3
Secure Renegotiation IS supported

客户端 

  • 客户端执行代码和执行结果  
  • gmssl s_client -gmtls -connect localhost:44330 -key CS.key.pem -cert CS.cert.pem -dkey CE.key.pem -dcert CE.cert.pem -CAfile CA.cert.pem -state -showcerts
chy-cpabe@ubuntu:~/GMSSL_certificate/sm2Certs$ gmssl s_client -gmtls -connect localhost:44330 -key CS.key.pem -cert CS.cert.pem -dkey CE.key.pem -dcert CE.cert.pem -CAfile CA.cert.pem -state -showcerts
[GMTLS_DEBUG] set sm2 signing certificate
[GMTLS_DEBUG] set sm2 signing private key
[GMTLS_DEBUG] set sm2 encryption certificate
[GMTLS_DEBUG] set sm2 decryption private key
CONNECTED(00000003)
SSL_connect:before SSL initialization
SSL_connect:SSLv3/TLS write client hello
SSL_connect:SSLv3/TLS write client hello
SSL_connect:SSLv3/TLS read server hello
depth=1 C = CN, ST = BJ, L = HaiDian, O = Beijing JNTA Technology LTD., OU = SORB of TASS, CN = Test CA (SM2)
verify return:1
depth=0 C = CN, ST = BJ, L = HaiDian, O = Beijing JNTA Technology LTD., OU = BSRC of TASS, CN = server sign (SM2)
verify return:1
SSL_connect:SSLv3/TLS read server certificate
Z=BCDCCB61AADD790C076DAC60ED09DDD5285A906A4025DD748DA2FB5816464C58
C=00021E3082021A308201C0A0030201020209008563C7E770648765300A06082A811CCF55018375308182310B300906035504061302434E310B300906035504080C02424A3110300E06035504070C074861694469616E31253023060355040A0C1C4265696A696E67204A4E544120546563686E6F6C6F6779204C54442E31153013060355040B0C0C534F5242206F6620544153533116301406035504030C0D546573742043412028534D3229301E170D3230303632303130313832365A170D3234303732393130313832365A308185310B300906035504061302434E310B300906035504080C02424A3110300E06035504070C074861694469616E31253023060355040A0C1C4265696A696E67204A4E544120546563686E6F6C6F6779204C54442E31153013060355040B0C0C42535243206F6620544153533119301706035504030C1073657276657220656E632028534D32293059301306072A8648CE3D020106082A811CCF5501822D03420004B999853302F02CC522CC4CCA287019E86B901FC24E3CCF9A61B93BB177B28C2CE8E23C5C522DF73C23F7AC36FF688CB2E685A3FA4770103F7C99EFC32D06C11FA31A301830090603551D1304023000300B0603551D0F040403020338300A06082A811CCF550183750348003045022100EC4368F400870BED441817AF4D359BDC61A9EDFDDEE54AB0C185084B450C46B902206E0C3A08BC584590046DC85603CD4E8A51F97D9669B1ACA3E2A3627BE61D49A2
SSL_connect:SSLv3/TLS read server key exchange
SSL_connect:SSLv3/TLS read server certificate request
SSL_connect:SSLv3/TLS read server done
SSL_connect:SSLv3/TLS write client certificate
SSL_connect:SSLv3/TLS write client key exchange
ssl_get_algorithm2=3268600008x
SSL_connect:SSLv3/TLS write certificate verify
SSL_connect:SSLv3/TLS write change cipher spec
SSL_connect:SSLv3/TLS write finished
SSL_connect:SSLv3/TLS write finished
SSL_connect:SSLv3/TLS read change cipher spec
SSL_connect:SSLv3/TLS read finished
---
Certificate chain
 0 s:/C=CN/ST=BJ/L=HaiDian/O=Beijing JNTA Technology LTD./OU=BSRC of TASS/CN=server sign (SM2)
   i:/C=CN/ST=BJ/L=HaiDian/O=Beijing JNTA Technology LTD./OU=SORB of TASS/CN=Test CA (SM2)
-----BEGIN CERTIFICATE-----
MIICGjCCAcGgAwIBAgIJAIVjx+dwZIdkMAoGCCqBHM9VAYN1MIGCMQswCQYDVQQG
EwJDTjELMAkGA1UECAwCQkoxEDAOBgNVBAcMB0hhaURpYW4xJTAjBgNVBAoMHEJl
aWppbmcgSk5UQSBUZWNobm9sb2d5IExURC4xFTATBgNVBAsMDFNPUkIgb2YgVEFT
UzEWMBQGA1UEAwwNVGVzdCBDQSAoU00yKTAeFw0yMDA2MjAxMDE4MjVaFw0yNDA3
MjkxMDE4MjVaMIGGMQswCQYDVQQGEwJDTjELMAkGA1UECAwCQkoxEDAOBgNVBAcM
B0hhaURpYW4xJTAjBgNVBAoMHEJlaWppbmcgSk5UQSBUZWNobm9sb2d5IExURC4x
FTATBgNVBAsMDEJTUkMgb2YgVEFTUzEaMBgGA1UEAwwRc2VydmVyIHNpZ24gKFNN
MikwWTATBgcqhkjOPQIBBggqgRzPVQGCLQNCAAS0lHzt7CkOzCtyf6VwCqoT2PYD
CL/AJrCsHa+6lE8wDZ7DShI2bvfmrpavndEW67CHQOlO0q6/aoEB0PoAgpopoxow
GDAJBgNVHRMEAjAAMAsGA1UdDwQEAwIGwDAKBggqgRzPVQGDdQNHADBEAiB06JWp
uxFbGBfvG9juhe2Umu/auI1H2XeMdvDjbOtfuQIgMXT8jewkzq9TR3OPzRTkZCRH
3H+xKEb8r8JsEEStwaU=
-----END CERTIFICATE-----
 1 s:/C=CN/ST=BJ/L=HaiDian/O=Beijing JNTA Technology LTD./OU=BSRC of TASS/CN=server enc (SM2)
   i:/C=CN/ST=BJ/L=HaiDian/O=Beijing JNTA Technology LTD./OU=SORB of TASS/CN=Test CA (SM2)
-----BEGIN CERTIFICATE-----
MIICGjCCAcCgAwIBAgIJAIVjx+dwZIdlMAoGCCqBHM9VAYN1MIGCMQswCQYDVQQG
EwJDTjELMAkGA1UECAwCQkoxEDAOBgNVBAcMB0hhaURpYW4xJTAjBgNVBAoMHEJl
aWppbmcgSk5UQSBUZWNobm9sb2d5IExURC4xFTATBgNVBAsMDFNPUkIgb2YgVEFT
UzEWMBQGA1UEAwwNVGVzdCBDQSAoU00yKTAeFw0yMDA2MjAxMDE4MjZaFw0yNDA3
MjkxMDE4MjZaMIGFMQswCQYDVQQGEwJDTjELMAkGA1UECAwCQkoxEDAOBgNVBAcM
B0hhaURpYW4xJTAjBgNVBAoMHEJlaWppbmcgSk5UQSBUZWNobm9sb2d5IExURC4x
FTATBgNVBAsMDEJTUkMgb2YgVEFTUzEZMBcGA1UEAwwQc2VydmVyIGVuYyAoU00y
KTBZMBMGByqGSM49AgEGCCqBHM9VAYItA0IABLmZhTMC8CzFIsxMyihwGehrkB/C
TjzPmmG5O7F3sows6OI8XFIt9zwj96w2/2iMsuaFo/pHcBA/fJnvwy0GwR+jGjAY
MAkGA1UdEwQCMAAwCwYDVR0PBAQDAgM4MAoGCCqBHM9VAYN1A0gAMEUCIQDsQ2j0
AIcL7UQYF69NNZvcYant/d7lSrDBhQhLRQxGuQIgbgw6CLxYRZAEbchWA81OilH5
fZZpsayj4qNie+YdSaI=
-----END CERTIFICATE-----
 2 s:/C=CN/ST=BJ/L=HaiDian/O=Beijing JNTA Technology LTD./OU=SORB of TASS/CN=Test CA (SM2)
   i:/C=CN/ST=BJ/L=HaiDian/O=Beijing JNTA Technology LTD./OU=SORB of TASS/CN=Test CA (SM2)
-----BEGIN CERTIFICATE-----
MIICWjCCAgCgAwIBAgIJAP5W2mLaOWq5MAoGCCqBHM9VAYN1MIGCMQswCQYDVQQG
EwJDTjELMAkGA1UECAwCQkoxEDAOBgNVBAcMB0hhaURpYW4xJTAjBgNVBAoMHEJl
aWppbmcgSk5UQSBUZWNobm9sb2d5IExURC4xFTATBgNVBAsMDFNPUkIgb2YgVEFT
UzEWMBQGA1UEAwwNVGVzdCBDQSAoU00yKTAeFw0yMDA2MjAxMDE4MjVaFw0yNDA3
MjkxMDE4MjVaMIGCMQswCQYDVQQGEwJDTjELMAkGA1UECAwCQkoxEDAOBgNVBAcM
B0hhaURpYW4xJTAjBgNVBAoMHEJlaWppbmcgSk5UQSBUZWNobm9sb2d5IExURC4x
FTATBgNVBAsMDFNPUkIgb2YgVEFTUzEWMBQGA1UEAwwNVGVzdCBDQSAoU00yKTBZ
MBMGByqGSM49AgEGCCqBHM9VAYItA0IABArjN7ag+H8D12eqXJpMeTOR9m3sB2RC
ojH7fZPB77SDfHZb9g1lcqUhrug0nw2F8wBMsLfjvsK3wQn/ryi3YvSjXTBbMB0G
A1UdDgQWBBRCcBGiEpd09qSpUlkiGkZ+q+CFbDAfBgNVHSMEGDAWgBRCcBGiEpd0
9qSpUlkiGkZ+q+CFbDAMBgNVHRMEBTADAQH/MAsGA1UdDwQEAwIBBjAKBggqgRzP
VQGDdQNIADBFAiBjdylWVsUoTRcHu9DoMHv4lgtYJMf2xHAGLoJUjmbizAIhAOFD
i3EmFVUgGVdgbnztFZcBLxtBzIAh/Q4Q3dm3/MFu
-----END CERTIFICATE-----
---
Server certificate
subject=/C=CN/ST=BJ/L=HaiDian/O=Beijing JNTA Technology LTD./OU=BSRC of TASS/CN=server sign (SM2)
issuer=/C=CN/ST=BJ/L=HaiDian/O=Beijing JNTA Technology LTD./OU=SORB of TASS/CN=Test CA (SM2)
---
Acceptable client certificate CA names
/C=CN/ST=BJ/L=HaiDian/O=Beijing JNTA Technology LTD./OU=SORB of TASS/CN=Test CA (SM2)
Client Certificate Types: RSA sign, DSA sign
---
SSL handshake has read 2121 bytes and written 2115 bytes
Verification: OK
---
New, GMTLSv1.1, Cipher is SM2-WITH-SMS4-SM3
Server public key is 256 bit
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
SSL-Session:
    Protocol  : GMTLSv1.1
    Cipher    : SM2-WITH-SMS4-SM3
    Session-ID: 1670076D7CFC8C88426620D51DFDEFC099874DA8D4DA955D4001B0024524040A
    Session-ID-ctx: 
    Master-Key: B6E5115CF610A50EE04086777D645DF50A6C3F4662E7BA034F50FF5F5C5504BDF0CBDCABAFF04EA51C3669FB2EE031F7
    PSK identity: None
    PSK identity hint: None
    SRP username: None
    Start Time: 1664155140
    Timeout   : 7200 (sec)
    Verify return code: 0 (ok)
    Extended master secret: no
---

双证书单向认证 

  • 同时指定签名和加密证书 且 采用双证书单向认证
  • 服务端执行代码
  • gmssl s_server -gmtls -accept 44330 -key SS.key.pem -cert SS.cert.pem -dkey SE.key.pem -dcert SE.cert.pem -CAfile CA.cert.pem -state
  • 只需要将verify删除,就由双向认证变成了单项认证
  • -state参数表示打印跟多信息,方便调试

s_server: Cannot open input file gmcrt/2_sign.crt, No such file or directory
s_server: Use -help for summary.
chy-cpabe@ubuntu:~/test_double_ssl/GMSSL双证书demo/sm2Certs$ ls
CA.cert.pem  CA.key.pem  CA.pem  CE.cert.pem  CE.key.pem  CE.pem  CS.cert.pem  CS.key.pem  CS.pem  SE.cert.pem  SE.key.pem  SE.pem  SS.cert.pem  SS.key.pem  SS.pem
chy-cpabe@ubuntu:~/test_double_ssl/GMSSL双证书demo/sm2Certs$ gmssl s_server -gmtls -accept 44330 -key SS.key.pem -cert SS.cert.pem  -dkey SE.key.pem -dcert SE.cert.pem -CAfile CA.cert.pem -state
Using default temp DH parameters
[GMTLS_DEBUG] set sm2 signing certificate
[GMTLS_DEBUG] set sm2 signing private key
[GMTLS_DEBUG] set sm2 encryption certificate
[GMTLS_DEBUG] set sm2 decryption private key
ACCEPT
SSL_accept:before SSL initialization
SSL_accept:before SSL initialization
ssl_get_algorithm2=2b81000008x
SSL_accept:SSLv3/TLS read client hello
SSL_accept:SSLv3/TLS write server hello
SSL_accept:SSLv3/TLS write certificate
SSL_accept:SSLv3/TLS write key exchange
SSL_accept:SSLv3/TLS write server done
SSL_accept:SSLv3/TLS write server done
SSL_accept:SSLv3/TLS read client key exchange
SSL_accept:SSLv3/TLS read change cipher spec
SSL_accept:SSLv3/TLS read finished
SSL_accept:SSLv3/TLS write change cipher spec
SSL_accept:SSLv3/TLS write finished
-----BEGIN SSL SESSION PARAMETERS-----
MHUCAQECAgEBBALgEwQg4tsFtm05e9thEdmOsDjCdEY797x1PAcVaGWd8chdLuoE
MDqjvlXZek3vSlC1q+aYT7NA40D6C7sbR0gNowPIhMfVan396kWxthLUmXIgz3t1
5qEGAgRjAfsxogQCAhwgpAYEBAEAAAA=
-----END SSL SESSION PARAMETERS-----
Shared ciphers:SM9-WITH-SMS4-SM3:SM9DHE-WITH-SMS4-SM3:SM2-WITH-SMS4-SM3:SM2DHE-WITH-SMS4-SM3:RSA-WITH-SMS4-SHA1:RSA-WITH-SMS4-SM3
CIPHER is SM2-WITH-SMS4-SM3
Secure Renegotiation IS supported
  • 客户端执行代码
  • gmssl s_client -gmtls -connect localhost:44330 -key CS.key.pem -cert CS.cert.pem -dkey CE.key.pem -dcert CE.cert.pem -CAfile CA.cert.pem -state
  • 可以看出,现在使用的协议已经变成gmtlsv1.1
  • SSL-Session:
  •     Protocol  : GMTLSv1.1

[GMTLS_DEBUG] set sm2 signing certificate
[GMTLS_DEBUG] set sm2 signing private key
[GMTLS_DEBUG] set sm2 encryption certificate
[GMTLS_DEBUG] set sm2 decryption private key
CONNECTED(00000003)
SSL_connect:before SSL initialization
SSL_connect:SSLv3/TLS write client hello
SSL_connect:SSLv3/TLS write client hello
SSL_connect:SSLv3/TLS read server hello
depth=1 C = CN, ST = BJ, L = HaiDian, O = Beijing JNTA Technology LTD., OU = SORB of TASS, CN = Test CA (SM2)
verify return:1
depth=0 C = CN, ST = BJ, L = HaiDian, O = Beijing JNTA Technology LTD., OU = BSRC of TASS, CN = server sign (SM2)
verify return:1
SSL_connect:SSLv3/TLS read server certificate
Z=BCDCCB61AADD790C076DAC60ED09DDD5285A906A4025DD748DA2FB5816464C58
C=00021E3082021A308201C0A0030201020209008563C7E770648765300A06082A811CCF55018375308182310B300906035504061302434E310B300906035504080C02424A3110300E06035504070C074861694469616E31253023060355040A0C1C4265696A696E67204A4E544120546563686E6F6C6F6779204C54442E31153013060355040B0C0C534F5242206F6620544153533116301406035504030C0D546573742043412028534D3229301E170D3230303632303130313832365A170D3234303732393130313832365A308185310B300906035504061302434E310B300906035504080C02424A3110300E06035504070C074861694469616E31253023060355040A0C1C4265696A696E67204A4E544120546563686E6F6C6F6779204C54442E31153013060355040B0C0C42535243206F6620544153533119301706035504030C1073657276657220656E632028534D32293059301306072A8648CE3D020106082A811CCF5501822D03420004B999853302F02CC522CC4CCA287019E86B901FC24E3CCF9A61B93BB177B28C2CE8E23C5C522DF73C23F7AC36FF688CB2E685A3FA4770103F7C99EFC32D06C11FA31A301830090603551D1304023000300B0603551D0F040403020338300A06082A811CCF550183750348003045022100EC4368F400870BED441817AF4D359BDC61A9EDFDDEE54AB0C185084B450C46B902206E0C3A08BC584590046DC85603CD4E8A51F97D9669B1ACA3E2A3627BE61D49A2
SSL_connect:SSLv3/TLS read server key exchange
SSL_connect:SSLv3/TLS read server done
SSL_connect:SSLv3/TLS write client key exchange
SSL_connect:SSLv3/TLS write change cipher spec
ssl_get_algorithm2=2790100008x
SSL_connect:SSLv3/TLS write finished
SSL_connect:SSLv3/TLS write finished
SSL_connect:SSLv3/TLS read change cipher spec
SSL_connect:SSLv3/TLS read finished
---
Certificate chain
 0 s:/C=CN/ST=BJ/L=HaiDian/O=Beijing JNTA Technology LTD./OU=BSRC of TASS/CN=server sign (SM2)
   i:/C=CN/ST=BJ/L=HaiDian/O=Beijing JNTA Technology LTD./OU=SORB of TASS/CN=Test CA (SM2)
 1 s:/C=CN/ST=BJ/L=HaiDian/O=Beijing JNTA Technology LTD./OU=BSRC of TASS/CN=server enc (SM2)
   i:/C=CN/ST=BJ/L=HaiDian/O=Beijing JNTA Technology LTD./OU=SORB of TASS/CN=Test CA (SM2)
 2 s:/C=CN/ST=BJ/L=HaiDian/O=Beijing JNTA Technology LTD./OU=SORB of TASS/CN=Test CA (SM2)
   i:/C=CN/ST=BJ/L=HaiDian/O=Beijing JNTA Technology LTD./OU=SORB of TASS/CN=Test CA (SM2)
---
Server certificate
-----BEGIN CERTIFICATE-----
MIICGjCCAcGgAwIBAgIJAIVjx+dwZIdkMAoGCCqBHM9VAYN1MIGCMQswCQYDVQQG
EwJDTjELMAkGA1UECAwCQkoxEDAOBgNVBAcMB0hhaURpYW4xJTAjBgNVBAoMHEJl
aWppbmcgSk5UQSBUZWNobm9sb2d5IExURC4xFTATBgNVBAsMDFNPUkIgb2YgVEFT
UzEWMBQGA1UEAwwNVGVzdCBDQSAoU00yKTAeFw0yMDA2MjAxMDE4MjVaFw0yNDA3
MjkxMDE4MjVaMIGGMQswCQYDVQQGEwJDTjELMAkGA1UECAwCQkoxEDAOBgNVBAcM
B0hhaURpYW4xJTAjBgNVBAoMHEJlaWppbmcgSk5UQSBUZWNobm9sb2d5IExURC4x
FTATBgNVBAsMDEJTUkMgb2YgVEFTUzEaMBgGA1UEAwwRc2VydmVyIHNpZ24gKFNN
MikwWTATBgcqhkjOPQIBBggqgRzPVQGCLQNCAAS0lHzt7CkOzCtyf6VwCqoT2PYD
CL/AJrCsHa+6lE8wDZ7DShI2bvfmrpavndEW67CHQOlO0q6/aoEB0PoAgpopoxow
GDAJBgNVHRMEAjAAMAsGA1UdDwQEAwIGwDAKBggqgRzPVQGDdQNHADBEAiB06JWp
uxFbGBfvG9juhe2Umu/auI1H2XeMdvDjbOtfuQIgMXT8jewkzq9TR3OPzRTkZCRH
3H+xKEb8r8JsEEStwaU=
-----END CERTIFICATE-----
subject=/C=CN/ST=BJ/L=HaiDian/O=Beijing JNTA Technology LTD./OU=BSRC of TASS/CN=server sign (SM2)
issuer=/C=CN/ST=BJ/L=HaiDian/O=Beijing JNTA Technology LTD./OU=SORB of TASS/CN=Test CA (SM2)
---
No client certificate CA names sent
---
SSL handshake has read 1973 bytes and written 320 bytes
Verification: OK
---
New, GMTLSv1.1, Cipher is SM2-WITH-SMS4-SM3
Server public key is 256 bit
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
SSL-Session:
    Protocol  : GMTLSv1.1
    Cipher    : SM2-WITH-SMS4-SM3
    Session-ID: E24D8195A9D25F9A6B877C63A85979492FA5199E58FA512A95915E33BA7A418B
    Session-ID-ctx: 
    Master-Key: 2ED26139965074A55F65D011A370DF7A4672A0FC7BBB4A0ED991DCD55A6231E92B5A09225BFE9F1ABD0546F1F75885A2
    PSK identity: None
    PSK identity hint: None
    SRP username: None
    Start Time: 1661073328
    Timeout   : 7200 (sec)
    Verify return code: 0 (ok)
    Extended master secret: no
---

  • 客户端命令
  • gmssl s_client -gmtls -connect localhost:44330 -key CS.key.pem -cert CS.cert.pem -dkey CE.key.pem -dcert CE.cert.pem -CAfile CA.cert.pem -state
gmssl s_client -gmtls -connect localhost:44330 -key CS.key.pem -cert CS.cert.pem -dkey CE.key.pem -dcert CE.cert.pem -CAfile CA.cert.pem -state
[GMTLS_DEBUG] set sm2 signing certificate
[GMTLS_DEBUG] set sm2 signing private key
[GMTLS_DEBUG] set sm2 encryption certificate
[GMTLS_DEBUG] set sm2 decryption private key
CONNECTED(00000003)
SSL_connect:before SSL initialization
SSL_connect:SSLv3/TLS write client hello
SSL_connect:SSLv3/TLS write client hello
SSL_connect:SSLv3/TLS read server hello
depth=1 C = CN, ST = BJ, L = HaiDian, O = Beijing JNTA Technology LTD., OU = SORB of TASS, CN = Test CA (SM2)
verify return:1
depth=0 C = CN, ST = BJ, L = HaiDian, O = Beijing JNTA Technology LTD., OU = BSRC of TASS, CN = server sign (SM2)
verify return:1
SSL_connect:SSLv3/TLS read server certificate
Z=BCDCCB61AADD790C076DAC60ED09DDD5285A906A4025DD748DA2FB5816464C58
C=00021E3082021A308201C0A0030201020209008563C7E770648765300A06082A811CCF55018375308182310B300906035504061302434E310B300906035504080C02424A3110300E06035504070C074861694469616E31253023060355040A0C1C4265696A696E67204A4E544120546563686E6F6C6F6779204C54442E31153013060355040B0C0C534F5242206F6620544153533116301406035504030C0D546573742043412028534D3229301E170D3230303632303130313832365A170D3234303732393130313832365A308185310B300906035504061302434E310B300906035504080C02424A3110300E06035504070C074861694469616E31253023060355040A0C1C4265696A696E67204A4E544120546563686E6F6C6F6779204C54442E31153013060355040B0C0C42535243206F6620544153533119301706035504030C1073657276657220656E632028534D32293059301306072A8648CE3D020106082A811CCF5501822D03420004B999853302F02CC522CC4CCA287019E86B901FC24E3CCF9A61B93BB177B28C2CE8E23C5C522DF73C23F7AC36FF688CB2E685A3FA4770103F7C99EFC32D06C11FA31A301830090603551D1304023000300B0603551D0F040403020338300A06082A811CCF550183750348003045022100EC4368F400870BED441817AF4D359BDC61A9EDFDDEE54AB0C185084B450C46B902206E0C3A08BC584590046DC85603CD4E8A51F97D9669B1ACA3E2A3627BE61D49A2
SSL_connect:SSLv3/TLS read server key exchange
SSL_connect:SSLv3/TLS read server certificate request
SSL_connect:SSLv3/TLS read server done
SSL_connect:SSLv3/TLS write client certificate
SSL_connect:SSLv3/TLS write client key exchange
ssl_get_algorithm2=3c3f900008x
SSL_connect:SSLv3/TLS write certificate verify
SSL_connect:SSLv3/TLS write change cipher spec
SSL_connect:SSLv3/TLS write finished
SSL3 alert read:fatal:decrypt error
SSL_connect:error in SSLv3/TLS write finished
140016949239808:error:1409441B:SSL routines:ssl3_read_bytes:tlsv1 alert decrypt error:ssl/record/rec_layer_s3.c:1385:SSL alert number 51
---
Certificate chain
 0 s:/C=CN/ST=BJ/L=HaiDian/O=Beijing JNTA Technology LTD./OU=BSRC of TASS/CN=server sign (SM2)
   i:/C=CN/ST=BJ/L=HaiDian/O=Beijing JNTA Technology LTD./OU=SORB of TASS/CN=Test CA (SM2)
 1 s:/C=CN/ST=BJ/L=HaiDian/O=Beijing JNTA Technology LTD./OU=BSRC of TASS/CN=server enc (SM2)
   i:/C=CN/ST=BJ/L=HaiDian/O=Beijing JNTA Technology LTD./OU=SORB of TASS/CN=Test CA (SM2)
 2 s:/C=CN/ST=BJ/L=HaiDian/O=Beijing JNTA Technology LTD./OU=SORB of TASS/CN=Test CA (SM2)
   i:/C=CN/ST=BJ/L=HaiDian/O=Beijing JNTA Technology LTD./OU=SORB of TASS/CN=Test CA (SM2)
---
Server certificate
-----BEGIN CERTIFICATE-----
MIICGjCCAcGgAwIBAgIJAIVjx+dwZIdkMAoGCCqBHM9VAYN1MIGCMQswCQYDVQQG
EwJDTjELMAkGA1UECAwCQkoxEDAOBgNVBAcMB0hhaURpYW4xJTAjBgNVBAoMHEJl
aWppbmcgSk5UQSBUZWNobm9sb2d5IExURC4xFTATBgNVBAsMDFNPUkIgb2YgVEFT
UzEWMBQGA1UEAwwNVGVzdCBDQSAoU00yKTAeFw0yMDA2MjAxMDE4MjVaFw0yNDA3
MjkxMDE4MjVaMIGGMQswCQYDVQQGEwJDTjELMAkGA1UECAwCQkoxEDAOBgNVBAcM
B0hhaURpYW4xJTAjBgNVBAoMHEJlaWppbmcgSk5UQSBUZWNobm9sb2d5IExURC4x
FTATBgNVBAsMDEJTUkMgb2YgVEFTUzEaMBgGA1UEAwwRc2VydmVyIHNpZ24gKFNN
MikwWTATBgcqhkjOPQIBBggqgRzPVQGCLQNCAAS0lHzt7CkOzCtyf6VwCqoT2PYD
CL/AJrCsHa+6lE8wDZ7DShI2bvfmrpavndEW67CHQOlO0q6/aoEB0PoAgpopoxow
GDAJBgNVHRMEAjAAMAsGA1UdDwQEAwIGwDAKBggqgRzPVQGDdQNHADBEAiB06JWp
uxFbGBfvG9juhe2Umu/auI1H2XeMdvDjbOtfuQIgMXT8jewkzq9TR3OPzRTkZCRH
3H+xKEb8r8JsEEStwaU=
-----END CERTIFICATE-----
subject=/C=CN/ST=BJ/L=HaiDian/O=Beijing JNTA Technology LTD./OU=BSRC of TASS/CN=server sign (SM2)
issuer=/C=CN/ST=BJ/L=HaiDian/O=Beijing JNTA Technology LTD./OU=SORB of TASS/CN=Test CA (SM2)
---
Acceptable client certificate CA names
/C=CN/ST=BJ/L=HaiDian/O=Beijing JNTA Technology LTD./OU=SORB of TASS/CN=Test CA (SM2)
Client Certificate Types: RSA sign, DSA sign
---
SSL handshake has read 2037 bytes and written 2116 bytes
Verification: OK
---
New, GMTLSv1.1, Cipher is SM2-WITH-SMS4-SM3
Server public key is 256 bit
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
SSL-Session:
    Protocol  : GMTLSv1.1
    Cipher    : SM2-WITH-SMS4-SM3
    Session-ID: 12664AE82CE989580C27B14AFF7487B19FF1C159C94291A0B76AA5F80D28317F
    Session-ID-ctx: 
    Master-Key: AD4D5164B7F54B9FA1F74A7A569C6B6E75CFD96967AB7519658C33E9C6FB8851EBCF1B10E175E736E9C7127E5FA8D32D
    PSK identity: None
    PSK identity hint: None
    SRP username: None
    Start Time: 1661074697
    Timeout   : 7200 (sec)
    Verify return code: 0 (ok)
    Extended master secret: no
---

双证书双向认证-代码实现

 参考链接

 注意事项

  • 基于TASSL开源项目中的Tassl_demo/mk_tls_cert 下的 SM2certgen.sh 脚本,共生成 15 个 PEM 文件,即根证书、服务端和客户端的签名和加密证书
  • 上述参考链接里面的下面这句话是错误的,服务端都不验证客户端身份了,还叫双向认证嘛??
  • 修改后代码如下
    // 是否要求校验对方证书 此处不验证客户端身份所以为: SSL_VERIFY_NONE
    SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL);

 服务端代码

#include <cstdio>
#include <cstdlib>
#include <cerrno>
#include <cstring>
#include <netinet/in.h>
#include <sys/socket.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <openssl/ssl.h>
#include <openssl/err.h>

#define MAXBUF 1500

//#define CA_CERT_FILE "/home/chy-cpabe/GMSSL_certificate/sm2Certs/CA.cert.pem"
//#define SIGN_CERT_FILE "/home/chy-cpabe/GMSSL_certificate/sm2Certs/SS.cert.pem"
//#define SIGN_KEY_FILE "/home/chy-cpabe/GMSSL_certificate/sm2Certs/SS.key.pem"
//#define ENCODE_CERT_FILE "/home/chy-cpabe/GMSSL_certificate/sm2Certs/SE.cert.pem"
//#define ENCODE_KEY_FILE "/home/chy-cpabe/GMSSL_certificate/sm2Certs/SE.key.pem"

#define CA_CERT_FILE "/home/chy-cpabe/tmp/second/rootcert.pem"
#define SIGN_CERT_FILE "/home/chy-cpabe/tmp/second/sign.pem"
#define SIGN_KEY_FILE "/home/chy-cpabe/tmp/second/sign.key"
#define ENCODE_CERT_FILE "/home/chy-cpabe/tmp/second/encrypt.pem"
#define ENCODE_KEY_FILE "/home/chy-cpabe/tmp/second/encrypt.key"

void ShowCerts(SSL * ssl)
{
    X509 *cert;
    char *line;

    cert = SSL_get_peer_certificate(ssl);
    // SSL_get_verify_result()是重点,SSL_CTX_set_verify()只是配置启不启用并没有执行认证,调用该函数才会真证进行证书认证
    // 如果验证不通过,那么程序抛出异常中止连接
    if(SSL_get_verify_result(ssl) == X509_V_OK){
        printf("证书验证通过\n");
    }
    if (cert != nullptr) {
        printf("数字证书信息:\n");
        line = X509_NAME_oneline(X509_get_subject_name(cert), nullptr, 0);
        printf("证书: %s\n", line);
        free(line);
        line = X509_NAME_oneline(X509_get_issuer_name(cert), nullptr, 0);
        printf("颁发者: %s\n", line);
        free(line);
        X509_free(cert);
    } else
        printf("无证书信息!\n");
}

int main(int argc, char **argv) {
    int listen_fd = -1; /* TCP监听套接字 */
    int accept_fd = -1; /* 已连接TCP套接字 */
    struct sockaddr_in server_addr, client_addr;
    bzero(&server_addr, sizeof(server_addr));

    SSL_CTX *ctx = nullptr; /* SSL会话环境 */

    SSL *ssl = nullptr; /* SSL安全套接字 */
    socklen_t len;
    char buf[MAXBUF]={0};  /* 服务器接收数据buffer */


    if( 3!=argc )
    {
        printf("argcment wrong:ip port\n");
    }

    SSL_library_init(); /* SSL 库初始化 */
    SSLeay_add_ssl_algorithms();
    OpenSSL_add_all_algorithms();  /* 载入所有 SSL 算法 */
    SSL_load_error_strings(); /* 载入所有 SSL 错误消息 */
//    ERR_load_BIO_strings();


    //TCP服务器:创建、绑定、监听
    if ((listen_fd = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
        perror("socket create wrong\n");
        exit(1);
    } else
        printf("socket created\n");

    server_addr.sin_family = PF_INET;
    server_addr.sin_port = htons(atoi(argv[2]));
    server_addr.sin_addr.s_addr = inet_addr(argv[1]);;

    if (bind(listen_fd, (struct sockaddr *) &server_addr, sizeof(struct sockaddr))
        == -1) {
        perror("bind wrong\n");
        exit(1);
    } else
        printf("binded success\n");
    int lisnum = 2;

    do{
        //使用SSL_CTX_new()创建会话环境,建立连接时要使用协议由TLS_server_method()来定。如果这一步出错,需要查看错误栈来查看原因
        if(nullptr == (ctx = SSL_CTX_new( GMTLS_server_method())))		//using sm3, TLSv1_2_method
        {
            ERR_print_errors_fp(stderr);
            break;
        }
//        SSL_CTX_set_security_level(ctx,0);


        // 双向验证
        // SSL_VERIFY_PEER---要求对证书进行认证,没有证书也会放行
        // SSL_VERIFY_FAIL_IF_NO_PEER_CERT---要求客户端需要提供证书,但验证发现单独使用没有证书也会放行
        SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT, nullptr);

        // 设置信任根证书
        if(SSL_CTX_load_verify_locations(ctx, CA_CERT_FILE, nullptr) != 1)
        {
            printf("SSL_CTX_load_verify_locations error\n");
            ERR_print_errors_fp(stderr);
            break;
        }

        // 签名证书和对应私钥
        if( 0>=SSL_CTX_use_certificate_file(ctx, SIGN_CERT_FILE, SSL_FILETYPE_PEM/*SSL_FILETYPE_ASN1*/) ) /* 为SSL会话加载用户证书 */
        {
            printf("SSL_CTX_use_certificate_file error!\n");
            ERR_print_errors_fp(stderr);
            break;
        }
        if( 0>=SSL_CTX_use_PrivateKey_file(ctx, SIGN_KEY_FILE, SSL_FILETYPE_PEM/*SSL_FILETYPE_ASN1*/) ) /* 为SSL会话加载用户私钥 */
        {
            printf("SSL_CTX_use_PrivateKey_file error!\n");
            ERR_print_errors_fp(stderr);
            break;
        }
        // 加密证书和对应私钥
        if(SSL_CTX_use_certificate_file(ctx, ENCODE_CERT_FILE, SSL_FILETYPE_PEM) <= 0)
        {
            printf("SSL_CTX_use_certificate_file error!\n");
            ERR_print_errors_fp(stderr);
            return -1;
        }
        if(SSL_CTX_use_PrivateKey_file(ctx, ENCODE_KEY_FILE, SSL_FILETYPE_PEM) <= 0)
        {
            printf("SSL_CTX_use_PrivateKey_file error!\n");
            ERR_print_errors_fp(stderr);
            return -1;
        }

        /* 检查用户私钥是否正确 */
        if(!SSL_CTX_check_private_key(ctx))                                 										 /* 验证私钥和证书是否相符 */
        {
            printf("SSL_CTX_check_private_key error!\n");
            ERR_print_errors_fp(stderr);
            break;
        }

        if (listen(listen_fd, lisnum) == -1) {
            perror("listen wrong\n");
            exit(1);
        } else
            printf("begin listen\n");

        len = sizeof(struct sockaddr);
        /* 等待客户端连上来 */
        if ((accept_fd = accept(listen_fd, (struct sockaddr *) &client_addr, &len))
            == -1) {
            perror("accept wrong\n");
            exit(errno);
        } else{
            printf("server: got connection from %s, port %d, socket %d\n",
                   inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port),
                   accept_fd);
        }

        ssl = SSL_new(ctx); /* 基于 ctx 产生一个新的 SSL */
        SSL_set_fd(ssl, accept_fd); /* 将连接用户的 socket 加入到 SSL */
        /* 建立 SSL 连接 */
        if (SSL_accept(ssl) == -1) {
            perror("accept wrong\n");
            SSL_shutdown(ssl);
            SSL_free(ssl);
            ssl= nullptr;
            close(accept_fd);
            accept_fd=-1;
            break;
        }
        ShowCerts(ssl);

        /* 开始处理每个新连接上的数据收发 */
        bzero(buf, MAXBUF + 1);
        strcpy(buf, "server->client");
        /* 发消息给客户端 */
        len = SSL_write(ssl, buf, strlen(buf));

        if (len <= 0) {
            printf("消息'%s'发送失败!错误代码是%d,错误信息是'%s'\n", buf, errno,
                   strerror(errno));
            goto finish;
        } else
            printf("消息'%s'发送成功,共发送了%d个字节!\n", buf, len);

        bzero(buf, MAXBUF + 1);
        /* 接收客户端的消息 */
        len = SSL_read(ssl, buf, MAXBUF);
        if (len > 0)
            printf("接收消息成功:'%s',共%d个字节的数据\n", buf, len);
        else
            printf("消息接收失败!错误代码是%d,错误信息是'%s'\n",
                   errno, strerror(errno));
        /* 处理每个新连接上的数据收发结束 */
        finish:
        /* 关闭 SSL 连接 */
        SSL_shutdown(ssl);
        /* 释放 SSL */
        SSL_free(ssl);
        ssl = nullptr;
        /* 关闭 socket */
        close(accept_fd);
        accept_fd = -1;
    }while(1);

    /* 关闭监听的 socket */
    close(listen_fd);
    listen_fd = -1;
    /* 释放 CTX */
    SSL_CTX_free(ctx);
    ctx = nullptr;
    return 0;
}

客户端代码

#include <cstdio>
#include <cstring>
#include <cerrno>
#include <sys/socket.h>
#include <cstdlib>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <openssl/ssl.h>
#include <openssl/err.h>

#define MAXBUF 1024
//#define CA_CERT_FILE "/home/chy-cpabe/GMSSL_certificate/sm2Certs/CA.cert.pem"
//#define CS_CERT_FILE "/home/chy-cpabe/GMSSL_certificate/sm2Certs/CS.cert.pem"
//#define CS_KEY_FILE "/home/chy-cpabe/GMSSL_certificate/sm2Certs/CS.key.pem"
//#define CE_CERT_FILE "/home/chy-cpabe/GMSSL_certificate/sm2Certs/CE.cert.pem"
//#define CE_KEY_FILE "/home/chy-cpabe/GMSSL_certificate/sm2Certs/CE.key.pem"

#define CA_CERT_FILE "/home/chy-cpabe/tmp/first/rootcert.pem"
#define CS_CERT_FILE "/home/chy-cpabe/tmp/first/sign.pem"
#define CS_KEY_FILE "/home/chy-cpabe/tmp/first/sign.key"
#define CE_CERT_FILE "/home/chy-cpabe/tmp/first/encrypt.pem"
#define CE_KEY_FILE "/home/chy-cpabe/tmp/first/encrypt.key"
void ShowCerts(SSL * ssl)
{
    X509 *cert;
    char *line;

    cert = SSL_get_peer_certificate(ssl);
    // SSL_get_verify_result()是重点,SSL_CTX_set_verify()只是配置启不启用并没有执行认证,调用该函数才会真证进行证书认证
    // 如果验证不通过,那么程序抛出异常中止连接
    if(SSL_get_verify_result(ssl) == X509_V_OK){
        printf("证书验证通过\n");
    }
    if (cert != nullptr) {
        printf("数字证书信息:\n");
        line = X509_NAME_oneline(X509_get_subject_name(cert), nullptr, 0);
        printf("证书: %s\n", line);
        free(line);
        line = X509_NAME_oneline(X509_get_issuer_name(cert), nullptr, 0);
        printf("颁发者: %s\n", line);
        free(line);
        X509_free(cert);
    } else
        printf("无证书信息!\n");
}

static void PrintData(char *p, char *buf,int len,char *filename)
{
    char *name=p;
    printf("%s[%d]:\n",p,len);
    for (p=buf; p && p++-buf<len;)
        printf("%02x%c",(unsigned char)p[-1],(!((p-buf)%16) || p-buf==len)?'\n':' ');
//	if (filename) FileWrite(name,buf,len,filename);
}

int main(int argc, char **argv)
{
    int sock_fd = -1;            /* TCP套接字    */
    int len = 0;                 /* SSL会话环境 */
    SSL *ssl = nullptr;          /* SSL安全套接字 */
    struct sockaddr_in ser_addr; /* 服务器地址 */
    bzero(&ser_addr, sizeof(ser_addr));
    SSL_CTX *ctx = nullptr;
    char buffer[MAXBUF + 1];

    if( argc != 3 )
    {
        printf("argcment wrong:ip port content\n");
        exit(0);
    }

    /* SSL 库初始化,参看 ssl-server.c 代码 */
    SSL_library_init();
    SSLeay_add_ssl_algorithms();
    OpenSSL_add_all_algorithms();
    SSL_load_error_strings();
//    ERR_load_BIO_strings();

    do{
        /* 申请SSL会话环境 */
        if( nullptr==(ctx=SSL_CTX_new(GMTLS_client_method())) )    //使用SSL_CTX_new()创建会话环境,建立连接时要使用协议由TLS_client_method()来定,服务器由对应的TLS_server_method()来定。如果这一步出错,需要查看错误栈来查看原因
        {
            printf("SSL_CTX_new error!\n");
            ERR_print_errors_fp(stderr);
            break;
        }
        // 双向验证
        // SSL_VERIFY_PEER---要求对证书进行认证,没有证书也会放行
        // SSL_VERIFY_FAIL_IF_NO_PEER_CERT---要求客户端需要提供证书,但验证发现单独使用没有证书也会放行
        SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT, nullptr);
//        if(SSL_CTX_set_cipher_list(ctx, "ECC-SM2-WITH-SM4-SM3") <= 0){
//            printf("SSL_CTX_set_cipher_list error!\n");
//            ERR_print_errors_fp(stderr);
//            exit(1);
//        }
        // 设置信任根证书
        if(SSL_CTX_load_verify_locations(ctx, CA_CERT_FILE, nullptr) != 1)
        {
            printf("SSL_CTX_load_verify_locations error!\n");
            ERR_print_errors_fp(stderr);
            exit(1);
        }

        // 签名证书和对应私钥
        if (SSL_CTX_use_certificate_file(ctx, CS_CERT_FILE, SSL_FILETYPE_PEM) <= 0)
        {
            printf("SSL_CTX_use_certificate_file error!\n");
            ERR_print_errors_fp(stderr);
            exit(1);
        }
        if (SSL_CTX_use_PrivateKey_file(ctx, CS_KEY_FILE, SSL_FILETYPE_PEM) <= 0)
        {
            printf("SSL_CTX_use_PrivateKey_file error!\n");
            ERR_print_errors_fp(stderr);
            exit(1);
        }
        // 加密证书和对应私钥
        if(SSL_CTX_use_certificate_file(ctx, CE_CERT_FILE, SSL_FILETYPE_PEM) <= 0)
        {
            printf("SSL_CTX_use_certificate_file error!\n");
            ERR_print_errors_fp(stderr);
            return -1;
        }

        if(SSL_CTX_use_PrivateKey_file(ctx, CE_KEY_FILE, SSL_FILETYPE_PEM) <= 0)
        {
            printf("SSL_CTX_use_PrivateKey_file error!\n");
            ERR_print_errors_fp(stderr);
            return -1;
        }
        //判定私钥是否正确
        if (!SSL_CTX_check_private_key(ctx)) {
            printf("SSL_CTX_check_private_key error!\n");
            ERR_print_errors_fp(stderr);
            exit(1);
        }
//        SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY);
        /* 创建一个 socket 用于 tcp 通信 */
        if(-1==(sock_fd=socket(AF_INET, SOCK_STREAM, 0)) )
        {
            printf("creat socket wrong\n");
            break;
        }
        printf("socket created\n");
        /* 初始化服务器端(对方)的地址和端口信息 */
        ser_addr.sin_family = AF_INET;
        ser_addr.sin_port = htons(atoi(argv[2]));
        ser_addr.sin_addr.s_addr = inet_addr(argv[1]);

        printf("address created\n");
        //建立连接
        if( -1==(connect(sock_fd, (struct sockaddr *)&ser_addr, sizeof(ser_addr))) )
        {
            printf("connect wrong\n");
            break;
        }
        printf("server connected\n");

        /* 基于 ctx 产生一个新的 SSL */
        ssl = SSL_new(ctx);
        SSL_set_fd(ssl, sock_fd);
        /* 建立 SSL 连接 */
        if (SSL_connect(ssl) == -1)
            ERR_print_errors_fp(stderr);
        else {
            printf("The relevant information is as follows:\n");
            printf("-->ssl version %s\n",SSL_get_version(ssl));
            printf("-->ssleay version %s\n",SSLeay_version(0));
            printf("-->Connected with %s encryption\n", SSL_get_cipher(ssl));
            ShowCerts(ssl);
        }

        //导出key和salt
        unsigned char buf[16];
        int err = -1;
        err = SSL_export_keying_material(ssl, buf, 16, nullptr,0, nullptr, 0, 1);
        if(err != 1){
            printf("SSL_export_keying_material error,err=%d\n",err);
        }else{
            PrintData("SSL_export_keying_material", (char*)buf, 16, nullptr);
        }


        /* 接收对方发过来的消息,最多接收 MAXBUF 个字节 */
        bzero(buffer, MAXBUF + 1);
        /* 接收服务器来的消息 */
        len = SSL_read(ssl, buffer, MAXBUF);
        if (len > 0)
            printf("接收消息成功:'%s',共%d个字节的数据\n",
                   buffer, len);
        else {
            printf
                    ("消息接收失败!错误代码是%d,错误信息是'%s'\n",
                     errno, strerror(errno));
            goto finish;
        }
        bzero(buffer, MAXBUF + 1);
        strcpy(buffer, "from client->server");
        /* 发消息给服务器 */
        len = SSL_write(ssl, buffer, strlen(buffer));
        if (len < 0)
            printf
                    ("消息'%s'发送失败!错误代码是%d,错误信息是'%s'\n",
                     buffer, errno, strerror(errno));
        else
            printf("消息'%s'发送成功,共发送了%d个字节!\n",
                   buffer, len);

        /* 处理每个新连接上的数据收发结束 */
        finish:
        /* 关闭 SSL 连接 */
        SSL_shutdown(ssl);
        /* 释放 SSL */
        SSL_free(ssl);
        ssl = nullptr;
    }while(0);

    /* 关闭socket */
    close(sock_fd);
    sock_fd = -1;
    /* 释放 CTX */
    SSL_CTX_free(ctx);
    ctx = nullptr;
    return 0;
}

注意事项

### 回答1: 国密CA的生成和签发涉及到应用数据国密加密、签名和解密。国密CA是国密算法的证书颁发机构,负责颁发和管理数字证书,确保数据的安全性和可信度。 首先,生成国密CA需要遵循相关的标准和规范。证书颁发机构需要进行身份验证,确保其具备发放数字证书的资质和能力。生成国密CA时还需要选择合适的国密算法,如SM2、SM3和SM4等,以保证数据的加密和签名安全。 生成国密CA后,可以开始应用数据的国密加密、签名和解密。在使用国密算法进行加密时,首先需要生成一对密钥,包括一个公钥和一个私钥。公钥用于加密数据,私钥用于解密数据。通过使用SM2算法对数据进行加密,可以保证数据的机密性和安全性。 对数据进行签名时,需要使用私钥对数据进行加密,并生成数字签名。通过使用SM2算法进行签名,可以确保签名的准确性和不可篡改性。签名后的数据可以与数字证书一起传播,用于证明数据的完整性和来源可靠性。 当接收方收到加密或签名数据后,使用相应的公钥进行解密或验证。使用SM2算法进行解密和验证,可以保证数据的解密正确性和签名的有效性。只有持有正确的私钥才能解密数据,只有正确的公钥能够验证签名。 总之,国密CA的生成和签发涉及到应用数据的加密、签名和解密。通过使用国密算法,可以保证数据的机密性、完整性和可信度。这些安全机制的应用使得数据传输和存储更加安全可靠。 ### 回答2: 国密CA(中国密码局认证中心)是由中国密码局授权的可信机构,负责国密算法下的数字证书的生成和签发。国密算法是中国自主研发的一种密码算法,用于保护数据的加密、签名和解密。 国密CA首先会生成一个根证书,该证书包含了国密算法所需的公钥和私钥等信息。根证书的私钥需要妥善保管,以确保证书的安全性。 在使用国密CA生成证书时,首先需要生成证书请求CSR(Certificate Signing Request)。CSR包含了证书的一些基本信息,比如需签发的证书的名称、密钥等。CSR由应用程序生成后,发送给国密CA。 国密CA收到CSR后,会对其进行验证,并使用根证书的私钥进行签名。签名后的证书会包含申请者的公钥以及其他相关信息,比如证书的有效期等。国密CA对签发的证书进行数字签名,以保证证书的真实性和完整性。 当应用程序需要进行数据的国密加密、签名或解密时,首先需要将数据进行相应的处理,然后使用证书中包含的公钥进行加密或签名操作。对于解密操作,则需要使用证书中对应的私钥进行解密。 国密CA的生成和签发过程保证了数字证书的可信和安全。应用程序可以通过使用国密算法下的证书实现数据的加密、签名和解密,确保数据的安全性和完整性。国密算法在国内得到了广泛的应用和认可,对于保护数据的安全非常重要。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值