一 改造背景
在介绍国密之前,我们先介绍下目前使用最广的Https, 而Https包含Http和SSL/TLS两部分,介绍如下:
- HTTP:(HyperText Transfer Protocol)超文本传输协议,相信大家都不陌生,打开浏览器就能看到。
- SSL:( Secure Sockets Layer )安全套件字层。可分为两层: SSL记录协议(SSL Record Protocol)和 SSL握手协议(SSL Handshake Protocol)。
- TLS:( Transport Layer Security )传输层安全协议。也分为两层 TLS 记录协议(TLS Record)和 TLS 握手协议(TLS Handshake)。
TLS就是建立在SSL3.0协议规范之上的协议。所以很多时候你会发现他们俩是被绑定在一起呈现的SSL/TLS。
但是越来越多的国际通用密码算法屡屡被传出被破解、被攻击的传闻,存在较高的安全风险。此外,当前我国金融系统大多采用国外制定的加密算法,存在着大量的不可控因素,一旦被不法分子利用攻击,所产生的损失将不可估量。所以国密改造提上日程。国密SSL通信依据的协议是中国人民共和国密码行业标准《SSL VPN技术规范GM/T 0024--2014》协议(链接)。其协议流程和传统的使用RSA证书的TLS协议流程基本一致,但是过程中使用的核心算法已经全部切换到国密相关的算法实现上,保证了通信的安全。所以监管机构开始推动国内金融行业进行国密改造。但是在我们日常运维的传统金融客户里,大部分加密方式还是不支持国密的相关加密方案,尤其是金融行业的银行App如何在现有的环境里快速支持国密改造,成为客户关注的重点。在我们和客户一起进行了多个国密项目的改造之后,这里分享下最近几个国密改造项目的积累的相关技术。
二 国密SSL改造
1. ProtocolVersion
TLS协议定义有三个版本号,为0x0301、0x0302、0x0303,分别对应TLS 1.0、1.1、1.2。国密SSL为了避免冲突,选择了0x0101。这在实现上带来一定的麻烦,因为现有很多网络库会认为这是一个无效的协议版本,需要一一将判断修改过来。国密SSL协议规范是TLS 1.1和TLS 1.2的混合体,大部分情况下参考TLS 1.1就可以了,少数地方又参考了TLS 1.2。
从事网络通信相关开发的朋友,应该对网络抓包很熟悉。通常在PC上使用的抓包软件为wireshark,在Android系统上的抓包工具有tcpdump。但是国密为SSL版本号定义了一个非常坑爹的值:0x0101,而大多数软件包对0x0300以下的值都会被认为是一个无效的版本号,所以如果使用标准版的wireshark抓国密SSL包,结果是这样的:
标准版wireshark抓包
幸运的是,已经有朋友在wireshark上增加了国密SSL支持,抓包结果如下:
支持国密版wireshark抓包
这个支持国密的wireshark项目地址为:https://github.com/pengtianabc/wireshark-gm
这个项目的release中有Windows的安装包,如果是Windows开发者,不用过多折腾,安装上即可。
2. CipherSuite
在SSL通信开始,双方就需要进行协商,采用何种算法进行通信。这里需要重点理解密码套件(CipherSuite)的概念。密码套件决定了本次连接采用哪一种加密算法、密钥协商算法、HMAC算法,协商的结果就是双方都认可的密码套件,如下图所示。客户端在Client_Hello里就携带了自己能支持的加密套件,服务端根据自身的协议进行选择。在实际的应用中,如果客户端支持的加密套件很多,那么客户端会逐步的把所有支持的加密套件都发送给服务端,供服务端选择。
国密SSL也定义了一些密码套件,如下图所示在我们的实际应用中现在在国密的SSL通信中主要使用的还是ECC_SM4_SM3(这里的ECC其实就是指SM2,SM2也是ECC改造的国密算法)。现在常见的支持国密通信的软件主要也是支持这个加密套件。通过ECC-SM2-WITH-SM4-SM3,我们可以看到,这个密码套件使用国密的 SM2 做签名验签,SM3 做 MAC 摘要计算,SM4 做对称加密,密钥协商为使用 SM2 非对称加密,由于 SM2 本身是 ECC 椭圆曲线算法的实现,因此也称 ECC 协商
3. 握手国密改造
一次典型的SSL 通信握手过程如下图所示。SSL 安全通信的本质根据协商生成的对称加密密钥对后续通信内容进行安全加密。因此改造工作的重要部分是实现一个支持国密算法的SSL实现模块,对通信消息中的密钥协商部分进行国密化适配。
SSL握手流程如下:
1 ClientHello
由客户端发送"client hello"消息向服务器发起握手请求。该消息包括支持的协议版本, 如 TLS 1.2; 一个客户端生成的随机数; 支持的密码学套件(比如 SM2_WITH_SM4_SM3(即使用国密的 SM2 做签名验签,SM3 做 MAC 摘要计算,SM4 做对称加密,密钥协商为使用 SM2 非对称加密,由于 SM2 本身是 ECC 椭圆曲线算法的实现,因此也称 ECC 协商)
2. ServerHello
1.服务端生成的随机数下发
2.确认与客户端使用的加密通信协议版本,如果客户端发送了不支持的版本,服务器将关闭加密通信
3.确认接下来协商会话密钥使用的加密方法,从客户端发送的加密方法列表中选择安全性最高的一个
3. Certificate
根据国密标准中定义,服务器必须双证书模式,即签名证书和加密证书必须分开,因此服务器发送证书需要改为发送两张证书。与标准TLS报文格式一样,但至少要包含两个证书,签名证书在前,加密证书在后。如果牵扯到证书链,问题就复杂了,而且协议这里也没有规定清楚。是签名证书 + 证书链 + 加密证书,还是签名证书 + 加密证书 + 证书链?在实现中发现TASSL采用的是前者,而沃通测试网站采用后者。在编码时请注意,最好是两者都兼容。
4. ServerKeyExchange
根据握手选择的密钥协商算法,需要分别适配 ECC 和 ECDHE 协商算法
5. ServerHelloDone
向客户端发送 Server Hello Done 消息,通知客户端,服务端已经发送了全部的相关信息。
6. ClientKeyExchange
客户端根据 ServerKeyExchange 中的密钥原材料,生成对应的另一半密钥原材料。
7. ChangeCipherSpec
通知服务器端,密钥协商完毕,接下来需要使用协商好的会话密钥来通信,由于该消息不参与消息 hash 的计算,因此往往被各个 tls 实现用于携带自定义的扩展字段。
8. Finished
发送client finished事件
9. ChangeCipherSpec
接受sendChangeCipherSpec的回复报文
10. Finished
收到client finished的回复的server finished报文
4. 双证书
证书部分是国密SSL协议与标准TLS协议最大的区别,国密为双证书体系。握手中需要发送签名证书以及加密证书,并且一般要求签名证书再前,加密证书在后。签名证书仅用于验证身份,其私钥由自己生成,由CA机构签发;加密证书用于数据加密,其私钥并非自己生成,而是CA机构生成后与证书以及保存。
5. 国密CA证书校验
国密证书指使用国密算法(SM2-SM3)的标准X509格式证书,需要将国密CA证书内置,CA证书包含了当前证书的公钥信息。内置后才可以支持国密证书校验。证书链的Root CA是在前面握手的时候,通过ServerCertificate下发的,可以通过ServerCertificate的Root CA对当前的客户端预置的国密公钥CA进行验证。
6. https接口改造
通过以上章节,主要完成通过SSL层面的国密SSL改造,但是在我们日常使用过程中,真正面向业务的,更多的是使用Http协议的接口,比如常用的HttpsURLConnection模块。所以我们需要把HttpsURLConnection的底层SSL实现替换到国密的SSL实现。过程如下:
- 通过BouncyCastleProvider提供国密的相关算法实现
2. 生成TrustManagerFactory对象,用做内置的域名CA证书校验
- 通过HttpsURLConnection模块提供的setSSLSocketFactory接口,用做设置支持国密的SSLSocketFactory
- 请求完成后,我通过getCipherSuite接口获取请求使用的密码套件,判断是否走了国密请求。