哈哈哈没想到勤劳勇敢的键者居然会那么快又开始写下一篇吧,在大年初一那么美好的一天,所以我们来讨论一下网络工程中的数字证书方案吧。
谨在此祝各位童鞋新的一年大吉大利,狗年旺旺~
咳咳(正经脸.webp),在《从数字签名到数字证书》中,键者简单的整理了从数字签名到数字证书的理论基础及推导逻辑,那么这篇其实就是工程上某种实现数字证书的签发管理……
OpenSSL
首先需要简要介绍的就是名为openssl
的工具,简单说,它是SSL/TLS
的开源实现,实现了相关的加密解密算法、具备数字证书管理等功能的一个程序。
至于安装方式嘛,相信难不倒各位童鞋的,键者秉持偷懒的心略过……
我们先来简单回顾下自建CA需要处理些什么问题?
- 我们需要能生成
不对称密钥
。 - 我们需要能基于
公钥
及一些基础信息
生成证书签名请求
- 我们需要能用
私钥
为证书签名请求
签名,从而生成数字证书
为了方便,以下可能会使用
CSR
描述证书签名请求
;CRT
表示数字证书
生成RSA
密钥
那么,我们首先认识一下生成RSA
密钥的命令吧:
openssl genrsa -out -des3 rsa.key 4096
+ `genrsa` 用于生成 RSA 密钥对的 OpenSSL 命令。
+ `-out` 令生成的密钥对保存到文件
+ `4096` RSA 模数位数
+ `-des3` 使用 3-DES 对称加密算法加密密钥对,该参数需要用户在密钥生成过程中输入一个口令用于加密。今后使用该密钥对时,需要输入相应的口令。如果不加该选项,则不对密钥进行加密。
此时,会生成rsa.key
文件,但注意,这个可不只是私钥
哦,里边还有包括p
、q
在内的其他参数,所以通过ca.key
直接推导出公钥
。
虽然理论上,
RSA
算法中的公钥
和私钥
是没有本质区别的,仅知道任何一个都无法推导另一个出来,但如果有了p
、q
等参数就不一样了。
所以请妥善保管ca.key
,这个文件其实等价于同时包含了公钥
和私钥
!
如果使用了-des3
命令,则生成时会要求用户输入一个密码,并用该密码对生成的文件内容再做一次加密;除了-des3
以外,还可以选择-aes128
、-aes256
等加密算法,相当于为生成的rsa.key
再加了一层保险。
不过用的时候也要相应地使用密码解密就是了。
在整个数字证书体系中,可以认为,每一个实体都会唯一持有一对不对称密钥
,这对密钥也是后续所有数字证书相关功能的身份验证基础。
这个实体可能是
CA
,也可能是Server
或者Client
。
目前工程上常用是RSA
算法,但并不是只有RSA
哦,有兴趣的童鞋可以自己去搜搜看~
生成CSR
如果说密钥
实现了身份的鉴别基础,那么CSR
其实本质上就是更具体的身份信息,就像基因
可能唯一标识了一个人,但这个人的社会属性如姓名
、经历
等信息也是构成这个人不可或缺的部分。
所以生成
CSR
的时候,需要同时打包公钥
和基本信息
。
openssl req -new -days 365 -key rsa.key -out someone.csr
+ `req` 用于生成证书请求的 OpenSSL 命令。
+ `-new` 生成一个新的证书请求。该参数将令 OpenSSL 在证书请求生成过程中要求用户填写一些相应的字段。
+ `-days 365` 证书有效时间。
+ `-key` 用于签名的CA私钥。
+ `-out` 将生成的请求保存到文件。
执行这个命令的时候,会提示要求输入国家代码(Country Name)等信息,这是数字证书标准中要求CSR
附带的基本信息,所以根据自己的情况填写即可,完成后即可得到someone.csr
。
其中填写
Common Name
时注意,这里请填写的运行服务的主机可以正确解析的域名,本地调试的话可以使用localhost
,否则可能会导致基于这个数字证书
的网络服务(如,https
)无法工作。
注意,这里虽然传入了rsa.key
,但其实本质上是为了将rsa.pub
写入someone.csr
中,以便后续生成证书,并不是把私钥
写入了someone.csr
中哦。
签名并生成CRT
生成证书其实就是用私钥
对证书请求
进行签名。
使用的私钥
可以是自己的,也可以是别人的。如果是自己的,则表示自签名,就像我为自己带盐一样。如果是别人的,则表示别人为这个证书请求
作担保。
一般这里的别人都承担着CA的职能。
openssl x509 -req -in someone.csr -signkey rsa.key -out rsa.crt
- `x509` 操作符合x509标准的数字证书
- `-req` 传入一个`证书请求`,对其签名并输出`证书`
- `-int` 待签名的`证书请求`文件。
- `-signkey` 用于签名的私钥。
- `-out` 将生成的证书保存到文件
x509其实是数字证书的文件格式标准,一般我们用的数字证书都是符合x509标准的。
小结
应用的关键在于:
- 要信任谁,则表现为信任其证书,本质是信任证书的签发机构。
- 要为谁做担保,则使用私钥为其请求签名,请求应包含被担保人的公钥。
实战:我们来实现一组双向认证的数字证书体系吧
前文三个命令已经涵盖了数字证书
管理体系中最核心的三个步骤,后续更复杂的参数其实也只是数字证书特性的灵活应用,所以现在我们来试着设计一个稍微复杂点的结构。
其实这才是键者之前在折腾的东西……
假设我们现在有一个Server
和一个Client
,每当Client
连接Server
的时候,Server
需要确认Client
有自己信任的CA
签发的CRT
,而Client
也需要确认Server
有自己信任的CA
签发的CRT
。
理论上这两个
CA
可以是同一个,也可以是不同的两个,为了复杂起见Orz,吖不,为了强调两者并没有关联性,我们来设计一个不同的场景,以下会称作SRV.CA
、CLI.CA
,分别表示SRV
信任的CA
、CLI
信任的CA
。
那么我们可以简单梳理出,这个体系中有四个实体,分别是SRV.CA
、CLI.CA
、SRV
、CLI
。
生成CA
那么我们先来看一下,怎么生成一个自签名的CA
,因为生成过程其实是一样的,只是用途不同。
# 生成CA的`密钥对`
openssl genrsa -out ca.key 4096
# 生成CA的`证书请求`
openssl req -new -key ca.key -out ca.csr
# 用CA的私钥为自己的`证书请求`签名,生成`数字证书`
openssl x509 -req -in ca.csr -signkey ca.key -out ca.crt
其实
*.crt
包含的核心内容就是基础信息
和公钥
。
根据上述代码,我们可以轻松获得两个CA
,以及它们的密钥
和数字证书
,我们现在已有的文件如下:
|- client.ca.key
|- client.ca.crt
|- server.ca.key
\- server.ca.crt
CSR
其实只是中间文件,可以保留,也可以删除,这里先省略了。
为Server
和Client
签发证书
先梳理一下思路,因为SRV.CA
是SRV
信任的证书签发机构,所以,要用SRV.CA
给Client
签发数字证书
;同理,Client.CA
其实是给Server
签发证书的机构。
那么我们先来看看Server
侧的生成代码:
# 生成Server的`密钥对`
openssl genrsa -out server.key 4096
# 生成Server的`证书请求`
openssl req -new -key server.key -out server.csr
# 用Client.CA的私钥为Server的`证书请求`签名,生成`数字证书`
openssl x509 -req -in server.csr -signkey client.ca.key -out server.crt
这里与前边的自签名证书就不同了,用于签名的私钥变成了
client.ca.key
。
同理,我们可以推导出Client
侧的签发代码:
# 生成Client的`密钥对`
openssl genrsa -out client.key 4096
# 生成Client的`证书请求`
openssl req -new -key client.key -out client.csr
# 用Server.CA的私钥为Client的`证书请求`签名,生成`数字证书`
openssl x509 -req -in client.csr -signkey server.ca.key -out client.crt
这样,我们就可以得到以下的文件集合:
|- client.ca.key
|- client.ca.crt
|- server.ca.key
|- server.ca.crt
|- client.key
|- client.crt
|- server.key
\- server.crt
木有错,这些就是我们完成整套工作时需要的文件,作为管理者,我们再看看分发后的场景:
\- ServerDirectory
|- server.ca.crt
|- server.key
\- server.crt
\- ClientDirectory
|- client.ca.crt
|- client.key
\- client.crt
实际工程中,我们应该仅分发足够应用的证书文件,特别是保护好私钥,私钥一旦泄漏,整个信任体系就会面临崩溃,特别是CA
的私钥。
小结
在去年的故事里,键者唠唠叨叨流水账了一波数字证书
的工作机制,那么今年的第一篇文章,就来具体讲讲怎么样通过OpenSSL
生成具备生产价值的数字证书……
其实键者一开始想写的只是怎么用
golang
实现gRPC
的基于TLS
的双向认证,没想到,故事越写越长,估计这个故事又要等下一期了……
相信有悟性高的童鞋已经发现了,其实CA
、Client
、Server
的身份都只是相对的,Server
的私钥同样可以签发新的证书,真正起作用的是其工作时承担的角色而已。CA
还可以继续签发CA
,从而形成一条证书链,证书链可以实现分层的授权管理。
当然,OpenSSL其实有更详细的参数,可以约束一个签发的证书仅可用于充当
CA
、Server
或者Client
等等,但只要理解其核心原理,万变不离其宗,相信已经不需要键者啰嗦咯~
最后的最后,其实管理各种证书是个很麻烦的事情,既牵涉到业务逻辑,又涉及各种密码的存管。别的不说光起名字就是个麻烦事,而且随着服务端、客户端的扩容,需要管理的证书只会多不会少,这块东西其实也是个问题。
键者目前是使用了一个叫
xca
的软件来管理证书,如果有童鞋有更好的推荐欢迎在评论中告诉键者~
本篇关键词
TLS:Transport Layer Security,传输层安全协议
SSL:Secure Sockets Layer,可以认为是TLS的前身。