Windows+OpenSSL创建自签名证书脚本

Windows+OpenSSL创建自签名证书脚本

前言

如果您想经常创建自签名证书,可以使用以下 shell 脚本。您只需要使用要添加到证书的域名或 IP 执行脚本。 将以下 shell 脚本另存为ssl.sh

准备工作

  • Git For Windows
  • Git Bash

脚本

ssl.sh脚本

ssl.sh
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
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
#! /bin/bash
# 自签证书【IP版】
# Grafana
# ./test.sh -co "SOYBEAN" -cou "SOYBEAN" -ccn "192.168.1.1" -cdomain "192.168.1.1" -so "SOYBEAN" -sou "192.168.1.2" -scn "Grafana" -sdomain "192.168.1.2"

if [ -s "$PWD/m_msg.sh" ]; then
source "$PWD/m_msg.sh"
fi
if [ -s "$PWD/common.sh" ]; then
source "$PWD/common.sh"
fi

# 固定参数【按需修改】
_C_C="CN"
_C_ST="ZJ"
_C_L="HZ"

_S_C="CN"
_S_ST="ZJ"
_S_L="HZ"
_S_Days=3650

# 参数

# Root CA
# 根CA 所在 IP/域名
_C_DOMAIN=
# CA组织、单位名称
_C_O=
_C_OU=
# Common Name
_C_CN=
# 签发证书序列号
_C_SRL="rootCA.SRL"


# Server
_S_O=
_S_OU=
# 服务的 Common Name
_S_CN=
_S_DOMAIN=

# openssl

_dhparamFlag=

# 参数获取

# Setup getopt.
long_opts="co:,cou:,ccn:,cdomain:,so:,sou:,scn:,sdomain:,dhparam"
getopt_cmd=$(getopt -a -o : --l "$long_opts" \
-- "$@") ||
{
echo -e "\nERROR: Getopt failed. Extra args\n"
exit 1
}

eval set -- "$getopt_cmd"
while true; do
case "$1" in
--co)
_C_O="$2"
shift
;;
--cou)
_C_OU="$2"
shift
;;
--ccn)
_C_CN="$2"
shift
;;
--cdomain)
_C_DOMAIN="$2"
shift
;;
--so)
_S_O="$2"
shift
;;
--sou)
_S_OU="$2"
shift
;;
--scn)
_S_CN="$2"
shift
;;
--sdomain)
_S_DOMAIN="$2"
shift
;;
--dhparam)
_dhparamFlag="1"
;;
--)
shift
break
;;
esac
shift
done

if [ ${#_C_DOMAIN} -lt 1 ]; then
printERROR "错误:未提供【C_DOMAIN】参数!"
exit 1
elif [ ${#_C_O} -lt 1 ]; then
printERROR "错误:未提供【C_O】参数!"
exit 1
elif [ ${#_C_OU} -lt 1 ]; then
printERROR "错误:未提供【C_OU】参数!"
exit 1
elif [ ${#_C_CN} -lt 1 ]; then
printERROR "错误:未提供【C_CN】参数!"
exit 1
elif [ ${#_S_O} -lt 1 ]; then
printERROR "错误:未提供【S_O】参数!"
exit 1
elif [ ${#_S_OU} -lt 1 ]; then
printERROR "错误:未提供【S_OU】参数!"
exit 1
elif [ ${#_S_CN} -lt 1 ]; then
printERROR "错误:未提供【S_CN】参数!"
elif [ ${#_S_DOMAIN} -lt 1 ]; then
printERROR "错误:未提供【S_DOMAIN】参数!"
fi


# 根CA 所在 IP/域名 格式化【处理特殊符号】替换".""-"
_C_DOMAINFORMAT=$(getFormaterStr "$_C_DOMAIN");
# 根CA 私钥、证书文件名称
_C_FileName="${_C_DOMAINFORMAT}_RootCA"
# 根CA 输出文件夹路径【默认为_C_DOMAINFORMAT】
_FilePath="./${_C_DOMAINFORMAT}"
# 根 CA 证书、私钥路径【默认目录为根据_FilePath】
_CAKey="${_C_FileName}.key"
_CACrt="${_C_FileName}.crt"


# 脚本工作目录
work_path=$(dirname "$(readlink -f "$0")")
printINFO "脚本工作目录:$work_path"

# 这里的-x 参数判断 $FilePath 是否存在并且是否具有可执行权限,不存在创建目录,存在输出路径;
if [ ! -x "$_FilePath" ]; then
mkdir "$_FilePath" && cd "$_" && printINFO "文件输出目录:$PWD"
else
cd "$_FilePath" && printINFO "文件输出目录:$PWD"
fi

# Server 证书序列号,默认1【十进制】
SERIAL_NUM=$(getSerialNum) ; printINFO "Server 证书序列号:$SERIAL_NUM"

# Server 私钥、证书文件名称
# 生成文件名称格式为:$_C_DOMAINFORMAT_$_S_CN
_S_FileName="${_C_DOMAINFORMAT}_"$(getFormaterStr "$_S_CN");

#当前命令行所在路径是否存在根 CA 证书和私钥
FileFLAG="true"

if [ ! -s "$_CAKey" ]; then
printERROR "根 CA 私钥 ${_CAKey} 不存在";FileFLAG="false"
elif [ ! -s "$_CACrt" ]; then
printERROR "根 CA 证书 ${_CACrt} 不存在";FileFLAG="false"
else
FileFLAG="true"
fi

if [ $FileFLAG = "true" ]; then
printOK "文件已存在,使用下列文件创建SSL证书:根CA证书:${_CAKey},根CA私钥:${_CACrt} "
else
printINFO "创建根 CA 证书和 CA 私钥 "
# 创建根 CA 证书和 CA 私钥【-nodes:无密码】
openssl req -x509 \
-sha256 -days 3560 \
-nodes \
-newkey rsa:2048 \
-subj "//C=${_C_C}/C=${_C_C}/ST=${_C_ST}/L=${_C_L}/O=${_C_O}/OU=${_C_OU}/CN=${_C_CN}" \
-keyout "${_C_FileName}".key -out "${_C_FileName}".crt
fi



printOK "生成 Server 私钥 : ${_S_FileName}.key"
# 生成 Server 私钥

openssl genrsa -out "${_S_FileName}".key 2048

printOK "创建 csr 配置: csr.conf "
# 创建 csr 配置

cat >csr.conf <<EOF
[ req ]
default_bits = 2048
prompt = no
default_md = sha256
req_extensions = req_ext
distinguished_name = dn

[ dn ]
C = $_S_C
ST = $_S_ST
L = $_S_L
O = $_S_O
OU = $_S_OU
CN = $_S_CN

[ req_ext ]
subjectAltName = @alt_names

[ alt_names ]
#DNS.1 = ${_S_DOMAIN}
IP.1 = ${_S_DOMAIN}

EOF

printOK "使用 Server 私钥创建 CSR 请求"
# 使用Server 私钥创建 CSR 请求

openssl req -new -key "${_S_FileName}".key -config csr.conf -out "${_S_FileName}".csr

printOK "为 Server CSR 请求创建一个外部配置文件:cert.conf"
# 为 Server CSR 请求创建一个外部配置文件

cat >cert.conf <<EOF

authorityKeyIdentifier=keyid,issuer
basicConstraints=CA:FALSE
keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
subjectAltName = @alt_names

[alt_names]
#DNS.1 = ${_S_DOMAIN}
IP.1 = ${_S_DOMAIN}

EOF

printOK "使用自签名 CA ${_CACrt} 创建 SSl证书 :${_S_FileName}.crt"
# 使用自签名 CA 创建 SSl证书

openssl x509 -req \
-in "${_S_FileName}".csr \
-CA "${_C_FileName}".crt -CAkey "${_C_FileName}".key \
-days "${_S_Days}" \
-sha256 -extfile cert.conf \
-CAcreateserial \
-set_serial "${SERIAL_NUM}" \
-out "${_S_FileName}".crt

printOK "合成 pkcs#12 证书"
# 转换证书编码格式
# 合成 pkcs#12 证书(含私钥和CA 证书)
openssl pkcs12 -export -name "${_S_CN}" -caname "${_C_CN}" \
-in "${_S_FileName}".crt \
-inkey "${_S_FileName}".key \
-nodes \
-password pass: \
-chain \
-CAfile "${_C_FileName}".crt \
-out "${_S_FileName}".pfx

if [ $_dhparamFlag ]
then
openssl dhparam 2048 -check -out dhparam.pem ; printOK "已生成dhparam.pem ! "
fi

printSUCCESS "CA 证书内容:"
openssl x509 -in "${_C_FileName}".crt -noout -text

printSUCCESS "SSl证书内容:"
openssl x509 -in "${_S_FileName}".crt -noout -text

printSUCCESS "CRT证书链 合成"
cat "${_S_FileName}".crt "${_C_FileName}".crt > "${_S_FileName}_ALL".crt

printSUCCESS "CRT证书链 合成内容:"
openssl x509 -in "${_S_FileName}_ALL".crt -noout -text

m_msg.sh脚本

m_msg.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#! /bin/bash

# echo 颜色样式
OK="\033[42;37m "
# OK="\033[32m "
SUCCESS="\033[42;37m "
INFO="\033[34m "
ERROR="\033[41;30m "
RESET="\033[0m "

printOK() {
echo -e "${OK}==== $* ====${RESET}"
}
printSUCCESS() {
echo -e "${SUCCESS}==== $* ====${RESET}"
}
printINFO() {
echo -e "${INFO}==== $* ====${RESET}"
}
printERROR() {
echo -e "${ERROR}==== $* ====${RESET}"
}

common.sh脚本

common.sh
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
#! /bin/bash

# 方法

# dec to hex
dec2hex() {
printf "%x" "$1"
}

# rootCA.SRL获取证书序列号【十进制数】,并更新数值
# 根据文件中的数值返回对应的十六进制值
# 文件不存在或无值,默认返回 0x1
getSerialNum() {
if [ ! -s "rootCA.SRL" ]; then
cat >rootCA.SRL <<EOF
1
EOF
else
num=$(<rootCA.SRL) &&
cat >rootCA.SRL <<EOF
$((num + 1))
EOF
fi

#十进制转十六进制
strserialnum=$(<rootCA.SRL)
printf "%s""$(dec2hex "$strserialnum")"
}

getFormaterStr() {
para=$1
for char in "." ":" "\\" "*" "?"; do
para=${para//"$char"/-}
done
echo "$para"
}

ssl.sh 脚本的使用

1
./ssl.sh -co "SOYBEAN" -cou "SOYBEAN" -ccn "192.168.1.1" -cdomain "192.168.1.1" -so "SOYBEAN" -sou "192.168.1.2" -scn "Grafana" -sdomain "192.168.1.2"

该脚本将创建我们使用各个命令创建的所有证书和密钥。 SSL 证书和私钥使用您作为脚本参数传递的IP命名。


Sign.sh脚本【按需修改脚本内容,执行脚本生成证书,可生成V1版本证书,用于兼容特殊环境。】

下列脚本生成了CA根证书 以及CAS服务证书:

Tips:通过-extfile x509.ext -extensions ca该参数,可以控制生成的证书是否添加证书拓展属性,该参数行默认添加,可以自行移除,移除后生成的证书为V1版本,无拓展属性。

sign.sh
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
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
#! /bin/bash
# V1证书 移除此参数:-extfile x509.ext -extensions ca
# https://www.openssl.org/docs/man3.0/man1/openssl-x509.html#-extfile
# https://***/openssl-x509.html#-req
cat >x509.ext <<EOF

[ ca ]
# X509 extensions for a ca
keyUsage = critical, cRLSign, keyCertSign
basicConstraints = CA:TRUE, pathlen:0
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer:always

[ server ]
# X509 extensions for a server
keyUsage = critical,digitalSignature,keyEncipherment
extendedKeyUsage = serverAuth,clientAuth
basicConstraints = critical,CA:FALSE
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer:always

EOF
# CA 根证书
openssl req -new -sha256 -nodes -newkey rsa:2048 \
-subj "//C=CN/C=CN/ST=ZJ/L=HZ/O=SOYBEAN/OU=SOYBEAN/CN=SOYBEANCA" \
-keyout CA.key \
-out CA.csr \

openssl x509 -req -sha256 -days 3650 \
-extfile x509.ext -extensions ca \
-in CA.csr \
-signkey CA.key \
-out CA.pem

# CAS
openssl req -new -sha256 -nodes \
-newkey rsa:2048 \
-subj "//C=CN/C=CN/ST=ZJ/L=HZ/O=SOYBEAN/OU=SOYBEAN/CN=CASSERVER" \
-keyout CAS.key \
-out CAS.csr \

openssl x509 -req -sha256 \
-CA CA.pem -CAkey CA.key \
-days 3650 -CAcreateserial -CAserial CA.srl \
-extfile x509.ext -extensions server \
-in CAS.csr \
-out CAS.pem

openssl pkcs12 -export -nodes -password pass: \
-name "CAS" \
-caname "SOYBEANCA" \
-in CAS.pem -inkey CAS.key \
-chain -CAfile CA.pem \
-out CAS.pfx


笔记

使用自签名证书有什么好处?

使用自签名证书有几个好处:

  1. 您无需依赖第三方来签署您的证书。
  2. 您可以创建和使用自己的证书颁发机构。
  3. 您不必为 CA 的证书付费。
  4. 您可以更好地控制您的证书。

使用自签名证书有什么缺点?

使用自签名证书也有几个缺点:

  1. 您的用户需要在他们的浏览器或应用程序中安装证书。
  2. 您的用户将需要手动信任您的证书颁发机构。
  3. 它们对于面向公众的应用程序不安全。
  4. 除非用户安装它们,否则所有浏览器或操作系统都不信任自签名证书。
  5. 容易受到中间人攻击。

通常,对于需要证明自己身份的应用程序,自签名证书是一个不错的选择。它们也是开发和测试环境的不错选择。但是,它们不应该用于生产应用程序。

组织中的自签名证书

许多组织对其不面向 Internet 的内部应用程序使用自签名证书。这些证书是使用组织的内部 PKI 基础结构生成的。

CRT、CER、PEM

.CRT = CRT扩展用于证书。证书可以被编码为二进制DERASCII PEM

CERCRT扩展几乎是同义词,最常见的于Unix 或类Unix系统。

CER = .crt的替代形式(Microsoft Convention)

可以用微软的工具把CRT文件转换为CER文件(CRT和CER必须是相同编码的,DER或者PEM)。

扩展名为CER的文件可以被IE识别并作为命令调用微软的cryptoAPI(具体点就是rudll32.exe cryptext.dll, CyrptExtOpenCER),进而弹出一个对话框来导入并/或查看证书内容。

查看证书细节

1
openssl x509 -in SOYBEAN.crt -noout -text

转换证书编码格式

.cer、crt 与 pem、pfx

.cer/.crt是用于存放证书,它是2进制形式存放的,不含私钥,含公钥

.pem跟.crt/.cer的区别是它以Ascii码来表示(字符串)

.pfx/.p12用于存放个人证书/私钥,它通常包含保护密码,2进制方式

注:node服务器需要的是.pem格式的私钥与证书,iOS中需要的是.cer二进制格式的证书。

1
2
3
4
5
6
7
8
#   .crt 转 .pem
openssl x509 -in SOYBEAN.crt -inform PEM -outform PEM -out SOYBEAN.pem
# .cer 转 .pem
# openssl x509 -in SOYBEAN.cer -inform PEM -outform PEM -out SOYBEAN.pem
# 合成 pkcs#12 证书(含私钥)
openssl pkcs12 -export -in SOYBEAN.crt -inkey SOYBEAN.key -name SOYBEANAPP -passout pass: -out SOYBEAN.pfx
# 合成 pkcs#12 证书(含私钥和CA 证书)
openssl pkcs12 -export -name SOYBEANAPP -caname CAServer -in SOYBEAN.crt -inkey SOYBEAN.key -nodes -password pass: -chain -CAfile ca.crt -out server-all.pfx

-subj项在Windows的git Bash 里报错

  1. 修改MSYS_NO_PATHCONV环境变量为1
  2. 将第一个/变成//,并将第一个参数重复;看起来像:-subj "/C=CN/ST=ZJ/L=HZ/O=SOYBEAN/OU=SOYBEANDEPT/CN=CASERVER"==>-subj "//C=CN/C=CN/ST=ZJ/L=HZ/O=SOYBEAN/OU=SOYBEANDEPT/CN=CASERVER"

Unable to use -subj with Windows Git Bash

1
2
3
4
5
openssl genrsa -out ca.key 2048
openssl req -new -x509 -days 3650 -key ca.key -out ca.crt -subj "//C=CN/C=CN/ST=ZJ/L=HZ/O=SOYBEAN/OU=SOYBEANDEPT/CN=CASERVER"
openssl genrsa -out server.key 2048
openssl req -new -key server.key -out server.csr -subj "//C=CN/C=CN/ST=ZJ/L=HZ/O=SOYBEAN/OU=SOYBEANDEPT/CN=192.168.1.1"
openssl x509 -req -days 3650 -in server.csr -CA ca.crt -CAkey ca.key -set_serial 01 -out server.crt

输出为pfx文件

生成pfx文件无响应,原来是少了个参数:-passout pass:SomePassword;即使密码为空也需要这个参数。

OpenSSL hangs during PKCS12 export with “Loading ‘screen’ into random state”

1
openssl pkcs12 -export -in server.crt -inkey server.key -name server -passout pass: -out server.pfx

参考

https://www.jianshu.com/p/e5f46dcf4664
https://ningyu1.github.io/site/post/51-ssl-cert/
https://www.cnblogs.com/junjiany/p/6273560.html
https://www.cnblogs.com/f-ck-need-u/p/7113610.html
https://blog.miniasp.com/post/2022/06/14/How-to-request-new-tls-certificate-using-OpenSSL

Windows创建自定义根证书、自签名服务证书【一】

Windows创建自定义根证书、自签名服务证书【一】

Windows创建自定义根证书、自签名服务证书【一】

参考文章

https://devopscube.com/create-self-signed-certificates-openssl

环境

  • Windows 21H2
  • Git For Windows
  • Git Bash

起步

创建自签根证书

我们需要为浏览器创建自己的根 CA 证书以信任自签名证书。因此,让我们首先创建根 CA 证书。 让我们创建一个名为 openssl 的目录来保存所有生成的密钥和证书。

1
mkdir openssl && cd openssl

执行以下openssl命令来创建rootCA.keyrootCA.crt。替换SOYBEANCA为您的域名或 IP 地址,这里用SOYBEAN作为单位和组织名称。

1
openssl req -new -x509 -days 3650 -nodes -subj "//C=CN/C=CN/ST=ZJ/L=HZ/O=SOYBEAN/OU=SOYBEAN/CN=SOYBEANCA" -keyout rootCA.key -out rootCA.crt

创建自签名服务证书

请按照以下步骤创建自签名证书。我们将使用我们在上一步中创建的根 CA 注销证书。

创建自签名服务私钥

1
openssl genrsa -out lis.key 2048

创建”证书签名请求”配置文件

证书签名请求英文名:Certificate signing request

我们将创建一个 lis_csr.conf 文件以包含生成 CSR 的所有信息。将 alt_names节点中的值替换为您的域名或 IP 地址。

lis_csr.conf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
[ req ]
default_bits = 2048
prompt = no
default_md = sha256
req_extensions = req_ext
distinguished_name = dn

[ dn ]
C = CN
ST = ZJ
L = HZ
O = SOYBEAN
OU = SOYBEAN
CN = 192.168.1.1

[ req_ext ]
subjectAltName = @alt_names

[ alt_names ]
IP.1 = 192.168.1.1
#DNS.1 = site.com

使用自签名服务私钥生成证书签名请求 (CSR)

1
openssl req -new -key lis.key -out lis.csr -config lis_csr.conf

现在我们的文件夹应该有三个文件。lis_csr.conf,lis.csrlis.key

创建自签名服务证书拓展属性配置文件

为 SSL 证书创建lis_cert.conf。将 alt_names节点中的值替换为您的域名或 IP 地址。

lis_cert.conf
1
2
3
4
5
6
7
8
authorityKeyIdentifier=keyid,issuer
basicConstraints=CA:FALSE
keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
subjectAltName = @alt_names

[alt_names]
IP.1 = 192.168.1.1
#DNS.1 = site.com

使用自签名根证书 生成 自签名服务证书

现在,执行以下命令来生成以rootCA.crtrootCA.key为证书颁发机构,创建自签名证书:lis.crt

1
openssl x509 -req  -days 3650 -CAcreateserial -set_serial 01 -CA rootCA.crt  -extfile lis_cert.conf -CAkey rootCA.key -in lis.csr  -out lis.crt  

上面的命令将生成 lis.crt ,它将与我们的 lis.key 一起使用,以在应用程序中启用 SSL。

tips:-CAcreateserial使用后,需要添加-set_serial 01以避免一些问题的发生。如果不指定serial值,会在输出目录生成一个SRL文件,是openssl跟踪可用于新证书的最新序列号的文件,关于SRL文件的问题,见:https://stackoverflow.com/a/66357989。

结束

执行上述流程后,应该会拥有4个文件:rootCA.crtrootCA.keylis.crtlis.key

Your browser is out-of-date!

Update your browser to view this website correctly.&npsb;Update my browser now

×