diff --git a/dev/easyrsa-tools.lib b/dev/easyrsa-tools.lib index f9f8505c..7f28edf6 100644 --- a/dev/easyrsa-tools.lib +++ b/dev/easyrsa-tools.lib @@ -1009,4 +1009,223 @@ 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 + + # Set fixed variables + x509=1 + date_stamp=1 + f_name="renew_ca_cert()" + + # Set default CA commonName + [ "$EASYRSA_REQ_CN" = ChangeMe ] || \ + warn "\ +$cmd does not support setting an external commonName." + + # Copy Old CA commonName as default + export EASYRSA_REQ_CN="$( + "$EASYRSA_OPENSSL" x509 -in "$ca_cert_file" \ + -noout -subject -nameopt utf8,multiline | \ + grep 'commonName' | sed -e \ + s\`^[[:blank:]]*commonName[[:blank:]]*=[[:blank:]]\`\` + )" + + # Set ssl batch mode, as required + [ "$EASYRSA_BATCH" ] && ssl_batch=1 + + # create local SSL cnf + write_easyrsa_ssl_cnf_tmp + + # 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" + + # 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 new CA cert: + 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 " +NEW CA CERTIFICATE: + +$new_ca_text + +WARNING !!! + +Your CA certificate is ready to be renewed. (Details above) + +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." + + # 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" + fi + + # 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 + + # Install renewed CA Cert temp-file as current CA cert + mv -f "$out_cert_tmp" "$ca_cert_file" || \ + die "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 diff --git a/easyrsa3/easyrsa b/easyrsa3/easyrsa index 340f5ebe..0cc7992e 100755 --- a/easyrsa3/easyrsa +++ b/easyrsa3/easyrsa @@ -6011,13 +6011,19 @@ case "$cmd" in verify_working_env show_host "$@" ;; - renew|show-expire|show-revoke|show-renew|verify-cert) + renew-ca|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