From b24fdc5e21b30c4d2b6e64ed690a018ee0f9717f Mon Sep 17 00:00:00 2001 From: Frank Breedijk Date: Mon, 4 Jul 2016 17:35:19 +0200 Subject: [PATCH] Back to our original commit --- testssl.sh | 127 ++++++++++------------------------------------------- 1 file changed, 23 insertions(+), 104 deletions(-) diff --git a/testssl.sh b/testssl.sh index 8d8b566..38eef5f 100755 --- a/testssl.sh +++ b/testssl.sh @@ -83,7 +83,7 @@ readonly PS4='${LINENO}> ${FUNCNAME[0]:+${FUNCNAME[0]}(): }' # make sure that temporary files are cleaned up after use in ANY case trap "cleanup" QUIT EXIT -readonly VERSION="2.8rc1" +readonly VERSION="2.7dev" readonly SWCONTACT="dirk aet testssl dot sh" egrep -q "dev|rc" <<< "$VERSION" && \ SWURL="https://testssl.sh/dev/" || @@ -170,12 +170,10 @@ USLEEP_SND=${USLEEP_SND:-0.1} # sleep time for general socket send USLEEP_REC=${USLEEP_REC:-0.2} # sleep time for general socket receive HSTS_MIN=${HSTS_MIN:-179} # >179 days is ok for HSTS HPKP_MIN=${HPKP_MIN:-30} # >=30 days should be ok for HPKP_MIN, practical hints? +readonly CLIENT_MIN_PFS=5 # number of ciphers needed to run a test for PFS DAYS2WARN1=${DAYS2WARN1:-60} # days to warn before cert expires, threshold 1 DAYS2WARN2=${DAYS2WARN2:-30} # days to warn before cert expires, threshold 2 VULN_THRESHLD=${VULN_THRESHLD:-1} # if vulnerabilities to check >$VULN_THRESHLD we DON'T show a separate header line in the output each vuln. check -readonly CLIENT_MIN_PFS=5 # number of ciphers needed to run a test for PFS - # generated from 'kEECDH:kEDH:!aNULL:!eNULL:!DES:!3DES:!RC4' with openssl 1.0.2i and openssl 1.1.0 -readonly ROBUST_PFS_CIPHERS="DHE-DSS-AES128-GCM-SHA256:DHE-DSS-AES128-SHA256:DHE-DSS-AES128-SHA:DHE-DSS-AES256-GCM-SHA384:DHE-DSS-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-DSS-CAMELLIA128-SHA256:DHE-DSS-CAMELLIA128-SHA:DHE-DSS-CAMELLIA256-SHA256:DHE-DSS-CAMELLIA256-SHA:DHE-DSS-SEED-SHA:DHE-RSA-AES128-CCM8:DHE-RSA-AES128-CCM:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-CCM8:DHE-RSA-AES256-CCM:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-CAMELLIA128-SHA256:DHE-RSA-CAMELLIA128-SHA:DHE-RSA-CAMELLIA256-SHA256:DHE-RSA-CAMELLIA256-SHA:DHE-RSA-CHACHA20-POLY1305-OLD:DHE-RSA-CHACHA20-POLY1305:DHE-RSA-SEED-SHA:ECDHE-ECDSA-AES128-CCM8:ECDHE-ECDSA-AES128-CCM:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-ECDSA-AES256-CCM8:ECDHE-ECDSA-AES256-CCM:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-ECDSA-CAMELLIA128-SHA256:ECDHE-ECDSA-CAMELLIA256-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305-OLD:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-RSA-CAMELLIA128-SHA256:ECDHE-RSA-CAMELLIA256-SHA384:ECDHE-RSA-CHACHA20-POLY1305-OLD:ECDHE-RSA-CHACHA20-POLY1305" HAD_SLEPT=0 CAPATH="${CAPATH:-/etc/ssl/certs/}" # Does nothing yet (FC has only a CA bundle per default, ==> openssl version -d) @@ -962,7 +960,6 @@ run_hpkp() { local i local hpkp_headers local first_hpkp_header - local ca_bundles="$INSTALL_DIR/etc/*.pem" if [[ ! -s $HEADERFILE ]]; then run_http_header "$1" || return 3 @@ -1032,98 +1029,21 @@ run_hpkp() { if [[ ! -s "$HOSTCERT" ]]; then get_host_cert || return 1 fi - - # Get the pins first - pins=$(tr ';' '\n' < $TMPFILE | tr -d ' ' | tr -d '\"' | awk -F'=' '/pin.*=/ { print $2 }') - # get the key fingerprint from the host certificate hpkp_key_hostcert="$($OPENSSL x509 -in $HOSTCERT -pubkey -noout | grep -v PUBLIC | \ $OPENSSL base64 -d | $OPENSSL dgst -sha256 -binary | $OPENSSL base64)" # compare it with the ones provided in the header - for hpkp_key in $(echo "$pins"); do + while read hpkp_key; do if [[ "$hpkp_key_hostcert" == "$hpkp_key" ]] || [[ "$hpkp_key_hostcert" == "$hpkp_key=" ]]; then out "\n$spaces matching host key: " pr_done_good "$hpkp_key" - fileout "hpkp_keymatch" "OK" "Host certificate key matches a key pinned in the HPKP header" + fileout "hpkp_keymatch" "OK" "Key matches a key pinned in the HPKP header" key_found=true fi debugme out "\n $hpkp_key | $hpkp_key_hostcert" - done - - if ! $key_found ; then - # Get keys from intermediate certificates - $OPENSSL s_client -showcerts $STARTTLS $BUGS $PROXY -showcerts -connect $NODEIP:$PORT ${sni[i]} $TMPFILE 2>$ERRFILE - # Place the server's certificate in $HOSTCERT and any intermediate - # certificates that were provided in $TEMPDIR/intermediatecerts.pem - # http://backreference.org/2010/05/09/ocsp-verification-with-openssl/ - awk -v n=-1 "/Certificate chain/ {start=1} - /-----BEGIN CERTIFICATE-----/{ if (start) {inc=1; n++} } - inc { print > (\"$TEMPDIR/level\" n \".crt\") } - /---END CERTIFICATE-----/{ inc=0 }" $TMPFILE - nrsaved=$(count_words "$(echo $TEMPDIR/level?.crt 2>/dev/null)") - rm $TEMPDIR/level0.crt - - # Compare them against the hashes found - if [[ nrsaved -ge 2 ]]; then - echo -n "" > "$TEMPDIR/hashes.intermediate" - for cert_fname in $TEMPDIR/level?.crt; do - hpkp_key_ca="$($OPENSSL x509 -in "$cert_fname" -pubkey -noout | grep -v PUBLIC|$OPENSSL dgst -sha256 -binary | $OPENSSL enc -base64)" - issuer="$(get_cn_from_cert $cert_fname)" - [[ -n $hpkp_name ]] || hpkp_name=$($OPENSSL x509 -in "$cert_fname" -subject -noout| sed "s/^subject= //") - echo "$hpkp_key_ca $bundle_name $issuer" >> "$TEMPDIR/hashes.intermediate" - done - for hpkp_key in $(echo $pins); do - hpkp_matches=$(grep "$hpkp_key" $TEMPDIR/hashes.intermediate) - if [[ -n $hpkp_matches ]]; then - # We have a winner! - key_found=true - out "\n$spaces Intermediate CA match : " - pr_done_good "$hpkp_matches" - fileout "hpkp_keymatch" "OK" "Intermediate CA key matches a key pinned in the HPKP header\nKey/CA: $hpkp_matches" - fi - done - fi - fi - - if ! $key_found ; then - # Get keys from Root CAs - for bundle_fname in $ca_bundles; do - local bundle_name=$(basename ${bundle_fname//.pem}) - if [[ ! -r $bundle_fname ]]; then - pr_warningln "\"$bundle_fname\" cannot be found / not readable" - return 7 - fi - debugme printf -- " %-12s" "${certificate_file[i]}" - # Split up the certificate bundle - awk -v n=-1 "BEGIN {start=1} - /-----BEGIN CERTIFICATE-----/{ if (start) {inc=1; n++} } - inc { print >> (\"$TEMPDIR/$bundle_name.\" n \".crt\") ; close (\"$TEMPDIR/$bundle_name.\" n \".crt\") } - /---END CERTIFICATE-----/{ inc=0 }" $bundle_fname - # Clear temp file - echo -n "" > "$TEMPDIR/hashes.$bundle_name" - for cert_fname in $TEMPDIR/$bundle_name.*.crt; do - hpkp_key_ca="$($OPENSSL x509 -in "$cert_fname" -pubkey -noout | grep -v PUBLIC|$OPENSSL dgst -sha256 -binary | $OPENSSL enc -base64)" - issuer="$(get_cn_from_cert $cert_fname)" - [[ -n $hpkp_name ]] || hpkp_name=$($OPENSSL x509 -in "$cert_fname" -subject -noout| sed "s/^subject= //") - echo "$hpkp_key_ca $bundle_name : $issuer" >> "$TEMPDIR/hashes.$bundle_name" - done - done - for hpkp_key in $(echo $pins); do - hpkp_matches=$(grep -h "$hpkp_key" $TEMPDIR/hashes.*) - if [[ -n $hpkp_matches ]]; then - # We have a winner! - key_found=true - out "\n$spaces Root CA match : " - pr_done_goodln "$hpkp_key" - #out "$hpkp_matches" - - fileout "hpkp_keymatch" "OK" "Root CA key matches a key pinned in the HPKP header\nKey/OS/CA: $hpkp_matches" - fi - done - fi - - # If all else fails... + done < <(tr ';' '\n' < $TMPFILE | tr -d ' ' | tr -d '\"' | awk -F'=' '/pin.*=/ { print $2 }') if ! $key_found ; then + out "\n$spaces" pr_svrty_high " No matching key for pins found " out "(CAs pinned? -- not checked for yet)" fileout "hpkp_keymatch" "DEBUG" "The TLS key does not match any key pinned in the HPKP header. If you pinned a CA key you can ignore this" @@ -1613,13 +1533,9 @@ neat_list(){ kx="${3//Kx=/}" enc="${4//Enc=/}" - strength="${enc//\)/}" # retrieve (). first remove traling ")" - strength="${strength#*\(}" # exfiltrate (VAL - enc="${enc%%\(*}" - - enc="${enc//POLY1305/}" # remove POLY1305 - enc="${enc//\//}" # remove "/" - + strength=$(sed -e 's/.*(//' -e 's/)//' <<< "$enc") # strength = encryption bits + strength="${strength//ChaCha20-Poly1305/ly1305}" + enc=$(sed -e 's/(.*)//g' -e 's/ChaCha20-Poly1305/ChaCha20-Po/g' <<< "$enc") # workaround for empty bits ChaCha20-Poly1305 echo "$export" | grep -iq export && strength="$strength,exp" #printf -- "%q" "$kx" | xxd | head -1 @@ -2093,7 +2009,7 @@ run_client_simulation() { local name tls proto cipher local using_sockets=true - if $SSL_NATIVE || [[ -n "$STARTTLS" ]]; then + if $SSL_NATIVE || [[ -n "$STARTTLS" ]] || ! $EXPERIMENTAL; then using_sockets=false fi @@ -3997,7 +3913,7 @@ certificate_info() { ;; *) out "$cert_sig_algo (" - pr_warning "FIXME: can't tell whether this is good or not" + pr_warning "FIXME: is unknown" outln ")" fileout "${json_prefix}algorithm" "DEBUG" "Signature Algorithm: $sign_algo" ;; @@ -4067,7 +3983,7 @@ certificate_info() { fi else out "$cert_keysize bits (" - pr_warning "FIXME: can't tell whether this is good or not" + pr_warning "FIXME: can't tell whether this is good here or not" outln ")" fileout "${json_prefix}key_size" "WARN" "Server keys $cert_keysize bits (unknown signature algorithm)" fi @@ -4463,13 +4379,18 @@ run_server_defaults() { done } +# http://www.heise.de/security/artikel/Forward-Secrecy-testen-und-einrichten-1932806.html run_pfs() { local -i sclient_success local pfs_offered=false local tmpfile local dhlen local hexcode dash pfs_cipher sslvers kx auth enc mac - local pfs_cipher_list="$ROBUST_PFS_CIPHERS" + # https://community.qualys.com/blogs/securitylabs/2013/08/05/configuring-apache-nginx-and-openssl-for-forward-secrecy -- but with RC4: + #local pfs_ciphers='EECDH+ECDSA+AESGCM EECDH+aRSA+AESGCM EECDH+ECDSA+SHA256 EECDH+aRSA+SHA256 EECDH+aRSA+RC4 EDH+aRSA EECDH RC4 !RC4-SHA !aNULL !eNULL !LOW !3DES !MD5 !EXP !PSK !SRP !DSS:@STRENGTH' + #w/o RC4: + #local pfs_ciphers='EECDH+ECDSA+AESGCM EECDH+aRSA+AESGCM EECDH+ECDSA+SHA256 EECDH+aRSA+SHA256 EDH+aRSA EECDH !RC4-SHA !aNULL !eNULL !LOW !3DES !MD5 !EXP !PSK !SRP !DSS:@STRENGTH' + local pfs_cipher_list="ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-CAMELLIA256-SHA256:DHE-RSA-CAMELLIA256-SHA:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-CAMELLIA256-SHA384:ECDHE-ECDSA-CAMELLIA256-SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-ECDSA-CAMELLIA128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-CAMELLIA128-SHA256:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-CAMELLIA128-SHA256:DHE-RSA-SEED-SHA:DHE-RSA-CAMELLIA128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA" local -i nr_supported_ciphers=0 local pfs_ciphers @@ -4489,7 +4410,7 @@ run_pfs() { return 1 fi - $OPENSSL s_client -cipher $pfs_cipher_list $STARTTLS $BUGS -connect $NODEIP:$PORT $PROXY $SNI >$TMPFILE 2>$ERRFILE $TMPFILE 2>$ERRFILE $LOGFILE outln "## Scan started as: \"$PROG_NAME $CMDLINE\"" >>${LOGFILE} - outln "## at $HNAME:$OPENSSL_LOCATION" >>${LOGFILE} - outln "## version testssl: $VERSION ${GIT_REL_SHORT:-$CVS_REL_SHORT} from $REL_DATE" >>${LOGFILE} - outln "## version openssl: \"$OSSL_VER\" from \"$OSSL_BUILD_DATE\")\n" >>${LOGFILE} + outln "## ($VERSION ${GIT_REL_SHORT:-$CVS_REL_SHORT} from $REL_DATE, at $HNAME:$OPENSSL_LOCATION)\n" >>${LOGFILE} exec > >(tee -a ${LOGFILE}) # not decided yet. Maybe good to have a separate file or none at all #exec 2> >(tee -a ${LOGFILE} >&2) @@ -8178,7 +8097,7 @@ find_openssl_binary maketempf mybanner check_proxy -check4openssl_oldfarts +openssl_age bsd-bash # TODO: it is ugly to have those two vars here --> main() @@ -8237,4 +8156,4 @@ fi exit $? -# $Id: testssl.sh,v 1.514 2016/07/04 11:59:38 dirkw Exp $ +# $Id: testssl.sh,v 1.509 2016/06/28 10:21:48 dirkw Exp $