由于项目需要使用双向认证,内部项目没有去申请ca证书,前期用的java的keytool生成的证书,后面考虑到项目可能会往nginx上面部署,所以改为了openssl生成的方式(ps:keytool生成的数字证书好像也可以在nginx里面使用,有兴趣的可以研究一下,这里不做分析了).
1. 单双向认证区别
单向认证:客户端会认证服务器端身份,服务器端不对客户端进行认证
双向认证:客户端和服务端都会互相认证,即双发之间要证书交换
2. 单双向认证原理
2.1. 单向认证原理
1. 客户端程序(浏览器)向服务器传送客户端 SSL 协议的版本号,加密算法的种类,产生的随机数,以及其他服务器和客户端之间通讯所需要的各种信息(发送的内容从服务端给的证书中加载,不需要程序处理,由建立的连接自动完成)。
2. 服务器向客户端传送 SSL 协议的版本号,加密算法的种类,随机数以及其他相关信息,同时服务器还将向客户端传送自己的证书(公钥)。
3. 客户端利用服务器传过来的信息验证服务器的合法性,服务器的合法性包括:证书是否过期,发行服务器证书的 CA 是否可靠,发行者证书的公钥能否正确解开服务器证书的“发行者的数字签名”,服务器证书上的域名是否和服务器的实际域名相匹配。如果合法性验证没有通过, 通讯将断开;如果合法性验证通过,将继续进行第四步。
4. 客户端随机产生一个用于后面通讯的“对称密码”,然后用服务器的公钥(服务器的公钥从步骤2中的服务器的证书中获得)对其加密,然后将加密后的“预主密码”传给服务器。
5. 如果服务器要求客户的身份认证(在握手过程中为可选),用户可以建立一个随机数然后对其进行数据签名,将这个含有签名的随机数和客户自己的证书以及加密过的“预主密码”一起传给服务器。
6. 如果服务器要求客户的身份认证,服务器必须检验客户证书和签名随机数的合法性,具体的合法性验证过程包括:客户的证书使用日期是否有效,为客户提供证书的 CA 是否可靠,发行 CA 的公钥能否正确解开客户证书的发行 CA 的数字签名,检查客户的证书是否在证书废止列表(CRL)中。检验如果没有通过,通讯立刻中断;如果验证通过,服务器将用自己的私钥解开加密的“预主密 码”,然后执行一系列步骤来产生主通讯密码(客户端也将通过同样的方法产生相同的主通讯密码)。
7. 服务器和客户端用相同的主密码即“通话密码”,一个对称密钥用于 SSL 协议的安全数据通讯的加解密通讯。同时在 SSL 通讯过程中还要完成数据通讯的完整性,防止数据通讯中的任何变化。
8. 客户端向服务器端发出信息,指明后面的数据通讯将使用的步骤7中的主密码为对称密钥,同时通知服务器客户端的握手过程结束。
9. 服务器向客户端发出信息,指明后面的数据通讯将使用的步骤7中的主密码为对称密钥,同时通知客户端服务器端的握手过程结束。
10. SSL 的握手部分结束,SSL 安全通道的数据通讯开始,客户和服务器开始使用相同的对称密钥进行数据通讯,同时进行通讯完整性的检验。
2.2. 双向认证原理
1. 浏览器发送一个连接请求给安全服务器。
2. 服务器将自己的证书,以及同证书相关的信息发送给客户端(浏览器)。
3. 客户端程序(浏览器)检查服务器送过来的证书是否是由自己信赖的 CA 中心所签发的。如果是,就继续执行协议;如果不是,客户端程序(浏览器)就给客户一个警告消息:警告客户这个证书不是可以信赖的,询问客户是否需要继续访问(类似chrome对12306的提示)。
4. 接着客户端程序(浏览器)比较证书里的消息,例如域名和公钥,与服务器刚刚发送的相关消息是否一致,如果是一致的,客户端程序(浏览器)认可这个服务器的合法身份。
5. 服务器要求客户端(浏览器)发送客户端(浏览器)自己的证书。服务器收到证书后验证客户端的证书,如果没有通过验证,拒绝连接;如果通过验证,服务器获得客户端的公钥。
6. 客户端(浏览器)告诉服务器自己所能够支持的通讯对称密码方案。
7. 服务器从客户发送过来的密码方案中,选择一种加密程度最高的密码方案,用客户的公钥加过密后通知浏览器。
8. 客户端(浏览器)针对这个密码方案,选择一个通话密钥,接着用服务器的公钥加过密后发送给服务器。
9. 服务器接收到浏览器送过来的消息,用自己的私钥解密,获得通话密钥。
10. 服务器、浏览器接下来的通讯都是用对称密码方案,对称密钥是加过密的。
上面所述的是双向认证 SSL 协议的具体通讯过程,这种情况要求服务器和用户双方都有证书。单向认证 SSL 协议不需要客户拥有 CA 证书,具体的过程相对于上面的步骤,只需将服务器端验证客户证书的过程去掉,以及在协商对称密码方案,对称通话密钥时,服务器发送给客户的是没有加过密的 (这并不影响 SSL 过程的安全性)密码方案。 这样,双方具体的通讯内容,就是加过密的数据,如果有第三方攻击,获得的只是加密的数据,第三方要获得有用的信息,就需要对加密的数据进行解密,这时候的 安全就依赖于密码方案的安全。而幸运的是,目前所用的密码方案,只要通讯密钥长度足够的长,就足够的安全。这也是我们强调要求使用 128 位加密通讯的原因。
以上原理阐述引用自http://www.cnblogs.com/UnGeek/p/6047843.html
3. 下面开始生成证书
环境介绍:我使用的是centos7.2,自己安装了opensll
3.1. 准备工作
创建users、newcerts、private、conf、server文件夹,创建index.txt和serial文件(serial文件中可以是任意四个字符),上面生成目录及文件在下面的openssl.conf文件中被引用
[root@localhost ca]# mkdir users newcerts private conf server
[root@localhost ca]# echo FACE > serial
[root@localhost ca]# touch index.txt
[root@localhost ca]# ll
总用量 4
drwxr-xr-x 2 root root 6 6月 28 17:36 conf
-rw-r--r-- 1 root root 0 6月 28 17:36 index.txt
drwxr-xr-x 2 root root 6 6月 28 17:36 newcerts
drwxr-xr-x 2 root root 6 6月 28 17:36 private
-rw-r--r-- 1 root root 5 6月 28 17:36 serial
drwxr-xr-x 2 root root 6 6月 28 17:36 server
drwxr-xr-x 2 root root 6 6月 28 17:36 users
[root@localhost ca]#
3.2. 生成ca的私钥key文件
[root@localhost ca]# openssl genrsa -out private/ca.key 2048
Generating RSA private key, 2048 bit long modulus
..................................................................................+++
................................................................................+++
e is 65537 (0x10001)
[root@localhost ca]# ll private/
总用量 4
-rw-r--r-- 1 root root 1675 6月 28 17:42 ca.key
# private 目录下有 ca.key 文件生成。
3.2. 根据ca的私钥key文件生成csr文件
[root@localhost ca]# openssl req -new -key private/ca.key -out private/ca.csr
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [XX]:cn
State or Province Name (full name) []:beijing
Locality Name (eg, city) [Default City]:beijing
Organization Name (eg, company) [Default Company Ltd]:rkg
Organizational Unit Name (eg, section) []:rkg
Common Name (eg, your name or your server's hostname) []:10.0.6.120
Email Address []:[email protected]
Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:renkaige
An optional company name []:rkg
##注意,Common Name (eg, your name or your server's hostname)[]:这里输入的信息一定要与服务器的ip地址或域名一致,我的服务使用的ip访问,所以这里输入服务器的ip地址
[root@localhost ca]# ll private/
总用量 8
-rw-r--r-- 1 root root 1102 6月 28 17:46 ca.csr
-rw-r--r-- 1 root root 1675 6月 28 17:42 ca.key
##再private目录下生产ca.csr文件
3.3. 根据key文件和csr文件生成自签署证书crt
[root@localhost ca]# openssl x509 -req -days 3650 -in private/ca.csr -signkey private/ca.key -out private/ca.crt
Signature ok
subject=/C=cn/ST=beijing/L=beijing/O=rkg/OU=rkg/CN=10.0.6.120/[email protected]
Getting Private key
[root@localhost ca]# ll private/
总用量 12
-rw-r--r-- 1 root root 1281 6月 28 17:52 ca.crt
-rw-r--r-- 1 root root 1102 6月 28 17:46 ca.csr
-rw-r--r-- 1 root root 1675 6月 28 17:42 ca.key
[root@localhost ca]#
##在private目录下生成了一个ca.crt文件
3.4. 为服务器生成私钥key
[root@localhost ca]# openssl genrsa -out server/server.key 2048
Generating RSA private key, 2048 bit long modulus
......+++
............................................+++
e is 65537 (0x10001)
[root@localhost ca]# ll server/
总用量 4
-rw-r--r-- 1 root root 1675 6月 28 18:03 server.key
[root@localhost ca]#
##server目录下生成了一个server.key文件
3.5. 根据ca的私钥key文件生成csr文件
由于由于合作厂商客户端程序使用的node.js,node.js在双向认证校验证书时如果Common Name配置的是ip则还必须验证证书的 使用者可选名称参数 这里引用openssl.conf文件来配置这个参数(如下图百度的数字证书里的 使用者可选名称参数)
执行下面命令前需要把openssl.conf文件放到conf目录下
[root@localhost ca]# clear
[root@localhost ca]# openssl req -new -key server/server.key -config "./conf/openssl.conf" -out server/server.csr
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [cn]:cn
beijing [beijing]:beijing
Locality Name (eg, city) [huayan]:beijing
iie [iie]:rkg
10.0.6.120 []:10.0.6.120
[root@localhost ca]# ll server/
总用量 8
-rw-r--r-- 1 root root 1066 6月 28 18:13 server.csr
-rw-r--r-- 1 root root 1675 6月 28 18:03 server.key
[root@localhost ca]#
##会在server目录下生成server.csr文件
3.6. openssl.conf
[ ca ]
default_ca = foo # The default ca section
[ foo ]
dir = ./ # top dir
database = ./index.txt # index file.
new_certs_dir = ./newcerts # new certs dir
certificate = ./private/ca.crt # The CA cert
serial = ./serial # serial no file
private_key = ./private/ca.key # CA private key
RANDFILE = ./private/.rand # random number file
default_days = 365 # how long to certify for
default_crl_days = 30 # how long before next CRL
default_md = sha1 # message digest method to use
unique_subject = no # Set to 'no' to allow creation of
# several ctificates with same subject.
policy = policy_any # default policy
[ policy_any ]
countryName = match
stateOrProvinceName = optional
organizationName = optional
organizationalUnitName = optional
localityName = optional
commonName = supplied
emailAddress = optional
[ req ]
distinguished_name = req_distinguished_name
req_extensions = v3_req
[ req_distinguished_name ]
countryName = Country Name (2 letter code)
countryName_default = cn
stateOrProvinceName = beijing
stateOrProvinceName_default = beijing
localityName = Locality Name (eg, city)
localityName_default = huayan
organizationalUnitName = iie
organizationalUnitName_default = iie
commonName = 10.0.6.120
commonName_max = 64
[ v3_req ]
#Extensions to add to a certificate request
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
subjectAltName = @alt_names
[ alt_names ]
IP.1 = 10.0.6.120
IP.2 = 127.0.0.1
#DNS.1 = www.rkg.com
注意,如果是域名访问服务端的话下面要换成域名,(使用的时候这几句要删除掉,不然会报错error on line -1 of ./conf/openssl.conf)
DNS.1 = www.rkg.com
commonName = www.rkg.com
3.7. 根据server.csr和ca.crt生成server.crt文件(指定了openssl.conf中的-extensions v3_req,利用ca.crt为我们的服务端证书进行签名)
[root@localhost ca]# openssl ca -in server/server.csr -days 3650 -cert private/ca.crt -keyfile private/ca.key -out server/server.crt -extensions v3_req -config "./conf/openssl.conf"
Using configuration from ./conf/openssl.conf
Check that the request matches the signature
Signature ok
The Subject's Distinguished Name is as follows
countryName :PRINTABLE:'cn'
stateOrProvinceName :PRINTABLE:'beijing'
localityName :PRINTABLE:'beijing'
organizationalUnitName:PRINTABLE:'rkg'
commonName :PRINTABLE:'10.0.6.120'
Certificate is to be certified until Jun 27 05:58:47 2027 GMT (3650 days)
Sign the certificate? [y/n]:y
1 out of 1 certificate requests certified, commit? [y/n]y
Write out database with 1 new entries
Data Base Updated
[root@localhost ca]# ll server/
总用量 16
-rw-r--r-- 1 root root 4297 6月 29 13:58 server.crt
-rw-r--r-- 1 root root 1066 6月 28 18:13 server.csr
-rw-r--r-- 1 root root 1675 6月 28 18:03 server.key
[root@localhost ca]#
##server目录下生成了一个server.crt文件
此时可以发现生成的server.crt文件属性里包含 使用者可选名称
3.7. 根据server.crt和server.key生成server.p12(需要为服务端证书设置密码)
[root@localhost ca]# openssl pkcs12 -export -clcerts -in server/server.crt -inkey server/server.key -out server/server.p12
Enter Export Password:
Verifying - Enter Export Password:
[root@localhost ca]# ll server
总用量 20
-rw-r--r-- 1 root root 4297 6月 29 14:08 server.crt
-rw-r--r-- 1 root root 1066 6月 28 18:13 server.csr
-rw-r--r-- 1 root root 1675 6月 28 18:03 server.key
-rw-r--r-- 1 root root 2509 6月 29 14:09 server.p12
[root@localhost ca]#
##会在server目录下生成一个server.p12文件
3.8. 生成客户端私钥
[root@localhost ca]# openssl genrsa -out ./users/client.key 2048
Generating RSA private key, 2048 bit long modulus
...................................+++
....+++
e is 65537 (0x10001)
[root@localhost ca]# ll users
总用量 4
-rw-r--r-- 1 root root 1675 6月 29 14:15 client.key
[root@localhost ca]#
##users目录下生成了一个client.key文件
3.9. 利用客户端私钥生成csr文件
[root@localhost ca]# openssl req -new -key ./users/client.key -config "./conf/openssl.conf" -out ./users/client.csr
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [cn]:cn
beijing [beijing]:beijing
Locality Name (eg, city) [huayan]:beijing
iie [iie]:rkg
10.0.6.120 []:10.0.6.120
[root@localhost ca]# ll users
总用量 8
-rw-r--r-- 1 root root 1066 6月 29 14:22 client.csr
-rw-r--r-- 1 root root 1675 6月 29 14:15 client.key
[root@localhost ca]#
##在users目录下生成了一个client.csr文件
3.10. 生成客户端证书文件client.crt
[root@localhost ca]# openssl ca -in ./users/client.csr -days 3650 -cert ./private/ca.crt -keyfile ./private/ca.key -out ./users/client.crt -extensions v3_req -config "./conf/openssl.conf"
Using configuration from ./conf/openssl.conf
Check that the request matches the signature
Signature ok
The Subject's Distinguished Name is as follows
countryName :PRINTABLE:'cn'
stateOrProvinceName :PRINTABLE:'beijing'
localityName :PRINTABLE:'beijing'
organizationalUnitName:PRINTABLE:'rkg'
commonName :PRINTABLE:'10.0.6.120'
Certificate is to be certified until Jun 27 06:23:21 2027 GMT (3650 days)
Sign the certificate? [y/n]:y
1 out of 1 certificate requests certified, commit? [y/n]y
Write out database with 1 new entries
Data Base Updated
[root@localhost ca]# ll users
总用量 16
-rw-r--r-- 1 root root 4297 6月 29 14:23 client.crt
-rw-r--r-- 1 root root 1066 6月 29 14:22 client.csr
-rw-r--r-- 1 root root 1675 6月 29 14:15 client.key
[root@localhost ca]#
##在users目录下生成了一个client.crt
3.11. 生成浏览器可识别的client.p12文件
[root@localhost ca]# openssl pkcs12 -export -clcerts -in ./users/client.crt -inkey ./users/client.key -out ./users/client.p12
Enter Export Password:
Verifying - Enter Export Password:
[root@localhost ca]# ll users
总用量 20
-rw-r--r-- 1 root root 4297 6月 29 14:23 client.crt
-rw-r--r-- 1 root root 1066 6月 29 14:22 client.csr
-rw-r--r-- 1 root root 1675 6月 29 14:15 client.key
-rw-r--r-- 1 root root 2509 6月 29 14:25 client.p12
[root@localhost ca]#
##在users目录下生成了一个client.p12文件,该文件给客户端,密码也需要给客户端,
客户端如果是浏览器则直接双击安装导入到浏览器中即可
3.12. 如果服务器是tomcat,还需要将openssl生成的文件转化为jks格式的文件,如果是nginx请看3.13,其他服务器未试验过,大家可以根据这个步骤实验一下
[root@localhost ca]# keytool -keystore truststore.jks -keypass iiehuayan -storepass iiehuayan -alias ca -import -trustcacerts -file private/ca.crt
所有者: [email protected], CN=10.0.6.120, OU=rkg, O=rkg, L=beijing, ST=beijing, C=cn
发布者: [email protected], CN=10.0.6.120, OU=rkg, O=rkg, L=beijing, ST=beijing, C=cn
序列号: 8c013ca13cb2b68d
有效期开始日期: Wed Jun 28 17:52:27 CST 2017, 截止日期: Sat Jun 26 17:52:27 CST 2027
证书指纹:
MD5: AB:E6:13:D5:83:6F:96:23:77:76:FB:3F:EA:FE:11:8F
SHA1: A6:00:96:78:57:84:03:EB:A3:02:95:7D:30:32:A4:12:D6:E2:E0:B4
SHA256: 34:32:E0:64:78:DE:57:3D:01:40:11:38:1B:96:FE:7C:71:16:1F:21:F1:85:89:D2:47:13:2A:CF:F8:D5:87:CC
签名算法名称: SHA1withRSA
版本: 1
是否信任此证书? [否]: y
证书已添加到密钥库中
[root@localhost ca]# ll
总用量 28
drwxr-xr-x 2 root root 26 6月 28 18:13 conf
-rw-r--r-- 1 root root 234 6月 29 14:23 index.txt
-rw-r--r-- 1 root root 20 6月 29 14:23 index.txt.attr
-rw-r--r-- 1 root root 20 6月 29 14:08 index.txt.attr.old
-rw-r--r-- 1 root root 156 6月 29 14:08 index.txt.old
drwxr-xr-x 2 root root 54 6月 29 14:23 newcerts
drwxr-xr-x 2 root root 48 6月 28 17:52 private
-rw-r--r-- 1 root root 5 6月 29 14:23 serial
-rw-r--r-- 1 root root 5 6月 29 14:08 serial.old
drwxr-xr-x 2 root root 78 6月 29 14:09 server
-rw-r--r-- 1 root root 963 6月 29 14:30 truststore.jks
drwxr-xr-x 2 root root 78 6月 29 14:25 users
[root@localhost ca]#
##当前目录下生成了一个truststore.jks
tomcat的server.xml配置
keystoreFile="conf/server.p12" keystorePass="123456" keystoreType="PKCS12"
truststoreFile="conf/truststore.jks" truststorePass="123456" truststoreType="JKS"
3.13. Nginx配置
listen 443;
server_name localhost;
ssi on;
ssi_silent_errors on;
ssi_types text/shtml;
ssl on;
ssl_certificate /usr/local/nginx/ca/server/server.crt;
ssl_certificate_key /usr/local/nginx/ca/server/server.key;
ssl_client_certificate /usr/local/nginx/ca/private/ca.crt;
ssl_session_timeout 5m;
ssl_verify_client on; #开户客户端证书验证
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDH:AES:HIGH:!aNULL:!MD5:!ADH:!DH;
ssl_prefer_server_ciphers on;
3.14. ca.crt文件和client.p12文件需要发送给客户端,如果客户端程序是浏览器直接双击安装这俩文件即可,如果是程序则使用对应的加载方式即可
总结
以上内容是根据自己实际开发中生成的数字证书步骤总结的,里面可能会有些地方写的不对欢迎大家提出修改意见,谢谢!
在生成证书时借鉴了下面几个博客,感谢素未谋面的博主,谢谢......
https://blog.imdst.com/nginx-ssl-shuang-xiang-ren-zheng-key-sheng-cheng-he-pei-zhi/
http://m.blog.csdn.net/liuchunming033/article/details/48470575
http://cnodejs.org/topic/54745ac22804a0997d38b32d