前言 如果您想经常创建自签名证书,可以使用以下 shell 脚本。您只需要使用要添加到证书的域名或 IP 执行脚本。 将以下 shell 脚本另存为ssl.sh
准备工作
脚本 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 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 # https://***/openssl-x509.html 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
笔记 使用自签名证书有什么好处? 使用自签名证书有几个好处:
您无需依赖第三方来签署您的证书。
您可以创建和使用自己的证书颁发机构。
您不必为 CA 的证书付费。
您可以更好地控制您的证书。
使用自签名证书有什么缺点? 使用自签名证书也有几个缺点:
您的用户需要在他们的浏览器或应用程序中安装证书。
您的用户将需要手动信任您的证书颁发机构。
它们对于面向公众的应用程序不安全。
除非用户安装它们,否则所有浏览器或操作系统都不信任自签名证书。
容易受到中间人攻击。
通常,对于需要证明自己身份的应用程序,自签名证书是一个不错的选择。它们也是开发和测试环境的不错选择。但是,它们不应该用于生产应用程序。
组织中的自签名证书 许多组织对其不面向 Internet 的内部应用程序使用自签名证书。这些证书是使用组织的内部 PKI 基础结构生成的。
CRT、CER、PEM .CRT
= CRT扩展用于证书
。证书可以被编码为二进制DER
或ASCII PEM
CER
和CRT
扩展几乎是同义词,最常见的于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 openssl pkcs12 -export -in SOYBEAN.crt -inkey SOYBEAN.key -name SOYBEANAPP -passout pass: -out SOYBEAN.pfx # 合成 pkcs 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 里报错
修改MSYS_NO_PATHCONV
环境变量为1
将第一个/
变成//
,并将第一个参数重复;看起来像:-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