Skip to content

Instantly share code, notes, and snippets.

@ppzz
Last active April 19, 2021 11:20
Show Gist options
  • Save ppzz/90e6c86c934bed0cdadea3bf736d6628 to your computer and use it in GitHub Desktop.
Save ppzz/90e6c86c934bed0cdadea3bf736d6628 to your computer and use it in GitHub Desktop.
openssl-generate-cab.bash
#!/usr/bin/env bash
# ref: https://linkscue.com/posts/2019-06-26-ca-and-self-signed-certificates/
# CA服务的存放位置
# 用来创建CA证书,首先创建一个根CA证书, 在创建一个次级CA证书,再用次级CA证书来签发其他的CA证书。
# code by penn
# CA服务相关文件的目录
SSL_DIR=/home/penn/ssl # 所有的数据存放目录
Config=${SSL_DIR}/openssl.cnf # 配置文件路径
CA_Dir=${SSL_DIR}/ca # CA证书的目录
CA_Data_Dir=${CA_Dir}/db # CA签发过程中的其他文件的路径
# 存储CA服务的文件路径
Root_CA_Dir=${CA_Dir}/root-ca # 根CA 目录
Root_CA_KEY=${Root_CA_Dir}/root-ca.key # 根CA Key
Root_CA_CRT=${Root_CA_Dir}/root-ca.crt # 根CA 证书
Sub_CA_Dir=${CA_Dir}/sub-ca # 根CA签发次级CA证书的目录
Service_Certificate_Dir=${CA_Dir}/service # 次级CA签发的服务证书的目录
# SUBJECT为CA服务的机构信息
CA_Subject="/C=CN/ST=SiChuan/O=HardNuts Inc."
Root_CA_Subject="${CA_Subject}/OU=ROOT-CA"
Sub_CA_Subject="${CA_Subject}/OU=SUB-CA"
Service_Subject="${CA_Subject}/OU=SERVICE"
# 签发证书有效的DNS或IP, 签发时需要在这里做适当的修改
DNS_List="DNS:*.penn.lab,DNS:git.penn.lab,DNS:hardnupennts.lab,DNS:*.service.penn.lab"
IP_List="IP:10.10.11.1,IP:10.10.11.2,IP:10.10.11.3,IP:10.10.11.4,IP:10.10.11.5,IP:10.10.11.6,IP:10.10.11.7,IP:10.10.11.8,IP:10.10.11.9,IP:10.10.11.10"
# 生成证书请求文件的时候:[req]:v3_req.basicConstraints
# 当basicConstraints=CA:TRUE时,表明要生成的证书请求是CA证书请求文件;
# 当basicConstraints=CA:FALSE时,表明要生成的证书请求文件是终端证书请求文件;
# 签发证书的时候。签发端使用默认扩展字段usr_cert,当在命令行使用了extensions选项时指定v3_ca字段
# 在默认的usr_cert字段中 basicConstraints=CA:FALSE;表明要签发终端证书
# 而在v3_ca字段中 basicConstraints=CA:TRUE;表明要签发CA证书
## 自建CA
function Init_Root_CA() {
mkdir -p ${Root_CA_Dir}
read -p "输入 root CA domain(eg:www.example.com): " Root_CA_Domain
[[ -f ${Root_CA_KEY} ]] && echo "${Root_CA_KEY} 已经存在, 手动删除后重新执行命令(慎重操作)。" && exit 0
# 生成密钥对
(
umask 077
openssl genrsa -out ${Root_CA_KEY} 2048
)
# 自签名
openssl req -new -x509 \
-subj "${Root_CA_Subject}/CN=$Root_CA_Domain" \
-key ${Root_CA_KEY} \
-out ${Root_CA_CRT} \
-days 3650
echo "Root CA ${Root_CA_Domain} 初始化完成"
}
function Create_Sub_CA() {
mkdir -p ${Sub_CA_Dir}
read -p "输入 Sub CA domain(eg:www.example.com): " Sub_CA_Domain
Sub_CA_key=${Sub_CA_Dir}/${Sub_CA_Domain}.key
Sub_CA_CSR=${Sub_CA_Dir}/${Sub_CA_Domain}.csr
Sub_CA_CRT=${Sub_CA_Dir}/${Sub_CA_Domain}.crt
Sub_CA_Chain_CRT=${Sub_CA_Dir}/${Sub_CA_Domain}.chain.crt
[[ -f ${Sub_CA_key} ]] && echo "${Sub_CA_key} 已经存在, 手动删除后重新执行命令(慎重操作)。" && exit 0
# 生成密钥对
(
umask 077
openssl genrsa -out ${Sub_CA_key} 2048
)
# 申请文件
openssl req -new \
-subj "${Sub_CA_Subject}/CN=${Sub_CA_Domain}" \
-key "${Sub_CA_key}" \
-out "${Sub_CA_CSR}" \
-config "${Config}"
# 生成证书
openssl ca \
-extensions v3_req \
-cert ${Root_CA_CRT} \
-keyfile ${Root_CA_KEY} \
-in "${Sub_CA_CSR}" \
-out "${Sub_CA_CRT}" \
-days 3650 \
-config ${Config}
cat "${Sub_CA_CRT}" "${Root_CA_CRT}" >"${Sub_CA_Chain_CRT}"
echo "Sub CA ${Sub_CA_Domain} 创建完成,验证信息:"
openssl verify -CAfile ${Root_CA_CRT} "${Sub_CA_CRT}"
}
function Create_Service_Certificate() {
mkdir -p ${Service_Certificate_Dir}
read -p "输入 service domain(eg:www.example.com): " Service_Domain
Service_Key=${Service_Certificate_Dir}/${Service_Domain}.key
Service_CSR=${Service_Certificate_Dir}/${Service_Domain}.csr
Service_CRT=${Service_Certificate_Dir}/${Service_Domain}.crt
Service_Chain_CRT=${Service_Certificate_Dir}/${Service_Domain}.chain.crt
[[ -f ${Service_Key} ]] && echo "${Service_Key} 已经存在, 手动删除后重新执行命令(慎重操作)。" && exit 0
read -p "输入用来签名的 Sub CA domain: " Sub_CA_Domain
Sub_CA_key=${Sub_CA_Dir}/${Sub_CA_Domain}.key
Sub_CA_CRT=${Sub_CA_Dir}/${Sub_CA_Domain}.crt
[[ -f ${Sub_CA_key} ]] || [[ -f ${Sub_CA_CRT} ]] || (
echo "${Sub_CA_Domain} not exist. 请重试"
exit 1
)
# 生成私钥
(
umask 077
openssl genrsa -out "${Service_Key}" 2048
)
# 生成证书签署请求
openssl req -new \
-subj "${Service_Subject}/CN=${Service_Domain}" \
-key "${Service_Key}" \
-out "${Service_CSR}"
# CA签署证书, Mac上最大支持的时间为825天
openssl ca \
-cert "${Sub_CA_CRT}" \
-keyfile "${Sub_CA_key}" \
-in "${Service_CSR}" \
-out "${Service_CRT}" \
-days 825 \
-config ${Config} \
-extensions SAN \
-extfile <(printf "[SAN]\nsubjectAltName=DNS:%s,%s,%s\n" "${Service_Domain}" "${DNS_List}" ${IP_List})
cat "${Service_CRT}" "${Sub_CA_CRT}" >"${Service_Chain_CRT}"
echo "Service 证书 ${Service_Domain} 创建完成, 验证信息:"
openssl verify -CAfile "${Service_Chain_CRT}" "${Service_CRT}"
}
function Init_Data() {
mkdir -p ${CA_Data_Dir}/newcerts
Index_File=${CA_Data_Dir}/index.txt
[[ -f ${Index_File} ]] || (touch ${Index_File})
Serial_File=${CA_Data_Dir}/serial
[[ -f ${Serial_File} ]] || (echo 01 >${Serial_File=})
}
function Prepare() {
echo -e "openssl 目录:${SSL_DIR}"
echo -e "openssl 配置文件:${Config}"
echo "确认配置: "
echo -e "\t openssl.cnf 中 dir 的值指向目录: ${CA_Data_Dir}"
read -p "确认无误? (y/n): " f
[[ ! ${f} == "y" ]] && echo "操作取消" && exit 0
}
function Main() {
Prepare
select cmd in "初始化RootCA" "创建SubCA" "创建Service证书" "退出"; do
case ${cmd} in
"初始化RootCA")
echo "初始化RootCA"
Init_Root_CA
;;
"创建SubCA")
echo "创建SubCA"
Init_Data
Create_Sub_CA
;;
"创建Service证书")
Create_Service_Certificate
echo "创建Service证书"
;;
"退出")
echo "退出"
break
;;
*)
echo "Invalid entry."
break
;;
esac
done
}
Main
#!/usr/bin/env bash
# 用来创建CA证书,首先创建一个根CA证书,再用根CA证书来签发其他的CA证书。
# wrote by penn
# CA服务的存放位置
SSL_DIR=/home/penn/ssl # 所有的数据存放目录
Config=${SSL_DIR}/openssl.cnf # 配置文件路径
CA_Dir=${SSL_DIR}/ca # CA证书的目录
CA_Data_Dir=${CA_Dir}/db # CA签发过程中的其他文件的路径
# 存储CA服务的文件路径
Root_CA_Dir=${CA_Dir}/root-ca # 根CA 目录
Root_CA_KEY=${Root_CA_Dir}/root-ca.key # 根CA Key
Root_CA_CRT=${Root_CA_Dir}/root-ca.crt # 根CA 证书
Service_Certificate_Dir=${CA_Dir}/service # 根CA签发的服务证书的目录
# SUBJECT为CA服务的机构信息,根据需要做适当的修改,证书meta信息
CA_Subject="/C=CN/ST=Sichuan/O=penn Lab"
Root_CA_Subject="${CA_Subject}/OU=ROOT-CA"
Service_Subject="${CA_Subject}/OU=SERVICE"
# 签发证书有效的DNS或IP, 签发时需要在这里做适当的修改
DNS_List="DNS:*.lab.lab,DNS:git.lab.lab,DNS:lab.lab,DNS:*.service.lab.lab"
IP_List="IP:10.10.11.1,IP:10.10.11.2,IP:10.10.11.3,IP:10.10.11.4,IP:10.10.11.5,IP:10.10.11.6,IP:10.10.11.7,IP:10.10.11.8,IP:10.10.11.9,IP:10.10.11.10"
## 自建CA
function Init_Root_CA() {
[[ -f ${Root_CA_KEY} ]] && echo "${Root_CA_KEY} 已经存在. 需要重新生成请先删除。" && return
mkdir -p ${Root_CA_Dir}
# 输入域名作为root—ca的CN
local Root_CA_Domain
read -p "输入 root CA domain(eg:www.example.com): " Root_CA_Domain
# 生成密钥对
(
umask 077
openssl genrsa -out ${Root_CA_KEY} 2048
)
# 生成自签证书
openssl req -new -x509 \
-subj "${Root_CA_Subject}/CN=${Root_CA_Domain}" \
-key ${Root_CA_KEY} \
-out ${Root_CA_CRT} \
-days 3650
}
# 用来确保签发证书必要的目录存在
function Init_Data() {
mkdir -p ${CA_Data_Dir}/newcerts
local Index_File=${CA_Data_Dir}/index.txt
[[ -f ${Index_File} ]] || (touch ${Index_File})
local Serial_File=${CA_Data_Dir}/serial
[[ -f ${Serial_File} ]] || (echo 01 >${Serial_File})
}
function Create_Service_Certificate() {
# 开始为你的域名申请证书
mkdir -p ${Service_Certificate_Dir}
local Service_Domain
read -p "输入 service domain(eg:www.example.com): " Service_Domain
local Service_Key=${Service_Certificate_Dir}/${Service_Domain}.key
local Service_CSR=${Service_Certificate_Dir}/${Service_Domain}.csr
local Service_CRT=${Service_Certificate_Dir}/${Service_Domain}.crt
[[ -f ${Service_Key} ]] && echo "${Service_Key} 已经存在. 需要重新生成请先删除,并设置 ${CA_Data_Dir}/index.txt.attr: unique_subject = no。" && return
# 生成私钥
(
umask 077
openssl genrsa -out "${Service_Key}" 2048
)
# 生成证书签署请求
openssl req -new \
-subj "${Service_Subject}/CN=$Service_Domain" \
-key "${Service_Key}" \
-out "${Service_CSR}"
# CA签署证书
openssl ca \
-cert ${Root_CA_CRT} \
-keyfile ${Root_CA_KEY} \
-in "${Service_CSR}" \
-out "${Service_CRT}" \
-days 825 \
-config ${Config} \
-extensions SAN \
-extfile <(printf "[SAN]\nsubjectAltName=DNS:%s,%s,%s\n" "${Service_Domain}" "${DNS_List}" "${IP_List}")
openssl verify -CAfile ${Root_CA_CRT} ${Service_CRT}
openssl x509 -in ${Service_CRT} -noout -text | grep ${Service_Domain}
}
function Main() {
Init_Root_CA
Init_Data
Create_Service_Certificate
}
Main
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment