Skip to content

Commit

Permalink
Merge branch 'TinCanTech-tools-renew-ca'
Browse files Browse the repository at this point in the history
Signed-off-by: Richard T Bonhomme <tincantech@protonmail.com>
  • Loading branch information
TinCanTech committed Nov 27, 2024
2 parents 104b44c + 62c3236 commit 64dbb37
Show file tree
Hide file tree
Showing 4 changed files with 251 additions and 8 deletions.
1 change: 1 addition & 0 deletions ChangeLog
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ Easy-RSA 3 ChangeLog

3.2.2 (TBD)

* easyrsa-tools.lib: Introduce new command 'renew-ca' (ba32b0d) (#1255)
* easyrsa-tools.lib: show-expire, allow --days to be zero (a1033a5) (#1254)
* Command 'help': Ignore EASYRSA_SILENT (8804d6b) (#1249)
* bugfix: easyrsa-tools.lib: renew SAN, remove excess word 'Address' (af17492) (#1251)
Expand Down
219 changes: 219 additions & 0 deletions dev/easyrsa-tools.lib
Original file line number Diff line number Diff line change
Expand Up @@ -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
31 changes: 24 additions & 7 deletions doc/EasyRSA-Renew-and-Revoke.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,22 +86,26 @@ Command Details: `renew`

#### `renew` has three different versions:

* `renew` **Version 1**: Easy-RSA version `3.0.6`, `3.0.7` and `3.0.8`.
* `renew` **Version 1**: Easy-RSA versions `3.0.6`, `3.0.7` and `3.0.8`.
- Both certificate and private key are rebuilt.
- Once a certificate has been renewed it **cannot** be revoked.

* `renew` **Version 2**: Easy-RSA version `3.0.9` and `3.1.0`.
* `renew` **Version 2**: Easy-RSA versions `3.0.9` and `3.1.0`.
- Both certificate and private key are rebuilt.
- Once a certificate has been renewed it **can** be revoked.
- Use command:

`revoke-renewed file-name-base [ reason ]`

* `renew` **Version 3**: Easy-RSA version `3.1.1+`.
* `renew` **Version 3**: Easy-RSA versions `3.1.1` through `3.1.7`.
- Only certificate is renewed.
- The original `renew` command has been renamed to `rebuild`, which
rebuilds both certificate and private key.

* `renew` **Version 4**: Easy-RSA version `3.2.0+`.
- Only certificate is renewed.
- Supports standard Easy-RSA X509 extension duplication.


Resolving issues with `renew` version 1
---------------------------------------
Expand Down Expand Up @@ -149,7 +153,14 @@ Renewed certificate can be revoked:
This is the preferred method to renew a certificate because the original
private key is still valid.

`renew` version 3 is **only** available since Easy-RSA version `3.1.1+`.
Using `renew` version 4
-----------------------

#### Upgrade Easy-RSA to version `3.2.0+` is required.

This is the most comprensive version of `renew`, which supports automatic
copying of Easy-RSA X509 extensions.


----

Expand Down Expand Up @@ -186,7 +197,15 @@ an old certificate/key pair, which has been _rebuilt_ by command `rebuild`.
Renew CA Certificate
====================

Easy-RSA Version 3.2.1+ supports a simple way to effectively renew a CA Certificate.
Easy-RSA Version `3.2.2+ includes command `renew-ca`, which will create a new
CA certificate using the original CA key. This new certificate will completely
replace the previous CA certificate. This command can be safely tested without
disturbing your current PKI. The command requires user confirmation before
installing the new CA certificate. The old CA certificate is archived to the
file 'pki/expired-ca.list'.


Easy-RSA Version `3.2.1+` supports a simple way to effectively renew a CA Certificate.

**Preamble** - Specifically for use with OpenVPN:

Expand Down Expand Up @@ -246,5 +265,3 @@ Please consider the method outlined here, which requires very little work:
`inline` files in the `pki/inline/private` directory include security keys,
which MUST only be transmitted over a secure connection, such as `https`.

As of Easy-RSA Version 3.2.1, this is the only supported way to renew an
expired CA certificate.
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-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

Expand Down

0 comments on commit 64dbb37

Please sign in to comment.