Files
ansible/secret/pki/lib/pki-authority
jose.canelas a8269203f0 Initial commit. This repo contains ansible CM that describes ECG infrastructure.
A test server (acacia root server) is already included in the inventory, with an ecg admin account.
2022-08-05 15:48:02 +01:00

1699 lines
60 KiB
Bash
Executable File

#!/usr/bin/env bash
# vim: foldmarker={{{,}}}:foldmethod=marker
# pki-authority: CA-side PKI management
# Copyright (C) 2016 Maciej Delmanowski <drybjed@gmail.com>
# Copyright (C) 2016-2017 Robin Schneider <ypid@riseup.net>
# Copyright (C) 2016-2020 DebOps <https://debops.org/>
# SPDX-License-Identifier: GPL-3.0-only
set -o nounset -o pipefail -o errexit
umask 022
script="$(basename "${0}")"
_openssl () {
# OpenSSL writes to stderr/stdout even when there are no errors. So just
# display the output if the exit code was != 0 to simplify debugging.
set +e
_openssl_out="$(openssl "${@}" 2>&1)"
local rc=$?
set -e
if [ ${rc} -ne 0 ]; then
echo "${script}: Error: failed to run $* (Exitcode: ${rc})" >&2
echo >&2
echo "Details:" >&2
echo "${_openssl_out}" >&2
exit ${rc}
fi
unset _openssl_out
return ${rc}
}
array_exists () {
# Check if an element is in an array
local array="$1[@]"
local seeking=${2}
local in=1
for element in "${!array}"; do
if [[ $element == "$seeking" ]]; then
in=0
break
fi
done
return $in
}
# Inlined in the following scripts: pki-authority, pki-realm {{{
version () {
# Normalize version numbers for comparison.
echo "$@" | awk -F. '{ printf("%d%03d%03d%03d\n", $1,$2,$3,$4); }'
}
key_exists () {
# Check if an associative array has a specified key present
# shellcheck disable=SC2086
eval '[ ${'$1'[$2]+test_of_existence} ]'
}
get_absolute_path () {
# Get an absolute path to a file
if type python3 > /dev/null ; then
python3 -c 'import sys, os.path; print(os.path.abspath(sys.argv[1]))' "${1}"
else
python -c 'import sys, os.path; print(os.path.abspath(sys.argv[1]))' "${1}"
fi
}
get_relative_path () {
# Get a relative path to a file
if type python3 > /dev/null ; then
python3 -c 'import sys, os.path; print(os.path.relpath(sys.argv[1], sys.argv[2]))' "${1}" "${2:-$PWD}"
else
python -c 'import sys, os.path; print(os.path.relpath(sys.argv[1], sys.argv[2]))' "${1}" "${2:-$PWD}"
fi
}
get_dnsdomainname () {
# Wrap dnsdomainname if it's not present (on MacOS X)
if type dnsdomainname > /dev/null 2>&1 ; then
dnsdomainname
else
local fqdn
fqdn="$(get_fqdn)"
if [[ ${fqdn} == *.* ]] ; then
echo "${fqdn#*.}"
else
echo ""
fi
fi
}
get_fqdn () {
shopt -s nocasematch
case $OSTYPE in
*bsd* | dragonfly* ) hostname;;
* ) hostname -f;;
esac
}
chmod_idempotent () {
# chmod does a `fchmodat` (after a `stat`) even if it does not need to
# change anything as of 8.23-4.
# This behavior is not ideal for this script as it would update the ctime.
local new_mode_in_octal="${1##0}"
local file_path="${2}"
if [ "$(stat -c %a "${file_path}")" != "${new_mode_in_octal}" ] ; then
chmod "${new_mode_in_octal}" "${file_path}"
fi
}
chgrp_idempotent () {
# chgrp does a `fchownat` (after a `newfstatat`) even if it does not need
# to change anything as of 8.23-4.
# This behavior is not ideal for this script as it would update the ctime.
local new_group_name="${1}"
local file_path="${2}"
if [ "$(stat -c %G "${file_path}")" != "${new_group_name}" ] ; then
chgrp "${new_group_name}" "${file_path}"
fi
}
# }}}
get_openssl_ocsp_uri_directive () {
local ocsp_uri
case "${config['ocsp']}" in
true|True)
ocsp_uri="OCSP;URI.0 = \$ocsp_url"
;;
false|False)
ocsp_uri=""
;;
*)
ocsp_uri="OCSP;URI.0 = ${config['ocsp']}"
;;
esac
echo "$ocsp_uri"
}
get_openssl_name_constraints_directive () {
local config_domain="${1}"
local name_constraints
case "${config['name_constraints']}" in
true|True)
case "${config['name_constraints_critical']}" in
false|False)
name_constraints="nameConstraints = permitted;DNS:${config_domain},permitted;DNS:.${config_domain}"
;;
*)
name_constraints="nameConstraints = critical, permitted;DNS:${config_domain},permitted;DNS:.${config_domain}"
;;
esac
;;
false|False)
name_constraints=""
;;
*)
name_constraints="nameConstraints = ${config['name_constraints']}"
;;
esac
echo "$name_constraints"
}
get_openssl_crl_distribution_points_directive () {
local crl_distribution_points=''
case "${config['crl']}" in
true|True)
crl_distribution_points="crlDistributionPoints = @crl_info"
;;
false|False)
crl_distribution_points=""
;;
*)
crl_distribution_points="crlDistributionPoints = ${config['crl']}"
;;
esac
echo "$crl_distribution_points"
}
initialize_environment () {
declare -gA config
config["pki_root"]="${PKI_ROOT:-$(pwd)}"
config["pki_library"]="${PKI_LIBRARY:-openssl}"
config["pki_ca_certificates"]="${PKI_CA_CERTIFICATES:-${config['pki_root']}/ca-certificates/by-group/all}"
config["system_ca"]="true"
config["pki_authorities"]="${config['pki_root']}/authorities"
config["pki_requests"]="${config['pki_root']}/requests"
config["pki_default_fqdn"]="$(get_fqdn)"
config["pki_default_domain"]="$(get_dnsdomainname)"
config["pki_default_domain_dn"]=$(echo "${config['pki_default_domain']}" | cut -d. -f1 | sed 's/.*/\u&/')
config["domain"]=""
config["ca_type"]=""
config["issuer_name"]=""
config["alt_authority"]=""
config["name_constraints"]=""
config["pki_default_sign_base"]="365"
config["pki_default_root_sign_multiplier"]="12"
config["pki_default_ca_sign_multiplier"]="10"
config["pki_default_cert_sign_multiplier"]="3"
config["root_sign_days"]=""
config["ca_sign_days"]=""
config["cert_sign_days"]=""
config["key_size"]="4096"
config["crl"]="true"
config["ocsp"]="true"
config["public_dir_group"]="$(id -g)"
config["public_file_group"]="$(id -g)"
config["private_dir_group"]="$(id -g)"
config["private_file_group"]="$(id -g)"
config["public_dir_mode"]="755"
config["private_dir_mode"]="700"
config["public_file_mode"]="644"
config["private_file_mode"]="600"
# shellcheck disable=SC2174
test -d ${config['pki_root']} || mkdir -p -m ${config['public_dir_mode']} ${config['pki_root']}
}
enter_authority () {
local authority="${1}"
local config_file="${2:-config/authority.conf}"
mkdir -p "${config['pki_authorities']}/${authority}"
chmod_idempotent ${config['public_dir_mode']} "${config['pki_authorities']}/${authority}"
cd "${config['pki_authorities']}/${authority}"
local rc=$?
if [ -r "${config_file}" ] ; then
# shellcheck source=/dev/null
. "${config_file}"
fi
return ${rc}
}
update_symlink () {
local symlink_target="${1}"
if [ -n "${symlink_target}" ] ; then
shift 1
for target in "${@}" ; do
if [ -r "${target}" ] ; then
if [ -L "${symlink_target}" ] && [ "$(readlink "${symlink_target}")" == "${target}" ] ; then
break
else
ln -sf "${target}" "${symlink_target}"
fi
break
fi
done
fi
}
create_openssl_request_config () {
local config_file="${1:-config/openssl-request.conf}"
local config_dn="${2}"
if [ -n "${config_file}" ] && [ -n "${config_dn}" ] && [ ! -r "${config_file}" ] ; then
cat << EOF > "${config_file}"
# Configuration file generated by pki-authority
[ req ]
default_md = sha256
default_bits = ${config['key_size']}
default_keyfile = private/key.pem
prompt = no
encrypt_key = no
distinguished_name = ca_dn
utf8 = yes
string_mask = utf8only
[ ca_dn ]
EOF
echo "${config_dn}" | tr "/" "\\n" | sed \
-e 's/^[Cc]=/countryName=/' \
-e 's/^[Ss][Tt]=/stateOrProvinceName=/' \
-e 's/^[Ll]=/localityName=/' \
-e 's/^[Oo]=/organizationName=/' \
-e 's/^[Oo][Uu]=/organizationalUnitName=/' \
-e 's/^[Cc][Nn]=/commonName=/' >> "${config_file}"
fi
}
create_gnutls_request_config () {
local config_file="${1:-config/gnutls-request.conf}"
local config_dn="${2}"
if [ -n "${config_file}" ] && [ -n "${config_dn}" ] && [ ! -r "${config_file}" ] ; then
cat << EOF > "${config_file}"
# Configuration file generated by pki-authority
EOF
echo "${config_dn}" | tr "/" "\\n" | sed \
-e 's/^[Cc]=/country = "/' \
-e 's/^[Ss][Tt]=/state = "/' \
-e 's/^[Ll]=/locality = "/' \
-e 's/^[Oo]=/organization = "/' \
-e 's/^[Oo][Uu]=/unit = "/' \
-e 's/^[Cc][Nn]=/cn = "/' \
-e 's/$/"/' >> "${config_file}"
fi
}
create_openssl_selfsign_config () {
local config_file="${1:-config/openssl-selfsign.conf}"
local config_name="${2}"
local config_domain="${3}"
local config_ca_type="${4}"
if [ -n "${config_file}" ] && [ ! -r "${config_file}" ] ; then
local ocsp_uri
ocsp_uri="$(get_openssl_ocsp_uri_directive)"
cat << EOF > "${config_file}"
# Configuration file generated by pki-authority
[ default ]
name = ${config_name}
domain_suffix = ${config_domain}
aia_url = http://\$name.\$domain_suffix/crt/
crl_url = http://\$name.\$domain_suffix/crl/
ocsp_url = http://\$name.\$domain_suffix/ocsp/
default_ca = ca_default
name_opt = utf8,esc_ctrl,multiline,lname,align
[ ca_default ]
home = .
database = \$home/database/index
serial = \$home/database/serial
crlnumber = \$home/database/crlnumber
certificate = \$home/subject/cert.pem
private_key = \$home/private/key.pem
RANDFILE = \$home/private/random
new_certs_dir = \$home/certs
unique_subject = no
copy_extensions = none
default_days = ${config['root_sign_days']:-$(( config['pki_default_sign_base'] * config['pki_default_root_sign_multiplier'] ))}
default_crl_days = 365
default_md = sha256
policy = policy_default
x509_extensions = extension_default
[ crl_info ]
URI.0 = \$crl_url
[ issuer_info ]
caIssuers;URI.0 = \$aia_url
${ocsp_uri}
[ extension_ocsp ]
authorityKeyIdentifier = keyid:always
basicConstraints = critical, CA:false
extendedKeyUsage = OCSPSigning
keyUsage = critical, digitalSignature
subjectKeyIdentifier = hash
[ policy_default ]
countryName = optional
stateOrProvinceName = optional
organizationName = optional
organizationalUnitName = optional
commonName = optional
emailAddress = optional
[ extension_default ]
EOF
local name_constraints=''
name_constraints="$(get_openssl_name_constraints_directive "$config_domain")"
local crl_distribution_points=''
crl_distribution_points="$(get_openssl_crl_distribution_points_directive)"
if [ -z "${config_ca_type}" ] || [ "${config_ca_type}" = "root" ] ; then
cat << EOF >> "${config_file}"
basicConstraints = critical, CA:TRUE
keyUsage = critical, keyCertSign, cRLSign
subjectKeyIdentifier = hash
${name_constraints}
EOF
elif [ "${config_ca_type}" = "service" ] ; then
cat << EOF >> "${config_file}"
authorityInfoAccess = @issuer_info
basicConstraints = critical, CA:TRUE, pathlen:0
${crl_distribution_points}
keyUsage = critical, keyCertSign, cRLSign
subjectKeyIdentifier = hash
${name_constraints}
EOF
fi
fi
}
create_gnutls_selfsign_config () {
local config_file="${1:-config/gnutls-selfsign.conf}"
local config_name="${2}"
local config_domain="${3}"
local config_ca_type="${4}"
if [ -n "${config_file}" ] && [ ! -r "${config_file}" ] ; then
cat << EOF > "${config_file}"
# Configuration file generated by pki-authority
expiration_days = ${config['root_sign_days']:-$(( config['pki_default_sign_base'] * config['pki_default_root_sign_multiplier'] ))}
EOF
if [ -z "${config_ca_type}" ] || [ "${config_ca_type}" = "root" ] ; then
cat << EOF >> "${config_file}"
ca
cert_signing_key
crl_signing_key
EOF
elif [ "${config_ca_type}" = "service" ] ; then
cat << EOF >> "${config_file}"
ca
cert_signing_key
crl_signing_key
path_len = 0
#ca_issuers_uri = "http://${config_name}.${config_domain}/crt/"
crl_dist_points = "http://${config_name}.${config_domain}/crl/"
#ocsp_uri = "http://${config_name}.${config_domain}/ocsp/"
EOF
fi
fi
}
create_openssl_sign_config () {
local config_file="${1:-config/openssl-sign.conf}"
local config_name="${2}"
local config_domain="${3}"
local config_ca_type="${4}"
local config_issuer="${5}"
if [ -n "${config_file}" ] && [ ! -r "${config_file}" ] ; then
local ocsp_uri
ocsp_uri="$(get_openssl_ocsp_uri_directive)"
cat << EOF > "${config_file}"
# Configuration file generated by pki-authority
[ default ]
name = ${config_name}
domain_suffix = ${config_domain}
aia_url = http://\$name.\$domain_suffix/crt/
crl_url = http://\$name.\$domain_suffix/crl/
ocsp_url = http://\$name.\$domain_suffix/ocsp/
default_ca = ca_default
name_opt = utf8,esc_ctrl,multiline,lname,align
[ ca_default ]
home = .
database = \$home/database/index
serial = \$home/database/serial
crlnumber = \$home/database/crlnumber
certificate = \$home/subject/cert.pem
private_key = \$home/private/key.pem
RANDFILE = \$home/private/random
new_certs_dir = \$home/certs
unique_subject = no
policy = policy_default
x509_extensions = extension_default
EOF
if [ -z "${config_issuer}" ] && [ -z "${config_ca_type}" ] || [ "${config_ca_type}" = "root" ] ; then
cat << EOF >> "${config_file}"
copy_extensions = none
default_days = ${config['ca_sign_days']:-$(( config['pki_default_sign_base'] * config['pki_default_ca_sign_multiplier'] ))}
default_crl_days = 365
default_md = sha256
EOF
elif [ -z "${config_issuer}" ] && [ "${config_ca_type}" = "service" ] ; then
cat << EOF >> "${config_file}"
copy_extensions = copy
default_days = ${config['cert_sign_days']:-$(( config['pki_default_sign_base'] * config['pki_default_cert_sign_multiplier'] ))}
default_crl_days = 365
default_md = sha256
EOF
elif [ -n "${config_issuer}" ] && [ -z "${config_ca_type}" ] || [ "${config_ca_type}" = "server" ] ; then
cat << EOF >> "${config_file}"
copy_extensions = copy
default_days = ${config['cert_sign_days']:-$(( config['pki_default_sign_base'] * config['pki_default_cert_sign_multiplier'] ))}
default_crl_days = 30
default_md = sha256
EOF
fi
cat << EOF >> "${config_file}"
[ crl_info ]
URI.0 = \$crl_url
[ issuer_info ]
caIssuers;URI.0 = \$aia_url
${ocsp_uri}
[ extension_ocsp ]
authorityKeyIdentifier = keyid:always
basicConstraints = critical, CA:false
extendedKeyUsage = OCSPSigning
keyUsage = critical, digitalSignature
subjectKeyIdentifier = hash
EOF
if [ -z "${config_issuer}" ] && [ -z "${config_ca_type}" ] || [ "${config_ca_type}" = "root" ] ; then
cat << EOF >> "${config_file}"
[ policy_default ]
countryName = optional
stateOrProvinceName = optional
organizationName = optional
organizationalUnitName = optional
commonName = optional
emailAddress = optional
EOF
elif [ -z "${config_issuer}" ] && [ "${config_ca_type}" = "service" ] ; then
cat << EOF >> "${config_file}"
[ policy_default ]
countryName = optional
stateOrProvinceName = optional
organizationName = optional
organizationalUnitName = optional
commonName = optional
emailAddress = optional
EOF
elif [ -n "${config_issuer}" ] && [ -z "${config_ca_type}" ] || [ "${config_ca_type}" = "server" ] ; then
cat << EOF >> "${config_file}"
[ policy_default ]
countryName = optional
stateOrProvinceName = optional
organizationName = optional
organizationalUnitName = optional
commonName = optional
emailAddress = optional
EOF
fi
local name_constraints=''
name_constraints="$(get_openssl_name_constraints_directive "$config_domain")"
local crl_distribution_points=''
crl_distribution_points="$(get_openssl_crl_distribution_points_directive)"
if [ -z "${config_issuer}" ] && [ -z "${config_ca_type}" ] || [ "${config_ca_type}" = "root" ] ; then
cat << EOF >> "${config_file}"
[ extension_default ]
authorityInfoAccess = @issuer_info
authorityKeyIdentifier = keyid:always
basicConstraints = critical, CA:TRUE, pathlen:0
${crl_distribution_points}
keyUsage = critical, keyCertSign, cRLSign
subjectKeyIdentifier = hash
${name_constraints}
EOF
elif [ -z "${config_issuer}" ] && [ "${config_ca_type}" = "service" ] ; then
cat << EOF >> "${config_file}"
[ extension_default ]
authorityInfoAccess = @issuer_info
authorityKeyIdentifier = keyid:always, issuer:always
basicConstraints = critical, CA:FALSE
${crl_distribution_points}
extendedKeyUsage = clientAuth, serverAuth
keyUsage = critical, digitalSignature, keyEncipherment
subjectKeyIdentifier = hash
EOF
elif [ -n "${config_issuer}" ] && [ -z "${config_ca_type}" ] || [ "${config_ca_type}" = "server" ] ; then
cat << EOF >> "${config_file}"
[ extension_default ]
authorityInfoAccess = @issuer_info
authorityKeyIdentifier = keyid:always, issuer:always
basicConstraints = critical, CA:FALSE
${crl_distribution_points}
extendedKeyUsage = clientAuth, serverAuth
keyUsage = critical, digitalSignature, keyEncipherment
subjectKeyIdentifier = hash
EOF
fi
fi
}
create_gnutls_sign_config () {
local config_file="${1:-config/gnutls-sign.conf}"
local config_name="${2}"
local config_domain="${3}"
local config_ca_type="${4}"
local config_issuer="${5}"
if [ -n "${config_file}" ] && [ ! -r "${config_file}" ] ; then
cat << EOF > "${config_file}"
# Configuration file generated by pki-authority
EOF
if [ -z "${config_issuer}" ] && [ -z "${config_ca_type}" ] || [ "${config_ca_type}" = "root" ] ; then
cat << EOF >> "${config_file}"
expiration_days = ${config['ca_sign_days']:-$(( config['pki_default_sign_base'] * config['pki_default_ca_sign_multiplier'] ))}
ca
cert_signing_key
crl_signing_key
path_len = 0
#ca_issuers_uri = "http://${config_name}.${config_domain}/crt/"
crl_dist_points = "http://${config_name}.${config_domain}/crl/"
#ocsp_uri = "http://${config_name}.${config_domain}/ocsp/"
EOF
elif [ -z "${config_issuer}" ] && [ "${config_ca_type}" = "service" ] ; then
cat << EOF >> "${config_file}"
expiration_days = ${config['cert_sign_days']:-$(( config['pki_default_sign_base'] * config['pki_default_cert_sign_multiplier'] ))}
#copy_extensions = copy
signing_key
encryption_key
tls_www_client
tls_www_server
#ca_issuers_uri = "http://${config_name}.${config_domain}/crt/"
crl_dist_points = "http://${config_name}.${config_domain}/crl/"
#ocsp_uri = "http://${config_name}.${config_domain}/ocsp/"
EOF
elif [ -n "${config_issuer}" ] && [ -z "${config_ca_type}" ] || [ "${config_ca_type}" = "server" ] ; then
cat << EOF >> "${config_file}"
expiration_days = ${config['cert_sign_days']:-$(( config['pki_default_sign_base'] * config['pki_default_cert_sign_multiplier'] ))}
#copy_extensions = copy
signing_key
encryption_key
tls_www_client
tls_www_server
#ca_issuers_uri = "http://${config_name}.${config_domain}/crt/"
crl_dist_points = "http://${config_name}.${config_domain}/crl/"
#ocsp_uri = "http://${config_name}.${config_domain}/ocsp/"
EOF
fi
fi
}
save_authority_config () {
local config_file="${1:-config/authority.conf}"
# shellcheck disable=SC2034
local ignored_config_vars=( pki_root pki_requests pki_authorities pki_ca_certificates public_file_group public_dir_group private_file_group private_dir_group )
if [ -r "${config_file}" ] ; then
if grep -q -E "^#\\s+Configuration\\s+file\\s+generated\\s+by\\s+pki-authority$" "${config_file}" ; then
rm -f "${config_file}"
fi
fi
if [ ! -r "${config_file}" ] ; then
cat << EOF > "${config_file}"
# Configuration file generated by pki-authority
EOF
for key in "${!config[@]}" ; do
if ! array_exists ignored_config_vars "${key}" ; then
echo "config['${key}']='${config[${key}]}'" >> "${config_file}"
fi
done
fi
}
check_openssl_req_session_match () {
local check_req="${1}"
local check_session="${PKI_SESSION_TOKEN:-}"
if [ -n "${check_req}" ] && [ -n "${check_session}" ] ; then
if [ -r "${check_req}" ] ; then
openssl asn1parse -in "${check_req}" | grep -q "${check_session}"
rc=$?
return ${rc}
fi
fi
return 1
}
check_gnutls_req_session_match () {
return "$(check_openssl_req_session_match "${@}")"
}
check_openssl_crt_ca_match () {
local check_crt="${1}"
local check_ca="${2}"
local check_ca_issuer="${3:-}"
if [ -n "${check_crt}" ] && [ -n "${check_ca}" ] ; then
if [ -r "${check_crt}" ] && [ -r "${check_ca}" ] ; then
if [ -n "${check_ca_issuer}" ] && [ -r "${check_ca_issuer}" ] ; then
_openssl verify -CAfile "${check_ca_issuer}" -untrusted "${check_ca}" "${check_crt}"
local rc=$?
else
_openssl verify -CAfile "${check_ca}" "${check_crt}"
local rc=$?
fi
return ${rc}
fi
fi
return 1
}
check_gnutls_crt_ca_match () {
return "$(check_openssl_crt_ca_match "${@}")"
}
check_openssl_req_crt_match () {
local check_req="${1}"
local check_crt="${2}"
local req_modulus
local crt_modulus
req_modulus="$(openssl req -noout -modulus -in "${check_req}" | base64)"
crt_modulus="$(openssl x509 -noout -modulus -in "${check_crt}" | base64)"
if [ "${req_modulus}" = "${crt_modulus}" ] ; then
return 0
else
return 1
fi
}
check_gnutls_req_crt_match () {
return "$(check_openssl_req_crt_match "${@}")"
}
sign_openssl_certificate () {
local sign_config="${1}"
local sign_request="${2}"
local sign_out="${3}"
local sign_sect="${4}"
local sign_ext="${5}"
if [ -n "${sign_config}" ] && [ -n "${sign_request}" ] && [ -n "${sign_out}" ] ; then
if [ -r "${sign_request}" ] && [ ! -r "${sign_out}" ] ; then
_openssl ca -batch -notext \
-in "${sign_request}" -out "${sign_out}.tmp" \
-name "${sign_sect}" -extensions "${sign_ext}" \
-config "${sign_config}"
if [ -r "${sign_out}.tmp" ] && [ -s "${sign_out}.tmp" ] ; then
mv "${sign_out}.tmp" "${sign_out}"
fi
if [ -d issuer ] ; then
if [ -r "$(dirname "${sign_out}")/intermediate.pem" ] ; then
if ! diff -q -N "$(get_relative_path "subject/cert.pem" "$(dirname "${sign_out}")")" "$(dirname "${sign_out}")/intermediate.pem" > /dev/null ; then
ln -sf "$(get_relative_path "subject/cert.pem" "$(dirname "${sign_out}")")" "$(dirname "${sign_out}")/intermediate.pem"
fi
else
ln -sf "$(get_relative_path "subject/cert.pem" "$(dirname "${sign_out}")")" "$(dirname "${sign_out}")/intermediate.pem"
fi
if [ -r "$(dirname "${sign_out}")/root.pem" ] ; then
if ! diff -q -N "$(get_relative_path "issuer/subject/cert.pem" "$(dirname "${sign_out}")")" "$(dirname "${sign_out}")/root.pem" > /dev/null ; then
ln -sf "$(get_relative_path "issuer/subject/cert.pem" "$(dirname "${sign_out}")")" "$(dirname "${sign_out}")/root.pem"
fi
else
ln -sf "$(get_relative_path "issuer/subject/cert.pem" "$(dirname "${sign_out}")")" "$(dirname "${sign_out}")/root.pem"
fi
else
if [ -r "$(dirname "${sign_out}")/root.pem" ] ; then
if ! diff -q -N "$(get_relative_path "subject/cert.pem" "$(dirname "${sign_out}")")" "$(dirname "${sign_out}")/root.pem" > /dev/null ; then
ln -sf "$(get_relative_path "subject/cert.pem" "$(dirname "${sign_out}")")" "$(dirname "${sign_out}")/root.pem"
fi
else
ln -sf "$(get_relative_path "subject/cert.pem" "$(dirname "${sign_out}")")" "$(dirname "${sign_out}")/root.pem"
fi
fi
fi
fi
}
sign_openssl_host_certificate () {
local sign_config="${1}"
local sign_request="${2}"
local sign_out="${3}"
local sign_alt="${4:-}"
if [ -n "${sign_config}" ] && [ -n "${sign_request}" ] && [ -n "${sign_out}" ] ; then
if [ -r "${sign_request}" ] && [ ! -r "${sign_out}" ] ; then
_openssl ca -batch -notext \
-in "${sign_request}" -out "${sign_out}.tmp" \
-config "${sign_config}"
if [ -r "${sign_out}.tmp" ] && [ -s "${sign_out}.tmp" ] ; then
mv "${sign_out}.tmp" "${sign_out}"
fi
if [ -d issuer ] ; then
if [ -r "$(dirname "${sign_out}")/intermediate.pem" ] ; then
if ! diff -q -N "$(get_relative_path "subject/cert.pem" "$(dirname "${sign_out}")")" "$(dirname "${sign_out}")/intermediate.pem" > /dev/null ; then
ln -sf "$(get_relative_path "subject/cert.pem" "$(dirname "${sign_out}")")" "$(dirname "${sign_out}")/intermediate.pem"
fi
else
ln -sf "$(get_relative_path "subject/cert.pem" "$(dirname "${sign_out}")")" "$(dirname "${sign_out}")/intermediate.pem"
fi
if [ -r "$(dirname "${sign_out}")/root.pem" ] ; then
if ! diff -q -N "$(get_relative_path "issuer/subject/cert.pem" "$(dirname "${sign_out}")")" "$(dirname "${sign_out}")/root.pem" > /dev/null ; then
ln -sf "$(get_relative_path "issuer/subject/cert.pem" "$(dirname "${sign_out}")")" "$(dirname "${sign_out}")/root.pem"
fi
else
ln -sf "$(get_relative_path "issuer/subject/cert.pem" "$(dirname "${sign_out}")")" "$(dirname "${sign_out}")/root.pem"
fi
else
if [ -r "$(dirname "${sign_out}")/root.pem" ] ; then
if ! diff -q -N "$(get_relative_path "subject/cert.pem" "$(dirname "${sign_out}")")" "$(dirname "${sign_out}")/root.pem" > /dev/null ; then
ln -sf "$(get_relative_path "subject/cert.pem" "$(dirname "${sign_out}")")" "$(dirname "${sign_out}")/root.pem"
fi
else
ln -sf "$(get_relative_path "subject/cert.pem" "$(dirname "${sign_out}")")" "$(dirname "${sign_out}")/root.pem"
fi
fi
if [ -n "${sign_alt}" ] ; then
if [ -d "${sign_alt}/issuer" ] ; then
if [ -r "$(dirname "${sign_out}")/alt_intermediate.pem" ] ; then
if ! diff -q -N "$(get_relative_path "${sign_alt}/subject/cert.pem" "$(dirname "${sign_out}")")" "$(dirname "${sign_out}")/alt_intermediate.pem" > /dev/null ; then
ln -sf "$(get_relative_path "${sign_alt}/subject/cert.pem" "$(dirname "${sign_out}")")" "$(dirname "${sign_out}")/alt_intermediate.pem"
fi
else
ln -sf "$(get_relative_path "${sign_alt}/subject/cert.pem" "$(dirname "${sign_out}")")" "$(dirname "${sign_out}")/alt_intermediate.pem"
fi
if [ -r "$(dirname "${sign_out}")/root.pem" ] ; then
if ! diff -q -N "$(get_relative_path "${sign_alt}/issuer/subject/cert.pem" "$(dirname "${sign_out}")")" "$(dirname "${sign_out}")/alt_root.pem" > /dev/null ; then
ln -sf "$(get_relative_path "${sign_alt}/issuer/subject/cert.pem" "$(dirname "${sign_out}")")" "$(dirname "${sign_out}")/alt_root.pem"
fi
else
ln -sf "$(get_relative_path "${sign_alt}/issuer/subject/cert.pem" "$(dirname "${sign_out}")")" "$(dirname "${sign_out}")/alt_root.pem"
fi
else
if [ -r "$(dirname "${sign_out}")/root.pem" ] ; then
if ! diff -q -N "$(get_relative_path "${sign_alt}/subject/cert.pem" "$(dirname "${sign_out}")")" "$(dirname "${sign_out}")/alt_root.pem" > /dev/null ; then
ln -sf "$(get_relative_path "${sign_alt}/subject/cert.pem" "$(dirname "${sign_out}")")" "$(dirname "${sign_out}")/alt_root.pem"
fi
else
ln -sf "$(get_relative_path "${sign_alt}/subject/cert.pem" "$(dirname "${sign_out}")")" "$(dirname "${sign_out}")/alt_root.pem"
fi
fi
fi
fi
fi
}
sign_gnutls_host_certificate () {
local sign_config="${1}"
local sign_request="${2}"
local sign_out="${3}"
local sign_alt="${4:-}"
if [ -n "${sign_config}" ] && [ -n "${sign_request}" ] && [ -n "${sign_out}" ] ; then
if [ -r "${sign_request}" ] && [ ! -r "${sign_out}" ] ; then
certtool --generate-certificate --template "${sign_config}" \
--load-request "${sign_request}" --load-ca-privkey private/key.pem \
--load-ca-certificate subject/cert.pem --outfile "${sign_out}.tmp"
if [ -r "${sign_out}.tmp" ] && [ -s "${sign_out}.tmp" ] ; then
mv "${sign_out}.tmp" "${sign_out}"
fi
if [ -d issuer ] ; then
if [ -r "$(dirname "${sign_out}")/intermediate.pem" ] ; then
if ! diff -q -N "$(get_relative_path "subject/cert.pem" "$(dirname "${sign_out}")")" "$(dirname "${sign_out}")/intermediate.pem" > /dev/null ; then
ln -sf "$(get_relative_path "subject/cert.pem" "$(dirname "${sign_out}")")" "$(dirname "${sign_out}")/intermediate.pem"
fi
else
ln -sf "$(get_relative_path "subject/cert.pem" "$(dirname "${sign_out}")")" "$(dirname "${sign_out}")/intermediate.pem"
fi
if [ -r "$(dirname "${sign_out}")/root.pem" ] ; then
if ! diff -q -N "$(get_relative_path "issuer/subject/cert.pem" "$(dirname "${sign_out}")")" "$(dirname "${sign_out}")/root.pem" > /dev/null ; then
ln -sf "$(get_relative_path "issuer/subject/cert.pem" "$(dirname "${sign_out}")")" "$(dirname "${sign_out}")/root.pem"
fi
else
ln -sf "$(get_relative_path "issuer/subject/cert.pem" "$(dirname "${sign_out}")")" "$(dirname "${sign_out}")/root.pem"
fi
else
if [ -r "$(dirname "${sign_out}")/root.pem" ] ; then
if ! diff -q -N "$(get_relative_path "subject/cert.pem" "$(dirname "${sign_out}")")" "$(dirname "${sign_out}")/root.pem" > /dev/null ; then
ln -sf "$(get_relative_path "subject/cert.pem" "$(dirname "${sign_out}")")" "$(dirname "${sign_out}")/root.pem"
fi
else
ln -sf "$(get_relative_path "subject/cert.pem" "$(dirname "${sign_out}")")" "$(dirname "${sign_out}")/root.pem"
fi
fi
if [ -n "${sign_alt}" ] ; then
if [ -d "${sign_alt}/issuer" ] ; then
if [ -r "$(dirname "${sign_out}")/alt_intermediate.pem" ] ; then
if ! diff -q -N "$(get_relative_path "${sign_alt}/subject/cert.pem" "$(dirname "${sign_out}")")" "$(dirname "${sign_out}")/alt_intermediate.pem" > /dev/null ; then
ln -sf "$(get_relative_path "${sign_alt}/subject/cert.pem" "$(dirname "${sign_out}")")" "$(dirname "${sign_out}")/alt_intermediate.pem"
fi
else
ln -sf "$(get_relative_path "${sign_alt}/subject/cert.pem" "$(dirname "${sign_out}")")" "$(dirname "${sign_out}")/alt_intermediate.pem"
fi
if [ -r "$(dirname "${sign_out}")/root.pem" ] ; then
if ! diff -q -N "$(get_relative_path "${sign_alt}/issuer/subject/cert.pem" "$(dirname "${sign_out}")")" "$(dirname "${sign_out}")/alt_root.pem" > /dev/null ; then
ln -sf "$(get_relative_path "${sign_alt}/issuer/subject/cert.pem" "$(dirname "${sign_out}")")" "$(dirname "${sign_out}")/alt_root.pem"
fi
else
ln -sf "$(get_relative_path "${sign_alt}/issuer/subject/cert.pem" "$(dirname "${sign_out}")")" "$(dirname "${sign_out}")/alt_root.pem"
fi
else
if [ -r "$(dirname "${sign_out}")/root.pem" ] ; then
if ! diff -q -N "$(get_relative_path "${sign_alt}/subject/cert.pem" "$(dirname "${sign_out}")")" "$(dirname "${sign_out}")/alt_root.pem" > /dev/null ; then
ln -sf "$(get_relative_path "${sign_alt}/subject/cert.pem" "$(dirname "${sign_out}")")" "$(dirname "${sign_out}")/alt_root.pem"
fi
else
ln -sf "$(get_relative_path "${sign_alt}/subject/cert.pem" "$(dirname "${sign_out}")")" "$(dirname "${sign_out}")/alt_root.pem"
fi
fi
fi
fi
fi
}
sign_openssl_ca_certificate () {
local sign_config="${1}"
local sign_request="${2}"
local sign_out="${3}"
if [ -n "${sign_config}" ] && [ -n "${sign_request}" ] && [ -n "${sign_out}" ] ; then
if [ -r "${sign_request}" ] && [ ! -r "${sign_out}" ] ; then
_openssl ca -batch -notext \
-in "${sign_request}" -out "${sign_out}.tmp" \
-config "${sign_config}"
if [ -r "${sign_out}.tmp" ] && [ -s "${sign_out}.tmp" ] ; then
mv "${sign_out}.tmp" "${sign_out}"
fi
fi
fi
}
sign_gnutls_ca_certificate () {
local sign_config="${1}"
local sign_request="${2}"
local sign_out="${3}"
if [ -n "${sign_config}" ] && [ -n "${sign_request}" ] && [ -n "${sign_out}" ] ; then
if [ -r "${sign_request}" ] && [ ! -r "${sign_out}" ] ; then
certtool --generate-certificate --template "${sign_config}" \
--load-request "${sign_request}" --load-ca-privkey private/key.pem \
--load-ca-certificate subject/cert.pem --outfile "${sign_out}.tmp"
if [ -r "${sign_out}.tmp" ] && [ -s "${sign_out}.tmp" ] ; then
mv "${sign_out}.tmp" "${sign_out}"
fi
fi
fi
}
sign_openssl_root_certificate () {
local sign_config="${1}"
local sign_request="${2}"
local sign_out="${3}"
if [ -n "${sign_config}" ] && [ -n "${sign_request}" ] && [ -n "${sign_out}" ] ; then
if [ -r "${sign_request}" ] && [ ! -r "${sign_out}" ] ; then
_openssl ca -selfsign -batch -notext \
-in "${sign_request}" -out "${sign_out}.tmp" \
-config "${sign_config}"
if [ -r "${sign_out}.tmp" ] && [ -s "${sign_out}.tmp" ] ; then
mv "${sign_out}.tmp" "${sign_out}"
fi
fi
fi
}
sign_gnutls_root_certificate () {
local sign_config="${1}"
local sign_request="${2}"
local sign_out="${3}"
if [ -n "${sign_config}" ] && [ -n "${sign_request}" ] && [ -n "${sign_out}" ] ; then
if [ -r "${sign_request}" ] && [ ! -r "${sign_out}" ] ; then
certtool --generate-self-signed --template "${sign_config}" \
--load-request "${sign_request}" --load-privkey private/key.pem \
--outfile "${sign_out}.tmp"
if [ -r "${sign_out}.tmp" ] && [ -s "${sign_out}.tmp" ] ; then
mv "${sign_out}.tmp" "${sign_out}"
fi
fi
fi
}
generate_openssl_request () {
local req_config="${1}"
local req_out="${2}"
if [ -n "${req_config}" ] && [ -n "${req_out}" ] ; then
if [ -r "${req_config}" ] && [ ! -r "${req_out}" ] ; then
local req_keyfile
req_keyfile=$(grep -E '^default_keyfile\s+=\s+' "${req_config}" | awk '{print $3}')
if [ -n "${req_keyfile}" ] ; then
openssl req -new -key "${req_keyfile}" -config "${req_config}" -out "${req_out}.tmp"
else
openssl req -new -config "${req_config}" -out "${req_out}.tmp"
fi
test -r "${req_out}.tmp" && mv "${req_out}.tmp" "${req_out}"
fi
fi
}
generate_gnutls_request () {
local req_config="${1}"
local req_out="${2}"
if [ -n "${req_config}" ] && [ -n "${req_out}" ] ; then
if [ -r "${req_config}" ] && [ ! -r "${req_out}" ] ; then
certtool --generate-request --template "${req_config}" \
--load-privkey private/key.pem --outfile "${req_out}.tmp"
# Remove text output from the request
test -r "${req_out}.tmp" && sed -n -i '/-----BEGIN NEW CERTIFICATE REQUEST-----/,$ p' "${req_out}.tmp"
test -r "${req_out}.tmp" && mv "${req_out}.tmp" "${req_out}"
fi
fi
}
generate_openssl_serial () {
local serial_file="${1}"
local serial_length="${2:-16}"
if [ -n "${serial_file}" ] && [ ! -r "${serial_file}" ] ; then
openssl rand -hex "${serial_length}" > "${serial_file}"
fi
}
generate_gnutls_serial () {
# GnuTLS doesn't use this, so do nothing
return 0
}
generate_openssl_rsa_private_key () {
local key_file="${1:-private/key.pem}"
local key_size="${2:-${config['key_size']}}"
local key_group="${3:-${config['private_file_group']}}"
test -r "${key_file}" || openssl genrsa -out "${key_file}.tmp" "${key_size}"
if [ -r "${key_file}.tmp" ] ; then
chmod "${config['private_file_mode']}" "${key_file}.tmp"
chgrp "${key_group}" "${key_file}.tmp"
mv "${key_file}.tmp" "${key_file}"
fi
chmod_idempotent ${config['private_file_mode']} "${key_file}"
chgrp_idempotent "${key_group}" "${key_file}"
}
generate_gnutls_rsa_private_key () {
local key_file="${1:-private/key.pem}"
local key_size="${2:-${config['key_size']}}"
local key_group="${3:-${config['private_file_group']}}"
if ! [ -r "${key_file}" ] ; then
if [ "$(version "$(certtool --version | head -n 1 | awk '{print $NF}')")" -lt "$(version 3.3.0)" ] ; then
certtool --generate-privkey --outfile "${key_file}.tmp" --bits "${key_size}"
else
certtool --generate-privkey --rsa --outfile "${key_file}.tmp" --bits "${key_size}"
fi
fi
if [ -r "${key_file}.tmp" ] ; then
sed -n -i '/-----BEGIN RSA PRIVATE KEY-----/,$ p' "${key_file}.tmp"
chmod "${config['private_file_mode']}" "${key_file}.tmp"
chgrp "${key_group}" "${key_file}.tmp"
mv "${key_file}.tmp" "${key_file}"
fi
chmod_idempotent "${config['private_file_mode']}" "${key_file}"
chgrp_idempotent "${key_group}" "${key_file}"
}
create_public_directories () {
local dir_group="${1}"
if [ -n "${dir_group}" ] ; then
shift
else
return 1
fi
local directories
read -r -a directories <<< "${@}"
for directory in "${directories[@]}" ; do
mkdir -p "${directory}"
chmod_idempotent "${config['public_dir_mode']}" "${directory}"
chgrp_idempotent "${dir_group}" "${directory}"
done
}
create_private_directories () {
local dir_group="${1}"
if [ -n "${dir_group}" ] ; then
shift
else
return 1
fi
local directories
read -r -a directories <<< "${@}"
for directory in "${directories[@]}" ; do
mkdir -p "${directory}"
chmod_idempotent "${config['private_dir_mode']}" "${directory}"
chgrp_idempotent "${dir_group}" "${directory}"
done
}
sub_sign () {
local -A args
local optspec=":hn-:"
while getopts "${optspec}" optchar; do
case "${optchar}" in
-)
case "${OPTARG}" in
name)
args["name"]="${!OPTIND}"; OPTIND=$(( OPTIND + 1 ))
;;
name=*)
args["name"]=${OPTARG#*=}
;;
req)
args["req"]="${!OPTIND}"; OPTIND=$(( OPTIND + 1 ))
;;
req=*)
args["req"]=${OPTARG#*=}
;;
out)
args["out"]="${!OPTIND}"; OPTIND=$(( OPTIND + 1 ))
;;
out=*)
args["out"]=${OPTARG#*=}
;;
*)
if [ "$OPTERR" = 1 ] && [ "${optspec:0:1}" != ":" ]; then
echo "Unknown option --${OPTARG}" >&2
fi
;;
esac
;;
h)
echo "usage: ${script} init <-n|--name[=]authority>" >&2
exit 2
;;
n)
args["name"]="${!OPTIND}"; OPTIND=$(( OPTIND + 1 ))
;;
*)
if [ "$OPTERR" != 1 ] || [ "${optspec:0:1}" = ":" ]; then
echo "Non-option argument: '-${OPTARG}'" >&2
fi
;;
esac
done
local name=""
local req=""
local out=""
if key_exists args "name" ; then
enter_authority "${args['name']}"
local library="${config['pki_library']}"
local input
local output
input="$(get_absolute_path ${args['req']})"
output="$(get_absolute_path ${args['out']})"
sign_${library}_certificate "config/${library}-sign.conf" "${input}" "${output}"
fi
}
sub_sign-by-host () {
if [ $# -gt 0 ] ; then
if [ -d requests ] && [ -d realms ] ; then
for authority in requests/* ; do
if [ -r "authorities/$(basename "${authority}")/subject/cert.pem" ] ; then
for host in "${authority}"/* ; do
for play_host in "${@}" ; do
if [ "$(basename "${host}")" = "${play_host}" ] ; then
for realm in "${host}"/* ; do
if [ -r "${realm}/request.pem" ] ; then
local input
local output
input="$(get_absolute_path "${realm}"/request.pem)"
output="$(get_absolute_path "realms/by-host/$(basename "${play_host}")/$(basename "${realm}")/internal/cert.pem")"
enter_authority "$(basename "${authority}")"
local alt_authority=""
if [ -n "${config['alt_authority']}" ] && [ -d ../${config['alt_authority']} ] ; then
alt_authority="$(get_absolute_path ../${config['alt_authority']})"
fi
if [ -r "${output}" ] && check_${config['pki_library']}_req_session_match "${input}" ; then
rm -f "${output}"
fi
if [ -r "${output}" ] && ! check_${config['pki_library']}_req_crt_match "${input}" "${output}" ; then
rm -f "${output}"
if ! check_${config['pki_library']}_req_session_match "${input}" ; then
rm -f "${input}"
fi
fi
if [ -r "${output}" ] && ! check_${config['pki_library']}_crt_ca_match "${output}" "subject/cert.pem" "issuer/subject/cert.pem" ; then
rm -f "${output}"
if ! check_${config['pki_library']}_req_session_match "${input}" ; then
rm -f "${input}"
fi
fi
if [ ! -r "${output}" ] && ! check_${config['pki_library']}_req_session_match "${input}" ; then
rm -f "${input}"
fi
if [ -r "${input}" ] ; then
sign_${config['pki_library']}_host_certificate "config/${config['pki_library']}-sign.conf" "${input}" "${output}" "${alt_authority}"
fi
cd - > /dev/null
fi
done
fi
done
done
fi
done
fi
else
cat << EOF >&2
Usage: ${script} sign-by-host [host1 host2 ...]
signs certificates for specified hosts and writes them to the secret/pki subdirectory
EOF
exit 1
fi
}
sub_new-ca () {
local -A args
local optspec=":hn-:"
while getopts "${optspec}" optchar; do
case "${optchar}" in
-)
case "${OPTARG}" in
name)
args["name"]="${!OPTIND}"; OPTIND=$(( OPTIND + 1 ))
;;
name=*)
args["name"]=${OPTARG#*=}
;;
system-ca)
# shellcheck disable=SC2154
args["system_ca"]="${!OPTIND}"; OPTIND=$(( OPTIND + 1 ))
;;
system-ca=*)
args["system_ca"]=${OPTARG#*=}
;;
alt-authority)
args["alt_authority"]="${!OPTIND}"; OPTIND=$(( OPTIND + 1 ))
;;
alt-authority=*)
args["alt_authority"]=${OPTARG#*=}
;;
library)
args["pki_library"]="${!OPTIND}"; OPTIND=$(( OPTIND + 1 ))
;;
library=*)
args["pki_library"]=${OPTARG#*=}
;;
subdomain)
# shellcheck disable=SC2154
args["subdomain"]="${!OPTIND}"; OPTIND=$(( OPTIND + 1 ))
;;
subdomain=*)
args["subdomain"]=${OPTARG#*=}
;;
subject)
# shellcheck disable=SC2154
args["subject"]="${!OPTIND}"; OPTIND=$(( OPTIND + 1 ))
;;
subject=*)
args["subject"]=${OPTARG#*=}
;;
type)
# shellcheck disable=SC2154
args["ca_type"]="${!OPTIND}"; OPTIND=$(( OPTIND + 1 ))
;;
type=*)
args["ca_type"]=${OPTARG#*=}
;;
issuer-name)
# shellcheck disable=SC2154
args["issuer_name"]="${!OPTIND}"; OPTIND=$(( OPTIND + 1 ))
;;
issuer-name=*)
args["issuer_name"]=${OPTARG#*=}
;;
domain)
# shellcheck disable=SC2154
args["domain"]="${!OPTIND}"; OPTIND=$(( OPTIND + 1 ))
;;
domain=*)
args["domain"]=${OPTARG#*=}
;;
root-sign-days)
args["root_sign_days"]="${!OPTIND}"; OPTIND=$(( OPTIND + 1 ))
;;
root-sign-days=*)
args["root_sign_days"]=${OPTARG#*=}
;;
ca-sign-days)
args["ca_sign_days"]="${!OPTIND}"; OPTIND=$(( OPTIND + 1 ))
;;
ca-sign-days=*)
args["ca_sign_days"]=${OPTARG#*=}
;;
cert-sign-days)
args["cert_sign_days"]="${!OPTIND}"; OPTIND=$(( OPTIND + 1 ))
;;
cert-sign-days=*)
args["cert_sign_days"]=${OPTARG#*=}
;;
key-size)
args["key_size"]="${!OPTIND}"; OPTIND=$(( OPTIND + 1 ))
;;
key-size=*)
args["key_size"]=${OPTARG#*=}
;;
crl)
args["crl"]="${!OPTIND}"; OPTIND=$(( OPTIND + 1 ))
;;
crl=*)
args["crl"]=${OPTARG#*=}
;;
ocsp)
args["ocsp"]="${!OPTIND}"; OPTIND=$(( OPTIND + 1 ))
;;
ocsp=*)
args["ocsp"]=${OPTARG#*=}
;;
name-constraints)
args["name_constraints"]="${!OPTIND}"; OPTIND=$(( OPTIND + 1 ))
;;
name-constraints=*)
args["name_constraints"]=${OPTARG#*=}
;;
name-constraints-critical)
args["name_constraints_critical"]="${!OPTIND}"; OPTIND=$(( OPTIND + 1 ))
;;
name-constraints-critical=*)
args["name_constraints_critical"]=${OPTARG#*=}
;;
*)
if [ "$OPTERR" = 1 ] && [ "${optspec:0:1}" != ":" ]; then
echo "Unknown option --${OPTARG}" >&2
fi
;;
esac
;;
h)
echo "usage: ${script} new-ca <-n|--name[=]authority>" >&2
exit 2
;;
n)
args["name"]="${!OPTIND}"; OPTIND=$(( OPTIND + 1 ))
;;
*)
if [ "$OPTERR" != 1 ] || [ "${optspec:0:1}" = ":" ]; then
echo "Non-option argument: '-${OPTARG}'" >&2
fi
;;
esac
done
if key_exists args "name" ; then
enter_authority "${args['name']}"
local config_changed="false"
for key in "${!args[@]}" ; do
if [ -n "${args[${key}]+x}" ] ; then
if key_exists config "${key}" ; then
if [ "${config[${key}]}" != "${args[${key}]}" ] ; then
local config_changed="true"
config["${key}"]="${args[${key}]}"
fi
else
local config_changed="true"
config["${key}"]="${args[${key}]}"
fi
fi
done
create_public_directories ${config['public_dir_group']} config database subject certs requests signed
create_private_directories ${config['private_dir_group']} private
if [ "${config_changed}" = "true" ] ; then
save_authority_config config/authority.conf
fi
local name="${config['name']}"
local library="${config['pki_library']}"
generate_${library}_rsa_private_key private/key.pem
create_${library}_request_config config/${library}-request.conf "${config['subject']}"
if [ -z "${config['issuer_name']}" ] ; then
create_${library}_selfsign_config config/${library}-selfsign.conf "${config['subdomain']}" "${config['domain']}" "${config['ca_type']}"
fi
create_${library}_sign_config config/${library}-sign.conf "${config['subdomain']}" "${config['domain']}" "${config['ca_type']}" "${config['issuer_name']}"
if [ -n "${config['issuer_name']}" ] ; then
update_symlink issuer ../${config['issuer_name']}
fi
if [ "${library}" = "openssl" ] ; then
generate_${library}_serial database/serial
test -r database/index || touch database/index
fi
generate_${library}_request config/${library}-request.conf subject/request.pem
if [ -z "${config['issuer_name']}" ] && [ ! -L issuer ] ; then
sign_${library}_root_certificate config/${library}-selfsign.conf \
subject/request.pem subject/cert.pem
elif [ -n "${config['issuer_name']}" ] && [ -L issuer ] ; then
local subject_dir
subject_dir="$(pwd)"
cd issuer || exit 1
sign_${library}_ca_certificate config/${library}-sign.conf \
"${subject_dir}/subject/request.pem" "${subject_dir}/subject/cert.pem"
cd - > /dev/null
fi
if [ "${config['system_ca']}" = "true" ] && [ -n "${config['pki_ca_certificates']}" ] && [ -n "${config['subdomain']}" ] && [ -z "${config['issuer_name']}" ] && [ ! -L issuer ] ; then
if [ -r "$(dirname "${config['pki_ca_certificates']}")/${config['subdomain']}.${config['domain']}.crt" ] ; then
if ! diff -q -N "$(get_relative_path "subject/cert.pem" "${config['pki_ca_certificates']}")" "${config['pki_ca_certificates']}/${config['subdomain']}.${config['domain']}.crt" > /dev/null ; then
ln -sf "$(get_relative_path "subject/cert.pem" "${config['pki_ca_certificates']}")" "${config['pki_ca_certificates']}/${config['subdomain']}.${config['domain']}.crt"
fi
else
ln -sf "$(get_relative_path "subject/cert.pem" "${config['pki_ca_certificates']}")" "${config['pki_ca_certificates']}/${config['subdomain']}.${config['domain']}.crt"
fi
fi
fi
}
sub_init () {
local -A args
local optspec=":hn-:"
while getopts "${optspec}" optchar; do
case "${optchar}" in
-)
case "${OPTARG}" in
name)
args["name"]="${!OPTIND}"; OPTIND=$(( OPTIND + 1 ))
;;
name=*)
args["name"]=${OPTARG#*=}
;;
library)
args["pki_library"]="${!OPTIND}"; OPTIND=$(( OPTIND + 1 ))
;;
library=*)
args["pki_library"]=${OPTARG#*=}
;;
default-sign-base)
args["pki_default_sign_base"]="${!OPTIND}"; OPTIND=$(( OPTIND + 1 ))
;;
default-sign-base=*)
args["pki_default_sign_base"]=${OPTARG#*=}
;;
root-sign-multiplier)
args["pki_default_root_sign_multiplier"]="${!OPTIND}"; OPTIND=$(( OPTIND + 1 ))
;;
root-sign-multiplier=*)
args["pki_default_root_sign_multiplier"]=${OPTARG#*=}
;;
ca-sign-multiplier)
args["pki_default_ca_sign_multiplier"]="${!OPTIND}"; OPTIND=$(( OPTIND + 1 ))
;;
ca-sign-multiplier=*)
args["pki_default_ca_sign_multiplier"]=${OPTARG#*=}
;;
cert-sign-multiplier)
args["pki_default_cert_sign_multiplier"]="${!OPTIND}"; OPTIND=$(( OPTIND + 1 ))
;;
cert-sign-multiplier=*)
args["pki_default_cert_sign_multiplier"]=${OPTARG#*=}
;;
*)
if [ "$OPTERR" = 1 ] && [ "${optspec:0:1}" != ":" ]; then
echo "Unknown option --${OPTARG}" >&2
fi
;;
esac
;;
h)
echo "usage: ${script} init <-n|--name[=]authority>" >&2
exit 2
;;
n)
args["name"]="${!OPTIND}"; OPTIND=$(( OPTIND + 1 ))
;;
*)
if [ "$OPTERR" != 1 ] || [ "${optspec:0:1}" = ":" ]; then
echo "Non-option argument: '-${OPTARG}'" >&2
fi
;;
esac
done
if key_exists args "name" ; then
enter_authority ${args['name']}
for key in "${!args[@]}" ; do
if [ -n "${args[${key}]+x}" ] ; then
if key_exists config "${key}" ; then
if [ "${config[${key}]}" != "${args[${key}]}" ] ; then
local config_changed="true"
config["${key}"]="${args[${key}]}"
fi
else
local config_changed="true"
config["${key}"]="${args[${key}]}"
fi
fi
done
create_public_directories ${config['public_dir_group']} config database subject certs requests signed
create_private_directories ${config['private_dir_group']} private
if [ "${config_changed}" = "true" ] ; then
save_authority_config config/authority.conf
fi
fi
}
print_usage () {
cat << EOF >&2
Usage: ${script} <command> [parameters]
Available commands:
init
usage: pki-authority init <-n|--name[=]authority>
new-ca
usage: pki-authority new-ca <-n|--name[=]authority>
sign
usage: pki-authority init <-n|--name[=]authority>
sign-by-host
usage: ${script} sign-by-host [host1 host2 ...]
signs certificates for specified hosts and writes them to the secret/pki subdirectory
EOF
}
initialize_environment
if [ $# -gt 0 ] ; then
subcommand="${1}"
if [ -n "${subcommand}" ] ; then
case "${subcommand}" in
init|new-ca|sign|sign-by-host)
shift
"sub_${subcommand}" "${@}"
;;
*)
echo "${script}: Error: unknown subcommand '${subcommand}'" >&2
print_usage
exit 1
;;
esac
fi
else
print_usage
exit 1
fi