Make build-ca() almost completely SSL library version independent

The only option which is not SSL version independent is:
  -nodes (version 1)
  -noenc (version 3)
This is managed via $no_password, which is set by verify_ssl_lib().

* Use SSL 'genpkey' to create All CA private keys.
  'genpkey' options are SSL version independent.

* Use SSL 'req' to create All CA certificate/key pairs.
  'req' options are SSL version independent.

* Replace $opts, $crypto and $crypto_opts with individual variables
  for each purpose.

* '$opts' usage:
  -x509 - Replaced by $x509
  -date - Replaced by $date_stamp ($date would be too common)
  -batch - Replaced by $ssl_batch

* '$crypto' usage:
  -aes256 - Replaced by $cipher

* '$crypto_opts' usage:
  -aes256 - Replaced by $cipher (2nd layer of unnecessary complexity)
  -nodes/-noenc - Replaced by $no_password

* Additional variable $digest for SSL 'req' - Defaults to '-sha256'

Insert $EASYRSA_EXTRA_EXTS into the config file along with x509-types
files 'ca' and COMMON.  Replaces the previous method of passing SSL
option '-addext foo:bar' directly to SSL command.

Create new EasyRSA option '--verbose'.  This prints the command passed
to the SSL library by easyrsa_openssl().

Add a shellcheck directive to install_data_to_pki().

Signed-off-by: Richard T Bonhomme <tincantech@protonmail.com>
This commit is contained in:
Richard T Bonhomme 2022-04-20 15:52:20 +01:00
parent 0cf547feab
commit e80c229559
No known key found for this signature in database
GPG Key ID: 2D767DB92FB6C246

View File

@ -444,11 +444,19 @@ easyrsa_openssl() {
mv "$easyrsa_openssl_conf" "$EASYRSA_SAFE_CONF" || \ mv "$easyrsa_openssl_conf" "$EASYRSA_SAFE_CONF" || \
die "easyrsa_openssl - makesafeconf failed" die "easyrsa_openssl - makesafeconf failed"
else else
# Verbose log
[ "$EASYRSA_VERBOSE" ] && printf '%s\n' \
"$EASYRSA_OPENSSL $openssl_command -config $easyrsa_openssl_conf $*"
# Exec SSL with -config temp-file # Exec SSL with -config temp-file
"$EASYRSA_OPENSSL" "$openssl_command" \ "$EASYRSA_OPENSSL" "$openssl_command" \
-config "$easyrsa_openssl_conf" "$@" || return -config "$easyrsa_openssl_conf" "$@" || return
fi fi
else else
# Verbose log
[ "$EASYRSA_VERBOSE" ] && [ ! "$openssl_command" = rand ] \
&& printf '%s\n' "$EASYRSA_OPENSSL $openssl_command $*"
# Exec SSL without -config temp-file # Exec SSL without -config temp-file
"$EASYRSA_OPENSSL" "$openssl_command" "$@" || return "$EASYRSA_OPENSSL" "$openssl_command" "$@" || return
fi fi
@ -765,6 +773,8 @@ install_data_to_pki () {
# EASYRSA_EXT_DIR must be found! No exceptions! # EASYRSA_EXT_DIR must be found! No exceptions!
# The shellcheck warning 2015 is valid, however, this code works correctly. # The shellcheck warning 2015 is valid, however, this code works correctly.
# Note that A && B || C is not if-then-else. C may run when A is true
# shellcheck disable=SC2015
[ -n "$EASYRSA_EXT_DIR" ] && [ -e "$EASYRSA_EXT_DIR" ] || \ [ -n "$EASYRSA_EXT_DIR" ] && [ -e "$EASYRSA_EXT_DIR" ] || \
die "x509-types folder cannot be found" die "x509-types folder cannot be found"
@ -795,16 +805,15 @@ hide_read_pass()
# build-ca backend: # build-ca backend:
build_ca() { build_ca() {
opts="" cipher="-aes256"
sub_ca="" digest="-sha256"
nopass="" unset -v nopass sub_ca ssl_batch date_stamp x509
crypto="-aes256"
while [ -n "$1" ]; do while [ -n "$1" ]; do
case "$1" in case "$1" in
intca) sub_ca=1 ;; intca) sub_ca=1 ;;
subca) sub_ca=1 ;; subca) sub_ca=1 ;;
nopass) nopass=1 ;; nopass) nopass=1 ;;
*) warn "Ignoring unknown command option: '$1'" ;; *) warn "Ignoring unknown command option: '$1'"
esac esac
shift shift
done done
@ -813,12 +822,23 @@ build_ca() {
[ "$EASYRSA_ALGO" = "ec" ] && verify_curve_ec [ "$EASYRSA_ALGO" = "ec" ] && verify_curve_ec
[ "$EASYRSA_ALGO" = "ed" ] && verify_curve_ed [ "$EASYRSA_ALGO" = "ed" ] && verify_curve_ed
# setup for the simpler intermediate CA situation and overwrite with root-CA if needed:
out_file="$EASYRSA_PKI/reqs/ca.req"
out_key="$EASYRSA_PKI/private/ca.key"
if [ -z "$sub_ca" ]; then
out_file="$EASYRSA_PKI/ca.crt" out_file="$EASYRSA_PKI/ca.crt"
opts="$opts -x509 -days $EASYRSA_CA_EXPIRE" out_key="$EASYRSA_PKI/private/ca.key"
# setup for an intermediate CA
if [ "$sub_ca" ]; then
# Gerate a CSR
out_file="$EASYRSA_PKI/reqs/ca.req"
else
# Gerate a certificate
date_stamp=1
x509=1
fi
# If encrypted then create the CA key using AES256 cipher
if [ "$nopass" ]; then
unset -v cipher
else
unset -v no_password
fi fi
# Test for existing CA, and complain if already present # Test for existing CA, and complain if already present
@ -849,9 +869,8 @@ current CA keypair. If you intended to start a new CA, run init-pki first."
printf '%s\n' "01" > "$EASYRSA_PKI/serial" || die "$err_file" printf '%s\n' "01" > "$EASYRSA_PKI/serial" || die "$err_file"
# Default CN only when not in global EASYRSA_BATCH mode: # Default CN only when not in global EASYRSA_BATCH mode:
# 2015 - Note that A && B || C is not if-then-else. C may run when A is true [ "$EASYRSA_BATCH" ] && ssl_batch=1
# shellcheck disable=SC2015 [ "$EASYRSA_REQ_CN" = ChangeMe ] && export EASYRSA_REQ_CN="Easy-RSA CA"
[ "$EASYRSA_BATCH" ] && opts="$opts -batch" || export EASYRSA_REQ_CN="Easy-RSA CA"
out_key_tmp="$(easyrsa_mktemp)" || die "Failed to create temporary file" out_key_tmp="$(easyrsa_mktemp)" || die "Failed to create temporary file"
out_file_tmp="$(easyrsa_mktemp)" || die "Failed to create temporary file" out_file_tmp="$(easyrsa_mktemp)" || die "Failed to create temporary file"
@ -870,62 +889,45 @@ current CA keypair. If you intended to start a new CA, run init-pki first."
hide_read_pass kpass2 hide_read_pass kpass2
echo echo
# shellcheck disable=2154 # var is referenced but not assigned # shellcheck disable=2154 # var is referenced but not assigned
if [ "$kpass" = "$kpass2" ]; if [ "$kpass" = "$kpass2" ]; then
then
printf "%s" "$kpass" > "$out_key_pass_tmp" printf "%s" "$kpass" > "$out_key_pass_tmp"
else else
die "Passphrases do not match." die "Passphrases do not match."
fi fi
fi fi
# Insert x509-types COMMON and 'ca' # Insert x509-types COMMON and 'ca' and EASYRSA_EXTRA_EXTS, if defined.
# shellcheck disable=SC2016 # vars don't expand in single quote # shellcheck disable=SC2016 # vars don't expand in single quote
awkscript=' awkscript='
{if ( match($0, "^#%X509_TYPES%") ) {if ( match($0, "^#%CA_X509_TYPES_EXTRA_EXTS%") )
{ while ( getline<"/dev/stdin" ) {print} next } { while ( getline<"/dev/stdin" ) {print} next }
{print} {print}
}' }'
conf_tmp="$(easyrsa_mktemp)" || die "Failed to create temporary file" conf_tmp="$(easyrsa_mktemp)" || die "Failed to create temporary file"
cat "${EASYRSA_EXT_DIR}/ca" "${EASYRSA_EXT_DIR}/COMMON" | \ {
cat "$EASYRSA_EXT_DIR/ca" "$EASYRSA_EXT_DIR/COMMON"
[ "$EASYRSA_EXTRA_EXTS" ] && print "$EASYRSA_EXTRA_EXTS"
} | \
awk "$awkscript" "$EASYRSA_SSL_CONF" \ awk "$awkscript" "$EASYRSA_SSL_CONF" \
> "$conf_tmp" \ > "$conf_tmp" \
|| die "Copying SSL config to temp file failed" || die "Copying X509_TYPES to config file failed"
# Use this new SSL config for the rest of this function # Use this new SSL config for the rest of this function
EASYRSA_SSL_CONF="$conf_tmp" EASYRSA_SSL_CONF="$conf_tmp"
# When EASYRSA_EXTRA_EXTS is defined, pass it as-is to SSL -addext
if [ -n "$EASYRSA_EXTRA_EXTS" ]; then
# example: "-addext foo,a:b -addext bah,c:d -addext baz e:f,g"
[ "${EASYRSA_EXTRA_EXTS%% *}" = '-addext' ] || \
die "EASYRSA_EXTRA_EXTS: $EASYRSA_EXTRA_EXTS"
fi
# Choose SSL Library version (1, 2(LibreSSL) or 3) and build CA # Choose SSL Library version (1, 2(LibreSSL) or 3) and build CA
case "$osslv_major" in # => BEGIN SSL lib version case "$osslv_major" in
# BEGIN SSL V3 # Version agnostic CA generation
3) # The only remaining option which is version dependent is -nodes/-noenc
# If encrypted then create the CA key using AES256 cipher ($crypto) 1|2|3)
# 'genpkey' requires '-pass' # Generate CA Key
crypto_opts=""
if [ -z "$nopass" ]; then
crypto_opts="$crypto"
if [ -z "$EASYRSA_PASSOUT" ]; then
#crypto_opts="$crypto_opts -pass file:$out_key_pass_tmp"
: # ok
fi
fi
# Generate CA Key - OpenSSL v3 'genpkey' is not compatible
# with easyrsa $opts and $no_password, do NOT use them here
case "$EASYRSA_ALGO" in case "$EASYRSA_ALGO" in
rsa) rsa)
# OpenSSL v3: 'genrsa' is deprecate, use 'genpkey'
easyrsa_openssl genpkey -algorithm "$EASYRSA_ALGO" \ easyrsa_openssl genpkey -algorithm "$EASYRSA_ALGO" \
-out "$out_key_tmp" \
-pkeyopt rsa_keygen_bits:"$EASYRSA_ALGO_PARAMS" \ -pkeyopt rsa_keygen_bits:"$EASYRSA_ALGO_PARAMS" \
${crypto_opts:+ "$crypto_opts"} \ -out "$out_key_tmp" \
${cipher+ "$cipher"} \
${EASYRSA_PASSOUT:+ -pass "$EASYRSA_PASSOUT"} \ ${EASYRSA_PASSOUT:+ -pass "$EASYRSA_PASSOUT"} \
${out_key_pass_tmp:+ -pass file:"$out_key_pass_tmp"} \ ${out_key_pass_tmp:+ -pass file:"$out_key_pass_tmp"} \
|| die "Failed create CA private key" || die "Failed create CA private key"
@ -933,130 +935,38 @@ current CA keypair. If you intended to start a new CA, run init-pki first."
ec) ec)
easyrsa_openssl genpkey -paramfile "$EASYRSA_ALGO_PARAMS" \ easyrsa_openssl genpkey -paramfile "$EASYRSA_ALGO_PARAMS" \
-out "$out_key_tmp" \ -out "$out_key_tmp" \
${crypto_opts:+ "$crypto_opts"} \ ${cipher+ "$cipher"} \
${EASYRSA_PASSOUT:+ -pass "$EASYRSA_PASSOUT"} \ ${EASYRSA_PASSOUT:+ -pass "$EASYRSA_PASSOUT"} \
${out_key_pass_tmp:+ -pass file:"$out_key_pass_tmp"} \ ${out_key_pass_tmp:+ -pass file:"$out_key_pass_tmp"} \
|| die "Failed create CA private key" || die "Failed create CA private key"
;; ;;
ed) ed)
case "$EASYRSA_CURVE" in
[eE][dD]25519|[eE][dD]448)
easyrsa_openssl genpkey -algorithm "$EASYRSA_CURVE" \ easyrsa_openssl genpkey -algorithm "$EASYRSA_CURVE" \
-out "$out_key_tmp" \ -out "$out_key_tmp" \
${crypto_opts:+ "$crypto_opts"} \ ${cipher+ "$cipher"} \
${EASYRSA_PASSOUT:+ -pass "$EASYRSA_PASSOUT"} \ ${EASYRSA_PASSOUT:+ -pass "$EASYRSA_PASSOUT"} \
${out_key_pass_tmp:+ -pass file:"$out_key_pass_tmp"} \ ${out_key_pass_tmp:+ -pass file:"$out_key_pass_tmp"} \
|| die "Failed create CA private key" || die "Failed create CA private key"
;; ;;
*) die "Unknown curve: $EASYRSA_CURVE"
esac
;;
*)
die "Unknown algorithm: $EASYRSA_ALGO"
esac
# Apply password or not
# Private key encryption password or use no_password
# 'req' requires '-passin'
crypto_opts=""
if [ -z "$nopass" ] && [ -z "$EASYRSA_PASSIN" ]; then
#crypto_opts="-passin file:$out_key_pass_tmp"
: # ok
else
crypto_opts="$no_password"
fi
# create the CA keypair:
# It is not suitable to quote $opts and $EASYRSA_EXTRA_EXTS
# because then they are passed to SSL as a single option
# with spaces, which is not the intended use.
# shellcheck disable=SC2086 # Double quote to prevent ..
easyrsa_openssl req -utf8 -new \
-key "$out_key_tmp" -keyout "$out_key_tmp" -out "$out_file_tmp" \
$opts $EASYRSA_EXTRA_EXTS \
${crypto_opts:+ "$crypto_opts"} \
${EASYRSA_PASSIN:+ -passin "$EASYRSA_PASSIN"} \
${out_key_pass_tmp:+ -passin file:"$out_key_pass_tmp"} \
|| die "Failed to build the CA"
;;
# END SSL V3
# BEGIN SSL V1 - Includes LibreSSL 2.x
1|2)
# If encrypted then create the CA key using AES256 cipher ($crypto)
crypto_opts=""
if [ -z "$nopass" ]; then
crypto_opts="$crypto"
if [ -z "$EASYRSA_PASSOUT" ]; then
#if [ "ed" = "$EASYRSA_ALGO" ]; then
# crypto_opts="$crypto_opts -pass file:$out_key_pass_tmp"
#else
# crypto_opts="$crypto_opts -passout file:$out_key_pass_tmp"
#fi
: # ok
fi
fi
# create the CA key
case "$EASYRSA_ALGO" in
rsa)
"$EASYRSA_OPENSSL" genrsa -out "$out_key_tmp" \
${crypto_opts:+ "$crypto_opts"} \
${EASYRSA_PASSOUT:+ -passout "$EASYRSA_PASSOUT"} \
${out_key_pass_tmp:+ -passout file:"$out_key_pass_tmp"} \
"$EASYRSA_ALGO_PARAMS" \
|| die "Failed create CA private key"
;;
ec)
"$EASYRSA_OPENSSL" ecparam -in "$EASYRSA_ALGO_PARAMS" -genkey | \
"$EASYRSA_OPENSSL" ec -out "$out_key_tmp" \
${crypto_opts:+ "$crypto_opts"} \
${EASYRSA_PASSOUT:+ -passout "$EASYRSA_PASSOUT"} \
${out_key_pass_tmp:+ -passout file:"$out_key_pass_tmp"} \
|| die "Failed create CA private key"
;;
ed)
case "$EASYRSA_CURVE" in
[eE][dD]25519|[eE][dD]448)
"$EASYRSA_OPENSSL" genpkey -algorithm "$EASYRSA_CURVE" \
-out "$out_key_tmp" \
${crypto_opts:+ "$crypto_opts"} \
${EASYRSA_PASSOUT:+ -pass "$EASYRSA_PASSOUT"} \
${out_key_pass_tmp:+ -pass file:"$out_key_pass_tmp"} \
|| die "Failed create CA private key"
;;
*) die "Unknown curve: $EASYRSA_CURVE"
esac
;;
*) die "Unknown algorithm: $EASYRSA_ALGO" *) die "Unknown algorithm: $EASYRSA_ALGO"
esac esac
# Apply password or not # Generate the CA keypair:
crypto_opts=""
if [ -z "$nopass" ] && [ -z "$EASYRSA_PASSIN" ]; then
#crypto_opts="-passin file:$out_key_pass_tmp"
: # ok
else
crypto_opts="$no_password"
fi
# create the CA keypair:
# It is not suitable to quote $opts and $EASYRSA_EXTRA_EXTS
# because then they are passed to SSL as a single option
# with spaces, which is not the intended use.
# shellcheck disable=SC2086 # Double quote to prevent .. # shellcheck disable=SC2086 # Double quote to prevent ..
easyrsa_openssl req -utf8 -new \ easyrsa_openssl req -utf8 -new \
-key "$out_key_tmp" -keyout "$out_key_tmp" -out "$out_file_tmp" \ -key "$out_key_tmp" -keyout "$out_key_tmp" \
$opts $EASYRSA_EXTRA_EXTS \ -out "$out_file_tmp" \
${crypto_opts:+ "$crypto_opts"} \ ${ssl_batch+ -batch} \
${x509+ -x509} \
${date_stamp+ -days "$EASYRSA_CA_EXPIRE"} \
"$digest" \
${no_password+ "$no_password"} \
${EASYRSA_PASSIN:+ -passin "$EASYRSA_PASSIN"} \ ${EASYRSA_PASSIN:+ -passin "$EASYRSA_PASSIN"} \
${out_key_pass_tmp:+ -passin file:"$out_key_pass_tmp"} \ ${out_key_pass_tmp:+ -passin file:"$out_key_pass_tmp"} \
|| die "Failed to build the CA" || die "Failed to build the CA"
;; ;;
# END SSL V1
*) die "build-ca ssl lib: $osslv_major" *) die "build-ca ssl lib: $osslv_major"
esac # => END SSL lib version esac
mv "$out_key_tmp" "$out_key" mv "$out_key_tmp" "$out_key"
mv "$out_file_tmp" "$out_file" mv "$out_file_tmp" "$out_file"
@ -1076,8 +986,6 @@ CA creation complete and you may now import and sign cert requests.
Your new CA certificate file for publishing is at: Your new CA certificate file for publishing is at:
$out_file" $out_file"
fi fi
return 0
} # => build_ca() } # => build_ca()
# gen-dh backend: # gen-dh backend:
@ -3038,6 +2946,9 @@ while :; do
empty_ok=1 empty_ok=1
export EASYRSA_SILENT=1 export EASYRSA_SILENT=1
export EASYRSA_BATCH=1 ;; export EASYRSA_BATCH=1 ;;
--verbose)
empty_ok=1
export EASYRSA_VERBOSE=1 ;;
--passin) --passin)
export EASYRSA_PASSIN="$val";; export EASYRSA_PASSIN="$val";;
--passout) --passout)