diff --git a/CREDITS.md b/CREDITS.md index fcbd2ca..6b6651b 100644 --- a/CREDITS.md +++ b/CREDITS.md @@ -7,7 +7,7 @@ - openssl sources support with the "missing" features * John Newbigin - - Proxy support + - Proxy support (sockets and openssl) * Jonathan Roach - TLS_FALLBACK_SCSV checks @@ -17,12 +17,13 @@ - Shellcheck static analysis * Frank Breedijk - - Detection of insecure redirect - - client simulation + - Detection of insecure redirects + - JSON and CSV output + - Client simulations * dcooper16 - Detection + output of multiple certificates - - cleanups of server certificate related stuff + - several cleanups of server certificate related stuff * Jean Marsault - client auth: ideas, code snipplets @@ -61,6 +62,10 @@ * Viktor Szépe - color function maker +* Thomas Martens + - colorblind + - no-rfc mapping + * Jonathon Rossi - fix for bash3 (Darwin) - and other Darwin fixes @@ -75,10 +80,6 @@ * Dmitri S - inspiration & help for Darwin port -* Frank Breedijk - - JSON and CSV output - - Client simulations - * Bug reports: - Viktor Szépe, Olivier Paroz, Jan H. Terstegge, Lorenz Adena, Jonathon Rossi, Stefan Stidl, Frank Breedijk diff --git a/Readme.md b/Readme.md index bfa15c3..740eca1 100644 --- a/Readme.md +++ b/Readme.md @@ -41,7 +41,9 @@ Done so far: * Logging to JSON + CSV * check for multiple server certificates * browser cipher simulation +* assistance for color-blind users * Even more compatibilty improvements for FreeBSD, RH-ish and F5 systems +* OpenSSL 1.1.0 compliant Contributions, feedback, also bug reports are welcome! For contributions please note: One patch per feature -- bug fix/improvement. Please test your changes thouroughly as reliability is important for this project. diff --git a/etc/curves.txt b/etc/curves.txt new file mode 100644 index 0000000..31217c7 --- /dev/null +++ b/etc/curves.txt @@ -0,0 +1,31 @@ +# Value, IANA name, +1, sect163k1, K-163 +2, sect163r1, +3, sect163r2, B-163 +4, sect193r1, +5, sect193r2, +6, sect233k1, K-233 +7, sect233r1, B-233 +8, sect239k1, +9, sect283k1, K-283 +10, sect283r1, B-283 +11, sect409k1, K-409 +12, sect409r1, B-409 +13, sect571k1, K-571 +14, sect571r1, B-571 +15, secp160k1, +16, secp160r1, +17, secp160r2, +18, secp192k1, +19, secp192r1, P-192 +20, secp224k1, +21, secp224r1, P-224 +22, secp256k1, +23, secp256r1, P-256 +24, secp384r1, P-384 +25, secp521r1, P-521 +26, brainpoolP256r1, +27, brainpoolP384r1, +28, brainpoolP512r1, +unknown, curve448, +unknown, curve25519 diff --git a/etc/mapping-rfc.txt b/etc/mapping-rfc.txt index 817af6d..0f9dd8d 100644 --- a/etc/mapping-rfc.txt +++ b/etc/mapping-rfc.txt @@ -340,6 +340,6 @@ xCC13 TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 xCC14 TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 xCC15 TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256 xFEFE SSL_RSA_FIPS_WITH_DES_CBC_SHA -xFEFE SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA +xFEFF SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA xFFE0 SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA xFFE1 SSL_RSA_FIPS_WITH_DES_CBC_SHA diff --git a/openssl-rfc.mappping.html b/openssl-rfc.mappping.html index 45bd4c0..fb747a3 100644 --- a/openssl-rfc.mappping.html +++ b/openssl-rfc.mappping.html @@ -14,6 +14,16 @@ td { border:1px solid #999; }
+ + @@ -26,6 +36,7 @@ td { border:1px solid #999; } + @@ -54,9 +65,13 @@ td { border:1px solid #999; } + + + + @@ -71,6 +86,13 @@ td { border:1px solid #999; } + + + + + + + @@ -89,6 +111,8 @@ td { border:1px solid #999; } + + @@ -96,7 +120,8 @@ td { border:1px solid #999; } - + + @@ -109,21 +134,26 @@ td { border:1px solid #999; } - - - - + + + + + + + + + + - @@ -133,12 +163,15 @@ td { border:1px solid #999; } + + + @@ -152,8 +185,47 @@ td { border:1px solid #999; } - + + + + + + + + + + + + + + + @@ -179,6 +251,8 @@ td { border:1px solid #999; } + + @@ -188,6 +262,8 @@ td { border:1px solid #999; } + + @@ -205,6 +281,7 @@ td { border:1px solid #999; } + @@ -214,6 +291,8 @@ td { border:1px solid #999; } + + @@ -269,6 +348,7 @@ td { border:1px solid #999; } + @@ -303,15 +383,16 @@ td { border:1px solid #999; } - - - - - - - - + + + + + + + + + @@ -328,6 +409,8 @@ td { border:1px solid #999; } + + @@ -341,8 +424,31 @@ td { border:1px solid #999; } + + + + + + + + + diff --git a/testssl.sh b/testssl.sh index 459c055..2ee8b96 100755 --- a/testssl.sh +++ b/testssl.sh @@ -135,6 +135,7 @@ declare -x OPENSSL COLOR=${COLOR:-2} # 2: Full color, 1: b/w+positioning, 0: no ESC at all COLORBLIND=${COLORBLIND:-false} # if true, swap blue and green in the output SHOW_EACH_C=${SHOW_EACH_C:-0} # where individual ciphers are tested show just the positively ones tested #FIXME: upside down value +SHOW_SIGALGO=${SHOW_SIGALGO:-false} # "secret" switch weher testssl.sh shows the signature algorithm for -E / -e SNEAKY=${SNEAKY:-false} # is the referer and useragent we leave behind just usual? QUIET=${QUIET:-false} # don't output the banner. By doing this yiu acknowledge usage term appearing in the banner SSL_NATIVE=${SSL_NATIVE:-false} # we do per default bash sockets where possible "true": switch back to "openssl native" @@ -368,6 +369,9 @@ pr_headlineln() { pr_headline "$1" ; outln; } pr_squoted() { out "'$1'"; } pr_dquoted() { out "\"$1\""; } +local_problem_ln() { pr_litemagentaln "Local problem: $1"; } +local_problem() { pr_litemagenta "Local problem: $1"; } + ### color switcher (see e.g. https://linuxtidbits.wordpress.com/2008/08/11/output-color-on-bash-scripts/ ### http://www.tldp.org/HOWTO/Bash-Prompt-HOWTO/x405.html set_color_functions() { @@ -449,23 +453,22 @@ fileout_footer() { } fileout() { # ID, SEVERITY, FINDING - local finding="$5" + local finding=$(strip_lf "$(newline_to_spaces "$(strip_quote "$3")")") if "$do_json"; then "$FIRST_FINDING" || echo "," >> $JSONFILE - finding=$(strip_quote "$3") echo -e " { - 'id' : '$1', - 'ip' : '$NODE/$NODEIP', - 'port' : '$PORT', - 'severity' : '$2', - 'finding' : '$finding' + \"id\" : \"$1\", + \"ip\" : \"$NODE/$NODEIP\", + \"port\" : \"$PORT\", + \"severity\" : \"$2\", + \"finding\" : \"$finding\" }" >> $JSONFILE fi # does the following do any sanitization? if "$do_csv"; then - echo -e \""$1\"",\"$NODE/$NODEIP\",\"$PORT"\",\""$2"\",\"$(strip_quote "$3")\"" >>$CSVFILE + echo -e \""$1\"",\"$NODE/$NODEIP\",\"$PORT"\",\""$2"\",\""$finding"\"" >>$CSVFILE fi "$FIRST_FINDING" && FIRST_FINDING=false } @@ -1280,8 +1283,13 @@ prettyprint_local() { local hexcode dash ciph sslvers kx auth enc mac export local re='^[0-9A-Fa-f]+$' + if [[ "$1" == 0x* ]] || [[ "$1" == 0X* ]]; then + fatal "pls supply x instead" 2 + fi + pr_headline " Displaying all local ciphers "; if [[ -n "$1" ]]; then + # pattern provided; which one? [[ $1 =~ $re ]] && \ pr_headline "matching number pattern \"$1\" " || \ pr_headline "matching word pattern "\"$1\"" (ignore case) " @@ -1384,7 +1392,7 @@ std_cipherlists() { tmpfile_handle $FUNCNAME.$debugname.txt else singlespaces=$(echo "$2" | sed -e 's/ \+/ /g' -e 's/^ //' -e 's/ $//g' -e 's/ //g') - local_problem "No $singlespaces configured in $OPENSSL" + local_problem_ln "No $singlespaces configured in $OPENSSL" fileout "std_$4" "WARN" "Cipher $2 ($1) not supported by local OpenSSL ($OPENSSL)" fi # we need 1xlf in those cases: @@ -1582,8 +1590,12 @@ run_allciphers(){ available="not a/v" fi fi + if "$SHOW_SIGALGO"; then + $OPENSSL x509 -noout -text -in $TMPFILE | awk -F':' '/Signature Algorithm/ { print $2 }' | head -1 + else + outln + fi fileout "cipher_$HEXC" "INFO" "$(neat_list "$HEXC" "$ciph" "$kx" "$enc") $available" - outln tmpfile_handle $FUNCNAME.txt done outln @@ -1628,7 +1640,11 @@ run_cipher_per_proto(){ available="not a/v" fi fi - outln + if "$SHOW_SIGALGO"; then + $OPENSSL x509 -noout -text -in $TMPFILE | awk -F':' '/Signature Algorithm/ { print $2 }' | head -1 + else + outln + fi id="cipher$proto" id+="_$HEXC" fileout "$id" "INFO" "$proto_text $(neat_list "$HEXC" "$ciph" "$kx" "$enc") $available" @@ -2040,7 +2056,7 @@ run_client_simulation() { locally_supported() { [[ -n "$2" ]] && out "$2 " if $OPENSSL s_client "$1" 2>&1 | grep -aq "unknown option"; then - local_problem "$OPENSSL doesn't support \"s_client $1\"" + local_problem_ln "$OPENSSL doesn't support \"s_client $1\"" return 7 fi return 0 @@ -2107,8 +2123,8 @@ run_protocols() { using_sockets=false else using_sockets=true - pr_headlineln "(via sockets except TLS 1.2 and SPDY/HTTP2) " - via+="via sockets except for TLS1.1 and SPDY/HTTP2" + pr_headlineln "(via sockets except TLS 1.2, SPDY+HTTP2) " + via+="via sockets except for TLS1.2, SPDY+HTTP2" fi fi outln @@ -2546,7 +2562,7 @@ run_server_preference() { } cipher_pref_check() { - local p proto protos + local p proto protos npn_protos local tested_cipher cipher order pr_bold " Cipher order" @@ -2579,8 +2595,8 @@ cipher_pref_check() { if ! spdy_pre " SPDY/NPN: "; then # is NPN/SPDY supported and is this no STARTTLS? outln else - protos=$($OPENSSL s_client -host $NODE -port $PORT $BUGS -nextprotoneg \"\" >$ERRFILE | grep -a "^Protocols " | sed -e 's/^Protocols.*server: //' -e 's/,//g') - for p in $protos; do + npn_protos=$($OPENSSL s_client -host $NODE -port $PORT $BUGS -nextprotoneg \"\" >$ERRFILE | grep -a "^Protocols " | sed -e 's/^Protocols.*server: //' -e 's/,//g') + for p in $npn_protos; do order="" $OPENSSL s_client -host $NODE -port $PORT $BUGS -nextprotoneg "$p" $PROXY >$ERRFILE >$TMPFILE cipher=$(grep -aw "Cipher" $TMPFILE | egrep -avw "New|is" | sed -e 's/^.*Cipher.*://' -e 's/ //g') @@ -2610,12 +2626,13 @@ cipher_pref_check() { get_host_cert() { local tmpvar=$TEMPDIR/$FUNCNAME.txt # change later to $TMPFILE - $OPENSSL s_client $STARTTLS $BUGS -connect $NODEIP:$PORT $PROXY $SNI $1 2>/dev/null $TEMPDIR/$FUNCNAME.txt + $OPENSSL s_client $STARTTLS $BUGS -connect $NODEIP:$PORT $PROXY $SNI $1 2>/dev/null $tmpdir if sclient_connect_successful $? $tmpvar; then awk '/-----BEGIN/,/-----END/ { print $0 }' $tmpvar >$HOSTCERT else return 1 fi + tmpfile_handle $FUNCNAME.txt # return $((${PIPESTATUS[0]} + ${PIPESTATUS[1]})) } @@ -2640,7 +2657,7 @@ verify_retcode_helper() { } determine_trust() { - local heading=$1 + local json_prefix=$1 local -i i=1 local -i num_ca_bundles=0 local bundle_fname @@ -2651,24 +2668,24 @@ determine_trust() { local some_ok=false local code local ca_bundles="$INSTALL_DIR/etc/*.pem" - local spaces=" " + local spaces=" " local -i certificates_provided=1+$(grep -c "\-\-\-\-\-BEGIN CERTIFICATE\-\-\-\-\-" $TEMPDIR/intermediatecerts.pem) local addtl_warning + + # If $json_prefix is not empty, then there is more than one certificate + # and the output should should be indented by two more spaces. + [[ -n $json_prefix ]] && spaces=" " if [[ $OSSL_VER_MAJOR.$OSSL_VER_MINOR == "1.1.0" ]]; then - pr_litemagentaln "Your $OPENSSL is too new, needed is version 1.0.2" - out "$spaces" - fileout "$heading trust" "WARN" "Your $OPENSSL is too new, need version 1.0.2 to determine trust" - return 7 + addtl_warning="(Your openssl 1.1.0 might be too new for a reliable check)" + fileout "${json_prefix}trust" "WARN" "Your $OPENSSL is too new, need version 1.0.2 to determine trust" elif [[ $OSSL_VER_MAJOR.$OSSL_VER_MINOR != "1.0.2" ]]; then - pr_litemagentaln "Your $OPENSSL is too old, needed is version >=1.0.2" - out "$spaces" - addtl_warning="Your $OPENSSL is too old, need version 1.0.2 to determine trust. Results may be unreliable." - fileout "$heading trust_warn" "WARN" "$addtl_warning" + addtl_warning="(Your openssl <= 1.0.2 might be too unreliable to determine trust)" + fileout "${json_prefix}trust_warn" "WARN" "$addtl_warning" fi debugme outln for bundle_fname in $ca_bundles; do - certificate_file[i]=$(basename "$bundle_fname" | sed 's/\.pem//') + certificate_file[i]=$(basename ${bundle_fname//.pem}) if [[ ! -r $bundle_fname ]]; then pr_litemagentaln "\"$bundle_fname\" cannot be found / not readable" return 7 @@ -2696,20 +2713,20 @@ determine_trust() { fi i=$((i + 1)) done - num_ca_bundles=$(($i - 1)) + num_ca_bundles=$((i - 1)) debugme out " " - # all stores ok if $all_ok; then - pr_litegreen "Ok " - fileout "$heading trust" "OK" "All certificate trust checks passed. $addtl_warning" - # at least one failed + # all stores ok + pr_litegreen "Ok "; pr_litemagenta "$addtl_warning" + fileout "${json_prefix}trust" "OK" "All certificate trust checks passed. $addtl_warning" else + # at least one failed pr_red "NOT ok" if ! $some_ok; then # all failed (we assume with the same issue), we're displaying the reason out " " verify_retcode_helper "${verify_retcode[2]}" - fileout "$heading trust" "NOT OK" "All certificate trust checks failed: $(verify_retcode_helper "${verify_retcode[2]}"). $addtl_warning" + fileout "${json_prefix}trust" "NOT OK" "All certificate trust checks failed: $(verify_retcode_helper "${verify_retcode[2]}"). $addtl_warning" else # is one ok and the others not ==> display the culprit store if $some_ok ; then @@ -2728,20 +2745,19 @@ determine_trust() { #pr_litered "$notok_was " #outln "$code" outln - #lf + green ones + # lf + green ones [[ "$DEBUG" -eq 0 ]] && out "$spaces" pr_litegreen "OK: $ok_was" fi - fileout "$heading trust" "NOT OK" "Some certificate trust checks failed : OK : $ok_was NOT ok: $notok_was $addtl_warning" + fileout "${json_prefix}trust" "NOT OK" "Some certificate trust checks failed : OK : $ok_was NOT ok: $notok_was $addtl_warning" fi + [[ -n "$addtl_warning" ]] && out "\n$spaces" && pr_litemagenta "$addtl_warning" fi outln return 0 } # not handled: Root CA supplied (contains anchor) -# attention: 1.0.1 fails on mozilla - tls_time() { local now difftime @@ -2774,7 +2790,6 @@ tls_time() { } # core function determining whether handshake succeded or not -# sclient_connect_successful() { [[ $1 -eq 0 ]] && return 0 [[ -n $(awk '/Master-Key: / { print $2 }' "$2") ]] && return 0 @@ -2800,7 +2815,7 @@ determine_tls_extensions() { # alpn: echo | openssl s_client -connect google.com:443 -tlsextdebug -alpn h2-14 -servername google.com <-- suport needs to be checked b4 -- see also: ssl/t1_trce.c $OPENSSL s_client $STARTTLS $BUGS $1 -showcerts -connect $NODEIP:$PORT $PROXY $SNI -$proto -tlsextdebug -nextprotoneg $alpn -status $ERRFILE >$TMPFILE sclient_connect_successful $? $TMPFILE && success=0 && break - done # this loop is needed for IIS/6 + done # this loop is needed for IIS6 and others which have a handshake size limitations if [[ $success -eq 7 ]]; then # "-status" above doesn't work for GOST only servers, so we do another test without it and see whether that works then: $OPENSSL s_client $STARTTLS $BUGS $1 -showcerts -connect $NODEIP:$PORT $PROXY $SNI -$proto -tlsextdebug >$ERRFILE >$TMPFILE @@ -2814,7 +2829,13 @@ determine_tls_extensions() { GOST_STATUS_PROBLEM=true fi fi - TLS_EXTENSIONS=$(awk -F'"' '/TLS server extension / { printf "\""$2"\" " }' $TMPFILE) + #TLS_EXTENSIONS=$(awk -F'"' '/TLS server extension / { printf "\""$2"\" " }' $TMPFILE) + # + # this is not beautiful (grep+sed) + # but maybe we should just get the ids and do a private matching, according to + # https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml <-- ALPN is missing + TLS_EXTENSIONS=$(grep -a 'TLS server extension ' $TMPFILE | sed -e 's/TLS server extension //g' -e 's/\" (id=/\/#/g' -e 's/,.*$/,/g' -e 's/),$/\"/g') + TLS_EXTENSIONS=$(echo $TLS_EXTENSIONS) # into one line # Place the server's certificate in $HOSTCERT and any intermediate # certificates that were provided in $TEMPDIR/intermediatecerts.pem @@ -2843,6 +2864,21 @@ determine_tls_extensions() { return $success } +# arg1: path to certificate +# returns CN +get_cn_from_cert() { + local subject + + # attention! openssl 1.0.2 doesn't properly handle online output from certifcates from trustwave.com/github.com + #FIXME: use -nameopt oid for robustness + + # for e.g. russian sites -esc_msb,utf8 works in an UTF8 terminal -- any way to check platform indepedent? + # see x509(1ssl): + subject="$($OPENSSL x509 -in $1 -noout -subject -nameopt multiline,-align,sname,-esc_msb,utf8,-space_eq 2>>$ERRFILE)" + echo "$(awk -F'=' '/CN=/ { print $2 }' <<< "$subject")" + return $? +} + certificate_info() { local proto @@ -2862,6 +2898,7 @@ certificate_info() { local cnfinding local cnok="OK" local expfinding expok="OK" + local json_prefix="" # string to place at begging of JSON IDs when there is more than one certificate local indent="" if [[ $number_of_certificates -gt 1 ]]; then @@ -2869,19 +2906,54 @@ certificate_info() { indent=" " out "$indent" pr_headlineln "Server Certificate #$certificate_number" + json_prefix="Server Certificate #$certificate_number " spaces=" " else spaces=" " fi - out "$indent" - pr_bold " Server key size " sig_algo=$($OPENSSL x509 -in $HOSTCERT -noout -text 2>>$ERRFILE | grep "Signature Algorithm" | sed 's/^.*Signature Algorithm: //' | sort -u ) key_algo=$($OPENSSL x509 -in $HOSTCERT -noout -text 2>>$ERRFILE | awk -F':' '/Public Key Algorithm:/ { print $2 }' | sort -u ) + out "$indent" ; pr_bold " Signature Algorithm " + case $sig_algo in + sha1WithRSAEncryption) + pr_brownln "SHA1 with RSA" + fileout "${json_prefix}algorithm" "WARN" "Signature Algorithm: SHA1 with RSA (warning)" + ;; + sha256WithRSAEncryption) + pr_litegreenln "SHA256 with RSA" + fileout "${json_prefix}algorithm" "OK" "Signature Algorithm: SHA256 with RSA (OK)" + ;; + sha384WithRSAEncryption) + pr_litegreenln "SHA384 with RSA" + fileout "${json_prefix}algorithm" "OK" "Signature Algorithm: SHA384 with RSA (OK)" + ;; + sha512WithRSAEncryption) + pr_litegreenln "SHA512 with RSA" + fileout "${json_prefix}algorithm" "OK" "Signature Algorithm: SHA512 with RSA (OK)" + ;; + ecdsa-with-SHA256) + pr_litegreenln "ECDSA with SHA256" + fileout "${json_prefix}algorithm" "OK" "Signature Algorithm: ECDSA with SHA256 (OK)" + ;; + md5*) + pr_redln "MD5" + fileout "${json_prefix}algorithm" "NOT OK" "Signature Algorithm: MD5 (NOT ok)" + ;; + *) + out "$sig_algo (" + pr_litemagenta "Unknown" + outln ")" + fileout "${json_prefix}algorithm" "INFO" "Signature Algorithm: $sign_algo" + ;; + esac + # old, but interesting: https://blog.hboeck.de/archives/754-Playing-with-the-EFF-SSL-Observatory.html + + out "$indent"; pr_bold " Server key size " if [[ -z "$keysize" ]]; then outln "(couldn't determine)" - fileout "$heading key_size" "WARN" "Server keys size cannot be determined" + fileout "${json_prefix}key_size" "WARN" "Server keys size cannot be determined" else # https://tools.ietf.org/html/rfc4492, http://www.keylength.com/en/compare/ # http://infoscience.epfl.ch/record/164526/files/NPDF-22.pdf @@ -2890,79 +2962,55 @@ certificate_info() { if [[ $sig_algo =~ ecdsa ]] || [[ $key_algo =~ ecPublicKey ]]; then if [[ "$keysize" -le 110 ]]; then # a guess pr_red "$keysize" - fileout "$heading key_size" "NOT OK" "Server keys $keysize EC bits (NOT ok)" + fileout "${json_prefix}key_size" "NOT OK" "Server keys $keysize EC bits (NOT ok)" elif [[ "$keysize" -le 123 ]]; then # a guess pr_litered "$keysize" - fileout "$heading key_size" "NOT OK" "Server keys $keysize EC bits (NOT ok)" + fileout "${json_prefix}key_size" "NOT OK" "Server keys $keysize EC bits (NOT ok)" elif [[ "$keysize" -le 163 ]]; then pr_brown "$keysize" - fileout "$heading key_size" "NOT OK" "Server keys $keysize EC bits (NOT ok)" + fileout "${json_prefix}key_size" "NOT OK" "Server keys $keysize EC bits (NOT ok)" elif [[ "$keysize" -le 224 ]]; then out "$keysize" - fileout "$heading key_size" "INFO" "Server keys $keysize EC bits" + fileout "${json_prefix}key_size" "INFO" "Server keys $keysize EC bits" elif [[ "$keysize" -le 533 ]]; then pr_litegreen "$keysize" - fileout "$heading key_size" "OK" "Server keys $keysize EC bits (OK)" + fileout "${json_prefix}key_size" "OK" "Server keys $keysize EC bits (OK)" else out "keysize: $keysize (not expected, FIXME)" - fileout "$heading key_size" "WARN" "Server keys $keysize bits (not expected)" + fileout "${json_prefix}key_size" "WARN" "Server keys $keysize bits (not expected)" fi - else + outln " bit" + elif [[ $sig_algo = *RSA* ]]; then if [[ "$keysize" -le 512 ]]; then pr_red "$keysize" - fileout "$heading key_size" "NOT OK" "Server keys $keysize bits (NOT ok)" + outln " bits" + fileout "${json_prefix}key_size" "NOT OK" "Server keys $keysize bits (NOT ok)" elif [[ "$keysize" -le 768 ]]; then pr_litered "$keysize" - fileout "$heading key_size" "NOT OK" "Server keys $keysize bits (NOT ok)" + outln " bits" + fileout "${json_prefix}key_size" "NOT OK" "Server keys $keysize bits (NOT ok)" elif [[ "$keysize" -le 1024 ]]; then pr_brown "$keysize" - fileout "$heading key_size" "NOT OK" "Server keys $keysize bits (NOT ok)" + outln " bits" + fileout "${json_prefix}key_size" "NOT OK" "Server keys $keysize bits (NOT ok)" elif [[ "$keysize" -le 2048 ]]; then - out "$keysize" - fileout "$heading key_size" "INFO" "Server keys $keysize bits" + outln "$keysize bits" + fileout "${json_prefix}key_size" "INFO" "Server keys $keysize bits" elif [[ "$keysize" -le 4096 ]]; then pr_litegreen "$keysize" - fileout "$heading key_size" "OK" "Server keys $keysize bits (OK)" + fileout "${json_prefix}key_size" "OK" "Server keys $keysize bits (OK)" + outln " bits" else - out "weird keysize: $keysize (compatibility problems)" - fileout "$heading key_size" "WARN" "Server keys $keysize bits (Odd)" + pr_magenta "weird keysize: $keysize bits"; outln " (could cause compatibility problems)" + fileout "${json_prefix}key_size" "WARN" "Server keys $keysize bits (Odd)" fi + else + out "$keysize bits (" + pr_litemagenta "can't tell whether $keysize bits is good or not" + outln ")" + fileout "${json_prefix}key_size" "WARN" "Server keys $keysize bits (unknown signature algorithm)" fi fi - outln " bit" - - out "$indent" ; pr_bold " Signature Algorithm " - case $sig_algo in - sha1WithRSAEncryption) - pr_brownln "SHA1 with RSA" - fileout "$heading algorithm" "WARN" "Signature Algorithm: SHA1 with RSA (warning)" - ;; - sha256WithRSAEncryption) - pr_litegreenln "SHA256 with RSA" - fileout "$heading algorithm" "OK" "Signature Algorithm: SHA256 with RSA (OK)" - ;; - sha384WithRSAEncryption) - pr_litegreenln "SHA384 with RSA" - fileout "$heading algorithm" "OK" "Signature Algorithm: SHA384 with RSA (OK)" - ;; - sha512WithRSAEncryption) - pr_litegreenln "SHA512 with RSA" - fileout "$heading algorithm" "OK" "Signature Algorithm: SHA512 with RSA (OK)" - ;; - ecdsa-with-SHA256) - pr_litegreenln "ECDSA with SHA256" - fileout "$heading algorithm" "OK" "Signature Algorithm: ECDSA with SHA256 (OK)" - ;; - md5*) - pr_redln "MD5" - fileout "$heading algorithm" "NOT OK" "Signature Algorithm: MD5 (NOT ok)" - ;; - *) - outln "$sig_algo" - fileout "$heading algorithm" "INFO" "Signature Algorithm: $sign_algo" - ;; - esac - # old, but interesting: https://blog.hboeck.de/archives/754-Playing-with-the-EFF-SSL-Observatory.html out "$indent"; pr_bold " Fingerprint / Serial " cert_fingerprint_sha1="$($OPENSSL x509 -noout -in $HOSTCERT -fingerprint -sha1 2>>$ERRFILE | sed 's/Fingerprint=//' | sed 's/://g')" @@ -2970,12 +3018,12 @@ certificate_info() { cert_fingerprint_sha2="$($OPENSSL x509 -noout -in $HOSTCERT -fingerprint -sha256 2>>$ERRFILE | sed 's/Fingerprint=//' | sed 's/://g' )" outln "$cert_fingerprint_sha1 / $cert_fingerprint_serial" outln "$spaces$cert_fingerprint_sha2" - fileout "$heading fingerprint" "INFO" "Fingerprints / Serial: $cert_fingerprint_sha1 / $cert_fingerprint_serial, $cert_fingerprint_sha2" + fileout "${json_prefix}fingerprint" "INFO" "Fingerprints / Serial: $cert_fingerprint_sha1 / $cert_fingerprint_serial, $cert_fingerprint_sha2" out "$indent"; pr_bold " Common Name (CN) " cnfinding="Common Name (CN) : " - if $OPENSSL x509 -in $HOSTCERT -noout -subject 2>>$ERRFILE | grep -wq CN; then - cn=$($OPENSSL x509 -in $HOSTCERT -noout -subject 2>>$ERRFILE | sed 's/subject= //' | sed -e 's/^.*CN=//' -e 's/\/emailAdd.*//') + cn="$(get_cn_from_cert $HOSTCERT)" + if [[ -n "$cn" ]]; then pr_dquoted "$cn" cnfinding="$cn" if echo -n "$cn" | grep -q '^*.' ; then @@ -2992,26 +3040,25 @@ certificate_info() { fi fi else - cn="(no CN field in subject)" - out "$cn" + cn="no CN field in subject" + pr_litemagenta "($cn)" cnfinding="$cn" cnok="INFO" fi - $OPENSSL s_client $STARTTLS $BUGS -cipher $cipher -connect $NODEIP:$PORT $PROXY $OPTIMAL_PROTO 2>>$ERRFILE $HOSTCERT.nosni - cn_nosni="" - if [[ -s $HOSTCERT.nosni ]]; then - if $OPENSSL x509 -in $HOSTCERT.nosni -noout -subject 2>>$ERRFILE | grep -wq CN; then - cn_nosni=$($OPENSSL x509 -in $HOSTCERT.nosni -noout -subject 2>>$ERRFILE | sed 's/subject= //' | sed -e 's/^.*CN=//' -e 's/\/emailAdd.*//') - else - cn_nosni="no CN field in subject" - fi - fi -#FIXME: check for SSLv3/v2 and look wheher it goes to a different CN + # no cipher suites specified here. We just want the default vhost subject + $OPENSSL s_client $STARTTLS $BUGS -connect $NODEIP:$PORT $PROXY $OPTIMAL_PROTO 2>>$ERRFILE $HOSTCERT.nosni + cn_nosni="$(get_cn_from_cert "$HOSTCERT.nosni")" + [[ -z "$cn_nosni" ]] && cn_nosni="no CN field in subject" + +#FIXME: check for SSLv3/v2 and look whether it goes to a different CN (probably not polite) debugme out "\"$NODE\" | \"$cn\" | \"$cn_nosni\"" - if [[ $NODE == "$cn_nosni" ]]; then - if [[ $SERVICE == "HTTP" ]] || $CLIENT_AUTH; then + if [[ "$cn_nosni" == "$cn" ]]; then + outln " (works w/o SNI)" + cnfinding+=" (works w/o SNI)" + elif [[ $NODE == "$cn_nosni" ]]; then + if [[ $SERVICE == "HTTP" ]] || $CLIENT_AUTH ; then outln " (works w/o SNI)" cnfinding+=" (works w/o SNI)" else @@ -3034,7 +3081,7 @@ certificate_info() { fi outln ")" cnfinding+=")" - elif [[ "$cn_nosni" == "*no CN field*" ]]; then + elif [[ "$cn_nosni" == *"no CN field"* ]]; then outln ", (request w/o SNI: $cn_nosni)" cnfinding+=", (request w/o SNI: $cn_nosni)" else @@ -3042,7 +3089,7 @@ certificate_info() { cnfinding+=" (CN in response to request w/o SNI: \"$cn_nosni\")" fi fi - fileout "$heading cn" "$cnok" "$cnfinding" + fileout "${json_prefix}cn" "$cnok" "$cnfinding" sans=$($OPENSSL x509 -in $HOSTCERT -noout -text 2>>$ERRFILE | grep -A3 "Subject Alternative Name" | grep "DNS:" | \ sed -e 's/DNS://g' -e 's/ //g' -e 's/,/ /g' -e 's/othername://g') @@ -3053,33 +3100,32 @@ certificate_info() { pr_dquoted "$san" out " " done - fileout "$heading san" "INFO" "subjectAltName (SAN) : $sans" + fileout "${json_prefix}san" "INFO" "subjectAltName (SAN) : $sans" else out "-- " - fileout "$heading san" "INFO" "subjectAltName (SAN) : --" + fileout "${json_prefix}san" "INFO" "subjectAltName (SAN) : --" fi outln out "$indent"; pr_bold " Issuer " - issuer=$($OPENSSL x509 -in $HOSTCERT -noout -issuer 2>>$ERRFILE| sed -e 's/^.*CN=//g' -e 's/\/.*$//g') - issuer_O=$($OPENSSL x509 -in $HOSTCERT -noout -issuer 2>>$ERRFILE | sed 's/^.*O=//g' | sed 's/\/.*$//g') - if $OPENSSL x509 -in $HOSTCERT -noout -issuer 2>>$ERRFILE | grep -q 'C=' ; then - issuer_C=$($OPENSSL x509 -in $HOSTCERT -noout -issuer 2>>$ERRFILE | sed 's/^.*C=//g' | sed 's/\/.*$//g') + #FIXME: oid would be better maybe (see above) + issuer="$($OPENSSL x509 -in $HOSTCERT -noout -issuer -nameopt multiline,-align,sname,-esc_msb,utf8,-space_eq 2>>$ERRFILE)" + issuer_CN="$(awk -F'=' '/CN=/ { print $2 }' <<< "$issuer")" + issuer_O="$(awk -F'=' '/O=/ { print $2 }' <<< "$issuer")" + issuer_C="$(awk -F'=' '/C=/ { print $2 }' <<< "$issuer")" + + if [[ "$issuer_O" == "issuer=" ]] || [[ "$issuer_O" == "issuer= " ]] || [[ "$issuer_CN" == "$CN" ]]; then + pr_redln "self-signed (NOT ok)" + fileout "${json_prefix}issuer" "NOT OK" "Issuer: selfsigned (NOT ok)" else - issuer_C="" # CACert would have 'issuer= ' here otherwise - fi - if [[ "$issuer_O" == "issuer=" ]] || [[ "$issuer_O" == "issuer= " ]] || [[ "$issuer" == "$CN" ]]; then - pr_redln "selfsigned (NOT ok)" - fileout "$heading issuer" "NOT OK" "Issuer: selfsigned (NOT ok)" - else - pr_dquoted "$issuer" + pr_dquoted "$issuer_CN" out " (" pr_dquoted "$issuer_O" if [[ -n "$issuer_C" ]]; then out " from " pr_dquoted "$issuer_C" - fileout "$heading issuer" "INFO" "Issuer: \"$issuer\" ( \"$issuer_O\" from \"$issuer_C\")" + fileout "${json_prefix}issuer" "INFO" "Issuer: \"$issuer\" ( \"$issuer_O\" from \"$issuer_C\")" else - fileout "$heading issuer" "INFO" "Issuer: \"$issuer\" ( \"$issuer_O\" )" + fileout "${json_prefix}issuer" "INFO" "Issuer: \"$issuer\" ( \"$issuer_O\" )" fi outln ")" fi @@ -3096,10 +3142,10 @@ certificate_info() { [[ 1.3.6.1.4.1.17326.10.8.12.1.2 == "$policy_oid" ]] || \ [[ 1.3.6.1.4.1.13177.10.1.3.10 == "$policy_oid" ]] ; then out "yes " - fileout "$heading ev" "OK" "Extended Validation (EV) (experimental) : yes" + fileout "${json_prefix}ev" "OK" "Extended Validation (EV) (experimental) : yes" else out "no " - fileout "$heading ev" "INFO" "Extended Validation (EV) (experimental) : no" + fileout "${json_prefix}ev" "INFO" "Extended Validation (EV) (experimental) : no" fi debugme echo "($(newline_to_spaces "$policy_oid"))" outln @@ -3121,7 +3167,7 @@ certificate_info() { fi days2expire=$((days2expire / 3600 / 24 )) - expire=$($OPENSSL x509 -in $HOSTCERT -checkend 0 2>>$ERRFILE) + expire=$($OPENSSL x509 -in $HOSTCERT -checkend 1 2>>$ERRFILE) if ! echo $expire | grep -qw not; then pr_red "expired!" expfinding="expired!" @@ -3147,72 +3193,75 @@ certificate_info() { fi fi outln " ($startdate --> $enddate)" - fileout "$heading expiration" "$expok" "Certificate Expiration : $expfinding ($startdate --> $enddate)" + fileout "${json_prefix}expiration" "$expok" "Certificate Expiration : $expfinding ($startdate --> $enddate)" certificates_provided=1+$(grep -c "\-\-\-\-\-BEGIN CERTIFICATE\-\-\-\-\-" $TEMPDIR/intermediatecerts.pem) out "$indent"; pr_bold " # of certificates provided"; outln " $certificates_provided" - fileout "$heading certcount" "INFO" "# of certificates provided : $certificates_provided" + fileout "${json_prefix}certcount" "INFO" "# of certificates provided : $certificates_provided" out "$indent"; pr_bold " Chain of trust"; out " (experim.) " - determine_trust "$heading" #Also handles fileout + determine_trust "$json_prefix" # Also handles fileout out "$indent"; pr_bold " Certificate Revocation List " crl="$($OPENSSL x509 -in $HOSTCERT -noout -text 2>>$ERRFILE | grep -A 4 "CRL Distribution" | grep URI | sed 's/^.*URI://')" if [[ -z "$crl" ]]; then pr_literedln "--" - fileout "$heading crl" "NOT OK" "No CRL provided (NOT ok)" + fileout "${json_prefix}crl" "NOT OK" "No CRL provided (NOT ok)" elif grep -q http <<< "$crl"; then if [[ $(count_lines "$crl") -eq 1 ]]; then outln "$crl" - fileout "$heading crl" "INFO" "Certificate Revocation List : $crl" + fileout "${json_prefix}crl" "INFO" "Certificate Revocation List : $crl" else # more than one CRL out_row_aligned "$crl" "$spaces" - fileout "$heading crl" "INFO" "Certificate Revocation List : $crl" + fileout "${json_prefix}crl" "INFO" "Certificate Revocation List : $crl" fi else pr_litemagentaln "no parsable output \"$crl\", pls report" - fileout "$heading crl" "WARN" "Certificate Revocation List : no parsable output \"$crl\", pls report" + fileout "${json_prefix}crl" "WARN" "Certificate Revocation List : no parsable output \"$crl\", pls report" fi out "$indent"; pr_bold " OCSP URI " ocsp_uri=$($OPENSSL x509 -in $HOSTCERT -noout -ocsp_uri 2>>$ERRFILE) if [[ -z "$ocsp_uri" ]]; then pr_literedln "--" - fileout "$heading ocsp_uri" "NOT OK" "OCSP URI : -- (NOT ok)" + fileout "${json_prefix}ocsp_uri" "NOT OK" "OCSP URI : -- (NOT ok)" else outln "$ocsp_uri" - fileout "$heading ocsp_uri" "INFO" "OCSP URI : $ocsp_uri" + fileout "${json_prefix}ocsp_uri" "INFO" "OCSP URI : $ocsp_uri" fi - out "$indent"; pr_bold " OCSP stapling " + out "$indent"; pr_bold " OCSP stapling " if grep -a "OCSP response" <<<"$ocsp_response" | grep -q "no response sent" ; then - outln " not offered" - fileout "$heading ocsp_stapling" "INFO" "OCSP stapling : not offered" + pr_yellow "--" + fileout "${json_prefix}ocsp_stapling" "INFO" "OCSP stapling : not offered" else if grep -a "OCSP Response Status" <<<"$ocsp_response_status" | grep -q successful; then - pr_litegreenln " offered" - fileout "$heading ocsp_stapling" "OK" "OCSP stapling : offered" + pr_litegreen "offered" + fileout "${json_prefix}ocsp_stapling" "OK" "OCSP stapling : offered" else if $GOST_STATUS_PROBLEM; then - outln " (GOST servers make problems here, sorry)" - fileout "$heading ocsp_stapling" "OK" "OCSP stapling : (GOST servers make problems here, sorry)" + outln "(GOST servers make problems here, sorry)" + fileout "${json_prefix}ocsp_stapling" "OK" "OCSP stapling : (GOST servers make problems here, sorry)" ret=0 else - outln " not sure what's going on here, debug:" - grep -aA 20 "OCSP response" <<<"$ocsp_response" - fileout "$heading ocsp_stapling" "OK" "OCSP stapling : not sure what's going on here, debug: grep -aA 20 "OCSP response" <<<"$ocsp_response"" + out "(response status unknown)" + fileout "${json_prefix}ocsp_stapling" "OK" "OCSP stapling : not sure what's going on here, debug: grep -aA 20 "OCSP response" <<<"$ocsp_response"" + debugme grep -a -A20 -B2 "OCSP response" <<<"$ocsp_response" ret=2 fi fi fi - outln + outln "\n" return $ret } # FIXME: revoked, see checkcert.sh # FIXME: Trust (only CN) + + + run_server_defaults() { local ciph match_found newhostcert local sessticket_str="" @@ -3304,7 +3353,7 @@ run_server_defaults() { pr_headlineln " Testing server defaults (Server Hello) " outln - pr_bold " TLS server extensions (std) " + pr_bold " TLS extensions (standard) " if [[ -z "$all_tls_extensions" ]]; then outln "(none)" fileout "tls_extensions" "INFO" "TLS server extensions (std): (none)" @@ -3369,7 +3418,7 @@ run_pfs() { nr_supported_ciphers=$(count_ciphers $(actually_supported_ciphers $pfs_cipher_list)) if [[ "$nr_supported_ciphers" -le "$CLIENT_MIN_PFS" ]]; then outln - local_problem "You only have $nr_supported_ciphers PFS ciphers on the client side " + local_problem_ln "You only have $nr_supported_ciphers PFS ciphers on the client side " fileout "pfs" "WARN" "(Perfect) Forward Secrecy tests: Skipped. You only have $nr_supported_ciphers PFS ciphers on the client site. ($CLIENT_MIN_PFS are required)" return 1 fi @@ -3482,7 +3531,7 @@ http2_pre(){ return 1 fi if ! $HAS_ALPN; then - local_problem "$OPENSSL doesn't support HTTP2/ALPN"; + local_problem_ln "$OPENSSL doesn't support HTTP2/ALPN"; fileout "https_alpn" "WARN" "HTTP2/ALPN : HTTP/2 was not tested as $OPENSSL does not support it" return 7 fi @@ -4424,10 +4473,6 @@ run_ccs_injection(){ return $ret } -local_problem() { - pr_litemagentaln "Local problem: $1" -} - run_renego() { # no SNI here. Not needed as there won't be two different SSL stacks for one IP local legacycmd="" @@ -4469,7 +4514,7 @@ run_renego() { 0.9.8*) # we need this for Mac OSX unfortunately case "$OSSL_VER_APPENDIX" in [a-l]) - local_problem "$OPENSSL cannot test this secure renegotiation vulnerability" + local_problem_ln "$OPENSSL cannot test this secure renegotiation vulnerability" fileout "sec_client_renego" "WARN" "Secure Client-Initiated Renegotiation : $OPENSSL cannot test this secure renegotiation vulnerability" return 3 ;; @@ -4540,7 +4585,7 @@ run_crime() { # first we need to test whether OpenSSL binary has zlib support $OPENSSL zlib -e -a -in /dev/stdin &>/dev/stdout &1 | grep -qw nextprotoneg +# $OPENSSL s_client -help 2>&1 | grep -qw nextprotoneg # if [[ $? -eq 0 ]]; then # $OPENSSL s_client -host $NODE -port $PORT -nextprotoneg $NPN_PROTOs $SNI /dev/null >$TMPFILE # if [[ $? -eq 0 ]]; then @@ -4618,7 +4663,7 @@ run_breach() { local url local spaces=" " local disclaimer="" - local when_makesense="Can be ignored for static pages or if no secrets in the page" + local when_makesense=" Can be ignored for static pages or if no secrets in the page" [[ $SERVICE != "HTTP" ]] && return 7 @@ -4716,8 +4761,8 @@ run_tls_fallback_scsv() { # the countermeasure to protect against protocol downgrade attacks. # First check we have support for TLS_FALLBACK_SCSV in our local OpenSSL - if ! $OPENSSL s_client -h 2>&1 | grep -q "\-fallback_scsv"; then - local_problem "$OPENSSL lacks TLS_FALLBACK_SCSV support" + if ! $OPENSSL s_client -help 2>&1 | grep -q "\-fallback_scsv"; then + local_problem_ln "$OPENSSL lacks TLS_FALLBACK_SCSV support" return 4 fi #TODO: this need some tuning: a) if one protocol is supported only it has practcally no value (theoretical it's interesting though) @@ -4784,7 +4829,7 @@ run_freak() { case $nr_supported_ciphers in 0) - local_problem "$OPENSSL doesn't have any EXPORT RSA ciphers configured" + local_problem_ln "$OPENSSL doesn't have any EXPORT RSA ciphers configured" fileout "freak" "WARN" "FREAK (CVE-2015-0204) : Not tested. $OPENSSL doesn't have any EXPORT RSA ciphers configured" return 7 ;; @@ -4830,7 +4875,7 @@ run_logjam() { case $nr_supported_ciphers in 0) - local_problem "$OPENSSL doesn't have any DHE EXPORT ciphers configured" + local_problem_ln "$OPENSSL doesn't have any DHE EXPORT ciphers configured" fileout "logjam" "WARN" "LOGJAM (CVE-2015-4000) : Not tested. $OPENSSL doesn't have any DHE EXPORT ciphers configured" return 3 ;; @@ -4891,12 +4936,11 @@ run_beast(){ outln fi pr_bold " BEAST"; out " (CVE-2011-3389) " - "$WIDE" && outln # output in wide mode if cipher doesn't exist is not ok >$ERRFILE - # first determine whether it's mitogated by higher protocols + # first determine whether it's mitigated by higher protocols for proto in tls1_1 tls1_2; do $OPENSSL s_client -state -"$proto" $STARTTLS $BUGS -connect $NODEIP:$PORT $PROXY $SNI 2>>$ERRFILE >$TMPFILE $TMPFILE 2>>$ERRFILE $TMPFILE 2>>$ERRFILE >$ERRFILE) # -V doesn't work with openssl < 1.0 @@ -4955,25 +5001,27 @@ run_beast(){ fi done - if [[ -n "$detected_cbc_ciphers" ]]; then - fileout "cbc_$proto" "NOT OK" "BEAST (CVE-2011-3389) : CBC ciphers for $(toupper $proto): $detected_cbc_ciphers" - if ! "$WIDE"; then + if ! "$WIDE"; then + if [[ -n "$detected_cbc_ciphers" ]]; then detected_cbc_ciphers=$(echo "$detected_cbc_ciphers" | sed -e "s/ /\\${cr} ${spaces}/9" -e "s/ /\\${cr} ${spaces}/6" -e "s/ /\\${cr} ${spaces}/3") + fileout "cbc_$proto" "NOT OK" "BEAST (CVE-2011-3389) : CBC ciphers for $(toupper $proto): $detected_cbc_ciphers" ! "$first" && out "$spaces" out "$(toupper $proto):" [[ -n "$higher_proto_supported" ]] && \ pr_yellowln "$detected_cbc_ciphers" || \ pr_brownln "$detected_cbc_ciphers" - detected_cbc_ciphers="" # empty for next round + detected_cbc_ciphers="" # empty for next round + first=false + else + [[ $proto == "tls1" ]] && ! $first && echo -n "$spaces " + pr_litegreenln "no CBC ciphers for $(toupper $proto) (OK)" first=false fi else - fileout "cbc_$proto" "OK" "BEAST (CVE-2011-3389) : No CBC ciphers for $(toupper $proto) (OK)" - if ! "$WIDE"; then - [[ $proto == "tls1" ]] && ! $first && echo -n "$spaces " - first=false + if ! "$vuln_beast" ; then + pr_litegreenln " no CBC ciphers for $(toupper $proto) (OK)" + fileout "cbc_$proto" "OK" "BEAST (CVE-2011-3389) : No CBC ciphers for $(toupper $proto) (OK)" fi - pr_litegreenln "no CBC ciphers for $(toupper $proto) (OK)" fi done # for proto in ssl3 tls1 @@ -4981,11 +5029,11 @@ run_beast(){ if [[ -n "$higher_proto_supported" ]]; then if "$WIDE"; then outln - # BOT ok seems too harsh for me if we have TLS >1.0 + # NOT ok seems too harsh for me if we have TLS >1.0 pr_yellow "VULNERABLE" outln " -- but also supports higher protocols (possible mitigation):$higher_proto_supported" else - out "${spaces}" + out "$spaces" pr_yellow "VULNERABLE" outln " -- but also supports higher protocols (possible mitigation):$higher_proto_supported" fi @@ -4994,14 +5042,14 @@ run_beast(){ if "$WIDE"; then outln else - out "${spaces}" + out "$spaces" fi pr_brown "VULNERABLE (NOT ok)" outln " -- and no higher protocols as mitigation supported" fileout "beast" "NOT OK" "BEAST (CVE-2011-3389) : VULNERABLE -- and no higher protocols as mitigation supported" fi fi - $first && pr_litegreenln "no CBC ciphers found for any protocol (OK)" + "$first" && ! "$vuln_beast" && pr_litegreenln "no CBC ciphers found for any protocol (OK)" tmpfile_handle $FUNCNAME.txt return 0 @@ -5214,10 +5262,10 @@ find_openssl_binary() { $OPENSSL s_client -ssl3 2>&1 | grep -aq "unknown option" || \ HAS_SSL3=true && \ HAS_SSL3=false - $OPENSSL s_client help 2>&1 | grep -qw '\-alpn' && \ + $OPENSSL s_client -help 2>&1 | grep -qw '\-alpn' && \ HAS_ALPN=true || \ HAS_ALPN=false - $OPENSSL s_client help 2>&1 | grep -qw '\-nextprotoneg' && \ + $OPENSSL s_client -help 2>&1 | grep -qw '\-nextprotoneg' && \ HAS_SPDY=true || \ HAS_SPDY=false @@ -5245,10 +5293,6 @@ openssl_age() { esac ignore_no_or_lame " Type \"yes\" to accept some false negatives or positives " fi - if [[ $OSSL_VER_MAJOR.$OSSL_VER_MINOR == "1.1.0" ]]; then - pr_magentaln "$PROG_NAME doesn't work yet with OpenSSL 1.1.0!" - ignore_no_or_lame "Type \"yes\" to accept weird output, false negatives and positives " - fi outln } @@ -5852,7 +5896,7 @@ get_mx_record() { # check_proxy() { if [[ -n "$PROXY" ]]; then - if ! $OPENSSL s_client help 2>&1 | grep -qw proxy; then + if ! $OPENSSL s_client -help 2>&1 | grep -qw proxy; then fatal "Your $OPENSSL is too old to support the \"--proxy\" option" -1 fi PROXYNODE=${PROXY%:*} @@ -6716,4 +6760,4 @@ fi exit $? -# $Id: testssl.sh,v 1.456 2016/02/01 16:33:58 dirkw Exp $ +# $Id: testssl.sh,v 1.464 2016/02/07 18:13:58 dirkw Exp $
Cipher Suite Name (OpenSSL) KeyExch. Encryption Bits Cipher Suite Name (RFC)
[0x00] NULL-MD5 RSA(512) None None, export TLS_NULL_WITH_NULL_NULL
[0x01] NULL-MD5 RSA None None TLS_RSA_WITH_NULL_MD5
[0x02] NULL-SHA RSA None None TLS_RSA_WITH_NULL_SHA
[0x19] EXP-ADH-DES-CBC-SHA DH(512) DES 40, export TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA
[0x1a] ADH-DES-CBC-SHA DH DES 56 TLS_DH_anon_WITH_DES_CBC_SHA
[0x1b] ADH-DES-CBC3-SHA DH 3DES 168 TLS_DH_anon_WITH_3DES_EDE_CBC_SHA
[0x1c] FORTEZZA None None SSL_FORTEZZA_KEA_WITH_NULL_SHA
[0x1d] FORTEZZA FORTEZZA_CBC 80 SSL_FORTEZZA_KEA_WITH_FORTEZZA_CBC_SHA
[0x1e] FORTEZZA FORTEZZA_RC4 128 SSL_FORTEZZA_KEA_WITH_RC4_128_SHA
[0x1e] KRB5-DES-CBC-SHA KRB5 DES 56 TLS_KRB5_WITH_DES_CBC_SHA
[0x1f] KRB5-DES-CBC3-SHA KRB5 3DES 168 TLS_KRB5_WITH_3DES_EDE_CBC_SHA
[0x20] KRB5-RC4-SHA KRB5 RC4 128 TLS_KRB5_WITH_RC4_128_SHA
[0x29] EXP-KRB5-DES-CBC-MD5 KRB5 DES 40, export TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5
[0x2a] EXP-KRB5-RC2-CBC-MD5 KRB5 RC2 40, export TLS_KRB5_EXPORT_WITH_RC2_CBC_40_MD5
[0x2b] EXP-KRB5-RC4-MD5 KRB5 RC4 40, export TLS_KRB5_EXPORT_WITH_RC4_40_MD5
[0x2c] EXP-KRB5-RC4-MD5 PSK None None TLS_PSK_WITH_NULL_SHA
[0x2d] EXP-KRB5-RC4-MD5 DH/PSK None None TLS_DHE_PSK_WITH_NULL_SHA
[0x2e] EXP-KRB5-RC4-MD5 RSA/PSK None None TLS_RSA_PSK_WITH_NULL_SHA
[0x2f] AES128-SHA RSA AES 128 TLS_RSA_WITH_AES_128_CBC_SHA
[0x30] DH-DSS-AES128-SHA DH/DSS AES 128 TLS_DH_DSS_WITH_AES_128_CBC_SHA
[0x31] DH-RSA-AES128-SHA DH/RSA AES 128 TLS_DH_RSA_WITH_AES_128_CBC_SHA
[0x3e] DH-DSS-AES128-SHA256 DH/DSS AES 128 TLS_DH_DSS_WITH_AES_128_CBC_SHA256
[0x3f] DH-RSA-AES128-SHA256 DH/RSA AES 128 TLS_DH_RSA_WITH_AES_128_CBC_SHA256
[0x40] DHE-DSS-AES128-SHA256 DH AES 128 TLS_DHE_DSS_WITH_AES_128_CBC_SHA256
[0x41] CAMELLIA128-SHA RSA Camellia 128 TLS_RSA_WITH_CAMELLIA_128_CBC_SHA
[0x42] DH-DSS-CAMELLIA128-SHA DH/DSS Camellia 128 TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA
[0x43] DH-RSA-CAMELLIA128-SHA DH/RSA Camellia 128 TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA
[0x45] DHE-RSA-CAMELLIA128-SHA DH Camellia 128 TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA
[0x46] ADH-CAMELLIA128-SHA DH Camellia 128 TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA
[0x60] EXP1024-RC4-MD5 RSA(1024) RC4 56, export TLS_RSA_EXPORT1024_WITH_RC4_56_MD5
[0x61] EXP1024-RC2-CBC-MD5 RSA(1024) RC2 56, export TLS_RSA_EXPORT1024_WITH_RC2_CBC_56_MD5
[0x62] EXP1024-DES-CBC-SHA RSA(1024) DES 56, export TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA
[0x63] EXP1024-DHE-DSS-DES-CBC-SHA DH(1024) DES 56, export TLS_DHE_DSS_EXPORT1024_WITH_DES_CBC_SHA
[0x64] EXP1024-RC4-SHA RSA(1024) RC4 56, export TLS_RSA_EXPORT1024_WITH_RC4_56_SHA
[0x6b] DHE-RSA-AES256-SHA256 DH AES 256 TLS_DHE_RSA_WITH_AES_256_CBC_SHA256
[0x6c] ADH-AES128-SHA256 DH AES 128 TLS_DH_anon_WITH_AES_128_CBC_SHA256
[0x6d] ADH-AES256-SHA256 DH AES 256 TLS_DH_anon_WITH_AES_256_CBC_SHA256
[0x80] GOST94-GOST89-GOST89 GOST GOST89 256 TLS_GOSTR341094_WITH_28147_CNT_IMIT
[0x81] GOST2001-GOST89-GOST89 GOST GOST89 256 TLS_GOSTR341001_WITH_28147_CNT_IMIT
[0x82] GOST94-NULL-GOST94 GOST eNULL None TLS_GOSTR341001_WITH_NULL_GOSTR3411
[0x83] GOST2001-GOST89-GOST89 GOST eNULL None TLS_GOSTR341094_WITH_NULL_GOSTR3411
[0x80] GOST94-GOST89-GOST89 VKO GOST 34.10-94 GOST89 256 TLS_GOSTR341094_WITH_28147_CNT_IMIT
[0x81] GOST2001-GOST89-GOST89 VKO GOST 34.10-2001 GOST89 256 TLS_GOSTR341001_WITH_28147_CNT_IMIT
[0x82] GOST94-NULL-GOST94 VKO GOST 34.10-94 eNULL None TLS_GOSTR341001_WITH_NULL_GOSTR3411
[0x83] GOST2001-GOST89-GOST89 VKO GOST 34.10-2001 eNULL None TLS_GOSTR341094_WITH_NULL_GOSTR3411
[0x84] CAMELLIA256-SHA RSA Camellia 256 TLS_RSA_WITH_CAMELLIA_256_CBC_SHA
[0x85] DH-DSS-CAMELLIA256-SHA DH/DSS Camellia 256 TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA
[0x86] DH-RSA-CAMELLIA256-SHA DH/RSA Camellia 256 TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA
[0x87] DHE-DSS-CAMELLIA256-SHA DH Camellia 256 TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA
[0x88] DHE-RSA-CAMELLIA256-SHA DH Camellia 256 TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA
[0x89] ADH-CAMELLIA256-SHA DH Camellia 256 TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA
[0x8a] PSK-RC4-SHA PSK RC4 128 TLS_PSK_WITH_RC4_128_SHA
[0x8b] PSK-3DES-EDE-CBC-SHA PSK 3DES 168 TLS_PSK_WITH_3DES_EDE_CBC_SHA
[0x8c] PSK-AES128-CBC-SHA PSK AES 128 TLS_PSK_WITH_AES_128_CBC_SHA
[0x8d] PSK-AES256-CBC-SHA PSK AES 256 TLS_PSK_WITH_AES_256_CBC_SHA
[0x8e] PSK/DHE RC4 128 TLS_DHE_PSK_WITH_RC4_128_SHA
[0x8f] PSK/DHE 3DES 168 TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA
[0x90] PSK/DHE AES 128 TLS_DHE_PSK_WITH_AES_128_CBC_SHA
[0x94] PSK/RSA AES 128 TLS_RSA_PSK_WITH_AES_128_CBC_SHA
[0x95] PSK/RSA AES 256 TLS_RSA_PSK_WITH_AES_256_CBC_SHA
[0x96] SEED-SHA RSA SEED 128 TLS_RSA_WITH_SEED_CBC_SHA
[0x97] DH-DSS-SEED-SHA DH/DSS SEED 128 TLS_DH_DSS_WITH_SEED_CBC_SHA
[0x98] DH-RSA-SEED-SHA DH/RSA SEED 128 TLS_DH_RSA_WITH_SEED_CBC_SHA
[0x99] DHE-DSS-SEED-SHA DH SEED 128 TLS_DHE_DSS_WITH_SEED_CBC_SHA
[0x9a] DHE-RSA-SEED-SHA DH SEED 128 TLS_DHE_RSA_WITH_SEED_CBC_SHA
[0x9b] ADH-SEED-SHA DH SEED 128 TLS_DH_anon_WITH_SEED_CBC_SHA
[0x9c] AES128-GCM-SHA256 RSA AESGCM 128 TLS_RSA_WITH_AES_128_GCM_SHA256
[0x9d] AES256-GCM-SHA384 RSA AESGCM 256 TLS_RSA_WITH_AES_256_GCM_SHA384
[0x9e] DHE-RSA-AES128-GCM-SHA256 DH AESGCM 128 TLS_DHE_RSA_WITH_AES_128_GCM_SHA256
[0xa6] ADH-AES128-GCM-SHA256 DH AESGCM 128 TLS_DH_anon_WITH_AES_128_GCM_SHA256
[0xa7] ADH-AES256-GCM-SHA384 DH AESGCM 256 TLS_DH_anon_WITH_AES_256_GCM_SHA384
[0x5600] TLS_FALLBACK_SCSV TLS_FALLBACK_SCSV
[0xba] CAMELLIA128-SHA256 RSA Camellia 128 TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256
[0xbb] DH-DSS-CAMELLIA128-SHA256 DH/DSS Camellia 128 TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256
[0xbc] DH-RSA-CAMELLIA128-SHA256 DH/RSA Camellia 128 TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256
[0xbd] DHE-DSS-CAMELLIA128-SHA256 DH Camellia 128 TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256
[0xbe] DHE-RSA-CAMELLIA128-SHA256 DH Camellia 128 TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256
[0xbf] ADH-CAMELLIA128-SHA256 DH Camellia 128 TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256
[0x5600] TLS_FALLBACK_SCSV TLS_EMPTY_RENEGOTIATION_INFO_SCSV
[0xc001] ECDH-ECDSA-NULL-SHA ECDH/ECDSA None None TLS_ECDH_ECDSA_WITH_NULL_SHA
[0xc002] ECDH-ECDSA-RC4-SHA ECDH/ECDSA RC4 128 TLS_ECDH_ECDSA_WITH_RC4_128_SHA
[0xc003] ECDH-ECDSA-DES-CBC3-SHA ECDH/ECDSA 3DES 168 TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA
[0xc017] AECDH-DES-CBC3-SHA ECDH 3DES 168 TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA
[0xc018] AECDH-AES128-SHA ECDH AES 128 TLS_ECDH_anon_WITH_AES_128_CBC_SHA
[0xc019] AECDH-AES256-SHA ECDH AES 256 TLS_ECDH_anon_WITH_AES_256_CBC_SHA
[0xc01a] SRP-3DES-EDE-CBC-SHA SRP 3DES 168 TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA
[0xc01b] SRP-RSA-3DES-EDE-CBC-SHA SRP 3DES 168 TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA
[0xc01c] SRP-DSS-3DES-EDE-CBC-SHA SRP 3DES 168 TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA
[0xc020] SRP-AES-256-CBC-SHA SRP AES 256 TLS_SRP_SHA_WITH_AES_256_CBC_SHA
[0xc021] SRP-RSA-AES-256-CBC-SHA SRP AES 256 TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA
[0xc022] SRP-DSS-AES-256-CBC-SHA SRP AES 256 TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA
[0xc023] ECDHE-ECDSA-AES128-SHA256 ECDH AES 128 TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256
[0xc024] ECDHE-ECDSA-AES256-SHA384 ECDH AES 256 TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384
[0xc025] ECDH-ECDSA-AES128-SHA256 ECDH/ECDSA AES 128 TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256
[0xc031] ECDH-RSA-AES128-GCM-SHA256 ECDH/RSA AESGCM 128 TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256
[0xc032] ECDH-RSA-AES256-GCM-SHA384 ECDH/RSA AESGCM 256 TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384
[0xc033] ECDHE-PSK-RC4-SHA PSK/ECDHE RC4 128 TLS_ECDHE_PSK_WITH_RC4_128_SHA
[0xc034] ECDHE-PSK-3DES-EDE-CBC-SHA PSK/ECDHE 3DES 168 TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA
[0xc035] ECDHE-PSK-AES128-CBC-SHA PSK/ECDHE AES 128 TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA
[0xc039] ECDHE-PSK-NULL-SHA PSK/ECDHE None None TLS_ECDHE_PSK_WITH_NULL_SHA
[0xc03A] ECDHE-PSK-NULL-SHA256 PSK/ECDHE None None TLS_ECDHE_PSK_WITH_NULL_SHA256
[0xc03B] ECDHE-PSK-NULL-SHA384 PSK/ECDHE None None TLS_ECDHE_PSK_WITH_NULL_SHA384
[0xc03C] TLS_RSA_WITH_ARIA_128_CBC_SHA256
[0xc03D] TLS_RSA_WITH_ARIA_256_CBC_SHA384
[0xc03E] TLS_DH_DSS_WITH_ARIA_128_CBC_SHA256
[0xc070] TLS_ECDHE_PSK_WITH_ARIA_128_CBC_SHA256
[0xc071] TLS_ECDHE_PSK_WITH_ARIA_256_CBC_SHA384
[0xc072] ECDHE-ECDSA-CAMELLIA128-SHA256 ECDH Camellia 128 TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256
[0xc073] ECDHE-ECDSA-CAMELLIA256-SHA38 ECDH Camellia 256 TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384
[0xc074] ECDH-ECDSA-CAMELLIA128-SHA256 ECDH/ECDSA Camellia 128 TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256
[0xc091] TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384
[0xc092] TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256
[0xc093] TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384
[0xc094] TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256
[0xc095] TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384
[0xc096] TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256
[0xc097] TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384
[0xc098] TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256
[0xc099] TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384
[0xc09A] TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256
[0xc09B] TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384
[0xc094] PSK-CAMELLIA128-SHA256 PSK CAMELLIA 128 TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256
[0xc095] PSK-CAMELLIA256-SHA384 PSK CAMELLIA 256 TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384
[0xc096] DHE-PSK-CAMELLIA128-SHA256 PSK/DHE CAMELLIA 128 TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256
[0xc097] DHE-PSK-CAMELLIA256-SHA384 PSK/DHE CAMELLIA 256 TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384
[0xc098] RSA-PSK-CAMELLIA128-SHA256 PSK/RSA CAMELLIA 128 TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256
[0xc099] RSA-PSK-CAMELLIA256-SHA384 PSK/RSA CAMELLIA 256 TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384
[0xc09A] ECDHE-PSK-CAMELLIA128-SHA25 PSK/ECDHE CAMELLIA 128 TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256
[0xc09B] ECDHE-PSK-CAMELLIA256-SHA38 PSK/ECDHE CAMELLIA 256 TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384
[0xc09c] AES128-CCM RSA AESCCM 128 TLS_RSA_WITH_AES_128_CCM
[0xc09d] AES256-CCM RSA AESCCM 256 TLS_RSA_WITH_AES_256_CCM
[0xc09e] DHE-RSA-AES128-CCM DH AESCCM 128 TLS_DHE_RSA_WITH_AES_128_CCM
[0xc0a9] PSK-AES256-CCM8 PSK AESCCM 256 TLS_PSK_WITH_AES_256_CCM_8
[0xc0aa] DHE-PSK-AES128-CCM8 PSK/DHE AESCCM 128 TLS_PSK_DHE_WITH_AES_128_CCM_8
[0xc0ab] DHE-PSK-AES256-CCM8 PSK/DHE AESCCM 256 TLS_PSK_DHE_WITH_AES_256_CCM_8
[0xc0ac] ECDHE-ECDSA-AES128-CCM ECDH AESCCM 128 TLS_ECDHE_ECDSA_WITH_AES_128_CCM
[0xc0ad] ECDHE-ECDSA-AES256-CCM ECDH AESCCM 256 TLS_ECDHE_ECDSA_WITH_AES_256_CCM
[0xc0ae] ECDHE-ECDSA-AES128-CCM8 ECDH AESCCM 128 TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8
[0xff01] GOST-GOST94 RSA GOST89 256 TLS_RSA_WITH_28147_CNT_GOST94
[0xff02] GOST-GOST89MAC RSA GOST89 256
[0xff03] GOST-GOST89STREAM RSA GOST89 256
[0xfefe] RSA DES 56 SSL_RSA_FIPS_WITH_DES_CBC_SHA
[0xfeff] RSA 3DES 168 SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA
[0xfee0] RSA 3DES 168 SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA
[0xfee1] RSA DES 56 SSL_RSA_FIPS_WITH_DES_CBC_SHA
[0x010080] RC4-MD5 RSA RC4 128 SSL_CK_RC4_128_WITH_MD5
[0x020080] EXP-RC4-MD5 RSA(512) RC4 40, export SSL_CK_RC4_128_EXPORT40_WITH_MD5
[0x030080] RC2-CBC-MD5 RSA RC2 128 SSL_CK_RC2_128_CBC_WITH_MD5
[0x040080] EXP-RC2-CBC-MD5 RSA(512) RC2 40, export SSL_CK_RC2_128_CBC_EXPORT40_WITH_MD5
[0x050080] IDEA-CBC-MD5 RSA IDEA 128 SSL_CK_IDEA_128_CBC_WITH_MD5