Merge branch 'TinCanTech-add-rebuild'

Signed-off-by: Richard T Bonhomme <tincantech@protonmail.com>
This commit is contained in:
Richard T Bonhomme 2022-09-21 21:34:25 +01:00
commit bceab3ee74
No known key found for this signature in database
GPG Key ID: 2D767DB92FB6C246

View File

@ -40,6 +40,7 @@ Here is the list of commands available with a short syntax reminder. Use the
renewable [ <file_name_base> ]
revoke-renewed <file_name_base> [cmd-opts]
rewind-renew <certificate-serial-number>
rebuild <file_name_base> [cmd-opts]
gen-crl
update-db
show-req <file_name_base> [ cmd-opts ]
@ -172,12 +173,21 @@ cmd_help() {
superseded
cessationOfOperation
certificateHold"
;;
rebuild)
text="
* rebuild <file_name_base> [ cmd-opts ]
Rebuild a certificate and key specified by <file_name_base>"
opts="
* nopass - do not encrypt the private key (default is encrypted)"
;;
renew)
text="
* renew <file_name_base> [ cmd-opts ]
Renew a certificate specified by the <file_name_base>"
Renew a certificate specified by <file_name_base>"
opts="
* nopass - do not encrypt the private key (default is encrypted)"
@ -188,7 +198,7 @@ cmd_help() {
Check which certificates can be renewed"
;;
rewind-renew)
rewind|rewind-renew)
text="
* rewind-renew <certificate-serial-number>
@ -673,9 +683,9 @@ cleanup() {
fi
# Restore files when renew is interrupted
if [ "$on_error_undo_renew_move" ]; then
renew_restore_move
fi
[ "$on_error_undo_renew_move" ] && renew_restore_move; :
# Restore files when rebuild is interrupted
[ "$on_error_undo_rebuild_move" ] && rebuild_restore_move; :
# shellcheck disable=SC3040 # In POSIX sh, set option [name] is undefined
case "$easyrsa_host_os" in
@ -1954,13 +1964,16 @@ Cannot revoke this certificate because a conflicting file exists.
unset -v deny_msg
# confirm operation by displaying DN:
unset -v if_exist_key_in if_exist_req_in
[ -e "$key_in" ] && if_exist_key_in="
* $key_in"
[ -e "$req_in" ] && if_exist_req_in="
* $req_in"
warn "\
This process is destructive!
These files will be moved to the 'revoked' storage sub-directory:
* $crt_in
* $key_in
* $req_in
* $crt_in${if_exist_key_in}${if_exist_req_in}
These files will be DELETED:
* All PKCS files for commonName : $file_name_base
@ -2068,7 +2081,6 @@ Run easyrsa without commands for usage and command help."
in_dir="$EASYRSA_PKI"
crt_in="$in_dir/issued/$file_name_base.crt"
key_in="$in_dir/private/$file_name_base.key"
req_in="$in_dir/reqs/$file_name_base.req"
creds_in="$in_dir/$file_name_base.creds"
@ -2109,25 +2121,14 @@ Unexpected input in file: $req_in"
# Set out_dir
out_dir="$EASYRSA_PKI/renewed"
crt_out="$out_dir/issued/$file_name_base.crt"
key_out="$out_dir/private/$file_name_base.key"
req_out="$out_dir/reqs/$file_name_base.req"
# NEVER over-write a renewed cert, revoke it first
deny_msg="\
Cannot renew this certificate because a conflicting file exists.
*"
[ -e "$crt_out" ] && die "$deny_msg certificate: $crt_out"
[ -e "$key_out" ] && die "$deny_msg private key: $key_out"
[ -e "$req_out" ] && die "$deny_msg request : $req_out"
unset -v deny_msg
# # Check if old cert is expired or expires within 30
# cert_dates "$crt_in"
#
# [ "$expire_date_s" -lt "$allow_renew_date_s" ] || die "\
#Certificate expires in more than $EASYRSA_CERT_RENEW days.
#Renewal not allowed."
# Extract certificate usage from old cert
cert_ext_key_usage="$(
easyrsa_openssl x509 -in "$crt_in" -noout -text |
@ -2167,8 +2168,6 @@ This process is destructive!
These files will be moved to the 'renewed' storage sub-directory:
* $crt_in
* $key_in
* $req_in
These files will be DELETED:
* All PKCS files for commonName : $file_name_base
@ -2190,11 +2189,10 @@ with the following subject:
on_error_undo_renew_move=1
# renew certificate
if build_full "$cert_type" "$file_name_base" "$opt_nopass"; then
if EASYRSA_BATCH=1 sign_req "$cert_type" "$file_name_base"; then
unset on_error_undo_renew_move
else
# If renew failed then restore cert, key and req. Otherwise, issue a warning
# If *restore* fails then at least the file-names are not serial-numbers
# If renew failed then restore cert. Otherwise, issue a warning
renew_restore_move
die "\
Renewal has failed to build a new certificate/key pair."
@ -2205,7 +2203,7 @@ Renewal has failed to build a new certificate/key pair."
* IMPORTANT *
Renew has created a new certificate and key, both files MUST be replaced!
Renew has created a new certificate, to replace the old certificate.
To revoke the old certificate, once the new one has been deployed,
use: 'revoke-renewed $file_name_base reason' ('reason' is optional)"
@ -2216,7 +2214,7 @@ use: 'revoke-renewed $file_name_base reason' ('reason' is optional)"
# Restore files on failure to renew
renew_restore_move() {
unset -v rrm_err on_error_undo_renew_move
# restore crt, key and req file to PKI folders
# restore crt file to PKI folders
if mv "$restore_crt_out" "$restore_crt_in"; then
: # ok
else
@ -2224,26 +2222,6 @@ renew_restore_move() {
rrm_err=1
fi
# only restore the key if we have it
if [ -e "$restore_key_out" ]; then
if mv "$restore_key_out" "$restore_key_in"; then
: # ok
else
warn "Failed to restore: $restore_key_out"
rrm_err=1
fi
fi
# only restore the req if we have it
if [ -e "$restore_req_out" ]; then
if mv "$restore_req_out" "$restore_req_in"; then
: # ok
else
warn "Failed to restore: $restore_req_out"
rrm_err=1
fi
fi
# messages
if [ "$rrm_err" ]; then
warn "Failed to restore renewed files."
@ -2274,20 +2252,6 @@ renew_move() {
restore_crt_out="$crt_out"
mv "$crt_in" "$crt_out" || die "Failed to move: $crt_in"
# only move the key if we have it
restore_key_in="$key_in"
restore_key_out="$key_out"
if [ -e "$key_in" ]; then
mv "$key_in" "$key_out" || warn "Failed to move: $key_in"
fi
# only move the req if we have it
restore_req_in="$req_in"
restore_req_out="$req_out"
if [ -e "$req_in" ]; then
mv "$req_in" "$req_out" || warn "Failed to move: $req_in"
fi
# remove any pkcs files
for pkcs in p12 p7b p8 p1; do
if [ -e "$in_dir/issued/$file_name_base.$pkcs" ]; then
@ -2401,13 +2365,16 @@ Cannot revoke this certificate because a conflicting file exists.
unset -v deny_msg
# confirm operation by displaying DN:
unset -v if_exist_key_in if_exist_req_in
[ -e "$key_in" ] && if_exist_key_in="
* $key_in"
[ -e "$req_in" ] && if_exist_req_in="
* $req_in"
warn "\
This process is destructive!
These files will be moved to the 'revoked' storage sub-directory:
* $crt_in
* $key_in
* $req_in"
* $crt_in${if_exist_key_in}${if_exist_req_in}"
confirm " Continue with revocation: " "yes" "\
Please confirm you wish to revoke the renewed certificate
@ -2618,6 +2585,275 @@ Serial number: $cert_serial
To revoke use: 'revoke-renewed $crt_cn'"
} # => rewind_renew()
# rebuild backend
rebuild() {
# pull filename base:
[ "$1" ] || die "\
Error: didn't find a file base name as the first argument.
Run easyrsa without commands for usage and command help."
verify_ca_init
# Assign file_name_base and dust off!
file_name_base="$1"
shift
in_dir="$EASYRSA_PKI"
crt_in="$in_dir/issued/$file_name_base.crt"
key_in="$in_dir/private/$file_name_base.key"
req_in="$in_dir/reqs/$file_name_base.req"
creds_in="$in_dir/$file_name_base.creds"
# Upgrade CA index.txt.attr - unique_subject = no
up23_upgrade_ca || die "Failed to upgrade CA to support renewal."
# Set 'nopass'
unset -v opt_nopass
case "$1" in
nopass) opt_nopass="$1"; shift ;;
'') : ;; # Empty ok
*) die "Unknown option: $1"
esac
# referenced cert must exist:
[ -f "$crt_in" ] || die "\
Unable to rebuild as no certificate was found. Certificate was expected
at: $crt_in"
# Verify certificate
verify_file x509 "$crt_in" || die "\
Unable to rebuild as the input file is not a valid certificate. Unexpected
input in file: $crt_in"
# Verify request
if [ -e "$req_in" ]; then
verify_file req "$req_in" || die "\
Unable to verify request. The file is not a valid request.
Unexpected input in file: $req_in"
fi
# get the serial number of the certificate -> serial=XXXX
cert_serial="$(easyrsa_openssl x509 -in "$crt_in" -noout -serial)"
# remove the serial= part -> we only need the XXXX part
cert_serial="${cert_serial##*=}"
duplicate_crt_by_serial="$EASYRSA_PKI/certs_by_serial/$cert_serial.pem"
# Set out_dir
out_dir="$EASYRSA_PKI/renewed"
crt_out="$out_dir/issued/$file_name_base.crt"
key_out="$out_dir/private/$file_name_base.key"
req_out="$out_dir/reqs/$file_name_base.req"
# NEVER over-write a renewed cert, revoke it first
deny_msg="\
Cannot rebuild this certificate because a conflicting file exists.
*"
[ -e "$crt_out" ] && die "$deny_msg certificate: $crt_out"
[ -e "$key_out" ] && die "$deny_msg private key: $key_out"
[ -e "$req_out" ] && die "$deny_msg request : $req_out"
unset -v deny_msg
# # Check if old cert is expired or expires within 30
# cert_dates "$crt_in"
#
# [ "$expire_date_s" -lt "$allow_renew_date_s" ] || die "\
#Certificate expires in more than $EASYRSA_CERT_RENEW days.
#Renewal not allowed."
# Extract certificate usage from old cert
cert_ext_key_usage="$(
easyrsa_openssl x509 -in "$crt_in" -noout -text |
sed -n "/X509v3 Extended Key Usage:/{n;s/^ *//g;p;}"
)"
case "$cert_ext_key_usage" in
"TLS Web Client Authentication")
cert_type=client
;;
"TLS Web Server Authentication")
cert_type=server
;;
"TLS Web Server Authentication, TLS Web Client Authentication")
cert_type=serverClient
;;
*) die "Unknown key usage: $cert_ext_key_usage"
esac
# Use SAN from --subject-alt-name if set else use SAN from old cert
if echo "$EASYRSA_EXTRA_EXTS" | grep -q subjectAltName; then
: # ok - Use current subjectAltName
else
san="$(
easyrsa_openssl x509 -in "$crt_in" -noout -text | sed -n \
"/X509v3 Subject Alternative Name:/{n;s/IP Address:/IP:/g;s/ //g;p;}"
)"
[ "$san" ] && export EASYRSA_EXTRA_EXTS="\
$EASYRSA_EXTRA_EXTS
subjectAltName = $san"
fi
# confirm operation by displaying DN:
unset -v if_exist_key_in if_exist_req_in
[ -e "$key_in" ] && if_exist_key_in="
* $key_in"
[ -e "$req_in" ] && if_exist_req_in="
* $req_in"
warn "\
This process is destructive!
These files will be moved to the 'renewed' storage sub-directory:
* $crt_in${if_exist_key_in}${if_exist_req_in}
These files will be DELETED:
* All PKCS files for commonName : $file_name_base
* The inline credentials file : $creds_in
* The duplicate certificate : $duplicate_crt_by_serial
IMPORTANT: The new key will${opt_nopass+ NOT} be password protected."
confirm " Continue with rebuild: " "yes" "\
Please confirm you wish to renew the certificate
with the following subject:
$(display_dn x509 "$crt_in")
serial-number: $cert_serial"
# move renewed files so we can reissue certificate with the same name
rebuild_move
on_error_undo_rebuild_move=1
# rebuild certificate
if EASYRSA_BATCH=1 build_full "$cert_type" "$file_name_base" "$opt_nopass"; then
unset on_error_undo_rebuild_move
else
# If rebuild failed then restore cert, key and req. Otherwise,
# issue a warning. If *restore* fails then at least the file-names
# are not serial-numbers
rebuild_restore_move
die "\
Rebuild has failed to build a new certificate/key pair."
fi
# Success messages
notice "Rebuild was successful.
* IMPORTANT *
Rebuild has created a new certificate and key, to replace both old files.
To revoke the old certificate, once the new one has been deployed,
use: 'revoke-renewed $file_name_base reason' ('reason' is optional)"
return 0
} # => rebuild()
# Restore files on failure to rebuild
rebuild_restore_move() {
unset -v rrm_err on_error_undo_renew_move
# restore crt, key and req file to PKI folders
if mv "$restore_crt_out" "$restore_crt_in"; then
: # ok
else
warn "Failed to restore: $restore_crt_out"
rrm_err=1
fi
# only restore the key if we have it
if [ -e "$restore_key_out" ]; then
if mv "$restore_key_out" "$restore_key_in"; then
: # ok
else
warn "Failed to restore: $restore_key_out"
rrm_err=1
fi
fi
# only restore the req if we have it
if [ -e "$restore_req_out" ]; then
if mv "$restore_req_out" "$restore_req_in"; then
: # ok
else
warn "Failed to restore: $restore_req_out"
rrm_err=1
fi
fi
# messages
if [ "$rrm_err" ]; then
warn "Failed to restore renewed files."
else
notice "Rebuild FAILED but files have been successfully restored."
fi
return 0
} # => rebuild_restore_move()
# rebuild_move
# moves renewed certificates to the 'renewed' folder
# allows reissuing certificates with the same name
rebuild_move() {
# make sure renewed dirs exist
for target in "$out_dir" \
"$out_dir/issued" \
"$out_dir/private" \
"$out_dir/reqs"
do
[ -d "$target" ] && continue
mkdir -p "$target" ||
die "Failed to mkdir: $target"
done
# move crt, key and req file to renewed folders
restore_crt_in="$crt_in"
restore_crt_out="$crt_out"
mv "$crt_in" "$crt_out" || die "Failed to move: $crt_in"
# only move the key if we have it
restore_key_in="$key_in"
restore_key_out="$key_out"
if [ -e "$key_in" ]; then
mv "$key_in" "$key_out" || warn "Failed to move: $key_in"
fi
# only move the req if we have it
restore_req_in="$req_in"
restore_req_out="$req_out"
if [ -e "$req_in" ]; then
mv "$req_in" "$req_out" || warn "Failed to move: $req_in"
fi
# remove any pkcs files
for pkcs in p12 p7b p8 p1; do
if [ -e "$in_dir/issued/$file_name_base.$pkcs" ]; then
# issued
rm "$in_dir/issued/$file_name_base.$pkcs" ||
warn "Failed to remove: $file_name_base.$pkcs"
elif [ -e "$in_dir/private/$file_name_base.$pkcs" ]; then
# private
rm "$in_dir/private/$file_name_base.$pkcs" ||
warn "Failed to remove: $file_name_base.$pkcs"
else
: # ok
fi
done
# remove the duplicate certificate in the certs_by_serial folder
if [ -e "$duplicate_crt_by_serial" ]; then
rm "$duplicate_crt_by_serial" || warn "\
Failed to remove the duplicate certificate in the certs_by_serial folder"
fi
# remove credentials file (if exists)
if [ -e "$creds_in" ]; then
rm "$creds_in" || warn "Failed to remove the inline file."
fi
return 0
} # => rebuild_move()
# gen-crl backend
gen_crl() {
verify_ca_init
@ -4846,6 +5082,10 @@ case "$cmd" in
rewind-renew)
rewind_renew "$@"
;;
rebuild)
[ "$alias_days" ] && export EASYRSA_CERT_EXPIRE="$alias_days"; :
rebuild "$@"
;;
import-req)
import_req "$@"
;;