ca.sh
· 17 KiB · Bash
原始文件
#!/bin/bash
# Source: https://jamielinux.com/docs/openssl-certificate-authority/index.html
if [ -z "$1" ]; then
echo "=x=> Path for your CA root is required!"
exit 1
fi
CA_ROOT=$(realpath "$1")
# Intermediate directory
INTERMEDIATE_ROOT="$CA_ROOT/intermediate"
# Static config blanks
read -r -d '' OPENSSL_CA_CFG << EOM
# OpenSSL root CA configuration file.
# Auto-generated.
[ ca ]
# \`man ca\`
default_ca = CA_default
[ CA_default ]
# Directory and file locations.
dir = $CA_ROOT
certs = \$dir/certs
crl_dir = \$dir/crl
new_certs_dir = \$dir/newcerts
database = \$dir/index.txt
serial = \$dir/serial
RANDFILE = \$dir/private/.rand
# The root key and root certificate.
private_key = \$dir/private/ca.key.pem
certificate = \$dir/certs/ca.cert.pem
# For certificate revocation lists.
crlnumber = \$dir/crlnumber
crl = \$dir/crl/ca.crl.pem
crl_extensions = crl_ext
default_crl_days = 30
# SHA-1 is deprecated, so use SHA-2 instead.
default_md = sha256
name_opt = ca_default
cert_opt = ca_default
default_days = 375
preserve = no
policy = policy_strict
[ policy_strict ]
# The root CA should only sign intermediate certificates that match.
# See the POLICY FORMAT section of \`man ca\`.
countryName = match
stateOrProvinceName = match
organizationName = match
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
[ policy_loose ]
# Allow the intermediate CA to sign a more diverse range of certificates.
# See the POLICY FORMAT section of the \`ca\` man page.
countryName = optional
stateOrProvinceName = optional
localityName = optional
organizationName = optional
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
[ req ]
# Options for the \`req\` tool (\`man req\`).
default_bits = 4096
distinguished_name = req_distinguished_name
string_mask = utf8only
# SHA-1 is deprecated, so use SHA-2 instead.
default_md = sha256
# Extension to add when the -x509 option is used.
x509_extensions = v3_ca
[ req_distinguished_name ]
# See <https://en.wikipedia.org/wiki/Certificate_signing_request>.
countryName = Country Name (2 letter code)
stateOrProvinceName = State or Province Name
localityName = Locality Name
0.organizationName = Organization Name
organizationalUnitName = Organizational Unit Name
commonName = Common Name
emailAddress = Email Address
[ v3_ca ]
# Extensions for a typical CA (\`man x509v3_config\`).
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer
basicConstraints = critical, CA:true
keyUsage = critical, digitalSignature, cRLSign, keyCertSign
[ v3_intermediate_ca ]
# Extensions for a typical intermediate CA (\`man x509v3_config\`).
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer
basicConstraints = critical, CA:true, pathlen:0
keyUsage = critical, digitalSignature, cRLSign, keyCertSign
[ usr_cert ]
# Extensions for client certificates (\`man x509v3_config\`).
basicConstraints = CA:FALSE
nsCertType = client, email
nsComment = "OpenSSL Generated Client Certificate"
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer
keyUsage = critical, nonRepudiation, digitalSignature, keyEncipherment
extendedKeyUsage = clientAuth, emailProtection
[ server_cert ]
# Extensions for server certificates (\`man x509v3_config\`).
basicConstraints = CA:FALSE
nsCertType = server
nsComment = "OpenSSL Generated Server Certificate"
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer:always
keyUsage = critical, digitalSignature, keyEncipherment
extendedKeyUsage = serverAuth
[ crl_ext ]
# Extension for CRLs (\`man x509v3_config\`).
authorityKeyIdentifier=keyid:always
[ ocsp ]
# Extension for OCSP signing certificates (\`man ocsp\`).
basicConstraints = CA:FALSE
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer
keyUsage = critical, digitalSignature
extendedKeyUsage = critical, OCSPSigning
EOM
read -r -d '' OPENSSL_INTERMEDIATE_CFG << EOM
# OpenSSL intermediate CA configuration file.
# Auto-generated.
[ ca ]
# \`man ca\`
default_ca = CA_default
[ CA_default ]
# Directory and file locations.
dir = $INTERMEDIATE_ROOT
certs = \$dir/certs
crl_dir = \$dir/crl
new_certs_dir = \$dir/newcerts
database = \$dir/index.txt
serial = \$dir/serial
RANDFILE = \$dir/private/.rand
# The root key and root certificate.
private_key = \$dir/private/intermediate.key.pem
certificate = \$dir/certs/intermediate.cert.pem
# For certificate revocation lists.
crlnumber = \$dir/crlnumber
crl = \$dir/crl/intermediate.crl.pem
crl_extensions = crl_ext
default_crl_days = 30
# SHA-1 is deprecated, so use SHA-2 instead.
default_md = sha256
name_opt = ca_default
cert_opt = ca_default
default_days = 375
preserve = no
policy = policy_loose
# Allow copying extensions from CSRs
copy_extensions = copy
[ policy_strict ]
# The root CA should only sign intermediate certificates that match.
# See the POLICY FORMAT section of \`man ca\`.
countryName = match
stateOrProvinceName = match
organizationName = match
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
[ policy_loose ]
# Allow the intermediate CA to sign a more diverse range of certificates.
# See the POLICY FORMAT section of the \`ca\` man page.
countryName = optional
stateOrProvinceName = optional
localityName = optional
organizationName = optional
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
[ req ]
# Options for the \`req\` tool (\`man req\`).
default_bits = 4096
distinguished_name = req_distinguished_name
string_mask = utf8only
# SHA-1 is deprecated, so use SHA-2 instead.
default_md = sha256
# Extension to add when the -x509 option is used.
x509_extensions = v3_intermediate_ca
[ req_distinguished_name ]
# See <https://en.wikipedia.org/wiki/Certificate_signing_request>.
countryName = Country Name (2 letter code)
stateOrProvinceName = State or Province Name
localityName = Locality Name
0.organizationName = Organization Name
organizationalUnitName = Organizational Unit Name
commonName = Common Name
emailAddress = Email Address
[ v3_ca ]
# Extensions for a typical CA (\`man x509v3_config\`).
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer
basicConstraints = critical, CA:true
keyUsage = critical, digitalSignature, cRLSign, keyCertSign
[ v3_intermediate_ca ]
# Extensions for a typical intermediate CA (\`man x509v3_config\`).
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer
basicConstraints = critical, CA:true, pathlen:0
keyUsage = critical, digitalSignature, cRLSign, keyCertSign
[ usr_cert ]
# Extensions for client certificates (\`man x509v3_config\`).
basicConstraints = CA:FALSE
nsCertType = client, email
nsComment = "OpenSSL Generated Client Certificate"
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer
keyUsage = critical, nonRepudiation, digitalSignature, keyEncipherment
extendedKeyUsage = clientAuth, emailProtection
[ server_cert ]
# Extensions for server certificates (\`man x509v3_config\`).
basicConstraints = CA:FALSE
nsCertType = server
nsComment = "OpenSSL Generated Server Certificate"
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer:always
keyUsage = critical, digitalSignature, keyEncipherment
extendedKeyUsage = serverAuth
[ crl_ext ]
# Extension for CRLs (\`man x509v3_config\`).
authorityKeyIdentifier=keyid:always
[ ocsp ]
# Extension for OCSP signing certificates (\`man ocsp\`).
basicConstraints = CA:FALSE
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer
keyUsage = critical, digitalSignature
extendedKeyUsage = critical, OCSPSigning
EOM
deployFiles () {
echo "Deploying a Certificate Authority to $CA_ROOT"
echo ''
if [ ! -d "$CA_ROOT" ]; then
# Create directory
mkdir -p "$CA_ROOT"
# Create sub-directories
mkdir -p "$CA_ROOT/private" "$CA_ROOT/csr" "$CA_ROOT/certs" "$CA_ROOT/newcerts"
touch "$CA_ROOT/index.txt"
echo 1000 > "$CA_ROOT/serial"
chmod 700 "$CA_ROOT/private"
echo "$OPENSSL_CA_CFG" > "$CA_ROOT/openssl.cfg"
fi
if [ ! -d "$INTERMEDIATE_ROOT" ]; then
mkdir -p "$INTERMEDIATE_ROOT/private" "$INTERMEDIATE_ROOT/csr" "$INTERMEDIATE_ROOT/certs" "$INTERMEDIATE_ROOT/newcerts"
touch "$INTERMEDIATE_ROOT/index.txt"
echo 1000 > "$INTERMEDIATE_ROOT/serial"
chmod 700 "$INTERMEDIATE_ROOT/private"
echo "$OPENSSL_INTERMEDIATE_CFG" > "$INTERMEDIATE_ROOT/openssl.cfg"
fi
}
generateRootPair () {
############################
# GENERATING ROOT KEY PAIR #
############################
echo '==> Starting the generation of the root key pair.'
echo '==> Please fill in the appropriate information asked.'
echo ''
# Set CWD
cd "$CA_ROOT"
# CA Root Private Key
if [ ! -e "$CA_ROOT/private/ca.key.pem" ]; then
echo '=> Generating CA key.. Please enter a strong passphrase.'
echo ''
openssl genrsa -aes256 -out private/ca.key.pem 4096
else
echo '=> Root CA key exists, skipping..'
fi
if [ ! -e "$CA_ROOT/private/ca.key.pem" ]; then
echo '=x=> Root CA key was not generated!'
return 1
fi
chmod 400 private/ca.key.pem
# CA Root Certificate
if [ ! -e "$CA_ROOT/certs/ca.cert.pem" ]; then
echo '=> Generating CA certificate..'
echo ''
openssl req -config "$CA_ROOT/openssl.cfg" \
-key private/ca.key.pem \
-new -x509 -days 7300 -sha256 -extensions v3_ca \
-out certs/ca.cert.pem
else
echo '=> Root certificate exists, skipping..'
fi
if [ ! -e "$CA_ROOT/certs/ca.cert.pem" ]; then
echo '=x=> Root certificate was not generated!'
return 1
fi
chmod 444 certs/ca.cert.pem
# Print info
openssl x509 -noout -text -in certs/ca.cert.pem
echo '==> Root key pair generated.'
echo ''
}
generateIntermediate () {
if [ ! -e "$CA_ROOT/certs/ca.cert.pem" ]; then
echo '=x=> Could not generate intermediate certificate.'
echo '=x=> CA certificate is missing!'
return 1
fi
####################################
# GENERATING INTERMEDIATE KEY PAIR #
####################################
cd "$CA_ROOT"
echo '==> Starting the generation of the intermediate key pair.'
echo '==> This is used to sign server and user certificates.'
echo '==> Please fill in the appropriate information asked.'
echo ''
if [ ! -e "$CA_ROOT/intermediate/private/intermediate.key.pem" ]; then
# Key
echo '=> Generating intermediate key.. Please enter a strong passphrase.'
echo ''
openssl genrsa -aes256 \
-out intermediate/private/intermediate.key.pem 4096
else
echo '=> Intermediate certificate key exists, skipping..'
fi
if [ ! -e "$CA_ROOT/intermediate/private/intermediate.key.pem" ]; then
echo '=x=> Intermediate certificate key was not generated!'
return 1
fi
chmod 400 intermediate/private/intermediate.key.pem
if [ -e "$CA_ROOT/intermediate/csr/intermediate.csr.pem" ]; then
rm -f intermediate/csr/intermediate.csr.pem
rm -f intermediate/certs/intermediate.cert.pem
fi
# Certificate Signing Request (CSR)
echo '=> Generating intermediate CSR..'
echo ''
openssl req -config "$INTERMEDIATE_ROOT/openssl.cfg" -new -sha256 \
-key intermediate/private/intermediate.key.pem \
-out intermediate/csr/intermediate.csr.pem
if [ ! -e "$CA_ROOT/intermediate/csr/intermediate.csr.pem" ]; then
echo '=x=> Intermediate signing request was not generated!'
return 1
fi
echo '=> Singing the intermediate certificate. Please answer yes in order to continue.'
echo ''
openssl ca -config "$CA_ROOT/openssl.cfg" -extensions v3_intermediate_ca \
-days 3650 -notext -md sha256 \
-in intermediate/csr/intermediate.csr.pem \
-out intermediate/certs/intermediate.cert.pem
if [ ! -e "$CA_ROOT/intermediate/certs/intermediate.cert.pem" ]; then
echo '=x=> Intermediate certificate was not signed!'
return 1
fi
chmod 444 intermediate/certs/intermediate.cert.pem
# Print info
openssl x509 -noout -text \
-in intermediate/certs/intermediate.cert.pem
openssl verify -CAfile certs/ca.cert.pem \
intermediate/certs/intermediate.cert.pem
# Generate Certificate Chain
cat intermediate/certs/intermediate.cert.pem \
certs/ca.cert.pem > intermediate/certs/ca-chain.cert.pem
chmod 444 intermediate/certs/ca-chain.cert.pem
echo '==> Intermediate key pair generated.'
echo "==> Your CA (Certificate Authority) is \"$INTERMEDIATE_ROOT/certs/ca-chain.cert.pem\""
}
createCertificate() {
if [ ! -e "$CA_ROOT" ]; then
echo "=x=> Certificate root was not found."
return 1
elif [ ! -e "$INTERMEDIATE_ROOT/openssl.cfg" ]; then
echo "=x=> Intermediate certificate configuration was not found."
return 1
fi
if [ -z "$1" ]; then
echo "=x=> Please provide a name for this certificate."
return 1
fi
if [ -z "$2" ] || [ "$2" != "server_cert" ] && [ "$2" != "usr_cert" ]; then
echo "=x=> Type must be one of server_cert or usr_cert. If you're unsure about this, use 'usr_cert'."
return 1
fi
cd "$CA_ROOT"
# Custom configuration file
local CSRCFG="$INTERMEDIATE_ROOT/openssl.cfg"
if [ -n $3 ]; then
CSRCFG="$3"
fi
# Generate the key if it does not exist
if [ ! -e "$INTERMEDIATE_ROOT/private/$1.key.pem" ]; then
echo "==> Generating key for \"$1\""
echo ''
openssl genrsa -out "$INTERMEDIATE_ROOT/private/$1.key.pem" 4096
chmod 400 "$INTERMEDIATE_ROOT/private/$1.key.pem"
if [ ! -e "$INTERMEDIATE_ROOT/private/$1.key.pem" ]; then
echo "=x=> Key was not created!"
return 1
fi
fi
echo "==> Generating CSR for \"$1\""
echo ''
openssl req -config "$CSRCFG" \
-key "$INTERMEDIATE_ROOT/private/$1.key.pem" \
-new -sha256 -out "$INTERMEDIATE_ROOT/csr/$1.csr.pem"
if [ ! -e "$INTERMEDIATE_ROOT/csr/$1.csr.pem" ]; then
echo "=x=> CSR was not created!"
return 1
fi
echo "==> Generating certificate for \"$1\""
echo ''
openssl ca -config "$INTERMEDIATE_ROOT/openssl.cfg" \
-extensions "$2" -days 375 -notext -md sha256 \
-in "$INTERMEDIATE_ROOT/csr/$1.csr.pem" \
-out "$INTERMEDIATE_ROOT/certs/$1.cert.pem"
if [ ! -e "$INTERMEDIATE_ROOT/certs/$1.cert.pem" ]; then
echo "=x=> Certificate was not created!"
return 1
fi
chmod 444 "$INTERMEDIATE_ROOT/certs/$1.cert.pem"
echo "==> Done."
echo "==> Key: $INTERMEDIATE_ROOT/private/$1.key.pem"
echo "==> Cert: $INTERMEDIATE_ROOT/certs/$1.cert.pem"
}
revokeCertificate() {
if [ ! -e "$CA_ROOT" ]; then
echo "=x=> Certificate root was not found."
return 1
elif [ ! -e "$INTERMEDIATE_ROOT/openssl.cfg" ]; then
echo "=x=> Intermediate certificate configuration was not found."
return 1
fi
if [ -z "$1" ]; then
echo "=x=> Please provide a name for a certificate to revoke."
return 1
fi
cd "$CA_ROOT"
echo "==> Revoking certificate"
openssl ca -config "$INTERMEDIATE_ROOT/openssl.cfg" \
-revoke "$INTERMEDIATE_ROOT/certs/$1.cert.pem"
echo "==> Done."
}
printInfo () {
if [ ! -e "$CA_ROOT" ]; then
echo "=x=> Certificate root was not found."
return 1
elif [ ! -e "$INTERMEDIATE_ROOT/openssl.cfg" ]; then
echo "=x=> Intermediate certificate configuration was not found."
return 1
fi
if [ -n "$1" ]; then
openssl x509 -noout -text -in "$CA_ROOT/intermediate/certs/$1.cert.pem"
return 0
fi
echo "=> Root certificate"
openssl x509 -noout -text -in "$CA_ROOT/certs/ca.cert.pem"
echo "=> Intermediate certificate"
openssl x509 -noout -text \
-in "$CA_ROOT/intermediate/certs/intermediate.cert.pem"
openssl verify -CAfile "$CA_ROOT/certs/ca.cert.pem" \
"$CA_ROOT/intermediate/certs/intermediate.cert.pem"
echo ""
echo "==> Paths"
echo "Root: $CA_ROOT"
echo "Intermediate: $CA_ROOT/intermediate"
echo ""
echo "Root Key: $CA_ROOT/private/ca.key.pem"
echo "Root Cert: $CA_ROOT/certs/ca.cert.pem"
echo "CA Key: $CA_ROOT/intermediate/private/intermediate.key.pem"
echo "Chain: $CA_ROOT/intermediate/certs/ca-chain.cert.pem"
echo ""
}
printHelp () {
echo "Usage: ./ca <CA Path> info | wizard | root | intm | revoke [<name>] | new [<name>] [ server_cert | usr_cert ] [ openssl.cfg ]"
echo -e " info\t- Print information about your CA"
echo -e " wizard\t- Create a new CA"
echo -e " root\t- Generate root certificate. For use when wizard fails."
echo -e " intm\t- Generate intermediate certificate. For use when wizard fails."
echo -e " new \t- Create a new certificate signed with your CA. Can also be used for renewal."
echo -e " revoke\t- Revoke a certificate by name"
}
set -e
case "$2" in
"info")
printInfo $3
;;
"wizard" | "generate" | "newca")
echo "==> Proceeding with full generation for path $1"
deployFiles
generateRootPair
generateIntermediate
printInfo
;;
"files")
deployFiles
;;
"rootpair" | "root")
generateRootPair
;;
"intermediate" | "intm")
generateIntermediate
;;
"certificate" | "cert" | "new" | "renew")
createCertificate $3 $4 $5
;;
"revoke")
revokeCertificate $3
;;
"help")
printHelp
;;
*)
echo "Usage: ./ca <CA Path> info | wizard | root | intm | revoke [<name>] | new [<name>] [ server_cert | usr_cert ] [ openssl.cfg ]"
;;
esac
| 1 | #!/bin/bash |
| 2 | |
| 3 | # Source: https://jamielinux.com/docs/openssl-certificate-authority/index.html |
| 4 | |
| 5 | if [ -z "$1" ]; then |
| 6 | echo "=x=> Path for your CA root is required!" |
| 7 | exit 1 |
| 8 | fi |
| 9 | |
| 10 | CA_ROOT=$(realpath "$1") |
| 11 | |
| 12 | # Intermediate directory |
| 13 | INTERMEDIATE_ROOT="$CA_ROOT/intermediate" |
| 14 | |
| 15 | # Static config blanks |
| 16 | |
| 17 | read -r -d '' OPENSSL_CA_CFG << EOM |
| 18 | # OpenSSL root CA configuration file. |
| 19 | # Auto-generated. |
| 20 | |
| 21 | [ ca ] |
| 22 | # \`man ca\` |
| 23 | default_ca = CA_default |
| 24 | |
| 25 | [ CA_default ] |
| 26 | # Directory and file locations. |
| 27 | dir = $CA_ROOT |
| 28 | certs = \$dir/certs |
| 29 | crl_dir = \$dir/crl |
| 30 | new_certs_dir = \$dir/newcerts |
| 31 | database = \$dir/index.txt |
| 32 | serial = \$dir/serial |
| 33 | RANDFILE = \$dir/private/.rand |
| 34 | |
| 35 | # The root key and root certificate. |
| 36 | private_key = \$dir/private/ca.key.pem |
| 37 | certificate = \$dir/certs/ca.cert.pem |
| 38 | |
| 39 | # For certificate revocation lists. |
| 40 | crlnumber = \$dir/crlnumber |
| 41 | crl = \$dir/crl/ca.crl.pem |
| 42 | crl_extensions = crl_ext |
| 43 | default_crl_days = 30 |
| 44 | |
| 45 | # SHA-1 is deprecated, so use SHA-2 instead. |
| 46 | default_md = sha256 |
| 47 | |
| 48 | name_opt = ca_default |
| 49 | cert_opt = ca_default |
| 50 | default_days = 375 |
| 51 | preserve = no |
| 52 | policy = policy_strict |
| 53 | |
| 54 | [ policy_strict ] |
| 55 | # The root CA should only sign intermediate certificates that match. |
| 56 | # See the POLICY FORMAT section of \`man ca\`. |
| 57 | countryName = match |
| 58 | stateOrProvinceName = match |
| 59 | organizationName = match |
| 60 | organizationalUnitName = optional |
| 61 | commonName = supplied |
| 62 | emailAddress = optional |
| 63 | |
| 64 | [ policy_loose ] |
| 65 | # Allow the intermediate CA to sign a more diverse range of certificates. |
| 66 | # See the POLICY FORMAT section of the \`ca\` man page. |
| 67 | countryName = optional |
| 68 | stateOrProvinceName = optional |
| 69 | localityName = optional |
| 70 | organizationName = optional |
| 71 | organizationalUnitName = optional |
| 72 | commonName = supplied |
| 73 | emailAddress = optional |
| 74 | |
| 75 | [ req ] |
| 76 | # Options for the \`req\` tool (\`man req\`). |
| 77 | default_bits = 4096 |
| 78 | distinguished_name = req_distinguished_name |
| 79 | string_mask = utf8only |
| 80 | |
| 81 | # SHA-1 is deprecated, so use SHA-2 instead. |
| 82 | default_md = sha256 |
| 83 | |
| 84 | # Extension to add when the -x509 option is used. |
| 85 | x509_extensions = v3_ca |
| 86 | |
| 87 | [ req_distinguished_name ] |
| 88 | # See <https://en.wikipedia.org/wiki/Certificate_signing_request>. |
| 89 | countryName = Country Name (2 letter code) |
| 90 | stateOrProvinceName = State or Province Name |
| 91 | localityName = Locality Name |
| 92 | 0.organizationName = Organization Name |
| 93 | organizationalUnitName = Organizational Unit Name |
| 94 | commonName = Common Name |
| 95 | emailAddress = Email Address |
| 96 | |
| 97 | [ v3_ca ] |
| 98 | # Extensions for a typical CA (\`man x509v3_config\`). |
| 99 | subjectKeyIdentifier = hash |
| 100 | authorityKeyIdentifier = keyid:always,issuer |
| 101 | basicConstraints = critical, CA:true |
| 102 | keyUsage = critical, digitalSignature, cRLSign, keyCertSign |
| 103 | |
| 104 | [ v3_intermediate_ca ] |
| 105 | # Extensions for a typical intermediate CA (\`man x509v3_config\`). |
| 106 | subjectKeyIdentifier = hash |
| 107 | authorityKeyIdentifier = keyid:always,issuer |
| 108 | basicConstraints = critical, CA:true, pathlen:0 |
| 109 | keyUsage = critical, digitalSignature, cRLSign, keyCertSign |
| 110 | |
| 111 | [ usr_cert ] |
| 112 | # Extensions for client certificates (\`man x509v3_config\`). |
| 113 | basicConstraints = CA:FALSE |
| 114 | nsCertType = client, email |
| 115 | nsComment = "OpenSSL Generated Client Certificate" |
| 116 | subjectKeyIdentifier = hash |
| 117 | authorityKeyIdentifier = keyid,issuer |
| 118 | keyUsage = critical, nonRepudiation, digitalSignature, keyEncipherment |
| 119 | extendedKeyUsage = clientAuth, emailProtection |
| 120 | |
| 121 | [ server_cert ] |
| 122 | # Extensions for server certificates (\`man x509v3_config\`). |
| 123 | basicConstraints = CA:FALSE |
| 124 | nsCertType = server |
| 125 | nsComment = "OpenSSL Generated Server Certificate" |
| 126 | subjectKeyIdentifier = hash |
| 127 | authorityKeyIdentifier = keyid,issuer:always |
| 128 | keyUsage = critical, digitalSignature, keyEncipherment |
| 129 | extendedKeyUsage = serverAuth |
| 130 | |
| 131 | [ crl_ext ] |
| 132 | # Extension for CRLs (\`man x509v3_config\`). |
| 133 | authorityKeyIdentifier=keyid:always |
| 134 | |
| 135 | [ ocsp ] |
| 136 | # Extension for OCSP signing certificates (\`man ocsp\`). |
| 137 | basicConstraints = CA:FALSE |
| 138 | subjectKeyIdentifier = hash |
| 139 | authorityKeyIdentifier = keyid,issuer |
| 140 | keyUsage = critical, digitalSignature |
| 141 | extendedKeyUsage = critical, OCSPSigning |
| 142 | |
| 143 | EOM |
| 144 | |
| 145 | read -r -d '' OPENSSL_INTERMEDIATE_CFG << EOM |
| 146 | # OpenSSL intermediate CA configuration file. |
| 147 | # Auto-generated. |
| 148 | |
| 149 | [ ca ] |
| 150 | # \`man ca\` |
| 151 | default_ca = CA_default |
| 152 | |
| 153 | [ CA_default ] |
| 154 | # Directory and file locations. |
| 155 | dir = $INTERMEDIATE_ROOT |
| 156 | certs = \$dir/certs |
| 157 | crl_dir = \$dir/crl |
| 158 | new_certs_dir = \$dir/newcerts |
| 159 | database = \$dir/index.txt |
| 160 | serial = \$dir/serial |
| 161 | RANDFILE = \$dir/private/.rand |
| 162 | |
| 163 | # The root key and root certificate. |
| 164 | private_key = \$dir/private/intermediate.key.pem |
| 165 | certificate = \$dir/certs/intermediate.cert.pem |
| 166 | |
| 167 | # For certificate revocation lists. |
| 168 | crlnumber = \$dir/crlnumber |
| 169 | crl = \$dir/crl/intermediate.crl.pem |
| 170 | crl_extensions = crl_ext |
| 171 | default_crl_days = 30 |
| 172 | |
| 173 | # SHA-1 is deprecated, so use SHA-2 instead. |
| 174 | default_md = sha256 |
| 175 | |
| 176 | name_opt = ca_default |
| 177 | cert_opt = ca_default |
| 178 | default_days = 375 |
| 179 | preserve = no |
| 180 | policy = policy_loose |
| 181 | |
| 182 | # Allow copying extensions from CSRs |
| 183 | copy_extensions = copy |
| 184 | |
| 185 | [ policy_strict ] |
| 186 | # The root CA should only sign intermediate certificates that match. |
| 187 | # See the POLICY FORMAT section of \`man ca\`. |
| 188 | countryName = match |
| 189 | stateOrProvinceName = match |
| 190 | organizationName = match |
| 191 | organizationalUnitName = optional |
| 192 | commonName = supplied |
| 193 | emailAddress = optional |
| 194 | |
| 195 | [ policy_loose ] |
| 196 | # Allow the intermediate CA to sign a more diverse range of certificates. |
| 197 | # See the POLICY FORMAT section of the \`ca\` man page. |
| 198 | countryName = optional |
| 199 | stateOrProvinceName = optional |
| 200 | localityName = optional |
| 201 | organizationName = optional |
| 202 | organizationalUnitName = optional |
| 203 | commonName = supplied |
| 204 | emailAddress = optional |
| 205 | |
| 206 | [ req ] |
| 207 | # Options for the \`req\` tool (\`man req\`). |
| 208 | default_bits = 4096 |
| 209 | distinguished_name = req_distinguished_name |
| 210 | string_mask = utf8only |
| 211 | |
| 212 | # SHA-1 is deprecated, so use SHA-2 instead. |
| 213 | default_md = sha256 |
| 214 | |
| 215 | # Extension to add when the -x509 option is used. |
| 216 | x509_extensions = v3_intermediate_ca |
| 217 | |
| 218 | [ req_distinguished_name ] |
| 219 | # See <https://en.wikipedia.org/wiki/Certificate_signing_request>. |
| 220 | countryName = Country Name (2 letter code) |
| 221 | stateOrProvinceName = State or Province Name |
| 222 | localityName = Locality Name |
| 223 | 0.organizationName = Organization Name |
| 224 | organizationalUnitName = Organizational Unit Name |
| 225 | commonName = Common Name |
| 226 | emailAddress = Email Address |
| 227 | |
| 228 | [ v3_ca ] |
| 229 | # Extensions for a typical CA (\`man x509v3_config\`). |
| 230 | subjectKeyIdentifier = hash |
| 231 | authorityKeyIdentifier = keyid:always,issuer |
| 232 | basicConstraints = critical, CA:true |
| 233 | keyUsage = critical, digitalSignature, cRLSign, keyCertSign |
| 234 | |
| 235 | [ v3_intermediate_ca ] |
| 236 | # Extensions for a typical intermediate CA (\`man x509v3_config\`). |
| 237 | subjectKeyIdentifier = hash |
| 238 | authorityKeyIdentifier = keyid:always,issuer |
| 239 | basicConstraints = critical, CA:true, pathlen:0 |
| 240 | keyUsage = critical, digitalSignature, cRLSign, keyCertSign |
| 241 | |
| 242 | [ usr_cert ] |
| 243 | # Extensions for client certificates (\`man x509v3_config\`). |
| 244 | basicConstraints = CA:FALSE |
| 245 | nsCertType = client, email |
| 246 | nsComment = "OpenSSL Generated Client Certificate" |
| 247 | subjectKeyIdentifier = hash |
| 248 | authorityKeyIdentifier = keyid,issuer |
| 249 | keyUsage = critical, nonRepudiation, digitalSignature, keyEncipherment |
| 250 | extendedKeyUsage = clientAuth, emailProtection |
| 251 | |
| 252 | [ server_cert ] |
| 253 | # Extensions for server certificates (\`man x509v3_config\`). |
| 254 | basicConstraints = CA:FALSE |
| 255 | nsCertType = server |
| 256 | nsComment = "OpenSSL Generated Server Certificate" |
| 257 | subjectKeyIdentifier = hash |
| 258 | authorityKeyIdentifier = keyid,issuer:always |
| 259 | keyUsage = critical, digitalSignature, keyEncipherment |
| 260 | extendedKeyUsage = serverAuth |
| 261 | |
| 262 | [ crl_ext ] |
| 263 | # Extension for CRLs (\`man x509v3_config\`). |
| 264 | authorityKeyIdentifier=keyid:always |
| 265 | |
| 266 | [ ocsp ] |
| 267 | # Extension for OCSP signing certificates (\`man ocsp\`). |
| 268 | basicConstraints = CA:FALSE |
| 269 | subjectKeyIdentifier = hash |
| 270 | authorityKeyIdentifier = keyid,issuer |
| 271 | keyUsage = critical, digitalSignature |
| 272 | extendedKeyUsage = critical, OCSPSigning |
| 273 | |
| 274 | EOM |
| 275 | |
| 276 | deployFiles () { |
| 277 | echo "Deploying a Certificate Authority to $CA_ROOT" |
| 278 | echo '' |
| 279 | |
| 280 | if [ ! -d "$CA_ROOT" ]; then |
| 281 | # Create directory |
| 282 | mkdir -p "$CA_ROOT" |
| 283 | |
| 284 | # Create sub-directories |
| 285 | mkdir -p "$CA_ROOT/private" "$CA_ROOT/csr" "$CA_ROOT/certs" "$CA_ROOT/newcerts" |
| 286 | touch "$CA_ROOT/index.txt" |
| 287 | echo 1000 > "$CA_ROOT/serial" |
| 288 | |
| 289 | chmod 700 "$CA_ROOT/private" |
| 290 | echo "$OPENSSL_CA_CFG" > "$CA_ROOT/openssl.cfg" |
| 291 | fi |
| 292 | |
| 293 | if [ ! -d "$INTERMEDIATE_ROOT" ]; then |
| 294 | mkdir -p "$INTERMEDIATE_ROOT/private" "$INTERMEDIATE_ROOT/csr" "$INTERMEDIATE_ROOT/certs" "$INTERMEDIATE_ROOT/newcerts" |
| 295 | touch "$INTERMEDIATE_ROOT/index.txt" |
| 296 | echo 1000 > "$INTERMEDIATE_ROOT/serial" |
| 297 | |
| 298 | chmod 700 "$INTERMEDIATE_ROOT/private" |
| 299 | echo "$OPENSSL_INTERMEDIATE_CFG" > "$INTERMEDIATE_ROOT/openssl.cfg" |
| 300 | fi |
| 301 | } |
| 302 | |
| 303 | generateRootPair () { |
| 304 | ############################ |
| 305 | # GENERATING ROOT KEY PAIR # |
| 306 | ############################ |
| 307 | |
| 308 | echo '==> Starting the generation of the root key pair.' |
| 309 | echo '==> Please fill in the appropriate information asked.' |
| 310 | echo '' |
| 311 | |
| 312 | # Set CWD |
| 313 | cd "$CA_ROOT" |
| 314 | |
| 315 | # CA Root Private Key |
| 316 | if [ ! -e "$CA_ROOT/private/ca.key.pem" ]; then |
| 317 | echo '=> Generating CA key.. Please enter a strong passphrase.' |
| 318 | echo '' |
| 319 | openssl genrsa -aes256 -out private/ca.key.pem 4096 |
| 320 | else |
| 321 | echo '=> Root CA key exists, skipping..' |
| 322 | fi |
| 323 | |
| 324 | if [ ! -e "$CA_ROOT/private/ca.key.pem" ]; then |
| 325 | echo '=x=> Root CA key was not generated!' |
| 326 | return 1 |
| 327 | fi |
| 328 | chmod 400 private/ca.key.pem |
| 329 | |
| 330 | # CA Root Certificate |
| 331 | if [ ! -e "$CA_ROOT/certs/ca.cert.pem" ]; then |
| 332 | echo '=> Generating CA certificate..' |
| 333 | echo '' |
| 334 | openssl req -config "$CA_ROOT/openssl.cfg" \ |
| 335 | -key private/ca.key.pem \ |
| 336 | -new -x509 -days 7300 -sha256 -extensions v3_ca \ |
| 337 | -out certs/ca.cert.pem |
| 338 | else |
| 339 | echo '=> Root certificate exists, skipping..' |
| 340 | fi |
| 341 | |
| 342 | if [ ! -e "$CA_ROOT/certs/ca.cert.pem" ]; then |
| 343 | echo '=x=> Root certificate was not generated!' |
| 344 | return 1 |
| 345 | fi |
| 346 | chmod 444 certs/ca.cert.pem |
| 347 | |
| 348 | # Print info |
| 349 | openssl x509 -noout -text -in certs/ca.cert.pem |
| 350 | |
| 351 | echo '==> Root key pair generated.' |
| 352 | echo '' |
| 353 | } |
| 354 | |
| 355 | generateIntermediate () { |
| 356 | if [ ! -e "$CA_ROOT/certs/ca.cert.pem" ]; then |
| 357 | echo '=x=> Could not generate intermediate certificate.' |
| 358 | echo '=x=> CA certificate is missing!' |
| 359 | return 1 |
| 360 | fi |
| 361 | |
| 362 | #################################### |
| 363 | # GENERATING INTERMEDIATE KEY PAIR # |
| 364 | #################################### |
| 365 | |
| 366 | cd "$CA_ROOT" |
| 367 | |
| 368 | echo '==> Starting the generation of the intermediate key pair.' |
| 369 | echo '==> This is used to sign server and user certificates.' |
| 370 | echo '==> Please fill in the appropriate information asked.' |
| 371 | echo '' |
| 372 | |
| 373 | if [ ! -e "$CA_ROOT/intermediate/private/intermediate.key.pem" ]; then |
| 374 | # Key |
| 375 | echo '=> Generating intermediate key.. Please enter a strong passphrase.' |
| 376 | echo '' |
| 377 | openssl genrsa -aes256 \ |
| 378 | -out intermediate/private/intermediate.key.pem 4096 |
| 379 | else |
| 380 | echo '=> Intermediate certificate key exists, skipping..' |
| 381 | fi |
| 382 | |
| 383 | if [ ! -e "$CA_ROOT/intermediate/private/intermediate.key.pem" ]; then |
| 384 | echo '=x=> Intermediate certificate key was not generated!' |
| 385 | return 1 |
| 386 | fi |
| 387 | |
| 388 | chmod 400 intermediate/private/intermediate.key.pem |
| 389 | |
| 390 | if [ -e "$CA_ROOT/intermediate/csr/intermediate.csr.pem" ]; then |
| 391 | rm -f intermediate/csr/intermediate.csr.pem |
| 392 | rm -f intermediate/certs/intermediate.cert.pem |
| 393 | fi |
| 394 | |
| 395 | # Certificate Signing Request (CSR) |
| 396 | echo '=> Generating intermediate CSR..' |
| 397 | echo '' |
| 398 | openssl req -config "$INTERMEDIATE_ROOT/openssl.cfg" -new -sha256 \ |
| 399 | -key intermediate/private/intermediate.key.pem \ |
| 400 | -out intermediate/csr/intermediate.csr.pem |
| 401 | |
| 402 | if [ ! -e "$CA_ROOT/intermediate/csr/intermediate.csr.pem" ]; then |
| 403 | echo '=x=> Intermediate signing request was not generated!' |
| 404 | return 1 |
| 405 | fi |
| 406 | |
| 407 | echo '=> Singing the intermediate certificate. Please answer yes in order to continue.' |
| 408 | echo '' |
| 409 | openssl ca -config "$CA_ROOT/openssl.cfg" -extensions v3_intermediate_ca \ |
| 410 | -days 3650 -notext -md sha256 \ |
| 411 | -in intermediate/csr/intermediate.csr.pem \ |
| 412 | -out intermediate/certs/intermediate.cert.pem |
| 413 | |
| 414 | if [ ! -e "$CA_ROOT/intermediate/certs/intermediate.cert.pem" ]; then |
| 415 | echo '=x=> Intermediate certificate was not signed!' |
| 416 | return 1 |
| 417 | fi |
| 418 | |
| 419 | chmod 444 intermediate/certs/intermediate.cert.pem |
| 420 | |
| 421 | # Print info |
| 422 | openssl x509 -noout -text \ |
| 423 | -in intermediate/certs/intermediate.cert.pem |
| 424 | |
| 425 | openssl verify -CAfile certs/ca.cert.pem \ |
| 426 | intermediate/certs/intermediate.cert.pem |
| 427 | |
| 428 | # Generate Certificate Chain |
| 429 | cat intermediate/certs/intermediate.cert.pem \ |
| 430 | certs/ca.cert.pem > intermediate/certs/ca-chain.cert.pem |
| 431 | |
| 432 | chmod 444 intermediate/certs/ca-chain.cert.pem |
| 433 | |
| 434 | echo '==> Intermediate key pair generated.' |
| 435 | echo "==> Your CA (Certificate Authority) is \"$INTERMEDIATE_ROOT/certs/ca-chain.cert.pem\"" |
| 436 | } |
| 437 | |
| 438 | createCertificate() { |
| 439 | if [ ! -e "$CA_ROOT" ]; then |
| 440 | echo "=x=> Certificate root was not found." |
| 441 | return 1 |
| 442 | elif [ ! -e "$INTERMEDIATE_ROOT/openssl.cfg" ]; then |
| 443 | echo "=x=> Intermediate certificate configuration was not found." |
| 444 | return 1 |
| 445 | fi |
| 446 | |
| 447 | if [ -z "$1" ]; then |
| 448 | echo "=x=> Please provide a name for this certificate." |
| 449 | return 1 |
| 450 | fi |
| 451 | |
| 452 | if [ -z "$2" ] || [ "$2" != "server_cert" ] && [ "$2" != "usr_cert" ]; then |
| 453 | echo "=x=> Type must be one of server_cert or usr_cert. If you're unsure about this, use 'usr_cert'." |
| 454 | return 1 |
| 455 | fi |
| 456 | |
| 457 | cd "$CA_ROOT" |
| 458 | |
| 459 | # Custom configuration file |
| 460 | local CSRCFG="$INTERMEDIATE_ROOT/openssl.cfg" |
| 461 | if [ -n $3 ]; then |
| 462 | CSRCFG="$3" |
| 463 | fi |
| 464 | |
| 465 | # Generate the key if it does not exist |
| 466 | if [ ! -e "$INTERMEDIATE_ROOT/private/$1.key.pem" ]; then |
| 467 | echo "==> Generating key for \"$1\"" |
| 468 | echo '' |
| 469 | |
| 470 | openssl genrsa -out "$INTERMEDIATE_ROOT/private/$1.key.pem" 4096 |
| 471 | chmod 400 "$INTERMEDIATE_ROOT/private/$1.key.pem" |
| 472 | |
| 473 | if [ ! -e "$INTERMEDIATE_ROOT/private/$1.key.pem" ]; then |
| 474 | echo "=x=> Key was not created!" |
| 475 | return 1 |
| 476 | fi |
| 477 | fi |
| 478 | |
| 479 | echo "==> Generating CSR for \"$1\"" |
| 480 | echo '' |
| 481 | |
| 482 | openssl req -config "$CSRCFG" \ |
| 483 | -key "$INTERMEDIATE_ROOT/private/$1.key.pem" \ |
| 484 | -new -sha256 -out "$INTERMEDIATE_ROOT/csr/$1.csr.pem" |
| 485 | |
| 486 | if [ ! -e "$INTERMEDIATE_ROOT/csr/$1.csr.pem" ]; then |
| 487 | echo "=x=> CSR was not created!" |
| 488 | return 1 |
| 489 | fi |
| 490 | |
| 491 | echo "==> Generating certificate for \"$1\"" |
| 492 | echo '' |
| 493 | |
| 494 | openssl ca -config "$INTERMEDIATE_ROOT/openssl.cfg" \ |
| 495 | -extensions "$2" -days 375 -notext -md sha256 \ |
| 496 | -in "$INTERMEDIATE_ROOT/csr/$1.csr.pem" \ |
| 497 | -out "$INTERMEDIATE_ROOT/certs/$1.cert.pem" |
| 498 | |
| 499 | if [ ! -e "$INTERMEDIATE_ROOT/certs/$1.cert.pem" ]; then |
| 500 | echo "=x=> Certificate was not created!" |
| 501 | return 1 |
| 502 | fi |
| 503 | |
| 504 | chmod 444 "$INTERMEDIATE_ROOT/certs/$1.cert.pem" |
| 505 | |
| 506 | echo "==> Done." |
| 507 | echo "==> Key: $INTERMEDIATE_ROOT/private/$1.key.pem" |
| 508 | echo "==> Cert: $INTERMEDIATE_ROOT/certs/$1.cert.pem" |
| 509 | } |
| 510 | |
| 511 | revokeCertificate() { |
| 512 | if [ ! -e "$CA_ROOT" ]; then |
| 513 | echo "=x=> Certificate root was not found." |
| 514 | return 1 |
| 515 | elif [ ! -e "$INTERMEDIATE_ROOT/openssl.cfg" ]; then |
| 516 | echo "=x=> Intermediate certificate configuration was not found." |
| 517 | return 1 |
| 518 | fi |
| 519 | |
| 520 | if [ -z "$1" ]; then |
| 521 | echo "=x=> Please provide a name for a certificate to revoke." |
| 522 | return 1 |
| 523 | fi |
| 524 | |
| 525 | cd "$CA_ROOT" |
| 526 | |
| 527 | echo "==> Revoking certificate" |
| 528 | |
| 529 | openssl ca -config "$INTERMEDIATE_ROOT/openssl.cfg" \ |
| 530 | -revoke "$INTERMEDIATE_ROOT/certs/$1.cert.pem" |
| 531 | |
| 532 | echo "==> Done." |
| 533 | } |
| 534 | |
| 535 | printInfo () { |
| 536 | if [ ! -e "$CA_ROOT" ]; then |
| 537 | echo "=x=> Certificate root was not found." |
| 538 | return 1 |
| 539 | elif [ ! -e "$INTERMEDIATE_ROOT/openssl.cfg" ]; then |
| 540 | echo "=x=> Intermediate certificate configuration was not found." |
| 541 | return 1 |
| 542 | fi |
| 543 | |
| 544 | if [ -n "$1" ]; then |
| 545 | openssl x509 -noout -text -in "$CA_ROOT/intermediate/certs/$1.cert.pem" |
| 546 | return 0 |
| 547 | fi |
| 548 | |
| 549 | echo "=> Root certificate" |
| 550 | openssl x509 -noout -text -in "$CA_ROOT/certs/ca.cert.pem" |
| 551 | |
| 552 | echo "=> Intermediate certificate" |
| 553 | openssl x509 -noout -text \ |
| 554 | -in "$CA_ROOT/intermediate/certs/intermediate.cert.pem" |
| 555 | |
| 556 | openssl verify -CAfile "$CA_ROOT/certs/ca.cert.pem" \ |
| 557 | "$CA_ROOT/intermediate/certs/intermediate.cert.pem" |
| 558 | |
| 559 | echo "" |
| 560 | echo "==> Paths" |
| 561 | echo "Root: $CA_ROOT" |
| 562 | echo "Intermediate: $CA_ROOT/intermediate" |
| 563 | echo "" |
| 564 | |
| 565 | echo "Root Key: $CA_ROOT/private/ca.key.pem" |
| 566 | echo "Root Cert: $CA_ROOT/certs/ca.cert.pem" |
| 567 | |
| 568 | echo "CA Key: $CA_ROOT/intermediate/private/intermediate.key.pem" |
| 569 | echo "Chain: $CA_ROOT/intermediate/certs/ca-chain.cert.pem" |
| 570 | echo "" |
| 571 | } |
| 572 | |
| 573 | printHelp () { |
| 574 | echo "Usage: ./ca <CA Path> info | wizard | root | intm | revoke [<name>] | new [<name>] [ server_cert | usr_cert ] [ openssl.cfg ]" |
| 575 | echo -e " info\t- Print information about your CA" |
| 576 | echo -e " wizard\t- Create a new CA" |
| 577 | echo -e " root\t- Generate root certificate. For use when wizard fails." |
| 578 | echo -e " intm\t- Generate intermediate certificate. For use when wizard fails." |
| 579 | echo -e " new \t- Create a new certificate signed with your CA. Can also be used for renewal." |
| 580 | echo -e " revoke\t- Revoke a certificate by name" |
| 581 | } |
| 582 | |
| 583 | set -e |
| 584 | case "$2" in |
| 585 | "info") |
| 586 | printInfo $3 |
| 587 | ;; |
| 588 | "wizard" | "generate" | "newca") |
| 589 | echo "==> Proceeding with full generation for path $1" |
| 590 | deployFiles |
| 591 | generateRootPair |
| 592 | generateIntermediate |
| 593 | printInfo |
| 594 | ;; |
| 595 | "files") |
| 596 | deployFiles |
| 597 | ;; |
| 598 | "rootpair" | "root") |
| 599 | generateRootPair |
| 600 | ;; |
| 601 | "intermediate" | "intm") |
| 602 | generateIntermediate |
| 603 | ;; |
| 604 | "certificate" | "cert" | "new" | "renew") |
| 605 | createCertificate $3 $4 $5 |
| 606 | ;; |
| 607 | "revoke") |
| 608 | revokeCertificate $3 |
| 609 | ;; |
| 610 | "help") |
| 611 | printHelp |
| 612 | ;; |
| 613 | *) |
| 614 | echo "Usage: ./ca <CA Path> info | wizard | root | intm | revoke [<name>] | new [<name>] [ server_cert | usr_cert ] [ openssl.cfg ]" |
| 615 | ;; |
| 616 | esac |
| 617 |