0x00 前言
遇到一个双向证书认证的APP,这个APP很奇怪,存在两个站点的双向认证,单纯的RSA-AES的mTLS还是简单的,但是还有一个站点是国密双证书认证的。那针对这个就有一些棘手了,所以需要做一定程度的研究才能解决问题。
0x01 mTLS
我们知道常规的TLS通信一般服务端并不会检验客户端的证书,但是在双向证书认证(mTLS)的场景下,就需要我们也获取到客户端的证书才能成功的建立链接。其中的工作流程如下:
1.客户端连接到服务器
2.服务器出示其TLS证书
3.客户端验证服务器的证书
4.客户端出示其TLS证书
5.服务器验证客户端的证书
6.服务器授予访问权限
7.客户端和服务器通过加密的TLS连接交换信息

在抓包的过程中如果使用Yakit并不能直接判断是mTLS,但是如果使用charles的话,就可以存在清晰的报错,提示是服务端拒绝了客户端证书。

面对这种场景首先尝试r0capture来把证书导出,会直接导出成.p12格式的文件。这里我们需要简单介绍一下p12的文件格式,p12文件通常是一个用于存储公钥和私钥的文件,并包含数字证书。那么每一个p12文件都会有一个密码来保护着它,我们可以从p12文件中分离出crt和key文件,前者就是单纯的证书,后者就是该证书对应的私钥。所以p12文件可以理解成一个保险柜,不仅存放着重要证件,还有私钥等等重要信息也存放在其中,被一个打开其的密码保护着。
0x02 证书格式
从文件格式类型来分类的话,证书分成两种
- Base64编码的文本格式。这种证书可以直接通过文本编辑器打开,并且编辑,常见的如PEM、CRT和key格式。
- Binary二进制文件。常见的有der证书格式,扩展名包括der和cer。
Linux系统使用crt,windows使用cer。
| 名词 | 含义 |
|---|---|
| X.509 | 一种通用的证书格式,包含证书持有人的公钥,加加密算法等信息 |
| pkcs1 ~pkcs12 | 公钥加密(非对称加密)的一种标准(Public Key Cryptography Standards),一般存储为 .pN,,.p12 是包含证书和私钥的封装格式 |
| *.der | 证书的二进制存储格式(不常用) |
| *.pem | 证书或密钥的 Base64 文本存储格式,可以单独存放证书或密钥,也可以同时存放证书或密钥 |
| *.key | 单独存放的 pem 格式的密钥,一般保存为 *.key |
| *.cer *.crt | 两个指的都是证书,Linux 下叫 crt,Windows 下叫 cer;存储格式可以是 pem,也可以是 der |
| *.csr | 证书签名请求(Certificate signing request),包含证书持有人的信息,如:国家,邮件,域名等信息 |
| *.pfx | 微软 IIS 的实现有点像p12文件格式一样 |
| *.jks | Java 的 keytool 实现的证书格式 |
那么hook出来p12证书之后,我们需要对其进行分离出证书和私钥
1 | openssl pkcs12 -in xxx.p12 -clcerts -nokeys -out client.crt -legacy |
直接使用curl访问站点会报错

这样设置好证书和私钥之后就不会报错了
1 | curl --cert client.crt --key client.key -X POST -H 'Accept: Application/JSON,*/*' -H 'Ver: 2' -H 'Content-Type: application/json; charset=utf-8' https://xxx.com --output - |
0x03 国密双证书
GMTLS就是国密TLS,其设计在原本的TLS的基础上增加了符合中国密码标准的独特设计。国密算法(SM2,SM3,SM4)替代了国际通用算法,其中:
- SM2:用于非对称加密和数字签名(替代RSA/ECDSA)
- SM3:用于哈希算法(替代SHA-256)
- SM4:用于对称加密(替代AES)
国密双证书体系的核心创新在于:将加密和签名两种用途的证书分离。
那么在curl工具本身并不支持国密通信,所以需要使用支持的工具,那么gmcurl做了国密适配版本的命令行工具。但是首先需要验证cert证书文件和key的私钥文件是否一致。
1 | ❯ openssl x509 -pubkey -noout -in XXS.cert.pem |
根据以上执行内容可以判断,证书中的公钥和私钥对应的公钥完全一致,说明这是正确的一对套件。现在需要判断两张证书哪张是签名证书哪张是加密证书
1 | openssl x509 -in XXS.cert.pem -text -noout | grep -A 5 "Key Usage" |
可以看到XXS.cert.pem证书是Digital Signature 数字签名证书,XXE.cert.pem证书是Key Encipherment加密证书。之后使用gmcurl指定双证书进行站点访问,成功通过了国密的mTLS认证。

0x04 Yakit导入
对于国密mTLS来说,一般仅导入签名证书就可以。但是导入之后抓包还是报错了,使用tcpdump抓包看看。
1 | ./tcpdump -i any -s 0 port 443 -w result.pcap |
抓包之后才发现原来是Unknown (CA)的问题,客户端还会检测我Yakit服务端的证书呢,还得继续逆向,哎。

(此处省略几行frida代码,反正就是过了客户端检测服务端证书了!)之后使用Yakit将证书导入就可以了

参考链接:
https://www.cloudflare-cn.com/learning/access-management/what-is-mutual-tls/
https://help.aliyun.com/zh/es/user-guide/es-p12-file-decryption-method
https://blog.csdn.net/crown_0726/article/details/129854566