参考链接:https://www.cnblogs.com/dreamingodd/p/7357029.html
Https、OpenSSL自建CA证书及签发证书、nginx单向认证、双向认证及使用Java访问
0.环境
本文的相关源码位于 https://github.com/dreamingodd/CA-generation-demo
必须安装nginx,必须安装openssl,(用apt-get update, apt-get install来安装比较简单)
1.配置和脚本
先创建一个demo目录(位置自己选择,我选择建在nginx的目录下):
mkdir /etc/nginx/ca-demo
cd /etc/nginx/ca-demo
修改SSL配置openssl.cnf(也可能是openssl.conf,不知道在哪可以用find -name / openssl.cnf查找)
将dir属性改成你上一步自建的目录,不要用相对路径,会踩坑,保存,如图:
我喜欢自动化,所以写了三个如下脚本,可以直接使用:
ca.sh
#!/bin/bash
#Create directory hierarchy.创建目录结构
touch index.txt serial
chmod 666 index.txt serial
echo 01 > serial
mkdir -p newcerts private
#生成RSA密钥对
openssl genrsa -des3 -out ./private/cakey.pem 2048
#openssl req -new -days 365 -key ./private/cakey.pem -out ca.csr
#openssl ca -selfsign -in ca.csr -out ca.crt
# one step.一步生成csr,crt,直接10年使用期
openssl req -new -x509 -days 3650 -key ./private/cakey.pem -out ca.crt
server.sh
#!/bin/bash
# 签发服务器证书
mkdir server
openssl genrsa -out ./server/server.key
openssl req -new -key ./server/server.key -out ./server/server.csr
openssl ca -in ./server/server.csr -cert ./ca.crt -keyfile ./private/cakey.pem -out ./server/server.crt -days 3650
client.sh:
#!/bin/bash
# 签发client证书
mkdir client
openssl genrsa -des3 -out ./client/client.key 2048
openssl req -new -key ./client/client.key -out ./client/client.csr
openssl ca -in ./client/client.csr -cert ./ca.crt -keyfile ./private/cakey.pem -out ./client/client.crt -config "/etc/ssl/openssl.cnf"
openssl pkcs12 -export -clcerts -in ./client/client.crt -inkey ./client/client.key -out ./client/client.p12
以上三个脚本都可以在 https://github.com/dreamingodd/CA-generation-demo 找到
将以上三个脚本复制到自建demo目录中,如下所示:
加入运行权限:
chmod +x *.sh
结果如下:
2.自建CA证书
运行脚本ca.sh,效果如下:
a.输入密码短语:(随便,记住就行,我填的是"demo",需要填3次)
b.生成证书需要填入一些信息:Country Name(国家),State or Province Name(省),Locality Name(市),Organizational Name(组织名,随便填,我填的是Choosefine Ltd),Common Name(一般填域名),其他可以不填。
这样证书就生成并自签名了:
其中,newcerts目录用于存放CA签署(颁发)过的数字证书(证书备份目录)。private目录用于存放CA的私钥。 文件serial和index.txt分别用于存放下一个证书的序列号和证书信息数据库。 文件serial填写第一个证书序列号(如10000001),之后每前一张证书,序列号自动加1。
可以把ca.crt下载到你的windows系统的PC机上,后面会用到。
3.签发服务端证书
运行脚本server.sh,效果如下:
最后一句是Data Base Updated,就表示成功了,要填的东西跟上一步非常相似,需要注意的是:
a.国家和省份必须和上一步一样。
b.Organizational Name必须和上一步一样。
c.Common Name,如果你的测试服务器有域名的话,填入域名,没有的话随便填一个网址,windows访问测试时配置一下hosts就好,我这里填的是ssl.demo.com。
d.challenge password随便填,记住就行,我填的demo。
e.pass phrase密码短语是CA证书的的,我生成的时候用的也是demo。
生成结果:
4.Nginx配置Https单向认证
这一步我要使用上面我们生成的证书s来配置一个安全的Https单向访问资源链接。
首先修改nginx配置文件,
vi /etc/nginx/nginx.conf
在http中加入以下内容:
server {
server_name ssl.demo.com;
listen 443;
ssl on;
ssl_certificate ca-demo/server/server.crt;
ssl_certificate_key ca-demo/server/server.key;
location / {
root html;
index index.html index.html;
}
}
运行以下命令检查和重启nginx:
/usr/sbin/nginx -t service nginx restart
使用IP访问一下:
成功了,会显示证书不安全。一般来说,如果花钱使用证书公司签发的server.crt和server.key不会有这个问题。
这里想解决这个问题的话需要windows本地信任我们自己的CA证书。如果对这个问题不感兴趣可以直接跳过。
首先,将我们第二步生成的CA证书下载到windows系统本地,双击打开
点击安装:
点击下一步:
选择自定义证书集合,点击浏览:
选择第二个,受信任的证书列表,一直下一步/完成/是的等,就可以了。
成功后效果如图:
一开始那个X已经没有了。
Status显示OK。
如果你想看到证书集合的情况,可以WIN+R -> certmgr.msc查看
名字是CA证书的Common Name。
最后(如果没有域名),修改以下hosts文件模拟一下域名:
使用域名访问,风险提示就消失了:
5.签发客户端证书
签发客户端证书,用于服务端开启了ssl的客户端验证时,要求客户端对请求做加密。
运行脚本client.sh
所有密码处我填的全是demo。
结果如下:
到此为止,证书的生成已经全部讲完了。
6.Nginx配置Https双向认证
Https双向认证不仅验证服务端的证书,服务端也要验证客户端的证书;不仅对客户端的请求进行了加密,并且服务端使用的加密方案也是使用客户端公钥加密后发送给客户端的。比单项认证更加安全。
我个人的理解是,单项认证防止请求被篡改,双向认证防止请求被模拟。
题外话,Https使用了对称加密+非对称加密,由于非对称加密的效率低,不适合传输的数据量大的时候。所以Https的客户端将对称加密的密钥用服务端的公钥进行加密再发送给服务端,服务端用私钥进行解密(非对称加密),对传输数据本身的加密使用的密钥是一样的(对称加密)。
进入正题,首先开启服务端nginx的客户端ssl认证,将之前加入的配置删除,贴入新的一份:
server {
server_name ssl.demo.com;
listen 443;
ssl on;
ssl_certificate ca-demo/server/server.crt;
ssl_certificate_key ca-demo/server/server.key;
ssl_client_certificate ca-demo/ca.crt;
ssl_verify_client on;
ssl_session_cache shared:SSL:1m;
ssl_session_timeout 5m;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
location / {
root html;
index index.html index.htm;
}
}
检查并重启,再次访问:
显示未发送客户端证书。
下载client.p12文件到本地,双击安装,这次安装到个人:
关闭浏览器再次访问,就有了证书选择的界面,选择后正常访问。
之前有不少网银都是使用这种方式进行交易的。
在上述的操作之后,发现在ie8中访问是ok的,但是在chrome中访问还是不安全的提示。所以继续参考下面链接:
https://blog.csdn.net/dotalee/article/details/78041691
SAN(Subject Alternative Name) 是 SSL 标准 x509 中定义的一个扩展。使用了 SAN 字段的 SSL 证书,可以扩展此证书支持的域名,使得一个证书可以支持多个不同域名的解析。
来看看百度的证书,百度证书的扩展域名有这么多,其中还有了*.hao123.com,那我们再看看www.hao123.com的证书
发现的确是用的前面的百度证书
所以SAN带来的好处就可以看出来了,一个证书可以用在各种不同的域名下,不需要一个域名买一个证书了。
因为是本地环境,直接用OpenSSL给自己颁发一个CA根证书用于后面给服务器做CA签署。
1. 生成CA密钥
openssl genrsa -des3 -out ca.key 2048
2.生成CA根证书
openssl req -sha256 -new -x509 -days 365 -key ca.key -out ca.crt \
-subj "/C=CN/ST=GD/L=SZ/O=lee/OU=study/CN=testRoot"
3.生成服务器密钥
openssl genrsa -des3 -out server.key 2048
4.生成服务器证书请求文件
openssl req -new \
-sha256 \
-key server.key \
-subj "/C=CN/ST=GD/L=SZ/O=lee/OU=study/CN=bdstatic.com" \
-reqexts SAN \
-config <(cat /etc/pki/tls/openssl.cnf \
<(printf "[SAN]\nsubjectAltName=DNS:*.bdstatic.com,DNS:*.baidu.com")) \
-out server.csr
5.CA签署服务器证书
openssl ca -in server.csr \
-md sha256 \
-keyfile ca.key \
-cert ca.crt \
-extensions SAN \
-config <(cat /etc/pki/tls/openssl.cnf \
<(printf "[SAN]\nsubjectAltName=DNS:*.bdstatic.com,DNS:*.baidu.com")) \
-out server.crt
之后把生成好的服务器证书和服务器密钥在服务器(ngnix,tomcat)里配置好,并且把ca.crt证书导入到浏览器的受信任的根证书颁发机构里,在浏览器访问就不会有红叉叉了。
1. 关于私钥的加密格式,因为笔者是在netty里使用的ssl协议,而netty仅支持PKCS8格式的私钥(见http://netty.io/wiki/sslcontextbuilder-and-private-key.html),需要对密钥格式进行转换
//私钥转成PKCS8格式
openssl pkcs8 -topk8 -nocrypt -in server.key -out server_pri.pem
代码如下
SslContext serverSslCtx = SslContextBuilder.forServer(new File("E:/server.crt"),new File("E:/server_pri.pem")).build();
PKCS1与PKCS8格式互转
//默认生成PKCS1格式PEM编码私钥
openssl genrsa -out ca.key 2048
//转换成PKCS8
openssl pkcs8 -topk8 -nocrypt -in ca.key -out ca_private.pem
//PKCS8转换成PKCS1
openssl rsa -in ca_private.pem -out ca.key
PEM与DER互转
//PEM转DER
openssl rsa -in ca.key -outform DER -out ca_private.der
openssl pkcs8 -topk8 -nocrypt -inform PEM -outform DER -in ca.key -out ca_private.der
//DER转PEM
openssl rsa -in ca_private.der -inform DER -outform PEM -out ca.key
PKCS7转PKCS12(tomcat证书)
//需加密码保护
openssl pkcs12 -export -clcerts -in server.crt -inkey server.key -name tomcat -out server.p12
//springboot SSL配置
server.port= 8443 //端口
server.ssl.key-store=classpath:server.p12 //证书路径
server.ssl.key-store-password= 123456 //p12证书密码
OpenSSL SAN 证书
使用OpenSSL生成多域名自签名证书进行HTTPS开发调试
使用 openssl 生成证书
随后,将两个链接中的配置命令合并起来,也就是增加了SAN的选项,通过ssl.demo.com访问就不会告警了。