SSL
ssl协议(Secure Sockets Layer安全套接层)是一套网络通信安全协议,是由网景公司在1994年创建设计的,它具有数据加密,完整性校验及身份验证功能。它的出现是为了保证网络数据传输的安全性。如果没有SSL的加持,我们在网络中传输的数据就都处在裸奔的状态。SSL协议处在应用层和传输层之间,可以为任何基于TCP等可靠连接的应用层协议提供安全性保证。
SSL协议本身分为两层:上层为SSL握手协议(SSL Handshake Protocol),SSL密码变化协议(SSL change cipher spec Protocol)和SSL警告协议(SSL alert Protocol),它们建立在SSL记录协议之上,用于在实际的数据传输开始前,通讯双方进行身份认证,协商加密算法,交换加密密钥等
SSL握手过程
SSL握手过程在客户端和服务器之间协商会话参数,并建立会话。会话包含的主要参数由会话ID,对方的证书,加密套件(密钥交换算法,数据加密算法和MAC算法等)以及主密钥(Master Secret)。通过SSL会话传输的数据,都将采用该会话的主密钥生成的工作密钥和加密套件进行加密,计算MAC等处理。
工作密钥:并不是直接生成的。是客户端生成一个预主密钥(pre master secret),然后用密钥交换算法发给服务器端。两端根据这个预主密钥计算生成主密钥,再用主密钥生成工作密钥。
RSA握手过程(简版)
ECDHE握手过程(简版)
单向校验流程
1 SSL客户端通过Client Hello消息将它支持的SSL版本,随机数(32位时间戳+28字节随机序列),会话ID,加密算法,密钥交换算法,MAC算法等信息发送给服务端。
2 服务端确定本次通信采用的SSL版本,加密套件,随机数,会话ID,并通过Server Hello消息通知给客户端
3 SSL服务端将自己的数字证书或者证书链通过Certificate消息发送给客户端
4 服务器发送Server Hello Done消息给客户端,通知客户端SSL版本和加密套件协商结束,开始进行密钥交换
5 客户端验证服务端证书的合法性,成功后利用证书中的公钥加密客户端随机生成的pre master secret,并通过client key exchange消息发送给服务端
6 客户端发送change cipher spec消息,通知服务端后续报文将采用协商好的密钥和加密套件进行加密和MAC计算。客户端计算已交互的握手信息(除change cipher spec消息外所有已交互的信息)的hash值,利用协商好的密钥和加密套件处理hash值(计算并添加MAC值,加密等),并通过Finished消息发送给服务器,服务端利用同样的方式计算已交互的握手信息的hash值,并和Finished消息的解密结果相比较,如果二者相同,且MAC值验证成功,则证明密钥和加密套件协商成功。
7 同步骤6方法,服务端发送change cipher spec消息,通知客户端后续报文发送将采用协商好的密钥和加密套件进行加密和MAC校验
8 同步骤7,服务器将处理后的数据通过Finished消息发送给客户端,客户端完成处理
双向校验流程
客户端身份验证是可选的,由服务端决定是否验证客户端身份,如果服务端要验证客户端身份,则握手双方除了交互只验证服务端的SSL握手过程中的消息外,还需要:
1 服务端发送server key exchange消息(有些情况下不需要),只有当服务器的证书没有包含必须的数据的时候才发送此消息,此消息包含签名,被签名的内容包括两个随机数以及服务器参数
2 服务器发送certificate request消息,请求客户端将其证书发送给服务端
3 客户端通过certificate消息将携带有自己公钥信息的证书发送给服务端,服务端验证该证书的合法性
4 客户端计算已交互过的握手信息,主密钥hash值,利用自己的私钥对其进行加密,并通过certificate verity消息发送给服务端
5 服务端计算已交互过的握手信息,主密钥的hash值,利用客户端证书中的公钥解密certificate verity消息,并将解密的结果与计算出的hash值比较,如果二者相同,则客户端身份验证成功
恢复原有会话的SSL握手过程
协商会话参数,建立会话的过程中,需要使用非对称密钥算法来加密密钥,验证通信双方的身份,计算量较大,占用了大量的系统资源,为了简化SSL握手过程,SSL允许重用已经协商过的会话,有两种方式:session id会话复用,session ticket会话复用
session id会话复用
1 客户端发送client hello消息,消息中的会话id设置位计划重用的会话id
2 服务器如果允许重用该会话,则通过在server hello消息中设置相同的会话id来应答,这样两端就可以利用原有会话的密钥和加密套件了,不用在重新协商
3 客户端发送change cipher spec消息,通知服务端后续报文将使用原有会话的密钥和加密套件进行加密和MAC计算
4 客户端计算已交互的握手信息的hash值,利用原有会话的密钥和加密套件处理hash值,并通过finished消息发送给服务端,以便服务器判断密钥和加密套件是否正确
5 同样的,服务端发送change cipher spec消息,通知客户端后续报文将使用原有会话的密钥和加密套件进行加密和MAC计算
6 服务端计算已交互的握手信息的hash值,利用原有会话的密钥和加密套件处理hash值,并通过finished消息发送给客户端,以便客户端判断密钥和加密套件是否正确
session ticket
1 客户端发起client hello,扩展中带上空的session ticket TLS,表明自己支持session ticket
2 服务器在握手过程中,如果支持session ticket,则发送new session ticket类型的握手报文,其中包含了能够恢复包括主密钥在内的会话信息。当然最简单的是只发送master key,为了让中间人不可见,这个session ticket部分会进行编码,加密操作
3 客户端收到这个session ticket后,就把当前的master key和这个session ticket组成一队键值对保存起来,服务器无需保存任何会话信息,客户端也无需知道session ticket具体代表的是什么
4 当客户端尝试进行会话复用的时候,会在client hello的扩展中加上session ticket,然后服务器收到session ticket后,进行解密,解码等相关操作。来恢复会话信息,如果能恢复会话信息,那么就会提取会话信息的主密钥进行后续的操作,服务器将按照会话复用流程,直接回复server hello,ccs,finished
SSL记录协议 SSL record protocol
在客户端和服务端完成握手后,进入SSL记录协议,记录协议向SSL连接提供两个服务
- 机密性,SSL记录协议会协助双方产生一把共有的密钥,利用这把密钥对SSL所传输的数据做传统的数据加密
- 消息完整性,SSL记录协议会协助双方产生另一把共有的密钥,利用这把密钥来计算消息认证码
记录协议收到应用程序所要传输的信息后,会将消息内部的数据切分成容易管理的小区块(分片),然后选择是否对这些分片进行压缩,在加上此分片的消息认证码,接着将数据区块和MAC一起做加密处理,加上SSL记录头后通过TCP传送出去,接收方接到数据后,进行解释,检查,解压缩及重组等步骤将数据还原
- 分片
- 是否压缩
- 计算压缩数据的消息认证码
- 压缩过后的数据会和MAC一起做对称加密
- 加上记录头
记录头包含以下信息:
- 数据类型(content type),8位用来处理这个分片的上层协议
- 主要版本号,8位,协议的主要版本,v3协议来说,这个字段值是3
- 次要版本号,8位,表示使用的次要版本,对于SSLv3协议来说,这个字段值是0
- 压缩后数据长度compressed length,16位,这个明文分片的长度(假如此分片已经经过压缩,则为压缩后的长度)
SSL密码变化协议 change cipher spec
密码变化协议是3个高层协议之一,也是最简单的一个。在客户端和服务端完成握手协议后,它需要向对方发送相关消息(此消息只包含一个值是1的单字节),通知对方随后的数据将用刚刚协商的密码规范算法和关联的密钥处理,并负责协调本方模块按照协商的算法和密钥工作。
使用OpenSSL生成证书
准备工作
-
下载openssl工具包,并且配置环境变量
-
找到安装目录bin路径下的openssl.cfg文件,修改dir属性值为自己想要指定的目录即可
- 接下来在ca目录下创建一些空文件,方便后续步骤使用,如下图所示
- 接下来继续构建一些需要用到的文件,命令和效果如下
完成上述操作之后,就可以开始进行证书的构建和签发了。注意如果上述命令创建不出index和serial文件,那么应该查看是否使用了管理员身份去操作,且该操作只能通过cmd命令终端进行,笔者在测试的时候发现通过widows powershell操作没有效果,手动在ca目录下创建下后续操作也会出现问题。
构建根证书
-
构建随机文件,命令如下
openssl rand -out private/.rand 1000
执行完该命令后你会发下private目录下已经有东西出现了
上述命令中各参数含义为,其中参数1000是指产生伪随机字节数
命令 | 解释 |
---|---|
rand | 随机数命令 |
-out | 输出文件路径,这里将随机数文件输出到private目录下 |
- 构建根证书密钥,命令如下
openssl genrsa -aes256 -out private/ca.key.pem 2048
各参数含义如下:
命令 | 解释 |
---|---|
genrsa | 产生RSA密钥命令 |
-aes256 | 使用AES算法(256位密钥)对产生的私钥加密。可选算法包括DES,DESede,IDEA和AES |
-out | 输出路径,这里指private/ca.key.pem |
2048 | 这里的参数是2048,指RSA密钥长度位数,默认长度为512位 |
-
生成根证书签发申请文件(ca.csr),命令如下
openssl req -new -key private/ca.key.pem -out private/ca.csr -subj "/C=CN/ST=BJ/L=BJ/O=yewenjie/OU=yewenjie/CN=*.yewenjie.org"
各参数含义如下:
命令 | 解释 |
---|---|
req | 产生证书签发申请命令 |
-new | 表示新请求 |
-key | 密钥,这里是private/ca.key.pem文件 |
-out | 输出路径,这里为private/ca.csr文件 |
-subj | 指定用户信息,这里使用泛域名 *.yewenjie.org 作为用户名 |
-
得到根证书签发申请文件后,我们可以将其发送给CA签发。也可以自行签发根证书。签发根证书命令如下
openssl x509 -req -days 365 -sha1 -extensions v3_ca -signkey private/ca.key.pem -in private/ca.csr -out certs/ca.cer
各参数含义如下:
命令 | 解释 |
---|---|
x509 | 签发x.509格式证书命令 |
-req | 证书输入请求 |
-days | 有效天数,这里为365天 |
-sha1 | 证书摘要算法,这里为sha1算法 |
-extensions | 按openssl配置文件v3_ca项添加扩展 |
-signkey | 自签名密钥,这里为private/ca.key.pem |
-in | 输入文件,这里为private/ca.csr |
-out | 输出文件,这里为certs/ca.cer |
-
由于通过openssl生成的证书无法直接在Java环境中使用,需要转换证书的编码格式才行。根证书转换格式命令如下
openssl pkcs12 -export -cacerts -inkey private/ca.key.pem -in certs/ca.cer -out certs/ca.p12
这时候查看我们生成的根证书文件,会发现两个证书文件类型是不同的
各参数含义如下:
命令 | 解释 |
---|---|
pkcs12 | PKCS#12编码格式证书命令 |
-export | 导出证书 |
-cacerts | 仅导出CA证书 |
-inkey | 输入密钥,这里为private/ca.key.pem |
-in | 输入文件,这里为certs/ca.cer |
-out | 输出文件,这里为certs/ca.p12 |
现在我们已经构建好根证书了,接下来使用根证书去构建服务端和客户端的证书。
构建服务器证书
-
首先构建私钥,命令如下
openssl genrsa -aes256 -out private/server.key.pem 2048
各参数含义如下:
命令 | 解释 |
---|---|
genrsa | 产生RSA密钥命令 |
-aes256 | 使用AES算法(256位密钥)对产生的私钥加密,可选算法包括DES,DESede,IDEA和AES |
-out | 输出路径,这里指private/server.key.pem |
参数2048 | 指RSA密钥长度位数,默认长度位512 |
-
生成服务器证书签发申请,命令如下
openssl req -new -key private/server.key.pem -out private/server.csr -subj "/C=CN/ST=BJ/L=BJ/O=yewenjie/OU=yewenjie/CN=www.yewenjie.org"
各参数含义如下
命令 | 解释 |
---|---|
req | 生成证书签发申请命令 |
-new | 新请求 |
-key | 密钥,这里为private/ca.key.pem文件 |
-out | 输出路径,这里为private/ca.csr文件 |
-subj | 指定用户信息,这里使用域名www.yewenjie.org作为用户名 |
-
使用根证书签发服务器证书,命令如下
openssl x509 -req -days 365 -sha1 -extensions v3_req -CA certs/ca.cer -CAkey private/ca.key.pem -CAserial ca.srl -CAcreateserial -in private/server.csr -out certs/server.cer
各参数含义如下
命令 | 解释 |
---|---|
x509 | 签发x.509格式证书命令 |
-req | 证书输入请求 |
-days | 有效天数,这里为365天 |
-sha1 | 证书摘要算法,这里为SHA1算法 |
-extensions | 按Openssl配置文件v3_req项添加扩展 |
-CA | CA证书,这里为certs/ca.cer |
-CAkey | CA证书密钥,这里为private/ca.key.pem |
-CAserial | CA证书序列号文件,这里为ca.srl |
-CAcreateserial | 创建CA证书序列号 |
-in | 输入文件,这里为private/server.csr |
-out | 输出文件,这里为certs/server.cer |
-
转换证书格式,命令如下
openssl pkcs12 -export -clcerts -inkey private/server.key.pem -in certs/server.cer -out certs/server.p12
各参数含义如下:
命令 | 解释 |
---|---|
pkcs12 | PKCS#12编码格式证书命令 |
-export | 导出证书 |
-clcerts | 仅导出客户证书 |
-inkey | 输入密钥文件路径,这里为private/server.key.pem |
-in | 输入文件路径,这里为certs/ca.cer |
-out | 输出文件路径,这里为certs/server.p12 |
构建客户证书
-
构建私钥,命令如下
openssl genrsa -aes256 -out private/client.key.pem 2048
各参数含义如下
命令 | 解释 |
---|---|
genrsa | 产生RSA密钥命令 |
-aes256 | 使用AES算法(256位密钥)对产生的私钥加密,可选算法包括DES,DESede,IDEA和AES |
-out | 输出路径,这里指private/client.key.pem |
参数2048 | 指RSA密钥长度位数,默认长度位512位 |
-
生成客户端证书签发申请,命令如下
openssl req -new -key private/client.key.pem -out private/client.csr -subj "/C=CN/ST=BJ/L=BJ/O=yewenjie/OU=yewenjie/CN=yewenjie"
各参数含义如下
命令 | 解释 |
---|---|
req | 产生证书签发申请命令 |
-new | 新请求 |
-key | 密钥,这里是private/client.key.pem文件 |
-out | 输出路径,这里是private/client.csr文件 |
-subj | 指定用户信息,这里使用yewenjie作为用户名 |
-
使用根证书签发客户证书,命令如下
openssl ca -days 365 -in private/client.csr -out certs/client.cer -cert certs/ca.cer -keyfile private/ca.key.pem
各参数命令如下
命令 | 解释 |
---|---|
ca | 签发证书命令 |
-days | 证书有效期,这里是365天 |
-in | 输入文件,这里是private/client.csr |
-out | 输出文件,这里是certs/server.cer |
-cert | 证书文件,这里是certs/ca.cer |
-keyfile | 根证书密钥文件,这里是private/ca.key.pem |
-
证书格式转换,命令如下
openssl pkcs12 -export -inkey private/client.key.pem -in certs/client.cer -out certs/client.p12
各参数含义如下:
命令 | 解释 |
---|---|
pkcs12 | PKCS#12编码格式证书命令 |
-export | 导出证书 |
-clcerts | 仅导出客户证书 |
-inkey | 输入密钥,这里为private/client.key.pem |
-in | 输入文件,这里是certs/client.cer |
-out | 输出文件,这里是certs/client.p12 |
到这里,我们完整了双向认证所需要的全部证书,效果如下
注意事项
- 没有展示的文件夹是空的
- 上述操作过程中,需要填充密码的地方可以自定义。本人使用的密码是123456
- 如果在操作过程中出现下列问题,那很有可能是openssl.cnf配置文件的环境变量有问题。
可以通过以下方法来解决:
一)设置windows环境变量,笔者如下设置。笔者的openssl安装包安装在d盘下
二)可以使用管理员身份在cmd命令终端如下设置即可
set OPENSSL_CONF=D:\OpenSSL-Win64\bin\openssl.cfg
echo %OPENSSL_CONF%
快来和博主打成一片吧 😃