From aaa44558b2d897e7a47fa648636d1c644fe08efb Mon Sep 17 00:00:00 2001 From: Richard T Bonhomme Date: Tue, 25 Jul 2023 15:11:26 +0100 Subject: [PATCH 1/3] Export PKCS: Expand usage for incomplete PKI The current export functions only allow use on a complete PKI, with CA. This change allows the following: * Server - Export P12/P7 without client key * Client - Export P12/P7 without CA, P8/P1 without PKI Due to the relative obscurity of the command options 'noca' and 'nokey', exporting P12/P7 with incorrect options can be adjusted on-the-fly with confirmation from the user. Correct behaviour of export-p1 with OpenSSL v3 by using -legacy option. Otherwise, OpenSSL v3 outputs a PKCS#8 format file. Minor improvements to comments. Signed-off-by: Richard T Bonhomme --- easyrsa3/easyrsa | 184 ++++++++++++++++++++++++++++++++++++----------- 1 file changed, 141 insertions(+), 43 deletions(-) diff --git a/easyrsa3/easyrsa b/easyrsa3/easyrsa index a8bbd1b46..ca544c6f4 100755 --- a/easyrsa3/easyrsa +++ b/easyrsa3/easyrsa @@ -64,7 +64,7 @@ A list of commands is shown below: # vars file details case "$found_vars" in - 0) vars_status="Missing or undefined." ;; + 0) vars_status="Missing or undefined" ;; 1) vars_status="$vars" ;; *) vars_status="WARNING: Multiple conflicting vars files!" esac @@ -81,7 +81,7 @@ A list of commands is shown below: CA_subject=" CA subject: ${CA_subject#subject=}" CA_status="${CA_status}${NL}${CA_subject}" else - CA_status=" CA status: CA has not been built." + CA_status=" CA status: CA has not been built" fi # Print details @@ -1131,6 +1131,7 @@ verify_ssl_lib() { # Run once only [ "$verify_ssl_lib_ok" ] && return verify_ssl_lib_ok=1 + unset -v openssl_v3 # redirect std-err, ignore missing ssl/openssl.cnf val="$( @@ -1169,8 +1170,13 @@ $error_msg" 2) no_password='-nodes' ;; 3) case "$ssl_lib" in - openssl) no_password='-noenc' ;; - libressl) no_password='-nodes' ;; + openssl) + openssl_v3=1 + no_password='-noenc' + ;; + libressl) + no_password='-nodes' + ;; *) die "Unexpected SSL library: $ssl_lib" esac ;; @@ -3715,7 +3721,7 @@ export_pkcs() { shift [ "$1" ] || user_error "\ -Unable to export p12: incorrect command syntax. +Unable to export '$pkcs_type': incorrect command syntax. Run easyrsa without commands for usage and command help." short_name="$1" @@ -3729,36 +3735,121 @@ Run easyrsa without commands for usage and command help." cipher=-aes256 want_ca=1 want_key=1 - unset -v pkcs_friendly_name + unset -v nokeys friendly_name while [ "$1" ]; do case "$1" in - noca) want_ca="" ;; - nokey) want_key="" ;; + noca) + want_ca="" + ;; + nokey) + want_key="" + # Undocumented OpenSSL feature: option + # -nokeys will ignore missing -inkey file + # No doubt, the reason for the extra -inkey + nokeys=-nokeys + ;; nopass) [ "$prohibit_no_pass" ] || EASYRSA_NO_PASS=1 ;; - usefn) pkcs_friendly_name="$short_name" ;; + usefn) + friendly_name="$short_name" + ;; *) warn "Ignoring unknown command option: '$1'" esac shift done - pkcs_certfile_path= + # Required options - PKCS, rhymes with mess + case "$pkcs_type" in + p12|p7) + : # ok + ;; + p8|p1) + want_key=1 + ;; + *) die "Unknown PKCS type: $pkcs_type" + esac + + # Check for CA, if required if [ "$want_ca" ]; then - verify_file x509 "$crt_ca" || user_error "\ -Unable to include CA cert in the $pkcs_type output. + case "$pkcs_type" in + p12|p7) + # verify_ca_init() here, otherwise not required + if verify_ca_init test; then + : # ok + else + warn "\ Missing CA file expected at: -* $crt_ca +* $crt_ca" + confirm "\ + Continue without CA certificate (EG: option 'noca') ? " yes " +Your PKI does not include a CA certificate. +You can export your user certificate to a $pkcs_type file +but it will not include the CA." + + # --batch mode does not allow + # on-the-fly command changes + if [ "$EASYRSA_BATCH" ]; then + die "export-$pkcs_type: Missing CA" + fi + want_ca="" + fi + ;; + p8|p1) + : # Not required + ;; + *) die "Unknown PKCS type: $pkcs_type" + esac + fi -Try 'noca' option.)" - pkcs_certfile_path="$crt_ca" + # Check for key, if required + if [ "$want_key" ]; then + if [ -e "$key_in" ]; then + : #ok + else + case "$pkcs_type" in + p12) + warn "\ +Missing key expected at: +* $key_in" + confirm "\ + Continue without Private key (EG: option 'nokey') ? " yes " +Your PKI does not include a Private key for '$short_name'. +You can export your user certificate to a '$pkcs_type' file +but it will not include the Private key." + + # --batch mode does not allow + # on-the-fly command changes + if [ "$EASYRSA_BATCH" ]; then + die "export-$pkcs_type: Missing key" + fi + nokeys=-nokeys + ;; + p8|p1) + user_error "Private key required." + ;; + p7) + : # Not required + ;; + *) die "Unknown PKCS type: $pkcs_type" + esac + fi fi - # input files must exist - verify_file x509 "$crt_in" || user_error "\ -Unable to export $pkcs_type for short name '$short_name'. -Missing cert expected at: -* $crt_in" + # Check for certificate, if required + if [ -e "$crt_in" ]; then + : # ok + else + case "$pkcs_type" in + p12|p7) + user_error "Certificate required." + ;; + p8|p1) + : # Not required + ;; + *) die "Unknown PKCS type: $pkcs_type" + esac + fi # For 'nopass' PKCS requires an explicit empty password if [ "$EASYRSA_NO_PASS" ]; then @@ -3767,27 +3858,18 @@ Missing cert expected at: unset -v cipher # pkcs#1 only fi + # Complete export case "$pkcs_type" in p12) pkcs_out="$EASYRSA_PKI/private/$short_name.p12" - if [ "$want_key" ]; then - [ -e "$key_in" ] || user_error "\ -Unable to export p12 for short name '$short_name'. -Missing key expected at: -* $key_in - -if you want a p12 without the private key, use 'nokey' option." - else - nokeys=1 - fi - # export the p12: - easyrsa_openssl pkcs12 -in "$crt_in" -inkey "$key_in" \ - -export -out "$pkcs_out" \ - ${nokeys:+ -nokeys} \ - ${pkcs_certfile_path:+ -certfile "$pkcs_certfile_path"} \ - ${pkcs_friendly_name:+ -name "$pkcs_friendly_name"} \ + easyrsa_openssl pkcs12 -export \ + -inkey "$key_in" -in "$crt_in" \ + -out "$pkcs_out" \ + ${nokeys} \ + ${want_ca:+ -certfile "$crt_ca"} \ + ${friendly_name:+ -name "$friendly_name"} \ ${EASYRSA_PASSIN:+ -passin "$EASYRSA_PASSIN"} \ ${EASYRSA_PASSOUT:+ -passout "$EASYRSA_PASSOUT"} \ || die "Failed to export PKCS#12" @@ -3796,28 +3878,43 @@ if you want a p12 without the private key, use 'nokey' option." pkcs_out="$EASYRSA_PKI/issued/$short_name.p7b" # export the p7: - easyrsa_openssl crl2pkcs7 -nocrl -certfile "$crt_in" \ + easyrsa_openssl crl2pkcs7 -nocrl \ + -certfile "$crt_in" \ -out "$pkcs_out" \ - ${pkcs_certfile_path:+ -certfile "$pkcs_certfile_path"} \ + ${want_ca:+ -certfile "$crt_ca"} \ || die "Failed to export PKCS#7" ;; p8) pkcs_out="$EASYRSA_PKI/private/$short_name.p8" # export the p8: - easyrsa_openssl pkcs8 -in "$key_in" -topk8 \ + easyrsa_openssl pkcs8 -topk8 \ + -in "$key_in" \ -out "$pkcs_out" \ ${EASYRSA_PASSIN:+ -passin "$EASYRSA_PASSIN"} \ ${EASYRSA_PASSOUT:+ -passout "$EASYRSA_PASSOUT"} \ || die "Failed to export PKCS#8" - ;; + ;; p1) pkcs_out="$EASYRSA_PKI/private/$short_name.p1" + # OpenSSLv3 requires -legacy for PKCS#1 + # Otherwise, OpenSSLv3 outputs PKCS#8 + [ "$verify_ssl_lib_ok" ] || \ + die "export_pkcs.p1: verify_ssl_lib_ok FAIL" + + if [ "$openssl_v3" ]; then + legacy=-legacy + else + unset -v legacy + fi + # export the p1: - easyrsa_openssl rsa -in "$key_in" \ + easyrsa_openssl rsa \ + -in "$key_in" \ -out "$pkcs_out" \ - ${cipher:+ "$cipher"} \ + ${legacy} \ + ${cipher} \ ${EASYRSA_PASSIN:+ -passin "$EASYRSA_PASSIN"} \ ${EASYRSA_PASSOUT:+ -passout "$EASYRSA_PASSOUT"} \ || die "Failed to export PKCS#1" @@ -6994,7 +7091,7 @@ case "$cmd" in require_pki=1 case "$cmd" in gen-req|gen-dh|build-ca|show-req| \ - make-safe-ssl) + make-safe-ssl|export-p*) unset -v require_ca ;; *) @@ -7009,6 +7106,7 @@ vars_setup mutual_exclusions # Hand off to the function responsible +# ONLY verify_working_env() for valid commands case "$cmd" in init-pki|clean-all) verify_working_env From e60b5e2f5ffa22e31276f7807b809d3e8de72c4a Mon Sep 17 00:00:00 2001 From: Richard T Bonhomme Date: Tue, 25 Jul 2023 17:10:46 +0100 Subject: [PATCH 2/3] Export PKCS: Rename variable $short_name to $file_name_base Signed-off-by: Richard T Bonhomme --- easyrsa3/easyrsa | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/easyrsa3/easyrsa b/easyrsa3/easyrsa index ca544c6f4..b9b7788b2 100755 --- a/easyrsa3/easyrsa +++ b/easyrsa3/easyrsa @@ -3724,11 +3724,11 @@ export_pkcs() { Unable to export '$pkcs_type': incorrect command syntax. Run easyrsa without commands for usage and command help." - short_name="$1" + file_name_base="$1" shift - crt_in="$EASYRSA_PKI/issued/$short_name.crt" - key_in="$EASYRSA_PKI/private/$short_name.key" + crt_in="$EASYRSA_PKI/issued/$file_name_base.crt" + key_in="$EASYRSA_PKI/private/$file_name_base.key" crt_ca="$EASYRSA_PKI/ca.crt" # opts support @@ -3752,7 +3752,7 @@ Run easyrsa without commands for usage and command help." [ "$prohibit_no_pass" ] || EASYRSA_NO_PASS=1 ;; usefn) - friendly_name="$short_name" + friendly_name="$file_name_base" ;; *) warn "Ignoring unknown command option: '$1'" esac @@ -3814,7 +3814,7 @@ Missing key expected at: * $key_in" confirm "\ Continue without Private key (EG: option 'nokey') ? " yes " -Your PKI does not include a Private key for '$short_name'. +Your PKI does not include a Private key for '$file_name_base'. You can export your user certificate to a '$pkcs_type' file but it will not include the Private key." @@ -3861,7 +3861,7 @@ but it will not include the Private key." # Complete export case "$pkcs_type" in p12) - pkcs_out="$EASYRSA_PKI/private/$short_name.p12" + pkcs_out="$EASYRSA_PKI/private/$file_name_base.p12" # export the p12: easyrsa_openssl pkcs12 -export \ @@ -3875,7 +3875,7 @@ but it will not include the Private key." || die "Failed to export PKCS#12" ;; p7) - pkcs_out="$EASYRSA_PKI/issued/$short_name.p7b" + pkcs_out="$EASYRSA_PKI/issued/$file_name_base.p7b" # export the p7: easyrsa_openssl crl2pkcs7 -nocrl \ @@ -3885,7 +3885,7 @@ but it will not include the Private key." || die "Failed to export PKCS#7" ;; p8) - pkcs_out="$EASYRSA_PKI/private/$short_name.p8" + pkcs_out="$EASYRSA_PKI/private/$file_name_base.p8" # export the p8: easyrsa_openssl pkcs8 -topk8 \ @@ -3896,7 +3896,7 @@ but it will not include the Private key." || die "Failed to export PKCS#8" ;; p1) - pkcs_out="$EASYRSA_PKI/private/$short_name.p1" + pkcs_out="$EASYRSA_PKI/private/$file_name_base.p1" # OpenSSLv3 requires -legacy for PKCS#1 # Otherwise, OpenSSLv3 outputs PKCS#8 From ef793f16298999e83c59a0a0d5421eef16288c91 Mon Sep 17 00:00:00 2001 From: Richard T Bonhomme Date: Tue, 25 Jul 2023 20:06:34 +0100 Subject: [PATCH 3/3] Export PKCS: Improve user messages, re-arrange p12 command Re-arranging the p12 command to follow the standard: - In file - out file Followed by - Conditional: -nokeys - Unconditional: -inkey file This is a reminder that '-inkey' is subordinate to '-nokeys' but is ALWAYS required. Signed-off-by: Richard T Bonhomme --- easyrsa3/easyrsa | 35 ++++++++++++++++++++--------------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/easyrsa3/easyrsa b/easyrsa3/easyrsa index b9b7788b2..55fd56346 100755 --- a/easyrsa3/easyrsa +++ b/easyrsa3/easyrsa @@ -3779,13 +3779,13 @@ Run easyrsa without commands for usage and command help." : # ok else warn "\ -Missing CA file expected at: +Missing CA Certificate, expected at: * $crt_ca" - confirm "\ - Continue without CA certificate (EG: option 'noca') ? " yes " -Your PKI does not include a CA certificate. -You can export your user certificate to a $pkcs_type file -but it will not include the CA." + confirm " + Continue without CA Certificate (EG: option 'noca') ? " yes " +Your PKI does not include a CA Certificate. +You can export your User Certificate to a $pkcs_type file +but the CA Certificate will not be included." # --batch mode does not allow # on-the-fly command changes @@ -3810,13 +3810,13 @@ but it will not include the CA." case "$pkcs_type" in p12) warn "\ -Missing key expected at: +Missing Private Key, expected at: * $key_in" - confirm "\ - Continue without Private key (EG: option 'nokey') ? " yes " -Your PKI does not include a Private key for '$file_name_base'. -You can export your user certificate to a '$pkcs_type' file -but it will not include the Private key." + confirm " + Continue without Private Key (EG: option 'nokey') ? " yes " +Your PKI does not include a Private Key for '$file_name_base'. +You can export your User Certificate to a '$pkcs_type' file +but the Private Key will not be included." # --batch mode does not allow # on-the-fly command changes @@ -3826,7 +3826,9 @@ but it will not include the Private key." nokeys=-nokeys ;; p8|p1) - user_error "Private key required." + user_error "\ +Missing Private Key, expected at: +* $key_in" ;; p7) : # Not required @@ -3842,7 +3844,9 @@ but it will not include the Private key." else case "$pkcs_type" in p12|p7) - user_error "Certificate required." + user_error "\ +Missing User Certificate, expected at: +* $crt_in" ;; p8|p1) : # Not required @@ -3865,9 +3869,10 @@ but it will not include the Private key." # export the p12: easyrsa_openssl pkcs12 -export \ - -inkey "$key_in" -in "$crt_in" \ + -in "$crt_in" \ -out "$pkcs_out" \ ${nokeys} \ + -inkey "$key_in" \ ${want_ca:+ -certfile "$crt_ca"} \ ${friendly_name:+ -name "$friendly_name"} \ ${EASYRSA_PASSIN:+ -passin "$EASYRSA_PASSIN"} \