From d5f6f69de25582c3e13bb7ee44830f756526ab41 Mon Sep 17 00:00:00 2001 From: Richard T Bonhomme Date: Sat, 21 May 2022 00:50:16 +0100 Subject: [PATCH] Introduce 'rewind-renew' - Recover "guineapig" renewed certificates The original version of EasyRSA command 'renew', leaves the certificate without a method to be revoked. This is due to 'renew' moving files OUT of the PKI, which means they cannot be targeted by command 'revoke'. Additionally, 'renew' renames the files to an unfriendly serial-number. -- Command 'rewind-renew' restores the original commonName as file-name-base. And moves these files to renewed folders which are targeted by 'revoke-renewed'. Closes: #578 (Thoroughly tested) Signed-off-by: Richard T Bonhomme --- easyrsa3/easyrsa | 112 ++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 107 insertions(+), 5 deletions(-) diff --git a/easyrsa3/easyrsa b/easyrsa3/easyrsa index c55fb2a..fd17ede 100755 --- a/easyrsa3/easyrsa +++ b/easyrsa3/easyrsa @@ -36,9 +36,10 @@ Here is the list of commands available with a short syntax reminder. Use the build-server-full [ cmd-opts ] build-serverClient-full [ cmd-opts ] revoke [cmd-opts] - revoke-renewed [cmd-opts] renew [cmd-opts] + revoke-renewed [cmd-opts] renewable [ ] + rewind-renewed gen-crl update-db show-req [ cmd-opts ] @@ -147,6 +148,12 @@ cmd_help() { renewable) text=" renewable [ ] Check which certificates can be renewed" ;; + rewind-renewed) text=" + rewind-renewed + Rewind EasyRSA version 3.0 style renewed certificates. + + Moves and renames certs, keys and reqs. Use with caution! + Ref: https://github.com/OpenVPN/easy-rsa/issues/578" ;; gen-crl) text=" gen-crl Generate a CRL" ;; @@ -1533,8 +1540,7 @@ Unable to revoke as the input file is not a valid certificate. Unexpected input in file: $crt_in" # Verify request - if [ -e "$req_in" ] - then + if [ -e "$req_in" ]; then verify_file req "$req_in" || die "\ Unable to move request. The file is not a valid request. Unexpected input in file: $req_in" @@ -1691,8 +1697,7 @@ Unable to renew as the input file is not a valid certificate. Unexpected input in file: $crt_in" # Verify request - if [ -e "$req_in" ] - then + if [ -e "$req_in" ]; then verify_file req "$req_in" || die "\ Unable to move request. The file is not a valid request. Unexpected input in file: $req_in" @@ -2079,6 +2084,100 @@ EOF return 0 } # => renewable +# Move renewed certs_by_serial to the new renew layout +rewind_renew() { + # pull filename base: serial number + [ "$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 "$#" # No options supported + + in_dir="$EASYRSA_PKI/renewed" + crt_in="$in_dir/certs_by_serial/$file_name_base.crt" + key_in="$in_dir/private_by_serial/$file_name_base.key" + req_in="$in_dir/reqs_by_serial/$file_name_base.req" + + # referenced cert must exist: + [ -f "$crt_in" ] || die "\ +Unable to renew as no certificate was found. Certificate was expected +at: $crt_in" + + # Verify certificate + verify_file x509 "$crt_in" || die "\ +Unable to renew 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 move request. The file is not a valid request. +Unexpected input in file: $req_in" + fi + + # get the commonName of the certificate via DN + crt_cn="$( + easyrsa_openssl x509 -in "$crt_in" -noout -subject -nameopt \ + utf8,multiline | grep '^[[:blank:]]*commonName[[:blank:]]*= ' + )" + crt_cn="${crt_cn#*= }" + + # Set out_dir + out_dir="$EASYRSA_PKI/renewed" + crt_out="$out_dir/issued/$crt_cn.crt" + key_out="$out_dir/private/$crt_cn.key" + req_out="$out_dir/reqs/$crt_cn.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 + + # move crt, key and req file to renewed folders + cp "$crt_in" "$crt_out" || die "Failed to move: $crt_in" + + # only move the key if we have it + if [ -e "$key_in" ]; then + if cp "$key_in" "$key_out"; then + : # ok + else + # Attempt restore + mv -f "$crt_out" "$crt_in" + mv -f "$key_out" "$key_in" 2>/dev/null + die "Failed to move: $key_in" + fi + fi + + # only move the req if we have it + if [ -e "$req_in" ]; then + if cp "$req_in" "$req_out"; then + : # ok + else + # Attempt restore + mv -f "$crt_out" "$crt_in" + mv -f "$key_out" "$key_in" + die "Failed to move: $req_in" + fi + fi + + # Success message + notice "\ +Rewind is successful. + +Common Name : $crt_cn +Serial number: $file_name_base + +To revoke use: 'revoke-renewed $crt_cn'" +} # => rewind_renew() + # Set certificate expire date, renew date and variables needed for fixdate cert_dates() { if [ -e "$1" ]; then @@ -4108,6 +4207,9 @@ case "$cmd" in show-renew) status renew "$@" ;; + rewind-renew) + rewind_renew "$@" + ;; upgrade) up23_manage_upgrade_23 "$@" ;;