参考链接
- SSL通信双方如何判断对方采用了国密 - Bigben - 博客园
- 滑动验证页面 OpenSSL TLS1.2密码套件推荐
- 安全的TLS协议 | Hexo
OID
- OID是由ISO/IEC、ITU-T国际标准化组织上世纪80年代联合提出的标识机制,其野心很大,为任何类型的对象(包括实体对象、虚拟对象和组合对象)进行全球唯一命名。
- 通过唯一的编码,我们就可以识别出对象。但要为所有对象进行唯一命名,其难度和工作量都很大,所以它采用了分层树形结构。
- OID对应于“OID树”或层次结构中的一个节点,该节点是使用ITU的OID标准X.660正式定义的。
- 树的根包含以下三个起点:0:ITU-T1:ISO2:ITU-T/ISO联合发布
- 树中的每个节点都由一系列由句点分隔的整数表示。比如,表示英特尔公司的OID如下所示:1.3.6.1.4.1.343
- 1 ISO1.3 识别组织1.3.6 美国国防部1.3.6.1 互联网1.3.6.1.4 私人1.3.6.1.4.1 IANA企业编号 1.3.6.1.4.1.343 因特尔公司
-
这里采用分而治之的策略,解决编码重复问题。树中的每个节点均由分配机构控制,该机构可以在该节点下定义子节点,并为子节点委托分配机构。在上面的例子中,根节点“1”下的节点号由ISO分配,“1.3.6”下的节点由美国国防部分配,“1.3.6.1.4.1”下的节点由IANA分配,“1.3.6.1.4.1.343”下的节点由英特尔公司分配,依此类推。只要有需求,可以一直往下分配下去,也解决了编码不够的问题。
- 在实际应用中,ISO/IEC国际标准化机构维护顶层OID标签,各个国家负责该国家分支下的OID分配、注册和解析等工作,实现自我管理和维护。相应的,针对国密,国家密码局也定义了各类对象的标识符:
- GMT 0006-2012 密码应用标识规范.pdf GM-Standards/GMT 0006-2012 密码应用标识规范.pdf at master · guanzhi/GM-Standards · GitHub
- 像"1.2.156.10197.1.100"这种字符串,人读起来比较直观,但对于计算机对字符串处理的效率非常低,所以在程序代码中,对OID又进行了一次编码。
- 通过 objects.pl 脚本,生成 obj_data.h文件,这个才是在代码中使用到的OID编码。 boringssl也类似,不过其采用了 go 语言编写的转换脚本。
- 在GmSSL源码中,原始的OIDs定义在crypto/objects/objects.txt文件中,在文件的尾部,我们可以看到国密的相关定义:
国密相关定义
sm-scheme 102 1 : SM1-ECB : sm1-ecb
sm-scheme 102 2 : SM1-CBC : sm1-cbc
!Cname sm1-ofb128
sm-scheme 102 3 : SM1-OFB : sm1-ofb
!Cname sm1-cfb128
sm-scheme 102 4 : SM1-CFB : sm1-cfb
sm-scheme 102 5 : SM1-CFB1 : sm1-cfb1
sm-scheme 102 6 : SM1-CFB8 : sm1-cfb8# SM2 OIDs
sm-scheme 301 : sm2p256v1
sm-scheme 301 1 : sm2sign
sm-scheme 301 2 : sm2exchange
sm-scheme 301 3 : sm2encryptsm-scheme 501 : SM2Sign-with-SM3 : sm2sign-with-sm3
sm-scheme 502 : SM2Sign-with-SHA1 : sm2sign-with-sha1
sm-scheme 503 : SM2Sign-with-SHA256 : sm2sign-with-sha256
sm-scheme 504 : SM2Sign-with-SHA511 : sm2sign-with-sha512
sm-scheme 505 : SM2Sign-with-SHA224 : sm2sign-with-sha224
sm-scheme 506 : SM2Sign-with-SHA384 : sm2sign-with-sha384
sm-scheme 507 : SM2Sign-with-RMD160 : sm2sign-with-rmd160
sm-scheme 520 : SM2Sign-with-Whirlpool : sm2sign-with-whirlpool
sm-scheme 521 : SM2Sign-with-Blake2b512 : sm2sign-with-blake2b512
sm-scheme 522 : SM2Sign-with-Blake2s256 : sm2sign-with-blake2s256sm2encrypt 1 : sm2encrypt-recommendedParameters
sm2encrypt 2 : sm2encrypt-specifiedParameters
sm2encrypt 2 1 : sm2encrypt-with-sm3
sm2encrypt 2 2 : sm2encrypt-with-sha1
sm2encrypt 2 3 : sm2encrypt-with-sha224
sm2encrypt 2 4 : sm2encrypt-with-sha256
sm2encrypt 2 5 : sm2encrypt-with-sha384
sm2encrypt 2 6 : sm2encrypt-with-sha512
sm2encrypt 2 7 : sm2encrypt-with-rmd160
sm2encrypt 2 8 : sm2encrypt-with-whirlpool
sm2encrypt 2 9 : sm2encrypt-with-blake2b512
sm2encrypt 2 10 : sm2encrypt-with-blake2s256
sm2encrypt 2 11 : sm2encrypt-with-md5# SM3
sm-scheme 401 : SM3 : sm3
sm-scheme 401 2 : HMAC-SM3 : hmac-sm3# SM4
sm-scheme 104 1 : SMS4-ECB : sms4-ecb
sm-scheme 104 2 : SMS4-CBC : sms4-cbc
!Cname sms4-ofb128
sm-scheme 104 3 : SMS4-OFB : sms4-ofb
!Cname sms4-cfb128
sm-scheme 104 4 : SMS4-CFB : sms4-cfb
sm-scheme 104 5 : SMS4-CFB1 : sms4-cfb1
sm-scheme 104 6 : SMS4-CFB8 : sms4-cfb8
sm-scheme 104 7 : SMS4-CTR : sms4-ctr
sm-scheme 104 8 : SMS4-GCM : sms4-gcm
sm-scheme 104 9 : SMS4-CCM : sms4-ccm
sm-scheme 104 10 : SMS4-XTS : sms4-xts
sm-scheme 104 11 : SMS4-WRAP : sms4-wrap
sm-scheme 104 12 : SMS4-WRAP-PAD : sms4-wrap-pad
sm-scheme 104 100 : SMS4-OCB : sms4-ocb# SM5/6/7/8
sm-scheme 201 : SM5 : sm5
sm-scheme 101 1 : SM6-ECB : sm6-ecb
sm-scheme 101 2 : SM6-CBC : sm6-cbc
!Cname sm6-ofb128
sm-scheme 101 3 : SM6-OFB : sm6-ofb
!Cname sm6-cfb128
sm-scheme 101 4 : SM6-CFB : sm6-cfb
!Alias sm7 sm-scheme 105
!Alias sm8 sm-scheme 106# SM9
sm-scheme 302 : id-sm9PublicKey
sm-scheme 302 1 : sm9sign
sm-scheme 302 2 : sm9keyagreement
sm-scheme 302 3 : sm9encrypt
sm-scheme 302 4 : sm9hash1
sm-scheme 303 7 : sm9hash2
sm-scheme 302 5 : sm9kdf
sm-scheme 302 6 : id-sm9MasterSecret
sm-scheme 302 6 1 : sm9bn256v1
sm9sign 1 : sm9sign-with-sm3
sm9sign 2 : sm9sign-with-sha256
sm9encrypt 1 : sm9encrypt-with-sm3-xor
sm9encrypt 2 : sm9encrypt-with-sm3-sms4-cbc
sm9encrypt 3 : sm9encrypt-with-sm3-sms4-ctr
sm9hash1 1 : sm9hash1-with-sm3
sm9hash1 2 : sm9hash1-with-sha256
sm9hash2 1 : sm9hash2-with-sm3
sm9hash2 2 : sm9hash2-with-sha256
sm9kdf 1 : sm9kdf-with-sm3
sm9kdf 2 : sm9kdf-with-sha256
密码套件
- 仅仅定义了OID还不够,因为国密并不是一个单一的标准,包含了很多加密、解密、哈希等算法,可以形成很多种组合,不能简单假定对方采用了国密就可以建立通信。
- 在SSL通信开始,双方就需要进行协商,采用何种算法进行通信。这就引出了密码套件(CipherSuite)的概念。
- 密码套件是一系列密码学算法的组合,主要包含多个密码学算法:
- 密钥交换算法:用于握手过程中建立信道,一般采用非对称加密算法
- 数据加密算法:用于信道建立之后的加密传输数据,一般采用对称加密算法
- 消息验证算法:用于验证消息的完整性,包括整个握手流程的完整性(例如TLS握手的最后一步就是一个对已有的握手消息的全盘哈希计算的过程)
- 密码套件的构成如下图所示:
- /home/chy-cpabe/Downloads/GmSSL-master/README.md 文件内部包含了国密算法套件的定义
- 代码可以参考 gmtls.h 文件,也可以使用GMSSL的命令查看所支持的密码套件: openssl ciphers -V | column -t
- 如果使用gmssl,将openssl替换成gmssl即可,如果未配置全局路径,需要到编译后生成的可执行脚本处执行上述命令
- 第一列:数值代表密码套件的编号,每个密码套件的编号由IANA定义。
- 第二列:代表密码套件的名称,虽然密码套件编号是一致的,不同的TLS/SSL协议实现其使用的名称可能是不一样的。
- 第三列:表示该密码套件适用于哪个TLS/SSL版本的协议。
- 第四列:表示密钥协商算法。
- 第五列:表示身份验证算法。
- 第六列:表示加密算法、加密模式、密钥长度。
- 第七列:表示HMAC算法。其中AEAD表示采用的是AEAD加密模式(比如AES128-GCM),无须HMAC算法。
操作流程
- 一个密码学套件是完成整个TLS握手的关键。在TLS握手的时候ClientHello里面携带了客户端支持的密码学套件列表,ServerHello中携带了Server根据Client提供的密码学套件列表中选择的本地也支持的密码学套件。
- 也就是说选择使用什么密码学套件的选择权在Server的手里,这句话感觉有问题,客户端先选择密码学套件列表,看服务器是否支持,或者服务器考虑到算法的安全性会禁用不安全的密码学套件 我的这句话有问题,借此提醒
注意事项
- 值得注意的是,这里的编码又没有采用OID,这也是开发过程中需要注意的,不同的地方使用了不同标准规范,需要在开发中翻阅相应的协议和规范。
- 可以看出,GmSSL并没有实现所有的国密的密码套件,但同时又扩充了几个标准未定义的密码套件,比如ECDHE-SM2-WITH-SMS4-GCM-SM3、ECDHE-SM2-WITH-SMS4-SM3等。这就体现出协商的重要性了,对双方所支持的密码套件取一个交集,从中选择一个。如果不存在交集,协商也就不成功。注意,协商过程中服务器端可能会禁用一些不太安全的密码套件(比如历史遗留的一些现今已不太安全的算法),这时即使双方都支持,也可能协商不成功。
- 我们可以测试服务器是否支持某个特定的密码套件:
代码编写
- Openssl定义了4中选择符号:“+”,“-”,“!”,“@”。其中,“+”表示取交集;“-”表示临时删除一个算法;“!”表示永久删除一个算法;“@“表示了排序方法。
- 多个描述之间可以用“:”或“,”或空格或“;”来分开。选择加密套件的时候按照从左到的右顺序构成双向链表,存放与内存中。
ALL:!DH:RC4+RSA:+SSLv2:@STRENGTH
- 表示的意义是:首先选择所有的加密套件,然后在得到的双向链表之中去掉密钥交换采用DH的加密套件;加入包含RC4对称加密算法与RSA身份认证算法的交集加密套件;再将支持老版本SSLv2的加密套件放在尾部;最后,
@STRENGTH
表示将得到的结果按照安全强度进行排序。 - SSL建立链接之前,客户端和服务器端用openssl函数来设置自己支持的加密套件。主要的函数有:
int SSL_set_cipher_list(SSL *s, const char *str);
int SSL_CTX_set_cipher_list(SSL_CTX *ctx, const char *str);
- 比如只设置一种加密套件:
int ret=SSL_set_cipher_list(ssl,"RC4-MD5");
- 如果服务端只设置了一种加密套件,那么客户端要么接受要么返回错误。
- 加密套件的选择是由服务端做出的。客户端没有权利指定其他加密套件。