6132 lines
156 KiB
Plaintext
6132 lines
156 KiB
Plaintext
|
#!/bin/sh
|
||
|
|
||
|
# Easy-RSA 3 -- A Shell-based CA Utility
|
||
|
#
|
||
|
# Copyright (C) 2024 - The Open-Source OpenVPN development community.
|
||
|
# A full list of contributors can be found on Github at:
|
||
|
# https://github.com/OpenVPN/easy-rsa/graphs/contributors
|
||
|
#
|
||
|
# This code released under version 2 of the GNU GPL; see COPYING
|
||
|
# and the Licensing/ directory of this project for full licensing
|
||
|
# details.
|
||
|
|
||
|
# Help/usage output to stdout
|
||
|
usage() {
|
||
|
# command help:
|
||
|
information "
|
||
|
Easy-RSA 3 usage and overview
|
||
|
|
||
|
$easyrsa_help_title
|
||
|
|
||
|
To get detailed usage and help for a command, use:
|
||
|
./easyrsa help COMMAND
|
||
|
|
||
|
For a list of global-options, use:
|
||
|
./easyrsa help options
|
||
|
|
||
|
For a list of utility commands, use:
|
||
|
./easyrsa help util
|
||
|
|
||
|
A list of commands is shown below:
|
||
|
init-pki [ cmd-opts ]
|
||
|
self-sign-server <file_name_base> [ cmd-opts ]
|
||
|
self-sign-client <file_name_base> [ cmd-opts ]
|
||
|
build-ca [ cmd-opts ]
|
||
|
gen-dh
|
||
|
gen-req <file_name_base> [ cmd-opts ]
|
||
|
sign-req <type> <file_name_base> [ cmd-opts ]
|
||
|
build-client-full <file_name_base> [ cmd-opts ]
|
||
|
build-server-full <file_name_base> [ cmd-opts ]
|
||
|
build-serverClient-full <file_name_base> [ cmd-opts ]
|
||
|
inline <file_name_base>
|
||
|
renew <file_name_base>
|
||
|
revoke <file_name_base> [ cmd-opts ]
|
||
|
expire <file_name_base>
|
||
|
revoke-expired <file_name_base> [ cmd-opts ]
|
||
|
revoke-renewed <file_name_base> [ cmd-opts ]
|
||
|
gen-crl
|
||
|
update-db
|
||
|
show-req <file_name_base> [ cmd-opts ]
|
||
|
show-cert <file_name_base> [ cmd-opts ]
|
||
|
show-ca [ cmd-opts ]
|
||
|
show-crl
|
||
|
verify-cert <file_name_base>
|
||
|
import-req <request_file_path> <short_name_base>
|
||
|
export-p1 <file_name_base> [ cmd-opts ]
|
||
|
export-p7 <file_name_base> [ cmd-opts ]
|
||
|
export-p8 <file_name_base> [ cmd-opts ]
|
||
|
export-p12 <file_name_base> [ cmd-opts ]
|
||
|
set-pass <file_name_base> [ cmd-opts ]
|
||
|
gen-tls-auth-key / gen-tls-crypt-key
|
||
|
write <type> [ cmd-opts ]"
|
||
|
|
||
|
# collect/show dir status:
|
||
|
text_only=1
|
||
|
work_dir="${EASYRSA:-undefined}"
|
||
|
pki_dir="${EASYRSA_PKI:-undefined}"
|
||
|
|
||
|
# check for vars changing PKI unexpectedly!
|
||
|
if [ "$invalid_vars" ]; then
|
||
|
ivmsg="
|
||
|
*WARNING*: \
|
||
|
Invalid vars setting for EASYRSA and/or EASYRSA_PKI${NL}"
|
||
|
else
|
||
|
unset -v ivmsg
|
||
|
fi
|
||
|
|
||
|
# Print details
|
||
|
information "
|
||
|
DIRECTORY STATUS (commands would take effect on these locations)
|
||
|
EASYRSA: $work_dir
|
||
|
PKI: $pki_dir
|
||
|
vars-file: ${EASYRSA_VARS_FILE:-Missing or undefined}${ivmsg}"
|
||
|
|
||
|
# CA Status
|
||
|
if verify_ca_init test; then
|
||
|
if [ -z "$EASYRSA_SILENT" ]; then
|
||
|
# Show SSL output directly, with easyrsa header
|
||
|
printf '%s' " CA status: OK${NL}${NL} "
|
||
|
"$EASYRSA_OPENSSL" x509 -in "$EASYRSA_PKI/ca.crt" \
|
||
|
-noout -subject -nameopt utf8,multiline
|
||
|
print "" # for a clean line
|
||
|
fi
|
||
|
else
|
||
|
information " CA status: CA has not been built${NL}"
|
||
|
fi
|
||
|
|
||
|
# verbose info
|
||
|
verbose "ssl-cnf: ${EASYRSA_SSL_CONF:-built-in}"
|
||
|
verbose "x509-types: ${EASYRSA_EXT_DIR:-built-in}"
|
||
|
if [ -d "$EASYRSA_TEMP_DIR" ]; then
|
||
|
verbose "temp-dir: Found: $EASYRSA_TEMP_DIR"
|
||
|
else
|
||
|
verbose "temp-dir: Missing: ${EASYRSA_TEMP_DIR:-undefined}"
|
||
|
fi
|
||
|
} # => usage()
|
||
|
|
||
|
# Detailed command help
|
||
|
# When called with no args, calls usage(),
|
||
|
# otherwise shows help for a command
|
||
|
# Please maintain strict indentation rules.
|
||
|
# Commands are TAB indented, while text is SPACE indented.
|
||
|
# 'case' indentation is minimalistic.
|
||
|
cmd_help() {
|
||
|
easyrsa_help_title="\
|
||
|
Usage: easyrsa [ OPTIONS.. ] <COMMAND> <TARGET> [ cmd-opts.. ]"
|
||
|
unset -v text err_text opts text_only
|
||
|
|
||
|
case "$1" in
|
||
|
init-pki|clean-all)
|
||
|
text="
|
||
|
* init-pki [ cmd-opts ]
|
||
|
|
||
|
Removes & re-initializes the PKI directory for a new PKI"
|
||
|
|
||
|
opts="
|
||
|
* hard - Recursively delete the ENTIRE PKI directory (default).
|
||
|
* soft - Keep the named PKI directory and PKI 'vars' file intact.
|
||
|
Also keep the current Request files,
|
||
|
to be signed by a new CA (Partial CA renewal)."
|
||
|
;;
|
||
|
self-sign*)
|
||
|
text="
|
||
|
* self-sign-server|self-sign-client <file_name_base> [ cmd-opts ]
|
||
|
|
||
|
Creates a new self-signed server|client key pair"
|
||
|
|
||
|
opts="
|
||
|
* nopass - Do not encrypt the private key (Default: encrypted)
|
||
|
(Equivalent to global option '--nopass|--no-pass')"
|
||
|
;;
|
||
|
build-ca)
|
||
|
text="
|
||
|
* build-ca [ cmd-opts ]
|
||
|
|
||
|
Creates a new CA"
|
||
|
|
||
|
opts="
|
||
|
* raw-ca - ONLY use SSL binary to input CA password
|
||
|
raw (Equivalent to global option '--raw-ca')
|
||
|
|
||
|
* nopass - Do not encrypt the private key (Default: encrypted)
|
||
|
(Equivalent to global option '--nopass|--no-pass')
|
||
|
|
||
|
* subca - Create an intermediate CA keypair and request
|
||
|
intca (default is a root CA)"
|
||
|
;;
|
||
|
gen-dh)
|
||
|
text="
|
||
|
* gen-dh
|
||
|
|
||
|
Generates DH (Diffie-Hellman) parameters file"
|
||
|
;;
|
||
|
gen-req)
|
||
|
text="
|
||
|
* gen-req <file_name_base> [ cmd-opts ]
|
||
|
|
||
|
Generate a standalone-private-key and certificate-signing-request
|
||
|
|
||
|
This request is suitable for sending to a remote CA for signing."
|
||
|
|
||
|
opts="
|
||
|
* nopass - Do not encrypt the private key (Default: encrypted)
|
||
|
(Equivalent to global option '--nopass|--no-pass')
|
||
|
* text - Include certificate text in request"
|
||
|
;;
|
||
|
sign|sign-req)
|
||
|
text="
|
||
|
* sign-req <type> <file_name_base> [ cmd-opts ]
|
||
|
|
||
|
Sign a certificate request of the defined type.
|
||
|
|
||
|
<type> must be a known type.
|
||
|
eg: 'client', 'server', 'serverClient', 'ca' or a user-added type.
|
||
|
All supported types are listed in the x509-types directory.
|
||
|
|
||
|
This request file must exist in the reqs/ dir and have a .req file
|
||
|
extension. See 'import-req' for importing from other sources."
|
||
|
opts="
|
||
|
* newsubj - Replace subject. See 'help subject'.
|
||
|
* preserve - Use the DN-field order of the CSR not the CA."
|
||
|
;;
|
||
|
build|build-client-full|build-server-full|build-serverClient-full)
|
||
|
text="
|
||
|
* build-client-full <file_name_base> [ cmd-opts ]
|
||
|
* build-server-full <file_name_base> [ cmd-opts ]
|
||
|
* build-serverClient-full <file_name_base> [ cmd-opts ]
|
||
|
|
||
|
Generate a keypair and sign locally.
|
||
|
|
||
|
This mode uses the <file_name_base> as the X509 commonName."
|
||
|
|
||
|
opts="
|
||
|
* nopass - Do not encrypt the private key (Default: encrypted)
|
||
|
(Equivalent to global option '--nopass|--no-pass')"
|
||
|
;;
|
||
|
inline)
|
||
|
text="
|
||
|
* inline <file_name_base>
|
||
|
|
||
|
Create inline file for <file_name_base>."
|
||
|
;;
|
||
|
revoke*)
|
||
|
text="
|
||
|
* revoke <file_name_base> [ reason ]
|
||
|
* revoke-expired <file_name_base> [ reason ]
|
||
|
* revoke-renewed <file_name_base> [ reason ]
|
||
|
|
||
|
Revoke a certificate specified by the <file_name_base>,
|
||
|
with an optional revocation [ reason ].
|
||
|
|
||
|
Commands 'revoke-expired' and 'revoke-renewed' are functionally
|
||
|
equivalent to 'revoke', however, they are used to revoke certificates
|
||
|
which have been either 'expired' or 'renewed' by EasyRSA commands."
|
||
|
opts="
|
||
|
* [ reason ]${NL}
|
||
|
Values accepted for option [ reason ]:${NL}
|
||
|
us | uns* | unspecified
|
||
|
kc | key* | keyCompromise
|
||
|
cc | ca* | CACompromise
|
||
|
ac | aff* | affiliationChanged
|
||
|
ss | sup* | superseded
|
||
|
co | ces* | cessationOfOperation
|
||
|
ch | cer* | certificateHold"
|
||
|
;;
|
||
|
expire)
|
||
|
text="
|
||
|
* expire <file_name_base>
|
||
|
|
||
|
Move a certificate specified by <file_name_base>
|
||
|
to the 'pki/expired' directory.
|
||
|
|
||
|
Allows an existing request to be signed again."
|
||
|
;;
|
||
|
renew)
|
||
|
text="
|
||
|
* renew <file_name_base>
|
||
|
|
||
|
Renew a certificate specified by <file_name_base>"
|
||
|
;;
|
||
|
gen-crl)
|
||
|
text="
|
||
|
* gen-crl
|
||
|
|
||
|
Generate a certificate revocation list [CRL]"
|
||
|
;;
|
||
|
update-db)
|
||
|
text="
|
||
|
* update-db
|
||
|
|
||
|
Update the index.txt database
|
||
|
|
||
|
This command will use the system time to update the status of
|
||
|
issued certificates."
|
||
|
;;
|
||
|
show-req|show-cert)
|
||
|
text="
|
||
|
* show-req <file_name_base> [ cmd-opts ]
|
||
|
* show-cert <file_name_base> [ cmd-opts ]
|
||
|
|
||
|
Shows details of the req or cert referenced by <file_name_base>
|
||
|
|
||
|
Human-readable output is shown, including any requested cert
|
||
|
options when showing a request."
|
||
|
|
||
|
opts="
|
||
|
* full - show full req/cert info, including pubkey/sig data"
|
||
|
;;
|
||
|
show-ca)
|
||
|
text="
|
||
|
* show-ca [ cmd-opts ]
|
||
|
|
||
|
Shows details of the Certificate Authority [CA] certificate
|
||
|
|
||
|
Human-readable output is shown."
|
||
|
|
||
|
opts="
|
||
|
* full - show full CA info, including pubkey/sig data"
|
||
|
;;
|
||
|
show-crl)
|
||
|
text="
|
||
|
* show-crl
|
||
|
|
||
|
Shows details of the current certificate revocation list (CRL)
|
||
|
|
||
|
Human-readable output is shown."
|
||
|
;;
|
||
|
verify|verify-cert)
|
||
|
text="
|
||
|
* verify-cert <file_name_base> [ cmd-opts ]
|
||
|
|
||
|
Verify certificate against CA
|
||
|
|
||
|
Returns the current validity of the certificate."
|
||
|
|
||
|
opts="
|
||
|
* batch - On failure to verify, return error (1) to caller"
|
||
|
;;
|
||
|
import-req)
|
||
|
text="
|
||
|
* import-req <request_file_path> <short_name_base>
|
||
|
|
||
|
Import a certificate request from a file
|
||
|
|
||
|
This will copy the specified file into the reqs/ dir in
|
||
|
preparation for signing.
|
||
|
|
||
|
The <short_name_base> is the <file_name_base> to create.
|
||
|
|
||
|
Example usage:
|
||
|
import-req /some/where/bob_request.req bob"
|
||
|
;;
|
||
|
export-p12)
|
||
|
text="
|
||
|
* export-p12 <file_name_base> [ cmd-opts ]
|
||
|
|
||
|
Export a PKCS#12 file with the keypair,
|
||
|
specified by <file_name_base>"
|
||
|
|
||
|
opts="
|
||
|
* nopass - Do not encrypt the private key (Default: encrypted)
|
||
|
(Equivalent to global option '--nopass|--no-pass')
|
||
|
* noca - Do not include the ca.crt file in the PKCS12 output
|
||
|
* nokey - Do not include the private key in the PKCS12 output
|
||
|
* nofn - Do not set 'friendlyName'
|
||
|
For more, see: 'easyrsa help friendly'
|
||
|
* legacy - Use legacy algorithm: RC2_CBC or 3DES_CBC + MAC: SHA1
|
||
|
(Default algorithm: AES-256-CBC + MAC: SHA256)"
|
||
|
;;
|
||
|
friendly)
|
||
|
text_only=1
|
||
|
text="
|
||
|
* export-p12: Internal file label 'friendlyName'
|
||
|
|
||
|
The 'friendlyname' is always set to the file-name-base.
|
||
|
|
||
|
An alternate friendlyName can be configured by using:
|
||
|
* Global option '--usefn=<friendlyName>'
|
||
|
|
||
|
Fallback to previous behavior can be configured by using:
|
||
|
* Command option 'nofn' ('friendlyname' will not be set)"
|
||
|
;;
|
||
|
export-p7)
|
||
|
text="
|
||
|
* export-p7 <file_name_base> [ cmd-opts ]
|
||
|
|
||
|
Export a PKCS#7 file with the pubkey,
|
||
|
specified by <file_name_base>"
|
||
|
|
||
|
opts="
|
||
|
* noca - Do not include the ca.crt file in the PKCS7 output"
|
||
|
;;
|
||
|
export-p8)
|
||
|
text="
|
||
|
* export-p8 <file_name_base> [ cmd-opts ]
|
||
|
|
||
|
Export a PKCS#8 file with the private key,
|
||
|
specified by <file_name_base>"
|
||
|
|
||
|
opts="
|
||
|
* nopass - Do not encrypt the private key (Default: encrypted)
|
||
|
(Equivalent to global option '--nopass|--no-pass')"
|
||
|
;;
|
||
|
export-p1)
|
||
|
text="
|
||
|
* export-p1 <file_name_base> [ cmd-opts ]
|
||
|
|
||
|
Export a PKCS#1 (RSA format) file with the pubkey,
|
||
|
specified by <file_name_base>"
|
||
|
|
||
|
opts="
|
||
|
* nopass - Do not encrypt the private key (Default: encrypted)
|
||
|
(Equivalent to global option '--nopass|--no-pass')"
|
||
|
;;
|
||
|
set-pass|set-ed-pass|set-rsa-pass|set-ec-pass)
|
||
|
text="
|
||
|
* set-pass <file_name_base> [ cmd-opts ]
|
||
|
|
||
|
Set a new passphrase for the private key specified by <file_name_base>
|
||
|
|
||
|
DEPRECATED: 'set-rsa-pass' and 'set-ec-pass'"
|
||
|
|
||
|
opts="
|
||
|
* nopass - Do not encrypt the private key (Default: encrypted)
|
||
|
(Equivalent to global option '--nopass|--no-pass')
|
||
|
* file - (Advanced) Treat the file as a raw path, not a short-name"
|
||
|
;;
|
||
|
write)
|
||
|
text="
|
||
|
* write <type> [<filename>] ['overwrite']
|
||
|
|
||
|
Write <type> data to stdout or <filename>
|
||
|
|
||
|
Types:
|
||
|
* ssl-cnf - Write EasyRSA SSL config file.
|
||
|
* safe-cnf - Write expanded EasyRSA SSL config file for LibreSSL.
|
||
|
* COMMON|ca|server|serverClient|client|codeSigning|email|kdc
|
||
|
- Write x509-type <type> file.
|
||
|
* legacy - Write ALL support files (above) to the PKI directory.
|
||
|
Will create '\$EASYRSA_PKI/x509-types' directory.
|
||
|
* legacy-hard
|
||
|
- Same as 'legacy' plus OVER-WRITE files.
|
||
|
* vars - Write vars.example file."
|
||
|
|
||
|
opts="
|
||
|
* filename - If <filename> is specified then it is the output
|
||
|
is directed to the named file.
|
||
|
Otherwise, the data is sent to stdout
|
||
|
* overwrite - Overwrite the <filename>.
|
||
|
<filename> is always preserved without 'overwrite'."
|
||
|
;;
|
||
|
--san|--subject-alt-name|altname|subjectaltname|san)
|
||
|
text_only=1
|
||
|
text="
|
||
|
* Global Option: --subject-alt-name=SAN_FORMAT_STRING
|
||
|
|
||
|
This global option adds a subjectAltName to the request or issued
|
||
|
certificate. It MUST be in a valid format accepted by openssl or
|
||
|
req/cert generation will fail. NOTE: --san can be specified more
|
||
|
than once on the command line.
|
||
|
|
||
|
The following two command line examples are equivalent:
|
||
|
1. --san=DNS:server1,DNS:serverA,IP:10.0.0.1
|
||
|
2. --san=DNS:server1 --san=DNS:serverA --san=IP:10.0.0.1
|
||
|
|
||
|
Examples of the SAN_FORMAT_STRING shown below:
|
||
|
|
||
|
* DNS:alternate.example.net
|
||
|
* DNS:primary.example.net,DNS:alternate.example.net
|
||
|
* IP:203.0.113.29
|
||
|
* email:alternate@example.net"
|
||
|
;;
|
||
|
--copy-ext|copy-ext|copyext)
|
||
|
text_only=1
|
||
|
text="
|
||
|
* Global Option: How to use --copy-ext and --san=<SAN>
|
||
|
|
||
|
These are the only commands that support --copy-ext and/or --san.
|
||
|
|
||
|
Command 'gen-req':
|
||
|
--san: Add SAN extension to the request file.
|
||
|
|
||
|
Command 'sign-req':
|
||
|
--copy-ext: Copy all request extensions to the signed certificate.
|
||
|
--san: Over write the request SAN with option SAN.
|
||
|
|
||
|
Command 'build-*-full':
|
||
|
--copy-ext: Always enabled.
|
||
|
--san: Add SAN extension to the request and signed certificate.
|
||
|
|
||
|
See 'help san' for option --san full syntax."
|
||
|
;;
|
||
|
--days|days)
|
||
|
text_only=1
|
||
|
text="
|
||
|
* Global Option: --days=DAYS
|
||
|
|
||
|
This global option is an alias for one of the following:
|
||
|
* Expiry days for a new CA.
|
||
|
eg: '--days=3650 build-ca'
|
||
|
* Expiry days for new/renewed certificate.
|
||
|
eg: '--days=1095 renew server'
|
||
|
* Expiry days for certificate revocation list.
|
||
|
eg: '--days=180 gen-crl'
|
||
|
* Cutoff days for command: show-expire.
|
||
|
eg: '--days=90 show-expire'"
|
||
|
;;
|
||
|
--new-subj*|new-subj*|newsubj*|subject)
|
||
|
text_only=1
|
||
|
text="
|
||
|
* Global Option: --new-subject=<SUBJECT>
|
||
|
|
||
|
This global option is used to set the new certificate subject,
|
||
|
when signing a new certificate
|
||
|
|
||
|
* REQUIRES Command option: 'newsubj', for command 'sign-req'
|
||
|
|
||
|
Using command 'sign-req', add command option 'newsubj',
|
||
|
to FORCE the --new-subject to be used.
|
||
|
|
||
|
Example:
|
||
|
--new-subject='/CN=foo' sign-req client bar newsubj
|
||
|
|
||
|
See OpenSSL command 'ca', option -subj, for full details."
|
||
|
;;
|
||
|
tool*|util*|more)
|
||
|
# Test features
|
||
|
text_only=1
|
||
|
text="
|
||
|
NOTE:
|
||
|
These commands are safe to test and will NOT effect your PKI.
|
||
|
|
||
|
Check <SERIAL> number is unique:
|
||
|
serial|check-serial <SERIAL>
|
||
|
|
||
|
Display DN of request or certificate: <form> = req|x509
|
||
|
display-dn <form> <DIR/FILE_NAME>
|
||
|
|
||
|
Display EKU of certificate:
|
||
|
show-eku <file_name_base>|<DIR/FILE_NAME>
|
||
|
|
||
|
Generate random hex:
|
||
|
rand <decimal_number>
|
||
|
|
||
|
These commands require easyrsa-tools.lib to be installed:
|
||
|
|
||
|
show-expire <file_name_base> (Optional)
|
||
|
show-revoke <file_name_base> (Optional)
|
||
|
show-renew <file_name_base> (Optional)"
|
||
|
;;
|
||
|
gen-tls*)
|
||
|
text_only=1
|
||
|
text="
|
||
|
Generate TLS keys for use with OpenVPN:
|
||
|
|
||
|
gen-tls-auth-key : Generate OpenVPN TLS-AUTH key
|
||
|
gen-tls-crypt-key : Generate OpenVPN TLS-CRYPT-V1 key (Preferred)
|
||
|
|
||
|
Only ONE TLS key is allowed to exist. (pki/private/easyrsa-tls.key)
|
||
|
This TLS key will be automatically added to inline files."
|
||
|
;;
|
||
|
opts|options)
|
||
|
opt_usage
|
||
|
cleanup ok
|
||
|
;;
|
||
|
"")
|
||
|
usage
|
||
|
cleanup ok
|
||
|
;;
|
||
|
*)
|
||
|
err_text="
|
||
|
Unknown command: '$1' \
|
||
|
(try without commands for a list of commands)"
|
||
|
easyrsa_exit_with_error=1
|
||
|
esac
|
||
|
|
||
|
if [ "$err_text" ]; then
|
||
|
print "$easyrsa_help_title"
|
||
|
print "${err_text}"
|
||
|
else
|
||
|
# display the help text
|
||
|
print "$easyrsa_help_title"
|
||
|
[ "$text" ] && print "$text"
|
||
|
|
||
|
if [ "$text_only" ]; then
|
||
|
: # ok - No opts message required
|
||
|
else
|
||
|
print "
|
||
|
Available command options [ cmd-opts ]:
|
||
|
${opts:-
|
||
|
* No supported command options}"
|
||
|
fi
|
||
|
fi
|
||
|
print
|
||
|
} # => cmd_help()
|
||
|
|
||
|
# Options usage
|
||
|
opt_usage() {
|
||
|
text_only=1
|
||
|
information "
|
||
|
Easy-RSA Global Option Flags
|
||
|
|
||
|
The following global-options may be provided before the command.
|
||
|
Options specified at runtime override env-vars and any 'vars'
|
||
|
file in use.
|
||
|
|
||
|
Unless noted, non-empty values to options are mandatory.
|
||
|
|
||
|
General options:
|
||
|
|
||
|
--version : Prints EasyRSA version and build information
|
||
|
--batch : Set automatic (no-prompts when possible) mode
|
||
|
--silent|-s : Disable all warnings, notices and information
|
||
|
--sbatch : Combined --silent and --batch operating mode
|
||
|
--silent-ssl|-S : Silence SSL output (Requires batch mode)
|
||
|
|
||
|
--nopass|no-pass: Do not use passwords
|
||
|
Can NOT be used with --passin or --passout
|
||
|
--passin=ARG : Set -passin ARG for openssl (eg: pass:xEasyRSAy)
|
||
|
--passout=ARG : Set -passout ARG for openssl (eg: pass:xEasyRSAy)
|
||
|
--raw-ca : Build CA with password via RAW SSL input
|
||
|
|
||
|
--vars=FILE : Define a specific 'vars' file to use for Easy-RSA config
|
||
|
(Default vars file is in the current working directory)
|
||
|
--pki=DIR : Declare the PKI directory
|
||
|
(Default PKI directory is sub-directory 'pki')
|
||
|
See Advanced.md for in depth usage.
|
||
|
|
||
|
--ssl-conf=FILE : Define a specific OpenSSL config file for Easy-RSA to use
|
||
|
(Default config file is in the EasyRSA PKI directory)
|
||
|
--force-safe-ssl: Always generate a safe SSL config file
|
||
|
(Default: Generate Safe SSL config once per instance)
|
||
|
|
||
|
--tools=FILE : Declare the full easyrsa-tools.lib file-name
|
||
|
--tmp-dir=DIR : Declare the temporary directory
|
||
|
(Default temporary directory is the EasyRSA PKI directory)
|
||
|
--keep-tmp=NAME : Keep the original temporary session by name: NAME
|
||
|
NAME is a sub-directory of the dir declared by --tmp-dir
|
||
|
This option ALWAYS over-writes a sub-dir of the same name.
|
||
|
|
||
|
Certificate & Request options: (these impact cert/req field values)
|
||
|
|
||
|
--notext|no-text: Create certificates without human readable text
|
||
|
--days=# : Sets the signing validity to the specified number of days
|
||
|
Applies to other commands. For details, see: 'help days'
|
||
|
--startdate=DATE: Sets the SSL option '-startdate' (Format 'YYYYMMDDhhmmssZ')
|
||
|
--enddate=DATE : Sets the SSL option '-enddate' (Format 'YYYYMMDDhhmmssZ')
|
||
|
|
||
|
--digest=ALG : Digest to use in the requests & certificates
|
||
|
--keysize=# : Size in bits of keypair to generate (RSA Only)
|
||
|
--use-algo=ALG : Crypto alg to use: choose rsa (default), ec or ed
|
||
|
--curve=NAME : For elliptic curve, sets the named curve
|
||
|
(Default: algo ec: secp384r1, algo ed: ed25519)
|
||
|
|
||
|
--subca-len=# : Path length of signed intermediate CA certificates
|
||
|
--copy-ext : Copy included request X509 extensions (namely subjAltName)
|
||
|
For more info, see: 'easyrsa help copyext'
|
||
|
|
||
|
--san|--subject-alt-name=SUBJECT_ALT_NAME
|
||
|
: Add a subjectAltName. Can be used multiple times.
|
||
|
For more info and syntax, see: 'easyrsa help altname'
|
||
|
--auto-san : Use commonName as subjectAltName: 'DNS:commonName'
|
||
|
If commonName is 'n.n.n.n' then set 'IP:commonName'
|
||
|
|
||
|
--san-crit : Mark X509v3 subjectAltName as critical
|
||
|
--bc-crit : Add X509 'basicContraints = critical' attribute.
|
||
|
--ku-crit : Add X509 'keyUsage = critical' attribute.
|
||
|
--eku-crit : Add X509 'extendedKeyUsage = critical' attribute.
|
||
|
|
||
|
--new-subject='SUBJECT'
|
||
|
: Specify a new subject field to sign a request with.
|
||
|
For more info and syntax, see: 'easyrsa help subject'
|
||
|
|
||
|
--usefn=NAME : export-p12, set 'friendlyName' to NAME
|
||
|
For more, see: 'easyrsa help friendly'
|
||
|
|
||
|
Distinguished Name mode:
|
||
|
|
||
|
--dn-mode=MODE : Distinguished Name mode to use 'cn_only' (Default) or 'org'
|
||
|
|
||
|
--req-cn=NAME : Request commonName
|
||
|
|
||
|
Distinguished Name Organizational options: (only used with '--dn-mode=org')
|
||
|
--req-c=CC : Country code (2-letters)
|
||
|
--req-st=NAME : State/Province
|
||
|
--req-city=NAME : City/Locality
|
||
|
--req-org=NAME : Organization
|
||
|
--req-email=NAME : Email addresses
|
||
|
--req-ou=NAME : Organizational Unit
|
||
|
--req-serial=VALUE : Entity serial number (Only used when declared)
|
||
|
|
||
|
Deprecated features:
|
||
|
|
||
|
--ns-cert : Include deprecated Netscape extensions
|
||
|
--ns-comment=COMMENT : Include deprecated Netscape comment (may be blank)"
|
||
|
} # => opt_usage()
|
||
|
|
||
|
# Wrapper around printf - clobber print since it's not POSIX anyway
|
||
|
# print() is used internally, so MUST NOT be silenced.
|
||
|
# shellcheck disable=SC1117 # printf format - print()
|
||
|
print() {
|
||
|
printf '%s\n' "$*"
|
||
|
} # => print()
|
||
|
|
||
|
# Exit fatally with a message to stderr
|
||
|
# present even with EASYRSA_BATCH as these are fatal problems
|
||
|
die() {
|
||
|
print "
|
||
|
Easy-RSA error:
|
||
|
|
||
|
$*${NL}"
|
||
|
|
||
|
# error_info is for hard-to-spot errors!
|
||
|
if [ "$error_info" ]; then
|
||
|
print " * $cmd: ${error_info}${NL}"
|
||
|
fi
|
||
|
|
||
|
# show host info
|
||
|
show_host
|
||
|
|
||
|
# exit to cleanup()
|
||
|
exit "${2:-1}"
|
||
|
} # => die()
|
||
|
|
||
|
# User errors, less noise than die()
|
||
|
user_error() {
|
||
|
print "
|
||
|
EasyRSA version $EASYRSA_version
|
||
|
|
||
|
Error
|
||
|
-----
|
||
|
$*${NL}"
|
||
|
|
||
|
easyrsa_exit_with_error=1
|
||
|
cleanup
|
||
|
} # => user_error()
|
||
|
|
||
|
# verbose information
|
||
|
verbose() {
|
||
|
[ "$EASYRSA_VERBOSE" ] || return 0
|
||
|
print " # $*"
|
||
|
} # => verbose()
|
||
|
|
||
|
# non-fatal warning output
|
||
|
warn() {
|
||
|
[ "$EASYRSA_SILENT" ] && return
|
||
|
print "
|
||
|
WARNING
|
||
|
=======
|
||
|
$*${NL}"
|
||
|
} # => warn()
|
||
|
|
||
|
# informational notices to stdout
|
||
|
notice() {
|
||
|
[ "$EASYRSA_SILENT" ] && return
|
||
|
print "
|
||
|
Notice
|
||
|
------
|
||
|
$*${NL}"
|
||
|
} # => notice()
|
||
|
|
||
|
# Helpful information
|
||
|
information() {
|
||
|
[ "$EASYRSA_SILENT" ] && return
|
||
|
print "$*"
|
||
|
} # => information()
|
||
|
|
||
|
# intent confirmation helper func
|
||
|
# returns without prompting in EASYRSA_BATCH
|
||
|
confirm() {
|
||
|
[ "$EASYRSA_BATCH" ] && return
|
||
|
prompt="$1"
|
||
|
value="$2"
|
||
|
msg="$3"
|
||
|
input=""
|
||
|
print "\
|
||
|
$msg
|
||
|
|
||
|
Type the word '$value' to continue, or any other input to abort."
|
||
|
printf %s " $prompt"
|
||
|
# shellcheck disable=SC2162 # read without -r - confirm()
|
||
|
read input
|
||
|
printf '\n'
|
||
|
[ "$input" = "$value" ] && return
|
||
|
easyrsa_exit_with_error=1
|
||
|
unset -v EASYRSA_SILENT
|
||
|
notice "Aborting without confirmation."
|
||
|
cleanup
|
||
|
} # => confirm()
|
||
|
|
||
|
# Generate random hex
|
||
|
easyrsa_random() {
|
||
|
case "$1" in
|
||
|
*[!1234567890]*|0*|"")
|
||
|
die "easyrsa_random - input"
|
||
|
esac
|
||
|
|
||
|
if rand_hex="$(
|
||
|
"$EASYRSA_OPENSSL" rand -hex "$1" 2>/dev/null
|
||
|
)"
|
||
|
then
|
||
|
if [ "$2" ]; then
|
||
|
force_set_var "$2" "$rand_hex"
|
||
|
else
|
||
|
print "$rand_hex"
|
||
|
fi
|
||
|
unset -v rand_hex
|
||
|
return 0
|
||
|
fi
|
||
|
|
||
|
die "easyrsa_random failed"
|
||
|
} # => easyrsa_random()
|
||
|
|
||
|
# Create session directory atomically or fail
|
||
|
secure_session() {
|
||
|
# Session must not be defined
|
||
|
[ -z "$secured_session" ] || die "session overload"
|
||
|
|
||
|
# Temporary directory must exist
|
||
|
[ -d "$EASYRSA_TEMP_DIR" ] || die "\
|
||
|
secure_session - Missing temporary directory:
|
||
|
* $EASYRSA_TEMP_DIR"
|
||
|
|
||
|
for i in 1 2 3; do
|
||
|
session=
|
||
|
easyrsa_random 4 session
|
||
|
secured_session="${EASYRSA_TEMP_DIR}/${session}"
|
||
|
|
||
|
# atomic:
|
||
|
# ONLY effects Windows 11 "broken" mkdir.exe
|
||
|
# The procedure now is a "poor man's" version
|
||
|
# of an atomic directory creation call.
|
||
|
# The "race condition" still exists but is minimized.
|
||
|
# What remains is equivalent to 32bit hash collision.
|
||
|
[ -d "$secured_session" ] && continue
|
||
|
if mkdir "$secured_session"; then
|
||
|
# Check mkdir.exe has created the directory
|
||
|
[ -d "$secured_session" ] || \
|
||
|
die "secure_session - mkdir FAILED"
|
||
|
[ -f "$secured_session"/temp.0.1 ] && \
|
||
|
die "secure_session - temp-file EXISTS"
|
||
|
|
||
|
# New session requires safe-ssl conf
|
||
|
unset -v session OPENSSL_CONF \
|
||
|
EASYRSA_SSL_CONF safe_ssl_cnf_tmp \
|
||
|
working_safe_ssl_conf working_safe_org_conf
|
||
|
|
||
|
easyrsa_err_log="$secured_session/error.log"
|
||
|
verbose "\
|
||
|
secure_session: CREATED: $secured_session"
|
||
|
return
|
||
|
fi
|
||
|
done
|
||
|
die "secure_session failed"
|
||
|
} # => secure_session()
|
||
|
|
||
|
# Remove secure session
|
||
|
remove_secure_session() {
|
||
|
[ -d "$secured_session" ] || return 0
|
||
|
if rm -rf "$secured_session"; then
|
||
|
verbose "\
|
||
|
remove_secure_session: DELETED: $secured_session"
|
||
|
unset -v secured_session OPENSSL_CONF \
|
||
|
EASYRSA_SSL_CONF safe_ssl_cnf_tmp \
|
||
|
working_safe_ssl_conf working_safe_org_conf
|
||
|
return
|
||
|
fi
|
||
|
die "remove_secure_session Failed: $secured_session"
|
||
|
} # => remove_secure_session()
|
||
|
|
||
|
# 'mkdir' wrapper, broken by win11, which fails without error
|
||
|
easyrsa_mkdir() {
|
||
|
[ "$2" ] && die "easyrsa_mkdir - excess input"
|
||
|
[ "$1" ] || die "easyrsa_mkdir - input"
|
||
|
[ -d "$1" ] && return
|
||
|
mkdir "$1" 2>/dev/null
|
||
|
[ -d "$1" ] && return
|
||
|
die "easyrsa_mkdir - FAIL: $1"
|
||
|
} # => easyrsa_mkdir()
|
||
|
|
||
|
# Create temp-file atomically or fail
|
||
|
# WARNING: Running easyrsa_openssl in a subshell
|
||
|
# will hide error message and verbose messages
|
||
|
# from easyrsa_mktemp()
|
||
|
easyrsa_mktemp() {
|
||
|
if [ -z "$1" ] || [ "$2" ]; then
|
||
|
die "easyrsa_mktemp - input error"
|
||
|
fi
|
||
|
|
||
|
# session directory must exist
|
||
|
[ -d "$secured_session" ] || die "\
|
||
|
easyrsa_mktemp - Temporary session undefined (--tmp-dir)"
|
||
|
|
||
|
# Force noclobber
|
||
|
if [ "$easyrsa_host_os" = win ]; then
|
||
|
set -o noclobber
|
||
|
else
|
||
|
set -C
|
||
|
fi
|
||
|
|
||
|
# Assign internal temp-file name
|
||
|
tmp_fname="${secured_session}/temp.${mktemp_counter}"
|
||
|
|
||
|
# Create shotfile
|
||
|
for shot_try in x y z; do
|
||
|
shotfile="${tmp_fname}.${shot_try}"
|
||
|
if [ -f "$shotfile" ]; then
|
||
|
verbose "\
|
||
|
easyrsa_mktemp: shotfile EXISTS: $shotfile"
|
||
|
continue
|
||
|
else
|
||
|
printf "" > "$shotfile" || die "\
|
||
|
easyrsa_mktemp: create shotfile failed (1) $1"
|
||
|
|
||
|
# Create temp-file or die
|
||
|
# subshells do not update mktemp_counter,
|
||
|
# which is why this extension is required.
|
||
|
# Current max required is 1 attempt
|
||
|
for ext_try in 1 2 3 4 5 6 7 8 9; do
|
||
|
want_tmp_file="${tmp_fname}.${ext_try}"
|
||
|
|
||
|
# Warn to error log file for max reached
|
||
|
if [ "$EASYRSA_MAX_TEMP" -lt "$ext_try" ]; then
|
||
|
print "\
|
||
|
Max temp-file limit $ext_try, hit for: $1" > "$easyrsa_err_log"
|
||
|
die "EASYRSA_MAX_TEMP exceeded"
|
||
|
fi
|
||
|
|
||
|
if [ -f "$want_tmp_file" ]; then
|
||
|
verbose "\
|
||
|
easyrsa_mktemp: temp-file EXISTS: $want_tmp_file"
|
||
|
continue
|
||
|
else
|
||
|
# atomic:
|
||
|
if mv "$shotfile" "$want_tmp_file"; then
|
||
|
# Assign external temp-file name
|
||
|
if force_set_var "$1" "$want_tmp_file"
|
||
|
then
|
||
|
verbose "\
|
||
|
: easyrsa_mktemp: $1 OK: $want_tmp_file"
|
||
|
|
||
|
# unset noclobber
|
||
|
if [ "$easyrsa_host_os" = win ]; then
|
||
|
set +o noclobber
|
||
|
else
|
||
|
set +C
|
||
|
fi
|
||
|
|
||
|
# Update counter
|
||
|
mktemp_counter="$((mktemp_counter+1))"
|
||
|
|
||
|
unset -v tmp_fname \
|
||
|
shotfile shot_try \
|
||
|
want_tmp_file ext_try
|
||
|
return
|
||
|
else
|
||
|
die "\
|
||
|
easyrsa_mktemp - force_set_var $1 failed"
|
||
|
fi
|
||
|
fi
|
||
|
fi
|
||
|
done
|
||
|
fi
|
||
|
done
|
||
|
|
||
|
# unset noclobber
|
||
|
if [ "$easyrsa_host_os" = win ]; then
|
||
|
set +o noclobber
|
||
|
else
|
||
|
set +C
|
||
|
fi
|
||
|
|
||
|
# In case of subshell abuse, report to error log
|
||
|
err_msg="\
|
||
|
easyrsa_mktemp - failed for: $1 @ attempt=$ext_try
|
||
|
want_tmp_file: $want_tmp_file"
|
||
|
print "$err_msg" > "$easyrsa_err_log"
|
||
|
die "$err_msg"
|
||
|
} # => easyrsa_mktemp()
|
||
|
|
||
|
# remove temp files and do terminal cleanups
|
||
|
cleanup() {
|
||
|
# In case of subshell abuse, display error log file
|
||
|
if [ -f "$easyrsa_err_log" ]; then
|
||
|
print; cat "$easyrsa_err_log"; print
|
||
|
fi
|
||
|
|
||
|
# Remove redundant file: index.txt.attr
|
||
|
if [ -f "$EASYRSA_PKI"/index.txt.attr ]; then
|
||
|
rm -f "$EASYRSA_PKI"/index.txt.attr
|
||
|
verbose "cleanup: DELETED $EASYRSA_PKI/index.txt.attr"
|
||
|
fi
|
||
|
|
||
|
# undo changes BEFORE delete temp-dir
|
||
|
# Remove files when build_full()->sign_req() is interrupted
|
||
|
[ "$error_build_full_cleanup" ] && \
|
||
|
rm -f "$crt_out" "$req_out" "$key_out"
|
||
|
|
||
|
# Restore files when renew is interrupted
|
||
|
[ "$error_undo_renew_move" ] && renew_restore_move
|
||
|
|
||
|
# Remove temp-session or create temp-snapshot
|
||
|
if [ -d "$secured_session" ]; then
|
||
|
if [ "$EASYRSA_KEEP_TEMP" ]; then
|
||
|
# skip on black-listed directory names, with a warning
|
||
|
# Use '-e' for directory or file name
|
||
|
if [ -e "$EASYRSA_TEMP_DIR/$EASYRSA_KEEP_TEMP" ]
|
||
|
then
|
||
|
warn "\
|
||
|
Prohibited value for --keep-tmp: '$EASYRSA_KEEP_TEMP'
|
||
|
Temporary session not preserved."
|
||
|
else
|
||
|
# create temp-snapshot
|
||
|
keep_tmp="$EASYRSA_TEMP_DIR/tmp/$EASYRSA_KEEP_TEMP"
|
||
|
easyrsa_mkdir "$EASYRSA_TEMP_DIR"/tmp
|
||
|
easyrsa_mkdir "$keep_tmp"
|
||
|
rm -rf "$keep_tmp"
|
||
|
mv -f "$secured_session" "$keep_tmp"
|
||
|
information "Temp session preserved: $keep_tmp"
|
||
|
unset -v secured_session
|
||
|
fi
|
||
|
fi
|
||
|
|
||
|
# remove temp-session
|
||
|
remove_secure_session
|
||
|
verbose "mktemp_counter: $mktemp_counter uses"
|
||
|
fi
|
||
|
|
||
|
# When prompt is disabled then restore prompt
|
||
|
case "$prompt_restore" in
|
||
|
0) : ;; # Not required
|
||
|
1)
|
||
|
[ -t 1 ] && stty echo
|
||
|
[ "$EASYRSA_SILENT" ] || print
|
||
|
;;
|
||
|
2)
|
||
|
# shellcheck disable=SC3040 # POSIX set -o
|
||
|
set -o echo
|
||
|
[ "$EASYRSA_SILENT" ] || print
|
||
|
;;
|
||
|
*) warn "Unknown prompt_restore: '$prompt_restore'"
|
||
|
esac
|
||
|
|
||
|
# Clear traps
|
||
|
trap - 0 1 2 3 6 15
|
||
|
|
||
|
# Exit: Known errors
|
||
|
# -> confirm(): aborted
|
||
|
# -> verify_cert(): verify failed --batch mode
|
||
|
# -> check_serial_unique(): not unique --batch mode
|
||
|
# -> user_error(): User errors but not die()
|
||
|
if [ "$easyrsa_exit_with_error" ]; then
|
||
|
verbose "Exit: Known errors = true"
|
||
|
exit 1
|
||
|
elif [ "$1" = 2 ]; then
|
||
|
verbose "exit SIGINT = true"
|
||
|
kill -2 "$$" # Exit: SIGINT
|
||
|
elif [ "$1" = ok ]; then
|
||
|
verbose "Exit: Final Success = true"
|
||
|
exit 0 # Exit: Final Success
|
||
|
fi
|
||
|
|
||
|
# if 'cleanup' is called without 'ok' then an error occurred
|
||
|
verbose "Exit: Final Fail = true"
|
||
|
exit 1 # Exit: Final Fail, unknown error
|
||
|
} # => cleanup()
|
||
|
|
||
|
# Escape hazardous characters
|
||
|
# Auto-escape hazardous characters:
|
||
|
# '&' - Workaround 'sed' behavior
|
||
|
# '$' - Workaround 'easyrsa' based limitation
|
||
|
# This is required for all SSL libs, otherwise,
|
||
|
# there are unacceptable differences in behavior
|
||
|
escape_hazard() {
|
||
|
if [ "$EASYRSA_FORCE_SAFE_SSL" ]; then # Always run
|
||
|
verbose "escape_hazard: FORCED"
|
||
|
elif [ "$working_safe_org_conf" ]; then # Has run once
|
||
|
verbose "escape_hazard: BYPASSED"
|
||
|
return
|
||
|
else # Run once
|
||
|
verbose "escape_hazard: RUN-ONCE"
|
||
|
working_safe_org_conf=1 # Set run once
|
||
|
fi
|
||
|
|
||
|
# Assign temp-file
|
||
|
escape_hazard_tmp=""
|
||
|
easyrsa_mktemp escape_hazard_tmp || die \
|
||
|
"escape_hazard - easyrsa_mktemp escape_hazard_tmp"
|
||
|
|
||
|
# write org fields to org temp-file and escape '&' and '$'
|
||
|
print "\
|
||
|
export EASYRSA_REQ_COUNTRY=\"$EASYRSA_REQ_COUNTRY\"
|
||
|
export EASYRSA_REQ_PROVINCE=\"$EASYRSA_REQ_PROVINCE\"
|
||
|
export EASYRSA_REQ_CITY=\"$EASYRSA_REQ_CITY\"
|
||
|
export EASYRSA_REQ_ORG=\"$EASYRSA_REQ_ORG\"
|
||
|
export EASYRSA_REQ_OU=\"$EASYRSA_REQ_OU\"
|
||
|
export EASYRSA_REQ_EMAIL=\"$EASYRSA_REQ_EMAIL\"
|
||
|
export EASYRSA_REQ_SERIAL=\"$EASYRSA_REQ_SERIAL\"\
|
||
|
" | sed -e s\`'\&'\`'\\\&'\`g \
|
||
|
-e s\`'\$'\`'\\\$'\`g > "$escape_hazard_tmp" || \
|
||
|
die "escape_hazard - Failed to write temp-file"
|
||
|
|
||
|
# Reload fields from fully escaped temp-file
|
||
|
# shellcheck disable=1090 # Non-constant source
|
||
|
. "$escape_hazard_tmp"
|
||
|
verbose "escape_hazard: COMPLETED"
|
||
|
} # => escape_hazard()
|
||
|
|
||
|
# Replace environment variable names with current value
|
||
|
# and write to temp-file or return error from sed
|
||
|
expand_ssl_config() {
|
||
|
if [ "$EASYRSA_FORCE_SAFE_SSL" ]; then # Always run
|
||
|
verbose "expand_ssl_config: FORCED"
|
||
|
elif [ "$working_safe_ssl_conf" ]; then # Has run once
|
||
|
verbose "expand_ssl_config: BYPASSED"
|
||
|
return
|
||
|
elif [ "$ssl_lib" = libressl ]; then # LibreSSL Always run
|
||
|
verbose "expand_ssl_config: REQUIRED"
|
||
|
elif [ "$ssl_lib" = openssl ]; then # OpenSSL not required
|
||
|
verbose "expand_ssl_config: IGNORED"
|
||
|
return
|
||
|
else
|
||
|
die "expand_ssl_config: EXCEPTION" # do NOT Run
|
||
|
fi
|
||
|
|
||
|
# Set run once
|
||
|
working_safe_ssl_conf=1
|
||
|
verbose "expand_ssl_config: RUN-ONCE"
|
||
|
|
||
|
# Assign temp-file
|
||
|
safe_ssl_cnf_tmp=""
|
||
|
easyrsa_mktemp safe_ssl_cnf_tmp || die \
|
||
|
"expand_ssl_config - easyrsa_mktemp safe_ssl_cnf_tmp"
|
||
|
|
||
|
# Rewrite
|
||
|
# shellcheck disable=SC2016 # No expand ''
|
||
|
if sed \
|
||
|
\
|
||
|
-e s\`'$dir'\`\
|
||
|
\""$EASYRSA_PKI"\"\`g \
|
||
|
\
|
||
|
-e s\`'$ENV::EASYRSA_PKI'\`\
|
||
|
\""$EASYRSA_PKI"\"\`g \
|
||
|
\
|
||
|
-e s\`'$ENV::EASYRSA_CERT_EXPIRE'\`\
|
||
|
\""$EASYRSA_CERT_EXPIRE"\"\`g \
|
||
|
\
|
||
|
-e s\`'$ENV::EASYRSA_CRL_DAYS'\`\
|
||
|
\""$EASYRSA_CRL_DAYS"\"\`g \
|
||
|
\
|
||
|
-e s\`'$ENV::EASYRSA_DIGEST'\`\
|
||
|
\""$EASYRSA_DIGEST"\"\`g \
|
||
|
\
|
||
|
-e s\`'$ENV::EASYRSA_KEY_SIZE'\`\
|
||
|
\""$EASYRSA_KEY_SIZE"\"\`g \
|
||
|
\
|
||
|
-e s\`'$ENV::EASYRSA_DN'\`\
|
||
|
\""$EASYRSA_DN"\"\`g \
|
||
|
\
|
||
|
-e s\`'$ENV::EASYRSA_REQ_CN'\`\
|
||
|
\""$EASYRSA_REQ_CN"\"\`g \
|
||
|
\
|
||
|
-e s\`'$ENV::EASYRSA_REQ_COUNTRY'\`\
|
||
|
\""$EASYRSA_REQ_COUNTRY"\"\`g \
|
||
|
\
|
||
|
-e s\`'$ENV::EASYRSA_REQ_PROVINCE'\`\
|
||
|
\""$EASYRSA_REQ_PROVINCE"\"\`g \
|
||
|
\
|
||
|
-e s\`'$ENV::EASYRSA_REQ_CITY'\`\
|
||
|
\""$EASYRSA_REQ_CITY"\"\`g \
|
||
|
\
|
||
|
-e s\`'$ENV::EASYRSA_REQ_ORG'\`\
|
||
|
\""$EASYRSA_REQ_ORG"\"\`g \
|
||
|
\
|
||
|
-e s\`'$ENV::EASYRSA_REQ_OU'\`\
|
||
|
\""$EASYRSA_REQ_OU"\"\`g \
|
||
|
\
|
||
|
-e s\`'$ENV::EASYRSA_REQ_EMAIL'\`\
|
||
|
\""$EASYRSA_REQ_EMAIL"\"\`g \
|
||
|
\
|
||
|
-e s\`'$ENV::EASYRSA_REQ_SERIAL'\`\
|
||
|
\""$EASYRSA_REQ_SERIAL"\"\`g \
|
||
|
\
|
||
|
"$EASYRSA_SSL_CONF" > "$safe_ssl_cnf_tmp"
|
||
|
then
|
||
|
verbose "expand_ssl_config: via 'sed' COMPLETED"
|
||
|
else
|
||
|
return 1
|
||
|
fi
|
||
|
|
||
|
export EASYRSA_SSL_CONF="$safe_ssl_cnf_tmp"
|
||
|
verbose \
|
||
|
"expand_ssl_config: EASYRSA_SSL_CONF = $EASYRSA_SSL_CONF"
|
||
|
} # => expand_ssl_config()
|
||
|
|
||
|
# Easy-RSA meta-wrapper for SSL
|
||
|
# WARNING: Running easyrsa_openssl in a subshell
|
||
|
# will hide error message and verbose messages
|
||
|
easyrsa_openssl() {
|
||
|
openssl_command="$1"; shift
|
||
|
|
||
|
if [ "$EASYRSA_DEBUG" ]; then
|
||
|
verbose "= easyrsa_openssl - BEGIN $openssl_command $*"
|
||
|
else
|
||
|
verbose "= easyrsa_openssl - BEGIN $openssl_command"
|
||
|
fi
|
||
|
|
||
|
# Do not allow 'rand' here, see easyrsa_random()
|
||
|
case "$openssl_command" in
|
||
|
rand) die "easyrsa_openssl: Illegal SSL command: rand"
|
||
|
esac
|
||
|
|
||
|
# Use $EASYRSA_SSL_CONF (local) or $OPENSSL_CONF (global)
|
||
|
if [ -f "$EASYRSA_SSL_CONF" ]; then
|
||
|
export OPENSSL_CONF="$EASYRSA_SSL_CONF"
|
||
|
else
|
||
|
[ -f "$OPENSSL_CONF" ] || \
|
||
|
die "easyrsa_openssl - OPENSSL_CONF undefined"
|
||
|
fi
|
||
|
verbose "= easyrsa_openssl: OPENSSL_CONF = $OPENSSL_CONF"
|
||
|
|
||
|
# Exec SSL
|
||
|
if [ "$EASYRSA_SILENT_SSL" ] && [ "$EASYRSA_BATCH" ]
|
||
|
then
|
||
|
if "$EASYRSA_OPENSSL" "$openssl_command" "$@" \
|
||
|
2>/dev/null
|
||
|
then
|
||
|
verbose "= easyrsa_openssl - END $openssl_command"
|
||
|
return
|
||
|
fi
|
||
|
else
|
||
|
if "$EASYRSA_OPENSSL" "$openssl_command" "$@"
|
||
|
then
|
||
|
verbose "= easyrsa_openssl - END $openssl_command"
|
||
|
return
|
||
|
fi
|
||
|
fi
|
||
|
|
||
|
# Always fail here
|
||
|
die "\
|
||
|
easyrsa_openssl - Command has failed:
|
||
|
* $EASYRSA_OPENSSL $openssl_command $*"
|
||
|
} # => easyrsa_openssl()
|
||
|
|
||
|
# Verify the SSL library is functional
|
||
|
# and establish version dependencies
|
||
|
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="$(
|
||
|
"$EASYRSA_OPENSSL" version 2>/dev/null
|
||
|
)"
|
||
|
ssl_version="$val"
|
||
|
|
||
|
# SSL lib name
|
||
|
case "${val%% *}" in
|
||
|
OpenSSL)
|
||
|
ssl_lib=openssl
|
||
|
# Honor EASYRSA_FORCE_SAFE_SSL
|
||
|
if [ "$EASYRSA_FORCE_SAFE_SSL" ]; then
|
||
|
ssl_cnf_type=safe-cnf
|
||
|
else
|
||
|
ssl_cnf_type=ssl-cnf
|
||
|
fi
|
||
|
;;
|
||
|
LibreSSL)
|
||
|
ssl_lib=libressl
|
||
|
ssl_cnf_type=safe-cnf
|
||
|
;;
|
||
|
*)
|
||
|
error_msg="$("$EASYRSA_OPENSSL" version 2>&1)"
|
||
|
user_error "\
|
||
|
* OpenSSL must either exist in your PATH
|
||
|
or be defined in your vars file.
|
||
|
|
||
|
Invalid SSL output for 'version':
|
||
|
|
||
|
$error_msg"
|
||
|
esac
|
||
|
|
||
|
# Set SSL version dependent $no_password option
|
||
|
osslv_major="${val#* }"
|
||
|
osslv_major="${osslv_major%%.*}"
|
||
|
case "$osslv_major" in
|
||
|
1) no_password='-nodes' ;;
|
||
|
2) no_password='-nodes' ;;
|
||
|
3|4)
|
||
|
case "$ssl_lib" in
|
||
|
openssl)
|
||
|
openssl_v3=1
|
||
|
no_password='-noenc'
|
||
|
;;
|
||
|
libressl)
|
||
|
no_password='-nodes'
|
||
|
;;
|
||
|
*) die "Unexpected SSL library: $ssl_lib"
|
||
|
esac
|
||
|
;;
|
||
|
*) die "Unexpected SSL version: $osslv_major"
|
||
|
esac
|
||
|
|
||
|
# Message
|
||
|
verbose "verify_ssl_lib(): $ssl_version ($EASYRSA_OPENSSL)"
|
||
|
} # => verify_ssl_lib()
|
||
|
|
||
|
# Basic sanity-check of PKI init and complain if missing
|
||
|
verify_pki_init() {
|
||
|
help_note="\
|
||
|
Run easyrsa without commands for usage and command help."
|
||
|
|
||
|
# Check for defined EASYRSA_PKI
|
||
|
[ "$EASYRSA_PKI" ] || die "\
|
||
|
EASYRSA_PKI env-var undefined"
|
||
|
|
||
|
# check that the pki dir exists
|
||
|
[ -d "$EASYRSA_PKI" ] || user_error "\
|
||
|
EASYRSA_PKI does not exist (perhaps you need to run init-pki)?
|
||
|
Expected to find the EASYRSA_PKI at:
|
||
|
* $EASYRSA_PKI
|
||
|
|
||
|
$help_note"
|
||
|
|
||
|
# verify expected dirs present:
|
||
|
for i in private reqs; do
|
||
|
[ -d "$EASYRSA_PKI/$i" ] || user_error "\
|
||
|
Missing expected directory: $i
|
||
|
|
||
|
(perhaps you need to run init-pki?)
|
||
|
|
||
|
$help_note"
|
||
|
done
|
||
|
unset -v help_note
|
||
|
} # => verify_pki_init()
|
||
|
|
||
|
# Verify core CA files present
|
||
|
verify_ca_init() {
|
||
|
verify_ca_help_note="\
|
||
|
Run easyrsa without commands for usage and command help."
|
||
|
|
||
|
# Verify expected files are present.
|
||
|
# Allow files to be regular files (or symlinks),
|
||
|
# but also pipes, for flexibility with ca.key
|
||
|
for i in ca.crt private/ca.key index.txt serial; do
|
||
|
if [ ! -f "$EASYRSA_PKI/$i" ] && \
|
||
|
[ ! -p "$EASYRSA_PKI/$i" ]
|
||
|
then
|
||
|
# Used by usage() and export-p12/p7
|
||
|
[ "$1" = "test" ] && return 1
|
||
|
|
||
|
user_error "\
|
||
|
Missing expected CA file: $i
|
||
|
|
||
|
(perhaps you need to run build-ca?)
|
||
|
|
||
|
$verify_ca_help_note"
|
||
|
fi
|
||
|
done
|
||
|
|
||
|
# When operating in 'test' mode, return success.
|
||
|
# test callers don't care about CA-specific dir structure
|
||
|
[ "$1" = "test" ] && return 0
|
||
|
|
||
|
# verify expected CA-specific dirs:
|
||
|
for i in issued certs_by_serial; do
|
||
|
[ -d "$EASYRSA_PKI/$i" ] || user_error "\
|
||
|
Missing expected CA dir: $i
|
||
|
|
||
|
(perhaps you need to run build-ca?)
|
||
|
|
||
|
$verify_ca_help_note"
|
||
|
done
|
||
|
} # => verify_ca_init()
|
||
|
|
||
|
# init-pki backend:
|
||
|
init_pki() {
|
||
|
# Process command options
|
||
|
reset="hard"
|
||
|
while [ "$1" ]; do
|
||
|
case "$1" in
|
||
|
hard-reset|hard)
|
||
|
reset="hard"
|
||
|
confirm_msg=
|
||
|
;;
|
||
|
soft-reset|soft)
|
||
|
reset="soft"
|
||
|
confirm_msg='PARTIALLY '
|
||
|
;;
|
||
|
*) warn "Ignoring unknown command option: '$1'"
|
||
|
esac
|
||
|
shift
|
||
|
done
|
||
|
|
||
|
# EasyRSA will NOT do 'rm -rf /'
|
||
|
case "$EASYRSA_PKI" in
|
||
|
.|..|./|../|.//*|..//*|/|//*|\\|?:|'')
|
||
|
user_error "Invalid PKI: $EASYRSA_PKI"
|
||
|
esac
|
||
|
|
||
|
# If EASYRSA_PKI exists, confirm before deletion
|
||
|
if [ -d "$EASYRSA_PKI" ]; then
|
||
|
confirm "Confirm removal: " "yes" "
|
||
|
WARNING!!!
|
||
|
|
||
|
You are about to ${confirm_msg}remove the EASYRSA_PKI at:
|
||
|
* $EASYRSA_PKI
|
||
|
|
||
|
and initialize a fresh PKI here."
|
||
|
|
||
|
# now remove it:
|
||
|
case "$reset" in
|
||
|
hard)
|
||
|
# Promote use of 'init-pki soft':
|
||
|
confirm "
|
||
|
WARNING: COMPLETELY DESTROY current PKI (NOT recommended) ?
|
||
|
|
||
|
[yes/NO]: " yes "\
|
||
|
******************************************
|
||
|
* SECOND WARNING - STOP - SECOND WARNING *
|
||
|
******************************************
|
||
|
|
||
|
To keep your current 'pki/vars' settings use 'init-pki soft'.
|
||
|
To keep your current Request files use 'init-pki soft'
|
||
|
The Requests can then be signed by a new CA (Partial CA renewal)
|
||
|
To keep your current Easy-RSA TLS Key use 'init-pki soft'
|
||
|
This private key file is in use by your current VPN.
|
||
|
|
||
|
** USE OF 'init-pki soft' IS RECOMMENDED **${NL}"
|
||
|
|
||
|
# # # shellcheck disable=SC2115 # Use "${var:?}"
|
||
|
rm -rf "$EASYRSA_PKI" || \
|
||
|
die "init-pki hard reset failed."
|
||
|
;;
|
||
|
soft)
|
||
|
# There is no unit test for a soft reset
|
||
|
# Save existing TLS key
|
||
|
tls_key_file="$EASYRSA_PKI"/private/easyrsa-tls.key
|
||
|
old_tls_key_file="$EASYRSA_PKI"/easyrsa-keepsafe-tls.key
|
||
|
|
||
|
# If both keys exist then they must be the same
|
||
|
if [ -f "$old_tls_key_file" ]; then
|
||
|
if [ -f "$tls_key_file" ]; then
|
||
|
# Match by hash
|
||
|
tls_key_hash="$(
|
||
|
"$EASYRSA_OPENSSL" dgst -sha256 \
|
||
|
"$tls_key_file")"
|
||
|
tls_key_hash="${tls_key_hash##* }"
|
||
|
old_tls_key_hash="$(
|
||
|
"$EASYRSA_OPENSSL" dgst -sha256 \
|
||
|
"$old_tls_key_file")"
|
||
|
old_tls_key_hash="${old_tls_key_hash##* }"
|
||
|
[ "$tls_key_hash" = "$old_tls_key_hash" ] || \
|
||
|
user_error "\
|
||
|
Easy-RSA TLS Keys do not match, only ONE of these files is valid:
|
||
|
* $tls_key_file
|
||
|
* $old_tls_key_file
|
||
|
|
||
|
Please delete the key above that is no longer in use."
|
||
|
fi
|
||
|
fi
|
||
|
|
||
|
# Save existing TLS key
|
||
|
if [ -f "$tls_key_file" ]; then
|
||
|
tls_key_data="$(cat "$tls_key_file")"
|
||
|
else
|
||
|
tls_key_data=
|
||
|
fi
|
||
|
|
||
|
# Do NOT remove pki/reqs sub-dir, for "renew ca"
|
||
|
for i in ca.crt crl.pem \
|
||
|
issued private inline revoked renewed expired \
|
||
|
serial serial.old index.txt index.txt.old \
|
||
|
index.txt.attr index.txt.attr.old certs_by_serial
|
||
|
do
|
||
|
# # # shellcheck disable=SC2115 # Use "${var:?}"
|
||
|
target="$EASYRSA_PKI/$i"
|
||
|
if [ "${target%/*}" ]; then
|
||
|
rm -rf "$target" || \
|
||
|
die "init-pki soft reset(1) failed!"
|
||
|
else
|
||
|
die "init-pki soft reset(2) failed!"
|
||
|
fi
|
||
|
done
|
||
|
;;
|
||
|
*)
|
||
|
user_error "Unknown reset type: $reset"
|
||
|
esac
|
||
|
fi
|
||
|
|
||
|
# new dirs:
|
||
|
easyrsa_mkdir "$EASYRSA_PKI"
|
||
|
for i in issued private reqs; do
|
||
|
easyrsa_mkdir "${EASYRSA_PKI}/$i"
|
||
|
done
|
||
|
|
||
|
# If one existed then recreate old TLS key backup file
|
||
|
if [ "$tls_key_data" ]; then
|
||
|
header="# Easy-RSA TLS Key: $(date)${NL}# DO NOT DELETE"
|
||
|
printf '%s\n\n%s\n' "$header" "$tls_key_data" \
|
||
|
> "$old_tls_key_file"
|
||
|
tls_msg="${NL}
|
||
|
Previous Easy-RSA TLS key saved to:
|
||
|
* $old_tls_key_file${NL}"
|
||
|
else
|
||
|
# if an OLD TLS key still exists then notify user
|
||
|
if [ -f "$old_tls_key_file" ]; then
|
||
|
tls_msg="${NL}
|
||
|
Existing Easy-RSA TLS key preserved:
|
||
|
* $old_tls_key_file${NL}"
|
||
|
else
|
||
|
tls_msg=
|
||
|
fi
|
||
|
fi
|
||
|
|
||
|
# write pki/vars.example - no temp-file because no session
|
||
|
write_legacy_file_v2 \
|
||
|
vars "$EASYRSA_PKI"/vars.example overwrite || \
|
||
|
warn "init-pki - Failed to create vars.example"
|
||
|
|
||
|
# User notice
|
||
|
notice "\
|
||
|
'init-pki' complete; you may now create a CA or requests.
|
||
|
|
||
|
Your newly created PKI dir is:
|
||
|
* $EASYRSA_PKI"
|
||
|
|
||
|
# Select and show vars file
|
||
|
unset -v EASYRSA_VARS_FILE
|
||
|
select_vars
|
||
|
information "\
|
||
|
Using Easy-RSA configuration:
|
||
|
* ${EASYRSA_VARS_FILE:-undefined}${tls_msg}"
|
||
|
} # => init_pki()
|
||
|
|
||
|
# Find support files from various sources
|
||
|
# Declare in preferred order, first wins
|
||
|
# beaten by command line.
|
||
|
# If these files are not found here then they
|
||
|
# will be built on-demand by the selected command.
|
||
|
locate_support_files() {
|
||
|
# Set required sources
|
||
|
ssl_cnf_file='openssl-easyrsa.cnf'
|
||
|
x509_types_dir='x509-types'
|
||
|
easyrsa_tools='easyrsa-tools.lib'
|
||
|
|
||
|
# Find data-files
|
||
|
for area in \
|
||
|
"$EASYRSA_PKI" \
|
||
|
"$EASYRSA" \
|
||
|
"$PWD" \
|
||
|
"${0%/*}" \
|
||
|
'/usr/local/share/easy-rsa' \
|
||
|
'/usr/share/easy-rsa' \
|
||
|
'/etc/easy-rsa' \
|
||
|
# EOL
|
||
|
do
|
||
|
# Find x509-types
|
||
|
if [ -d "${area}/${x509_types_dir}" ]; then
|
||
|
set_var EASYRSA_EXT_DIR "${area}/${x509_types_dir}"
|
||
|
fi
|
||
|
|
||
|
# Find openssl-easyrsa.cnf
|
||
|
if [ -f "${area}/${ssl_cnf_file}" ]; then
|
||
|
set_var EASYRSA_SSL_CONF "${area}/${ssl_cnf_file}"
|
||
|
fi
|
||
|
|
||
|
# Find easyrsa-tools.lib
|
||
|
if [ -f "${area}/${easyrsa_tools}" ]; then
|
||
|
set_var EASYRSA_TOOLS_LIB "${area}/${easyrsa_tools}"
|
||
|
fi
|
||
|
done
|
||
|
|
||
|
verbose ": EASYRSA_EXT_DIR: ${EASYRSA_EXT_DIR:-built-in}"
|
||
|
verbose ": EASYRSA_SSL_CONF: ${EASYRSA_SSL_CONF:-built-in}"
|
||
|
verbose ": EASYRSA_TOOLS_LIB: ${EASYRSA_TOOLS_LIB:-undefined}"
|
||
|
verbose "locate_support_files: COMPLETED"
|
||
|
} # => locate_support_files()
|
||
|
|
||
|
# Disable terminal echo, if possible, otherwise warn
|
||
|
hide_read_pass() {
|
||
|
# 3040 - In POSIX sh, set option [name] is undefined
|
||
|
# 3045 - In POSIX sh, some-command-with-flag is undefined
|
||
|
# 3061 - In POSIX sh, read without a variable is undefined.
|
||
|
# shellcheck disable=SC3040,SC3045,SC3061
|
||
|
if stty -echo 2>/dev/null; then
|
||
|
prompt_restore=1
|
||
|
read -r "$@"
|
||
|
stty echo
|
||
|
elif (set +o echo 2>/dev/null); then
|
||
|
prompt_restore=2
|
||
|
set +o echo
|
||
|
read -r "$@"
|
||
|
set -o echo
|
||
|
elif (echo | read -r -s 2>/dev/null) ; then
|
||
|
read -r -s "$@"
|
||
|
else
|
||
|
warn "\
|
||
|
Could not disable echo. Password will be shown on screen!"
|
||
|
read -r "$@"
|
||
|
fi
|
||
|
prompt_restore=0
|
||
|
} # => hide_read_pass()
|
||
|
|
||
|
# Get passphrase
|
||
|
get_passphrase() {
|
||
|
t="$1"; shift || die "password malfunction"
|
||
|
while :; do
|
||
|
r=""
|
||
|
printf '\n%s' "$*"
|
||
|
hide_read_pass r
|
||
|
|
||
|
if [ "${#r}" -lt 4 ]; then
|
||
|
printf '\n%s\n' \
|
||
|
"Passphrase must be at least 4 characters!"
|
||
|
else
|
||
|
# shellcheck disable=SC2229 # does not read 't'
|
||
|
read -r "$t" <<- SECRET
|
||
|
$r
|
||
|
SECRET
|
||
|
|
||
|
unset -v r t
|
||
|
print
|
||
|
return 0
|
||
|
fi
|
||
|
done
|
||
|
} # => get_passphrase()
|
||
|
|
||
|
# build-ca backend:
|
||
|
build_ca() {
|
||
|
cipher="-aes256"
|
||
|
unset -v sub_ca date_stamp x509 error_info \
|
||
|
ca_password_via_cmdline
|
||
|
|
||
|
while [ "$1" ]; do
|
||
|
case "$1" in
|
||
|
intca|subca)
|
||
|
sub_ca=1
|
||
|
;;
|
||
|
nopass)
|
||
|
[ "$prohibit_no_pass" ] || EASYRSA_NO_PASS=1
|
||
|
;;
|
||
|
raw*)
|
||
|
EASYRSA_RAW_CA=1
|
||
|
;;
|
||
|
*) user_error "Unknown command option: '$1'"
|
||
|
esac
|
||
|
shift
|
||
|
done
|
||
|
|
||
|
out_key="$EASYRSA_PKI/private/ca.key"
|
||
|
# setup for an intermediate CA
|
||
|
if [ "$sub_ca" ]; then
|
||
|
# Generate a CSR
|
||
|
out_file="$EASYRSA_PKI/reqs/ca.req"
|
||
|
else
|
||
|
# Generate a certificate
|
||
|
out_file="$EASYRSA_PKI/ca.crt"
|
||
|
date_stamp=1
|
||
|
x509=1
|
||
|
fi
|
||
|
|
||
|
# RAW mode must take priority
|
||
|
if [ "$EASYRSA_RAW_CA" ]; then
|
||
|
unset -v EASYRSA_NO_PASS EASYRSA_PASSOUT EASYRSA_PASSIN
|
||
|
verbose "build-ca: CA password RAW method"
|
||
|
else
|
||
|
# If encrypted then create the CA key with AES256 cipher
|
||
|
if [ "$EASYRSA_NO_PASS" ]; then
|
||
|
unset -v cipher
|
||
|
else
|
||
|
unset -v no_password
|
||
|
fi
|
||
|
fi
|
||
|
|
||
|
# Test for existing CA, and complain if already present
|
||
|
if verify_ca_init test; then
|
||
|
user_error "\
|
||
|
Unable to create a CA as you already seem to have one set up.
|
||
|
If you intended to start a new CA, run init-pki first."
|
||
|
fi
|
||
|
|
||
|
# If a private key exists, an intermediate ca was created
|
||
|
# but not signed.
|
||
|
# Notify user and require a signed ca.crt or a init-pki:
|
||
|
if [ -f "$out_key" ]; then
|
||
|
user_error "\
|
||
|
A CA private key exists but no ca.crt is found in your PKI:
|
||
|
* $EASYRSA_PKI
|
||
|
|
||
|
Refusing to create a new CA as this would overwrite your
|
||
|
current CA. To start a new CA, run init-pki first."
|
||
|
fi
|
||
|
|
||
|
# create necessary dirs:
|
||
|
err_msg="\
|
||
|
Unable to create necessary PKI files (permissions?)"
|
||
|
|
||
|
easyrsa_mkdir "${EASYRSA_PKI}"/certs_by_serial
|
||
|
easyrsa_mkdir "${EASYRSA_PKI}"/revoked
|
||
|
easyrsa_mkdir "${EASYRSA_PKI}"/revoked/certs_by_serial
|
||
|
easyrsa_mkdir "${EASYRSA_PKI}"/revoked/private_by_serial
|
||
|
|
||
|
# create necessary files:
|
||
|
printf "" > \
|
||
|
"$EASYRSA_PKI/index.txt" || die "$err_msg"
|
||
|
printf '%s\n' "01" \
|
||
|
> "$EASYRSA_PKI/serial" || die "$err_msg"
|
||
|
unset -v err_msg
|
||
|
|
||
|
# If one exists then recreate TLS Key
|
||
|
tls_key_file="$EASYRSA_PKI"/private/easyrsa-tls.key
|
||
|
old_tls_key_file="$EASYRSA_PKI"/easyrsa-keepsafe-tls.key
|
||
|
if [ -f "$old_tls_key_file" ]; then
|
||
|
confirm "Re-install existing Easy-RSA TLS Key ? " yes "
|
||
|
An Easy-RSA TLS Key, saved by 'init-pki soft', has been found.
|
||
|
This TLS Key is in use by your VPN, it is recommended that you
|
||
|
re-install this TLS Key.
|
||
|
|
||
|
Note:
|
||
|
This is a private key and will NOT be added to new inline files.
|
||
|
|
||
|
To create a new Easy-RSA TLS Key, delete this old TLS Key above."
|
||
|
cp "$old_tls_key_file" "$tls_key_file" || \
|
||
|
warn "Failed to install TLS Key!"
|
||
|
tls_key_msg="${NL}
|
||
|
NOTICE: The previous Easy-RSA TLS Key has been installed:
|
||
|
* $tls_key_file
|
||
|
|
||
|
This TLS Key will NOT be added to new inline files. These new
|
||
|
inline files can then be easily distributed to your servers and
|
||
|
clients. The TLS Key that your servers and clients have previously
|
||
|
received, can be added to the inline file manually.
|
||
|
|
||
|
To re-enable automatically adding this TLS Key to inline files,
|
||
|
simply delete the backup TLS Key at:
|
||
|
* $old_tls_key_file
|
||
|
|
||
|
To create a new Easy-RSA TLS Key, delete both TLS Keys above."
|
||
|
else
|
||
|
tls_key_msg="${NL}
|
||
|
Create an OpenVPN TLS-AUTH|TLS-CRYPT-V1 key now: See 'help gen-tls'"
|
||
|
fi
|
||
|
|
||
|
# Set ssl batch mode, as required
|
||
|
[ "$EASYRSA_BATCH" ] && ssl_batch=1
|
||
|
|
||
|
# Default CA commonName
|
||
|
if [ "$EASYRSA_REQ_CN" = ChangeMe ]; then
|
||
|
if [ "$sub_ca" ]; then
|
||
|
export EASYRSA_REQ_CN="Easy-RSA Sub-CA"
|
||
|
else
|
||
|
export EASYRSA_REQ_CN="Easy-RSA CA"
|
||
|
fi
|
||
|
fi
|
||
|
|
||
|
# create local SSL cnf
|
||
|
write_easyrsa_ssl_cnf_tmp
|
||
|
|
||
|
# Assign cert and key temp files
|
||
|
out_key_tmp=""
|
||
|
easyrsa_mktemp out_key_tmp || \
|
||
|
die "build_ca - easyrsa_mktemp out_key_tmp"
|
||
|
out_file_tmp=""
|
||
|
easyrsa_mktemp out_file_tmp || \
|
||
|
die "build_ca - easyrsa_mktemp out_file_tmp"
|
||
|
|
||
|
# Get passphrase from user if necessary
|
||
|
if [ "$EASYRSA_RAW_CA" ]
|
||
|
then
|
||
|
# Passphrase will be provided
|
||
|
confirm "
|
||
|
Accept ? " yes "\
|
||
|
Raw CA mode
|
||
|
===========
|
||
|
|
||
|
CA password must be input THREE times:
|
||
|
|
||
|
1. Set the password.
|
||
|
2. Confirm the password.
|
||
|
3. Use the password. (Create the Root CA)"
|
||
|
|
||
|
elif [ "$EASYRSA_NO_PASS" ]
|
||
|
then
|
||
|
: # No passphrase required
|
||
|
|
||
|
elif [ "$EASYRSA_PASSOUT" ] && [ "$EASYRSA_PASSIN" ]
|
||
|
then
|
||
|
# passphrase defined on command line
|
||
|
# Both --passout and --passin
|
||
|
# must be defined for a CA with a password
|
||
|
ca_password_via_cmdline=1
|
||
|
|
||
|
else
|
||
|
# Assign passphrase vars
|
||
|
# Heed shellcheck SC2154
|
||
|
p=""
|
||
|
q=""
|
||
|
|
||
|
# Get passphrase p
|
||
|
get_passphrase p \
|
||
|
"Enter New CA Key Passphrase: "
|
||
|
|
||
|
# Confirm passphrase q
|
||
|
get_passphrase q \
|
||
|
"Confirm New CA Key Passphrase: "
|
||
|
|
||
|
# Validate passphrase
|
||
|
if [ "$p" ] && [ "$p" = "$q" ]; then
|
||
|
# CA password via temp-files
|
||
|
in_key_pass_tmp=""
|
||
|
easyrsa_mktemp in_key_pass_tmp || \
|
||
|
die "build_ca - in_key_pass_tmp"
|
||
|
out_key_pass_tmp=""
|
||
|
easyrsa_mktemp out_key_pass_tmp || \
|
||
|
die "build_ca - out_key_pass_tmp"
|
||
|
printf "%s" "$p" > "$in_key_pass_tmp" || \
|
||
|
die "in_key_pass_tmp: write"
|
||
|
printf "%s" "$p" > "$out_key_pass_tmp" || \
|
||
|
die "out_key_pass_tmp: write"
|
||
|
unset -v p q
|
||
|
else
|
||
|
unset -v p q
|
||
|
user_error "Passphrases do not match!"
|
||
|
fi
|
||
|
fi
|
||
|
|
||
|
# 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
|
||
|
|
||
|
# keyUsage critical
|
||
|
if [ "$EASYRSA_KU_CRIT" ]; then
|
||
|
crit_tmp=
|
||
|
easyrsa_mktemp crit_tmp || \
|
||
|
die "build-ca - easyrsa_mktemp KU crit_tmp"
|
||
|
|
||
|
add_critical_attrib keyUsage "$x509_type_file" \
|
||
|
"$crit_tmp" || die "build-ca - KU add_critical_attrib"
|
||
|
|
||
|
# Use the new tmp-file with critical attribute
|
||
|
x509_type_file="$crit_tmp"
|
||
|
verbose "build_ca: keyUsage critical OK"
|
||
|
fi
|
||
|
|
||
|
# basicConstraints critical
|
||
|
if [ "$EASYRSA_BC_CRIT" ]; then
|
||
|
crit_tmp=
|
||
|
easyrsa_mktemp crit_tmp || \
|
||
|
die "build-ca - easyrsa_mktemp BC crit_tmp"
|
||
|
|
||
|
add_critical_attrib basicConstraints "$x509_type_file" \
|
||
|
"$crit_tmp" || die "build-ca - BC add_critical_attrib"
|
||
|
|
||
|
# Use the new tmp-file with critical attribute
|
||
|
x509_type_file="$crit_tmp"
|
||
|
verbose "build_ca: basicConstraints 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 "build_ca - 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 "Copying X509_TYPES to config file failed"
|
||
|
verbose "build-ca: insert x509 and extensions OK"
|
||
|
|
||
|
# Use this new SSL config for the rest of this function
|
||
|
EASYRSA_SSL_CONF="$adjusted_ssl_cnf_tmp"
|
||
|
|
||
|
# Generate CA Key
|
||
|
case "$EASYRSA_ALGO" in
|
||
|
rsa)
|
||
|
easyrsa_openssl genpkey \
|
||
|
-algorithm "$EASYRSA_ALGO" \
|
||
|
-pkeyopt rsa_keygen_bits:"$EASYRSA_ALGO_PARAMS" \
|
||
|
-out "$out_key_tmp" \
|
||
|
${cipher:+ "$cipher"} \
|
||
|
${EASYRSA_PASSOUT:+ -pass "$EASYRSA_PASSOUT"} \
|
||
|
${out_key_pass_tmp:+ -pass file:"$out_key_pass_tmp"} \
|
||
|
|| die "Failed create CA private key"
|
||
|
;;
|
||
|
ec)
|
||
|
easyrsa_openssl genpkey \
|
||
|
-paramfile "$EASYRSA_ALGO_PARAMS" \
|
||
|
-out "$out_key_tmp" \
|
||
|
${cipher:+ "$cipher"} \
|
||
|
${EASYRSA_PASSOUT:+ -pass "$EASYRSA_PASSOUT"} \
|
||
|
${out_key_pass_tmp:+ -pass file:"$out_key_pass_tmp"} \
|
||
|
|| die "Failed create CA private key"
|
||
|
;;
|
||
|
ed)
|
||
|
easyrsa_openssl genpkey \
|
||
|
-algorithm "$EASYRSA_CURVE" \
|
||
|
-out "$out_key_tmp" \
|
||
|
${cipher:+ "$cipher"} \
|
||
|
${EASYRSA_PASSOUT:+ -pass "$EASYRSA_PASSOUT"} \
|
||
|
${out_key_pass_tmp:+ -pass file:"$out_key_pass_tmp"} \
|
||
|
|| die "Failed create CA private key"
|
||
|
;;
|
||
|
*) die "Unknown algorithm: $EASYRSA_ALGO"
|
||
|
esac
|
||
|
|
||
|
# verbose notice
|
||
|
if [ "$EASYRSA_RAW_CA" ]; then
|
||
|
verbose "\
|
||
|
build_ca: CA key password created via RAW"
|
||
|
else
|
||
|
if [ "$ca_password_via_cmdline" ]; then
|
||
|
verbose "\
|
||
|
build_ca: CA key password created via command options"
|
||
|
else
|
||
|
if [ "$EASYRSA_NO_PASS" ]; then
|
||
|
verbose "\
|
||
|
build_ca: CA key has no password"
|
||
|
else
|
||
|
verbose "\
|
||
|
build_ca: CA key password created via temp-files"
|
||
|
fi
|
||
|
fi
|
||
|
fi
|
||
|
|
||
|
# Generate the CA keypair:
|
||
|
easyrsa_openssl req -utf8 -new \
|
||
|
-key "$out_key_tmp" \
|
||
|
-out "$out_file_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"} \
|
||
|
${EASYRSA_PASSOUT:+ -passout "$EASYRSA_PASSOUT"} \
|
||
|
${in_key_pass_tmp:+ -passin file:"$in_key_pass_tmp"} \
|
||
|
${out_key_pass_tmp:+ -passout file:"$out_key_pass_tmp"} \
|
||
|
|| die "Failed to build the CA keypair"
|
||
|
|
||
|
# Move temp-files to target-files
|
||
|
mv "$out_key_tmp" "$out_key" || mv_temp_error=1
|
||
|
mv "$out_file_tmp" "$out_file" || mv_temp_error=1
|
||
|
if [ "$mv_temp_error" ]; then
|
||
|
rm -f "$out_key" "$out_file"
|
||
|
die "Failed to move new CA files."
|
||
|
fi
|
||
|
|
||
|
# Success messages
|
||
|
if [ "$sub_ca" ]; then
|
||
|
notice "\
|
||
|
Your intermediate CA request is at:
|
||
|
* $out_file
|
||
|
and now must be sent to your parent CA for signing.
|
||
|
|
||
|
Prior to signing operations, place your resulting Sub-CA cert at:
|
||
|
* $EASYRSA_PKI/ca.crt"
|
||
|
else
|
||
|
notice "\
|
||
|
CA creation complete. Your new CA certificate is at:
|
||
|
* $out_file${tls_key_msg}
|
||
|
|
||
|
Build-ca completed successfully."
|
||
|
fi
|
||
|
} # => build_ca()
|
||
|
|
||
|
# Build self signed key pair
|
||
|
self_sign() {
|
||
|
# Define x509 type
|
||
|
case "$1" in
|
||
|
server)
|
||
|
selfsign_eku=serverAuth
|
||
|
crt_type=self-signed-server
|
||
|
;;
|
||
|
client)
|
||
|
selfsign_eku=clientAuth
|
||
|
crt_type=self-signed-client
|
||
|
;;
|
||
|
*)
|
||
|
die "self_sign: Unknown EKU '$1'"
|
||
|
esac
|
||
|
shift
|
||
|
|
||
|
# pull $file_name_base
|
||
|
[ "$1" ] || user_error "\
|
||
|
Error: didn't find a file base name as the first argument.
|
||
|
Run easyrsa without commands for usage and command help."
|
||
|
|
||
|
file_name_base="$1"
|
||
|
shift
|
||
|
|
||
|
# Prohibit --req-cn
|
||
|
[ "$EASYRSA_REQ_CN" = ChangeMe ] || user_error "\
|
||
|
Option conflict --req-cn:
|
||
|
* '$cmd' does not support setting an external commonName"
|
||
|
|
||
|
# Enforce commonName
|
||
|
export EASYRSA_REQ_CN="$file_name_base"
|
||
|
|
||
|
# create local SSL cnf
|
||
|
write_easyrsa_ssl_cnf_tmp
|
||
|
|
||
|
# Refuse option as name
|
||
|
case "$file_name_base" in
|
||
|
nopass)
|
||
|
user_error "Refusing '$file_name_base' as name."
|
||
|
esac
|
||
|
|
||
|
# function opts support
|
||
|
while [ "$1" ]; do
|
||
|
case "$1" in
|
||
|
nopass)
|
||
|
[ "$prohibit_no_pass" ] || EASYRSA_NO_PASS=1
|
||
|
;;
|
||
|
*)
|
||
|
user_error "Unknown command option: '$1'"
|
||
|
esac
|
||
|
shift
|
||
|
done
|
||
|
|
||
|
# Assign output files
|
||
|
key_out="$EASYRSA_PKI/private/${file_name_base}.key"
|
||
|
crt_out="$EASYRSA_PKI/issued/${file_name_base}.crt"
|
||
|
inline_out="$EASYRSA_PKI/inline/${file_name_base}.inline"
|
||
|
|
||
|
# key file must NOT exist
|
||
|
[ -f "$key_out" ] && user_error "\
|
||
|
Cannot self-sign this request for '$file_name_base'.
|
||
|
Conflicting key exists at:
|
||
|
* $key_out"
|
||
|
|
||
|
# Certificate file must NOT exist
|
||
|
[ -f "$crt_out" ] && user_error "\
|
||
|
Cannot self-sign this request for '$file_name_base'.
|
||
|
Conflicting certificate exists at:
|
||
|
* $crt_out"
|
||
|
|
||
|
# Check algo and curve
|
||
|
case "$EASYRSA_ALGO" in
|
||
|
rsa|ec)
|
||
|
# Silently use ec instead of rsa
|
||
|
export EASYRSA_ALGO=ec
|
||
|
# Selectively set --curve=secp384r1
|
||
|
set_var EASYRSA_CURVE secp384r1
|
||
|
|
||
|
# temp-file for params-file
|
||
|
selfsign_params_file=""
|
||
|
easyrsa_mktemp selfsign_params_file || \
|
||
|
die "self_sign - easyrsa_mktemp selfsign_params_file"
|
||
|
|
||
|
# params-file
|
||
|
"$EASYRSA_OPENSSL" ecparam \
|
||
|
-name "$EASYRSA_CURVE" \
|
||
|
-out "$selfsign_params_file" || \
|
||
|
die "self_sign - params-file failed"
|
||
|
|
||
|
newkey_params="$EASYRSA_ALGO":"$selfsign_params_file"
|
||
|
;;
|
||
|
ed)
|
||
|
# Selectively set --curve=ed25519
|
||
|
set_var EASYRSA_CURVE ed25519
|
||
|
newkey_params="$EASYRSA_CURVE"
|
||
|
;;
|
||
|
*)
|
||
|
user_error "Unrecognised algorithm: '$EASYRSA_ALGO'"
|
||
|
esac
|
||
|
|
||
|
verbose "\
|
||
|
self-sign: Use ALGO:'$EASYRSA_ALGO' / CURVE:'$EASYRSA_CURVE'"
|
||
|
|
||
|
# Assign tmp-file for config
|
||
|
adjusted_ssl_cnf_tmp=""
|
||
|
easyrsa_mktemp adjusted_ssl_cnf_tmp || \
|
||
|
die "self_sign - easyrsa_mktemp adjusted_ssl_cnf_tmp"
|
||
|
|
||
|
# 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}
|
||
|
}'
|
||
|
|
||
|
# Find or create x509 selfsign file
|
||
|
if [ -f "$EASYRSA_EXT_DIR/selfsign" ]; then
|
||
|
# Use the x509-types/selfsign file
|
||
|
x509_selfsign_file="$EASYRSA_EXT_DIR/selfsign"
|
||
|
else
|
||
|
# Use a temp file
|
||
|
write_x509_type_tmp selfsign
|
||
|
x509_selfsign_file="$write_x509_file_tmp"
|
||
|
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
|
||
|
|
||
|
# Insert x509-types COMMON and 'selfsign' and EASYRSA_EXTRA_EXTS
|
||
|
{
|
||
|
# X509 files
|
||
|
cat "$x509_selfsign_file" "$x509_COMMON_file"
|
||
|
|
||
|
# User extensions
|
||
|
[ "$EASYRSA_EXTRA_EXTS" ] && \
|
||
|
print "$EASYRSA_EXTRA_EXTS"
|
||
|
|
||
|
} | awk "$awkscript" "$EASYRSA_SSL_CONF" \
|
||
|
> "$adjusted_ssl_cnf_tmp" || \
|
||
|
die "Copying X509_TYPES to config file failed"
|
||
|
verbose "self_sign: insert x509 and extensions OK"
|
||
|
|
||
|
# Use this new SSL config for the rest of this function
|
||
|
EASYRSA_SSL_CONF="$adjusted_ssl_cnf_tmp"
|
||
|
|
||
|
# Create temp-files for output
|
||
|
tmp_key_out=""
|
||
|
easyrsa_mktemp tmp_key_out || \
|
||
|
die "self_sign - easyrsa_mktemp tmp_key_out"
|
||
|
|
||
|
tmp_crt_out=""
|
||
|
easyrsa_mktemp tmp_crt_out || \
|
||
|
die "self_sign - easyrsa_mktemp tmp_crt_out"
|
||
|
|
||
|
# create self-signed key pair
|
||
|
easyrsa_openssl req -x509 -utf8 -sha256 -text \
|
||
|
-newkey "$newkey_params" \
|
||
|
-keyout "$tmp_key_out" \
|
||
|
-out "$tmp_crt_out" \
|
||
|
-subj "/CN=$file_name_base" \
|
||
|
${EASYRSA_NO_PASS:+ "$no_password"} \
|
||
|
${EASYRSA_PASSIN:+ -passin "$EASYRSA_PASSIN"} \
|
||
|
${EASYRSA_PASSOUT:+ -passout "$EASYRSA_PASSOUT"} \
|
||
|
${EASYRSA_CERT_EXPIRE:+ -days "$EASYRSA_CERT_EXPIRE"} \
|
||
|
${EASYRSA_START_DATE:+ -startdate "$EASYRSA_START_DATE"} \
|
||
|
${EASYRSA_END_DATE:+ -enddate "$EASYRSA_END_DATE"}
|
||
|
|
||
|
# Move temp-files to target-files
|
||
|
mv "$tmp_key_out" "$key_out" || mv_temp_error=1
|
||
|
mv "$tmp_crt_out" "$crt_out" || mv_temp_error=1
|
||
|
if [ "$mv_temp_error" ]; then
|
||
|
rm -f "$key_out" "$crt_out"
|
||
|
die "Failed to move new key/cert files."
|
||
|
fi
|
||
|
|
||
|
# inline key/cert/fingerprint
|
||
|
inline_file "$file_name_base"
|
||
|
|
||
|
# User info
|
||
|
notice "\
|
||
|
Self-signed '$EASYRSA_ALGO/$EASYRSA_CURVE' \
|
||
|
key and certificate created:
|
||
|
* $key_out
|
||
|
* $crt_out"
|
||
|
} # => self_sign()
|
||
|
|
||
|
# gen-dh backend:
|
||
|
gen_dh() {
|
||
|
out_file="$EASYRSA_PKI/dh.pem"
|
||
|
|
||
|
# check to see if we already have a dh parameters file
|
||
|
if [ -f "$out_file" ]; then
|
||
|
if [ "$EASYRSA_BATCH" ]; then
|
||
|
# if batch is enabled, die
|
||
|
user_error "\
|
||
|
DH parameters file already exists
|
||
|
at: $out_file"
|
||
|
else
|
||
|
# warn the user, allow to force overwrite
|
||
|
confirm "Overwrite? " "yes" "\
|
||
|
DH parameters file already exists
|
||
|
at: $out_file"
|
||
|
fi
|
||
|
fi
|
||
|
|
||
|
# Create a temp file
|
||
|
# otherwise user abort leaves an incomplete dh.pem
|
||
|
tmp_dh_file=""
|
||
|
easyrsa_mktemp tmp_dh_file || \
|
||
|
die "gen_dh - easyrsa_mktemp tmp_dh_file"
|
||
|
|
||
|
# Generate dh.pem
|
||
|
easyrsa_openssl dhparam -out "$tmp_dh_file" \
|
||
|
"$EASYRSA_KEY_SIZE" || die "Failed to generate DH params"
|
||
|
|
||
|
# Validate dh.pem
|
||
|
easyrsa_openssl dhparam -in "$tmp_dh_file" \
|
||
|
-check -noout || die "Failed to validate DH params"
|
||
|
|
||
|
# Move temp-files to target-files
|
||
|
mv "$tmp_dh_file" "$out_file" || mv_temp_error=1
|
||
|
if [ "$mv_temp_error" ]; then
|
||
|
rm -f "$out_file"
|
||
|
die "Failed to move temp DH file."
|
||
|
fi
|
||
|
|
||
|
notice "
|
||
|
DH parameters of size $EASYRSA_KEY_SIZE created at:
|
||
|
* $out_file"
|
||
|
} # => gen_dh()
|
||
|
|
||
|
# gen-req and key backend:
|
||
|
gen_req() {
|
||
|
# pull filename, use as default interactive CommonName
|
||
|
[ "$1" ] || user_error "\
|
||
|
Error: gen-req must have a file-name-base as the first argument.
|
||
|
Run easyrsa without commands for usage and commands."
|
||
|
|
||
|
file_name_base="$1"
|
||
|
shift # scrape off file-name-base
|
||
|
|
||
|
# Set ssl batch mode as required
|
||
|
[ "$EASYRSA_BATCH" ] && ssl_batch=1
|
||
|
|
||
|
# Set commonName
|
||
|
if [ "$EASYRSA_REQ_CN" = ChangeMe ]; then
|
||
|
export EASYRSA_REQ_CN="$file_name_base"
|
||
|
fi
|
||
|
|
||
|
# create local SSL cnf
|
||
|
write_easyrsa_ssl_cnf_tmp
|
||
|
|
||
|
# Output files
|
||
|
key_out="$EASYRSA_PKI/private/${file_name_base}.key"
|
||
|
req_out="$EASYRSA_PKI/reqs/${file_name_base}.req"
|
||
|
|
||
|
# function opts support
|
||
|
while [ "$1" ]; do
|
||
|
case "$1" in
|
||
|
text)
|
||
|
text=1
|
||
|
;;
|
||
|
nopass)
|
||
|
[ "$prohibit_no_pass" ] || EASYRSA_NO_PASS=1
|
||
|
;;
|
||
|
# batch flag supports internal caller build_full()
|
||
|
batch)
|
||
|
ssl_batch=1
|
||
|
;;
|
||
|
*) user_error "Unknown command option: '$1'"
|
||
|
esac
|
||
|
shift
|
||
|
done
|
||
|
|
||
|
# don't wipe out an existing request without confirmation
|
||
|
[ -f "$req_out" ] && confirm "Confirm request overwrite: " "yes" "\
|
||
|
|
||
|
WARNING!!!
|
||
|
|
||
|
An existing request file was found at
|
||
|
* $req_out
|
||
|
|
||
|
Continuing with key generation will replace this request."
|
||
|
|
||
|
# don't wipe out an existing private key without confirmation
|
||
|
[ -f "$key_out" ] && confirm "Confirm key overwrite: " "yes" "\
|
||
|
|
||
|
WARNING!!!
|
||
|
|
||
|
An existing private key was found at
|
||
|
* $key_out
|
||
|
|
||
|
Continuing with key generation will replace this key."
|
||
|
|
||
|
# When EASYRSA_EXTRA_EXTS is defined,
|
||
|
# append it to openssl's [req] section:
|
||
|
if [ "$EASYRSA_EXTRA_EXTS" ]; then
|
||
|
# Check for insert-marker in ssl config file
|
||
|
if ! grep -q '^#%EXTRA_EXTS%' "$EASYRSA_SSL_CONF"
|
||
|
then
|
||
|
die "\
|
||
|
This openssl config file does \
|
||
|
does not support EASYRSA_EXTRA_EXTS.
|
||
|
* $EASYRSA_SSL_CONF
|
||
|
|
||
|
Please update 'openssl-easyrsa.cnf' \
|
||
|
to the latest Easy-RSA release."
|
||
|
fi
|
||
|
|
||
|
# Setup & insert the extra ext data keyed by magic line
|
||
|
extra_exts="
|
||
|
req_extensions = req_extra
|
||
|
[ req_extra ]
|
||
|
$EASYRSA_EXTRA_EXTS"
|
||
|
# shellcheck disable=SC2016 # No expand '' - gen_req()
|
||
|
awkscript='
|
||
|
{if ( match($0, "^#%EXTRA_EXTS%") )
|
||
|
{ while ( getline<"/dev/stdin" ) {print} next }
|
||
|
{print}
|
||
|
}'
|
||
|
# Assign temp-file for config
|
||
|
adjusted_ssl_cnf_tmp=""
|
||
|
easyrsa_mktemp adjusted_ssl_cnf_tmp || \
|
||
|
die "gen_req - easyrsa_mktemp adjusted_ssl_cnf_tmp"
|
||
|
|
||
|
# Insert $extra_exts @ %EXTRA_EXTS% in SSL Config
|
||
|
print "$extra_exts" | \
|
||
|
awk "$awkscript" "$EASYRSA_SSL_CONF" \
|
||
|
> "$adjusted_ssl_cnf_tmp" || \
|
||
|
die "Writing SSL config to temp file failed"
|
||
|
|
||
|
[ "${EASYRSA_SAN_CRIT}" ] && \
|
||
|
verbose "gen-req: SAN critical OK"
|
||
|
|
||
|
# Use this SSL config for the rest of this function
|
||
|
EASYRSA_SSL_CONF="$adjusted_ssl_cnf_tmp"
|
||
|
fi
|
||
|
|
||
|
# Name temp files
|
||
|
key_out_tmp=""
|
||
|
easyrsa_mktemp key_out_tmp || \
|
||
|
die "gen_req - easyrsa_mktemp key_out_tmp"
|
||
|
req_out_tmp=""
|
||
|
easyrsa_mktemp req_out_tmp || \
|
||
|
die "gen_req - easyrsa_mktemp req_out_tmp"
|
||
|
|
||
|
# Set algorithm options
|
||
|
algo_opts=""
|
||
|
case "$EASYRSA_ALGO" in
|
||
|
rsa|ec)
|
||
|
# Set elliptic curve parameters-file
|
||
|
# or RSA bit-length
|
||
|
algo_opts="$EASYRSA_ALGO:$EASYRSA_ALGO_PARAMS"
|
||
|
;;
|
||
|
ed)
|
||
|
# Set Edwards curve name
|
||
|
algo_opts="$EASYRSA_CURVE"
|
||
|
;;
|
||
|
*)
|
||
|
die "gen_req - Unknown algorithm: $EASYRSA_ALGO"
|
||
|
esac
|
||
|
|
||
|
# Generate request
|
||
|
if easyrsa_openssl req -utf8 -new -newkey "$algo_opts" \
|
||
|
-keyout "$key_out_tmp" \
|
||
|
-out "$req_out_tmp" \
|
||
|
${EASYRSA_NO_PASS:+ "$no_password"} \
|
||
|
${text:+ -text} \
|
||
|
${ssl_batch:+ -batch} \
|
||
|
${EASYRSA_PASSOUT:+ -passout "$EASYRSA_PASSOUT"}
|
||
|
then
|
||
|
: # ok
|
||
|
else
|
||
|
die "Failed to generate request"
|
||
|
fi
|
||
|
|
||
|
# Move temp-files to target-files
|
||
|
mv "$key_out_tmp" "$key_out" || mv_temp_error=1
|
||
|
mv "$req_out_tmp" "$req_out" || mv_temp_error=1
|
||
|
if [ "$mv_temp_error" ]; then
|
||
|
rm -f "$key_out" "$req_out"
|
||
|
die "Failed to move temp key/req file."
|
||
|
fi
|
||
|
|
||
|
# Success messages
|
||
|
notice "\
|
||
|
Private-Key and Public-Certificate-Request files created.
|
||
|
Your files are:
|
||
|
* req: $req_out
|
||
|
* key: $key_out${do_build_full:+ $NL}"
|
||
|
} # => gen_req()
|
||
|
|
||
|
# common signing backend
|
||
|
sign_req() {
|
||
|
crt_type="$1"
|
||
|
file_name_base="$2"
|
||
|
|
||
|
# Verify $crt_type is valid
|
||
|
case "$crt_type" in
|
||
|
ca|server|serverClient|client|codeSigning|email|kdc)
|
||
|
: # All known types plus CA for sub-ca
|
||
|
;;
|
||
|
*)
|
||
|
warn "\
|
||
|
Unrecognised x509-type: '$crt_type'
|
||
|
|
||
|
In order to sign a custom X509 Type certificate, there must be a
|
||
|
corresponding SSL configuration file in the 'x509-type' folder."
|
||
|
esac
|
||
|
|
||
|
# Check argument sanity:
|
||
|
[ "$file_name_base" ] || user_error "\
|
||
|
Incorrect number of arguments provided to sign-req:
|
||
|
expected 2, got $# (see command help for usage)"
|
||
|
|
||
|
req_in="$EASYRSA_PKI/reqs/$file_name_base.req"
|
||
|
crt_out="$EASYRSA_PKI/issued/$file_name_base.crt"
|
||
|
shift 2
|
||
|
|
||
|
# create local SSL cnf
|
||
|
write_easyrsa_ssl_cnf_tmp
|
||
|
|
||
|
# Check optional subject
|
||
|
force_subj=
|
||
|
while [ "$1" ]; do
|
||
|
case "$1" in
|
||
|
nopass)
|
||
|
warn "Ignoring option '$1'"
|
||
|
;;
|
||
|
newsubj*)
|
||
|
# verify force_subj opts are used correctly
|
||
|
[ "$EASYRSA_NEW_SUBJECT" ] || user_error "\
|
||
|
To force a new certificate subject, global option --new-subject
|
||
|
must also be specified."
|
||
|
force_subj="$EASYRSA_NEW_SUBJECT"
|
||
|
;;
|
||
|
preserve*)
|
||
|
export EASYRSA_PRESERVE_DN=1
|
||
|
;;
|
||
|
*)
|
||
|
user_error "Unknown option '$1'"
|
||
|
esac
|
||
|
shift
|
||
|
done
|
||
|
|
||
|
# verify force_subj opts are used correctly
|
||
|
if [ "$EASYRSA_NEW_SUBJECT" ]; then
|
||
|
[ "$force_subj" ] || user_error "\
|
||
|
To force a new certificate subject, command option 'newsubj'
|
||
|
must also be specified."
|
||
|
fi
|
||
|
|
||
|
# Cert type must NOT be COMMON
|
||
|
[ "$crt_type" = COMMON ] && user_error "\
|
||
|
Invalid certificate type: '$crt_type'"
|
||
|
|
||
|
# Request file must exist
|
||
|
[ -f "$req_in" ] || user_error "\
|
||
|
No request found for the input: '$file_name_base'
|
||
|
Expected to find the request at:
|
||
|
* $req_in"
|
||
|
|
||
|
# Certificate file must NOT exist
|
||
|
[ -f "$crt_out" ] && user_error "\
|
||
|
Cannot sign this request for '$file_name_base'.
|
||
|
Conflicting certificate exists at:
|
||
|
* $crt_out"
|
||
|
|
||
|
# Confirm input is a cert req
|
||
|
verify_file req "$req_in" || user_error "\
|
||
|
The certificate request file is not in a valid X509 format:
|
||
|
* $req_in"
|
||
|
|
||
|
# Randomize Serial number
|
||
|
if [ "$EASYRSA_RAND_SN" != no ]; then
|
||
|
serial=""
|
||
|
check_serial=""
|
||
|
unset -v serial_is_unique
|
||
|
for i in 1 2 3 4 5; do
|
||
|
easyrsa_random 16 serial
|
||
|
|
||
|
# Require 128bit serial number
|
||
|
[ "$serial" = "${serial#00}" ] || continue
|
||
|
|
||
|
# Check for duplicate serial in CA db
|
||
|
if check_serial_unique "$serial" batch; then
|
||
|
serial_is_unique=1
|
||
|
break
|
||
|
fi
|
||
|
done
|
||
|
|
||
|
# Check for unique_serial
|
||
|
[ "$serial_is_unique" ] || die "\
|
||
|
sign_req - Randomize Serial number failed:
|
||
|
|
||
|
$check_serial"
|
||
|
|
||
|
# Print random $serial to pki/serial file
|
||
|
# for use by SSL config
|
||
|
print "$serial" > "$EASYRSA_PKI/serial" || \
|
||
|
die "sign_req - write serial to file"
|
||
|
unset -v serial check_serial serial_is_unique
|
||
|
fi
|
||
|
|
||
|
# When EASYRSA_CP_EXT is defined,
|
||
|
# adjust openssl's [default_ca] section:
|
||
|
if [ "$EASYRSA_CP_EXT" ]; then
|
||
|
# Check for insert-marker in ssl config file
|
||
|
if ! grep -q '^#%COPY_EXTS%' "$EASYRSA_SSL_CONF"
|
||
|
then
|
||
|
die "\
|
||
|
This openssl config file does \
|
||
|
not support option '--copy-ext'.
|
||
|
* $EASYRSA_SSL_CONF
|
||
|
|
||
|
Please update 'openssl-easyrsa.cnf' \
|
||
|
to the latest Easy-RSA release."
|
||
|
fi
|
||
|
|
||
|
# Setup & insert the copy_extensions data
|
||
|
# keyed by a magic line
|
||
|
copy_exts="copy_extensions = copy"
|
||
|
# shellcheck disable=SC2016 # No expand '' - sign_req()
|
||
|
awkscript='
|
||
|
{if ( match($0, "^#%COPY_EXTS%") )
|
||
|
{ while ( getline<"/dev/stdin" ) {print} next }
|
||
|
{print}
|
||
|
}'
|
||
|
# Assign temp-file for config
|
||
|
adjusted_ssl_cnf_tmp=""
|
||
|
easyrsa_mktemp adjusted_ssl_cnf_tmp || \
|
||
|
die "sign_req - easyrsa_mktemp adjusted_ssl_cnf_tmp"
|
||
|
|
||
|
print "$copy_exts" | \
|
||
|
awk "$awkscript" "$EASYRSA_SSL_CONF" \
|
||
|
> "$adjusted_ssl_cnf_tmp" || die "\
|
||
|
Writing 'copy_exts' to SSL config temp-file failed"
|
||
|
|
||
|
# Use this SSL config for the rest of this function
|
||
|
EASYRSA_SSL_CONF="$adjusted_ssl_cnf_tmp"
|
||
|
verbose "sign_req: Using '$copy_exts'"
|
||
|
verbose "sign_req: EASYRSA_SSL_CONF = $EASYRSA_SSL_CONF"
|
||
|
fi
|
||
|
|
||
|
# Find or create x509-type file
|
||
|
if [ -f "$EASYRSA_EXT_DIR/$crt_type" ]; then
|
||
|
# Use the x509-types/$crt_type file
|
||
|
x509_type_file="$EASYRSA_EXT_DIR/$crt_type"
|
||
|
else
|
||
|
# Use a temp file
|
||
|
write_x509_type_tmp "$crt_type"
|
||
|
x509_type_file="$write_x509_file_tmp"
|
||
|
fi
|
||
|
|
||
|
# keyUsage critical
|
||
|
confirm_ku_crit=
|
||
|
if [ "$EASYRSA_KU_CRIT" ]; then
|
||
|
crit_tmp=
|
||
|
easyrsa_mktemp crit_tmp || \
|
||
|
die "sign-req - easyrsa_mktemp KU crit_tmp"
|
||
|
|
||
|
add_critical_attrib keyUsage "$x509_type_file" \
|
||
|
"$crit_tmp" || die "sign-req - KU add_critical_attrib"
|
||
|
|
||
|
# Use the new tmp-file with critical attribute
|
||
|
x509_type_file="$crit_tmp"
|
||
|
confirm_ku_crit=" keyUsage: 'critical'${NL}"
|
||
|
verbose "sign_req: keyUsage critical OK"
|
||
|
fi
|
||
|
|
||
|
# basicConstraints critical
|
||
|
confirm_bc_crit=
|
||
|
if [ "$EASYRSA_BC_CRIT" ]; then
|
||
|
crit_tmp=
|
||
|
easyrsa_mktemp crit_tmp || \
|
||
|
die "sign-req - easyrsa_mktemp BC crit_tmp"
|
||
|
|
||
|
add_critical_attrib basicConstraints "$x509_type_file" \
|
||
|
"$crit_tmp" || die "sign-req - BC add_critical_attrib"
|
||
|
|
||
|
# Use the new tmp-file with critical attribute
|
||
|
x509_type_file="$crit_tmp"
|
||
|
confirm_bc_crit=" basicConstraints: 'critical'${NL}"
|
||
|
verbose "sign_req: basicConstraints critical OK"
|
||
|
fi
|
||
|
|
||
|
# extendedKeyUsage critical
|
||
|
confirm_eku_crit=
|
||
|
if [ "$EASYRSA_EKU_CRIT" ]; then
|
||
|
crit_tmp=
|
||
|
easyrsa_mktemp crit_tmp || \
|
||
|
die "sign-req - easyrsa_mktemp EKU crit_tmp"
|
||
|
|
||
|
add_critical_attrib extendedKeyUsage "$x509_type_file" \
|
||
|
"$crit_tmp" || die "sign-req - EKU add_critical_attrib"
|
||
|
|
||
|
# Use the new tmp-file with critical attribute
|
||
|
x509_type_file="$crit_tmp"
|
||
|
confirm_eku_crit=" extendedKeyUsage: 'critical'${NL}"
|
||
|
verbose "sign_req: extendedKeyUsage 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
|
||
|
|
||
|
# Support a dynamic CA path length when present:
|
||
|
unset -v basicConstraints confirm_bc_len
|
||
|
if [ "$crt_type" = "ca" ] && [ "$EASYRSA_SUBCA_LEN" ]
|
||
|
then
|
||
|
# Print the last occurrence of basicConstraints in
|
||
|
# x509-types/ca
|
||
|
# If basicConstraints is not defined then bail
|
||
|
# shellcheck disable=SC2016 # No expand '' - sign_req()
|
||
|
awkscript='\
|
||
|
/^[[:blank:]]*basicConstraints[[:blank:]]*=/ { bC=$0 }
|
||
|
END { if (length(bC) == 0 ) exit 1; print bC }'
|
||
|
basicConstraints="$(
|
||
|
awk "$awkscript" "$x509_type_file"
|
||
|
)" || die "\
|
||
|
basicConstraints is not defined, cannot use 'pathlen'"
|
||
|
confirm_pathlen="
|
||
|
Path length: '$EASYRSA_SUBCA_LEN'${NL}"
|
||
|
verbose "sign_req: Using basicConstraints pathlen"
|
||
|
fi
|
||
|
|
||
|
# Deprecated Netscape extension support
|
||
|
case "$EASYRSA_NS_SUPPORT" in
|
||
|
[yY][eE][sS])
|
||
|
|
||
|
confirm "Confirm use of Netscape extensions: " yes \
|
||
|
"WARNING: Netscape extensions are DEPRECATED!"
|
||
|
|
||
|
# Netscape extension
|
||
|
case "$crt_type" in
|
||
|
serverClient)
|
||
|
ns_cert_type="nsCertType = serverClient" ;;
|
||
|
server)
|
||
|
ns_cert_type="nsCertType = server" ;;
|
||
|
client)
|
||
|
ns_cert_type="nsCertType = client" ;;
|
||
|
ca)
|
||
|
ns_cert_type="nsCertType = sslCA" ;;
|
||
|
*)
|
||
|
ns_cert_type="nsCertType = $crt_type"
|
||
|
esac
|
||
|
verbose "sign_req: Using $ns_cert_type"
|
||
|
;;
|
||
|
*)
|
||
|
# ok No NS support required
|
||
|
unset -v ns_cert_type
|
||
|
esac
|
||
|
|
||
|
# Get request CN
|
||
|
# EASYRSA_REQ_CN MUST always be set to the CSR CN
|
||
|
EASYRSA_REQ_CN="$(
|
||
|
"$EASYRSA_OPENSSL" req -utf8 -in "$req_in" -noout \
|
||
|
-subject -nameopt multiline | grep 'commonName'
|
||
|
)" || warn "sign-req - EASYRSA_REQ_CN FAILED"
|
||
|
EASYRSA_REQ_CN="${EASYRSA_REQ_CN##*= }"
|
||
|
|
||
|
# Add auto SAN, if EASYRSA_AUTO_SAN is enabled
|
||
|
if [ -z "$EASYRSA_SAN" ] && [ "$EASYRSA_AUTO_SAN" ]; then
|
||
|
# Choose DNS:san or IP:san
|
||
|
if print "$EASYRSA_REQ_CN" | grep -q \
|
||
|
'^[0-9]\+\.[0-9]\+\.[0-9]\+\.[0-9]\+$'
|
||
|
then
|
||
|
EASYRSA_SAN="IP:${EASYRSA_REQ_CN}"
|
||
|
else
|
||
|
EASYRSA_SAN="DNS:${EASYRSA_REQ_CN}"
|
||
|
fi
|
||
|
|
||
|
# Add auto SAN to EASYRSA_EXTRA_EXTS
|
||
|
EASYRSA_EXTRA_EXTS="\
|
||
|
$EASYRSA_EXTRA_EXTS
|
||
|
subjectAltName = ${EASYRSA_SAN_CRIT}${EASYRSA_SAN}"
|
||
|
verbose "sign-req: Auto SAN: ${EASYRSA_SAN}"
|
||
|
fi
|
||
|
|
||
|
# confirm SAN critical
|
||
|
confirm_san_crit=
|
||
|
if [ "${EASYRSA_SAN_CRIT}" ]; then
|
||
|
confirm_san_crit=" subjectAltName: 'critical'${NL}"
|
||
|
verbose "sign-req: SAN critical OK"
|
||
|
fi
|
||
|
|
||
|
# Generate the extensions file for this cert:
|
||
|
ext_tmp=""
|
||
|
easyrsa_mktemp ext_tmp || \
|
||
|
die "sign_req - easyrsa_mktemp ext_tmp"
|
||
|
|
||
|
# Begin output redirect
|
||
|
{
|
||
|
# Append $cert-type extensions
|
||
|
cat "$x509_COMMON_file" "$x509_type_file"
|
||
|
|
||
|
# Support a dynamic CA path length when present:
|
||
|
if [ "$basicConstraints" ]; then
|
||
|
print "$basicConstraints, pathlen:$EASYRSA_SUBCA_LEN"
|
||
|
fi
|
||
|
|
||
|
# Deprecated Netscape extension support
|
||
|
if [ "$ns_cert_type" ]; then
|
||
|
print "$ns_cert_type"
|
||
|
print "nsComment = \"$EASYRSA_NS_COMMENT\""
|
||
|
fi
|
||
|
|
||
|
# Add user supplied extra extensions
|
||
|
# and/or SAN extension
|
||
|
if [ "$EASYRSA_EXTRA_EXTS" ]; then
|
||
|
print "$EASYRSA_EXTRA_EXTS"
|
||
|
fi
|
||
|
} > "$ext_tmp" || die "\
|
||
|
Failed to create temp extension file (bad permissions?) at:
|
||
|
* $ext_tmp"
|
||
|
verbose "sign_req: Generated extensions file OK"
|
||
|
|
||
|
# Set confirm CN
|
||
|
confirm_CN=" Requested CN: '$EASYRSA_REQ_CN'"
|
||
|
|
||
|
# Set confirm type
|
||
|
confirm_type=" Requested type: '$crt_type'"
|
||
|
|
||
|
# Set confirm valid_period message
|
||
|
if [ "$EASYRSA_END_DATE" ]; then
|
||
|
confirm_period=" Valid until: '$EASYRSA_END_DATE'"
|
||
|
else
|
||
|
confirm_period=" Valid for: '$EASYRSA_CERT_EXPIRE' days"
|
||
|
fi
|
||
|
|
||
|
# Set confirm DN
|
||
|
if [ "$force_subj" ]; then
|
||
|
confirm_dn="${NL}* Forced Subject: '$force_subj'${NL}"
|
||
|
else
|
||
|
confirm_dn="${NL}$(display_dn req "$req_in")" || \
|
||
|
die "sign-req: display_dn"
|
||
|
fi
|
||
|
|
||
|
# Set confirm SAN
|
||
|
# SAN from .req
|
||
|
if [ "$EASYRSA_CP_EXT" ]; then
|
||
|
# capture complete CSR
|
||
|
req_text="$(
|
||
|
"$EASYRSA_OPENSSL" req -utf8 -in "$req_in" -noout -text
|
||
|
)" || die "sign-req: openssl: req_text"
|
||
|
|
||
|
# Check CSR for any requested SAN
|
||
|
if echo "$req_text" | \
|
||
|
grep -q 'X509v3 Subject Alternative Name'
|
||
|
then
|
||
|
# extract requested SAN
|
||
|
# 'grep -A' may not be strictly POSIX, die on error
|
||
|
req_x509_san="$(
|
||
|
echo "$req_text" | \
|
||
|
grep -A 1 'X509v3 Subject Alternative Name'
|
||
|
)" || die "sign-req: req_x509_san: grep -A 1 (POSIX)"
|
||
|
else
|
||
|
# No requested SAN
|
||
|
req_x509_san=
|
||
|
fi
|
||
|
fi
|
||
|
|
||
|
# Set confirm details
|
||
|
confirm_critical_attribs="
|
||
|
${confirm_bc_crit}${confirm_ku_crit}\
|
||
|
${confirm_eku_crit}${confirm_san_crit}"
|
||
|
|
||
|
confirm_details="\
|
||
|
${confirm_CN}
|
||
|
${confirm_type}${confirm_pathlen}
|
||
|
${confirm_period}
|
||
|
${confirm_critical_attribs}${confirm_dn}"
|
||
|
|
||
|
# --san takes priority over req SAN and --copy-ext
|
||
|
if [ "$EASYRSA_SAN" ]; then
|
||
|
confirm_san="\
|
||
|
X509v3 Subject Alternative Name:
|
||
|
${EASYRSA_SAN_CRIT}${EASYRSA_SAN}"
|
||
|
else
|
||
|
confirm_san="$req_x509_san"
|
||
|
fi
|
||
|
|
||
|
# Set confirm SAN
|
||
|
if [ "$EASYRSA_SAN" ] || [ "$req_x509_san" ]; then
|
||
|
confirm_details="$confirm_details${NL}${NL}$confirm_san"
|
||
|
fi
|
||
|
|
||
|
# Display the request subject in an easy-to-read format
|
||
|
# Confirm the user wishes to sign this request
|
||
|
# The foreign_request confirmation is not required
|
||
|
# for build_full:
|
||
|
if [ "$local_request" ]; then
|
||
|
unset -v foreign_request
|
||
|
else
|
||
|
foreign_request="\
|
||
|
Please check over the details shown below for accuracy. \
|
||
|
Note that this request
|
||
|
has not been cryptographically verified. Please be sure \
|
||
|
it came from a trusted
|
||
|
source or that you have verified the request checksum \
|
||
|
with the sender.$NL"
|
||
|
fi
|
||
|
|
||
|
confirm "Confirm requested details: " "yes" "\
|
||
|
${foreign_request}You are about to sign the following certificate:
|
||
|
|
||
|
$confirm_details" # => confirm end
|
||
|
|
||
|
# Assign temp cert file
|
||
|
crt_out_tmp=""
|
||
|
easyrsa_mktemp crt_out_tmp || \
|
||
|
die "sign_req - easyrsa_mktemp crt_out_tmp"
|
||
|
|
||
|
# sign request
|
||
|
easyrsa_openssl ca -utf8 -batch \
|
||
|
-in "$req_in" -out "$crt_out_tmp" \
|
||
|
-extfile "$ext_tmp" \
|
||
|
${EASYRSA_PRESERVE_DN:+ -preserveDN} \
|
||
|
${force_subj:+ -subj "$force_subj"} \
|
||
|
${EASYRSA_PASSIN:+ -passin "$EASYRSA_PASSIN"} \
|
||
|
${EASYRSA_NO_TEXT:+ -notext} \
|
||
|
${EASYRSA_CERT_EXPIRE:+ -days "$EASYRSA_CERT_EXPIRE"} \
|
||
|
${EASYRSA_START_DATE:+ -startdate "$EASYRSA_START_DATE"} \
|
||
|
${EASYRSA_END_DATE:+ -enddate "$EASYRSA_END_DATE"} \
|
||
|
|| die "\
|
||
|
Signing failed (openssl output above may have more detail)"
|
||
|
verbose "sign_req: signed cert '$file_name_base' OK"
|
||
|
|
||
|
# Move temp-files to target-files
|
||
|
mv "$crt_out_tmp" "$crt_out" || mv_temp_error=1
|
||
|
if [ "$mv_temp_error" ]; then
|
||
|
rm -f "$crt_out"
|
||
|
die "Failed to move temp certificate file."
|
||
|
fi
|
||
|
|
||
|
# inline file
|
||
|
inline_file "$file_name_base"
|
||
|
|
||
|
# Success messages
|
||
|
notice "\
|
||
|
Certificate created at:
|
||
|
* $crt_out"
|
||
|
} # => sign_req()
|
||
|
|
||
|
# Add 'critical' attribute to X509-type file
|
||
|
add_critical_attrib() {
|
||
|
case "$1" in
|
||
|
basicConstraints|keyUsage|extendedKeyUsage) : ;; # ok
|
||
|
*) die "add_critical_attrib - usage: '$1'"
|
||
|
esac
|
||
|
|
||
|
[ -f "$2" ] || die "add_critical_attrib - file-2: '$2'"
|
||
|
[ -f "$3" ] || die "add_critical_attrib - file-3: '$3'"
|
||
|
|
||
|
sed s/"$1 = "/"$1 = critical,"/g "$2" > "$3"
|
||
|
} # => add_critical_attrib()
|
||
|
|
||
|
# Check serial in db
|
||
|
check_serial_unique() {
|
||
|
[ "$1" ] || user_error "Serial number required!"
|
||
|
case "$1" in
|
||
|
(*[!1234567890abcdef]*)
|
||
|
user_error "Invalid serial number: '$1'"
|
||
|
esac
|
||
|
|
||
|
unset -v unique_serial_true
|
||
|
|
||
|
# Check for openssl -status of serial number
|
||
|
# Always errors out - Do not capture error
|
||
|
# unset EASYRSA_SILENT_SSL to capture all output
|
||
|
# Do NOT unset check_serial for sign-req error msg
|
||
|
check_serial="$(
|
||
|
"$EASYRSA_OPENSSL" ca -status "$1" 2>&1
|
||
|
)" || :
|
||
|
|
||
|
# Check for duplicate serial in CA db
|
||
|
case "$check_serial" in
|
||
|
(*"not present in db"*)
|
||
|
unique_serial_true=1
|
||
|
verbose "check_serial_unique: unique_serial=true"
|
||
|
;;
|
||
|
*)
|
||
|
: # Some other response
|
||
|
verbose "check_serial_unique: unique_serial=false"
|
||
|
esac
|
||
|
|
||
|
# In batch mode return result only
|
||
|
if [ "$2" = batch ] || [ "$EASYRSA_BATCH" ]; then
|
||
|
if [ "$unique_serial_true" ]; then
|
||
|
unset -v unique_serial_true
|
||
|
return 0
|
||
|
else
|
||
|
unset -v unique_serial_true
|
||
|
return 1
|
||
|
fi
|
||
|
fi
|
||
|
|
||
|
# Otherwise, show result to user
|
||
|
# and do not return any error code
|
||
|
print "
|
||
|
check_serial_status RESULT:
|
||
|
========================================
|
||
|
|
||
|
$check_serial
|
||
|
|
||
|
========================================
|
||
|
COMPLETE"
|
||
|
} # => check_serial_unique()
|
||
|
|
||
|
# common build backend
|
||
|
# used to generate+sign in 1 step
|
||
|
build_full() {
|
||
|
# pull filename base:
|
||
|
[ "$2" ] || user_error "\
|
||
|
Error: didn't find a file base name as the first argument.
|
||
|
Run easyrsa without commands for usage and commands."
|
||
|
|
||
|
crt_type="$1"
|
||
|
name="$2"
|
||
|
shift 2
|
||
|
|
||
|
req_out="$EASYRSA_PKI/reqs/$name.req"
|
||
|
key_out="$EASYRSA_PKI/private/$name.key"
|
||
|
crt_out="$EASYRSA_PKI/issued/$name.crt"
|
||
|
|
||
|
# function opts support
|
||
|
while [ "$1" ]; do
|
||
|
case "$1" in
|
||
|
nopass)
|
||
|
[ "$prohibit_no_pass" ] || EASYRSA_NO_PASS=1
|
||
|
;;
|
||
|
*) user_error "Unknown command option: '$1'"
|
||
|
esac
|
||
|
shift
|
||
|
done
|
||
|
|
||
|
# abort on existing req/key/crt files
|
||
|
err_exists="\
|
||
|
file already exists. Aborting build to avoid overwriting this file.
|
||
|
If you wish to continue, please use a different name.
|
||
|
Conflicting file found at:
|
||
|
*"
|
||
|
[ -f "$req_out" ] && \
|
||
|
user_error "Request $err_exists $req_out"
|
||
|
[ -f "$key_out" ] && \
|
||
|
user_error "Key $err_exists $key_out"
|
||
|
[ -f "$crt_out" ] && \
|
||
|
user_error "Certificate $err_exists $crt_out"
|
||
|
unset -v err_exists
|
||
|
|
||
|
# create request
|
||
|
verbose "build_full: BEGIN gen_req"
|
||
|
gen_req "$name" batch
|
||
|
verbose "build_full: END gen_req"
|
||
|
|
||
|
# Set to modify sign-req confirmation message
|
||
|
local_request=1
|
||
|
|
||
|
# Recreate temp-session and
|
||
|
# drop edits to SSL Conf file
|
||
|
remove_secure_session
|
||
|
locate_support_files
|
||
|
secure_session
|
||
|
write_global_safe_ssl_cnf_tmp
|
||
|
|
||
|
# Require --copy-ext
|
||
|
export EASYRSA_CP_EXT=1
|
||
|
|
||
|
# Sign it
|
||
|
verbose "build_full: BEGIN sign_req"
|
||
|
error_build_full_cleanup=1
|
||
|
if sign_req "$crt_type" "$name"; then
|
||
|
unset -v error_build_full_cleanup do_build_full
|
||
|
else
|
||
|
die "\
|
||
|
Failed to sign '$name' - \
|
||
|
See error messages above for details."
|
||
|
fi
|
||
|
verbose "build_full: END sign_req"
|
||
|
} # => build_full()
|
||
|
|
||
|
# Generate inline file V2
|
||
|
inline_file() {
|
||
|
# Allow complete disable
|
||
|
[ "$EASYRSA_DISABLE_INLINE" ] && return
|
||
|
|
||
|
# definitive source
|
||
|
[ "$1" ] || die "inline_file - Missing file_name_base"
|
||
|
|
||
|
# make inline dirs
|
||
|
easyrsa_mkdir "$EASYRSA_PKI"/inline
|
||
|
easyrsa_mkdir "$EASYRSA_PKI"/inline/private
|
||
|
|
||
|
# Source files
|
||
|
crt_source="${EASYRSA_PKI}/issued/${1}.crt"
|
||
|
key_source="${EASYRSA_PKI}/private/${1}.key"
|
||
|
ca_source="$EASYRSA_PKI"/ca.crt
|
||
|
tls_source="$EASYRSA_PKI"/private/easyrsa-tls.key
|
||
|
old_tls_key_file="$EASYRSA_PKI"/easyrsa-keepsafe-tls.key
|
||
|
|
||
|
# output
|
||
|
inline_out="${EASYRSA_PKI}/inline/${1}.inline"
|
||
|
print "\
|
||
|
# Inline files in the 'private' directory contain security keys which
|
||
|
# MUST only be transmitted over a secure connection, such as 'scp'." \
|
||
|
> "$EASYRSA_PKI"/inline/private/README.inline.private
|
||
|
inline_incomplete=
|
||
|
inline_private=
|
||
|
|
||
|
# Generate Inline data
|
||
|
# Certificate
|
||
|
if [ -f "$crt_source" ]; then
|
||
|
crt_data="\
|
||
|
<cert>
|
||
|
$(cat "$crt_source")
|
||
|
</cert>"
|
||
|
|
||
|
# Calculate decimal value for serial number
|
||
|
# because openvpn uses decimal serial ?!?
|
||
|
# for '--crl-verify /path/to/dir dir'
|
||
|
# For reasons unknown..
|
||
|
if which bc >/dev/null; then
|
||
|
crt_serial="$(
|
||
|
"$EASYRSA_OPENSSL" x509 -in "$crt_source" \
|
||
|
-noout -serial
|
||
|
)" || die "inline_file - SSL -serial failed"
|
||
|
crt_serial="${crt_serial#*=}"
|
||
|
crt_serial_dec="$(
|
||
|
echo "ibase=16; $crt_serial" | bc
|
||
|
)" || die "inline_file - HEX to DEC failed"
|
||
|
else
|
||
|
crt_serial_dec="Unavailable"
|
||
|
fi
|
||
|
|
||
|
# Generate fingerprint
|
||
|
crt_fingerprint="$(
|
||
|
"$EASYRSA_OPENSSL" x509 -in "$crt_source" \
|
||
|
-noout -sha256 -fingerprint
|
||
|
)" || die "inline_file - Failed -fingerprint"
|
||
|
# strip prefix
|
||
|
crt_fingerprint="${crt_fingerprint#*=}"
|
||
|
|
||
|
# Certificate type
|
||
|
if [ -z "$crt_type" ]; then
|
||
|
ssl_cert_x509v3_eku "$crt_source" crt_type || \
|
||
|
die "inline_file: Failed to set crt_type"
|
||
|
fi
|
||
|
|
||
|
# commonName
|
||
|
crt_CN="$(
|
||
|
display_dn x509 "$crt_source" | grep 'commonName'
|
||
|
)" || die "inline_file: Failed to set crt_CN"
|
||
|
# strip prefix
|
||
|
crt_CN="${crt_CN#*= }"
|
||
|
else
|
||
|
inline_incomplete=1
|
||
|
crt_data="\
|
||
|
# When you recieve your signed certificate place it in the
|
||
|
# 'pki/issued' sub-dir of your PKI and use command 'inline'
|
||
|
# to rebuild this inline file with your certificate.
|
||
|
# <cert>
|
||
|
# * Paste your user certificate here *
|
||
|
# </cert>"
|
||
|
|
||
|
crt_fingerprint=unknown
|
||
|
crt_type=unknown
|
||
|
crt_CN=unknown
|
||
|
fi
|
||
|
|
||
|
# Private key
|
||
|
if [ -f "$key_source" ]; then
|
||
|
inline_private=1
|
||
|
key_data="\
|
||
|
<key>
|
||
|
$(cat "$key_source")
|
||
|
</key>"
|
||
|
else
|
||
|
inline_incomplete=1
|
||
|
key_data="\
|
||
|
# When you recieve your key place it in the
|
||
|
# 'pki/private' sub-dir of your PKI and use command 'inline'
|
||
|
# to rebuild this inline file with your key.
|
||
|
# <key>
|
||
|
# * Paste your private key here *
|
||
|
# </key>"
|
||
|
fi
|
||
|
|
||
|
# CA certificate
|
||
|
if [ -f "$ca_source" ]; then
|
||
|
ca_data="\
|
||
|
<ca>
|
||
|
$(cat "$ca_source")
|
||
|
</ca>"
|
||
|
else
|
||
|
inline_incomplete=1
|
||
|
ca_data="\
|
||
|
# When you recieve your CA certificate place it in the
|
||
|
# 'pki' sub-dir of your PKI and use command 'inline'
|
||
|
# to rebuild this inline file with your CA certificate.
|
||
|
# <ca>
|
||
|
# * Paste your CA certificate here *
|
||
|
# </ca>"
|
||
|
fi
|
||
|
|
||
|
# TLS KEY - Set TLS auth|crypt key inline label
|
||
|
if [ -f "$tls_source" ]; then
|
||
|
tls_key_data="$(cat "$tls_source")"
|
||
|
case "$tls_key_data" in
|
||
|
*'TLS-AUTH'*) tls_key_label=tls-auth ;;
|
||
|
*'TLS-CRYPT'*) tls_key_label=tls-crypt ;;
|
||
|
*) tls_key_label=
|
||
|
esac
|
||
|
fi
|
||
|
|
||
|
# Do NOT add TLS key if OLD TLS key exists
|
||
|
# because this PSK has already been shared.
|
||
|
if [ -f "$old_tls_key_file" ]; then
|
||
|
tls_data="\
|
||
|
# Add the existing TLS AUTH/CRYPT-V1 Key here:
|
||
|
# <${tls_key_label}>
|
||
|
# * Paste The existing pre-shared TLS key here *
|
||
|
# </${tls_key_label}>"
|
||
|
|
||
|
# Add --key-direction for TLS-AUTH
|
||
|
[ "$tls_key_label" = tls-auth ] && \
|
||
|
tls_data="$tls_data
|
||
|
#
|
||
|
# Add the required 'key-direction 0|1' here:
|
||
|
# key-direction 1"
|
||
|
unset -v tls_key_data tls_key_label
|
||
|
else
|
||
|
# Add standard TLS key details
|
||
|
if [ -f "$tls_source" ]; then
|
||
|
inline_private=1
|
||
|
if [ "$tls_key_label" ]; then
|
||
|
tls_data="\
|
||
|
<${tls_key_label}>
|
||
|
${tls_key_data}
|
||
|
</${tls_key_label}>"
|
||
|
else
|
||
|
inline_incomplete=1
|
||
|
tls_data="# Easy-RSA TLS Key not recognised!"
|
||
|
fi
|
||
|
else
|
||
|
#inline_incomplete=1
|
||
|
tls_data="# Easy-RSA TLS Key not found!"
|
||
|
fi
|
||
|
fi
|
||
|
|
||
|
# Only support inline TLS keys for OpenVPN server/client use
|
||
|
case "$crt_type" in
|
||
|
server) key_direction="key-direction 0" ;;
|
||
|
client) key_direction="key-direction 1" ;;
|
||
|
*)
|
||
|
verbose "inline: Unsupported certificate type: $crt_type"
|
||
|
tls_key_label=
|
||
|
key_direction=
|
||
|
tls_data="# No TLS Key support for cert-type: $crt_type"
|
||
|
esac
|
||
|
|
||
|
# Add --key-direction for TLS-AUTH
|
||
|
if [ "$tls_key_label" = tls-auth ]; then
|
||
|
tls_data="${tls_data}${NL}${NL}${key_direction}"
|
||
|
fi
|
||
|
|
||
|
# If inline file has keys then redirect to 'private' dir
|
||
|
[ "$inline_private" ] && \
|
||
|
inline_out="${EASYRSA_PKI}/inline/private/${1}.inline"
|
||
|
|
||
|
# Print data
|
||
|
print "\
|
||
|
# Easy-RSA Inline file
|
||
|
# Certificate type: $crt_type
|
||
|
# commonName: $crt_CN
|
||
|
# SHA256 fingerprint:
|
||
|
# $crt_fingerprint
|
||
|
# Decimal serial number: $crt_serial_dec
|
||
|
|
||
|
$crt_data
|
||
|
|
||
|
$key_data
|
||
|
|
||
|
$ca_data
|
||
|
|
||
|
$tls_data
|
||
|
" > "$inline_out"
|
||
|
|
||
|
# user info
|
||
|
if [ "$inline_incomplete" ]; then
|
||
|
warn "\
|
||
|
INCOMPLETE Inline file created:
|
||
|
* $inline_out"
|
||
|
else
|
||
|
notice "\
|
||
|
Inline file created:
|
||
|
* $inline_out"
|
||
|
fi
|
||
|
} # => inline_file()
|
||
|
|
||
|
# revoke backend
|
||
|
revoke() {
|
||
|
# pull filename base:
|
||
|
[ "$1" ] || user_error "\
|
||
|
Error: didn't find a file base name as the first argument.
|
||
|
Run easyrsa without commands for usage and command help."
|
||
|
|
||
|
# Assign file_name_base and dust off!
|
||
|
file_name_base="$1"
|
||
|
shift
|
||
|
|
||
|
# create local SSL cnf
|
||
|
write_easyrsa_ssl_cnf_tmp
|
||
|
|
||
|
in_dir="$EASYRSA_PKI"
|
||
|
key_in="$in_dir/private/${file_name_base}.key"
|
||
|
req_in="$in_dir/reqs/${file_name_base}.req"
|
||
|
inline_pub="$in_dir/inline/${file_name_base}.inline"
|
||
|
inline_pri="$in_dir/inline/private/${file_name_base}.inline"
|
||
|
|
||
|
# input cert for revocation: issued, expired or renewed
|
||
|
crt_in="${in_dir}/${cert_dir}/${file_name_base}.crt"
|
||
|
|
||
|
# Assign possible "crl_reason"
|
||
|
if [ "$1" ]; then
|
||
|
crl_reason="$1"
|
||
|
shift
|
||
|
|
||
|
case "$crl_reason" in
|
||
|
us|uns*) crl_reason=unspecified ;;
|
||
|
kc|key*) crl_reason=keyCompromise ;;
|
||
|
cc|[Cc][Aa]*) crl_reason=CACompromise ;;
|
||
|
ac|aff*) crl_reason=affiliationChanged ;;
|
||
|
ss|sup*) crl_reason=superseded ;;
|
||
|
co|ces*) crl_reason=cessationOfOperation ;;
|
||
|
ch|cer*) crl_reason=certificateHold ;;
|
||
|
*) user_error "\
|
||
|
Unexpected reason: '$crl_reason'. See 'help revoke' for valid reasons."
|
||
|
esac
|
||
|
else
|
||
|
unset -v crl_reason
|
||
|
fi
|
||
|
|
||
|
# Enforce syntax
|
||
|
if [ "$1" ]; then
|
||
|
user_error "Syntax error: $1"
|
||
|
fi
|
||
|
|
||
|
# referenced cert must exist:
|
||
|
[ -f "$crt_in" ] || user_error "\
|
||
|
Unable to revoke as no certificate was found.
|
||
|
Certificate was expected at:
|
||
|
* $crt_in"
|
||
|
|
||
|
# Verify certificate
|
||
|
verify_file x509 "$crt_in" || user_error "\
|
||
|
Unable to revoke as the input-file is not a valid certificate.
|
||
|
Certificate was expected at:
|
||
|
* $crt_in"
|
||
|
|
||
|
# Check for misuse of revoke when revoke-* is intended
|
||
|
case "$cert_dir" in
|
||
|
issued)
|
||
|
# expired cert
|
||
|
exp_exist="${in_dir}/expired/${file_name_base}.crt"
|
||
|
if [ -f "$exp_exist" ]; then
|
||
|
exp_endd="$(
|
||
|
"$EASYRSA_OPENSSL" x509 -in "$exp_exist" -noout \
|
||
|
-enddate -serial)" || die "revoke - expire -enddate"
|
||
|
# shellcheck disable=SC2295 # Expansions inside ${..}
|
||
|
exp_confirm="
|
||
|
Expired certificate:
|
||
|
* $exp_exist
|
||
|
Expiry: ${exp_endd%%${NL}serial=*}
|
||
|
Serial: ${exp_endd##*serial=}
|
||
|
Use command 'revoke-expired' to revoke this certificate."
|
||
|
else
|
||
|
unset -v exp_exist exp_endd exp_confirm
|
||
|
fi
|
||
|
|
||
|
# renewed cert
|
||
|
ren_exist="${in_dir}/renewed/${file_name_base}.crt"
|
||
|
if [ -f "$ren_exist" ]; then
|
||
|
ren_endd="$(
|
||
|
"$EASYRSA_OPENSSL" x509 -in "$ren_exist" -noout \
|
||
|
-enddate -serial)" || die "revoke - renew -enddate"
|
||
|
# shellcheck disable=SC2295 # Expansions inside ${..}
|
||
|
ren_confirm="
|
||
|
Renewed certificate:
|
||
|
* $ren_exist
|
||
|
Expiry: ${ren_endd%%${NL}serial=*}
|
||
|
Serial: ${ren_endd##*serial=}
|
||
|
Use command 'revoke-renewed' to revoke this certificate."
|
||
|
else
|
||
|
unset -v ren_exist ren_endd ren_confirm
|
||
|
fi
|
||
|
|
||
|
# issued cert
|
||
|
crt_endd="$(
|
||
|
"$EASYRSA_OPENSSL" x509 -in "$crt_in" -noout \
|
||
|
-enddate -serial)" || die "revoke - expire -enddate"
|
||
|
|
||
|
# Confirm intended use of 'revoke'
|
||
|
if [ "$exp_exist" ] || [ "$ren_exist" ]; then
|
||
|
warn "The following certificate(s) exist:
|
||
|
${exp_exist:+${exp_confirm}${NL}}${ren_exist:+${ren_confirm}${NL}}"
|
||
|
# shellcheck disable=SC2295 # Expansions inside ${..}
|
||
|
confirm " Confirm intended use of 'revoke' ? " yes "\
|
||
|
Please confirm your intended use of 'revoke' for the following
|
||
|
issued certificate:${NL}
|
||
|
* $crt_in
|
||
|
Expiry: ${crt_endd%%${NL}serial=*}
|
||
|
Serial: ${crt_endd##*serial=}"
|
||
|
fi
|
||
|
|
||
|
# Revoking an issued cert forces req/key to be moved
|
||
|
move_req_and_key=1
|
||
|
;;
|
||
|
expired|renewed/issued)
|
||
|
# Revoke-expired/renewed cert means req/key can remain
|
||
|
move_req_and_key=
|
||
|
;;
|
||
|
*)
|
||
|
die "Invalid cert_dir: '$cert_dir'"
|
||
|
esac
|
||
|
|
||
|
# Verify request
|
||
|
if [ -f "$req_in" ]; then
|
||
|
verify_file req "$req_in" || user_error "\
|
||
|
Unable to verify request. The file is not a valid request.
|
||
|
Request was expected at:
|
||
|
* $req_in"
|
||
|
fi
|
||
|
|
||
|
# get the serial number of the certificate
|
||
|
cert_serial=
|
||
|
ssl_cert_serial "$crt_in" cert_serial || \
|
||
|
die "$cmd: Failed to get cert serial number!"
|
||
|
|
||
|
# Set out_dir
|
||
|
out_dir="$EASYRSA_PKI/revoked"
|
||
|
crt_out="$out_dir/certs_by_serial/${cert_serial}.crt"
|
||
|
key_out="$out_dir/private_by_serial/${cert_serial}.key"
|
||
|
req_out="$out_dir/reqs_by_serial/${cert_serial}.req"
|
||
|
|
||
|
# NEVER over-write a revoked cert, serial must be unique
|
||
|
deny_msg="\
|
||
|
Cannot revoke this certificate, a conflicting file exists.
|
||
|
*"
|
||
|
[ -f "$crt_out" ] && \
|
||
|
user_error "$deny_msg certificate: $crt_out"
|
||
|
[ -f "$key_out" ] && \
|
||
|
user_error "$deny_msg private key: $key_out"
|
||
|
[ -f "$req_out" ] && \
|
||
|
user_error "$deny_msg request : $req_out"
|
||
|
unset -v deny_msg
|
||
|
|
||
|
# Check for key and request files
|
||
|
unset -v if_exist_key_in if_exist_req_in
|
||
|
if [ "$move_req_and_key" ] && [ -f "$key_in" ]; then
|
||
|
if_exist_key_in="
|
||
|
* $key_in"
|
||
|
fi
|
||
|
|
||
|
if [ "$move_req_and_key" ] && [ -f "$req_in" ]; then
|
||
|
if_exist_req_in="
|
||
|
* $req_in"
|
||
|
fi
|
||
|
|
||
|
# Set confirm DN and serial
|
||
|
confirm_dn="$(display_dn x509 "$crt_in")" || \
|
||
|
die "revoke: display_dn"
|
||
|
confirm_sn=" serial-number = $cert_serial"
|
||
|
|
||
|
# confirm operation by displaying DN:
|
||
|
warn "\
|
||
|
This process is destructive!
|
||
|
|
||
|
These files will be MOVED to the 'revoked' sub-directory:
|
||
|
* $crt_in${if_exist_key_in}${if_exist_req_in}
|
||
|
|
||
|
These files will be DELETED:
|
||
|
All PKCS files for commonName: $file_name_base
|
||
|
|
||
|
The inline credentials files:
|
||
|
* $inline_pub
|
||
|
* $inline_pri"
|
||
|
|
||
|
confirm " Continue with revocation: " "yes" "
|
||
|
Please confirm that you wish to revoke the certificate
|
||
|
with the following subject:
|
||
|
|
||
|
$confirm_dn
|
||
|
$confirm_sn
|
||
|
|
||
|
Reason: ${crl_reason:-None given}"
|
||
|
|
||
|
# Revoke certificate
|
||
|
easyrsa_openssl ca -utf8 -revoke "$crt_in" \
|
||
|
${crl_reason:+ -crl_reason "$crl_reason"} \
|
||
|
${EASYRSA_PASSIN:+ -passin "$EASYRSA_PASSIN"} \
|
||
|
|| die "\
|
||
|
Failed to revoke certificate: revocation command failed."
|
||
|
|
||
|
# move revoked files
|
||
|
# so we can reissue certificates with the same name
|
||
|
revoke_move
|
||
|
|
||
|
notice "\
|
||
|
* IMPORTANT *
|
||
|
|
||
|
Revocation was successful. You must run 'gen-crl' and upload
|
||
|
a new CRL to your infrastructure in order to prevent the revoked
|
||
|
certificate from being accepted."
|
||
|
} # => revoke()
|
||
|
|
||
|
# revoke_move
|
||
|
# moves revoked certificates to the 'revoked' folder
|
||
|
# allows reissuing certificates with the same name
|
||
|
revoke_move() {
|
||
|
easyrsa_mkdir "$EASYRSA_PKI"/revoked
|
||
|
easyrsa_mkdir "$EASYRSA_PKI"/revoked/reqs_by_serial
|
||
|
easyrsa_mkdir "$EASYRSA_PKI"/revoked/certs_by_serial
|
||
|
easyrsa_mkdir "$EASYRSA_PKI"/revoked/private_by_serial
|
||
|
|
||
|
# only move the req when revoking an issued cert
|
||
|
# and if we have the req
|
||
|
if [ "$move_req_and_key" ] && [ -f "$req_in" ]; then
|
||
|
mv "$req_in" "$req_out" || warn "Failed to move: $req_in"
|
||
|
fi
|
||
|
|
||
|
# move crt to revoked folder
|
||
|
mv "$crt_in" "$crt_out" || die "Failed to move: $crt_in"
|
||
|
|
||
|
# only move the key when revoking an issued cert
|
||
|
# and if we have the key
|
||
|
if [ "$move_req_and_key" ] && [ -f "$key_in" ]; then
|
||
|
mv "$key_in" "$key_out" || warn "Failed to move: $key_in"
|
||
|
fi
|
||
|
|
||
|
# remove any pkcs files
|
||
|
for pkcs in p12 p7b p8 p1; do
|
||
|
if [ -f "$in_dir/issued/$file_name_base.$pkcs" ]; then
|
||
|
# issued
|
||
|
rm "$in_dir/issued/$file_name_base.$pkcs" ||
|
||
|
warn "Failed to remove: $file_name_base.$pkcs"
|
||
|
fi
|
||
|
|
||
|
if [ -f "$in_dir/private/$file_name_base.$pkcs" ]; then
|
||
|
# private
|
||
|
rm "$in_dir/private/$file_name_base.$pkcs" ||
|
||
|
warn "Failed to remove: $file_name_base.$pkcs"
|
||
|
fi
|
||
|
done
|
||
|
|
||
|
# remove inline files
|
||
|
rm -f "$inline_pub" "$inline_pri" || warn \
|
||
|
"revoke_move - Error trying to remove inline files."
|
||
|
} # => revoke_move()
|
||
|
|
||
|
# Move expired cert out of pki/issued to pki/expired
|
||
|
# to allow renewal
|
||
|
expire_cert() {
|
||
|
# pull filename base:
|
||
|
[ "$1" ] || user_error "\
|
||
|
Error: didn't find a file base name as the first argument.
|
||
|
Run easyrsa without commands for usage and command help."
|
||
|
|
||
|
# Assign file_name_base and dust off!
|
||
|
file_name_base="$1"
|
||
|
shift
|
||
|
|
||
|
# input
|
||
|
in_dir="$EASYRSA_PKI/issued"
|
||
|
crt_in="$in_dir/$file_name_base.crt"
|
||
|
#key_in="$in_dir/private/$file_name_base.key"
|
||
|
#req_in="$in_dir/reqs/$file_name_base.req"
|
||
|
|
||
|
# output
|
||
|
out_dir="$EASYRSA_PKI/expired"
|
||
|
crt_out="$out_dir/$file_name_base.crt"
|
||
|
|
||
|
# make output folder
|
||
|
easyrsa_mkdir "$EASYRSA_PKI"/expired
|
||
|
|
||
|
# Do not over write existing cert
|
||
|
if [ -f "$crt_out" ]; then
|
||
|
user_error "\
|
||
|
Existing file must be revoked:
|
||
|
* $crt_out"
|
||
|
fi
|
||
|
|
||
|
# deprecate ALL options
|
||
|
while [ "$1" ]; do
|
||
|
case "$1" in
|
||
|
nopass)
|
||
|
warn "\
|
||
|
Option 'nopass' is not supported by command '$cmd'."
|
||
|
;;
|
||
|
*) user_error "Unknown option: $1"
|
||
|
esac
|
||
|
shift
|
||
|
done
|
||
|
|
||
|
# Verify certificate
|
||
|
if [ -f "$crt_in" ]; then
|
||
|
verify_file x509 "$crt_in" || user_error "\
|
||
|
Input file is not a valid certificate:
|
||
|
* $crt_in"
|
||
|
else
|
||
|
user_error "\
|
||
|
Missing certificate file:
|
||
|
* $crt_in"
|
||
|
fi
|
||
|
|
||
|
# get the serial number of the certificate
|
||
|
cert_serial=
|
||
|
ssl_cert_serial "$crt_in" cert_serial || \
|
||
|
die "$cmd: Failed to get cert serial number!"
|
||
|
|
||
|
# Set confirm DN and serial
|
||
|
confirm_dn="$(display_dn x509 "$crt_in")" || \
|
||
|
die "expire: display_dn"
|
||
|
confirm_sn=" serial-number = $cert_serial"
|
||
|
|
||
|
# date of expiry
|
||
|
# Equal to: easyrsa-tools.lib - ssl_cert_not_after_date()
|
||
|
# This is left as a reminder that easyrsa does not handle
|
||
|
# dates well and they should be avoided, at all cost.
|
||
|
# This is for confirmation purposes ONLY.
|
||
|
crt_expire="$(
|
||
|
"$EASYRSA_OPENSSL" x509 -in "$crt_in" -noout -enddate
|
||
|
)" || die "expire: enddate"
|
||
|
confirm_ex=" notAfter date = ${crt_expire#*=}"
|
||
|
|
||
|
# confirm
|
||
|
confirm " Continue with expiry: " yes "
|
||
|
Please confirm you wish to expire the certificate
|
||
|
with the following subject:
|
||
|
|
||
|
$confirm_dn
|
||
|
|
||
|
$confirm_sn
|
||
|
|
||
|
$confirm_ex" # => End confirm
|
||
|
|
||
|
# move cert to expired dir
|
||
|
mv "$crt_in" "$crt_out" || die "failed to move expired: $crt_in"
|
||
|
|
||
|
# User message
|
||
|
notice "\
|
||
|
Certificate has been successfully moved to the expired directory.
|
||
|
* $crt_out
|
||
|
|
||
|
This certificate is still valid, until it expires.
|
||
|
It can be revoked with command 'revoke-expired'.
|
||
|
|
||
|
It is now possible to sign a new certificate for '$file_name_base'"
|
||
|
} # => expire_cert()
|
||
|
|
||
|
# gen-crl backend
|
||
|
gen_crl() {
|
||
|
out_file="$EASYRSA_PKI/crl.pem"
|
||
|
out_der="$EASYRSA_PKI/crl.der"
|
||
|
|
||
|
out_file_tmp=""
|
||
|
easyrsa_mktemp out_file_tmp || \
|
||
|
die "gen_crl - easyrsa_mktemp out_file_tmp"
|
||
|
|
||
|
if [ -r "$out_file" ]; then
|
||
|
cp -p "$out_file" "$out_file_tmp" || \
|
||
|
warn "Failed to preserve CRL file permissions."
|
||
|
fi
|
||
|
|
||
|
easyrsa_openssl ca -utf8 -gencrl -out "$out_file_tmp" \
|
||
|
${EASYRSA_CRL_DAYS:+ -crldays "$EASYRSA_CRL_DAYS"} \
|
||
|
${EASYRSA_PASSIN:+ -passin "$EASYRSA_PASSIN"} || \
|
||
|
die "CRL Generation failed."
|
||
|
|
||
|
# Move temp-files to target-files
|
||
|
mv "$out_file_tmp" "$out_file" || mv_temp_error=1
|
||
|
if [ "$mv_temp_error" ]; then
|
||
|
#rm -f "$out_file"
|
||
|
die "Failed to move temp CRL file."
|
||
|
fi
|
||
|
|
||
|
# Copy to DER - As published by OpenSSL
|
||
|
if "$EASYRSA_OPENSSL" crl -in "$out_file" -out "$out_der" \
|
||
|
-outform DER
|
||
|
then
|
||
|
crl_der_note="An updated CRL DER copy has been created:
|
||
|
* $out_der"
|
||
|
else
|
||
|
crl_der_note="Failed to create CRL DER copy!"
|
||
|
fi
|
||
|
|
||
|
notice "\
|
||
|
$crl_der_note
|
||
|
|
||
|
An updated CRL has been created:
|
||
|
* $out_file"
|
||
|
} # => gen_crl()
|
||
|
|
||
|
# import-req backend
|
||
|
import_req() {
|
||
|
# pull passed paths
|
||
|
in_req="$1"
|
||
|
short_name="$2"
|
||
|
out_req="$EASYRSA_PKI/reqs/$2.req"
|
||
|
|
||
|
[ "$short_name" ] || user_error "\
|
||
|
Unable to import: incorrect command syntax.
|
||
|
Run easyrsa without commands for usage and command help."
|
||
|
|
||
|
# Request file must exist
|
||
|
[ -f "$in_req" ] || user_error "\
|
||
|
No request found for the input: '$2'
|
||
|
Expected to find the request at:
|
||
|
* $in_req"
|
||
|
|
||
|
verify_file req "$in_req" || user_error "\
|
||
|
The certificate request file is not in a valid X509 format:
|
||
|
* $in_req"
|
||
|
|
||
|
# destination must not exist
|
||
|
[ -f "$out_req" ] && user_error "\
|
||
|
Please choose a different name for your imported request file.
|
||
|
Conflicting file already exists at:
|
||
|
* $out_req"
|
||
|
|
||
|
# now import it
|
||
|
cp "$in_req" "$out_req"
|
||
|
|
||
|
notice "\
|
||
|
Request successfully imported with short-name: $short_name
|
||
|
This request is now ready to be signed."
|
||
|
} # => import_req()
|
||
|
|
||
|
# export pkcs#12, pkcs#7, pkcs#8 or pkcs#1
|
||
|
export_pkcs() {
|
||
|
pkcs_type="$1"
|
||
|
shift
|
||
|
|
||
|
[ "$1" ] || user_error "\
|
||
|
Unable to export '$pkcs_type': incorrect command syntax.
|
||
|
Run easyrsa without commands for usage and command help."
|
||
|
|
||
|
file_name_base="$1"
|
||
|
shift
|
||
|
|
||
|
crt_in="$EASYRSA_PKI/issued/$file_name_base.crt"
|
||
|
key_in="$EASYRSA_PKI/private/$file_name_base.key"
|
||
|
crt_ca="$EASYRSA_PKI/ca.crt"
|
||
|
|
||
|
# Always set a friendly_name
|
||
|
set_var EASYRSA_P12_FR_NAME "$file_name_base"
|
||
|
friendly_name="$EASYRSA_P12_FR_NAME"
|
||
|
|
||
|
# opts support
|
||
|
cipher=-aes256
|
||
|
want_ca=1
|
||
|
want_key=1
|
||
|
unset -v nokeys legacy
|
||
|
|
||
|
# Under OpenSSL 1.1, use the PBE/MAC algorithms OpenSSL 3.0 uses,
|
||
|
# unless "legacy" is set. This makes the .p12 files readable by
|
||
|
# OpenSSL 3.0 without needing '-legacy'.
|
||
|
if [ "$openssl_v3" ]; then
|
||
|
# No cipher opts required
|
||
|
p12_cipher_opts=""
|
||
|
else
|
||
|
# Upgrade PBE & MAC opts - Reset by option 'legacy'
|
||
|
p12_cipher_opts="-keypbe AES-256-CBC -certpbe AES-256-CBC"
|
||
|
p12_cipher_opts="${p12_cipher_opts} -macalg sha256"
|
||
|
fi
|
||
|
|
||
|
while [ "$1" ]; do
|
||
|
case "$1" in
|
||
|
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
|
||
|
;;
|
||
|
nofn)
|
||
|
friendly_name=""
|
||
|
;;
|
||
|
legacy)
|
||
|
if [ "$openssl_v3" ]; then
|
||
|
legacy=-legacy
|
||
|
else
|
||
|
# Downgrade PBE & MAC opts
|
||
|
p12_cipher_opts=""
|
||
|
fi
|
||
|
;;
|
||
|
*)
|
||
|
user_error "Unknown command option: '$1'"
|
||
|
esac
|
||
|
shift
|
||
|
done
|
||
|
|
||
|
# 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
|
||
|
case "$pkcs_type" in
|
||
|
p12|p7)
|
||
|
# verify_ca_init() here, otherwise not required
|
||
|
if verify_ca_init test; then
|
||
|
: # ok
|
||
|
else
|
||
|
warn "\
|
||
|
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 the CA Certificate will not be included."
|
||
|
|
||
|
# --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
|
||
|
|
||
|
# Check for key, if required
|
||
|
if [ "$want_key" ]; then
|
||
|
if [ -f "$key_in" ]; then
|
||
|
: #ok
|
||
|
else
|
||
|
case "$pkcs_type" in
|
||
|
p12)
|
||
|
warn "\
|
||
|
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 the Private Key will not be included."
|
||
|
|
||
|
# --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 "\
|
||
|
Missing Private Key, expected at:
|
||
|
* $key_in"
|
||
|
;;
|
||
|
p7)
|
||
|
: # Not required
|
||
|
;;
|
||
|
*) die "Unknown PKCS type: $pkcs_type"
|
||
|
esac
|
||
|
fi
|
||
|
fi
|
||
|
|
||
|
# Check for certificate, if required
|
||
|
if [ -f "$crt_in" ]; then
|
||
|
: # ok
|
||
|
else
|
||
|
case "$pkcs_type" in
|
||
|
p12|p7)
|
||
|
user_error "\
|
||
|
Missing User Certificate, expected at:
|
||
|
* $crt_in"
|
||
|
;;
|
||
|
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
|
||
|
EASYRSA_PASSIN=pass:
|
||
|
EASYRSA_PASSOUT=pass:
|
||
|
unset -v cipher # pkcs#1 only
|
||
|
fi
|
||
|
|
||
|
# Complete export
|
||
|
inline_out=
|
||
|
inline_msg=
|
||
|
case "$pkcs_type" in
|
||
|
p12)
|
||
|
pkcs_out="$EASYRSA_PKI/private/$file_name_base.p12"
|
||
|
inline_out="$EASYRSA_PKI/inline/$file_name_base-p12.inline"
|
||
|
|
||
|
[ "$legacy" ] && \
|
||
|
error_info="SSL library may not support -legacy mode"
|
||
|
|
||
|
# export the p12:
|
||
|
# shellcheck disable=2086 # Double quote p12_cipher_opts
|
||
|
easyrsa_openssl pkcs12 -export \
|
||
|
-in "$crt_in" \
|
||
|
-out "$pkcs_out" \
|
||
|
-inkey "$key_in" \
|
||
|
${nokeys} \
|
||
|
${legacy} \
|
||
|
${p12_cipher_opts} \
|
||
|
${friendly_name:+ -name "$friendly_name"} \
|
||
|
${want_ca:+ -certfile "$crt_ca"} \
|
||
|
${EASYRSA_PASSIN:+ -passin "$EASYRSA_PASSIN"} \
|
||
|
${EASYRSA_PASSOUT:+ -passout "$EASYRSA_PASSOUT"} \
|
||
|
|| die "Failed to export PKCS#12"
|
||
|
|
||
|
# Inline .p12 only
|
||
|
# Get cert CN
|
||
|
inline_CN="$(
|
||
|
"$EASYRSA_OPENSSL" x509 -in "$crt_in" -noout -subject \
|
||
|
-nameopt multiline,-esc_msb | grep 'commonName'
|
||
|
)" || die "export_pkcs - inline_CN FAILED"
|
||
|
inline_CN="${inline_CN##*= }"
|
||
|
|
||
|
# BASE64 encode pkcs12
|
||
|
inline_tmp=
|
||
|
easyrsa_mktemp inline_tmp || die "export_pkcs - inline_tmp"
|
||
|
if "$EASYRSA_OPENSSL" enc -a -in "$pkcs_out" > "$inline_tmp"
|
||
|
then
|
||
|
# make inline file
|
||
|
{
|
||
|
print "\
|
||
|
# Easy-RSA inline file: pkcs12
|
||
|
# commonName: ${inline_CN}${NL}"
|
||
|
print "<pkcs12>"
|
||
|
cat "$inline_tmp"
|
||
|
print "</pkcs12>"
|
||
|
} > "$inline_out" || die "export_pkcs - make inline"
|
||
|
|
||
|
inline_msg="\
|
||
|
A BASE64 encoded inline file has also been created at:
|
||
|
* ${inline_out}${NL}"
|
||
|
else
|
||
|
inline_msg="\
|
||
|
Failed to create a BASE64 encoded inline file${NL}"
|
||
|
fi
|
||
|
;;
|
||
|
p7)
|
||
|
pkcs_out="$EASYRSA_PKI/issued/$file_name_base.p7b"
|
||
|
|
||
|
# export the p7:
|
||
|
easyrsa_openssl crl2pkcs7 -nocrl \
|
||
|
-certfile "$crt_in" \
|
||
|
-out "$pkcs_out" \
|
||
|
${want_ca:+ -certfile "$crt_ca"} \
|
||
|
|| die "Failed to export PKCS#7"
|
||
|
;;
|
||
|
p8)
|
||
|
pkcs_out="$EASYRSA_PKI/private/$file_name_base.p8"
|
||
|
|
||
|
# export the p8:
|
||
|
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/$file_name_base.p1"
|
||
|
|
||
|
# OpenSSLv3 requires -traditional 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
|
||
|
traditional=-traditional
|
||
|
else
|
||
|
unset -v traditional
|
||
|
fi
|
||
|
|
||
|
# export the p1:
|
||
|
easyrsa_openssl rsa \
|
||
|
-in "$key_in" \
|
||
|
-out "$pkcs_out" \
|
||
|
${traditional} \
|
||
|
${cipher} \
|
||
|
${EASYRSA_PASSIN:+ -passin "$EASYRSA_PASSIN"} \
|
||
|
${EASYRSA_PASSOUT:+ -passout "$EASYRSA_PASSOUT"} \
|
||
|
|| die "Failed to export PKCS#1"
|
||
|
;;
|
||
|
*) die "Unknown PKCS type: $pkcs_type"
|
||
|
esac
|
||
|
|
||
|
# User messages
|
||
|
notice "\
|
||
|
Successful export of $pkcs_type file. Your exported file is at:
|
||
|
* $pkcs_out"
|
||
|
[ "$inline_msg" ] && print "$inline_msg"
|
||
|
|
||
|
return 0
|
||
|
} # => export_pkcs()
|
||
|
|
||
|
# set-pass backend
|
||
|
set_pass() {
|
||
|
# values supplied by the user:
|
||
|
raw_file="$1"
|
||
|
file="$EASYRSA_PKI/private/$raw_file.key"
|
||
|
|
||
|
if [ "$raw_file" ]; then
|
||
|
shift
|
||
|
else
|
||
|
user_error "\
|
||
|
Missing argument: no name/file supplied."
|
||
|
fi
|
||
|
|
||
|
# parse command options
|
||
|
cipher="-aes256"
|
||
|
while [ "$1" ]; do
|
||
|
case "$1" in
|
||
|
nopass)
|
||
|
[ "$prohibit_no_pass" ] || EASYRSA_NO_PASS=1
|
||
|
;;
|
||
|
file)
|
||
|
file="$raw_file"
|
||
|
;;
|
||
|
*) user_error "Unknown command option: '$1'"
|
||
|
esac
|
||
|
shift
|
||
|
done
|
||
|
|
||
|
# If nopass then do not encrypt else encrypt with password.
|
||
|
if [ "$EASYRSA_NO_PASS" ]; then
|
||
|
unset -v cipher
|
||
|
fi
|
||
|
|
||
|
[ -f "$file" ] || user_error "\
|
||
|
Missing private key: expected to find the private key file at:
|
||
|
* $file"
|
||
|
|
||
|
notice "\
|
||
|
If the key is encrypted then you must supply the current password.
|
||
|
${cipher:+You will then enter a new password for this key.$NL}"
|
||
|
|
||
|
# Set password
|
||
|
out_key_tmp=""
|
||
|
easyrsa_mktemp out_key_tmp || \
|
||
|
die "set_pass - easyrsa_mktemp out_key_tmp"
|
||
|
|
||
|
easyrsa_openssl pkey -in "$file" -out "$out_key_tmp" \
|
||
|
${cipher:+ "$cipher"} \
|
||
|
${EASYRSA_PASSIN:+ -passin "$EASYRSA_PASSIN"} \
|
||
|
${EASYRSA_PASSOUT:+ -passout "$EASYRSA_PASSOUT"} || \
|
||
|
die "Failed to change the private key passphrase."
|
||
|
|
||
|
# Move old key-file out of the way
|
||
|
mv "$file" "${file}.tmp" || \
|
||
|
die "Failed to move the old-key file."
|
||
|
|
||
|
# Move new key-file into place
|
||
|
if mv "$out_key_tmp" "$file"; then
|
||
|
rm -f "${file}.tmp"
|
||
|
else
|
||
|
mv -f "${file}.tmp" "$file"
|
||
|
die "Failed to update the private key file."
|
||
|
fi
|
||
|
|
||
|
key_update=changed
|
||
|
[ "$EASYRSA_NO_PASS" ] && key_update=removed
|
||
|
notice "Key passphrase successfully $key_update"
|
||
|
} # => set_pass()
|
||
|
|
||
|
# update-db backend
|
||
|
update_db() {
|
||
|
easyrsa_openssl ca -utf8 -updatedb \
|
||
|
${EASYRSA_PASSIN:+ -passin "$EASYRSA_PASSIN"} || \
|
||
|
die "Failed to perform update-db."
|
||
|
} # => update_db()
|
||
|
|
||
|
# display cert DN info on a req/X509, passed by full pathname
|
||
|
display_dn() {
|
||
|
[ "$#" = 2 ] || die "\
|
||
|
display_dn - input error"
|
||
|
|
||
|
format="$1"
|
||
|
path="$2"
|
||
|
shift 2
|
||
|
|
||
|
# Display DN
|
||
|
"$EASYRSA_OPENSSL" "$format" -in "$path" -noout -subject \
|
||
|
-nameopt utf8,sep_multiline,space_eq,lname,align
|
||
|
} # => display_dn()
|
||
|
|
||
|
# verify a file seems to be a valid req/X509
|
||
|
verify_file() {
|
||
|
format="$1"
|
||
|
path="$2"
|
||
|
"$EASYRSA_OPENSSL" "$format" -in "$path" -noout 2>/dev/null
|
||
|
} # => verify_file()
|
||
|
|
||
|
# show-* command backend
|
||
|
# Prints req/cert details in a readable format
|
||
|
show() {
|
||
|
type="$1"
|
||
|
name="$2"
|
||
|
in_file=""
|
||
|
format=""
|
||
|
[ "$name" ] || user_error "\
|
||
|
Missing expected <file_name_base> argument.
|
||
|
Run easyrsa without commands for usage help."
|
||
|
shift 2
|
||
|
|
||
|
# opts support
|
||
|
type_opts="-${type}opt"
|
||
|
out_opts="no_pubkey,no_sigdump"
|
||
|
name_opts="utf8,sep_multiline,space_eq,lname,align"
|
||
|
while [ "$1" ]; do
|
||
|
case "$1" in
|
||
|
full) out_opts= ;;
|
||
|
*) warn "Ignoring unknown command option: '$1'"
|
||
|
esac
|
||
|
shift
|
||
|
done
|
||
|
|
||
|
# Determine cert/req type (v2)
|
||
|
case "$type" in
|
||
|
cert)
|
||
|
in_file="$EASYRSA_PKI/issued/$name.crt"
|
||
|
format="x509"
|
||
|
;;
|
||
|
req)
|
||
|
in_file="$EASYRSA_PKI/reqs/$name.req"
|
||
|
format="req"
|
||
|
;;
|
||
|
crl)
|
||
|
in_file="$EASYRSA_PKI/$name.pem"
|
||
|
format="crl"
|
||
|
unset -v type_opts out_opts name_opts
|
||
|
;;
|
||
|
*) die "Unrecognised type: $type"
|
||
|
esac
|
||
|
|
||
|
# Verify file exists and is of the correct type
|
||
|
[ -f "$in_file" ] || user_error "\
|
||
|
No such '$type' type file with a <file_name_base> of '$name'.
|
||
|
Expected to find this file at:
|
||
|
* $in_file"
|
||
|
|
||
|
verify_file "$format" "$in_file" || user_error "\
|
||
|
This file is not a valid $type file:
|
||
|
* $in_file"
|
||
|
|
||
|
notice "\
|
||
|
Showing '$type' details for: '$name'
|
||
|
|
||
|
This file is stored at:
|
||
|
* $in_file${NL}"
|
||
|
|
||
|
easyrsa_openssl "$format" -in "$in_file" -noout -text \
|
||
|
${type_opts:+ "$type_opts" "$out_opts"} \
|
||
|
${name_opts:+ -nameopt "$name_opts"} || \
|
||
|
die "OpenSSL failure to process the input"
|
||
|
} # => show()
|
||
|
|
||
|
# show-ca command backend
|
||
|
# Prints CA cert details in a readable format
|
||
|
show_ca() {
|
||
|
# opts support
|
||
|
out_opts="no_pubkey,no_sigdump"
|
||
|
name_opts="utf8,sep_multiline,space_eq,lname,align"
|
||
|
while [ "$1" ]; do
|
||
|
case "$1" in
|
||
|
full) out_opts= ;;
|
||
|
*) warn "Ignoring unknown command option: '$1'"
|
||
|
esac
|
||
|
shift
|
||
|
done
|
||
|
|
||
|
in_file="$EASYRSA_PKI/ca.crt"
|
||
|
format="x509"
|
||
|
|
||
|
# Verify file exists and is of the correct type
|
||
|
[ -f "$in_file" ] || user_error "\
|
||
|
No such $type file with a basename of '$name' is present.
|
||
|
Expected to find this file at:
|
||
|
$in_file"
|
||
|
|
||
|
verify_file "$format" "$in_file" || user_error "\
|
||
|
This file is not a valid $type file:
|
||
|
$in_file"
|
||
|
|
||
|
notice "\
|
||
|
Showing details for CA certificate, at:
|
||
|
* $in_file${NL}"
|
||
|
|
||
|
easyrsa_openssl "$format" -in "$in_file" -noout -text \
|
||
|
-nameopt "$name_opts" -certopt "$out_opts" || \
|
||
|
die "OpenSSL failure to process the input"
|
||
|
} # => show_ca()
|
||
|
|
||
|
# Certificate X509v3 Extended Key Usage
|
||
|
ssl_cert_x509v3_eku() {
|
||
|
[ "$1" ] || die "ssl_cert_x509v3_eku - Missing input"
|
||
|
|
||
|
# check input file name
|
||
|
if [ -f "$1" ]; then
|
||
|
__crt="$1"
|
||
|
else
|
||
|
__crt="${EASYRSA_PKI}/issued/${1}.crt"
|
||
|
[ -f "$__crt" ] || \
|
||
|
die "ssl_cert_x509v3_eku - Missing cert '$__crt'"
|
||
|
fi
|
||
|
|
||
|
# Set output variable
|
||
|
__var="$2"
|
||
|
shift "$#"
|
||
|
|
||
|
# required variables
|
||
|
__pattern="X509v3 Extended Key Usage:"
|
||
|
__cli="TLS Web Client Authentication"
|
||
|
__srv="TLS Web Server Authentication"
|
||
|
__srv_cli="${__srv}, ${__cli}"
|
||
|
__codeSign="Code Signing"
|
||
|
unset -v __known
|
||
|
|
||
|
# Extract certificate Extended Key Usage
|
||
|
if [ "$ssl_lib" = libressl ]; then
|
||
|
__eku="$(
|
||
|
"$EASYRSA_OPENSSL" x509 -in "${__crt}" -noout -text | \
|
||
|
sed -n "/${__pattern}/{n;s/^ *//g;p;}"
|
||
|
)"
|
||
|
else
|
||
|
__eku="$(
|
||
|
"$EASYRSA_OPENSSL" x509 -in "${__crt}" -noout \
|
||
|
-ext extendedKeyUsage | \
|
||
|
sed -e /"${__pattern}"/d -e s/^\ *//
|
||
|
)"
|
||
|
fi
|
||
|
|
||
|
# Match EKU with supported usage
|
||
|
case "$__eku" in
|
||
|
"$__srv_cli")
|
||
|
__known=1
|
||
|
__type=serverClient
|
||
|
;;
|
||
|
"$__cli")
|
||
|
__known=1
|
||
|
__type=client
|
||
|
;;
|
||
|
"$__srv")
|
||
|
__known=1
|
||
|
__type=server
|
||
|
;;
|
||
|
"$__codeSign")
|
||
|
__known=1
|
||
|
__type=codeSign
|
||
|
;;
|
||
|
'')
|
||
|
__type=undefined
|
||
|
;;
|
||
|
*)
|
||
|
__type="'$__eku'"
|
||
|
esac
|
||
|
|
||
|
# Check for self-sign
|
||
|
if "$EASYRSA_OPENSSL" x509 -in "$__crt" -noout -text | \
|
||
|
grep -q 'CA:TRUE'
|
||
|
then
|
||
|
__type="self-signed-$__type"
|
||
|
fi
|
||
|
|
||
|
# Set variable to return
|
||
|
if [ "$__var" ]; then
|
||
|
verbose "ssl_cert_x509v3_eku - EKU: $__type"
|
||
|
force_set_var "$__var" "$__type"
|
||
|
elif [ "$__known" ]; then
|
||
|
information "
|
||
|
* Known X509v3 Extended Key Usage: $__type"
|
||
|
else
|
||
|
information "
|
||
|
* Unknown X509v3 Extended Key Usage: $__type"
|
||
|
fi
|
||
|
|
||
|
unset -v __crt __var __pattern __srv_cli __cli __srv \
|
||
|
__codeSign __eku __type
|
||
|
|
||
|
if [ "$__known" ]; then
|
||
|
unset -v __known
|
||
|
return
|
||
|
fi
|
||
|
|
||
|
# Also, catch errors from SSL x509 command
|
||
|
# for '__eku' subshell+pipe
|
||
|
return 1
|
||
|
} # => ssl_cert_x509v3_eku()
|
||
|
|
||
|
# get the serial number of the certificate -> serial=XXXX
|
||
|
ssl_cert_serial() {
|
||
|
[ "$#" = 2 ] || die "ssl_cert_serial - input error"
|
||
|
[ -f "$1" ] || die "ssl_cert_serial - missing cert"
|
||
|
|
||
|
fn_ssl_out="$(
|
||
|
"$EASYRSA_OPENSSL" x509 -in "$1" -noout -serial
|
||
|
)" || die "ssl_cert_serial - failed: -serial"
|
||
|
# remove the serial= part -> we only need the XXXX part
|
||
|
fn_ssl_out="${fn_ssl_out##*=}"
|
||
|
|
||
|
force_set_var "$2" "$fn_ssl_out" || \
|
||
|
die "ssl_cert_serial - failed to set var '$*'"
|
||
|
|
||
|
unset -v fn_ssl_out
|
||
|
} # => ssl_cert_serial()
|
||
|
|
||
|
# Identify host OS
|
||
|
detect_host() {
|
||
|
unset -v \
|
||
|
easyrsa_ver_test easyrsa_host_os easyrsa_host_test \
|
||
|
easyrsa_win_git_bash
|
||
|
|
||
|
# Detect Windows
|
||
|
[ "${OS}" ] && easyrsa_host_test="${OS}"
|
||
|
|
||
|
# shellcheck disable=SC2016 # No expand '' - detect_host()
|
||
|
easyrsa_ksh=\
|
||
|
'@(#)MIRBSD KSH R39-w32-beta14 $Date: 2013/06/28 21:28:57 $'
|
||
|
|
||
|
[ "${KSH_VERSION}" = "${easyrsa_ksh}" ] && \
|
||
|
easyrsa_host_test="${easyrsa_ksh}"
|
||
|
unset -v easyrsa_ksh
|
||
|
|
||
|
# If not Windows then nix
|
||
|
if [ "${easyrsa_host_test}" ]; then
|
||
|
easyrsa_host_os=win
|
||
|
easyrsa_uname="${easyrsa_host_test}"
|
||
|
easyrsa_shell="$SHELL"
|
||
|
# Detect Windows git/bash
|
||
|
if [ "${EXEPATH}" ]; then
|
||
|
easyrsa_shell="$SHELL (Git)"
|
||
|
easyrsa_win_git_bash="${EXEPATH}"
|
||
|
# If found then set openssl NOW!
|
||
|
#[ -e /usr/bin/openssl ] && \
|
||
|
# set_var EASYRSA_OPENSSL /usr/bin/openssl
|
||
|
fi
|
||
|
else
|
||
|
easyrsa_host_os=nix
|
||
|
easyrsa_uname="$(uname 2>/dev/null)"
|
||
|
easyrsa_shell="${SHELL:-undefined}"
|
||
|
fi
|
||
|
|
||
|
easyrsa_ver_test="${EASYRSA_version%%~*}"
|
||
|
if [ "$easyrsa_ver_test" ]; then
|
||
|
host_out="Host: $EASYRSA_version"
|
||
|
else
|
||
|
host_out="Host: dev"
|
||
|
fi
|
||
|
|
||
|
host_out="\
|
||
|
$host_out | $easyrsa_host_os | $easyrsa_uname | $easyrsa_shell"
|
||
|
host_out="\
|
||
|
${host_out}${easyrsa_win_git_bash+ | "$easyrsa_win_git_bash"}"
|
||
|
unset -v easyrsa_ver_test easyrsa_host_test
|
||
|
} # => detect_host()
|
||
|
|
||
|
# Extra diagnostics
|
||
|
show_host() {
|
||
|
[ "$EASYRSA_SILENT" ] && return
|
||
|
print_version
|
||
|
print "$host_out"
|
||
|
[ "$EASYRSA_DEBUG" ] || return 0
|
||
|
case "$easyrsa_host_os" in
|
||
|
win) set ;;
|
||
|
nix) env ;;
|
||
|
*) print "Unknown host OS: $easyrsa_host_os"
|
||
|
esac
|
||
|
} # => show_host()
|
||
|
|
||
|
# Verify the selected algorithm parameters
|
||
|
verify_algo_params() {
|
||
|
case "$EASYRSA_ALGO" in
|
||
|
rsa)
|
||
|
# Set RSA key size
|
||
|
EASYRSA_ALGO_PARAMS="$EASYRSA_KEY_SIZE"
|
||
|
;;
|
||
|
ec)
|
||
|
# Verify Elliptic curve
|
||
|
EASYRSA_ALGO_PARAMS=""
|
||
|
easyrsa_mktemp EASYRSA_ALGO_PARAMS || \
|
||
|
die "\
|
||
|
verify_algo_params - easyrsa_mktemp EASYRSA_ALGO_PARAMS"
|
||
|
|
||
|
# Create the required ecparams file, temp-file
|
||
|
# call openssl directly because error is expected
|
||
|
"$EASYRSA_OPENSSL" ecparam \
|
||
|
-name "$EASYRSA_CURVE" \
|
||
|
-out "$EASYRSA_ALGO_PARAMS" \
|
||
|
>/dev/null 2>&1 || user_error "\
|
||
|
Failed to generate ecparam file for curve '$EASYRSA_CURVE'"
|
||
|
;;
|
||
|
ed)
|
||
|
# Verify Edwards curve
|
||
|
# call openssl directly because error is expected
|
||
|
"$EASYRSA_OPENSSL" genpkey \
|
||
|
-algorithm "$EASYRSA_CURVE" \
|
||
|
>/dev/null 2>&1 || user_error "\
|
||
|
Edwards Curve '$EASYRSA_CURVE' not found."
|
||
|
;;
|
||
|
*) user_error "\
|
||
|
Unknown algorithm '$EASYRSA_ALGO': Must be 'rsa', 'ec' or 'ed'"
|
||
|
esac
|
||
|
verbose "\
|
||
|
verify_algo_params: Params verified for algo '$EASYRSA_ALGO' OK"
|
||
|
} # => verify_algo_params()
|
||
|
|
||
|
# Check for conflicting input options
|
||
|
mutual_exclusions() {
|
||
|
# --nopass cannot be used with --passout
|
||
|
if [ "$EASYRSA_PASSOUT" ]; then
|
||
|
# --passout MUST take priority over --nopass
|
||
|
[ "$EASYRSA_NO_PASS" ] && warn "\
|
||
|
Option --passout cannot be used with --nopass|nopass."
|
||
|
unset -v EASYRSA_NO_PASS
|
||
|
prohibit_no_pass=1
|
||
|
fi
|
||
|
|
||
|
# --silent-ssl requires --batch
|
||
|
if [ "$EASYRSA_SILENT_SSL" ]; then
|
||
|
[ "$EASYRSA_BATCH" ] || warn "\
|
||
|
Option --silent-ssl requires batch mode --batch."
|
||
|
fi
|
||
|
|
||
|
# --startdate requires --enddate
|
||
|
# otherwise, --days counts from now
|
||
|
if [ "$EASYRSA_START_DATE" ]; then
|
||
|
[ "$EASYRSA_END_DATE" ] || user_error "\
|
||
|
Use of --startdate requires use of --enddate."
|
||
|
fi
|
||
|
|
||
|
# --enddate may over-rule EASYRSA_CERT_EXPIRE
|
||
|
if [ "$EASYRSA_END_DATE" ]; then
|
||
|
case "$cmd" in
|
||
|
sign-req|build-*-full|renew)
|
||
|
# User specified alias_days IS over-ruled
|
||
|
if [ "$alias_days" ]; then
|
||
|
warn "\
|
||
|
Option --days is over-ruled by option --enddate."
|
||
|
fi
|
||
|
unset -v EASYRSA_CERT_EXPIRE alias_days
|
||
|
;;
|
||
|
*)
|
||
|
warn "\
|
||
|
EasyRSA '$cmd' does not support --startdate or --enddate"
|
||
|
unset -v EASYRSA_START_DATE EASYRSA_END_DATE
|
||
|
esac
|
||
|
fi
|
||
|
|
||
|
# Insecure Windows directory
|
||
|
if [ "$easyrsa_host_os" = win ]; then
|
||
|
if echo "$PWD" | grep -q '/Prog.*/OpenVPN/easy-rsa'
|
||
|
then
|
||
|
verbose "\
|
||
|
Using Windows-System-Folders for your PKI is NOT SECURE!
|
||
|
Your Easy-RSA PKI CA Private Key is WORLD readable.
|
||
|
|
||
|
To correct this problem, it is recommended that you either:
|
||
|
* Copy Easy-RSA to your User folders and run it from there, OR
|
||
|
* Define your PKI to be in your User folders. EG:
|
||
|
'easyrsa --pki-dir=\"C:/Users/<your-user-name>/easy-rsa/pki\"\
|
||
|
<command>'"
|
||
|
fi
|
||
|
fi
|
||
|
|
||
|
verbose "mutual_exclusions: COMPLETED"
|
||
|
} # => mutual_exclusions()
|
||
|
|
||
|
# Select vars in order preference:
|
||
|
# Here sourcing of 'vars' if present occurs.
|
||
|
# If not present, defaults are used to support
|
||
|
# running without a sourced config format.
|
||
|
select_vars() {
|
||
|
# User specified vars file will be used ONLY
|
||
|
if [ "$EASYRSA_VARS_FILE" ]; then
|
||
|
# Takes priority, nothing to do
|
||
|
verbose "select_vars: EASYRSA_VARS_FILE"
|
||
|
|
||
|
# This is where auto-load goes bananas
|
||
|
else
|
||
|
|
||
|
# User specified PKI; if vars exists, use it ONLY
|
||
|
if [ "$EASYRSA_PKI" ]; then
|
||
|
if [ -f "$EASYRSA_PKI/vars" ]; then
|
||
|
verbose "select_vars: source EASYRSA_PKI/vars"
|
||
|
set_var EASYRSA_VARS_FILE "$EASYRSA_PKI/vars"
|
||
|
fi
|
||
|
fi
|
||
|
|
||
|
# User specified EASYRSA; if vars exists, use it ONLY
|
||
|
if [ "$EASYRSA" ]; then
|
||
|
if [ -f "$EASYRSA/vars" ]; then
|
||
|
verbose "select_vars: EASYRSA/vars"
|
||
|
set_var EASYRSA_VARS_FILE "$EASYRSA/vars"
|
||
|
fi
|
||
|
fi
|
||
|
|
||
|
# Default PKI; if vars exists, use it ONLY
|
||
|
if [ -f "$PWD/pki/vars" ] && \
|
||
|
[ -z "$EASYRSA_PKI" ] && \
|
||
|
[ -z "$EASYRSA" ]
|
||
|
then
|
||
|
# Prevent vars from changing expected PKI.
|
||
|
# A vars in the PKI MUST always imply EASYRSA_PKI
|
||
|
# This is NOT backward compatible
|
||
|
# Use expected value comparison for v3.1.7
|
||
|
if [ -z "$EASYRSA_VARS_FILE" ]; then
|
||
|
expected_EASYRSA="$PWD"
|
||
|
expected_EASYRSA_PKI="$PWD/pki"
|
||
|
fi
|
||
|
|
||
|
# Use this for v3.2.0
|
||
|
# If the pki/vars sets a different PKI then
|
||
|
# there will be no PKI in the default /pki
|
||
|
#set_var EASYRSA "$PWD"
|
||
|
#set_var EASYRSA_PKI "$EASYRSA/pki"
|
||
|
|
||
|
verbose "select_vars: PWD/pki/vars"
|
||
|
set_var EASYRSA_VARS_FILE "$PWD/pki/vars"
|
||
|
fi
|
||
|
|
||
|
# Default working dir; if vars exists, use it ONLY
|
||
|
if [ -f "$PWD/vars" ]; then
|
||
|
verbose "select_vars: PWD/vars"
|
||
|
set_var EASYRSA_VARS_FILE "$PWD/vars"
|
||
|
fi
|
||
|
fi
|
||
|
|
||
|
# if select_vars failed to find a vars file
|
||
|
if [ -z "$EASYRSA_VARS_FILE" ]; then
|
||
|
verbose "select_vars: No vars"
|
||
|
return 1
|
||
|
fi
|
||
|
} # => select_vars()
|
||
|
|
||
|
# Source a vars file
|
||
|
source_vars() {
|
||
|
# File to be sourced
|
||
|
target_file="$1"
|
||
|
|
||
|
# 'vars' MUST not be a directory
|
||
|
[ -d "$target_file" ] && user_error "\
|
||
|
Missing vars file:
|
||
|
* $target_file"
|
||
|
|
||
|
# 'vars' now MUST exist
|
||
|
[ -f "$target_file" ] || user_error "\
|
||
|
Missing vars file:
|
||
|
* $target_file"
|
||
|
|
||
|
# Sanitize vars
|
||
|
if grep -q \
|
||
|
-e 'EASYRSA_PASSIN' -e 'EASYRSA_PASSOUT' \
|
||
|
-e '[^(]`[^)]' \
|
||
|
-e 'export ' \
|
||
|
-e 'unset ' \
|
||
|
"$target_file"
|
||
|
then
|
||
|
# here we go ..
|
||
|
err_msg="\
|
||
|
These problems have been found in your 'vars' settings:${NL}"
|
||
|
|
||
|
# No passwords!
|
||
|
if grep -q \
|
||
|
-e 'EASYRSA_PASSIN' -e 'EASYRSA_PASSOUT' \
|
||
|
"$target_file"
|
||
|
then
|
||
|
err_msg="${err_msg}
|
||
|
Use of 'EASYRSA_PASSIN' or 'EASYRSA_PASSOUT':
|
||
|
Storing password information in the 'vars' file is not permitted."
|
||
|
fi
|
||
|
|
||
|
# No backticks
|
||
|
if grep -q \
|
||
|
-e '[^(]`[^)]' \
|
||
|
"$target_file"
|
||
|
then
|
||
|
err_msg="${err_msg}
|
||
|
Use of unsupported characters:
|
||
|
These characters are not supported: \` backtick"
|
||
|
fi
|
||
|
|
||
|
# No export
|
||
|
if grep -q \
|
||
|
-e 'export ' \
|
||
|
"$target_file"
|
||
|
then
|
||
|
err_msg="${err_msg}
|
||
|
Use of 'export':
|
||
|
Remove 'export' or replace it with 'set_var'."
|
||
|
fi
|
||
|
|
||
|
# No unset
|
||
|
if grep -q \
|
||
|
-e 'unset ' \
|
||
|
"$target_file"
|
||
|
then
|
||
|
err_msg="${err_msg}
|
||
|
Use of 'unset':
|
||
|
Remove 'unset' ('force_set_var' may also work)."
|
||
|
fi
|
||
|
|
||
|
# Fatal error
|
||
|
user_error "${err_msg}${NL}
|
||
|
Please, correct these errors and try again."
|
||
|
|
||
|
else
|
||
|
verbose "source_vars: CLEAN '$target_file'"
|
||
|
fi
|
||
|
|
||
|
# Enable sourcing 'vars'
|
||
|
# shellcheck disable=SC2034 # appears unused - source_vars()
|
||
|
EASYRSA_CALLER=1
|
||
|
easyrsa_path="$PATH"
|
||
|
# shellcheck disable=SC2123 # PATH is - source_vars()
|
||
|
PATH=./
|
||
|
|
||
|
# Test sourcing 'vars' in a subshell
|
||
|
# shellcheck disable=1090 # can't follow - source_vars()
|
||
|
if ( . "$target_file" ); then
|
||
|
# Source 'vars' now
|
||
|
# shellcheck disable=1090 # can't follow - source_vars()
|
||
|
. "$target_file" || \
|
||
|
die "Failed to source the '$target_file' file."
|
||
|
else
|
||
|
PATH="$easyrsa_path"
|
||
|
die "Failed to dry-run the '$target_file' file."
|
||
|
fi
|
||
|
|
||
|
PATH="$easyrsa_path"
|
||
|
verbose "source_vars: sourced OK '$target_file'"
|
||
|
unset -v EASYRSA_CALLER easyrsa_path target_file
|
||
|
} # => source_vars()
|
||
|
|
||
|
# Set defaults
|
||
|
default_vars() {
|
||
|
# Set defaults, preferring existing env-vars if present
|
||
|
set_var EASYRSA "$PWD"
|
||
|
set_var EASYRSA_OPENSSL openssl
|
||
|
set_var EASYRSA_PKI "$EASYRSA/pki"
|
||
|
set_var EASYRSA_DN cn_only
|
||
|
set_var EASYRSA_REQ_COUNTRY "US"
|
||
|
set_var EASYRSA_REQ_PROVINCE "California"
|
||
|
set_var EASYRSA_REQ_CITY "San Francisco"
|
||
|
set_var EASYRSA_REQ_ORG "Copyleft Certificate Co"
|
||
|
set_var EASYRSA_REQ_EMAIL me@example.net
|
||
|
set_var EASYRSA_REQ_OU "My Organizational Unit"
|
||
|
set_var EASYRSA_REQ_SERIAL ""
|
||
|
set_var EASYRSA_ALGO rsa
|
||
|
set_var EASYRSA_KEY_SIZE 2048
|
||
|
|
||
|
case "$EASYRSA_ALGO" in
|
||
|
rsa)
|
||
|
: # ok
|
||
|
# default EASYRSA_KEY_SIZE must always be set
|
||
|
# it must NOT be set selectively because it is
|
||
|
# present in the SSL config file
|
||
|
;;
|
||
|
ec)
|
||
|
set_var EASYRSA_CURVE secp384r1
|
||
|
;;
|
||
|
ed)
|
||
|
set_var EASYRSA_CURVE ed25519
|
||
|
;;
|
||
|
*) user_error "\
|
||
|
Algorithm '$EASYRSA_ALGO' is invalid: Must be 'rsa', 'ec' or 'ed'"
|
||
|
esac
|
||
|
|
||
|
set_var EASYRSA_CA_EXPIRE 3650
|
||
|
set_var EASYRSA_CERT_EXPIRE 825
|
||
|
set_var \
|
||
|
EASYRSA_PRE_EXPIRY_WINDOW 90
|
||
|
set_var EASYRSA_CRL_DAYS 180
|
||
|
set_var EASYRSA_NS_SUPPORT no
|
||
|
set_var EASYRSA_NS_COMMENT \
|
||
|
"Easy-RSA (~VER~) Generated Certificate"
|
||
|
|
||
|
set_var EASYRSA_TEMP_DIR "$EASYRSA_PKI"
|
||
|
set_var EASYRSA_REQ_CN ChangeMe
|
||
|
set_var EASYRSA_DIGEST sha256
|
||
|
|
||
|
set_var EASYRSA_KDC_REALM "CHANGEME.EXAMPLE.COM"
|
||
|
|
||
|
set_var EASYRSA_MAX_TEMP 1
|
||
|
} # => default_vars()
|
||
|
|
||
|
# Validate expected values for EASYRSA and EASYRSA_PKI
|
||
|
validate_default_vars() {
|
||
|
unset -v unexpected_error
|
||
|
|
||
|
# Keep checks separate
|
||
|
# EASYRSA
|
||
|
if [ "$expected_EASYRSA" ]; then
|
||
|
[ "$expected_EASYRSA" = "$EASYRSA" ] || \
|
||
|
unexpected_error="\
|
||
|
EASYRSA: $EASYRSA
|
||
|
Expected: $expected_EASYRSA"
|
||
|
fi
|
||
|
|
||
|
# EASYRSA_PKI
|
||
|
if [ "$expected_EASYRSA_PKI" ]; then
|
||
|
if [ "$expected_EASYRSA_PKI" = "$EASYRSA_PKI" ]; then
|
||
|
: # ok
|
||
|
else
|
||
|
if [ "$unexpected_error" ]; then
|
||
|
# Add a new-line Extra separator, for clarity
|
||
|
unexpected_error="${unexpected_error}${NL}${NL}"
|
||
|
fi
|
||
|
unexpected_error="${unexpected_error}\
|
||
|
EASYRSA_PKI: $EASYRSA_PKI
|
||
|
Expected: $expected_EASYRSA_PKI"
|
||
|
fi
|
||
|
fi
|
||
|
|
||
|
# Return no error
|
||
|
[ -z "$unexpected_error" ] && return
|
||
|
|
||
|
# This is an almost unacceptable error
|
||
|
invalid_vars=1
|
||
|
[ "$quiet_vars" ] || user_error "\
|
||
|
The values in the vars file have unexpectedly changed the values for
|
||
|
EASYRSA and/or EASYRSA_PKI. The default pki/vars file is forbidden to
|
||
|
change these values.
|
||
|
|
||
|
vars-file: $EASYRSA_VARS_FILE
|
||
|
|
||
|
${unexpected_error}"
|
||
|
} # => validate_default_vars()
|
||
|
|
||
|
# Verify working environment
|
||
|
verify_working_env() {
|
||
|
verbose "verify_working_env: BEGIN"
|
||
|
# For commands which 'require a PKI' and PKI exists
|
||
|
if [ "$require_pki" ]; then
|
||
|
# Verify PKI is initialised
|
||
|
verify_pki_init
|
||
|
|
||
|
# Temp dir session
|
||
|
secure_session
|
||
|
|
||
|
# global safe ssl cnf temp
|
||
|
write_global_safe_ssl_cnf_tmp
|
||
|
|
||
|
# Verify selected algorithm and parameters
|
||
|
verify_algo_params
|
||
|
|
||
|
# Verify CA is initialised
|
||
|
if [ "$require_ca" ]; then
|
||
|
verify_ca_init
|
||
|
fi
|
||
|
else
|
||
|
# For commands that do not require a PKI
|
||
|
# but do require a temp-dir, eg. 'write'
|
||
|
# If there is a valid temp-dir:
|
||
|
# Create temp-session and openssl-easyrsa.cnf (Temp) now
|
||
|
if [ -d "$EASYRSA_TEMP_DIR" ]; then
|
||
|
# Temp dir session
|
||
|
secure_session
|
||
|
|
||
|
# global safe ssl cnf temp
|
||
|
write_global_safe_ssl_cnf_tmp
|
||
|
fi
|
||
|
fi
|
||
|
verbose "verify_working_env: COMPLETED Handover-to: $cmd"
|
||
|
} # => verify_working_env()
|
||
|
|
||
|
# variable assignment by indirection.
|
||
|
# Sets '$1' as the value contained in '$2'
|
||
|
# and exports (may be blank)
|
||
|
set_var() {
|
||
|
[ -z "$*" ] && return
|
||
|
[ -z "$3" ] || \
|
||
|
user_error "set_var - excess input '$*'"
|
||
|
case "$1" in
|
||
|
*=*) user_error "set_var - var '$1'"
|
||
|
esac
|
||
|
eval "export \"$1\"=\"\${$1-$2}\"" && return
|
||
|
die "set_var - eval '$*'"
|
||
|
} # => set_var()
|
||
|
|
||
|
# sanitize and set var
|
||
|
# nix.sh/win.sh/busybox.sh never return error from unset
|
||
|
# when an invalid variable name 'a=b' is used with a value
|
||
|
# to set, eg. 'c'; This causes EasyRSA to execute:
|
||
|
# eval "export a=b=c". 'set_var EASYRSA_PKI=pki' results in
|
||
|
# $EASYRSA_PKI being set to 'pki=pki-', without error!
|
||
|
# Guard against this possible user error with 'case'.
|
||
|
force_set_var() {
|
||
|
[ -z "$3" ] || \
|
||
|
user_error "force_set_var - excess input '$*'"
|
||
|
case "$1" in
|
||
|
*=*) user_error "force_set_var - var '$1'"
|
||
|
esac
|
||
|
# force unsetting $1; Guard unset with '|| die', just in case
|
||
|
unset -v "$1" || die "force_set_var - unset '$1'"
|
||
|
# Allow empty value to unset variable by returning
|
||
|
[ "$2" ] || return 0
|
||
|
set_var "$1" "$2" && return
|
||
|
die "force_set_var - set_var '$*'"
|
||
|
} # => force_set_var()
|
||
|
|
||
|
# global Safe SSL conf file, for use by any SSL lib
|
||
|
write_global_safe_ssl_cnf_tmp() {
|
||
|
global_safe_ssl_cnf_tmp=
|
||
|
easyrsa_mktemp global_safe_ssl_cnf_tmp || die "\
|
||
|
verify_working_env - easyrsa_mktemp global_safe_ssl_cnf_tmp"
|
||
|
|
||
|
write_legacy_file_v2 safe-cnf "$global_safe_ssl_cnf_tmp" || \
|
||
|
die "verify_working_env - write safe-cnf"
|
||
|
|
||
|
export OPENSSL_CONF="$global_safe_ssl_cnf_tmp"
|
||
|
verbose "GLOBAL - OPENSSL_CONF = $OPENSSL_CONF"
|
||
|
} # => write_global_safe_ssl_cnf_tmp()
|
||
|
|
||
|
# Create as needed: $EASYRSA_SSL_CONF pki/openssl-easyrsa.cnf
|
||
|
# If the existing file has a known hash then use temp-file.
|
||
|
# Otherwise, use the file in place.
|
||
|
write_easyrsa_ssl_cnf_tmp() {
|
||
|
if [ -f "$EASYRSA_SSL_CONF" ]; then
|
||
|
verbose "write_easyrsa_ssl_cnf_tmp: SSL config EXISTS"
|
||
|
|
||
|
# Set known hashes
|
||
|
# 3.1.7 -> Current
|
||
|
known_file_317="\
|
||
|
13ca05f031d58c5e2912652b33099ce9\
|
||
|
ac05f49595e5d5fe96367229e3ce070c"
|
||
|
|
||
|
# 3.1.5 -> 3.1.6
|
||
|
known_file_315="\
|
||
|
87d51ca0db1cc0ac3cc2634792fc5576\
|
||
|
e0034ebf9d546de11674b897514f3afb"
|
||
|
|
||
|
# 3.1.0 -> 3.1.4
|
||
|
known_file_310="\
|
||
|
5455947df40f01f845bf79c1e89f102c\
|
||
|
628faaa65d71a6512d0e17bdd183feb0"
|
||
|
|
||
|
# 3.0.8 -> 3.0.9
|
||
|
known_file_308="\
|
||
|
1cc6a1de93ca357b5c364aa0fa2c4bea\
|
||
|
f97425686fa1976d436fa31f550641aa"
|
||
|
|
||
|
# Built-in here-doc 3.2.0
|
||
|
known_heredoc_320="\
|
||
|
82439f1860838e28f6270d5d06b17717\
|
||
|
56db777861e19bf9edc21222f86a310d"
|
||
|
|
||
|
# Get file hash
|
||
|
file_hash="$(
|
||
|
"$EASYRSA_OPENSSL" dgst -sha256 -r \
|
||
|
"$EASYRSA_SSL_CONF" 2>/dev/null
|
||
|
)" || die "write_easyrsa_ssl_cnf_tmp - hash malfunction!"
|
||
|
|
||
|
# Strip excess SSL info
|
||
|
file_hash="${file_hash%% *}"
|
||
|
|
||
|
# Compare SSL output
|
||
|
case "$file_hash" in
|
||
|
*[!1234567890abcdef]*|'')
|
||
|
die "write_easyrsa_ssl_cnf_tmp - hash failure!"
|
||
|
esac
|
||
|
|
||
|
# Check file hash against known hash
|
||
|
hash_is_unknown=""
|
||
|
|
||
|
case "$file_hash" in
|
||
|
"$known_file_317") ;;
|
||
|
"$known_file_315") ;;
|
||
|
"$known_file_310") ;;
|
||
|
"$known_file_308") ;;
|
||
|
"$known_heredoc_320") ;;
|
||
|
|
||
|
*)
|
||
|
# File is unknown or has been changed
|
||
|
# leave in place
|
||
|
hash_is_unknown=1
|
||
|
esac
|
||
|
|
||
|
# Cleanup
|
||
|
unset -v file_hash known_heredoc_320 \
|
||
|
known_file_317 \
|
||
|
known_file_315 \
|
||
|
known_file_310 \
|
||
|
known_file_308
|
||
|
|
||
|
# Use the existing file ONLY
|
||
|
if [ "$hash_is_unknown" ] || [ "$EASYRSA_FORCE_SAFE_SSL" ]
|
||
|
then
|
||
|
unset -v hash_is_unknown
|
||
|
verbose "write_easyrsa_ssl_cnf_tmp: SSL config UNKNOWN!"
|
||
|
|
||
|
# Auto-escape hazardous characters
|
||
|
escape_hazard || \
|
||
|
die "easyrsa_openssl - escape_hazard failed"
|
||
|
|
||
|
# Rewrite SSL config
|
||
|
expand_ssl_config || \
|
||
|
die "easyrsa_openssl - expand_ssl_config failed"
|
||
|
|
||
|
return 0
|
||
|
fi
|
||
|
|
||
|
# Ignore existing file, prefer to use a temp-file
|
||
|
verbose "write_easyrsa_ssl_cnf_tmp: SSL config KNOWN"
|
||
|
fi
|
||
|
|
||
|
# SET and USE temp-file from here-doc Now
|
||
|
# Create temp-file
|
||
|
ssl_cnf_tmp=
|
||
|
easyrsa_mktemp ssl_cnf_tmp || die "\
|
||
|
write_easyrsa_ssl_cnf_tmp - easyrsa_mktemp"
|
||
|
|
||
|
# Write SSL cnf to temp-file
|
||
|
write_legacy_file_v2 "$ssl_cnf_type" "$ssl_cnf_tmp" || die "\
|
||
|
write_easyrsa_ssl_cnf_tmp - write $ssl_cnf_type: $ssl_cnf_tmp"
|
||
|
|
||
|
# export SSL cnf tmp
|
||
|
export EASYRSA_SSL_CONF="$ssl_cnf_tmp"
|
||
|
verbose "\
|
||
|
write_easyrsa_ssl_cnf_tmp: $ssl_cnf_type \
|
||
|
- EASYRSA_SSL_CONF = $EASYRSA_SSL_CONF"
|
||
|
|
||
|
export OPENSSL_CONF="$EASYRSA_SSL_CONF"
|
||
|
verbose "LOCAL - OPENSSL_CONF = $OPENSSL_CONF"
|
||
|
} # => write_easyrsa_ssl_cnf_tmp()
|
||
|
|
||
|
# Write x509 type file to a temp file
|
||
|
write_x509_type_tmp() {
|
||
|
# Verify x509-type before redirect
|
||
|
case "$1" in
|
||
|
COMMON|ca|server|serverClient|client|email| \
|
||
|
codeSigning|kdc|selfsign)
|
||
|
: # ok
|
||
|
;;
|
||
|
*)
|
||
|
die "write_x509_type_tmp - unknown type '$1'"
|
||
|
esac
|
||
|
|
||
|
write_x509_file_tmp=""
|
||
|
easyrsa_mktemp write_x509_file_tmp || \
|
||
|
die "write_x509_type_tmp - easyrsa_mktemp"
|
||
|
|
||
|
write_legacy_file_v2 "$1" "$write_x509_file_tmp" || \
|
||
|
die "write_x509_type_tmp - write $1"
|
||
|
|
||
|
|
||
|
verbose ": write_x509_type_tmp: $1 COMPLETE"
|
||
|
} # => write_x509_type_tmp()
|
||
|
|
||
|
############################################################################
|
||
|
#
|
||
|
# Create legacy files
|
||
|
#
|
||
|
|
||
|
# Write ALL legacy files to $1 or default
|
||
|
all_legacy_files_v2() {
|
||
|
# Confirm over write
|
||
|
if [ "$legacy_file_over_write" ]; then
|
||
|
confirm "${NL} Confirm OVER-WRITE files ? " yes "
|
||
|
Warning:
|
||
|
'legacy-hard' will OVER-WRITE all legacy files to default settings.
|
||
|
|
||
|
Legacy files:
|
||
|
* File: ${EASYRSA_PKI}/openssl-easyrsa.cnf
|
||
|
* File: ${EASYRSA_PKI}/vars.example
|
||
|
* Dir: ${EASYRSA_PKI}/x509-types/*"
|
||
|
|
||
|
verbose "all_legacy_files_v2 - over-write ENABLED"
|
||
|
fi
|
||
|
|
||
|
# Output directories
|
||
|
legacy_out_d="$EASYRSA_PKI"
|
||
|
easyrsa_mkdir "$legacy_out_d"
|
||
|
x509_types_d="$legacy_out_d"/x509-types
|
||
|
easyrsa_mkdir "$x509_types_d"
|
||
|
|
||
|
# Create x509-types
|
||
|
for legacy_type in COMMON ca server serverClient client \
|
||
|
email codeSigning kdc
|
||
|
do
|
||
|
legacy_target="${x509_types_d}/${legacy_type}"
|
||
|
write_legacy_file_v2 "$legacy_type" "$legacy_target" \
|
||
|
"$legacy_file_over_write"
|
||
|
done
|
||
|
|
||
|
# vars.example
|
||
|
legacy_type=vars
|
||
|
legacy_target="$legacy_out_d"/vars.example
|
||
|
write_legacy_file_v2 "$legacy_type" "$legacy_target" \
|
||
|
"$legacy_file_over_write"
|
||
|
|
||
|
# openssl-easyrsa.cnf
|
||
|
legacy_type=ssl-cnf
|
||
|
legacy_target="$legacy_out_d"/openssl-easyrsa.cnf
|
||
|
write_legacy_file_v2 "$legacy_type" "$legacy_target" \
|
||
|
"$legacy_file_over_write"
|
||
|
|
||
|
# User notice
|
||
|
if [ "$legacy_file_over_write" ]; then
|
||
|
notice "legacy-hard has updated all files."
|
||
|
else
|
||
|
notice "legacy has updated missing files."
|
||
|
fi
|
||
|
} # => all_legacy_files_v2()
|
||
|
|
||
|
# write legacy files to stdout or user defined file
|
||
|
write_legacy_file_v2() {
|
||
|
# recursion check
|
||
|
write_recursion="$(( write_recursion + 1 ))"
|
||
|
if [ "$write_recursion" -gt 1 ]; then
|
||
|
print "write recursion" > "$easyrsa_err_log"
|
||
|
die "write recursion"
|
||
|
fi
|
||
|
|
||
|
write_type="$1"
|
||
|
write_file="$2"
|
||
|
write_over=
|
||
|
[ "$3" = overwrite ] && write_over="$3"
|
||
|
|
||
|
# Select by type
|
||
|
case "$write_type" in
|
||
|
ssl-cnf)
|
||
|
set_openssl_easyrsa_cnf_vars unexpanded
|
||
|
;;
|
||
|
safe-cnf)
|
||
|
set_openssl_easyrsa_cnf_vars expanded
|
||
|
;;
|
||
|
vars)
|
||
|
;;
|
||
|
# This correctly renames 'code-signing' to 'codeSigning'
|
||
|
COMMON|ca|server|serverClient|client|codeSigning|email|kdc)
|
||
|
;;
|
||
|
selfsign)
|
||
|
;;
|
||
|
*)
|
||
|
user_error "write - unknown type '$write_type'"
|
||
|
esac
|
||
|
|
||
|
# If $write_file is given then establish overwrite rules
|
||
|
if [ "$write_file" ]; then
|
||
|
|
||
|
# $write_file must not be a directory
|
||
|
[ -d "$write_file" ] && user_error \
|
||
|
"write: Target is a directory: '$write_file'"
|
||
|
|
||
|
# If $write_file exists then check for temp-file
|
||
|
if [ -f "$write_file" ]; then
|
||
|
# if this is a temp file then enable auto-overwrite
|
||
|
path="${write_file%%/temp.*}"
|
||
|
if [ "${secured_session}" = "$path" ]; then
|
||
|
verbose ": write_legacy_file_v2 - temp-file ACCEPTED"
|
||
|
write_over=overwrite
|
||
|
else
|
||
|
# target is not a temp-file, overwrite not changed
|
||
|
verbose ": Target is not a temp-file: $write_file"
|
||
|
fi
|
||
|
else
|
||
|
# enable overwrite, "there is no file" to over write
|
||
|
verbose ": Missing input file: $write_file"
|
||
|
write_over=overwrite
|
||
|
fi
|
||
|
fi
|
||
|
|
||
|
# write legacy data stream to stdout or file
|
||
|
if [ "$write_file" ]; then
|
||
|
if [ "$write_over" ]; then
|
||
|
verbose ": write_legacy_file_v2 - over-write ENABLED"
|
||
|
create_legacy_stream "$write_type" > "$write_file" || \
|
||
|
die "write failed"
|
||
|
else
|
||
|
user_error "write: Over-write refused for existing file!"
|
||
|
fi
|
||
|
else
|
||
|
# write stream to stdout ONLY
|
||
|
create_legacy_stream "$write_type"
|
||
|
fi
|
||
|
|
||
|
write_recursion="$(( write_recursion - 1 ))"
|
||
|
} # => write_legacy_file_v2()
|
||
|
|
||
|
# set heredoc variables for openssl-easyrsa.cnf
|
||
|
# shellcheck disable=SC2016 # (info): $ don't expand in ''
|
||
|
set_openssl_easyrsa_cnf_vars(){
|
||
|
case "$1" in
|
||
|
expanded)
|
||
|
# fully expand ssl-cnf for safe-cnf
|
||
|
conf_EASYRSA_dir="$EASYRSA_PKI"
|
||
|
conf_EASYRSA_PKI="$EASYRSA_PKI"
|
||
|
conf_EASYRSA_DIGEST="$EASYRSA_DIGEST"
|
||
|
conf_EASYRSA_KEY_SIZE="$EASYRSA_KEY_SIZE"
|
||
|
conf_EASYRSA_DN="$EASYRSA_DN"
|
||
|
conf_EASYRSA_REQ_CN="$EASYRSA_REQ_CN"
|
||
|
conf_EASYRSA_REQ_COUNTRY="$EASYRSA_REQ_COUNTRY"
|
||
|
conf_EASYRSA_REQ_PROVINCE="$EASYRSA_REQ_PROVINCE"
|
||
|
conf_EASYRSA_REQ_CITY="$EASYRSA_REQ_CITY"
|
||
|
conf_EASYRSA_REQ_ORG="$EASYRSA_REQ_ORG"
|
||
|
conf_EASYRSA_REQ_OU="$EASYRSA_REQ_OU"
|
||
|
conf_EASYRSA_REQ_EMAIL="$EASYRSA_REQ_EMAIL"
|
||
|
conf_EASYRSA_REQ_SERIAL="$EASYRSA_REQ_SERIAL"
|
||
|
;;
|
||
|
unexpanded)
|
||
|
# write standard ssl-cnf
|
||
|
conf_EASYRSA_dir='$dir'
|
||
|
conf_EASYRSA_PKI='$ENV::EASYRSA_PKI'
|
||
|
conf_EASYRSA_DIGEST='$ENV::EASYRSA_DIGEST'
|
||
|
conf_EASYRSA_KEY_SIZE='$ENV::EASYRSA_KEY_SIZE'
|
||
|
conf_EASYRSA_DN='$ENV::EASYRSA_DN'
|
||
|
conf_EASYRSA_REQ_CN='$ENV::EASYRSA_REQ_CN'
|
||
|
conf_EASYRSA_REQ_COUNTRY='$ENV::EASYRSA_REQ_COUNTRY'
|
||
|
conf_EASYRSA_REQ_PROVINCE='$ENV::EASYRSA_REQ_PROVINCE'
|
||
|
conf_EASYRSA_REQ_CITY='$ENV::EASYRSA_REQ_CITY'
|
||
|
conf_EASYRSA_REQ_ORG='$ENV::EASYRSA_REQ_ORG'
|
||
|
conf_EASYRSA_REQ_OU='$ENV::EASYRSA_REQ_OU'
|
||
|
conf_EASYRSA_REQ_EMAIL='$ENV::EASYRSA_REQ_EMAIL'
|
||
|
conf_EASYRSA_REQ_SERIAL='$ENV::EASYRSA_REQ_SERIAL'
|
||
|
;;
|
||
|
*)
|
||
|
die "set_openssl_easyrsa_cnf_vars - input"
|
||
|
esac
|
||
|
} # => set_openssl_easyrsa_cnf_vars()
|
||
|
|
||
|
# Create x509 type
|
||
|
create_legacy_stream() {
|
||
|
case "$1" in
|
||
|
COMMON)
|
||
|
# COMMON is not very useful
|
||
|
cat <<- "CREATE_X509_TYPE_COMMON"
|
||
|
CREATE_X509_TYPE_COMMON
|
||
|
;;
|
||
|
easyrsa)
|
||
|
# This could be COMMON but not is not suitable for a CA
|
||
|
cat <<- "CREATE_X509_TYPE_EASYRSA"
|
||
|
basicConstraints = CA:FALSE
|
||
|
subjectKeyIdentifier = hash
|
||
|
authorityKeyIdentifier = keyid,issuer:always
|
||
|
keyUsage = digitalSignature,keyEncipherment
|
||
|
CREATE_X509_TYPE_EASYRSA
|
||
|
;;
|
||
|
serverClient)
|
||
|
# serverClient
|
||
|
create_legacy_stream easyrsa
|
||
|
cat <<- "CREATE_X509_TYPE_SERV_CLI"
|
||
|
extendedKeyUsage = serverAuth,clientAuth
|
||
|
CREATE_X509_TYPE_SERV_CLI
|
||
|
;;
|
||
|
server)
|
||
|
# server
|
||
|
create_legacy_stream easyrsa
|
||
|
cat <<- "CREATE_X509_TYPE_SERV"
|
||
|
extendedKeyUsage = serverAuth
|
||
|
CREATE_X509_TYPE_SERV
|
||
|
;;
|
||
|
client)
|
||
|
# client
|
||
|
create_legacy_stream easyrsa
|
||
|
cat <<- "CREATE_X509_TYPE_CLI"
|
||
|
extendedKeyUsage = clientAuth
|
||
|
CREATE_X509_TYPE_CLI
|
||
|
;;
|
||
|
ca)
|
||
|
# ca
|
||
|
cat <<- "CREATE_X509_TYPE_CA"
|
||
|
basicConstraints = CA:TRUE
|
||
|
subjectKeyIdentifier = hash
|
||
|
authorityKeyIdentifier = keyid:always,issuer:always
|
||
|
keyUsage = cRLSign, keyCertSign
|
||
|
CREATE_X509_TYPE_CA
|
||
|
;;
|
||
|
selfsign)
|
||
|
# selfsign
|
||
|
cat <<- "CREATE_X509_TYPE_SELFSIGN"
|
||
|
subjectKeyIdentifier = hash
|
||
|
authorityKeyIdentifier = keyid:always,issuer:always
|
||
|
basicConstraints = CA:TRUE
|
||
|
keyUsage = digitalSignature,keyEncipherment
|
||
|
CREATE_X509_TYPE_SELFSIGN
|
||
|
|
||
|
print "extendedKeyUsage = $selfsign_eku"
|
||
|
;;
|
||
|
codeSigning)
|
||
|
# codeSigning
|
||
|
cat <<- "CREATE_X509_CODE_SIGNING"
|
||
|
basicConstraints = CA:FALSE
|
||
|
subjectKeyIdentifier = hash
|
||
|
authorityKeyIdentifier = keyid,issuer:always
|
||
|
extendedKeyUsage = codeSigning
|
||
|
keyUsage = digitalSignature
|
||
|
CREATE_X509_CODE_SIGNING
|
||
|
;;
|
||
|
email)
|
||
|
# email
|
||
|
cat <<- "CREATE_X509_TYPE_EMAIL"
|
||
|
basicConstraints = CA:FALSE
|
||
|
subjectKeyIdentifier = hash
|
||
|
authorityKeyIdentifier = keyid,issuer:always
|
||
|
extendedKeyUsage = emailProtection
|
||
|
keyUsage = digitalSignature,keyEncipherment,nonRepudiation
|
||
|
CREATE_X509_TYPE_EMAIL
|
||
|
;;
|
||
|
kdc)
|
||
|
# kdc
|
||
|
cat <<- "CREATE_X509_TYPE_KDC"
|
||
|
basicConstraints = CA:FALSE
|
||
|
subjectKeyIdentifier = hash
|
||
|
authorityKeyIdentifier = keyid,issuer:always
|
||
|
extendedKeyUsage = 1.3.6.1.5.2.3.5
|
||
|
keyUsage = nonRepudiation,digitalSignature,keyEncipherment,keyAgreement
|
||
|
issuerAltName = issuer:copy
|
||
|
subjectAltName = otherName:1.3.6.1.5.2.2;SEQUENCE:kdc_princ_name
|
||
|
|
||
|
[kdc_princ_name]
|
||
|
realm = EXP:0,GeneralString:${ENV::EASYRSA_KDC_REALM}
|
||
|
principal_name = EXP:1,SEQUENCE:kdc_principal_seq
|
||
|
|
||
|
[kdc_principal_seq]
|
||
|
name_type = EXP:0,INTEGER:1
|
||
|
name_string = EXP:1,SEQUENCE:kdc_principals
|
||
|
|
||
|
[kdc_principals]
|
||
|
princ1 = GeneralString:krbtgt
|
||
|
princ2 = GeneralString:${ENV::EASYRSA_KDC_REALM}
|
||
|
CREATE_X509_TYPE_KDC
|
||
|
;;
|
||
|
vars)
|
||
|
# vars
|
||
|
cat << "CREATE_VARS_EXAMPLE"
|
||
|
# Easy-RSA 3 parameter settings
|
||
|
|
||
|
# NOTE: If you installed Easy-RSA from your package manager, do not edit
|
||
|
# this file in place -- instead, you should copy the entire easy-rsa directory
|
||
|
# to another location so future upgrades do not wipe out your changes.
|
||
|
|
||
|
# HOW TO USE THIS FILE
|
||
|
#
|
||
|
# vars.example contains built-in examples to Easy-RSA settings. You MUST name
|
||
|
# this file "vars" if you want it to be used as a configuration file. If you
|
||
|
# do not, it WILL NOT be automatically read when you call easyrsa commands.
|
||
|
#
|
||
|
# It is not necessary to use this config file unless you wish to change
|
||
|
# operational defaults. These defaults should be fine for many uses without
|
||
|
# the need to copy and edit the "vars" file.
|
||
|
#
|
||
|
# All of the editable settings are shown commented and start with the command
|
||
|
# "set_var" -- this means any set_var command that is uncommented has been
|
||
|
# modified by the user. If you are happy with a default, there is no need to
|
||
|
# define the value to its default.
|
||
|
|
||
|
# NOTES FOR WINDOWS USERS
|
||
|
#
|
||
|
# Paths for Windows *MUST* use forward slashes, or optionally double-escaped
|
||
|
# backslashes (single forward slashes are recommended.) This means your path
|
||
|
# to the openssl binary might look like this:
|
||
|
# "C:/Program Files/OpenSSL-Win32/bin/openssl.exe"
|
||
|
|
||
|
# A little housekeeping: DO NOT EDIT THIS SECTION
|
||
|
#
|
||
|
# Easy-RSA 3.x does not source into the environment directly.
|
||
|
# Complain if a user tries to do this:
|
||
|
if [ -z "$EASYRSA_CALLER" ]; then
|
||
|
echo "You appear to be sourcing an Easy-RSA *vars* file. This is" >&2
|
||
|
echo "no longer necessary and is disallowed. See the section called" >&2
|
||
|
echo "*How to use this file* near the top comments for more details." >&2
|
||
|
return 1
|
||
|
fi
|
||
|
|
||
|
# DO YOUR EDITS BELOW THIS POINT
|
||
|
|
||
|
# If your OpenSSL command is not in the system PATH, you will need to define
|
||
|
# the path here. Normally this means a full path to the executable, otherwise
|
||
|
# you could have left it undefined here and the shown default would be used.
|
||
|
#
|
||
|
# Windows users, remember to use paths with forward-slashes (or escaped
|
||
|
# back-slashes.) Windows users should declare the full path to the openssl
|
||
|
# binary here if it is not in their system PATH.
|
||
|
#
|
||
|
#set_var EASYRSA_OPENSSL "openssl"
|
||
|
#
|
||
|
# This sample is in Windows syntax -- edit it for your path if not using PATH:
|
||
|
#set_var EASYRSA_OPENSSL "C:/Program Files/OpenSSL-Win32/bin/openssl.exe"
|
||
|
|
||
|
# Windows users, to generate OpenVPN TLS Keys the Openvpn binary must be
|
||
|
# defined here.
|
||
|
#
|
||
|
#set_var EASYRSA_OPENVPN "C:\\Program Files\\Openvpn\\bin\\openvpn.exe"
|
||
|
|
||
|
# Define X509 DN mode.
|
||
|
#
|
||
|
# This is used to adjust which elements are included in the Subject field
|
||
|
# as the DN ("Distinguished Name"). Note that in 'cn_only' mode the
|
||
|
# Organizational fields, listed further below, are not used.
|
||
|
#
|
||
|
# Choices are:
|
||
|
# cn_only - Use just a commonName value.
|
||
|
# org - Use the "traditional" format:
|
||
|
# Country/Province/City/Org/Org.Unit/email/commonName
|
||
|
#
|
||
|
#set_var EASYRSA_DN "cn_only"
|
||
|
|
||
|
# Organizational fields (used with "org" mode and ignored in "cn_only" mode).
|
||
|
# These are the default values for fields which will be placed in the
|
||
|
# certificate. Do not leave any of these fields blank, although interactively
|
||
|
# you may omit any specific field by typing the "." symbol (not valid for
|
||
|
# email).
|
||
|
#
|
||
|
# NOTE: The following characters are not supported
|
||
|
# in these "Organizational fields" by Easy-RSA:
|
||
|
# back-tick (`)
|
||
|
#
|
||
|
#set_var EASYRSA_REQ_COUNTRY "US"
|
||
|
#set_var EASYRSA_REQ_PROVINCE "California"
|
||
|
#set_var EASYRSA_REQ_CITY "San Francisco"
|
||
|
#set_var EASYRSA_REQ_ORG "Copyleft Certificate Co"
|
||
|
#set_var EASYRSA_REQ_EMAIL "me@example.net"
|
||
|
#set_var EASYRSA_REQ_OU "My Organizational Unit"
|
||
|
|
||
|
# Preserve the Distinguished Name field order
|
||
|
# of the certificate signing request
|
||
|
# *Only* effective in --dn-mode=org
|
||
|
#
|
||
|
#set_var EASYRSA_PRESERVE_DN 1
|
||
|
|
||
|
# Set no password mode - This will create the entire PKI without passwords.
|
||
|
# This can be better managed by choosing which entity private keys should be
|
||
|
# encrypted with the following command line options:
|
||
|
# Global option '--no-pass' or command option 'nopass'.
|
||
|
#
|
||
|
#set_var EASYRSA_NO_PASS 1
|
||
|
|
||
|
# Choose a size in bits for your keypairs. The recommended value is 2048.
|
||
|
# Using 2048-bit keys is considered more than sufficient for many years into
|
||
|
# the future. Larger keysizes will slow down TLS negotiation and make key/DH
|
||
|
# param generation take much longer. Values up to 4096 should be accepted by
|
||
|
# most software. Only used when the crypto alg is rsa, see below.
|
||
|
#
|
||
|
#set_var EASYRSA_KEY_SIZE 2048
|
||
|
|
||
|
# The default crypto mode is rsa; ec can enable elliptic curve support.
|
||
|
# Note that not all software supports ECC, so use care when enabling it.
|
||
|
# Choices for crypto alg are: (each in lower-case)
|
||
|
# * rsa
|
||
|
# * ec
|
||
|
# * ed
|
||
|
#
|
||
|
#set_var EASYRSA_ALGO rsa
|
||
|
|
||
|
# Define the named curve, used in ec & ed modes:
|
||
|
#
|
||
|
#set_var EASYRSA_CURVE secp384r1
|
||
|
|
||
|
# In how many days should the root CA key expire?
|
||
|
#
|
||
|
#set_var EASYRSA_CA_EXPIRE 3650
|
||
|
|
||
|
# In how many days should certificates expire?
|
||
|
#
|
||
|
#set_var EASYRSA_CERT_EXPIRE 825
|
||
|
|
||
|
# How many days until the next CRL publish date? Note that the CRL can still
|
||
|
# be parsed after this timeframe passes. It is only used for an expected next
|
||
|
# publication date.
|
||
|
#
|
||
|
#set_var EASYRSA_CRL_DAYS 180
|
||
|
|
||
|
# Random serial numbers by default.
|
||
|
# Set to 'no' for the old incremental serial numbers.
|
||
|
#
|
||
|
#set_var EASYRSA_RAND_SN "yes"
|
||
|
|
||
|
# Cut-off window for checking expiring certificates.
|
||
|
#
|
||
|
#set_var EASYRSA_PRE_EXPIRY_WINDOW 90
|
||
|
|
||
|
# Generate automatic subjectAltName for certificates
|
||
|
#
|
||
|
#set_var EASYRSA_AUTO_SAN 1
|
||
|
|
||
|
# Add critical attribute to X509 fields: basicConstraints (BC),
|
||
|
# keyUsage (KU), extendedKeyUsage (EKU) or SAN
|
||
|
#
|
||
|
#set_var EASYRSA_BC_CRIT 1
|
||
|
#set_var EASYRSA_KU_CRIT 1
|
||
|
#set_var EASYRSA_EKU_CRIT 1
|
||
|
#set_var EASYRSA_SAN_CRIT 1
|
||
|
|
||
|
# Disable automatic inline files
|
||
|
#
|
||
|
#set_var EASYRSA_DISABLE_INLINE 1
|
||
|
CREATE_VARS_EXAMPLE
|
||
|
;;
|
||
|
ssl-cnf|safe-cnf)
|
||
|
# SSL config v3.2.0-1
|
||
|
cat << CREATE_SSL_CONFIG
|
||
|
# For use with Easy-RSA 3.0+ and OpenSSL or LibreSSL
|
||
|
|
||
|
####################################################################
|
||
|
[ ca ]
|
||
|
default_ca = CA_default # The default ca section
|
||
|
|
||
|
####################################################################
|
||
|
[ CA_default ]
|
||
|
|
||
|
dir = $conf_EASYRSA_PKI # Where everything is kept
|
||
|
certs = $conf_EASYRSA_dir # Where the issued certs are kept
|
||
|
crl_dir = $conf_EASYRSA_dir # Where the issued crl are kept
|
||
|
database = $conf_EASYRSA_dir/index.txt # database index file.
|
||
|
new_certs_dir = $conf_EASYRSA_dir/certs_by_serial # default place for new certs.
|
||
|
|
||
|
certificate = $conf_EASYRSA_dir/ca.crt # The CA certificate
|
||
|
serial = $conf_EASYRSA_dir/serial # The current serial number
|
||
|
crl = $conf_EASYRSA_dir/crl.pem # The current CRL
|
||
|
private_key = $conf_EASYRSA_dir/private/ca.key # The private key
|
||
|
RANDFILE = $conf_EASYRSA_dir/.rand # private random number file
|
||
|
|
||
|
x509_extensions = basic_exts # The extensions to add to the cert
|
||
|
|
||
|
# A placeholder to handle the --copy-ext feature:
|
||
|
#%COPY_EXTS% # Do NOT remove or change this line as --copy-ext support requires it
|
||
|
|
||
|
# This allows a V2 CRL. Ancient browsers don't like it, but anything Easy-RSA
|
||
|
# is designed for will. In return, we get the Issuer attached to CRLs.
|
||
|
crl_extensions = crl_ext
|
||
|
|
||
|
# These fields are always configured via the command line.
|
||
|
# These fields are removed from this here-doc but retained
|
||
|
# in 'openssl-easyrsa.cnf' file, in case something breaks.
|
||
|
# default_days is no longer required by Easy-RSA
|
||
|
#default_days = \$ENV::EASYRSA_CERT_EXPIRE # how long to certify for
|
||
|
# default_crl_days is no longer required by Easy-RSA
|
||
|
#default_crl_days = \$ENV::EASYRSA_CRL_DAYS # how long before next CRL
|
||
|
|
||
|
default_md = $conf_EASYRSA_DIGEST # use public key default MD
|
||
|
preserve = no # keep passed DN ordering
|
||
|
|
||
|
# This allows to renew certificates which have not been revoked
|
||
|
unique_subject = no
|
||
|
|
||
|
# A few different ways of specifying how similar the request should look
|
||
|
# For type CA, the listed attributes must be the same, and the optional
|
||
|
# and supplied fields are just that :-)
|
||
|
policy = policy_anything
|
||
|
|
||
|
# For the 'anything' policy, which defines allowed DN fields
|
||
|
[ policy_anything ]
|
||
|
countryName = optional
|
||
|
stateOrProvinceName = optional
|
||
|
localityName = optional
|
||
|
organizationName = optional
|
||
|
organizationalUnitName = optional
|
||
|
commonName = supplied
|
||
|
emailAddress = optional
|
||
|
serialNumber = optional
|
||
|
|
||
|
####################################################################
|
||
|
# Easy-RSA request handling
|
||
|
# We key off \$DN_MODE to determine how to format the DN
|
||
|
[ req ]
|
||
|
default_bits = $conf_EASYRSA_KEY_SIZE
|
||
|
default_keyfile = privkey.pem
|
||
|
default_md = $conf_EASYRSA_DIGEST
|
||
|
distinguished_name = $conf_EASYRSA_DN
|
||
|
x509_extensions = easyrsa_ca # The extensions to add to the self signed cert
|
||
|
|
||
|
# A placeholder to handle the \$EXTRA_EXTS feature:
|
||
|
#%EXTRA_EXTS% # Do NOT remove or change this line as \$EXTRA_EXTS support requires it
|
||
|
|
||
|
####################################################################
|
||
|
# Easy-RSA DN (Subject) handling
|
||
|
|
||
|
# Easy-RSA DN for cn_only support:
|
||
|
[ cn_only ]
|
||
|
commonName = Common Name (eg: your user, host, or server name)
|
||
|
commonName_max = 64
|
||
|
commonName_default = $conf_EASYRSA_REQ_CN
|
||
|
|
||
|
# Easy-RSA DN for org support:
|
||
|
[ org ]
|
||
|
countryName = Country Name (2 letter code)
|
||
|
countryName_default = $conf_EASYRSA_REQ_COUNTRY
|
||
|
countryName_min = 2
|
||
|
countryName_max = 2
|
||
|
|
||
|
stateOrProvinceName = State or Province Name (full name)
|
||
|
stateOrProvinceName_default = $conf_EASYRSA_REQ_PROVINCE
|
||
|
|
||
|
localityName = Locality Name (eg, city)
|
||
|
localityName_default = $conf_EASYRSA_REQ_CITY
|
||
|
|
||
|
0.organizationName = Organization Name (eg, company)
|
||
|
0.organizationName_default = $conf_EASYRSA_REQ_ORG
|
||
|
|
||
|
organizationalUnitName = Organizational Unit Name (eg, section)
|
||
|
organizationalUnitName_default = $conf_EASYRSA_REQ_OU
|
||
|
|
||
|
commonName = Common Name (eg: your user, host, or server name)
|
||
|
commonName_max = 64
|
||
|
commonName_default = $conf_EASYRSA_REQ_CN
|
||
|
|
||
|
emailAddress = Email Address
|
||
|
emailAddress_default = $conf_EASYRSA_REQ_EMAIL
|
||
|
emailAddress_max = 64
|
||
|
|
||
|
serialNumber = Serial-number (eg, device serial-number)
|
||
|
serialNumber_default = $conf_EASYRSA_REQ_SERIAL
|
||
|
|
||
|
####################################################################
|
||
|
# Easy-RSA cert extension handling
|
||
|
|
||
|
# This section is effectively unused as the main script sets extensions
|
||
|
# dynamically. This core section is left to support the odd usecase where
|
||
|
# a user calls openssl directly.
|
||
|
[ basic_exts ]
|
||
|
basicConstraints = CA:FALSE
|
||
|
subjectKeyIdentifier = hash
|
||
|
authorityKeyIdentifier = keyid,issuer:always
|
||
|
|
||
|
# The Easy-RSA CA extensions
|
||
|
[ easyrsa_ca ]
|
||
|
|
||
|
# PKIX recommendations:
|
||
|
|
||
|
subjectKeyIdentifier=hash
|
||
|
authorityKeyIdentifier=keyid:always,issuer:always
|
||
|
|
||
|
# This could be marked critical, but it's nice to support reading by any
|
||
|
# broken clients who attempt to do so.
|
||
|
basicConstraints = CA:true
|
||
|
|
||
|
# Limit key usage to CA tasks. If you really want to use the generated pair as
|
||
|
# a self-signed cert, comment this out.
|
||
|
keyUsage = cRLSign, keyCertSign
|
||
|
|
||
|
# nsCertType omitted by default. Let's try to let the deprecated stuff die.
|
||
|
# nsCertType = sslCA
|
||
|
|
||
|
# A placeholder to handle the \$X509_TYPES and CA extra extensions \$EXTRA_EXTS:
|
||
|
#%CA_X509_TYPES_EXTRA_EXTS% # Do NOT remove or change this line as \$X509_TYPES and EXTRA_EXTS demands it
|
||
|
|
||
|
# CRL extensions.
|
||
|
[ crl_ext ]
|
||
|
|
||
|
# Only issuerAltName and authorityKeyIdentifier make any sense in a CRL.
|
||
|
|
||
|
# issuerAltName=issuer:copy
|
||
|
authorityKeyIdentifier=keyid:always,issuer:always
|
||
|
CREATE_SSL_CONFIG
|
||
|
;;
|
||
|
*)
|
||
|
die "create_legacy_stream: unknown type '$1'"
|
||
|
esac
|
||
|
} # => create_legacy_stream()
|
||
|
|
||
|
# Load easyrsa-tools.lib
|
||
|
source_easyrsa_tools_lib() {
|
||
|
if [ -f "$EASYRSA_TOOLS_LIB" ]; then
|
||
|
export EASYRSA_TOOLS_CALLER=1
|
||
|
# shellcheck disable=SC1090 # can't follow non-constant..
|
||
|
. "$EASYRSA_TOOLS_LIB" || \
|
||
|
die "Source failed: $EASYRSA_TOOLS_LIB"
|
||
|
unset -v EASYRSA_TOOLS_CALLER tools_error
|
||
|
|
||
|
verbose "EASYRSA_TOOLS_LIB: $EASYRSA_TOOLS_LIB"
|
||
|
verbose "EASYRSA_TOOLS_VERSION: $EASYRSA_TOOLS_VERSION"
|
||
|
|
||
|
# Verify tools version
|
||
|
if [ "$EASYRSA_TOOLS_VERSION" -lt 321 ]; then
|
||
|
tools_error_txt="\
|
||
|
EasyRSA Tools version is out of date:
|
||
|
* EASYRSA_TOOLS_VERSION: $EASYRSA_TOOLS_VERSION"
|
||
|
return 1
|
||
|
fi
|
||
|
else
|
||
|
verbose "Missing: easyrsa-tools.lib"
|
||
|
tools_error_txt="Missing: easyrsa-tools.lib
|
||
|
|
||
|
Use of command '$cmd' requires Easy-RSA tools library.
|
||
|
Source: https://github.com/OpenVPN/easy-rsa/dev/easyrsa-tools.lib
|
||
|
Download: https://raw.githubusercontent.com/OpenVPN/easy-rsa/refs/heads/master/dev/easyrsa-tools.lib
|
||
|
|
||
|
Place a copy of easyrsa-tools.lib in a standard system location."
|
||
|
return 1
|
||
|
fi
|
||
|
} # => source_easyrsa_tools_lib()
|
||
|
|
||
|
# Version information
|
||
|
print_version() {
|
||
|
ssl_version="$(
|
||
|
"${EASYRSA_OPENSSL:-openssl}" version 2>/dev/null
|
||
|
)"
|
||
|
cat << VERSION_TEXT
|
||
|
EasyRSA Version Information
|
||
|
Version: $EASYRSA_version
|
||
|
Generated: ~DATE~
|
||
|
SSL Lib: ${ssl_version:-undefined}
|
||
|
Git Commit: ~GITHEAD~
|
||
|
Source Repo: https://github.com/OpenVPN/easy-rsa
|
||
|
VERSION_TEXT
|
||
|
} # => print_version()
|
||
|
|
||
|
|
||
|
########################################
|
||
|
# Invocation entry point:
|
||
|
|
||
|
EASYRSA_version="~VER~"
|
||
|
NL='
|
||
|
'
|
||
|
|
||
|
# Be secure with a restrictive umask
|
||
|
[ "$EASYRSA_NO_UMASK" ] || umask "${EASYRSA_UMASK:=077}"
|
||
|
|
||
|
# Register cleanup on EXIT
|
||
|
trap 'cleanup $?' EXIT
|
||
|
# When SIGHUP, SIGINT, SIGQUIT, SIGABRT and SIGTERM,
|
||
|
# explicitly exit to signal EXIT (non-bash shells)
|
||
|
trap "exit 1" 1
|
||
|
trap "exit 2" 2
|
||
|
trap "exit 3" 3
|
||
|
trap "exit 6" 6
|
||
|
trap "exit 15" 15
|
||
|
|
||
|
# Get host details - No configurable input allowed
|
||
|
detect_host
|
||
|
|
||
|
# Initialisation requirements
|
||
|
unset -v \
|
||
|
OPENSSL_CONF \
|
||
|
verify_ssl_lib_ok ssl_batch \
|
||
|
secured_session \
|
||
|
working_safe_ssl_conf working_safe_org_conf \
|
||
|
alias_days text \
|
||
|
prohibit_no_pass \
|
||
|
invalid_vars \
|
||
|
local_request error_build_full_cleanup \
|
||
|
selfsign_eku \
|
||
|
internal_batch mv_temp_error \
|
||
|
easyrsa_exit_with_error error_info \
|
||
|
write_recursion tools_error tools_error_txt
|
||
|
|
||
|
# Used by build-ca->cleanup to restore prompt
|
||
|
# after user interrupt when using manual password
|
||
|
prompt_restore=0
|
||
|
# Sequential temp-file counter
|
||
|
mktemp_counter=0
|
||
|
|
||
|
# Parse options
|
||
|
while :; do
|
||
|
# Reset per pass flags
|
||
|
unset -v opt val \
|
||
|
is_empty empty_ok number_only zero_allowed
|
||
|
|
||
|
# Separate option from value:
|
||
|
opt="${1%%=*}"
|
||
|
val="${1#*=}"
|
||
|
|
||
|
# Empty values are not allowed unless expected
|
||
|
# eg: '--batch'
|
||
|
[ "$opt" = "$val" ] && is_empty=1
|
||
|
# eg: '--pki-dir='
|
||
|
[ "$val" ] || is_empty=1
|
||
|
|
||
|
case "$opt" in
|
||
|
--days)
|
||
|
number_only=1
|
||
|
# Set the appropriate date variable
|
||
|
# when called by command later
|
||
|
alias_days="$val"
|
||
|
;;
|
||
|
--startdate)
|
||
|
export EASYRSA_START_DATE="$val"
|
||
|
;;
|
||
|
--enddate)
|
||
|
export EASYRSA_END_DATE="$val"
|
||
|
;;
|
||
|
--pki-dir|--pki)
|
||
|
export EASYRSA_PKI="$val"
|
||
|
;;
|
||
|
--tmp-dir)
|
||
|
export EASYRSA_TEMP_DIR="$val"
|
||
|
;;
|
||
|
--ssl-conf)
|
||
|
export EASYRSA_SSL_CONF="$val"
|
||
|
;;
|
||
|
--keep-tmp)
|
||
|
export EASYRSA_KEEP_TEMP="$val"
|
||
|
;;
|
||
|
--use-algo)
|
||
|
export EASYRSA_ALGO="$val"
|
||
|
;;
|
||
|
--keysize)
|
||
|
number_only=1
|
||
|
export EASYRSA_KEY_SIZE="$val"
|
||
|
;;
|
||
|
--curve)
|
||
|
export EASYRSA_CURVE="$val"
|
||
|
;;
|
||
|
--dn-mode)
|
||
|
export EASYRSA_DN="$val"
|
||
|
;;
|
||
|
--req-cn)
|
||
|
export EASYRSA_REQ_CN="$val"
|
||
|
;;
|
||
|
--digest)
|
||
|
export EASYRSA_DIGEST="$val"
|
||
|
;;
|
||
|
--req-c)
|
||
|
empty_ok=1
|
||
|
export EASYRSA_REQ_COUNTRY="$val"
|
||
|
;;
|
||
|
--req-st)
|
||
|
empty_ok=1
|
||
|
export EASYRSA_REQ_PROVINCE="$val"
|
||
|
;;
|
||
|
--req-city)
|
||
|
empty_ok=1
|
||
|
export EASYRSA_REQ_CITY="$val"
|
||
|
;;
|
||
|
--req-org)
|
||
|
empty_ok=1
|
||
|
export EASYRSA_REQ_ORG="$val"
|
||
|
;;
|
||
|
--req-email)
|
||
|
empty_ok=1
|
||
|
export EASYRSA_REQ_EMAIL="$val"
|
||
|
;;
|
||
|
--req-ou)
|
||
|
empty_ok=1
|
||
|
export EASYRSA_REQ_OU="$val"
|
||
|
;;
|
||
|
--req-serial)
|
||
|
empty_ok=1
|
||
|
export EASYRSA_REQ_SERIAL="$val"
|
||
|
;;
|
||
|
--ns-cert)
|
||
|
empty_ok=1
|
||
|
[ "$is_empty" ] && unset -v val
|
||
|
export EASYRSA_NS_SUPPORT="${val:-yes}"
|
||
|
;;
|
||
|
--ns-comment)
|
||
|
empty_ok=1
|
||
|
export EASYRSA_NS_COMMENT="$val"
|
||
|
;;
|
||
|
--batch)
|
||
|
empty_ok=1
|
||
|
export EASYRSA_BATCH=1
|
||
|
;;
|
||
|
-s|--silent)
|
||
|
empty_ok=1
|
||
|
export EASYRSA_SILENT=1
|
||
|
;;
|
||
|
--sbatch|--silent-batch)
|
||
|
empty_ok=1
|
||
|
export EASYRSA_SILENT=1
|
||
|
export EASYRSA_BATCH=1
|
||
|
;;
|
||
|
--verbose)
|
||
|
empty_ok=1
|
||
|
export EASYRSA_VERBOSE=1
|
||
|
;;
|
||
|
--days-margin)
|
||
|
# ONLY ALLOWED use by status reports
|
||
|
number_only=1
|
||
|
export EASYRSA_iso_8601_MARGIN="$val"
|
||
|
;;
|
||
|
-S|--silent-ssl)
|
||
|
empty_ok=1
|
||
|
export EASYRSA_SILENT_SSL=1
|
||
|
;;
|
||
|
--force-safe-ssl)
|
||
|
empty_ok=1
|
||
|
export EASYRSA_FORCE_SAFE_SSL=1
|
||
|
;;
|
||
|
--nopass|--no-pass)
|
||
|
empty_ok=1
|
||
|
export EASYRSA_NO_PASS=1
|
||
|
;;
|
||
|
--passin)
|
||
|
export EASYRSA_PASSIN="$val"
|
||
|
;;
|
||
|
--passout)
|
||
|
export EASYRSA_PASSOUT="$val"
|
||
|
;;
|
||
|
--raw-ca)
|
||
|
empty_ok=1
|
||
|
export EASYRSA_RAW_CA=1
|
||
|
;;
|
||
|
--notext|--no-text)
|
||
|
empty_ok=1
|
||
|
export EASYRSA_NO_TEXT=1
|
||
|
;;
|
||
|
--subca-len)
|
||
|
number_only=1
|
||
|
zero_allowed=1
|
||
|
export EASYRSA_SUBCA_LEN="$val"
|
||
|
;;
|
||
|
--vars)
|
||
|
export EASYRSA_VARS_FILE="$val"
|
||
|
;;
|
||
|
--copy-ext)
|
||
|
empty_ok=1
|
||
|
export EASYRSA_CP_EXT=1
|
||
|
;;
|
||
|
--subject-alt-name|--san)
|
||
|
# This allows --san to be used multiple times
|
||
|
if [ "$EASYRSA_SAN" ]; then
|
||
|
EASYRSA_SAN="$EASYRSA_SAN, $val"
|
||
|
else
|
||
|
EASYRSA_SAN="$val"
|
||
|
fi
|
||
|
;;
|
||
|
--auto-san)
|
||
|
empty_ok=1
|
||
|
export EASYRSA_AUTO_SAN=1
|
||
|
;;
|
||
|
--san-crit*)
|
||
|
empty_ok=1
|
||
|
export EASYRSA_SAN_CRIT='critical,'
|
||
|
;;
|
||
|
--bc-crit*)
|
||
|
empty_ok=1
|
||
|
export EASYRSA_BC_CRIT=1
|
||
|
;;
|
||
|
--ku-crit*)
|
||
|
empty_ok=1
|
||
|
export EASYRSA_KU_CRIT=1
|
||
|
;;
|
||
|
--eku-crit*)
|
||
|
empty_ok=1
|
||
|
export EASYRSA_EKU_CRIT=1
|
||
|
;;
|
||
|
--new-subj*)
|
||
|
export EASYRSA_NEW_SUBJECT="$val"
|
||
|
;;
|
||
|
--usefn)
|
||
|
export EASYRSA_P12_FR_NAME="$val"
|
||
|
;;
|
||
|
--tools)
|
||
|
export EASYRSA_TOOLS_LIB="$val"
|
||
|
;;
|
||
|
--version)
|
||
|
shift "$#"
|
||
|
set -- "$@" "version"
|
||
|
break
|
||
|
;;
|
||
|
-*)
|
||
|
user_error "\
|
||
|
Unknown option '$opt'.
|
||
|
Run 'easyrsa help options' for option help."
|
||
|
;;
|
||
|
*)
|
||
|
break
|
||
|
esac
|
||
|
|
||
|
# fatal error when no value was provided
|
||
|
if [ "$is_empty" ]; then
|
||
|
[ "$empty_ok" ] || \
|
||
|
user_error "Missing value to option: $opt"
|
||
|
fi
|
||
|
|
||
|
# fatal error when a number is expected but not provided
|
||
|
if [ "$number_only" ]; then
|
||
|
case "$val" in
|
||
|
(0)
|
||
|
# Allow zero only
|
||
|
[ "$zero_allowed" ] || \
|
||
|
user_error "$opt - Number expected: '$val'"
|
||
|
;;
|
||
|
(*[!1234567890]*|0*)
|
||
|
user_error "$opt - Number expected: '$val'"
|
||
|
esac
|
||
|
fi
|
||
|
|
||
|
shift
|
||
|
done
|
||
|
|
||
|
# option dependencies
|
||
|
# Add full --san to extra extensions
|
||
|
if [ "$EASYRSA_SAN" ]; then
|
||
|
EASYRSA_EXTRA_EXTS="\
|
||
|
$EASYRSA_EXTRA_EXTS
|
||
|
subjectAltName = ${EASYRSA_SAN_CRIT}${EASYRSA_SAN}"
|
||
|
fi
|
||
|
|
||
|
# Set cmd now
|
||
|
# vars_setup needs to know if this is init-pki
|
||
|
cmd="$1"
|
||
|
[ "$1" ] && shift # scrape off command
|
||
|
|
||
|
# Establish PKI and CA initialisation requirements
|
||
|
unset -v require_pki require_ca quiet_vars
|
||
|
|
||
|
case "$cmd" in
|
||
|
''|help|-h|--help|--usage| \
|
||
|
version|show-host|rand|random)
|
||
|
quiet_vars=1
|
||
|
;;
|
||
|
init-pki|clean-all)
|
||
|
: # ok
|
||
|
;;
|
||
|
*)
|
||
|
require_pki=1
|
||
|
case "$cmd" in
|
||
|
gen-req|gen-dh|build-ca|show-req|export-p*| \
|
||
|
inline|self-sign-*|write)
|
||
|
: ;; # ok
|
||
|
*) require_ca=1
|
||
|
esac
|
||
|
esac
|
||
|
|
||
|
# Intelligent env-var detection and auto-loading:
|
||
|
# Select vars file as EASYRSA_VARS_FILE
|
||
|
# then source the vars file, if found
|
||
|
# otherwise, ignore no vars file
|
||
|
if select_vars; then
|
||
|
[ "$quiet_vars" ] || information "\
|
||
|
Using Easy-RSA 'vars' configuration:
|
||
|
* $EASYRSA_VARS_FILE"
|
||
|
source_vars "$EASYRSA_VARS_FILE"
|
||
|
else
|
||
|
verbose "\
|
||
|
No Easy-RSA 'vars' configuration file exists!"
|
||
|
fi
|
||
|
|
||
|
# then set defaults
|
||
|
default_vars
|
||
|
|
||
|
# Check for unexpected changes to EASYRSA or EASYRSA_PKI
|
||
|
# https://github.com/OpenVPN/easy-rsa/issues/1006
|
||
|
validate_default_vars
|
||
|
|
||
|
# Check for conflicting input options
|
||
|
mutual_exclusions
|
||
|
|
||
|
# Find x509-types, openssl-easyrsa.cnf and easyrsa-tools.lib
|
||
|
locate_support_files
|
||
|
|
||
|
# Verify SSL Lib - One time ONLY
|
||
|
verify_ssl_lib
|
||
|
|
||
|
# Check $working_safe_ssl_conf, to build
|
||
|
# a fully configured safe ssl conf, on the
|
||
|
# next invocation of easyrsa_openssl()
|
||
|
if [ "$working_safe_ssl_conf" ]; then
|
||
|
die "working_safe_ssl_conf must not be set!"
|
||
|
fi
|
||
|
|
||
|
# Hand off to the function responsible
|
||
|
# ONLY verify_working_env() for valid commands
|
||
|
case "$cmd" in
|
||
|
init-pki|clean-all)
|
||
|
verify_working_env
|
||
|
init_pki "$@"
|
||
|
;;
|
||
|
build-ca)
|
||
|
verify_working_env
|
||
|
[ -z "$alias_days" ] || \
|
||
|
export EASYRSA_CA_EXPIRE="$alias_days"
|
||
|
build_ca "$@"
|
||
|
;;
|
||
|
self-sign-server)
|
||
|
verify_working_env
|
||
|
[ -z "$alias_days" ] || \
|
||
|
export EASYRSA_CERT_EXPIRE="$alias_days"
|
||
|
self_sign server "$@"
|
||
|
;;
|
||
|
self-sign-client)
|
||
|
verify_working_env
|
||
|
[ -z "$alias_days" ] || \
|
||
|
export EASYRSA_CERT_EXPIRE="$alias_days"
|
||
|
self_sign client "$@"
|
||
|
;;
|
||
|
self*)
|
||
|
user_error "Self-sign syntax example: 'self-sign-server foo'"
|
||
|
;;
|
||
|
gen-dh)
|
||
|
verify_working_env
|
||
|
gen_dh
|
||
|
;;
|
||
|
gen-req)
|
||
|
verify_working_env
|
||
|
gen_req "$@"
|
||
|
;;
|
||
|
sign|sign-req)
|
||
|
verify_working_env
|
||
|
[ -z "$alias_days" ] || \
|
||
|
export EASYRSA_CERT_EXPIRE="$alias_days"
|
||
|
sign_req "$@"
|
||
|
;;
|
||
|
build-client-full)
|
||
|
verify_working_env
|
||
|
[ -z "$alias_days" ] || \
|
||
|
export EASYRSA_CERT_EXPIRE="$alias_days"
|
||
|
build_full client "$@"
|
||
|
;;
|
||
|
build-server-full)
|
||
|
verify_working_env
|
||
|
[ -z "$alias_days" ] || \
|
||
|
export EASYRSA_CERT_EXPIRE="$alias_days"
|
||
|
build_full server "$@"
|
||
|
;;
|
||
|
build-serverClient-full)
|
||
|
verify_working_env
|
||
|
[ -z "$alias_days" ] || \
|
||
|
export EASYRSA_CERT_EXPIRE="$alias_days"
|
||
|
build_full serverClient "$@"
|
||
|
;;
|
||
|
gen-crl)
|
||
|
verify_working_env
|
||
|
[ -z "$alias_days" ] || \
|
||
|
export EASYRSA_CRL_DAYS="$alias_days"
|
||
|
gen_crl
|
||
|
;;
|
||
|
revoke)
|
||
|
verify_working_env
|
||
|
cert_dir=issued
|
||
|
revoke "$@"
|
||
|
;;
|
||
|
revoke-expired)
|
||
|
verify_working_env
|
||
|
cert_dir=expired
|
||
|
revoke "$@"
|
||
|
;;
|
||
|
revoke-renewed)
|
||
|
verify_working_env
|
||
|
cert_dir=renewed/issued
|
||
|
revoke "$@"
|
||
|
;;
|
||
|
import-req)
|
||
|
verify_working_env
|
||
|
import_req "$@"
|
||
|
;;
|
||
|
expire)
|
||
|
verify_working_env
|
||
|
expire_cert "$@"
|
||
|
;;
|
||
|
inline)
|
||
|
verify_working_env
|
||
|
inline_file "$@"
|
||
|
;;
|
||
|
export-p12)
|
||
|
verify_working_env
|
||
|
export_pkcs p12 "$@"
|
||
|
;;
|
||
|
export-p7)
|
||
|
verify_working_env
|
||
|
export_pkcs p7 "$@"
|
||
|
;;
|
||
|
export-p8)
|
||
|
verify_working_env
|
||
|
export_pkcs p8 "$@"
|
||
|
;;
|
||
|
export-p1)
|
||
|
verify_working_env
|
||
|
export_pkcs p1 "$@"
|
||
|
;;
|
||
|
set-pass|set-rsa-pass|set-ec-pass|set-ed-pass)
|
||
|
verify_working_env
|
||
|
set_pass "$@"
|
||
|
;;
|
||
|
update-db)
|
||
|
verify_working_env
|
||
|
update_db
|
||
|
;;
|
||
|
show-req)
|
||
|
verify_working_env
|
||
|
show req "$@"
|
||
|
;;
|
||
|
show-cert)
|
||
|
verify_working_env
|
||
|
show cert "$@"
|
||
|
;;
|
||
|
show-crl)
|
||
|
verify_working_env
|
||
|
show crl crl
|
||
|
;;
|
||
|
show-ca)
|
||
|
verify_working_env
|
||
|
show_ca "$@"
|
||
|
;;
|
||
|
show-host)
|
||
|
verify_working_env
|
||
|
show_host "$@"
|
||
|
;;
|
||
|
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)
|
||
|
[ "$tools_error" ] && user_error "$tools_error_txt
|
||
|
|
||
|
A certificate can be renewed without EasyRSA Tools. Expire the certificate
|
||
|
using command 'expire' and sign the original request with 'sign-req'."
|
||
|
[ -z "$alias_days" ] || \
|
||
|
export EASYRSA_CERT_EXPIRE="$alias_days"
|
||
|
renew "$@"
|
||
|
;;
|
||
|
show-expire)
|
||
|
[ "$tools_error" ] && user_error "$tools_error_txt"
|
||
|
[ -z "$alias_days" ] || \
|
||
|
export EASYRSA_PRE_EXPIRY_WINDOW="$alias_days"
|
||
|
status expire "$@"
|
||
|
;;
|
||
|
show-revoke)
|
||
|
[ "$tools_error" ] && user_error "$tools_error_txt"
|
||
|
status revoke "$@"
|
||
|
;;
|
||
|
show-renew)
|
||
|
[ "$tools_error" ] && user_error "$tools_error_txt"
|
||
|
status renew "$@"
|
||
|
;;
|
||
|
verify-cert)
|
||
|
[ "$tools_error" ] && user_error "$tools_error_txt"
|
||
|
# Called with --batch, this will return error
|
||
|
# when the certificate fails verification.
|
||
|
# Therefore, on error, exit with error.
|
||
|
verify_cert "$@" || easyrsa_exit_with_error=1
|
||
|
;;
|
||
|
*)
|
||
|
die "Unknown command: '$cmd'"
|
||
|
esac
|
||
|
;;
|
||
|
gen-tls-*)
|
||
|
verify_working_env
|
||
|
|
||
|
# easyrsa-tools.lib is required
|
||
|
source_easyrsa_tools_lib || tools_error=1
|
||
|
[ "$tools_error" ] && user_error "$tools_error_txt"
|
||
|
|
||
|
case "$cmd" in
|
||
|
gen-tls-auth|gen-tls-auth-*)
|
||
|
tls_key_gen tls-auth "$@"
|
||
|
;;
|
||
|
gen-tls-crypt|gen-tls-crypt-*)
|
||
|
tls_key_gen tls-crypt "$@"
|
||
|
;;
|
||
|
gen-tls-cryptv2|gen-tls-cryptv2-*)
|
||
|
tls_key_gen tls-crypt-v2 "$@"
|
||
|
;;
|
||
|
*)
|
||
|
die "Command '$cmd' not currently implemented."
|
||
|
esac
|
||
|
;;
|
||
|
write)
|
||
|
verify_working_env
|
||
|
|
||
|
# Write legacy files to write_dir
|
||
|
# or EASYRSA_PKI or EASYRSA
|
||
|
case "$1" in
|
||
|
legacy)
|
||
|
# over-write NO
|
||
|
shift
|
||
|
legacy_file_over_write=
|
||
|
all_legacy_files_v2 "$@"
|
||
|
;;
|
||
|
legacy-hard)
|
||
|
# over-write YES
|
||
|
shift
|
||
|
legacy_file_over_write=overwrite
|
||
|
all_legacy_files_v2 "$@"
|
||
|
;;
|
||
|
*)
|
||
|
write_legacy_file_v2 "$@"
|
||
|
esac
|
||
|
;;
|
||
|
serial|check-serial)
|
||
|
verify_working_env
|
||
|
# Called with --batch, this will return error
|
||
|
# when the serial number is not unique.
|
||
|
# Therefore, on error, exit with error.
|
||
|
check_serial_unique "$@" || \
|
||
|
easyrsa_exit_with_error=1
|
||
|
;;
|
||
|
display-dn)
|
||
|
verify_working_env
|
||
|
display_dn "$@"
|
||
|
;;
|
||
|
x509-eku|show-eku)
|
||
|
verify_working_env
|
||
|
ssl_cert_x509v3_eku "$@" || \
|
||
|
easyrsa_exit_with_error=1
|
||
|
;;
|
||
|
rand|random)
|
||
|
easyrsa_random "$1"
|
||
|
;;
|
||
|
""|help|-h|--help|--usage)
|
||
|
verify_working_env
|
||
|
cmd_help "$1"
|
||
|
;;
|
||
|
version)
|
||
|
print_version
|
||
|
;;
|
||
|
*)
|
||
|
user_error "\
|
||
|
Unknown command '$cmd'. Run without commands for usage help."
|
||
|
esac
|
||
|
|
||
|
# Check for untrapped errors
|
||
|
# shellcheck disable=SC2181 # Quote expand - pre-cleanup $?
|
||
|
if [ $? = 0 ]; then
|
||
|
# Do 'cleanup ok' on successful completion
|
||
|
cleanup ok
|
||
|
fi
|
||
|
|
||
|
# Otherwise, exit with error
|
||
|
print "Untrapped error detected!"
|
||
|
cleanup
|
||
|
|
||
|
# vim: ft=sh nu ai sw=8 ts=8 noet
|