理解X509标准证书及其使用方法
文档更新说明
- 最后更新 2020年07月22日
- 首次更新 2020年07月22日
前言
入职安全公司一个月了, 很忙, 只剩下周日才有空(这句话可以细心品味一下😂), 周日还要去看房, 生活胖若两人. 趁今晚任务开发得差不多了, 抽空写一下博文, 算是对近一个月部分工作内容做个总结吧.
目前我负责MacOS桌面级服务进程的开发, 还有Mac GUI开发, 开发技术栈用的OC, C, 还有Golang, 接触的大部分都是之前做iOS没接触过的, 团队人数也挺多的, 基本上是对我以前短板的技能做一个的补充, 补充的技能包括: 参与中大型项目,多人协作,git管理,TCP/UDP通讯,多进程开发等, 对于之前做多了iOS应用层开发的我来说, 还是有很大进步的.
客户端用Golang? 这个我之前确实没想到, Golang一般是用在服务端的, 但是他在桌面服务进程上也能很好的发挥他的优势, 除了没有操作数据库之外, 其他都和服务端开发类似, 挺不错, 公司很多C++项目都慢慢转撑Golang了, 这算是以前学习Golang误打误撞, 变成今天工作利器了.
正文
说了这么多, 开始正文吧, 本文主要是总结一下近期用到的X509标准加密通讯, 这个标准确实是很不错, 很方便多端安全通讯, 实现起来也不复杂.
X509证书认证逻辑
可能有些人不知道什么是X509, 那应该知道HTTPS, TLS吧? 这两个协议用的就是X509证书认证原理, 还有平时做iOS开发用的那些证书杀的, 俗称数字签名, 用的都是X509这套东西, 我之前大多数是停留在理论知识的学习, 还有HTTPS这些的使用, 今天就来总结一下证书的生成, 自签名等逻辑, 以及在实际开发中如何发挥X509的威力!
相关文件扩展名的含义
先来说清楚X509体系里面一些不同格式的数据到底代表什么. 这部分摘自网络
我们已经知道有PEM和DER这两种编码格式,但文件扩展名并不一定就叫”PEM”或者”DER”,常见的扩展名除了PEM和DER还有以下这些,它们除了编码格式可能不同之外,内容也有差别,但大多数都能相互转换编码格式.
CRT - CRT应该是certificate的三个字母,其实还是证书的意思,常见于*NIX系统,有可能是PEM编码,也有可能是DER编码,大多数应该是PEM编码,相信你已经知道怎么辨别.
CER - 还是certificate,还是证书,常见于Windows系统,同样的,可能是PEM编码,也可能是DER编码,大多数应该是DER编码.
KEY - 通常用来存放一个公钥或者私钥,并非X.509证书,编码同样的,可能是PEM,也可能是DER.
JKS - 即Java Key Storage,这是Java的专利,跟OpenSSL关系不大,利用Java的一个叫”keytool”的工具,可以将PFX转为JKS,当然了,keytool也能直接生成JKS,不过在此就不多表了.
上面到两种编码格式, PEM是base64格式, DER则是二进制格式, 后续实例中, 我全部用的PEM格式, PEM格式比较方便在多端传输.
证书的制作
下面全部用OpenSSL示例, 具体对于到代码里怎么写,不同语言有不同的处理库, 只要用OpenSSL验证过, 基本没什么大问题
第一步, 生成私钥+请求文件
生成2048位私钥
1 | openssl genrsa -out ca.key 2048 |
请求文件对于做iOS的估计很熟悉, 一般申请APP的开发证书, 苹果要你传一个证书请求文件上去, 就是这个了.
1 | openssl req -new -sha256 -key ca.key -out ca.csr -subj "/C=CN/ST=GuangDong/L=ShenZhen/O=ROOT/OU=dc/CN=ROOT/emailAddress=test@xx.com" |
subj字段的内容其实就是证书发行者的一些信息, 规定使用sha256算法, 也是目前啊最可靠的散列算法了.
其中CN字段对应的是公司名字, 或者HTTPS常见的网站域名, 不过这个都不重要, 后续我们如果是客户端对服务端通讯的话, 可以直接把CN省略, 或者验证的时候忽略掉即可.
第二步, 生成CA证书
1 | openssl x509 -req -in ca.csr -out ca.crt -signkey ca.key -days 3650 -sha256 -extfile v3.ext |
上面的-extfile是可选的, 如果指定扩展了信息, 则会生成V3版本证书. 需要先创建文件 v3.ext, 内容如下:
1 | authorityKeyIdentifier=keyid,issuer |
ext信息具体可以怎么填写, 可以参考这个文档, 说得很清楚https://www.openssl.org/docs/manmaster/man5/x509v3_config.html
到这里, 就可以得到一个具备签发其他证书的权威CA根证书了, 接着就可以用这个证书来签发一级证书, 二级证书等.
第二步, 签发下级证书
证书签发原理, 之前写的HTTPS原理的文章有说到, 现在是站在实战的角度来看.
记得一开始的生成CA证书的时候输入了私钥吗? 其实这种叫做自签名, 而且没有指定生成证书的CA参数, 这样生成的证书里头, Subject(发行者)和Issuer(签发者)是同一个人, 而且还用CA证书自己的私钥为自己签名了(其实签名不签名都可以, 因为发行者和签发者是同一个人, 则证书的公钥默认就是发行者的有效公钥, 无需后续验证)
这了假设生成服务端证书, 还是一样先生成私钥和请求文件
1 | openssl genrsa -out server.key 2048 |
利用CA证书, 为服务端证书做一个签名
1 | openssl x509 -req -in server.csr -out server.crt -CA ca.crt -CAkey ca.key -CAcreateserial -days 3650 -sha256 -extfile v3.ext |
这里可以看出, 签发下级证书是需要上级证书的, 这里上级证书就是ca.crt, 这样服务端证书的Subject是服务端, 但是Issuer是CA证书的发行者. 到时候要认证服务端证书是否合法, 就要靠上级ca证书了
上面提到的签名, 数字签名的原理, 就是对一段数据, 这里是服务端证书数据部分, 做一次sha256散列运算, 得到256位运算结果, 再用上级CAkey进行加密后, 附在证书上.
到时候要认证服务端证书是否有效的人(比如浏览器), 就需要拿到签发者的公钥解密证书签名部分, 结合自己对服务端数据部分做sha256运算得到的值, 做一个比较, 如果结果一样, 那么服务端证书就是可信的. 这里应该说得很清楚了. HTTPS证书校验的核心原理也就是这块了.
注意: 如果ca证书不是根证书(也就是发行者和签发者不是同一个人), 那么就需要用同样的原理验证ca证书的合法性.
第三步, 如何校验证书的合法性
这一步是最重要的, 我们上面做了那么多证书, 目的就是为了验证合法性, 这样才能确定和自己通讯的一端是否是合法的.
验证二级证书是否合法, 只需要一个根证书即可验证
1 | openssl verify -CAfile ca.crt server.crt |
如果是验证多级证书是否合法, 则需要把证书的全部上级证书链都放进来一起验证
1 | # 如果有多个证书链, 则需要把每个上级证书的文件名改成 hash值.0(比如7a191709.0), 并且指定整个目录 |
上面说的把多个证书合并在一起, 合并的顺序看不同编程语言的要求. 如果是控制台用openssl的话, 上级证书放顶部, 如果是某些golang的库, 则上级证书放底部, 具体看文档说明.
开发中如何利用X509
代码大概可以这么写
上面说的是证书怎么制作, 具体到怎么用具体编程语言来动态生成证书, 这个还得具体看文档才知道. 我只做过golang版本的, 下面直接贴代码吧, 利用已经有的CA证书, 签发新的下级证书:
1 | package internal |
使用方法, 就是直接调用CreateCRTByPublicKey
函数, 传入要签发的公钥和CA证书+私钥. 另外的一些函数都是一些格式换行函数.
其中PEM格式是base64, 也就是字符串, 传参的时候直接把每一个字符都看成一个byte而已, 其实就是[]byte(“xxxxx”).
上面一大坨代码, 看不懂也无所谓, 查查文档就懂了. 重点是证书签发的流程.
安全认证的思路
认证思路, 总结起来大概就是几点
第一种, 数字签名
- 对数据做数字摘要, 用私钥加密, 也就是数字签名.
- 接收方收到数据, 结合发送放的证书信息, 提取公钥解密, 解密签名信息, 再和数据部分对比较, 确认数据完整性.
这种可以用在文件下载上, 对请求方做一个签名验证. 也可以用在对文件有效性判断上, 比如苹果系统用的最多的数字签名验证.
第二种, 可信任校验
这个就是HTTPS那种, 是实现TLS层的基石, 本质就是校验对方公钥是否可信, 从而明确是否信任对方, 并用对方的公钥解密数据, 可以做单向校验或者双向校验.