Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

easyrsa-tools.lib: New command 'renew ca' #1255

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
225 changes: 225 additions & 0 deletions dev/easyrsa-tools.lib
Original file line number Diff line number Diff line change
Expand Up @@ -1009,4 +1009,229 @@ Input is not a valid certificate:
fi
} # => verify_cert()

# Renew CA certificate
renew_ca_cert() {
# dirs and files
ca_key_file="$EASYRSA_PKI"/private/ca.key
ca_cert_file="$EASYRSA_PKI"/ca.crt
exp_ca_cert_list="$EASYRSA_PKI"/expired-ca.list

# create local SSL cnf
write_easyrsa_ssl_cnf_tmp

# Set ssl batch mode, as required
[ "$EASYRSA_BATCH" ] && ssl_batch=1

# Set fixed variables
x509=1
date_stamp=1
f_name="renew_ca_cert -"

# Collect Old CA commonName
old_ca_commonName="$(
"$EASYRSA_OPENSSL" x509 -in "$ca_cert_file" \
-noout -subject -nameopt utf8,multiline | \
grep 'commonName' | sed -e \
s\`^[[:blank:]]*commonName[[:blank:]]*=[[:blank:]]\`\`
)"

# Set default CA commonName
if [ "$EASYRSA_REQ_CN" = ChangeMe ]; then
export EASYRSA_REQ_CN="$old_ca_commonName"
else
user_error "\
$cmd does not support setting an external commonName."
fi

# Assign new cert temp-file
out_cert_tmp=
easyrsa_mktemp out_cert_tmp || \
die "$f_name easyrsa_mktemp out_cert_tmp"

# Assign old cert temp-file
old_cert_tmp=
easyrsa_mktemp old_cert_tmp || \
die "$f_name easyrsa_mktemp old_cert_tmp"

# Write complete CA cert to old cert temp-file
"$EASYRSA_OPENSSL" x509 -in "$ca_cert_file" \
-text > "$old_cert_tmp" || \
die "$f_name Write CA cert to temp-file"

# Prepare header file for updated old CA list
header_tmp=
easyrsa_mktemp header_tmp || \
die "$f_name easyrsa_mktemp header_tmp"

# header and separator text
hdr='# Easy-RSA expired CA certificate list:'
spr='# ====================================='

# make full header temp-file
printf '%s\n%s\n\n' "$hdr" "$spr" > "$header_tmp" || \
die "$f_name printf header to header-temp"

# Prepare old cert list
if [ -f "$exp_ca_cert_list" ]; then
# Assign old cert list temp file
exp_cert_list_tmp=
easyrsa_mktemp exp_cert_list_tmp || \
die "$f_name easyrsa_mktemp exp_cert_list_tmp"

# write list to temp-fie, remove header not separators
sed -e s/"^${hdr}$"// \
"$exp_ca_cert_list" > "$exp_cert_list_tmp" || \
die "$f_name sed exp_ca_cert_list exp_cert_list_tmp"
fi

# Find or create x509 CA file
if [ -f "$EASYRSA_EXT_DIR/ca" ]; then
# Use the x509-types/ca file
x509_type_file="$EASYRSA_EXT_DIR/ca"
else
# Use a temp file
write_x509_type_tmp ca
x509_type_file="$write_x509_file_tmp"
fi

# basicConstraints critical
if grep -q 'Basic Constraints: critical' "$old_cert_tmp"
then
crit_tmp=
easyrsa_mktemp crit_tmp || \
die "$f_name easyrsa_mktemp BC crit_tmp"

add_critical_attrib basicConstraints "$x509_type_file" \
"$crit_tmp" || die "$f_name BC add_critical_attrib"

# Use the new tmp-file with critical attribute
x509_type_file="$crit_tmp"
verbose "renew_ca_cert: basicConstraints critical OK"
fi

# keyUsage critical
if grep -q 'Key Usage: critical' "$old_cert_tmp"
then
crit_tmp=
easyrsa_mktemp crit_tmp || \
die "$f_name easyrsa_mktemp KU crit_tmp"

add_critical_attrib keyUsage "$x509_type_file" \
"$crit_tmp" || die "$f_name KU add_critical_attrib"

# Use the new tmp-file with critical attribute
x509_type_file="$crit_tmp"
verbose "renew_ca_cert: keyUsage critical OK"
fi

# Find or create x509 COMMON file
if [ -f "$EASYRSA_EXT_DIR/COMMON" ]; then
# Use the x509-types/COMMON file
x509_COMMON_file="$EASYRSA_EXT_DIR/COMMON"
else
# Use a temp file
write_x509_type_tmp COMMON
x509_COMMON_file="$write_x509_file_tmp"
fi

# Check for insert-marker in ssl config file
if ! grep -q '^#%CA_X509_TYPES_EXTRA_EXTS%' \
"$EASYRSA_SSL_CONF"
then
die "\
This openssl config file does not support X509-type 'ca'.
* $EASYRSA_SSL_CONF

Please update 'openssl-easyrsa.cnf' to the latest Easy-RSA release."
fi

# Assign awkscript to insert EASYRSA_EXTRA_EXTS
# shellcheck disable=SC2016 # No expand '' - build_ca()
awkscript='\
{if ( match($0, "^#%CA_X509_TYPES_EXTRA_EXTS%") )
{ while ( getline<"/dev/stdin" ) {print} next }
{print}
}'

# Assign tmp-file for config
adjusted_ssl_cnf_tmp=""
easyrsa_mktemp adjusted_ssl_cnf_tmp || \
die "$f_name easyrsa_mktemp adjusted_ssl_cnf_tmp"

# Insert x509-types COMMON and 'ca' and EASYRSA_EXTRA_EXTS
{
# X509 files
cat "$x509_type_file" "$x509_COMMON_file"

# User extensions
[ "$EASYRSA_EXTRA_EXTS" ] && \
print "$EASYRSA_EXTRA_EXTS"

} | awk "$awkscript" "$EASYRSA_SSL_CONF" \
> "$adjusted_ssl_cnf_tmp" || \
die "$f_name Copy X509_TYPES to config failed"
verbose "$f_name insert x509 and extensions OK"

# Use this new SSL config for the rest of this function
EASYRSA_SSL_CONF="$adjusted_ssl_cnf_tmp"

# Generate the CA keypair:
easyrsa_openssl req -utf8 -new \
-key "$ca_key_file" \
-out "$out_cert_tmp" \
${ssl_batch:+ -batch} \
${x509:+ -x509} \
${date_stamp:+ -days "$EASYRSA_CA_EXPIRE"} \
${EASYRSA_DIGEST:+ -"$EASYRSA_DIGEST"} \
${EASYRSA_NO_PASS:+ "$no_password"} \
${EASYRSA_PASSIN:+ -passin "$EASYRSA_PASSIN"} \
# EOL

# Collect New CA text
new_ca_text="$(
"$EASYRSA_OPENSSL" x509 -in "$out_cert_tmp" -noout -text
)"

# Confirm renewed certificate installation
confirm "Install the new CA certificate? " yes "\
Your CA certificate has been renewed. The details follow:

$new_ca_text

WARNING!!!

This new CA certificate will completely replace the old one.
The old CA will be archived to the 'expired-ca.list' file.

Please check the details above are correct, before continuing."

# Add full old CA Cert to old CA Cert list file
if [ -f "$exp_cert_list_tmp" ]; then
cat "$header_tmp" "$old_cert_tmp" "$exp_cert_list_tmp" \
> "$exp_ca_cert_list" || \
die "$f_name cat exp_cert_list_tmp"
else
cat "$header_tmp" "$old_cert_tmp" \
> "$exp_ca_cert_list" || \
die "$f_name cat old_cert_tmp"
fi

# Remove old CA cert file - already saved
rm "$ca_cert_file" || \
warn "Failed to remove old CA cert-file!"

# Install renewed CA Cert temp-file as current CA cert
mv "$out_cert_tmp" "$ca_cert_file" || \
warn "Failed to install renewed CA temp-file!"

notice "\
CA certificate has been successfully renewed.

Your old CA cerificate has been added to the expired CA list at:
* $exp_ca_cert_list

Your renewed CA cerificate is at:
* $ca_cert_file"
} # => renew_ca_cert()

# vim: ft=sh nu ai sw=8 ts=8 noet
8 changes: 7 additions & 1 deletion easyrsa3/easyrsa
Original file line number Diff line number Diff line change
Expand Up @@ -6011,13 +6011,19 @@ case "$cmd" in
verify_working_env
show_host "$@"
;;
renew|show-expire|show-revoke|show-renew|verify-cert)
renew*|show-expire|show-revoke|show-renew|verify-cert)
verify_working_env

# easyrsa-tools.lib is required
source_easyrsa_tools_lib || tools_error=1

case "$cmd" in
renew-ca)
[ "$tools_error" ] && user_error "$tools_error_txt"
[ -z "$alias_days" ] || \
export EASYRSA_CA_EXPIRE="$alias_days"
renew_ca_cert "$@"
;;
renew)
[ "$tools_error" ] && user_error "$tools_error_txt

Expand Down