生成根证书CA及签发子证书及配置站点实践

使用 OPENSSL 生成CA证书及签名

环境准备

需要安装 openssl。具体安装方法见:https://www.openssl.org/source/

这里用的ubuntu16.04,自带的。

1
2
ff@xx:~$ openssl version
OpenSSL 1.0.2g 1 Mar 2016

实践过程

1
2
3
4
5
6
7
8
9
# 生成ca密钥
openssl genrsa -out ca.key 2048
# 生成CA证书
openssl req -x509 -new -nodes -key ca.key -subj "/CN=FENG" -days 365 -out ca.crt
# 把ca导出成p12格式,
openssl pkcs12 -export -clcerts -in ./ca.crt -inkey ca.key -out ca.p12

# 指定p12密码的方法
# openssl pkcs12 -export -clcerts -in ./ca.crt -inkey ca.key -out ca.p12 -password pass:123123
1
2
3
4
5
6
7
8
9
10
11
# 生成站点证书密钥
openssl genrsa -out server.key 2048
# 生成签发申请文件(csr文件)
openssl req -new -key server.key -subj "/CN=yy.xx.com" -out server.csr
# 用CA对上面生成的证书信息进行签名
openssl x509 -req -days 30 -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt
# 把服务器的证书导出成p12格式
openssl pkcs12 -export -clcerts -in ./server.crt -inkey server.key -out server.p12

# 指定密码
# openssl pkcs12 -export -clcerts -in ./server.crt -inkey server.key -out server.p12 -password pass:123123

这样操作这后文件会生成这8个文件

1
2
3
4
5
6
7
8
ca.crt
ca.key
ca.p12
ca.srl
server.crt
server.csr
server.key
server.p12
  • .key为私钥文件,以RSA PRIVATE KEY开始和结束,也可能是.pem后缀
  • .csr为签发申请文件,包含的申请人的一些基本信息,以CERTIFICATE REQUEST开始和结束
  • .crt为证书文件,是通过密钥和基本信息加密生成的,以CERTIFICATE开始的结束,也可能有别的后缀,如.cer
  • .p12 为把证书与中间证书及私钥加密放在一个文件中,为二进制文件
  • 其中.csr文件可以用 CSR文件在线生成工具 来生成
  • 关于文件格式的说明详细的可以看 格式说明这篇

实际应用

现在已有站点yy.xx.comserver.crt(证书文件),server.key(私钥文件)。
于是可以在nginx上配置yy.xx.com的https访问了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name yy.xx.com;
ssl_certificate /dir/server.crt;
ssl_certificate_key /dir/server.key;
ssl_session_timeout 1d;
ssl_session_cache shared:SSL:50m;
ssl_session_tickets off;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS';
ssl_prefer_server_ciphers on;

root /tmp/nginx/;

}

crul 验证

配置好之后运行

1
curl -v https://yy.xx.com

发现报错unable to get local issuer certificate

1
2
3
4
5
6
7
8
9
10
11
* SSL certificate problem: unable to get local issuer certificate
* Closing connection 0
* TLSv1.2 (OUT), TLS alert, Client hello (1):
curl: (60) SSL certificate problem: unable to get local issuer certificate
More details here: https://curl.haxx.se/docs/sslcerts.html

```

正常的,因为生成的CA证书明显在不curl默认的根证书列表中的。

所以需要指定根证书,如下

curl -v –cacert ca.crt https://yy.xx.com

1
2

运行结果会握手成功

  • TLSv1.2 (IN), TLS handshake, Finished (20):
  • SSL connection using TLSv1.2 / ECDHE-RSA-AES128-GCM-SHA256
  • ALPN, server accepted to use h2
  • Server certificate:
  • subject: CN=yy.xx.com
    `

浏览器验证

用浏览器(以chrome为例)直接访问
会现NET::ERR_CERT_INVALID这样的错误

也是正常的,也是因为生成根证书并不在计算机中。

现在把根证书导入到计算机中。

把crt文件拷贝到计算机中,打开,安装证书,进入证书导入向导。
第二步中(证书存储)中要选第二项,点浏览,选受信任的根证书颁发机构这一项。
最后会有一个安全警告,选是就可以了。

结果:
IE上,https访问未报错误。
chrome,换一个提示,提示NET::ERR_CERT_COMMON_NAME_INVALID

查了下,参见 主题备用名称缺失

Chrome 58 及以上版本只会使用 subjectAlternativeName 扩展程序(而不是 commonName)来匹配域名和网站证书。主题备用名称可以是域名,也可以是 IP 地址。如果证书没有正确的 subjectAlternativeName 扩展程序,系统就会向用户发送 NET::ERR_CERT_COMMON_NAME_INVALID 错误消息,告知他们连接并非处于私密状态。如果证书缺少 subjectAlternativeName 扩展程序,系统就会在 Chrome DevTools 的“安全”面板中显示警告,告知用户主题备用名称缺失。

简单来说就是签名证书的缺参数。因为这本来也是试验,这部分参书未继续探究。

参考