From a0dbc346bd92088ee481f5488ac53a7537b32073 Mon Sep 17 00:00:00 2001 From: Richard T Bonhomme Date: Fri, 18 Mar 2022 14:43:28 +0000 Subject: [PATCH] Introduce support for OpenSSL version 3 Required changes: * Use 'verify_ssl_lib()' to determine SSL Library version. Returns '1', '3' OR error. Sets 'no_password' to either '-nodes' (SSLv1) or '-noenc' (SSLv3) * Replace OpenSSL paramater '-nodes' [DEPRECATED], with '-noenc'. Ref: https://www.openssl.org/docs/man3.0/man1/openssl-req.html This effects All Easy-RSA CAs built using OpenSSL version 3. * Replace OpenSSL command 'genrsa' [DEPRECATED], with 'genpkey'. Ref: https://www.openssl.org/docs/man3.0/man1/openssl-genrsa.html This effects Easy-RSA 'RSA' CAs built using OpenSSL version 3. OpenSSL advises using 'genpkey' over 'genrsa'. * OpenSSL 'genpkey' does not accept the parameters defined by easyrsa $opts and $no_password when generating CA private keys. Do not use these variables for OpenSSL-v3 'genpkey'. Optional changes: * Use 'easyrsa_openssl()' wrapper function to build All CAs. * Add 'genpkey' to easyrsa_openssl() wrapper, to include using the EasyRSA/OpenSSL Configuration file $EASYRSA_SAFE_CONF. * Change EasyRSA Elliptic Curve (ec) CA's to also use OpenSSL 'genpkey', instead of OpenSSL 'ec'. This change is not required, however, this means that all EasyRSA CA Private keys are created using 'genpkey' with OpenSSL v3. * EasyRSA 'gen_req()' is the only other code which uses OpenSSL '-nodes'. Make 'gen_req()' aware of the SSL Library version and therefore the correct parameter for an unencrypted private key. (-noenc vs -nodes) Note: OpenSSL '-nodes' is only deprecated not removed. * Indent OpenSSL version 1 code block to match. No functional changes. Tests Passed: Full extended unit tests, with both OpenSSL version 1.1.x and 3.0.1 (Includes standard test for Edwards Curve PKI) Manual building of All OpenSSL *v3* CAs with passwords and subsequent building and signing of a server or client certificate. Manual building of OpenSSL *v1* EC CA with password and subsequent building and signing of a server or client certificate. Tested due to changing CA key from OpenSSL 'ec' to 'genpkey'. Signed-off-by: Richard T Bonhomme --- easyrsa3/easyrsa | 128 +++++++++++++++++++++++++++++++++++++---------- 1 file changed, 101 insertions(+), 27 deletions(-) diff --git a/easyrsa3/easyrsa b/easyrsa3/easyrsa index 796b612..5450a25 100755 --- a/easyrsa3/easyrsa +++ b/easyrsa3/easyrsa @@ -351,7 +351,7 @@ easyrsa_openssl() { case $openssl_command in makesafeconf) has_config=true;; - ca|req|srp|ts) has_config=true;; + ca|req|srp|ts|genpkey) has_config=true;; *) has_config=false;; esac @@ -452,6 +452,13 @@ verify_ssl_lib () { val="$("$EASYRSA_OPENSSL" version)" case "${val%% *}" in OpenSSL|LibreSSL) + osslv_major="${val#* }" + osslv_major="${osslv_major%%.*}" + case "$osslv_major" in + 1) no_password='-nodes' ;; + 3) no_password='-noenc' ;; + *) die "Unsupported SSL library: $osslv_major" + esac print "\ Using SSL: $EASYRSA_OPENSSL $("$EASYRSA_OPENSSL" version)" ;; *) die "\ @@ -667,33 +674,98 @@ current CA keypair. If you intended to start a new CA, run init-pki first." fi fi fi - if [ "$EASYRSA_ALGO" = "rsa" ]; then - #shellcheck disable=SC2086 - "$EASYRSA_OPENSSL" genrsa -out "$out_key_tmp" $crypto_opts ${EASYRSA_PASSOUT:+-passout "$EASYRSA_PASSOUT"} "$EASYRSA_ALGO_PARAMS" || \ - die "Failed create CA private key" - elif [ "$EASYRSA_ALGO" = "ec" ]; then - #shellcheck disable=SC2086 - "$EASYRSA_OPENSSL" ecparam -in "$EASYRSA_ALGO_PARAMS" -genkey | \ - "$EASYRSA_OPENSSL" ec -out "$out_key_tmp" $crypto_opts ${EASYRSA_PASSOUT:+-passout "$EASYRSA_PASSOUT"} || \ - die "Failed create CA private key" - elif [ "ed" = "$EASYRSA_ALGO" ]; then - if [ "ed25519" = "$EASYRSA_CURVE" ]; then - "$EASYRSA_OPENSSL" genpkey -algorithm ED25519 -out $out_key_tmp $crypto_opts ${EASYRSA_PASSOUT:+-pass "$EASYRSA_PASSOUT"} || \ - die "Failed create CA private key" - elif [ "ed448" = "$EASYRSA_CURVE" ]; then - "$EASYRSA_OPENSSL" genpkey -algorithm ED448 -out $out_key_tmp $crypto_opts ${EASYRSA_PASSOUT:+-pass "$EASYRSA_PASSOUT"} || \ - die "Failed create CA private key" + + # Choose SSL Library version (1 or 3) and build CA + case "$osslv_major" in # => BEGIN SSL lib version + + # BEGIN SSL V3 + 3) + # Generate CA Key - OpenSSL v3 'genpkey' is not compatible + # with easyrsa $opts and $no_password, do NOT use them here + # shellcheck disable=SC2086 # Ignore unquoted variables + case "$EASYRSA_ALGO" in + rsa) + # OpenSSL v3: 'genrsa' is deprecate, use 'genpkey' + easyrsa_openssl genpkey -algorithm "$EASYRSA_ALGO" \ + -out "$out_key_tmp" ${crypto_opts} \ + -pkeyopt rsa_keygen_bits:"$EASYRSA_ALGO_PARAMS" \ + ${EASYRSA_PASSOUT:+-pass "$EASYRSA_PASSOUT"} || \ + die "Failed create CA private key" ;; + ec) + easyrsa_openssl genpkey -paramfile "$EASYRSA_ALGO_PARAMS" \ + -out "$out_key_tmp" ${crypto_opts} \ + ${EASYRSA_PASSOUT:+-pass "$EASYRSA_PASSOUT"} || \ + die "Failed create CA private key" ;; + ed) + case "$EASYRSA_CURVE" in + ed25519) + easyrsa_openssl genpkey -algorithm "$EASYRSA_CURVE" \ + -out "$out_key_tmp" ${crypto_opts} \ + ${EASYRSA_PASSOUT:+-pass "$EASYRSA_PASSOUT"} || \ + die "Failed create CA private key" ;; + ed448) + easyrsa_openssl genpkey -algorithm "$EASYRSA_CURVE" \ + -out "$out_key_tmp" ${crypto_opts} \ + ${EASYRSA_PASSOUT:+-pass "$EASYRSA_PASSOUT"} || \ + die "Failed create CA private key" ;; + *) + die "Unknown curve: $EASYRSA_CURVE" + esac + ;; + *) + die "Unknown algorithm: $EASYRSA_ALGO" + esac + + # OpenSSL v3: '-nodes' is deprecate, use '-noenc' + unset -v no_password; [ ! $nopass ] || no_password='-noenc' + + # create the CA keypair: + crypto_opts="" + [ ! $nopass ] && [ -z "$EASYRSA_PASSIN" ] && \ + crypto_opts="-passin file:$out_key_pass_tmp" + + # shellcheck disable=SC2086 + easyrsa_openssl req -utf8 "${no_password}" -new -key "$out_key_tmp" \ + -keyout "$out_key_tmp" -out "$out_file_tmp" ${opts} ${crypto_opts} \ + ${EASYRSA_PASSIN:+-passin "$EASYRSA_PASSIN"} || \ + die "Failed to build the CA" + ;; + # END SSL V3 + + # BEGIN SSL V1 + 1) + if [ "$EASYRSA_ALGO" = "rsa" ]; then + #shellcheck disable=SC2086 + "$EASYRSA_OPENSSL" genrsa -out "$out_key_tmp" $crypto_opts ${EASYRSA_PASSOUT:+-passout "$EASYRSA_PASSOUT"} "$EASYRSA_ALGO_PARAMS" || \ + die "Failed create CA private key" + elif [ "$EASYRSA_ALGO" = "ec" ]; then + #shellcheck disable=SC2086 + "$EASYRSA_OPENSSL" ecparam -in "$EASYRSA_ALGO_PARAMS" -genkey | \ + "$EASYRSA_OPENSSL" ec -out "$out_key_tmp" $crypto_opts ${EASYRSA_PASSOUT:+-passout "$EASYRSA_PASSOUT"} || \ + die "Failed create CA private key" + elif [ "ed" = "$EASYRSA_ALGO" ]; then + if [ "ed25519" = "$EASYRSA_CURVE" ]; then + "$EASYRSA_OPENSSL" genpkey -algorithm ED25519 -out $out_key_tmp $crypto_opts ${EASYRSA_PASSOUT:+-pass "$EASYRSA_PASSOUT"} || \ + die "Failed create CA private key" + elif [ "ed448" = "$EASYRSA_CURVE" ]; then + "$EASYRSA_OPENSSL" genpkey -algorithm ED448 -out $out_key_tmp $crypto_opts ${EASYRSA_PASSOUT:+-pass "$EASYRSA_PASSOUT"} || \ + die "Failed create CA private key" + fi fi - fi - # create the CA keypair: - crypto_opts="" - [ ! $nopass ] && [ -z "$EASYRSA_PASSIN" ] && crypto_opts="-passin file:$out_key_pass_tmp" + # create the CA keypair: + crypto_opts="" + [ ! $nopass ] && [ -z "$EASYRSA_PASSIN" ] && crypto_opts="-passin file:$out_key_pass_tmp" - #shellcheck disable=SC2086 - easyrsa_openssl req -utf8 -new -key "$out_key_tmp" \ - -keyout "$out_key_tmp" -out "$out_file_tmp" $crypto_opts $opts ${EASYRSA_PASSIN:+-passin "$EASYRSA_PASSIN"} || \ - die "Failed to build the CA" + #shellcheck disable=SC2086 + easyrsa_openssl req -utf8 -new -key "$out_key_tmp" \ + -keyout "$out_key_tmp" -out "$out_file_tmp" $crypto_opts $opts ${EASYRSA_PASSIN:+-passin "$EASYRSA_PASSIN"} || \ + die "Failed to build the CA" + ;; + # END SSL V1 + + *) die "build-ca ssl lib: $osslv_major" + esac # => END SSL lib version mv "$out_key_tmp" "$out_key" mv "$out_file_tmp" "$out_file" @@ -751,11 +823,14 @@ Run easyrsa without commands for usage and commands." [ ! "$EASYRSA_BATCH" ] && EASYRSA_REQ_CN="$1" shift + # Require SSL Lib version for 'nopass' -> $no_password + verify_pki_init + # function opts support opts= while [ -n "$1" ]; do case "$1" in - nopass) opts="$opts -nodes" ;; + nopass) opts="$opts $no_password" ;; # batch flag supports internal callers needing silent operation batch) EASYRSA_BATCH=1 ;; *) warn "Ignoring unknown command option: '$1'" ;; @@ -763,7 +838,6 @@ Run easyrsa without commands for usage and commands." shift done - verify_pki_init [ "$EASYRSA_ALGO" = "ec" ] && verify_curve_ec [ "$EASYRSA_ALGO" = "ed" ] && verify_curve_ed