ssl证书制作

之前公司网站转为使用https方式访问,在此记录一下过程。

EasyRSA

参考https://sskaje.me/2015/09/easy-rsa-3-howto/

安装

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
wget https://github.com/OpenVPN/easy-rsa/releases/download/v3.0.3/EasyRSA-3.0.3.zip
unzip EasyRSA-3.0.3.zip && mv EasyRSA-3.0.3 /usr/local/
cd /usr/local/EasyRSA-3.0.3
wget -O vars https://raw.githubusercontent.com/OpenVPN/easy-rsa/master/easyrsa3/vars.example

cat >> /usr/local/EasyRSA-3.0.3/vars << EOF
set_var EASYRSA "\$PWD"
set_var EASYRSA_PKI "\$EASYRSA/pki"
set_var EASYRSA_DN "cn_only"
set_var EASYRSA_REQ_COUNTRY "CN"
set_var EASYRSA_REQ_PROVINCE "Guangdong"
set_var EASYRSA_REQ_CITY "Shenzhen"
set_var EASYRSA_REQ_ORG "PTC"
set_var EASYRSA_REQ_EMAIL "zhaoxunyong@qq.com"
set_var EASYRSA_REQ_OU "Devops"
set_var EASYRSA_KEY_SIZE 2048
set_var EASYRSA_ALGO rsa
set_var EASYRSA_CA_EXPIRE 7500
set_var EASYRSA_CERT_EXPIRE 365
set_var EASYRSA_NS_SUPPORT "no"
set_var EASYRSA_NS_COMMENT "SSKAJE CERTIFICATE AUTHORITY"
set_var EASYRSA_EXT_DIR "\$EASYRSA/x509-types"
set_var EASYRSA_SSL_CONF "\$EASYRSA/openssl-1.0.cnf"
set_var EASYRSA_DIGEST "sha256"
EOF

初始化PKI

1
./easyrsa init-pki

创建CA

1
./easyrsa build-ca

生成证书

生成证书的操作步骤就两步,生成请求文件,根据请求文件签发证书。
easy-rsa 3.0签发证书时要求制定type,可选的值参考x509-types目录下的文件名,包括

server:TLS服务端,适用于https服务端和vpn服务端
client:TLS客户端,适用于web浏览器和vpn客户端
ca:签发子CA证书
gen-req, build-client-full, build-server-full 可以使用 nopass 参数生成不加密的私钥。

一步创建:
可以使用 build-client-full 和 build-server-full 直接完成 gen-req 和 sign-req 的过程:

1
2
3
4
5
6
#./easyrsa build-client-full abc.com nopass
#./easyrsa build-client-full abc.com nopass
#gen-req and sign-req,对应的文件位于pki/reqs/与pki/private目录下
#./easyrsa build-server-full abc.com
$HOSTNAME=abc
./easyrsa --subject-alt-name="DNS:$HOSTNAME,DNS:www.example.net" build-server-full $HOSTNAME nopass

abc.com:为文件名称。
nopass:生成不加密的私钥。

也可以分步创建:
生成请求:

1
./easyrsa  gen-req abc.com

abc.com为文件名称,最终会生成abc.com.key给你abc.com.req文件。

签发证书:

1
./easyrsa sign-req server abc.com

abc.com为文件名称。

签发req文件:
如果req文件是外部创建的,可以使用 import-req 导入,再用 sign-req 签发:

1
./easyrsa import-req <request_file_path> <short_basename>

导出PKCS 7/PKCS 12

1
./easyrsa export-p7 abc.com

查看证书/查看请求文件

使用 show-cert 和 show-req 查看请求文件,参数是请求时的名字:

1
2
./easyrsa show-cert abc.com
./easyrsa show-req abc.com

更新数据库

1
./easyrsa update-db

使用2.x版本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
yum install epel-release
yum install easy-rsa
cd /usr/share/easy-rsa/2.0

#修改vars 相关变量:
export KEY_COUNTRY="CN"
export KEY_PROVINCE="Guangdong"
export KEY_CITY="shenzhen"
export KEY_ORG="abc.com"
export KEY_EMAIL="admin@abc.com"
export KEY_OU="OPS"

#执行以下命令:
. vars
#清除文件
./clean-all
#生成服务端CA
./build-ca
#生成服务端证书
./build-key-server server
#生成客户端证书
./build-key client1

openssl生成https/ssl的证书

假设生成根域名证书,域名为:*.abc.com。

颁发证书

如果是对外的服务,需要公共CA机构签署,不需要这步。
内网环境CA要给别人颁发证书,首先自己得有一个作为根证书:

1
2
3
4
5
6
7
8
9
10
11
12
13
#初始化
cd /etc/pki/CA/
touch index.txt serial
echo '01' > serial

#生成根密钥
#为了安全起见,修改cakey.pem私钥文件权限为600或400
umask 077; openssl genrsa -out private/cakey.pem 2048

#生成根证书
openssl req \
-subj "/C=CN/ST=GuangDong/L=ShenZhen/O=PTC/OU=Devops/CN=*.abc.com" \
-new -x509 -key private/cakey.pem -out cacert.pem

如果没有加-subj参数时,需要输入以下相关信息:
openssl

为web服务器生成ssl密钥

方法一:创建签名请求,然后通过私有CA签署:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#openssl req -newkey rsa:4096 -nodes -sha256 -keyout abc.com.key -out abc.com.csr
#-reqexts SAN -config参数为添加SAN信息,如果不需要SAN的话,可以不用。
openssl req \
-subj "/C=CN/ST=GuangDong/L=ShenZhen/O=PTC/OU=Devops/CN=*.abc.com" \
-reqexts SAN -config <(cat /etc/pki/tls/openssl.cnf <(printf "[SAN]\nsubjectAltName=DNS:www.abc.com,IP:192.168.10.6")) \
-newkey rsa:2048 -keyout abc.com.key -out abc.com.csr
#或者
#openssl genrsa -out abc.com.key 2048
#openssl req -subj "/C=CN/ST=GuangDong/L=ShenZhen/O=PTC/OU=Devops/CN=*.abc.com" -new -key abc.com.key -out abc.com.csr

# 自己签署
#一般内网环境采用自己签署(如果是对外的服务,需要公共CA机构签署):
openssl ca -in abc.com.csr -out abc.com.crt -cert /etc/pki/CA/cacert.pem -keyfile /etc/pki/CA/private/cakey.pem -outdir ./
#openssl x509 -req -in abc.com.csr -CA /etc/pki/CA/cacert.pem -CAkey /etc/pki/CA/private/cakey.pem -CAcreateserial -out abc.com.crt -days 365 -extensions v3_req -extfile openssl.cnf

方法二:创建签名请求,创建一个加密的私钥,然后通过私钥签署:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 生成私钥:
openssl genrsa -des3 -out abc.key.pem.encrypted 2048
# 生成解密后的private key:
openssl rsa -in abc.key.pem.encrypted -out abc.com.key

# 创建签名请求:
#-reqexts SAN -config参数为添加SAN信息,如果不需要SAN的话,可以不用。
openssl req -utf8 -config /etc/pki/tls/openssl.cnf \
-subj "/C=CN/ST=GuangDong/L=ShenZhen/O=PTC/OU=Devops/CN=*.abc.com" \
-reqexts SAN -config <(cat /etc/pki/tls/openssl.cnf <(printf "[SAN]\nsubjectAltName=DNS:www.abc.com,IP:192.168.10.6")) \
-new -key abc.key.pem.encrypted \
-out abc.req.csr -days 365

# 自己签署
#一般内网环境采用自己签署(如果是对外的服务,需要公共CA机构签署):
openssl x509 -req -days 365 -signkey abc.key.pem.encrypted -in abc.req.csr -out abc.cert.crt

公共CA机构签署

可以购买geotrust服务或者申请startssl免费一年的服务,具体请参考免费申请-StartSSL-证书

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# 生成key與csr
openssl req -newkey rsa:2048 -keyout abc.com.key -out abc.com.csr

# 将csr内容上传geotrust后,会生成IntermediateCA.crt、ssl_certificate.crt两个文件
cat ssl_certificate.crt IntermediateCA.crt >> abc.com.crt

### 添加
#将abc.com.crt与abc.key.pem加入到nginx中即可,比如:
server {
listen 80;
server_name abc.com;
rewrite ^(.*) https://$server_name$1 permanent;
}

server {
listen 443;
server_name abc.com;
access_log /var/log/nginx/your-domain.log main;

ssl on;
ssl_certificate /etc/nginx/ssl/abc.com.crt;
ssl_certificate_key /etc/nginx/ssl/abc.com.key;

location / {

log_not_found on;

proxy_pass http://127.0.0.1:8080;
proxy_read_timeout 300;
proxy_connect_timeout 300;
proxy_redirect off;

proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
}
}

私有CA签署时,浏览器不信任证书的解决方案

以macos为例:

1
2
#下载ca文件
sz /etc/pki/CA/cacert.pem

然后再导入系统,具体请参考:解决Mac Chrome打开HTTPS证书错误问题

SAN

什么是 SAN,SAN(Subject Alternative Name)是 SSL 标准 x509 中定义的一个扩展。使用了 SAN 字段的 SSL 证书,可以扩展此证书支持的域名,使得一个证书可以支持多个不同域名的解析。比如说:Common Name 字段是 *.google.com,这张证书通过SAN就能够被 www.youtube.com 这个域名所使用。原因就是这是一张带有 SAN 扩展的证书。
所以,只执行 NO SAN 命令也可以签发证书,不过却不能够添加多个域名。

想要添加多个域名或泛域名,你需要使用到该扩展。那么默认的 OpenSSL 的配置是不能够满足的,我们需要复制或下载一份默认的 openssl.cnf 文件到本地。如 github openssl

修改匹配策略:
默认匹配策略是:国家名,省份,组织名必须相同(match)。我们改为可选(optional),这样避免我们生成证书请求文件时(csr)去参考 CA 证书。

编辑/etc/pki/tls/openssl.cnf文件:

1
2
3
4
5
6
7
8
# For the CA policy
[ policy_match ]
countryName = match
stateOrProvinceName = optional
organizationName = optional
organizationalUnitName = optional
commonName = supplied
emailAddress = optional

以上为可选项。

修改默认值:
修改默认值,可以让你更快的颁发证书,一直回车就可以了:
编辑/etc/pki/tls/openssl.cnf文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
[ req_distinguished_name ]
countryName = Country Name (2 letter code)
countryName_default = CN
countryName_min = 2
countryName_max = 2

stateOrProvinceName = State or Province Name (full name)
stateOrProvinceName_default = Guangdong

localityName = Locality Name (eg, city)
localityName_default = Shenzhen

0.organizationName = Organization Name (eg, company)
0.organizationName_default = Dev

# we can do this but it is not needed normally :-)
#1.organizationName = Second Organization Name (eg, company)
#1.organizationName_default = World Wide Web Pty Ltd

organizationalUnitName = Organizational Unit Name (eg, section)
organizationalUnitName_default = Dev

commonName = Common Name (eg, your name or your server\'s hostname)
commonName_max = 64

emailAddress = zhaoxunyong@qq.com
emailAddress_max = 64

# SET-ex3 = SET extension number 3

关键步骤:
最关键的地方是修改 v3_req。添加成如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[ v3_req ]

# Extensions to add to a certificate request

basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
subjectAltName = @alt_names

[ alt_names ]
DNS.1 = abc.com
DNS.2 = *.abc.com
DNS.3 = localhost
IP.1 = 127.0.0.1
IP.2 = 192.168.10.6
IP.3 = 192.168.10.7
IP.4 = 192.168.10.8

环境变量:
openssl 通过 $ENV::name 获取环境变量,在配置文件里使用的时候只需将 name 替换为需要用到的环境变量的名称就可以了:

1
$ export SNAS=DNS:abc.com,DNS:*.abc.com,DNS:xyz.com,IP:127.0.0.1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 修改 openssl.cnf
[ v3_req ]

# Extensions to add to a certificate request

basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
subjectAltName = $ENV::SANS

# 注释掉这段配置
#[ alt_names ]
#DNS.1 = abc.com
#DNS.2 = *.abc.com
#DNS.3 = localhost
#IP.1 = 127.0.0.1
#IP.2 = 192.168.10.6
#IP.3 = 192.168.10.7
#IP.4 = 192.168.10.8

jks证书

1
2
3
#生成jks:
keytool -genkey -alias abc.com -keyalg RSA -keystore abc.jks -keysize 2048 -dname "CN=*.abc.com,OU=,O=xxxx有限公司,L=深圳市,ST=广东省,C=CN" -storepass "Aa123456" -keypass "Aa123456"
#注意:CN表示颁发给哪个url,可以用*.abc.com表示所有

转换jks为OpenSSL的PEM格式文件(.key + .crt)

http://ju.outofmemory.cn/entry/212469

先导出p12:

1
keytool -importkeystore -srckeystore abc.jks -destkeystore abc.p12 -srcstoretype jks -deststoretype pkcs12

方式一:
生成pem证书(包含了key,server证书和ca证书):

1
2
3
4
5
6
7
8
9
10
11
# 生成key 加密的pem证书
$ openssl pkcs12 -in abc.p12 -out abc.key.pem
Enter Import Password:
MAC verified OK
Enter PEM pass phrase:
Verifying - Enter PEM pass phrase:

# 生成key 非加密的pem证书
$ openssl pkcs12 -nodes -in server.p12 -out abc.key.pem
Enter Import Password:
MAC verified OK

剩下步骤与为web服务器生成ssl密钥类似。

方式二:
单独导出key:

1
2
3
4
5
6
#生成key加密的pem证书:
$ openssl pkcs12 -in server.p12 -out abc.key.pem

#生成非加密的key:
#(只保留BEGIN与END中的内容,包括BEGIN与END)
openssl pkcs12 -in abc.p12 -nocerts -nodes -out abc.key.pem

单独导出server证书:

1
openssl pkcs12 -in abc.p12  -nokeys -cacerts -out abc.cert.crt

单独导出ca证书:

1
openssl pkcs12 -in abc.p12  -nokeys -cacerts -out ca.crt

方式三:

1
2
#生成csr文件:
keytool -certreq -keyalg RSA -alias abc.com -file abc.req.csr -keystore abc.jks -storepass "Aa123456" -keypass "Aa123456"

生成私钥:
windows下运行kestore-export中的工具:

1
2
3
4
5
6
7
JKS2PFX.bat abc.jks "Aa123456" "abc.com" "key/abc" "D:\Developer\java\jdk1.7.0_51\jre\bin"

#上传key/abc.com.key到linux下并执行:
openssl rsa -in abc.com.key -des3 -out abc.key.encrypted

#自己签署csr文件:
#openssl x509 -req -days 365 -in abc.req.csr -signkey abc.key.encrypted -out abc.cert.crt

1
2
#将csr内容上传geotrust后,会生成IntermediateCA.crt、ssl_certificate.crt两个文件
cat ssl_certificate.crt IntermediateCA.crt >> abc.com.crt

格式转换

https://support.wosign.com/index.php?/Knowledgebase/Article/View/36/0/

key、crt转换为p12

1
openssl pkcs12 -export -clcerts -in abc.cert.crt -inkey abc.key.pem -out abc.p12

key、crt转换为pfx

1
openssl pkcs12 -export -inkey abc.key.pem -in abc.com.crt -out abc.pfx

pfx转换jks

1
keytool -importkeystore -srckeystore abc.pfx -destkeystore abc.com.jks -srcstoretype PKCS12 -deststoretype JKS

crt转换为jks

1
keytool -import -v -trustcacerts -storepass "Aa123456" -alias abc.com -file abc.cert.crt -keystore abc.jks

参考

https://deepzz.com/post/based-on-openssl-privateCA-issuer-cert.html
http://liaoph.com/openssl-san/
https://mritd.me/2016/07/03/Harbor-%E4%BC%81%E4%B8%9A%E7%BA%A7-Docker-Registry-HTTPS%E9%85%8D%E7%BD%AE/
https://mritd.me/2016/07/02/%E4%BA%92%E8%81%94%E7%BD%91%E5%8A%A0%E5%AF%86%E5%8F%8AOpenSSL%E4%BB%8B%E7%BB%8D%E5%92%8C%E7%AE%80%E5%8D%95%E4%BD%BF%E7%94%A8/
https://mritd.me/2016/06/22/%E5%85%8D%E8%B4%B9%E7%94%B3%E8%AF%B7-StartSSL-%E8%AF%81%E4%B9%A6/
http://seanlook.com/2015/01/18/openssl-self-sign-ca/
http://seanlook.com/2015/01/15/openssl-certificate-encryption/
http://seanlook.com/2015/01/07/tls-ssl/#comments
http://netsecurity.51cto.com/art/200602/21066.htm
http://cnzhx.net/blog/self-signed-certificate-as-trusted-root-ca-in-windows/
http://www.cnblogs.com/snandy/p/3262661.html
http://www.iloveandroid.net/2015/10/14/jksTopm/