diff options
author | Julius Goryavsky <julius.goryavsky@mariadb.com> | 2021-09-23 16:14:54 +0200 |
---|---|---|
committer | Julius Goryavsky <julius.goryavsky@mariadb.com> | 2021-09-24 11:31:27 +0200 |
commit | 77b11965220e249b8fe1dc178e0aff4a8a58db2a (patch) | |
tree | 626c757bcb5905ea4371f20b17ba183f07659ea1 | |
parent | 467011bcac3b3f42ae6f21dde8d88e78708b21d1 (diff) | |
download | mariadb-git-bb-10.2-MDEV-26360-galera.tar.gz |
MDEV-26360: Using hostnames breaks certificate validationbb-10.2-MDEV-26360-galera
Fixed flaws with overly strict or, conversely,
overly soft verification of certificates in some
scenarios:
1. Removed the check that the 'commonname' (CN) in the
certificate matches the 'localhost' value on the side
of the joiner node, which was performed earlier, even
if the address was received by the script only as an
argument (out of the exchange via the Galera protocol) -
since for the joining node this argument always contains
its own local address, not the address of the remote host,
so it is always treated as 'localhost', which is not
necessarily true (outside of mtr testing);
2. Removed checking the domain name or IP-address of the
peer node in the encrypt=2 mode;
3. Fixed checking of compliance of certificates when
rsync SST is used;
4. Added the ability to specify CA not only as a file,
but also as a path to the directory where the certificates
are stored. To do this, the user just needs to specify the
path to this directory as the value ssl-ca or tca parameter,
ending with the '/' character.
-rw-r--r-- | scripts/wsrep_sst_common.sh | 16 | ||||
-rw-r--r-- | scripts/wsrep_sst_mariabackup.sh | 55 | ||||
-rw-r--r-- | scripts/wsrep_sst_rsync.sh | 63 | ||||
-rw-r--r-- | scripts/wsrep_sst_xtrabackup-v2.sh | 61 |
4 files changed, 136 insertions, 59 deletions
diff --git a/scripts/wsrep_sst_common.sh b/scripts/wsrep_sst_common.sh index 67244a7c622..a1293fcb749 100644 --- a/scripts/wsrep_sst_common.sh +++ b/scripts/wsrep_sst_common.sh @@ -1065,8 +1065,9 @@ check_for_dhparams() # verify_ca_matches_cert() { - local ca_path="$1" - local cert_path="$2" + local ca="$1" + local cert="$2" + local path=${3:-0} # If the openssl utility is not installed, then # we will not do this certificate check: @@ -1075,8 +1076,15 @@ verify_ca_matches_cert() return fi - if ! "$OPENSSL_BINARY" verify -verbose -CAfile "$ca_path" "$cert_path" >/dev/null 2>&1 - then + local not_match=0 + + if [ $path -eq 0 ]; then + "$OPENSSL_BINARY" verify -verbose -CAfile "$ca" "$cert" >/dev/null 2>&1 || not_match=1 + else + "$OPENSSL_BINARY" verify -verbose -CApath "$ca" "$cert" >/dev/null 2>&1 || not_match=1 + fi + + if [ $not_match -eq 1 ]; then wsrep_log_error "******** FATAL ERROR ********************************************" wsrep_log_error "* The certifcate and CA (certificate authority) do not match. *" wsrep_log_error "* It does not appear that the certificate was issued by the CA. *" diff --git a/scripts/wsrep_sst_mariabackup.sh b/scripts/wsrep_sst_mariabackup.sh index 54632e5f79b..3fe3bf5c206 100644 --- a/scripts/wsrep_sst_mariabackup.sh +++ b/scripts/wsrep_sst_mariabackup.sh @@ -34,6 +34,7 @@ ssyslog="" ssystag="" BACKUP_PID="" tcert="" +tpath=0 tpem="" tkey="" tmode="DISABLED" @@ -85,7 +86,6 @@ readonly SECRET_TAG="secret" # Required for backup locks # For backup locks it is 1 sent by joiner -# 5.6.21 PXC and later can't donate to an older joiner sst_ver=1 if [ -n "$(command -v pv)" ] && pv --help | grep -qw -- '-F'; then @@ -339,64 +339,83 @@ get_transfer() fi fi + CN_option=",commonname=''" + if [ $encrypt -eq 2 ]; then wsrep_log_info "Using openssl based encryption with socat: with crt and pem" if [ -z "$tpem" -o -z "$tcert" ]; then - wsrep_log_error "Both PEM and CRT files required" + wsrep_log_error \ + "Both PEM file and CRT file (or path) are required" exit 22 fi if [ ! -r "$tpem" -o ! -r "$tcert" ]; then - wsrep_log_error "Both PEM and CRT files must be readable" + wsrep_log_error \ + "Both PEM file and CRT file (or path) must be readable" exit 22 fi - verify_ca_matches_cert "$tcert" "$tpem" - tcmd="$tcmd,cert='$tpem',cafile='$tcert'$sockopt" + verify_ca_matches_cert "$tcert" "$tpem" $tpath + if [ $tpath -eq 0 ]; then + tcmd="$tcmd,cert='$tpem',cafile='$tcert'" + else + tcmd="$tcmd,cert='$tpem',capath='$tcert'" + fi stagemsg="$stagemsg-OpenSSL-Encrypted-2" - wsrep_log_info "$action with cert=$tpem, cafile=$tcert" + wsrep_log_info "$action with cert=$tpem, ca=$tcert" elif [ $encrypt -eq 3 -o $encrypt -eq 4 ]; then wsrep_log_info "Using openssl based encryption with socat: with key and crt" if [ -z "$tpem" -o -z "$tkey" ]; then - wsrep_log_error "Both certificate and key files required" + wsrep_log_error "Both certificate file (or path) " \ + "and key file are required" exit 22 fi if [ ! -r "$tpem" -o ! -r "$tkey" ]; then - wsrep_log_error "Both certificate and key files must be readable" + wsrep_log_error "Both certificate file (or path) " \ + "and key file must be readable" exit 22 fi verify_cert_matches_key "$tpem" "$tkey" stagemsg="$stagemsg-OpenSSL-Encrypted-3" if [ -z "$tcert" ]; then if [ $encrypt -eq 4 ]; then - wsrep_log_error "Peer certificate required if encrypt=4" + wsrep_log_error \ + "Peer certificate file (or path) required if encrypt=4" exit 22 fi # no verification - tcmd="$tcmd,cert='$tpem',key='$tkey',verify=0$sockopt" + CN_option="" + tcmd="$tcmd,cert='$tpem',key='$tkey',verify=0" wsrep_log_info "$action with cert=$tpem, key=$tkey, verify=0" else # CA verification if [ ! -r "$tcert" ]; then - wsrep_log_error "Certificate file must be readable" + wsrep_log_error "Certificate file or path must be readable" exit 22 fi - verify_ca_matches_cert "$tcert" "$tpem" + verify_ca_matches_cert "$tcert" "$tpem" $tpath if [ -n "$WSREP_SST_OPT_REMOTE_USER" ]; then CN_option=",commonname='$WSREP_SST_OPT_REMOTE_USER'" - elif [ $encrypt -eq 4 ]; then + elif [ "$WSREP_SST_OPT_ROLE" = 'joiner' -o $encrypt -eq 4 ] + then CN_option=",commonname=''" elif is_local_ip "$WSREP_SST_OPT_HOST_UNESCAPED"; then CN_option=',commonname=localhost' else CN_option=",commonname='$WSREP_SST_OPT_HOST_UNESCAPED'" fi - tcmd="$tcmd,cert='$tpem',key='$tkey',cafile='$tcert'$CN_option$sockopt" - wsrep_log_info "$action with cert=$tpem, key=$tkey, cafile=$tcert" + if [ $tpath -eq 0 ]; then + tcmd="$tcmd,cert='$tpem',key='$tkey',cafile='$tcert'" + else + tcmd="$tcmd,cert='$tpem',key='$tkey',capath='$tcert'" + fi + wsrep_log_info "$action with cert=$tpem, key=$tkey, ca=$tcert" fi else wsrep_log_info "Unknown encryption mode: encrypt=$encrypt" exit 22 fi + tcmd="$tcmd$CN_option$sockopt" + if [ "$WSREP_SST_OPT_ROLE" = 'joiner' ]; then tcmd="$tcmd stdio" fi @@ -473,6 +492,12 @@ check_server_ssl_config() "of the tca, tcert and/or tkey in the [sst] section" fi fi + if [ -n "$tcert" ]; then + tcert=$(trim_string "$tcert") + if [ "${tcert%/}" != "$tcert" ]; then + tpath=1 + fi + fi } read_cnf() diff --git a/scripts/wsrep_sst_rsync.sh b/scripts/wsrep_sst_rsync.sh index e16ed75cb16..ad9688011e1 100644 --- a/scripts/wsrep_sst_rsync.sh +++ b/scripts/wsrep_sst_rsync.sh @@ -236,11 +236,18 @@ check_server_ssl_config() SSLMODE=$(parse_cnf "$SST_SECTIONS" 'ssl-mode' | tr [:lower:] [:upper:]) # no old-style SSL config in [sst], check for new one: -if [ -z "$SSTKEY" -a -z "$SSTCERT" -a -z "$SSTCA" ] -then +if [ -z "$SSTKEY" -a -z "$SSTCERT" -a -z "$SSTCA" ]; then check_server_ssl_config fi +SSTPATH=0 +if [ -n "$SSTCA" ]; then + SSTCA=$(trim_string "$SSTCA") + if [ "${SSTCA%/}" != "$SSTCA" ]; then + SSTPATH=1 + fi +fi + if [ -z "$SSLMODE" ]; then # Implicit verification if CA is set and the SSL mode # is not specified by user: @@ -254,9 +261,19 @@ if [ -z "$SSLMODE" ]; then fi fi -if [ -n "$SSTCA" ] -then - CAFILE_OPT="CAfile = $SSTCA" +if [ -n "$SSTCERT" -a -n "$SSTKEY" ]; then + verify_cert_matches_key "$SSTCERT" "$SSTKEY" +fi + +if [ -n "$SSTCA" ]; then + if [ $SSTPATH -eq 0 ]; then + CAFILE_OPT="CAfile = $SSTCA" + else + CAFILE_OPT="CApath = $SSTCA" + fi + if [ -n "$SSTCERT" ]; then + verify_ca_matches_cert "$SSTCA" "$SSTCERT" $SSTPATH + fi else CAFILE_OPT="" fi @@ -272,38 +289,38 @@ then ;; 'VERIFY_CA') VERIFY_OPT='verifyChain = yes' - if [ -n "$WSREP_SST_OPT_REMOTE_USER" ]; then - CHECK_OPT="checkHost = $WSREP_SST_OPT_REMOTE_USER" - else - # check if the address is an ip-address (v4 or v6): - if echo "$WSREP_SST_OPT_HOST_UNESCAPED" | \ - grep -q -E '^([0-9]+(\.[0-9]+){3}|[0-9a-fA-F]*(\:[0-9a-fA-F]*)+)$' - then - CHECK_OPT="checkIP = $WSREP_SST_OPT_HOST_UNESCAPED" - else - CHECK_OPT="checkHost = $WSREP_SST_OPT_HOST" - fi - if is_local_ip "$WSREP_SST_OPT_HOST_UNESCAPED"; then - CHECK_OPT_LOCAL="checkHost = localhost" - fi - fi ;; *) wsrep_log_error "Unrecognized ssl-mode option: '$SSLMODE'" exit 22 # EINVAL ;; esac - if [ -z "$CAFILE_OPT" ]; then - wsrep_log_error "Can't have ssl-mode='$SSLMODE' without CA file" + if [ -z "$SSTCA" ]; then + wsrep_log_error "Can't have ssl-mode='$SSLMODE' without CA file or path" exit 22 # EINVAL fi + if [ -n "$WSREP_SST_OPT_REMOTE_USER" ]; then + CHECK_OPT="checkHost = $WSREP_SST_OPT_REMOTE_USER" + elif [ "$WSREP_SST_OPT_ROLE" = 'donor' ]; then + # check if the address is an ip-address (v4 or v6): + if echo "$WSREP_SST_OPT_HOST_UNESCAPED" | \ + grep -q -E '^([0-9]+(\.[0-9]+){3}|[0-9a-fA-F]*(\:[0-9a-fA-F]*)+)$' + then + CHECK_OPT="checkIP = $WSREP_SST_OPT_HOST_UNESCAPED" + else + CHECK_OPT="checkHost = $WSREP_SST_OPT_HOST" + fi + if is_local_ip "$WSREP_SST_OPT_HOST_UNESCAPED"; then + CHECK_OPT_LOCAL="checkHost = localhost" + fi + fi fi STUNNEL="" if [ -n "$SSLMODE" -a "$SSLMODE" != 'DISABLED' ]; then STUNNEL_BIN="$(command -v stunnel)" if [ -n "$STUNNEL_BIN" ]; then - wsrep_log_info "Using stunnel for SSL encryption: CAfile: '$SSTCA', ssl-mode='$SSLMODE'" + wsrep_log_info "Using stunnel for SSL encryption: CA: '$SSTCA', ssl-mode='$SSLMODE'" STUNNEL="$STUNNEL_BIN $STUNNEL_CONF" fi fi diff --git a/scripts/wsrep_sst_xtrabackup-v2.sh b/scripts/wsrep_sst_xtrabackup-v2.sh index 999c6c649ba..7cc05185ce3 100644 --- a/scripts/wsrep_sst_xtrabackup-v2.sh +++ b/scripts/wsrep_sst_xtrabackup-v2.sh @@ -34,6 +34,7 @@ ssyslog="" ssystag="" BACKUP_PID="" tcert="" +tpath=0 tpem="" tkey="" tmode="DISABLED" @@ -201,9 +202,10 @@ get_keys() if [ -z "$ekey" ]; then ecmd="xbcrypt --encrypt-algo='$ealgo' --encrypt-key-file='$ekeyfile'" else - wsrep_log_warning "Using the 'encrypt-key' option causes the encryption key" - wsrep_log_warning "to be set via the command-line and is considered insecure." - wsrep_log_warning "It is recommended to use the 'encrypt-key-file' option instead." + wsrep_log_warning \ + "Using the 'encrypt-key' option causes the encryption key " \ + "to be set via the command-line and is considered insecure. " \ + "It is recommended to use the 'encrypt-key-file' option instead." ecmd="xbcrypt --encrypt-algo='$ealgo' --encrypt-key='$ekey'" fi if [ -n "$encrypt_threads" ]; then @@ -341,64 +343,83 @@ get_transfer() fi fi + CN_option=",commonname=''" + if [ $encrypt -eq 2 ]; then wsrep_log_info "Using openssl based encryption with socat: with crt and pem" if [ -z "$tpem" -o -z "$tcert" ]; then - wsrep_log_error "Both PEM and CRT files required" + wsrep_log_error \ + "Both PEM file and CRT file (or path) are required" exit 22 fi if [ ! -r "$tpem" -o ! -r "$tcert" ]; then - wsrep_log_error "Both PEM and CRT files must be readable" + wsrep_log_error \ + "Both PEM file and CRT file (or path) must be readable" exit 22 fi - verify_ca_matches_cert "$tcert" "$tpem" - tcmd="$tcmd,cert='$tpem',cafile='$tcert'$sockopt" + verify_ca_matches_cert "$tcert" "$tpem" $tpath + if [ $tpath -eq 0 ]; then + tcmd="$tcmd,cert='$tpem',cafile='$tcert'" + else + tcmd="$tcmd,cert='$tpem',capath='$tcert'" + fi stagemsg="$stagemsg-OpenSSL-Encrypted-2" - wsrep_log_info "$action with cert=$tpem, cafile=$tcert" + wsrep_log_info "$action with cert=$tpem, ca=$tcert" elif [ $encrypt -eq 3 -o $encrypt -eq 4 ]; then wsrep_log_info "Using openssl based encryption with socat: with key and crt" if [ -z "$tpem" -o -z "$tkey" ]; then - wsrep_log_error "Both certificate and key files required" + wsrep_log_error "Both certificate file (or path) " \ + "and key file are required" exit 22 fi if [ ! -r "$tpem" -o ! -r "$tkey" ]; then - wsrep_log_error "Both certificate and key files must be readable" + wsrep_log_error "Both certificate file (or path) " \ + "and key file must be readable" exit 22 fi verify_cert_matches_key "$tpem" "$tkey" stagemsg="$stagemsg-OpenSSL-Encrypted-3" if [ -z "$tcert" ]; then if [ $encrypt -eq 4 ]; then - wsrep_log_error "Peer certificate required if encrypt=4" + wsrep_log_error \ + "Peer certificate file (or path) required if encrypt=4" exit 22 fi # no verification - tcmd="$tcmd,cert='$tpem',key='$tkey',verify=0$sockopt" + CN_option="" + tcmd="$tcmd,cert='$tpem',key='$tkey',verify=0" wsrep_log_info "$action with cert=$tpem, key=$tkey, verify=0" else # CA verification if [ ! -r "$tcert" ]; then - wsrep_log_error "Certificate file must be readable" + wsrep_log_error "Certificate file or path must be readable" exit 22 fi - verify_ca_matches_cert "$tcert" "$tpem" + verify_ca_matches_cert "$tcert" "$tpem" $tpath if [ -n "$WSREP_SST_OPT_REMOTE_USER" ]; then CN_option=",commonname='$WSREP_SST_OPT_REMOTE_USER'" - elif [ $encrypt -eq 4 ]; then + elif [ "$WSREP_SST_OPT_ROLE" = 'joiner' -o $encrypt -eq 4 ] + then CN_option=",commonname=''" elif is_local_ip "$WSREP_SST_OPT_HOST_UNESCAPED"; then CN_option=',commonname=localhost' else CN_option=",commonname='$WSREP_SST_OPT_HOST_UNESCAPED'" fi - tcmd="$tcmd,cert='$tpem',key='$tkey',cafile='$tcert'$CN_option$sockopt" - wsrep_log_info "$action with cert=$tpem, key=$tkey, cafile=$tcert" + if [ $tpath -eq 0 ]; then + tcmd="$tcmd,cert='$tpem',key='$tkey',cafile='$tcert'" + else + tcmd="$tcmd,cert='$tpem',key='$tkey',capath='$tcert'" + fi + wsrep_log_info "$action with cert=$tpem, key=$tkey, ca=$tcert" fi else wsrep_log_info "Unknown encryption mode: encrypt=$encrypt" exit 22 fi + tcmd="$tcmd$CN_option$sockopt" + if [ "$WSREP_SST_OPT_ROLE" = 'joiner' ]; then tcmd="$tcmd stdio" fi @@ -475,6 +496,12 @@ check_server_ssl_config() "of the tca, tcert and/or tkey in the [sst] section" fi fi + if [ -n "$tcert" ]; then + tcert=$(trim_string "$tcert") + if [ "${tcert%/}" != "$tcert" ]; then + tpath=1 + fi + fi } read_cnf() |